# v2 git bundle
ce6dd1af15e823bf2b5faf569d3c730e1b05465c refs/heads/bundle
ce6dd1af15e823bf2b5faf569d3c730e1b05465c HEAD

PACK      x Etree 039dba2ccdd446c3c83c5bd32852d6e5841288d4
author Defeng <dfhu921@163.com> 1783929660 +0800
committer Defeng <dfhu921@163.com> 1783929660 +0800

Initial commit: 初始化项目代码
=?x
100644 README.md ⛲CK)wZS40000 __pycache__ %!Y6q}p]:100644 agent_create_request.py e}Aui!F8100644 agent_ids.txt 䏇-9W,s1[100644 agent_role_request.py egK!ާ5 "100644 app copy.py uH,bNYhl100644 app.py S(Wrbk{100644 checkpointer_config.py e]?oLތ
100644 chunk_text.py 6l0g8̬?K100644 config.py p`1y{&(#|\100644 doc2pdf.py %6T.Gdy/100644 documents_prompt.py =*[NA#P100644 fileparse_util.py r=|l	_?E_Ą100644 main_agent.py ;UPrh8Km40000 modelsAPI y58^ǃu40000 picture *Q)PmȮb뺂|vm100644 prompt.py fe['=dPLM7100644 prompts.py Bh*@|a`z^7100644 requirements.txt z~f`tI9Sc=100644 template.tex k'%mK(w[x*100644 test_ship_mapping.py 6-ġ<%H40000 tools 9-]`(40000 utils ~ia8z 34>w100644 workflow_registry.py F^f 7g40000 workflows X-TO<+^lR+m0x     &xa100644 app.cpython-312.pyc fX42;\6\]100644 checkpointer_config.cpython-312.pyc S:lʦ]R100644 chunk_text.cpython-312.pyc ̆h,23hۦ貁8M100644 config.cpython-312.pyc ǩHM=
dH"k-v100644 doc2pdf.cpython-312.pyc "3;Wzkx^6100644 documents_prompt.cpython-312.pyc [n`x\GۣBmj100644 documents_prompt.cpython-313.pyc jRk5j:Gh}K100644 fileparse_util.cpython-312.pyc T*ř(oj6(100644 main_agent.cpython-312.pyc ,0fv7{100644 prompts.cpython-312.pyc HF(${5c@x100644 workflow_registry.cpython-312.pyc </Or];ŉS0qy*x?}
    g\Oj{p                        d dl Z d dlmZmZmZmZ d dlZd dlmZm	Z	m
Z
 d dlmZmZ d dlmZ 	 d dlmZmZ d dlmZmZmZ d dlmZ d d	lmZmZmZmZm Z   e       Z! G d
 de      Z"ddddddddddd
Z#de"de$fdZ%de$fdZ&e!jO                  d      de"fd       Z( G d de      Z) G d  d!e      Z*d"ee$   de$fd#Z+de)de$fd$Z,de$fd%Z-e!jO                  d&      de)fd'       Z.de*de$fd(Z/de$fd)Z0e!jO                  d*      de*fd+       Z1 G d, d-e      Z2 G d. d/e      Z3 G d0 d1e      Z4d2ee$   dee$   fd3Z5d4e$d5ee$   dee$   fd6Z6d7ee7   d8e$d9ee$   d:ee$   dee7   f
d;Z8d7ee7   d<ee$   dee7   fd=Z9d7ee7   d>e$dee7   fd?Z:d@ Z;dAee$   d8e$dBee$   dee   fdCZ< e jz                  dDe j|                        Z?d4e$dee7   fdEZ@dee   de$fdFZAd8e$dAee$   dBee$   dee7   fdGZBd8e$dAee$   dBee$   d9ee$   d:ee$   d<ee$   dee7   fdHZCe!jO                  dIe4J      de2fdK       ZDeEdLk(  rd dlFZF eFj                  e!dMdNO       yy# e$ r d dlmZmZ Y "w xY w)P    N)OptionalListSetIterable)	BaseModelFieldmodel_validator)FastAPIHTTPException)StreamingResponse)FewShotPromptTemplatePromptTemplate) ChatCompletionSystemMessageParamChatCompletionUserMessageParamChatCompletionMessageParam)	model_api)BEAUTIFY_TYPE_DICTTEMPLATE_DICTGENERATE_NORMAL_OUTLINE_PROMPT%GENERATE_MARKDOWN_LIST_OUTLINE_PROMPTGENERATE_METHOD_OUTLINE_PROMPTc                   ^    e Zd ZU dZee   ed<   dZee   ed<   dZee   ed<   dZ	ee   ed<   y)RewriteRequestNrewrite_typecontentrequiresentence)
__name__
__module____qualname__r   r   str__annotations__r   r   r        2E:\ZKYNLP\Hjunproject\project0506\aidoc_api\app.pyr   r      s:    "&L(3-&!GXc]!!GXc]!"Hhsm"r$   r   u   金句润色u	   书面化u	   讲稿化u   规整u   扩写u   续写u   汇报u   金句u   精简u   总结)
quotePolishformalStylespeechStyle
formattingexpandcontinueWritingreportquote	summarizecondenserequestreturnc                 f   t         j                  | j                  xs d      }|st        dd| j                         t	        j                  |      }|st        dd|       |j                  | j                  xs d| j                  xs d| j                  xs | j                  xs d      S )N   u   不支持的 rewrite_type: status_codedetailu   未找到提示词模板: )r   r   r   )	REWRITE_TYPE_MAPgetr   r   r   formatr   r   r   )r0   beautify_typeprompt_templates      r%   build_rewrite_promptr=   /   s    $(()=)=)CDM6QRYRfRfQg4hii(,,];O6PQ^P_4`aa!!%2%2!!:W__: "  r$   promptc                |   K   t         j                  j                  | d dg       2 3 d {   }|s| 7 6 y w)NuB   你是专业文稿改写助手，根据要求进行文本改写。querymodelsystem_promptmessagesr   	OpenaiAPIopen_api_chat_streamr>   chunks     r%   stream_llm_contentrJ   ?   sH      **??Z	 @  e K     $<:8:<<:<z/Rewritec                 L   K   t        |       }t        t        |      d      S wNztext/plain; charset=utf-8)
media_type)r=   r   rJ   r0   r>   s     r%   rewriterP   J   s(     !'*F6".    "$c                       e Zd ZU dZee   ed<   dZee   ed<   dZee   ed<   dZ	ee   ed<   dZ
ee   ed<   dZee   ed<   dZee   ed<   dZee   ed	<   y)
WriteRequestNroletemplatetitlelengthrequirement
referencesoutliner>   )r   r   r    rT   r   r!   r"   rU   rV   rW   rX   rY   rZ   r>   r#   r$   r%   rS   rS   T   sr    D(3-"Hhsm"E8C= FHSM !%K#% $J$!GXc]! FHSM r$   rS   c                       e Zd ZU dZee   ed<   dZee   ed<   dZee   ed<   dZ	ee   ed<   dZ
ee   ed<   dZee   ed<   dZee   ed<   y)	OutlineRequestNrT   rU   rV   rW   rX   rY   r>   )r   r   r    rT   r   r!   r"   rU   rV   rW   rX   rY   r>   r#   r$   r%   r\   r\   _   sd    D(3-"Hhsm"E8C= FHSM !%K#% $J$ FHSM r$   r\   rW   c                 2    | dk(  ry| dk(  ry| dk(  ry| xs dS )Nu   短u   1000字u   中u   1000-2000字u   长u   2000-5000字r3   r#   )rW   s    r%   length_convertr^   i   s*    <Rr$   c           	         | j                   r4| j                   j                         r| j                   j                         S | j                  xs d}t        j                  |      }|st        dd|       | j                  xs d}|j                         st        dd      |j                  | j                  xs d|t        | j                        | j                  xs d| j                  xs d| j                  xs d      S )Nr3   r4   u   不支持的写作模板: r5      title不能为空)rT   rV   rW   rX   rY   rZ   )r>   striprU   r   r9   r   rV   r:   rT   r^   rW   rX   rY   rZ   )r0   rU   r<   rV   s       r%   build_write_promptrb   s   s    ~~'....0~~##%%%2H#''1O6PQYPZ4[\\MMRE;;=4GHH!!\\Rgnn-''-2%%+%2 "  r$   c                |   K   t         j                  j                  | d dg       2 3 d {   }|s| 7 6 y w)Nu?   你是专业公文写作助手，请直接输出正文内容。r@   rE   rH   s     r%   stream_write_contentrd      sH      **??W	 @  e K rK   z/Writec                 L   K   t        |       }t        t        |      d      S wrM   )rb   r   rd   rO   s     r%   writerf      s(     (FV$. rQ   c           	         | j                   r4| j                   j                         r| j                   j                         S | j                  xs d}| j                  xs d}|j                         st	        dd      h d}t
        }|dk(  rt        }n
||v rt        }|j                  | j                  xs d||t        | j                        | j                  xs d| j                  xs d      S )Nr3   r4   r`   r5   >      函   报告   文书   工作总结u   方案)rT   rU   rV   rW   rX   rY   )r>   ra   rU   rV   r   r   r   r   r:   rT   r^   rW   rX   rY   )r0   rU   rV   markdown_list_templater<   s        r%   build_outline_promptrm      s    ~~'....0~~##%%%2HMMRE;;=4GHHH4O88	+	+?!!\\Rgnn-''-2%%+ "  r$   c                |   K   t         j                  j                  | d dg       2 3 d {   }|s| 7 6 y w)NuE   你是专业公文提纲生成助手，请直接输出提纲内容。r@   rE   rH   s     r%   stream_outline_contentro      sH      **??]	 @  e K rK   z/Outlinec                 L   K   t        |       }t        t        |      d      S wrM   )rm   r   ro   rO   s     r%   rZ   rZ      s(     !'*Fv&. rQ   c                       e Zd ZU  edd      Zee   ed<    edd      Zeed<    edd      Z	e
e   ed	<    eed
      Ze
e   ed<    eed      Ze
e   ed<    eed      Ze
e   ed<    ed      d        Zy)ReviewRequestNu   额外校对要求)descriptionr   .u   待校对文本r   u   检查类型types   敏感词汇)default_factoryrs   sensitive_words   错误词汇negative_wordsu   正词词汇positive_wordsafter)modec                 h    | j                   r| j                   j                         st        d      | S )Nu   content不能为空)r   ra   
ValueError)selfs    r%   check_contentzReviewRequest.check_content   s)    ||4<<#5#5#7233r$   )r   r   r    r   r   r   r!   r"   r   rt   r   listrw   ry   rz   r	   r   r#   r$   r%   rr   rr      s    "45IJGXc]J*;<GS<Sn=E49=!&t!XOT#YX %d WNDIW %d WNDIW'" #r$   rr   c                   ,    e Zd ZU eed<   eed<   eed<   y)
ReviewItemoriginalerror
suggestionN)r   r   r    r!   r"   r#   r$   r%   r   r      s    MJOr$   r   c                       e Zd ZU ee   ed<   y)ReviewResponsedataN)r   r   r    r   r   r"   r#   r$   r%   r   r      s    
z
r$   r   wordsc                 p    | D ch c]&  }|s|j                         s|j                         ( c}S c c}w N)ra   )r   words     r%   normalize_wordsr      s*    %*DUTdtzz|DJJLUDDDs   333textkeyword_setc                 (   | r|sg S t        j                         }t        |      D ]  \  }}|j                  |||f        |j	                          t               }|j                  |       D ]  \  }\  }}|j                  |        t        |      S r   )	ahocorasick	Automaton	enumerateadd_wordmake_automatonsetiteraddr   )r   r   	automatonidxkeywordfound_s          r%   find_keywordsr      s    {	%%'I!+.W7S'N3 / EE$>>$/<Aw		' 0 ;r$   itemsr   rw   ry   c                     t        ||      D ]  }| j                  |ddd        t        ||      D ]  }| j                  |ddd        | S )Nru   r3   r   r   r   rx   )r   append)r   r   rw   ry   r   s        r%   append_dictionary_resultsr      sc     g7#
 	 8 g~6#
 	 7 Lr$   rz   c                    |s| S g }| D ]r  }t        |j                  dd            t        |j                  dd            }t        fd|D              }d|v xs
 d|v xs d|v }|r|rb|j                  |       t |S )Nr   r3   r   c              3   &   K   | ]  }|v  
 y wr   r#   ).0r   r   s     r%   	<genexpr>z7filter_positive_word_false_positives.<locals>.<genexpr>"  s     L^T 0^s   u	   错别字u	   错别词u   错别词语)r!   r9   anyr   )r   rz   resultitemr   has_positive_wordis_typo_errorr   s          @r%   $filter_positive_word_false_positivesr     s     Ftxx
B/0DHHWb)*L^LL5  'e#'& 	 d   Mr$   source_textc                    t               }g }| D ]  }t        |j                  dd            j                         }t        |j                  dd            j                         }t        |j                  dd            j                         }|s||k(  r||vr|||f}||v r|j	                  |       |j                  |||d        |S )Nr   r3   r   r   r   )r   r!   r9   ra   r   r   )	r   r   seenr   r   r   r   r   keys	            r%   dedupe_and_filterr   1  s    5DFtxx
B/0668DHHWb)*002,34::<
z!;&
+$; $
 	' 2 Mr$   c                     d}d}d| d}d}d}d| d}d}d| d}d}	||d	d
||dd
||	dd
g}
d}t        g d
|      }t        |
|dddgd      }|j                  |       }|S )Nu  
    人工智能正在深刻改变现,代教育的方式。通过智能教学系统【】AI可以根据学生的学习习惯和掌握情况，提供个性化的学习内容和节奏学习内容和节奏，提高学习效率。同时，AI还能辅助教师进行作业批改、学习分析，甚至参与课堂互动，减轻教师的重复工作压力。
    虚拟助教、智能语音识别、自动文达系统等技术，也让远程教育更加高效和便捷。更加高效和便捷。随着AI技术的发展，教育不再局限于固定的教材和课堂，而是变得更加开放、灵活和智能化------让每个雪生都能获得更适合自己的学习体验。人工智能不仅是工具，更是推动教育公平和质量提升的重要力量。
    u  
    "深刻改变现,代教育中"多了","，修改为“深刻改变现代教育中”；“智能教学系统【】”中存在错误符号“【】”，修改为“智能教学系统”；“提供个性化的学习内容和节奏学习内容和节奏”存在重复内容，修改为"提供个性化的学习内容和节奏"；"自动文达系统"存在错误词语"文达"，修改为”自动问答系统“；”而是变得更加开放、灵活和智能化------“
    中存在错误符号“------”，修改为“而是变得更加开放、灵活和智能化，”；“每个雪生”中存在错别字“雪生”，修改为“每个学生”；检查完上述错误之后，正确的文本内容应该是：人工智能正在深刻改变现代教育的方式。通过智能教学系统，AI可以根据学生的学习习惯和掌握情况，提供个性化的学习内容和节奏，提高学习效率。同时，AI还能辅助教师进行作业批改、学习分析，甚至参与课堂互动，减轻教师的重复工作压力。虚拟助教、智能语音识别、自动问答系统等技术，也让远程教育更加高效和便捷。
    随着AI技术的发展，教育不再局限于固定的教材和课堂，而是变得更加开放、灵活和智能化，让每个学生都能获得更适合自己的学习体验。人工智能不仅是工具，更是推动教育公平和质量提升的重要力量。
    u   
    文本内容为u0  ,对给出的文本内容进行逻辑校对、基础校对和合规性检查，逻辑校对检测文本逻辑连贯性，基础校对检查文本中错别字、错误标点符号和重复内容。
    校对文本之后，如果你发现没有任何错误，不需要返回其他内容，只需要返回：
    ###
###
    发现错误时返回：
    ###
错误：错别字、标点不规范
原文：星光店电；万里乌云
建议：星光点点，万里无云
       
错误：错别词语、标点不规范
原文：请注丰收与团圆。
建议：庆祝丰收与团圆。
       
错误：标点不规范
原文：你好；明天
建议：你好，明天
       
错误：重复内容
原文：我听说你心情很不错不错。你心情很不错不错。
建议：我听说你心情很不错。###
    u  
    关于近期工作安排的通知
    各位同事，
    京公司研九决定，现将近期工作安排通知通知如下：
    一、项目推进方面。各部门需加快项目进度，确保按时交付。如有问题，及时与相关领导沟通解决。项目负责人要切实履行职责，加强团队协作，提高工作效率。
    二、培训学习方面：公司将组织系列培训课程，提升员工专业技能。具体时间、地点另行通知。员工需按时参加，不得无辜缺席。自即日起，严禁在工作时间从事与工作无关的活动。
    二、纪律要求。近期发现部分员工上班时间做与工作无关的事情，如炒股、聊天等，严重影响工作效率和公司形象。自即日起，严禁在工作时间从事与工作无关的活动。违反规定者，将按照公司规章制度严肃处理。
    特此通知：
    [公司名称]
    [日期]
    u  
    "京公司研九决定"中存在错别字和词语“京”、“研九”，修改为“经公司研究决定”；“工作安排通知通知”存在重复内容，修改为“工作安排通知”；“一、项目推进方面。”存在错误标点符号，参与后续内容中“二、培训学习方面：”，因此“一、项目推进方面”之后应当使用“：”，修改为“一、项目推进方面：”；“无辜缺席。”中存在错别字“辜”，修改为“无故缺席”；
    “二、纪律要求。”存在错别字、标点不规范，纪律要求应该是第三点，应该使用”：“，修改为“三、纪律要求：”；”特此通知：“中存在标点不规范，应该修改为”特此通知。“检查完上述错误之后，正确的文本内容应该是：关于近期工作安排的通知
    各位同事，
    经公司研究决定，现将近期工作安排通知如下：
    一、项目推进方面：各部门需加快项目进度，确保按时交付。如有问题，及时与相关领导沟通解决。项目负责人要切实履行职责，加强团队协作，提高工作效率。
    二、培训学习方面：公司将组织系列培训课程，提升员工专业技能。具体时间、地点另行通知。员工需按时参加，不得无故缺席。自即日起，严禁在工作时间从事与工作无关的活动。
    三、纪律要求：近期发现部分员工上班时间做与工作无关的事情，如炒股、聊天等，严重影响工作效率和公司形象。自即日起，严禁在工作时间从事与工作无关的活动。违反规定者，将按照公司规章制度严肃处理。
    特此通知。
    [公司名称]
    [日期]
    u  
    《水声目标识别》课程教学计划

    一、课程名称
    水声目标识别，该课程式用于海洋科学、水声工程、电子信息等专业本科生asfqfqfqwfwqf、研究生，以及军事院校学员、相关领域科研人员和企业技术人员技术人员。

    三、计划学时
    2026学年，总学时：48学时（理论授课32学时，实作授课16学时）

    三、授课时间
    每周4学时，共12周完成
    四、教学目标
    1. 知识目标
       使学生掌握水声目标识别的几本原理】方法和技术，包括声纳信号的特性、目标特征提取、分类与识别算法等。
       了解水声目标识别在军事（如潜艇作战、反潜作战等）和民用（如海洋资源勘探、水下考古等）领域的应用。
       熟悉水声目标识别系统的基本组成和工作原理，
    2. 能力目标
       培养学生运用所学知识对水声信号进行分析处理、特征提取和目标识别的能力。
       提高学生运用专业软件（如MATLAB等）进行水声水声信号处理和目标识别仿真的能力。
       增强学生解决实际水声目标识别问题的实践能力和创新思维。
    3. 素质目标
       培养学生严谨的科学态度和扎实的专业素养，使其剧备良好的团队协作精神和沟通能力。
       激发学生对水声技术领域的学习兴趣和探索精神，培养其自主学习和终身学习的意识。
    us  
    "式用"中存在错别字“式”，修改为：“适用”；“本科生asfqfqfqwfwqf、”中存在错别字和符号“asfqfqfqwfwqf”，修改为：“本科生、”；“三、计划学时”存在错别字使用不当，修改为：“二、计划学时”；
    “几本原理】”存在错别字、标点不规范，应该修改为：“基本原理”；“工作原理，”存在标点不规范，应该修改为：“工作原理。”；“水声水声信号”中存在重复内容“水声”，应该修改为“水声信号”；
    “剧备”存在错别字“剧”，应该修改为：”具备“。检查完上述错误之后，正确的文本内容应该是：
    《水声目标识别》课程教学计划

    一、课程名称
    水声目标识别，该课程式用于海洋科学、水声工程、电子信息等专业本科生、研究生，以及军事院校学员、相关领域科研人员和企业技术人员。

    三、计划学时
    2026学年，总学时：48学时（理论授课32学时，实作授课16学时）

    三、授课时间
    每周4学时，共12周完成
    四、教学目标
    1. 知识目标
       使学生掌握水声目标识别的基本原理、方法和技术，包括声纳信号的特性、目标特征提取、分类与识别算法等。
       了解水声目标识别在军事（如潜艇作战、反潜作战等）和民用（如海洋资源勘探、水下考古等）领域的应用。
       熟悉水声目标识别系统的基本组成和工作原理。
    2. 能力目标
       培养学生运用所学知识对水声信号进行分析处理、特征提取和目标识别的能力。
       提高学生运用专业软件（如MATLAB等）进行水声信号处理和目标识别仿真的能力。
       增强学生解决实际水声目标识别问题的实践能力和创新思维。
    3. 素质目标
       培养学生严谨的科学态度和扎实的专业素养，使其具备良好的团队协作精神和沟通能力。
       激发学生对水声技术领域的学习兴趣和探索精神，培养其自主学习和终身学习的意识。
    u  
                    
错误：标点不规范
原文：现,代教育
建议：现代教育
                    
错误：标点不规范
原文：智能教学系统【】
建议：智能教学系统
                    
错误：重复内容
原文：提供个性化的学习内容和节奏学习内容和节奏
建议：提供个性化的学习内容和节奏
                    
错误：错别字、错别词语
原文：自动文达系统
建议：自动问答系统
                    
错误：标点不规范
原文：而是变得更加开放、灵活和智能化------
建议：而是变得更加开放、灵活和智能化，
                    
错误：错别字、错别词语
原文：每个雪生
建议：每个学生
            )question	reasoningansweru)  
                    
错误：错别字、错别词语
原文：京公司研九决定
建议：经公司研究决定
                    
错误：重复内容
原文：工作安排通知通知
建议：工作安排通知
                    
错误：错别字、错别词语
原文：无辜缺席。
建议：无故缺席
                    
错误：错别字、标点不规范
原文：二、纪律要求。
建议：三、纪律要求：
                    
错误：标点不规范
原文：特此通知：
建议：特此通知。
            u  
                   
错误：错别字、错别词语
原文：式用
建议：适用
                   
错误：错别字、错别字符
原文：本科生asfqfqfqwfwqf、
建议：本科生、
                   
错误：错别字、逻辑不顺
原文：三、计划学时
建议：二、计划学时
                   
错误：错别字、标点不规范
原文：几本原理】
建议：基本原理
                   
错误：标点不规范
原文：工作原理，
建议：工作原理。
                   
错误：重复内容
原文：水声水声信号
建议：水声信号
                   
错误：错别字、错别词语
原文：剧备
建议：具备
            uO   
    问题: {question}
    推理过程: {reasoning}
    答案: {answer}
    )input_variablesrU   u   你是一个文本内容校对高手。能够根据要要求进行错误检查。请根据以下示例，解决用户提出的问题。u    问题: {question}
推理过程:r   z

)examplesexample_promptprefixsuffixr   example_separator)r   )r   r   r:   )rA   conten1
reasoning1quesconten2
reasoning2ques2conten3ques3
reasoning3r   example_templater   few_shot_promptr>   s                  r%   	cotpromptr   P  s   GJ
9 	D
GJ9 	EG29 	EJ> #	
 #
	
 #	
1%HP $;!N ,% Y2# O ##U#3FMr$   rt   r   c                 "   |d}d}t        |       D ]E  \  }}|dk(  r|| dz  }|dk(  r || dz  }|| dz  }|| dz  }|| d	z  }|d
k(  s>|| dz  }G d| d}t        |      }t        dd      t        d|      t        d|      gS )Nr3   u6   现在需要你帮我完成以下文本校对任务：u   逻辑校对u#    对这段文本进行逻辑校对
u   基础校对u   .1 进行错别字校对，错别字错误主要以文本用字不当为主，例如：星光店电，正确的应该为：星光点点。
u   .2 进行标点校对，主要以标点符号使用不当为主，例如：星光点点；万里无云，正确的应该为：星光点点，万里无云
u   .3 进行格式规范校对
u   .4 进行重复内容校对，主要以原文中出现重复词语、句子或文本为主，例如：“今天今天心情相当不错，我很开心。我很开心。“，正确的内容应该为：今天心情相当不错，我很开心。
u   合规性检查u&    对这段文本进行合规性检查
u>   
       我会给你对应的文本，进行相应的检查，z
    useru*   请不要进行思考，直接输出内容)rT   r   )r   r   r   )rt   r   r   review_titrA   query1s           r%   build_review_promptr   	  s   GH5!A~1#ABBH~1#  j  k  kH1#  y  z  zH1#:;;H1#  S  T  TH1#DEEH ">>FZ HE wF&F<hi&FEB&FFC r$   u   错误[:：]\s*(?P<error>.*?)\s*[\r\n]+原文[:：]\s*(?P<original>.*?)\s*[\r\n]+建议[:：]\s*(?P<suggestion>.*?)(?=\n\s*\n|$)c                    | j                         } | j                  d      r| dd  j                         } | j                  d      r| d d j                         } g }t        j	                  |       D ]n  }|j                  |j                  d      j                         |j                  d      j                         |j                  d      j                         d       p |S )Nz###   r   r   r   )r   r   r   )ra   
startswithendswith_REVIEW_BLOCK_REfinditerr   group)r   r   matchs      r%   parse_review_outputr   -  s    ::<DuABx~~}}UCRy F!**40[[)//1J/557++l399;
 	 1 Mr$   c                    K   d}d}t         j                  j                  d d|| dd      2 3 d {   }|s||z  }7 6 |S w)Nu   你是一个专业的文本校对专家，能够根据要求进行内容的纠正和改错请严格按照用户要求的格式输出。不要输出推理过程、解释性文字、前缀或总结。r3   Fg?)rB   json_outputrC   rD   enable_thinkingtemperaturerE   )r>   rC   	full_textrI   s       r%   call_review_modelr   B  sm     	J  I **??# @  	e I	  s(   *AA >A AAA  Ac                 f   K   t        | ||      }t        |       d {   }t        |      S 7 w)Nr   rt   r   )r   r   r   )r   rt   r   r>   model_outputs        r%   review_chunkr   Y  s:     
 !F +622L|,, 3s   1/1c                 ^  K   t        |      }t        |      }t        |      }d}	t        dt        |       |	      D 
cg c]
  }
| |
|
|	z     }}
g }|D ]D  }t        |||       d {   }t	        ||      }t        ||||      }|j                  |       F t        ||       S c c}
w 7 Cw)Ni  r   r   )r   rw   ry   )r   rangelenr   r   r   extendr   )r   rt   r   rw   ry   rz   sensitive_word_setnegative_word_setpositive_word_set
chunk_sizer   chunks	all_itemsrI   	llm_itemss                  r%   review_textr   h  s      )9'7'7J q#g,
33A 	!j.!3  
 I&
 
	 9
	
 ..,	
	 	#' * Y009
s   <B-B&B-'B+(AB-z/Review)response_modelc                    K   t        | j                  | j                  | j                  | j                  | j
                  | j                         d {   }d|iS 7 w)N)r   rt   r   rw   ry   rz   r   )r   r   rt   r   rw   ry   rz   )r0   r   s     r%   reviewr     sW     mm//---- F Fs   AAA	A__main__z0.0.0.0i#  )hostport)Hretypingr   r   r   r   r   pydanticr   r   r	   fastapir
   r   fastapi.responsesr   langchain_core.promptsr   r   ImportErrorlangchain.promptsopenai.types.chatr   r   r   	modelsAPIr   documents_promptr   r   r   r   r   appr   r8   r!   r=   rJ   postrP   rS   r\   r^   rb   rd   rf   rm   ro   rZ   rr   r   r   r   r   dictr   r   r   r   r   compileSr   r   r   r   r   r   r   uvicornrunr#   r$   r%   <module>r	     s   	 / /  6 6 * /HL { z   i#Y # " . S  S  *>  !9 !!Y !8C= S   .s  (  . S 6  *>  I  Y E49 ES E #c( tCy $: X H	
 
$Z.:H 
$Z8T$Z c d4j >vrtCy 3 # S[\vSw 8 2::7 DD	 c d4j *H-G$H S .--9- c]- 
$Z	-)1)19)1 c])1 #Y	)1
 I)1 I)1 
$Z)1X )N3
- 
 4
 zGKK)$/ q  HGGHs   I II9ݿx`
    MjEN                     "   d Z ddlZddlZddlmZ ddlmZ ddlmZ dZ	de
de
d	e
fd
Zde
d	ee
e
f   fdZd	efdZd Zd Zdde
fdZdde
fdZdde
fdZ G d d      Z e       Zedk(  r# ed        ede	         ederdnd        yy)u   
LangGraph Checkpointer 配置模块

支持多种持久化后端：
1. MemorySaver - 内存存储（仅用于测试）
2. PostgresSaver - PostgreSQL 数据库（生产环境）

使用 message_id 和 chat_id 作为 thread_id 来恢复工作流状态
    N)Optional)MemorySaver)POSTGRES_CONNECTION_STRINGpostgreschat_id
message_idreturnc                     |  d| S )u   
    生成唯一的 thread_id
    
    Args:
        chat_id: 聊天会话 ID
        message_id: 消息 ID
    
    Returns:
        组合后的唯一 thread_id
    : )r   r   s     Be:\ZKYNLP\Hjunproject\project0506\aidoc_api\checkpointer_config.pyget_thread_idr      s     Ya
|$$    	thread_idc                 d    | j                  dd      }t        |      dk(  r
|d   |d   fS |d   dfS )u   
    解析 thread_id 获取 chat_id 和 message_id
    
    Args:
        thread_id: 组合的 thread_id
    
    Returns:
        (chat_id, message_id) 元组
    r         r    )splitlen)r   partss     r   parse_thread_idr   "   s@     OOC#E
5zQQxq!!8R<r   c            	      j  K   	 ddl m}  	  | t        ddi      4 d{   }|j	                         4 d{   }|j                         4 d{   }|j                  d       d{    |j                          d{   d   }|j                  d	       d{    |j                          d{   d   }|j                  d
       d{    |j                          d{   d   }|r|r|s2	 ddd      d{    ddd      d{    ddd      d{    y|j                  d       d{    |j                          d{   }|r|d   dk7  rHt        d|r|d   nd d       	 ddd      d{    ddd      d{    ddd      d{    y|j                  d       d{    |j                          d{   d   }|s=t        d       	 ddd      d{    ddd      d{    ddd      d{    y|j                  d       d{    |j                          d{   d   }	|	dk7  rAt        d|	 d       	 ddd      d{    ddd      d{    ddd      d{    y	 ddd      d{    ddd      d{    ddd      d{    y# t        $ r Y yw xY w7 7 7 7 z7 e7 L7 77 7 	7 7 7 7 7 7 ~7 q7 d7 M7 87 7 7 7 7 7 7 7 7 7 q7 c# 1 d{  7  sw Y   nxY wddd      d{  7   n# 1 d{  7  sw Y   nxY wddd      d{  7   y# 1 d{  7  sw Y   yxY w# t        $ r}
t        d|
        Y d}
~
yd}
~
ww xY ww)u   
    验证 checkpointer 所需的数据库表是否存在且结构正确
    
    Returns:
        True 如果所有必需的表都存在且结构正确，否则 False
    r   AsyncConnectionPoolF
autocommitTkwargsNa  
                        SELECT EXISTS (
                            SELECT FROM information_schema.tables 
                            WHERE table_schema = 'public' 
                            AND table_name = 'checkpoints'
                        )
                    a  
                        SELECT EXISTS (
                            SELECT FROM information_schema.tables 
                            WHERE table_schema = 'public' 
                            AND table_name = 'checkpoint_writes'
                        )
                    a  
                        SELECT EXISTS (
                            SELECT FROM information_schema.tables 
                            WHERE table_schema = 'public' 
                            AND table_name = 'checkpoint_blobs'
                        )
                    z
                        SELECT data_type 
                        FROM information_schema.columns 
                        WHERE table_name = 'checkpoints' 
                        AND column_name = 'checkpoint'
                    jsonbz5[Checkpointer] checkpoints.checkpoint column type is NULLz, expected 'jsonb'a  
                        SELECT EXISTS (
                            SELECT FROM information_schema.columns 
                            WHERE table_name = 'checkpoint_writes' 
                            AND column_name = 'task_path'
                        )
                    z@[Checkpointer] checkpoint_writes.task_path column does not exista  
                        SELECT COUNT(*) 
                        FROM information_schema.table_constraints tc
                        JOIN information_schema.key_column_usage kcu 
                        ON tc.constraint_name = kcu.constraint_name
                        WHERE tc.table_name = 'checkpoint_writes' 
                        AND tc.constraint_type = 'PRIMARY KEY'
                       z%[Checkpointer] checkpoint_writes has z  primary key columns, expected 5z'[Checkpointer] Error verifying tables: )
psycopg_poolr   ImportErrorr   
connectioncursorexecutefetchoneprint	Exception)r   poolconncurcheckpoints_existswrites_existsblobs_existsresulttask_path_existspk_countes              r    verify_checkpointer_tables_existr4   2   s    4R&& $'
 
 ((D;;==C++ '    14*>)B& ++ '    ,/<<>%91$=M ++ '    +.,,.$8!#<L.=\$A )= )(	
 
 
P ++ '    $'<<>1F!VAY'%9 UciV\]^V_ouUv  wI  J  K$Y )= )(	
 
 
h ++ '    /2lln(<a'@$+ `b$s )= )(	
 
 
B ++ '    '*lln 4a8H1} EhZOopq$O )= )(	
 
 
\  S )= )(	
 
 
	  
 )( +? &: %9; ) )	
P 2S ) )	
h )=m ) )	
B !5I ) )	

 ) )	

 )== )((((	
 
 
 
 
^  7s;<s{  N3K N KN M:KM:MK!
ML,*K$
+L,K'
L,K*
L,6K-
7L,K0
L,*K3
+L,9MK6M	M:K9M:N $K<%N )N3*L,>K?
?L,L
%L,<MLMM:LM:N 'L(N ,N3-L,L
L,L
L,/M:L;M?M:
LM:N LN N3 L,4L
5L,L
L,)M4L 5M9M:L"M:	N L$N N3L,M&L&'M+M:6L(7M:;N L*N N3	KN3KN3N M:!M$L,'L,*L,-L,0L,3L,6M9M:<N ?L,L,MM:N L,L,MM:N L,L, M"M:$N &M(M:*N ,L>2L53L>:MM:MM:M%	MM%	!M:(N 3M64N 9N3:N NNN N3N 	N0N+&N3+N00N3c                    K   t         dk7  ry	 ddlm}  ddlm} ddl}t                d{   }|rt        d	       yt        d
       	  |t        ddi      4 d{   } | |      }|j                          d{    t        d       ddd      d{    t                d{   }|st        d       	 t                d{    yt        d       y# t        $ r*}t        d|        t        d       t        d      |d}~ww xY w7 7 7 7 # 1 d{  7  sw Y   xY w# t        $ r}t        d|        Y d}~d}~ww xY w7 7 # t        $ r}t        d|         d}~ww xY ww)u   
    初始化 PostgreSQL checkpointer 数据库表
    使用 AsyncPostgresSaver 的 setup 方法创建正确的表结构
    r   Nr   AsyncPostgresSaverr   z0[Checkpointer] ERROR: Missing required package: zU[Checkpointer] Please install: pip install langgraph-checkpoint-postgres psycopg-poolzxlanggraph-checkpoint-postgres or psycopg-pool not installed. Run: pip install langgraph-checkpoint-postgres psycopg-poolzE[Checkpointer] Database tables already exist, skipping initializationz9[Checkpointer] Initializing PostgreSQL database tables...r   Tr   2[Checkpointer] AsyncPostgresSaver.setup() executed2[Checkpointer] AsyncPostgresSaver.setup() failed: A[Checkpointer] Tables not created by setup(), using direct SQL...z6[Checkpointer] Direct SQL initialization also failed: z?[Checkpointer] PostgreSQL database tables verified successfully)CHECKPOINTER_TYPE!langgraph.checkpoint.postgres.aior7   r"   r   psycopgr#   r(   r4   r   setupr)   #create_checkpointer_tables_directly)	r7   r   r=   r3   tables_existr*   checkpointertables_exist_aftere2s	            r   init_checkpointer_dbrD      s    
 J&
H4 :;;LUW	EG	H&& $'
 
 -d3L$$&&&FH
 
  @AAQS	5777
 	OQO  @DEegJ
 	 <

 '
 
 
 
  HB1#FGGH B
 8 	J2$OP	s   E8C E8DE8
D0 DD0 "D>D?DD0 DD0 E8+E,E8>E EE E8	D&%DDE8D0 DD0 D-!D$"D-)D0 0	E9EE8EE8E 	E5!E00E55E8c            	      2  K   	 ddl m}  t        d        | t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d	       d{    |j                  d
       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    t        d       |j                  d       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    t        d       ddd      d{    ddd      d{    ddd      d{    y# t        $ r}t        d|         d}~ww xY w7 7 7 7 7 7 7 x7 b7 L7 +7 7 7 7 7 7 7 7 r# 1 d{  7  sw Y   xY w7 y# 1 d{  7  sw Y   xY w7 # 1 d{  7  sw Y   yxY ww)u'  
    直接通过 SQL 语句创建 checkpointer 所需的数据库表
    这是备用方案，当 AsyncPostgresSaver.setup() 失败时使用
    
    注意：LangGraph AsyncPostgresSaver 使用 JSONB 类型存储数据
    表名必须是: checkpoints, checkpoint_writes, checkpoint_blobs
    r   r   z,[Checkpointer] ERROR: Missing psycopg-pool: Nz?[Checkpointer] Creating checkpointer tables using direct SQL...r   Tr   z(DROP TABLE IF EXISTS checkpoints CASCADEz#DROP TABLE IF EXISTS writes CASCADEz-DROP TABLE IF EXISTS checkpoint_blobs CASCADEz.DROP TABLE IF EXISTS checkpoint_writes CASCADEz"DROP TABLE IF EXISTS blobs CASCADEz2DROP TABLE IF EXISTS checkpoint_migrations CASCADEz&[Checkpointer] Dropped existing tablesz
                    CREATE TABLE IF NOT EXISTS checkpoint_migrations (
                        v INTEGER PRIMARY KEY
                    )
                a,  
                    CREATE TABLE IF NOT EXISTS checkpoints (
                        thread_id TEXT NOT NULL,
                        checkpoint_ns TEXT NOT NULL DEFAULT '',
                        checkpoint_id TEXT NOT NULL,
                        parent_checkpoint_id TEXT,
                        type TEXT,
                        checkpoint JSONB NOT NULL DEFAULT '{}',
                        metadata JSONB NOT NULL DEFAULT '{}',
                        PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
                    )
                a{  
                    CREATE TABLE IF NOT EXISTS checkpoint_writes (
                        thread_id TEXT NOT NULL,
                        checkpoint_ns TEXT NOT NULL DEFAULT '',
                        checkpoint_id TEXT NOT NULL,
                        task_id TEXT NOT NULL,
                        task_path TEXT NOT NULL DEFAULT '',
                        idx INTEGER NOT NULL,
                        channel TEXT NOT NULL,
                        type TEXT,
                        blob BYTEA,
                        PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)
                    )
                a  
                    CREATE TABLE IF NOT EXISTS checkpoint_blobs (
                        thread_id TEXT NOT NULL,
                        checkpoint_ns TEXT NOT NULL DEFAULT '',
                        channel TEXT NOT NULL,
                        version TEXT NOT NULL,
                        type TEXT NOT NULL,
                        blob BYTEA,
                        PRIMARY KEY (thread_id, checkpoint_ns, channel, version)
                    )
                zt
                    CREATE INDEX IF NOT EXISTS checkpoints_thread_id_idx ON checkpoints(thread_id)
                z
                    CREATE INDEX IF NOT EXISTS checkpoint_writes_thread_id_idx ON checkpoint_writes(thread_id)
                z~
                    CREATE INDEX IF NOT EXISTS checkpoint_blobs_thread_id_idx ON checkpoint_blobs(thread_id)
                zm
                    INSERT INTO checkpoint_migrations (v) VALUES (1) ON CONFLICT DO NOTHING
                zF[Checkpointer] Checkpointer tables created successfully via direct SQL)r"   r   r#   r(   r   r$   r%   r&   )r   r3   r*   r+   r,   s        r   r?   r?      s    4
 
KM""d#  
??$${{}}kk"LMMMkk"GHHHkk"QRRRkk"RSSSkk"FGGGkk"VWWW>@ kk #    kk #    kk #     kk 
# 
 
 
 kk #    kk #    kk #   
 kk #    ^`Y %} %$	    <QC@A %$MHRSGW 

Q %}}} %$$$	   s  JH JH%JJH(JI+H+
I+I4H.
5IH1
I&H4
'I?H7
 IH:
I1H=
2#II 
I.I
/II
I I
!I9I

:II
I+I
,II
II+I I+$J/I)0J4J?J  J	H"HH""J(J+I+.I1I4I7I:I=I IIII
IIIII+I&II&"I+)J+I=	1I42I=	9J JJJ	JJcheckpointer_typec                 .   | xs t         } | dk(  r
t               S | dk(  r;	 ddlm} ddlm} t        st        d      |j                  t              } ||      S t        d|  d	       t               S # t        $ r t        d       t               cY S w xY w)
u   
    创建同步 checkpointer 实例
    
    Args:
        checkpointer_type: checkpointer 类型，可选 "memory", "postgres"
    
    Returns:
        checkpointer 实例
    memoryr   r   )PostgresSaver)
Connection0   POSTGRES_CONNECTION_STRING 环境变量未设置uP   [WARNING] psycopg 或 langgraph.checkpoint.postgres 未安装，回退到 memory)   [WARNING] 未知的 checkpointer 类型:    ，使用 memory)r;   r   langgraph.checkpoint.postgresrI   r=   rJ   r   
ValueErrorconnectr#   r(   )rF   rI   rJ   r+   s       r   create_checkpointerrQ   -  s     *>->H$}	j	(		!C*- !STT%%&@AD && 	9:K9LL\]^}  	!de= 	!s   9A3 3BBc                 N   | xs t         } t        d|         | dk(  rt        d       t               S | dk(  r2	 ddlm} ddlm} t        st        d       |t              } ||      S t        d
|  d       t               S # t        $ r t        d	       t               cY S w xY w)u   
    创建异步 checkpointer 实例
    
    Args:
        checkpointer_type: checkpointer 类型
    
    Returns:
        异步 checkpointer 实例
    u8   [Checkpointer] 创建异步 checkpointer, 类型配置: rH   u!   [Checkpointer] 使用 MemorySaverr   r   r6   r   rK   uU   [WARNING] psycopg_pool 或 langgraph.checkpoint.postgres 未安装，回退到 memoryrL   rM   )
r;   r(   r   r<   r7   r"   r   r   rO   r#   )rF   r7   r   r*   s       r   create_async_checkpointerrS   M  s     *>->	DEVDW
XYH$12}	j	(		!L8- !STT&'ABD%d++ 	9:K9LL\]^}  	!ij= 	!s   0B B$#B$c                 p   K   t        |       }t        |d      r|j                          d{   }|S 7 w)u   
    获取或创建异步 checkpointer 实例（正确处理上下文管理器）
    
    Args:
        checkpointer_type: checkpointer 类型
    
    Returns:
        已初始化的异步 checkpointer 实例
    
__aenter__N)rS   hasattrrU   )rF   rA   s     r    get_or_create_async_checkpointerrW   o  s9      -->?L|\*)4466 7s   +646c                   N     e Zd ZdZdZdZdZdZdZ fdZ	d Z
d Zd Zd Z xZS )	CheckpointerManageruk   
    Checkpointer 管理器 - 单例模式
    
    用于管理多个工作流的 checkpointer 实例
    NFc                 \    | j                   t        | 	  |       | _         | j                   S N)	_instancesuper__new__)cls	__class__s    r   r^   zCheckpointerManager.__new__  s'    == !GOC0CM}}r   c                 P    | j                   t               | _         | j                   S )u    获取同步 checkpointer 实例)_sync_checkpointerrQ   selfs    r   get_checkpointerz$CheckpointerManager.get_checkpointer  s%    ""*&9&;D#&&&r   c                 n  K   | j                   lt        dk(  r	 ddlm} ddlm} t        st        d       |t        d      | _        | j                  j                          d{     || j                        | _         t                d{   }|s`	 | j                   j                          d{    t        d	       t                d{   }|s)t        d       t                d{    nt        d       t        ddt        v rt        j                  d      d   nt                nFt        dk(  rt#               | _         t        d       n"t#               | _         t        dt         d       t        dt%        | j                         j&                          | j                   S 7 K7 %7 # t        $ r}t        d
|        Y d}~d}~ww xY w7 7 # t         $ r(}t        d| d       t#               | _         Y d}~d}~wt        $ r}t        d|         d}~ww xY ww)u2   
        获取异步 checkpointer 实例
        Nr   r   r6   r   z"POSTGRES_CONNECTION_STRING not setF)openr8   r9   r:   z,[Checkpointer] Database tables already existz7[Checkpointer] AsyncPostgresSaver created, connection: @r   zG[WARNING] psycopg_pool or langgraph.checkpoint.postgres not installed: z, fallback to memoryz;[Checkpointer] ERROR: Failed to create AsyncPostgresSaver: rH   z [Checkpointer] Using MemorySaverz[Checkpointer] Unknown type z, using MemorySaverz([Checkpointer] Async checkpointer type: )_async_checkpointerr;   r<   r7   r"   r   r   rO   _async_conn_poolrg   r4   r>   r(   r)   r?   r   r#   r   type__name__)rd   r7   r   r@   setup_erB   r3   s          r   get_async_checkpointerz*CheckpointerManager.get_async_checkpointer  s+     ##+ J.'T@5()MNN,?2"-D) //44666/A$BWBW/XD, *J)K#KL'b"&":":"@"@"BBB!$VX
 4T3U-U*1!$eg"E"GGG LNS  AD  Hb  AbTnTtTtuxTyz{T|  hB  TC  D  E #h.+6=(89+6=(45F4GGZ[\8d>V>V9W9`9`8abc'''M 7 $L
 C( b!$VW^V_"`aab .V H
 # =cdecffz{|/:}D,,  WXYWZ[\s   H5AG& (F3)(G& F6G& F< 6F97F< G& G!G& 2G$3AG& 5A>H53G& 6G& 9F< <	GGG& GG& $G& &	H2/HH5H2H--H22H5c                 L  K   | j                   sFt                d{    	 ddlm}  |        d{    	 ddlm}  |        d{    d| _         yy7 97 %# t        $ r}t        d|        Y d}~?d}~ww xY w7 5# t        $ r}t        d|        Y d}~Od}~ww xY ww)uC   
        初始化 checkpointer（创建数据库表等）
        Nr   )init_fault_records_tableu2   [Checkpointer] 初始化 fault_records 表失败: )init_ship_model_mapping_tableu7   [Checkpointer] 初始化 ship_model_mapping 表失败: T)_initializedrD   tools.fault_record_dbrp   r)   r(   tools.ship_model_dbrq   )rd   rp   r3   rq   s       r   r>   zCheckpointerManager.setup  s        &(((PJ.000UM3555 !%D !( 1 PJ1#NOOP 6 UOPQsSTTUs}   B$AB$A AA B  A>	B  
B$A 	A;#A61B$6A;;B$>B   	B!	BB$B!!B$c                 <    d| _         d| _        d| _        d| _        y)u+   重置 checkpointer（主要用于测试）NF)rb   ri   rj   rr   rc   s    r   resetzCheckpointerManager.reset  s"    "&#'  $!r   )rl   
__module____qualname____doc__r\   rb   rj   ri   rr   r^   re   rn   r>   rv   __classcell__)r`   s   @r   rY   rY     s@     IL
'6(p%$"r   rY   __main__u   Checkpointer 配置测试:u
     类型: u     PostgreSQL 连接: u	   已配置u	   未配置r[   )ry   osasynciotypingr   langgraph.checkpoint.memoryr   configr   r;   strr   tupler   boolr4   rD   r?   rQ   rS   rW   rY   checkpointer_managerrl   r(   r   r   r   <module>r      s    
   3 - %3 %C %C %s uS#X  ^ ^B3RlaaH3 @ Dc $g" g"T +,  z	
&'	J()
*+	!1K+Q\!]
^_ r   (xa
    kOj`                     &   U d dl Z d dlZd dlZd dlmZ d dlZd dlmZ d dlZd dl	m
Z
mZmZmZmZmZ d dlmZ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 d dlZd dl Z d dl!Z!d dl"Z"d dl#m$Z$  e"jJ                  e&      Z'd g e(e$      z  Z) ejT                         Z+d	 Z,d?d
e-de.fdZ/de-fdZ0de-de-fdZ1de-de
e
e-      de2fdZ3de-de
e
e-      de2fdZ4g dg dg dg dgZ5e
e
e-      e6d<   e5dfde
ee-ef      de
e
e-      de7dz  dee
e
e      e
e   f   fdZ8de-de2fdZ9d@dZ:d  Z;dAd"Z<d# Z=dAd$Z>d% Z?dBd&Z@d' ZAdCd(ZBdAd)ZCdAd*ZDd+ ZEdDd-ZFdEd/ZGd0ed1e-d2e-deee-ef      fd3ZHd0ed1e-d2e-deee-ef      fd4ZIe&d5k(  rcd6ZJ	  eKeJd7d.8      5 ZL e j                  eL      ZNddd       g d:ZR eAeNd;<      ZN e?eN=      ZS eDeSd!      ZT eFeTd,>      ZUeUD ]
  ZV eQeV        yy# 1 sw Y   DxY w# eO$ rZP eQd9eP        g ZNY dZP[P^dZP[Pww xY w)F    N)Counter)OpenAI)ListDictOptionalUnionAnyTuple)PurePathPath)	FastAPIFiler   
UploadFileHTTPExceptionFormRequestHeaderBody)process_document)API_URLSc                 F   ddgdgdgdgd}g }| j                  dg       D ]n  }|j                  d      }|j                  d	i       }||v s+d
}||   D ])  \  }}t        |j                  |d
            }	|| |	 z  }+ |j                  |       p d
j                  |      S )N)u	   舰艇为   名称)u	   ，舷号   舷号)u   ，系统：r   )u   ，子系统：r   )u   ，设备：r   )u   舰艇u   系统u	   子系统u   设备entitiestype
properties )getstrappendjoin)
datatype_mapping
text_partsentityentity_typer   
entity_strprefixattr_keyvalues
             9e:\ZKYNLP\Hjunproject\project0506\aidoc_api\chunk_text.pyformat_entity_textr,      s     +,CD-.34-.	L J ((:r*jj(ZZb1
 ,&J$0$= JNN8R8900
 %> j) +  77:    task_idreturnc                     t         5  t        j                  t        t                    }t        |xx   dz  cc<   ddd       t           }|S # 1 sw Y   xY w)uM   返回 (analyze_url, contentlist_url)，选当前 inflight 最少的实例。   N)_api_url_lock_api_url_inflightindexminr   )r.   idxbases      r+   get_api_urlr8   8   sH    	%%c*;&<=#!# 
 C=DK	 
s   4AAurlc                     t         5  | t        v r2t        j                  |       }t        dt        |   dz
        t        |<   d d d        y # 1 sw Y   y xY w)Nr   r1   )r2   r   r4   maxr3   )r9   r6   s     r+   release_api_urlr<   A   sA    	(?..%C%(,=c,BQ,F%Gc" 
s   ;AAhtmlc                    t        | t              syt        j                  d| t        j                  t        j
                  z        }|sy|j                  d      }t        j                  dd|      }|j                         S )uB   提取 HTML 表格中第一个 <tr> 内的文本（去除标签）r   <tr[^>]*>(.*?)</tr>r1   <[^>]+>	
isinstancer   research
IGNORECASEDOTALLgroupsubstrip)r=   matchfirst_tr_contenttexts       r+   extract_text_from_first_trrM   F   sb    dC II,dBMMBII4MNE{{1~66*b"23D::<r-   rL   patternsc                 f    | sy| j                         |D ]  }t        fd|D              s y y)u?   检查文本是否包含任意一组关键词（全部命中）Fc              3   &   K   | ]  }|v  
 y wN ).0keyword
text_lowers     r+   	<genexpr>z&matches_any_pattern.<locals>.<genexpr>Y   s     <Gw*$G   T)lowerall)rL   rN   patternrU   s      @r+   matches_any_patternr[   S   s4    J<G<<  r-   
table_bodyc                 0    t        |       }t        ||      S )uT   判断是否为维修项目表格：仅检查第一个 <tr> 是否匹配任一模式)rM   r[   )r\   rN   first_tr_texts      r+   is_maintenance_tabler_   ^   s    .z:M}h77r-   )   维修项目编号u   组成编码r   u   维修项目u   维修间隔期)r`   u   维修级别r   )   项目编号u   编码u   维修内容u   周期)u   序号u	   维修项u   标准u   频次MAINTENANCE_TABLE_PATTERNSrecordsmax_following_for_lastc                 L   g }d }t               }d}| D ]  }|j                  d      dk(  xr t        |j                  dd      |      }|r6|sd}d }>|)|j                  |       |j	                  d |D               |g}m|p|j                  |        |)|j                  |       |j	                  d |D               |r>|<|d	   }	|d
z   }
t        |	      |
kD  r$|	d |
 }|	|
d  D ch c]  }|d   	 }}||z  }||d	<   | D cg c]  }|d   |vs| }}||fS c c}w c c}w )NFr   tabler\   r   Tc              3   &   K   | ]	  }|d      ywidNrR   rS   rs     r+   rV   z;extract_maintenance_groups_and_remaining.<locals>.<genexpr>   s     ?A$   c              3   &   K   | ]	  }|d      ywrh   rR   rj   s     r+   rV   z;extract_maintenance_groups_and_remaining.<locals>.<genexpr>   s     7A$rl   r1   ri   )setr   r_   r    updatelen)rc   rN   rd   groupscurrent_groupused_idsskipped_firstrecordis_start
last_groupmax_len	truncatedrk   removed_idsremaining_recordss                  r+   (extract_maintenance_groups_and_remainingr}   t   sw   
 FMuH MJJv') I L"!=xH 	
   $ $ (m,???#HM($$V,+ 0  m$777 (4BZ
(1,z?W$"8G,I,6wx,@A,@q1T7,@KA#H"F2J %,GGqqwh/FGG$$$ B Hs   )DD!D!c                 "   t        | t              syt        j                  d| t        j                  t        j
                  z        }|sy|j                  d      }t        j                  dd|      }|j                         }d|v }d|v }|xr |S )u   
    判断 table_body 是否为操作项目表，依据是第一行 <tr> 中是否包含 '项目编号' 和 '操作项目'
    Fr?   r1   r@   r   ra   u   操作项目rA   )r\   rJ   first_tr_htmltext_in_first_tr
text_cleanhas_codehas_items          r+   is_operation_table_by_first_trr      s     j#& II,j"--")):STEKKNM vvj"m< "'')J +H+H  r-   c                 \   g }d}t               }d}| D ]  }|j                  d      dk(  xr t        |j                  dd            }|r8|2|sd}n)|j                  |       |j	                  d |D               |g}j|g}n|q|j                  |        |,|sn)|j                  |       |j	                  d	 |D               |rB|@|d
   }t        |      |dz   kD  r*|d|dz    }	||dz   d D 
ch c]  }
|
d   	 }}
||z  }|	|d
<   | D 
cg c]  }
|
d   |vs|
 }}
||fS c c}
w c c}
w )u  
    通过语义判断表格是否为操作项目表（基于第一行内容），并分组。
    注意：第一个识别到的操作项目表及其后续记录组成的 group 会被跳过（不加入 groups），
          但这些记录仍保留在 remaining_records 中。
    
    普通起始标记：组 = [start, ..., next_start - 1]
    最后一个起始标记：组 = [start, ..., start + max_following_for_last] （若指定）
    NFr   rf   r\   r   Tc              3   &   K   | ]	  }|d      ywrh   rR   rj   s     r+   rV   z9extract_operation_groups_and_remaining.<locals>.<genexpr>   s     #C]AdG]rl   c              3   &   K   | ]	  }|d      ywrh   rR   rj   s     r+   rV   z9extract_operation_groups_and_remaining.<locals>.<genexpr>   s     ;]AdG]rl   rn   r1   ri   )ro   r   r   r    rp   rq   )rc   rd   rr   rs   rt   first_group_skippedrv   rw   rx   rz   rk   r{   r|   s                r+   &extract_operation_groups_and_remainingr      s    FMuHJJv') M.vzz,/KL 	
 (**.' MM-0OO#C]#CC!' "(($$V,/ 4  "MM-(OO;];; (4BZ
z?3a77"#>$:Q$>?I,67MPQ7Q7R,ST,Sq1T7,SKT#H"F2J$+GGqqwh/FGG$$$ U Hs   1D$D)D)c                    g d}g }t               }g }t        |       D ]R  \  }}|j                  d      dk(  s|j                  dd      t        fd|D              sB|j	                  |       T t        |      D ]  \  }}|dz   t        |      k  r	||dz      }	nt        |       }	g }
dD ]2  }||z
  }|dk\  s|
j	                  | |          |j                  |       4 t        ||	      D ]'  }|
j	                  | |          |j                  |       ) |j	                  |
        t        t        |             D cg c]  }||vr| |    }}||fS c c}w )	N)u   一、故障现象u   单位:u   故障名称:u   一、基本情况u   故障现象及原因:u   故障名称：u   实例故障r   rL   r   c              3   &   K   | ]  }|v  
 y wrQ   rR   )rS   rT   rL   s     r+   rV   z!extract_wxanli.<locals>.<genexpr>  s     ;(w7d?(rW   r1   )   r1   r   )ro   	enumerater   anyr    rq   addrange)rc   keywordsslicesprocessed_indiceskeyword_positionsirv   r6   	start_posend_posslice_recordsoffsetprev_idxr|   rL   s                 @r+   extract_wxanlir     s   H F w'	6::f'::fb)D;(;;!((+ ( $$56Y7S*++'a0G'lG  F 6)H1}$$WX%67!%%h/	  y'*A  ,!!!$ + 	m$- 74 "#g,//q%% 	
/  
 $$$s   E@  c                    g }g }d}g }| D ]0  }d|vr	|j                  d      s|j                  d      }|j                  dd      }d}	d}
|d   dk(  rX|j                  dd      }|j                  d      }|*t        |t              r|d	kD  rd
t        |d      z  dz   |z   }|dz   }	d}
n|d   dk(  r|j                  d      }|j                  dd      }dD ]  }|j	                  |d      } d}|r4t        |t
              rdj                  d |D              }nt        |      }t        |j                               }t        |j                               }|s|r||rdndz   |z   dz   }	nd}	d}
n|d   dk(  r|j                  dd      }|j                  dd      }t        |t
              rdj                  d |D              }nt        |t              st        |      }t        |t
              rdj                  d |D              }nt        |t              st        |      }|j                         s|j                         r|dz   |z   dz   }	nd}	d}
n7|d   dk(  r-|j                  dd      }|j                         r|dz   }	nd}	d}
n||d}|	j                         s|
st        |      t        |	      z   |kD  }|	j                         r>|r<|s|r1|j                  |j                  d             |j                  |       |	}|g}|	j                         r||	z  }|
s |j                  |       3 |s|r1|j                  |j                  d             |j                  |       ||fS )Nr   r   bboxpage_idxrn   FrL   
text_levelr   #    
Trf   table_captionr\   z colspan="1"z rowspan="1"z colspan='1'z rowspan='1'z
 colspan=1z
 rowspan=1c              3   2   K   | ]  }t        |        y wrQ   r   rS   cs     r+   rV   z%split_content_bbox.<locals>.<genexpr>b       +JMqCFM   imageimage_captionimg_pathc              3   2   K   | ]  }t        |        y wrQ   r   rS   items     r+   rV   z%split_content_bbox.<locals>.<genexpr>w       )N#d)r   c              3   2   K   | ]  }t        |        y wrQ   r   rS   ps     r+   rV   z%split_content_bbox.<locals>.<genexpr>|       $>XSVXr   	discardedr   r   )r   rB   intr5   replacelistr!   r   boolrI   rq   r    rstrip)r"   
max_lengthcontentshighlight_listscurrent_contentcurrent_highlightsinsr   r   new_textshould_record_highlightrL   levelr   r\   rZ   caption_strhas_captionhas_bodyr   r   highlight_itemwould_exceeds                          r+   split_content_bboxr   <  sz   HOOwwvwwv77:r*"'v;& 7762&DGGL)E Zs%;	S]*S047d{H&*#[G#GGO4Mr2J x'//<
 x KmT2"&))+JM+J"JK"%m"4K {0023KJ,,./Hh&+$2FSVZZ '+#[G#GGOR8Mwwz2.H-. $		)N)N Ns3 #M 2(D)99$>X$>>#.x=""$(8(4/(:TA&*#[K'7762&Dzz|$;&*# 
 '/=~~(? ?+c(m;jH >>"4 6 6t <=&&'9:&O"0!1 ~~8+&")).9O T ,..t4512_$$r-   c                     g }g }t        |       D ]F  \  }}d|v r,|d   r'|r|j                  |       g }|j                  |       6|j                  |       H |r|j                  |       |S )Nr   )r   r    )rc   resultrs   r   r   s        r+   group_recordsr     sv    FMG$333|#4m, "  %   % % m$Mr-   c                    g }| D ]f  }|j                  d      dk7  r|j                  dd      }|j                  dg       }|j                  d      }|j                  dd      xs d}d	D ]  }|j                  |d      } d}	|r4t        |t              rd
j	                  d |D              }	nt        |      }	t        |	j                               }
t        |j                               }|
s|s|	|
rd
ndz   |z   }||dg}t        |      |kD  r8t        ||      }|D ]%  }|j                  |j                  d
      |d       ' D|j                  |j                  d
      |d       i |D cg c]C  }|j                  d      r0t        |d   t              rt        |d         dkD  rd|d   d   v r|E }}|j                  d        |S c c}w )u  
    处理没有 bbox 信息的文件数据（主要面向纯表格类内容）。
    每个 table 作为一个独立切片，不与其他记录拼接。
    
    - 单个 table 内容超过 max_length 时，调用 chunk_reset 在 </tr> 处安全切分，
      切分后的多个 chunk 共享同一组 positions
    - 清理冗余 colspan="1" / rowspan="1" 属性
    - bbox 缺失时填充空列表 []
    
    返回结构与 get_chunk_bbox 一致：[{"content": str, "positions": [...]}]
    r   rf   r   rn   r   r   r\   r   r   r   c              3   2   K   | ]  }t        |        y wrQ   r   r   s     r+   rV   z+get_chunk_bbox_otherfile.<locals>.<genexpr>  s     'F1Ar   r   content	positionsr   r   c                     | d   d   d   S Nr   rn   r   rR   r   s    r+   <lambda>z*get_chunk_bbox_otherfile.<locals>.<lambda>  s    tK'8'<Z'Hr-   key)r   r   rB   r   r!   r   r   rI   rq   chunk_resetr    r   sort)r"   r   r   r   r   r   r   r\   rZ   r   r   r   r   r   
sub_chunksrH   r   valid_slicess                     r+   get_chunk_bbox_otherfiler     s    F776?g%77:r*wwvr"0WW\2.4"

G
 $++GR8J
 -."ii'F'FF!-0;,,./
((*+x"=
J"*D9:	 w<*$$Wj9J!"zz$/!*  " MM">>$/& Y f  88K tK($/[!"Q&${+A..	 	   HIs   3AGc                    t        | d      D ]
  \  }}||d<    t        | d      \  }}t        | d      \  }}t        |       \  }}g }	t	        |      dkD  r|D ]D  }
t        |
      \  }}t        t        ||            D ]  \  }\  }}|	j                  ||d        F t        |      }|D ]D  }
t        |
      \  }}t        t        ||            D ]  \  }\  }}|	j                  ||d        F |	D cg c]C  }|j                  d      r0t        |d   t              rt	        |d         dkD  rd	|d   d   v r|E }}t        |d
       }	|	S t	        |      dkD  r|D ]D  }
t        |
      \  }}t        t        ||            D ]  \  }\  }}|	j                  ||d        F t        |      }|D ]D  }
t        |
      \  }}t        t        ||            D ]  \  }\  }}|	j                  ||d        F |	D cg c]C  }|j                  d      r0t        |d   t              rt	        |d         dkD  rd	|d   d   v r|E }}t        |d       }	|	S t	        |      dkD  r|D ]D  }
t        |
      \  }}t        t        ||            D ]  \  }\  }}|	j                  ||d        F |D ]  }
|
j                  d      s|
j                  d	d      }|
d   }||dg}|
d   dk(  rR|
j                  d      r-|
j                  dd      }|
j                  d      }d|z  |z   }nP|
j                  dd      }n<|
d   dk(  r0|
j                  d      xs ddz   |
j                  d      xs dz   }n|
d   dk(  r|
j                  dg       }|
j                  dg       }t        |t              rdj                  d |D              }nt        |t              st        |      }t        |t              rdj                  d |D              }nt        |t              st        |      }|j                         s|j                         r|xs ddz   |xs dz   }n|
d   dk(  r|
j                  dd      }n|	j                  ||d        |	D cg c]C  }|j                  d      r0t        |d   t              rt	        |d         dkD  rd	|d   d   v r|E }}t        |d       }	|	S t        |       }|D ]D  }
t        |
      \  }}t        t        ||            D ]  \  }\  }}|	j                  ||d        F |	D cg c]C  }|j                  d      r0t        |d   t              rt	        |d         dkD  rd	|d   d   v r|E }}|	D cg c]C  }|j                  d      r0t        |d   t              rt	        |d         dkD  rd	|d   d   v r|E }}t        |d       }	|	S c c}w c c}w c c}w c c}w c c}w ) Nr1   )startri      )rd   r   r   r   r   c                     | d   d   d   S r   rR   r   s    r+   r   z get_chunk_bbox.<locals>.<lambda>4      tK7H7LZ7Xr-   r   c                     | d   d   d   S r   rR   r   s    r+   r   z get_chunk_bbox.<locals>.<lambda>L  r   r-   r   r   r   rL   r   r   r   rf   r   r   r\   r   r   r   c              3   2   K   | ]  }t        |        y wrQ   r   r   s     r+   rV   z!get_chunk_bbox.<locals>.<genexpr>l  s     -RMDc$iMr   c              3   2   K   | ]  }t        |        y wrQ   r   r   s     r+   rV   z!get_chunk_bbox.<locals>.<genexpr>r  s     (BAQr   r   c                     | d   d   d   S r   rR   r   s    r+   r   z get_chunk_bbox.<locals>.<lambda>  r   r-   c                     | d   d   d   S r   rR   r   s    r+   r   z get_chunk_bbox.<locals>.<lambda>  r   r-   )r   r}   r   r   rq   r   zipr    r   r   rB   r   sortedr!   r   rI   )r"   r6   r   repair_dataclean_repair_recordsoperation_dataclean_operation_recordswxanli_dataclean_wxanli_datar   r   r   highlight_listr   h_listrr   r   r   r   r   rL   r   r   r   s                           r+   get_chunk_bboxr     s   t1-	TT
 .(PQUmo(p%K%.TUYqs.t+N+%3D%9"K"F
;!C&8&=#G^(1#g~2N(O$$GV ' &  )P  34C&8&=#G^(1#g~2N(O$$GV ' &  )P  $
#Txx$4,d3D%&*d;/22	 V 	 
 *XY\ M[ 
^	q	 !C&8&=#G^(1#g~2N(O$$GV ' &  )P " 67C&8&=#G^(1#g~2N(O$$GV ' &  )P  $
#Txx$4,d3D%&*d;/22	 V 	 
 *XYl Mi 
[	A	C&8&=#G^(1#g~2N(O$$GV ' &  )P  %C776?wwz1-Hv;D&.=>I6{f$77<(7762.DGGL1E!EkD0G!ggfb1GV'77?39rTASWW\EZE`^`aV' # <77:r2 mT2$(II-RM-R$RM#M37$'$6M h-#yy(B(BBH#Hc2"8}H &&(HNN,<,2d:hn"MGV+''&"-MMgIFGS %Z $
#Txx$4,d3D%&*d;/22	 V 	 
 *XY2 M/ t$C&8&=#G^(1#g~2N(O$$GV ' &  )P  $
#Txx$4,d3D%&*d;/22	 V 	 
 $
#Txx$4,d3D%&*d;/22	 V 	 
 *XYMk
0
z
"

s#   :AW5AW:AW?AXAX	c                    t        |       |k  r| gS t        j                  d|       }g }t        dt        |      d      D ]4  }||   |dz   t        |      k  r||dz      ndz   }|j	                  |       6 g }d}|D ]Q  }t        |      t        |      z   |k  r||z  }#|r|j	                  |       n|j	                  |d |        ||d  }|}S |r|j	                  |       |S )Nu   ([。！？；!?])r   r   r1   r   )rq   rC   splitr   r    )	rL   r   parts	sentencesr   schunkscurrentsents	            r+   split_text_preserve_sentencesr     s    
4yJv HH*D1EI1c%j!$!HacCJ&6ac
B? % FGw<#d)#z1tOGg& d;J/0JK(G  gMr-   c                    ddl m} | D ]u  }t        |t              sd|v s|d   } ||      }|j                  r9|j                  d   dk(  r't         ||j                  dd        }d| | d|d<   kd| | d|d<   w | S )	u   
    遍历 data 列表，若元素包含 'img_path' 字段，则移除前缀 'images/' 并拼接新前缀。
    使用 pathlib 安全处理路径。
    r   )PurePosixPathr   imagesr1   Nu
   ![图片]())pathlibr   rB   dictr   r   )r"   r(   r   r   r   r   relative_paths          r+   data_replacer    s    
 &c4 Z3%6:Hh'Aww1771:1 #M17712;$? @$.vh}oQ"GJ %/vhxj"BJ  Kr-   c                    g dg fd}| D ]  }d|vr	d}|j                  dg       }|j                  dd      }|d   dk(  r|j                  dd      }|dz   }n:|d   d	k(  rj|j                  d
      }|j                  d      }	d}
|r4t        |t              rdj                  d |D              }
nt	        |      }
|
dz   |	xs dz   dz   }n|d   dk(  r|j                  dd      }|j                  dd      }t        |t              rdj                  d |D              }nt        |t              st	        |      }t        |t              rdj                  d |D              }nt        |t              st	        |      }|s|r|dz   |z   dz   }nt              t        |      z   |kD  rUr |        dg t        |      |kD  r"|d| j                  ||d        |        |j                  ||d       |z  j                  ||d        srj                  d       S )u   
    将 data 中的 text/table/image 内容按字符长度分块（每块不超过 max_length），
    返回 [{"content": str, "highlight_list": list}, ...]
    r   c                  T    sr# j                  j                         d       yy)u:   内部函数：将当前内容打包进 chunks，并重置r   r   N)r    copy)r   r   current_highlight_lists   r+   _flush_chunkz)filter_content_bbox.<locals>._flush_chunk  s.    4MM*"8"="="?  5r-   r   r   r   rn   rL   r   rf   r   r\   c              3   2   K   | ]  }t        |        y wrQ   r   r   s     r+   rV   z&filter_content_bbox.<locals>.<genexpr>  r   r   r   r   r   c              3   2   K   | ]  }t        |        y wrQ   r   r   s     r+   rV   z&filter_content_bbox.<locals>.<genexpr>  r   r   c              3   2   K   | ]  }t        |        y wrQ   r   r   s     r+   rV   z&filter_content_bbox.<locals>.<genexpr>
  r   r   Nr   r	  )r   rB   r   r!   r   rq   r    )r"   r   r  r   added_contentr   r   text_contentr   r\   r   r   r   r   r   r  s                @@@r+   filter_content_bboxr    sZ   
 FO wwvr"77:r*v;& 7762.L(4/M[G#GGO4M.JKmT2"&))+JM+J"JK"%m"4K'$.*2BCdJM[G#GGOR8Mwwz2.H-. $		)N)N Ns3 #M 2(D)99$>X$>>#.x= - 4x ?$ F #m"44zA"$)+& =!J."/"<&--8T.RS"/&--8T.RS},O"))x*NOG L 0&4
 	
 Mr-   c                 \   g }d}|t        |       k  r||z   }|t        |       k\  r|j                  | |d         	 |S | || }|j                  d      }|dk7  r||z   t        d      z   }n|j                  d      }|dk7  r||z   }n	 |j                  | ||        |}|t        |       k  r|S )Nr   z</tr>rn   r   )rq   r    rfind)r   
MAX_lengthr   r   endsnippetlast_tr_endlast_newlines           r+   r   r   5  s    FE
#g,
j #g,MM'%&/*  M %$mmG,"+%G4C #==.Lr!l* geC()' #g,
( Mr-   c                     g }| D ]S  }|d   }|d   }t        |      dk  r|j                  |       -t        ||      }|D ]  }|j                  ||d        U |S )Nr   r   r   r   )rq   r    r   )r"   r  slice_resetr   r   r   r   chunks           r+   chunk_checkr  M  sw    Ki.$	w<4s# !*5F""$!*$     r-   c                    |j                  dg       D cg c]  }d|v rd|d   v r|d   d    }}|sy|d   }	 t        | dd      5 }t        j                  |      }ddd       D ]M  }t	        |j                  d	            t	        |      k(  s*|j                  d
      |j                  d      dc S  yc c}w # 1 sw Y   axY w# t
        $ r t        d|         Y yt        j                  $ r t        d       Y yw xY w)u  
    从NER结果中提取舷号，再从JSON文件中查找对应的舰船信息
    :param json_file_path: JSON文件路径
    :param data: get_entity() 返回的NER结果字典
    :return: 包含 model_name 和 ship_name 的字典，未找到返回 None
    r   r   r   Nr   rk   utf-8encodinghull_number
model_name	ship_name)r#  r$  u   错误：找不到文件 u#   错误：JSON 文件格式不正确)r   openjsonloadr   FileNotFoundErrorprintJSONDecodeError)json_file_pathr"   r%   hullstarget_hullf	ship_datar   s           r+   find_ship_info_by_hullr0  ^  s    hhz2..F6!h&2F&F 	|X&. 
 
 (K.#8A		!I 9 D488M*+s;/??"&((<"8!%+!6   - 98  ).)9:; 34s@   B9C
 B>3C
 $C
 7C
 >CC
 
D#DD   c                 
   | s| S g }g }g }| D ]  }|j                  dd      xs d}|j                  dg       xs g }t        |      |k  r#|j                  |       |j                  |       `|r&dj	                  |      }	|	|	rdndz   |z   }||z   }g }g }|j                  ||d        |rVdj	                  |      }
|r/|d   }|d   xs d|d   rdndz   |
z   |d<   |d   xs g |z   |d<   |S |j                  |
|d       |S )u   
    合并过短的切片：
    - 如果某切片 content 长度 <= min_length，则将其合并到下一个切片的开头
    - 若处于末尾无下一个切片，则反向合并到上一个切片末尾
    - content 用换行拼接，positions 顺序拼接
    
    Args:
        slices: [{"content": str, "positions": [...]}]
        min_length: 短切片的字符长度阈值（含）
        filename: 用于实体提取的文件名
    
    Returns:
        合并后的 slices 列表
    r   r   r   r   r   rn   )r   rq   r    extendr!   )r   
min_lengthfilenamer   pending_contentspending_positionsr   r   r   merged_prefixmerged_suffixlasts               r+   merge_short_slicesr;    sT    F'')R(.BGGK,2	w<:%##G,$$Y/   $		*: ;'=4bIGS-	9	#% $&!MM"& # 0 		"23":D#I4"iVXY\iiDO!%k!2!8b<M MD M MM(. 
 Mr-   r  c                    t         j                  j                  |      }|d   }| d}t        d|        t        j                  |       D ]\  \  }}}||v st         j                  j                  ||      }		 t        |	d|      5 }
t        j                  |
      }|cddd       c S  y# 1 sw Y   nxY wm# t        j                  $ r t        d|	 d       Y  yt        $ r}t        d	|	 d
|        Y d}~ yd}~ww xY w)u~   
    根据原始文件名，在指定目录及其子目录下查找对应的 _content_list.json 文件并返回内容。
    r   z_content_list.jsonu   正在查找文件: rk   r   Nu   文件 u    不是有效的 JSON 格式。u   读取文件 u    时发生错误: )ospathsplitextr)  walkr!   r%  r&  r'  r*  	Exception)	directoryoriginal_filenamer!  	base_name	file_nametarget_filenamerootdirsfiles	file_pathr.  	json_dataes                r+   find_and_read_content_listrM    s      !23I!I"#56O	  1
23  WWY/dEe#T?;I	)S8< $		!I$ =< 0  =<< '' 	{*IJK i[0B1#FGs6   :B:B-	B:-B6	2B::"DD'C>>Dpdf_pathimage_prefixr5  c                 l  K   t        |       d{   }|?|\  }}|r=|r;t        ||      }t        |      }t        |d      }t	        |d|      }||dS g i dS t               }		 t        j                  | d      4 d{   }
|
j                          d{   }ddd      d{    d|dfi}t        j                  d	
      4 d{   }|j                  |	|       d{   }ddd      d{    j                  dk7  r<t        j                  d|j                   d|j                          	 t!        |	       y|j#                         }|j%                  di       }|j%                  dg       }|j%                  di       }t        ||      }t        |      }t        |d      }t	        |d|      }g i dt!        |	       S 7 7 S7 >7 1# 1 d{  7  sw Y   BxY w7 $7 7 # 1 d{  7  sw Y   xY w# t"        j&                  $ rG t        j                  d       t        j)                  j                         g i dcY t!        |	       S t*        $ r/}t        j                  d| d       Y d}~t!        |	       yd}~ww xY w# t!        |	       w xY ww)u,   异步调用 PDF 分析服务并处理响应Nr   r1  r4  r5  r   r  rbfilezapplication/pdfi  )timeout)rI     u"   ❌ API 请求失败，状态码: u
   , 响应: r"   content_listr  u%   ❌ 响应不是有效的 JSON 格式u   处理 PDF 文件时出错: T)exc_info)r   r  r   r  r;  r8   aiofilesr%  readhttpxAsyncClientpoststatus_codeloggererrorrL   r<   r&  r   r*  debugrA  )rN  rO  r5  
doc_resultrW  r  replaced_content_listr   slices_checkapi_urlr.  file_contentrI  clientresponser   r"   rL  s                     r+   process_pdf_fileri    sj    '11J)fF$0|$L!#$9:F&vt4L-lrS[\L*f==++mG!==400A!">L 10(L2CDE$$W55#[[[>>H 65 3&LL=h>R>R=SS]^f^k^k]lmn* 	 ' zz&"%xx3(B' ,\< H 56"640),2xX+ 	 W 2 1) 1000 6> 6555$  ,<=X]]#++
 	 	  3A37$G 	 	 s  J4GAJ4'H GH GGGH )G*%H G3H G;*G6+G;/H :G9;AH >J4
A;H J4H GH G0#G&$G0+	H 6G;9H ;HHH	H AJ!J$ J4*J!2JJ$ J4J!!J$ $J11J4c                    K   t        |       d{   }|A|\  }}|r9|r6t        ||      }t        |      }t        |d      }t	        |d|      }||dS yyg i dS 7 Lw)u5   异步调用 Office 文件分析服务并处理响应Nr   r1  rQ  rR  )r   r  r   r  r;  )	rN  rO  r5  rb  rW  r  rc  r   rd  s	            r+   process_other_filerk    s      (11J)fF$0|$L!#$9:F&vt4L-lrS[\L*f== #< ++ 2s   A AAA __main__uc   E:\ZKYNLP\Hjunproject\project0506\kgrag\122-06A0014-B01001_发动机-维修手册_content_list.jsonrk   r   u   读取 JSON 文件时出错：)1234567890u   第u   十u   一u   二u   三u   四u   五u   六u   七u   八u   九z/api/v1/knowledge/files/images/)r"   r(   )r"   )r4  )r   )r   )r   )iL  )i  )r1  u-   122-06A0014-B01003_雷达-使用说明书.pdf)r  )Wr&  fitzr=  collectionsr   uuidopenair   rC   typingr   r   r   r   r	   r
   r  r   r   PathLibfastapir   r   r   r   r   r   r   r   fileparse_utilr   	threadingrY  r[  loggingconfigr   	getLogger__name__r_  rq   r3   Lockr2   r,   r   tupler8   r<   rM   r   r[   r_   rb   __annotations__r   r}   r   r   r   r   r   r   r   r   r  r  r   r  r0  r;  rM  ri  rk  filepathr%  rT  r'  r"   rA  rL  r)  start_charsr   slices_1slices_2r   rR   r-   r+   <module>r     s     	    	 : : . _ _ _ +     			8	$ C#h-' 	 > e H H

S 
S 
c T$s)_  8S 8DcO 8 8 X48/	/ DcO  !;)-5%$sCx.!5%49o5%  $J5% 4T
T$Z'(	5%p!s !t !2:%z8%tu%r*IVM^>&]~0"%L;x<-!T -! -!c -!hW[\_ad\dWeNf -!^,t ,3 ,# ,RZ[_`ceh`h[iRj , zuH(C'2d499T?D 3RK T)JKD&F&$'H!(r:H c
 '  32 .qc23s0   G4 G(%G4 (G1-G4 4H9HHӳxl
    kOj                        U d Z ddlZddlmZ ddlmZ ddlmZmZm	Z	  e        ddd e
d	       ed
       ed      dZdddddZ edd      Zeeeeef         ed<   dddddddZ G d de      Z e       Z	 	 	 	 	 dRdee   dee   dee   dee   dee   f
d Zd! e
d"       ed#      d$d%Zd& e
d"       ed'       ed(       ed#      d)Zd* e
d"       ed#      d+Z ed'       e
d,       ed      d-Zd.d/d0d1Zd2d3d4 ed      d5Zd6d7d8Zd9d:d;d<Zd=d>iZd?d@dAdBZdCZ dDZ!dEdFdGdHdIdJdKZ"dLdMdNdOdPZ#d9d:d;d<ZdQgZ$y)Su.   
项目配置文件
从.env文件读取配置
    N)load_dotenv)
ContextVar)OptionalDictAnyz46-qwen3.5-35Bzhttp://192.168.0.46:59800/v1:gpustack_dee9ca823290886c_5edfc86aeeeceb1e9ee5162941cb2cb5z0.1819230)modelbase_urlapi_keytemperature
max_tokenstimeoutzbge-m3z'http://192.168.0.46:59700/v1/embeddingszhttp://192.168.0.46:59700/v1)r   r   r   base_url_v2request_user_config)default_request_user_configz2http://192.168.0.46:11000/api/v1/knowledge/search/1testuseradmin)search_endpoint	x-user-idx-user-namex-rolekb-idfile-idc                   H    e Zd ZdZdefdZd
defdZdefdZd Zd Z	d	 Z
y)DynamicRAGConfigu   
    动态RAG配置类，支持线程安全的请求级配置
    当访问用户相关配置时，自动从当前请求上下文读取
    其他配置项直接返回默认值
    兼容字典的所有操作方式（如 get(), [], in 等）
    keyc                     |dv r(t         j                         }|r	||v r||   S t        |   S t        j                  |      S )N)r   r   r   r   r   )r   get_RAG_CONFIG_DEFAULT)selfr    request_configs      5e:\ZKYNLP\Hjunproject\project0506\aidoc_api\config.py__getitem__zDynamicRAGConfig.__getitem__7   sJ    LL1557N#"7%c**&s++"&&s++    Nc                 0    	 | |   S # t         $ r |cY S w xY w)u   支持 get() 方法)KeyError)r$   r    r   s      r&   r"   zDynamicRAGConfig.getB   s%    	9 	N	s    c                     |t         v S )u   支持 in 操作符)r#   r$   r    s     r&   __contains__zDynamicRAGConfig.__contains__I   s    )))r(   c                 *    t         j                         S )u   返回所有键r#   keys)r$   s    r&   r0   zDynamicRAGConfig.keysM   s    "''))r(   c                 V    t         j                         D cg c]  }| |   	 c}S c c}w )u-   返回所有值（动态读取用户配置）r/   r,   s     r&   valueszDynamicRAGConfig.valuesQ   s)    %8%=%=%?@%?cS	%?@@@s   &c                 Z    t         j                         D cg c]	  }|| |   f c}S c c}w )u3   返回所有键值对（动态读取用户配置）r/   r,   s     r&   itemszDynamicRAGConfig.itemsU   s.    ,?,D,D,FG,FSd3i ,FGGGs   ()N)__name__
__module____qualname____doc__strr'   r"   r-   r0   r2   r4    r(   r&   r   r   0   s<    	,s 	,s * **AHr(   r   	x_user_idx_user_namex_role
text_kb_idtext_file_idc                 J   i }| | |d<   |||d<   |||d<   |5t        |      j                         rt        |      j                         |d<   |5t        |      j                         rt        |      j                         |d<   t        j                  |r|       yd       y)u
  
    设置当前请求的用户配置和知识库参数（线程安全）
    
    Args:
        x_user_id: 用户ID
        x_user_name: 用户名称
        x_role: 角色
        text_kb_id: 文本检索知识库ID
        text_file_id: 文本检索文件ID
    Nr   r   r   r   r   )r9   stripr   set)r;   r<   r=   r>   r?   configs         r&   set_request_user_configrD   ]   s     F'{ +}!x#j/"7"7"9j///1wC$5$;$;$=-335yvV848r(   z&http://192.168.0.46:59085/search_graphz30.010z0http://192.168.0.46:59085/operation_graph_search)r   graph_timeoutdefault_top_koperation_search_endpointz*http://192.168.0.46:59085/device_to_system28)endpointr   default_min_hopsdefault_max_hopsrG   z)http://192.168.0.46:59085/atlas_retrieval)rK   r   rG   z0.7)max_retry_countimage_clarity_thresholddefault_timeoutz192.168.0.4659088zhttp://192.168.0.46:59088)hostportr   zhttp://192.168.0.46:59900/v1basezh)api_baser   languager   zhttp://192.168.0.46:59801/v1zQwen3-VL-8B)rV   r   zneo4j://192.168.0.46:57687neo4jzzdht123@)uriuserpasswordurlz>http://192.168.0.46:11000/api/v1/knowledge/knowledge_base/treezhttp://192.168.0.46:22000z15088888888@163.com11223344)r\   emailr[   z9postgresql://postgres:password@192.168.0.46:5432/an_webuizApostgresql+psycopg://postgres:password@192.168.0.46:5432/an_webuiu   名称fulltext	embedding
Searchableglobal_searchable_embedding global_searchable_content_search)NAME_PROPERTYFULLTEXT_PROPERTYEMBEDDING_PROPERTYSEARCH_LABELVECTOR_INDEX_NAMEFULLTEXT_INDEX_NAMEfaultsystem_namedevice_nameship_number)u   故障模式u   系统u   设备u   舷号z%http://192.168.0.46:59988/analyze-pdf)NNNNN)%r8   osdotenvr   contextvarsr   typingr   r   r   floatint
LLM_CONFIGEMBEDDING_CONFIGr   r9   __annotations__r#   dictr   
RAG_CONFIGrD   GRAPH_SEARCH_CONFIGDEVICE_SYSTEM_CONFIGATLAS_CONFIGWORKFLOW_CONFIGSERVER_CONFIG
ASR_CONFIG
VLM_CONFIGNEO4J_CONFIGKB_TREE_CONFIGREPAIR_FEEDBACK_CONFIGPOSTGRES_CONNECTION_STRINGPOSTGRES_SQLALCHEMY_URLINDEX_CONFIGMAP_INSAPI_URLSr:   r(   r&   <module>r      s\   
  " & & 
 .K<f+4y	
 9K2	  >HH]gk=l j$sCx.!9: l L 'Ht 'HV 
7;9=488<:>	9x} 9)1#9$,SM9 )19 +33-	9> @6]Y!S	  =V}CCY  <V}Y 3x$U|4y + /4y	
 0
 ( 
K '"  Y ] 
 #&!7> 		 ( .r(   2Iax&	
    JKj                     x    d 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
 G d d      Zd Zedk(  r e        yy)	u   
文档转 PDF 工具
使用 LibreOffice 将各种文档格式转换为 PDF

支持格式：
- Word: .doc, .docx, .rtf
- Excel: .xls, .xlsx
- PowerPoint: .ppt, .pptx
- OpenDocument: .odt, .ods, .odp
- 文本: .txt, .csv
- 图片: .jpg, .png (会嵌入PDF)
    N)Path)OptionalListc            
           e Zd ZdZh dZddefdZd Z	 	 ddedee   d	e	d
efdZ
	 	 ddee   dee   de	d
ee   fdZ	 	 ddedee   ded
ee   fdZy)Doc2PDFu   文档转 PDF 转换器>   .bmp.csv.doc.gif.htm.jpg.odp.ods.odt.png.ppt.rtf.txt.xls.xml.docx.html.jpeg.pptx.xlsxlibreoffice_pathc                 2    || _         | j                          y )N)r   _verify_libreoffice)selfr   s     6e:\ZKYNLP\Hjunproject\project0506\aidoc_api\doc2pdf.py__init__zDoc2PDF.__init__'   s     0  "    c                 4   	 t        j                  | j                  dgdd      }|j                  dk7  rt	        d      t        d|j                  j                         j                  t        d            d           y	# t        $ r t	        d      w xY w)
u   验证 LibreOffice 是否可用z	--versionT)capture_outputtextr   u   LibreOffice 不可用u   ✓ 检测到 
   u$   未找到 LibreOffice，请先安装N)
subprocessrunr   
returncodeRuntimeErrorprintstdoutstripsplitchrFileNotFoundError)r   results     r    r   zDoc2PDF._verify_libreoffice+   s    		G^^&&4#$F   A%"#:;;N6==#6#6#8#>#>s2w#G#J"KLM  	GEFF	Gs   A?B BN
input_file
output_dirtimeoutreturnc                    t        |      j                         }|j                         st        d|       |j                  j                         }|| j                  vrt        d|       |t        |j                        }n9t        t        |      j                               }t        j                  |d       | j                  ddddd	d
d|t        |      g
}t        d|j                   ddd       	 t        j                   |dd|      }|j"                  dk7  r#t        d       t%        d|j&                         t        j(                  j+                  ||j,                   d      }t        j(                  j                  |      rt        d       |S t        d       t%        d      # t        j.                  $ r t        d       t%        d| d      w xY w)u%  
        转换单个文件为 PDF
        
        Args:
            input_file: 输入文件路径
            output_dir: 输出目录（默认为输入文件所在目录）
            timeout: 超时时间（秒）
        
        Returns:
            生成的 PDF 文件路径
        u   文件不存在: u   不支持的格式: T)exist_okz
--headlessz--invisiblez--nologoz--nofirststartwizardz--convert-topdfz--outdiru     转换中: z ... )endflush)r$   r%   r4   r   u   ✗u   转换失败: z.pdfu   ✓u$   转换完成但未找到输出文件u   ✗ (超时)u   转换超时 (u   秒))r   resolveexistsr0   suffixlowerSUPPORTED_FORMATS
ValueErrorstrparentosmakedirsr   r+   namer'   r(   r)   r*   stderrpathjoinstemTimeoutExpired)	r   r2   r3   r4   
input_pathr>   cmdr1   output_files	            r    convertzDoc2PDF.convert8   s   " *%--/
  "#&7
|$DEE""((*///3F8<==Z../JT*-5578JKK
T2 !!"E

O	
 	joo.d3DI	?^^#	F   A%e"^FMM?#CDD'',,zjoo5Fd3KLKww~~k*e""e"#IJJ(( 	?.!y=>>	?s   ;B#F5 F5 5.G#input_filesmax_workersc           
         g }t        dt        |       d       t        |d      D ]K  \  }}t        d| dt        |       dd       	 | j                  ||      }|j	                  ||d	d
d       M t        d |D              }	t        d|	 dt        |       d       |S # t
        $ r)}|j	                  |d
dt        |      d       Y d
}~d
}~ww xY w)u   
        批量转换文件
        
        Args:
            input_files: 输入文件列表
            output_dir: 输出目录
            max_workers: 并发数
        
        Returns:
            转换结果列表
        u   
开始批量转换 u    个文件...
   [/] )r:   TN)inputoutputsuccesserrorFc              3   ,   K   | ]  }|d    s	d  yw)rZ   rS   N ).0rs     r    	<genexpr>z(Doc2PDF.convert_batch.<locals>.<genexpr>   s     ?w!!I,Aws   
u   
转换完成: u    成功)r+   len	enumeraterO   append	ExceptionrB   sum)
r   rP   r3   rQ   resultsir2   rN   esuccess_counts
             r    convert_batchzDoc2PDF.convert_batch~   s    " %c+&6%7GH&{A6MAzAaS#k*+1-26"ll:zB')#!	  	 7& ?w?? qWgFG  '"$ V	   s   (B$$	C-CC	input_dir	recursivec                 v   t        |      }|j                         st        d|       g }|rdnd}|j                  |      D ]T  }|j	                         s|j
                  j                         | j                  v s;|j                  t        |             V |st        d       g S | j                  ||      S )u   
        转换目录中的所有支持文件
        
        Args:
            input_dir: 输入目录
            output_dir: 输出目录
            recursive: 是否递归处理子目录
        u   不是目录: z**/**u   未找到支持的文件)r   is_dirNotADirectoryErrorglobis_filer>   r?   r@   rc   rB   r+   rj   )r   rk   r3   rl   rL   filespattern	file_paths           r    convert_directoryzDoc2PDF.convert_directory   s     )_
  "$~i[%ABB %&3#1I  "y'7'7'='='?4CYCY'YS^, 2 ,-I!!%44r"   )libreoffice)Nx   )NrS   )NF)__name__
__module____qualname____doc__r@   rB   r!   r   r   intrO   r   dictrj   boolrv   r]   r"   r    r   r      s    !# #G  %)	D?D? SMD? 	D?
 
D?R %)	+#Y+ SM+ 	+
 
d+` %)	55 SM5 	5
 
d5r"   r   c                     ddl } | j                  d| j                  d      }|j                  dd       |j                  d	d
d       |j                  dddd       |j                  ddt        dd       |j                         }t               }t        |j                        }|j                         rA	 |j                  |j                  |j                  |j                        }t        d|        y|j#                         rs|j%                  |j                  |j                  |j&                        }|D cg c]
  }|d   r	| }	}|	r*t        d       |	D ]  }
t        d|
d    d|
d            yyt        d|j                          t        j                   d       y# t        $ r-}t        d|        t        j                   d       Y d}~yd}~ww xY wc c}w )u   命令行入口r   Nu)   使用 LibreOffice 将文档转换为 PDFu   
示例:
  python doc2pdf.py document.docx
  python doc2pdf.py document.xlsx -o ./output
  python doc2pdf.py ./documents/ -o ./pdfs -r
        )descriptionformatter_classepilogrX   u   输入文件或目录)helpz-oz--outputu   输出目录z-rz--recursive
store_trueu   递归处理子目录)actionr   z-tz	--timeoutrx   u'   单个文件转换超时时间（秒）)typedefaultr   u   
输出文件: u	   
错误: rS   rZ   u   
失败的文件:z  - z: r[   u   错误: 路径不存在 - )argparseArgumentParserRawDescriptionHelpFormatteradd_argumentr}   
parse_argsr   r   rX   rr   rO   rY   r4   r+   rd   sysexitro   rv   rl   )r   parserargs	converterrL   rY   rh   rf   r_   failuresfs              r    mainr      s   $$? << % 	F &=>
j~>
mL4  6
kSF  H D	Idjj!J	&&tzz4;;MF$VH-.
 
			--JJKKNN
  ';w!a	lAw;&'QwZL1W:,78   	*4::,78+  	Jqc"#HHQKK	 <s$   9?F* >
G#	G#*	G 3#GG __main__)r|   r'   rD   r   pathlibr   typingr   r   concurrent.futures
concurrentr   r   ry   r]   r"   r    <module>r      sE     	 
  ! s5 s5l6r zF r"   mB.x   
    MjD                        / S Q/ SQS/SS/S.r SSSS	S
SSSSSSS.rSrSrSrSrSrSrSrSr	Sr
SrSrSrSrSr\\\\\\\\
\	\S .
rS!rS"rS#rS$rS%rS&rS'rS(rS)rS*rS+rS,rS-rS.rS/rS0r S1r!g2)3)   金句润色	   书面化	   讲稿化   规整)   扩写   续写   汇报   金句   精简   总结)u   润色r   u   推荐u   缩写uU  你是一位专业文案大师，擅长用精炼的语言创作令人印象深刻的金句。请根据用户提供的文本，在保持原意的基础上进行金句润色，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 对选择的金句进行润色，保证句子结构不变的情况下，将润色后句子进行金句替换。
3. 禁止使用Markdown，不添加无关内容，保持原有用词风格。
4. 最后，通读润色后的文本，确保没有语法错误，表意清晰，金句融入自然。
5. 整体润色后的文本既精炼又富有文采，符合用户的所有要求。
6. 如果有其他要求，则继续考虑到该要求进行金句润色，如果没有，则保持上述要求进行金句润色。
7. 请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出润色后的金句，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要润色的金句如下：{sentence}u  你是一位专业文案大师，擅长文本改写成书面文字的形式。请根据用户提供的文本，在保持原意的基础上进行书面化改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行书面化改写和润色。
3. 禁止使用Markdown，不添加无关内容，保持纯文本风格，改写后的文本必须严格对应原文，不能添加或删减信息。
4. 考虑公文的要求：书面化、严谨、规范这些要求，避免重复内容出现。
5. 最后，通读书面化改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯，符合公文的庄重风格
6. 如果有其他要求，则继续考虑到该要求进行书面化改写，如果没有，则保持上述要求进行书面化改写。
7. 请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出书面化改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要书面化改写的内容如下：{sentence}u  你是一位专业文案大师，擅长文本改写成讲稿化的形式，即文本转换为正式场合发言的口语化版本。请根据用户提供的文本，在保持原意的基础上进行讲稿化改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行讲稿化改写，并转换为正式场合发言的口语化版本。
3. 将文本中的比喻和描绘转化为更平实的表达，同时保留原有的意境和情感。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，改写后的文本必须严格对应原文，不能添加或删减信息。
5. 避免有过于复杂的词汇或结构，原文中的破折号和星号标记需要去除，改用连贯的句子连接。
6. 最后，通读讲稿化改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯，确保整个发言稿的结构合理，有开头、中间和结尾，符合正式发言的流程。
7. 如果有其他要求，则继续考虑到该要求进行讲稿化改写，如果没有，则保持上述要求进行讲稿化改写。
8，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
9. 只需要输出讲稿化改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要讲稿化改写的内容如下：{sentence}u  你是一位专业文案大师，擅长对文本进行规整，即对文本进行格式规范、内容严谨和语言得体的调整。请根据用户提供的文本，在保持原意的基础上进行规整改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行规整改写。
3. 忽略原文的文学风格，将其转换为符合公文要求的正式、简洁、准确的语言。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，改写后的文本必须严格对应原文，不能添加或删减信息。
5. 检查格式规范，避免抒情和比喻语句，将需要改写的内容转换为客观、准确的描述
6. 需要确认描述的内容是否符合实际情况，是否有数据或政策支持。
7. 语言方面，文本若使用大量文学修辞，需要调整为庄重、简洁的公文语言。
6. 最后，通读规整改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯，确保不遗漏任何关键要素，比如时间、地点、具体设施等，并删除所有口语化或情感化的表达，保持客观中立。
7. 如果有其他要求，则继续考虑到该要求进行规整，如果没有，则保持上述要求进行规整。
8，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
9. 只需要输出规整改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要规整改写的内容如下：{sentence}u  你是一位专业文案大师，擅长对文本进行扩写，即对选中的文本内容进行扩充。请根据用户提供的文本，在保持原意的基础上进行扩写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行扩写。
3. 扩写的内容不能超过200字，保持在100字到200字这个范围内。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在扩写过程中，扩写后的内容都紧扣原文，不能脱离中心思想。
6. 扩写的内容为公文风格，严格遵守格式和内容规范，确保内容符合公文口吻。
6. 最后，通读扩写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行扩写，如果没有，则保持上述要求进行扩写。
8，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
9. 只需要输出扩写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要扩写的内容如下：{sentence}u  你是一位专业文案大师，擅长对文本进行续写，即对选中的文本内容进行续写。请根据用户提供的文本，在保持原意的基础上进行续写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行续写。
3. 续写的内容不能超过200字，保持在100字到200字这个范围内。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在续写过程中，续写后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
5. 最后，通读续写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
6. 如果有其他要求，则继续考虑到该要求进行续写，如果没有，则保持上述要求进行续写。
7，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出续写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要续写的内容如下：{sentence}u1  你是一位专业文案大师，擅长对文本进行汇报改写，即对选中的文本内容转化为适合口头汇报的口语化内容。请根据用户提供的文本，在保持原意的基础上进行汇报改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行汇报改写。
3. 将选中内容转化为适合口头汇报的口语化内容，避免使用复杂句式，多用短句和连接词，让内容更自然。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在汇报改写过程中，改写后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
5. 最后，通读汇报改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
6. 如果有其他要求，则继续考虑到该要求进行汇报改写，如果没有，则保持上述要求进行汇报改写。
7，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出汇报改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要汇报改写的内容如下：{sentence}ud&   你是一位专业文案大师，擅长对文本进行金句提取，即从选中文字里找出五句适合润色或替换的金句，然后输出每个句子。请根据用户提供的文本，在保持原意的基础上进行金句提取，要求满足以下条件：
问题: 
文本内容为
在生活的长河中，我们常常追求明确的答案和确定的方向，渴望每一步都踏在坚实的基石上。然而，人生的真谛往往隐藏于那些不确定之中。正如夜空中闪烁的星辰，它们并不总是固定不动，而是随着时间流转而变换位置，却依旧照亮着旅人的道路。
不确定性并非是阻碍前行的绊脚石，而是引导我们探索未知、发现自我的灯塔。每一次面对选择时的犹豫不决，每一个未曾预料到的结果，都是生命赋予我们的宝贵礼物。它们教会我们在变化中寻找平衡，在迷茫里坚守希望。
真正的智慧，并非来自于对所有问题都有确切答案，而是懂得如何在无常的世界里保持内心的平静与坚韧。接受生活中的不确定性，才能真正体会到成长的意义，让心灵在风雨兼程的路上愈发坚强。
这便是人生旅程中最深刻的教诲之一：不是所有的疑问都需要解答，有时候，学会与未知共舞才是最重要的技能。
你可以对给出的文本内容进行详细的阅读和解析，然后输出3至5个金句,请根据以下原则进行生成：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行金句提取。
3. 金句通常是指那些表达精准、富有感染力、能提升文章档次的句子。
4. 润色的地方包括重复的用词、平淡的描述，或者可以更生动、更具文学性的部分，或者使用相关名人名言。
5. 确保句子结构多样，避免重复。比如使用不同的比喻手法，泼墨、银绸、琴键、星辰、寓言，这些意象都符合原文的自然和神秘氛围。
6. 逐条输出每个句子的内容，确认没有超过五句，且每句都是独立的润色点。
7. 如果有其他要求，则继续考虑到该要求进行金句提取，如果没有，则保持上述要求进行金句提取。
8，请将根据上述要求提取后的金句直接输出，不要输出额外的信息描述。


推理过程: 
好的，用户需要我根据提供的文本生成5个符合要求的金句。首先，我要仔细阅读原文，理解核心观点。原文主要讲的是接受生活中的不确定性，学会在未知中成长，强调不确定性的积极意义。接下来，需要运用指定的句式技巧：对偶、对比、排比、追问。用户没有指定具体哪种，所以可以自由组合。
先看对偶，结构对称的句子，比如前半句和后半句字数相近，意义相关。例如原文提到的“不是所有疑问都需要解答，与未知共舞”可以转化为对偶句式。
然后是排比，三个或以上结构相似的句子。原文中有提到“教会我们在变化中寻找平衡，在迷茫里坚守希望”，可以扩展成排比结构，比如“在变化中寻找平衡，在迷茫里坚守希望，在未知里孕育新生。”
对比句式的话，可以用“不是...而是...”的结构，比如“不是被动承受，而是主动拥抱；不是停滞不前，而是破浪乘风。”这样突出不确定性的积极作用。
还要检查是否符合公文语体，避免口语化。比如“让心灵在风雨兼程的路上愈发坚强”比较文学化，可能需要调整，但原文允许适当的文采，所以可以保留。
需要注意不要使用Markdown，严格按JSON格式输出。用户要求5个，所以需要生成五个不同句式，涵盖各种技巧，并确保每个金句都准确提炼原文，不偏离主题。
现在开始逐一构思：
1.使用对比句式，对比过去对不确定性的看法和现在的积极态度：“不确定性不是前行的绊脚石，而是探索的导航仪；不是命运的考验场，而是成长的必修课。”这样既对比了两种观点，又符合对偶结构。
2.排比句式，三个结构相似的分句：“在变化中寻找平衡，在迷茫里坚守希望，在未知里孕育新生。”这里三个“在...中”结构，增强语势。
3.对偶和对比结合：“不是所有疑问都需要解答，有时答案在追寻中显现；不是所有方向都必须明确，真正的道路在脚下延伸。”前半句对偶，后半句对比，突出核心观点。
4.另一个排比结构，强调关键动词：“以平静接纳无常，以坚韧应对挑战，以智慧点亮未知。”三个“以...”结构，简洁有力。
5.对比和排比的混合：“与未知共舞，方知生命之广阔；与变化同行，方见成长之壮美。”这里用对偶结构，两个“与...方...”句式，形成对比和节奏感。
检查每个金句是否准确反映原文，是否有套话，确保信息密度高。例如第四个金句中的“以智慧点亮未知”呼应了原文的“智慧来自于如何在无常中保持平静”。第五个金句中的“与未知共舞”直接引用原文关键句，符合要求。
最后，确保每个金句在句式上各有不同，涵盖对偶、排比、对比，并且语言庄重简洁，符合公文要求。没有使用反问，避免尖锐，保持设问的引导性。完成五个金句后，进行输出。

答案: 
                
不确定性不是前行的绊脚石,而是探索的导航仪；不是命运的考验场,而是成长的必修课。

                
在变化中寻找平衡,在迷茫里坚守希望,在未知里孕育新生。

                
不是所有疑问都需要解答,有时答案在追寻中显现；不是所有方向都必须明确,真正的道路在脚下延伸。

                
以平静接纳无常,以坚韧应对挑战,以智慧点亮未知。

                
与未知共舞,方知生命之广阔；与变化同行,方见成长之壮美。


问题: 
文本内容为
在公文写作中，这句话前有“蔓发”，后有“可望”，预示着更大的成功指日可待。这一句适合用在写于冬末春初时的文章中，如团拜会上的讲话、一项工作开始之初、一个项目开展之初等。
,对给出的文本内容进行详细的阅读和解析，然后输出3至5个金句,请根据以下原则进行生成：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行金句提取。
3. 金句通常是指那些表达精准、富有感染力、能提升文章档次的句子。
4. 润色的地方包括重复的用词、平淡的描述，或者可以更生动、更具文学性的部分，或者使用相关名人名言。
5. 确保句子结构多样，避免重复。比如使用不同的比喻手法，泼墨、银绸、琴键、星辰、寓言，这些意象都符合原文的自然和神秘氛围。
6. 逐条输出每个句子的内容，确认没有超过五句，且每句都是独立的润色点。
7. 如果有其他要求，则继续考虑到该要求进行金句提取，如果没有，则保持上述要求进行金句提取。
8，请将根据上述要求提取后的金句直接输出，不要输出额外的信息描述。

推理过程: 
好的，我需要为用户的公文内容生成三到五个金句，主要使用对偶、对比、排比和追问句式。首先，用户提供的原文是关于冬末春初的文章，比如团拜会讲话或项目开始阶段，强调“蔓发”和“可望”，预示成功即将到来。首先分析原文的关键点：“蔓发”意味着开始生长，有蓬勃发展的势头；“可望”表示目标在望，成功在即。需要将这两个概念融入金句中，同时适合公文的正式语境。
考虑对偶句式，结构对称。比如“春山蔓发启新程，锦绣可望向未来”，前半句描述开始，后半句展望未来，符合冬末春初的时间点。
接下来是排比，可能需要三个结构相似的短语。例如“蔓发的是奋进的号角，可望的是丰收的硕果，升腾的是跨越的信心”，三个部分都围绕核心概念展开，增强语势。
对比句式可以强调变化，比如“不是简单的时序更替，而是发展的厚积薄发；不是寻常的春耕夏耘，而是事业的乘势而上”，突出现在与过去的不同，强调积累和机遇。
另一个对偶句：“冬寒未尽蕴生机，春意已彰展宏图”，对比冬寒与春意，展示转折点，符合原文的时间背景。
最后用排比加强气势：“以蔓发之势抢抓机遇，以可望之志勇攀高峰，以笃行之姿再创辉煌”，三个“以...之...”结构，层层递进，适合工作或项目初期的动员。
需要确保每个金句都紧扣原文，不使用套话，保持公文庄重的语气。检查是否符合句式要求，如对偶的结构是否对称，排比是否有三个以上的相似结构，对比是否清晰。然后按适用程度排序，把最贴切、结构最工整的放在前面。

答案: 
                
春山蔓发启新程,锦绣可望向未来。

                
蔓发的是奋进的号角,可望的是丰收的硕果,升腾的是跨越的信心。

                
不是简单的时序更替,而是发展的厚积薄发；不是寻常的春耕夏耘,而是事业的乘势而上。

                
冬寒未尽蕴生机,春意已彰展宏图。

                
以蔓发之势抢抓机遇,以可望之志勇攀高峰,以笃行之姿再创辉煌。

        
其他要求如下：{require}
需要进行金句提取的内容如下：{content}
u  你是一位专业文案大师，擅长对文本进行精简，即对选中文本进行精简缩写。请根据用户提供的文本，在保持原意的基础上进行精简，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行精简。
3. 确保精简后的文本保留文本中原有元素，但用更简洁的语言表达。
4. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
5. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在精简过程中，精简后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
6. 最后，通读精简后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行精简，如果没有，则保持上述要求进行精简。
8，请将根据上述要求精简后的内容直接输出，不要输出额外的信息描述。
    其他要求如下：{require}
    文本内容如下：{content}
    需要进行精简的内容如下：{sentence}us  你是一位专业文案大师，擅长对文本进行总结，即将选中文本总结为一段话。请根据用户提供的文本，在保持原意的基础上进行总结，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行总结，将其总结为一段话。
3. 确保提取文本中的关键信息，比如时间地点人物等元素，同时，要注意保留原文的意境。将这些元素组织成一段连贯的话，确保语言简洁，涵盖所有要点。需要避免使用复杂结构，保持口语化但专业。
4. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
5. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在总结过程中，总结后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
6. 最后，通读总结后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行总结，如果没有，则保持上述要求进行总结。
8，请将根据上述要求总结后的内容直接输出，不要输出额外的信息描述。
    其他要求如下：{require}
    文本内容如下：{content}
    需要进行总结的内容如下：{sentence}u  你是一位专业文案大师，擅长对文本进行改写，即根据选中的文本，在保持原意的基础上进行改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容，按照用户输入的要求进行改写，
3. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在改写过程中，改写后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
5. 最后，通读改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
6，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
    用户输入的要求如下：{other_require}
    文本内容如下：{content}
    需要进行改写的内容如下：{sentence})r   r   r   r   r   r   r   r	   r
   r    u  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
** 撰写{template}大纲时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的{template}大纲长度应控制在{length}字以内。需要合理分配各部分内容，大纲的结构要符合中文的层级，比如用一、（一）、1.这样的编号。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}大纲的格式需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}大纲格式的相关内容，必须严格按照{template}大纲格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。
**规则9**：大纲只生成标题不生成内容。
** 输出格式如下：
## 一、标题
### （一）子标题
### （二）子标题
....
## 二、标题
### （一）子标题
### （二）子标题
...
输出示例：
## 一、活动背景
## 二、活动目的
## 三、活动内容
### （一）开幕式
### （二）正式比赛
### （二）闭幕式
## 四、活动总结
** 检查：
1.严格按照上述格式生成，生成内容大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
2.只生成标题，不深城其他额外内容。
3. 上述要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行{template}大纲撰写。u	  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
** 撰写{template}大纲时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的{template}大纲长度应控制在{length}字以内。需要合理分配各部分内容，大纲的结构要符合中文的层级，比如用一、（一）、1.这样的编号。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}大纲的格式需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}大纲格式的相关内容，必须严格按照{template}大纲格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。
**规则9**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则10**：编写方法大纲时，按照输出示例的格式进行编写,只产生格式和标题，不产生内容。
**规则11**：不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
**规则12**：大纲只生成标题不生成内容。
** Markdown有序列表语法的连续嵌套格式如下：
1. 标题
    1. 标题
        1. 标题
** 输出示例：
1. 确定学习目标
    1. 设定具体目标
        1. 上半年目标
        2. 下半年目标
    2. 选择合适的学习资源
2. 构建基础知识
    1. 学习基本概念
    2. 掌握编程环境
** 检查：
1. 编写方法大纲时，按照输出示例的格式进行编写,只产生格式和标题，不产生内容。
2. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
3. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行{template}大纲撰写。u7  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
** 撰写{template}大纲时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的{template}大纲长度应控制在{length}字以内。需要合理分配各部分内容，大纲的结构要符合中文的层级，比如用一、（一）、1.这样的编号。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}大纲的格式需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}大纲格式的相关内容，必须严格按照{template}大纲格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。
**规则9**：编写方法大纲时，按照输出示例的格式进行编写,只产生格式和标题，不产生内容。
**规则10**：大纲只生成标题不生成内容。
** 输出示例：
## 第一章 总 则
### 第一条 
### 第二条 

## 第二章 分 则
### 第三条 

##  第三章 附 则
### 第XX条
** 检查：
1. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
2. 大纲只生成标题不生成内容。
3. 上述要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行{template}大纲撰写。u  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写{template}时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}不得脱离文章标题：{title}和文章大纲内容，需要围绕文章标题和文章大纲内容的主旨进行撰写。
**规则3**：撰写的{template}长度应控制在{length}字以内。需要分析文章大纲内容，确保每个小标题都得到充分展开，同时，需要合理分配各部分内容，确保每个部分都符合要求，如果需要成文日期用阿拉伯数字，格式正确。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}的内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}格式的相关内容，必须严格按照{template}格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：严格按照文章大纲：{outline}的格式输出，只对已有文章大纲：{outline}的内容做填充，格式标题不变。

** 检查：
1. 格式必须和文章大纲：{outline}一样，只对文章大纲：{outline}进行内容填充标题不变。
2. 严格按照文章篇幅要求生成字数。
3. 必须满足上述条件，如果不满足重新思考输出。
请根据以上内容进行{template}撰写。u  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写通知时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的通知不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的通知长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的通知内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的通知的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排。
**规则7**：只能生成符合通知格式的相关内容，必须严格按照通知格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”等，并且成文日期用阿拉伯数字，格式正确。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 严格按照文章篇幅要求生成字数。
请根据以上内容进行通知撰写。ul  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
报告大纲：{outline}，
文章大纲：{outline}，
** 撰写报告时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的报告不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的报告长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的报告内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的报告的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**：不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
** Markdown有序列表语法的连续嵌套格式
1. 标题
    1. 标题
        1. 标题
** 输出示例：
<nospace>主送机关：市场部</nospace>
<text>
2025年一季度，全球经济复苏动能分化，国内经济在“稳增长、调结构、促改革”政策基调下实现平稳开局。我行紧密围绕国家战略导向，坚持“服务实体、防控风险、深化改革”三大主线，推动业务规模稳健增长、结构持续优化。
1. 主要经营指标完成情况
    1. 规模与效益
        资产规模：截至季末，全行资产总额XX万亿元，同比增长XX%，增速居同业前列。
        营收与利润：实现营业收入XX亿元，同比增长XX%；净利润XX亿元，同比增长XX%，盈利能力保持行业第一梯队。
    2. 资产质量与风险抵御能力
        不良贷款率：XX%，较年初下降XX个基点，资产质量持续改善。
        拨备覆盖率：XX%，风险抵补能力进一步增强。
2. 重点战略推进成效
    1. 数字化转型：从“线上化”到“智能化”
        1. 技术投入
            研发支出XX亿元，同比增长XX%，AI客服覆盖率提升至XX%，智能风控系统拦截可疑交易XX万笔。
        2. 场景生态
            手机银行MAU（月活跃用户）突破XX万，新增“智慧园区”“跨境e汇”等场景服务，线上贷款审批效率提升XX%。
</text>
<div style="text-align: right>机关短署名：市场运营部</div>
<div style="text-align: right>20××年×月×日</div>
** 检查：
1. 如果有连续嵌套标题形式必须改为markdown有序列表语法的输出形式。
2. 连续嵌套标题序号必须为“1. ”，“2. ”，“3. ”...这种形式,不可以是“（1）”，“一.”等这种形式。
3. 输出格式参考输出示例。正文必须用<text></text>包裹，机关短署名必须用<div style="text-align: right></div>包裹，落款时间必须用<div style="text-align: right></div>包裹。
4. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
5. 如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，增加署名和时间。
6. 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
7. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行报告撰写。u4
  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写办法时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的办法不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的办法长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的办法内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的办法的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：结尾不需要加落款，时间等。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
** 输出示例：
## 第一章 总 则
### <strong>第一条</strong> 为规范××××行为，加强××××管理，保障××××合法权益，依据《中华人民共和国××法》《×××条例》等有关法律法规，结合本地区/本单位实际，制定本办法。 
### <strong>第二条</strong> 本办法适用于本行政区域内/本系统内从事××××活动的单位和个人。

## 第二章 分 则
### <strong>第三条</strong> 本部门对从事××××活动的单位，应当具备下列条件：
（一）具有合法的主体资格；
（二）具备相应的技术能力和专业人员；

##  第三章 附 则
### <strong>第XX条</strong> 本办法所称“××××”，是指……（可对关键术语进行解释）。
** 检查：
1. 每一条内容必须被<strong>/<strong>包裹。必须要从“第一章”开始生成。
2.只在每章结束后换一空白行。
3. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行办法撰写。u  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写函时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。函是指不相隶属机关之间商洽工作、询问和答复问题，请求批准和答复审批事项时所使用的公文。
**规则2**：撰写的函不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的函长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的函内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的函的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则9**：结尾不需要加落款，时间等。
**规则10**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
** Markdown有序列表语法的连续嵌套格式
1. 标题
    1. 标题
        1. 标题
** 输出示例：
<nospace>主送机关：XX市公安局交通警察支队</nospace>
<text>
为深入贯彻落实《国家综合立体交通网规划纲要》精神，加快推进我市智慧交通建设，提升城市交通管理智能化、精细化水平，我局拟于近期组织开展“XX市智慧交通系统建设与应用”专题调研。
1. 调研目的
    1. 总体目标
        此次调研旨在总结我市智慧交通发展经验，研究解决共性问题，为下一步优化顶层设计、推动跨部门协同提供决策参考。
    2. 具体目标
        收集并分析智慧交通系统建设中的成功案例。探讨并解决当前智慧交通建设中遇到的技术和管理难题。建立长期有效的合作交流机制，促进信息共享和技术进步。
2. 请求事项
    1. 资料提供
        1. 技术资料
            恳请贵单位提供近年来在智慧交通平台建设、关键技术应用、数据资源整合利用等方面的总结报告、技术文档。
        2. 其他资料
            恳请贵单位提供近年来在智慧交通平台的其他资料。
</text>
** 检查：
1. 如果有连续嵌套标题形式必须改为markdown有序列表语法的输出形式。
2. 连续嵌套标题序号必须为“1. ”，“2. ”，“3. ”...这种形式,不可以是“（1）”，“一.”等这种形式。
3. 输出格式参考输出示例。正文必须用<text></text>包裹,机关短署名必须用<div style="text-align: right></div>包裹，落款时间必须用<div style="text-align: right></div>包裹。
4. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”，“（1）”等。
5. 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
6. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行函撰写。u  角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写工作总结时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的工作总结不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的工作总结长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的工作总结内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的工作总结的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
** Markdown有序列表语法的连续嵌套格式
1. 标题
    1. 标题
        1. 标题
** 输出示例：
<text>
20XX年，在上级党委（或主管部门）的坚强领导下，我单位坚持以习近平新时代中国特色社会主义思想为指导，深入学习贯彻党的二十大精神，紧紧围绕年度中心工作和重点任务，牢牢把握高质量发展主题，主动适应新形势、新任务、新要求，凝心聚力、攻坚克难，扎实推进各项工作落实落地，较好地完成了全年各项目标任务，为推动单位（或行业/地区）发展作出了积极贡献。
1. 主要成绩与做法
    1. 聚焦主责主业，核心业务实现新突破
        1. 重点项目取得关键进展
            全力推进XXX重大项目建设，完成投资XX亿元，主体工程如期封顶（或：顺利投产运行）；成功实施XXX技术改造，生产效率提升
2. 经验与体会
    1. 服务大局是核心要求
        必须紧紧围绕中心任务，找准定位，主动作为，才能体现价值、赢得支持。
    2. 改革创新是不竭动力
        面对新挑战，唯有勇于创新、深化改革，才能破解难题、激发活力。
</text>
<div style="text-align: right>发文机关署名（加盖公章）</div>
<div style="text-align: right>20XX年X月X日</div>

**内容要求：
1. 开头用于总结的开头主要用来概述基本情况，有需要时可以列出前言部分。开头包括单位名称，工作性质、主要任务、时代背景、指导思想，以及总结目的、主要内容提示等。总结的开头要注意简明扼要，文字不宜过多。
2. 主体主要内容包括成绩和做法、经验和教训、今后打算等。这部分篇幅长、内容多，要特别注意使层次分明、条理清楚。
3. 结尾一般应在总结经验教训的基础上，提出今后的方向、任务和措施，表明决心、展望前景，篇幅不应过长。有时总结也可以省略结尾，不用专门书写。

** 检查：
1. 如果有连续嵌套标题形式必须改为markdown有序列表语法的输出形式。
2. 连续嵌套标题序号必须为“1. ”，“2. ”，“3. ”...这种形式,不可以是“（1）”，“一.”等这种形式。
3. 输出格式参考输出示例。正文必须用<text></text>包裹。
4. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”，“（1）”等。
5. 如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，增加署名和时间。
6. 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
7. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行函撰写。ui  {role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写公告时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的公告不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的公告长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的公告内容需要严格遵守内容要求。如果内容要求：{requirement}为空，也请为该公共撰写合理的公告事项。
**规则5**：如果参考材料：{references}不为空，撰写的公告的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合公告格式的相关内容，必须严格按照公告格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
请根据以上内容进行公告撰写。u  {role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写请示时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的请示不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的请示长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的请示内容需要严格遵守内容要求所包含请示机关和请示缘由。如果内容要求：{requirement}为空，也请为该请示撰写合理的请示机关和请示缘由。
**规则5**：如果参考材料：{references}不为空，撰写的请示的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字，直接呈现内容。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合请示格式的相关内容，必须严格按照请示格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
请根据以上内容进行请示撰写。u	  {role}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写文书时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的文书不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的文书长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的文书内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的文书的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字，直接呈现内容。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合文书格式的相关内容，必须严格按照文书格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
请根据以上内容进行文书撰写。u  {role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写批复时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的批复不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的批复长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。批复的主送机关，必须和请示的机关一致，需要使用全称或规范化简称，不能随意简化。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的批复内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的批复的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合批复格式的相关内容，必须严格按照批复格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。结尾部分用“此复”或“特此批复”。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
请根据以上内容进行批复撰写。uA  {role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写方案时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的方案不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的方案长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的方案内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的方案的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合方案格式的相关内容，必须严格按照方案格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。结尾部分用“此复”或“特此方案”。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：{length}生成字数，不得超过字数限制。
请根据以上内容进行方案撰写。)
u   通知u   报告u   公告u   请示u   文书u   批复u   方案u   工作总结u   函u   方法u  <optimized_prompt>
{title}中内容：{doc_content}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
其他要求：{other_require}
学时：{time_1}
授课方式：{jiangshou_type}
注意：
** 只生成与当前章节名称：{chapter}相关内容。**
<instructions>
** 根据用户上传文件生成教学目标，教学目标必须贴合节名称。
** 生成教学目标必须满足以下格式要求。
** 生成字数300字左右。
</instructions>
## 格式要求如下：
<output_format>
# 一、教学目标
（一）知识目标

（二）能力目标

</output_format>
## 检查以下条件必须满足：
1. **严格按照给定格式生成内容。**
2. **生成内容不能重复，不能有解释等无关内容。**
3. **在生成内容后面不要加入字数描述，例如“（160字）。**
4. **必须满足上述需求，如果不满足，重新生成。**
</optimized_prompt>
u0	  <optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
教授方法：{jiangshou_type}
年级：{level}
科目：{subj}
其他要求：{other_require}
注意：
** 在上一轮生成的内容基础上继续生成，开始生成的时候请换行（

）与上一轮生成区分。**
** 不要生成与上一轮生成内容相同的东西。例如“一、教学目标。**
** 不要对上一轮生成内容进行任何操作（更新，优化，删除等）。**
** 只生成当前章节名称：{chapter}相关内容。**
<instructions>
** 参考{doc_content}中内容和知识库内容进行生成。
** 确保所有内容必须基于知识库内容进行拓展，不能脱离知识库凭空编造。**
** 确保内容要关注起承转合，教学活动衔接自然，必要时可加入表格对比知识点。**
** “# 二、教学重点与难点”生成的内容总字数为400字，“# 三、授课方法”生成字数为400字，请合理分配每个子章节内容**
** 确保当前生成的内容围绕当前章节：{chapter}检索知识库内容进行生成。**
** 教学重点要突出章节重点，包含该章节重点基础理论、原理、应用场景等。**
** 教学难点要根据该章节内容，列出该章节内容对学生理解比较晦涩难懂的概念，理论和在场景中的应用方法。**
** 教学手段包含：多样化教学（讲授、案例分析、小组合作、项目式学习、翻转课堂等）、技术辅助（使用多媒体、在线平台(如学习管理系统)、虚拟实验工具等）、  差异化教学（针对不同学习能力的学生提供分层任务或辅导）等等。**
** 强制按照给定的格式生成。
</instructions>
## 格式要求如下：
<output_format>
# 二、教学重点与难点
##  1.教学重点

##  2.教学难点

# 三、授课方法
##  1.授课方式
    {jiangshou_type}
##  2.教学手段
    
</<output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（180字）”**
</optimized_prompt>
u  <optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
授课方式：{jiangshou_type}
其他要求：{other_require}
注意：
** 请在上一轮生成内容的基础上继续生成，**换行（

）与之前内容区分**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** 教学方法设计要**
** 时间分配考虑学时{time_1},如果{time_1}为一学时，时间为45分钟。如果为二学时，时间为90分钟,以此类推**
** 该章节生成的内容总字数为500字，合理分配每个子章节字数。**
</instructions>
## 格式要求如下：
<output_format>
# 四、教学过程设计
##  1.教学内容设计
    
##  2.教学方法设计
    
##  3.时间分配
      
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
u  <optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
授课方式：{jiangshou_type}
其他要求：{other_require}

注意：
** 请在上一轮生成内容的基础上继续生成，**换行（

）与之前内容区分**
** 参考{doc_content}中内容和知识-rҍ库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** 仔细读取{title}中内容和参考知识材料，“## 4.板书设计”目标是生成符合{chapter}的章节目录。**
** 严格按照以下格式生成。
</instructions>
## 格式要求如下：
<output_format>
##  4.板书设计
## 1.标题
## 1.1.标题
## 2.标题
## 2.1.标题
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
5. **在生成内容后面不要加入描述，不要解释原因”**
</optimized_prompt>
u  <optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
授课方式：{jiangshou_type}
其他要求：{other_require}
注意：
** 请在上一轮生成内容的基础上继续生成，**换行（

）与之前内容区分**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** 仔细读取{title}中内容和参考知识材料，“# 五、小节与作业”目标是达成教学目标、巩固学习效果需求，从而布置作业题、思考题、阅读参考资料、复习和预习等课前或课后学习任务，输出内容要紧紧贴近“章节名称”这个主题，力求清晰、明确，该章节生成的内容总字数为500字，每个子章节生成100字。**
** 严格按照以下格式生成。
</instructions>
## 格式要求如下：
<output_format>
# 五、小节与作业
##  1.作业题
      
##  2.思考题
      
##  3.阅读参考资料
      
##  4.复习
      
##  5.预习
      
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
uJ  <optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
其他要求：{other_require}
注意：
** 请在上一轮生成内容的基础上继续生成，**换行（

）与之前内容区分**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计，五、小节与作业”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** “## 导入新课”内容生成字数为800字。导入新课要求将教学内容自然过渡到当前章节{chapter}，为接下来的教学做准备。**
** 严格按照以下格式生成。
</instructions>
## 格式要求如下：
<output_format>
# 六、教学内容
##  1.导入新课

</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
u8  <optimized_prompt>
{title}中内容：{doc_content}
案例：{all_case}
上一轮生成的内容：{text}
章节名称：{chapter}
序号：{step}
数据库内容：{reference_sql}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
年级：{level}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `

` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成章节名称：{chapter}”相关内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于1000字**；
**  生成“标题”，“内容”不能重复。** 
**  围绕章节名称：{chapter}，结合知识库内容和数据库内容生成。** 
**  如果案例不为空生成内容必须包含对应案例，使用案例不能重复** 
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
### 2.{step}.1.标题 

### 2.{step}.2.标题

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **“2.{step}.1.标题”，“2.{step}.2.标题”必须有，生成标题与{chapter}相关。**
3. **严格按照给定格式生成内容**
4. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
5. **在生成内容后面不要加入字数描述，例如“（1000字）”**
6. **生成完2.{step}.2.内容后结束生成，禁止生成2.{step}.3.标题和内容**
7. **必须生成“2.{step}.2.标题”的内容，不能只生成到“2.{step}.1.标题”内容就终止生成。**
8. **格式中所有“标题”字样必须替换为和{chapter}内容相关的具体标题，“内容”必须是模型参考知识库和数据库生成和{chapter}相关的内容。**
9. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
10. **强制生成内容不能重复**
</optimized_prompt>
u  <optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter_1}
子章节一名称：{title_1_real}
子章节一相关内容：{content_1}
序号：{step}
一序号：{step_1}
子章节一知识库内容：{reference_1}
年级：{level}
科目：{subj}
学时：{time_1}
年级：{level}
其他要求：{other_require}
注意：
** 在上一轮内容基础上继续生成，请以 `

` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于1000字**；
**  生成“标题”，“内容”不能重复。** 
**  2.{step}.{step_1}.{title_1_real}生成的内容参考子章节一相关内容和子章节一知识库内容进行生成** 
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  必须严格按照下面格式生成：**
<instructions>

<output_format>
### 2.{step}.{step_1}.{title_1_real}

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
4. **生成内容必须与“2.{step}.{step_1}.{title_1_real}”相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
5. **在生成内容后面不要加入字数描述，例如“（1000字）”**
6. **生成完“2.{step}.{step_1}.{title_1_real}”内容后结束生成，禁止生成2.{step}.2.标题和内容**
7.**强制生成内容不能重复。**
</optimized_prompt>
u  <optimized_prompt>
{title}中内容：{doc_content}
案例：{case_2}
上一轮生成的内容：{text}
章节名称：{chapter_1}
子章节二名称：{title_2_real}
子章节二相关内容：{content_2}
序号：{step}
二序号：{step_2}
子章节二知识库内容：{reference_2}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
年级：{level}
其他要求：{other_require}
注意：
** 在上一轮内容基础上继续生成，请以 `

` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 如果子章节二名称：{title_2_real}为空，则生成子章节二相关名称替换。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于1000字**；
**  生成“标题”，“内容”不能重复。** 
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  如果{title_2_real}不为空, 2.{step}.{step_2}.{title_2_real}生成的内容参考子章节二相关内容和子章节二知识库内容进行生成** 
**  如果{title_2_real}为空, 生成{title_2_real}与{chapter_1}相关,“2.{step}.{step_2}.{title_2_real}"生成的内容参考知识库内容进行生成**
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
### 2.{step}.{step_2}.{title_2_real}

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
4. **生成内容必须与“2.{step}.{step_2}.{title_2_real}”相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
5. **在生成内容后面不要加入字数描述，例如“（1000字）”**
6. **生成完“2.{step}.{step_2}.{title_2_real}”内容后结束生成，禁止生成2.{step}.3.标题和内容**
7. **必须生成“2.{step}.{step_2}.{title_2_real}”的内容**
8.**如果{title_2_real}为空，必须为其生成具体标题内容。**
9.**强制生成内容不能重复。**
</optimized_prompt>
u
  <optimized_prompt>
{title}中内容：{doc_content}
案例：{all_case}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
年级：{level}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `

` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成章节名称：{chapter}”相关内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  参考{doc_content}中内容和知识库内容进行生成。
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  生成每个内容字数范围在1000字到4000字之间**；
**  必须保证生成的内容不能重复。**
**  生成“标题”，“内容”不能重复。** 
**  围绕章节名称：{chapter}，结合知识库内容和数据库内容生成。** 
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
##  2.1. 标题
###   2.1.1.标题

##  2.1.2.标题

##  2.2.标题
###  2.2.1.标题

### 2.2.2.标题

</output_format>

## 检查以下条件必须满足：
1.** 不要生成“第几章”，“第几节”这种字样。例如“第一章”，“第一节”这种形式的内容。** 
2.** 必需满足生成按照上述格式要求生成，字数是否符合要求，内容与之前生成不重复这几个基本要求。** 
3.** 禁止延展生成“2.1.1.1.”，“2.1.2.1.”，“2.2.1.1.”，“2.2.2.1.”，“2.2.3.”，“2.3.”，等标题内容，必须按照上述固定格式内容输出。**
4.** 不要生成额外的解释。**
5.** 必须要从“2.1.标题”开始生成到“2.2.2.”相关内容结束。**
6.** “2.1.标题”和“2.1.1.标题”之间不能有内容。**
7.** “2.2.标题”和“2.2.1.标题”之间不能有内容。**
8.** 生成每个内容字数不能低于1000字**
9.** 格式中所有“标题”字样必须替换为和{chapter}内容相关的具体标题，“内容”必须是模型生成和{chapter}相关的内容。**
10.** 保证标题间的所属关系。**
11.** 强制生成内容不能重复**
12.**禁止生成2.2.3.标题*和2.3.标题**
13.**如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
14.**生成内容不能重复，如果有重复内容重新输出**
15.**不要思考过程，快速输出内容**
</optimized_prompt>u 
  <optimized_prompt>
{title}中内容：{doc_content}
案例：{all_case}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
年级：{level}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `

` 换行区分。**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成章节名称：{chapter}”相关内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容字数范围在1000字到4000字之间**
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  生成“标题”，“内容”不能重复。** 
**  必须保证生成的内容不能重复。**
**  围绕章节名称：{chapter}，结合知识库内容和数据库内容生成。** 
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
##  2.3. 标题
### 2.3.1.标题

### 2.3.2.标题

##  2.4.标题
### 2.4.1.标题

### 2.4.2.标题

</output_format>

## 检查以下条件必须满足：
1.** 不要生成“第几章”，“第几节”这种字样。例如“第一章”，“第一节”这种形式的内容。** 
2.** 必需满足生成按照上述格式要求生成，字数是否符合要求，内容与之前生成不重复这几个基本要求。** 
3.** 禁止延展生成“2.3.1.1.”，“2.3.2.1.”，“2.4.1.1.”，“2.4.2.1.”，“2.4.3.”，“2.5.”等标题内容，必须按照上述固定格式内容输出。**
4.** 不要生成额外的解释。**
5.** 生成每个内容字数不能低于1000字**
6.** 必须要从“2.3.标题”开始生成到“2.4.2.”相关内容结束。**
7.** “2.3.标题”和“2.3.1.标题”之间不能有内容，“2.4.标题”和“2.4.1.标题”之间不能有内容。**
8.** 格式中所有“标题”字样必须替换为和{chapter}内容相关的具体标题，“内容”必须是模型生成和{chapter}相关的内容。**
9.** 保证标题间的所属关系。**
10. **强制生成内容不能重复**
11. **禁止生成2.4.3.标题*和2.5.标题**
12. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
14.**生成内容不能重复，如果有重复内容重新输出**
15. **不要思考过程，快速输出内容**
</optimized_prompt>u  <optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `

` 换行区分。**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成当前章节：“{chapter}”相关内容。**
<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于500字**；
**  围绕当前章节：“{chapter}”，结合知识库生成内容。** 
**  输出必须从以下格式开始并完整结束：** 
<instructions>
<output_format>
##  3.课堂小结
##  3.1.当前章节回顾
### 3.1.1.知识点总结  

### 3.1.2. 重点难点梳理  

##  4.课后作业
##  4.1. 当前章节作业安排
### 4.1.1. 巩固练习  

### 4.1.2. 拓展任务  

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
u  <optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{content}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
教学形式：{jiangshou_type}
其他要求：{other_require}
注意：
** 在上一轮生成的内容基础上继续生成，开始生成的时候请换行（

）与上一轮生成区分。
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要生成与上一轮生成内容相同的东西。例如“一、教学目标，二、教学重点与难点，三、授课方式与手段，四、教学过程设计，五、小节与作业”直接继续生成第六章内容。
** 不要对上一轮生成内容进行任何操作（更新，优化，删除等）。
** 只生成当前章节名称：{chapter}相关内容。
<instructions>
** 确保所有内容必须基于知识库内容进行拓展，不能脱离知识库凭空编造。
** 确保内容要关注起承转合，教学活动衔接自然，必要时可加入表格对比知识点。
** 确保当前生成的内容围绕当前章节：{chapter}检索知识库内容进行生成。
**不要思考过程，快速输出内容**
</instructions>
</<output_format>
如果授课方式为实作授课，生成的内容总字数不得少于4000个汉字，每一部分参考知识库内容生成尽量详细,。在生成内容后面不要加入字数描述，例如“（300字）,输出形式为：
<output_format>
# 六、教学内容
##  场景二：{jiangshou_type}
### 1.教学准备
### 2.下达任务
### 3.讲解示范
### 4.组织训练
### 5.总结点评
### 6.小节与作业
### 7.教学后记
</output_format>

u  <optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
其他要求：{other_require}
学时：{time_1}
注意：
** 在上一轮生成的内容基础上继续生成，开始生成的时候请换行（

）与上一轮生成区分。
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计，五、小节与作业，六、教学内容”等标题，直接从当前章节对应的内容开始**
** 不要对上一轮生成内容进行任何操作（更新，优化，删除等）。
** 只生成当前章节名称：{chapter}相关内容。
** 必须要包含下面所有格式的内容。
<instructions>
** 强制确保标题和内容之间有换行“

”。** 
** 填写主要教学环节、教学设计意图、以及教学时间分配相关内容** 
** 填写重难知识点讲授策略、解析方法等相关内容** 
** 填写板书具体设计与书写时机相关内容** 
** 填写思政具体设计与融入方法相关内容** 
** 填写注意事项。如：起承转合时机、教学活动关注要点、注意调整授课节奏等相关内容。** 
** 教学时间分配分配考虑学时{time_1},如果{time_1}为一学时，时间为45分钟。如果为二学时，时间为90分钟,以此类推。** 
** “七、备注”章节生成的内容总字数为700字，每个子章节生成100字左右。**
</instructions>
<output_format>
# 七、备注
##  1、教学环节

##  2、教学设计意图

##  3、教学时间分配

##  4、重难知识点讲授策略及解析方法

##  5、板书具体设计与书写时机

##  6、思政具体设计与融入方法

##  7、注意事项

</output_format>
<instructions>
** 课堂表现评估内容为总结学员在课堂上的参与度，包括是否积极回答问题、参与小组讨论等。对学员的发言进行评价，看其对知识的理解程度和分析问题的能力。** 
** 作业评估内容根据学生提交的课后作业，对论文的质量、资料简报的内容完整性和准确性等方面进行评分。通过作业评估，了解学员对本节课知识的掌握情况和自主学习能力，发现教学中存在的不足之处，以便在今后的教学中进行改进。** 
** “八、教学后记”章节生成字数为300字，每个子章节150字左右。**
</instructions>
<output_format>
# 八、教学后记
##  1、课堂表现评估

##  2、作业评估
  
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
u  你是一案例查找专家，擅长根据给定的文本查找与标题相关的案例。现在有文本内容{case_content}和标题{case_title}如下：
文本内容：{case_content}
标题：{case_title}
请根据文本内容和标题按照以下要求查找案例：
** 1. 找到的案例必须与标题相关且包含具体内容，案例内容越丰富越好。
** 2. 案例包含一些经典应用和基于教材参数的典型应用。
** 3. 案例包含一些场景，系统配置，影响和分析等。
** 4. 不能编造案例。
** 5. 不需要输出解释等无关内容。
** 6. 如果没有案例输出“没有相关案例”。
** 7. 找到相关案例输出格式如下：
**输出格式：
案例1："......"
案例2："......"
......
u  你现在是一个开题报告编写专家，请帮我生成一个主题为{title}的开题报告，开题报告的输出形式参考我给你的开题报告模版，生成的内容要准确、清晰无误，同时满足以下要求：
 1.研究目的要阐述清楚，为什么要开展{title}的研究，其最终目的是什么。
 2.研究意义中，需要介绍在怎样的背景下，研究对象是什么，为什么要研究这个选题，然后阐明选题着重解决哪些问题(讨论范围)。先写宏观背景，然后介绍企业背景，然后引入到本文的研究。从理论意义和实践意义两个角度开展叙述。
 3.研究现状要从国内和国外现状开展阐述，结合当下最新的研究，进行详细的分析并生成国内外研究现状。
 4.章节研究目标、内容（论文提纲）及拟解决关键问题，从研究目标、研究内容、拟解决问题和论文提纲开展阐述，其中研究目标要清晰明确，研究内容需要说清楚研究哪些内容，论文提纲可以使用多个多级标题。
 5.研究方法及技术路线，从研究方法和具体实现的技术路线开展研究，要准确，贴近主题，根据给出的大纲内容进行生成，同时可以适当加入一些流程图和表格。
 6.主要参考文献及出处，请给出与{title}相关的参考文献，同时给出对应的论文引用方式
 7.研究进度时间安排表，请输出一个表格，记录整个论文的时间和工作安排
 8.整个开题报告的字数为{length}左右，同时会给你一些参考资料，请根据参考资料的内容，进行上述{title}的开题报告编写。请尽量多生成一些内容，保证字数。
 9.其中，在满足上述要求的同时，如果还存在其他要求，也要一并兼顾考虑；如果没有，则根据上述要求编写开题报告即可。
 10.生成内容时，进行换行时，模版中每一行生成后，用两个换行“

”进行换行，不要使用一个“
”。
 11.其中“姓名：”、“学号：”和“论文题目：”与“生成内容”中间不要进行添加“
”,作为同一行输出,请严格遵循该要求。
 12. 如果完成教案内容的编写，在编写的内容之后加入"end"；否则，内容不能一次性完全输出的情况下，不要加入“end"
   其中，开题报告模版如下：

姓名：生成内容

学号：生成内容

论文题目：生成内容

# 一、选题的背景和意义（含国内外研究现状综述）
## （一）研究目的
## （二）研究意义
### 1.理论意义
### 2.实践意义
## （三）研究现状
### 1.国内研究现状
### 2.国外研究现状
# 二、研究目标、内容（论文提纲）及拟解决关键问题
## （一）研究目标
## （二）研究内容
## （三）拟解决问题
## （四）论文提纲
    - 1. 一级标题
        - 1.1. 二级标题
            - 1.1.1. 三级标题
            - 1.1.2. 三级标题
        - 1.2. 二级标题
        - 1.3. 二级标题
    - 2. 一级标题
    .....
# 三、研究方法及技术路线
## （一）研究方法
## （二）技术路线
# 四、主要参考文献及出处


(1)Amesim 机电一体化仿真教程[M]. 梁全,谢基晨,聂利卫.机械工业出版社.2021.


(2)信息与文献参考文献著录规则[M]. 梁全,谢基晨,聂利卫.机械工业出版社.2021.


    .....


# 五、研究进度时间安排表


   其他要求如下：{other_require}
   参考资料如下：{reference}
u  你是一位专业文案大师，擅长对文本进行精简，即对选中文本进行精简缩写。请根据用户提供的文本，在保持原意的基础上进行精简，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行精简。
3. 确保精简后的文本保留文本中原有元素，但用更简洁的语言表达。
4. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
5. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在精简过程中，精简后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
6. 通读精简后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行精简，如果没有，则保持上述要求进行精简。
8. 请将根据上述要求精简后的内容直接输出，不要输出额外的信息描述。
9. 精简后字数控制在100字左右。
10.不能生成其他额外的内容。只将精简后的内容进行输出。
文本内容如下：{content}
N)"BEAUTIFY_TYPESBEAUTIFY_TYPE_DICTGENERATE_NORMAL_OUTLINE_PROMPT%GENERATE_MARKDOWN_LIST_OUTLINE_PROMPTGENERATE_METHOD_OUTLINE_PROMPTWRITE_PROMPTWRITE_NOTIFY_PROMPTWRITE_REPORT_PROMPTWRITE_METHOD_PROMPTWRITE_HAN_PROMPTWRITE_WORK_SUMMARY_PROMPTWRITE_ANNOUNCEMENT_PROMPTWRITE_REQUEST_PROMPTWRITE_DOCUMENT_PROMPTWRITE_RESPONSE_PROMPTWRITE_PLAN_PROMPTTEMPLATE_DICTWRITE_LEARNING_PLAN_PROMPT_0WRITE_LEARNING_PLAN_PROMPT_1WRITE_LEARNING_PLAN_PROMPT_2WRITE_LEARNING_PLAN_PROMPT_3WRITE_LEARNING_PLAN_PROMPT_4WRITE_LEARNING_PLAN_PROMPT_5WRITE_LEARNING_PLAN_PROMPT_6WRITE_LEARNING_PLAN_PROMPT_12WRITE_LEARNING_PLAN_PROMPT_13WRITE_LEARNING_PLAN_PROMPT_7WRITE_LEARNING_PLAN_PROMPT_8WRITE_LEARNING_PLAN_PROMPT_9WRITE_LEARNING_PLAN_PROMPT_10WRITE_LEARNING_PLAN_PROMPT_11REFERENCE_CASE_FINDWRITE_PROJECT_PROPOSAL_PROMPTTEXT_CUT     ?E:\ZKYNLP\Hjunproject\project0506\aidoc_api\documents_prompt.py<module>r2      s  B,j"	0996"006Rj66	6ud N$"8 N#)8 %L"8 B2.. (2. h . D,+ \1+ h. (. &. $. &. ( "!'"##,
!  B,  \&  R%  Z)  V   P0  j*! Z0! j9 v8 B*  `#! H=! @ `>! Br0   ;?x ˑ) g d g ddgddgdZ dddd	d
dddddd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dZeeeeeeeRe
e	e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d.Zd/Zd0Z d1Z!y<o?e:pu>x%
    kOjb                        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mZmZ d dl	Z	 ej                  ej                          ej                  e      Z	 ddedededeee   ee   f   fdZd	edefd
Zdedededeeee   f   fdZ	 ddedededeeef   fdZ	 	 	 ddedee   dee   dedeeeeeef   f      f
dZd Zedk(  r  ej4                   e             Z ee       yy)    N)OptionalTupleDict)level	directoryoriginal_filenameencodingreturnc                    
K   t         j                  j                  |      \  }}| d
t        j	                  d
         
fd}t        j                  |       d{   }|y	 t        j                  |d|      4 d{   }|j                          d{   }ddd      d{    t        j                        |fS 7 h7 E7 /7 !# 1 d{  7  sw Y   1xY w# t        j                  $ r t        j                  d| d	       Y yt        $ r%}	t        j                  d
| d|	        Y d}	~	yd}	~	ww xY ww)uJ   根据原始文件名查找并读取对应的 _content_list.json 文件。z_content_list.jsonu   正在查找文件: c                      t        j                        D ],  \  } }}|v st         j                  j                  |       c S  y N)oswalkpathjoin)root_filesr   target_filenames      =e:\ZKYNLP\Hjunproject\project0506\aidoc_api\fileparse_util.py_walk_for_filez2find_and_read_content_list.<locals>._walk_for_file   s>     ggi0ND!U%'ww||D/:: 1     N)NNr)r	   u   文件 u    不是有效的 JSON 格式。u   读取文件 u    时发生错误: )r   r   splitextloggerinfoasyncio	to_threadaiofilesopenreadjsonloadsJSONDecodeErrorerror	Exception)r   r   r	   	file_namer   r   	file_pathftexter   s   `         @r   find_and_read_content_listr,      s#     77##$56LIq"#56O
KK&&789 ''77I
==C(CCq>D DC zz$** 8
 D! DCCC  wyk)HIJ }YK/A!EFs   AE"C#E+C( CC( CC C$C( /C0C( 
EC( CC( C%CC%!C( (,EEED>9E>EEdoc_datac                     t               }| D ]R  }d|v s|d   s|d   }|j                  d      s%|j                  t        j                  j                  |             T |S )u]   从文档数据中提取所有 .jpg 图片的纯文件名。纯 CPU 操作,不需要 async。img_pathz.jpg)setendswithaddr   r   basename)r-   
result_setitemr/   s       r   extract_all_jpg_filenamesr6   /   s]    J$z"2J'H  (rww//9:	 
 r   img_filelocal_image_dirmime_mapc           	        K   t         j                  j                  ||       }t         j                  j                  |      st        j                  d|        | dfS 	 t        j                  |d      4 d{   }|j                          d{   }ddd      d{    t        j                        j                  d      }| j                         j                  dd      d   }d|j                  |d	       }| d
| d| fS 7 7 |7 n# 1 d{  7  sw Y   ~xY w# t        $ r2}	t        j!                  d|  dt#        |	              | dfcY d}	~	S d}	~	ww xY ww)u;   编码单张图片,返回 (文件名, data_uri 或 None)。u   图片不存在: Nrbutf-8.   zimage/pngzdata:z;base64,u   编码图片失败 z: )r   r   r   isfiler   warningr   r    r!   base64	b64encodedecodelowerrsplitgetr&   r%   str)
r7   r8   r9   r/   r)   	img_bytes
img_base64ext	mime_typer+   s
             r   _encode_one_imagerN   :   s4     ww||OX6H77>>(#*8*56~
==400AffhI 10 %%i077@
nn%%c1-b1X\\#u567	58J<@@@ 1& 1000  *8*Bs1vh?@~s   AE%D' 9D:D' =DDDD' !D"A)D' E%D' DD' D$DD$ D' '	E"0'EE"E%E""E%referenced_imagesconcurrencyc                 6   K   t         j                  j                         r|si S ddddddt        j                  |      dt
        f fdt        j                  fd|D          d	{   }|D ci c]  \  }}|	|| c}}S 7 c c}}w w)
u+   并发将引用的图片编码为 base64。jpegr@   gifwebp)jpgrR   r@   rS   rT   r7   c                    K   4 d {    t        |        d {   cd d d       d {    S 7 *7 7 	# 1 d {  7  sw Y   y xY wwr   )rN   )r7   r8   r9   sems    r   _boundedz)encode_images_to_base64.<locals>._bounded`   s5     3*8_hOO 33O 333sH   A5A;7;A9A;AAAA	Ac              3   .   K   | ]  } |        y wr    ).0r)   rX   s     r   	<genexpr>z*encode_images_to_base64.<locals>.<genexpr>d   s     $L:KQXa[:Ks   N)r   r   existsr   	SemaphorerI   gather)	r8   rO   rP   resultsnamedatarX   r9   rW   s	   `     @@@r   encode_images_to_base64rc   R   s      77>>/*2C	veESYZH 

K
(CP P NN$L:K$LMMG)0E:4D4DD$JEE NEs*   A-B3B4	B=
BBBBinput_file_name
search_dirc           
        K   t        ||        d{   \  }}|t        j                  d       yt        j                  d|        t        j                  dt	        |      j
                   dt        t        |                    |=t        j                  j                  t        j                  j                  |      d      }t        j                  d|        t        |      }t        j                  dt        |              t        |||	       d{   }t        j                  d
t        |       d       ||fS 7 77 -w)u  
    异步处理文档:查找 content_list.json,提取图片引用,并发编码为 base64。

    Args:
        input_file_name: 原始文件名(如 "xxx.pdf")
        search_dir: 搜索 _content_list.json 的根目录
        local_image_dir: 图片所在目录,None 则自动推断
        concurrency: 图片编码的并发数上限,默认 32

    Returns:
        成功: (content_list, images_dict)
        失败: None
    Nu3   ❌ 未找到指定的 _content_list.json 文件。u   ✅ 找到文件: u   内容类型: u
   , 长度: imagesu   图片目录: u   引用图片数量: )rP   u   成功编码 u
    张图片)r,   r   r%   r   type__name__lenrI   r   r   r   dirnamer6   rc   )rd   re   r8   rP   contentcontent_pathrO   images_dicts           r   process_documentro   h   s    & #=Z"YYG\JK
KK$\N34
KK.g!7!7 8
3s7|CTBUVW'',,rww|'DhO
KK. 1231':
KK&s+<'=&>?@/* K KK-K 01<=K) Zs"   EE	DEE+EEc                    K   t        ddd       d {   } | y| \  }}t        d       t        dt        |              t        dt        |              |r,t        t	        |            }t        d	| d
||   d d  d       y7 tw)Nu-   163-06A0014-B01001_发动机-维修手册.pdf/app/mineru_output    )rd   re   rP   r>   u   
=== 处理完成 ===u   文档段落数: u   图片数量: u   示例图片 [z]: P   z...r   )ro   printrj   nextiter)resultrl   rn   	first_keys       r   mainry      s     #G' F ~!G[	"$	c'l^
,-	N3{+,
-.k*+	yk[-CCR-H,IMN!s   BB	A5B__main__)r<   )rr   )rq   Nrr   )r   r"   rC   r   loggingtypingr   r   r   r   basicConfigINFO	getLoggerri   r   rI   listr,   r0   r6   dictrN   intrc   ro   ry   run	exit_codeexitrZ   r   r   <module>r      s   	     ( (    ',, '			8	$   8D>8C=()	D    3	6 FFF F 
#s(^	F0 !5%)	' ' '  c]'  	' 
 eD$sCx.()*' T( zDF#IO r   VUx"M
    Mj                     R   d Z ddlmZmZmZmZmZmZ ddlm	Z	m
Z
mZ ddlmZmZmZ ddlmZ ddlmZ ddlmZ ddlZddlZ G d	 d
e      Zdedeeef   fdZdedeeef   fdZdedeeef   fdZd ZddlmZ dedefdZ e!dk(  rddl"Z"d Z# e"jH                   e#              yy)u!  
主脑Agent - 简化版（无意图分类）

职责：
1. 输入处理：图片、音频、文本提取
2. 直接路由：根据外部传入的 route_flag 决定调用哪个工作流

工作流列表（来自 workflow_registry）：
- 故障排查与修理
- 舰船百科
- 操作使用
    )	TypedDictLiteralOptionalDictAnyList)
StateGraphSTARTEND)vlm_image_to_textasr_audio_to_textdetect_input_type)	OpenaiAPI)track_function_calls)VALID_ROUTE_FLAGSNc                       e Zd ZU dZeeef   ed<   eed<   eed<   eed<   eed<   eed<   eed<   eed	<   eed
<   eed<   eed<   eed<   e	eeef      ed<   eed<   eed<   eed<   eeef   ed<   y)MainAgentStateu   主脑Agent状态	raw_input	has_image	has_audio	has_queryhas_file_text
input_typehistory_messageextracted_textimage_descriptionasr_text	file_textcombined_queryworkflow_resultfinal_responseerror_message
route_flagroute_paramsN)
__name__
__module____qualname____doc__r   strr   __annotations__boolr        9e:\ZKYNLP\Hjunproject\project0506\aidoc_api\main_agent.pyr   r      s    CH~OOOOMNd38n--OsCx. r-   r   statereturnc                    | d   }t        |       t        d       t        j                  d|i      }|j                  dd      }|j                  dd      }|j                  dd      }d}|j                  d      }t	        |t
              r|j                         rd}d	}t        ||||g      }	|	d
k(  r|rd}n|rd}n	|rd}n|rd}|||||dS )u   检测输入类型r   l   cq,n$Lr   Fr   r   r   Tmixed   imageaudiotextfile)r   r   r   r   r   )printr   invokeget
isinstancer)   stripsum)
r/   rawresultr   r   r   r   file_text_vr   counts
             r.   detect_input_type_noderB   4   s    

C	#J	
$%%%{C&89F

;.I

;.I

;.IM''+&K+s#(9(9(;JIy-@AEz J JJJ &  r-   c                   K   | j                  dd      }| j                  dd      }| j                  dd      }| j                  dd      }| d   }d}d}d}	 |rI|j                  dd      }	|	r5	 t        j                  d	|	i       d
{   }|r|j                  d      rd}|rI|j                  dd      }
|
r5	 t        j                  d|
i       d
{   }|r|j                  d      rd}g }|j                  d      r|j                  |d          |r|j                  d|        |r|j                  d|        |j                  d      r|j                  d|d           |rdj                  |      nd}|j                  dd      xs |}|||||j                  dd      dS 7 ## t        $ r d}Y w xY w7 # t        $ r d}Y w xY w# t        $ r}dt        |       ddcY d
}~S d
}~ww xY ww)u   处理多模态输入r   Fr   r   r   r    r4   
image_pathNu   VLM 调用失败r5   
audio_pathu   ASR 调用失败queryu   [图片描述] u   [语音转文字] r   u   [文件内容] 
)r   r   r   r   r   u   输入处理失败: )r"   r   )	r:   r   ainvoke
startswith	Exceptionr   appendjoinr)   )r/   r   r   r   r   r>   r   r   r   rE   rF   
text_partsr   es                 r.   process_multimodal_inputrP   Y   s?    		+u-I		+u-I		+u-IIIou5M

CHN2
"-J+.?.G.G$jI / )% -0A0L0LM_0`,.) "-J"%6%>%>$j@ &  H $x':':;M'N#% 
777c'l+0A/BCD 28*=>77;K0@/ABC2<:.""-? -!2 ,b1
 	
C)
 ! +(*%+ 
 ! "!H"0  
3CF8< 
 	

s   AG:G .F. F+	F. "G 9G G G -B=G *G:+F. .F=9G <F==G  G GG GG 	G7G2,G7-G:2G77G:c                    | j                  dd      }|t        vrd}| j                  dd      }| j                  dd      xs |}| j                  di       }|j                  dd      }|||d}|j                  d	      r|d	   |d	<   t        d
|        t        d|dd  d       |dk(  rd}n|dk(  rd}n|dk(  rd}n
|dk(  rd}nd}|||dS )u2   
    🤖分析意图，调用相关智能体
    r#   u   问题排查r   rD   r   r   r   )r   r   r   r   u   [主脑Agent] 路由到: u%   [主脑Agent] 参数: combined_query=Nd   ...u!   正在调用问题排查智能体u   百科问答u!   正在调用百科问答智能体u   操作使用u!   正在调用操作使用智能体u   统计u   正在调用统计智能体u   正在调用通用智能体)r#   r$   
__detail__)r:   r   r8   )r/   r#   
query_textr   r   r   r$   details           r.   route_to_workflowrW      s    <8J**#
+R0JYY/4B
N		+r*Imm$5r:O %(*L }}[!$-k$:[!	%j\
23	1.#2F1Gs
KL^#4	~	%4	~	%4	x	.. !$ r-   c                  d   t        t              } | j                  dt               | j                  dt               | j                  dt
               | j                  t        d       | j                  dd       | j                  dd       | j                  dt               | j                         S )u   创建主脑Agentr   process_inputroute)
r	   r   add_noderB   rP   rW   add_edger
   r   compile)workflows    r.   create_main_agentr_      s    .)H)+ABo'?@g01e01)?;ow/gs#r-   )filter_image_urlscontentc                    K   	 d| dd  }t        j                  |ddg        d{   }|r|j                         nd}t        |      dkD  r|dd dz   }|S 7 0# t        $ r Y yw xY ww)	u   提取对话标题uO   请从以下对话内容中提取一个简短的标题（不超过20字）：

Ni  uT   你是一个标题提取助手，请从对话内容中提取一个简短的标题。)rG   modelsystem_promptmessagesu	   新对话   rS   )r   open_api_chat_without_thinkingr<   lenrK   )ra   promptresponsetitles       r.   extract_conversation_titlerl      s     delmqnqerdst"AAp	
 
 %- +u:?#2J&E
  s8   A*$A A/A A*A 	A'$A*&A''A*__main__c                     K   t        d       t               } | j                  ddidd       d {   }t        d|        y 7 w)Nu   测试主脑AgentrG   u   101舰主机发生异响u   故障排查与修理)r   r#   u   结果: )r8   r_   rI   )agentr?   s     r.   testrp      sQ     !"!#}}!#=>1&
   	!"	s   /AAA)%r(   typingr   r   r   r   r   r   langgraph.graphr	   r
   r   tools.function_toolr   r   r   modelsAPI.model_apir   utils.function_trackerr   workflow_registryr   jsonrer   r)   rB   rP   rW   r_   workflows.history_managerr`   rl   r%   asynciorp   runr,   r-   r.   <module>r|      s    A @ 2 2 
 * 7 /  	!Y !0". "T#s(^ "J>
. >
T#s(^ >
B*^ *S#X *Z  8c c $ z# GKK r-   -Ax^q
    αMj                         d Z i ddddddddd	d
dddddddddddddddddddddd d!d"d#d$d%d&d'Zd(d)d*d+d,d-d.d/Zd0d1d2d3d4Zd5d6d7d8d9d:d;Zd<d=d>d?d@dAdBdCZdDdEdFdGdHdIdJdCZyK)Lum  
提示词集中管理模块
将各工作流中的提示词统一提取到此处，方便调整和维护。
每个提示词都附有详细注释说明其用途和所属工作流节点。

模块结构：
- COMMON_PROMPTS: 多个工作流共享的提示词（格式规范、友好回复、无检索建议等）
- BAIKE_PROMPTS: 百科问答工作流专用提示词
- STATISTICS_PROMPTS: 统计工作流专用提示词
- FAULT_DIAGNOSIS_PROMPTS: 故障诊断工作流专用提示词（仅含与操作指导不同的部分）
- OPERATE_PROMPTS: 操作指导工作流专用提示词（仅含与故障诊断不同的部分）
format_systemul   你是一个专业的格式规范助手，负责将给定的文本内容规范成美观、易读的格式。format_user_with_image_examplesu[  请将以下内容规范成美观、易读的Markdown格式：

【原始内容】
{raw_content}

【格式规范要求】
1. 保持原始内容的完整性和准确性，**不要修改任何内容**，只调整格式
2. 适当使用标题、段落分隔等Markdown格式，使内容更易读
3. 确保图片链接在相关位置自然展示使用，并且只输出准确格式，`![图片](/api/v1/knowledge/files/images/xxx.jpg)` 
4. 如果参考资料中没有图片，**不要输出任何关于图片的说明**
5. 确保LaTeX公式格式正确：$$...$$，并在 $$...$$ 前后加空格
6. 如果有代码片段，使用适当的代码块格式
7. 不要添加任何额外的解释或说明

【图片输出示例】
示例一:  原始内容：`![图片](images/xxx.jpg)`
        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`
示例二:  原始内容：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`
        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`
示例三:  原始内容：`images/xxx.jpg`
        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`
示例四:  原始内容：`xxx.jpg`
        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`
示例五:  原始内容：`![油污清理](/api/v1/knowledge/files/images/ce9650912c24fa0ed693228469322ec2a735f14d9ac729a1dc87427441bad0b.jpg)`
        规范后输出：`![图片](/api/v1/knowledge/files/images/ce9650912c24fa0ed693228469322ec2a735f14d9ac729a1dc87427441bad0b.jpg)`
示例六： 原始内容：`![部分断裂的螺栓及垫片](![图片](/api/v1/knowledge/files/images/e34eb1ddbe26730c84409e02365db416e74ce9e3bf2793a2605db5a085548415.jpg)`
        规范后输出：`![图片](/api/v1/knowledge/files/images/e34eb1ddbe26730c84409e02365db416e74ce9e3bf2793a2605db5a085548415.jpg)`

请直接输出规范后的内容：format_user_simpleuK  请将以下{content_label}内容规范成美观、易读的Markdown格式：

【原始内容】
{raw_content}

【格式规范要求】
1. 保持原始内容的完整性和准确性，**不要修改任何内容**，只调整格式
2. 适当使用标题、列表、段落分隔等Markdown格式，使内容更易读
3. 确保图片链接保持原样：`![图片](URL)`
4. 确保LaTeX公式格式正确：$$...$$，并在 $$...$$ 前后加空格
5. 如果有代码片段，使用适当的代码块格式
6. 不要添加任何额外的解释或说明

请直接输出规范后的内容：classify_intent_useruP   
### 用户输入
"{combined_query}"

请根据上述标准进行意图分类：extract_info_useru   请从以下内容中提取{biz_label}相关信息：

【已提取的信息】
{existing_info_str}

【历史对话】
{history_str}

【当前用户输入】
{combined_query}

请提取信息（JSON格式）：ask_user_systemu   你是一个专业的{biz_label}助手，需要友好地引导用户提供缺失信息。

要求：
1. 语气友好、专业，不要生硬
2. 说明为什么需要这些信息（更准确的{biz_label_short}）
3. 鼓励用户提供更多细节ask_user_promptu   请生成一段友好的回复，引导用户补充缺失信息。

【已获取的信息】（完整性评分: {info_completeness}）
{existing_str}

【缺失的信息】
{missing_str}

【用户当前输入】
{combined_query}

请生成回复：!generate_response_friendly_systemu   你是一个友好的{biz_label}助手。用户可能只是在打招呼或询问一般性问题。
请友好地回复，并简要介绍你能提供的帮助。generate_response_friendly_useru0   用户说：{combined_query}

请友好回复：generate_response_no_rag_systemu   你是一个专业的{biz_label}助手。
虽然没有检索到相关资料，但可以根据用户提供的信息给出一般性建议。
注意：明确告知用户这是基于一般经验的建议。&generate_response_no_rag_simple_systemu   你是一个专业的{biz_label}助手。
虽然没有检索到相关资料，但可以根据用户提供的信息给出一般性建议。generate_response_follow_upu  你是一名资深工业设备{biz_label}工程师。用户正在与你进行后续交互。

【设备信息】
- 舷号：{ship_number}
- 设备名称：{device_name}
- {item_label}：{item_name}
{detail_info}【参考资料】
{rag_answer}

【用户当前问题】
{combined_query}

【输出要求】
1. {image_guidance}
2. 如果参考资料包含表格，请转化成不用表格的形式输出内容
3. 如果参考资料包含 LaTeX 公式，请转为 $$...$$ 公式格式输出，并在 $$...$$ 前后加空格
4. 所有链接必须与参考资料保持一致，不得裁剪、转义或改写
5. 不能虚构参考资料中未提及的图片、表格、零件号或步骤

请给出回复：generate_response_normalu  你是一名资深工业设备{biz_label}工程师，请根据以下信息生成{biz_label}分析与{biz_label}方案。

【设备信息】
- 舷号：{ship_number}
- 设备名称：{device_name}
- {item_label}：{item_name}
{detail_info}当前的{item_label}要以{item_name}为准，{item_action}。

【参考资料】
{rag_answer}

【输出要求】
1. **重要**：如果参考资料中包含图片链接（格式为 `![图片](URL)` 或 `images/xxx.jpg`），请务必在相关位置自然展示使用，如果参考资料中没有图片，**不要输出任何关于图片的说明**
2. 如果参考资料包含 LaTeX 公式、连接等，请在对应位置正常使用，不得修改或删除
3. 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性
4. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式
5. 如果参考资料包含表格，请不要输出表格，而要直接描述表格的内容

请给出回复：generate_response_regeneratingus  你是一名资深工业设备{biz_label}工程师。用户对之前的方案有反馈，请根据反馈重新生成{biz_label}分析与{biz_label}方案。

【设备信息】
- 舷号：{ship_number}
- 设备名称：{device_name}
- {item_label}：{item_name}
{detail_info}【用户反馈】
{user_feedback_for_regenerate}

【参考资料】
{rag_answer}

【输出要求】
1. 先用一句话判断{item_label}原因（包含舷号、设备、{item_label}，不超过40字）
2. 然后给出{biz_label}方案，步骤清晰、可直接执行
3. 根据用户的反馈调整方案
4. 如果参考资料信息不足，明确指出缺少什么
5. {image_guidance}，如果参考资料中没有图片，**不要输出任何关于图片的说明**
6. 如果参考资料包含表格，请转化成不用表格的形式输出内容
7. 如果参考资料包含 LaTeX 公式，请转为 $$...$$ 公式格式输出，并在 $$...$$ 前后加空格
8. 所有链接必须与参考资料保持一致，不得裁剪、转义或改写
9. 不能虚构参考资料中未提及的图片、表格、零件号或步骤

请直接输出调整后的方案： generate_response_content_systemu   你是一名资深工业设备{biz_label}工程师，严格依据检索信息生成{biz_label}方案。请专注于内容的准确性、完整性和逻辑性，如果参考资料中包含图片，请务必在回答中展示出来。deep_rag_analysis_systemu  你是一名资深工业设备{biz_label}专家。用户反馈之前的方案没有解决问题，请分析：
1. 之前方案可能存在的不足
2. 用户当前问题的关键点
3. 选择3-5个可以深入检索的分析点（如特定部件、原理、{biz_label}方法等）

输出格式（JSON）：
{
    "analysis_points": ["分析点1", "分析点2", "分析点3"],
    "reason": "分析理由"
}deep_rag_analysis_useru&  【设备信息】
- 舷号：{ship_number}
- 设备名称：{device_name}
- {item_label}：{item_name}
{detail_info}
【对话历史】
{history_str}

【之前的方案】
{last_generated_scheme}

【用户当前反馈】
{combined_query}

请分析并选择深度分析点（JSON格式）：u  你是一名资深工业设备{biz_label}专家。用户反馈之前的方案没有解决问题，请根据多维度深度检索的资料，进行深入的{item_label}原因分析和解决方案规划。

【设备信息】
- 舷号：{ship_number}
- 设备名称：{device_name}
- {item_label}：{item_name}
{detail_info}【用户反馈】
{combined_query}
{analysis_points_prompt}【针对分析点的深度检索资料】
{analysis_points_text}
{original_rag_text}

【图谱检索结果】
{graph_results}

【输出要求】
1. 首先重新深入分析{item_label}原因，结合所有检索资料进行推理
2. 给出更详细、更精准的{biz_label}方案，步骤清晰、可直接执行
3. 重点关注用户反馈的问题，根据用户反馈和检索资料，进行{item_label}原因分析和解决方案规划。
4. **重要**：如果参考资料中包含图片链接（格式为 `![图片](URL)` 或 `images/xxx.jpg`），请务必在相关位置自然展示使用，如果参考资料中没有图片，**不要输出任何关于图片的说明**
5. 如果参考资料包含 LaTeX 公式、连接等，请在对应位置正常使用，不得修改或删除
6. 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性
7. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式
8. 如果参考资料包含表格，请不要输出表格，而要直接描述表格的内容

请直接输出深度分析和方案：u   你是一名资深工业设备{biz_label}专家，严格依据检索信息进行深度分析和方案生成。请专注于内容的准确性、完整性和逻辑性，如果参考资料中包含图片，请务必在回答中展示出来。u  你是一名资深工业设备{biz_label}专家。用户对之前的{biz_label}方案有反馈，请根据反馈直接修改方案。

【设备信息】
- 舷号：{ship_number}
- 设备名称：{device_name}
- {item_label}：{item_name}
{detail_info}当前的{item_label}要以{item_name}为准，{item_action}。

【之前的方案】
{last_scheme}

【用户反馈】
{user_feedback}

【输出要求】
1. 首先根据用户反馈，分析之前方案的问题所在
2. 然后基于之前的方案进行修改和优化，给出调整后的方案
3. 重点解决用户反馈的问题
4. {image_guidance}
5. 如果之前方案包含表格，请转化成不用表格的形式输出内容
6. 如果之前方案包含 LaTeX 公式，请转为 $$...$$ 公式格式输出，并在 $$...$$ 前后加空格
7. 所有链接必须与原方案保持一致，不得裁剪、转义或改写
8. 不能虚构原方案中未提及的图片、表格、零件号或步骤

请直接输出修改后的完整方案：u   你是一名资深工业设备{biz_label}专家，根据用户反馈直接修改和优化{biz_label}方案。请专注于内容的准确性、完整性和逻辑性。)generate_deep_response%generate_deep_response_content_systemregenerate_scheme_from_feedback&regenerate_scheme_from_feedback_systemu&  你是一个专业的问题分析助手，请判断用户的问题是否需要检索知识库才能回答。

【判断标准】
需要检索的情况：
- 询问特定设备、技术、规程、规范的具体内容
- 需要专业知识或特定数据支持的问题
- 询问故障诊断、维修方法等专业领域问题
- 询问历史事件、法规条款、技术标准等需要查证的内容

不需要检索的情况：
- 简单的问候、寒暄
- 常识性问题（如常识性知识、简单计算等）
- 明确不需要专业知识的问题
- 对之前对话的简单追问，上下文已足够回答

【对话历史】
{history_messages}

【当前用户问题】
{original_query}

请仅输出 "true" 或 "false"（不带引号），true 表示需要检索，false 表示不需要检索。uU  你是一个专业的检索query重写助手，负责根据对话历史和当前用户问题，生成**适合向量检索/RAG 的单条查询语句**。

请严格遵守以下要求：
1. 只融合与当前问题语义强相关的**最近几轮对话信息**，不要机械拼接全部历史。
2. 消除指代和省略（例如：这个、刚才那个问题、上面说的故障等），补全成自洽、完整的描述。
3. 不要加入与用户问题无关的背景信息，不要过度扩展检索范围。
4. 输出必须是一句自然的中文问句或陈述句，便于检索；不要包含条目符号、编号或解释性文字。
5. 只输出改写后的query本身：
   - 不要输出说明文字
   - 不要包含「改写结果：」「检索query：」等前缀
   - 不要添加引号

【特别提示】
- 请优先参考**上一轮用户的问题**来重写本轮query。
- 上一轮用户的问题是：{last_user_query}

【对话历史（JSON 格式，已按时间排序）】
{history_str}

【当前用户问题】
{original_query}

请给出最终用于检索的单条中文query。u  你是一个专业的工业设备问答助手。根据以下问答内容，生成两个用户可能关心的后续问题。

【用户问题】
{question}

【回答内容】
{answer}

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与当前问答内容相关，能够帮助用户进一步了解相关信息
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {{"title": "问题1的标题", "content": "问题1的完整内容"}},
    {{"title": "问题2的标题", "content": "问题2的完整内容"}}
]

只输出JSON，不要有其他文字说明。u   我是一个专业的{domain_desc}知识问答助手，根据用户的问题，综合所有检索结果，提供准确、专业、完整的回答内容。u  {extracted_text}

# 检索到的相关信息（共 {rag_count} 条）：

{all_source_text}

【输出要求】
1. **重要**：如果参考资料中包含图片链接（格式为 `![图片](URL)` 或 `images/xxx.jpg`），请务必在相关位置自然展示使用，如果参考资料中没有图片，**不要输出任何关于图片的说明**
2. 如果参考资料包含 LaTeX 公式、连接等，请在对应位置正常使用，不得修改或删除
3. 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性
4. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式
5. 如果参考资料包含表格，请不要输出表格，而要直接描述表格的内容

请给出回复：u   我是一个专业的{domain_desc}知识问答助手，根据用户的问题，结合我的专业知识，提供准确、专业、完整的回答内容。u   {extracted_text}

【输出要求】
1. 请根据您的专业知识提供准确、完整的回答
2. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式
3. 请专注于内容的准确性和专业性

请给出回复：)judge_need_retrievalrewrite_query_with_historygenerate_suggested_replies%generate_answer_with_retrieval_system#generate_answer_with_retrieval_user(generate_answer_without_retrieval_system&generate_answer_without_retrieval_useru  从以下文本中提取统计所需的信息，返回JSON格式。
提取内容：
- system: 系统名称（如：动力系统、电气系统等），如果没有则为空字符串
- time: 时间描述（如：近一个月、上周等），如果没有则为空字符串

文本：
{text}

输出格式示例：
{{"system": "动力系统", "time": "近一个月"}}
{{"system": "", "time": "上周"}}
{{"system": "电气系统", "time": ""}}

现在请提取：u  从以下文本中提取统计所需的信息，返回JSON格式。
提取内容：
- ship_number: 舷号数字（如：101、163等），如果没有则为空字符串
- time: 时间描述（如：近一个月、上周等），如果没有则为空字符串

文本：
{text}

输出格式示例：
{{"ship_number": "101", "time": "近一个月"}}
{{"ship_number": "", "time": "上周"}}
{{"ship_number": "163", "time": ""}}

现在请提取：u+  从以下文本中提取统计所需的信息，返回JSON格式。
提取内容：
- source: 反馈来源（如：好评、差评、反馈），如果没有则为空字符串

文本：
{text}

输出格式示例：
{{"source": "差评"}}
{{"source": "好评"}}
{{"source": ""}}

现在请提取：u  你是一个参数提取助手。请从用户问题中提取统计工具所需的参数。

当前日期：{current_date}

工具名称：{tool_name}
工具描述：{tool_description}

所需参数：
{params_desc_str}

对话历史：
{history_str}

用户问题：
{extracted_text}

请特别注意：
1. 时间参数映射：
   - "最近一周" -> 开始日期为当前日期前7天，结束日期为当前日期
   - "最近一个月" -> 开始日期为当前日期前30天，结束日期为当前日期
   - "最近三个月" -> 开始日期为当前日期前90天，结束日期为当前日期
   - "上个月" -> 开始日期为上个月1号，结束日期为上个月最后一天
   - "今年" -> 开始日期为今年1月1日，结束日期为当前日期
   - 如果用户提到具体日期，请按原样提取
{extra_instructions}
3. top_n参数：
   - 如果用户提到"前N个"、"Top N"等，提取N的值
   - 否则使用默认值

请输出JSON格式：
{{
    "parameters": {{
        "参数名": "参数值"
    }},
    "missing_required": ["缺少的必填参数列表"],
    "confidence": 0.0-1.0之间的置信度
}}

如果某个参数在用户问题中没有提到且不是必填，则不要包含在parameters中。
只输出JSON，不要有其他文字。)extract_fault_frequency_infoextract_spare_parts_infoextract_repair_feedback_infoextract_tool_parametersu  你是一个路由判断专家。请判断用户的问题是否需要查询数据库进行统计分析。

判断标准：
- 如果问题涉及统计、排名、频次、数量、趋势、对比、分布等，需要查询数据库 → 回答 "statistics"
- 如果问题涉及维修反馈、好评、差评等，需要查询外部系统 → 回答 "feedback"
- 如果是一般性知识问答、维修方法、操作指导等，不需要查询数据库 → 回答 "normal"

用户问题：{question}

请输出JSON格式：
{{"route": "statistics" 或 "feedback" 或 "normal", "reason": "判断理由"}}
只输出JSON，不要有其他文字。uo  你是舰船维修数据分析助手。请根据用户问题生成SQL查询。

【数据库Schema】
{schema}

【当前日期】{current_date}

【用户问题】
{question}

【其他有效信息】
{extra_info}
【生成规则】
1. 只能生成 SELECT 语句，禁止 INSERT/UPDATE/DELETE
2. 只能查询 fault_records 表
3. 默认 LIMIT 100（如果未指定）
4. 不允许使用 UNION、子查询嵌套超过2层
5. 不允许使用任何危险SQL（如 pg_sleep、注释注入等）
6. 时间条件使用 created_at 字段
7. 备件统计需要使用 jsonb_array_elements_text(spare_parts) 展开JSONB数组
8. 系统名称使用 system_name 字段，必须使用 LIKE 模糊匹配（如 system_name LIKE '%动力%'），不要用等号精确匹配
9. 舷号使用 ship_number 字段

【常见统计模式】
- 故障频次排名：SELECT device_name || fault AS name, system_name, COUNT(*) AS count FROM fault_records [WHERE ...] GROUP BY name, system_name ORDER BY count DESC LIMIT N
- 备件消耗排名：SELECT sp AS name, system_name, COUNT(*) AS count FROM fault_records, jsonb_array_elements_text(spare_parts) AS sp [WHERE ...] GROUP BY sp, system_name ORDER BY count DESC LIMIT N
- 故障类型分布：SELECT system_name, COUNT(*) AS count FROM fault_records [WHERE ...] GROUP BY system_name ORDER BY count DESC
- 按舷号统计：在WHERE中添加 ship_number = 'xxx'
- 按系统筛选：在WHERE中添加 system_name LIKE '%动力%'
- 按时间范围：在WHERE中添加 created_at >= 'xxx' AND created_at <= 'xxx'

【时间映射规则】
- "最近一周" → created_at >= 当前日期前7天
- "最近一个月" → created_at >= 当前日期前30天
- "最近三个月" → created_at >= 当前日期前90天
- "今年" → created_at >= 当年1月1日

请输出JSON格式：
{{"sql": "SELECT ...", "explanation": "SQL逻辑说明"}}
只输出JSON，不要有其他文字。u  你是舰船维修数据分析助手。之前的SQL存在问题，请根据反馈重新生成。

【数据库Schema】
{schema}

【当前日期】{current_date}

【用户问题】
{question}

【之前的SQL】
{previous_sql}

【问题反馈】
{feedback}

请根据反馈修正SQL，输出JSON格式：
{{"sql": "SELECT ...", "explanation": "修正说明"}}
只输出JSON，不要有其他文字。u  你是SQL审查专家。请检查以下SQL是否真正回答了用户问题。

【数据库Schema】
{schema}

【用户问题】
{question}

【待审查SQL】
{sql}

【审查要点】
1. 时间条件是否正确（用户说"近一个月"，SQL是否有对应的时间范围？）
2. 聚合逻辑是否正确（COUNT、GROUP BY是否与问题匹配？）
3. 排序是否正确（排名类问题是否ORDER BY DESC？）
4. 字段是否存在（所有字段都在Schema中？）
5. 是否符合业务语义（故障频次应统计device_name+fault，备件应展开spare_parts）
6. WHERE条件是否遗漏（用户指定了舷号/系统，SQL是否包含？）
7. 备件统计是否正确使用了 jsonb_array_elements_text

请输出JSON格式：
{{
  "approved": true 或 false,
  "issues": ["问题1", "问题2"],
  "suggested_sql": "修正后的SQL（如果approved为false，提供修正版本）",
  "review_comment": "审查意见"
}}
只输出JSON，不要有其他文字。u  你是数据分析审查专家。请检查SQL查询结果是否合理地回答了用户问题。

【用户问题】
{question}

【执行的SQL】
{sql}

【结果概况】
- 返回行数：{row_count}
- 前5行数据：
{sample_rows}

【判断标准】
1. 如果结果为空（0行），可能SQL有问题 → 需要重试
2. 如果结果数量异常少（如统计排名只有1条），可能条件过严 → 需要重试
3. 如果结果明显不符合业务逻辑 → 需要重试
4. 如果结果合理 → 通过

请输出JSON格式：
{{
  "reasonable": true 或 false,
  "reason": "判断理由",
  "suggestion": "如果不合理，给出改进建议"
}}
只输出JSON，不要有其他文字。u+  你是舰船维修数据分析助手。请将SQL查询结果转换为清晰的自然语言回答。

【用户问题】
{question}

【执行的SQL】
{sql}

【查询结果】（共{row_count}条）
{result_data}

【回答要求】
1. 用自然语言总结核心结论
2. 如果是排名类结果，用Markdown表格展示（列名：排名、名称、次数/数量、系统等）
3. 如果是分布类结果，说明各部分的占比
4. 数字要准确，不要编造数据
5. 语言简洁专业
6. 如果结果为空，说明可能没有相关数据
)routersql_generationsql_regeneration
sql_reviewresult_reflectionfinal_answeru  你是一个船舶设备维修诊断系统的意图识别专家。你的任务是精准识别用户的核心诉求，将其分类为"维修"或"百科"。

### 📚 分类定义与判别标准

#### 1. 维修
- **核心特征**：用户描述了一个具体的**故障现象**、**异常状态**、**报警代码**，或者明确询问**解决方案**、**排查步骤**。
- **关键判定规则**：
    - **故障即维修**：只要用户陈述了一个设备故障现象（如"主机排烟温度高"），即使没有说"怎么修"，也默认归类为维修（隐含求助意图）。
    - **排查导向**：涉及"原因分析"、"处理措施"、"应急操作"的内容。
- **示例**：
    - "主机滑油压力低"（隐含：怎么办？）
    - "发电机启动失败，有报警E05"
    - "分油机震动大怎么处理"
    - "锅炉点火失败的原因"（针对具体故障的原因分析属于维修）

#### 2. 百科
- **核心特征**：用户询问**理论知识**、**设备原理**、**参数定义**、**结构组成**或**常规保养规范**，且不涉及当前的具体故障。
- **关键判定规则**：
    - **概念导向**：包含"什么是"、"原理"、"作用"、"结构"、"定义"等词汇。
    - **通用性**：问题适用于所有同类设备，而非针对某一台坏掉的设备。
- **示例**：
    - "柴油机的工作原理是什么"
    - "滑油分油机的结构图"
    - "什么是扫气箱着火"（询问定义）
    - "主机日常保养项目有哪些"

### ⚠️ 冲突处理原则
- 如果用户输入既像原理又像故障（例如"涡轮增压器喘振"），**优先归类为"维修"**，因为用户更可能是在遇到故障。
- 如果用户明确使用了"什么是"、"怎么定义"，归类为"百科"。

### 📤 输出格式
请仅输出一个标准的 JSON 对象，不要包含 markdown 标记或其他文本：
{
    "intent": "维修" 或 "百科",
    "reason": "简短的判断理由，指出触发分类的关键特征词或逻辑"
}u  你是一个信息提取专家，负责从用户输入中提取维修相关信息。

你需要提取以下信息：
1. 舷号：船舰编号，如"101","111","122"等
2. 设备名称：故障设备的名称
3. 故障现象：故障的具体表现
4. 故障码：报警代码或故障代码
5. 故障时间：故障发生的时间
6. 故障频率：故障发生的频率
7. 已尝试措施：用户已经尝试过的维修方法
8. 运行工况：设备运行时的参数
9. 其他信息：其他补充说明

提取规则：
- 如果某项信息没有提及，返回空字符串
- 优先使用当前输入中的信息
- 注意保留已有的信息，不要丢失

输出格式（JSON）：
{
    "ship_number": "舷号",
    "device_name": "设备名称",
    "fault": "故障现象",
    "fault_code": "故障码",
    "fault_time": "故障时间",
    "fault_frequency": "故障频率",
    "tried_measures": "已尝试措施",
    "running_condition": "运行工况",
    "additional_info": "其他信息"
}uI  你是一个专业的意图分析专家，用于船舶故障诊断系统。

根据对话历史和用户当前输入，判断用户的意图。

【意图分类说明】
1. generate_report: 用户明确要求生成、导出、下载、保存维修报告
   - 示例："生成报告"、"写报告"、"导出报告"、"下载报告"、"保存报告"

2. modify_info: 用户需要修改或补充之前提供的故障信息（舷号、设备名称、故障现象等）
   - 示例："其实是..."、"不对，应该是..."、"我补充一下..."、"修改设备名称是..."、"更正一下，故障是..."

3. has_error: 用户指出之前生成的维修方案有错误、需要修改或调整方案内容
   - 示例："方案有误"、"这个步骤不对"、"需要修改方案"、"这个方案有问题"

4. not_solved: 用户反映按照之前的方案执行后，故障问题依然没有解决，需要更深入的分析
   - 示例："没有解决"、"还是不行"、"问题依旧"、"还是没解决"、"按照方案做了但还是有问题"、"需要更深入的分析故障"、"需要详细的解决方案"

5. related_question: 用户询问与当前故障、设备、原理等相关的问题（非方案调整、非信息修改）
   - 示例："为什么会出现这个故障？"、"这个设备的工作原理是什么？"、"这个部件怎么更换？"、"执行方案时遇到问题：..."

6. other: 其他无法归类到上述类别的意图
   - 示例：打招呼、闲聊、与当前故障诊断无关的问题

输出格式（JSON）：
{"intent": "意图类型", "reason": "判断理由"}u   【当前故障诊断信息】
- 舷号: {ship_number}
- 设备名称: {device_name}
- 故障现象: {fault}

【对话历史】
{history_str}

【用户当前输入】
{combined_query}

请分析用户意图（JSON格式）：u-  从用户输入中提取缺失的信息。

缺失的信息类型: {missing_str}

用户输入: {user_query}

请提取用户补充的信息，输出JSON格式：
{{"ship_number": "舷号", "device_name": "设备名称", "fault": "故障现象"}}
如果某项信息没有提及，返回空字符串。uL  用户描述：
- 舷号: {ship_number}
- 设备名称: {device_name}
- 故障现象: {fault}
- 故障码: {fault_code}
- 故障时间: {fault_time}
- 故障频率: {fault_frequency}
- 已尝试措施: {tried_measures}
- 运行工况: {running_condition}
- 其他信息: {additional_info}

请给出一般性的故障诊断建议：u   用户描述：
- 舷号: {ship_number}
- 设备名称: {device_name}
- 故障现象: {fault}

请给出一般性的故障诊断建议：)classify_intent_systemextract_info_systemagent_think_intent_systemagent_think_intent_userask_user_extractgenerate_response_no_rag_user$generate_response_no_rag_simple_useru  你是一个船舶设备操作指导系统的意图识别专家。你的任务是精准识别用户的核心诉求，将其分类为"操作"或"百科"。

### 📚 分类定义与判别标准

#### 1. 操作
- **核心特征**：用户描述了一个具体的**操作需求**、**操作步骤**、**操作代码**，或者明确询问**操作方法**、**操作流程**。
- **关键判定规则**：
    - **操作即指导**：只要用户陈述了一个设备操作需求（如"主机启动操作"），即使没有说"怎么操作"，也默认归类为操作（隐含求助意图）。
    - **流程导向**：涉及"操作步骤"、"操作方法"、"操作规程"的内容。
- **示例**：
    - "主机启动操作步骤"（隐含：怎么做？）
    - "发电机并车操作流程"
    - "分油机操作方法"
    - "锅炉点火操作规程"

#### 2. 百科
- **核心特征**：用户询问**理论知识**、**设备原理**、**参数定义**、**结构组成**或**常规保养规范**，且不涉及当前的具体操作。
- **关键判定规则**：
    - **概念导向**：包含"什么是"、"原理"、"作用"、"结构"、"定义"等词汇。
    - **通用性**：问题适用于所有同类设备，而非针对某一项具体操作。
- **示例**：
    - "柴油机的工作原理是什么"
    - "滑油分油机的结构图"
    - "什么是扫气箱着火"（询问定义）
    - "主机日常保养项目有哪些"

### ⚠️ 冲突处理原则
- 如果用户输入既像原理又像操作（例如"涡轮增压器操作"），**优先归类为"操作"**，因为用户更可能是需要操作指导。
- 如果用户明确使用了"什么是"、"怎么定义"，归类为"百科"。

### 📤 输出格式
请仅输出一个标准的 JSON 对象，不要包含 markdown 标记或其他文本：
{
    "intent": "操作" 或 "百科",
    "reason": "简短的判断理由，指出触发分类的关键特征词或逻辑"
}u  你是一个信息提取专家，负责从用户输入中提取操作相关信息。

你需要提取以下信息：
1. 舷号：船舰编号，如"101","111","122"等
2. 设备名称：操作设备的名称
3. 操作项目：操作的具体内容
4. 操作代码：报警代码或操作代码
5. 操作时间：操作发生的时间
6. 操作频率：操作发生的频率
7. 已尝试措施：用户已经尝试过的操作方法
8. 运行工况：设备运行时的参数
9. 其他信息：其他补充说明

提取规则：
- 如果某项信息没有提及，返回空字符串
- 优先使用当前输入中的信息
- 注意保留已有的信息，不要丢失

输出格式（JSON）：
{
    "ship_number": "舷号",
    "device_name": "设备名称",
    "operation_item": "操作项目",
    "operation_code": "操作代码",
    "operation_time": "操作时间",
    "operation_frequency": "操作频率",
    "tried_measures": "已尝试措施",
    "running_condition": "运行工况",
    "additional_info": "其他信息"
}u  你是一个专业的意图分析专家，用于船舶操作指导系统。

根据对话历史和用户当前输入，判断用户的意图。

【意图分类说明】
1. modify_info: 用户需要修改或补充之前提供的操作信息（舷号、设备名称、操作项目等）
   - 示例："其实是..."、"不对，应该是..."、"我补充一下..."、"修改设备名称是..."、"更正一下，操作是..."

2. has_error: 用户指出之前生成的操作方案有错误、需要修改或调整方案内容
   - 示例："方案有误"、"这个步骤不对"、"需要修改方案"、"这个方案有问题"

3. not_solved: 用户反映按照之前的方案执行后，操作问题依然没有解决，需要更深入的分析
   - 示例："没有解决"、"还是不行"、"问题依旧"、"还是没解决"、"按照方案做了但还是有问题"、"需要更深入的分析"、"需要详细的解决方案"

4. related_question: 用户询问与当前操作、设备、原理等相关的问题（非方案调整、非信息修改）
   - 示例："为什么会出现这个操作问题？"、"这个设备的工作原理是什么？"、"这个部件怎么更换？"、"执行方案时遇到问题：..."

5. other: 其他无法归类到上述类别的意图
   - 示例：打招呼、闲聊、与当前操作指导无关的问题

输出格式（JSON）：
{"intent": "意图类型", "reason": "判断理由"}u   【当前操作指导信息】
- 舷号: {ship_number}
- 设备名称: {device_name}
- 操作项目: {operation_item}

【对话历史】
{history_str}

【用户当前输入】
{combined_query}

请分析用户意图（JSON格式）：u6  从用户输入中提取缺失的信息。

缺失的信息类型: {missing_str}

用户输入: {user_query}

请提取用户补充的信息，输出JSON格式：
{{"ship_number": "舷号", "device_name": "设备名称", "operation_item": "操作项目"}}
如果某项信息没有提及，返回空字符串。ud  用户描述：
- 舷号: {ship_number}
- 设备名称: {device_name}
- 操作项目: {operation_item}
- 操作代码: {operation_code}
- 操作时间: {operation_time}
- 操作频率: {operation_frequency}
- 已尝试措施: {tried_measures}
- 运行工况: {running_condition}
- 其他信息: {additional_info}

请给出一般性的操作指导建议：u   用户描述：
- 舷号: {ship_number}
- 设备名称: {device_name}
- 操作项目: {operation_item}

请给出一般性的操作指导建议：N)__doc__COMMON_PROMPTSBAIKE_PROMPTSSTATISTICS_PROMPTSTEXT2SQL_PROMPTSFAULT_DIAGNOSIS_PROMPTSOPERATE_PROMPTS     6e:\ZKYNLP\Hjunproject\project0506\aidoc_api\prompts.py<module>r9      sB  $G
 vG &	/Gf 	/iGR 	5UGl 	-oGR 	,UGl 	oGP (	GSGb &	eGt &	JwGF -	kIG\ "	_GV 	YGP %	/SGN ' 	sQG\ 		_G@	 	?C	Gt		2D 	z	5@ 	qKGh	{:	=<	98 	e	* 	e	EKp	*	*	*'	3Kn v	3&'	3^	34	3F	3B	CMy N#	V	J	G@	3&	A"	5&	5[t D#	V	J	G:	3&	A$	5&	5Wrr7   6xI
    ѱMj8"                         d Z ddddddddddddddddddddddddddddd	d
ddddddddddd
ZddddddddZ eej	                               Zy)u   
工作流注册表 - 主代理与 app 共用
主代理阶段四根据此配置路由到所有注册的子 agent；
app 据此执行对应工作流。
添加新工作流时，在此配置 WORKFLOW_CONFIG 与 ROUTE_DESCRIPTIONS。
z"workflows.workflow_fault_diagnosisrun_fault_diagnosis_workflowT)modulefunctionis_asynczworkflows.workflow_qarun_qa_workflowz)workflows.workflow_spare_parts_statistics#run_spare_parts_statistics_workflowzworkflows.workflow_baikerun_baike_workflowzworkflows.workflow_operaterun_operate_workflowzworkflows.workflow_statisticsrun_statistics_workflow)
fault_diagnosisqau   问题排查spare_parts_statisticsrulesotherreportu   百科问答u   操作使用u   统计u  
   - 特征：用户描述**当前或近期发生的设备异常、报警、性能下降等具体故障现象**，需要分析原因或定位问题。
   - 关键词：报警、异常、异响、冒烟、过热、无法启动、突然停机、振动大、压力低、温度高、故障代码、不工作
   - 示例：
     • 主机滑油压力突然降到0.2MPa并报警  
     • 柴油机启动后冒黑烟且转速不稳  
     • 舵机发出异常噪音，疑似齿轮损坏  
   - 注意：若历史记录中包含“请补充”、“【需要更多信息】”，通常属于此类，因已聚焦具体故障场景。
     当用户问题中只有舷号、设备或故障现象时属于此类，舷号一般为连续的阿拉伯数字如“101”,"111","122","163"，"16","17","554","602","545","985","31","3261","799","905","781"等,或者数字后加舰，比如“101舰","199舰","18舰"等。
  u  
   - 特征：询问定义、原理、结构、功能、分类、标准配置、常见类型、安全规范等**一般性知识**；也包括对专业术语、现象、部件作用的解释。  
     **即使问题表述模糊、不完整、缺少上下文，只要涉及船舶、机械、电气、动力等技术内容，均优先归为此类。**
   - 关键词：什么是、如何工作、为什么、请问、介绍、解释、有哪些、常见、典型、一般、作用、组成、是不是、叫什么
   - 示例：
     • 船舶主发动机有哪些常见故障类型？  
     • 涡轮增压器的工作原理是什么？  
     • 主机由哪些主要部件组成？  
     • 什么是MAN B&W柴油机？  
   - 注意：
     • **本类作为技术相关问题的默认兜底类别**——凡涉及设备、系统、部件、工况、参数等技术语境的问题，若无法明确归入 fault_diagnosis / repair / spare_parts_statistics / rules，则优先视为 qa。
  u  
   - 特征：用户明确请求**维修方法、操作步骤、检修流程、更换方案或现场处理建议**，通常在已知故障或需预防性维护时提出。
   - 关键词：怎么修、如何维修、维修步骤、检修方法、更换、拆卸、安装、处理、修复、维护、保养、调整
   - 示例：
     • 主机喷油器漏油，怎么更换？  
     • 给出主机缸套磨损的维修方案  
     • 如何拆卸增压器进行检修？
  u  
   - 特征：用户需要对**备品备件的数量、使用记录、库存、消耗趋势、预测需求或成本分析**进行查询或统计。
   - 关键词：备件、备品、库存、数量、统计、预测、分析、消耗、需求、清单、台账、寿命、更换周期、用了多少、还剩多少
   - 示例：
     • 统计过去一年主机喷油嘴的使用数量  
     • 预测下季度所需空冷器备件数量  
     • 主机活塞环的平均更换周期是多少？
   - 注意：若仅问“某个部件是不是备件”或“这个备件叫什么名字”，属于知识问答（qa），而非本类。
  uF  
   - 特征：用户询问与船舶设备维修、检验、安全、环保、保密等相关的**国家法规、军用标准（如GJB）、行业规范、船级社要求或管理制度**。
   - 关键词：法规、标准、规范、规定、合规、条例、依据、要求、准则、制度、认证、资质、船级社、CCS、IMO、SOLAS、MARPOL、资格
   - 示例：
     • 船舶主机修理需遵循哪些GJB标准？  
     • IMO对主机排放有哪些强制要求？  
     • 舰船维修单位需要哪些资质？  
     • 保密资格申请流程是什么？
   - 注意：若问题提到“标准里有没有…”但未指明具体法规/标准名称，且无“法规”“标准”等关键词，可先归为 qa；一旦明确提及“法规”“标准”“规范”“SOLAS”等，则归为 rules。
  u}  
  - 特征：**完全不涉及新的技术问题、故障诊断、维修请求、备件统计、法规查询或报告生成**，而是针对**已有对话内容、方案、步骤或文本的反馈、修正、补充、顺序调整或格式优化**。典型场景包括：
    • 指出之前提供的操作步骤有误（如“异物清理步骤有误”）
    • 要求调整操作顺序（如“这一步应当先怎样，然后再怎么操作，最后……”）
    • 对生成内容提出修改意见（如“步骤有误/有补充”“请重写第三点”）
    • 请求优化语言、格式或结构（如“请用更简洁的方式表达”）
    • 闲聊、非技术性确认或与当前技术任务无关的交互

  - 注意：
    • **只要用户意图是修正、补充或调整已有内容，而非提出新问题，即使涉及技术术语，也应归为 other**。
    • 不要将此类反馈误判为 repair 或 qa——它们不是在问“该怎么修”或“原理是什么”，而是在说“你刚才说的不对/不全”。
    • 此类通常出现在多轮对话中，是对前文输出的回应。
  u  
   - 特征：用户明确要求**生成、整理、导出或汇总**某种形式的文档、报表、清单或总结材料。通常涉及将分散的故障记录、维修历史、备件数据或问答内容整合成结构化文本（如日报、周报、故障分析报告、维修总结、备件消耗表等）。
   - 关键词：生成报告、写总结、导出表格、整理清单、汇总数据、形成文档、日报、周报、月报、分析报告、维修记录单、台账报表
   - 示例：
     • 请根据本周的故障记录生成一份主机系统运行分析报告
     • 总结这次对话
     • 导出过去一年的备件消耗统计报告
     • 帮我写一份关于此次主机停机事故的详细处理总结
  )r   r   repairr   r   r   r   N)__doc__WORKFLOW_CONFIGROUTE_DESCRIPTIONStuplekeysVALID_ROUTE_FLAGS     @e:\ZKYNLP\Hjunproject\project0506\aidoc_api\workflow_registry.py<module>r      s   & 72 *% 72 >9 *% 72 72 -( /* 2-k;~			GL \ /..01 r   9ux35# create_agents.py
import requests
import urllib3
from uuid import uuid4

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

BASE_URL = "http://192.168.0.46:22000"
AGENT_API = f"{BASE_URL}/api/v1/agents/"
HEADERS = {
    "Accept": "application/json",
    "Content-Type": "application/json",
}

TIMEOUT = 10
OUTPUT_FILE = "agent_ids.txt"

AGENT_META = {
    str(uuid4()): {
        "icon_index": 1,
        "name": "修理工程管理",
        "description": "对舰船修理工程实施全过程管理，包括任务分解、进度控制、工序协调和资源调配。",
        "prompt": "助理员您好，我是修理工程管理助手，我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。我可以为您提供舰船设备的标准修理内容范围、作业工序清单以及安全施工要求，请直接告诉我您需要查询的设备名称。",
        "default_query": [
            {"title": "查询设备标准  →", "content": "查询设备标准"},
            {"title": "查看作业工序  →", "content": "查看作业工序"}
        ],
    },
    str(uuid4()): {
        "icon_index": 2,
        "name": "器材统计与分析",
        "description": "对舰船维修保障过程中涉及的器材进行统计分析与趋势研判。",
        "prompt": "助理员您好，我是器材统计与分析助手。我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。为您提供多维度的器材消耗统计与库存分析服务。请告诉我您需要统计的具体业务场景。",
        "default_query": [
            {"title": "统计第一季度器材消耗  →", "content": "统计第一季度器材消耗"},
            {"title": "分析当前库存周转率  →", "content": "分析当前库存周转率"},
            {"title": "查看特定型号历史记录  →", "content": "查看特定型号历史记录"}
        ],
    },
    str(uuid4()): {
        "icon_index": 3,
        "name": "修理法规知识查询",
        "description": "提供舰船修理相关法规、标准和制度的查询与解读。",
        "prompt": "您好！我是修理法规知识查询助手。我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。请告诉我需要查询的主题。",
         "default_query": [
            {"title": "查询焊接工艺规程  →", "content": "查询焊接工艺规程"},
            {"title": "查看设备拆装安全规程  →", "content": "查看设备拆装安全规程"},
            {"title": "搜索环保作业规定  →", "content": "搜索环保作业规定"}
        ],
    },
    str(uuid4()): {
        "icon_index": 4,
        "name": "船舰知识查询",
        "description": "提供舰船结构、系统组成与功能原理等知识。",
        "prompt": "您好！我是舰船知识查询助手。我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。请告诉我需要了解的主题。",
        "default_query": [
            {"title": "了解舰船电力系统组成  →", "content": "了解舰船电力系统组成"},
            {"title": "查询舰船推进装置类型  →", "content": "查询舰船推进装置类型"},
            {"title": "搜索舰船雷达系统原理  →", "content": "搜索舰船雷达系统原理"}
        ],
    },
    str(uuid4()): {
        "icon_index": 5,
        "name": "故障排查与修理",
        "description": "辅助进行舰船设备故障分析、原因定位与修理方案制定。",
        "prompt": "您好！我是智能故障排查与修理助手。我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。提供舷号、设备名称和故障现象，我可以协助您进行复杂故障的研判诊断。",
        "default_query": [
            {"title": "多模态输出与校验  →", "content": "多模态输出与校验"},
            {"title": "诊断研判与可能性排序  →", "content": "诊断研判与可能性排序"},
            {"title": "GT-25000燃气轮机的日常维护保养方案  →", "content": "GT-25000燃气轮机的日常维护保养方案"}
        ],
    },
    str(uuid4()): {
        "icon_index": 6,
        "name": "舰船机电知识",
        "description": "提供舰船动力、电气、液压等机电系统相关知识。",
        "prompt": "机电长您好，我是舰船机电知识查询助手。我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。请告诉我需了解的主题。",
        "default_query": [
            {"title": "了解主推进系统构成  →", "content": "了解主推进系统构成"},
            {"title": "查看舰艇液压机参数  →", "content": "查看舰艇液压机参数"},
            {"title": "查看舰机液压系统参数  →", "content": "查看舰机液压系统参数"}
        ],
    },
    str(uuid4()): {
        "icon_index": 7,
        "name": "现场维修作业向导",
        "description": "为一线维修人员提供现场操作流程与安全指导。",
        "prompt": "您好！我是现场维修作业向导。我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。您可以询问具体的维修步骤、拆装工艺或查询安全操作规程。",
        "default_query": [
            {"title": "离心泵汽蚀的典型特征  →", "content": "离心泵汽蚀的典型特征"},
            {"title": "海水泵汽蚀的维修步骤  →", "content": "海水泵汽蚀的维修步骤"},
            {"title": "GT-25000燃气轮机的日常维护步骤  →", "content": "GT-25000燃气轮机的日常维护步骤"}
        ],
    },
    str(uuid4()): {
        "icon_index": 8,
        "name": "舰船技术知识百科",
        "description": "综合性舰船技术知识库。",
        "prompt": "您好，我是舰船技术知识百科助手。我已经绑定了技术资料、通用知识、故障知识、法规标准知识库。请告诉我您需要查询的技术主题。",
        "default_query": [
            {"title": "了解船体高强钢性能  →", "content": "了解船体高强钢性能"},
            {"title": "查询焊接工艺评定标准  →", "content": "查询焊接工艺评定标准"},
            {"title": "查看防腐涂装技术规范  →", "content": "查看防腐涂装技术规范"}
        ],
    },
}


def build_agent_json(agent_id: str) -> dict:
    meta = AGENT_META[agent_id]
    return {
        "id": agent_id,
        "name": meta["name"],
        "description": meta["description"],
        "prompt": meta["prompt"],
        "background": "string",
        "access_control": {},
        "default_query": meta["default_query"],
    }


def create_agent(agent_id: str) -> bool:
    resp = requests.post(
        AGENT_API,
        headers=HEADERS,
        json=build_agent_json(agent_id),
        verify=False,
        timeout=TIMEOUT,
    )
    print(resp.json())
    print(f"[CREATE] {agent_id} -> {resp.status_code}")

    return resp.status_code in (200, 201, 409)


def main():
    created_ids = []

    for agent_id in AGENT_META.keys():
        if create_agent(agent_id):
            created_ids.append(agent_id)

    with open(OUTPUT_FILE, "w", encoding="utf-8") as f:
        for aid in created_ids:
            f.write(aid + "\n")

    print(f"\n✅ 已写入 {len(created_ids)} 个 Agent UUID 到 {OUTPUT_FILE}")


if __name__ == "__main__":
    main()




# import requests
# import urllib3
# from uuid import uuid4
# from typing import List, Tuple

# # =========================
# # 0. 关闭 HTTPS 警告（开发环境）
# # =========================
# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# # =========================
# # 1. 基础配置
# # =========================

# BASE_URL = "https://devb.zdht.hjkl01.cn:65432"

# AGENT_API = f"{BASE_URL}/api/v1/agents/"
# ROLE_BIND_API = f"{BASE_URL}/api/v1/agent-roles/association"

# HEADERS = {
#     "Accept": "application/json",
#     "Content-Type": "application/json",
# }

# TIMEOUT = 10

# # =========================
# # 2. 角色 ID（数据库真实存在）
# # =========================

# AGENT_ROLE_1 = "2"  # 助理员助手 (1-4)
# AGENT_ROLE_2 = "3"  # 机电长助手 (5-6)
# AGENT_ROLE_3 = "4"  # 维修员助手 (7-8)

# ROLE_NAME_MAP = {
#     AGENT_ROLE_1: "助理员助手",
#     AGENT_ROLE_2: "机电长助手",
#     AGENT_ROLE_3: "维修员助手",
# }

# # =========================
# # 3. Agent 元数据
# # =========================

# AGENT_META = {
#     str(uuid4()): {
#         "icon_index": 1,
#         "name": "修理工程管理",
#         "description": "对舰船修理工程实施全过程管理，包括任务分解、进度控制、工序协调和资源调配。",
#         "prompt": "您好！我是一名舰船修理工程管理专家。",
#     },
#     str(uuid4()): {
#         "icon_index": 2,
#         "name": "器材统计与分析",
#         "description": "对舰船维修保障过程中涉及的器材进行统计分析与趋势研判。",
#         "prompt": "您好！我是一名舰船器材统计与分析专家。",
#     },
#     str(uuid4()): {
#         "icon_index": 3,
#         "name": "修理法规知识查询",
#         "description": "提供舰船修理相关法规、标准和制度的查询与解读。",
#         "prompt": "您好！我是一名舰船修理法规专家。",
#     },
#     str(uuid4()): {
#         "icon_index": 4,
#         "name": "船舰知识查询",
#         "description": "提供舰船结构、系统组成与功能原理等知识。",
#         "prompt": "您好！我是一名舰船专业知识顾问。",
#     },
#     str(uuid4()): {
#         "icon_index": 5,
#         "name": "故障排查与修理",
#         "description": "辅助进行舰船设备故障分析、原因定位与修理方案制定。",
#         "prompt": "您好！我是一名舰船设备故障诊断专家。",
#     },
#     str(uuid4()): {
#         "icon_index": 6,
#         "name": "舰船机电知识",
#         "description": "提供舰船动力、电气、液压等机电系统相关知识。",
#         "prompt": "您好！我是一名舰船机电系统专家。",
#     },
#     str(uuid4()): {
#         "icon_index": 7,
#         "name": "现场维修作业向导",
#         "description": "为一线维修人员提供现场操作流程与安全指导。",
#         "prompt": "您好！我是一名现场维修作业向导。",
#     },
#     str(uuid4()): {
#         "icon_index": 8,
#         "name": "舰船技术知识百科",
#         "description": "综合性舰船技术知识库。",
#         "prompt": "您好！我是一部舰船技术知识百科。",
#     },
# }

# # =========================
# # 4. 构建 Agent JSON
# # =========================

# def build_agent_json(agent_id: str) -> dict:
#     meta = AGENT_META[agent_id]
#     return {
#         "id": agent_id,
#         "name": meta["name"],
#         "description": meta["description"],
#         "prompt": meta["prompt"],
#         "background": "string",
#         "access_control": {},
#     }

# # =========================
# # 5. 创建 Agent
# # =========================

# def create_agent(agent_id: str) -> bool:
#     resp = requests.post(
#         AGENT_API,
#         headers=HEADERS,
#         json=build_agent_json(agent_id),
#         verify=False,
#         timeout=TIMEOUT,
#     )

#     print(f"[CREATE] Agent {agent_id} -> {resp.status_code}")

#     if resp.status_code in (200, 201, 409):
#         return True

#     print("  ↳ 返回值:", resp.text)
#     return False

# # =========================
# # 6. 绑定 Agent 到角色
# # =========================

# def bind_agent_to_role(agent_id: str, role_id: str) -> bool:
#     payload = [
#         {
#             "agent_id": agent_id,
#             "agent_role_id": role_id,
#             "is_active": True,
#         }
#     ]

#     resp = requests.post(
#         ROLE_BIND_API,
#         headers=HEADERS,
#         json=payload,
#         verify=False,
#         timeout=TIMEOUT,
#     )

#     print(
#         f"[BIND] Agent {agent_id} -> Role {role_id} "
#         f"({ROLE_NAME_MAP.get(role_id)}) => {resp.status_code}"
#     )

#     if resp.status_code in (200, 201):
#         return True

#     print("  ↳ 返回值:", resp.text)
#     return False

# # =========================
# # 7. 主流程（先创建 → 再统一绑定）
# # =========================

# def main():
#     pending_bindings: List[Tuple[str, str]] = []

#     print("=== 开始创建 Agent ===")

#     for agent_id, meta in AGENT_META.items():
#         try:
#             if not create_agent(agent_id):
#                 continue

#             idx = meta["icon_index"]

#             if 1 <= idx <= 4:
#                 role_id = AGENT_ROLE_1
#             elif 5 <= idx <= 6:
#                 role_id = AGENT_ROLE_2
#             elif 7 <= idx <= 8:
#                 role_id = AGENT_ROLE_3
#             else:
#                 continue

#             pending_bindings.append((agent_id, role_id))

#         except Exception as e:
#             print(f"[ERROR] Agent {agent_id} -> {e}")

#     print("\n=== 开始统一绑定角色 ===")

#     for agent_id, role_id in pending_bindings:
#         bind_agent_to_role(agent_id, role_id)

#     print("\n=== 全部完成 ===")

# # =========================
# # 8. 入口
# # =========================

# if __name__ == "__main__":
#     main()
Dx(17cb4f33-f84d-473a-9299-d8138e8ea9d6
a8352abb-900d-468a-97b1-ac93f012ccb2
f6363563-fd44-4c11-aa24-d2d97abbaa96
2fc6a72e-69a9-497e-b7f4-12cd6833c781
16c1320c-444a-4fb7-9e2e-34748f16d361
c742915b-4bf1-47e3-b64f-903a4ce60de8
6089a40f-a1b3-4514-a229-25bc8f42789e
9cc84831-747e-4cdf-b941-736dcdc9514c
K x$# # bind_agents.py
# import requests
# import urllib3

# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# BASE_URL = "https://devb.zdht.hjkl01.cn:65432"
# ROLE_BIND_API = f"{BASE_URL}/api/v1/agent-roles/association"

# HEADERS = {
#     "Accept": "application/json",
#     "Content-Type": "application/json",
# }

# TIMEOUT = 10
# INPUT_FILE = "agent_ids.txt"

# # 角色 ID
# AGENT_ROLE_0 = "1"  # 1-8
# AGENT_ROLE_1 = "2"  # 1-4
# AGENT_ROLE_2 = "3"  # 5-6
# AGENT_ROLE_3 = "4"  # 7-8


# def calc_role_id_by_index(index: int) -> str:
#     if 1 <= index <= 4:
#         return AGENT_ROLE_1
#     elif 5 <= index <= 6:
#         return AGENT_ROLE_2
#     elif 7 <= index <= 8:
#         return AGENT_ROLE_3
#     else:
#         raise ValueError("非法 icon_index")


# def bind_agent(agent_id: str, role_id: str):
#     payload = [
#         {
#             "agent_id": agent_id,
#             "agent_role_id": role_id,
#             "is_active": True,
#         }
#     ]

#     resp = requests.post(
#         ROLE_BIND_API,
#         headers=HEADERS,
#         json=payload,
#         verify=False,
#         timeout=TIMEOUT,
#     )

#     print(f"[BIND] {agent_id} -> role {role_id} => {resp.status_code}")
#     if resp.status_code not in (200, 201):
#         print("  ↳", resp.text)


# def main():
#     with open(INPUT_FILE, "r", encoding="utf-8") as f:
#         agent_ids = [line.strip() for line in f if line.strip()]

#     print(f"=== 读取到 {len(agent_ids)} 个 Agent ===")

#     for idx, agent_id in enumerate(agent_ids, start=1):
#         role_id = calc_role_id_by_index(idx)
#         bind_agent(agent_id, role_id)

#     print("\n✅ 绑定完成")


# if __name__ == "__main__":
#     main()







import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

BASE_URL = "http://192.168.0.46:22000"
ROLE_BIND_API = f"{BASE_URL}/api/v1/agent-roles/association"
HEADERS = {
    "Accept": "application/json",
    "Content-Type": "application/json",
}

TIMEOUT = 10
INPUT_FILE = "agent_ids.txt"

# 角色 ID
AGENT_ROLE_0 = "1"  # 所有 Agent 必绑
AGENT_ROLE_1 = "2"  # 1-4
AGENT_ROLE_2 = "3"  # 5-6
AGENT_ROLE_3 = "4"  # 7-8


def calc_role_id_by_index(index: int) -> str:
    if 1 <= index <= 4:
        return AGENT_ROLE_1
    elif 5 <= index <= 6:
        return AGENT_ROLE_2
    elif 7 <= index <= 8:
        return AGENT_ROLE_3
    else:
        raise ValueError("非法 index")


def bind_agent(agent_id: str, role_id: str):
    payload = [
        {
            "agent_id": agent_id,
            "agent_role_id": role_id,
            "is_active": True,
        }
    ]

    resp = requests.post(
        ROLE_BIND_API,
        headers=HEADERS,
        json=payload,
        verify=False,
        timeout=TIMEOUT,
    )

    print(f"[BIND] {agent_id} -> role {role_id} => {resp.status_code}")
    if resp.status_code not in (200, 201):
        print("  ↳", resp.text)


def main():
    with open(INPUT_FILE, "r", encoding="utf-8") as f:
        agent_ids = [line.strip() for line in f if line.strip()]

    print(f"=== 读取到 {len(agent_ids)} 个 Agent ===")

    for idx, agent_id in enumerate(agent_ids, start=1):
        # 1️⃣ 所有 Agent 统一绑定角色 1
        bind_agent(agent_id, AGENT_ROLE_0)

        # 2️⃣ 再绑定分组角色
        group_role = calc_role_id_by_index(idx)

        # 防止重复绑定
        if group_role != AGENT_ROLE_0:
            bind_agent(agent_id, group_role)

    print("\n✅ 绑定完成（角色 1 + 分组角色）")


if __name__ == "__main__":
    main()
&Joximport asyncio
import re
import sys
from typing import Optional, List, Set,Iterable

if sys.platform.startswith("win") and hasattr(asyncio, "WindowsSelectorEventLoopPolicy"):
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

import ahocorasick
from pydantic import BaseModel, Field, model_validator
from fastapi import FastAPI, File, Path, UploadFile, HTTPException, Form, Request, Header, Body, BackgroundTasks
from fastapi.responses import StreamingResponse
try:
    from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
except ImportError:
    from langchain.prompts import FewShotPromptTemplate, PromptTemplate
from openai.types.chat import ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam, ChatCompletionMessageParam
from chunk_text import get_chunk_bbox, split_text_preserve_sentences, data_replace, chunk_check,merge_short_slices,find_and_read_content_list,process_pdf_file,process_other_file
from fastapi.responses import JSONResponse, StreamingResponse
import requests
from pathlib import PurePath, Path as PathLib
import tempfile

from modelsAPI import model_api
from documents_prompt import (
    BEAUTIFY_TYPE_DICT,
    TEMPLATE_DICT,
    GENERATE_NORMAL_OUTLINE_PROMPT,
    GENERATE_MARKDOWN_LIST_OUTLINE_PROMPT,
    GENERATE_METHOD_OUTLINE_PROMPT,
)
"""app.py
FastAPI 主 Agent 接口 - 修复重复执行问题
提供主脑 Agent 的 HTTP API 服务，支持流式输出
集成 LangGraph Checkpointer 实现状态持久化
"""
import logging
from time import sleep
import aiofiles

from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse, FileResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from typing import Optional, Dict, Any, AsyncGenerator,List
import uvicorn
import json
import os
import uuid
from main_agent import create_main_agent
from utils.function_tracker import (
    register_event_callback,
    create_stream_event_handler,
    unregister_event_callback,
    clear_current_stream_handler
)
import asyncio
import importlib
from doc2pdf import Doc2PDF

from workflow_registry import WORKFLOW_CONFIG, VALID_ROUTE_FLAGS
from main_agent import extract_conversation_title
from workflows.history_manager import filter_image_urls, preprocess_from_request
from config import set_request_user_config
from checkpointer_config import (
    CheckpointerManager,
    checkpointer_manager
)
app = FastAPI(max_request_size=1024 * 1024 * 10)

converter = Doc2PDF()
DATA_DIR = "/app/files"
load_dotenv()

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# app.mount("/picture", StaticFiles(directory="/app/picture"), name="pictures")


@app.on_event("startup")
async def startup_event():
    """应用启动时初始化"""
    await checkpointer_manager.setup()
    # 初始化智能体使用统计表
    from tools.agent_usage_statistics import init_agent_usage_table
    await init_agent_usage_table()
    logger.info("应用启动完成，PostgreSQL Checkpointer 已配置")


# =============== PDF 文件目录配置 ===============
# 创建 PDF 文件目录（用于存储生成的 PDF 等文件）
PDF_DIR = os.path.join(os.path.dirname(__file__), "created_pdf")
# 创建 word 文件目录（用于存储生成的 word 等文件）
WORD_DIR = os.path.join(os.path.dirname(__file__), "created_word")
os.makedirs(PDF_DIR, exist_ok=True)

class RewriteRequest(BaseModel):
    rewrite_type: Optional[str] = None
    content: Optional[str] = None
    require: Optional[str] = None
    sentence: Optional[str] = None


REWRITE_TYPE_MAP = {
    "quotePolish": "金句润色",
    "formalStyle": "书面化",
    "speechStyle": "讲稿化",
    "formatting": "规整",
    "expand": "扩写",
    "continueWriting": "续写",
    "report": "汇报",
    "quote": "金句",
    "summarize": "精简",
    "condense": "总结",
}


def build_rewrite_prompt(request: RewriteRequest) -> str:
    beautify_type = REWRITE_TYPE_MAP.get(request.rewrite_type or "")
    if not beautify_type:
        raise HTTPException(status_code=400, detail=f"不支持的 rewrite_type: {request.rewrite_type}")

    prompt_template = BEAUTIFY_TYPE_DICT.get(beautify_type)
    if not prompt_template:
        raise HTTPException(status_code=400, detail=f"未找到提示词模板: {beautify_type}")

    return prompt_template.format(
        require=request.require or "",
        content=request.content or "",
        sentence=request.sentence or request.content or "",
    )


async def stream_llm_content(prompt: str):
    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        query=prompt,
        model=None,
        system_prompt="你是专业文稿改写助手，根据要求进行文本改写。",
        messages=[],
    ):
        if chunk:
            yield chunk


@app.post("/Rewrite")
async def rewrite(request: RewriteRequest):
    prompt = build_rewrite_prompt(request)

    return StreamingResponse(
        stream_llm_content(prompt),
        media_type="text/plain; charset=utf-8",
    )


class WriteRequest(BaseModel):
    role: Optional[str] = None
    template: Optional[str] = None
    title: Optional[str] = None
    length: Optional[str] = None
    requirement: Optional[str] = None
    references: Optional[str] = None
    outline: Optional[str] = None
    konwlege: Optional[str] = None
    prompt: Optional[str] = None


class OutlineRequest(BaseModel):
    role: Optional[str] = None
    template: Optional[str] = None
    title: Optional[str] = None
    length: Optional[str] = None
    requirement: Optional[str] = None
    references: Optional[str] = None
    konwlege: Optional[str] = None
    prompt: Optional[str] = None


def length_convert(length: Optional[str]) -> str:
    if length == "短":
        return "1000字"
    if length == "中":
        return "1000-2000字"
    if length == "长":
        return "2000-5000字"
    return length or ""


def build_write_prompt(request: WriteRequest) -> str:
    if request.prompt and request.prompt.strip():
        return request.prompt.strip()

    template = request.template or ""
    prompt_template = TEMPLATE_DICT.get(template)
    if not prompt_template:
        raise HTTPException(status_code=400, detail=f"不支持的写作模板: {template}")

    title = request.title or ""
    if not title.strip():
        raise HTTPException(status_code=400, detail="title不能为空")

    return prompt_template.format(
        role=request.role or "",
        title=title,
        length=length_convert(request.length),
        requirement=request.requirement or "",
        references=request.references or "",
        outline=request.outline or "",
    )


async def stream_write_content(prompt: str):
    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        query=prompt,
        model=None,
        system_prompt="你是专业公文写作助手，请直接输出正文内容。",
        messages=[],
    ):
        if chunk:
            yield chunk


@app.post("/Write")
async def write(request: WriteRequest):
    prompt = build_write_prompt(request)

    return StreamingResponse(
        stream_write_content(prompt),
        media_type="text/plain; charset=utf-8",
    )


def build_outline_prompt(request: OutlineRequest) -> str:
    if request.prompt and request.prompt.strip():
        return request.prompt.strip()

    template = request.template or ""
    title = request.title or ""
    if not title.strip():
        raise HTTPException(status_code=400, detail="title不能为空")

    markdown_list_template = {"报告", "函", "文书", "工作总结"}
    prompt_template = GENERATE_NORMAL_OUTLINE_PROMPT

    if template == "方案":
        prompt_template = GENERATE_METHOD_OUTLINE_PROMPT
    elif template in markdown_list_template:
        prompt_template = GENERATE_MARKDOWN_LIST_OUTLINE_PROMPT

    return prompt_template.format(
        role=request.role or "",
        template=template,
        title=title,
        length=length_convert(request.length),
        requirement=request.requirement or "",
        references=request.references or "",
    )


async def stream_outline_content(prompt: str):
    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        query=prompt,
        model=None,
        system_prompt="你是专业公文提纲生成助手，请直接输出提纲内容。",
        messages=[],
    ):
        if chunk:
            yield chunk


@app.post("/Outline")
async def outline(request: OutlineRequest):
    prompt = build_outline_prompt(request)

    return StreamingResponse(
        stream_outline_content(prompt),
        media_type="text/plain; charset=utf-8",
    )


class ReviewRequest(BaseModel):
    require: Optional[str] = Field(None, description="额外校对要求")
    content: str = Field(..., description="待校对文本")
    types: List[str] = Field(..., description="检查类型")
    sensitive_words: List[str] = Field(default_factory=list, description="敏感词汇")
    negative_words: List[str] = Field(default_factory=list, description="错误词汇")
    positive_words: List[str] = Field(default_factory=list, description="正词词汇")

    @model_validator(mode="after")
    def check_content(self):
        if not self.content or not self.content.strip():
            raise ValueError("content不能为空")
        return self


class ReviewItem(BaseModel):
    original: str
    error: str
    suggestion: str


class ReviewResponse(BaseModel):
    data: List[ReviewItem]


def normalize_words(words: List[str]) -> Set[str]:
    return {word.strip() for word in words if word and word.strip()}


def find_keywords(text: str, keyword_set: Set[str]) -> List[str]:
    if not text or not keyword_set:
        return []

    automaton = ahocorasick.Automaton()

    for idx, keyword in enumerate(keyword_set):
        automaton.add_word(keyword, (idx, keyword))

    automaton.make_automaton()

    found = set()
    for _, (_, keyword) in automaton.iter(text):
        found.add(keyword)

    return list(found)


def append_dictionary_results(
    items: List[dict],
    content: str,
    sensitive_words: Set[str],
    negative_words: Set[str],
) -> List[dict]:
    for word in find_keywords(content, sensitive_words):
        items.append({
            "original": word,
            "error": "敏感词汇",
            "suggestion": "",
        })

    for word in find_keywords(content, negative_words):
        items.append({
            "original": word,
            "error": "错误词汇",
            "suggestion": "",
        })

    return items


def filter_positive_word_false_positives(
    items: List[dict],
    positive_words: Set[str],
) -> List[dict]:
    if not positive_words:
        return items

    result = []

    for item in items:
        original = str(item.get("original", ""))
        error = str(item.get("error", ""))

        has_positive_word = any(word in original for word in positive_words)
        is_typo_error = (
            "错别字" in error
            or "错别词" in error
            or "错别词语" in error
        )

        if has_positive_word and is_typo_error:
            continue

        result.append(item)

    return result


def dedupe_and_filter(items: List[dict], source_text: str) -> List[dict]:
    seen = set()
    result = []

    for item in items:
        original = str(item.get("original", "")).strip()
        error = str(item.get("error", "")).strip()
        suggestion = str(item.get("suggestion", "")).strip()

        if not original:
            continue

        if original == suggestion:
            continue

        if original not in source_text:
            continue

        key = (original, error, suggestion)
        if key in seen:
            continue

        seen.add(key)
        result.append({
            "original": original,
            "error": error,
            "suggestion": suggestion,
        })

    return result

def cotprompt(query):
    conten1 = """
    人工智能正在深刻改变现,代教育的方式。通过智能教学系统【】AI可以根据学生的学习习惯和掌握情况，提供个性化的学习内容和节奏学习内容和节奏，提高学习效率。同时，AI还能辅助教师进行作业批改、学习分析，甚至参与课堂互动，减轻教师的重复工作压力。
    虚拟助教、智能语音识别、自动文达系统等技术，也让远程教育更加高效和便捷。更加高效和便捷。随着AI技术的发展，教育不再局限于固定的教材和课堂，而是变得更加开放、灵活和智能化------让每个雪生都能获得更适合自己的学习体验。人工智能不仅是工具，更是推动教育公平和质量提升的重要力量。
    """
    reasoning1 = """
    "深刻改变现,代教育中"多了","，修改为“深刻改变现代教育中”；“智能教学系统【】”中存在错误符号“【】”，修改为“智能教学系统”；“提供个性化的学习内容和节奏学习内容和节奏”存在重复内容，修改为"提供个性化的学习内容和节奏"；"自动文达系统"存在错误词语"文达"，修改为”自动问答系统“；”而是变得更加开放、灵活和智能化------“
    中存在错误符号“------”，修改为“而是变得更加开放、灵活和智能化，”；“每个雪生”中存在错别字“雪生”，修改为“每个学生”；检查完上述错误之后，正确的文本内容应该是：人工智能正在深刻改变现代教育的方式。通过智能教学系统，AI可以根据学生的学习习惯和掌握情况，提供个性化的学习内容和节奏，提高学习效率。同时，AI还能辅助教师进行作业批改、学习分析，甚至参与课堂互动，减轻教师的重复工作压力。虚拟助教、智能语音识别、自动问答系统等技术，也让远程教育更加高效和便捷。
    随着AI技术的发展，教育不再局限于固定的教材和课堂，而是变得更加开放、灵活和智能化，让每个学生都能获得更适合自己的学习体验。人工智能不仅是工具，更是推动教育公平和质量提升的重要力量。
    """
    ques = f"""
    文本内容为{conten1},对给出的文本内容进行逻辑校对、基础校对和合规性检查，逻辑校对检测文本逻辑连贯性，基础校对检查文本中错别字、错误标点符号和重复内容。
    校对文本之后，如果你发现没有任何错误，不需要返回其他内容，只需要返回：
    ###\n###
    发现错误时返回：
    ###\n错误：错别字、标点不规范\n原文：星光店电；万里乌云\n建议：星光点点，万里无云
       \n错误：错别词语、标点不规范\n原文：请注丰收与团圆。\n建议：庆祝丰收与团圆。
       \n错误：标点不规范\n原文：你好；明天\n建议：你好，明天
       \n错误：重复内容\n原文：我听说你心情很不错不错。你心情很不错不错。\n建议：我听说你心情很不错。###
    """

    conten2 = """
    关于近期工作安排的通知
    各位同事，
    京公司研九决定，现将近期工作安排通知通知如下：
    一、项目推进方面。各部门需加快项目进度，确保按时交付。如有问题，及时与相关领导沟通解决。项目负责人要切实履行职责，加强团队协作，提高工作效率。
    二、培训学习方面：公司将组织系列培训课程，提升员工专业技能。具体时间、地点另行通知。员工需按时参加，不得无辜缺席。自即日起，严禁在工作时间从事与工作无关的活动。
    二、纪律要求。近期发现部分员工上班时间做与工作无关的事情，如炒股、聊天等，严重影响工作效率和公司形象。自即日起，严禁在工作时间从事与工作无关的活动。违反规定者，将按照公司规章制度严肃处理。
    特此通知：
    [公司名称]
    [日期]
    """
    reasoning2 = """
    "京公司研九决定"中存在错别字和词语“京”、“研九”，修改为“经公司研究决定”；“工作安排通知通知”存在重复内容，修改为“工作安排通知”；“一、项目推进方面。”存在错误标点符号，参与后续内容中“二、培训学习方面：”，因此“一、项目推进方面”之后应当使用“：”，修改为“一、项目推进方面：”；“无辜缺席。”中存在错别字“辜”，修改为“无故缺席”；
    “二、纪律要求。”存在错别字、标点不规范，纪律要求应该是第三点，应该使用”：“，修改为“三、纪律要求：”；”特此通知：“中存在标点不规范，应该修改为”特此通知。“检查完上述错误之后，正确的文本内容应该是：关于近期工作安排的通知
    各位同事，
    经公司研究决定，现将近期工作安排通知如下：
    一、项目推进方面：各部门需加快项目进度，确保按时交付。如有问题，及时与相关领导沟通解决。项目负责人要切实履行职责，加强团队协作，提高工作效率。
    二、培训学习方面：公司将组织系列培训课程，提升员工专业技能。具体时间、地点另行通知。员工需按时参加，不得无故缺席。自即日起，严禁在工作时间从事与工作无关的活动。
    三、纪律要求：近期发现部分员工上班时间做与工作无关的事情，如炒股、聊天等，严重影响工作效率和公司形象。自即日起，严禁在工作时间从事与工作无关的活动。违反规定者，将按照公司规章制度严肃处理。
    特此通知。
    [公司名称]
    [日期]
    """

    ques2 = f"""
    文本内容为{conten2},对给出的文本内容进行逻辑校对、基础校对和合规性检查，逻辑校对检测文本逻辑连贯性，基础校对检查文本中错别字、错误标点符号和重复内容。
    校对文本之后，如果你发现没有任何错误，不需要返回其他内容，只需要返回：
    ###\n###
    发现错误时返回：
    ###\n错误：错别字、标点不规范\n原文：星光店电；万里乌云\n建议：星光点点，万里无云
       \n错误：错别词语、标点不规范\n原文：请注丰收与团圆。\n建议：庆祝丰收与团圆。
       \n错误：标点不规范\n原文：你好；明天\n建议：你好，明天
       \n错误：重复内容\n原文：我听说你心情很不错不错。你心情很不错不错。\n建议：我听说你心情很不错。###
    """

    conten3 = """
    《水声目标识别》课程教学计划

    一、课程名称
    水声目标识别，该课程式用于海洋科学、水声工程、电子信息等专业本科生asfqfqfqwfwqf、研究生，以及军事院校学员、相关领域科研人员和企业技术人员技术人员。

    三、计划学时
    2026学年，总学时：48学时（理论授课32学时，实作授课16学时）

    三、授课时间
    每周4学时，共12周完成
    四、教学目标
    1. 知识目标
       使学生掌握水声目标识别的几本原理】方法和技术，包括声纳信号的特性、目标特征提取、分类与识别算法等。
       了解水声目标识别在军事（如潜艇作战、反潜作战等）和民用（如海洋资源勘探、水下考古等）领域的应用。
       熟悉水声目标识别系统的基本组成和工作原理，
    2. 能力目标
       培养学生运用所学知识对水声信号进行分析处理、特征提取和目标识别的能力。
       提高学生运用专业软件（如MATLAB等）进行水声水声信号处理和目标识别仿真的能力。
       增强学生解决实际水声目标识别问题的实践能力和创新思维。
    3. 素质目标
       培养学生严谨的科学态度和扎实的专业素养，使其剧备良好的团队协作精神和沟通能力。
       激发学生对水声技术领域的学习兴趣和探索精神，培养其自主学习和终身学习的意识。
    """

    ques3 = f"""
    文本内容为{conten3},对给出的文本内容进行逻辑校对、基础校对和合规性检查，逻辑校对检测文本逻辑连贯性，基础校对检查文本中错别字、错误标点符号和重复内容。
    校对文本之后，如果你发现没有任何错误，不需要返回其他内容，只需要返回：
    ###\n###
    发现错误时返回：
    ###\n错误：错别字、标点不规范\n原文：星光店电；万里乌云\n建议：星光点点，万里无云
       \n错误：错别词语、标点不规范\n原文：请注丰收与团圆。\n建议：庆祝丰收与团圆。
       \n错误：标点不规范\n原文：你好；明天\n建议：你好，明天
       \n错误：重复内容\n原文：我听说你心情很不错不错。你心情很不错不错。\n建议：我听说你心情很不错。###
    """
    reasoning3 = """
    "式用"中存在错别字“式”，修改为：“适用”；“本科生asfqfqfqwfwqf、”中存在错别字和符号“asfqfqfqwfwqf”，修改为：“本科生、”；“三、计划学时”存在错别字使用不当，修改为：“二、计划学时”；
    “几本原理】”存在错别字、标点不规范，应该修改为：“基本原理”；“工作原理，”存在标点不规范，应该修改为：“工作原理。”；“水声水声信号”中存在重复内容“水声”，应该修改为“水声信号”；
    “剧备”存在错别字“剧”，应该修改为：”具备“。检查完上述错误之后，正确的文本内容应该是：
    《水声目标识别》课程教学计划

    一、课程名称
    水声目标识别，该课程式用于海洋科学、水声工程、电子信息等专业本科生、研究生，以及军事院校学员、相关领域科研人员和企业技术人员。

    三、计划学时
    2026学年，总学时：48学时（理论授课32学时，实作授课16学时）

    三、授课时间
    每周4学时，共12周完成
    四、教学目标
    1. 知识目标
       使学生掌握水声目标识别的基本原理、方法和技术，包括声纳信号的特性、目标特征提取、分类与识别算法等。
       了解水声目标识别在军事（如潜艇作战、反潜作战等）和民用（如海洋资源勘探、水下考古等）领域的应用。
       熟悉水声目标识别系统的基本组成和工作原理。
    2. 能力目标
       培养学生运用所学知识对水声信号进行分析处理、特征提取和目标识别的能力。
       提高学生运用专业软件（如MATLAB等）进行水声信号处理和目标识别仿真的能力。
       增强学生解决实际水声目标识别问题的实践能力和创新思维。
    3. 素质目标
       培养学生严谨的科学态度和扎实的专业素养，使其具备良好的团队协作精神和沟通能力。
       激发学生对水声技术领域的学习兴趣和探索精神，培养其自主学习和终身学习的意识。
    """

    # 定义 Few-Shot CoT 示例
    examples = [
        {
            "question": ques,
            "reasoning": reasoning1,
            "answer": """
                    \n错误：标点不规范\n原文：现,代教育\n建议：现代教育
                    \n错误：标点不规范\n原文：智能教学系统【】\n建议：智能教学系统
                    \n错误：重复内容\n原文：提供个性化的学习内容和节奏学习内容和节奏\n建议：提供个性化的学习内容和节奏
                    \n错误：错别字、错别词语\n原文：自动文达系统\n建议：自动问答系统
                    \n错误：标点不规范\n原文：而是变得更加开放、灵活和智能化------\n建议：而是变得更加开放、灵活和智能化，
                    \n错误：错别字、错别词语\n原文：每个雪生\n建议：每个学生
            """
        },
        {
            "question": ques2,
            "reasoning": reasoning2,
            "answer": """
                    \n错误：错别字、错别词语\n原文：京公司研九决定\n建议：经公司研究决定
                    \n错误：重复内容\n原文：工作安排通知通知\n建议：工作安排通知
                    \n错误：错别字、错别词语\n原文：无辜缺席。\n建议：无故缺席
                    \n错误：错别字、标点不规范\n原文：二、纪律要求。\n建议：三、纪律要求：
                    \n错误：标点不规范\n原文：特此通知：\n建议：特此通知。
            """
        },
        {
            "question": ques3,
            "reasoning": reasoning3,
            "answer": """
                   \n错误：错别字、错别词语\n原文：式用\n建议：适用
                   \n错误：错别字、错别字符\n原文：本科生asfqfqfqwfwqf、\n建议：本科生、
                   \n错误：错别字、逻辑不顺\n原文：三、计划学时\n建议：二、计划学时
                   \n错误：错别字、标点不规范\n原文：几本原理】\n建议：基本原理
                   \n错误：标点不规范\n原文：工作原理，\n建议：工作原理。
                   \n错误：重复内容\n原文：水声水声信号\n建议：水声信号
                   \n错误：错别字、错别词语\n原文：剧备\n建议：具备
            """
        }
    ]

    # 定义单个示例的模板
    example_template = """
    问题: {question}
    推理过程: {reasoning}
    答案: {answer}
    """

    # 创建 PromptTemplate 对象
    example_prompt = PromptTemplate(
        input_variables=["question", "reasoning", "answer"],
        template=example_template
    )

    # 创建 FewShotPromptTemplate 对象
    few_shot_prompt = FewShotPromptTemplate(
        examples=examples,
        example_prompt=example_prompt,
        prefix="你是一个文本内容校对高手。能够根据要要求进行错误检查。请根据以下示例，解决用户提出的问题。",
        suffix="问题: {question}\n推理过程:",
        input_variables=["question"],
        example_separator="\n\n"
    )
    prompt = few_shot_prompt.format(question=query)
    return prompt


def build_review_prompt(types: List[str], content: str, require: Optional[str]) -> Iterable[ChatCompletionMessageParam]:
    if require is None:
        require = ""
    review_t = "现在需要你帮我完成以下文本校对任务："
    for i , t in enumerate(types):
        if t =="逻辑校对":
            review_t += f"{i} 对这段文本进行逻辑校对\n"
        if t =="基础校对":
            review_t += f"{i}.1 进行错别字校对，错别字错误主要以文本用字不当为主，例如：星光店电，正确的应该为：星光点点。\n"
            review_t += f"{i}.2 进行标点校对，主要以标点符号使用不当为主，例如：星光点点；万里无云，正确的应该为：星光点点，万里无云\n"
            review_t += f"{i}.3 进行格式规范校对\n"
            review_t += f"{i}.4 进行重复内容校对，主要以原文中出现重复词语、句子或文本为主，例如：“今天今天心情相当不错，我很开心。我很开心。“，正确的内容应该为：今天心情相当不错，我很开心。\n"
        if t=="合规性检查":
            review_t += f"{i} 对这段文本进行合规性检查\n"
    query = f"""
       我会给你对应的文本，进行相应的检查，{review_t}
    """
    query1 = cotprompt(content)
    return [
        ChatCompletionUserMessageParam(role="user", content="请不要进行思考，直接输出内容"),
        ChatCompletionUserMessageParam(role="user", content=query),
        ChatCompletionUserMessageParam(role="user", content=query1),

    ]




_REVIEW_BLOCK_RE = re.compile(
    r"错误[:：]\s*(?P<error>.*?)\s*[\r\n]+"
    r"原文[:：]\s*(?P<original>.*?)\s*[\r\n]+"
    r"建议[:：]\s*(?P<suggestion>.*?)(?=\n\s*\n|$)",
    re.S,
)


def parse_review_output(text: str) -> List[dict]:
    text = text.strip()

    if text.startswith("###"):
        text = text[3:].strip()

    if text.endswith("###"):
        text = text[:-3].strip()

    result = []

    for match in _REVIEW_BLOCK_RE.finditer(text):
        result.append({
            "error": match.group("error").strip(),
            "original": match.group("original").strip(),
            "suggestion": match.group("suggestion").strip(),
        })

    return result


async def call_review_model(prompt: Iterable[ChatCompletionMessageParam]) -> str:
    system_prompt = (
        "你是一个专业的文本校对专家，能够根据要求进行内容的纠正和改错"
        "请严格按照用户要求的格式输出。"
        "不要输出推理过程、解释性文字、前缀或总结。"
    )

    full_text = ""

    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        model=None,
        json_output=False,
        system_prompt=system_prompt,
        messages=prompt,
        enable_thinking=False,
        temperature=0.1,
    ):
        if chunk:
            full_text += chunk

    return full_text


async def review_chunk(
    content: str,
    types: List[str],
    require: Optional[str],
) -> List[dict]:
    prompt = build_review_prompt(
        content=content,
        types=types,
        require=require,
    )

    model_output = await call_review_model(prompt)
    return parse_review_output(model_output)


async def review_text(
    content: str,
    types: List[str],
    require: Optional[str],
    sensitive_words: List[str],
    negative_words: List[str],
    positive_words: List[str],
) -> List[dict]:
    sensitive_word_set = normalize_words(sensitive_words)
    negative_word_set = normalize_words(negative_words)
    positive_word_set = normalize_words(positive_words)

    chunk_size = 1000
    chunks = [
        content[i:i + chunk_size]
        for i in range(0, len(content), chunk_size)
    ]

    all_items = []

    for chunk in chunks:
        llm_items = await review_chunk(
            content=chunk,
            types=types,
            require=require,
        )

        llm_items = filter_positive_word_false_positives(
            llm_items,
            positive_word_set,
        )

        llm_items = append_dictionary_results(
            llm_items,
            content=chunk,
            sensitive_words=sensitive_word_set,
            negative_words=negative_word_set,
        )

        all_items.extend(llm_items)

    return dedupe_and_filter(all_items, content)


@app.post("/Review", response_model=ReviewResponse)
async def review(request: ReviewRequest):
    result = await review_text(
        content=request.content,
        types=request.types,
        require=request.require,
        sensitive_words=request.sensitive_words,
        negative_words=request.negative_words,
        positive_words=request.positive_words,
    )

    return {"data": result}



# =============== 请求模型 ===============


class AgentRequest(BaseModel):
    """Agent 请求模型"""
    query: Optional[Any] = None  # 用户文本输入
    file_text: Optional[str] = None  # 文件文本输入
    image: Optional[str] = None  # 图片路径
    audio: Optional[str] = None  # 音频路径（支持 audio 或 asr）

    # 路由标志（可选，如果提供则跳过任务分类）
    route_flag: Optional[str] = None  # 路由标志
    history_message: Optional[Any] = None  # 历史信息（支持字符串或列表格式）

    # 接收参数
    top_k: Optional[Any] = None  # rag 前top_k
    rag_prompt: Optional[Any] = None  # rag 提示词模板（支持字符串、列表、字典等多种类型）
    image_kb_id: Optional[str] = None  # 图库 知识库id
    image_file_id: Optional[str] = None  # 图库 文件id
    text_kb_id: Optional[str] = None  # 检索 知识库id
    text_file_id: Optional[str] = None  # 检索 文件id

    # Socket.IO 格式所需字段
    chat_id: Optional[str] = None  # 聊天ID
    message_id: Optional[str] = None  # 消息ID

    # 知识库配置
    x_user_id: Optional[str] = "1"  # 用户ID
    x_user_name: Optional[str] = "testuser"  # 用户名称
    x_role: Optional[str] = "admin" # 角色


class AgentResponse(BaseModel):
    """Agent 响应模型"""
    success: bool
    message: str
    data: Optional[Dict[str, Any]] = None
    error: Optional[str] = None

class FeedbackClassifyRequest(BaseModel):
    """反馈分类请求模型"""
    feedback_text: str



# =============== 辅助函数 ===============
def process_rag_prompt(rag_prompt: Any) -> str:
    """
    处理 rag_prompt 参数，将各种类型转换为字符串

    Args:
        rag_prompt: 可以是字符串、列表、字典等任意类型

    Returns:
        处理后的字符串
    """
    if rag_prompt is None:
        return ""

    # 如果是字符串，直接返回
    if isinstance(rag_prompt, str):
        return rag_prompt.strip()

    # 如果是列表，转换为多行字符串
    if isinstance(rag_prompt, list):
        # 将列表中的每个元素转换为字符串，并用换行符连接
        return "\n".join(str(item) for item in rag_prompt if item)

    # 如果是字典，转换为 JSON 字符串
    if isinstance(rag_prompt, dict):
        try:
            return json.dumps(rag_prompt, ensure_ascii=False, indent=2)
        except Exception as e:
            logger.warning(f"rag_prompt 字典转换失败: {e}")
            return str(rag_prompt)

    # 其他类型，直接转换为字符串
    return str(rag_prompt).strip()


def format_stream_event(event_type: str,
                        data: Dict[str, Any],
                        chat_id: str = "",
                        message_id: str = "",
                        type: str = "chat:completion",
                        ) -> str:
    """格式化流式事件输出为 Socket.IO 格式"""
    # 生成 message_id（如果没有提供）
    if not message_id:
        message_id = str(uuid.uuid4())

    # 根据事件类型构建不同的数据结构
    if event_type == "stream_content":
        # stream_content 事件使用 chat:completion 格式
        content = data.get("content", "")
        event_data = {
            "chat_id": chat_id,
            "message_id": message_id,
            "data": {
                "type": "chat:completion",
                "data": {
                    "content": content
                }
            }
        }
    elif event_type == "function_end":
        # function_end 事件
        event_data = {
            "chat_id": chat_id,
            "message_id": message_id,
            "data": {
                "type": "chat:completion",
                "data": {
                    "stepsBlueprint": data
                }
            }
        }
    elif event_type == "execution_complete":
        # execution_complete 事件

        rag_result = data.get("rag_result", {})
        graph_result = data.get("graph_result", [])
        final_result = data.get("final_result", {})
        title = data.get("title", "")

        # 判断是否有有效的 RAG 结果（非空 dict）
        has_rag = isinstance(rag_result, dict) and bool(rag_result)

        # 判断是否有有效的图谱结果（非空 list，且至少一个元素的 nodes 非空）
        has_graph = (
                isinstance(graph_result, list)
                and len(graph_result) > 0
                and any(isinstance(item, dict) and item.get("nodes") for item in graph_result)
        )


        # 只有当 RAG 或图谱有有效内容时，才构建 sourceCitation
        source_citation = None
        if has_rag or has_graph:
            source_citation = {}
            if has_rag:
                source_citation.update(rag_result)
            if has_graph:
                source_citation["xxxx.graph"] = graph_result

        # 构建 event_data（title 由调用方异步计算后传入）
        if final_result:
            content = final_result.get("content", "")
            event_data = {
                "chat_id": chat_id,
                "message_id": message_id,
                "data": {
                    "type": "chat:completion",
                    "data": {
                        "content": content,
                    },
                    "actions": final_result.get("actions", ""),
                    "suggestedReplies": final_result.get("suggestedReplies", "")
                }
            }
        else:
            event_data = {
                "chat_id": chat_id,
                "message_id": message_id,
                "data": {
                    "type": "chat:completion",
                    "data": {
                        "data": {},
                        "done": True,
                        "title": title or "新对话",
                    }
                }
            }

            # 仅在有引用来源时添加 sourceCitation 字段
            if source_citation is not None:
                event_data["data"]["data"]["sourceCitation"] = source_citation

    else:
        # 其他事件
        event_data = {
            "chat_id": chat_id,
            "message_id": message_id,
            "type": event_type,
            "data": {
                "type": event_type,
                "data": ""
            }
        }

    # Socket.IO 格式：["chat-events", {...}]
    socket_io_message = ["chat-events", event_data]
    return f"{json.dumps(socket_io_message, ensure_ascii=False)}\n"




async def execute_workflow_chain(
    route_flag: str,
    route_params: Dict[str, Any],
    chat_id: str = "",
    message_id: str = "",
    checkpointer=None
) -> Dict[str, Any]:
    """
    执行工作流
    
    Args:
        route_flag: 路由标志
        route_params: 路由参数
        chat_id: 聊天会话 ID
        message_id: 消息 ID
        checkpointer: LangGraph checkpointer 实例
    
    Returns:
        工作流执行结果
    """
    
    print("子工作流标志：", route_flag)
    print("子工作流参数：", route_params)    

    if not route_flag:
        return {}

    extracted_text = route_params.get("extracted_text", "")
    combined_query = route_params.get("combined_query", "")
    history_message = route_params.get("history_message", "")
    
    workflow_info = WORKFLOW_CONFIG.get(route_flag)
    
    if not workflow_info:
        logger.warning(f"未知的路由标志: {route_flag}，使用默认的qa工作流")
        workflow_info = WORKFLOW_CONFIG.get("qa", WORKFLOW_CONFIG.get(list(WORKFLOW_CONFIG.keys())[0]))
    
    try:
        module = importlib.import_module(workflow_info["module"])
        workflow_func = getattr(module, workflow_info["function"])
    except (ImportError, AttributeError) as e:
        print(e)
        logger.error(f"无法导入工作流 {route_flag}: {e}")
        return {}
    
    print("zigongggggggggggggggggggggggg") 
    
    try:
        import inspect
        sig = inspect.signature(workflow_func)
        params = list(sig.parameters.keys())
        
        kwargs = {
            "extracted_text": extracted_text,
            "combined_query": combined_query,
            "history_message": history_message,
            "route_flag": route_flag,
        }
        
        if "chat_id" in params:
            kwargs["chat_id"] = chat_id
        if "message_id" in params:
            kwargs["message_id"] = message_id
        if "checkpointer" in params:
            kwargs["checkpointer"] = checkpointer
        
        result = await workflow_func(**kwargs)
    except Exception as e:
        print(e)
        logger.error(f"工作流执行失败: {e}")
        return {}
    
    return result or {}


async def stream_main_agent_execution(
    raw_input: Dict[str, Any],
    route_flag: str = "",
    rag_prompt: str = "",
    chat_id: str = "",
    message_id: str = ""
) -> AsyncGenerator[str, None]:
    """
    流式执行主Agent并输出函数调用信息（使用装饰器事件）
    
    Args:
        raw_input: 原始输入数据
        route_flag: 路由标志
        rag_prompt: RAG 提示词
        chat_id: 聊天会话 ID
        message_id: 消息 ID
    
    Yields:
        格式化的流式事件字符串
    """
    if not chat_id:
        chat_id = str(uuid.uuid4())
    if not message_id:
        message_id = str(uuid.uuid4())

    stream_handler, event_queue = create_stream_event_handler()
    register_event_callback(stream_handler)

    try:
        execution_done = asyncio.Event()
        execution_error = None
        final_result = None
        checkpointer = None

        async def run_agent():
            nonlocal execution_error, final_result, checkpointer
            route_flag_value: str = ""
            try:
                from checkpointer_config import checkpointer_manager
                checkpointer = await checkpointer_manager.get_async_checkpointer()
                
                main_agent = create_main_agent()

                initial_route_flag: str = route_flag if (route_flag and route_flag in VALID_ROUTE_FLAGS) else ""

                initial_state = {
                    "raw_input": raw_input,
                    "input_type": "",
                    "has_query":False,
                    "has_image": False,
                    "has_audio": False,
                    "has_file_text": False,
                    "history_message":raw_input.get("history_message", ""),
                    "extracted_text": "",
                    "image_description": "",
                    "asr_text": "",
                    "file_text": raw_input.get("file_text", ""),
                    "combined_query": "",
                    "task_type": "",
                    "task_classification_result": None,
                    "workflow_result": None,
                    "final_response": "",
                    "error_message": "",
                    "route_flag": initial_route_flag,
                    "route_params": {}
                }

                main_result = await main_agent.ainvoke(initial_state)

                route_flag_value = (main_result.get("route_flag")or main_result.get("task_type")or "")

                route_params = main_result.get("route_params") or {"combined_query": main_result.get("combined_query", "")
                    or main_result.get("extracted_text", ""),"extracted_text": main_result.get("extracted_text", "")}

                if "file_text" in raw_input:
                    route_params["file_text"] = raw_input["file_text"]

                if "history_message" not in route_params and "history_message" in raw_input:
                    route_params["history_message"] = filter_image_urls(raw_input["history_message"])
                    
                print("历史记录",route_params["history_message"])
                print("用户问题", route_params["combined_query"])
                print("ttttttt", route_params["extracted_text"])
                
                sub_result = await execute_workflow_chain(
                    route_flag=route_flag_value,
                    route_params=route_params,
                    chat_id=chat_id,
                    message_id=message_id,
                    checkpointer=checkpointer
                )

                processed_content = ""
                if sub_result.get("response"):
                    processed_content = sub_result.get("response", "")

                else:
                    logger.warning("子agent没有返回response")
                    processed_content = ""

                final_result = {
                    "content": processed_content,
                    "actions": sub_result.get("actions", []),
                    "result_tag": sub_result.get("result_tag", ""),
                    "suggestedReplies": sub_result.get("suggestedReplies", [])
                }
            except Exception as e:
                execution_error = e
            finally:
                execution_done.set()
                await event_queue.put({"type": "execution_complete"})

        agent_task = asyncio.create_task(run_agent())

        execution_complete_received = False
        rag_result = []
        graph_result = []
        while True:
            try:
                event = await asyncio.wait_for(event_queue.get(), timeout=0.1)

                if event.get("type") == "execution_complete":
                    execution_complete_received = True
                    continue

                event_type = event.get("type")
                title = event.get("title", "")
                details = event.get("details", "")
                result = event.get("result")

                if event_type == "function_execution":
                    logger.info(f"function_execution event - title: {title}, has_result: {result is not None}, result_type: {type(result)}")
                    if title == "知识库搜索工具" and result and isinstance(result, dict):
                        print("===============================", result)
                        rag_result_raw = result.get("sourceCitation", {})
                        rag_result = {}
                        for doc_name, chunks in rag_result_raw.items():
                            if isinstance(chunks, list):
                                rag_result[doc_name] = [
                                    {k: v for k, v in item.items() if k != "text"}
                                    if isinstance(item, dict) else item
                                    for item in chunks
                                ]
                            else:
                                rag_result[doc_name] = chunks
                    elif title == "图谱检索工具" and result and isinstance(result, dict):
                        print("===============================", result)
                        graph_result = result.get("xxxx.graph", [])
                    else:
                        yield format_stream_event("function_end", {
                            "title": title,
                            "details": details
                        }, chat_id=chat_id, message_id=message_id)

                elif event_type == "function_error":
                    yield format_stream_event("function_error", {
                        "title": title,
                        "error": details,
                        "details": details
                    }, chat_id=chat_id, message_id=message_id)

                elif event_type == "stream_content":
                    content = event.get("content", "")

                    yield format_stream_event("stream_content", {
                        "content": content
                    }, chat_id=chat_id, message_id=message_id)


            except asyncio.TimeoutError:
                if execution_complete_received:
                    break
                if execution_done.is_set() and event_queue.empty():
                    break
                continue

        await agent_task

        if execution_error:
            yield format_stream_event("error", {
                "error": str(execution_error)
            }, chat_id=chat_id, message_id=message_id)
        else:
            title = await extract_conversation_title(final_result.get("content", "") if final_result else "")
            yield format_stream_event("execution_complete", {
                "final_result": final_result
            }, chat_id=chat_id, message_id=message_id)

            yield format_stream_event("execution_complete", {
                "rag_result": rag_result,
                "graph_result": graph_result,
                "title": title
            }, chat_id=chat_id, message_id=message_id)

    except Exception as e:
        yield format_stream_event("error", {
            "error": str(e)
        }, chat_id=chat_id, message_id=message_id)
    finally:
        unregister_event_callback(stream_handler)
        clear_current_stream_handler()

# =============== API 接口 ===============
@app.post("/api/agent/stream_process")
async def stream_process_request(request: AgentRequest):
    """
    流式处理 Agent 请求，实时输出节点执行信息
    不保存历史，调用端会自己保存历史对话信息
    每次请求时创建新的主Agent实例
    """

    print(f"🔍 [调试] 接收到的原始请求: {request.model_dump_json(indent=2)}")

    print(f"[DEBUG] 收到请求 chat_id={request.chat_id!r}, message_id={request.message_id!r}, route_flag={request.route_flag!r}, query={str(request.query)[:100]}")
    # 1. 构建当前请求的输入数据
    raw_input = {}
    if request.query:
        if isinstance(request.query, str):
            raw_input["query"] = request.query
        elif isinstance(request.query, list):
            for item in request.query:
                if item.get("type") == "text":
                    raw_input["query"] = item.get("text")
        print(f"当前查询: {raw_input['query']}")
    if request.image:
        raw_input["image"] = request.image
    if request.audio:
        # audio 字段支持 audio 或 asr，统一使用 audio 键
        raw_input["audio"] = request.audio
    # [新增] 提取 file_text
    if request.file_text:
        raw_input["file_text"] = request.file_text[:5000]

    # 历史消息预处理：解析、移除当前用户消息、序列化
    if request.history_message:
        raw_input["history_message"] = preprocess_from_request(request.history_message, exclude_last=True)

    # 2. 验证至少有一个输入
    if not raw_input:
        raise HTTPException(
            status_code=400,
            detail="至少需要提供一个输入：query、image 或 audio"
        )

    # 3. 获取路由标志（如果提供，将跳过任务分类步骤）
    # 始终传递 route_flag，默认值为空字符串
    route_flag = request.route_flag or ""
    print("打印agent对应的route_flag：")
    print(route_flag)
    rag_prompt = process_rag_prompt(request.rag_prompt) if request.rag_prompt else ""
    chat_id = request.chat_id or ""
    message_id = request.message_id or ""

    # 记录智能体使用情况
    if route_flag and chat_id:
        from tools.agent_usage_statistics import record_agent_usage
        asyncio.create_task(record_agent_usage(
            chat_id=chat_id,
            route_flag=route_flag,
            message_id=message_id
        ))
        logger.info(f"记录智能体使用: chat_id={chat_id}, route_flag={route_flag}")



    # 4. 设置当前请求的用户配置和知识库参数（线程安全，支持多用户并发）
    # 如果请求中提供了这些参数，则使用请求中的值；否则使用默认值
    set_request_user_config(
        x_user_id=request.x_user_id,
        x_user_name=request.x_user_name,
        x_role=request.x_role,
        text_kb_id=request.text_kb_id,
        text_file_id=request.text_file_id
    )

    #5. 执行主Agent
    async def event_generator():
        async for event in stream_main_agent_execution(
            raw_input=raw_input,
            route_flag=route_flag,
            rag_prompt=rag_prompt,
            chat_id=chat_id,
            message_id=message_id
        ):
            yield event

    return StreamingResponse(event_generator(), media_type="text/event-stream")


@app.get("/api/download/{file_name}")
async def download_file(file_name: str):
    """
    文件下载接口

    Args:
        file_name: 文件名

    Returns:
        文件下载响应
    """
    pdf_path = os.path.join(PDF_DIR, file_name)
    word_path = os.path.join(WORD_DIR, file_name)
    file_path = pdf_path if os.path.exists(pdf_path) else word_path
    print(f"下载文件：{file_path}")
    # 检查文件是否存在
    ext = os.path.splitext(file_name)[1].lower()
    media_type = {
        ".pdf": "application/pdf",
        ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        ".doc": "application/msword",
    }.get(ext, "application/octet-stream")
    
    # 返回文件
    return FileResponse(
        path=file_path,
        filename=file_name,
        media_type=media_type
    )


@app.get("/api/health")
async def health_check():
    """健康检查接口"""
    return {
        "status": "healthy",
        "message": "服务正常运行，每次请求时创建新的Agent实例"
    }



@app.post("/api/v1/feedback/classify")
async def feedback_classify(request: FeedbackClassifyRequest):
    """
    反馈内容分类接口
    
    功能：
    1. 从反馈文本中提取设备名称
    2. 根据设备名称反推系统名称
    3. 对反馈内容进行分类
    
    Args:
        request: 包含 feedback_text 字段的请求体
    
    Returns:
        {
            "success": true,
            "system": "系统名称",
            "category": "分类结果"
        }
        
        分类类别：
        - 信息过时：反映文档或手册中的信息已经过时，不再适用
        - 步骤错误：反映操作步骤或流程存在错误
        - 步骤缺失：反映缺少必要的操作步骤或流程说明
        - 备件信息有误：反映备件型号、规格、数量等信息有误
        - 安全提示不足：反映缺少必要的安全警示或注意事项
        - 图示不清：反映图片、示意图不清晰或难以理解
        - 其他：不属于以上类别
    """
    from tools.fault_statistics import analyze_feedback_and_classify
    
    result = await analyze_feedback_and_classify(request.feedback_text)
    
    if not result.get("success", False):
        raise HTTPException(
            status_code=500,
            detail=result.get("error", "分类失败")
        )
    
    return result

class PdfContentItem(BaseModel):
    page_idx: int
    bbox: Optional[str] = None
    text: Optional[str] = None
    text_level: Optional[int] = None
    img_path: Optional[str] = None
    table_body: Optional[str] = None


class RequestWrapper(BaseModel):
    pdf_contents: List[PdfContentItem]




@app.post("/split_content_list")
async def split_content_list(request_data: RequestWrapper):
    pdf_contents = request_data.pdf_contents
    processed_list = []

    for item in pdf_contents:
        # 将 Pydantic 模型转换为字典，方便修改
        item_dict = item.model_dump()

        # --- 核心逻辑：判断并添加 type 字段 ---
        item_type = None

        # 1. 如果 text 非空 -> type: "text"
        if item.text:
            item_type = "text"

        # 2. 如果 table_body 非空 -> type: "table"
        # 注意：如果 text 和 table_body 都有，根据代码顺序，table 会覆盖 text。
        # 如果你的业务逻辑是互斥的或需要优先级，请调整此处顺序。
        elif item.table_body:
            item_type = "table"

        # 3. 如果 img_path 非空 且 table_body 为空 -> type: "image"
        # 注意：上面用了 elif 判断 table_body，所以到这里 table_body 肯定为空，
        # 但为了逻辑清晰，显式写出条件。
        elif item.img_path and not item.table_body:
            item_type = "image"

        # 如果匹配到了类型，写入字典
        if item_type:
            item_dict["type"] = item_type

        processed_list.append(item_dict)
    slices = get_chunk_bbox(processed_list)
    slices_check = chunk_check(slices, 8000)

    return {"code": 200, "message": "ok", "data": {"slices": slices_check}}


@app.post("/split_result")
async def split_result(
    file: UploadFile = File(...),
    image_prefix: str = Form("/api/v1/knowledge/files/images/"),
):
    if not file.filename:
        raise HTTPException(status_code=400, detail="File name is missing")

    chunk_size = 1024
    chunk_overlap = 100

    filename = file.filename
    suffix = PathLib(filename).suffix.lower()  # 获取文件后缀
    temp_input_path: Optional[PathLib] = None
    converted_pdf_path: Optional[PathLib] = None
    logger.info("调用知识切分接口")

    try:
        # ? 创建临时文件时指定后缀名
        with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp_in:
            content = await file.read()
            logger.info(f"文件大小:{len(content)}")
            logger.info(f"前10字节:{content[:10]}")
            # if not content.startwith(b"%PDF"):
            #   logger.error("不是合法PDF")
            #  raise HTTPException(status_code=400,detail="Uploaded file is not a valid PDF")
            tmp_in.write(content)
            temp_input_path = PathLib(tmp_in.name)
        # 2. 根据文件类型处理
        if suffix == ".pdf":
            logger.info("调用pdf切分方式")

            result_data = await process_pdf_file(temp_input_path, image_prefix,filename)
            if result_data is None:
                raise HTTPException(status_code=502, detail="PDF processing failed")
        elif suffix == ".docx":
            logger.info("调用docx切分方式")
            logger.info(f"转换 DOCX -> PDF: {filename}")

            # 执行转换
            converter.convert(str(temp_input_path), output_dir=str(DATA_DIR))

            # ? 使用临时文件的基础名查找 PDF
            temp_base_name = temp_input_path.stem  # 如 tmp2bb0l4cn
            converted_pdf_path = PathLib(DATA_DIR) / f"{temp_base_name}.pdf"

            if not converted_pdf_path.exists():
                raise HTTPException(status_code=500, detail=f"PDF 转换失败: {converted_pdf_path}")

            result_data = await process_pdf_file(converted_pdf_path, image_prefix)
            if result_data is None:
                raise HTTPException(status_code=502, detail="DOCX to PDF processing failed")

        elif suffix in (".txt", ".md"):
            logger.info("调用txt切分方式")

            # 直接读取文本内容
            async with aiofiles.open(temp_input_path, "r", encoding="utf-8", errors="ignore") as f:
                text_content = await f.read()
            contents = split_text_preserve_sentences(text_content)
            # 构造统一结构（无 images）
            slices = []
            for ins in contents:
                slices.append({"content": ins, "positions": []})
            result_data = {"slices": slices, "images": {}}
        elif suffix in [".xlsx"]:
            # converter.convert(str(temp_input_path), output_dir=str(DATA_DIR))
            # temp_base_name = temp_input_path.stem  # 如 tmp2bb0l4cn
            # converted_pdf_path = PathLib(DATA_DIR) / f"{temp_base_name}.pdf"
            # if not converted_pdf_path.exists():
            #     raise HTTPException(status_code=500, detail=f"PDF 转换失败: {converted_pdf_path}")
            logger.info("调用xlsx切分方式")

            result_data = await process_other_file(temp_input_path, image_prefix,filename)
            if result_data is None:
                raise HTTPException(status_code=502, detail="DOCX parse failed")
        elif suffix in [".ppt", ".pptx"]:
            logger.info("调用 PPT/PPTX 切分方式")
            
            # 1. 判断是否为旧版 .ppt 格式，如果是，则先进行转换
            if suffix == ".ppt":
                logger.info(f"检测到旧版 PPT 文件，正在转换为 PPTX: {temp_input_path}")
                try:
                    # 定义 LibreOffice 转换命令
                    command = [
                        'libreoffice',
                        '--headless',       # 无头模式，不弹出图形界面
                        '--convert-to', 'pptx',
                        '--outdir', os.path.dirname(temp_input_path),
                        temp_input_path
                    ]
                    
                    # 2. 使用 run_in_executor 将阻塞的同步转换操作放入线程池，避免阻塞异步事件循环
                    loop = asyncio.get_event_loop()
                    result = await loop.run_in_executor(
                        None, 
                        lambda: subprocess.run(command, capture_output=True, text=True)
                    )
                    
                    # 3. 检查转换是否成功
                    if result.returncode != 0:
                        logger.error(f"PPT 转换失败: {result.stderr}")
                        raise HTTPException(status_code=500, detail="PPT to PPTX conversion failed")
                    
                    # 4. 转换成功后，更新输入路径为新生成的 .pptx 文件路径
                    temp_input_path = os.path.splitext(temp_input_path)[0] + ".pptx"
                    logger.info(f"PPT 转换成功，新文件路径: {temp_input_path}")
                    
                except Exception as e:
                    logger.exception(f"PPT 转换过程发生异常: {e}")
                    raise HTTPException(status_code=500, detail=f"PPT conversion error: {str(e)}")

            # 5. 无论是原本就是 .pptx，还是刚刚转换完成的 .pptx，都统一走后续处理逻辑
            result_data = await process_other_file(temp_input_path, image_prefix, filename)
            if result_data is None:
                raise HTTPException(status_code=502, detail="PPTX parse failed")
        else:
            raise HTTPException(
                status_code=400, detail="Unsupported file type. Only PDF, DOCX, TXT, and MD are supported."
            )

        return JSONResponse({"code": 200, "message": "ok", "data": result_data})

    except requests.RequestException as e:
        logger.error(f"Split service request failed: {e}")
        raise HTTPException(status_code=502, detail=f"Split service error: {str(e)}")
    except Exception as e:
        logger.error(f"Internal error: {e}")
        raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
    finally:
        # 清理临时文件
        for path in [temp_input_path, converted_pdf_path]:
            if path and path.exists():
                try:
                    path.unlink()
                except Exception as e:
                    logger.warning(f"Failed to delete temp file {path}: {e}")


@app.get("/")
async def root():
    """根路径"""
    return {
        "message": "Agent API 服务",
        "docs": "/docs"
    }

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=9090)
W x   import asyncio
import re
import sys
from typing import Optional, List, Set,Iterable

if sys.platform.startswith("win") and hasattr(asyncio, "WindowsSelectorEventLoopPolicy"):
    asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())

import ahocorasick
from pydantic import BaseModel, Field, model_validator
from fastapi import FastAPI, File, Path, UploadFile, HTTPException, Form, Request, Header, Body, BackgroundTasks
from fastapi.responses import StreamingResponse
try:
    from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate
except ImportError:
    from langchain.prompts import FewShotPromptTemplate, PromptTemplate
from openai.types.chat import ChatCompletionSystemMessageParam, ChatCompletionUserMessageParam, ChatCompletionMessageParam
from chunk_text import get_chunk_bbox, split_text_preserve_sentences, data_replace, chunk_check,merge_short_slices,find_and_read_content_list,process_pdf_file,process_other_file
from fastapi.responses import JSONResponse, StreamingResponse
import requests
from pathlib import PurePath, Path as PathLib
import tempfile

from modelsAPI import model_api
from documents_prompt import (
    BEAUTIFY_TYPE_DICT,
    TEMPLATE_DICT,
    GENERATE_NORMAL_OUTLINE_PROMPT,
    GENERATE_MARKDOWN_LIST_OUTLINE_PROMPT,
    GENERATE_METHOD_OUTLINE_PROMPT,
)
"""app.py
FastAPI 主 Agent 接口 - 修复重复执行问题
提供主脑 Agent 的 HTTP API 服务，支持流式输出
集成 LangGraph Checkpointer 实现状态持久化
"""
import logging
from time import sleep
import aiofiles

from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException
from fastapi.responses import StreamingResponse, FileResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from typing import Optional, Dict, Any, AsyncGenerator,List
import uvicorn
import json
import os
import uuid
from main_agent import create_main_agent
from utils.function_tracker import (
    register_event_callback,
    create_stream_event_handler,
    unregister_event_callback,
    clear_current_stream_handler
)
import asyncio
import importlib
from doc2pdf import Doc2PDF

from workflow_registry import WORKFLOW_CONFIG, VALID_ROUTE_FLAGS
from main_agent import extract_conversation_title
from workflows.history_manager import filter_image_urls, preprocess_from_request
from config import set_request_user_config
from checkpointer_config import (
    CheckpointerManager,
    checkpointer_manager
)
app = FastAPI(max_request_size=1024 * 1024 * 10)

converter = Doc2PDF()
DATA_DIR = "/app/files"
load_dotenv()

logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# app.mount("/picture", StaticFiles(directory="/app/picture"), name="pictures")

STREAM_RESPONSE_HEADERS = {
    "Cache-Control": "no-cache",
    "X-Accel-Buffering": "no",
    "X-Content-Type-Options": "nosniff",
}


def llm_text_stream_response(content) -> StreamingResponse:
    return StreamingResponse(
        content,
        media_type="text/plain; charset=utf-8",
        headers=STREAM_RESPONSE_HEADERS,
    )


@app.on_event("startup")
async def startup_event():
    """应用启动时初始化"""
    await checkpointer_manager.setup()
    # 初始化智能体使用统计表
    from tools.agent_usage_statistics import init_agent_usage_table
    await init_agent_usage_table()
    logger.info("应用启动完成，PostgreSQL Checkpointer 已配置")


# =============== PDF 文件目录配置 ===============
# 创建 PDF 文件目录（用于存储生成的 PDF 等文件）
PDF_DIR = os.path.join(os.path.dirname(__file__), "created_pdf")
# 创建 word 文件目录（用于存储生成的 word 等文件）
WORD_DIR = os.path.join(os.path.dirname(__file__), "created_word")
os.makedirs(PDF_DIR, exist_ok=True)

class RewriteRequest(BaseModel):
    rewrite_type: Optional[str] = None
    content: Optional[str] = None
    require: Optional[str] = None
    sentence: Optional[str] = None


REWRITE_TYPE_MAP = {
    "quotePolish": "金句润色",
    "formalStyle": "书面化",
    "speechStyle": "讲稿化",
    "formatting": "规整",
    "expand": "扩写",
    "continueWriting": "续写",
    "report": "汇报",
    "quote": "金句",
    "summarize": "精简",
    "condense": "总结",
}


def build_rewrite_prompt(request: RewriteRequest) -> str:
    beautify_type = REWRITE_TYPE_MAP.get(request.rewrite_type or "")
    if not beautify_type:
        raise HTTPException(status_code=400, detail=f"不支持的 rewrite_type: {request.rewrite_type}")

    prompt_template = BEAUTIFY_TYPE_DICT.get(beautify_type)
    if not prompt_template:
        raise HTTPException(status_code=400, detail=f"未找到提示词模板: {beautify_type}")

    return prompt_template.format(
        require=request.require or "",
        content=request.content or "",
        sentence=request.sentence or request.content or "",
    )


async def stream_llm_content(prompt: str):
    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        query=prompt,
        model=None,
        system_prompt="你是专业文稿改写助手，根据要求进行文本改写。",
        messages=[],
    ):
        if chunk:
            yield chunk


@app.post("/Rewrite")
async def rewrite(request: RewriteRequest):
    prompt = build_rewrite_prompt(request)

    return llm_text_stream_response(stream_llm_content(prompt))


class WriteRequest(BaseModel):
    role: Optional[str] = None
    template: Optional[str] = None
    title: Optional[str] = None
    length: Optional[str] = None
    requirement: Optional[str] = None
    references: Optional[str] = None
    outline: Optional[str] = None
    konwlege: Optional[str] = None
    prompt: Optional[str] = None
    
class OutlineRequest(BaseModel):
    role: Optional[str] = None
    template: Optional[str] = None
    title: Optional[str] = None
    length: Optional[str] = None
    requirement: Optional[str] = None
    references: Optional[str] = None
    konwlege: Optional[str] = None
    prompt: Optional[str] = None


def length_convert(length: Optional[str]) -> str:
    if length == "短":
        return "1000字"
    if length == "中":
        return "1000-2000字"
    if length == "长":
        return "2000-5000字"
    return length or ""


def build_write_prompt(request: WriteRequest) -> str:
    prompt = request.prompt or ""
    length = length_convert(request.length)
    template = request.template or ""
    content = f"请生成一篇字数在{length}的{template}，字数严格遵守该规则，并且不能超过给定字数范围。{prompt}"
    prompt_template = TEMPLATE_DICT.get(template)
    if not prompt_template:
        raise HTTPException(status_code=400, detail=f"不支持的写作模板: {template}")

    title = request.title or ""
    if not title.strip():
        raise HTTPException(status_code=400, detail="title不能为空")

    return content+prompt_template.format(
        role=request.role or "",
        title=title,
        length=length_convert(request.length),
        requirement=request.requirement or "",
        references=request.references or "",
        outline=request.outline or "",
    )


async def stream_write_content(prompt: str):
    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        query=prompt,
        model=None,
        system_prompt="你是专业公文写作助手，请直接输出正文内容。",
        messages=[],
    ):
        if chunk:
            yield chunk


@app.post("/Write")
async def write(request: WriteRequest):
    prompt = build_write_prompt(request)

    return llm_text_stream_response(stream_write_content(prompt))


def build_outline_prompt(request: OutlineRequest) -> str:
    if request.prompt and request.prompt.strip():
        return request.prompt.strip()

    template = request.template or ""
    title = request.title or ""
    if not title.strip():
        raise HTTPException(status_code=400, detail="title不能为空")

    markdown_list_template = {"报告", "函", "文书", "工作总结"}
    prompt_template = GENERATE_NORMAL_OUTLINE_PROMPT

    if template == "方案":
        prompt_template = GENERATE_METHOD_OUTLINE_PROMPT
    elif template in markdown_list_template:
        prompt_template = GENERATE_MARKDOWN_LIST_OUTLINE_PROMPT

    return prompt_template.format(
        role=request.role or "",
        template=template,
        title=title,
        length=length_convert(request.length),
        requirement=request.requirement or "",
        references=request.references or "",
    )


async def stream_outline_content(prompt: str):
    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        query=prompt,
        model=None,
        system_prompt="你是专业公文提纲生成助手，请直接输出提纲内容。",
        messages=[],
    ):
        if chunk:
            yield chunk


@app.post("/Outline")
async def outline(request: OutlineRequest):
    prompt = build_outline_prompt(request)

    return llm_text_stream_response(stream_outline_content(prompt))


class ReviewRequest(BaseModel):
    require: Optional[str] = Field(None, description="额外校对要求")
    content: str = Field(..., description="待校对文本")
    types: List[str] = Field(..., description="检查类型")
    sensitive_words: List[str] = Field(default_factory=list, description="敏感词汇")
    negative_words: List[str] = Field(default_factory=list, description="错误词汇")
    positive_words: List[str] = Field(default_factory=list, description="正词词汇")

    @model_validator(mode="after")
    def check_content(self):
        if not self.content or not self.content.strip():
            raise ValueError("content不能为空")
        return self


class ReviewItem(BaseModel):
    original: str
    error: str
    suggestion: str


class ReviewResponse(BaseModel):
    data: List[ReviewItem]


def normalize_words(words: List[str]) -> Set[str]:
    return {word.strip() for word in words if word and word.strip()}


def find_keywords(text: str, keyword_set: Set[str]) -> List[str]:
    if not text or not keyword_set:
        return []

    automaton = ahocorasick.Automaton()

    for idx, keyword in enumerate(keyword_set):
        automaton.add_word(keyword, (idx, keyword))

    automaton.make_automaton()

    found = set()
    for _, (_, keyword) in automaton.iter(text):
        found.add(keyword)

    return list(found)


def append_dictionary_results(
    items: List[dict],
    content: str,
    sensitive_words: Set[str],
    negative_words: Set[str],
) -> List[dict]:
    for word in find_keywords(content, sensitive_words):
        items.append({
            "original": word,
            "error": "敏感词汇",
            "suggestion": "",
        })

    for word in find_keywords(content, negative_words):
        items.append({
            "original": word,
            "error": "错误词汇",
            "suggestion": "",
        })

    return items


def filter_positive_word_false_positives(
    items: List[dict],
    positive_words: Set[str],
) -> List[dict]:
    if not positive_words:
        return items

    result = []

    for item in items:
        original = str(item.get("original", ""))
        error = str(item.get("error", ""))

        has_positive_word = any(word in original for word in positive_words)
        is_typo_error = (
            "错别字" in error
            or "错别词" in error
            or "错别词语" in error
        )

        if has_positive_word and is_typo_error:
            continue

        result.append(item)

    return result


def dedupe_and_filter(items: List[dict], source_text: str) -> List[dict]:
    seen = set()
    result = []

    for item in items:
        original = str(item.get("original", "")).strip()
        error = str(item.get("error", "")).strip()
        suggestion = str(item.get("suggestion", "")).strip()

        if not original:
            continue

        if original == suggestion:
            continue

        if original not in source_text:
            continue

        key = (original, error, suggestion)
        if key in seen:
            continue

        seen.add(key)
        result.append({
            "original": original,
            "error": error,
            "suggestion": suggestion,
        })

    return result

def cotprompt(query):
    conten1 = """
    人工智能正在深刻改变现,代教育的方式。通过智能教学系统【】AI可以根据学生的学习习惯和掌握情况，提供个性化的学习内容和节奏学习内容和节奏，提高学习效率。同时，AI还能辅助教师进行作业批改、学习分析，甚至参与课堂互动，减轻教师的重复工作压力。
    虚拟助教、智能语音识别、自动文达系统等技术，也让远程教育更加高效和便捷。更加高效和便捷。随着AI技术的发展，教育不再局限于固定的教材和课堂，而是变得更加开放、灵活和智能化------让每个雪生都能获得更适合自己的学习体验。人工智能不仅是工具，更是推动教育公平和质量提升的重要力量。
    """
    reasoning1 = """
    "深刻改变现,代教育中"多了","，修改为“深刻改变现代教育中”；“智能教学系统【】”中存在错误符号“【】”，修改为“智能教学系统”；“提供个性化的学习内容和节奏学习内容和节奏”存在重复内容，修改为"提供个性化的学习内容和节奏"；"自动文达系统"存在错误词语"文达"，修改为”自动问答系统“；”而是变得更加开放、灵活和智能化------“
    中存在错误符号“------”，修改为“而是变得更加开放、灵活和智能化，”；“每个雪生”中存在错别字“雪生”，修改为“每个学生”；检查完上述错误之后，正确的文本内容应该是：人工智能正在深刻改变现代教育的方式。通过智能教学系统，AI可以根据学生的学习习惯和掌握情况，提供个性化的学习内容和节奏，提高学习效率。同时，AI还能辅助教师进行作业批改、学习分析，甚至参与课堂互动，减轻教师的重复工作压力。虚拟助教、智能语音识别、自动问答系统等技术，也让远程教育更加高效和便捷。
    随着AI技术的发展，教育不再局限于固定的教材和课堂，而是变得更加开放、灵活和智能化，让每个学生都能获得更适合自己的学习体验。人工智能不仅是工具，更是推动教育公平和质量提升的重要力量。
    """
    ques = f"""
    文本内容为{conten1},对给出的文本内容进行逻辑校对、基础校对和合规性检查，逻辑校对检测文本逻辑连贯性，基础校对检查文本中错别字、错误标点符号和重复内容。
    校对文本之后，如果你发现没有任何错误，不需要返回其他内容，只需要返回：
    ###\n###
    发现错误时返回：
    ###\n错误：错别字、标点不规范\n原文：星光店电；万里乌云\n建议：星光点点，万里无云
       \n错误：错别词语、标点不规范\n原文：请注丰收与团圆。\n建议：庆祝丰收与团圆。
       \n错误：标点不规范\n原文：你好；明天\n建议：你好，明天
       \n错误：重复内容\n原文：我听说你心情很不错不错。你心情很不错不错。\n建议：我听说你心情很不错。###
    """

    conten2 = """
    关于近期工作安排的通知
    各位同事，
    京公司研九决定，现将近期工作安排通知通知如下：
    一、项目推进方面。各部门需加快项目进度，确保按时交付。如有问题，及时与相关领导沟通解决。项目负责人要切实履行职责，加强团队协作，提高工作效率。
    二、培训学习方面：公司将组织系列培训课程，提升员工专业技能。具体时间、地点另行通知。员工需按时参加，不得无辜缺席。自即日起，严禁在工作时间从事与工作无关的活动。
    二、纪律要求。近期发现部分员工上班时间做与工作无关的事情，如炒股、聊天等，严重影响工作效率和公司形象。自即日起，严禁在工作时间从事与工作无关的活动。违反规定者，将按照公司规章制度严肃处理。
    特此通知：
    [公司名称]
    [日期]
    """
    reasoning2 = """
    "京公司研九决定"中存在错别字和词语“京”、“研九”，修改为“经公司研究决定”；“工作安排通知通知”存在重复内容，修改为“工作安排通知”；“一、项目推进方面。”存在错误标点符号，参与后续内容中“二、培训学习方面：”，因此“一、项目推进方面”之后应当使用“：”，修改为“一、项目推进方面：”；“无辜缺席。”中存在错别字“辜”，修改为“无故缺席”；
    “二、纪律要求。”存在错别字、标点不规范，纪律要求应该是第三点，应该使用”：“，修改为“三、纪律要求：”；”特此通知：“中存在标点不规范，应该修改为”特此通知。“检查完上述错误之后，正确的文本内容应该是：关于近期工作安排的通知
    各位同事，
    经公司研究决定，现将近期工作安排通知如下：
    一、项目推进方面：各部门需加快项目进度，确保按时交付。如有问题，及时与相关领导沟通解决。项目负责人要切实履行职责，加强团队协作，提高工作效率。
    二、培训学习方面：公司将组织系列培训课程，提升员工专业技能。具体时间、地点另行通知。员工需按时参加，不得无故缺席。自即日起，严禁在工作时间从事与工作无关的活动。
    三、纪律要求：近期发现部分员工上班时间做与工作无关的事情，如炒股、聊天等，严重影响工作效率和公司形象。自即日起，严禁在工作时间从事与工作无关的活动。违反规定者，将按照公司规章制度严肃处理。
    特此通知。
    [公司名称]
    [日期]
    """

    ques2 = f"""
    文本内容为{conten2},对给出的文本内容进行逻辑校对、基础校对和合规性检查，逻辑校对检测文本逻辑连贯性，基础校对检查文本中错别字、错误标点符号和重复内容。
    校对文本之后，如果你发现没有任何错误，不需要返回其他内容，只需要返回：
    ###\n###
    发现错误时返回：
    ###\n错误：错别字、标点不规范\n原文：星光店电；万里乌云\n建议：星光点点，万里无云
       \n错误：错别词语、标点不规范\n原文：请注丰收与团圆。\n建议：庆祝丰收与团圆。
       \n错误：标点不规范\n原文：你好；明天\n建议：你好，明天
       \n错误：重复内容\n原文：我听说你心情很不错不错。你心情很不错不错。\n建议：我听说你心情很不错。###
    """

    conten3 = """
    《水声目标识别》课程教学计划

    一、课程名称
    水声目标识别，该课程式用于海洋科学、水声工程、电子信息等专业本科生asfqfqfqwfwqf、研究生，以及军事院校学员、相关领域科研人员和企业技术人员技术人员。

    三、计划学时
    2026学年，总学时：48学时（理论授课32学时，实作授课16学时）

    三、授课时间
    每周4学时，共12周完成
    四、教学目标
    1. 知识目标
       使学生掌握水声目标识别的几本原理】方法和技术，包括声纳信号的特性、目标特征提取、分类与识别算法等。
       了解水声目标识别在军事（如潜艇作战、反潜作战等）和民用（如海洋资源勘探、水下考古等）领域的应用。
       熟悉水声目标识别系统的基本组成和工作原理，
    2. 能力目标
       培养学生运用所学知识对水声信号进行分析处理、特征提取和目标识别的能力。
       提高学生运用专业软件（如MATLAB等）进行水声水声信号处理和目标识别仿真的能力。
       增强学生解决实际水声目标识别问题的实践能力和创新思维。
    3. 素质目标
       培养学生严谨的科学态度和扎实的专业素养，使其剧备良好的团队协作精神和沟通能力。
       激发学生对水声技术领域的学习兴趣和探索精神，培养其自主学习和终身学习的意识。
    """

    ques3 = f"""
    文本内容为{conten3},对给出的文本内容进行逻辑校对、基础校对和合规性检查，逻辑校对检测文本逻辑连贯性，基础校对检查文本中错别字、错误标点符号和重复内容。
    校对文本之后，如果你发现没有任何错误，不需要返回其他内容，只需要返回：
    ###\n###
    发现错误时返回：
    ###\n错误：错别字、标点不规范\n原文：星光店电；万里乌云\n建议：星光点点，万里无云
       \n错误：错别词语、标点不规范\n原文：请注丰收与团圆。\n建议：庆祝丰收与团圆。
       \n错误：标点不规范\n原文：你好；明天\n建议：你好，明天
       \n错误：重复内容\n原文：我听说你心情很不错不错。你心情很不错不错。\n建议：我听说你心情很不错。###
    """
    reasoning3 = """
    "式用"中存在错别字“式”，修改为：“适用”；“本科生asfqfqfqwfwqf、”中存在错别字和符号“asfqfqfqwfwqf”，修改为：“本科生、”；“三、计划学时”存在错别字使用不当，修改为：“二、计划学时”；
    “几本原理】”存在错别字、标点不规范，应该修改为：“基本原理”；“工作原理，”存在标点不规范，应该修改为：“工作原理。”；“水声水声信号”中存在重复内容“水声”，应该修改为“水声信号”；
    “剧备”存在错别字“剧”，应该修改为：”具备“。检查完上述错误之后，正确的文本内容应该是：
    《水声目标识别》课程教学计划

    一、课程名称
    水声目标识别，该课程式用于海洋科学、水声工程、电子信息等专业本科生、研究生，以及军事院校学员、相关领域科研人员和企业技术人员。

    三、计划学时
    2026学年，总学时：48学时（理论授课32学时，实作授课16学时）

    三、授课时间
    每周4学时，共12周完成
    四、教学目标
    1. 知识目标
       使学生掌握水声目标识别的基本原理、方法和技术，包括声纳信号的特性、目标特征提取、分类与识别算法等。
       了解水声目标识别在军事（如潜艇作战、反潜作战等）和民用（如海洋资源勘探、水下考古等）领域的应用。
       熟悉水声目标识别系统的基本组成和工作原理。
    2. 能力目标
       培养学生运用所学知识对水声信号进行分析处理、特征提取和目标识别的能力。
       提高学生运用专业软件（如MATLAB等）进行水声信号处理和目标识别仿真的能力。
       增强学生解决实际水声目标识别问题的实践能力和创新思维。
    3. 素质目标
       培养学生严谨的科学态度和扎实的专业素养，使其具备良好的团队协作精神和沟通能力。
       激发学生对水声技术领域的学习兴趣和探索精神，培养其自主学习和终身学习的意识。
    """

    # 定义 Few-Shot CoT 示例
    examples = [
        {
            "question": ques,
            "reasoning": reasoning1,
            "answer": """
                    \n错误：标点不规范\n原文：现,代教育\n建议：现代教育
                    \n错误：标点不规范\n原文：智能教学系统【】\n建议：智能教学系统
                    \n错误：重复内容\n原文：提供个性化的学习内容和节奏学习内容和节奏\n建议：提供个性化的学习内容和节奏
                    \n错误：错别字、错别词语\n原文：自动文达系统\n建议：自动问答系统
                    \n错误：标点不规范\n原文：而是变得更加开放、灵活和智能化------\n建议：而是变得更加开放、灵活和智能化，
                    \n错误：错别字、错别词语\n原文：每个雪生\n建议：每个学生
            """
        },
        {
            "question": ques2,
            "reasoning": reasoning2,
            "answer": """
                    \n错误：错别字、错别词语\n原文：京公司研九决定\n建议：经公司研究决定
                    \n错误：重复内容\n原文：工作安排通知通知\n建议：工作安排通知
                    \n错误：错别字、错别词语\n原文：无辜缺席。\n建议：无故缺席
                    \n错误：错别字、标点不规范\n原文：二、纪律要求。\n建议：三、纪律要求：
                    \n错误：标点不规范\n原文：特此通知：\n建议：特此通知。
            """
        },
        {
            "question": ques3,
            "reasoning": reasoning3,
            "answer": """
                   \n错误：错别字、错别词语\n原文：式用\n建议：适用
                   \n错误：错别字、错别字符\n原文：本科生asfqfqfqwfwqf、\n建议：本科生、
                   \n错误：错别字、逻辑不顺\n原文：三、计划学时\n建议：二、计划学时
                   \n错误：错别字、标点不规范\n原文：几本原理】\n建议：基本原理
                   \n错误：标点不规范\n原文：工作原理，\n建议：工作原理。
                   \n错误：重复内容\n原文：水声水声信号\n建议：水声信号
                   \n错误：错别字、错别词语\n原文：剧备\n建议：具备
            """
        }
    ]

    # 定义单个示例的模板
    example_template = """
    问题: {question}
    推理过程: {reasoning}
    答案: {answer}
    """

    # 创建 PromptTemplate 对象
    example_prompt = PromptTemplate(
        input_variables=["question", "reasoning", "answer"],
        template=example_template
    )

    # 创建 FewShotPromptTemplate 对象
    few_shot_prompt = FewShotPromptTemplate(
        examples=examples,
        example_prompt=example_prompt,
        prefix="你是一个文本内容校对高手。能够根据要要求进行错误检查。请根据以下示例，解决用户提出的问题。",
        suffix="问题: {question}\n推理过程:",
        input_variables=["question"],
        example_separator="\n\n"
    )
    prompt = few_shot_prompt.format(question=query)
    return prompt


def build_review_prompt(types: List[str], content: str, require: Optional[str]) -> Iterable[ChatCompletionMessageParam]:
    if require is None:
        require = ""
    require = require.strip()
    review_t = "现在需要你帮我完成以下文本校对任务："
    for i , t in enumerate(types):
        if t =="逻辑校对":
            review_t += f"{i} 对这段文本进行逻辑校对\n"
        if t =="基础校对":
            review_t += f"{i}.1 进行错别字校对，错别字错误主要以文本用字不当为主，例如：星光店电，正确的应该为：星光点点。\n"
            review_t += f"{i}.2 进行标点校对，主要以标点符号使用不当为主，例如：星光点点；万里无云，正确的应该为：星光点点，万里无云\n"
            review_t += f"{i}.3 进行格式规范校对\n"
            review_t += f"{i}.4 进行重复内容校对，主要以原文中出现重复词语、句子或文本为主，例如：“今天今天心情相当不错，我很开心。我很开心。“，正确的内容应该为：今天心情相当不错，我很开心。\n"
        if t=="合规性检查":
            review_t += f"{i} 对这段文本进行合规性检查\n"
    require_text = f"\n额外要求：{require}\n" if require else ""
    query = f"""
       我会给你对应的文本，进行相应的检查，{review_t}
       {require_text}
    """
    query1 = cotprompt(content)
    return [
        ChatCompletionUserMessageParam(role="user", content="请不要进行思考，直接输出内容"),
        ChatCompletionUserMessageParam(role="user", content=query),
        ChatCompletionUserMessageParam(role="user", content=query1),

    ]




_REVIEW_BLOCK_RE = re.compile(
    r"错误[:：]\s*(?P<error>.*?)\s*[\r\n]+"
    r"原文[:：]\s*(?P<original>.*?)\s*[\r\n]+"
    r"建议[:：]\s*(?P<suggestion>.*?)(?=\n\s*\n|$)",
    re.S,
)


def parse_review_output(text: str) -> List[dict]:
    text = text.strip()

    if text.startswith("###"):
        text = text[3:].strip()

    if text.endswith("###"):
        text = text[:-3].strip()

    result = []

    for match in _REVIEW_BLOCK_RE.finditer(text):
        result.append({
            "error": match.group("error").strip(),
            "original": match.group("original").strip(),
            "suggestion": match.group("suggestion").strip(),
        })

    return result


REVIEW_SYSTEM_PROMPT = (
    "你是一个专业的文本校对专家，能够根据要求进行内容的纠正和改错"
    "请严格按照用户要求的格式输出。"
    "不要输出推理过程、解释性文字、前缀或总结。"
)


async def stream_review_model(prompt: Iterable[ChatCompletionMessageParam]):
    async for chunk in model_api.OpenaiAPI.open_api_chat_stream(
        model=None,
        json_output=False,
        system_prompt=REVIEW_SYSTEM_PROMPT,
        messages=prompt,
        enable_thinking=False,
        temperature=0.1,
    ):
        if chunk:
            yield chunk


async def call_review_model(prompt: Iterable[ChatCompletionMessageParam]) -> str:
    full_text = ""

    async for chunk in stream_review_model(prompt):
        full_text += chunk

    return full_text


def build_review_stream_require(
    require: Optional[str],
    sensitive_words: List[str],
    negative_words: List[str],
    positive_words: List[str],
) -> Optional[str]:
    requirements = []

    if require and require.strip():
        requirements.append(require.strip())

    sensitive_text = "、".join(dict.fromkeys(word.strip() for word in sensitive_words if word and word.strip()))
    if sensitive_text:
        requirements.append(f"请重点检查以下敏感词：{sensitive_text}。如果原文出现这些词，错误类型写“敏感词汇”。")

    negative_text = "、".join(dict.fromkeys(word.strip() for word in negative_words if word and word.strip()))
    if negative_text:
        requirements.append(f"请重点检查以下错误词：{negative_text}。如果原文出现这些词，错误类型写“错误词汇”。")

    positive_text = "、".join(dict.fromkeys(word.strip() for word in positive_words if word and word.strip()))
    if positive_text:
        requirements.append(f"以下词为正确词，涉及错别字判断时不要误判：{positive_text}。")

    if not requirements:
        return None

    return "\n".join(requirements)


async def stream_review_content(
    content: str,
    types: List[str],
    require: Optional[str],
    sensitive_words: List[str],
    negative_words: List[str],
    positive_words: List[str],
):
    review_require = build_review_stream_require(
        require=require,
        sensitive_words=sensitive_words,
        negative_words=negative_words,
        positive_words=positive_words,
    )

    chunk_size = 1000
    chunks = [
        content[i:i + chunk_size]
        for i in range(0, len(content), chunk_size)
    ]

    for chunk in chunks:
        prompt = build_review_prompt(
            content=chunk,
            types=types,
            require=review_require,
        )

        async for token in stream_review_model(prompt):
            yield token


async def review_chunk(
    content: str,
    types: List[str],
    require: Optional[str],
) -> List[dict]:
    prompt = build_review_prompt(
        content=content,
        types=types,
        require=require,
    )

    model_output = await call_review_model(prompt)
    return parse_review_output(model_output)


async def review_text(
    content: str,
    types: List[str],
    require: Optional[str],
    sensitive_words: List[str],
    negative_words: List[str],
    positive_words: List[str],
) -> List[dict]:
    sensitive_word_set = normalize_words(sensitive_words)
    negative_word_set = normalize_words(negative_words)
    positive_word_set = normalize_words(positive_words)

    chunk_size = 1000
    chunks = [
        content[i:i + chunk_size]
        for i in range(0, len(content), chunk_size)
    ]

    all_items = []

    for chunk in chunks:
        llm_items = await review_chunk(
            content=chunk,
            types=types,
            require=require,
        )

        llm_items = filter_positive_word_false_positives(
            llm_items,
            positive_word_set,
        )

        llm_items = append_dictionary_results(
            llm_items,
            content=chunk,
            sensitive_words=sensitive_word_set,
            negative_words=negative_word_set,
        )

        all_items.extend(llm_items)

    return dedupe_and_filter(all_items, content)


@app.post("/Review")
async def review(request: ReviewRequest):
    return llm_text_stream_response(stream_review_content(
        content=request.content,
        types=request.types,
        require=request.require,
        sensitive_words=request.sensitive_words,
        negative_words=request.negative_words,
        positive_words=request.positive_words,
    ))



# =============== 请求模型 ===============


class AgentRequest(BaseModel):
    """Agent 请求模型"""
    query: Optional[Any] = None  # 用户文本输入
    file_text: Optional[str] = None  # 文件文本输入
    image: Optional[str] = None  # 图片路径
    audio: Optional[str] = None  # 音频路径（支持 audio 或 asr）

    # 路由标志（可选，如果提供则跳过任务分类）
    route_flag: Optional[str] = None  # 路由标志
    history_message: Optional[Any] = None  # 历史信息（支持字符串或列表格式）

    # 接收参数
    top_k: Optional[Any] = None  # rag 前top_k
    rag_prompt: Optional[Any] = None  # rag 提示词模板（支持字符串、列表、字典等多种类型）
    image_kb_id: Optional[str] = None  # 图库 知识库id
    image_file_id: Optional[str] = None  # 图库 文件id
    text_kb_id: Optional[str] = None  # 检索 知识库id
    text_file_id: Optional[str] = None  # 检索 文件id

    # Socket.IO 格式所需字段
    chat_id: Optional[str] = None  # 聊天ID
    message_id: Optional[str] = None  # 消息ID

    # 知识库配置
    x_user_id: Optional[str] = "1"  # 用户ID
    x_user_name: Optional[str] = "testuser"  # 用户名称
    x_role: Optional[str] = "admin" # 角色


class AgentResponse(BaseModel):
    """Agent 响应模型"""
    success: bool
    message: str
    data: Optional[Dict[str, Any]] = None
    error: Optional[str] = None

class FeedbackClassifyRequest(BaseModel):
    """反馈分类请求模型"""
    feedback_text: str



# =============== 辅助函数 ===============
def process_rag_prompt(rag_prompt: Any) -> str:
    """
    处理 rag_prompt 参数，将各种类型转换为字符串

    Args:
        rag_prompt: 可以是字符串、列表、字典等任意类型

    Returns:
        处理后的字符串
    """
    if rag_prompt is None:
        return ""

    # 如果是字符串，直接返回
    if isinstance(rag_prompt, str):
        return rag_prompt.strip()

    # 如果是列表，转换为多行字符串
    if isinstance(rag_prompt, list):
        # 将列表中的每个元素转换为字符串，并用换行符连接
        return "\n".join(str(item) for item in rag_prompt if item)

    # 如果是字典，转换为 JSON 字符串
    if isinstance(rag_prompt, dict):
        try:
            return json.dumps(rag_prompt, ensure_ascii=False, indent=2)
        except Exception as e:
            logger.warning(f"rag_prompt 字典转换失败: {e}")
            return str(rag_prompt)

    # 其他类型，直接转换为字符串
    return str(rag_prompt).strip()


def format_stream_event(event_type: str,
                        data: Dict[str, Any],
                        chat_id: str = "",
                        message_id: str = "",
                        type: str = "chat:completion",
                        ) -> str:
    """格式化流式事件输出为 Socket.IO 格式"""
    # 生成 message_id（如果没有提供）
    if not message_id:
        message_id = str(uuid.uuid4())

    # 根据事件类型构建不同的数据结构
    if event_type == "stream_content":
        # stream_content 事件使用 chat:completion 格式
        content = data.get("content", "")
        event_data = {
            "chat_id": chat_id,
            "message_id": message_id,
            "data": {
                "type": "chat:completion",
                "data": {
                    "content": content
                }
            }
        }
    elif event_type == "function_end":
        # function_end 事件
        event_data = {
            "chat_id": chat_id,
            "message_id": message_id,
            "data": {
                "type": "chat:completion",
                "data": {
                    "stepsBlueprint": data
                }
            }
        }
    elif event_type == "execution_complete":
        # execution_complete 事件

        rag_result = data.get("rag_result", {})
        graph_result = data.get("graph_result", [])
        final_result = data.get("final_result", {})
        title = data.get("title", "")

        # 判断是否有有效的 RAG 结果（非空 dict）
        has_rag = isinstance(rag_result, dict) and bool(rag_result)

        # 判断是否有有效的图谱结果（非空 list，且至少一个元素的 nodes 非空）
        has_graph = (
                isinstance(graph_result, list)
                and len(graph_result) > 0
                and any(isinstance(item, dict) and item.get("nodes") for item in graph_result)
        )


        # 只有当 RAG 或图谱有有效内容时，才构建 sourceCitation
        source_citation = None
        if has_rag or has_graph:
            source_citation = {}
            if has_rag:
                source_citation.update(rag_result)
            if has_graph:
                source_citation["xxxx.graph"] = graph_result

        # 构建 event_data（title 由调用方异步计算后传入）
        if final_result:
            content = final_result.get("content", "")
            event_data = {
                "chat_id": chat_id,
                "message_id": message_id,
                "data": {
                    "type": "chat:completion",
                    "data": {
                        "content": content,
                    },
                    "actions": final_result.get("actions", ""),
                    "suggestedReplies": final_result.get("suggestedReplies", "")
                }
            }
        else:
            event_data = {
                "chat_id": chat_id,
                "message_id": message_id,
                "data": {
                    "type": "chat:completion",
                    "data": {
                        "data": {},
                        "done": True,
                        "title": title or "新对话",
                    }
                }
            }

            # 仅在有引用来源时添加 sourceCitation 字段
            if source_citation is not None:
                event_data["data"]["data"]["sourceCitation"] = source_citation

    else:
        # 其他事件
        event_data = {
            "chat_id": chat_id,
            "message_id": message_id,
            "type": event_type,
            "data": {
                "type": event_type,
                "data": ""
            }
        }

    # Socket.IO 格式：["chat-events", {...}]
    socket_io_message = ["chat-events", event_data]
    return f"{json.dumps(socket_io_message, ensure_ascii=False)}\n"




async def execute_workflow_chain(
    route_flag: str,
    route_params: Dict[str, Any],
    chat_id: str = "",
    message_id: str = "",
    checkpointer=None
) -> Dict[str, Any]:
    """
    执行工作流
    
    Args:
        route_flag: 路由标志
        route_params: 路由参数
        chat_id: 聊天会话 ID
        message_id: 消息 ID
        checkpointer: LangGraph checkpointer 实例
    
    Returns:
        工作流执行结果
    """
    
    print("子工作流标志：", route_flag)
    print("子工作流参数：", route_params)    

    if not route_flag:
        return {}

    extracted_text = route_params.get("extracted_text", "")
    combined_query = route_params.get("combined_query", "")
    history_message = route_params.get("history_message", "")
    
    workflow_info = WORKFLOW_CONFIG.get(route_flag)
    
    if not workflow_info:
        logger.warning(f"未知的路由标志: {route_flag}，使用默认的qa工作流")
        workflow_info = WORKFLOW_CONFIG.get("qa", WORKFLOW_CONFIG.get(list(WORKFLOW_CONFIG.keys())[0]))
    
    try:
        module = importlib.import_module(workflow_info["module"])
        workflow_func = getattr(module, workflow_info["function"])
    except (ImportError, AttributeError) as e:
        print(e)
        logger.error(f"无法导入工作流 {route_flag}: {e}")
        return {}
    
    print("zigongggggggggggggggggggggggg") 
    
    try:
        import inspect
        sig = inspect.signature(workflow_func)
        params = list(sig.parameters.keys())
        
        kwargs = {
            "extracted_text": extracted_text,
            "combined_query": combined_query,
            "history_message": history_message,
            "route_flag": route_flag,
        }
        
        if "chat_id" in params:
            kwargs["chat_id"] = chat_id
        if "message_id" in params:
            kwargs["message_id"] = message_id
        if "checkpointer" in params:
            kwargs["checkpointer"] = checkpointer
        
        result = await workflow_func(**kwargs)
    except Exception as e:
        print(e)
        logger.error(f"工作流执行失败: {e}")
        return {}
    
    return result or {}


async def stream_main_agent_execution(
    raw_input: Dict[str, Any],
    route_flag: str = "",
    rag_prompt: str = "",
    chat_id: str = "",
    message_id: str = ""
) -> AsyncGenerator[str, None]:
    """
    流式执行主Agent并输出函数调用信息（使用装饰器事件）
    
    Args:
        raw_input: 原始输入数据
        route_flag: 路由标志
        rag_prompt: RAG 提示词
        chat_id: 聊天会话 ID
        message_id: 消息 ID
    
    Yields:
        格式化的流式事件字符串
    """
    if not chat_id:
        chat_id = str(uuid.uuid4())
    if not message_id:
        message_id = str(uuid.uuid4())

    stream_handler, event_queue = create_stream_event_handler()
    register_event_callback(stream_handler)

    try:
        execution_done = asyncio.Event()
        execution_error = None
        final_result = None
        checkpointer = None

        async def run_agent():
            nonlocal execution_error, final_result, checkpointer
            route_flag_value: str = ""
            try:
                from checkpointer_config import checkpointer_manager
                checkpointer = await checkpointer_manager.get_async_checkpointer()
                
                main_agent = create_main_agent()

                initial_route_flag: str = route_flag if (route_flag and route_flag in VALID_ROUTE_FLAGS) else ""

                initial_state = {
                    "raw_input": raw_input,
                    "input_type": "",
                    "has_query":False,
                    "has_image": False,
                    "has_audio": False,
                    "has_file_text": False,
                    "history_message":raw_input.get("history_message", ""),
                    "extracted_text": "",
                    "image_description": "",
                    "asr_text": "",
                    "file_text": raw_input.get("file_text", ""),
                    "combined_query": "",
                    "task_type": "",
                    "task_classification_result": None,
                    "workflow_result": None,
                    "final_response": "",
                    "error_message": "",
                    "route_flag": initial_route_flag,
                    "route_params": {}
                }

                main_result = await main_agent.ainvoke(initial_state)

                route_flag_value = (main_result.get("route_flag")or main_result.get("task_type")or "")

                route_params = main_result.get("route_params") or {"combined_query": main_result.get("combined_query", "")
                    or main_result.get("extracted_text", ""),"extracted_text": main_result.get("extracted_text", "")}

                if "file_text" in raw_input:
                    route_params["file_text"] = raw_input["file_text"]

                if "history_message" not in route_params and "history_message" in raw_input:
                    route_params["history_message"] = filter_image_urls(raw_input["history_message"])
                    
                print("历史记录",route_params["history_message"])
                print("用户问题", route_params["combined_query"])
                print("ttttttt", route_params["extracted_text"])
                
                sub_result = await execute_workflow_chain(
                    route_flag=route_flag_value,
                    route_params=route_params,
                    chat_id=chat_id,
                    message_id=message_id,
                    checkpointer=checkpointer
                )

                processed_content = ""
                if sub_result.get("response"):
                    processed_content = sub_result.get("response", "")

                else:
                    logger.warning("子agent没有返回response")
                    processed_content = ""

                final_result = {
                    "content": processed_content,
                    "actions": sub_result.get("actions", []),
                    "result_tag": sub_result.get("result_tag", ""),
                    "suggestedReplies": sub_result.get("suggestedReplies", [])
                }
            except Exception as e:
                execution_error = e
            finally:
                execution_done.set()
                await event_queue.put({"type": "execution_complete"})

        agent_task = asyncio.create_task(run_agent())

        execution_complete_received = False
        rag_result = []
        graph_result = []
        while True:
            try:
                event = await asyncio.wait_for(event_queue.get(), timeout=0.1)

                if event.get("type") == "execution_complete":
                    execution_complete_received = True
                    continue

                event_type = event.get("type")
                title = event.get("title", "")
                details = event.get("details", "")
                result = event.get("result")

                if event_type == "function_execution":
                    logger.info(f"function_execution event - title: {title}, has_result: {result is not None}, result_type: {type(result)}")
                    if title == "知识库搜索工具" and result and isinstance(result, dict):
                        print("===============================", result)
                        rag_result_raw = result.get("sourceCitation", {})
                        rag_result = {}
                        for doc_name, chunks in rag_result_raw.items():
                            if isinstance(chunks, list):
                                rag_result[doc_name] = [
                                    {k: v for k, v in item.items() if k != "text"}
                                    if isinstance(item, dict) else item
                                    for item in chunks
                                ]
                            else:
                                rag_result[doc_name] = chunks
                    elif title == "图谱检索工具" and result and isinstance(result, dict):
                        print("===============================", result)
                        graph_result = result.get("xxxx.graph", [])
                    else:
                        yield format_stream_event("function_end", {
                            "title": title,
                            "details": details
                        }, chat_id=chat_id, message_id=message_id)

                elif event_type == "function_error":
                    yield format_stream_event("function_error", {
                        "title": title,
                        "error": details,
                        "details": details
                    }, chat_id=chat_id, message_id=message_id)

                elif event_type == "stream_content":
                    content = event.get("content", "")

                    yield format_stream_event("stream_content", {
                        "content": content
                    }, chat_id=chat_id, message_id=message_id)


            except asyncio.TimeoutError:
                if execution_complete_received:
                    break
                if execution_done.is_set() and event_queue.empty():
                    break
                continue

        await agent_task

        if execution_error:
            yield format_stream_event("error", {
                "error": str(execution_error)
            }, chat_id=chat_id, message_id=message_id)
        else:
            title = await extract_conversation_title(final_result.get("content", "") if final_result else "")
            yield format_stream_event("execution_complete", {
                "final_result": final_result
            }, chat_id=chat_id, message_id=message_id)

            yield format_stream_event("execution_complete", {
                "rag_result": rag_result,
                "graph_result": graph_result,
                "title": title
            }, chat_id=chat_id, message_id=message_id)

    except Exception as e:
        yield format_stream_event("error", {
            "error": str(e)
        }, chat_id=chat_id, message_id=message_id)
    finally:
        unregister_event_callback(stream_handler)
        clear_current_stream_handler()

# =============== API 接口 ===============
@app.post("/api/agent/stream_process")
async def stream_process_request(request: AgentRequest):
    """
    流式处理 Agent 请求，实时输出节点执行信息
    不保存历史，调用端会自己保存历史对话信息
    每次请求时创建新的主Agent实例
    """

    print(f"🔍 [调试] 接收到的原始请求: {request.model_dump_json(indent=2)}")

    print(f"[DEBUG] 收到请求 chat_id={request.chat_id!r}, message_id={request.message_id!r}, route_flag={request.route_flag!r}, query={str(request.query)[:100]}")
    # 1. 构建当前请求的输入数据
    raw_input = {}
    if request.query:
        if isinstance(request.query, str):
            raw_input["query"] = request.query
        elif isinstance(request.query, list):
            for item in request.query:
                if item.get("type") == "text":
                    raw_input["query"] = item.get("text")
        print(f"当前查询: {raw_input['query']}")
    if request.image:
        raw_input["image"] = request.image
    if request.audio:
        # audio 字段支持 audio 或 asr，统一使用 audio 键
        raw_input["audio"] = request.audio
    # [新增] 提取 file_text
    if request.file_text:
        raw_input["file_text"] = request.file_text[:5000]

    # 历史消息预处理：解析、移除当前用户消息、序列化
    if request.history_message:
        raw_input["history_message"] = preprocess_from_request(request.history_message, exclude_last=True)

    # 2. 验证至少有一个输入
    if not raw_input:
        raise HTTPException(
            status_code=400,
            detail="至少需要提供一个输入：query、image 或 audio"
        )

    # 3. 获取路由标志（如果提供，将跳过任务分类步骤）
    # 始终传递 route_flag，默认值为空字符串
    route_flag = request.route_flag or ""
    print("打印agent对应的route_flag：")
    print(route_flag)
    rag_prompt = process_rag_prompt(request.rag_prompt) if request.rag_prompt else ""
    chat_id = request.chat_id or ""
    message_id = request.message_id or ""

    # 记录智能体使用情况
    if route_flag and chat_id:
        from tools.agent_usage_statistics import record_agent_usage
        asyncio.create_task(record_agent_usage(
            chat_id=chat_id,
            route_flag=route_flag,
            message_id=message_id
        ))
        logger.info(f"记录智能体使用: chat_id={chat_id}, route_flag={route_flag}")



    # 4. 设置当前请求的用户配置和知识库参数（线程安全，支持多用户并发）
    # 如果请求中提供了这些参数，则使用请求中的值；否则使用默认值
    set_request_user_config(
        x_user_id=request.x_user_id,
        x_user_name=request.x_user_name,
        x_role=request.x_role,
        text_kb_id=request.text_kb_id,
        text_file_id=request.text_file_id
    )

    #5. 执行主Agent
    async def event_generator():
        async for event in stream_main_agent_execution(
            raw_input=raw_input,
            route_flag=route_flag,
            rag_prompt=rag_prompt,
            chat_id=chat_id,
            message_id=message_id
        ):
            yield event

    return StreamingResponse(event_generator(), media_type="text/event-stream")


@app.get("/api/download/{file_name}")
async def download_file(file_name: str):
    """
    文件下载接口

    Args:
        file_name: 文件名

    Returns:
        文件下载响应
    """
    pdf_path = os.path.join(PDF_DIR, file_name)
    word_path = os.path.join(WORD_DIR, file_name)
    file_path = pdf_path if os.path.exists(pdf_path) else word_path
    print(f"下载文件：{file_path}")
    # 检查文件是否存在
    ext = os.path.splitext(file_name)[1].lower()
    media_type = {
        ".pdf": "application/pdf",
        ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        ".doc": "application/msword",
    }.get(ext, "application/octet-stream")
    
    # 返回文件
    return FileResponse(
        path=file_path,
        filename=file_name,
        media_type=media_type
    )


@app.get("/api/health")
async def health_check():
    """健康检查接口"""
    return {
        "status": "healthy",
        "message": "服务正常运行，每次请求时创建新的Agent实例"
    }



@app.post("/api/v1/feedback/classify")
async def feedback_classify(request: FeedbackClassifyRequest):
    """
    反馈内容分类接口
    
    功能：
    1. 从反馈文本中提取设备名称
    2. 根据设备名称反推系统名称
    3. 对反馈内容进行分类
    
    Args:
        request: 包含 feedback_text 字段的请求体
    
    Returns:
        {
            "success": true,
            "system": "系统名称",
            "category": "分类结果"
        }
        
        分类类别：
        - 信息过时：反映文档或手册中的信息已经过时，不再适用
        - 步骤错误：反映操作步骤或流程存在错误
        - 步骤缺失：反映缺少必要的操作步骤或流程说明
        - 备件信息有误：反映备件型号、规格、数量等信息有误
        - 安全提示不足：反映缺少必要的安全警示或注意事项
        - 图示不清：反映图片、示意图不清晰或难以理解
        - 其他：不属于以上类别
    """
    from tools.fault_statistics import analyze_feedback_and_classify
    
    result = await analyze_feedback_and_classify(request.feedback_text)
    
    if not result.get("success", False):
        raise HTTPException(
            status_code=500,
            detail=result.get("error", "分类失败")
        )
    
    return result

class PdfContentItem(BaseModel):
    page_idx: int
    bbox: Optional[str] = None
    text: Optional[str] = None
    text_level: Optional[int] = None
    img_path: Optional[str] = None
    table_body: Optional[str] = None


class RequestWrapper(BaseModel):
    pdf_contents: List[PdfContentItem]




@app.post("/split_content_list")
async def split_content_list(request_data: RequestWrapper):
    pdf_contents = request_data.pdf_contents
    processed_list = []

    for item in pdf_contents:
        # 将 Pydantic 模型转换为字典，方便修改
        item_dict = item.model_dump()

        # --- 核心逻辑：判断并添加 type 字段 ---
        item_type = None

        # 1. 如果 text 非空 -> type: "text"
        if item.text:
            item_type = "text"

        # 2. 如果 table_body 非空 -> type: "table"
        # 注意：如果 text 和 table_body 都有，根据代码顺序，table 会覆盖 text。
        # 如果你的业务逻辑是互斥的或需要优先级，请调整此处顺序。
        elif item.table_body:
            item_type = "table"

        # 3. 如果 img_path 非空 且 table_body 为空 -> type: "image"
        # 注意：上面用了 elif 判断 table_body，所以到这里 table_body 肯定为空，
        # 但为了逻辑清晰，显式写出条件。
        elif item.img_path and not item.table_body:
            item_type = "image"

        # 如果匹配到了类型，写入字典
        if item_type:
            item_dict["type"] = item_type

        processed_list.append(item_dict)
    slices = get_chunk_bbox(processed_list)
    slices_check = chunk_check(slices, 8000)

    return {"code": 200, "message": "ok", "data": {"slices": slices_check}}


@app.post("/split_result")
async def split_result(
    file: UploadFile = File(...),
    image_prefix: str = Form("/api/v1/knowledge/files/images/"),
):
    if not file.filename:
        raise HTTPException(status_code=400, detail="File name is missing")

    chunk_size = 1024
    chunk_overlap = 100

    filename = file.filename
    suffix = PathLib(filename).suffix.lower()  # 获取文件后缀
    temp_input_path: Optional[PathLib] = None
    converted_pdf_path: Optional[PathLib] = None
    logger.info("调用知识切分接口")

    try:
        # ? 创建临时文件时指定后缀名
        with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp_in:
            content = await file.read()
            logger.info(f"文件大小:{len(content)}")
            logger.info(f"前10字节:{content[:10]}")
            # if not content.startwith(b"%PDF"):
            #   logger.error("不是合法PDF")
            #  raise HTTPException(status_code=400,detail="Uploaded file is not a valid PDF")
            tmp_in.write(content)
            temp_input_path = PathLib(tmp_in.name)
        # 2. 根据文件类型处理
        if suffix == ".pdf":
            logger.info("调用pdf切分方式")

            result_data = await process_pdf_file(temp_input_path, image_prefix,filename)
            if result_data is None:
                raise HTTPException(status_code=502, detail="PDF processing failed")
        elif suffix == ".docx":
            logger.info("调用docx切分方式")
            logger.info(f"转换 DOCX -> PDF: {filename}")

            # 执行转换
            converter.convert(str(temp_input_path), output_dir=str(DATA_DIR))

            # ? 使用临时文件的基础名查找 PDF
            temp_base_name = temp_input_path.stem  # 如 tmp2bb0l4cn
            converted_pdf_path = PathLib(DATA_DIR) / f"{temp_base_name}.pdf"

            if not converted_pdf_path.exists():
                raise HTTPException(status_code=500, detail=f"PDF 转换失败: {converted_pdf_path}")

            result_data = await process_pdf_file(converted_pdf_path, image_prefix)
            if result_data is None:
                raise HTTPException(status_code=502, detail="DOCX to PDF processing failed")

        elif suffix in (".txt", ".md"):
            logger.info("调用txt切分方式")

            # 直接读取文本内容
            async with aiofiles.open(temp_input_path, "r", encoding="utf-8", errors="ignore") as f:
                text_content = await f.read()
            contents = split_text_preserve_sentences(text_content)
            # 构造统一结构（无 images）
            slices = []
            for ins in contents:
                slices.append({"content": ins, "positions": []})
            result_data = {"slices": slices, "images": {}}
        elif suffix in [".xlsx"]:
            # converter.convert(str(temp_input_path), output_dir=str(DATA_DIR))
            # temp_base_name = temp_input_path.stem  # 如 tmp2bb0l4cn
            # converted_pdf_path = PathLib(DATA_DIR) / f"{temp_base_name}.pdf"
            # if not converted_pdf_path.exists():
            #     raise HTTPException(status_code=500, detail=f"PDF 转换失败: {converted_pdf_path}")
            logger.info("调用xlsx切分方式")

            result_data = await process_other_file(temp_input_path, image_prefix,filename)
            if result_data is None:
                raise HTTPException(status_code=502, detail="DOCX parse failed")
        elif suffix in [".ppt", ".pptx"]:
            logger.info("调用 PPT/PPTX 切分方式")
            
            # 1. 判断是否为旧版 .ppt 格式，如果是，则先进行转换
            if suffix == ".ppt":
                logger.info(f"检测到旧版 PPT 文件，正在转换为 PPTX: {temp_input_path}")
                try:
                    # 定义 LibreOffice 转换命令
                    command = [
                        'libreoffice',
                        '--headless',       # 无头模式，不弹出图形界面
                        '--convert-to', 'pptx',
                        '--outdir', os.path.dirname(temp_input_path),
                        temp_input_path
                    ]
                    
                    # 2. 使用 run_in_executor 将阻塞的同步转换操作放入线程池，避免阻塞异步事件循环
                    loop = asyncio.get_event_loop()
                    result = await loop.run_in_executor(
                        None, 
                        lambda: subprocess.run(command, capture_output=True, text=True)
                    )
                    
                    # 3. 检查转换是否成功
                    if result.returncode != 0:
                        logger.error(f"PPT 转换失败: {result.stderr}")
                        raise HTTPException(status_code=500, detail="PPT to PPTX conversion failed")
                    
                    # 4. 转换成功后，更新输入路径为新生成的 .pptx 文件路径
                    temp_input_path = os.path.splitext(temp_input_path)[0] + ".pptx"
                    logger.info(f"PPT 转换成功，新文件路径: {temp_input_path}")
                    
                except Exception as e:
                    logger.exception(f"PPT 转换过程发生异常: {e}")
                    raise HTTPException(status_code=500, detail=f"PPT conversion error: {str(e)}")

            # 5. 无论是原本就是 .pptx，还是刚刚转换完成的 .pptx，都统一走后续处理逻辑
            result_data = await process_other_file(temp_input_path, image_prefix, filename)
            if result_data is None:
                raise HTTPException(status_code=502, detail="PPTX parse failed")
        else:
            raise HTTPException(
                status_code=400, detail="Unsupported file type. Only PDF, DOCX, TXT, and MD are supported."
            )

        return JSONResponse({"code": 200, "message": "ok", "data": result_data})

    except requests.RequestException as e:
        logger.error(f"Split service request failed: {e}")
        raise HTTPException(status_code=502, detail=f"Split service error: {str(e)}")
    except Exception as e:
        logger.error(f"Internal error: {e}")
        raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
    finally:
        # 清理临时文件
        for path in [temp_input_path, converted_pdf_path]:
            if path and path.exists():
                try:
                    path.unlink()
                except Exception as e:
                    logger.warning(f"Failed to delete temp file {path}: {e}")


@app.get("/")
asy *nc def root():
    """根路径"""
    return {
        "message": "Agent API 服务",
        "docs": "/docs"
    }

if __name__ == "__main__":
    import uvicorn

    uvicorn.run(app, host="0.0.0.0", port=9090)
ae	xEN"""
LangGraph Checkpointer 配置模块

支持多种持久化后端：
1. MemorySaver - 内存存储（仅用于测试）
2. PostgresSaver - PostgreSQL 数据库（生产环境）

使用 message_id 和 chat_id 作为 thread_id 来恢复工作流状态
"""

import os
import asyncio
from typing import Optional
from langgraph.checkpoint.memory import MemorySaver
from config import POSTGRES_CONNECTION_STRING

CHECKPOINTER_TYPE = "postgres"


def get_thread_id(chat_id: str, message_id: str) -> str:
    """
    生成唯一的 thread_id
    
    Args:
        chat_id: 聊天会话 ID
        message_id: 消息 ID
    
    Returns:
        组合后的唯一 thread_id
    """
    return f"{chat_id}:{message_id}"


def parse_thread_id(thread_id: str) -> tuple[str, str]:
    """
    解析 thread_id 获取 chat_id 和 message_id
    
    Args:
        thread_id: 组合的 thread_id
    
    Returns:
        (chat_id, message_id) 元组
    """
    parts = thread_id.split(":", 1)
    if len(parts) == 2:
        return parts[0], parts[1]
    return parts[0], ""


async def verify_checkpointer_tables_exist() -> bool:
    """
    验证 checkpointer 所需的数据库表是否存在且结构正确
    
    Returns:
        True 如果所有必需的表都存在且结构正确，否则 False
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        return False
    
    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    # 检查 checkpoints 表
                    await cur.execute("""
                        SELECT EXISTS (
                            SELECT FROM information_schema.tables 
                            WHERE table_schema = 'public' 
                            AND table_name = 'checkpoints'
                        )
                    """)
                    checkpoints_exists = (await cur.fetchone())[0]
                    
                    # 检查 checkpoint_writes 表
                    await cur.execute("""
                        SELECT EXISTS (
                            SELECT FROM information_schema.tables 
                            WHERE table_schema = 'public' 
                            AND table_name = 'checkpoint_writes'
                        )
                    """)
                    writes_exists = (await cur.fetchone())[0]
                    
                    # 检查 checkpoint_blobs 表
                    await cur.execute("""
                        SELECT EXISTS (
                            SELECT FROM information_schema.tables 
                            WHERE table_schema = 'public' 
                            AND table_name = 'checkpoint_blobs'
                        )
                    """)
                    blobs_exists = (await cur.fetchone())[0]
                    
                    if not (checkpoints_exists and writes_exists and blobs_exists):
                        return False
                    
                    # 检查 checkpoints 表的 checkpoint 字段是否为 JSONB 类型
                    await cur.execute("""
                        SELECT data_type 
                        FROM information_schema.columns 
                        WHERE table_name = 'checkpoints' 
                        AND column_name = 'checkpoint'
                    """)
                    result = await cur.fetchone()
                    if not result or result[0] != 'jsonb':
                        print(f"[Checkpointer] checkpoints.checkpoint column type is {result[0] if result else 'NULL'}, expected 'jsonb'")
                        return False
                    
                    # 检查 checkpoint_writes 表是否有 task_path 列
                    await cur.execute("""
                        SELECT EXISTS (
                            SELECT FROM information_schema.columns 
                            WHERE table_name = 'checkpoint_writes' 
                            AND column_name = 'task_path'
                        )
                    """)
                    task_path_exists = (await cur.fetchone())[0]
                    if not task_path_exists:
                        print(f"[Checkpointer] checkpoint_writes.task_path column does not exist")
                        return False
                    
                    # 检查 checkpoint_writes 表的主键是否正确
                    await cur.execute("""
                        SELECT COUNT(*) 
                        FROM information_schema.table_constraints tc
                        JOIN information_schema.key_column_usage kcu 
                        ON tc.constraint_name = kcu.constraint_name
                        WHERE tc.table_name = 'checkpoint_writes' 
                        AND tc.constraint_type = 'PRIMARY KEY'
                    """)
                    pk_count = (await cur.fetchone())[0]
                    if pk_count != 5:  # 应该有 5 个主键列
                        print(f"[Checkpointer] checkpoint_writes has {pk_count} primary key columns, expected 5")
                        return False
                    
                    return True
    except Exception as e:
        print(f"[Checkpointer] Error verifying tables: {e}")
        return False


async def init_checkpointer_db():
    """
    初始化 PostgreSQL checkpointer 数据库表
    使用 AsyncPostgresSaver 的 setup 方法创建正确的表结构
    """
    if CHECKPOINTER_TYPE != "postgres":
        return
    
    try:
        from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
        from psycopg_pool import AsyncConnectionPool
        import psycopg
    except ImportError as e:
        print(f"[Checkpointer] ERROR: Missing required package: {e}")
        print(f"[Checkpointer] Please install: pip install langgraph-checkpoint-postgres psycopg-pool")
        raise ImportError(
            "langgraph-checkpoint-postgres or psycopg-pool not installed. "
            "Run: pip install langgraph-checkpoint-postgres psycopg-pool"
        ) from e
    
    # 首先检查表是否已存在
    tables_exist = await verify_checkpointer_tables_exist()
    if tables_exist:
        print(f"[Checkpointer] Database tables already exist, skipping initialization")
        return
    
    print(f"[Checkpointer] Initializing PostgreSQL database tables...")
    
    # 尝试使用 AsyncPostgresSaver 的 setup 方法
    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            checkpointer = AsyncPostgresSaver(pool)
            await checkpointer.setup()
            print(f"[Checkpointer] AsyncPostgresSaver.setup() executed")
    except Exception as e:
        print(f"[Checkpointer] AsyncPostgresSaver.setup() failed: {e}")
    
    # 验证表是否真的被创建
    tables_exist_after = await verify_checkpointer_tables_exist()
    
    if not tables_exist_after:
        print(f"[Checkpointer] Tables not created by setup(), using direct SQL...")
        try:
            await create_checkpointer_tables_directly()
        except Exception as e2:
            print(f"[Checkpointer] Direct SQL initialization also failed: {e2}")
            raise
    else:
        print(f"[Checkpointer] PostgreSQL database tables verified successfully")


async def create_checkpointer_tables_directly():
    """
    直接通过 SQL 语句创建 checkpointer 所需的数据库表
    这是备用方案，当 AsyncPostgresSaver.setup() 失败时使用
    
    注意：LangGraph AsyncPostgresSaver 使用 JSONB 类型存储数据
    表名必须是: checkpoints, checkpoint_writes, checkpoint_blobs
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError as e:
        print(f"[Checkpointer] ERROR: Missing psycopg-pool: {e}")
        raise
    
    print(f"[Checkpointer] Creating checkpointer tables using direct SQL...")
    
    async with AsyncConnectionPool(
        POSTGRES_CONNECTION_STRING,
        kwargs={"autocommit": True}
    ) as pool:
        async with pool.connection() as conn:
            async with conn.cursor() as cur:
                # 先删除旧表（如果存在错误的表结构）
                await cur.execute("DROP TABLE IF EXISTS checkpoints CASCADE")
                await cur.execute("DROP TABLE IF EXISTS writes CASCADE")
                await cur.execute("DROP TABLE IF EXISTS checkpoint_blobs CASCADE")
                await cur.execute("DROP TABLE IF EXISTS checkpoint_writes CASCADE")
                await cur.execute("DROP TABLE IF EXISTS blobs CASCADE")
                await cur.execute("DROP TABLE IF EXISTS checkpoint_migrations CASCADE")
                print(f"[Checkpointer] Dropped existing tables")
                
                # 创建 checkpoint_migrations 表（用于跟踪迁移版本）
                await cur.execute("""
                    CREATE TABLE IF NOT EXISTS checkpoint_migrations (
                        v INTEGER PRIMARY KEY
                    )
                """)
                
                # 创建 checkpoints 表 - 使用 JSONB 类型
                await cur.execute("""
                    CREATE TABLE IF NOT EXISTS checkpoints (
                        thread_id TEXT NOT NULL,
                        checkpoint_ns TEXT NOT NULL DEFAULT '',
                        checkpoint_id TEXT NOT NULL,
                        parent_checkpoint_id TEXT,
                        type TEXT,
                        checkpoint JSONB NOT NULL DEFAULT '{}',
                        metadata JSONB NOT NULL DEFAULT '{}',
                        PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id)
                    )
                """)
                
                # 创建 checkpoint_writes 表 - 使用 BYTEA 类型
                await cur.execute("""
                    CREATE TABLE IF NOT EXISTS checkpoint_writes (
                        thread_id TEXT NOT NULL,
                        checkpoint_ns TEXT NOT NULL DEFAULT '',
                        checkpoint_id TEXT NOT NULL,
                        task_id TEXT NOT NULL,
                        task_path TEXT NOT NULL DEFAULT '',
                        idx INTEGER NOT NULL,
                        channel TEXT NOT NULL,
                        type TEXT,
                        blob BYTEA,
                        PRIMARY KEY (thread_id, checkpoint_ns, checkpoint_id, task_id, idx)
                    )
                """)
                
                # 创建 checkpoint_blobs 表 - 使用 BYTEA 类型存储二进制数据
                await cur.execute("""
                    CREATE TABLE IF NOT EXISTS checkpoint_blobs (
                        thread_id TEXT NOT NULL,
                        checkpoint_ns TEXT NOT NULL DEFAULT '',
                        channel TEXT NOT NULL,
                        version TEXT NOT NULL,
                        type TEXT NOT NULL,
                        blob BYTEA,
                        PRIMARY KEY (thread_id, checkpoint_ns, channel, version)
                    )
                """)
                
                # 创建索引以提高查询性能
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS checkpoints_thread_id_idx ON checkpoints(thread_id)
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS checkpoint_writes_thread_id_idx ON checkpoint_writes(thread_id)
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS checkpoint_blobs_thread_id_idx ON checkpoint_blobs(thread_id)
                """)
                
                # 插入迁移版本记录
                await cur.execute("""
                    INSERT INTO checkpoint_migrations (v) VALUES (1) ON CONFLICT DO NOTHING
                """)
                
                print(f"[Checkpointer] Checkpointer tables created successfully via direct SQL")


def create_checkpointer(checkpointer_type: str = None):
    """
    创建同步 checkpointer 实例
    
    Args:
        checkpointer_type: checkpointer 类型，可选 "memory", "postgres"
    
    Returns:
        checkpointer 实例
    """
    checkpointer_type = checkpointer_type or CHECKPOINTER_TYPE
    
    if checkpointer_type == "memory":
        return MemorySaver()
    
    elif checkpointer_type == "postgres":
        try:
            from langgraph.checkpoint.postgres import PostgresSaver
            from psycopg import Connection
            if not POSTGRES_CONNECTION_STRING:
                raise ValueError("POSTGRES_CONNECTION_STRING 环境变量未设置")
            conn = Connection.connect(POSTGRES_CONNECTION_STRING)
            return PostgresSaver(conn)
        except ImportError:
            print("[WARNING] psycopg 或 langgraph.checkpoint.postgres 未安装，回退到 memory")
            return MemorySaver()
    
    else:
        print(f"[WARNING] 未知的 checkpointer 类型: {checkpointer_type}，使用 memory")
        return MemorySaver()


def create_async_checkpointer(checkpointer_type: str = None):
    """
    创建异步 checkpointer 实例
    
    Args:
        checkpointer_type: checkpointer 类型
    
    Returns:
        异步 checkpointer 实例
    """
    checkpointer_type = checkpointer_type or CHECKPOINTER_TYPE
    print(f"[Checkpointer] 创建异步 checkpointer, 类型配置: {checkpointer_type}")
    
    if checkpointer_type == "memory":
        print("[Checkpointer] 使用 MemorySaver")
        return MemorySaver()
    
    elif checkpointer_type == "postgres":
        try:
            from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
            from psycopg_pool import AsyncConnectionPool
            if not POSTGRES_CONNECTION_STRING:
                raise ValueError("POSTGRES_CONNECTION_STRING 环境变量未设置")
            pool = AsyncConnectionPool(POSTGRES_CONNECTION_STRING)
            return AsyncPostgresSaver(pool)
        except ImportError:
            print("[WARNING] psycopg_pool 或 langgraph.checkpoint.postgres 未安装，回退到 memory")
            return MemorySaver()
    
    else:
        print(f"[WARNING] 未知的 checkpointer 类型: {checkpointer_type}，使用 memory")
        return MemorySaver()


async def get_or_create_async_checkpointer(checkpointer_type: str = None):
    """
    获取或创建异步 checkpointer 实例（正确处理上下文管理器）
    
    Args:
        checkpointer_type: checkpointer 类型
    
    Returns:
        已初始化的异步 checkpointer 实例
    """
    checkpointer = create_async_checkpointer(checkpointer_type)
    
    if hasattr(checkpointer, '__aenter__'):
        checkpointer = await checkpointer.__aenter__()
    
    return checkpointer


class CheckpointerManager:
    """
    Checkpointer 管理器 - 单例模式
    
    用于管理多个工作流的 checkpointer 实例
    """
    
    _instance = None
    _sync_checkpointer = None
    _async_conn_pool = None
    _async_checkpointer = None
    _initialized = False
    
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance
    
    def get_checkpointer(self):
        """获取同步 checkpointer 实例"""
        if self._sync_checkpointer is None:
            self._sync_checkpointer = create_checkpointer()
        return self._sync_checkpointer
    
    async def get_async_checkpointer(self):
        """
        获取异步 checkpointer 实例
        """
        if self._async_checkpointer is None:
            if CHECKPOINTER_TYPE == "postgres":
                try:
                    from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
                    from psycopg_pool import AsyncConnectionPool
                    if not POSTGRES_CONNECTION_STRING:
                        raise ValueError("POSTGRES_CONNECTION_STRING not set")
                    
                    self._async_conn_pool = AsyncConnectionPool(
                        POSTGRES_CONNECTION_STRING,
                        open=False
                    )
                    await self._async_conn_pool.open()
                    self._async_checkpointer = AsyncPostgresSaver(self._async_conn_pool)
                    
                    # 检查表是否存在
                    tables_exist = await verify_checkpointer_tables_exist()
                    
                    if not tables_exist:
                        # 尝试使用 setup() 方法
                        try:
                            await self._async_checkpointer.setup()
                            print(f"[Checkpointer] AsyncPostgresSaver.setup() executed")
                        except Exception as setup_e:
                            print(f"[Checkpointer] AsyncPostgresSaver.setup() failed: {setup_e}")
                        
                        # 再次验证表是否被创建
                        tables_exist_after = await verify_checkpointer_tables_exist()
                        
                        if not tables_exist_after:
                            print(f"[Checkpointer] Tables not created by setup(), using direct SQL...")
                            await create_checkpointer_tables_directly()
                    else:
                        print(f"[Checkpointer] Database tables already exist")
                    
                    print(f"[Checkpointer] AsyncPostgresSaver created, connection: {POSTGRES_CONNECTION_STRING.split('@')[1] if '@' in POSTGRES_CONNECTION_STRING else POSTGRES_CONNECTION_STRING}")
                except ImportError as e:
                    print(f"[WARNING] psycopg_pool or langgraph.checkpoint.postgres not installed: {e}, fallback to memory")
                    self._async_checkpointer = MemorySaver()
                except Exception as e:
                    print(f"[Checkpointer] ERROR: Failed to create AsyncPostgresSaver: {e}")
                    raise
            elif CHECKPOINTER_TYPE == "memory":
                self._async_checkpointer = MemorySaver()
                print("[Checkpointer] Using MemorySaver")
            else:
                self._async_checkpointer = MemorySaver()
                print(f"[Checkpointer] Unknown type {CHECKPOINTER_TYPE}, using MemorySaver")
        
        print(f"[Checkpointer] Async checkpointer type: {type(self._async_checkpointer).__name__}")
        return self._async_checkpointer
    
    async def setup(self):
        """
        初始化 checkpointer（创建数据库表等）
        """
        if not self._initialized:
            await init_checkpointer_db()
            try:
                from tools.fault_record_db import init_fault_records_table
                await init_fault_records_table()
            except Exception as e:
                print(f"[Checkpointer] 初始化 fault_records 表失败: {e}")
            try:
                from tools.ship_model_db import init_ship_model_mapping_table
                await init_ship_model_mapping_table()
            except Exception as e:
                print(f"[Checkpointer] 初始化 ship_model_mapping 表失败: {e}")
            self._initialized = True
    
    def reset(self):
        """重置 checkpointer（主要用于测试）"""
        self._sync_checkpointer = None
        self._async_checkpointer = None
        self._async_conn_pool = None
        self._initialized = False


checkpointer_manager = CheckpointerManager()


if __name__ == "__main__":
    print("Checkpointer 配置测试:")
    print(f"  类型: {CHECKPOINTER_TYPE}")
    print(f"  PostgreSQL 连接: {'已配置' if POSTGRES_CONNECTION_STRING else '未配置'}")

CMx1aimport json
import fitz  # PyMuPDF
import os
from collections import Counter
import uuid
from openai import OpenAI
import re
from typing import List, Dict, Optional, Union, Any, Tuple
# 指定 JSON 文件路径
# file_path = '/storage01/home/hdf/project/wxkgrag/kgextract/output/122-06A0014-B01001_发动机-维修手册_content_list.json'
from pathlib import PurePath, Path as PathLib
from fastapi import FastAPI, File, Path, UploadFile, HTTPException, Form, Request, Header, Body
from fileparse_util import process_document
import threading
import aiofiles
import httpx
import logging
from config import API_URLS
logger = logging.getLogger(__name__)


_api_url_inflight = [0] * len(API_URLS)
_api_url_lock = threading.Lock()

def format_entity_text(data):
    # 1. 定义实体类型与属性的映射关系
    # 格式: '实体类型': [ ('前缀1', '属性1'), ('前缀2', '属性2') ]
    type_mapping = {
        '舰艇': [('舰艇为', '名称'), ('，舷号', '舷号')],
        '系统': [('，系统：', '名称')],
        '子系统': [('，子系统：', '名称')],
        '设备': [('，设备：', '名称')]
    }
    
    text_parts = []
    
    # 2. 遍历 entities 列表
    for entity in data.get('entities', []):
        entity_type = entity.get('type')

        properties = entity.get('properties', {})
        
        # 3. 如果当前实体类型在映射表中，则进行拼接
        if entity_type in type_mapping:
            entity_str = ""
            # 遍历该实体需要提取的所有属性
            for prefix, attr_key in type_mapping[entity_type]:
                value = str(properties.get(attr_key, ''))
                entity_str += f"{prefix}{value}"
            text_parts.append(entity_str)
            
    # 4. 将所有部分拼接成一段完整的文本
    # 注意：因为前缀中已经包含了逗号，这里直接拼接即可
    return ''.join(text_parts)

def get_api_url(task_id: str = "") -> tuple:
    """返回 (analyze_url, contentlist_url)，选当前 inflight 最少的实例。"""
    with _api_url_lock:
        idx = _api_url_inflight.index(min(_api_url_inflight))
        _api_url_inflight[idx] += 1
    base = API_URLS[idx]
    return base


def release_api_url(url: str):
    with _api_url_lock:
        if url in API_URLS:
            idx = API_URLS.index(url)
            _api_url_inflight[idx] = max(0, _api_url_inflight[idx] - 1)
def extract_text_from_first_tr(html: str) -> str:
    """提取 HTML 表格中第一个 <tr> 内的文本（去除标签）"""
    if not isinstance(html, str):
        return ""
    match = re.search(r'<tr[^>]*>(.*?)</tr>', html, re.IGNORECASE | re.DOTALL)
    if not match:
        return ""
    first_tr_content = match.group(1)
    # 去除所有 HTML 标签
    text = re.sub(r'<[^>]+>', '', first_tr_content)
    return text.strip()


def matches_any_pattern(text: str, patterns: List[List[str]]) -> bool:
    """检查文本是否包含任意一组关键词（全部命中）"""
    if not text:
        return False
    text_lower = text.lower()
    for pattern in patterns:
        if all(keyword in text_lower for keyword in pattern):
            return True
    return False


def is_maintenance_table(table_body: str, patterns: List[List[str]]) -> bool:
    """判断是否为维修项目表格：仅检查第一个 <tr> 是否匹配任一模式"""
    first_tr_text = extract_text_from_first_tr(table_body)
    return matches_any_pattern(first_tr_text, patterns)


# ==============================
# 维修项目表格的关键词模式（可按需扩展）
# ==============================

MAINTENANCE_TABLE_PATTERNS: List[List[str]] = [
    ["维修项目编号", "组成编码", "名称", "维修项目", "维修间隔期"],
    ["维修项目编号", "维修级别", "名称"],
    ["项目编号", "编码", "维修内容", "周期"],
    ["序号", "维修项", "标准", "频次"],  # 示例：可继续添加业务变体
]


# ==============================
# 主函数：提取维修项目表格及其后续内容组
# ==============================

def extract_maintenance_groups_and_remaining(
    records: List[Dict[str, Any]],
    patterns: List[List[str]] = MAINTENANCE_TABLE_PATTERNS,
    max_following_for_last: int | None = None
) -> Tuple[List[List[Dict]], List[Dict]]:
    groups = []
    current_group = None
    used_ids = set()
    
    # 标记是否已经遇到第一个维修表格（用于跳过）
    skipped_first = False

    for record in records:
        is_start = (
            record.get("type") == "table" and
            is_maintenance_table(record.get("table_body", ""), patterns)
        )

        if is_start:
            # 如果是第一个维修表，跳过（不加入 groups，也不标记 used_ids）
            if not skipped_first:
                skipped_first = True
                # 注意：这里不清空 current_group，因为前面不可能有 group（第一个 start）
                current_group = None  # 确保不会把之前的非 start 内容误加
                continue  # 跳过这个 record，不加入任何 group

            # 从第二个维修表开始，才正常分组
            if current_group is not None:
                groups.append(current_group)
                used_ids.update(r["id"] for r in current_group)
            current_group = [record]
        else:
            if current_group is not None:
                current_group.append(record)

    # 处理最后一个 group（仅当有有效 group 时）
    if current_group is not None:
        groups.append(current_group)
        used_ids.update(r["id"] for r in current_group)

    # 限制最后一个 group 长度
    if groups and max_following_for_last is not None:
        last_group = groups[-1]
        max_len = max_following_for_last + 1
        if len(last_group) > max_len:
            truncated = last_group[:max_len]
            removed_ids = {r["id"] for r in last_group[max_len:]}
            used_ids -= removed_ids
            groups[-1] = truncated

    # remaining_records 包含所有未被 used_ids 标记的记录
    # 由于第一个 group 没有加入 used_ids，所以会保留在 remaining_records 中
    remaining_records = [r for r in records if r["id"] not in used_ids]
    return groups, remaining_records


def is_operation_table_by_first_tr(table_body: str) -> bool:
    """
    判断 table_body 是否为操作项目表，依据是第一行 <tr> 中是否包含 '项目编号' 和 '操作项目'
    """
    if not isinstance(table_body, str):
        return False
    
    # 非贪婪匹配第一个 <tr> ... </tr>
    match = re.search(r'<tr[^>]*>(.*?)</tr>', table_body, re.IGNORECASE | re.DOTALL)
    if not match:
        return False
    
    first_tr_html = match.group(1)
    
    # 去除所有 HTML 标签，提取纯文本
    text_in_first_tr = re.sub(r'<[^>]+>', '', first_tr_html)
    
    # 转为小写（中文无所谓大小写，但统一处理更安全）
    text_clean = text_in_first_tr.strip()
    
    # 检查是否同时包含两个关键词
    has_code = "项目编号" in text_clean
    has_item = "操作项目" in text_clean
    return has_code and has_item

def extract_operation_groups_and_remaining(records, max_following_for_last=23):
    """
    通过语义判断表格是否为操作项目表（基于第一行内容），并分组。
    注意：第一个识别到的操作项目表及其后续记录组成的 group 会被跳过（不加入 groups），
          但这些记录仍保留在 remaining_records 中。
    
    普通起始标记：组 = [start, ..., next_start - 1]
    最后一个起始标记：组 = [start, ..., start + max_following_for_last] （若指定）
    """
    groups = []
    current_group = None
    used_ids = set()
    first_group_skipped = False  # 标记是否已跳过第一个 group

    for record in records:
        is_start = (
            record.get("type") == "table" 
            and is_operation_table_by_first_tr(record.get("table_body", ""))
        )
        
        if is_start:
            if current_group is not None:
                # 决定是否保留当前积累的 group
                if not first_group_skipped:
                    # 跳过第一个 group：不清空 current_group，也不加入 groups 或 used_ids
                    first_group_skipped = True
                    # 注意：这里不把 current_group 加入 groups，也不更新 used_ids
                else:
                    groups.append(current_group)
                    used_ids.update(r["id"] for r in current_group)
                # 开启新 group
                current_group = [record]
            else:
                # 第一个起始点
                current_group = [record]
        else:
            if current_group is not None:
                current_group.append(record)

    # 处理最后一个 group（如果存在）
    if current_group is not None:
        if not first_group_skipped:
            # 整个数据中只有一个 group，且是第一个 → 跳过它
            pass  # 不加入 groups，也不加 id 到 used_ids
        else:
            groups.append(current_group)
            used_ids.update(r["id"] for r in current_group)

    # —————— 后处理：截断最后一个 group（如果需要） ——————
    if groups and max_following_for_last is not None:
        last_group = groups[-1]
        if len(last_group) > max_following_for_last + 1:  # +1 是起始记录本身
            truncated = last_group[:max_following_for_last + 1]
            removed_ids = {r["id"] for r in last_group[max_following_for_last + 1:]}
            used_ids -= removed_ids
            groups[-1] = truncated

    remaining_records = [r for r in records if r["id"] not in used_ids]
    return groups, remaining_records


def extract_wxanli(records):
    keywords = [
        "一、故障现象",
        "单位:",
        "故障名称:",
        "一、基本情况",
        "故障现象及原因:",
        "故障名称：",
        "实例故障"
    ]
    
    # 存储切片
    slices = []
    # 标记已处理的记录索引
    processed_indices = set()
    
    # 查找所有包含关键词的记录位置
    keyword_positions = []
    for i, record in enumerate(records):
        if record.get("type") == "text":
            text = record.get("text", "")
            # 检查是否包含任一关键词
            if any(keyword in text for keyword in keywords):
                keyword_positions.append(i)
    
    # 为每个关键词位置创建切片
    for idx, start_pos in enumerate(keyword_positions):
        # 确定切片结束位置
        if idx + 1 < len(keyword_positions):
            end_pos = keyword_positions[idx + 1]
        else:
            end_pos = len(records)
        
        # 收集当前切片
        slice_records = []
        
        # 添加前2个记录（如果存在且未超出边界）
        for offset in [2, 1]:
            prev_idx = start_pos - offset
            if prev_idx >= 0:
                slice_records.append(records[prev_idx])
                processed_indices.add(prev_idx)
        
        # 添加从关键词位置到下一个关键词位置的所有记录
        for i in range(start_pos, end_pos):
            slice_records.append(records[i])
            processed_indices.add(i)
        
        slices.append(slice_records)
    
    # 收集未处理的剩余记录
    remaining_records = [
        records[i] for i in range(len(records))
        if i not in processed_indices
    ]
    
    return slices, remaining_records

def split_content_bbox(data, max_length=8000):
    contents = []
    highlight_lists = []
    
    current_content = ""
    current_highlights = []

    for ins in data:
        if "type" not in ins:
            continue
        if not ins.get("bbox"):
            continue
        # 提取通用字段
        bbox = ins.get("bbox")
        page_idx = ins.get("page_idx", -1) 

        new_text = ""
        should_record_highlight = False  # 标记是否需要记录 highlight（即使 new_text 为空）

        if ins["type"] == "text":
            text = ins.get("text", "")
            level = ins.get("text_level")
            if level is not None and isinstance(level, int) and level > 0:
                text = "#" * min(level, 6) + " " + text  # 安全限制标题级别
            new_text = text + "\n"
            should_record_highlight = True

        elif ins["type"] == "table":
            table_caption = ins.get("table_caption")
            table_body = ins.get("table_body", "")

            # 清理冗余属性
            for pattern in [' colspan="1"', ' rowspan="1"', " colspan='1'", " rowspan='1'", " colspan=1", " rowspan=1"]:
                table_body = table_body.replace(pattern, "")

            caption_str = ""
            if table_caption:
                if isinstance(table_caption, list):
                    caption_str = "\n".join(str(c) for c in table_caption)
                else:
                    caption_str = str(table_caption)

            # 判断是否有实质内容
            has_caption = bool(caption_str.strip())
            has_body = bool(table_body.strip())

            if has_caption or has_body:
                new_text = caption_str + ("\n" if has_caption else "") + table_body + "\n"
            else:
                new_text = ""  # 空内容，不拼接

            # 即使内容为空，只要是 table 类型，就记录 highlight（满足你的需求）
            should_record_highlight = True

        elif ins["type"] == "image":
            image_caption = ins.get("image_caption", "")
            img_path = ins.get("img_path", "")

            if isinstance(image_caption, list):
                image_caption = "\n".join(str(item) for item in image_caption)
            elif not isinstance(image_caption, str):
                image_caption = str(image_caption)

            if isinstance(img_path, list):
                img_path = "\n".join(str(p) for p in img_path)
            elif not isinstance(img_path, str):
                img_path = str(img_path)

            if image_caption.strip() or img_path.strip():
                new_text = image_caption + "\n" + img_path + "\n"
            else:
                new_text = ""

            should_record_highlight = True

        elif ins["type"] == "discarded":
            text = ins.get("text", "")
            if text.strip():
                new_text = text + "\n"
            else:
                new_text = ""
            should_record_highlight = True

        else:
            continue  # 不支持的 type，跳过且不记录 highlight

        # --- 关键：即使 new_text 为空，只要 should_record_highlight 为 True，就要处理 chunk 切分和 highlight 记录 ---

        # 构造 highlight 项（即使 new_text 为空）
        highlight_item = {"page_idx": page_idx, "bbox": bbox}

        if not new_text.strip() and not should_record_highlight:
            continue  # 完全跳过

        # 检查是否需要切分（仅当 new_text 非空时才影响长度）
        would_exceed = len(current_content) + len(new_text) > max_length

        # 如果 new_text 非空 且 会导致超长，则先保存当前 chunk
        if new_text.strip() and would_exceed:
            if current_content or current_highlights:
                contents.append(current_content.rstrip('\n'))
                highlight_lists.append(current_highlights)
            current_content = new_text
            current_highlights = [highlight_item]
        else:
            # 追加内容（如果 new_text 非空）
            if new_text.strip():
                current_content += new_text
            # 无论如何，只要 should_record_highlight，就加 highlight
            if should_record_highlight:
                current_highlights.append(highlight_item)

    # 保存最后一段
    if current_content or current_highlights:
        contents.append(current_content.rstrip('\n'))
        highlight_lists.append(current_highlights)

    return contents, highlight_lists



def group_records(records):
    result = []
    current_group = []

    for i, ins in enumerate(records):
        if 'text_level' in ins and ins['text_level']:
            # 当遇到新的text_level时，如果current_group非空，则先将其添加到结果中
            if current_group:
                result.append(current_group)
                current_group = []  # 开始新一组
            current_group.append(ins)
        else:
            # 如果当前记录没有text_level或其值为空，则继续添加到当前组
            current_group.append(ins)

    # 别忘了将最后一个组添加到结果中
    if current_group:
        result.append(current_group)

    return result

def get_chunk_bbox_otherfile(data, max_length=8000):
    """
    处理没有 bbox 信息的文件数据（主要面向纯表格类内容）。
    每个 table 作为一个独立切片，不与其他记录拼接。
    
    - 单个 table 内容超过 max_length 时，调用 chunk_reset 在 </tr> 处安全切分，
      切分后的多个 chunk 共享同一组 positions
    - 清理冗余 colspan="1" / rowspan="1" 属性
    - bbox 缺失时填充空列表 []
    
    返回结构与 get_chunk_bbox 一致：[{"content": str, "positions": [...]}]
    """
    slices = []

    for ins in data:
        if ins.get("type") != "table":
            continue

        page_idx = ins.get("page_idx", -1)
        bbox = ins.get("bbox", [])

        table_caption = ins.get("table_caption")
        table_body = ins.get("table_body", "") or ""

        # 清理冗余属性
        for pattern in [
            ' colspan="1"', ' rowspan="1"',
            " colspan='1'", " rowspan='1'",
            " colspan=1", " rowspan=1",
        ]:
            table_body = table_body.replace(pattern, "")

        # 拼接 caption
        caption_str = ""
        if table_caption:
            if isinstance(table_caption, list):
                caption_str = "\n".join(str(c) for c in table_caption)
            else:
                caption_str = str(table_caption)

        has_caption = bool(caption_str.strip())
        has_body = bool(table_body.strip())

        if not (has_caption or has_body):
            continue  # 空表格跳过

        content = caption_str + ("\n" if has_caption else "") + table_body
        positions = [{"page_idx": page_idx, "bbox": bbox}]

        # 单表超长 → 在 </tr> 处切分，多个 chunk 共享 positions
        if len(content) > max_length:
            sub_chunks = chunk_reset(content, max_length)
            for sub in sub_chunks:
                slices.append({
                    "content": sub.rstrip('\n'),
                    "positions": positions
                })
        else:
            slices.append({
                "content": content.rstrip('\n'),
                "positions": positions
            })

    # 按 page_idx 排序，与 get_chunk_bbox 风格一致
    valid_slices = [
        item for item in slices
        if item.get("positions")
        and isinstance(item["positions"], list)
        and len(item["positions"]) > 0
        and "page_idx" in item["positions"][0]
    ]
    valid_slices.sort(key=lambda item: item["positions"][-1]["page_idx"])

    return valid_slices

def get_chunk_bbox(data):
    for idx, item in enumerate(data, start=1):
        item["id"] = idx
    repair_data, clean_repair_records = extract_maintenance_groups_and_remaining(data,max_following_for_last=23)
    operation_data, clean_operation_records = extract_operation_groups_and_remaining(data,max_following_for_last=23)
    wxanli_data, clean_wxanli_data = extract_wxanli(data)
    slices = []
    if len(repair_data) > 0 :
        for ins in repair_data:
            content, highlight_list = split_content_bbox(ins)
            for i, (content, h_list) in enumerate(zip(content, highlight_list)):
                slices.append({
                    "content" : content,
                    "positions":h_list
                })
        groups = group_records(clean_repair_records)
        for ins in groups:
            content, highlight_list = split_content_bbox(ins)
            for i, (content, h_list) in enumerate(zip(content, highlight_list)):
                slices.append({
                    "content" : content,
                    "positions":h_list
                })

        valid_slices = [
            item for item in slices
            if item.get('positions')
            and isinstance(item['positions'], list)
            and len(item['positions']) > 0
            and 'page_idx' in item['positions'][0]
        ]
        slices = sorted(valid_slices, key=lambda item: item['positions'][-1]['page_idx'])
    elif len(operation_data) > 0:
        for ins in operation_data:
            content, highlight_list = split_content_bbox(ins)
            for i, (content, h_list) in enumerate(zip(content, highlight_list)):
                slices.append({
                    "content" : content,
                    "positions":h_list
                })
        groups = group_records(clean_operation_records)
        for ins in groups:
            content, highlight_list = split_content_bbox(ins)
            for i, (content, h_list) in enumerate(zip(content, highlight_list)):
                slices.append({
                    "content" : content,
                    "positions":h_list
                })
        valid_slices = [
            item for item in slices
            if item.get('positions')
            and isinstance(item['positions'], list)
            and len(item['positions']) > 0
            and 'page_idx' in item['positions'][0]
        ]
        slices = sorted(valid_slices, key=lambda item: item['positions'][-1]['page_idx'])

    elif len(wxanli_data) > 0:
        for ins in wxanli_data:
            content, highlight_list = split_content_bbox(ins)
            for i, (content, h_list) in enumerate(zip(content, highlight_list)):
                slices.append({
                    "content" : content,
                    "positions":h_list
                })
        for ins in clean_wxanli_data:
            if not ins.get("bbox"):
                continue
            page_idx = ins.get("page_idx", 0)
            bbox = ins["bbox"]
            positions = [{"page_idx": page_idx, "bbox": bbox}]

            if ins["type"] == "text":
                if ins.get("text_level"):
                    text = ins.get("text", "")
                    level = ins.get("text_level")
                    content = "#" * level + text
                else:
                    content = ins.get("text", "")
            elif ins["type"] == "table":
                content = (ins.get("table_caption") or "") + "\n" + (ins.get("table_body") or "")
            elif ins["type"] == "image":
                image_caption = ins.get("image_caption", [])
                img_path = ins.get("img_path", [])

                # 如果 image_caption 是列表，则将其转换为字符串
                if isinstance(image_caption, list):
                    image_caption = "\n".join(str(item) for item in image_caption)
                elif not isinstance(image_caption, str):
                    image_caption = str(image_caption)

                # 如果 img_path 是列表，则将其转换为字符串
                if isinstance(img_path, list):
                    img_path = "\n".join(str(p) for p in img_path)
                elif not isinstance(img_path, str):
                    img_path = str(img_path)

                if image_caption.strip() or img_path.strip():
                    content = (image_caption or "") + "\n" + (img_path or "")
                else:
                    continue  # 跳过空图像项
            elif ins["type"] == "discarded":
                content = ins.get("text", "")
            else:
                continue

            slices.append({"content": content, "positions": positions})


        valid_slices = [
            item for item in slices
            if item.get('positions')
            and isinstance(item['positions'], list)
            and len(item['positions']) > 0
            and 'page_idx' in item['positions'][0]
        ]
        slices = sorted(valid_slices, key=lambda item: item['positions'][-1]['page_idx'])
    else:
        groups = group_records(data)
        for ins in groups:
            content, highlight_list = split_content_bbox(ins)
            for i, (content, h_list) in enumerate(zip(content, highlight_list)):
                slices.append({
                    "content" : content,
                    "positions":h_list
                })
        valid_slices = [
            item for item in slices
            if item.get('positions')
            and isinstance(item['positions'], list)
            and len(item['positions']) > 0
            and 'page_idx' in item['positions'][0]
        ]
        valid_slices = [
            item for item in slices
            if item.get('positions')
            and isinstance(item['positions'], list)
            and len(item['positions']) > 0
            and 'page_idx' in item['positions'][0]
        ]
        slices = sorted(valid_slices, key=lambda item: item['positions'][-1]['page_idx'])
    return slices

def split_text_preserve_sentences(text, max_length=7500):
    if len(text) <= max_length:
        return [text]

    # 按句子分割，保留标点
    parts = re.split(r'([。！？；!?])', text)
    sentences = []
    for i in range(0, len(parts), 2):
        s = parts[i] + (parts[i+1] if i+1 < len(parts) else '')
        sentences.append(s)

    chunks = []
    current = ""

    for sent in sentences:
        if len(current) + len(sent) <= max_length:
            current += sent
        else:
            if current:
                chunks.append(current)
            else:
                # 单句超长，硬切（极端情况）
                chunks.append(sent[:max_length])
                sent = sent[max_length:]
            current = sent

    if current:
        chunks.append(current)

    return chunks

def data_replace(data, prefix):
    """
    遍历 data 列表，若元素包含 'img_path' 字段，则移除前缀 'images/' 并拼接新前缀。
    使用 pathlib 安全处理路径。
    """
    from pathlib import PurePosixPath
    for ins in data:
        if isinstance(ins, dict) and "img_path" in ins:
            img_path = ins["img_path"]
            p = PurePosixPath(img_path)
            # 如果以 images/ 开头，去掉第一级目录
            if p.parts and p.parts[0] == "images":
                relative_path = str(PurePosixPath(*p.parts[1:]))
                ins["img_path"] = f"![图片]({prefix}{relative_path})"
            else:
                # 否则保留原路径（或按需处理）
                ins["img_path"] = f"![图片]({prefix}{img_path})"
    return data

def filter_content_bbox(data, max_length=3000):
    """
    将 data 中的 text/table/image 内容按字符长度分块（每块不超过 max_length），
    返回 [{"content": str, "highlight_list": list}, ...]
    """
    chunks = []
    current_content = ""
    current_highlight_list = []

    def _flush_chunk():
        """内部函数：将当前内容打包进 chunks，并重置"""
        if current_content or current_highlight_list:
            chunks.append({
                "content": current_content,
                "highlight_list": current_highlight_list.copy()
            })

    for ins in data:
        if "type" not in ins:
            continue

        added_content = ""
        bbox = ins.get("bbox", [])
        page_idx = ins.get("page_idx", -1)

        if ins["type"] == "text":
            text_content = ins.get("text", "")
            added_content = text_content + "\n"

        elif ins["type"] == "table":
            table_caption = ins.get("table_caption")
            table_body = ins.get("table_body")

            caption_str = ""
            if table_caption:
                if isinstance(table_caption, list):
                    caption_str = "\n".join(str(c) for c in table_caption)
                else:
                    caption_str = str(table_caption)

            added_content = caption_str + "\n" + (table_body or "") + "\n"

        elif ins["type"] == "image":
            image_caption = ins.get("image_caption", "")
            img_path = ins.get("img_path", "")

            if isinstance(image_caption, list):
                image_caption = "\n".join(str(item) for item in image_caption)
            elif not isinstance(image_caption, str):
                image_caption = str(image_caption)

            if isinstance(img_path, list):
                img_path = "\n".join(str(p) for p in img_path)
            elif not isinstance(img_path, str):
                img_path = str(img_path)

            if image_caption or img_path:
                added_content = image_caption + "\n" + img_path + "\n"
            else:
                continue  # 跳过空图像项
        else:
            continue

        # 检查加上 added_content 后是否超限
        if len(current_content) + len(added_content) > max_length:
            # 如果当前块非空，先 flush
            if current_content:
                _flush_chunk()
                current_content = ""
                current_highlight_list = []

            # 如果单个 added_content 超过 max_length，仍需保留（避免丢弃）
            if len(added_content) > max_length:
                # 强制截断或直接放入（这里选择直接放入，避免信息丢失）
                current_content = added_content[:max_length]
                current_highlight_list.append({"page_idx": page_idx, "bbox": bbox})
                _flush_chunk()
                # 剩余部分？此处简化处理：忽略超长部分（或可递归拆分，但复杂）
                continue
            else:
                current_content = added_content
                current_highlight_list.append({"page_idx": page_idx, "bbox": bbox})
        else:
            current_content += added_content
            current_highlight_list.append({"page_idx": page_idx, "bbox": bbox})

    # 处理最后一块
    if current_content or current_highlight_list:
        chunks.append({
            "content": current_content,
            "highlight_list": current_highlight_list
        })

    return chunks

def chunk_reset(content,MAX_length=8000):
    chunks = []
    start = 0
    while start < len(content):
        end = start + MAX_length
        if end >= len(content):
            chunks.append(content[start:])
            break
        # 尽量在 </tr> 后面切分
        snippet = content[start:end]
        last_tr_end = snippet.rfind("</tr>")
        if last_tr_end != -1:
            end = start + last_tr_end + len("</tr>")
        else:
            # 如果找不到 </tr>，退回到最近的换行或空白
            last_newline = snippet.rfind("\n")
            if last_newline != -1:
                end = start + last_newline
            else:
                # 实在不行就硬切
                pass
        chunks.append(content[start:end])
        start = end
    return chunks
def chunk_check(data,MAX_length=8000):
    slice_reset = []
    for ins in data:
        content = ins["content"]
        positions = ins["positions"]
        if len(content) <= 8000:
            slice_reset.append(ins)
        else:
            # 使用你的 chunk_reset 函数切分 content
            chunks = chunk_reset(content, MAX_length)
            for chunk in chunks:
                slice_reset.append({
                    "content": chunk,
                    "positions": positions  # 共享原始位置信息
                })
    return slice_reset

def find_ship_info_by_hull(json_file_path, data):
    """
    从NER结果中提取舷号，再从JSON文件中查找对应的舰船信息
    :param json_file_path: JSON文件路径
    :param data: get_entity() 返回的NER结果字典
    :return: 包含 model_name 和 ship_name 的字典，未找到返回 None
    """
    # 1. 提取舷号
    hulls = [
        entity['properties']['舷号']
        for entity in data.get('entities', [])
        if 'properties' in entity and '舷号' in entity['properties']
    ]
    if not hulls:
        return None

    target_hull = hulls[0]

    # 2. 根据舷号查找舰船信息
    try:
        with open(json_file_path, 'r', encoding='utf-8') as f:
            ship_data = json.load(f)

        for item in ship_data:
            if str(item.get('hull_number')) == str(target_hull):
                return {
                    "model_name": item.get('model_name'),
                    "ship_name": item.get('ship_name')
                }

        return None

    except FileNotFoundError:
        print(f"错误：找不到文件 {json_file_path}")
        return None
    except json.JSONDecodeError:
        print("错误：JSON 文件格式不正确")
        return None
def merge_short_slices(slices, min_length=30,filename="122-06A0014-B01003_雷达-使用说明书.pdf"):
    """ 
    合并过短的切片：
    - 如果某切片 content 长度 <= min_length，则将其合并到下一个切片的开头
    - 若处于末尾无下一个切片，则反向合并到上一个切片末尾
    - content 用换行拼接，positions 顺序拼接
    
    Args:
        slices: [{"content": str, "positions": [...]}]
        min_length: 短切片的字符长度阈值（含）
        filename: 用于实体提取的文件名
    
    Returns:
        合并后的 slices 列表
    """
    if not slices:
        return slices

    result = []
    pending_contents = []  # 缓存等待合并到"下一个"的短切片 content
    pending_positions = []  # 缓存对应的 positions

    for ins in slices:
        content = ins.get("content", "") or ""
        positions = ins.get("positions", []) or []

        if len(content) <= min_length:
            # 暂存，等到下一个正常长度的切片再合并
            pending_contents.append(content)
            pending_positions.extend(positions)
        else:
            # 正常切片：把暂存的短切片合并到它的开头
            if pending_contents:
                merged_prefix = "\n".join(pending_contents)
                content = merged_prefix + ("\n" if merged_prefix else "") + content
                positions = pending_positions + positions
                pending_contents = []
                pending_positions = []
            
            result.append({
                "content": content,
                "positions": positions
            })

    # 收尾：如果末尾还有未合并的短切片（后面没有正常切片可合并）
    # 则反向合并到上一个切片末尾
    if pending_contents:
        merged_suffix = "\n".join(pending_contents)
        if result:
            last = result[-1]
            last["content"] = (last["content"] or "") + ("\n" if last["content"] else "") + merged_suffix
            last["positions"] = (last["positions"] or []) + pending_positions
        else:
            # 极端情况：所有切片都很短，整体作为一个切片返回
            result.append({
                "content": merged_suffix,
                "positions": pending_positions
            })

    return result
def find_and_read_content_list(directory, original_filename, encoding='utf-8'):
    """
    根据原始文件名，在指定目录及其子目录下查找对应的 _content_list.json 文件并返回内容。
    """
    # 1. 去除原始文件的后缀，并拼接新的后缀
    # 加上  只获取不带后缀的文件名部分
    base_name = os.path.splitext(original_filename)
    file_name = base_name[0]
    target_filename = f"{file_name}_content_list.json"
    
    print(f"正在查找文件: {target_filename}")

    # 2. 使用 os.walk 递归遍历目录
    for root, dirs, files in os.walk(directory):
        if target_filename in files:
            file_path = os.path.join(root, target_filename)
            
            try:
                with open(file_path, 'r', encoding=encoding) as f:
                    json_data = json.load(f)
                    return json_data
            except json.JSONDecodeError:
                print(f"文件 {file_path} 不是有效的 JSON 格式。")
                return None
            except Exception as e:
                print(f"读取文件 {file_path} 时发生错误: {e}")
                return None
                
    return None

async def process_pdf_file(pdf_path: Path, image_prefix: str,filename:str) -> Optional[Dict[str, Any]]:
    """异步调用 PDF 分析服务并处理响应"""
    doc_result = await process_document(filename)
    if doc_result is not None:
        content_list, images = doc_result
        if content_list and images:
            replaced_content_list = data_replace(content_list, image_prefix)
            slices = get_chunk_bbox(replaced_content_list)
            slices_check = chunk_check(slices, 8000)
            slices_check = merge_short_slices(slices_check, min_length=30,filename=filename) 
            return {"slices": slices_check, "images": images}
    else:
        return {"slices": [], "images": {}}
    api_url = get_api_url()
    try:
        async with aiofiles.open(pdf_path, "rb") as f:
            file_content = await f.read()
        files = {"file": (filename, file_content, "application/pdf")}

        async with httpx.AsyncClient(timeout=60 * 20) as client:
            response = await client.post(api_url, files=files)

        if response.status_code != 200:
            logger.error(f"❌ API 请求失败，状态码: {response.status_code}, 响应: {response.text}")
            return None

        result = response.json()
        data = result.get("data", {})
        content_list = data.get("content_list", [])
        images = data.get("images", {})
        replaced_content_list = data_replace(content_list, image_prefix)
        slices = get_chunk_bbox(replaced_content_list)
        slices_check = chunk_check(slices, 8000)
        slices_check = merge_short_slices(slices_check, min_length=30,filename=filename) 

        return {"slices": [], "images": {}}

    except json.JSONDecodeError:
        logger.error("❌ 响应不是有效的 JSON 格式")
        logger.debug(response.text)
        return {"slices": [], "images": {}}
    except Exception as e:
        logger.error(f"处理 PDF 文件时出错: {e}", exc_info=True)
        return None
    finally:
        release_api_url(api_url)

async def process_other_file(pdf_path: Path, image_prefix: str, filename: str) -> Optional[Dict[str, Any]]:
    """异步调用 Office 文件分析服务并处理响应"""
    # 优先尝试走本地/缓存处理（保持与你原逻辑一致）
    doc_result = await process_document(filename)
    if doc_result is not None:
        content_list, images = doc_result
        if content_list and images:
            replaced_content_list = data_replace(content_list, image_prefix)
            slices = get_chunk_bbox(replaced_content_list)
            slices_check = chunk_check(slices, 8000)
            slices_check = merge_short_slices(slices_check, min_length=30,filename=filename) 
            return {"slices": slices_check, "images": images}
    else:
        return {"slices": [], "images": {}}
if __name__ == "__main__":

    filepath = r"E:\ZKYNLP\Hjunproject\project0506\kgrag\122-06A0014-B01001_发动机-维修手册_content_list.json"
    try:
        with open(filepath, 'r', encoding='utf-8') as file:
            data = json.load(file)
    except Exception as e:
        print(f"读取 JSON 文件时出错：{e}")
        data = []
    # print(len(data))
    start_chars = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "第", "十",
                   "一", "二", "三", "四", "五", "六", "七", "八", "九"]

    data = data_replace(data=data,prefix="/api/v1/knowledge/files/images/")
    slices = get_chunk_bbox(data=data)
    slices_1 =chunk_check(slices, 8000)
    slices_2 = merge_short_slices(slices_1, min_length=30)   # ← 新增这一行


    for ins in slices_2:
        print(ins)
EVƲx}"""
项目配置文件
从.env文件读取配置
"""
import os
from dotenv import load_dotenv
from contextvars import ContextVar
from typing import Optional, Dict, Any

# 加载.env文件
load_dotenv()

# ==================== 大模型配置 ====================
LLM_CONFIG = {
#    "model": "Qwen3.5-35B-A3B",
    "model": "46-qwen3.5-35B",
#    "model": "Qwen3-14B",
    "base_url": "http://192.168.0.46:59800/v1",
    "api_key": "gpustack_dee9ca823290886c_5edfc86aeeeceb1e9ee5162941cb2cb5",
    "temperature": float("0.1"),
    "max_tokens": int("8192"),
    "timeout": int("30")
}

# ==================== 嵌入模型配置 ====================
EMBEDDING_CONFIG = {
    "model": "bge-m3",
    "base_url": "http://192.168.0.46:59700/v1/embeddings",
    "api_key": "gpustack_dee9ca823290886c_5edfc86aeeeceb1e9ee5162941cb2cb5",
    "base_url_v2" : "http://192.168.0.46:59700/v1",
}


# ==================== 线程安全的请求上下文配置 ====================
# 使用 contextvars 存储每个请求的用户配置，确保多用户并发时不会相互干扰
_request_user_config: ContextVar[Optional[Dict[str, str]]] = ContextVar('request_user_config', default=None)

# RAG配置的默认值
_RAG_CONFIG_DEFAULT = {
    "search_endpoint": "http://192.168.0.46:11000/api/v1/knowledge/search/",
    "x-user-id": "1",
    "x-user-name": "testuser",
    "x-role": "admin",
    "kb-id": None,
    "file-id": None
}

class DynamicRAGConfig(dict):
    """
    动态RAG配置类，支持线程安全的请求级配置
    当访问用户相关配置时，自动从当前请求上下文读取
    其他配置项直接返回默认值
    兼容字典的所有操作方式（如 get(), [], in 等）
    """
    def __getitem__(self, key: str):
        # 如果是用户相关配置或知识库参数，从当前请求上下文读取
        if key in ["x-user-id", "x-user-name", "x-role", "kb-id", "file-id"]:
            request_config = _request_user_config.get()
            if request_config and key in request_config:
                return request_config[key]
            # 如果没有设置，返回默认值
            return _RAG_CONFIG_DEFAULT[key]
        # 其他配置项直接返回默认值
        return _RAG_CONFIG_DEFAULT.get(key)
    
    def get(self, key: str, default=None):
        """支持 get() 方法"""
        try:
            return self[key]
        except KeyError:
            return default
    
    def __contains__(self, key: str):
        """支持 in 操作符"""
        return key in _RAG_CONFIG_DEFAULT
    
    def keys(self):
        """返回所有键"""
        return _RAG_CONFIG_DEFAULT.keys()
    
    def values(self):
        """返回所有值（动态读取用户配置）"""
        return [self[key] for key in _RAG_CONFIG_DEFAULT.keys()]
    
    def items(self):
        """返回所有键值对（动态读取用户配置）"""
        return [(key, self[key]) for key in _RAG_CONFIG_DEFAULT.keys()]

# ==================== RAG服务配置 ====================
# 使用动态配置类，支持多用户并发时自动读取各自的配置
RAG_CONFIG = DynamicRAGConfig()

def set_request_user_config(x_user_id: Optional[str] = None, 
                            x_user_name: Optional[str] = None, 
                            x_role: Optional[str] = None,
                            text_kb_id: Optional[str] = None,
                            text_file_id: Optional[str] = None):
    """
    设置当前请求的用户配置和知识库参数（线程安全）
    
    Args:
        x_user_id: 用户ID
        x_user_name: 用户名称
        x_role: 角色
        text_kb_id: 文本检索知识库ID
        text_file_id: 文本检索文件ID
    """
    config = {}
    if x_user_id is not None:
        config["x-user-id"] = x_user_id
    if x_user_name is not None:
        config["x-user-name"] = x_user_name
    if x_role is not None:
        config["x-role"] = x_role
    # 仅当非空字符串时才设置，空字符串时不传入 RAG 接口
    if text_kb_id is not None and str(text_kb_id).strip():
        config["kb-id"] = str(text_kb_id).strip()
    if text_file_id is not None and str(text_file_id).strip():
        config["file-id"] = str(text_file_id).strip()
    _request_user_config.set(config if config else None)

# ==================== 图谱检索服务配置 ====================
GRAPH_SEARCH_CONFIG = {
    "search_endpoint": "http://192.168.0.46:59085/search_graph",
    "graph_timeout": float("30.0"),
    "default_top_k": int("10"),
    "operation_search_endpoint": "http://192.168.0.46:59085/operation_graph_search"
}

# ==================== 设备到系统检索服务配置 ====================
DEVICE_SYSTEM_CONFIG = {
    "endpoint": "http://192.168.0.46:59085/device_to_system",
    "timeout": float("30.0"),
    "default_min_hops": int("2"),
    "default_max_hops": int("8"),
    "default_top_k": int("10")
}

# ==================== 图册检索服务配置 ====================
ATLAS_CONFIG = {
    "endpoint": "http://192.168.0.46:59085/atlas_retrieval",
    "timeout": float("30.0"),
    "default_top_k": int("10")
}

# ==================== 工作流配置 ====================
WORKFLOW_CONFIG = {
    "max_retry_count": int("2"),  # 最大重试次数
    "image_clarity_threshold": float("0.7"),  # 图片清晰度阈值
    "default_timeout": int("30")  # 默认超时时间（秒）
}

# ==================== 服务器配置 ====================
SERVER_CONFIG = {
    "host": "192.168.0.46",
    "port": "59088",
    "base_url": "http://192.168.0.46:59088"
}

# ==================== ASR服务配置 ====================
ASR_CONFIG = {
    "api_base": "http://192.168.0.46:59900/v1",
    "model": "base",
    "language": "zh",
    "timeout": int("30")
}

# ==================== VLM服务配置 ====================
VLM_CONFIG = {
    "api_base" : "http://192.168.0.46:59801/v1",
    "model" :  "Qwen3-VL-8B"
}

# ==================== Neo4J配置 ====================
NEO4J_CONFIG = {
    "uri": "neo4j://192.168.0.46:57687",
    "user": "neo4j",
    "password": "zdht123@"
}

# ==================== 知识库匹配配置 ====================
KB_TREE_CONFIG = {
    "url": "http://192.168.0.46:11000/api/v1/knowledge/knowledge_base/tree"
}

# ==================== 维修反馈统计配置 ====================
REPAIR_FEEDBACK_CONFIG = {
    "url": "http://192.168.0.46:22000",
    "email": "15088888888@163.com",
    "password": "11223344"
}

# ==================== 数据库配置 ====================
POSTGRES_CONNECTION_STRING = "postgresql://postgres:password@192.168.0.46:5432/an_webui"
#POSTGRES_CONNECTION_STRING = "postgresql+psycopg://postgres:password@192.168.0.46:5432/an_webui"
POSTGRES_SQLALCHEMY_URL = "postgresql+psycopg://postgres:password@192.168.0.46:5432/an_webui"


# ==================== 索引配置 ====================
INDEX_CONFIG = {
    "NAME_PROPERTY" : "名称",
    "FULLTEXT_PROPERTY" :"fulltext",
    "EMBEDDING_PROPERTY" : "embedding",
    "SEARCH_LABEL" : "Searchable",
    "VECTOR_INDEX_NAME" : "global_searchable_embedding",
    "FULLTEXT_INDEX_NAME" : "global_searchable_content_search"
}

# ==================== sql表格字段与neo4j节点映射 ====================
MAP_INS={
    "故障模式" : "fault",
    "系统" : "system_name",
    "设备" : "device_name",
    "舷号" : "ship_number",
}

# ==================== neo4j配置 ====================
NEO4J_CONFIG = {
    "uri": "neo4j://192.168.0.46:57687",
    "user": "neo4j",
    "password": "zdht123@"
}
API_URLS = [
      "http://192.168.0.46:59988/analyze-pdf",
    # "http://192.168.0.111:9977/analyze-pdf",
    # "http://192.168.0.111:9978/analyze-pdf",
    #"http://192.168.0.111:9979/analyze-pdf",
    #"http://192.168.0.111:9980/analyze-pdf",
    # "http://192.168.0.111:9975/analyze-pdf",
]
㟃xV#!/usr/bin/env python3
"""
文档转 PDF 工具
使用 LibreOffice 将各种文档格式转换为 PDF

支持格式：
- Word: .doc, .docx, .rtf
- Excel: .xls, .xlsx
- PowerPoint: .ppt, .pptx
- OpenDocument: .odt, .ods, .odp
- 文本: .txt, .csv
- 图片: .jpg, .png (会嵌入PDF)
"""

import subprocess
import os
import sys
from pathlib import Path
from typing import Optional, List
import concurrent.futures


class Doc2PDF:
    """文档转 PDF 转换器"""
    
    SUPPORTED_FORMATS = {
        # 文档
        '.doc', '.docx', '.rtf', '.odt', '.txt',
        # 表格
        '.xls', '.xlsx', '.ods', '.csv',
        # 演示文稿
        '.ppt', '.pptx', '.odp',
        # 图片
        '.jpg', '.jpeg', '.png', '.bmp', '.gif',
        # 其他
        '.html', '.htm', '.xml'
    }
    
    def __init__(self, libreoffice_path: str = 'libreoffice'):
        self.libreoffice_path = libreoffice_path
        self._verify_libreoffice()
    
    def _verify_libreoffice(self):
        """验证 LibreOffice 是否可用"""
        try:
            result = subprocess.run(
                [self.libreoffice_path, '--version'],
                capture_output=True, text=True
            )
            if result.returncode != 0:
                raise RuntimeError("LibreOffice 不可用")
            print(f"✓ 检测到 {result.stdout.strip().split(chr(10))[0]}")
        except FileNotFoundError:
            raise RuntimeError("未找到 LibreOffice，请先安装")
    
    def convert(
        self, 
        input_file: str, 
        output_dir: Optional[str] = None,
        timeout: int = 120
    ) -> str:
        """
        转换单个文件为 PDF
        
        Args:
            input_file: 输入文件路径
            output_dir: 输出目录（默认为输入文件所在目录）
            timeout: 超时时间（秒）
        
        Returns:
            生成的 PDF 文件路径
        """
        input_path = Path(input_file).resolve()
        
        if not input_path.exists():
            raise FileNotFoundError(f"文件不存在: {input_file}")
        
        suffix = input_path.suffix.lower()
        if suffix not in self.SUPPORTED_FORMATS:
            raise ValueError(f"不支持的格式: {suffix}")
        
        if output_dir is None:
            output_dir = str(input_path.parent)
        else:
            output_dir = str(Path(output_dir).resolve())
            os.makedirs(output_dir, exist_ok=True)
        
        cmd = [
            self.libreoffice_path,
            '--headless',
            '--invisible',
            '--nologo',
            '--nofirststartwizard',
            '--convert-to', 'pdf',
            '--outdir', output_dir,
            str(input_path)
        ]
        
        print(f"  转换中: {input_path.name} ...", end=' ', flush=True)
        
        try:
            result = subprocess.run(
                cmd, 
                capture_output=True, 
                text=True, 
                timeout=timeout
            )
            
            if result.returncode != 0:
                print("✗")
                raise RuntimeError(f"转换失败: {result.stderr}")
            
            output_file = os.path.join(output_dir, f"{input_path.stem}.pdf")
            
            if os.path.exists(output_file):
                print("✓")
                return output_file
            else:
                print("✗")
                raise RuntimeError("转换完成但未找到输出文件")
                
        except subprocess.TimeoutExpired:
            print("✗ (超时)")
            raise RuntimeError(f"转换超时 ({timeout}秒)")
    
    def convert_batch(
        self, 
        input_files: List[str], 
        output_dir: Optional[str] = None,
        max_workers: int = 1  # LibreOffice 并发可能有问题，建议设为1
    ) -> List[dict]:
        """
        批量转换文件
        
        Args:
            input_files: 输入文件列表
            output_dir: 输出目录
            max_workers: 并发数
        
        Returns:
            转换结果列表
        """
        results = []
        
        print(f"\n开始批量转换 {len(input_files)} 个文件...\n")
        
        for i, input_file in enumerate(input_files, 1):
            print(f"[{i}/{len(input_files)}]", end='')
            try:
                output_file = self.convert(input_file, output_dir)
                results.append({
                    'input': input_file,
                    'output': output_file,
                    'success': True,
                    'error': None
                })
            except Exception as e:
                results.append({
                    'input': input_file,
                    'output': None,
                    'success': False,
                    'error': str(e)
                })
        
        # 打印统计
        success_count = sum(1 for r in results if r['success'])
        print(f"\n转换完成: {success_count}/{len(results)} 成功")
        
        return results
    
    def convert_directory(
        self, 
        input_dir: str, 
        output_dir: Optional[str] = None,
        recursive: bool = False
    ) -> List[dict]:
        """
        转换目录中的所有支持文件
        
        Args:
            input_dir: 输入目录
            output_dir: 输出目录
            recursive: 是否递归处理子目录
        """
        input_path = Path(input_dir)
        
        if not input_path.is_dir():
            raise NotADirectoryError(f"不是目录: {input_dir}")
        
        # 收集所有支持的文件
        files = []
        pattern = '**/*' if recursive else '*'
        
        for file_path in input_path.glob(pattern):
            if file_path.is_file() and file_path.suffix.lower() in self.SUPPORTED_FORMATS:
                files.append(str(file_path))
        
        if not files:
            print("未找到支持的文件")
            return []
        
        return self.convert_batch(files, output_dir)


def main():
    """命令行入口"""
    import argparse
    
    parser = argparse.ArgumentParser(
        description='使用 LibreOffice 将文档转换为 PDF',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='''
示例:
  python doc2pdf.py document.docx
  python doc2pdf.py document.xlsx -o ./output
  python doc2pdf.py ./documents/ -o ./pdfs -r
        '''
    )
    
    parser.add_argument('input', help='输入文件或目录')
    parser.add_argument('-o', '--output', help='输出目录')
    parser.add_argument('-r', '--recursive', action='store_true', 
                        help='递归处理子目录')
    parser.add_argument('-t', '--timeout', type=int, default=120,
                        help='单个文件转换超时时间（秒）')
    
    args = parser.parse_args()
    
    converter = Doc2PDF()
    
    input_path = Path(args.input)
    
    if input_path.is_file():
        # 单文件转换
        try:
            output = converter.convert(args.input, args.output, args.timeout)
            print(f"\n输出文件: {output}")
        except Exception as e:
            print(f"\n错误: {e}")
            sys.exit(1)
    
    elif input_path.is_dir():
        # 目录转换
        results = converter.convert_directory(
            args.input, 
            args.output, 
            args.recursive
        )
        
        # 显示失败的文件
        failures = [r for r in results if not r['success']]
        if failures:
            print("\n失败的文件:")
            for f in failures:
                print(f"  - {f['input']}: {f['error']}")
    
    else:
        print(f"错误: 路径不存在 - {args.input}")
        sys.exit(1)


if __name__ == '__main__':
    main()
4x   BEAUTIFY_TYPES = {
    "润色": ["金句润色", "书面化", "讲稿化", "规整"],
    "扩写": ["扩写", "续写", "汇报"],
    "推荐": ["金句"],
    "缩写": ["精简", "总结"]
}

BEAUTIFY_TYPE_DICT = {
    "金句润色":
"""你是一位专业文案大师，擅长用精炼的语言创作令人印象深刻的金句。请根据用户提供的文本，在保持原意的基础上进行金句润色，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 对选择的金句进行润色，保证句子结构不变的情况下，将润色后句子进行金句替换。
3. 禁止使用Markdown，不添加无关内容，保持原有用词风格。
4. 最后，通读润色后的文本，确保没有语法错误，表意清晰，金句融入自然。
5. 整体润色后的文本既精炼又富有文采，符合用户的所有要求。
6. 如果有其他要求，则继续考虑到该要求进行金句润色，如果没有，则保持上述要求进行金句润色。
7. 请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出润色后的金句，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要润色的金句如下：{sentence}""",

    "书面化":
"""你是一位专业文案大师，擅长文本改写成书面文字的形式。请根据用户提供的文本，在保持原意的基础上进行书面化改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行书面化改写和润色。
3. 禁止使用Markdown，不添加无关内容，保持纯文本风格，改写后的文本必须严格对应原文，不能添加或删减信息。
4. 考虑公文的要求：书面化、严谨、规范这些要求，避免重复内容出现。
5. 最后，通读书面化改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯，符合公文的庄重风格
6. 如果有其他要求，则继续考虑到该要求进行书面化改写，如果没有，则保持上述要求进行书面化改写。
7. 请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出书面化改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要书面化改写的内容如下：{sentence}""",

    "讲稿化":
"""你是一位专业文案大师，擅长文本改写成讲稿化的形式，即文本转换为正式场合发言的口语化版本。请根据用户提供的文本，在保持原意的基础上进行讲稿化改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行讲稿化改写，并转换为正式场合发言的口语化版本。
3. 将文本中的比喻和描绘转化为更平实的表达，同时保留原有的意境和情感。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，改写后的文本必须严格对应原文，不能添加或删减信息。
5. 避免有过于复杂的词汇或结构，原文中的破折号和星号标记需要去除，改用连贯的句子连接。
6. 最后，通读讲稿化改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯，确保整个发言稿的结构合理，有开头、中间和结尾，符合正式发言的流程。
7. 如果有其他要求，则继续考虑到该要求进行讲稿化改写，如果没有，则保持上述要求进行讲稿化改写。
8，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
9. 只需要输出讲稿化改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要讲稿化改写的内容如下：{sentence}""",

    "规整":
"""你是一位专业文案大师，擅长对文本进行规整，即对文本进行格式规范、内容严谨和语言得体的调整。请根据用户提供的文本，在保持原意的基础上进行规整改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行规整改写。
3. 忽略原文的文学风格，将其转换为符合公文要求的正式、简洁、准确的语言。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，改写后的文本必须严格对应原文，不能添加或删减信息。
5. 检查格式规范，避免抒情和比喻语句，将需要改写的内容转换为客观、准确的描述
6. 需要确认描述的内容是否符合实际情况，是否有数据或政策支持。
7. 语言方面，文本若使用大量文学修辞，需要调整为庄重、简洁的公文语言。
6. 最后，通读规整改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯，确保不遗漏任何关键要素，比如时间、地点、具体设施等，并删除所有口语化或情感化的表达，保持客观中立。
7. 如果有其他要求，则继续考虑到该要求进行规整，如果没有，则保持上述要求进行规整。
8，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
9. 只需要输出规整改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要规整改写的内容如下：{sentence}""",

    "扩写":
"""你是一位专业文案大师，擅长对文本进行扩写，即对选中的文本内容进行扩充。请根据用户提供的文本，在保持原意的基础上进行扩写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行扩写。
3. 扩写的内容不能超过200字，保持在100字到200字这个范围内。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在扩写过程中，扩写后的内容都紧扣原文，不能脱离中心思想。
6. 扩写的内容为公文风格，严格遵守格式和内容规范，确保内容符合公文口吻。
6. 最后，通读扩写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行扩写，如果没有，则保持上述要求进行扩写。
8，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
9. 只需要输出扩写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要扩写的内容如下：{sentence}""",

    "续写":
"""你是一位专业文案大师，擅长对文本进行续写，即对选中的文本内容进行续写。请根据用户提供的文本，在保持原意的基础上进行续写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行续写。
3. 续写的内容不能超过200字，保持在100字到200字这个范围内。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在续写过程中，续写后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
5. 最后，通读续写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
6. 如果有其他要求，则继续考虑到该要求进行续写，如果没有，则保持上述要求进行续写。
7，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出续写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要续写的内容如下：{sentence}""",

    "汇报":
"""你是一位专业文案大师，擅长对文本进行汇报改写，即对选中的文本内容转化为适合口头汇报的口语化内容。请根据用户提供的文本，在保持原意的基础上进行汇报改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并仔细理解文本内容含义。
2. 仔细分析原文的结构和用词，对选择的文本内容进行汇报改写。
3. 将选中内容转化为适合口头汇报的口语化内容，避免使用复杂句式，多用短句和连接词，让内容更自然。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在汇报改写过程中，改写后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
5. 最后，通读汇报改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
6. 如果有其他要求，则继续考虑到该要求进行汇报改写，如果没有，则保持上述要求进行汇报改写。
7，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
8. 只需要输出汇报改写的内容，请不要输出文本内容，严格遵守该指令。
    其他要求如下：{require}
    文本内容如下：{content}
    需要汇报改写的内容如下：{sentence}""",

    "金句":
""" 你是一位专业文案大师，擅长对文本进行金句提取，即从选中文字里找出五句适合润色或替换的金句，然后输出每个句子。请根据用户提供的文本，在保持原意的基础上进行金句提取，要求满足以下条件：
问题: 
文本内容为
在生活的长河中，我们常常追求明确的答案和确定的方向，渴望每一步都踏在坚实的基石上。然而，人生的真谛往往隐藏于那些不确定之中。正如夜空中闪烁的星辰，它们并不总是固定不动，而是随着时间流转而变换位置，却依旧照亮着旅人的道路。
不确定性并非是阻碍前行的绊脚石，而是引导我们探索未知、发现自我的灯塔。每一次面对选择时的犹豫不决，每一个未曾预料到的结果，都是生命赋予我们的宝贵礼物。它们教会我们在变化中寻找平衡，在迷茫里坚守希望。
真正的智慧，并非来自于对所有问题都有确切答案，而是懂得如何在无常的世界里保持内心的平静与坚韧。接受生活中的不确定性，才能真正体会到成长的意义，让心灵在风雨兼程的路上愈发坚强。
这便是人生旅程中最深刻的教诲之一：不是所有的疑问都需要解答，有时候，学会与未知共舞才是最重要的技能。
你可以对给出的文本内容进行详细的阅读和解析，然后输出3至5个金句,请根据以下原则进行生成：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行金句提取。
3. 金句通常是指那些表达精准、富有感染力、能提升文章档次的句子。
4. 润色的地方包括重复的用词、平淡的描述，或者可以更生动、更具文学性的部分，或者使用相关名人名言。
5. 确保句子结构多样，避免重复。比如使用不同的比喻手法，泼墨、银绸、琴键、星辰、寓言，这些意象都符合原文的自然和神秘氛围。
6. 逐条输出每个句子的内容，确认没有超过五句，且每句都是独立的润色点。
7. 如果有其他要求，则继续考虑到该要求进行金句提取，如果没有，则保持上述要求进行金句提取。
8，请将根据上述要求提取后的金句直接输出，不要输出额外的信息描述。


推理过程: 
好的，用户需要我根据提供的文本生成5个符合要求的金句。首先，我要仔细阅读原文，理解核心观点。原文主要讲的是接受生活中的不确定性，学会在未知中成长，强调不确定性的积极意义。接下来，需要运用指定的句式技巧：对偶、对比、排比、追问。用户没有指定具体哪种，所以可以自由组合。
先看对偶，结构对称的句子，比如前半句和后半句字数相近，意义相关。例如原文提到的“不是所有疑问都需要解答，与未知共舞”可以转化为对偶句式。
然后是排比，三个或以上结构相似的句子。原文中有提到“教会我们在变化中寻找平衡，在迷茫里坚守希望”，可以扩展成排比结构，比如“在变化中寻找平衡，在迷茫里坚守希望，在未知里孕育新生。”
对比句式的话，可以用“不是...而是...”的结构，比如“不是被动承受，而是主动拥抱；不是停滞不前，而是破浪乘风。”这样突出不确定性的积极作用。
还要检查是否符合公文语体，避免口语化。比如“让心灵在风雨兼程的路上愈发坚强”比较文学化，可能需要调整，但原文允许适当的文采，所以可以保留。
需要注意不要使用Markdown，严格按JSON格式输出。用户要求5个，所以需要生成五个不同句式，涵盖各种技巧，并确保每个金句都准确提炼原文，不偏离主题。
现在开始逐一构思：
1.使用对比句式，对比过去对不确定性的看法和现在的积极态度：“不确定性不是前行的绊脚石，而是探索的导航仪；不是命运的考验场，而是成长的必修课。”这样既对比了两种观点，又符合对偶结构。
2.排比句式，三个结构相似的分句：“在变化中寻找平衡，在迷茫里坚守希望，在未知里孕育新生。”这里三个“在...中”结构，增强语势。
3.对偶和对比结合：“不是所有疑问都需要解答，有时答案在追寻中显现；不是所有方向都必须明确，真正的道路在脚下延伸。”前半句对偶，后半句对比，突出核心观点。
4.另一个排比结构，强调关键动词：“以平静接纳无常，以坚韧应对挑战，以智慧点亮未知。”三个“以...”结构，简洁有力。
5.对比和排比的混合：“与未知共舞，方知生命之广阔；与变化同行，方见成长之壮美。”这里用对偶结构，两个“与...方...”句式，形成对比和节奏感。
检查每个金句是否准确反映原文，是否有套话，确保信息密度高。例如第四个金句中的“以智慧点亮未知”呼应了原文的“智慧来自于如何在无常中保持平静”。第五个金句中的“与未知共舞”直接引用原文关键句，符合要求。
最后，确保每个金句在句式上各有不同，涵盖对偶、排比、对比，并且语言庄重简洁，符合公文要求。没有使用反问，避免尖锐，保持设问的引导性。完成五个金句后，进行输出。

答案: 
                
不确定性不是前行的绊脚石,而是探索的导航仪；不是命运的考验场,而是成长的必修课。\n
                
在变化中寻找平衡,在迷茫里坚守希望,在未知里孕育新生。\n
                
不是所有疑问都需要解答,有时答案在追寻中显现；不是所有方向都必须明确,真正的道路在脚下延伸。\n
                
以平静接纳无常,以坚韧应对挑战,以智慧点亮未知。\n
                
与未知共舞,方知生命之广阔；与变化同行,方见成长之壮美。\n

问题: 
文本内容为
在公文写作中，这句话前有“蔓发”，后有“可望”，预示着更大的成功指日可待。这一句适合用在写于冬末春初时的文章中，如团拜会上的讲话、一项工作开始之初、一个项目开展之初等。
,对给出的文本内容进行详细的阅读和解析，然后输出3至5个金句,请根据以下原则进行生成：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行金句提取。
3. 金句通常是指那些表达精准、富有感染力、能提升文章档次的句子。
4. 润色的地方包括重复的用词、平淡的描述，或者可以更生动、更具文学性的部分，或者使用相关名人名言。
5. 确保句子结构多样，避免重复。比如使用不同的比喻手法，泼墨、银绸、琴键、星辰、寓言，这些意象都符合原文的自然和神秘氛围。
6. 逐条输出每个句子的内容，确认没有超过五句，且每句都是独立的润色点。
7. 如果有其他要求，则继续考虑到该要求进行金句提取，如果没有，则保持上述要求进行金句提取。
8，请将根据上述要求提取后的金句直接输出，不要输出额外的信息描述。

推理过程: 
好的，我需要为用户的公文内容生成三到五个金句，主要使用对偶、对比、排比和追问句式。首先，用户提供的原文是关于冬末春初的文章，比如团拜会讲话或项目开始阶段，强调“蔓发”和“可望”，预示成功即将到来。首先分析原文的关键点：“蔓发”意味着开始生长，有蓬勃发展的势头；“可望”表示目标在望，成功在即。需要将这两个概念融入金句中，同时适合公文的正式语境。
考虑对偶句式，结构对称。比如“春山蔓发启新程，锦绣可望向未来”，前半句描述开始，后半句展望未来，符合冬末春初的时间点。
接下来是排比，可能需要三个结构相似的短语。例如“蔓发的是奋进的号角，可望的是丰收的硕果，升腾的是跨越的信心”，三个部分都围绕核心概念展开，增强语势。
对比句式可以强调变化，比如“不是简单的时序更替，而是发展的厚积薄发；不是寻常的春耕夏耘，而是事业的乘势而上”，突出现在与过去的不同，强调积累和机遇。
另一个对偶句：“冬寒未尽蕴生机，春意已彰展宏图”，对比冬寒与春意，展示转折点，符合原文的时间背景。
最后用排比加强气势：“以蔓发之势抢抓机遇，以可望之志勇攀高峰，以笃行之姿再创辉煌”，三个“以...之...”结构，层层递进，适合工作或项目初期的动员。
需要确保每个金句都紧扣原文，不使用套话，保持公文庄重的语气。检查是否符合句式要求，如对偶的结构是否对称，排比是否有三个以上的相似结构，对比是否清晰。然后按适用程度排序，把最贴切、结构最工整的放在前面。

答案: 
                
春山蔓发启新程,锦绣可望向未来。\n
                
蔓发的是奋进的号角,可望的是丰收的硕果,升腾的是跨越的信心。\n
                
不是简单的时序更替,而是发展的厚积薄发；不是寻常的春耕夏耘,而是事业的乘势而上。\n
                
冬寒未尽蕴生机,春意已彰展宏图。\n
                
以蔓发之势抢抓机遇,以可望之志勇攀高峰,以笃行之姿再创辉煌。\n
        
其他要求如下：{require}
需要进行金句提取的内容如下：{content}
""",

    "精简":
"""你是一位专业文案大师，擅长对文本进行精简，即对选中文本进行精简缩写。请根据用户提供的文本，在保持原意的基础上进行精简，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行精简。
3. 确保精简后的文本保留文本中原有元素，但用更简洁的语言表达。
4. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
5. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在精简过程中，精简后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
6. 最后，通读精简后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行精简，如果没有，则保持上述要求进行精简。
8，请将根据上述要求精简后的内容直接输出，不要输出额外的信息描述。
    其他要求如下：{require}
    文本内容如下：{content}
    需要进行精简的内容如下：{sentence}""",

    "总结":
"""你是一位专业文案大师，擅长对文本进行总结，即将选中文本总结为一段话。请根据用户提供的文本，在保持原意的基础上进行总结，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行总结，将其总结为一段话。
3. 确保提取文本中的关键信息，比如时间地点人物等元素，同时，要注意保留原文的意境。将这些元素组织成一段连贯的话，确保语言简洁，涵盖所有要点。需要避免使用复杂结构，保持口语化但专业。
4. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
5. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在总结过程中，总结后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
6. 最后，通读总结后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行总结，如果没有，则保持上述要求进行总结。
8，请将根据上述要求总结后的内容直接输出，不要输出额外的信息描述。
    其他要求如下：{require}
    文本内容如下：{content}
    需要进行总结的内容如下：{sentence}""",

    "":
"""你是一位专业文案大师，擅长对文本进行改写，即根据选中的文本，在保持原意的基础上进行改写，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容，按照用户输入的要求进行改写，
3. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
4. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在改写过程中，改写后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
5. 最后，通读改写后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
6，请将根据上述要求改写后的内容直接输出，不要输出额外的信息描述。
    用户输入的要求如下：{other_require}
    文本内容如下：{content}
    需要进行改写的内容如下：{sentence}"""
}


GENERATE_NORMAL_OUTLINE_PROMPT = """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
** 撰写{template}大纲时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的{template}大纲长度应控制在{length}字以内。需要合理分配各部分内容，大纲的结构要符合中文的层级，比如用一、（一）、1.这样的编号。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}大纲的格式需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}大纲格式的相关内容，必须严格按照{template}大纲格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。
**规则9**：大纲只生成标题不生成内容。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
** 输出格式如下：
## 一、标题
### （一）子标题
### （二）子标题
....
## 二、标题
### （一）子标题
### （二）子标题
...
输出示例：
## 一、活动背景
## 二、活动目的
## 三、活动内容
### （一）开幕式
### （二）正式比赛
### （二）闭幕式
## 四、活动总结
** 检查：
1.严格按照上述格式生成，生成内容大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
2.只生成标题，不深城其他额外内容。
3. 上述要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行{template}大纲撰写。"""


GENERATE_MARKDOWN_LIST_OUTLINE_PROMPT = """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
** 撰写{template}大纲时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的{template}大纲长度应控制在{length}字以内。需要合理分配各部分内容，大纲的结构要符合中文的层级，比如用一、（一）、1.这样的编号。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}大纲的格式需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}大纲格式的相关内容，必须严格按照{template}大纲格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。
**规则9**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则10**：编写方法大纲时，按照输出示例的格式进行编写,只产生格式和标题，不产生内容。
**规则11**：不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
**规则12**：大纲只生成标题不生成内容。
**规则13**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
** Markdown有序列表语法的连续嵌套格式如下：
1. 标题
    1. 标题
        1. 标题
** 输出示例：
1. 确定学习目标
    1. 设定具体目标
        1. 上半年目标
        2. 下半年目标
    2. 选择合适的学习资源
2. 构建基础知识
    1. 学习基本概念
    2. 掌握编程环境
** 检查：
1. 编写方法大纲时，按照输出示例的格式进行编写,只产生格式和标题，不产生内容。
2. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
3. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行{template}大纲撰写。"""


GENERATE_METHOD_OUTLINE_PROMPT = """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
** 撰写{template}大纲时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}大纲不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的{template}大纲长度应控制在{length}字以内。需要合理分配各部分内容，大纲的结构要符合中文的层级，比如用一、（一）、1.这样的编号。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}大纲的格式需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}大纲格式的相关内容，必须严格按照{template}大纲格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。
**规则9**：编写方法大纲时，按照输出示例的格式进行编写,只产生格式和标题，不产生内容。
**规则10**：大纲只生成标题不生成内容。
**规则11**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
** 输出示例：
## 第一章 总 则
### 第一条 
### 第二条 

## 第二章 分 则
### 第三条 

##  第三章 附 则
### 第XX条
** 检查：
1. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
2. 大纲只生成标题不生成内容。
3. 上述要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行{template}大纲撰写。"""


WRITE_PROMPT = """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写{template}时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的{template}不得脱离文章标题：{title}和文章大纲内容，需要围绕文章标题和文章大纲内容的主旨进行撰写。
**规则3**：撰写的{template}长度应控制在{length}字以内。需要分析文章大纲内容，确保每个小标题都得到充分展开，同时，需要合理分配各部分内容，确保每个部分都符合要求，如果需要成文日期用阿拉伯数字，格式正确。
**规则4**：如果内容要求：{requirement}不为空，撰写的{template}内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的{template}的内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：只能生成符合{template}格式的相关内容，必须严格按照{template}格式，确保没有使用任何被禁止的格式或无关内容。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：严格按照文章大纲：{outline}的格式输出，只对已有文章大纲：{outline}的内容做填充，格式标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。

** 检查：
1. 格式必须和文章大纲：{outline}一样，只对文章大纲：{outline}进行内容填充标题不变。
2. 严格按照文章篇幅要求生成字数。
3. 必须满足上述条件，如果不满足重新思考输出。
请根据以上内容进行{template}撰写。"""

WRITE_NOTIFY_PROMPT = """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写通知时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的通知不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的通知长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的通知内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的通知的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排。
**规则7**：只能生成符合通知格式的相关内容，必须严格按照通知格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”等，并且成文日期用阿拉伯数字，格式正确。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。

请根据以上内容进行通知撰写。"""


WRITE_REPORT_PROMPT = """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
报告大纲：{outline}，
文章大纲：{outline}，
** 撰写报告时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的报告不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的报告长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的报告内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的报告的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**：不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
**规则11**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。

** Markdown有序列表语法的连续嵌套格式
1. 标题
    1. 标题
        1. 标题
** 输出示例：
<nospace>主送机关：市场部</nospace>
<text>
2025年一季度，全球经济复苏动能分化，国内经济在“稳增长、调结构、促改革”政策基调下实现平稳开局。我行紧密围绕国家战略导向，坚持“服务实体、防控风险、深化改革”三大主线，推动业务规模稳健增长、结构持续优化。
1. 主要经营指标完成情况
    1. 规模与效益
        资产规模：截至季末，全行资产总额XX万亿元，同比增长XX%，增速居同业前列。
        营收与利润：实现营业收入XX亿元，同比增长XX%；净利润XX亿元，同比增长XX%，盈利能力保持行业第一梯队。
    2. 资产质量与风险抵御能力
        不良贷款率：XX%，较年初下降XX个基点，资产质量持续改善。
        拨备覆盖率：XX%，风险抵补能力进一步增强。
2. 重点战略推进成效
    1. 数字化转型：从“线上化”到“智能化”
        1. 技术投入
            研发支出XX亿元，同比增长XX%，AI客服覆盖率提升至XX%，智能风控系统拦截可疑交易XX万笔。
        2. 场景生态
            手机银行MAU（月活跃用户）突破XX万，新增“智慧园区”“跨境e汇”等场景服务，线上贷款审批效率提升XX%。
</text>
<div style="text-align: right>机关短署名：市场运营部</div>
<div style="text-align: right>20××年×月×日</div>
** 检查：
1. 如果有连续嵌套标题形式必须改为markdown有序列表语法的输出形式。
2. 连续嵌套标题序号必须为“1. ”，“2. ”，“3. ”...这种形式,不可以是“（1）”，“一.”等这种形式。
3. 输出格式参考输出示例。正文必须用<text></text>包裹，机关短署名必须用<div style="text-align: right></div>包裹，落款时间必须用<div style="text-align: right></div>包裹。
4. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”等“数字.数字”的形式也不能出现“（数字）”的形式。
5. 如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，增加署名和时间。
6. 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
7. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行报告撰写。"""

WRITE_METHOD_PROMPT = """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写办法时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的办法不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的办法长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的办法内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的办法的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：结尾不需要加落款，时间等。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
** 输出示例：
## 第一章 总 则
### <strong>第一条</strong> 为规范××××行为，加强××××管理，保障××××合法权益，依据《中华人民共和国××法》《×××条例》等有关法律法规，结合本地区/本单位实际，制定本办法。 
### <strong>第二条</strong> 本办法适用于本行政区域内/本系统内从事××××活动的单位和个人。

## 第二章 分 则
### <strong>第三条</strong> 本部门对从事××××活动的单位，应当具备下列条件：
（一）具有合法的主体资格；
（二）具备相应的技术能力和专业人员；

##  第三章 附 则
### <strong>第XX条</strong> 本办法所称“××××”，是指……（可对关键术语进行解释）。
** 检查：
1. 每一条内容必须被<strong>/<strong>包裹。必须要从“第一章”开始生成。
2.只在每章结束后换一空白行。
3. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行办法撰写。"""

WRITE_HAN_PROMPT =  """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写函时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。函是指不相隶属机关之间商洽工作、询问和答复问题，请求批准和答复审批事项时所使用的公文。
**规则2**：撰写的函不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的函长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的函内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的函的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则9**：结尾不需要加落款，时间等。
**规则10**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
** Markdown有序列表语法的连续嵌套格式
1. 标题
    1. 标题
        1. 标题
** 输出示例：
<nospace>主送机关：XX市公安局交通警察支队</nospace>
<text>
为深入贯彻落实《国家综合立体交通网规划纲要》精神，加快推进我市智慧交通建设，提升城市交通管理智能化、精细化水平，我局拟于近期组织开展“XX市智慧交通系统建设与应用”专题调研。
1. 调研目的
    1. 总体目标
        此次调研旨在总结我市智慧交通发展经验，研究解决共性问题，为下一步优化顶层设计、推动跨部门协同提供决策参考。
    2. 具体目标
        收集并分析智慧交通系统建设中的成功案例。探讨并解决当前智慧交通建设中遇到的技术和管理难题。建立长期有效的合作交流机制，促进信息共享和技术进步。
2. 请求事项
    1. 资料提供
        1. 技术资料
            恳请贵单位提供近年来在智慧交通平台建设、关键技术应用、数据资源整合利用等方面的总结报告、技术文档。
        2. 其他资料
            恳请贵单位提供近年来在智慧交通平台的其他资料。
</text>
** 检查：
1. 如果有连续嵌套标题形式必须改为markdown有序列表语法的输出形式。
2. 连续嵌套标题序号必须为“1. ”，“2. ”，“3. ”...这种形式,不可以是“（1）”，“一.”等这种形式。
3. 输出格式参考输出示例。正文必须用<text></text>包裹,机关短署名必须用<div style="text-align: right></div>包裹，落款时间必须用<div style="text-align: right></div>包裹。
4. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”，“（1）”等。
5. 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
6. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行函撰写。"""

WRITE_WORK_SUMMARY_PROMPT =  """角色：{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
** 撰写工作总结时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的工作总结不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的工作总结长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的工作总结内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的工作总结的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则8**：当输出有连续嵌套标题格式时比如“1. ”,“1.1. ”,“1.1.1. ”这种嵌套格式，改为Markdown语法的有序列表形式。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
** Markdown有序列表语法的连续嵌套格式
1. 标题
    1. 标题
        1. 标题
** 输出示例：
<text>
20XX年，在上级党委（或主管部门）的坚强领导下，我单位坚持以习近平新时代中国特色社会主义思想为指导，深入学习贯彻党的二十大精神，紧紧围绕年度中心工作和重点任务，牢牢把握高质量发展主题，主动适应新形势、新任务、新要求，凝心聚力、攻坚克难，扎实推进各项工作落实落地，较好地完成了全年各项目标任务，为推动单位（或行业/地区）发展作出了积极贡献。
1. 主要成绩与做法
    1. 聚焦主责主业，核心业务实现新突破
        1. 重点项目取得关键进展
            全力推进XXX重大项目建设，完成投资XX亿元，主体工程如期封顶（或：顺利投产运行）；成功实施XXX技术改造，生产效率提升
2. 经验与体会
    1. 服务大局是核心要求
        必须紧紧围绕中心任务，找准定位，主动作为，才能体现价值、赢得支持。
    2. 改革创新是不竭动力
        面对新挑战，唯有勇于创新、深化改革，才能破解难题、激发活力。
</text>
<div style="text-align: right>发文机关署名（加盖公章）</div>
<div style="text-align: right>20XX年X月X日</div>

**内容要求：
1. 开头用于总结的开头主要用来概述基本情况，有需要时可以列出前言部分。开头包括单位名称，工作性质、主要任务、时代背景、指导思想，以及总结目的、主要内容提示等。总结的开头要注意简明扼要，文字不宜过多。
2. 主体主要内容包括成绩和做法、经验和教训、今后打算等。这部分篇幅长、内容多，要特别注意使层次分明、条理清楚。
3. 结尾一般应在总结经验教训的基础上，提出今后的方向、任务和措施，表明决心、展望前景，篇幅不应过长。有时总结也可以省略结尾，不用专门书写。

** 检查：
1. 如果有连续嵌套标题形式必须改为markdown有序列表语法的输出形式。
2. 连续嵌套标题序号必须为“1. ”，“2. ”，“3. ”...这种形式,不可以是“（1）”，“一.”等这种形式。
3. 输出格式参考输出示例。正文必须用<text></text>包裹。
4. 严格参照markdown有序列表嵌入方式不能出现“1.1”，“1.2”，“（1）”等。
5. 如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，增加署名和时间。
6. 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
7. 上述格式要求必须满足，如果不满足，则重新思考输出，直到满足要求为止。
请根据以上内容进行函撰写。"""


WRITE_ANNOUNCEMENT_PROMPT = """{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写公告时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的公告不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的公告长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的公告内容需要严格遵守内容要求。如果内容要求：{requirement}为空，也请为该公共撰写合理的公告事项。
**规则5**：如果参考材料：{references}不为空，撰写的公告的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合公告格式的相关内容，必须严格按照公告格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
请根据以上内容进行公告撰写。"""


WRITE_REQUEST_PROMPT = """{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写请示时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的请示不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的请示长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的请示内容需要严格遵守内容要求所包含请示机关和请示缘由。如果内容要求：{requirement}为空，也请为该请示撰写合理的请示机关和请示缘由。
**规则5**：如果参考材料：{references}不为空，撰写的请示的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字，直接呈现内容。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合请示格式的相关内容，必须严格按照请示格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
请根据以上内容进行请示撰写。"""

WRITE_DOCUMENT_PROMPT = """{role}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写文书时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的文书不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的文书长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的文书内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的文书的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字，直接呈现内容。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合文书格式的相关内容，必须严格按照文书格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
请根据以上内容进行文书撰写。"""

WRITE_RESPONSE_PROMPT = """{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写批复时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的批复不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的批复长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。批复的主送机关，必须和请示的机关一致，需要使用全称或规范化简称，不能随意简化。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的批复内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的批复的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合批复格式的相关内容，必须严格按照批复格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。结尾部分用“此复”或“特此批复”。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
请根据以上内容进行批复撰写。"""

WRITE_PLAN_PROMPT = """{role}，
文章标题：{title}，
文章篇幅：{length}，
内容要求：{requirement}，
参考材料：{references}，
文章大纲：{outline}，
## 撰写方案时遵循以下规则：
**规则1**：如果角色：{role}不为空，那么你就是这个角色。
**规则2**：撰写的方案不得脱离文章标题：{title}，需要围绕文章标题所含有的主旨进行撰写。
**规则3**：撰写的方案长度应控制在{length}字以内。需要合理分配各部分内容，确保开头简明扼要，主体详细，结尾简洁。确保内容充实但不过于冗长。
**规则4**：如果内容要求：{requirement}不为空，撰写的方案内容需要严格遵守内容要求。
**规则5**：如果参考材料：{references}不为空，撰写的方案的格式和内容需要参考参考材料。
**规则6**：不要添加无关内容，比如字数统计或解释性文字。不得生成重复内容，发文机关署名和成文日期需要正确编排，并且成文日期用阿拉伯数字，格式正确。
**规则7**：只能生成符合方案格式的相关内容，必须严格按照方案格式，确保没有使用任何被禁止的格式或无关内容，比如“此致敬礼”等书信用语。确保每个部分都符合要求，比如结构层次使用“一、”“（一）”“1.”，结构清晰，语言严谨。结尾部分用“此复”或“特此方案”。
**规则8**：输出为Markdown格式，输出时不要添加 ```markdown 的标识。同时，不能漏掉标题。如果文章篇幅：{length}比较长，每个部分要展开详细写作，特别是二级、三级标题的内容，可能需要引经据典来增加权威性和详细度。如果文章篇幅：{length}比较短，每个部分内容进行合理，精简，准确撰写。
**规则9**：如果文章大纲不为空，严格按照文章大纲的格式输出，只对已有文章大纲的内容做填充，格式、标题不变。
**规则10**： 必须严格按照文章篇幅：生成字数必须在{length}字以内，不能超过给定字数范围，也不能低于给定字数范围，必须遵守该规则。
请根据以上内容进行方案撰写。"""

TEMPLATE_DICT = {
    "通知": WRITE_NOTIFY_PROMPT,
    "报告": WRITE_REPORT_PROMPT,
    "公告": WRITE_ANNOUNCEMENT_PROMPT,
    "请示": WRITE_REQUEST_PROMPT,
    "文书": WRITE_DOCUMENT_PROMPT,
    "批复": WRITE_RESPONSE_PROMPT,
    "方案": WRITE_PLAN_PROMPT,
    "工作总结":WRITE_WORK_SUMMARY_PROMPT,
    "函":WRITE_HAN_PROMPT,
    "方法": WRITE_METHOD_PROMPT,
}

##Qwen3-14B
WRITE_LEARNING_PLAN_PROMPT_0 = """<optimized_prompt>
{title}中内容：{doc_content}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
其他要求：{other_require}
学时：{time_1}
授课方式：{jiangshou_type}
注意：
** 只生成与当前章节名称：{chapter}相关内容。**
<instructions>
** 根据用户上传文件生成教学目标，教学目标必须贴合节名称。
** 生成教学目标必须满足以下格式要求。
** 生成字数300字左右。
</instructions>
## 格式要求如下：
<output_format>
# 一、教学目标
（一）知识目标

（二）能力目标

</output_format>
## 检查以下条件必须满足：
1. **严格按照给定格式生成内容。**
2. **生成内容不能重复，不能有解释等无关内容。**
3. **在生成内容后面不要加入字数描述，例如“（160字）。**
4. **必须满足上述需求，如果不满足，重新生成。**
</optimized_prompt>
"""


WRITE_LEARNING_PLAN_PROMPT_1 = """<optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
教授方法：{jiangshou_type}
年级：{level}
科目：{subj}
其他要求：{other_require}
注意：
** 在上一轮生成的内容基础上继续生成，开始生成的时候请换行（\n\n）与上一轮生成区分。**
** 不要生成与上一轮生成内容相同的东西。例如“一、教学目标。**
** 不要对上一轮生成内容进行任何操作（更新，优化，删除等）。**
** 只生成当前章节名称：{chapter}相关内容。**
<instructions>
** 参考{doc_content}中内容和知识库内容进行生成。
** 确保所有内容必须基于知识库内容进行拓展，不能脱离知识库凭空编造。**
** 确保内容要关注起承转合，教学活动衔接自然，必要时可加入表格对比知识点。**
** “# 二、教学重点与难点”生成的内容总字数为400字，“# 三、授课方法”生成字数为400字，请合理分配每个子章节内容**
** 确保当前生成的内容围绕当前章节：{chapter}检索知识库内容进行生成。**
** 教学重点要突出章节重点，包含该章节重点基础理论、原理、应用场景等。**
** 教学难点要根据该章节内容，列出该章节内容对学生理解比较晦涩难懂的概念，理论和在场景中的应用方法。**
** 教学手段包含：多样化教学（讲授、案例分析、小组合作、项目式学习、翻转课堂等）、技术辅助（使用多媒体、在线平台(如学习管理系统)、虚拟实验工具等）、  差异化教学（针对不同学习能力的学ߢ ]生提供分层任务或辅导）等等。**
** 强制按照给定的格式生成。
</instructions>
## 格式要求如下：
<output_format>
# 二、教学重点与难点
##  1.教学重点

##  2.教学难点

# 三、授课方法
##  1.授课方式
    {jiangshou_type}
##  2.教学手段
    
</<output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（180字）”**
</optimized_prompt>
"""

WRITE_LEARNING_PLAN_PROMPT_2 = """<optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
授课方式：{jiangshou_type}
其他要求：{other_require}
注意：
** 请在上一轮生成内容的基础上继续生成，**换行（\n\n）与之前内容区分**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** 教学方法设计要**
** 时间分配考虑学时{time_1},如果{time_1}为一学时，时间为45分钟。如果为二学时，时间为90分钟,以此类推**
** 该章节生成的内容总字数为500字，合理分配每个子章节字数。**
</instructions>
## 格式要求如下：
<output_format>
# 四、教学过程设计
##  1.教学内容设计
    
##  2.教学方法设计
    
##  3.时间分配
      
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
"""


WRITE_LEARNING_PLAN_PROMPT_3 = """<optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
授课方式：{jiangshou_type}
其他要求：{other_require}

注意：
** 请在上一轮生成内容的基础上继续生成，**换行（\n\n）与之前内容区分**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** 仔细读取{title}中内容和参考知识材料，“## 4.板书设计”目标是生成符合{chapter}的章节目录。**
** 严格按照以下格式生成。
</instructions>
## 格式要求如下：
<output_format>
##  4.板书设计
## 1.标题
## 1.1.标题
## 2.标题
## 2.1.标题
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
5. **在生成内容后面不要加入描述，不要解释原因”**
</optimized_prompt>
"""







WRITE_LEARNING_PLAN_PROMPT_4 = """<optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
授课方式：{jiangshou_type}
其他要求：{other_require}
注意：
** 请在上一轮生成内容的基础上继续生成，**换行（\n\n）与之前内容区分**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** 仔细读取{title}中内容和参考知识材料，“# 五、小节与作业”目标是达成教学目标、巩固学习效果需求，从而布置作业题、思考题、阅读参考资料、复习和预习等课前或课后学习任务，输出内容要紧紧贴近“章节名称”这个主题，力求清晰、明确，该章节生成的内容总字数为500字，每个子章节生成100字。**
** 严格按照以下格式生成。
</instructions>
## 格式要求如下：
<output_format>
# 五、小节与作业
##  1.作业题
      
##  2.思考题
      
##  3.阅读参考资料
      
##  4.复习
      
##  5.预习
      
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
"""

WRITE_LEARNING_PLAN_PROMPT_5 = """<optimized_prompt>
{title} 中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
其他要求：{other_require}
注意：
** 请在上一轮生成内容的基础上继续生成，**换行（\n\n）与之前内容区分**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计，五、小节与作业”等标题，直接从当前章节对应的内容开始**
** 不得对已有内容进行更新、优化或删除等操作**
** 仅生成当前章节名称："{chapter}"相关的内容，不能偏离。**
<instructions>
** 教学内容设计要紧贴{chapter}进行生成，不能偏离。合理规划每一内容的生成顺序，循序渐进，避免重复生成。**
** “## 导入新课”内容生成字数为800字。导入新课要求将教学内容自然过渡到当前章节{chapter}，为接下来的教学做准备。**
** 严格按照以下格式生成。
</instructions>
## 格式要求如下：
<output_format>
# 六、教学内容
##  1.导入新课

</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
"""





## 1.{step}. {chapter}
#教案生成
WRITE_LEARNING_PLAN_PROMPT_6 = """<optimized_prompt>
{title}中内容：{doc_content}
案例：{all_case}
上一轮生成的内容：{text}
章节名称：{chapter}
序号：{step}
数据库内容：{reference_sql}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
年级：{level}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成章节名称：{chapter}”相关内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于1000字**；
**  生成“标题”，“内容”不能重复。** 
**  围绕章节名称：{chapter}，结合知识库内容和数据库内容生成。** 
**  如果案例不为空生成内容必须包含对应案例，使用案例不能重复** 
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
### 2.{step}.1.标题 

### 2.{step}.2.标题

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **“2.{step}.1.标题”，“2.{step}.2.标题”必须有，生成标题与{chapter}相关。**
3. **严格按照给定格式生成内容**
4. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
5. **在生成内容后面不要加入字数描述，例如“（1000字）”**
6. **生成完2.{step}.2.内容后结束生成，禁止生成2.{step}.3.标题和内容**
7. **必须生成“2.{step}.2.标题”的内容，不能只生成到“2.{step}.1.标题”内容就终止生成。**
8. **格式中所有“标题”字样必须替换为和{chapter}内容相关的具体标题，“内容”必须是模型参考知识库和数据库生成和{chapter}相关的内容。**
9. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
10. **强制生成内容不能重复**
</optimized_prompt>
"""
# ** 必需满足生成按照上述格式要求生成，字数是否符合要求，内容与之前生成不重复这几个基本要求。



WRITE_LEARNING_PLAN_PROMPT_12 = """<optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter_1}
子章节一名称：{title_1_real}
子章节一相关内容：{content_1}
序号：{step}
一序号：{step_1}
子章节一知识库内容：{reference_1}
年级：{level}
科目：{subj}
学时：{time_1}
年级：{level}
其他要求：{other_require}
注意：
** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于1000字**；
**  生成“标题”，“内容”不能重复。** 
**  2.{step}.{step_1}.{title_1_real}生成的内容参考子章节一相关内容和子章节一知识库内容进行生成** 
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  必须严格按照下面格式生成：**
<instructions>

<output_format>
### 2.{step}.{step_1}.{title_1_real}

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
4. **生成内容必须与“2.{step}.{step_1}.{title_1_real}”相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
5. **在生成内容后面不要加入字数描述，例如“（1000字）”**
6. **生成完“2.{step}.{step_1}.{title_1_real}”内容后结束生成，禁止生成2.{step}.2.标题和内容**
7.**强制生成内容不能重复。**
</optimized_prompt>
"""


WRITE_LEARNING_PLAN_PROMPT_13 = """<optimized_prompt>
{title}中内容：{doc_content}
案例：{case_2}
上一轮生成的内容：{text}
章节名称：{chapter_1}
子章节二名称：{title_2_real}
子章节二相关内容：{content_2}
序号：{step}
二序号：{step_2}
子章节二知识库内容：{reference_2}
知识库内容：{reference}
年级：{level}
科目：{subj}
学时：{time_1}
年级：{level}
其他要求：{other_require}
注意：
** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 如果子章节二名称：{title_2_real}为空，则生成子章节二相关名称替换。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于1000字**；
**  生成“标题”，“内容”不能重复。** 
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  如果{title_2_real}不为空, 2.{step}.{step_2}.{title_2_real}生成的内容参考子章节二相关内容和子章节二知识库内容进行生成** 
**  如果{title_2_real}为空, 生成{title_2_real}与{chapter_1}相关,“2.{step}.{step_2}.{title_2_real}"生成的内容参考知识库内容进行生成**
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
### 2.{step}.{step_2}.{title_2_real}

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
4. **生成内容必须与“2.{step}.{step_2}.{title_2_real}”相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
5. **在生成内容后面不要加入字数描述，例如“（1000字）”**
6. **生成完“2.{step}.{step_2}.{title_2_real}”内容后结束生成，禁止生成2.{step}.3.标题和内容**
7. **必须生成“2.{step}.{step_2}.{title_2_real}”的内容**
8.**如果{title_2_real}为空，必须为其生成具体标题内容。**
9.**强制生成内容不能重复。**
</optimized_prompt>
"""



#教案生成
WRITE_LEARNING_PLAN_PROMPT_7 ="""<optimized_prompt>
{title}中内容：{doc_content}
案例：{all_case}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
年级：{level}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成章节名称：{chapter}”相关内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  参考{doc_content}中内容和知识库内容进行生成。
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  生成每个内容字数范围在1000字到4000字之间**；
**  必须保证生成的内容不能重复。**
**  生成“标题”，“内容”不能重复。** 
**  围绕章节名称：{chapter}，结合知识库内容和数据库内容生成。** 
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
##  2.1. 标题
###   2.1.1.标题

##  2.1.2.标题

##  2.2.标题
###  2.2.1.标题

### 2.2.2.标题

</output_format>

## 检查以下条件必须满足：
1.** 不要生成“第几章”，“第几节”这种字样。例如“第一章”，“第一节”这种形式的内容。** 
2.** 必需满足生成按照上述格式要求生成，字数是否符合要求，内容与之前生成不重复这几个基本要求。** 
3.** 禁止延展生成“2.1.1.1.”，“2.1.2.1.”，“2.2.1.1.”，“2.2.2.1.”，“2.2.3.”，“2.3.”，等标题内容，必须按照上述固定格式内容输出。**
4.** 不要生成额外的解释。**
5.** 必须要从“2.1.标题”开始生成到“2.2.2.”相关内容结束。**
6.** “2.1.标题”和“2.1.1.标题”之间不能有内容。**
7.** “2.2.标题”和“2.2.1.标题”之间不能有内容。**
8.** 生成每个内容字数不能低于1000字**
9.** 格式中所有“标题”字样必须替换为和{chapter}内容相关的具体标题，“内容”必须是模型生成和{chapter}相关的内容。**
10.** 保证标题间的所属关系。**
11.** 强制生成内容不能重复**
12.**禁止生成2.2.3.标题*和2.3.标题**
13.**如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
14.**生成内容不能重复，如果有重复内容重新输出**
15.**不要思考过程，快速输出内容**
</optimized_prompt>"""

WRITE_LEARNING_PLAN_PROMPT_8 ="""<optimized_prompt>
{title}中内容：{doc_content}
案例：{all_case}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
年级：{level}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成章节名称：{chapter}”相关内容。**

<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容字数范围在1000字到4000字之间**
**  如果案例不为空生成内容必须包含对应案例，使用案例不能与之前重复** 
**  生成“标题”，“内容”不能重复。** 
**  必须保证生成的内容不能重复。**
**  围绕章节名称：{chapter}，结合知识库内容和数据库内容生成。** 
** 必须严格按照下面格式生成：**
<instructions>

<output_format>
##  2.3. 标题
### 2.3.1.标题

### 2.3.2.标题

##  2.4.标题
### 2.4.1.标题

### 2.4.2.标题

</output_format>

## 检查以下条件必须满足：
1.** 不要生成“第几章”，“第几节”这种字样。例如“第一章”，“第一节”这种形式的内容。** 
2.** 必需满足生成按照上述格式要求生成，字数是否符合要求，内容与之前生成不重复这几个基本要求。** 
3.** 禁止延展生成“2.3.1.1.”，“2.3.2.1.”，“2.4.1.1.”，“2.4.2.1.”，“2.4.3.”，“2.5.”等标题内容，必须按照上述固定格式内容输出。**
4.** 不要生成额外的解释。**
5.** 生成每个内容字数不能低于1000字**
6.** 必须要从“2.3.标题”开始生成到“2.4.2.”相关内容结束。**
7.** “2.3.标题”和“2.3.1.标题”之间不能有内容，“2.4.标题”和“2.4.1.标题”之间不能有内容。**
8.** 格式中所有“标题”字样必须替换为和{chapter}内容相关的具体标题，“内容”必须是模型生成和{chapter}相关的内容。**
9.** 保证标题间的所属关系。**
10. **强制生成内容不能重复**
11. **禁止生成2.4.3.标题*和2.5.标题**
12. **如果有对应案例，生成内容必须包含对应案例，案例不能使用之前使用过的案例**
14.**生成内容不能重复，如果有重复内容重新输出**
15. **不要思考过程，快速输出内容**
</optimized_prompt>"""




# 备份
# WRITE_LEARNING_PLAN_PROMPT_12 = """<optimized_prompt>
# {title}中内容：{doc_content}
# 上一轮生成的内容：{text}
# 章节名称：{chapter_1}
# 子章节一名称：{title_1_real}
# 子章节二名称：{title_2_real}
# 子章节一相关内容：{content_1}
# 子章节二相关内容：{content_2}
# 序号：{step}
# 一序号：{step_1}
# 二序号：{step_2}
# 子章节一知识库内容：{reference_1}
# 子章节二知识库内容：{reference_2}
# 年级：{level}
# 科目：{subj}
# 学时：{time_1}
# 年级：{level}
# 其他要求：{other_require}
# 注意：
# ** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
# ** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
# ** 不得修改或删除已有内容。**
# ** 如果子章节二名称：{title_2_real}为空，则生成子章节二相关名称替换。**

# <instructions>
# **  所有内容必须基于知识库拓展，不得凭空编造。** 
# **  生成每个内容不能低于1000字**；
# **  禁止出现公式、图表编号等非文本内容。** 
# **  生成“标题”，“内容”不能重复。** 
# **  2.{step}.{step_1}.{title_1_real}生成的内容参考子章节一相关内容和子章节一知识库内容进行生成** 
# **  如果{title_2_real}不为空, 2.{step}.{step_1}.{title_2_real}生成的内容参考子章节二相关内容和子章节二知识库内容进行生成** 
# **  如果{title_2_real}为空, 生成{title_2_real}与{title_1_real}相关,“2.{step}.{step_2}.{title_2_real}"生成的内容参考子章节一相关内容和子章节一知识库内容进行生成**
# ** 必须严格按照下面格式生成：**
# <instructions>

# <output_format>
# ### 2.{step}.{step_1}.{title_1_real}

# ### 2.{step}.{step_2}.{title_2_real}

# </output_format>

# ## 检查以下条件必须满足：
# 1. **不要思考过程，快速输出内容**
# 2. **严格按照给定格式生成内容**
# 3. **生成内容必须与“2.{step}.{step_1}.{title_1_real}”和“2.{step}.{step_1}.{title_2_real}”相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
# 4. **在生成内容后面不要加入字数描述，例如“（1000字）”**
# 5. **生成完“2.{step}.{step_2}.{title_2_real}”内容后结束生成，禁止生成2.{step}.3.标题和内容**
# 6. **必须生成“2.{step}.{step_2}.{title_2_real}”的内容，不能只生成到“2.{step}.{step_1}.{title_1_real}”内容就终止生成。**
# 7.**如果{title_2_real}为空，必须为其生成具体标题内容。**
# 8.**强制生成内容不能重复。**
# </optimized_prompt>
# """



# WRITE_LEARNING_PLAN_PROMPT_8 = """<optimized_prompt>
# {title}中内容：{doc_content}
# 上一轮生成的内容：{content}
# 章节名称：{chapter}
# 知识库内容：{reference}
# 年级：{level}
# 科目：{subj}
# 其他要求：{other_require}

# <task>根据上一轮生成的内容继续生成参考知识库内容生成只与当前章节相关内容。字数不少于1000字，不要在后面写“（1000字）”</task>
# ** 注意：
# 1. **严格按照上一轮生成的格式继续生成。不能对格式有任何修改。
# 2. **只在三级标题生成内容，其他标题只生成标题。
# 3. **生成的三级标题必须要有两个。不能多也不能少。
# 4. **强制内容生成从“## 2. 一级标题”开始生成，到“## 2.1.2. 三级标题 三级标题相关内容”结束。不能生成其他额外内容。
# 5. **最终检查是否符合标题层级、内容长度、格式结构等要求**；
# 6. **确保不添加额外无关内容，如“六、教学内容（续）”等**；
# 7. **确认三级标题与相关内容之间存在换行，整体输出严格遵循给定格式**；
# 8. **强制内容生成从“## 1.3. 二级标题”开始生成，到“## 1.3.2.. 三级标题 三级标题相关内容”结束。不能生成其他额外内容。
# 9. **生成每个三级标题相关内容不能低于1000字**；
# 10. **生成内容不能与之前内容重复**；
# 11. **不能生成“## 1.4 二级标题”，“## 1.3.3. 三级标题”等，生成到“## 1.3.2. 三级标题 三级标题相关内容”就结束**；
# 12. **生成内容一定要根据章节名称：{chapter}到知识库中检索强相关内容。
# <output_format>
# ## 1.3. 二级标题
# ## 1.3.1.三级标题
#   三级标题相关内容
# ## 1.3.2. 三级标题
#   三级标题相关内容
# </output_format>
# *** 检查如下条件必须满足：
# ** 开始生成时“## 1.3. 二级标题”二级标题要紧接上一轮生成的内容，继续生成。
# ** 生成内容一定要与章节名称{chapter}所检索到到的知识库内容相关。
# ** 不能直接生成“1.3. 二级标题”，“1.3.1 三级标题”，“三级标题相关内容”等字样，要把“二级标题”，“三级标题”替换为真正与当前章节内容相关的标题。“三级标题相关内容”为真正与本章节相关的内容。
# ** 必需满足生成按照上述格式要求生成，字数是否符合要求，内容与之前生成不重复这几个基本要求。
# ** 不能生成“## 1.4. 标题”，“## 1.3.3. 标题”，“1.3.1.1.标题 相关内容，1.3.1.2.标题 相关内容”等**；
# ** 一定要从生从“## 1.3. 二级标题”开始生成到“## 1.3.2. 三级标题 三级标题相关内容”就结束
# ** 不要生成额外的解释。
# ** 一定不要生成和之前相同的内容。
# </optimized_prompt>
# """


WRITE_LEARNING_PLAN_PROMPT_9 = """<optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
其他要求：{other_require}

注意：
** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
** 不得修改或删除已有内容。**
** 只生成当前章节：“{chapter}”相关内容。**
<instructions>
**  所有内容必须基于知识库拓展，不得凭空编造。** 
**  生成每个内容不能低于500字**；
**  围绕当前章节：“{chapter}”，结合知识库生成内容。** 
**  输出必须从以下格式开始并完整结束：** 
<instructions>
<output_format>
##  3.课堂小结
##  3.1.当前章节回顾
### 3.1.1.知识点总结  

### 3.1.2. 重点难点梳理  

##  4.课后作业
##  4.1. 当前章节作业安排
### 4.1.1. 巩固练习  

### 4.1.2. 拓展任务  

</output_format>

## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
"""





WRITE_LEARNING_PLAN_PROMPT_10 = """<optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{content}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
教学形式：{jiangshou_type}
其他要求：{other_require}
注意：
** 在上一轮生成的内容基础上继续生成，开始生成的时候请换行（\n\n）与上一轮生成区分。
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要生成与上一轮生成内容相同的东西。例如“一、教学目标，二、教学重点与难点，三、授课方式与手段，四、教学过程设计，五、小节与作业”直接继续生成第六章内容。
** 不要对上一轮生成内容进行任何操作（更新，优化，删除等）。
** 只生成当前章节名称：{chapter}相关内容。
<instructions>
** 确保所有内容必须基于知识库内容进行拓展，不能脱离知识库凭空编造。
** 确保内容要关注起承转合，教学活动衔接自然，必要时可加入表格对比知识点。
** 确保当前生成的内容围绕当前章节：{chapter}检索知识库内容进行生成。
**不要思考过程，快速输出内容**
</instructions>
</<output_format>
如果授课方式为实作授课，生成的内容总字数不得少于4000个汉字，每一部分参考知识库内容生成尽量详细,。在生成内容后面不要加入字数描述，例如“（300字）,输出形式为：
<output_format>
# 六、教学内容
##  场景二：{jiangshou_type}
### 1.教学准备
### 2.下达任务
### 3.讲解示范
### 4.组织训练
### 5.总结点评
### 6.小节与作业
### 7.教学后记
</output_format>

"""
WRITE_LEARNING_PLAN_PROMPT_11 = """<optimized_prompt>
{title}中内容：{doc_content}
上一轮生成的内容：{text}
章节名称：{chapter}
知识库内容：{reference}
年级：{level}
科目：{subj}
其他要求：{other_require}
学时：{time_1}
注意：
** 在上一轮生成的内容基础上继续生成，开始生成的时候请换行（\n\n）与上一轮生成区分。
** 参考{doc_content}中内容和知识库内容进行生成。
** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计，五、小节与作业，六、教学内容”等标题，直接从当前章节对应的内容开始**
** 不要对上一轮生成内容进行任何操作（更新，优化，删除等）。
** 只生成当前章节名称：{chapter}相关内容。
** 必须要包含下面所有格式的内容。
<instructions>
** 强制确保标题和内容之间有换行“\n\n”。** 
** 填写主要教学环节、教学设计意图、以及教学时间分配相关内容** 
** 填写重难知识点讲授策略、解析方法等相关内容** 
** 填写板书具体设计与书写时机相关内容** 
** 填写思政具体设计与融入方法相关内容** 
** 填写注意事项。如：起承转合时机、教学活动关注要点、注意调整授课节奏等相关内容。** 
** 教学时间分配分配考虑学时{time_1},如果{time_1}为一学时，时间为45分钟。如果为二学时，时间为90分钟,以此类推。** 
** “七、备注”章节生成的内容总字数为700字，每个子章节生成100字左右。**
</instructions>
<output_format>
# 七、备注
##  1、教学环节

##  2、教学设计意图

##  3、教学时间分配

##  4、重难知识点讲授策略及解析方法

##  5、板书具体设计与书写时机

##  6、思政具体设计与融入方法

##  7、注意事项

</output_format>
<instructions>
** 课堂表现评估内容为总结学员在课堂上的参与度，包括是否积极回答问题、参与小组讨论等。对学员的发言进行评价，看其对知识的理解程度和分析问题的能力。** 
** 作业评估内容根据学生提交的课后作业，对论文的质量、资料简报的内容完整性和准确性等方面进行评分。通过作业评估，了解学员对本节课知识的掌握情况和自主学习能力，发现教学中存在的不足之处，以便在今后的教学中进行改进。** 
** “八、教学后记”章节生成字数为300字，每个子章节150字左右。**
</instructions>
<output_format>
# 八、教学后记
##  1、课堂表现评估

##  2、作业评估
  
</output_format>
## 检查以下条件必须满足：
1. **不要思考过程，快速输出内容**
2. **严格按照给定格式生成内容**
3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
4. **在生成内容后面不要加入字数描述，例如“（200字）”**
</optimized_prompt>
"""


REFERENCE_CASE_FIND="""你是一案例查找专家，擅长根据给定的文本查找与标题相关的案例。现在有文本内容{case_content}和标题{case_title}如下：
文本内容：{case_content}
标题：{case_title}
请根据文本内容和标题按照以下要求查找案例：
** 1. 找到的案例必须与标题相关且包含具体内容，案例内容越丰富越好。
** 2. 案例包含一些经典应用和基于教材参数的典型应用。
** 3. 案例包含一些场景，系统配置，影响和分析等。
** 4. 不能编造案例。
** 5. 不需要输出解释等无关内容。
** 6. 如果没有案例输出“没有相关案例”。
** 7. 找到相关案例输出格式如下：
**输出格式：
案例1："......"
案例2："......"
......
"""











#教案生成
# WRITE_LEARNING_PLAN_PROMPT_8 = """<optimized_prompt>
# {title}中内容：{doc_content}
# 上一轮生成的内容：{text}
# 章节名称：{chapter}
# 知识库内容：{reference}
# 年级：{level}
# 科目：{subj}
# 其他要求：{other_require}

# 注意：
# ** 在上一轮内容基础上继续生成，请以 `\n\n` 换行区分。**
# ** 不要重复生成已有内容，如“教学目标”、“教学重点”等标题。**
# ** 不得修改或删除已有内容。**
# ** 只生成当前章节：“{chapter}”相关内容。**
# <instructions>
# **  所有内容必须基于知识库拓展，不得凭空编造。** 
# **  生成每个内容不能低于500字**；
# **  禁止出现公式、图表编号等非文本内容。** 
# **  围绕当前章节：“{chapter}”，结合知识库生成内容。** 
# **  输出必须从以下格式开始并完整结束：** 
# <instructions>
# <output_format>
# ## 课堂小结
# ## 1. 课堂小结
# ## 1.1. 当前章节回顾
# ## 1.1.1. 知识点总结  
#   内容
# ## 1.1.2. 重点难点梳理  
#   内容
# ## 课后作业
# ## 1. 课后作业
# ## 1.1. 当前章节作业安排
# ## 1.1.1. 巩固练习  
#   内容
# ## 1.1.2. 拓展任务  
#   内容
# </output_format>

# ## 检查以下条件必须满足：
# 1. **不要思考过程，快速输出内容**
# 2. **严格按照给定格式生成内容**
# 3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
# 4. **在生成内容后面不要加入字数描述，例如“（200字）”**
# </optimized_prompt>
# """





# WRITE_LEARNING_PLAN_PROMPT_6 = """<optimized_prompt>
# {title}中内容：{doc_content}
# 上一轮生成的内容：{text}
# 章节名称：{chapter}
# 知识库内容：{reference}
# 年级：{level}
# 科目：{subj}
# 其他要求：{other_require}
# 学时：{time}
# 注意：
# ** 在上一轮生成的内容基础上继续生成，开始生成的时候请换行（\n\n）与上一轮生成区分。
# ** 不要重复生成上一轮已有的内容**，例如“一、教学目标，二、教学重点与难点，三、授课方法，四、教学过程设计，五、小节与作业，六、教学内容”等标题，直接从当前章节对应的内容开始**
# ** 不要对上一轮生成内容进行任何操作（更新，优化，删除等）。
# ** 只生成当前章节名称：{chapter}相关内容。
# ** 必须要包含下面所有格式的内容。
# <instructions>
# ** 强制确保标题和内容之间有换行“\n\n”。** 
# ** 填写主要教学环节、教学设计意图、以及教学时间分配相关内容** 
# ** 填写重难知识点讲授策略、解析方法等相关内容** 
# ** 填写板书具体设计与书写时机相关内容** 
# ** 填写思政具体设计与融入方法相关内容** 
# ** 填写注意事项。如：起承转合时机、教学活动关注要点、注意调整授课节奏等相关内容。** 
# ** 教学时间分配分配考虑学时{time},如果{time}为一学时，时间为45分钟。如果为二学时，时间为90分钟,以此类推。** 
# ** “七、备注”章节生成的内容总字数为700字，每个子章节生成100字左右。**
# </instructions>
# <output_format>
# # 七、备注
# ## 1、教学环节

# ## 2、教学设计意图

# ## 3、教学时间分配

# ## 4、重难知识点讲授策略及解析方法

# ## 5、板书具体设计与书写时机

# ## 6、思政具体设计与融入方法

# ## 7、注意事项

# </output_format>
# <instructions>
# ** 课堂表现评估内容为总结学员在课堂上的参与度，包括是否积极回答问题、参与小组讨论等。对学员的发言进行评价，看其对知识的理解程度和分析问题的能力。** 
# ** 作业评估内容根据学生提交的课后作业，对论文的质量、资料简报的内容完整性和准确性等方面进行评分。通过作业评估，了解学员对本节课知识的掌握情况和自主学习能力，发现教学中存在的不足之处，以便在今后的教学中进行改进。** 
# ** “八、教学后记”章节生成字数为300字，每个子章节150字左右。**
# </instructions>
# <output_format>
# # 八、教学后记
# ## 1、课堂表现评估

# ## 2、作业评估
  
# </output_format>
# ## 检查以下条件必须满足：
# 1. **不要思考过程，快速输出内容**
# 2. **严格按照给定格式生成内容**
# 3. **生成内容必须与本章节相关，不能重复生成与之前相同的内容，不能有解释等无关内容**
# 4. **在生成内容后面不要加入字数描述，例如“（200字）”**
# </optimized_prompt>
# """





WRITE_PROJECT_PROPOSAL_PROMPT = """你现在是一个开题报告编写专家，请帮我生成一个主题为{title}的开题报告，开题报告的输出形式参考我给你的开题报告模版，生成的内容要准确、清晰无误，同时满足以下要求：
 1.研究目的要阐述清楚，为什么要开展{title}的研究，其最终目的是什么。
 2.研究意义中，需要介绍在怎样的背景下，研究对象是什么，为什么要研究这个选题，然后阐明选题着重解决哪些问题(讨论范围)。先写宏观背景，然后介绍企业背景，然后引入到本文的研究。从理论意义和实践意义两个角度开展叙述。
 3.研究现状要从国内和国外现状开展阐述，结合当下最新的研究，进行详细的分析并生成国内外研究现状。
 4.章节研究目标、内容（论文提纲）及拟解决关键问题，从研究目标、研究内容、拟解决问题和论文提纲开展阐述，其中研究目标要清晰明确，研究内容需要说清楚研究哪些内容，论文提纲可以使用多个多级标题。
 5.研究方法及技术路线，从研究方法和具体实现的技术路线开展研究，要准确，贴近主题，根据给出的大纲内容进行生成，同时可以适当加入一些流程图和表格。
 6.主要参考文献及出处，请给出与{title}相关的参考文献，同时给出对应的论文引用方式
 7.研究进度时间安排表，请输出一个表格，记录整个论文的时间和工作安排
 8.整个开题报告的字数为{length}左右，同时会给你一些参考资料，请根据参考资料的内容，进行上述{title}的开题报告编写。请尽量多生成一些内容，保证字数。
 9.其中，在满足上述要求的同时，如果还存在其他要求，也要一并兼顾考虑；如果没有，则根据上述要求编写开题报告即可。
 10.生成内容时，进行换行时，模版中每一行生成后，用两个换行“\n\n”进行换行，不要使用一个“\n”。
 11.其中“姓名：”、“学号：”和“论文题目：”与“生成内容”中间不要进行添加“\n”,作为同一行输出,请严格遵循该要求。
 12. 如果完成教案内容的编写，在编写的内容之后加入"end"；否则，内容不能一次性完全输出的情况下，不要加入“end"
   其中，开题报告模版如下：

姓名：生成内容

学号：生成内容

论文题目：生成内容

# 一、选题的背景和意义（含国内外研究现状综述）
## （一）研究目的
## （二）研究意义
### 1.理论意义
### 2.实践意义
## （三）研究现状
### 1.国内研究现状
### 2.国外研究现状
# 二、研究目标、内容（论文提纲）及拟解决关键问题
## （一）研究目标
## （二）研究内容
## （三）拟解决问题
## （四）论文提纲
    - 1. 一级标题
        - 1.1. 二级标题
            - 1.1.1. 三级标题
            - 1.1.2. 三级标题
        - 1.2. 二级标题
        - 1.3. 二级标题
    - 2. 一级标题
    .....
# 三、研究方法及技术路线
## （一）研究方法
## （二）技术路线
# 四、主要参考文献及出处


(1)Amesim 机电一体化仿真教程[M]. 梁全,谢基晨,聂利卫.机械工业出版社.2021.


(2)信息与文献参考文献著录规则[M]. 梁全,谢基晨,聂利卫.机械工业出版社.2021.


    .....


# 五、研究进度时间安排表


   其他要求如下：{other_require}
   参考资料如下：{reference}
"""


TEXT_CUT= """你是一位专业文案大师，擅长对文本进行精简，即对选中文本进行精简缩写。请根据用户提供的文本，在保持原意的基础上进行精简，要求满足以下条件：
1. 首先仔细阅读给出的文本内容，分析并理解其内容和意境。
2. 仔细分析原文的结构和用词，对选择的文本内容进行精简。
3. 确保精简后的文本保留文本中原有元素，但用更简洁的语言表达。
4. 要确保整体通顺，不丢失原意，同时符合书面表达，去除冗余词汇。
5. 禁止使用Markdown，不添加无关内容，保持纯文本风格，在精简过程中，精简后的内容都紧扣原文，同时要无缝衔接，不能脱离中心思想。
6. 通读精简后的文本，确保没有语法错误，确保整体段落结构清晰，逻辑连贯。
7. 如果有其他要求，则继续考虑到该要求进行精简，如果没有，则保持上述要求进行精简。
8. 请将根据上述要求精简后的内容直接输出，不要输出额外的信息描述。
9. 精简后字数控制在100字左右。
10.不能生成其他额外的内容。只将精简后的内容进行输出。
文本内容如下：{content}
"""

(^xEimport os
import json
import base64
import asyncio
import logging
from typing import Optional, Tuple, Dict
import aiofiles  # pip install aiofiles

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


async def find_and_read_content_list(
    directory: str,
    original_filename: str,
    encoding: str = 'utf-8'
) -> Tuple[Optional[list], Optional[str]]:
    """根据原始文件名查找并读取对应的 _content_list.json 文件。"""
    file_name, _ = os.path.splitext(original_filename)
    target_filename = f"{file_name}_content_list.json"
    logger.info(f"正在查找文件: {target_filename}")

    # os.walk 没有原生 async 版本,放到线程里执行避免阻塞事件循环
    def _walk_for_file():
        for root, _, files in os.walk(directory):
            if target_filename in files:
                return os.path.join(root, target_filename)
        return None

    file_path = await asyncio.to_thread(_walk_for_file)
    if file_path is None:
        return None, None

    try:
        async with aiofiles.open(file_path, 'r', encoding=encoding) as f:
            text = await f.read()
        # JSON 解析是 CPU 操作,大文件可考虑放线程
        return json.loads(text), file_path
    except json.JSONDecodeError:
        logger.error(f"文件 {file_path} 不是有效的 JSON 格式。")
        return None, None
    except Exception as e:
        logger.error(f"读取文件 {file_path} 时发生错误: {e}")
        return None, None


def extract_all_jpg_filenames(doc_data: list) -> set:
    """从文档数据中提取所有 .jpg 图片的纯文件名。纯 CPU 操作,不需要 async。"""
    result_set = set()
    for item in doc_data:
        if 'img_path' in item and item['img_path']:
            img_path = item['img_path']
            if img_path.endswith('.jpg'):
                result_set.add(os.path.basename(img_path))
    return result_set


async def _encode_one_image(
    img_file: str,
    local_image_dir: str,
    mime_map: dict,
) -> Tuple[str, Optional[str]]:
    """编码单张图片,返回 (文件名, data_uri 或 None)。"""
    img_path = os.path.join(local_image_dir, img_file)
    if not os.path.isfile(img_path):
        logger.warning(f"图片不存在: {img_path}")
        return img_file, None

    try:
        async with aiofiles.open(img_path, "rb") as f:
            img_bytes = await f.read()
        # base64 编码是 CPU 操作,小文件直接做即可;大文件可放线程
        img_base64 = base64.b64encode(img_bytes).decode('utf-8')
        ext = img_file.lower().rsplit('.', 1)[-1]
        mime_type = f"image/{mime_map.get(ext, 'png')}"
        return img_file, f"data:{mime_type};base64,{img_base64}"
    except Exception as e:
        logger.error(f"编码图片失败 {img_file}: {str(e)}")
        return img_file, None


async def encode_images_to_base64(
    local_image_dir: str,
    referenced_images: set,
    concurrency: int = 32,
) -> Dict[str, str]:
    """并发将引用的图片编码为 base64。"""
    if not os.path.exists(local_image_dir) or not referenced_images:
        return {}

    mime_map = {'jpg': 'jpeg', 'jpeg': 'jpeg', 'png': 'png', 'gif': 'gif', 'webp': 'webp'}

    # 用 Semaphore 限制并发数,避免一次性打开几百个文件句柄
    sem = asyncio.Semaphore(concurrency)

    async def _bounded(img_file: str):
        async with sem:
            return await _encode_one_image(img_file, local_image_dir, mime_map)

    results = await asyncio.gather(*(_bounded(f) for f in referenced_images))
    return {name: data for name, data in results if data is not None}


async def process_document(
    input_file_name: str,
    search_dir: Optional[str] = "/app/mineru_output",
    local_image_dir: Optional[str] = None,
    concurrency: int = 32,
) -> Optional[Tuple[list, Dict[str, str]]]:
    """
    异步处理文档:查找 content_list.json,提取图片引用,并发编码为 base64。

    Args:
        input_file_name: 原始文件名(如 "xxx.pdf")
        search_dir: 搜索 _content_list.json 的根目录
        local_image_dir: 图片所在目录,None 则自动推断
        concurrency: 图片编码的并发数上限,默认 32

    Returns:
        成功: (content_list, images_dict)
        失败: None
    """
    content, content_path = await find_and_read_content_list(search_dir, input_file_name)
    if content is None:
        logger.error("❌ 未找到指定的 _content_list.json 文件。")
        return None

    logger.info(f"✅ 找到文件: {content_path}")
    logger.info(f"内容类型: {type(content).__name__}, 长度: {len(str(content))}")

    if local_image_dir is None:
        local_image_dir = os.path.join(os.path.dirname(content_path), "images")
    logger.info(f"图片目录: {local_image_dir}")

    referenced_images = extract_all_jpg_filenames(content)
    logger.info(f"引用图片数量: {len(referenced_images)}")

    images_dict = await encode_images_to_base64(
        local_image_dir, referenced_images, concurrency=concurrency
    )
    logger.info(f"成功编码 {len(images_dict)} 张图片")

    return content, images_dict


async def main():
    result = await process_document(
        input_file_name="163-06A0014-B01001_发动机-维修手册.pdf",
        search_dir="/app/mineru_output",
        concurrency=32,
    )

    if result is None:
        return 1

    content, images_dict = result
    print(f"\n=== 处理完成 ===")
    print(f"文档段落数: {len(content)}")
    print(f"图片数量: {len(images_dict)}")
    if images_dict:
        first_key = next(iter(images_dict))
        print(f"示例图片 [{first_key}]: {images_dict[first_key][:80]}...")
    return 0


if __name__ == "__main__":
    exit_code = asyncio.run(main())
    exit(exit_code)
Fx""""
主脑Agent - 简化版（无意图分类）

职责：
1. 输入处理：图片、音频、文本提取
2. 直接路由：根据外部传入的 route_flag 决定调用哪个工作流

工作流列表（来自 workflow_registry）：
- 故障排查与修理
- 舰船百科
- 操作使用
"""

from typing import TypedDict, Literal, Optional, Dict, Any, List
from langgraph.graph import StateGraph, START, END
from tools.function_tool import (
    vlm_image_to_text,
    asr_audio_to_text,
    detect_input_type
)
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import track_function_calls
from workflow_registry import VALID_ROUTE_FLAGS
import json
import re


class MainAgentState(TypedDict):
    """主脑Agent状态"""
    raw_input: Dict[str, Any]
    has_image: bool
    has_audio: bool
    has_query: bool
    has_file_text: bool
    input_type: str
    
    history_message: str
    extracted_text: str
    image_description: str
    asr_text: str
    file_text: str
    combined_query: str
    
    workflow_result: Optional[Dict[str, Any]]
    final_response: str
    error_message: str
    
    route_flag: str
    route_params: Dict[str, Any]


def detect_input_type_node(state: MainAgentState) -> Dict[str, Any]:
    """检测输入类型"""
    raw = state["raw_input"]
    print(raw)
    print(22222222222222222222222222)
    result = detect_input_type.invoke({"raw_input": raw})
    
    has_image = result.get("has_image", False)
    has_audio = result.get("has_audio", False)
    has_query = result.get("has_query", False)
    
    has_file_text = False
    file_text_v = raw.get("file_text")
    if isinstance(file_text_v, str) and file_text_v.strip():
        has_file_text = True
    
    input_type = "mixed"
    count = sum([has_image, has_audio, has_query, has_file_text])
    if count == 1:
        if has_image:
            input_type = "image"
        elif has_audio:
            input_type = "audio"
        elif has_query:
            input_type = "text"
        elif has_file_text:
            input_type = "file"
    
    return {
        "has_image": has_image,
        "has_audio": has_audio,
        "has_query": has_query,
        "has_file_text": has_file_text,
        "input_type": input_type,
    }


async def process_multimodal_input(state: MainAgentState) -> Dict[str, Any]:
    """处理多模态输入"""
    has_image = state.get("has_image", False)
    has_audio = state.get("has_audio", False)
    has_query = state.get("has_query", False)
    has_file_text = state.get("has_file_text", False)
    raw = state["raw_input"]
    
    image_description = ""
    asr_text = ""
    extracted_text = ""
    
    try:
        if has_image:
            image_path = raw.get("image", "")
            if image_path:
                try:
                    image_description = await vlm_image_to_text.ainvoke({
                        "image_path": image_path
                    })
                    if not image_description or image_description.startswith("VLM 调用失败"):
                        image_description = ""
                except Exception:
                    image_description = ""
        
        if has_audio:
            audio_path = raw.get("audio", "")
            if audio_path:
                try:
                    asr_text = await asr_audio_to_text.ainvoke({
                        "audio_path": audio_path
                    })
                    if not asr_text or asr_text.startswith("ASR 调用失败"):
                        asr_text = ""
                except Exception:
                    asr_text = ""
        
        text_parts = []
        if raw.get("query"):
            text_parts.append(raw["query"])
        if image_description:
            text_parts.append(f"[图片描述] {image_description}")
        if asr_text:
            text_parts.append(f"[语音转文字] {asr_text}")
        if raw.get("file_text"):
            text_parts.append(f"[文件内容] {raw['file_text']}")
        
        extracted_text = "\n".join(text_parts) if text_parts else ""
        combined_query = raw.get("query", "") or extracted_text
        
        return {
            "extracted_text": extracted_text,
            "image_description": image_description,
            "asr_text": asr_text,
            "combined_query": combined_query,
            "file_text": raw.get("file_text", ""),
        }
    
    except Exception as e:
        return {
            "error_message": f"输入处理失败: {str(e)}",
            "extracted_text": "",
        }

# @track_function_calls
def route_to_workflow(state: MainAgentState) -> Dict[str, Any]:
    """
    🤖分析意图，调用相关智能体
    """
    route_flag = state.get("route_flag", "问题排查")
    
    if route_flag not in VALID_ROUTE_FLAGS:
        route_flag = "问题排查"
    
    query_text = state.get("extracted_text", "")
    combined_query = state.get("combined_query", "") or query_text
    
    raw_input = state.get("raw_input", {})
    history_message = raw_input.get("history_message", "")
    
    route_params = {
        "extracted_text": query_text,
        "combined_query": combined_query,
        "history_message": history_message,
    }
    
    if raw_input.get("file_text"):
        route_params["file_text"] = raw_input["file_text"]
    
    print(f"[主脑Agent] 路由到: {route_flag}")
    print(f"[主脑Agent] 参数: combined_query={combined_query[:100]}...")

    if route_flag == "问题排查":
        detail = "正在调用问题排查智能体"
    elif route_flag == "百科问答":
        detail = "正在调用百科问答智能体"
    elif route_flag == "操作使用":
        detail = "正在调用操作使用智能体"
    elif route_flag == "统计":
        detail = "正在调用统计智能体"
    else:
        detail = "正在调用通用智能体"
    
    return {
        "route_flag": route_flag,
        "route_params": route_params,
        "__detail__": detail,
    }


def create_main_agent():
    """创建主脑Agent"""
    workflow = StateGraph(MainAgentState)
    
    workflow.add_node("detect_input_type", detect_input_type_node)
    workflow.add_node("process_input", process_multimodal_input)
    workflow.add_node("route", route_to_workflow)
    
    workflow.add_edge(START, "detect_input_type")
    workflow.add_edge("detect_input_type", "process_input")
    workflow.add_edge("process_input", "route")
    workflow.add_edge("route", END)
    
    return workflow.compile()


from workflows.history_manager import filter_image_urls


async def extract_conversation_title(content: str) -> str:
    """提取对话标题"""
    try:
        prompt = f"请从以下对话内容中提取一个简短的标题（不超过20字）：\n\n{content[:500]}"
        response = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            model=None,
            system_prompt="你是一个标题提取助手，请从对话内容中提取一个简短的标题。",
            messages=[]
        )
        title = response.strip() if response else "新对话"
        if len(title) > 30:
            title = title[:30] + "..."
        return title
    except Exception:
        return "新对话"


if __name__ == "__main__":
    import asyncio
    
    async def test():
        print("测试主脑Agent")
        agent = create_main_agent()
        result = await agent.ainvoke({
            "raw_input": {"query": "101舰主机发生异响"},
            "route_flag": "故障排查与修理"
        })
        print(f"结果: {result}")
    
    asyncio.run(test())

_ۥxu 100644 __init__.py ⛲CK)wZS40000 __pycache__ ÉM"l[hY|100644 model_api.py ^VZUڰ~ZF	E1x -100644 __init__.cpython-310.pyc |Wï[j܍`l100644 __init__.cpython-312.pyc C5Qvojja100644 model_api.cpython-310.pyc 3Pq~hLP100644 model_api.cpython-312.pyc 2j͑9exlPSnL5Uxw o
    li                       @   s   d S )N r   r   r   /app/modelsAPI/__init__.py<module>   s    X~
x Z
    ˱Mj                            y )N r       De:\ZKYNLP\Hjunproject\project0506\wx-agent\app\modelsAPI\__init__.py<module>r      s   r   f@){x"o
    liv,                     @   s   d dl Z d dlZd dlmZmZ d dlZd dlZd dlm	Z	 d dl
mZmZ d dlmZ G dd dZedkrIe ejd	d
dd
dZee dS dS )    N)ListUnion)OpenAI)
LLM_CONFIGEMBEDDING_CONFIG)AsyncOpenAIc                   @   s  e Zd Ze							d5dedededed	ed
ededefddZededefddZ	edefddZ
ededee fddZedee deee  fddZedeee ejf deee ejf defddZedeee ejf deeee ejf  dee fd d!Ze	"	#	$	%	$	&d6d'ed(ee d)ed*ed+ed,ed-ed.edefd/d0Zed1ed2edefd3d4ZdS )7	OpenaiAPINFT皙?querymodeljson_outputsystem_promptmessagesenable_thinkingtemperaturereturnc                    s   |d u r	t d }|d u rd}d|dg}|d ur|| | d ur*|d| d tt d t d d}|||d	t d
 d}	ddd	ii|	d< |rNddi|	d< td| |jjjdi |	I d H }
|
jd j	j
S )Nr   u   我是一个专业的AI助手，请用中文回答问题。请直接给出最终答案，不要包含任何推理步骤、思考过程、解释性文字或前缀。systemrolecontentuserapi_keybase_urlr   r   F
max_tokensr   r   r   streamr   chat_template_kwargsr   
extra_bodytypejson_objectresponse_formatzmodel API. history messager    )r   extendappendr   printchatcompletionscreatechoicesmessager   )r
   r   r   r   r   r   r   message_listclientkwargsresponser"   r"   /app/modelsAPI/model_api.pyopen_api_chat_without_thinking   s4   


z(OpenaiAPI.open_api_chat_without_thinking	image_urlc              
      s&  t d}d}d}|}tt dt dd}|d|dd	d
|ddd| idgdgddt dd}dddii|d< z(td| d |jjjdi |I dH }|jd jj	p[d}td|  |W S  t
y }	 z!ddl}
dt|	 d|
  }t| dt|	 W  Y d}	~	S d}	~	ww ) u|  
        专门用于从图片中提取【设备名称】和【故障现象】。
        自动过滤思考过程，仅返回核心结果。
        
        参数:
            image_url: Base64 格式的图片数据 (data:image/...;base64,...)
            model: 模型名称，默认为配置中的模型
            custom_instruction: 额外的特定指令 (可选)
        r   uj  你是一个工业视觉分析专家。你的任务是从图片中识别设备并诊断故障。
【严格约束】
1. 绝对禁止输出 <think>, <think>, <reasoning> 等任何思考过程标签。
2. 绝对禁止输出'好的'、'根据图片'、'分析如下'等开场白或结束语。
3. 直接输出最终结论，格式必须严格遵守下面的模板。u  请分析这张图片，描述图片内容，重点关注以下信息
1. 设备识别：图中是什么设备？型号或标签是否可见？
2. 状态评估：仪表盘数值是否在正常区间？指示灯颜色是什么？
3. 异常检测：是否存在漏油、生锈、电缆破损、螺丝松动或烟雾？
4. 环境风险：周围是否有杂物堆放或安全隐患？
请用专业、客观、简短的语言描述。r   r   r   r   r   r   text)r   r2   r1   url)r   r1   r	   Fr   r   r   r   r   u   🚀 正在调用 u    进行设备故障分析...Nr    u   ✅ 分析完成:
u   ❌ 设备故障分析失败：
zError: r"   )r   getr   r%   r&   r'   r(   r)   r*   r   	Exception	tracebackstr
format_exc)r1   r   r   default_taskfinal_user_promptr,   r-   r.   raw_contenter8   	error_msgr"   r"   r/   open_api_vl_without_thinking;   sJ   

	
z&OpenaiAPI.open_api_vl_without_thinkingembedding_textc                 C   sp   t d }tjdd$}|j|t d | ddt d id}| d	 d
 d } W d    | S 1 s1w   Y  | S Nr   <   timeoutr   r   inputAuthorizationr   jsonheadersdatar   	embedding)r   httpxClientpostrJ   )rA   embedding_base_urlr,   r.   r"   r"   r/   get_embeddings   s   

zOpenaiAPI.get_embeddingsc              	      s   t d }tjdd4 I d H *}|j|t d | ddt d idI d H }| d	 d
 d }W d   I d H  |S 1 I d H s?w   Y  |S rB   )r   rN   AsyncClientrP   rJ   )rA   rQ   r,   r.   rM   r"   r"   r/   get_embeddings_async   s   
zOpenaiAPI.get_embeddings_asynctextsc              	      s   t d }tjdd4 I d H 5}|j|t d | ddt d idI d H }| d	 }t|d
d d}dd |D }W d   I d H  |S 1 I d H sJw   Y  |S )Nr   x   rD   r   rF   rH   r   rI   rL   c                 S      | d S )Nindexr"   xr"   r"   r/   <lambda>       z6OpenaiAPI.get_embeddings_batch_async.<locals>.<lambda>)keyc                 S   s   g | ]}|d  qS )rM   r"   ).0itemr"   r"   r/   
<listcomp>   s    z8OpenaiAPI.get_embeddings_batch_async.<locals>.<listcomp>)r   rN   rS   rP   rJ   sorted)rU   rQ   r,   r.   rL   sorted_data
embeddingsr"   r"   r/   get_embeddings_batch_async   s   
		z$OpenaiAPI.get_embeddings_batch_asyncvec1vec2c                 C   sx   t | tjst| n| }t |tjst|n|}tj|}tj|}|dks.|dkr0dS tt||||  S )Nr           )
isinstancenpndarrayarraylinalgnormfloatdot)re   rf   v1v2norm1norm2r"   r"   r/   cosine_similarity   s   zOpenaiAPI.cosine_similarity	query_veccandidates_vecsc           	      C   s   t | tjst| n| }dd |D }tj|}|dkr%dgt| S g }|D ]#}tj|}|dkr;|d q)tt	||||  }|| q)|S )Nc                 S   s&   g | ]}t |tjst|n|qS r"   )rh   ri   rj   rk   )r^   vr"   r"   r/   r`      s   & z5OpenaiAPI.cosine_similarity_batch.<locals>.<listcomp>r   rg   )
rh   ri   rj   rk   rl   rm   lenr$   rn   ro   )	ru   rv   r
   
candidates
query_normsimilarities	candidate	cand_normsimr"   r"   r/   cosine_similarity_batch   s   z!OpenaiAPI.cosine_similarity_batchdisplay_namerM   333333?ffffff?      ?
query_textry   name_keyembedding_keytext_weightsemantic_weighttext_thresholdsemantic_thresholdc              	      s.  |sdS t | I d H }g }	t|D ]W\}
}||d}|s6|di }|dp5|dp5|dp5d}t | |}|di }||pK||}|rUt ||}nd}|| ||  }|	|||||
d q|	jd	d
 dd |	d }|d }|d }t|| ||  d}||k rd |fS ||fS )N)Nrg   r4   propsnameu   名称u   设备名称rg   )r|   
text_scoresemantic_scorecombined_scorerX   c                 S   rW   )Nr   r"   rY   r"   r"   r/   r[     r\   z8OpenaiAPI.hybrid_match_with_embeddings.<locals>.<lambda>T)r]   reverser   r|   r   r   )	r   rT   	enumerater6   _compute_text_similarityrt   r$   sortmax)r   ry   r   r   r   r   r   r   query_embeddingscored_candidatesidxr|   r   r   r   candidate_embeddingr   r   bestbest_candidate
best_scoremin_thresholdr"   r"   r/   hybrid_match_with_embeddings   s@   "
z&OpenaiAPI.hybrid_match_with_embeddingsabc           	      C   s   | r|sdS t |   } t |  }| r|sdS | |kr"dS | |v s*|| v r,dS t| t|}}t||@ }t||B pBd}|| }tt| t| }tdd|tt| t|d  }d| d|  S )Nrg   g      ?g?   r   )r9   striplowersetrx   absr   )	r   r   set_aset_binterunionjaccardlen_difflen_penaltyr"   r"   r/   r     s"   "z"OpenaiAPI._compute_text_similarity)NNFNNTr	   )r   rM   r   r   r   r   )__name__
__module____qualname__staticmethodr9   boollistrn   r0   r@   rR   r   rT   rd   r   ri   rj   rt   r   dicttupler   r   r"   r"   r"   r/   r      s    -O 4	8r   __main__u   你好Tu   你是一个助手，请用中文回答问题。请直接给出最终答案，不要包含任何推理步骤、思考过程、解释性文字或前缀。)r
   r   r   r   )asynciorN   typingr   r   osnumpyri   openair   configr   r   r   r   r   runr0   answerr%   r"   r"   r"   r/   <module>   s(      \0xND
    ˱Mj^7                        U d dl Z d dlZd dlmZmZ d dlZd dlZd dlm	Z	 d dl
mZmZ d dlmZ d dlmZ daeed<   defd	Z G d
 d      Z G d de      Zedk(  r. e j,                  ej/                  dddd            Z ee       yy)    N)ListUnion)OpenAI)
LLM_CONFIGEMBEDDING_CONFIG)Embedder)AsyncOpenAI_async_clientreturnc                  P    t         t        t        d   t        d         a t         S )u+   获取或创建 AsyncOpenAI 单例客户端api_keybase_url)r   r   )r
   r	   r        Ee:\ZKYNLP\Hjunproject\project0506\wx-agent\app\modelsAPI\model_api.py_get_async_clientr      s,     #y)
+
 r   c                   H   e Zd Ze	 	 	 	 	 	 	 d%dededededededed	efd
       Ze	 	 	 	 	 	 	 d%dededededededefd       Z	eded	efd       Z
edefd       Zeded	ee   fd       Zedee   d	eee      fd       Zedeee   ej"                  f   deee   ej"                  f   d	efd       Zedeee   ej"                  f   deeee   ej"                  f      d	ee   fd       Ze	 	 	 	 	 	 d&dedee   dededededed ed	efd!       Zed"ed#ed	efd$       Zy)'	OpenaiAPINquerymodeljson_outputsystem_promptmessagesenable_thinkingtemperaturer   c                   K   |	t         d   }|d}d|dg}||j                  |       | |j                  d| d       t               }|||dt         d   d}	d	d
dii|	d<   |rddi|	d<   t	        d|        |j
                  j                  j                  di |	 d {   }
|
j                  d   j                  j                  S 7 'w)Nr      我是一个专业的AI助手，请用中文回答问题。请直接给出最终答案，不要包含任何推理步骤、思考过程、解释性文字或前缀。systemrolecontentuserF
max_tokensr   r   r   streamr#   chat_template_kwargsr   
extra_bodytypejson_objectresponse_formatzmodel API. history messager   r   )r   extendappendr   printchatcompletionscreatechoicesmessager!   )r   r   r   r   r   r   r   message_listclientkwargsresponses              r   open_api_chat_without_thinkingz(OpenaiAPI.open_api_chat_without_thinking   s      =w'E  CM "*mDE)E BC"$ $&#L1
 !79JE8RS|)/(?F$%*L970077A&AA"**222 Bs   BC!C	"(Cc                *  K   |	t         d   }|d}d|dg}||j                  |       | |j                  d| d       t               }|||dt         d   d	}	d
ddii|	d<   |rddi|	d<   t	        d|        |j
                  j                  j                  di |	 d{   }
|
2 3 d{   }|j                  st        |j                        dkD  s/|j                  d   j                  }|j                  sU|j                   e7 k7 b6 yw)uj   
        流式输出大模型响应
        
        Yields:
            str: 流式内容片段
        Nr   r   r   r   r"   Tr#   r$   r&   r   Fr'   r(   r)   r*   z!model API stream. history messager   r   )r   r+   r,   r   r-   r.   r/   r0   r1   lendeltar!   )r   r   r   r   r   r   r   r3   r4   r5   r%   chunkr:   s                r   open_api_chat_streamzOpenaiAPI.open_api_chat_streamG   s2      =w'E  CM "*mDE)E BC"$ $&#L1
 !79JE8RS|)/(?F$%1<@5v{{..55???! 	(%}}U]]!3a!7a(..==--' @	(6sH   BD!D"D(D,D-D0D>D%D=DDD	image_urlc                 R  K   t        j                  d      }d}d}|}t               }|d|ddd|dd	d
| idgdgddt        j                  d      d}dddii|d<   	 t        d| d        |j                  j
                  j                  di | d{   }|j                  d   j                  j                  xs d}t        d|        |S 7 ;# t        $ rF}	ddl}
dt        |	       d|
j                          }t        |       dt        |	       cY d}	~	S d}	~	ww xY ww)u|  
        专门用于从图片中提取【设备名称】和【故障现象】。
        自动过滤思考过程，仅返回核心结果。
        
        参数:
            image_url: Base64 格式的图片数据 (data:image/...;base64,...)
            model: 模型名称，默认为配置中的模型
            custom_instruction: 额外的特定指令 (可选)
        r   uj  你是一个工业视觉分析专家。你的任务是从图片中识别设备并诊断故障。
【严格约束】
1. 绝对禁止输出 <think>, <think>, <reasoning> 等任何思考过程标签。
2. 绝对禁止输出'好的'、'根据图片'、'分析如下'等开场白或结束语。
3. 直接输出最终结论，格式必须严格遵守下面的模板。u  请分析这张图片，描述图片内容，重点关注以下信息
1. 设备识别：图中是什么设备？型号或标签是否可见？
2. 状态评估：仪表盘数值是否在正常区间？指示灯颜色是什么？
3. 异常检测：是否存在漏油、生锈、电缆破损、螺丝松动或烟雾？
4. 环境风险：周围是否有杂物堆放或安全隐患？
请用专业、客观、简短的语言描述。r   r   r"   text)r(   r?   r=   url)r(   r=   皙?Fr#   r$   r&   r   r'   u   🚀 正在调用 u    进行设备故障分析...Nr    u   ✅ 分析完成:
u   ❌ 设备故障分析失败：
zError: r   )r   getr   r-   r.   r/   r0   r1   r2   r!   	Exception	tracebackstr
format_exc)r=   r   r   default_taskfinal_user_promptr4   r5   r6   raw_contenterF   	error_msgs               r   open_api_vl_without_thinkingz&OpenaiAPI.open_api_vl_without_thinking|   sh     w'
W 	? 	 ) #$ !m<"!'1BC!,E9;MN 	 $..6
$ !79JE8RS|	&&ug-IJK;V[[44;;EfEEH"**1-55==CK'}56	 F  	&9#a&IDXDXDZC[\I)SVH%%		&sH   AD'8C C:C D'C 	D$;DD$D'D$$D'embedding_textc                     t         d   }t        j                  d      5 }|j                  |t         d   | ddt         d   i      }|j	                         d	   d
   d   } d d d        | S # 1 sw Y   | S xY wNr   <   timeoutr   r   inputAuthorizationr   jsonheadersdatar   	embedding)r   httpxClientpostrY   )rO   embedding_base_urlr4   r6   s       r   get_embeddingszOpenaiAPI.get_embeddings   s    -j9\\"%{{+G4~N$&6y&AB # 
H
 &]]_V4Q7DN &  & s   AA++A5c                 F  K   t         d   }t        j                  d      4 d {   }|j                  |t         d   | ddt         d   i       d {   }|j	                         d	   d
   d   }d d d       d {    |S 7 ^7 17 
# 1 d {  7  sw Y   S xY wwrQ   )r   r]   AsyncClientr_   rY   )rO   r`   r4   r6   r\   s        r   get_embeddings_asynczOpenaiAPI.get_embeddings_async   s     -j9$$R00F#[["/8>R(*:9*EF )  H
 !/2;?I 10  1 1000 sV   $B!BB!+BBB3B!>B	?B!B	B!BBBB!textsc                   K   t         d   }t        j                  d      4 d {   }|j                  |t         d   | ddt         d   i       d {   }|j	                         d	   }t        |d
       }|D cg c]  }|d   	 }}d d d       d {    |S 7 x7 Kc c}w 7 # 1 d {  7  sw Y   S xY ww)Nr   x   rS   r   rU   rW   r   rX   r[   c                     | d   S )Nindexr   xs    r   <lambda>z6OpenaiAPI.get_embeddings_batch_async.<locals>.<lambda>   s    QwZr   )keyr\   )r   r]   rc   r_   rY   sorted)re   r`   r4   r6   r[   sorted_dataitem
embeddingss           r   get_embeddings_batch_asyncz$OpenaiAPI.get_embeddings_batch_async   s     -j9$$S11V#[["/85I(*:9*EF )  H
 ==?6*D +?@K8CD${+JD 21  2 E 2111 sh   $C BC +B*B!)B*?B#B*C B(C !B*#B*(C *B=0B31B=8C vec1vec2c                    t        | t        j                        st        j                  |       n| }t        |t        j                        st        j                  |      n|}t        j                  j                  |      }t        j                  j                  |      }|dk(  s|dk(  ryt        t        j                  ||      ||z  z        S Nr           )
isinstancenpndarrayarraylinalgnormfloatdot)rs   rt   v1v2norm1norm2s         r   cosine_similarityzOpenaiAPI.cosine_similarity   s    #-dBJJ#?RXXd^T#-dBJJ#?RXXd^T		r"		r"A:!RVVB^uu}566r   	query_veccandidates_vecsc                 >   t        | t        j                        st        j                  |       n| }|D cg c]3  }t        |t        j                        st        j                  |      n|5 }}t        j                  j                  |      }|dk(  rdgt        |      z  S g }|D ]n  }t        j                  j                  |      }|dk(  r|j                  d       9t        t        j                  ||      ||z  z        }	|j                  |	       p |S c c}w rv   )
rx   ry   rz   r{   r|   r}   r9   r,   r~   r   )
r   r   r   v
candidates
query_normsimilarities	candidate	cand_normsims
             r   cosine_similarity_batchz!OpenaiAPI.cosine_similarity_batch   s     ,6i+L#R[SbcSbaArzz)BbhhqkISb
cYY^^E*
?53z?**#I		y1IA~##C(BFF5)4
Y8NOP##C( $  ds   8D
query_textr   name_keyembedding_keytext_weightsemantic_weighttext_thresholdsemantic_thresholdc           	        K   |syt         j                  |        d {   }g }	t        |      D ]  \  }
}|j                  |d      }|sM|j                  di       }|j                  d      xs( |j                  d      xs |j                  d      xs d}t         j	                  | |      }|j                  di       }|j                  |      xs |j                  |      }|rt         j                  ||      }nd}||z  ||z  z   }|	j                  |||||
d        |	j                  d	 d
       |	d   }|d   }|d   }t        ||z  ||z  z   d      }||k  rd |fS ||fS 7 Iw)N)Nrw   rB   propsnameu   名称u   设备名称rw   )r   
text_scoresemantic_scorecombined_scoreri   c                     | d   S )Nr   r   rj   s    r   rl   z8OpenaiAPI.hybrid_match_with_embeddings.<locals>.<lambda>@  s
    Q/?-@r   T)rm   reverser   r   r   333333?)	r   rd   	enumeraterD   _compute_text_similarityr   r,   sortmax)r   r   r   r   r   r   r   r   query_embeddingscored_candidatesidxr   r   r   r   candidate_embeddingr   r   bestbest_candidate
best_scoremin_thresholds                         r   hybrid_match_with_embeddingsz&OpenaiAPI.hybrid_match_with_embeddings  s      ) > >z JJ'
3NC==2.D!gr2yy(bEIIh,?b599^C\b`b";;JMJMM'2.E"'))M":"ZimmM>Z"!*!<!<_Na!b!$(:5.8XXN$$&("0"0& % 44 	#@$O #k**+
N[8;MP_;__ade%##z))S Ks   E*E'E	E*abc                    | r|syt        |       j                         j                         } t        |      j                         j                         }| r|sy| |k(  ry| |v s|| v ryt        |       t        |      }}t	        ||z        }t	        ||z        xs d}||z  }t        t	        |       t	        |      z
        }t        dd|t        t	        |       t	        |      d      z  z
        }d|z  d|z  z   S )Nrw   g      ?g?         ?)rG   striplowersetr9   absr   )	r   r   set_aset_binterunionjaccardlen_difflen_penaltys	            r   r   z"OpenaiAPI._compute_text_similarityM  s    FLLN  "FLLN  "66Q!V1vs1vuEEM"EEM"'a%-s1vA'#sXCFCFA0F%FFGW}s[000r   )NNFNNTrA   )display_namer\   r   gffffff?r   r   )__name__
__module____qualname__staticmethodrG   boollistr~   r7   r<   rN   ra   r   rd   rr   r   ry   rz   r   r   dicttupler   r   r   r   r   r   r      s   !! $ (3(3(3 (3 	(3
 (3 (3 (3 
(3 (3T !! $ 2(2(2( 2( 	2(
 2( 2( 2( 2(h J&J&	J& J&X 
s 
 
 
3 
4; 
 
 S	 d4;>O   
7d5k2::&= > 
7eDQVKY[YcYcLcFd 
7in 
7 
7 5ebjj1H+I 37d5k2::>U8V3W\`af\g (  '( !$ #$'6*6*J6* 6* 	6*
 6* 6* 6* "6* 
6* 6*p 1C 1C 1E 1 1r   r   c                   Z    e Zd ZddededefdZdedee   fdZdee   deee      fd	Zy
)LocalBgeM3Embeddingsr   r   
model_namec                 .    || _         || _        || _        y )N)r   r   r   )selfr   r   r   s       r   __init__zLocalBgeM3Embeddings.__init__e  s     $r   r?   r   c                 ,    | j                  |g      d   S )Nr   )embed_documents)r   r?   s     r   embed_queryz LocalBgeM3Embeddings.embed_queryj  s    ##TF+A..r   re   c                 $   | j                   }t        j                  d      5 }|j                  || j                  |ddd| j
                   i      }|j                         d   D cg c]  }|d   	 c}cd d d        S c c}w # 1 sw Y   y xY w)	NrR   rS   rU   rW   zBearer rX   r[   r\   )r   r]   r^   r_   r   r   rY   )r   re   r@   r4   r6   rp   s         r   r   z$LocalBgeM3Embeddings.embed_documentsm  s    mm\\"%{{#?(GDLL>*BC # H
 3;--/&2IJ2I$D%2IJ &% K &%s   AB)B5BBBN)zbge-m3)	r   r   r   rG   r   r   r~   r   r   r   r   r   r   r   d  sV    % %s % %
/ /U /KT#Y K4U3D Kr   r   __main__u   你好Tu   你是一个助手，请用中文回答问题。请直接给出最终答案，不要包含任何推理步骤、思考过程、解释性文字或前缀。)r   r   r   r   )asyncior]   typingr   r   osnumpyry   openair   configr   r   neo4j_graphrag.embeddings.baser   r	   r
   __annotations__r   r   r   r   runr7   answerr-   r   r   r   <module>r      s       	   / 3  "{ !; G1 G1R
K8 K( zW[[AA r	 B  F 
&M r   Dx^7import asyncio
import httpx
from typing import List, Union
import os
import numpy as np
from openai import OpenAI
from config import LLM_CONFIG, EMBEDDING_CONFIG
from neo4j_graphrag.embeddings.base import Embedder

from openai import AsyncOpenAI

# 模块级单例客户端，避免每次调用都创建新连接
_async_client: AsyncOpenAI = None


def _get_async_client() -> AsyncOpenAI:
    """获取或创建 AsyncOpenAI 单例客户端"""
    global _async_client
    if _async_client is None:
        _async_client = AsyncOpenAI(
            api_key=LLM_CONFIG["api_key"],
            base_url=LLM_CONFIG["base_url"],
        )
    return _async_client


class OpenaiAPI:
    @staticmethod
    async def open_api_chat_without_thinking(
        query: str = None,
        model: str = None,
        json_output: bool = False,
        system_prompt: str = None,
        messages: list = None,
        enable_thinking: bool = True,
        temperature: float = 0.1
    ) -> str:
        if model is None:
            model = LLM_CONFIG["model"]
        if system_prompt is None:
            system_prompt = "我是一个专业的AI助手，请用中文回答问题。请直接给出最终答案，不要包含任何推理步骤、思考过程、解释性文字或前缀。"


        # 构建消息
        message_list = [{"role": "system", "content": system_prompt}]
    
        if messages is not None:
            message_list.extend(messages)
        if query is not None:
            message_list.append({"role": "user", "content": query})

        client = _get_async_client()

        kwargs = {
            "model": model,
            "messages": message_list,
            "temperature": temperature,
            "stream": False,
            "max_tokens":LLM_CONFIG["max_tokens"]
        }

        kwargs["extra_body"] = {"chat_template_kwargs": {"enable_thinking": False}}

        if json_output:
            kwargs["response_format"] = {"type": "json_object"}
        
        print("model API. history message", message_list)
        response = await client.chat.completions.create(**kwargs)
        return response.choices[0].message.content
    
    @staticmethod
    async def open_api_chat_stream(
        query: str = None,
        model: str = None,
        json_output: bool = False,
        system_prompt: str = None,
        messages: list = None,
        enable_thinking: bool = True,
        temperature: float = 0.1
    ):
        """
        流式输出大模型响应
        
        Yields:
            str: 流式内容片段
        """
        if model is None:
            model = LLM_CONFIG["model"]
        if system_prompt is None:
            system_prompt = "我是一个专业的AI助手，请用中文回答问题。请直接给出最终答案，不要包含任何推理步骤、思考过程、解释性文字或前缀。"

        # 构建消息
        message_list = [{"role": "system", "content": system_prompt}]
    
        if messages is not None:
            message_list.extend(messages)
        if query is not None:
            message_list.append({"role": "user", "content": query})

        client = _get_async_client()

        kwargs = {
            "model": model,
            "messages": message_list,
            "temperature": temperature,
            "stream": True,
            "max_tokens":LLM_CONFIG["max_tokens"]
        }

        kwargs["extra_body"] = {"chat_template_kwargs": {"enable_thinking": False}}

        if json_output:
            kwargs["response_format"] = {"type": "json_object"}
        
        print("model API stream. history message", message_list)
        
        stream = await client.chat.completions.create(**kwargs)
        async for chunk in stream:
            if chunk.choices and len(chunk.choices) > 0:
                delta = chunk.choices[0].delta
                if delta.content:
                    yield delta.content

    @staticmethod   
    async def open_api_vl_without_thinking(
        image_url: str
    ) -> str:
        """
        专门用于从图片中提取【设备名称】和【故障现象】。
        自动过滤思考过程，仅返回核心结果。
        
        参数:
            image_url: Base64 格式的图片数据 (data:image/...;base64,...)
            model: 模型名称，默认为配置中的模型
            custom_instruction: 额外的特定指令 (可选)
        """
        
        # 1. 确定模型名称
        model = LLM_CONFIG.get("model")
        
        # 2. 构建强约束的 System Prompt
        # 核心目标：禁止思考标签，禁止废话，只给结果
        system_prompt = (
            "你是一个工业视觉分析专家。你的任务是从图片中识别设备并诊断故障。\n"
            "【严格约束】\n"
            "1. 绝对禁止输出 <think>, <think>, <reasoning> 等任何思考过程标签。\n"
            "2. 绝对禁止输出'好的'、'根据图片'、'分析如下'等开场白或结束语。\n"
            "3. 直接输出最终结论，格式必须严格遵守下面的模板。"
        )

        # 3. 构建针对性的 User Prompt
        default_task = (
            "请分析这张图片，描述图片内容，重点关注以下信息\n"
            "1. 设备识别：图中是什么设备？型号或标签是否可见？\n"
            "2. 状态评估：仪表盘数值是否在正常区间？指示灯颜色是什么？\n"
            "3. 异常检测：是否存在漏油、生锈、电缆破损、螺丝松动或烟雾？\n"
            "4. 环境风险：周围是否有杂物堆放或安全隐患？\n"
            "请用专业、客观、简短的语言描述。"
        )
        
        final_user_prompt = default_task

        # 4. 初始化客户端
        client = _get_async_client()

        # 5. 构建请求参数
        kwargs = {
            "model": model,
            "messages": [
                {"role": "system", "content": system_prompt},
                {
                    "role": "user",
                    "content": [
                        {"type": "text", "text": final_user_prompt},
                        {"type": "image_url", "image_url": {"url": image_url}}
                    ]
                }
            ],
            "temperature": 0.1,  # 低温度以保证事实准确性
            "stream": False,
            "max_tokens": LLM_CONFIG.get("max_tokens"),
        }

        # 尝试通过参数关闭思考 (取决于后端支持情况)
        kwargs["extra_body"] = {"chat_template_kwargs": {"enable_thinking": False}}

        try:
            print(f"🚀 正在调用 {model} 进行设备故障分析...")
            response = await client.chat.completions.create(**kwargs)
            raw_content = response.choices[0].message.content or ""

            print(f"✅ 分析完成:\n{raw_content}")
            return raw_content

        except Exception as e:
            import traceback
            error_msg = f"❌ 设备故障分析失败：{str(e)}\n{traceback.format_exc()}"
            print(error_msg)
            return f"Error: {str(e)}"

    @staticmethod
    def get_embeddings(embedding_text: str):
        embedding_base_url = EMBEDDING_CONFIG["base_url"]

        with httpx.Client(timeout=60) as client:
            response = client.post(
            embedding_base_url,
            json={"model": EMBEDDING_CONFIG["model"], "input": embedding_text},
            headers={"Authorization": EMBEDDING_CONFIG["api_key"]},
        )
            embedding_text = response.json()["data"][0]["embedding"]
        return embedding_text

    @staticmethod
    async def get_embeddings_async(embedding_text: str) -> List[float]:
        embedding_base_url = EMBEDDING_CONFIG["base_url"]

        async with httpx.AsyncClient(timeout=60) as client:
            response = await client.post(
                embedding_base_url,
                json={"model": EMBEDDING_CONFIG["model"], "input": embedding_text},
                headers={"Authorization": EMBEDDING_CONFIG["api_key"]},
            )
            embedding = response.json()["data"][0]["embedding"]
        return embedding

    @staticmethod
    async def get_embeddings_batch_async(texts: List[str]) -> List[List[float]]:
        embedding_base_url = EMBEDDING_CONFIG["base_url"]

        async with httpx.AsyncClient(timeout=120) as client:
            response = await client.post(
                embedding_base_url,
                json={"model": EMBEDDING_CONFIG["model"], "input": texts},
                headers={"Authorization": EMBEDDING_CONFIG["api_key"]},
            )
            data = response.json()["data"]
            sorted_data = sorted(data, key=lambda x: x["index"])
            embeddings = [item["embedding"] for item in sorted_data]
        return embeddings

    @staticmethod
    def cosine_similarity(vec1: Union[List[float], np.ndarray], vec2: Union[List[float], np.ndarray]) -> float:
        v1 = np.array(vec1) if not isinstance(vec1, np.ndarray) else vec1
        v2 = np.array(vec2) if not isinstance(vec2, np.ndarray) else vec2
        
        norm1 = np.linalg.norm(v1)
        norm2 = np.linalg.norm(v2)
        
        if norm1 == 0 or norm2 == 0:
            return 0.0
        
        return float(np.dot(v1, v2) / (norm1 * norm2))

    @staticmethod
    def cosine_similarity_batch(query_vec: Union[List[float], np.ndarray], 
                                  candidates_vecs: List[Union[List[float], np.ndarray]]) -> List[float]:
        query = np.array(query_vec) if not isinstance(query_vec, np.ndarray) else query_vec
        candidates = [np.array(v) if not isinstance(v, np.ndarray) else v for v in candidates_vecs]
        
        query_norm = np.linalg.norm(query)
        if query_norm == 0:
            return [0.0] * len(candidates)
        
        similarities = []
        for candidate in candidates:
            cand_norm = np.linalg.norm(candidate)
            if cand_norm == 0:
                similarities.append(0.0)
            else:
                sim = float(np.dot(query, candidate) / (query_norm * cand_norm))
                similarities.append(sim)
        
        return similarities

    @staticmethod
    async def hybrid_match_with_embeddings(
        query_text: str,
        candidates: List[dict],
        name_key: str = "display_name",
        embedding_key: str = "embedding",
        text_weight: float = 0.3,
        semantic_weight: float = 0.7,
        text_threshold: float = 0.3,
        semantic_threshold: float = 0.5
    ) -> tuple:
        if not candidates:
            return None, 0.0
        
        query_embedding = await OpenaiAPI.get_embeddings_async(query_text)
        
        scored_candidates = []
        
        for idx, candidate in enumerate(candidates):
            name = candidate.get(name_key, "")
            if not name:
                props = candidate.get("props", {})
                name = props.get("name") or props.get("名称") or props.get("设备名称") or ""
            
            text_score = OpenaiAPI._compute_text_similarity(query_text, name)
            
            props = candidate.get("props", {})
            candidate_embedding = props.get(embedding_key) or candidate.get(embedding_key)
            
            if candidate_embedding:
                semantic_score = OpenaiAPI.cosine_similarity(query_embedding, candidate_embedding)
            else:
                semantic_score = 0.0
            
            combined_score = text_weight * text_score + semantic_weight * semantic_score
            
            scored_candidates.append({
                "candidate": candidate,
                "text_score": text_score,
                "semantic_score": semantic_score,
                "combined_score": combined_score,
                "index": idx
            })
        
        scored_candidates.sort(key=lambda x: x["combined_score"], reverse=True)
        
        best = scored_candidates[0]
        best_candidate = best["candidate"]
        best_score = best["combined_score"]
        
        min_threshold = max(text_threshold * text_weight + semantic_threshold * semantic_weight, 0.3)
        
        if best_score < min_threshold:
            return None, best_score
        
        return best_candidate, best_score

    @staticmethod
    def _compute_text_similarity(a: str, b: str) -> float:
        if not a or not b:
            return 0.0
        a = str(a).strip().lower()
        b = str(b).strip().lower()
        if not a or not b:
            return 0.0
        if a == b:
            return 1.0
        if a in b or b in a:
            return 0.9
        
        set_a, set_b = set(a), set(b)
        inter = len(set_a & set_b)
        union = len(set_a | set_b) or 1
        jaccard = inter / union
        
        len_diff = abs(len(a) - len(b))
        len_penalty = max(0.0, 1.0 - len_diff / max(len(a), len(b), 1))
        
        return 0.5 * jaccard + 0.5 * len_penalty

class LocalBgeM3Embeddings(Embedder):
    def __init__(self, base_url: str, api_key: str, model_name: str = "bge-m3"):
        self.base_url = base_url
        self.api_key = api_key
        self.model_name = model_name

    def embed_query(self, text: str) -> List[float]:
        return self.embed_documents([text])[0]

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        url = self.base_url 
        with httpx.Client(timeout=60) as client:
            response = client.post(
                url,
                json={"model": self.model_name, "input": texts},
                headers={"Authorization": f"Bearer {self.api_key}"},
            )
            return [item["embedding"] for item in response.json()["data"]]
    

if __name__ == "__main__":
    answer = asyncio.run(OpenaiAPI.open_api_chat_without_thinking(
        query="你好",
        json_output=True,
        system_prompt="你是一个助手，请用中文回答问题。请直接给出最终答案，不要包含任何推理步骤、思考过程、解释性文字或前缀。",
        enable_thinking=True
    ))
    print(answer)
        


NBx'100644 015ebb33d2a3_20260324072409.png )iqN100644 08f8efd6f1d4_20260324110619.png )iqN100644 1ee23229170a_20260324082344.png )iqN100644 22f06245ed56_20260601022623.png pG58od=t0100644 334ee511347b_20260323061707.png КklI<ٴ|-%0100644 4341.png <hSu~FY9+t100644 44b07d453030_20260323024633.png КklI<ٴ|-%0100644 50da933dcb11_20260323062013.jpg `qjxf@ZT:100644 58a85f24f7cf_20260323024053.png ]i9%h?z100644 79493c5be2ac_20260324081251.png )iqN100644 95f8928fb88c_20260324083528.png )iqN100644 OIP-C.png )iqN100644 bbeb197ac231_20260323060515.png КklI<ٴ|-%0100644 d345fbf33f95_20260325031818.png )iqN100644 dcd6a33ef2b0_20260324071427.png )iqN100644 e0bb42e29c58_20260323062055.jpg `qjxf@ZT:100644 f233ccc07264_20260323060328.png КklI<ٴ|-%0100644 f38267265a8a_20260323032735.png ˚kURꐪF100644 image_records.json >HL)f5QpȲx)}RIFFz)  WEBPVP8 n)   * >BI%"*Q~ gn1 d?.tʴյn'g/#﨏47|@sjt[Q\Uo5ߋ0%|Z^Z쥇}>YJmNzb՛ab,kcj學75PP&r\)V*$nx7bs:&\M̈́m4\&:!W+vW.eH;ӬF?HtWx~y=L*v/EykdC{䵠}v*U̠s"Qܩ"	zaeDiu}%'wB8/kߞwsa8:WRA'a(ӺHғ[Q@1ܝܤ60tsNp8o IR~,yk?s1`١Cpfɬ]uڶON2mR)
Oe׬	.AO|p~>Ro\R)j0kϧSE|iiӟ[ǩIUx.bj;oɲi-ǿwٍj3D3L7*N:TzB"78zr	G,Vh?^3.n]8, ( {9-R9}Nۦ17'1!yeX_~bN#^5IfsbQ>5ٳɔ+A&%:J"Iy7:
g(TttY&w=7|_j5XR
a8iIKZKx35I	7`Q9lF/|_&2Zl?yQ_#;]F"~} жD&ph0Op}~>גhp\6N(gK0N1x΂{ 'i[YѾ1zpk@1@`(
"b-zߨwT{Gz$Rӊ1q>YQg4a@faKg\ k&~W1F;GTODkṂ!Q-s5t9#3N."-$K89OyxYQT	M,Ĕ]JQѝy(EDPg}Q)L96ήB3ǠKIO1[6Fg)C!Z'{C/m>&I.&~
f4E|88m׷Qb	#[_L[\IV94Ĝz$~@F$c5rJ@WXcz\\J)S}âp7@'#A)
|t&PPh~Fw̑?*UTe?r7*[e[CAZ~jKoGG_=@]w~J&Ψf7*  EiJ[:%dIBMJŌT?k_D"k .;QT!ryQ'=Lt'#ߐ2I\*oKtk%ͦ.B<߶mEZ}AXT?OƷ^	]ڠٔ5YuoE)r89MxYmCʝj|9pt@Vi/YKee5vA7-wKQx(?	Pym|-Z=~q0r
զ5@|<MȉQVϷB͹(
'jFIw[kְ<&x\`.A!aG7?к!Y[ڳ/ԗe5&UɅx:==;ܝsʊDZ.NulYlcvxn}aO9P)[A8~Y.;h{E	66ڎ<l U;v"ئ<KnwR-+Xz"XVLsAE|U>Nȹ̽nKn"gdrhfՠdto뗮;6T9=>ԙj;TwIAe8A&M6VȻ,Sf5UȠ~rH%|e6K^0c>E5=7;%+s	kx2є>)ʲ\u>v]ċݎ{Z A1| c2"k'12jjv$hN:5AR\3׬-.Xp	JfǴ#P&K)]G`z [`xx[zvy!;w)~FjClѡ=%u-!}GHɮB򘫾@V7FHؔs3wS8 sm<
6Rwzq0{"Rexf{pS܁=gQlDQzEQ)&!osvYoPav"+Tbp/|_r"yPhx -|ī%6΋Jl˥eUev27Gx;MA~5_/c+̻fOYs@cD䚹*8-π'lܤ%.I::2/xYcvD]/ǝ	όz*=^;`թ06ҝzXձ~Ӥ>16RV{K0#41prL߇A!/h=65C^A4m:zwgq/|ۡ􀸱C`m;NR=gH˸Faw<D#5zǵu{@
\d*{E"d6y3و~3cN-a{OB![T4J` g~T_ bmQcS`cF[N4I`aj#9όGjSo5zDeHޓ;%lFL
,_A~V;ѷ/ͨNQ8C'stC* ^ц#̲fr'j}ɕrNT9)kϫ`?l.Ud-݅vRw:<І2GqI9aFP+̸5܈&.``_r5{(U#YNi1"0qřn d6ό^Xl]0]sW[H:4<G(8x>hZK4.~]W+T
Tv/]¨TQ"}0L5'r@'J9	zf.teq.1'y#*"RzrsоA'&j(1_0K|IG=FE:ml/t=#B?VDǳ	;<O׻ϩABEO"ROOLlz 쎗gQ[MzY^@&`PYi	ށ^< \99OD_{frE|5ťVOu_>
`.Z>Tf@}ΛYTT$qbgDC%oזӝtYN|;.`ZoYy	ϧ&Elzn6.IаjyTRf
vC?EyUZ]l~~\ Z34wk㪨6yeE;NqjR8BOm,cw5V @kXrh]mKT3/S:]dpg]t^i:Uny n]"HV{26!^մJ5H`f+N_^!	}z-ht>oL"+gtuLದ]Rb<W~%!L.h}_{>1IL2D-MJ^9M!3n'qV5X_)`Ź~Eb
>&64ReL(+#͸BALV /@ޢH62ݎ>la&euQh)?eFmea|=HUիJ?"!J=
`	$SF7oܞ>#&gi
Lbh]RQ={ܰɊcrsR?l-)&'0םL f	N"csu+6YZ2p0he!n&X 
%7z@̐m"sAw5Jkݛ:ydApP߭jFd|8jHm% & F'Զvi7.!tjߚ鹉٫:9/9b<W>U9MnvzE$Fw>")9[1Yny8J'#;DY>;-p~bTs!԰zpRA-;N 3Gc;,(c76ř]!gf'ːK0{IGM#ܭq	B&F1%PE_1:\8MQVgh:4j}l bƑ9-Sᄻ9T@=
t:ޛv8urG;5ZMGkD Kͨx<j>T{;jM2?FuCCIyd%oг%45YXM/=+ۍ'/l2s',2`C(Q{ rLɌ "0f'z'W T2t%aFكaFC5~}4.kԽ绿Lm4pD㡘5m!jA*zu{zF:pzh=,(*>1dgA* S< TCE7pg$36ŮqL%."aYHkmׁ_w	"
LCmc ɉJd*1w2	C8!} iѷ%'' _7i&Og?.U"%grYwVFA}wOO<گO",\@h|CPɳ5MEoB26GE1?w	9Ռe_:!mOI"*/|4|1Нm`ƌx~$?Xs@vuEΜoĎL>eyiMyA}bQ60]DH/}oiHNЪ㪿5+N:ctF5r˼!_B4]*q=8;prh[v#hSl Ef\,0Qe%8ps6G{xڐ7aR6X|i;-@at๼tBAKm}ţ7G
HҜv<
(˥Hʰ=H$iNs5 _rzPw5ϻbD{&d K5^PB$6#0io	oDmHL͕;Е J3nf/Mh/04k$=rZ(T|-G9XVM1{-@t=-ig^b'zҎ-BzJ*24*9{ZcaEwJ9!J(w3懱$[ZW81ʹ٫zɨEʇ^ԓV97T!kāqp(C@*LԵ	J
rDq3G3_)${T:vī*Yy@!JV\id$ӔN?y0ke(Wā kYBKGNPe'ynD:xtzj7Z!Qޛ20L{_Jsi18E|HS";ʽay<uے_
ĉ|q?\DɜH(]u 1x梒U#B1JPHJ>~.q1ZQft%ƸSGZJ*qxkZD|*_4MJt7ʌ3ݫ2Z%AkۓO:Ķ*ЎKaDR&q6[J[N~`2`+=B|r7]N=ghUv[QD+ N,E<=feyŖb.F)]cLrU ~u`:c]hS|2%aHN) Y>ҸE}
[J|0#M<=&ϓ`͡F|L:1OJ@!<g"vUZ&h}ne[ZU7+Zqy^9(ѼPgZHD0_z:,щ
ءXyC&0(
rUrFn'_lA?KF+լһl$7<tBc3ی=P٭by7<`PAo#U.D㵍xPioE')~ zH;/?zt+i bvtB7IڄD6_B%]X8;4@%:܍8-z3eĨ{'hIw)+R/Fa|Om&~6#K_3a,$pe&Ő4^rCL˛w`cެbk.ثvc4ؠAmUך!|aA"1C<J_'+3p/߻Xr]oC͒[OO4^WDH~jU=I2*=Gz羄GW1eʉ1Pm_jsS78kD(ρro}\࿉)^5b {^te[tߕ
gWep̝:>CZ1lpOGS@<<.RǶ^XU' H3+Hб1P^GE{պnGZ@ϾBogBb8҆t{j"[$YCj6os>FjZ`*;v%êME		]حhZR2xQG򤾠#r5&7qXES*!Sd|)];XZjmv7,B30eBH۾ O9Q 3(p>n}9zk/4?
).n[8MRI7vT]?|6:sI-Oư=@c@>/Y_.(݄5<83CU5}HD:G}JSgd.t~:bl*r"@+Yf&ijeT$;Kv=sd+sţMMOskn)B
x͡\챩GܐQĳ=-*G?)1K$TREWϦ-9b-5+9ZQ!ro9E	Wݭ'*?ܕ8u@ MjԶvm_tnQvCԐv"8&ZT6Y4i84?2jDr>ji/&e#ĈnGC~ހ ryź&v!L+U6]o|7<2cRl`/>'*J?r^8jJ/GjC6P{*(\TWjsCyNB n`_H4鯰5l=B @!wk	SxKla7'Q~lyXks}?DpOC$O\Vֈ-F`-/W$:E׉vSnu=n^!r)"֊?E?.?ю+'m)5?](;sd X3LTw1S0WC%Jܶ3vl>JkLqL&jHB	8o߄`/eKq'ǊA7[V}aң9=-p[^,,H?z`G7luzIG T%Oc}AtH:Z1N#U|Y7F]OqyxX9َTO*,|R]oIcD3?bI0bZkݜ0Nw<n,V1 <yCv*;b;FU 1וGy.~vnߛ\ #z)N)f85zDO?C"8A7|䷂xpPw3W!YUn:2[$֡#Z';!|1N'jagGvPwY 	E$G!aChP3o>cBS)&PcxaFNv)\8љ9?	
JA?bDt*?REoVy/ʾm]S<%iH qyg)C@:	uoAFF[Q#T=\e 6Jϲۗu< ^'1Fau٦pk3'bB+jZސ֣bݛB/jy@gDԘVXnI!T@F:eh$P퓢Ҍcsdz>b` =ɇl>S@)ش	X%SaTU[Ɲ[{
#V`{9qm-Jϓ<	D+Z܁FE~?U
b:V朮v4o?*\^t7WEdSڋG!4hGH`fQ%%bǘٲk	!Hv=īfn-}%*
tͳ]'vʹaͳ[@[鮧R%gSZK~&jԪaш'!Zjqy".MNZ߄8hiǰ^,Hoqi8'vxj`KL/p"bɼo Vv 6xFoڙL~|{X[b_-UEy6
I6B'jZcKqBOG0<YvdX]Gddw{\+:RL"^Ż	LhG]/6豘ϡbS]B쎢`1rZ@*0	%wզ5\աӑA$ؤ4(3r|<Ҙ*U{lMrF듣"b?$  M2vZ~(W3}Qu.P8QI@KE0>ԃ>{%ν}W1.kܔHk֘iMXhCE㘀0f)&&ёSsA_Ǵ mfAؔ+JMúm!^du
HCRXRB{DW3&!HԙցEBjz+>t_*	UA,`=XJ*K6Wj)02p1qLpsR1ħEdv@m~aޕ|?U I43vSaL\ ʵj6#{N,J~03=eY{[vmx2؆G\zzCKK<c>@,Fl}C+znR&y[k()SL't:L5Ppz$7/o'1M9nwʿIݖ-UޙyMס\A$+t51:Sĝ)sU(NjqEV49suWHq.6v{.{OK2dQs74]4 D(n$+8K/<%`<9.濽})γy?&e	7ŷ@.34Pw}^xܑNS!V̈́D}_t_|%$Ån8%~~uqQՌ֜H=B>]Mۓ*DTЕ ZAg:,gZǨ!)G[r|]{r_.X6sUժ80Jmp \( 	MCP(Lm@9ASRN׈8N dbnhX	XFeĊ>ʒh9T51ݥ<2~1&AUu	a#eHZzJ׾m ۝Ͱx   PNG

   IHDR    L   Gr   sRGB    gAMA  a   	pHYs    od  IDATx^[fzׇ>kua-DI%e,D.* p+N.X2U\NPec#BeH`8 "ׇ{uwy]@c13s9|['_oM'[A[Un߹7o^޽]Vv[t/^0Ͻ{Mwjsyf*3<K&t\r{իVU+x~noޠO;l/^۫/W	ogrB*OWQ6㓻wl/%'S1|vEI 5}n߾%޵}۲ys3L?<<m~-MmMnG>F[o+hy?׿ ~Cuܲg|+n?$a*8z1}J,h7?P5_] OKsJvCUWԿf($f<z:#"45ϛ_]%O_vL; c|Dk-2:g>Լ	n41UB}7im 'Uﷷ'fpC%c])g߾y-Z2EXҸP+Pu	WzK]T""9һ@&4о"KYCt׭id§PV	=x35#y# I_,>Hs7L͜!Piǥ:ħ{E|Xbhq5&SN@\䑊pTQvqa<\p+f,8g^90Ɂʹ;cƠ9Ct2^5Wh=@G%bҁs.ŋE"i3 s<a8ww{|kCO&;=պӈc;T|~-l I&:#PnxKחJ3btlԑT´ܿ=8۞?T{n٩i!~ڛV|{e+}ϵ/.Mw&OO$[~݉چ/S߷| yX7/W}r?įq'ּsGG?9ETVWS^㜛>nk$n3DJJu?ȃ'wet;2Wdz	l<D }_ש9ydKrHW"c4U	%F?}mVuo=~=CCqݞ<y<ퟱ@{Wo?p9R/4X_3ۢ}&,{qú9Inً|ŨeCnI1kb DS?<RZ|~`sR}k2^j^Tss<ȁ7߹y75>k55`G?gΗCwޞoSCُ>u "||[n3myH,d@4mco9|+8 1Z*	]sf	:xڱ3<9a{~9]hGmvOO<yyF@v:xPȤewKYx	%cAnڧ=JV0";;R+϶18 &/P4L
JɖRb'PJ0AQUqE{C/ZOj[t[ws/AKQQ9Զ,qۂXxҎ7[0{}}Cu6ڬV#lTfasfCK̠U Q =+A:g$=Co̉JЦK	*a<g.q!3u#PeZ4zvBmag-Xܺ-p / Z_И'Ұ}PȮ!4W SUk 9%dCm/Ӳ__
gZ>_X3p/}|!1lS?eʆyiN 4:roZT[?MwGKcsc?䮲v}_$2t}T\:"13Yl =t+c8eu-E^jez}1*1VZ89jՉjk9)oLae35nzJ/^\ZFìLxIOJR9>`9{#/_ߚR~(O?%&<I{&+:yT ?{.1xXDeA{BmoepQowT7@q
4qA44 r|V%Ud>sЛ-H\nCOwCo$H|3$|Vȱ'x.a0a`un?=M]mN6!^hDN?idY-@~<zLjB:K}/\`(u,$#8r;&JbӧTCTgIgI!(9&=`Bmp$-m7hi?2A&Ą,	CGi!b/yG:Q)2+6Pol}XDu1͍!&C&644o4Ȝ1tɎK~*93
%1J_";TVѦ?}|-(04,Y˙\]N.SqCA"]8
5ܤmX¡m&hPN;OёTbKX{s>@ynՅ`]P>o*IDz_ nrÚ+Ix$ӬT=nqݯ^fN<'1{s<;,*lH䛢w'Y/\o.c1,:,.)O=A!99=ztfݞqWWч=g}#	܂!lTHq)]q}` s)\iD;CA6F7PA,7C6={E>C&Q-!"e\pAXZvZL
g.$dz~u:F{vTrPϼ-: uk{iuziƢׄM[gmHvVƋlM.Z(߼.t__}dsUuUr(m܀>`T(-=e`Aʬ\~O<;;zbpuVz(sxj3}ѣl2\]}I{%^6鶀W<O)@c>lR\ڲ@I`6?O^>|D}%^rW뒾^&݃{u(g3)sj|&(%o x7gj;yEṔbQvU?ss"~B{?ٕj}+B!{_g.4G1G']
۾oio}y 8GЇ̕]c:GWVrE߹]XS&6|ϩ'wB +"R8Ca^HS1|
vůq=)迶;-QNɚC8d3͛iWX`qS"»+S&Ykp X9N5,uŬ]QL4f\}	Nxern2Qϊ?@E564r3>P`:Z2&n+]r2[YiBi!Xr<?)uIˮikp<y9-ǚo`EDlQyubUZ.:`e>g7%bk
>E)Udmt૔!vp[cm0rmY)<zm|(1i7JtԻȎv'\cu[q'fQA#4i~\3ru# 5廏Џ_+S,O"b#'5u%ǃ3u]eQ:$m?^s/yp5̯͝oؠb$򕮊5Wrmkԁr_a<Η ~uP	풑kTƶΨY
 <$5gx:7>%qHAa)z^|Wl+u5V9uhɔC'at*c#gLΆiH<y|trnZOIg0'AXB1p!<t#3ǛU_Yǒ> {\粉΃Ryp&D<L03:`A|ʼat{'_b/Qu5	|(L ө>&H_6	Z6RLbI)~/f--H]ұsCLn(h<2J?)3Nt[~֛>I8@I!}i.3̕ʖmEBa<Ķ)J_+1\7"V({9l
(^~}(A
А?`CNFK(}cZig8XFۨIouxb=8nfӄ~.ů]/&ICh'2^E^S=DE؎HxkHL'@yCF|D+
sglRRU<@D̸p%
zs;܄bzk&h0yQRh/&VDt u^''=r^*&5:?04ioS[%	k4bnXs*C|X8G{[@"uA6t>wJ7,ϱ-T_o`1sh8'@gVu`#7ln,BĹA}M/et;/0e"gNs%{ ̫:zkW9p97 J|wT/L@*|yOA!k,(lľ+.cs {S}r跼@.&\०l0V{#/NɍߠכRخr?l-bUy5vCII[Q,׸7^78GyI{wOiK))&G0D"A/5qrSȣqBk =5lmK'GS}?r|5W oږ: |򵭐,%p@Wفa(?G 0:Rʋ'ۙڝ_߰YBv""ߕ7;veNȃ	[l[<b-F'oBR)כv^e-r"QPB>Zy`*CB\^|g$K5}#gg</Ny|b@sCf98OMꉯgۑYP;I;` |o@QGJ|Ue\!u+_R3
5G\7̂9rRZ]M(]T$z1\o-flJGZyޥ݀G+lDō~R>ne^nFwtny7`R9-e|H[1._\ڮ4`nFr :Eƛ=vSLzadft,%]0x^vRؾ$zP|1:4@0o]`A9DSpȈ t̳̅u.G_£rKg֥"/rwKWR`(4sU,B*"vԧ״g_?EqCCJoRrb ͔EP>d#X[֡4}iil`s$-/{!2\DwPxRNx"S]hu$kIbsы%.k9쵕״ m $ŏMXEcZCxL@q|FW:pEE(eXѩ(<Tf	Rكx~FtkJN8Xo1&^;u?N@y	:SzlXf:ey	@ej`tR,<J₟
pAD[=74̖X}TymE7QE%,4@Ca䓗,%~2flOC~7_p@r{ȗ..d[~JX`BCwI n PO؝䧶>]:@q<2Ia;q1`uŦ\O3r3hhٲLv!kڒr&>dpk\4ўSx|c&bq+ZO\LN*V ߐu&f8ڦwnC	Q(
mb $:~@b}/\ $q(㶮'KDs8L&ĶWA1$CbC5CQZ P,_ㇾvc3Ȗ$Y[d|qB8RUQyƸLC~"O`sxRO3kH[i2-" 7J:I@	fI	>zіT&\ϑ5t:D 0]s3ϵ#ftQG];!"&I6"6ޞ.JK'Vahc7xr3r 
Q,,dڔNʸxCy>(Ч8G1-QDfolSQd?ݗ} -Čgd`>~]Y(hXl4	6)rΖLO=~칉<7S3_(-|ebfn>^l'Mm_qC[941]ctz]_21N񸘱-9c;ܯF1:A>eT?s09k((h/Kzx#勫NoJ&7Y+̅k=EkTaML"[xqz"tQ'Q7: 'IE˚/䃌%!Pp@G߼/Yt6ݍtv#I8}{nƓғ|:a,yA/Η:$$ТvpT7ؔpMUlqB04~?,W-$m
sR]=
8:JcivE!Q24p]}Su`r7\C/[Q:JAz&c%0>7L%2{|rC&-T SjtT&cnf]^\'$Uek\:79ֱJח
̑¯AyO&SE$c=5ye2-)j2W_Ff۳Naafq]wPλMU6HWP"َ.Q8W^mfwЅ*%m?;[zۓcfY4f>mb˾>ZP=]a{(3bH3k	Z~߽M&y&d#;M#\c!JRRqKki|ORP@}oR}ǉ
&
4;s +瓚m *MO֠n3S)}e7:4D͹>m~x	D@X}hD;y8b*>i_*> \X{af:1Xm*>y \j:0>ǂA	vk\߮< |pC*ic mï"<5y9w&}[.úk	)`y@YA4F.vPIR\sH'< ŵ:<*xA<okuǏ#\AHc&0mΓ\
Ϳ7z-d׃ 9dHKP2γ5Li~u[5ɝW5s_/cʁ~,ߜ'JIC|iŎq 'T).Ц^B?\mM'F~:6 :2Hvq,,[:'`iW.Rt͍#o<<Xi`oyuԗTIdB߾~nx#i '=`֐@Z6Yj?2P(Fj&z5I ޓhNsS,+zYS 6f}Q6=8I͛9a;V_Otp&n4be
HC?,nʒOMI)qMJBGI?j#,9`=7.Cx gN3y1Bm\#-cp˃5ԋBOdهMoȅ-:P'KS7{H/mu|T)
?Ɨ ^L>UjYngbC38.(t/گ^L )(O҂n^9$K	Pyd3t+ xc,	uK \ͼ
 m/KS:2L_ǮM1nKy*Ooyt^K#ю'Qۣ/uapuUXxFn/^~nPB}DFJؑŹla,%vnF"7Ǎ;iq0ʮ}N{wOկ?X0#v?RoܭP/n˾}vސp0Oq#^'a~΍V7tSJ\|%]XN/e)
}5$£!ϡY>fR
s0mo~FBoP7_PG_Mm}Xel>T{f"RE37?`͓)<'.,7@`mYz@Rؕ>Ϩژ
@_P!d\i}E~._3]'ϫ8Ь|p.̹q=@YdحhΧ'8hX)?]&$TVgA84.Xp&PȻh}ϛ#1qBuΤiA2D.8QCe
w:nJ,ۼI=#R@SVIŜ}1p_s&UcLI`L8Mlg<mۇO_W~P?)|f%zS\WG5O&926gͣ*?s:WC{	Mm9"eEnZXl͹?(|xx=?1QR'|3{	pb+/}"e78/Ay$_
?3/$Gb3uvQXT;2QS5PA>VnF~dkro)GbŬE`pfo=Qߤᘒ*Oyewؔ5U kJ:5 7맏y	L<y}Γ__|%xQ}L(n>ďn[˫^kY؎PwƐ(N?xK`z˚Lz+a'L;4!Y[TF,dBT2QaRk§Dg,9<uxB#	m)@H?̬Um[-]ldH+f^kX
I XG VBcwqQ\X׺7ԓyEx%·A*ZM4ȔH>m(j"Ў!0e.t}:mJɀ4U{5k C\r-{nџ }LPcSu\l̓n1xIyge嚤q%:{J/u#bsb^lH;mTw'*Tog2t=RKHX`;<26n0>c}ʜX^ ҼNpYŅ{gQ2 ޹蛾Zҍ;vI3,';eMtl*)`=@sA78ē?2 %aZ͉|(ܽ9-MǢ{5!<17gBvy9'{=)Πr(47t4'bzlT$f,e1I>bz8ȁ3	c?ub[V}CQb꟢m4~rDd=Z~"K'Kk;<њʂ~\58VT5v4U>ZZd+Rס`.AE*8"@id5o˦LX#r%iZMWvOC)32S``}בÛٴsz-i%^|$N%`s_^/}L#ի"GǱ	+AW(Itx)p;+۾1uk\?cDˁ.>;ƼY
>dևML>
&1 &}|t/.KOGI3kA22NkvHiͷ^:Z>LN["M6	t?q=Q$7K\УK.ųϟQ5D섎sbYfEMԋh,?kqM6{.y+,@ʍn/]h`xoHo/NW=,Yp<og!zxs(/|s_YG6&gnU]X'жSfg\@}4f57sd'-K=ђ-_k˗ٌ99>lh {QCdsvzӌ~7?,<Ae}[(Jz]s:< [6mt+4w80tP:2WwHTE2E6W?WrHI42b|)G;xAa*/ ko=~%~vv<v6'r/&'0	ˤC,8 ;~#i/,4eYb˙JQ  \![BRq6
,i@z8wX_f%]j(^R:Y3z1Θױ)(.Ƨǹھk7{6
	y88>А(t_%dmK6}{)TV@)h*!sx2cCѰ㞣5|nzVI@<<GåuS,n?]̗Zv̕eQ*juyz=|OQ/!҆~!@&2tYd2D0đ54XLA7;yAPe*|(k+W,`tH:<`[2gy寅"@\]ZfOʂ$q8wQ`{͘9B"9.>׳Sh|+0}ŚCW|JA)}u%#Wk#C׺!d϶%9N<6vUBxH]<x"_}7|65AavSnߩ}#3$5=48Kڂ5]SI97*ю2[M1]Hr/*v%BB2#{URrSsHzT5\Ul6F=oȐJyk#66y(y|268\p=Z{?&{v._?`-|}/⾆_8ZdZd՜eMzGNx!ލ`/s|T'yED-&)]ǮcZz,F~X!ҷ ?lQ]>$_s61"y5 4jX]]NXFgG(*gvGTpA@G84}h]kSO#.:rFǿg>3GN0#Ee
@-p~uZs4d(JG[mև8GVJL(6dۨȜU%*`;7}B\&*@QrnƔnK_ *o:SyM|SLWw ~ExȘ|e:z{` ǝ)(zp81a4 fPg+Mjp;TY|zS/7ڌ0"HHK4I"ܖxnCTpo+tP681yL kL}	,(n뤯tc^hM,Fbl$lsRxO`}R`
f]oK6Ժߪ,&YVmln^և6LBEV(^&z*mc>]kI.+:
XPDSi+60MҎaة='}^`s$a>yӑbFmCs:6+=GXcop&BLs]Ҫ ͟2<S\GL?͆/QUsII?xC߉/,8Q|d<yľ n@q6@][<f	/[V"D~fll{69z4BGݱ	d<SY-z-|<|TE_	c>ZnbOl\:壔y>G*}soJm2>|jӗ#:t[Ȥe|)Ye-p\PW~&]C Rc=u<q|pB(+Xfs+OC׻g4
q?0*z\h:H	(n3Z 0^K&J+P=l~X7\3]6'c&
H̗TI"=B*|λ90283BumKqpN+sFVyCB6Ws (2e2ő4![QsNܤ4sRcCLo-%6tLR@MP~_ڇncbˌH(;4]vq-||79&]ġԓ"?"WmCn>	Dڈm|yy{ZSu\4Qy%.X)Z%U :Й tZHo0q_Ji֟DG\_>lbsNR
f/0)sAk&}nind#kJα/OH2E	 =|kR4 TXQ]C	mA8ؕ8(@a%š#dH_gtQAIE(	^K~cU#*[gUB/#\*=ɒWq8$SxUcD6kw:;<vr\x|%wNڐ__kNmʆZCͷm'v :1K6|W;";\κAi:u]ӌ*'_|9ޡoR[[Z)A!BQFKEυ0>BdUHQ@IZϾK>Ӭasyh1?J =}1ь!,L`=0a1Ek8+T{222.ІsindF.igx_k RdTlh6s֝
.\Tn`hpwy6hYB144+`CQ%	_g:y
}z._>A>ڲB@:54 9#I	ِ+#uXad2Q2ѣVDğ*Ĺ	Ot0^>p[!W|2TNwKM?o-m1ek}$ʑX+a*mmt(pC]EtfPPGHɡhe;UE<4ĥ _%Y	*ZDf\h|x+,x%On	D_q;%~H$723Omە.{,__ :5׾<)F׻p!ghAxPqîdX! E[m:p#!Ѵ'mnp9O&11G!NfNJ۾ϼes9<U67Z,}ÐEg'ԛp&QB?W܋;1Bo;	NqjErO6Xs.:p(_!:s!p=~<^$JV`ہxH$Y.V	^h+~z7aYܓ\6;AC%{$/L,\ñYMp	[N'Y=2~5G3@8.XOOxM'_97EoK&oV_?nj={3uY&:O29gӛ:Ï 
,Ϩc7 -O.x9/˩ҷ#õ#~ %<$p0,UP [EuS4	7.Iv?_Q}#?[DOTvyBN0Kq'\ocqH79!<KH9l2v$Xd(I@87{0Ͼ.ENNxťc(Q_Ao\ix)SFsA"ƋJ
+A'xSǨPldtWPf9iWKY樜G9|
2TG)u"׍>ἀ,
])<2nM0dqZCi@!͙El,j~> K+ q贵YCS'>= o94DPPW\N2]Naݕ$`YŮJdk#, C\ô=ىl)`*̭c@s_5/d朌,]Gp</QG6%N[O&VpL4x`;%Z'Y/"^^^q,!#P+p4<&J
JB~eSQuyJ'0q$1T2c*~L[ͰWؼ+kC72"ߩ/d+y:QgGcдsәgXZNAPR8;ppk
IQ"ƹk!*!{3tyWYT{|ϲG8?,1#CѬ8ӹ?J~Rջw?a?繗9 jB5H+p=s%y<׾ϵ[Wk^/x<5C6<;Wy-6_F=ᒮ2Ё9*?BOÕzO)a֧lJ!׺Y޿p[0U;+I9O}n	W,\w\F7w858T&+)Xf!UoT0LX03ز͍
Jr!ߩ#jL#X@9xt6-e'`7Etlu(ͤE6)/ɻf7F&d܌L$.6;r1$e#VeKк+DEh]?&&NEZbX*׼L،?|$|.ʗ`CIhƆT]GNAHH9}ɰ[0# wе`[)TC-Mp K\4N,u;"T$y%Ziuh.2:8$ /;.G/
At}Ň@1(F}zd:b U6Ҿ|/c9U,L<&@J>(>hO;ef0 i8b'&%V+!`QĊuq#9ΞfE:[`|C0o`eyLqvTpLQ8~#nU@UzۅKpٗ
yC7kN'<>"	~ag6R__YϥWpӈ6p@hfh)M?隋!Ho.do*s5	nSox۬2-5sC7b?CP`sZ,six ʆGΉlX﹡&ԁ#*{xz,<f߉
	6>(\^\d]ߪ\X!9 z5v߭[7JeِAA^oZJ>MJN	SoȈ?7ȠpNu߸_GF}LU|"0/y Uڋ8dcs.>ǲ="H9܋,LmLx-}86?|`{7g"{3@ՙ6da"OwZ5 Ttd+>zs._'065=<?>a9!	,?2ئWN2W4XӁ0Z|+BrP߄N@R~ȇC.:oiI| 1c>\k5xʘSfXhHG;9kp!T>=\OA{ϭ-1.j4ȰM cRnD3u
7ɇ \ƛ./9S8|[!sgϷ?|D_ELKq?5	1%iOJec5-b6-9,7`<~t:$vi>6vcJ;f(Y߼ý؁DRWn#e$qڙIdNe=OA#5c2ww|9s[qIpK傖c0|̌ ᷯY'Bvr(KҒ`b	"^ ׉tѝ'.Wқ^gW7=a@7 f=j'qǴ>w@şOpPzư#L|x
_Nd5UxsX&/
&srER>;6dҽ֤K}~<aONQ}t*d@١/z/5<5&fdM#/k3rk	d]@wx?r$8cJܕXe3DvUp5Tm;qi- \s{flڮ) ʀK"KShQ^&Gvƈ$}U1>.ʞ+"]pJr cJjvU&+XSI 8#/r8&e5nPs&p4xXu4h T`y+"6IPbQXKI|؃afP.-ef|CLr{ز13> :<9 |91Jw	L:6H'Lȴd>x7ɰڌ  &|23d&r8	ɫK$o9yx3:ud"LMщXL1HR5SOk &?;"+pr{ɡ9Phɋd
%0	IYoN^O whF_g#Gǲ-$hiYaGi,UU؈|ײK]ps(TMRWe$PMPԂ;nz{!|N3 (ST} $M'B<,x,N~d;2k Js,;>칔ܾs嫫\d^|Wu"l{RJ1/<YAl-Ph*V?͠~BU6oC/X
Pp?F,R4l\
9s#b6wgNOO{ۜ^f~D$z \
S+H?[&6NX3"OMH(/!J~"jb3#i'sE&QnftEd

^(8#?+@bt3Qܜ27xi~ɞ-<УJMWl fD7ҟuc#[Wpb̉^GI:;s 
JBbՙ6wImu.[;>ۃ2V餔~KJX#ug=~vĦ;w[?Ns#,L6m)%!k(@Ќ3FoԻ;7mۂoC9b%..q/_ͼqݞ>}jǂU71v22	n>G~TѺ>TWS~|á^}}4DIMd']
;I?q)dGHdNbQp*cd+pne
_R-#ÇUFthPF%Aܭ^iB} #蠯吔N18 ]l xS|y?OB(Iӕ5QA8t!r+}0j_}ФoCe81ȀWi&
8upR"sD`1pEO570fg7:: ;ihb3kpYioE;4'/=uGRbj?*4k*oK_KKCEfȅ	fEm36'IL特L^.q} ql!BݑK?<CCY:`P*>BHM)iָ]4J7[AxV<6$ZoN+? d5m ZWrSP氣%B=|* R˶C٪GW嘟3;Cpw򳺬,~0׀oB\]HєsxCj
X <lArZͥƑŸQTWkOpidLMe\ix>?s2^d4-<)E%& X GC)a\o01Bb->	4(P3`sLU&bD݋ W@ldPdyK c@9:e`fJ<Z2zIvtxL#1]nNp3!g6KcdQrYADl6Th:!8"Xp;ȣ
B2l [>#7/@DJwˬ :z3h8:drX2X}x#POBvsdAK#<\R'B"3}@_6ԧ)99U6`y0[h=hK5LgJ2 J܎6)t
K'tf {J𙈺--|:=rE!zB	(=6I&XA'|W(Xul&|s@}l
.}Ľ؁<A?7)ON\(=C	^}t}[P	9#oK8MߌluX	rH~OėX7B*r_X
b㇯>@.`n#Pket$I.(ǀ&#>diW 
ߙ+dU̹Y~ƈ*þ /o1t1|$HtbKt>o0ƳmDX-+h+9Ư_$^]?6<74ԛ8\?M%6, 4.bCWay>:?glɅ	PW7luPuL6LCdS_P<OϦClzpOZRs|9\&ϛeY7~y~2R_֜JToJl?cuʶ<qڟ~	?:g=<ymXq9Q:_ֈr+^_D7n1ROtpQCmWr`۟B@q~aÃˋA4Hl,=z|ZzBmYo{aw&=Dpd(9*`@8
x3izT?QmnJ nӮhې<Dz{[lƭM?jZxXb>@A#II_.'e4)qyR7.s;(Snyi79RP?mM;:s֟B(O0)bveSyKD:mݣdTR#yrp4<J>an<CiԹMTފU5U]T(!nYvO.ѠCl¯p+<U>nEDTHq߼$#>=5DU?yr표>-,\w2\RETöplI;T9Rw&}:٧c vFio(HiХ]eLڲʔ.OXkNl'~5cM\sXXAť4V2;X!L=Oa j7ؽf[	c/SCi×U4ghBga.u
o'1H߲ܽIoiuTS)6{	foUJ,*'4o^	l$ϾR/"|otB6V~.\9'fҾ^Z^rk-04yH^Hƶk hdIA>THV΀.-< ߐI۾Bt ڏAxּbr"4;#Bsn++eC_7CFxi0jhЇ^ 򣇐|߹?Nlp]	׳
+p]:\}g5. AIˀQQ;[)\Nc::ٶ7Jn0)O>5[mVX796 y1K*c2vIw{o>&˷{dd`Gg7X	AAJ=OUޡl-;-_~r+f)}#'m7hB,[x}Սi^ u"*tR6msa¤II1韓sVXLfA|ף3aIՉE;*sdY.I1X} \<aަE
4nKTA秐r>tt$@6OGm#Anj\,@|n&h]^@Dx6B7|oz^ѧOhFDV8ɶ±5Tj_a:*5IA8]Gpnߏr;Xo9&PٕDФ»Yrbۡ~bn1΋S:(rEܤ֓<s}391azc$f4[x}.טgcK
p~ut1BDXӬeoS \&6sE
7O_Kohq#~B97]˦
Nؚ_kHb
; ?3x{z uHmgP:$>Z;Sx)olx%7+{M&։M]ѱf|f=OqGz$6lVNޑl97#^*6cZ?c@]7$Q|U;/}!|9dDL>P2R*K狲'2郎E'KtE WSFxR5KϞ>੊n'.+6_02z_i;wo[\xL8ahCnIZ,u(]@>kKWx*oA3H1JE}z0Ƒ|}qq=k(XdX!ZP(Фهԣ	lZʃ@`Y+%dm]I~2iκϻBi9ڌ7EA'٬>Kltr[/JI&-6@&Aۺ>ddn٤-:yhHO%C($
lXcomu)UTW99d=5Ks+6UZͬ
amy3>DY"WH~|)QCOJ[aX㹓v3P|(rC;cN9t_[~'r/ZnP^.aCc53-O27
o5L;kHӲ#%3)P\@~W冲#H44y|XsFg|?3mD~Eȶ>g{ma@&m_+re	Ѓ7l*$BDD9CiN2fd_U%+B:GE{ u(P)lmeΤ|CQֶG^k6oR޶M$I!u>M[<ls?M>>4>ؼĨקl !K \kK 
n(C:pdߥYKO>gSqAQC4s	:K?ƦNOiJ7dU>k83i?	ܕEQ7oCV粛]e{Y޺MM7$PΎ2G\w*ZO5BH"0MbdVuQPqAzhR)SLx\p3N@2ZTn*OǨ6^Ny"*KF.l:'zA<2@?6#3qq~1)37.xpEG̲Zw&-Y`A|o'P	^8ʨ?OS_7o	>Er'=|EAx&d2"bLFqK`x!q *)n!XqNLRuD1jQ8Xm`.*d8۝nm= ~r\h)aѱ!:fڝ5H?Pe-\ư_?nG(͟,J1Jw~ZXf\+߯^^٦Գ~呅P$Uslt`gРbaGNFlqhd|)sB=?i/k&e$aľ;貏
lM7Yvtǉcc&i<MʚgC-MFzp%'nSBV8۞]b1/}~sB91[*l.5'``swӦfA6c?[W:g'bOn`#'^W"=mK1sz_sv	.h@x~9Q86eބ2#^Dڒ26yec
Zv)b؏n~z<CliK )+*cCnCY\̥<}W:-?ސz-}=5&{XdPxh}sVv&(r1o|\~8rLǦk'ؑpAsTb[zpvo{
<Hxv`@7%/wLale㨵cP^	Cm%AD?bG C42Fݷ#:~BXf;},d,Ӈ]Ё`ۅC~Ɓy:/
(Hyʓ<eޕOayŢuZdЦh	o)ҙoc< >	w#~mX=11Sx^iuכ+䱣ྍͶ5vecy<3<yԏ8AFiԂXr#_i
<>bn 7jĦSuvoYm>\ʛi<؊<qCVc	吳) SB QstjB-GUؑ=7-Unʴ&=\ag$Y\ԃ|]Uʡ;KR7DZD:Ys#Is*2%y$䙏H(fܹ@[,P m0_8GqN::`5d?Y8dxᵦ&)sYڀj'zۣ*cL:ptqF)Xț##MZ-p?>_\\뚲MAlG7zC0
k -%]be=Kr919O@h44ݠ %b"GAٝKS5-wNOoHDuD9,<>ΥytRX'ä(S9ѵbG9}m+2*1ɵ\2\|.clϴx	030bN7,̯`=;!JPv`]W	~ d+rHM:Hk#:I6 lWz1#$}j~؁ @B^n/ ɡ#ڤ+)7p00c(EQ =0!?'H庺4!p,j.6Rt'`.cxJ[׏5<dѯ,^?_t[|A'tSmy\)<8(bEnuGUb*BT@H$
o!*z2a.oFeC'fV5>7B?G$So(!Sn[Kem}2:u`}'aZRaX`I1B!)m))	t= h倿Goз 5Q&OۤD 7DyxJ䝳䲀\~Gnba	2'`QfB~
scyLƢ2<ͅXǫ	9V#/c\bb~ 9mԕ!p9Tp.9:x`;/I3?m\U]	'~2«LM @I3;	hqj<77iW
`	rSUF+r&[>6(~*nuq٘]z>O2:3Gx<-pu9,FsbnE:\L	2G"fzV@.~Z綔YGSvoG}Nyxvcs8cQS_ v@o#zgeOh7:x>k]Tޛm܀6np!C'RYk'5"b>ȤM&{zMAg%x@
=X=G3a8Q2E["u+o!5TĳݖUJ	Q}3Yt6}>FK7m/z(o6`D_填{×#h>+)t?<6f}>ZM8w4>508ŏܜE%GCEB}YCPJS_+7(n{d+[@vipzMo(;ސ}x/W=cO]i_7Q(+-';:3/,_]<a>62#'׼h~mMb2ڢ'F`̥=UsI<"x<*I$T} _~4?gOkzCJ}MS< 6S(;V"&h~g"M<6wcݺA\]픽<Ɔ+O}x/qr_PozԸ@u FvuG4ع.3(~lM"7;4.v	K)2yx__}Ȼn1\t8UƲWe[M}r0UƔ7WtO
ᡍ}4M)`:Ux\j4J^kn@dYew}Yb$]ӁW z*LVʢz6]CN;OZr Tae#TM)|P.@,/AoS67~]¹Z՚/"qu܀l+jp:Rľ%RsB(|A۽N/&xpNNT>+k\ׅb|NK`<vZwj̩&tiNu_ŘOP:JeY^ 7><\TsG/A2:uEOyz{׍#:eI
ʗ}W|E_ Hs]7.
)|`DTr6J0b/tE-X 16E4QêpX0%+@5rSA\U0s7}?NJYSLʕ<x1j@X8	"}Ju:4n蓑r gn @	Gd*vC)c2pH\e\"F|lekZ%)FYcp&I?[giQ'\#b;g֛HTF@*&B&ޗw䷤؋?<q0|?7pr_<V{<\)%|CihEbIFL 2ͳ2OU+p h ER2 _8UMlrJa9C<p7xU1@
gs65DS4Y_x}g<I6N$o1@!OLLu|6`l&d.ho?Cshq/ߥoTZl+PlC+(5w텣F1|VyrMd<M(Gh\Y>I4v79VTyF}D_`ދS%C`[Uh29a_N5>x+_yDN23+In)yN'-[~F$;J sQ%%c;t/\/i* x/7tp	v4"X#O̅%:2Cb9`aupr4H?&)idZ]܌k%(rG4qӟ7L u{Cs%x}m?pvil^<}^^!^\9l86XBs9vLYe
CBdI雸EhcוaOjHNz1?n	,[X42)'?0z6/+$:A!>܄%w*f]AaE@?$67uTAA&8MY܌x|myGb$+n\Ħz$Io}T"ٸ=dSIB]rC!:!h[?
Z UJuY}B@OY׎=~U635gȬK=2hWoo\,H1FrTń%[XAfKpp߮9I? !!]|r]w6T}4k_eV|Й9Va&ҕ	ڼ..
㕠%ܴ>BSQ?*1ڷtΖ4՟2W	V6x[@C|>7wUŗ%x.BlU`|)nhmx8xΖOOrC.W#u뫮]w_1 0	{
)0̈~cho
@|"|V	^
U-L2?9!cQVB#ZL]8O ݞ|^t5ץ?Y*[,&͔ع+>_'UifR3е][tBIZYxPԞ9L:p"*BM0f΁O/U2rX 0{dUЄ4/$;\cRm7C霤1́.EYb)jnCbh]9%QOz~ϰ i jLzKUL*Wˆ<oʎ{-J$_-|]a#H9,粚crmzɇ;&Qȫe3Y@yuHB"r
A@b
(WH&
aRL"f[bMz|1,:8ױ@_}^)5c8:s ] )v:Iu5H9Et!ST#]ug65X uͷ;3Z$1:8mf40߰h&:Բl
Fc'\jBnFeT4rOB3	cZx[~
"$FCh.)5LtfRֲ%=R t^/`Ŧ*̀6` FV)}Bs{꯺=)ub]?#2\쁧BҁlH6uZq/t2!B!|I dXeԚo:S*a^1שQbQiGxS C]F'Vo|EZE1wo:f:uJ<f/m])m(ap5%iN*辠BJl2?r8vBS2FG+KTP<>X/C~~`<]K,W0mMvv.(ˍH0Bɬ>,)<!i ._g̢˶CuWl;J^+!z4'tpEIuht	F?Z
EFYMʥ\wAtVmlω1~s4˪bk#:x=/;$B郡~T*^>}&qΓ]q_G?u@.~Iyہsqx~2͍%APwl"7	M'eY`oF0z[/ۍaMĜŲϷyӘy$nJR:xiƚG-ȶJ7)TN]Lvg)\ڂ:p0"<߸AL]l `#'f7+	篗a\忞zYGR@Rj$ן/*P`/O]}n7ƖrM?pm9Frl>>Ov_Wpd;y:7E{'coNWυv'~GGtrS:[Ǚhq=ItJ]3ȎD3VncқI;〾ż4%nk<J՟Ihfv8%]&Nײn珃4[bC<{N::Y,,&QmP&ity$_*i7qS3)rԩ:P_ʅetCVفpM¥`CO]'9+gl;8"tXBJGc*	7xr9y#oYyR ŰTH6k"GGĴ#7B\S>y#KME0nN胺8dOI}u2&P0'Bt;kkd9BfN8n
IBb6xD'q}#1UGa/)l7Ym5h#~!'tۋK3YF%y)O. d;
G@;w:;]3&_ْ+;549l;HHs.4oRG,70)S_KNR,d!\AF7닜
X_oڑXgWO*s&LpMa
bs?>_u>W8!cw
hO\[![mm;:2Z"P*񚝘;E2U\1#K7j%)vbSJR|KP,؎*O9h$~;s5t;"e+{874<dʗ_l[5irgd
F;㧯>kNT%Q0y#*tyIx:q֪^0D \p"7n	w'oegrCo>qB;~bO2f˅!|QE :Hx:ɀ{"\l`yf"<UQA#7bn$ƴٵာ@%-~	%vOpܠgB禍\ME:gEi|%|DJ@odl3>'i1܏Jwh"}{XEC<He.x9Ty:v?d!?@^ Y.wF>"+_em: PYp	ՊowmϏ*CI byb3,J&?B57^܄%'<ySbî<陧b#ThgKJYLqU'LQ2^7ŷn?)RN"vr)ėֶE>8ĕi AY}>X/`kLczAB$S44 +ǁ]#:O~9KWhdQ;xg}'}ʭr*_iJ37&и(9.<0AbF.̓9ʶgRnRꜬjov@:4C2,o3Q9҆xߘ>̦34	%6>7ó濼xaO䁜OEMxs56Box?AW|+`G>Cs.xh%Gn뱁9GU%)1Njިs/xa˦:31I68L~μe?0<L	;ս{Hփo@#9#O$SiQ8Pyo?mE11CV[8胬0sXql|21dm78zU8?om$l	ܻE`Op)F6nPLw͜㴈' e#bc懌wǉͤ'H0>/IZ/X:kI'=t|;M$p;GQƯy>^6rϖ5gpTnY3oW!z>!]V?nȓuB'gCImx+ <z{@dKZB]$z^~Gtc[7IQ8""%|UfZ|]nx!c j2yDg,vvzP#Ąl%."LOb^~PMN'N)?YSu.,h0F3ȕ`\PgBewPCVJ:^@.Ø'4opVX/z'oE厝q+.|47tϙ3`r4?uTm̴hV&K8}~2/`ĈBj`% #6_Y;HK(
|cUˀĻ9jU<
CZ:-M@|=:A貶=-,&;QY|_|kK.1Y.O>j<YVyT֧jtng-0CS^k<v}hm~a9@Y(T~p,DO4aOb !յPqmWw@BqsW9DqR!c\N!`<OOi>(a͍NжgmI߰ɑc5k{m|`((_{u!Ƣ"q]o^_?i?\7զ_>|J#lCwH)'<vq7\ uEI K"WHP<iĎ3!&	7rcyi&8PbF_7eOB|KHnq	
#p|v翸݂^zrDA	Aeپ'?7I}m?Kd~_#߷۷_>};o{?=ӿo۷kz{;o{*ȏmWow$C<J}7o_}}fy\f~ӿiGG_?'ٿS[3+~Snlm|ߞs"h__c`__ol+۟۷?+{r{f'o[_~#[g o68pPv7}~{~V؛yL[NXo~L~`O)e7{856zx1!]Yb1\	µ(	!oi>aɀ# [N y1+C3/_!z5oc':Ō8`;<@.Pb3c+.y*vj$x'K2JQN8WjϞoo՞PܢPBXG z}ch8+
&A;y*+# N gpY
 9$~&e-I8JW9-v5LFd*+ yE kywnsOt{OƆ*bI=?|-4abNMgJXKL>?;Eϟ]x#7as7e%/,Whm`\M|~>E7z$9?&n~=|xbNBn>zy7I^xN{M>	z<lx~qᛮ۶Y$޼{l^c#o~	anc7?{:$ϝۯK~碑9yq/YCgc:7O_JȺQzp~`o<{\N>y;>}&;3?wg;;;s S3|GO<6xS=)hAݼcOBב<产P? iG_H?L#lj9G6zoݢgs~Ǐ0H	3cy196Txm!zѩ~yzz=yԼavߥvO.~HI{o@g%mDt9^b%!<uGC@*lE!<'Ӳ]=o2E8F/0~c);؎fu ˓%k>`b΋sIDh[\/ǌws7DE̴,7Ɂ:t{5F">>Q=mdU^Jd+]vmlBSV&`578l^#I	`Ю@.7mdo)M̡4TQ!.ukf'_Z|n},^vQjl&)!,ܕh`q
;<=3&e;󬱞J=ǡsNO@2ǩl(}ZԲl2 S`Dkǟz//ZУK_ڀ	ry`+SJnOX0bj`EZԷZK=xtzUِk!@١ål
tn#nrck`4c
Æ@>lk7.9~p{9#3&d$E2"?coֱ9M3+a^ K
, ~"4;wO#4&b:s[Oȃkȼ=iC6l@\ bBy$e]Qc&|~;X5V<P"T:`%k>MP@XcS6]mb7Ku,t-{'_՜we |'7%_9-g7{|F_Ӿya EzACJ0 \L{وW/<G'*ܢPmyD-xhg,lAnL *^,b0?<?{`Fh		Mp
j8*PbtL|a
 w!OBg8bO'wvIGM*rC3A(B ?vB쉅`t 3a;_S߳}	(L?zw|G_[yf~W|5L?۾c[_~O~vOm[~}_ظ?^EپD0#_wJ_.߾/|~h3~+##۷}Co-vuK߽}u7@d5_wޞ>s=ۗؾ?]F&=7~g7vP_}Ϸ_u}OWCyWѣ?gDMH(>}=S*tПsqY8@eWe`Wn3О0L5GXy2z{QgibHum
SkYŷ
!CR2wY4#(􄯐]6]u2?o,%Bod-'>in#iٳ`tޤ{o\.-0!;C?4U:*aKL),UaQ4jMH`#biLzLq hYkJ*ww7mδm~&1t`cI*8orS7]c.e@~ѯb߈ zl{dc?}?D67V?,wO+{d@9F oxzcKvjsAOx;|7yt`!q(3;OԠ˯O>'{٘(*&lKgD9-3<&M*0߷+[Q__k.{Tn
7xq+ZyOoge/76 H}t Lڏu.~}7(6d|9}(mO>|ʑ:gm]*S,Ah?lF}jYFB-׃{Zs=P}c3Ao'OFʃ_x]x㎷M6HNmلysPWi=36r\&M9m6@|}`|lQYk@m06$YVRn,Vcq%CeAG(˵T|buHDYgEt꣈4c<&3)|X./D*u`S[eEl_5/^bt	\4ƞuZ YruAL(SR$0o;luBy`BwzHCt@=+o(R
7l_B]#;Zmk	H})	Hۨ5,z>17KhCOp5cy7Lנ̯pێi`M Px"qa%B8u(5>[-Yl_[l 4{C7ȷZ&SvN6+!xj{5mIߋS~	_:L: ݮAR$G9CTksm{˺Odicrl0Iy15y*ai9؄!j1dΆ.]RȮ|@|'>M>k	_㛀:(jl,9@(S OUC:lpk	d`urcW㤎.L+y%dNcONȞ|/^sd-FQHJu d'q&Qm8p\יGDX	D2\3A!kAA6sJI9&tyxi}#շ@F$%bxtnCs;(N)&>%5ʎk+}y]#3o2q]ǽ+6^^zBt*#F
)ErÎ\UDe|`]\i}iw+-pAd?ޏI6Ǧo~|z}fjO_tG +QB`GDS\8	{
`c?7L*Lb
_Id\V,✋~	ɎJޙx'K.E/fPCS:0j;W)D? 0n୥o⻷/~`T ea/ٞ,o;I_Om?G~"L۷s_SnWyooue~߿}go$g+ool,M?}G?}7l۳n?+sO͵n;Deݾ~f7gnM;>;`zOǿkc46ѨgT}!%U \ǀNI{Aџ~IW>x')	d]܄ㆧٿ@	ӧn,gq|ȄzRpO}"g41NϷ=ި<1.TΡ.|MVT>,u
K@	"Iء)|1YP8i[+Re4?;1BK֓l/^XSlUՋ1tHVYAnBJou)X*0 CnXІuEzDU0ы!$عøᚸm%?6ꋴ+&=b.
unpNK1q.X۳,+1ϱ7(0+m6'xC{yl6A
o2q7+8m;o&laq}߄gc{SFxi͐ɿ'>m1iϟ.''*gÀGaOЕA^dʛTJ+6_5f4<M,={L:QzXI}	ݥuƵbP>?v=|tf7;Em}<9>F6 ýD,{ʳɄ_k9smiMڍÕ/i|y1͞?%ߛh]1HK^Ƞ/
5l<Wqo0PnwWqۛplҾa\9{٩˯⥝phѲl(UѴCi}7}3 W92=e?$5k|sf\|c
#N!+Y/훊N3iC(QBY_蓾	*|=^KZȺ.]B5,=r-Wl-'G#M`]@f>z$6r;?ָv6(&F>=Qxs!m:}lRE6pס
%=-'(R%.cem#}렾oiֵ+-(Cq>;TA7,ɮQPк!O ;E(bv0<Һ"J辑aOu3mA38AiFh s$12d8/Fv|;ֿHJF)t2uh-7!Ցr>	gZ6{Ci^a7&,UY;*V_)rw㢔â7y&#7,;nhnoE:??PREe E[(_ʚ1Qi)JzA}VR^h' ]u7Jڸwl/SM0	6AM%]hl3q`IA+}Gu_X`]z>uWYdϵV1W,@ЉAږ/ĮR}y1r5˄㶥=T[gεE|}Jni)
=@(]t&fLCJ6"ruҝw蛾ۃ'/䥕UO~4l Uu|Dz n
3EBgC>aAqq5Xy2w_ѰDUmQP_'?m 'ox;S<'=7WM	's2ܴDYITp%G3!5U(׺x9`Ǆȍ.fр/ϫ52aА؄Ho~ͯn":PhM?&ҷ~l({?ANmw?1eA/mhbSj{l{h~)߾Z<soo_~4EO7lɹL_ٶ<Eȋ]gp UOneo~l}B`l|O۾?}6~_w?>OmO[۾!Yo $}nu[[L-ۧ?m
?%=4,_?^4c&O1s'۹&^#T;+אo< @.`RV!}<L,BsRɻcM=^~Dnxf:DEw/+🽫3"}ҹHJ(uBHa+VD95>IL[thsS=mӾO7ˉ%Lb4I m\voʮ،%`+բ/L4J 7?TWn4Ly;8@O!O!:,
K@iQ8=@
5*{k@q/˹Y_ >Vzlia>v_F`Lb\ʼ'h"RyY8UzBaz:!R-H=+zԜΛ,J32M!ѳV%n񒹑\Ɇx_iVPoeS*6z9zᘍ"~7-C+7_sxlRrJos7؀c.hleO`-#ԋGGޔ.nPe\SwgG//̢5=oc:ZdП(ss;l!F?vOm{yqiS;6O/[Vhҟ|ɟbG>ݞ>LU`_H(0˧	E/X6R@h_hϏ&
2=¯Tcm_lߧ~ł__jIu_ֺ^v9&:C/>Up,yY_f$hNuƈTzɂ/}5k-;rsEC7:BMyrEk~	DxXr%oRGc#F6=0BΛ	hPRA9qѺ GlW ů~|W2@gO"0&5	ՠk(PZRi ~}o0N,X Dfh*P}IV!O%hdHez#"x&TawB)e*8.l˯ajJ>sSy?Όx8hXh̦ٚ'2r>96AAf /'' Q̚YpA~C#!L+6Otzy<\rL~[R1J;q[{l0MqalCvE>DW`s])#u[eS#L϶ϥ"+N*	%ޅ+﷐U~kqXn;+9}!P	e/cG%J+'U?C07S>tD0k9W^idNDeU`Ϧ
t~@&6ʈTR>e֚sP#To3~9@fY7ˁtC8<5KF_+X A!si*7h	7WYD}CŐc%#3G]?ۤb]M
 =؊MSzӰJB5_C0p@n%dKrų^?CH/^\\}}x"-u3NbOħYSf+ʽEׁR'3oԂ]~sGk\\^)yXPb[í?TL+\C!59D7M!IGOn 0>V0ґ<Stu4&\ű+|rq(7oTb7X<%'@)ÄGgkcIo:) 7y#<w_+N<v;/PQ'
khdN2?V+MH_UJJe!jBI:0:yFP @5 K˕E	_gY+'20/8L"C{ٙꕱÓל~O?|W*	OO'6{9i{	'~ɞU.O'SNG!4H2EYm~>,Ji3U'$8lc3cs%b+ )ucfYPca+3%TepQMX~j^1K/|q2i7 }qySac^*{o|Q`Kf%xX\g_8)
OOn;dԬbYPt..Z,ɮ +*\ڿV|]#AUA(p=[`Ů!~
}йy] '@~UG5q>"(haNޒGEsWA\/7nPzzNJ}47/nE=~t6Ǎl5Gϟkԙ>yt-2B|p&s2|5-cٚ<r<ŗ6?:\6.mAo&V)˜8gOFI*=ܘ>\Ov$2a%b@Φ:s~f~+9<8;?Y;jMp}5Q
ӹ2(?uǍ%~&yrky}7s>i{M&|&ڏ"6Ϲ;ԑ6fbbAtP%[X!e~՜{WEFg~(xNpqO=l6 xcsӟ~_vOi-GgnG'd8,<ǃئG>uɣa-؀l2C@C*P7mR
}}#e- bd;&J<ʏe,~LMq=ֶo!B|Ol2'D`^䧊!vĹR/@:(H"wr?=5LֻǊkL7Ow$r
#Q#ibXAWpPS7h"tM_Y 3E͒EE:TFN@}9:T-s]Gqk:rxL(¾=y-`@5c`<a|뾊@;ok4b?"A )O1(R~	J1R3 17]B{chuq{]"oӫK7ԞB8
VX5ޝ~oZyods II
#$DY7+T))@Gr@aٖ~"<#pݎЏ#;[61s.d mg} CRb
uBOXt;NlRsuO1r!-69ʕnHu乗s?W92	kr^?CDZ;^8늨޸!΃AYUcrI[Dy -J9uYACv:H:_XY{pȚt=71&`Zm3E^]ӻ[Oޖv+;=ً˷X5_xOiX39_ڣpt
FEM8~CƇ]zZ)^
]m~ `ם V]sw}J&@Z3m.8Gb2\8өou_M8*]>t%C:(< UKMYG}E V8בSgfB@d+T.uD7(ggi21DN̏5|4dRL±bOmO,i#"#rС:>crn-?C~9u3u}öxDA$ٖmv1?>ɚo<xc9槯.\/p18A,n2(w~`M \|[Vpd&&<o?ևϷ[Oͨ<iDL_OC|A_r4cʭ9Ʀ!GȖ)(P6uʒCV|=@~%O,xcde!WzÍAsMnCI)T1zGE)!|T7t.L.q2mjH~sSsE"R8r.sZWCr`M&[w>("|p 3c@
ʮP &^Ccָy5N߇QW*õIHB1' ^5]##+gX?}K۪@SL5>	jyV"X(X6,@0e$;%oMh!*O<q#<1{釜?X2g⢋yڹsbs+o(oH7O.V`*yE[OY	B.r	ԕ	1|zOugc{Sc+\Eѿњ{?-̃8	=Fů'7UqdqaT?=nQKuG>hڃ:r1dSm:SNt+ <3цL^B>B@g>-mt~`|񟑖Q7+ؐ-	1>[؀`+v}M"	?;}྇L G||lDaJ\1J={v}XL6fclrba.`~bE'I;|ԷDI}5~q~2*cUn¸/$x
^W@jm&nY	/	}$^lnRLޛcu'3S9-:CNgPf!(*-}lGvP?_4q)z\>mkD\m'v,:ݞzQO3)<)O 80sR|W۳gA<.AJ eb'I_`EٖL>c]3G	XQ%͉#NVlވ5pHIg$}crT''*rla *q^ow9Z>:!^<z(OqO-/cJȟ
?ЭXgΒnP+dq7~LΛ7qr(=7umtyHZ 7x*)cszv>\&KyҌ;.(.}"@c?~dPr_.Mmܯ&=Joړ9Y ly>}B1)w+w#aG# c}YӎAؙGK<Ŵ`9 QQv J`]3£:H'd2wMC[٥gʁZzYPaCYO[Ig{|ki]^i
-Nig~wZ$?I+`GI/4y艷G- э'[uycH?|{=)`WE14fסqY%+1)*ӊv(]~8>l;N9"u=dyڱcsXA:#JG'˺8"T`]&=^CMy'-%A+𺷄zw}a
]VQ!(_鳋&D:kdgh0pS=B.8bO NL>z2o@H'eLсcwȗۛ_u<ZMbi.N#Dz47J. ÒDMiKZ)7A]OOǠepVXńxNi~;~,Vёu "h)BOiʢ4)-0Cq@[ktaI׬`6k<+==|TxߤX!7GHՁ'
qƻxR`d7hT5Fkt#?:zz`#A8DdWdC$XIzUp]L zv4tLROѹ8xڊb!+CYUGn\iHkXPd`߸VoHCRdխk9Ѳu41*s}?iA[=aw\)dW>$[pE/$q4(adW(p̇8"E\54cq=yxH*C#^Y^]^% }H/,aLޜ;$S1*oN,olxaot).Q@~87ӫbs)n:tr~yA&b޺b"-<Xs}T.2'gmFhc4RI-&3K۶+nP߾i,;dfzLś/Ȥ~oƕl6vUH$NnRPNmڙm+(O?q!dсϨcQ%<>v;	/]~֏6H2r{}%Mb&~R2޶ç+w<[l(:~|m4P&Oݺ޴y ڒ<?#.6i}k~1:c'l'[ܚv	hk@8%O94]~ ӅLS9D6ubq:V='(c^^+vYq
xAɓ~[],2F m6Y)Wu0 d'U[=%kBYĆ#uƦ\i[uěw*R2џFYx:s|ercO8!8+o< n&S^FHQz*qx~%e@Q5iU_w䜴NP<d)Ӂl	H]+N~BF@RL>TEKiz7 76@ߧC\u ]L k1̕),ɯsy0-߇p>_@|}IAg`>בo^qW3?W<.q(kHjig*82"S%xI6%sIbZ`y5!3p
l:u	k}6i	W DiDwYRvT0Zw݅i\h*Шp5X7Im*eFp\Ӱ?be1Y{:n+px5!N~晷♓xsl&1_im\Xs W渌v֔.#.N볤k0pBU8bO
U	Z[B`h	e⎰6=cʹ2G$0,R$,Ç=ӁUIka3
hߠa[uoi#_c.#(ؘFOnKt?'sLdP/<"Zݫ᷊Q!bo9x6`W̎g-=8ݸ6^e8\QNS99*HovgP̢_≓7\xm	O4$]&RQH|a9S_WROq*\D$Y\dYH'*:ǐ:  wءHvdfғG8K&s@љAϢ@^mWz8aKvh0@;W0_<!4=u3BAq;Lo|x4cT,.vK%YN]BbkM&mɰܧI*r]3C/C龑.e 7Y@:@m<_btUn~B%~Io0щG7a{^AEMA5:'mInAΘR\7,F^ImEmM`iP6`bBWbgH\#R8${qECe"7Uv8y!EyBѐVleGu۶!#ؤMW]s|ʂHEl-ؠO''-.bjR̍xna3Y0Fo~}ązh1#{~3뫷n獤ZJ'#ϼ1=~eEm?yH]yۑ<6PWXhcJp۟mZxrtZi~B4f^qk˱k4Z*_B?}^4Z8]Y9SlݕYfcrD#E\O3~ZkcEr"E*oIu="[<Tϐkڴy:C6|򰟺='E};}p	p69"<&:ф~7'F
$\H>(;IS e؎,:@OKL}Ĺ:6w@f0"v-!8
lݔ{3D~v|*򩙟
fH#6O7\[nu5Pm9,?G.6Q>}*W2 %&R$]2J<x2k=yPK`hl_c<'#@	$cc2҇Q}q(|N8rNDhhWD ǢV̆71f=6a
ꨮdaAf<J4r j/ekakeMX/NsL,=(0,xzti,rRZyW|, m*.) Gg 55\a$yXyے*Pi>	`;{x?>7-K%	rr~0ǫ`PRi	X+[p2:vʡJ[b-~u]
D;>H:Gƞlf|+ʚuVHWڱ JJ׼MpKߥ{D2A8ѕOp3Щĳ$|)ȍiA\o0Ub~K'>DWqO
j|~˿UHgI6[D$77|ԝ1Cfӿy4+'m4-w\vЎA=u
zփC1<54={-dkѰ\+Gs
	 (2I"vE|1?vzt KwG;Ӷ	Y՛v ]t:m#T%mv}>!A* ?(Gf^]!؂[7j[gmpJQ?D%|9_󫶟	7@*M֤]!(
2FF)/s(Љ8R1'Jɲa	Re.@*:!o|FN3jt&L.hbǝWo>0Arr44_&@	>Y	@<5NhNMU5}mgH: Iu2+[|" zsK}k"SXɢ~ C>(\[~a]щi~v&@ܰ 82.7B|nK!L,;uz6N&cG}}67]Bj:sK[K1 E`P@31R\\%||K%Z)C)+5&Ռw2q)	;Wn.w%A2nַ>H6YC^
੫}F[TU`}?T.`\iJWI!6)kK<H,xđl~0aQ>JfxOEQFuلd)zҀDVv>iyqBZ>.+bdXM,мq7(N=C9?ݜcܴD4o0o$ipryq$n$27Vzۉfҙ}O]R|fYwMy5My/Ѕh<~$x$|(y'sb3Kf7&ߐ7-
]g[_OӪ t
7fg)ohFe+Tta "/q6A[SqM$b?c22y?U7'~Oۓc5uHb?}NG4|R8ԕ~:7<Gg;1?tg(36\gJ~E 	>>l!Ń!	ԓ)<sD>@{v3xՃƓ	GOR;(Ct~5Ob	vݼd?j]F,S6	7%x,^_}䷎ ~ʎ]6X#b<χ2c z`O cYz+e.+vdP`"4iQ?6Nf~zl3cg%Jv?_5-Þ}{ӈi@-Ɩ*(Xȑ*\VDT%A
IY|JD >Y+)IŔH\H %pS_9{9z٧Xk>s1s1m-ؐ;*%&\7L:zcی:hycbHS`
k	Ĥ >VBl72Ct7[3Yzi#@֪vPZha=%]췮B^!*#Բ	7}H?c)"&'^0o?
0&D$2ĦfpZtoa5z
_2ɩ%J/o7/;ٗ<zp|^lv,q*9?K\?Ed+Gn2C 9;ȲZ^c"UeIDIީoӯHfM>}x*r ҸsJsoJ&e$plt}aBܪ

*>TG 뿐k^Վ%O(PH,y 2߯7C	w+T\:jlｋYh៽Vs&uҿ"ZčOeJW'uKȲ`BNBӪAhQܣʓ"V}+hyAp:B;~!:gZ1a\IOBR)l1	_<G<㥃K([ln
yx%YP~I|+k'{KYe[g\`3k!UA	n0uW) ?F/I%ݓ~P0R7MnRPq3M[<}| 'S	NN2~&JS O5|cD8'/7nW>ۥ{͛ΛЀLD!@[-BS969gIT@΄fbJmGb%Kn?CA<phګQ&rыy%mzүDݰ?cϜ#<\|b\6#.ѿ0=ӊ=	#JcLAr5DkU5} 7Dˡv%:*?pSH-љ: K]̉r+' Qd/t`\f={=i9d	$
P}"f0N#B.
E
 F+޼O*QiMT\;J6bTrm]-!=t\/O'ИnPIM'`l<E)>y-fM+N}˼:fB*mYuY?oTTZ' ^XRQRC%=e}:G6?{yA6s\dY!nݺyQѯw7f4a?U<(tCx]SsO)|'	yeO,(7-|3ф~|wUﲁmqox'b	M]
nw$Ar<<Du,2ޓɿt.?9W}|12#Gƥrv`lLN؛ $mǍ-|>X$n#p~J'>)2c?M<_pC͋nB=z<zx^O|?vm\nq|ڟ~A{F)7Z[7ܜDʎ0%nۉ*gEw)wVy)|ȍ7Ǟ+Q=՛7>}XAO/J pS/*$'hQޚPHA:\.hrLm76ԲD)b93gn)⩡Y8{'<lVm-P(aT0y+/Viz
곪Bî5/銗 =56`C#vgI?g	t(b%Ag}LyZS@NH*
,S)u2G~"9oS01ALU\iz՛׷o៛k=˯D
HQ. ش27x$'4}0ghA{7[+/+[1fIǴYՖe0|ш<!3rP+GI:ha!쨝 .ӅθkQ銃QQ۲6]_ AY7 \S YBHwvBr
J2S%m$G
eJk>r}	y^
{Yzªk=v&ml& ck+%#JSki6Td~)s͓mV`T&:|a_r.V	C}Y!9U24`>ȫ7g?0x]^+HdzίrcB|}7ǆE?2.sV÷BY>FlDT=/V|tPu_WߴζY	3$PC0-ݯL9~oT+=0t-dGQ>{pGIv	e"'v>A 'ͤa!h@OH0R:xw{ܶ{7W}2>V C8E{% 0U(Ha&b R<J=ۗIGˌ@g P\`Q98	IAcNOV^ @qV])}nh}/_UG@?Qax\pQPs1.${-a#h?ϡa&O*6Tg`dA<S'(%.Do	ME&/9С>rh݊UcF
S^^2ިզMN&G<1WXmCP;
j!(˖=+S2+4S}	Wݰ:|Dg.MJV .x{VÄUM4Ia8Yvt9m՗Q n9cu2i_kp$D~Ti[ٓb (CY4KnvnkmNt8DK<|M~얫;` 4e3s̙$s=EWL8ec6\tbN&=ܔbxz1l'P:3.nyκ*(Bz2jZqZ,7kYpӘ#Wn?b"2WJYn5|<B뉷yx)=&-Bwro.4V}N*X[h\cDOh^Ѓ7"_T6~ z?[?o^}d~o&9m۰&@w_uy{T"77觗}>5a~b=$uN[/H_T_sUlWх\oI~nꦝ?ꛫ~pƛ{/c$eNIqGV3C@i /MPǡM||Y9 +ʰv=("[ 4)Z;NG(c!L,홾Y6(P}ݗbp~x \DJL*MY
ı1Ѫb8C(RSع;oH	= 'ZƔڨ|Ǔ~>ʮæ$Ԯt	+8m{?e^2'=s>SE*oֱ~`=;Xtk\oY/ ˸>Z|!6s1:/v`*I[o~M^A	uY]1\VQz|[(] Hs9ŝ(4=*Dg9f;^O=m=K6j.C1(E$'Gpv3gJg3GrЛx*Ts⻝"{?F=\Ǖ0! }W4VMlw ҉!>ڵ[7,~S 2E'+.PD<K%]N$I?Qr<vB7̛u	iѥ~AAyb`0PۮX* :{"y|d7sײ9߸3:5ԡ|"'$1}j /Dn俭AByb&j9dPw!S͹蚃l_2/|ω/	ո"t5DMWCFJ4m"n?wq7YH-gdr|װJ*n z+8#7?hg:ycpRxjC,(
X$KpqyңJ&:J{7PAU6FC^)^N?2JMgL'O[:#%uMw!eBA62SG҈;ALΙ(/)'fAAx@=idʇMp"iySC 37	T{:}ٟ.'˿˄og2|I7hOQd^x҆r<IN~dxZo{S12CF YTǑcTTY R,|旀GIHztet.FErlqLMLj8>~eAB[/NpM[w̌qmXdJG[?%_`p:.=.7y5J,E^0UH̥`J{qqEJ4ྀ
Y)WD苴(MA1:07Q+Z3%˙+p71n?F8z=eȅW_z%^Ipj2o.RTAه@gܰ41qzp!5T/<$߷d|__|pv78)wIiv=?L|(UfitcoFe\>%P*̩c}M.߀|Qa)q)	c%oOX>x4
OFا4P_×9H~n:>ts:첟+W#k_,Z|GVZҏ>8?q!y*0%%䡃zgC6=4ۑqgxIk}G;~F^UG&݁%c#Eঐb!cU|Z-\n
=Q?7g #78U%S[lBKT/,{&q8+
ke{_h ^`C'8z{Fet!r|ac60
OZ}	񹀁yƒA}s8_@Gl: _q{lawe{)225`*ԄV9LK
b\4sPΛ6b)
M
&ss
2i˗mVfK	p	{q3b\`ϋj\Dt+osy`B}zO$tAK}Lz|wXm
#)>d0 "obZ>1@m{pdIқomuIss	zn<! @W9$*1ssS%Qh,HRB\|JN?^X22 <;;OƑ2|Ȁ9ڰ>$ϙ|0d%;paft@	&Li8&$ yfLbu f!Fv;t;7P{[ 
meqOi~M{R9z=ԋw?nϲo]gbO3x`͌C{CWSPW8u`clS}a OK ZbPzkHtڸC9נӏ'kR.2i^	׃Q1DŵJ~@e'2E O䵭`Ii5*iޣ,JMEGW?r}s"1rm^Gt!&`?W0F 
0a/oWK@|@(xræ~IO6ar;ߕ?5<QQl9c'仳a'w7 'K).o6f]D+bS?8Qhˢ<x][.}lm]tt vN4N[Pé4P5+@3h5%'T>
FE#֛fe򖳇ϬBM,\k5m᧫bF4"%c%G }uׯmۭ.{]_.?x(co`\I 	QEG~ŢQkХeNtqS=COYb"w.5tz}CiB|8v`D|^xzKFb}DMNyx6	3c5itsSYh\71;K#S.\b 1G|Un.t((+=LGV@(Ėâ}
;4
!5\ri3'6M5V>M*Rkc-sL)%L_gМ,S 8 >z̕lN=8ycmaa!n qӃOx_ܫyasM*2Q[8aÏƛR')kD}<iˍ	](و7Ll2)3G<<Bbա\ƾGɖAJCÇݾh&Yng?:?~ċOIOՃoYn6.y<@Rixp~9Lh~ĉd"s]dJ_D
S٬ךwg"gT%/ڝG7Vn$qc4	()o=VqC2S6L?SLe&\-6m7|3Uk]۹P*|ҁ[ou:<w{nK8BX^K1t䨍ǈ;oK_©?]BsP:PKp q=
#CS=<ҦDeXoeO.d
2CِZ8 oc_1}Ds	{'=> UWRQq'8Ȱc2=ZcZ"˴pTDjrY{;ukmX-};l]$޴w$iװfl̻'[G)2pn@]80Ğr.SknC<Cq¹[ׅwWvW1z;2$Xд)
EMSĂ2U >-dTWq7mwW?w&Z2-:DK5(gނ9Ȓ4CK5MℯtHyb<#mn2\?C'N"Eki]PkBqtN8ؤIDԄLUP[t{EpR[QF. 2,"I
e>M
}0.Jw]KhožjmO=Cg:(9F3 ГXl[`o״a-șse?U1LS׾BغU Au|GÝ] ~HdʎH2!{_ceĽ^]f]љY3y42y n}ͽ|}Q˹opfn˛uurF$G4KuCܱE90	_fU<:Ⱦ\d\`w1	;|#y
hֻXmKi@7r>07'tܫ`C$|Gpo˕&K^w}H^U)7ʮ!dɩ>ąNryʕC]NI;>,(xщ}}1w_ )ԇE&gwoo޸8<f(+~	T9fV$W" ;<(*>oҶ\ L.bQ;1Or iC'yEBA'\ɄE|tv#a^b>	Ν;|ރ.	H[E`bdaaɒ>ٔ'L})e:oP"4}op}d)CD|QO\4&,)o':xn$^+:||rDNoK&t&,0v>\âhT +2=˩/ig`#T~G&$ruh]+\{6p@K+h%ql~_/%OaʟZ"ʂlW\ V!<h;J%̪2)_vu`#eZY\܇oz+DINn[dp^{lco@1/?'	yq>A|*s9y}Inŧ6`L8SyjO95>NY3/oTX	\D	ůVЕ>ꏿr1TY}pOru[sc|+dz`f;{9P>y XRrZ<o8nAVֺ?e!%.̫j[|+e(>8{O1>bw};~R%훣67]u/ް	^_z_zަm<^ދSl%}j	MPLj˸I=Kg[PTCKޡ/Z2؍MGe9L;uO2:NɼHWKڒ4	uMnSE椞 _0@ߦ~KCT[i.	~^n_
n_	"`d!Xͧ ez&TZ)kheab$(dKG(Nw5'0r=|;%*;cGl-2HtI}A 7k=Xy 1[޷xNH75'h/Zی+	Z8mH_$fXN^Ö5_}[iuqȕux,"S}dMp(vv}SjڶS	bR2l.*:yo8zl̤~@ST!YB6r.&X>^ٟhХFq$躲4^j?gqoS.C}~HNJd[:hHOP RvXҌqVy݆n&bzGH{ :Zٳ%NP|Z+r.4&8o~sa{.B&?ER	M ""Gvh>ǃTȈ&
d^[|h㘚,Ueҕw{
qHĳSq%o8R 8O].;KKsϯlggGYxe鎳آMZTO۵O"kb/">^H-C{jv>oc~%XzT>Cy?a9bHQGq`vb:­tm64l[悅FgWZ)'
|tqnHotHf(ЫPQ|q_Ut]ZeW)~r)/Hض 5597v`P~i -|ߌ%nоLY:- =^i
+'DvDɑ3V2aKCsWu] =Zm(r@n(-~n'wＱ=<$Ek?@vƑS(St,'CN`6/@)UY+f1A9cR+>ni^ዄODBnd"׌Ehݟ<XO2h]5n|]n0kൡxӭe:8	BڌE8'̅O|w$hN9dP tp,B+83 
>me,
$_:~	 17#nxMJw3Y-=a	xˎ%:A\X횼$Zbk(1Gַ2c8ʪ捑qѣȲFi.cyzn霂aC3M%ugn~߇tbBd)v>y&?S)܌-}S"YOs<T@}tQ&c}sex=旓ɳ	乖_*)d09c^ 96lfM2+1W,\cW()'0J^7fcˑ6L%sL2O/ç mL[1)_yK>rZtύW`#1muQ%?[G;fQVs'soKqs$ax?%s.夲>@^2A.LYe귔'>s#@TRsKwT)KGwیN}RBzw(.:<Xwa%=zBS	'Aidbe١ױkjtu"7>sC%\̧/2PǔI.xf<5N9'V: '^EǅOhԩd yy&s1m91
B
/K* 
r.Z[[vdӟq&ׇ71V:䊒:J45e$P?@|w^LiϙK4rz&7yfMI? =c~qYX :u<ۖ׃+j^ovlNd9G ,dX&W衵g϶7>=</˃1gi_fr.}V,I)Yhφ@ClY⦷?]'bCW^\6 ,~~E1H=+&9/N_U
#m\q=Wu/Y^-){GMl; ~QDFtĺ'b;q]//)<[>9DǄhxV@V2\L8tuAenRG
&5;ϦUXStY;fet\ŹbÖg`mr2IysBJY[ˡʯqZ4@3X+݆C!}\Ud7`o01NE\?0gp^=j%ֱTD[b`z/W𢇙:d1_3Y`H]ytb>Z4FZ8GGR#'zܙky1	Nu3[iUKIo},mFN0Ugu$2&oxX	TɑLLtRl(>"_m` eSEm'mQmu7њdc2l\Aʂj,q)sx5͹9t>e.W+6,E¶/:3	"/abr,JUnmʒ,fLdvd	4ЯS\M#އgp%޸:-6I6Wr	qѹy3X4ۦ5Eg_H}zUEz|Zߢw@:E7w\fp"' >ݸysr7-2Wt^K8`lG )#ꏌ)_~01-bld;%wǌ-pwkWbrOf'5i%̭gh~J@ḶNe^4cB9襍LWö1	]I?met#<Ǎ7"jIțp'a."ǸYi/=7жMҢ8q"-Oȧ0SR#>:	36/G/䭎ku
}ǜě9<Iu:7#]G֡eb2rٿ#ԍJ1#
<1Yc
+)_}_6d,SQԫ"K|>&? 77QxpH}Hk   [  IDAT=Ԛc0y6@plj}T~	ܼh/]`F1b8I>Vm!|!y1JJN87x+?+	\K:qzAkyU.%ՠ7A)כ>%evf%dߵiBv0,LZW8.zHŶVfeL!0.3?_b<8CP?E5tcqn
ADw<Q T bs@w;Ahϸ>|@cjR

H"(0P!XQݮ{
|?%P$)HYͱ-bo-|_rwAMʔ=c:_#6ՋeB\fZqbs(W)o .mA<5nysN͢ߘ:D9gr--bVlOd˦%$J!~-o]9WͺVs\ GV$U&S͇)jvB|+3%c+pC@*"3ٔ5X	{CXA7{%uڿO<(͝g+2'[%Ǡଳ=&4qq(JTq-%kDO.&|.{N{/MxMO-\?yu~ܚm=)#WN*.6P	q}B, Z"pP$h1o>2o+}^ {@iMQ	@LOW}N}"kڼ{+
/;cp.$>`v-8jXJ97~2NBs`}KDeCWȗA')F.t]XaMtxSJ(XPOЇzo?ܷ)XM1~"$u@i^0t,W>Bt*{0~D'Ӟr);aBUH]bCt'~ط`(@MVo0&BnK{U9){Z5&8't01hLeCQ<QxQDJFi"KO\X|=!ǆH?bL9P]ׯ6ŃXGsy@lRf?iS7h ԩ22E\\`c%"ܛ%n0
ne{7hENlܐJ{am"xU>y]bSIЁc(O$a[G<MsU}Er7딹植;wa趡ζG(`jWe, j=Q$Cbꘌ37{߼E
	/0O!:c@VD
j/,:`?0Nd뜄.ÁC/.=b1gv}lm.0GsB2-q=@bmtMp55o9vZ26WڀRWkӧ+W]hbNIAYy?c yWn~X}P"tt@иB	\Tdś>s7Ox{& ?7ϚC9~D4%V2do"qY{-fn`#o0؇OɿlQ=}OM9N&s!j46ze{|Mނ?i18kEqwgHʠ4Zd npa$F)v1c434{3g}ٯyUYvO7cnOBexR]mK;fh"L??eUilvoMf	3@hb_JP0A)TOYrޤ%>\mȴ5H
)q$n[9#Y
X	AW6\iO o9r!4y
ie+iz|J2D39> 㩬Y6q%F$$ߊ8Xtah``bY㵃vYoQ-pQU>>yf*KD$m(n,.sKYYl/05)L0cr|g`Z.yfDCβ!In<!&y]zgdf"8fdFsd@0)h>3dxANyC$ R"hf%'P/ܒpJ׼CHDbBA;sgyv}s)ۤ6հ Egy1ib0Qz] f[ٻ뷫~R!tŷĲZ{ԍ7<i}|"{ێOëkuTS]l<_D.D?
<( |݇<P:bըhcUKL<Ջ 06P;Bh88U@{A:x9w6
Q!EbB0I<}tHdEb؅пR3t۵`;gIf.}n֌N;EjUʜϩW6zL+*JUA1b5uC~`*>	Μ7<TG9"_[HTo0b!;K3{/<$Esn0.R:L7R}I5pH~K'D*q˖̓wὠ~6gYx	 2y4E PY.t!Xj@N1TcqcVx\J9Ic_!fo{ْ~UC]<> LGZO_}]  +IFgǯSD>\ Co#frC2n;wa]S VD׻Ү?tai5`nEJ\7d?\䃋7n^O pׅU4Eq3.+wn¨nyY[cE	\VPt[m~ѱ\3.?ݸuS+&\242IQ8/d<_\S'垾Rj«&;=6a=4.z@phC=,
\d3'sltluS]]fH؅_PS!٤ƝQ"[f	HY4"rlet7N3̳\ny%e%kqk@G:r
w=JWps>[$fĜ1t0w@CEF큸0A	a<Ā}VM$bNٗ=tCn0nAΖ\`.?^#.PTh?S(#b*ewD'b!4-<##]SImՀjo?JM#dYC"^yX7_x<ă>oԘ`o$h-rZ>I_0R.QtOQ&6QWϡ77nR^*4哇FS-C&Ǵxl7o@)Wvcp
}!
mK7Y#O*vH N'2@AG+(>gW^aXO +=D ` -:c'_޲Bށg?vW2x竾 Ot8e>{y%[QŤ<Tp1VzcX@s!SqD!|F_a}DɑUɊk~
YPqNR78/{Yۺ<ЎƋ?ǓY+r:}IM$wժe_h$"ߌkeYw2Ok:NkRqKkV:`ޥާ##+1k8LN+5=/Cl<c^C!njX/=;@{^O㝝mgo܁6'9 5kD(Sd,ҕ.vmc)9U9>@ifll't+dHpH=jJ샸K>>8v%x_ڠJXa#/G\AlLHC 11ײn#!%OiWh.<.O8bAv\-C)Gˢ{_XnA3&@
5T;qǊ99@gȧ=cٴÔ%^ƥ9Z3U1.|d\h$L2.xBmrzF?Ti+
ekwpdH遶@sa7}?mߓSaB1* :vf?TWo2y1rGChkZ%:@"$-eP	r{j@:Ch^Crt	ano',кVǢ#L_}Hbbʸ$~+} X	SI؀~xY?ra }6CP&QL{M.OB]=1')~&.r$?t4\htɊd:']¸A%ְѡ v
wXM:jƤÕܖ
0dqY,; ԁgzg'(7@og٘nmQ2n5Dg!մa^GݔCvlڇ+	Rd6мě
A2?;+QCQfH5%7rDC7wƍGUm͏k=2\p]vOv~C9,zX.H:y[E+cb}Mk |Ml_[)W|.);1T$9#{vt_s%Ϛzt&ܼxr#:`}zdOњ_,gH)<'ZS`K795GP /'cNJNl}̝M6l S^[)eoVq!'x7%Yw-<x#)~Mxc[eiU:~E@:4H?9Pm7wn*$qho<\WUMRjOPt_[[9I_Mc̓X_הz*-"GΛ˛m*T,1%>._A,tId3L"WlO=A)dJr/_ Syd}?m'=7T3ax;㪣&eߨtl'@]
%w-j+W<%o uSSvbg-pف}tt{)v;*пCOnҀR}DGk;H+֧L,0($-YFco귀IBM=cx<csTBC|vӇp_	Cskcay+pZNZ.D>vZ$m_`o#S&H_kKyPOZOFZRݾnWy̛	}S%.nb8fZ@j+d)Cv4Pќ{D|GgҼ1qW
p^$@8ohuGkc>:=uyվw˺5Q
)'Ƀ0M<0:ox*f^D:t*\T~O2
ξrG7^%.%'cj~k=)8ʔ65a_YК-f
)'cueHwnb6VUS)uk ^y4>[s{m}	
JP	8]x(rYӪmӇ	#hv9]@E}޴_Bl_e?.18(L!oӦ@Cۏ
1>/ܮWCh9`kJ	
 +EE윤SvR'|_`9K6|W #V4c'~n:m C:$+M)~0gԉj{vna`Jvćp} 0?<ȗK7ܒ5Lp
gZDSY<K}M7K8728Ҁ`a@^:Ӌr;A0t5%/Dn>0\bv|wWu8iw:68̍CA1NVxvffJ?EBpz'+KM@_0#]:i.VHraAkPE~*mOCt}4M*~$FZo>"ylO&}pu`+B)ͰNf7TnbP7!ap~_E+'^R,8%ᝡdtH\l,l髗7ox3=n剑-\1~bc̴3~|2>LU2'%k'/ęf6Ra
L8mԚm8"d&D6EN?H7$O*MNew&B]<pOfmfBݎt	^

'(͉qnCxŘA
o\b$Xf B:~	n;S J>ŘBAgң-O{"Pey<s0XouE)fP9=b\G'aμqy67>&^n 3}&Aq1X"0|s+XoҨySwK^=AnD1?EsHHr~zdk::c"CXx@KaW+}:V~H}]cύtZW]ݘb0ʢNe)}Y-C=!
}=I'ғx0Cic<G%(ZHձhJ*<S2õIPcuEp3wy|"Di{;.?f5/48 Y
 ԊT
\ni|p
c=sqCиIʃyA):5 ɅO2fV"FG(qyc!s͌x`ܡ#@\AzXUՒntSdrX=~ Z|ɟ9~A]%N!쯦;>H+XH}gM͑R>R>RM	]a&Fv'&J	љ4zx\=X&
L\ͪu:g}ƹT2aV{@atRC:&gj4n		^qם\Ft~I*<OFi|y+V.K8'vJo0@bS"`K.y|Pe+^S瀪SIpJ^W	v5 >a_|u :H7hÁ;I'մ9@z#f[O_U{`p6EVykaN+#
-y;eQm0 |;;]/cS/< p~taO4]_5gcƄYk:A:q>=eC~BmNrfyi([mB906%D=F) om">፛sFEG{!CB lr*iC\ѡC <rG?y;t6Uyf8b}·?0~7Y" XW',qDB;྘.Cf#d5e
p.Fw.η)^-y2@6l*5Is^:wU}C^jV8$f¨`MWXM_U6q%2c&TiPu(E6Y+%#Ob!Bk|E}7T$։O;"}*^}H?6"(6s's_s?8lS۔ML.z.l\hr#H[|:d|8{z\{¤zjקrčh-<pyOxË'`%8.EG R%YȲuQD9"wc?`<30mc5>0V8b*+>QFABDV|2eH
D:qHead!,EAe&] gqPM
PB/?R8)uҼ"YnF=#YW.obWz(wl%'Nk)opX&nhԢ>cD'~ŗ|.Ky2Mu(r\F|CA8{_Se [Sgu⢨dqݨKH>|%!>WJe:םdwq:BЈ+_a_B8>gRu.LbrEk7y47>/|1Yh;=)9Y@t4Uv|
`N(foJ>/f._:x>7/Wc~{QD!.BS<7 4Aů*&in02YUzN'ėH҇A3!iO"A81aNPo>iҬ`c# s^] AII?r<}h?cGTyv ujRgIg@T}˪tD79vȗcm;( ?%Dr+y
,Cjk$Cc=<@)Ss!:o!MwC7)zW0ĉg{b,\XAL)#sYYQL+v4˘Pi kĀe4Q0A؝v+z4tCb$@4|m8N`'M| \k8*Iv5y2rۭ͛wGj=9x#Xه_PMn"dl+¼^i_=6Ry¹"G{{?3\91ቄI؏7DϠ!6>nFb!7ػOU/&OuX*iۗ`!pZFhS3(~N2O[h3٢a!	HYmZкv\9yG)MY:d:	aW_\/"k﫫}8z/ZGUR3Jи|ZsfXGxuޗ;#ҨO3c@O~4$YiE
ZS}BU$>ỉ}SKf=Ik\Xul!v.@CI6GP;vÚPsFYS ,[ wk} f|0gB-ԯM
47 Pku`ɿbA`5YSp\xqB9OcNV6o}(3pq6"hϋ,xyp#";ύky󉐷V
ICKi.C'a|GvC ZQ_8
Ą7+LROLQX>:s8oH|*0 95}*p(ޅ|q+iԗC@dYOB}i[B9(CkYDЇmsqpTn
M;nk|$H#f߇p!i8w
=$񼔓_%HPV7a?hؖvL8"\d}،}M*hsS>uF+t|i)g=?ektT
55
/wS*,F^C;JCÞ^qcۆUcjTek\\bV :a͟++_c4Mg:P"'<`yӳ;ϑ;FZ49sIk/`S^"՗uH;8@Sҙ~-qQq-7Y2t5W8)1<} D{O 
9vĄrT61fYg -	촂֘ҊLHC֎dn]wN}|zss'Ii;.]VLnxZGSˉg/F"^׈}P+2\7C(s:T?Pe<Y}Yi'ۃGmt{pd{{??:*!Ct-R?oR>>-쿻߰W.5h~~x{̛)J9DÅ]C8Ώδ(!ZGAW[4BF\Mz>RTlΪt TA_yD{.W
Eu$!PD+s4+VFB}ºO;@Ek629+]PcEOےߞMP| tVC1Rf'ST`ƀbڔu0t*~ć,V>8-n
w	G:&+HZ叴Z┓R$[YDPަg@Fx~0hBy8	UWR"JS*J<uӃ
jL d7/×ZxĻ]w[*:3o>n*͍$n*q)u~5o<h?fmS7f7|k=KZ+2ހZjnSt:HEo{N ->&YȃJ'Gr\@0_YZ	7A{c|e=P@*N6a3CiNcCc5e7tN+̩0k<H0&f_kro4 ;t=SE2œZ`rXqvI;ȵ&&CGB\ Paƭ!za%l*Ivdߓ6D8!%<Ad3Z^0(o{@a5yuηC]9{Blz(aw!~@Ҿm)o;/ uοVׄS`݂yJ//ܾrh%Pv igNɬe7|ǽBHy揮ixQ4N,4ـM@NYpB	4c7˳[vK-ӱ_Hkq,'oqӐ?_<lk|";pU@lPI׍c%5uaMb$D6g$r|I5O"7
6,,c2!MerUKm߾oz&(0~.d>}~ͥ<u/D)ESje|zj 5MEΛu.<0p]B. |ܞeE@6_+w|N*l?{Ԕ~b\'*0H1VW?O8v xS٪U.]]~?w'^>}UUPv3t({rl@%&V_ZfNgu`5$3HDCLaڗyRt]2|dWwg+RLj4$t]m;'Ďjn}-vp+俀;g}RNM{D:H<\SFXZ$Ro=niߣ''ߺ}ϩeǷ5H?vߒ ߹i7d,9Cu"Ihhxѽۄ\܃>>*t0D1$3E8L(ӻE-ĥ]5 s
D:X\ި7f=3>2SZ}f]yPoJZX%>6kAty<Ft;T7I݇Dt?ͶkOpQ}y*捛nwMv)F"쿐Fl{Qq&*mн_MX"w>t%Y*}HikdQVT0V^"؃(D(E^S=?؀@6c{ju``dh^+JOS|Ȝ|S)KAl@J(1-Gs-3o.xlg	Wx.W{m;l'm|圆D']7-@s<II1CMѬBz'@|Ҕe*?Q8҉UBl[:i+ab"WU3.X=UT#GIԻ+uf)+G1K6hy5F7Z)&nM`I4뽽}'Hށn[/RfzT"9>19n
&'Nۭty^#XSzbu+ ~H^1$g83xt	GCݚ TYQ@ܰvS< #5O>p{~/O??smj:E '@k{/`=^V%H;aB&%b:}Q?/T6rUj3*W*^q*|A|Ly(G`3VmF<}㇞!{R%6</qǇ7.;W+m{PW~zly+쟙Crn]{ʢLSJ1Ѵ!k:8GpJ@yPZw~kt@)u~mr<6m#!+O3h<|	7g]]2^oەh=8X>db4?}|uˤ_JjW Lཤ_٩3.>딢twZߟ2*h3^Gq~}Gp0o0p3U-R`Us$ݤZT;yVJfon@Bu ++)#b@GcB~,rBIwυGq!g~`ѶsP1:	T(جҁZMEW	T(6u1J.ȉl=bK}	2HjCe}yڮRwlb'/l.qqٶݽ~s7>m(XdyH'*@`K^,Fg}V{lOgGW|qtUa IV|IhF*hP|tQu4׀R/y٦MO}Fc;47&TǺ^W1Rt4o7^~Uܟ	m<.]gq vPa`iVZs ЈhbjZ ;HK;D1tݪq@ndGYg:?(ΩJU}@r1qo85B*Ej{C+t7@+7n^QeHqR[
]bU?'={=xx+F <\0H'\v'_%%@l&3O0.>,1w4Db]L"3 byUu$ ;BG);<Ձt	VNXdu" @AW8ۧءTP}>GN =Js[ 9m~jo/ _Q9dEeωMNIIlj$^1O~ʉ.hPh?ޙ:\'3cS [`g,q~~o<a?ͫ~JQtR>?'গof~FÇIԿ\HMlGGq2~"lP3!k~8;_b C̑^!mG ,Ʌg2+6GucNvmE+u-gR9'r/b} }@t+h<;)vOkxM;#Ԣ#XqO(Eݕ-|1ixX/P5F2.bQwHv\tG"L֋NüK8<De-qQ@z9UUHUP;7=0 悃ϴ=]8~.Թo *=%f@Vxe<29DY.1!Qa>J4h=-=OfGRA@4_;O Blq.'61+ډ8~OL8~u!gM4sH'iS5s:VlɃ
;YxC7" }
ٶƝ_{e`z;珟3דg<N'"8瀲KJߌ]Ba2~ =g#b-rBmݟ8/Ǫ)Ugbr9E_je3$1myX|Un.S]I7V1~$C+d2 #	d-nֶX2e{L`%͋_V[\a=Lڿ"/7?UYDUE	uGzWm\}:~[80>Ď).7;tɘyV@BC;AXd@TJ |=ATG7#g+ނaXX_uo8m\^i'd7x%ߚ9Ip*EN|,q!U.\װY`վBFJ'EɒƋ3{drĬhymVf#~ɡ}IMƺ>s/m>'\cP ڽ,7EJ_fSWYh]acAK9i\|£?n(M)e@O(wƫF6E΍>zk֧ﻻ=rsN7 T/Qf? Çj+C,` ~퓤2̊XR|.t9?	-'Dx!"Y]ٮݺi7Ok|*JPԕo>|G`>(:˿o|0ʵ&d960hWGb!?2cvLn8t}N>j;*?s= Y1::}͗|SREêߩ	04q=| 9)8PInЖy]cS!PDxkbq!@黷ܔN$l98.0'/4*p7=Ln6*~n>aOp%ޞKeꊽ`  <VE,4ې9:ړ!8sb[󿟦ˉ롃n>_8-3`L;Rb FdUGYa%=kB3%TJr:wl<V)?å`?+^[n2J&r#E{R?xC~XeOYzN6<yWR&87v j.}e{O˩_)8@0{bG'A)nA/)z>Jy<?9'OīCᾊM]Gy[qe:<cAmiϽx⬸с1?p9@hxxo¾賏;O:9x_p,]guVԎNL@߇ronKueL
k.
8X,d#BCC,ڔ~5n\e:+-x,f&Wx
a,upn߱7OTxF\IҲNuRlaJ\lٶwoCIu@o䩧;yYs<k	]CM!-~pzn+eyJюtotY@>b]nߔ]rQ=	D;<#d}O۽_'"/Q2ޯN=|Wohnm7nONu?Шu:F.k"a*pM1?ϏSveh#n?H SR0$*
ۮӡtgY!,t^bQuA)gxR~V91FÄqH^5h%
.q"@}akR+/cմvöÔX+;pn8E:4We,jCf_
w9i
EpJ7eDgSn}b&tq~`/nocu@%Spsm_lc`[SSҐR{|}>'#}ivOLDqXAuF 
|F:n0SB_ք>w
\c`ȳ-~	O+D7+6Pt>>*yIg'
hIpfsQѿjgfrܰ1x v@hMi\Ƿ΃}>уC*'ik=b	'<}HN9;.vR<,x62s?k{zK'K%mtj߱wWU䗤uP`'Fnvk"im~sBQO'7Z(AX 뛎hTSԣ#Aoޭ
.Fw+}v/ZK&ďCU70~a?G	ƛ6'y	"eƐH51^s*$p儚D!RZI~d޺~;W&`҆ [<p"[,$OqYX]={:|-o0Pg۽O&.2(8:U(GÓ1]ӇpL1\ `mf	_`C@Y÷
>^0!ayiPRvc{nK?3EqaZl8t>H:HffD,T;?8$ɓlL޾ yZ|\ů\"<c>6i[Kfs7޸+Feٔ54~smo6}{L}r۞o(D3P'?~^Y5o  u2Yu6G̘7JY'#\L~ 
98&Usyll(ߊ
}SFHs)q, {Z(F*CBe_\,q?,ۡb| ~<5-^r(8\[x㎷;|c\)INAY*9:nMd.Qvt8NMX}~>p7/3_Gc|$W:2'q7_zt{w3)=ϥhE*zcAX+45v7_R@mLY3gӷYe#:B'";R"d)Ae
?7_`%SNlH)d#~
}ʟ@dowco1Gʷo;\$"1-zZV$D]R9>t׏/)r:`D8M Z9ĞvqBtEo~?lͥ.{%7O[J`CȰ(`\	)1a|ݪ,j\BE`9%ٗpC9youH00~7-V1kÅ0O@gqAbJm2ǜdvm KϡVCSU9iCw~lpAeβėښʦErWm43,md'7{me|TU+ۣG`$<{k\&±š0(T 6aVן7OU;3ߴtifɬ@!54't&M5ue`	Jvbj@Μ])i?EmW臅3ee	X(aG1>aKۆhuQ-h?_E|R$4It.sٓ}P~N\E9¼}9Fsr[jo5Q I|Llʥ%k(51蟌{Gfcٚ:'>97_ȃԞ력O	hjha,C}wpZqֿHʃT͐)dHkkUC)&^$l]pg7ʜ!1nv^Λ0kJ`;lasLx4S/U,rSC堇͞;@jӋ]N#^^/4Pp`S".y!ǅ2@w:=9,/~>{{ EHO D,tўsq6b _PpXo`_b_|T.on/.ur`ʄB`ܾc#y]|IB2OtjRTX!M<r11q1I9֧6[#S ""]4o"N^Xq,<@C'[|!Ji"B>7ia<?O*I2ăMl;QH'~k m\Jİ}Sӥ'6 Qީ@h="՟g
 j[
wEVh*BZ'ЁNBj2_|Kx//#?y]ל
:M T0wKੌ`$sl@5wp7:IbzIXMTu+ƜDzӲ0N
)k=3GO"pAem+o.=~N\xOOJeGPRnLPgDNejނx+m;,=M'i(`~] k=A
sJE.acRҬ-HΉ^p6c;G$%^M1F:OSN,yusBle_蟏?S?{䟄{\SѣsOr1Yued7ↂ31Vj2ӌ1Be>C/+@[?	
419u#8IyцG3L6},[A)^%>3t5tYˀ"nXVЇ3IQd6@*2}`-2}By)KI=voZs.q[T fAڳ_ҀhW5._dE겁NPJ@^.y"Q5oA~ކ~Ծ?]1U~`&,xH,&(<̭o	i!ØG9(@iCCh5.?
m0+@m:odc?P&G:+O3؈Y1MRѷwBfו~	M}סGK^+y]tpeba-/tmR"e;w7nW KEMF=κ}I5pA=Ig*"Jcq9	ny1]v
;nƊqK1
^+J);WM}g"~dMikpR#F7l\/n>1p^:0^Su>e[/2S@1rBIF;cjdL0Oyo2[F-gyeG{DPE^4`$(u%rz[!e-MZq{waop)DUqg{V>6(bKs9`Dd4NL3:m4t|5?=ZkG;Z)t燆-+/M]a$|uC<d1rT@؏r8$&͞~9[Ek,eWNci>LvAbCnr* '㰦-dp= E.])3$&iF۲&E,hWW6?ZďHyAГ ;N!C#gE1^mտΰ+oe1^cpܴq .9ڑkA¡0i|8nΆh&9gGy52Ԕ?/'tW<]~t}ڠbRnt$v+m/o.M`y7lȝgC|;=.ݾW>ٞ%򹾭-!JВ{,!

<<ǲMcLFoRxW@#ouVCk#0sb	}Aт'>aRy^t),uj@&yM]p6/yGq }a-AbNR˼Ȧ+ԏ8 io>nx(Ƕ!s7v,e$AFw5[*[Pr'W]pw,R3EF9EjV(<03g7wƃ1dȠ5c@gmjf촛+7OУ=7?U7r:+F77uu'.}t8< |Cba=~fw:(i>I.o$,6xttG*;?cWuMEPmJʸz!k'>A.hl9*)ʅ8opI17FkF
@l%nc"bCt(OIKCdQo^}Yg]qD͹
&6mX}gѝ?!=~X~m/mNN2oay>J!MDT6O)(@+v <>1tkWF=܎|Ņ	8iܶq@Zvz_7~Ei7u' [ǾAQපu	WN.lv
2I:8SĦ	#-ݵty`34jۼk.B!IqX36J`|*V`|,)O;@ީ_Ęc.glZv;]F]B'y͇(	-Qpfno.| xdG6P>?.|0M0 :P{N-vX{΢#R A_̛ifL{'91weݲpFXnD2[N6B+CP¹B&G7>j1QC稉ͣ>|鑌Qq[@~O<<B<wF[3@xcXC`8]|X8;{(dvѱSШJ9QgަUv@cud xR?{GQM%YEacb\5+%'mvvrj+:x4A7Sm3^_큋!A9BT&a:0Ggs>K_ߒ_6j?4{A1^pZ;F P	[U5I8#Xo|yUH+-zFo"Ǖ~\We',8y/.]a_|
O*nTLjmmğ}nfL\y,+>FN%ہ=/mfl"6 cr7Ҽ95uq/3+_Oy	r4?é~8C>>ڍKx7pBO	kqås?LUhۃ8TyT1o@d8=بLNݐ:a0YPe3GYV()H	\)w5pYśw˿"×>Q1M+0YlqTv!2_	;wl[ 3!eڲ6qʑ ϴ'l|
ϮB{PoqL}ZǍ7ݗOnS<GXCKw}ӟAOﱠŠ\^r~}&Hi=TƲx<5I;rƣWyR̜ y4&1TML	e[- =s^6=a<9xɾkK%L?"K;`MzH*ݤ[gNߌs([tzQaٖV
b!%̽Ix-hU%!>^W	ˎB8:r`-*prȜV"C<d,ZEVhJ_}2SeFW}Aa_扂ҧa c~3	]lĘOYj| 
ϟ6hdmnr6雒?x1#yn&>!sS2o78g$t;2/[@Qa%dQ|Ћr[Gnpjbi_<QYuq2,;fd"!/U|5]@_E/>b%7ѯy*,yGɆ;<͢sn <V '`Nj?h;	1swI)+_SuSܠ/	xӎNoM[NbUOb|7oԅ</^\N}N Xl?g
k~m,hMҏ)ߑ}Eu A%|CT.q灳32z=45.ӯX_dze9}E|)x#XB,0G})G٦@RԽјN: \6"^ K}ɟ ve/3;gyoQQHpwV`]bE2*V,/ƸG-+GǞP5R!eDMa2^Ҭc#0ԃ@A`)AZqBڗBAR2ctcS$»A~J?/AqV\DEc)ŰO	A?bo|Yk-!l~s\b׎KWͫV{+sKrcǿ|iĝHhÑ;J/&8o$胒h
?lFoo雇k2Qm:?~SXbB[w4`oSRKMrݻ^od_AP0C684ߵW⍥#{).-uՆ`'2O_MͰdhNCMbc5| P9C&n݋P2kT1hdO|7~Hwn?lj_1k
سd0,'ԙ=Za,6^2tU+y|`nr{HY'4 nڇ[݇Iw
9tL~au G'2yaINV| G!0X2M;~<.藫=@-I˄y4Z#&hI/89h1&~u9/ypSi9Cٳ<G	K#U}s2s}4}94>èׅ	\RVw`nI;nY8 X *hX9:C4}iC᳐M$ojc?wOΕ ~i6N'ֹz_K?%m
KM)%'Tjv=ñ17@_ӯ^Up	k^2yf3Q*@U1}~v}8bpڗ~
b{Q!1SʙU"vۋwmWoԆ"0Q?&kiAzB}Jn'tb΢#ӶlaU 3)26i<&9q8.X
|B(Ck[7;￫rރtWFV)::3L9p=GX~t
飧۽OT}꺢 6:
ARS&Ͱ:HCc0.#(VΌKKmqL~b(6c4>RyD_%Cv()!dt.$uVttakRҲ-{	4faMgg3P6HÅ$6ӟ]<O0Is?',Çc=Y~{H6ܬ2֤\ezHz%Kԉ,=Ul~Xn$Oo4p<<qe;Ӽ-W59 	4n	ŀnka[.@}M[+4NlY eŘD&70XG~Vt>n%d_m'NdKo:qK\:[GPp B~@'s߈Ng>)R@M/mW;g7^nx#; dP|Q+k}Bә-E$Be`cCrl(/F8jA[GE9 \-99wG}%_q.Բ'
2h|Ha7cz1p	[-Tm<۴3vP`{J1:9.+:|TKHd#<!>tYђ}r_)OA=%.@yz͸ix"G|8cZ.6H&t'7e׭3_<qYRf0{)$|y@Y1cWZ3LhS!TfE,Sc㒎U6mp҄Jh'2wG<`[Ji#OÓЙ1O*uA%TM5	UGJt胎	7뚣kp҂*E&v,v^dqgDL=`DPaMTSfۈmfN.lm?&9*-XK>rL7ԿG?ޞ<|sdlaR{uhY5i`߲g|ߛoh>֧l!?/`EUp.}2")9L%7璈ZS|/-h\zh3&	yT.XnQ<0x=,Wyk3pmF~gõQb⷇:Wzy	Y7|#󩷴VMH/Eb}ٗej`l8HM|}Oj.rH7(Wj"	|pu::ۭ5M:K]
gb%C=6bԬ鎅';؅ϴOG _ɳV↴H9stS;MWs9%݊Ĵ5QbY@I
:/Y&06?FC:)<}R]|dY87oѕ?gOE$~JTPs>~"QƑjH+59ɡC1twY9t$䈍z$o8 "A."[?u	nZ_h8/ C~@ٓ[o
+l|A%͸`Ne
^vO,aqE5O&jz%n;a,}YsHqr8nP)eeqcɅm) m`	B8!,s7a츐qkCb!eI"zT9MR75eu(b	wXTp1tt	NGsMqppZqv":	.(9:oJsB,'PO=f$б@(eX}yU`HH6!jAz"*Aı:ˏFﶞixr=PҞPF"Cl4ѷBd=@ΰ5q{f*!`,`(^Jd@q"	ͯC(v8 ]Fٟ:{CC.b~]ԏ3kq2~'ex<ސӵu:|xW˙jlzV}?6S%=z8E97BSIW_AKoܽ,oOm	>u;3ЕxۧW`ƶl\(dJ'⤊cigxO2KA1C9noːmغ䷏ϫWy?Nt\mܾP!ޓnʆ->+Ч7t	K1υzt6- 7op?_R;DVwQ7,"; }پ8r<L'O䫧
lci+̸x{7BKh4c DٴAng^U2?K~O;ic%)ą&FJU9qZ$d3o	U+@iX5"tߴ\ѱ^e@7J7Q5ЧRJ+cDmf#SK*ӎҲV=,bX?>u'|7lӺ"]wXRM]CPTy0o2f|l`-jꤏd{|dFs22a^ˉv7@e8DP0:_h}aI+ZFuȐkdeæD	h_VZ#ʔtzQJqo]MRx\]H?[ɒv֙jAyG<r8ϒ@)k|J/r Nw ioiIB# IÜ'O-zXӇl]?5W`Mb<C@,OxZ5{Qrn2OԼ+dd%G=zu5}yBQtfLq{hEgXAժC:kUm|K+3SVaOk
& 4(x[zioAP/nq?HK^ eP2U6زkHLhJI86PJR5o\y''H{
'@C^[+䢢S9[z%̴4yk9l/	)|2o瀤*1=acrUNL`M@QsD94b-%|VJ묲NxTXCק8<o!鼋 ޾q6ѰShMhʹlC*t1e~wL5޶/uoo0A͑V:U	'aVpv+I[nL."3.N<t~Oj.NNesrQGP'~췗DC߸=ۗ'T_mۯlf)#m?`\П[wdgoV?/?}Go'=wͼ}oH?~c߲ݧn?Zm)w֊AKsT}?'t7lZ };Vl`m_n_nw+-_9% }wn[݇S`b#_fzLT{3E>_+Sjrf뫢ؐ^yP3gRKzF&C7qÇIR1IVy9"b,k=(du5Er6"57tty{7鬔9z`b&BaB^4\ӓGOzg{y'32B};h 8d8%"ό{(-h#EMb7k"/*W/^u"(EVV剒c46CIheEjաup2n8o0b%,>XbH!U+Ȥ|];ǙO
MSЗMfD4>w53k2syCoB߽{[s7EzH{ƔǶb0x2Rʡҿ6?тk7nw޹7f 8Lnlt;_=PeT2'n]	4{۷D=Px(*FKԄ $d,53Gܛz yi51X(2hĉ+e ]^kdqʑ<77N0/n["tV8\0#2R< pF]TpH 6pOT':-C	k!?=%I{rB-e
{S#/?t% 60YiTeݥJgce5O/	ocZ<0-ѳ۷[nX	dl$O>muuHG,(;
 'rkzPo{GLeSI؀X
3V2.4.*(1(X6ğ1*蔳Ҝ!m~U{H]prʊWE׮8ީh
9A}҇'>U{R\D1|}qs=ƨ4؎4	e>+?E4xs|H+?h	Cpq(=YJB,` :6ft@[gFe2#7㽪, eH'y	&6eg9!G.<,Tg  |쁮: 'zp򞄃Q\VIeZWyTkaR;?vֳ[fi8BYj{@&m0vpKޞ腞KYCwB!râ^w0y&oKS`(}!"\zi6G[g7o/Rbre	b$?ƞHq@KJ1vl8>:z3<+,&E 3Gs>?̟={Vȭe2H2Sd} !]U6=b|Ww	W.qnмù`?7띷z%Q|($7h[tPAF\ dd-Ep}O"vA/7ɳw`o>pZ"veN]J56}.79LX
aq\1^L,y'i Ru3$0	xJkp|9(H#F_D`P{4JZ(If|+o$<|ޓ2.Ӿ95[x(N?]ٿT`6oEU$r=D}dCb GyXkϞ&EVjC*{G+/훾/k!h@+[L(9}uh NS?G2 ✈Q
EP&M~N:s'/y|~y{?~?ھ.7{~bzmG7,~ۇ#
@?ύQE*+zwڟ~/|pз~aCg?;v-e/sO2b!}to?ˆm^D"7~?\|6G?k9ڞgۗ{$7dw]/=FOo[\KW]B`/,
꟞<y][@c&ǤSaiW-#<X#橗l sI<MBy$T~rYedN}SB:F]cgjN[;oj_FqDN)"6ib/rp} C\Pt"`Rg|y陟~Է}&g.+oM7b	#kf|$Pxk f0kW'27^Osk3UG5 tU-mdp:>U`UsX\	3yv 9^ګZ'9YBoޒ޸}Gc]扛xA`{NӖ?Vp1M[!\$76ScT8m=lrn$<~'u^<+v?Ϛ1y[ߓ<</jé=KAy̵wo-F ai`Y' .n:g>(1&yUNqC>7o3LqM㥯e̫+϶ *gl+)SB7e |,?FJ({ru:eLh]T]nߺ.l7Fn
U[_?将6?4HFN=V>vKDKC@bN|E`O1&7ȯ)~;?;o?եcT7ЗB/e?GnU^I`yC#IqC/<|'tIF<ḏ,2_1(v;Q7'b:Ȧ6ݼaHcxj}\7x˱57΋@u\M8'sCtmGx[%?udgr݆f[x*?cyCv+XmwUns`8b5O`:mZTR*gEH1!bEXo_L2I';`
̹}āUcJi}1];g|)ooy[5$3bɫ>f[fUfTH˃H(XVESAf Z0`J7ꦌ&ϫ?#j+cg*вŢCe^>Ws꟬>b{#hvJ|ӇNB6V`.+鹝_ :̭'sdyGXC5NnCLpuN6nuJG.S'wv\ڋ\<Rx>[^U'*sʖn"e۩t\c`aT%ۘc5s)9h}MʩگSXQ8AKk6jPqC9vr"Tl)3 +0_ͼXOi+|NY4c>%9H'ǋ2AιbʙΤ7V 1U?^l4ЏOVN_@# SST'U'ỹymo?A *SP@IԁtUr@L] l:HcS3]& TAfxFXu3ϐ0Uǥpq l.5dwG>]~zm$; J~k_͟>ǿf7_#eC"4n-p?͒?-/m?7~K/m_Wlȟ~W_{|~n
}M?W7vc_2j2>t?nG?q9VO$]-77lk~1<j{׷n/sGovoU2`2HA>˶}WmO/l)Lqu79Nzl/i_3ĘP8QEͷbp=u7Lͤ/xt2>>$=?lgr=m3, 7s׆$5yת7S&7]QV*z)D]'h=<p+'lYSTs;cһ,a8"H&ر)8n2֋;ެ}:.Ru)=͎P^#X.9̶ yZ(h"x&JN/* 	8oOfy*:88Bd>~|ܘ:׉~Fs7c2~=~U>DO@K ƍo ?LpSWSE}א,smpXv|؛d7O<D 7RaM]teU/ax+jN\9qH6M"CuzYYBN^	ѰBj]MEnr^ٷelǎ?sQ.f	A@ޚQ!$휴S~rߞyO>=?(Jqu^ p-_t+{-?3<9H#>=y>O1$'p44һ|ɘAii Cîw9\иr;=ӏaAZ[7=y8v{⁉vQ[-?@oS6]m263n.y,~vh#x@r!|P_"gV|we-)xuT29
XcJBpלyDun@.E{	Ssh!vn2qq9H|(ֲ]C[\:$y (N-}͍=cuCl t-Rܒ_hb}e^n.!t@n(|K*cVs&3:aXXwD_9p)E; jZAeĜV#yT%PT0LHC,L:veO?ݛs;{QUP\0^YP`2>)HK0Tiz!ۭ;g趘V](ml0#H_{(f<eLavBgqP0n j>oPj+D/{%+ꗾ۳~#n0XW~+abw}.sp7$9m']hDbEρYk0g>I}IsyMc:a)ePVh| [
cnw7`VO:asbpؘEq7wzPJdH2/e uXw@:%6|z5to9ofZ(0Ү?=TLhRoC4mؓ<{˖-6MdHvQeh1P;2LA|q`|odGO=%籜33{\q7%a
HOsNO9,3u8 $ab'jy׮ExU9m
c.XˡbaՐ2E<^4XJ)7n9OrNǷw4LXXP	}WN$-^In=08LMal(=W7(PJtfN&9/獨&o;t^:exry3pp.d3ЙHКp_jL~⫷_v{䇷߳}OOI᷐WxD'pGE߂Lokg_|䗷_K> l/j?G_tOqǾn]MW>G?w>n_E폊zɿǾu{`ҹ]/޿}|΅a?~Wn?w=??Cr_*
~hi#mşp޴'_Ii(+?_p:}=y_>KB\Nk-Qo/L|zq.WA0E!Ğ$O'L;/ 5(^2t~$TsBSC'پV\4ӁG>yEj 5sɜ5yXzbaDo%^6ȜMIogCp_P5ǍÂh;hL0 m
+}v z*.rAc1 <Bt@FhT \D=5p[h'k>JG%Y"bO^CL3 a?e"X?[l>"F.s&?	7/#le9/{}=A).vk=nNwlw޸.?3wcܸi^<1hOo3zoGKϟl<x~Ⴧ'\XdϚ6c?\Vyz3vڳ9/P~ZeޗYo[p4˾Flq9by۶CJ[{>P`n3&;hC~ o/L!Qe z2>|1p~铚
/`s^9/lR/?9;/8t~y#㋶H
On0'ϩzsOmy3ɤs :q>~7cw\(P\FqXu
h@Ќ\:rfN'a(_xyTܔ=,p?I8^$;:f\%Rx%3V>V4sX2n>B߼!cLah=@e}9Pvmlw<pOȜY>[ Fk@baunɳBJS٪,5`,wkB}VɎ$x"qdojF{L"IѸNaJ.CʺvPH^KbJ	u	bHn&d	x-Oe^)RǑ`-kh5<9ʟ{nQ:JW&/1<~Q̷yI)uiaq 5pQd;,戟,x9E'Oks־<;eJtw,_?b+ٽJ zS^.>-w
.چ*YSqF0$}Z)xP&-SICE.<!vxʴfBwp
\'2I@x%w{DUdukC_,ΫTĬ73/i37e >8퇏r;VַS2yHfZ!78?p=/c	Bw?;]e[Nq8ݩSt}Y32r B5mBQ\.𑗀ܗHqi,YB\41|J_Kn]eܧħ`ǳ앒Aځa 3yuN
W~ә㷼#0G'̝\}D;4;n^.-]cl;zl?c"oA~?a']IgmOׇno4|۾~x|E)n|}/4{o'5uGawS*7x~1vQЇꇬ+_>~p~u~7߶w/ǳ??۾G~xG>nwSF_{OlW>L}1W^qE;a ̡\k	LN#EC.ošqЗIqT:$Sz<;&09KeS=l2'6 y3t3,$)\((%()@7zq/
,s:+ޥBYGgM ݋yz^` VɆ2'!mXvIoxI'`tfVS
Pc-<
:8i>4WA$7݉W`+Xj|*fSi_
߸}jB:1aϕk۝[;xslħS;lXuҤM~~	#ҁG ?}8'TJΐ+뫾itӁw]~
?w${F&y?䌺7${H0{{1}p97*ױ*+_S~/*D5ίy+~Uͱ@ yJqj=t.#ب%ʠQ%g+mp$ʓ.nsD}D#W!5&уOnO*mk^ %I?mg3ܼX{}uր\5N)xeJ7Jx04>Jb?)3QeOqÍyR||?)D_w\e
~
+PU&+#1*1YdyL@݃{`Eqnt-~͚0CH88D]'64iEܸm+cp9()T+*oMD3EZ҂5vo	
| s
`8z`\(
Bx` b"$#Ad[׬*ނSAzJ),@C@R_
[} qѪo`Nהbәγd97XOZ?K˺QHbJ eaB4_cP!j)C#KɀpG彆	ڷifkƞ7֥}><30@ `q\A0`T32Qɶv[5T"KLVhZŵ$ۂe`;Jq\̸yy~k׵uh}|RDX$'o()*CzPtLd9IbVRS{eԣZ}\Tt?Ĕ(	eض	PU.pA.s};mi
KE)A\#m9{h|D|	{ŠIh
A&%)%ULBɸ־=׊`P> JWp
 e h,V̼>u'^	@ \t$>b)ps4}C%\::9/?znߺݹ}GkQ^	v1yR#!?`XG:y#87?y7č۟kSKJwjqM.G37XeqlJI|M`?&ٳXÏ>AS5&/)M|DtղJK;,]2OGLA|˖""g\IյwF.bb.tBnp\(ϯ켢B@]dwI
~30yצ:lgk׆_W틶/_*y<jyɌI
>`?wzvw`K'Ց:1??TF]w>=rrTp+\Mdvu{:	pQޏ߷//hA:?	y]?C2<3w}˶ζ~nxmo~]L'vv#&\R/Ԁ-\әXr%EtĉL$AW*@\>|@vu^>~Q=)u{ѳ/󇏷^58,4`:u"f }!KB_
IMW?x57%ZȖ:	+`&}LTbl.R(Qyts/ pChl[G11fj+ML8%nY70L]GyB{)1<upL7{G.bOW_u,a6S pݤ/%"]?k-Q=C\c4<Ox͞I:|18RR>fN|_\y"~u5\Gs(-9آ=4ȡ|2f9&MI)o~YW)DJȂ3(MQg G6]}ȧ_ل_ШE4M2bbǌZ ܶٯ94=-@Lf`"s?y:?ل/se|8O7޸>;yM75hƪ~jwoEA3gײ'ƘdeQ}/vH?{ޖ
NLgç?߼y}87B-KY _lA}M{^wUu?? g<o޿}>>S@OySW)u7T74uQ	Ҥ~&4dS~8F~~15 bʠr 2LK| LD2P7h_/mu#Bc+NxtUI]˨ܥ~"\x$5u˚
.i%JLsAS=_mGߤOXD<أ?(zAvl!hV6gR.Db,ZY])>~"GC.;mkC֪&("pqD{OLmˉG\e_sHꕀ~mG`h)q[gc.E~Λonwݞjii)\dAf[(ƖBS /{N  ]hOCl'DmZcnP|,s,ZV >wl$^et})jvvL-~b{WoW4<jf<b_יF[YJ*lk{YoeEShV"MK_l9&"";8uQN
jFP4Ѥtrs	-WsފW
aKvntTqf_(=Xݨ9	dm$;-D |΅V׿r.C-{PmgX?rس=FP~ 3#}4V@0q~r"͸<䜷%)_`5_
3~\.uN_?+|-L5	prGmWC=fcIH5GA|Yѫ<X`8rS2$?^?oxʸȫ%R{΄eLx
y$xCA	^D1=Eh{tjf4?|hIFU׉;yrh|?\SInH~FW)>	߶
nvodxZ޻wQ~lyiz/T	'~틶{_};O,_ۯol<Qu8῱9On][}RCGj?ooO^u}÷o?{|TY`ZbO0]oxs9|}7+n	sn_MdX+0"\O+rl;PcsFΧPbb:Չ\,fŲ&*lzhdi[Hgb&D怶^hUq;n/8W>@ZoChx>LETyvs9
l^f+ubjEh͌Sz?O(mޑ>-Ke tZbƸEG<@ii56ޡ-2,O 7咽 .x[1xXIo֠;U}sſ|I^kzocb\,Oq}<Q149K؋;|BQ69xɅ;d;~"ulCnnJpcO'qA\p;;5yg۽w;wy]^އbmx
	عpꍜq4|_aJ+ļ9a󂘂R|ALG"%{S/O(0z*}'eh:y9.psO6cIYǻݐuVAt(32}qS1vok)|œ3Zcz\`~|  ؽ~=cYt17D(;'(I*g΍cB'7oi۷oeZod:PZ젶mȓ+i懒17RE'ޫSd::^W=rP郰 U^:]Fwt@⒗NDs@6G^["uo⫏Zaxc=YDB-z҆23nS%MI/2QMy/%Bʑ6^(S"3e
;uZҶsr~* K:OE+F&"YT:z	AԠ=Rm75?38l'ǘ{Mt{`׹p`ȸwHekW̉K>\A?"(p <Imb3m|_/Pj6]p~9cZ#BVղU喺Qh`[yQ-A,È9=((1q?eF>S|d@(!kiϩAˏfz?Pl0wYc`WQP+Eo|I#1Y+ M5Ӣ%C羮VQ4(Ŋ!m|@%W绁o-/m4!s\oˠ?&T|GY@W ȇy~C͛vx{Zp<D$9|D㑶'VuOCnBMGc\x@}^|yBN#|#"(S8,zju4]#ev1;eZXs#$:	_4JY>Ͱ՝["FD#Ͼdcn_pqЪ8t[ ,+		U4^knUpQBK"b.x1F/zUPިB'܉D0P3~͖RǍ/j_۷l:SN
	^	?v.>q_SCBd'h~ˡx~d߻m_mlۯ}I_پ}w~~}}l_3|ѯ/r	>&wLg~vEomc߽OIپ??3%իm<ܾe?}?;}7q]~ۗho߳ꏿP߱~r{7moD)	,O0Џot|cu".1/^cf?ß3*ߋ-Vpbu#˾l˿
%z1ȱ5~D_G~%ntOYЍ>oJ88HD`+jp
䯢xj+w@>*C°~E`?~ۯ#*^d#FVDnC}p'41T·϶O0yCD(ECH0#Nq((tuOBre|*Soo`ZА2Q]VBL,h'釴)q."t@|]8/6ҁbS6^+OGQEh"JkF]P9⽱ml_f6)e}'@l?.\e`:;aOqS=Sǥ-ѓe7t󯚜4k!TD_zJX*զ./+h."{+<<I03'5O9+Gt]{+y~\J.xXm3Qr+XYRNĴǮP95Ia(#L=HJUlLhք~hKb;!{<F[N\L|ϛ?Ϟ=RNa=6{Qhbi8^	'˨{u~_84 𓲠SX?wfdqFeV]hB>ޚZΑ[r_9yfL?V=p覟^]bf<='1Oo3xO{ЇxڱԢړvч2ͺߘhkGzx6bX-mZ1OEXà v}Ny^cFM? h/t%[xǃA
\5&toB$d4mƳ"Kx[eJ_\UyQt0t<16ac'g8VO$v91,X,cu}g$~Bw4vČ|.ԀWb0\)DАs"uр	] mz="
1EhWazW햄]9(܈z<$?RQ2Gqs {fpZ~uh-R1׍*ylݽO۳s'y10[K:UY@Lsv>ӎq03vTфqmd>T)%Gܼ}xuox={7n9"|MlWP^c!ea4b-=ir-5@[ZR)eku-D	}]ei:PJzx)@ܔ  5h+O14-xS~ ${uL>;zZL06:P/P-b]+-F:x+3Ǧm@!zWǼ?V+ѥk\GؿǗaae~mBGlZ{ɴ.5ݹ}$r'4/ŞQ^SX]pƁWss==>#%]:VrZ<UщUg0O#'Lu@ `!d̹oLyb4t\W	p^@́MF2oν_]vsiڰUx`+Ml!P4 C`	1
 X9q#Lwj,4kǯlx̑S]?lbv7Jl\ε;< <$<AēKܜѣW~CS'~pohO4'?+l_WCqX߿|C-E
O(`IG?}7}Be`n.?CJ&l>~엷<Uo|}NiG߷>m~w1!_ݻ_!~%Ol탳Lw)3WTzs	_Lu4`(ws^W>N+&,h=IU^ObWBLHW2qǬДr"W`[YP=43K4 crR,7pb+9kB#&'.2(c'IOޚ(jW]	c9G_u,ulYJA]d	OY6+ h_=\D|>U']:ڍ$[랛t@K2 Cu J*PCH3@#H^d8}P} G*hְ"(h3SD^(;C?9٣<ͫ!}Q[b\G`
Y7N ~o=;lX}^Ʃ0FvXF>B1(_|s#e0mAi=Sgs['0"''\,֣xk§>Pk6OuB)6lW+f,g?̋uA\xDRpuL 61|Tm8m1AdH2!R&U|˖K }"CHgR8ʫ8(o&,yz9{R(ҖQ9̫\pW萓Xs1?%Oh|+vZ:9D^ܼvQC}S<,"nU񝲰7U!'73/dloGTfU΀:Y=3Rܘ??gEzktFF9
+DGpmIqxG".f`d\W <-o=9U!0Bވ~#)ˬ
-vq;(0cZcYIoُs+^JVcҷ动#fhy(xUXtK@횾&G_kk!	%vÊ*SRlG(?0հ%N]%}`'  [d\>N3r:q|4w_}&>`!ʑV4{/ZAH0NspәW4r.54VxJSb븾J4Jlw983t[
ZXUz,icysWsSz߂3*yȩU< 7A_r,`Ƃ(dq;iCynlÇQß)KtHܲ>	Q>֤;& gRyOJ{L!o]'hqi<`#p,$ASZu6 *:L0 ^Y {-')md*	r[ՠ463UJβRt' EFZ¼ {'hs0? tS?_RT>e@7@ݻ~b=
*m:p{~SdBp^5s8S^id{Hp^%7vXg'=arƃoy=~Bٹ8o~+qO^#<ne+
0
@y[׿>Y[e:<4&:$L(hZϫ=[I" #	fs^IVռW2eXf	ewxeͳ[oYWOpdxԅhU]p 4/@k`~Gi7\dp"FٯӀ@M9][O/^c
`B"blu\x/~WnLKpkk
GߋΏ@$_mt/%~y"n,AWaUۿ.>ˍS=oh0uCv?OCK~oov};yom<}߿=q#gW]5ν>cjo5XKn>oÏoW~G\"ӧz`ݕGVd
 }Eߓ"L	!Xq`{˪,4DVq>Ϋ R<#)mV6ĕQeqAȂE,L۶\Q=oM8K	MқVq,P7Z+RL܊=7 Z?ZɓZlb}ץ}8
T`i Np,-*^$.U_O	(pZqsJ+nC+XوZm_Xb6}2D_=cn=T(T>ѷԟRO;?.#n6qJH"q_aU)>cv_2p' *>>OJ5oa$S|'HG~m&eb/'v}Ɍ<7J_Ҏ:U nrCǆɗ4v xy]2]:
74?q/}3]׎i0xzryE*ēmE[uL$ =7#z9WgOyue}}	wY= 	c7c'-Ϙdd 	XI,cxm۔:*䣌N	hkpDuL[Bֆ 4l'{l*,au
:c|ӣ1`=8=2E`O^œ. lB ut9BxbM]mZ^a>L(A#L9&yȰO[R#?
x|_t 1<CHm<QC<O-+PWyG0,PI$V,hZ-kj!3 ̘O[B{6C밇*W0CdG䇯O!4y^T1}]̥βȳadT9pÑV[N~|;$9ZTc:xVs E )@J1sj'4 cVD`[iIs7=뺘 1t*/78
o^"P@Ih6
>xkz|A1f vaH^vBgq(t٢ͅ7az	b:] eQΔуx?}Qva Br9δlX?8qϡYDp9O
q)ZF<m<uqCz:<:.B(b_*<*!yLiߐQ>!8-o$>Dk'!dpL=*~̞.ԵEf/<y>v^ubDIO+>iHǻ	V N%&!u)pVy0b|D&>L?$j/6@MrGnzxwL(?V??v[9y^8}>W}ڛ}uLf<SC S&۟<"hP/f2¥& Q*rLq!ӒsУ$#$t&Sҷݑ:^޷]'4cٛF9{?WwGg}|O$}2i~y/>UPlxiB_ھr۾n+m>V-+|{}Cswm_wѯcǔc?1+bߵGowyom?_D|_4?OSܮ~m/>{߱}o_n?'~΄4_ѿonqۗ>~5Kay-^@Wݷov7%ȶ}mWݢ!":*BPt h/G?]Oy3+&aB>O0BApؕ&_tb	=/XܔP1Teݹw~ύƦI;aylI^aQ`CZ}2uv=w]_Otv]<qӵozaOZs|^\г\ߍ.xEz/<U`,zsox>hMʖŸs'B0u&LͱIОAuR;4ğ(h ȕ1|ׄFla'\)Z{m5dfV`5p`hU>٩Ӱ+B7ml'HSyx
,!Eފi{h$Oḵ	Ց#AxR6>%>1c,)ot2qasAycc2$!g"	s8~ݯxoG]Nb/S/fʈThĉVPKȧ(	4$ϼևF#02-یǴ0WAdfP\;~8fi]&\=h>f(p'1^&?b2Ivltb_j|~ў17$~=.7qCܤz2GtuIzpo*}>OԘg鄙uN^o/]85K&|'Ϝ {mPR*]lo%n~Sک7ܘCpnW(?ʎo:啅b׽=TG/P$u2w:Һ*ԚvTfW^kWne"V#1A-#KEvƏˠ}k1@῍+(nK:I#Ti~X*n=E*?eɎxT%ʷV;WC_-J%0b~2#S d l jƾ`]?4<wB nn'ۏz.Zg k|#^,>EYyQ#XGÆH :a
$ү&Duuv7t/Ogy鷟Ye3ة"Ye_||[J_c`[7T2SH6<*kް<#.(ySo"cV j4Py7%0U.ko~گ>}W=+7S>nXD"|M2D]CM34mH8!X]sl-7_VB61{ `܉\`:I !n)0	7:&!7
=&GV$+IѷY/	ϵi+h$hO()rjri=0H mNPe5eb(/q 4eC`~Ϋ>yX7wIKBq'D䘹l
 S\9&f{+~n:ZDjW0E@v	(nq.m"ϱSXHi7<r\H_nsjn]k$O|tIu]~ȷ= ^E5l'ZCH<_bftd66 -bKm'= `RrH.B%VQjRpHE\sG8}wcƫƦCaϿo0&8Fce3Inxn$)Wb_:s>6\:4p䆓ߦE6RigzcȾs+dQ/fN2L&q㶋l.f7MF`m+U2d!#4~:Vο۵_S3\	7k[):cBt\l9
pKj;&Ƌ&fh|0x&,2	V\4bn>Uߐ.>R
įy9>cq7t7<|]S=F@iئl5w=jyݼ/x"o0=UTSn_ŴZ5~h9n-EL[z-z9V'ҖiNl9W{`ˋ#-qNeڂ+`$׉O;9p17-Z
9B"zB&k}#&IT~9`d,;cO银L^4ґ?oT'녹|<J*z$mYlXf&0םh|Flw8R/J+pd|-B~sc?,л-LQ~M禾,202
]>ϑVBd'-|E:+!%Fn^q3GJ:7<FK.&=;A
էt~K۰@uyN~ʅ-tQM<!B'y_FUayo~7X}>Ag\{Ӷ{^P9xF:?)&&k9n_^<?q]3GWMBpb뱧LZ7))P>deUԺV:׾ļ3~Q~
V|zAbzHLS6Jixџ ^Թk6(U. d75ViKcmrvj´ie޻>&8ǴQ˶@Cp4ԯSmF{#DWk@EQKq`X@>c(7]FEU-P%dR"|b`g\N{NUV9L5jr6͜6ew+1봎$ =@Y&*U0E])ZlxN2Lx 	Ǚޭuu_7<EL([gaX _`$yl &(>dX 3YP3}ԀLUPaMa̅4Guܐ:>Fߑר1ה}0=^h?jT{Kce`Zʑǟ!?.ǉ:#$`aZ
w(4~F~6VSHeh։sQY(2PXQ}u;гQp e\ykٴ^|~^Ͳw$e}h?\Π	##D>V(H"9] IEٓv}bls<uc82=
ۺ]52KWe%S1˾]Qs=_0&L7rkyi>`}2/,}b!0mׇT+*9OAfq*H_0W&Uvf#oR8CZdiKw{J{^RKk?w7>D:8U''GxB* ˕O(0T FR6ZiV$	{17/F&s&'D ~ !'tѕR|Z.yoOS{[k|S`Wtp4PquOC+.t
@dd4\[	@ /5O0"!V:ôϻkmBɉpZ'}/vS+ EeK-KMghГa֋b`}Z!y;/ӭ,&O܍?'VuZ,Jb ۾pąbF~	p8!\Ź~ly&.7"@E( .7ɃivŢU׮s(o>W*䢏1}0Շqg"(纝OAFKU_n/b`>|7T_2wv d).:Xb]sђ.
DukN.A@ B!0G;Pe7ɶaf m	S[r?y?&r^6dɡ|U'j~ק3빹Ժ620E\]:~fOe%'c6\M.!XX<5~#1jХ_@kZ0atEԽC(RiOyg8$\`ZO[rQDa҃q\]3
5ӿFUW&>	W`ctI:/ɓf%ơǋR\TJ}Bt=Jl@Nb?yZK'+/$"b*>	}?!mȃ'wrI~ɟB3^ݮ)bY>vg_ї׋78ụ=gwέ^crҸ}?=(|+'BLiS	_$YhP67/tJmi6|ޡH:؁C{1hkBҗsa:~8{S2$Ս+VNctt! 0yI Z|&aMٗ6;Ŧrq|ǟ }'KQ眜T|pQQܦ! m`5w pLpҶ"N73uAX5@R!~U .\&c!nAXD_ M3/|GjW3*Nluo4aΠeAL;d|;F)s^V؜בBe-*Ϭ5DQcԹ*P~ªi'9Woi~d"U>~bpT10Y7q|(&2RШvnwJ 1P8Qw:=֩zEӨpfP1.9T~1GC̹bNBbi}Ps%8&k.nXܾ}?U5wf]0Y?k״7e^jW)M~~Zp 2G'S8云m =Ȏm#ENa~O4Ii-؇S&ƞ	dNg>0Pz搻q{>?R Y\%p]bڏ;[]8dA9c$]7~(?{?ZUeVcI+iʢ6o`1,7Owo>?M^z׾Kt9gG G!/);`G=j|Á;n`U>T;%,4'Ot8e@yl_2Ɏ;T`ºL?g<خp⊍ D`J&z1;Vz=;$VAW,,ޔqVp6ipnk*zXvaSÑXDVfI]*L	o^a^p֭DCԾ`r*I^aR!C6zK'ČIK
%j9̅,c}.eAN79ǼB3N~n_9X1?!v}*0]ಪ<JTӾɤTlϟLHF@}BWXe9"sQv;*"b\}Z,vL26a|5A6~F s%j;Nr2r09"i'*X 4P1e\N=6HHZ!l'Z~k'T  z3c -fSUu#5|Uf11Дc.!sɎ۾Z̼|C_w{m=ͣ<	s5ѱh$.
 !rFC`v^}ӆ2GN{ Bpا0e!62\P@]	ąWaF(s{ *;"ǻπy:O\Kxn$gOK<@N)v>بƩ[m@#6&`n}',b[/Ceq~
y'qwLFVnomwxK:\ `p{e!żiXD\UԬGurү(C4.Xb"tK-Jш^kӰLhO\
fXt-L"AD_b([n2&g{eɂ*Q v2N-䡯]ץǉP cXctm~ =YXC0|A?XycӢdȾDOGSd`]%VR%},p h7הJ82n'$-@{3/T\Q2>>UIeZ9l)9ve^I!3yl/1W(`L#yuvEo+T2(`x?96cUlA	ffLL+Pk?8H38|R`cIcLb˾ -땔!v K)秣qOrҀA0 9ZI֍drw\`b~,0J$ؤfmV|粷_B/zྐྵyE6oBiE-\tϓ(@_1{U^c{FyWilK{\}oiEv0ɴg᳗vb~a|
on@4s9&|
eCu]
A[N.\!nA)ī}T o87JDBC\CYގĒ/LcSofn|5;X+-.D\Gb_92 ?{}Ob#gpݰ8oI!sC}Fs|]ce#skwFUp8:o_6}?V(NuX&	NyNylhYEnç	R-Y@å# Aө`*k:ļ
};,(aCpRۮ|򓪆E*΃Z1|m_OVٗ :~mX.unPڲ@|Q	ִ6T|
5ǩk>o˝ի'm AdG|b mvp}۳6MM Tgj{8tx/䋷+!X>?+bd|qL$el*ׁex >/Xl\tcί3 GeiE.)!6L\`+28-ABMj(da?$S}rEQ?P+!1mPRd'& roi	7iwFynbzsuZ۝MǕWCӡтWBY1w;[GBV^A~Bh,ݴvIPeہ.ARt0_y%OYhg#N8m1qş eAI7#-yp'QPD?^+6qtC>c|r %WepA(U~Z8ƎSJtLñbdE6b$em*-uM.Jh@WeS]7"eeНtנpk<Lǐ:1W0~]]ѮH+Uf+\'E6$	ͽ}	󣇏|R_%_ƅO޵5܈ʯnN ((-/'h6}2Ax-rlh<i/7l	(lX~moܻݹu>byиD]s".wޑ>7y.B/XRm-sR|j7'ɽ
-!Ggs_8굜`d$ A z%V`;
!pX)2ѧi"zS&_tL1Kvb@ZyE!q l(&i@'=>$Y}0D΂X @3xM|{E35}%b%#0d^k K&Sԣ=ġ#;)aaIS];@!*(NR@ړ?su[Os/,'x}D$ɵm*2TQ,ϸͻ*_#0pɠ4:GzkrlE
&@G(1|xQ6\dkTPҹ_Ϡ%㽌LuJ8VG&hzi)$=
U9NZ
[v:ʒ0!ԩ0?sd]5s.4 s (#KӮJ\8px2-YMylG|I[8{0^Y/X#!nmggp.$';Gn<%{nmK_f'7M^>OAnU:U3jY>sN?h헜8~:h%mpT`;A%,tp"I!(RL/8a\sfqn\ϫc= k2Rn }2=Q-}bmPZ37v7΁s~Ma <[+оo}B9;/OS<Bm$:vV"
ECN}{Jv_uJ(LZ|}#`<<&8=T%֜w@B]3+~Ō'Rʾt=~J 1?'0}U<旫t6uXo:^^O~*4b`\8/ |"g+)=h<NK>b2Lt%uDUHE-I
 Jӱ/ 9CiޒE
qΎ?b
/מnW?j=崏$m @E.,va8gGݸ~c71m.dWU\J|~4oPn6ys^~7?X1m36j4ɺ^B(-u yn0'cqGp|_4XS7ܦYU >zurO2`PIl#,p^6 85r)6;!.uH,k7]"a#`$Hӫ}lk¥t lt@ʾ#	Hf24 pB lhR@1vIOALwyX_@h_}4̲m%_wH {&yT[cI0.b)ie
	HSZlhUO"نV2ӯMpJnYNN>0-^N/sXt0Ƌ6YMǞ7scbET3ra'
@zvNx-؟>|x<pV }lT/\t99"vKY+k]_xJu:l"u-ۨ;$?Y7ETr<Da؄W4 cTe=hωǏIrͷ@!e>^0!'4QDRoǯ gjd9Ф{mxb| 4G`8p5w҇V*Nώ[W>>]/~\ȁ]>XШ¡/<&rh0-B7b| /St$"R2
ZNL&$=yPJ逅<`7!
&&5yg^{عF_La/
P=GI^
mi0;YbWis?ďwEg>*Mf:8$ԤRE!/96	yb1~񂑯h"ZtHhXKo#ogkP4?W +)kK]u@>n"g$۹ɵ2d_j/eBsUP3w7n޹sSe~,BhO!%2${ AxBG#н)C2;m.&0^cGɘ/`RN3L
s\qɇ8RcO*>:N`BM?Q98<h{yPsWv}UrtQeKR+tT):_Gүrѯ s=\b=1q<V?]~E1{& @c@S&]w9H6БШi	lć`G+',.+~}s17Vˏv@5X=hg |Fb͠isx<uGrPaҀsuy`~~hG;/="~jyY(u:wW#:Mu-i>5Ƅ*1;7'Nkng>34
9O
eb[x@ǯ!lAMcѰL|<FV']ШP^-\4:rxa̂đIMN#Gʧl/߸mꃇ0EU!܍.ׂ_I_BÁKe:w$Ք'aK=It|{5xG@[,$470
FgJR:ʇj5z]gw\*]TKY=ic>0Gpv]b=i^ǌcqt> ѵdLF c|13N~ sՕyrRٟN,R>/Xnh!&5m`U:5cB9$rF4QG-6M?"%@	 {^zaׁ>ӈçʙR ~2^pB)^d̡k@N6鬬E!K{>L^vpIT>f4tpXi%hA[yjZ8 N-8z/1BXNKv5Zf毐D₣Ŧ8+MV>
MKg(IB H;xHC([@`$@9 bY+6ƱG(4!cLH;Cn7dEGz<Wzʫ?Rϟ>Eoh$t'W(?yr'"UsdIt~9?^W9um
-Q4g`>]l[ɠoH'v?$YbSwXLFD0[CodQGϷǏ~L{~MPfmONucKFOR,2ZӉ܇kOL>idc6;èuC
Xvts{~B.R r;ܮ*/Z(0
O3^( ic)36dd4tAP.GJ8eY`(,%g]RSu8syP9!Bǵ2x 
O ovBoNNeq'~(	ept-O\)gH \ 9jf".B#XbSژL:(zO)V TUr֋ɚ*<blQ14R1#G2Z<~r!ڢX9б|En=#.n>۞+Ó\+>}-QF~HW/Ex5G3va˪:wu;?䇒=<lA!>@8ae{lǥ0=}3hk|*L M}z<B2>a.B!Oei%<
1rΞyUZ ttǍ87+j;O|ÈE>);} oPBٝcǬe7C~c{:ڳ[G6cN صKb|Gnk-i7Ac1j+7!$C`M/[촕yGCuȡnNwG,M̜_+䗼3?D'͡#W}X4O}HUq\جʒ5#WK|vMm>J=	.mb3c'[;q A~̤W_{(̥tG֊wY[вSvq0TxT\تXu
J<_Yt^722ҍNA"<aXr,oăʽʣU9v;#~@vL(pRbUF'_!^LjclsvX%N[m31t&Fd~P7]mI&D#X+6PJI$6kւAK+OmWGHMTazJ$c :xMbDGxl)Jd+l/)Ah.C:"#aNBO7+ss'F:)LwѧH@D ]' ׭ ;{h/0Y"Yϱ8޸`AOpGν7`kZX!i}̜:X<lz3"c1'bkFwi9TOSufق;|:_cӲg/

SrhΡz/Z _ZaԢrL
Z\p|U}v|)+CHhWuԸ&-^j.Bhc!.@4-3WV/ ,Yq)?0&6sjUNL^kZ2g9&RYb[tFUh;}tzQX[eҧ"cn0q"st,P6J'- pSq®йs/1A[|Gi8=('䔎Et?$_?B.`'p6&M߲<Y(rWb@wNg7o)r{uix8;6^ǚ~Zj`%|"^r/6GҒ_)M<aߑIv='PƔj3"q'(ԓPǻ9}39h&WS!Yo@̇EpX-՟g"d
jO1i<#!y\dt_>BmN^C`xcNrw}⃃7v@Ԑ;$2Z"ޚQsrQOR#Q<J{ЄBʷ2DӔ5?=cj~rn*5KWe[2F
x 0`xL]"!}:Bio׍LFxx`PUZu  ޸>KԸ;Ċԗ24:yJH1>es U|۬'raGA7M87^ 	/z`t*RLs<[&'5CWVZg j7oqfn4)o!`<=A/l@gP`e'-~V0FߖxGm%ڜ3oQ4 |o9it.)3[{0	{noBθ\OrC)7z ?yBN(Oz[D6EOjo\ Oo}*2Xi%L۟QWLH#_whzK~LKhG7>I&	?SfR
s6!cRusJ[#ca>=_IC#]E_!H{i$}}&O"t3t=_	n^&eo %(C>ɮ%>L|.{@
¼̘rY<@؆mqUmHr~i:VO0.sƯ(;>sf;Pb>.0!	OdN*/^e`T״T'-ŠvrX(qLL?-E&b =\dqdlԶI+Kd?dꛆgw3lA[V<`D`n uCMSzj&+fXIg'^<*Կ% 3bf$SmH:GH HRS9D߿|m>۵-5b
ΡL_iMhQ!-1],nRUA >X1_;g3~ w| -G?dF(/yM_\`" k`lhe<Rϙ@E&~/r>]K\AVXiGs9ɰ
CKK>+^_KdmS!jK6ЅRGF)?:>Qh@SH)p+Z^$'*}T f'I :n8_	xpQ
u4J.z]\`,dT}HZ"rљgݦ2N'N0TG¡{ί3-u4   \4Jx  IDATG~烀Fմ5)A 4(H)}é~	|h㤁=]~ƻU!iIH9(ME{XpҤSYNAЯ8ՕiBL#:Zhv^zFm+J[rH[cQɗ/ P8ydܹ-@W|s	q[uSOܐò<Ȁoz6$b @.$]B:ĉ"\vIbedS\G ;RnT	cr 8>S9dc gcmZ	>E`ʡ*4c[LWc6R+{=滃)2-"ђYC:n7H/JUmhDup:21N\+.'soy1Ch+`x=)5ݶ4ìpsqũpZr^Qf,5`AmmBSZ/6rnzCFy*e$527P^<r%EIb*7p!V}wMʊꓭp(WLzhigsPf"P>fK/"+Ԯj]&Z87j%	AT^s+Nu*C=؂hiM'/TL#ԘbnS#6/2ο -Bsӈoͧ6y׳J/S!xKN.NP#[k{h [%
t"y\b3C:OhQȼ9Imq^0J<y`]:}Ȱ0*4c44 [biSmƉYgCT֜ПF7|'҂kͣ~d[C<&a=csqe37q/"fd9B7$K^R{	%}ђ=\]GA?ELZ F>N&y	Zz6ْ#.(ڗ@2YE(u͞ߩ?|&Ela:dn\	#n'T}̡ٯC?C~|	4ʍ[F}>͹s_굋KUv |`H.7icF>Kj3{}27ͼq:#ټ}V2e}W4rЁ'DS	Ę??/Ꮭ7s"_p`MItfX+tM8~o&S
̅ltr˶02r3F;dDaX~&y+tw3ׅ,M	蕴H{tcub/ru΃qQ. ݎ!pRIf~ł#\hמ	bA*6!lYxJbj_$i~7>g{s>oܯi6[!V &/e	=q}UȃdKgAAДL'EtlEY4-IZ*m$X</A
^h'dJKv̈́|ϟ@^й9_'OSh=AO}UW,`Zm z_|巖yB/_JN&2QoўCKP/t:Y Z,;ɏY#>f&΅=ҋ
 = ȼ_M7.⠫U\Д&x4&(N>Zd;jH;s<sG-(61-2qli	ʮ0yvv}{w;t6"崅nFMM[!0φM}Yvh<P~@)hUyR14Qf qva<uq=P滍a5mwH#묛n`ӲV1
[XdcinҌM%cee?I9qaaْG>L۾a«i|MO0xs{(n0a#6=2ILz$><ȯ'Ogʇ.4U2eMBYSywەCQ:dni/+}|f"|vJsW]ZBJn7x^mrMp&.wS'tt+m8}@Z2@kSXɚF!9sZz]YV!"x*SʷNxrTL)ylrt:mMe7V/ޑmS=ˆ͙t
=Be'#RD ح׌}`*_9GS~!*&Zf1	$?w2LAʑ&x?QH<`G D|`;cojX-#БFFJSGU'xS'.,0eNp
ù=j9AWsTt`R`1pw QqVX;:us7?bν"BbcB;J\c}!pS(OifxO-sH<yq2z*4 T7!S'N~6m4
]cLfp?$yG9B$^XjcX7bAQPCn@0Aҋ$:Xm{U/@:Ju
Kdy'XsxG'W飺qlF}їujo¼oxO~#1|<f)%edL^oJN6Gdijwc*%Lvh?+	yA{X:G w?~tȄ|\w
\ o7Z|)	AqX$_`߈+gnBY7qίD$fMɀV|ڛv$A#Otwq{;e~?ͦ6.h6L'y K% Ċ(u<jq0U>ۤr
.}%bY_-}Q,K:R};p2չK|}+Oh[J&=ՠ;w}?]!ڄJX}/wړeR4bɜkh@<}vncU&UiK2JDH
^M"q 9:;8<Z]M'Enqw{y$6Mo%uZ ʾ,&bI-fBDjk53/%y؆ڔ_>ħWjXpʃO?^⫣q}]L6L]賳"K.|dNH(/&.Ե?<Q&_Oȡ8=4k"+`ͲML{Җbn\niL޹wz\P{|+zsN"G(W#HVBy_ɆR=yp=VL\Ћ &n(IL)M	#
TD̍7_ܫMml`Y>]'$syL\@)yt߃*:_kICс ;mdJDb56#TÞ]x%|YWtVvڕaWWk<Qkh#X%#v$a-$	~N}Y{cuquj@?qZH}$>6O	\!h޼<|
uy
vNX+h4TB`uHZb!MQw}Þe.: c"Wc f-/Ύ!:]| |>U qaB9~P}[Zx sB^'NXle+DNʘB7՗o?Mn<S~6w8ac}b/ǫnwޑ3#ſ!;h-g\t82rqb꽀|bۣtioyP6Z6&o;۽(	Z>1.޹}65czdcZHAxOx9EǤ?+vXI&V`ԅJ1KbMa/bk)NA9VvE_"C!?N=Q99MVuy q׹c^c/ܟJBq"G@>W,y+.=SxwVSVUnCzO#P"OStT1|#Ld9=)!2OA؂H_ *u$H}9c{،Dl$PVX(PNb)n٨ZcHs@.>=I)TY<y#z:ӃFJ{lK1?#폄ݼs{
{SS2s7R6$B؋M;$wM3IzAs1Q㬝tEP7+pLqlRIƑEIж	ŹȬΊPH)6͹Cc<k.x/'nSg[P} b$#V;>2)/l5}͑_Y+}M$C,z?qqeiuYzbɘn@d%_SVzY׶s?Ys7r9?g ~J>XA@43\ӽuTe?[}_࣢w > }7^/7I*[ONݼvU[;SA^iypekwsv VSxIDcb#{.XLyk+@>i#nC1杧O}Du=\g7ҵwzl B瓼@Fjc~
D#@:R_ē!9exl Am:usO`*6n0?êcT@hpb#⟓ِ@{iW?=X-.|)wlXp8W&E:S|+7g] 3YUk=W3(ȏa`'0y]-1R
;!Ov^bf|d	ff<zHn-:5].ԝ]hk_poF;Lmkl_}kPj>65)7}YܷU{M Уsf\ɾlQcH^/Sf.Oy3ž@.:7|$i_;onB/8t{$_XJ;C1:֓1d7GeCƞ<x=fG7́'c`ozW}/r? x@3m	KT!ﾠ42sLq@7fG,OT]x\\t;M~_UbZ(:Il`73+(U>ꥉE[7|`v@zi#F~Ƭ3'cm橝9ՕȖ-d$cG%r,s(r ~y[5R~ve;5CY'b!(˒nh9*rLإp="1~Y.Y42ꔴif|fpQ8\'n?dEO2?@i.1Pu^PlbA	euIc3k.'Kq[N/g7eO\C_>|-ߘӹ&'aΛ-r_T+MkOMcs25_rqrP'nWe𙛸XOLc<|쮻%Ᏼ=>z=R]?(®w~=ί7Tw|M=-9/~㓮<"| ToK:ݑ:m;T.Dedm&`z{ ;<֧سezG!	ś|Qm0y#.OO_i{lK#:cNM`)2qH;&@#foCGfAR.=U$k<WŌ1D/{q#}nk>U'D:ǝ-oP	6 oU=2%j_N]H-_@訾P%{dmX5@/|"^7|yx&A4"-S0@5.K`:r=~*(uon-fenŦꔚCnn!L 6%nf:z7IEJB:XZv_Mnj"^P|d+W0ۋ5O+Ff7AkeEd&.ϟ<۞<z=ڀv51|, m\K/8.(	jhFYm]"eC9ey_M/w~"r31mmdHDb+"(ݶ	PfڒdP1ړW9&fd|.Geܾ\ݷRvcVj].|m `ҜAN%C~Ŝ#s+'s:e(=Y;͏.[KtcYi/fn]n[ud)ߕOì@%*XE.?Ώ_)?3d|}ӔyMrNqs{9ʦvFt`-v$F~E둹dV"Gɑ@ *Ebʼ`O5xw(sy+Qh+#j3}9/L8ԏ/^R/n?_Cδ@pːNFE3Kë i|ntf@WG?@5mh0i@QG bSqoNP_G!::GlؠrrDD']7SKh.+ C:@~]B(cEe@B:KCUĐJB `Tɉzd;)hK`ǃq"\	x<@n}GiFtm_ɍC?TՇy("cCp׫|zkYv>o}b6\ lqͤ#	J<ohJyE^>0mj}k34c<L׹+|?Kpa@wbMh~$é //bwS̹)_{Rv໴Ziݷ#j $#5ɲt,
hŻE?:o]R=l5ɆMkا=C=4msFɆ/v6eh$9	*mW}:R|g%yɔy
z-P 6=dҦY Il@h0W&A#N(H5eff<G}l=Vs!G"_H_#2Jz28|Od7ZN{Q=$1d٭ 	uӉݻ;?Ļ}䏿syQlalu1=vvOrr\E+\|#[>0[@=-{eʂ,:R_5xUTr0oxR_a?9IrY9":JxAgg$~yEBqnG,8]VAeU2:Rn1ݽsuM.K*J%)]vC v!/</>x @n
CyMv_0όTޣ7@?oԕo8J-k:
竘7'ݏ[&Uk江 =E	DF,ฝj"S|ȿĩսߵ%.>]]e(7&Dm)}eaɠ0xM7ĞdhM+o<KM
]w(/-G-̂ܿLÊa^`\4ȏVb:I[	UTS;Mo91q2.cĤ~e|\YWx='OkkyRə+z0^(nG=O3&<BIZI4x#2\!S2K #^p\浮c/b:H}7?$A}ʠ9EX৚O"27st_#K\8v{|	O2Q&O>Sؿ9췸kks OQlΔVgN9,eyyoB_>FU44ӭ[]!Kxݎ3@[DE*\g/>&rU,{-GMxBdĒ_^=HW_tأ>;He# nz!+c6= /'͏d[{{|lB!P¬3D92n釧0jـdgaH:!Qk?4ƑsF z3BM<u(B1I@s~Sl_C짃x8q^'<fY#Ƿ"N{(sH1krQ|l?VY8(m
Ltă8SN}fŝxiB
?]--UTIƀ	i`	H	pbଆF+?iu
-Ft"L#;S9PO'I5K4ZM[SBnU'.3p0A$[=z,fht9[JAVw$9N_g0=J´L.<iHSzpMꂕ]GH)B6Lsr7ӱL&!-&6t(/@ mlFljopҾ3 B@:YIw c@w2>7ƙq- ONMhp$obmdy¾!gRFlڋü& `Ux>Y2Òr9*̽,RnMn^pUfAU,x@O7ԛ/bjLO7"}#֔IEwEa.Kȗ_	SfبNTԡ+YBKsJAeC6YǋmJON6SiQLɧ-O3k3<QmU̶s=&U7\&xPcSܯVS^JNOWQ?}+P+Pl8-gR?}^J@ד^!VdXqI^k'dTA=E2|LS@2Kn07iVp=?;K˶ToߺuHm߸,\utm?QēID_xZ3/sɹ	
.xR'L5ˍ_)j##Pa]uMP_*}c:|"DW
~Qm@ 's<QnK{.#)H/c1J;N.2oMNd'Ư 
V/V+;BHTE.t7ݾvޓyхc<pPzeQ7;?:b7bE4)9 p̊䉽6C$;TwQA"ʨ u(ttvW&oDw~SOMhދopZf訹mQ@M\QMp_f=@49*KjPq)u4`IsYM-GK<Ɠ	[x|0RO'FxaF7}3_cq'K_?и9ϕfs_m]unQOKR)E#Rm(YԂ5j] ׬`r=J	n1G p2yE
l.шl9E9[kg._7/^hTy6R&uV9_+1##ybnѼytRhu.iu*~e'o!Ƒo\-1}ءaY[;^n\h|%{	N7ʫcCtYs7|#XUH8I*$I;n*/'>G'7.GVMH;:LCJg>Iv\φ}Y/a	dnel:T$!'+_;6>ǜ*;wOg r_%/ch{B;0#V^t;7`ٷӆoBOYcU}8ȁS\oNSAE8T;T~#s'|V<x^fKޥ:bqt
sͱb W74mOn0G~AvN|.-HQXwa+eHp<:'t #@$,dc,ڸЍZwV4~Z݌ (}r_鈸̈́؛h!RWlC- 3q>@PLbuj iAP@r*ȀU*n lĨ&Jy$FnJmkrE8	8O1W.aOLRV02& QNɞ5@M;z%3G,O-_e;5Kƛ(x%^3C۵JPN!|Fn@h
dY7o&,/-rO5VmK''
<SL"?	&Jf=XڎuzAK\98|M? 1uL|+Ջ>y~=B7?5'xrA_ߴal6Gd|7'j;[:Ԓ>8w<=eP:bo#)]VBg3zT%Ŋw/9̝%[{6tzm8_}D@sN,I]ٞs!%4Kp%W C@uO_fL0G@,XV"׶FZ)zb\Wx.{;I~`K>i
O<.?*l487&%ҦM ,P]@Nș9r@1͠W}.<?tR?/s׃v!qo$7=~WL	$7x"La%m|Bwԃo8YBe%OTuYDN.-;_S~M ,n 1l m$sI`0kO;\̠޽r_ܬQ.GC20OةSq(u?Ke+J,V=\7yNij<('|i)ڀ&(bCUPqA~-bX^Hrڢ/Rt_yٿF.]lH1+j5 ̣8dʍoXi(XDv8VӜ@4gj0NZ>r$JE^&!0R #T9td xCO|Ӎ+wXrK$2|lХ0I|C!OL{PЏ0;)
X[_MTL55	fd<
YU\uk31_n0?۬#@gc㖼U=#Kv)Zl2zCfO^bh}}hW08	oS!\pbEōNB%56{{7b`ˍwHvɥ%1_/ !vin\b2g?T!km(JP{SoD
c]99շU`nlVQ7c'	S $,# %k.7{<ك7ఊYT"}O(җXi\МeT9mz\Ry,Ҝyҍ,{\?Oq͙*F;3-{2f5h4Rs_T?ξJ}:}>v'S\$:vZ%9pO젺~V<67d'eg0ninļeȏvy7Ðvu47h+q04GSGwS댩_BH-1Pa:>6G^D΃4S
Dqrir4 iL?<$
' r,DǨt1?ZԔ C4J*LDG8h,aw_Bk;#h_b7D痥i>M_v*~88.vK`%YQgtttQNQ0 "qMkrC-Я >N6΄4̿`hiE)_	"jP|XP?[
6%oiXN/4',ȼ2&_:)mzO_&C| (dmr 0Cv|N5_ <sm,r;J_bW%^-ZP禒2}''o*<ŒeIzb浐3FrB%̀~?}@ү{,U&nSvmK\ZY᲼
z:r	û/@٨^3ؙ C{	A,ؠmI-<'? z.
NOb'&cKEJ^$Ҟ_u^cSѹ7'ȫ^lh׸uѸVF؄[A	Ұ;nbA;CՆ	WxX	2CpRvaQ`[B4bl%£G]i/J°r*G<.3ɵԔ}T\)c$'Y?>qn@H? E>Q#*ʻؙmZ<Ҍa;?ȗW<䆑^1O"54b<y悿zͅO(>r+PǾ+sG]89H9&78k`GV
fKܷϴ7ϯ:qõf4'^`S`=s`N `gR/`N+if?*aUb.U%nttC(K20_T0db9 6uY"`P&CCs,DRi۬yIs+?kA<n0{>]x,V4:bAP:8Tek52G93PO̍؍-_dF]Kf$8Q!!=\㰬w\#5$@Gm{ɗgƧ@مې:6}*@ٝrˎx˸Kx!@p*=^ʗw[wO>*
_W|1{52Kw7>%ЃүdzB̍	iLwoJ]{$1z|+nsU?Vw\AHƺ8y\!α-u>I| ?`\kpVdY.d2HP<d1ҦqQ<Ol(b߈}}>qAKvK
ސzC_NGuH.He<;8+yQTd`&ɟ2Q5Fy9g<oDrKXb::,wb> {m`&`o/K7rS7P$/ry-i?uFs zB;3/R_afG7GЧ%hz8LU*6о+Vk&rsew8Q.w1iJsZ?+zy
>/_jkyM;7}\̞i?p(Ǵ`HA Ɖc'2gi1>@veL88>
\OSK* k'$'EH'scqn
ބ	y>ުʇ>уțl׼@r鴙{"+@x{R 8)%w5e[bIyqtܒ= .(zK*C-
^\@ڴ#!xST벪!䦂gpNa׆G}+|$pw{yZj i&&`JN~D%aR4eMxJ'1bJR&UH^͟ls2C-T޺J٢Cegrk!|;} x:+DqR`&}:nz9~ey7IuhRvOs,4y@d<,M67xDOB<M\N^uR=;㙦:/yEdfCTdc({DE7c 
!.U#$*EҤ*}^\P]6`g1$V:CIY<"O=[vq>hp<b]#Qx8m͋@V`OY&s!sW编]<onQ|;vyr@Hm"ƧХqɜtɦ'y1Gݎ|6g}3?Ԃ 쏏&t.l- c. >QŦ_4 Mϑ*O0a1=dur'~"Ar^kAWost[y'{ʧ/fc*]p|_=5HɑI>>yT9bBeNW@&6Wʹi|׎ۭ[\$?J&eAhJ3+rC!3'R4V61ii	-lցXAP1?ܐK=[r
 <Vh%.]lg/gћ)ڴ8 &+F̐.z@$eF<˒hn^XWZբf/e줼>5+DLM9zi@W5kup㽒}4V}Q}i TH$Hz@LQhn<ޫ#`u0NN\WD`'Ѯ
D8>8Jp dlaCзP0ܼ@ȧ}Sj \y-h5y.Bs¹y淋ν{Oz/~K9#>{G<ƹ/^k`<Ta:|d#\8@q{{zF7A`Z+.c76	\a因-2si9 (lz1m}u?7"
)睗5-|7ȃpњcSs(e"\>2-L]>yYC pc6pJG{%|s9l,"&fPC_Ì#8\"7QƓIUh_Ӟ<ANTZ
y)vIuΦCa ]D+[C
m9#O7s#>>܀HeL7ږ $$kE7Fxzoo~Dj#G<R,29
|CO Lh_)Wغwv:[k
N[Vߒǯ1hb>W<+^?@%GP	?%1#_Pu[Vkl7|YsqݒBהclCg,y&o+.nr;V%ÚVׂ2xgDWbCPZ ZЖd.BtN0P<٩a`Й]/
ݬ>΁a  HG"'\ڝ1Pl˦X{\./dCe7D1P$/P:'zzl/% ΢"L]C^Mm6I|A2+QQ80,M@>6[N_~w?|`-+ M	yl;dӾ0 :ir/ثH],+/Jx:U1g9[Cya](m'*43i+M-Q<oϹ_i#)%]	\A6hn̓olLRaWВљPne@e~X$~B1gsf\qvwu.p}6``thbCJ$̙}i}GUTq"hё5n&K%	J4Utl9PUOb\v)Hw8azvu5N8m:OuIUty6h~`a=s-x/9KmGdwz+&]:#.$mV|HmA?t2enmx$=B@zt	;)VaLH,DgiD0_Nb8#eEy/\`fQ{SOKP2]*7Q=|A=מO]-fPO>׉*|X*/C۶̿k=;_2_DJç|z,!7'W?i:[_ ?=j˗5~
	<o/ ?HWϟ<=/e#6Zm]}Nua1':9tЏ.jH3Xc&U0`:rb@Ps>~\:	̓% _kI	=ϵ|;_ H^N-]p6rr[T*	4ɢVPaA:uO(:}¦|Q'c;^@>mUPj·#(~zG%* <v;N#ҰxY`'@f'هD6&\6%/$JX^[JYR$/@\|z~%{mƪ8+?]v=%O0'xݨO|CT
i[*bicN'`iJL	SPp$n,qW.u\IX>1lW_PZk>+Y"b|fmPX8'<nJ
~_	^-|Orp]ٳyz?%dާNO[C~,}+P!v 
Nw
æ3*~R^et .Z
vl쮟yt
I<U7Zߣbk5aYxG*,UuEc	_u3q(S>%uIؙHDBr+=jSuoy/+;{4ʇ~{QW_Ҕ>ɥp#lfO\a\'Xs(V]Ƶ?/*A@;'PaWzW7i_:w})hGa2Q똲:&v%OvMDC>R9xaHr+Uh݇:P|3 ӟhlab1Y]({!+q?#84TzyN {.w<pM#>8vc\ Nz'g8ի,\_.WEߖzU#@A	 '  a@?y.?Q(JiBtZLҝEEBzqz%xBJ9@cB^ oMp59|Lr4\'HȴVk0m  P9:rs'Ă`.˄0.&!2\~t2]uEtYY:OHFtƖm7`Fl7sLn!s}۾=6F"RmM<Ɓ)ԣ;_%HgCO]$i[6<3^6)S3s(L3e% X0NHpC}<VN_&d/b"vq8%3lN=W+
&pj(KeĀ爲uP
+	>.b%X撾`3rBT(	c*jyqk;<y>B6ҴUR$,MÖ7(šw:B{	H1:/Q6͋'u)CK  "OзJ%	]}DōG'H0I/A^q]C-d$ugbYp^"vk 7:O[z-N m?:1OAcF:l$\?7bM=q/ fo
~:VN9O ?	|NO </6%.C9|G<0nac:g&)x 8%ߕsC<1VynyH~%"p2<F=lGnQnWp|%<Oe10mly&<rfw{)}zm[ĩH5Ÿ+߾M 6z+-Ԓg$c40ON}zA: >Pt竏2o-feAy/w~L	"M9iq,,@&p'iIǙ'©<t'Kb, .RUgstLD:8}D6*BB؛2KOw5$iy=6m; 5Mj0/J^BZ!v)B /ݺ1W7=(ѮrǄyq	&U@łA2	cC,4%f*6Jh<qχQ8<
:Ut uf3fYVHa|878c=vD#Bo.6CX'<$)7!?oTfϘv S	C'k?Owcnp/`1Fh%u\踀`]~1NV>$.Pt\L_[kHTz	Db<J>Ǹ|R<U0*^I{S}=پVoB2K}~H^#B>C
$gK~M,)K-O##zliJ2<aaC~~0U/ɇ1IT5Y>jCKܔaDAҔp2{xomWU^7H6ԏV#
3*/
YN_S.Cn	ۺQ<K%#p
R@mDI}OIG 2#XvP:(ӞŴo_Қ#`U`:S(?PONɆIm,NY^mIJ?e9N[sMxIE炋|QhM0`dFg*`#G6.pm:ekW,8EB{xY|j%=1SEYq:&LaʬQ]y=A._h#MMOth	pqnBтb i,s0Wr9I^uhffVtC`9}D)G[3p
|z:	}`aLxq4?mk`OTTt䳇:'dYâl0J-v/S`2؈h3W&భΘSgQV6"HUSGU&Am♝ʰS=!W0kncÕRcĦEvj^uH'׌n>@;/Ra h3;
`!~oo/8~$xw&
ԂҌw:4Zhٕ	Ktr'av>-hZFNy6W_NvZ"8K@soN$kӗXGW;$=#3E~Z4()}9Q_NsYdz'ۤrF<W|:cD+KG&R챹 lŌ#/&(#
p ӈB%ͭy{]/__B	Уo9O~[noxjM^r&]|HTꚼ72tl6%r|(B.cLaϢ-4Bs ]b|1 ]g٢A(ȿg5)#_u+@M87̣rN.w]њʹK}:@ȳJRN'H*L;jy)X	Yˠߣ	Gh}SKιS@k#m'0jMO.([S	n/(?&+|L@'^5;"mJabKU`{<h]ݹ)=aTn`
 >*21kjZe4.x	=ՂA:&_׺SFowݽ;?:ԭ[a}S	;}9ʹg'ۣ	?=K:x2
x^.v+? xBVC`i4D\gAyaLYTtXVt
0|{d}uD;'p$OՓs.ҹ[ƅf셸7+ط]i7q~$ޓ`LoT+v_#Ħ'7_')lXi>,02b2&JR&X47MPeu=U쯝vVo/ҁE#iLГܙ;wnw߿/vKsMs=l'}]un})mrۥr5a/[o1-CibV5i:`:ؤB?`OSMtUݯCkʫ!jL;0{`S.]pY|.I4t tOGCO7>%t񬪞<1Yi0,QFp%GO҄+p]f`wLZt|F9%ˤ|S۔F8Glt \0N"tKp]Nܡ\KgPh4XdS5ŭuBl@Ld=+Ww݃[sKǘC ;+J<u(þ2dFZc	$_%e'H\jꞱi1x@d]iEBrU/ %9m?Lmhs3.~5d YұT972 bTAen&CXK%mis.[>](AT-nC3>)Ktoa	n.\xOjrY\NN= )bjzcpkiґr؎AblxBJAcK8т]pѫij%|B96¬c7/Pi\I!3mB(!G7-kR{+%0=Ri8w~M4r$Ԁя]>u!=%1Sl![{gIg<7]8:{Tt9>78OI]zOs (SO֠b?HΏWDr(_'l2 7R&|lS9_K'Ç\D{Aۣc8G?>޻ݿw>Qvdi5hm~ɋ,-~Tx
i9_+6d%o`{F`aZ1J;/X SiZt!U\977&~E~znQ׋Ig"`~U9(d,K('۾ _ɺCS^ykt{oYaNT4I<U'-ڍ@ncAeXF1~n"D"xVRh)Uv%0
ce	8֡՚XŇ8NM-hm#ٲ2q>]\̇:L=:5갥J;QWNCCS/Rdk@q0$gC:[qܜ%v|_n#{xLrvBܹ}{sGnݖ|^%S,]2oIG½oi|_@7}suOp:
}ޓX:|It`M)a?c<kz-ݖogZwyEjZ"*uxO8uj$|%Zzw1HW01تb$Wu!KטWZ¹NVG*em3)=z%q)2uCxߠWr4JMQ3+ؖx|
IL nYyKރ>Yn0p}OqHL?<oO{GY9$zhRN 7ڹu@;uY:뛼' 2z㼒>&	'Nr!q	ҎO	}È6<NզM[G\B5WzKemN~ cn)p?iFu&s$e"9(UԻpKQA5yr9CCoYv<,Wic~
'D	x:i!l2kY&Lŕ]]MIgй *1ЙwW}#6'oSSj -u<a~E(45&./n4&:A#R]ǺȻ3?LX1sJJݤUdTS?[# YąNIH#3ɞoZZ6]cʊaoK`8:_$;eEW*8#ޒԡڢ'(K/:r+cbp*˱~%o1 W#@7쳰`&J~;('SY0ßJľ$z>-{JG`LqS`B\$2-*nZiQh=UjQׁo<aa?`>ܐg<#=*W.By} N~
oJ
(v(*`^ WQ̫l<$A=Oq	/`rPlbu8)%De8v5KPSWQ.."|̓|(S1*{-VׁEk9klPLR<iӥ9(g&E)fn1ÈoNۮd^@C鲙	=tHQ{ox.Na}X;N0xћTʎMX<ےFiDH#u89`'<<ddۜpYb>9W}rywH|xΟ䚓Nd঄OKb.>6b#'|R4/[zcrfm$FRBOШ#ѼXGKi)idh	Lecn1eqιn61'P>ޟx/mo?㵺*O:gU[sҸ ۼ﹯2.>|7~X_s)ŝ3įcerϯȣ\gd &i%=Flg:[/6xѵs/ncl`c7BkMoQkμ/?{X3*dXuy&퀾!CP~,$mYo8;%d'F+de+T(_$M'*Hf@WAJL$^AG0#J}TwVBQ_~P}yW@_7~C0pbheC2?xPП-ԓ@Ĳ㹕NɖUj;"zĻNvN].n
T/jM_~(bAzdL㷽^˴bF\O܁ׯTAI]<r1֜ꒊ?=oݾ߼+ <~\fng?BLN'+UWy1@
o\`
rPbVJBa]{]'kI	<xpӇW/UD˾sC:ϓBgDC;}ad۝'}*ĐkTr>,?o<OK:܌vOȵ:B]c}C~,:*rL8DRԃK{mgc޿ ]w}ss_Ȓ 6Q`"	PqwQ<rT0*HLABtFI;mH6jYֽ?Zs}sumk9cXk5zd0Kɶ*6+)3z^sXp;_˨fp9f8uB+b3t	)nr.9 Wq\ӯۥo%$n	ުV4N,ZmL84`f.E3q^TrWqN }Jz)j
`6op=aߋy`
?@FKE{ǉ70HaA>֝Rug\`wӐw~rS2c7۾tcЅ=<04bL³FݾhǛ0	i(a+O-@bM#ʲKTЀ|C@:(g6Lrc@>l|jʢ/6]
gs>Q04x;:̪nPȮ$gO;.DgӎhfYu/)W|u۵J8:*{ wJ
:h\wA:hII@qf@.u:2@a3g;uQa&tLE@0^M66NGℵ<`q$;=b_[Uw4]WYv́E6XuO87-%ބfIcp`TC[Y@@f7)S +QQg4}*޾0m`K*?(gWXٳUMaE,KSGV'ͷ28iވy(18iޚZ8T
o7'<ŸЮMHXK}Zjϝ&^K(_;t_ItaV6'")O D~+aҹcX0⌇㠂2)pqIu:fblgR  ~xH/=Γ: GS|(؁<ʇw|R^[.i/EGꊋW?}H`]!ĆڴHL^t-ߡu e.S\%O{\;<=}d,lG)PA:/hG|joQgk :6gU?*8^ZVifld!jYjeZ3hpRl=~ER4w@w'vŃ"\za`}扼'HDF!Ǥ촊:fAVIyj#L:xt|\Gq҇-+3:s]h]u@>4MK-0}ΐbֆY·hOdxƱ܂ZKT1A#yFy?WB*CXmNihFw{┷ܴ3w;2e ^T90?eӬ~%.^D<ud҈z-97\35Oys樅"nB#9O߾}{}綟Bu<,O@xnL<a񄅿sls_"Ǿ7ȃ	fŹYa7O-~W2&,&0.!Cj|u:P=VMy}>t~anAsC9YTvLճ+sSEu%wmpXӨ/KPցȘkfjObvrIiOՏ#~d2˘:ʿhCUf&ml9} q34Nk	^z]U94f6ziЁy8ZgOOrd1Hy(Zbq9ײ8B.O:ߥX>E%]%''s(Iۇvan@:Z>n?QVuK_$G:r,R.9'FEQ@3OӶIOqTG}SV]h1d($m0Ź帎<#oߵ2a$RFQKEil(,p;%92jJ Læuٕ+8q3e=9`4'*̙9dm}݀(-n %*Q[-É}rPaC76 NBa3pmu0B;trХݦp88QJ2>0 "]1ɟ>ł#k1#ϹRubhq+-6,ڌCTd/(z:	 IluzVˀBq2IJa&X:Y4Zyp>x֝у
;d]btXyD<٠-RsFJ˷{Nglk`AqAp'6`&t`ht>`%5K66|Am,Qv}͓AY!Ay:\ʟgVٹ +9Z&nYFc:ה}tR|NtVxE֊¸8H?5;H 0@`RlIs> a@Rwc/枍6}Ĭ|wKܪK.xє$~O"̙c>tt{s'b
.57yP4KY0(qc7ߜI5_&j<c&s]CWԑ/?qQGޣQ9W>KvKh}'NK۲xq](ql?kRfp.sy,8^dɃ1
\u,ڣzh;2 x͛;ɠ3%Dx˄VEWUy31ʍz[} oOf'
t"WLhuuLݻ{lSI	<9$L@uу<ogk%P]WJlՏo0kY\Y?镗ozRq|K//iՇW;wMn.<wܝ`'TLj^8бZИ֭۲)c0 oPILP`8/&yx"i/1!Dw@AP<qOq{m)-etr4׭tЈpNn6RVmd01ea¾}(mKh/BES>}µUY)'~|[6b<A6/j{.}>I}6-Huu{7'')G^9wa/._8s")NqS<:7=͟O]{xwg}m|
,E&jxKtcAlBmmB3k'ucl}&?q7(=^!6'ֵ̡kHCG &%:}hȶ1vܪFsyخuR#fbw{44b<c܃x=ĭ]36uG߈m݀f/ց6!%\4
$iBy>I4MwVDB@v[KMvڗ@
p1	{µv|zgpOΆ|"/pDQT?n1-F&YcG:*MJuo6~"g/;,Z][
ÁxyОJ#<._:"HU{ԎDue,VEe=rG}~)Fl|sډ$_ڐ)b"~OOD}!2huq϶	s{y
h=cH,?,͘H-<Nqԣ\zSŅoVppH3-`fS qg°LyOUa1dG%CZm	'PD2>NSrNhRKle8gݜ[dpoܭHcVɣ-oW]|lb<Yesjڜj'(iǴvH_99OK$^-mW&C'cfDY_7c*tUq\|7~| wr	Z0cH~70s:]VB޲70 LD',փcR/dWy#߸]T?IΫce#Cڎ[5'9ZD?dXxU/b߻`zptʕC_Qdh|n+J}TG4"6 b% ?ob*r	  Ptc%A<CimIZS)B&GoW1y8G_a(adjG~%٘:O:53>C2yp̠-]n\a]}OoUwm_N/+o[3.wS8)N:=i:8|^|o5_t*mLђCm!'mo4o=fJ0k\c44l <ʹBsa0A8+[q\%]xx4n:|S>x\u1cƍ}.Ƒg_.Kj6eٝ`MU_Ǩ4rFEٯ3av{`snp%\?/8#zls}q^$)Va*DMs4Rö9M@t4bRN!ml}7.rGt&{|:O(lzJY(~_nisK־j0glu^){0!ۇfXBJ$@rICeH{.V]JK4m[Qyr
G X쳏ApGܶXACYNw$*VPR\eZmlr&SRHkӃNG܉:!!>GvU6!c]5:*fBAڏ.?.5/~VyRkZQ#1!}e7:[vtgbsyL?ثtC')JC}2e"Vs|ZBD;I|,\s0`V6Kv*cxă!6m02	@h
_[>c &X)lϼPwv/Byb|%cچM,G.|3g=lyY0,[dRI9?|P`{oU";@9ܰ1}&*bl/?~KqΝN",}WT:!E_'oU/Gś&޾l<*̫`Q)#,3.L
չd %+~ <akiXbhμuqns8.64dh۷?$Pg.vQxU⍛Wnޚ^qOVLr9wk'ZalE'9$y{5B)-eځ
Tq*Ɏ[aѲ/9Ѵ+ڜ_ri;JK2,.	}TQ*6	ɋ-uB%IdL{bh+(Rb*m{?<IAɉ_lc&¯./*+08)Nq2;ʋM~0Ɉׄ-e%0A\0X5!&'(EgڔqRHYGGHuH-k=rҪ0zm/v2Ny<,Zi31rd폌)[h44OmڒŎ%o_&C_LxGqrgu64Js]8-s'vEz)Iŵ-wU׼;!U"ki7aI<	čQ2/a.hG9_.D6V,W_
s1?P8<MA[vlVïW^$ ɸ)H$><.3W|LkOt`4"i	(; 9E.]O8Z~Kbsjh4#@HW[6ke$XnEBmc"AneRV2A@p夐	\UiCJ)	H8BЛpF~՜9.49[L/8\@wg"b<	S]!Tw:'S;^Fmp5gPIb
+O+Z\!7[_PEXRo)l)P5<@j?#3@rG&ѷ`O0KC}dSı׳!矠a=!$F	.PVg$	ۘG'%<,)1&s"R.3w1)g%_)8^6%%V>iM#WǉsL^*3aaӅϮ"}QԔRecxVl.?MW
TT؇}=׼q#|.aƩy?BqZg8sNBt۫~JA|t[&?l:WrĘE$1򪿼
|2A*L=[|<],elklt7aoJ\""5Xv^}g{'ߺpJNh9Kt	s\Y,(X<rIޒJ0jŦ_eI_yu]h	b	1Q~AWKGY؇8k2L}]/B 6Jn	l(VUxcgWnG%dco`i%QpǼqVgivb?I$Y&TtVaxcwNoo+Ӆ]S8)N6\|ozs_c$#УeiIt(x5N	׸.SO7'Ck7kc͈1=WbkR`MnulK!@ʅ<	+n$Vk$nE%4&wwvVu37	']X;}'w[Zados`IFq" e(b0o@:˟32YDSD=)G|Gz'otp WyB|T;+UubGt3(3 ⋒sU79ϲs ^9gI҆
;fZŭ#!U$mW/t`>mSAb¼@.m)KJRM3׺TdF}u@A8ڶDKAdi^pOA[A,&YBߋ1LR?[C鸁oV'gڀw.:@+z.''Mt:?)޻6В"-Kc9nsiZpĨ^9[_}_s
Mڠ,Dj<e&/6J	\Q>Jه>A&sg=y}OIY"kDR<,}sM;q|Eu1|6s'>#RrX|vB>Q. e'k;	A_>.-=OL^,:יs50$9.r7HsgcZ?8Wj+WLWNׯ_vܵPurAlGrSV.tCҌ\<S.[2QMi=]]wc{rR'kY㼢ï}_ryRezxU=|ψvʥgSZqZ̯<m
?SK۾c-':q9clf|nTG٭e%}X=Pu'au,15z	9Om9։\S`5LJa'7)Xlc[l;T]ϻʾؠpJרܞfѱ|?w}+B퓟ަ# u>ViߴcL w}wOWKB<)NqS{χj\);!]ZD8rm5ˑUpBQ-*h1(c"tc2ߠD|\*cXmE4{jl]4Й48^!c|d[qI\}P1i0^l"=CMVX~Gp5nl܀M{M:ڴYU`	.C$_َ|%=;R\Є?̔"ם}w|ݳs.XS]?NS+h₟W@wFf)=a{_	*L޸L:lIXSg
!5(snنfia%d㒆I:!gczt`LtZZ?94Pmo|ω'VUtS?v5(_G80_m2Pn׾GfGFৎl_״-4;хTN]0ZK?힎;T[Uj=	P1eԻX6l;?Ɩu ION'"Y4ysJђRt{ 	fvI7ӎIܮ1hKi%$잱CdИ_б.+y6s.g9lyX^vwC^(ܚ~2]a]%@oHRQoaG{%؆V,Ǜcup9?`Z@ɸBg%_ёbY6O vɱHݥQXhb~Y:N_Kgi$?~zN^T|x./+OM,,z=?Mٮ)/Uwܶ}tf2-.] yORSX~'w^AmKws @H^S}.7BZK),LQ߼n}bfŦ,Fɝ;֋SLW^$x~=)!"ysmq,hu,$ŋMocpңr/vELY+|gngєignHw$HZ?:GgT`'/Ieo8^xalEXU^kB7Tu^ 9>z!EY$h8+Q|@ˑ_܋ߜ%Md8)NqS4>xߞzrCn"OMU=}W!	/Ç1N|j rG():	% eu.Sɷv4:urY2\h1th4i݆yBI $08taߵ@|$Á|>=b.ٓ|Lsp&ҥU>4;Lc`؎K|p/'A*}Ixh[&5|[VB=MoO`'|a=֖k\Qs(%me(194d@	<C/S`!}XwM3yyӯMe=mXչ7_/h;^U<gtxM~NDՌn~gE 	sd&HNjM>*GGzk(88
98mI(>N(}l>/VY$1~q_"OQwsWxTWCC܌QtmJq4όu; <	m	8~ROLn)qOȼms	Mn.<I{08#kUMC$q`FIa}l؆o;t$G%+D895T=;8x2悵1Y\̝ZrOluPTy`Id*uӧ:j IOdfzGUIڽxfy	6RU@<Q؂1|e<|,4A?5QEdhu$?[ݛ5owz!= 2ce, 8.sLa\D_G?7XV>"؄x^uYsSTQڕB2Wڙx=/^l+d}^GpyNis˱1`x- h=GX|46PyޠEY(~LK*+YU]s)#-15]~uB\a/:$cN2#HTαAA<.0	ZGjk<#m\&	7W(KCIpHzTPw!vP]cTbz!Ƈ<4o }-N{'mqg>~Kn	E'SLs}?*vS8)NLgW>jvXx;:-qGگ<:x}%-)Y	8K	2$up}}wuz<}&!u==<l\:qlia4qTNKE.u$ \sQՠA/8DueoBF6,!`s+䮧jc*b{(Qpi<=	芞h`ڍϾlOʗjGL%ڗFD;W;Gqj&X8`Llf?/aC ԅm46Єž1OE&\u=_j-\v2;o}s	ίt}a|dmӳ:'m:73!"|MȆLо/L3X`z{RA@djBMvyI'Wyc,p:9WkI5e[-@a7xi<.:3c+{"د%>x`qm&Nm-mTMĐ~I~}g)z_Pyh|emhI5>h
 sI'js1z]]?c3;^B/^"Vęc]>vM_%j1FEfV6ˈvU
1]xk~[_=Bo	?q96NolAI/v"B-,(4w8Hs|'޺=	u x$(?<I0	_NΥ>'=y2`/|7GY`,I1`D9VbL8b<,"M:âC,1IƽgzN?8k{8yE7c l}913ȓ'l]/Ÿ$׳B^Kgr^<=kH{xE-pE	S/TxUEY_*;w8bƓPz@{jQz25FC9n&$ul-vo\JW4<ϼʋk&l]/0gSˊbbSJPB'yL`V?i'e)-X|L_	Cկ)AhS rס4[s/.XB^Ґc?yF30i&4O0f Z8-!<\;j3
Ppn_oN_8)NqSⱸ`NgjØ}m!c(6Dx7<	3-Dmq|aްg|[YHݼu[ir?c#eIw-0Oɒ8m /K>AZsE,i4Kk(,O76M>O0qͣq\2雋蟵[ utr)@/*<_ x[(LMd$đDH˶5mAǖ!6E˨6Ѵ/3;d& ~C$x҇b_">	&mjxfBsyoc"&@xCXԁ1x)0.qBa\.+
Ώ.zyE9WGf)waC 8uˢc2S@EjUeE|DDX	dr0GSd+jٟakNOX'GᕋE9ї.]+z$O9]QXiaoqUh/空i|i4UrҞ`Qh ꘲+ؙP+o]l]:8;Gy.<⅞n-l||\BD06mb3F#"Lwi^\U)7>WCfkg@#:'R&}Nx6\^暏M\IU'4c2Ir\~j8w_fl#G]@oOqBoEʹ,B[rBX2+jXa0Q[{/_.yLӽO	?I"7)h?:{V~Α9OGnX@EV>M~2S:}/(3O<XJwuOvp^
Z/aGR-,Z8xr	y)Rc2nHNx|ļy]V*Z!7Q<E\xg6
xXScw){k)/O|]*G<Da^&;\J.O7а1\0ʷX4YAeL<L|p|ădVqGgg6[;PZ7܎̘t&BU7a0c3(G?i?;H[SH~RƠi+?bfW2׆,ؐW:Vj?5тV:vUY'\|sM߀pS8)Nĸdzxg??+8ek2Ů^!Aլma:'3f+}]<	xO} x8}K~%G@fnW>.H֚3ŅMlM,"1gE\뗋%@.8NAni	w=lA<zCO05q1Łf\6wLǘwaV/ȪDE~l3W~\	O(TeBWp??uEiǫ˗PwC'"$o	[[N|vxg9&GsBҜ(-F-ToFl#FYf}*PޚkINɕ2Q	em+$ƶR'z%
&d_s?bE!<	R#Yr+jųYkĠ+GXp9ʃzsצk=hsC5Qpx;v|j$muHKё6" Môօ}-^o<Fn#>ᰜQ6Í#Q'٦ms<rIFO"Ƙ[y*@zҳKv]	ĸGEM;xشQu|rA"dCskz<
"u4mis^\VK|I'KR}\*7UvMxSiԧ4	U
2i@`WZ9]h8T8s93MU9|ӃEұs#q`09z!;+xa^k[%p@~l#vx獏ReΓ),VqA.JbCm8$V7O(xɃcyxjBcm'>bx
.Ty"KNqP|YtC y1]ݽ=ݹsG;ߝ'mLoߚnߺ)wku-S`ܨFݴ	m<՘oiJu%_}쵫]~8^$Ǔ˗ɃXlʸخ҉Vvkӕ7o8GX'	G;e$qFS	mb0 m;Cbd~ђͧEGืD˼U~j+;1!.KZO16 V>G79i#sZy;E~*e[k9nC9A|-0߉ėVnu9>-)NqS8wM}%5zp}=c?qg*y31GC%W۲YFR?CBSe8&W{+r(WnM??;o~CV d)4gB:AhƼM[$7}W<l+2'Wt;̀B?4m)t\[=:t<ti3)f%:w:3y@c)4zI>Mv).eR$;{&psٙdRBWy&E7u)tzEz w5|}+ #RL|%=ݯ
d."meg1V:kPw9IxpŶQpiT?Kfq]Q'J^Tv?qQ[jًlG5dgdr9/E&d{:A}rmr)4	m!fޢ{W/XQ?LUt-簓	?&P7}U@)ƫ`Є&v-f$W~2Tv3NY,Q}`]q]4it eֲ`o+ۥrdI:d{<dLqqwqUBrDǷ@7+t\!wSnB!T))A

TUYpP;Ԏ4wcfFX|h칯6i7?U{HѦLT)^8^s7v<yuO&.o`4߅plp;U7G9C\󂂨=X/r~"X`)(ZLRO|FEсU{p ]h"/:dSz _'8?muuGxrn#}H'e!_?\?#-m2Faj$|0/
ݹ;ݾ}{}Z@|ϱh2tOBQ/^+rW
t$ҎNwnݞnܸ1ݼqk{>PyEga-\ez^<Rݹ\q+Qi++fGh7I+W<i͙ ~[\{eGR#H٘2'D^驉i+9ɫ1wMN7IXDS(EFʫJ_Y?6B)ykJb$B~*4'Ds?O 9N߭	Il}af<)NqSxzh/d|Nq\~<[2~-j\'o.?o,
>Sx|FrkJq\P}?7]ηZhrp,iݴArku-<d;RxMBwoLЈ-%|ŏØ9?٨Sx@{G\nI-ɕ(>|!.2<{`]WЂ`?r
ߨ_ou#9OHpJҠ	.ܝK\q Xc2y͋9"0;R|l)bWV$QV&UzwBwٷ+C7D0MMml>1jnq'j}P4dSMDx||//yAמR(Xv##Q"K"_}̙dfhLEѝ_QU1+?Pȇm3(=G^5'E.cA9#}8%ޣ OğV:o ؗ	3̌E-:40Cz|\rh#:e9΢W0"m:5]ϑMIe/bfz0aburͮ,'i!M)޹|5JVR$cg{lyVym"3wʳ-4w%rRutIqSGG`ckC@7wpUuS$m={is~Fճx
~C/6W^ƲxH8)`/_~8=UW.M]:ӛxJ['ϡK&Tr,f]
KdOEQE*_ª|-C}>}ey*JytĢ	bXf,]8XšK7Ľp$'UtW.]^2]"Utx(צ+|O?}9/ЩިgeT~/^ =W흾rq)EZ8ָSQzbO+c+W.{D^H΄{:t'I@jn؊7rEsСՊ
oXs;)4$|]$nr
;,<8Wup,ЮUD4[һUdEu2#0EueRF E jmFw|I8)NqSo|b7*؎O!j 4*gas7\׸-gmE1{;1ݨpm~˯Lx4̖{4vG-.N_5CܣM߆;t*A\UG+D	-V.烖oKFPJCr̤avm8_D4aCБS[(ВԤb ߸,a|bL.⇋L@8|wb7{MC'Wb[洞^@BȒ|URFj+Aa9ꉋ?Ș`]JW;CK"|֓55-5@ӜoۂAƓK__' 1/QQ/A.[>vsF|+"	Mjfj[u]_CZd62LxRpMnxCa	hut$eCnӿң/^ā={tuesGN􁒱	gk!F{"%5dy-?)m7񪏒%:ŷ9궙֓M>^Q^7`H'i&S9lᚰEͬ<o}	B'ܿFw&MW'b	coМ%2㽽)V]5-X }#yZcs³㼩c
Ϙcc.-Hx,>xH986m<ۛ>#97Ţ_R0DW2_zuz[^" O'HkAx ,pqwGKu\>3]8M5gKMW^_<M/>7]rIKƓ;S=NqxBڹ*|
P!WQH@8x8swn+x:W^n޸ݺu{-G:㜆}}=|[,b
QgLkHS_F;œN,^2zp|,7U\~:OJ1(R?++"|j؏X@zķX.^]|S	<}qg)	s0EG,>iU.}/ZG:c&lT1*_Ɛڠ'mg	9ۯ#ImSS>#PLKF%^4Q;.Ka)HPvjkES8)Nڃcс 需on8\d[A)E}5}q7o},+FE+mvM-L?vcK ȉ|d$TlM{8猞6ۺŝpLDtԗ(fvx
w㍊vhuAܴlƯ=9\WHX׬zRN	Cbzy 䂑'&J3=uw3q}hph3~F$/~~OkNR[mOddZU12";BEep8cZ#BNJu@bȾLS<dn YTi<rCEVpF-/Wx~dz;:%V)[IģQs72:e'MGryν+7LwރWG8hO_	)'rkӾAmA~\)hF$=~,*G@>zB(" uUxF-l$:vTzJ\{ϋ\>u[* a5m!w߸DOڪ=,w
lSR,mLBO8\2E@<7|ՍWњR貿x#
AwZl
o.c܀Y]?vBy
+R[Ӄ[81mT(fR:>כ ^MoZEe薖xxWNUif5:"9}LTB׭(Ptc~\yMو1O	ҥ(傎W._"\R9Aɧ˗.N/<M9/`;pݶ>bKnzIȆs$~@C]u, MROyj;nܸE;]gu穛:!txQ e%7=`{hYÆ,,cCWmMOSztaAv`q v|CrtK?d,t14|$+Y/ǥۉ@9ڏ;/\W_.b%(*nY@]!ԃ͔6C(G]^oKfq!Qo]-H4˟ۀV嫺\OCsF	i_ҐkpbhtK/~LH*yDZCZ*\n˧Ͼb8)NqS.Eӵ_Σq<Y3`56kF=6E?tkSaIg5&t=h`u`ہ7LooRhVuF+֦r1:m-yHRUV9-(	;!0?ƀ]ZS>5ҩEZC.+u2/ǫyxvm(z(.Yh)WZǒFIW t/|5}hk;կS/*{͋OP#-<\De]1q.2!śRC zm0&]f-	
+irrS\:GǠY3AiI}Przc#
?⑜'U NT3|YY\o`^}Hװn-/ZHxq,򄂜'ӓׯMן>==Gpvx9w\_;
ŦW^5K7܍?ϣI#?!^]6ǁD٧'+f/T=XrX#uIs[8%YY/-nK}6Ě@՗oa""nw\Ã_Y-eW|$aH{qX*8 Y+#ɉ뎞<8{fx!DVĂh
6cwhU^AQ2_ic(iEݘP,;Z.H=:`$r$s7PEXllKx;wN缸pxo~ADD!F'5n5y/_{2K[Pil]N03ӡ|ګhg4N:X8r,eqNt?TVIo`+$}A'!ŷEG<ASx*c(hxbK.<Cgϝy|SJ:qduV6T.u~-
9]tD4OzSJBJǮizQnxE5n#.7B	f۠_}IY&w^x]ʥ0vWg,RE7aYzĢllzwJ̱>0SdbHj+"M}+rJuj/pS8ⱥ1I{cvksjim}tD(_Z?i;;j#k4MOӷT8)_>7}OE*A>Oiz7}EYDۺ?L<-~t#.s<!a{Mz/Ef2mm}05b̏à̳CT}=gHZNTFqu]_`00o_ -6ɯJZ$QlG%mĆ:2X4&)L=u#iR@tXlewʧJ{e9Ĺ %z!%\} SK$JD2'@J6ÕlL\Cݾs۪hs/?O1I#xcmsdc'Vrȧ*CxƓ)o?ds.rp$?9,`ln\(-I&1|,
.,d8YO@-M}:uK8nbt|ȋy^3&XR_I1LjO՝"S9Ud̹ӕgצwOGO(8r\yt9b[m`Av˹W	3GӝoM<SOr`s0ȃz8L>RϜz=vIWyϓY(XGG\>\7T|tDd3꽁]p6EejY+eg;U[8*t9΍^SEC.>qdX(M({%	g_uoDK?e轺>˝YQaPNٻho&eۑGH7G/>PUU: 
b>4mj;cxǖ#q9RLc<v':n޺u=wzSPe0:{?Na6\'N NoeM]p1DU"~oSD7y|F:a|Jyjx-kgv%#?	C/pItC^'ڢPs(N<g(kϛ_|iآB0L:,J힫W/.ǉśMg<&Z2t7UկWFfT8Ѿ9⁏(:W{:G޼yS8sf^d	yNgT,H1eSJ0e3Sܾ}W1wT"R@/dZuGYX<zW\G7.xGKlCٱ>"ī4ގcҟ82f(Hm@wnR,;×M:]ӱ+/"{:D@:(_s֏歼`EqQ]Nu):߿gNo(Eē&3'PݿO1藤 c,hpJHDoelٰ5I)9onwQrKiౌhЭZLJ=ǁ#(KtD<Nx)yKI;sE?zΗM}4}(Z[~4}4}Nmğÿw[>is?w(ߗow4}wal쎲OMW"qRݹzB~4M<a?y,T_7l(kON1m7ڵ/=`ݟrȿsq8X|jz/|~@>Sn.{w}寮cwbًg&bO #</)p	'y_U,thz˿G&_zmp;Mb~fFDQHWǡф<R<f_	7*
T%gOgZ:3/Q`/`T &7M^R5	RXq]o
6ZzFD`lpyW٢dm`j'i!n+?	?omڸ긐ȨnV+"tٙG2p⃉"v#w"wEmЫdl{ͯT. 1en.RD'|=)Ya4c
!Eɾ+1hα̶l6x͏e%;ɇr2"Gud6!v1)3ɽvsyY`b$u滞m3j.r%O2Et(=e
(ab#П-N^WzA5/\+<o9Kzѽ6͢Ǧ7Otz(e`*d܁|8<5~ȫVۡ ]觐HpKڽnTtXBTn+B>}J}ܾDe,K]]n|Dsz2fN?}
VrCDA^ʯ .i	hۇIrL_0= nqK,ql3<+Aq⼚-hFgu2I%"mJpkbh%`]'FM=is>3Jq<й9 A35=u$~[j)'v٭qKh_}SIslmo]bgwBD7j+[`jعJumx91w|mv]1ry#}]αoOs̴(/9Jy{Gҡs'7p<ұs@x2eJ)A)'-~3?5FPucHȊvΔ	||nfqXU%q6}%ؾ:RghkBcˍ8_vC[K2"?>bC:	pvGyZP^i9ntX:b'0QlDUibOM{fuٗ^Mut~yE?V}A@wT:BoBȄ_:,ڄ M#EYe))ǅQV~CIڌ68-4D|QDG_
bcD$ zHwy#B7?`>ece˅f(niVI=D_~/CMLoݕ&xRG[7M~)Lg埰uO1Q&'5LL~N*IzOZ$y"0MMӯ}4Idן_,_NˎoSmWGAml~L?a%{b~WdiAf%xRcxv[-J~\'7x҅/?qaa׻r,*Ϯ}ر o==;oΉ5 >>-upb;Oqeٗ7ÞyiTt+1/t3oŕ'7}ǋxܷ{Q7Sa"̰tlQJx~Dmz.uNw.̶<[`ȸ:=~+c}Þ =a$>
8A'y:dm̟4{\ Vj)uye`ZH_0/0Iʖ]XKb@2-cuvY=Y):qP*3j&TbN#peLu;44[.!t~{i%L+Tc`	Jߙ3,n]ȞTV/ޤC6,h>r:LqqI`RēMxnuAE#:O V$/'4/
{Ͳ,&}V`zz	ctnKcP]8Ǉ_ip
0	2u^`JL>r|#oO,ǱLT1) {'8ۻΈl'鄙(j-0ztÉ4l\RQ v?%jI}὇ӝWt:WA>8e+
$tB&xy2:慄0C 6TЈKW(bv<BEXþhQ!KS:{1#ڟ~&Ds݆}ZNFIh;L+#y1wF?Y'0(W"X*Ь`(Tb ˤd7.ہs`v-on]Ef[x$%61+h&zO߫.[L|r\;vͯuT^3ct!\i_&*oxJb?`+Z'4(2*m^`mR}s20֋=-	fT~t Y~LRk%)y琅:8*V`/ܕ$#dΞ<|{	d|E	U?GG)݇>~n&_zIWu<7y@Bc.'`1z-]XߴmoY0C29KWt(<"䕗oX0Uiix$yr/g:c<cqm&,IAh	RW)`
,*Xput]cVW!r\L*/$ǯvCss0{MeL6"eOc1ݓuϽtcstJ"bի߼qCiÍE3>rH(}K@9u f܋iCOm^o`
Y 7I2gԏ7 =2zawhȩAI`%۔j<B.VU J'$9@iB/~mT,GCk k2%0=n(k_A'\s͈&eO}O/mw|xZ|zɋT(%S͗7C*so*Py/LӟKE>MwH~Ǧ_?Y]xW+_,?1MU_~CR@|W[l<U=<mNjbB0"'aGOU9~T}uT>z}[}^쨃]mhX݅FšMn{uᅨOGo?Swb~ɿ#E3=>/E_c;.BE/쌋E='xE-0M?ciW߂k?7W=-0oũL?g?Ըt9nF0NhM_3Y~8#?pet큝q6+!OkX`5悈2GxX~#y>g`%3O x Lȹ8x</a$Nټ4(|P	ԣڭ3AmIJk^P7zSǄ@p~:}_LS/LqL޽bOцPa&7\L^xbB^q&W_aڥ<0x8>2oY\ӑf@ȵ-D[D^8~Po*&){	3nO Es
^F/W]B.v"|[LDo&F4B	<ܺ;g	>/SgB-`߫U7gUs癨N;?X8Vgy"[lR=D}}i\+s6c}ek.DVB	[^޿>F(Ì!l'.a˃#9 V5	NhJJqʈwm6읾 fؔ'8O&#繓&6'|IԌ>``7C" ?ITx8nWxZss)~k^\YO0Yըlj*!r3L?:1CT8_O	I>-ߑEEBJt Ɛ_UhgݓPJdD=c[r[4}nE:z'`](}p?P5圿Y^"Zz~k9q%~}9?T%?ʺ(vMA`vPtGʟ2tq:r^bB95>Ӷr:sA/0"X!S:{S`cSmIABuH|k+plYmNTiCbYȧ/n߾7ݹ{eL?%7輬0<UN&	Rm&._q['~O?+n#N3њ0AQjO_eF#<z]lYVBZ% G>Yd@;p>i*X!91>9ɼ~M>/v!u[fV*zSŌ>/})h6ZSx?Bc,Ur[ 38UG6'nݦ8~%|NW?21'iϓL?RTĖu;'-kB]d{/.O\4;iJ*(WNMR9hz1zƋקO~4QN|DWTgkX?OjW֋NʫhOʷ	ſO."šk] Q~nN[녏u>Odرlzw2TʞEcZ]ucd]OKgkͱlcVԥ1bS%^۱	^`EQ-7MDǼ8}~O']-"zd"ULǎ|Yy2<\U}XڳCitɝyj?L~5Q}Pv"chIq&wnȱCٜ9NH=ۍ_cR߅%O<Q aP'gq%nfPFO p|zzYt	@]9;o?	Vmޥjr w;@Q.>΢&̅Yh'jЮc2XNbD\O.2Hߧ/k<Dɇ>̓}v.Re1ZtA~uzFM.=&H޹؃;NDh41~SQ0ǘ͹oo	i.FcJI/)ÓTrLPy.U=S zVBŤ>3WO ^f9pu=ZfߖwZo܁ۋwC=|dǫpʄ&p$j@w=qW8'`\۞F1e_J`,`uBT"7Mc"?l᳨C:h\4rc~ӟ$9KxN_ ήv*Va1ܬɩS%߲Ov]8	 [{Oᤩߙlp ns̀L|W9vZhkFGqyщ-an9_>[wX亘lRj~b0xQw8r|V8"
FJ}%kuޙ
O#o;sϐsb&rHINaF Nϒn3/k׮MuuϷ\2]tf駌u{t*^d̃~jS)mu^_nBT]z±99ʻLE r!H'-l?wJUֱ)[1L?;r]ti:80]p%j* n*=a;gR=H-yFBrԣU<~n<ት/I9l畻\VqЙE.L_T7ǭ88_YibF_|s/^lQ*k?Z}
	RKP)Ym	>fѮ;݁4C#{lv[~>oy_=[k!YXЮisxrΎ.Ɯ_%7w]V;r¼ǥzzP75	4}O|4}ߞ+̄U؎7Uw[W.;,t&G:n;Eك/IOTO+$3Ec۾CNzYdҝI4}4^\?_Oӟt~h7MtWLo+iuOHqK+ܓm?|}͉O^R~o6oUJ70yO_Zgg05?b%u,<HY56=~'jRF~tG_;	?w_](ڟS^xǜw]U[;߷}>VmހBײg㵸iO}wS+M ǵc7e7m?и/Tݠ&{7Nӵ^}0~dG^t);a-c_.?2kCN&%*S';ũ}c`O(ߚM]q;<|˘v_b{*wO헪۞HڱbGZU(.%c#\AUKx)ߖ@+w#Ed/ZB_t.4gM	9@ dP>1ZmZR.2Ku8K\G. 4 ذIiI9.
zpc[;V^BxpD ą5A,6ia2*BE6w.="|Ɂ=d54߉ҼOO $+p"#dj" w,<ڞcmR/z:wW>Qc׺ۭe#HQMGFQL.5p%ƭ
df:	9պ8w_{e~ELD_ٖ3mas#O|.}=ba TIhYP=z"S݇;=ñkj'%zCխ}/&*r.BPVU:iAr?Ov5yi4Z_@6Ulm7>֐GbE8]i⭿P𷒆$T5zӍV$\fo%r\D΍:WխK5LE"GSX-k2O%wg;:*	1ai=B"Вc%F<*VXa	X^,T^1I܊{׮%yUylGG\p6igS28'"ifAR<a.(ES6e;A4*KCr~c<D>c	՚뉂\ziz<FΈK06Vaut{}41O>u-uyܝ7o	ϝ{Η"&~zBe-΢#O4/^5R~&RQ<;<F/yp"7 s/A駯:ܷ慨TgwLyF<T;FFx@44?0y-Ɛ)lp*j󐝿u6}؀>@}k"߿{3|.%e(mP^ۯ\:.]8W=ʕKxe(DzE'<0O@	iXGlވX{P*V9U4rńC_YzyovIkrVQB!K,ւ!"H,xsE_3i!
K|<?xS\՟)ϨนI鑎7~ʭY(?Vx
{>+QxJIc
'2!{&xxdCO,CZvF෽S)->mX844+rNӁ^ӓu}>2|2o~Uҩ[AmJOw~X}}oa̋oXzfE5/^<3.v=9׋H'Ʒ~),KE]5~E-]ĝv`3?%}ӉXڷxբ>|)On?>dJ_JÜ?6=|?ˍy{\tOŬc`^ 7k6vO^a@ߴ#.L.|.Eoxu}fs'5}I(=V)`Mc(cA`xm{}睚Mj4BD%<|%`bKLcrҥ;맠xmg9/~*'<.یN-\1u8i$LIXg?ANJ;k㼭#	#3? ;|-8{W۫m;b)*~tcRkLQ,0a^bo&̪roųʟ3<D[..Ƽ$@FCܨmf1=yuAls:RĤ02^' L]ԱLϔr{טɜ8ی	E@0/OPqͮ"`۰9m	H(i3MIuXNss_1UL&/L
N\Cq^)u/؞5g,RpV}Fk$i1ZjwkJĦ/;MXţD7)Ds`_yjR<KHo;7v]U	,[!e_RLP뤨&Gl@ gu;g'P[ F>ηjzֽr^<fLۃ1]D9T}yH^m۽OL
=g)wc=U眧60y1cto7!6m@dhv:hO*0K-]>EqNvv;DX#)9G'Q^xa|tFhy4q^~ԓ=ςu֘u<}JEۭ0vv%y89ېr~MuׄAhrh>hvW :"@Np%kvoWEpqӅyktɧ-3I_l.o[SwT-hh0l/rF*7C$e$"C<aqx߷q\nm2ql:'b'[t+]^K!3_b	8ӉKXUMIT&҃PRvef{-B}W,7)\Z$Sh$Z}5.\Ա⢮w.xSuϱۖe"yߴ}lr*Cʖv(/<cò8e1osOɯN&uz?Aē[H{ח=]ʟe	SOF->zq˻}N>?)wE*_zo^'ZO񿢲iGTiѿ9MmOg]Owv==慓͓oжXȂ?aOUmXߧz?5~k);wXȥ-z2_v'/.\/"-d8>'XTU8.IGp>?+[êCPa!j|f]ArUٞOo'F>5=i߱]_bM7?ً$'ZobFE>qitqn^>!֋Zo؇l^2¯{uf<	o}[wCf)	w|h!Ip'1=-8vj-Ǜ	 nY_DWcl_fȇ˕I=J,;ePJk ʣ|ė0y.lm 5D\ltti:/<ډ6j;ul4M[p. ZSWs;\cwL0Ir೉_KB&
V3VD	v{vJ:yKRVe)fu@	x7ewT>z.t$.x}3,Iu.B|],Z7tM&d PYɇ~-敓V$@lJhԓt%S`ɽYR|6ΰ$N0!6mv.o(-yOFe;iF" lDt0ڢ9]ϰe&qthQ>O
(/J2
ȮX<"7x)j2ہwqS _Xd>_4O6i_g)mӻC4?>¹e.ʖsybv&9l6	JdJ4Esh+0ۺÁ}>	#؈ylia1mAF8ӕgH|nӏKlWq2a]ަ|ފi3TлHma{IptJ5).Y>y:`(f_熤bo]؅JorCB@?iT,X̲k83S|!4LB<3O aŁ%o?R\l'tEiT7~u<O`g~7Οev)[Ŕ2u^:pu-
+Z|aH3˕BZ;ٱDwƅB{ދ,9opJ\۰pq"'f"O@hڪNjD1s{|.]8?7x>qH\?|LKacc
Ԥ8X NzXf6yJ}D;>2W,3ϲ7+׼^O]¼-O_(Q-u9K?$EE?ezMi\L_ D8,UtQe(MrH&7%֕mAώvb5:<pœ8<,b3{c/;MSL@~ڂ'^>w4}I蟚?#'O.?v_1?1MoSMަP~A;j~MHAǋjG`AXd>Ue\
پ?}XϾ<,*u/]O|[Uԥܸ/Bf!tlCO;;,}PZGAn^i7ڿڋ'v-J'e.^]$'x-oY̪ZXXzUmh~{h;^v-r|š^
߿=_7@WO-'~"0c~jUqس3ǽ"/TdEo[^t[>5֓N/M]F	{(1w7KaSۡ'ZB}G1Lǌu=4,J*KLN<{4\L߽}Qڅ#&1qJϢTM⤔,sז/X'`'N\0 碹ÃuR;]Xd[艟K5v[@gvވ[E
#I[v'BH.*vf;k#_",q\ҎceM,Gpz5'"f;;ܩ̓O"?5Sy wOa	/E.$?o]J,~
M|瀣Bf*ȔFǅwqݻs1RI	ct# $C
eI7^.T^/Fɮug0#q_\DiiѭLU_[H|M!R9
ex~YZh^r?dAW=ِc1O6'Kr\GprsHu;r.OPEA.p7nv~/fa|ku/m]i8~_-gTR.li໴փv'`ԳZm/|*Cxh2jm=bO9[ul2G7XO]8?"+A.ugU!ve4d 9U=2Q*q6)AW^N:D.N>;m%Z,W5sp⺖p&s&w]N?:W~7F><?OxyGyQFa9-,4(@D4#i%?Ą0:`o>OؓLN3ث8xL-vZvSt"+?w4-j-ꨶ!'t80~0uA2";?:;|~+Nb)eu=r|+͋뺃f(sYhY(#p{q^d?fb#o%tڄ@ư.|h2*mGqR*"wdtهO'W⧻-iFBdj5)fujnst_N>ƾ8O].Eѥ<[ޑ96P'^8©vɍTy]!Dv!qzE'D7y'*pHG3q7<ѽ"Ɵ鄏/[1<p=9)?;&A-dpM2[=	yR;">\O4{*|o?k?OӛTǿB	og^pa~X5"W%E~txuO="˶p^P{F7.`m_M'9<2|+h	yj>J7MAI#lniq=a/`yr|iշj{ӈ}pmu4El.OO"5></([ǵLw<ѳyE>᥯]^SMoݻxM\kx'Hgm{_aǖ^OxwT?zH`n$0CX,I$2=ލ',IގEFp4?Wqxz;|}{R>JL[` ˾߃\d3g;I)P*E?@xT\f́$u죿XInU" <ƅMtA鳧M	ehM]ed|ɮ.K,wu4O\|w.Hb{da4LTbP}d;zEJ'lԯL_>-7Poc
(jseC+au::]~ٷα6rH4{>1F89騐ܸ0g>u%[j8s+:{`I]E~Hhߎ/GywS/-$Bc?ӔNwsuKy!wrj{"eS=, u;C:g3?Tk;кWLsd֍!6)1݆J
O\a5'SLPQOn9ꕰ_
#kOHO86Bqaԟb[xtܬݵ|ip^;: 'NHv:9d;0}^1d2sL,b]ad4?v*aM.:88)m\`жiCw:AB/3F!Np*AZw	ΓS*> kh3w##zˍ9 }ē^|	g3
P1]%o>c8*OM<!;Jf|+iMLmeg}K|$N V~ʘ<O`V?<ew7nݾZ ObZ&ugCH>+H:5GAʠQ1d'N.'创1d'z/Mǯ`xACի+WWqWtE%ge,Xs%!sG/8n졝mu_^*D"Lk``͚@G_l$@
3SJ'U4(Ԏ=w f~c"~xX`zwUX0ěNtj?$6|Y&E+5NB#[-
vlד{E_6_o>}aW<ԯ?Ŀ4mxkoM';	,6,"3OR[o#-c_6I-ll~:ZWI.>ne|7,۵nJI[޻Yyhܯo==?o3"O=ܽ8(U~Xzw!:x=LķEl1N¥w4Pc
͌?X:Y082c~=׿g\-|Ǔz9],T[Y:S])ħWn~Eݻg߾au:2tڿ5}OnmoE~O}ytt1RJ'"<#wk3z۔cџ}ycA]45_@\%7NMA
ŹBFOr}d/+Ȭ'E=Ʌ#_x	`@|Axp?;"; Xدʘ(X`c_t;8cNi#HӭE|&w	(6>hr)S<ηw|/;Y++MmR;ZlB_a]uqE۲ Ipw";]|}qt$;.EsK$zߐnS1G)b!Y쒿8]?V
A>׎ilٴ4QzW^	xVcHRLW!3j'hQ|]ĉg6K$LJ/^Va_:\`%Mp/m7IOlPLTm(]ۄ*Q>hc, &J%Oʒ~,ڗb־STM찿:W {^(<%J[*YOU<B1mJ ̗00깒O'RݶE$8>_Fĳ]Dd
/<+|$IZ$4؄t_*~6VzOy"7TtxbFDvKSxw`l3R?t=x}'(h;<9FN1W>{ıD<9	a_);DgK, tΊIw϶4=Ǳ%/8}p!d9F1p2̰!5!C{Oo>RONrMJlW<&J|c6J?me`~Q,[)&+@6a*6h|F3[l߶09#5v'=>wٯh˂J_-m:mMO:_ǓiLL[	|cy]61zx{mKE+v)FyΝ;ӝwrw(~7Uu^?H底rU{ĕ.Ϙ6ƿwzJ[ u%NXQD)cR%>1]0jO^F
a.9oç:DnCV1N{	T	>|U   [%u  IDATLxNtUX~%.vkύ<)N?_Nӏ0=-_>M$PM;>ucOߛ=1^WY2oum-?*cNZ0Dv)'<w1?gAu_,6觴]^^,:5&m]?Ecl7_/ԩ@Q۟Ց=a݋v,$KxڈWpVȫo3'U}QOVy'E'Ǝ?q_E|O0-!z~'}}}S@W?
ɿdJkH~%{<)D`ڍu?1v!a׮sjA^X߸Z#ƚ_*Y\֟vN[UjόO<k:s#ҵo&4fszW-֓1^W):Ġ
{ȠqrbZcY_Lʦ.0$_.BoݼJ= z_x12b{иGR|QmAX}[kxEBJ"HR_\,K:̾`,&i!FOglJ+읨Ά߄u?UD6td w}rᦋT.ziw.щN2yB_ Cql/*lOH\<,|-}V;o3֙æp֤mIuw9`_X"Y3eLSX"
 :> rCC|9faN^EjCv6,4kjKL/8Re&DMg+71::ޒ ݮuR@XҥI1nsiCS7%/?Ī!5V?՞Ģ:1v{^!o U4
Ե~=Qt=g'z+ob/UԡNx-Tn+,.v9|Et̤x	ɋ.c'sLgSV6.ߴ?*8^KFW٨0Q+(e^#*Rhب aAG㕎i#NE[`	)dzLvW{s	"E~K8F +*æ~)9~F6i^kl70\1?ܗЇ<yɘaIZ/b)Yc/Rrtv:ˍWP~7\?NQLh<ЖC^۟:ƶd|IoA7,uwyu
%]xHdZ"Kxʥ'/dy@>eS<IXA1+J[&4Oܩ̊Ђ,Q^vx	qg#9E28LՇκ!X%4W:'vp.,_c.].]rwN^ˢ)3YMaG!O͢#/[hTF~My_LU:N
^}i[Gy,KP.q	ЊnDyNAoò6嶀^*ưiY-f⒚ǉ^H$ν2*[e:5k5y<`M{͗M?gic7MwiiWxr7M2M?7/tizP}4W*?~4)}di?|;𶫓t鉞|=,6pkOczuC}okx J<U:ciLe	ˮS޿Uh(ʦt ]S[ 5<%7<ѵkO*wk,8o\Vm@3c~҆e	F*ڼ@'en'ӧH<CzO7_쇦++Sw/{S`ڇ+逸Em 9PO_>"<q:nO,x)OZ~ñzps_aJv_e+1u:+25G~_ƅ7}6:oSG[9wa+U2#\u-ˌY47[LPe]5h6l:ҡJ.B}(
#O2	σ.G<{S]qQEKte8\=~\/2	WF0p.I ~hzDY}kc$69:^/\'$HIeryZuw8q
V$5'%7IUmMz
~CI&(K~C{K_ꢔd<(dvIɣVL0W~8]L&۲+:XRPmE|"\Wצ}0˂{@ttC\bEQ"٦yz)Шn6?hXPP#l	 1$o*MXal3u#po ݤE~}2g/,:І#OV@%M6n#XV$ǮGk|@t/PM_qdUDˉR]zhzhOS2K`71̴ǘAWK&	: ?XEE^'?db:h?): I1zyX6~ʱFi|*SG#vNXyX?yX
d9G)Tˆ|O}l4[v=_aCKh1,^-LEZn@UFȏ)	"sT;г76(?O"K@?gc:Ղs>jW!$;wL7uw[u_&W:yvwSb^'Dz>z8J̛ 6"b IW̵Y$P6O'8til
w]dEk]I	6 IDȓ4Vz@c.6ї'l.2½vlJP>'	p,_bfr3oOܜGΩ ["r{y.ET:}kӳ^_?.E{9ׯt.*drd>g/_:Mh,*'d/';spnHSHwD|RO)sWon>T*셬nWYgsZL:2q܁LgZHbU47iAB':y罂N#N{E^K'Q4Wq뙸fyI߿1M<yi-i~`>ki}_3Mo{0M>M׊oSYWLw~[}݋iaN?i"Osz|[6}E^wiY( O>jG&~`Ǣñ_zANӟ :xvd?V4,$ھXaae兙^i	),*$Dnڹx'o4~ޮyͫZU|Խ_yf/ojIxvt&'۟)MsS2;^->/$}cd8jD+_.
ʯoM>	Mo1]pxЁ#O1![TG{c>{=կ+^?Av^xtiOko:}s={t,/ȧ2wCv`(v 2'3?KSʦ/|[?r"O|/~.P(0!)a.\TAZHjn-@'%֚.fc/\<p]r\r1axE
IYIϟK_sC-I/PXiحe:<	ۖrQBp_A苶`oe	.nY,e):4"hړA:m 'a.=27/\ -6Eg)9wh6QISoiwIrd|Փ@zI%m(U86̩ؔ7x<IMůu3rk(;" ;|ϟc#߾E\-5iNu/$	wӾ|YgMG;NְUA	!y1Od(B=Yk:?פ,w[Mg$ _"e]묰y#\<znHp8z	\r|&Rz2cI^̕$Or
mfQ_	"Zd;2 Z7-oՍQix#՘nM{j$u<5?^nA͓Xn+DI|{jȥ8$ RBxcZٟmo%/׮N=nݺe#xcWF+_BۋǱ(trojq؅17kͺĸxdSU>gn['L޼ɔ<[kmC1gסڒO7xEca1I<LTCuW̒
˘оԅ",&i$/Ǜ+*땫~¶KOܾ:Xc줋ƫ>Y	Ѧ4ۄ/4AOz#}%&ҷD#@cm/LK	ghMuR76M"ו@>|1	46m"_yFJX] ߛG)O&y+R~fEc7
Hq951!)VZWVhhȦm<Js;ELmG:SBţ$Sg(?+j#ɪE^tɼ'g7c{aQF+lnUO8 `(@:|+7ڹԑbIK2.˅,CVầ[ι֬pS;.^d]*P	Yl6=Sb؀-K+8Q/\:t(\Y/%FnS#v*L#
y]3aOiY>SAc1)ǲ>?%_{`zǯ'`b72!':My<x'Zi,gсiS'Q~N Ԓۧ<M	/|K|/|.0M杪|s]}EeQg^ltO;mzYۓb?j^Zn_~?cSއVW*;1ꮶɥ]	:Cٱ;]o}n[cWڦO]ۀש=ub.L&/: Bjy`]?E&2zoJO&y;X	q哱~tcXOWL8`}}_K7˻yױڋ:Uׅ9vδ]zI2}bKo*u{z3IXl'ӟmh8zt]C777hfaZ6YF^/mh,0żeiQ u5HBb1HH5 Vr{<\/!q[Xc[ɲr1ȶRLӸXJYa҉A9
\ݽsLV"d
Œ/(=mҩbOҗ-:[0VYGEe@5][,r$h/<3A,:ui(D.[o&?yF=s1L;1Dt`/0AǶ9OM>0Emͅq hRapIJ#y*kG<֓AKH<wt"EY΋V=	>eW绗e'z|-0mWx̊؏U58Gj+?wtt*MwoшQ.J!䕀n'R ~%ٳ3䟙ݾ7ݿywzr=9$-`\7¢@
/LۗF"O^\q	?g)~O&/ϟ{FF3E)DR+PN;}ڴ^>H;%n&).~meT<[37Z.46Vk]Qo,5$۴ּЩg'ScTĨ:#[U[yqy[/(V^WE=)n"} nؿַDECPUh!UCܦXFn`=Y܌g y͈r؛e-)/&"^91kWm=FKaqAYx@?5m{\Ԋ`C"9n5Od=iן}VcCb,|ׅ5iCgv,uPϢarXr*1M7nOoX07:G'Ww2ac-YS.v-_fmՇZ=<8cso!!Dkk?5 rEH3mYlu'xP6buk<O59&8nE l/b[`ZcX?Y(Ɯ0F/hr屉6^ѱh^`"Ջ3_Qjc'_x,'.LW/OMDy$p)M_cn>סtL)slnzJьp1.ea=0^Pj,4rlwO1ڋ:ZRFʊLPa+g_D6c3J&ꅼq(snw!Dy>Nwx'{4iSYV3U"\x-e#$.f'UWLø$7=b$)~?	d/vbϼXы!x#?FǅH:lnv:aAipB?yQӖ.>c6NJ//DA,K>uw<ޖt ;Y FLX;6تנ.o6<0>y?+2OHWX_M>8GFNX5錶*}5|Y=O=wV-PPcZ/b=<eSHz~כd=0`;@BNcÏC.O
E֙`m8F0L"X/],0k\T J̅Ҝ<IL`A$7Ph:`$nk\4l%鐍Zl	]	Υ)+\Å1G,0.wN?Dx|&}.U}BȎfSc=YvA#>"-G|	cc.%@RzCC6q'f$y;eܨkuL [`b_=<:d`?}	6bX&l*+|tCF/bo#Elrͼү}	Xtګl|#Xd@26;i%&Ϝg!-wzV`feQIJԗʜ>5+	vty30;jl_we/8K~&*ϋ̙צ,02i3䘈eU{?\T}*)֪kcmnB/|]_D.߶
#~o䬡di-=9tN2ig&>@zƺv܂2/5sdZє1ߟ7Ag?uج<q}>ҵRg	ɣjܔ'+c3	QvqmhAC(眴JSfre:mվȤir|k!f KSFNip%<!2Q!oܼ95ZW::&"`Yca7TnR46$aiW/+|fstM_xVc{ǘ ^W=ه!yʂy}E,U7EnK~`ŷoޙnݾs9LL*Ó\vE{Ul?681L&*sBއvV*_u۶]ϧeޏ*ޚa'o0Ҟ>72rFu}}&UkI
g	ECh1:$oXmrBNQGisEQy固n5oC)FMX@2|qM؉EHݼ+=E^)]v<W^{g<t;Lt!L}4Ya\j|yǩ^`:iK}Ƴ>l@<ɇܬqy2 w)J.M͂#([knۘzOyKL2|Q]9Yu9ݮ(zoʛ.8@/L8)NqS'^_fŞ= E TZ5`ߦp̐O0ոDc7WFl.t▉	i2 WwIJ`+W=;sr.B.Z>|QXj:)гn1<bkb5(Z6Lŧ»tA=/b.9ҙy\y@-.rQA.2(+3\B-QtQǅuB<-pAuG]#<!~)pGF7=9ϥrq&O>\ ʩBDl6MOsJ5	0_pnvVBsTurS$ezυL^O|e}JV*ǱquF*WT@^ځ|dy'h3-OxpNk]뀣"-	Z}M|QR->-@zQ5Sb@@aMI-9^$C~Hޗ%YAB/gm`)T]"	21].~_SJ>rTS8?cX9(֋	rCL~}IK.g:+oeȓxk_.I0l'ߐxs)>G8hZ:6;kvm<R-R3juc/R-T-e+*3Lsbst.#G[ƾ'1ƾӳ^u|@@%?SEc~/Ve!}\_	˄j\
٬0)z7伆81pFSJ0eu|+o70_I<Sw.֖<	"J͸ܴ8.(*>/Ʋ}<)q<ɍs׃	&ioY`a'-gd= 㰏eO=;[{Q͓1¼:< 0&#qQir|{f'eTb&ic()7p: ,jP@<zI '28W |O܄ڏ6+o'ٷCxѨ̻|=yǱǢZ$]q(vihoGg(NK{n5ɴ(=n={}rqrp#YN2r$/#Gry=t=C}t>16}ES0Uv6]G<״[O|EK$a?AN|h,X(AcU\bkQm |Un9_h_8;d$EۨMhQ5]α zhS]n8<qXb't.S8)Nq5_/.1y[ǰD	ڌLq+qNU|/n
~h[c@ЏF^H᮷7nLwօέ;?ɢӵkצWU_V9yB<k@T	EwB'[
8s:cP=8D\?kY/| v+ugv| .x5ߡE_3@I	|ꖉu]Op8OYזxl֢0)0WVj/:,41IQ$	ˣ+^.pEQdb\?.Ĺ"ŗ1vd\iAiWj?<-K8Nh?Jh;v`d.Pg3e6~	
)A}uˤ,uN[Z*Hs|k;midWԭGig[ivqۓNl>ڟօ[4uG$?{W07Ok@Uv'21_=`!^mcmyZ-w)gRL}߁>;;s̄R,j.EL>b7RB̝+fKZZ,Zsa_HN{%pBC~/ǫM'H[$`:Y[o*6?~$2sQ 6y?E<G<Wٕ.RKDhma~^19,	HSh]n;"/!~*JtR]$:h֧e4o!+fX/pz8e~?<˃T~e1ϭj~IZ&oxl9F=̢'n>.rsOJ^x֭;WnLܸ9xtwNwD	~7jkc 
Z.+\x$槣l_^q+O=@NzF]6jZu㱵~>Ș6eTx#sߑj?8)6 -1a'#ސ1"<ܦ#~*\ړ' SmRmYEwlX`c[A~}=?Mn~#':EL69M(WAǗ|_|8( N_C%H"D/Ъ6qxMb1'Y=Y%Eia63~B0g8<;rRwӿdǚu'>-E;/ԩ}X~^Pb~2^huw䳿VO>B?J(=)NqS?0ɀi	w|lO -c9K%NKUy
jrmo}~oyɏ ?[!6_$5*&@"`㢗8NhJ\@Z,pG%\\FgPf ӆ<%.__lܮFF-?[	I΃m.@Uv3 gR:a`I ."ۃs*3s]LD[!A{I| _$t6MP0$:!ΆR=!2S4k?uTH"PY%:\GNg&.k ܓHKFGgvGTfMmeHo>@HOP2H~;VC՟R3w7FHw<m[Ѵ`	1),jsqLc&;V].evr,wk3yGSϔb	-uh71[P.A8V'8i""G꘨]nX)xk~z,d<z.Ğ>uaB(+dNh.[9^>q4
0ԅy+Ƀ|~#l2y"bE\cp>rLP޹1d	aVX3gPKzmڃdœ?_2]J'<ͶhZM/Qn+5*mB︐mM6"#l̓}.mJ-pwst>f|Q⏙WK9yN#?FG[pd9䑶E˂
1Bn"X<UV519'D̼/>e%PwuE'O- |e+J:Ѭ
)9X1y2gۖ-:/uNQu
L	nRn'x"쿂!l+x WFm^!D@TB$!$\UJ%Rsk5Zǘsϩ3-[^z왽mW[KYv_7o7=μ_15sp̥Xz|\)߬cxc9eƏBPe`3A[ҧRyUH]rD=ڄ30pqĭ%PBҎe,0H;eV:}vz9%<GRkK<<o+˹[Ag33R}iB^9CY_j%GI9٤HuQ~jʫ/el	S{ҸCh#?Hىu}ho6\HFYjߗa?qk"IW	Pbi3e24-p{tvBz|{<#uUQo5slO9]|d{eMBdB'sǏc#;W_wp;52{:?'+n'4?ӧß?G_q]CĶ3bZI,,4hn=)$ckkn_;h˄4~}Ոfd%.Cːl0cmvW-H{㦒?YequJ?8OVFZ2M@nSyaF]l#[V;ewe;ޔrk.+Z|n:-a yȄ8
a=ȧ>Tn%s<!	$2Hjl3) 0e7^@NuCO97r,v-aOfϺ~𓔌%,.ǋ, Zy|؋~ly4 lQa@3'[z6S`j1:pG>#>왰7ZL<@{GieDGrdFMc] mא\7fHO+wiTvE ܾ?HшNˎPiaXq>!m\"lhғ/YLQ"nmv97VFeqGɆd2ce6zJJڮC`a-.sY$CsV:~@ax׮ݑ)8GH}Dv7NEZ GM'PN -}T'ys[=C
gy
'XNRSe{[tAFGƩ}s^R.RvOyaLؗ0cq8b5,0'lne7׋\T$^6	νqᰜ3o(,۠y 5t>zS㈟#۔Z NuS}~H=nGDfq["1׈H34CdAǗUGR(uFyX>iUe9uǼeA¹l _블*:WZ1=2B]zcQaQVy`%AG?%9
ljÅkR6Q+.To+Y꣢> $
Q7`"	bWO[#ّ5@nu+<Oq'~H$ҼQ2}/@ꑶ">~S{|\>1ǭ*Cos0K/Jbp;w>X_7o~ǀL!HJ!ɰTS6=p͛%w/&O(7	u7x91;SEdna><yO"(7Ef}'N(+PZ)-|rSzxPgS%ޔ
K.^ǋ,Va!չMQXw[Ma$f/Or%6Sh&|hnMڅ([F^^3<Z*E8n)	8N*`E-78nV8YYSbs.ȡ0z9$OO"$\q!mPyXlVbGXV;|7nBh[Sce7xbO;r{#Y8s'R|ʂSE,$/|#oti~21)?[(mp^٣PqNeR%Ǚ }$^g:6U&oucsU%pVؠ4 PP=8v@N{'A!iꎺ]lczI`:aڒt	1ʇvP -
rnd`{2)p^%Әp3z1#;Kng,0~¨`BH2-yes!QkjW!l#jM9Hg!|!}ŮMawmc)<uln;aNTnV58@G*yMc@V\^O m T|/uyzsRyX.vGxYL|J)厵kPZeC g`'%1ʔ~rO`97.\Wx\T~S|6y3f/Ug$z7l׻S,NVYMɏ qxuZonq}hkw}hee^EzCZ^a	ۮE:82OHF[_)"`c]HjC)n(oy]$*Q|+%@l;.c?;Man94a$wsB{3ڨr" uG?/$W2V+AL*mrbGhKQa޼59ksM*~ӝ(%B,5|I5K~3ғgnB񱡤FdhrT^OԳ0^SEFV۰ZըrFyS]GK= OOfSI=P;6G	T#'o~|xwp;᛿_ OI%<$=klc&XNGt~ؓԿwT4о'L`D%w\44vQc+(JJ
/o8F僕Efn%鰦{Qnr<%ef9R睹otSa7 l7M:)D8ߤ
R#uCv@ڷP[}:P 7@XԦ(#tCȍؔtB'L(L0n*8	]V>rIAS\vCopF}X ">b]7XPA/uElol|"=m"͸\/vYIcy:F&%-=u}A$lgixOCo0ݻ }kK=ĴnkʚJBYaD9m뷇wogIuɄ
y &6Z@XGDj$%Ë d[+6҈s%Z, Bx
P_994Y EFEF@wAؕtR&Ⱥ]aw$br黕&mX:Ja<IT:*^GDo ~qfg6pБ/< E߰:
1v3gq#fGƠ/ñMmWK`J;9_++b,R	@näERqm޶ao~t'NKncfS%? ޠ6ޮ$=ogl	c=ob?qxXr{Yx>g3Gl<ZMuiMPO~~>7|^_;oZ4Yy'"WdgoJE{?U6rx<{JOW=Ŷ/G{&T[2.Xq4Ik7	]CoBG=eT| <+sk[>PfzwPQt<'7;,T] U>m͵K?1F;$߈vjgzjEz:ucog6c$ ;:wF#MВQl9џ4&9Q'ͪ	@R?'wΝ}rV}*{ans=V;ԛYK9~Y\h=na\86\&E/N'yp;w>ǿW,)oָJ4&>fIn0;<}r~/wb+*F&W~͓>ߓEL(r eE@TڦE&qgGE3u[q`	+wiqR̸\Q#',CpK*J<n&<<N曖zn
:mn\	#MXa@)F@h%3/MF6RɾiF*i 	sBAi>uFpJf =/,q-M8ǽH#SՃʙvi{mfш;>~n^9W͸sqzd*[HYwm>cׇ> "w-Z3^Mlٙ	X:kX01b+7b$_!=x â[ꂷ&ETm*"V:[FBӑ48:ӱ:<fq(?鱄	_e[lT(!zT"'i0M5'h7lEhC| a\
Z/Yjy}[̛C:)A.^o0)B45JsKHBBhg8cCܔk7]ȺCĖtoX>4r(Bt);ꁟct=4;=hSҷnQ5@m{.+pU.7<s	1B&iܞO M^DJѕl;KyfSIOZbysM.6i\,.ǯ0d=VMSzr#"rŰ,'Isu+~$uG~\4]xz}vzk?RWWW_Y+ϧ~sҲb6g\/ܠyysPAuhUG2!m>>Տ~6o{SLHAqm.E%&TNeHyp(k_Z	+`J~Y/3R=w9	\oE	$ %BsRs3?Ϧdؕ7hoڞ3@ȧ֟m׍$HW<B4|~r0o$)޼amJJ<S6B{3uzǹ6Zu][reN.uPϹu$>4;T(sśkvF4P9D{lMCUT;sME'{k1ο'#;wp~on&<˜/tôn3Nӵ[{6O`/ÏMXL,Py3E">0m`LH5eVR>A#~ǶNIF«@3+xFldt~ss]Z@oxrc`ID}-LIXx#M4	1nʆ@
b0wN=T\^[2r*ukP/xиi,A|oOܰ.L(l⌟#cnt獻K6II"ad!1k.YFS<oiPI][ؓXi·Zjg	%&ܧ+k0qQ;Ytf^xÞ2Y1KOfS<hYμILE YʂP%ZsnKN}/wWl\?%5:hFcWq*Bll'3m6HM^h}aթ8Z	V;l7mGv. #;`s\cK1q(;(Ox'z}b1ZעsMnƪ.su; E:u}*H2bMZtR1|;rrEO={]{pZn!l`c o/q]`&ǖ-jBq.8vG1gu@b#ՕԅΆ:XeÄk+qdy1kΛfr$rco}렌K,c7j	PV@r\:r(G6~O{Q/OC'}<Z0$OM	v4|3d-_X	LX6&*yɓNRDaS2hRm[0Y8c4ҙp#,ZvF?z:ߙOx]rCBўf*'VmG=?6*-POm3ڦt[6xeT?SGxE;@ȋso∆=j~JӺ*@=y"; yu'3xק#Tw\9*ie0qu*:.ڏO8Gk~lDp;wN7\Z!{:WܳVVw&#18Z'IxSӷ\?/|?Ei*=/rl(rS?ŷ v~2{ӱOZہc;WFnoOpJZ4YbFC4D>M?dOaӯmY4n=
0%B).:Fs\,b6:'Owi-8%|JS	*7#Ԑ+ܲF`#raPa*b{e!?ygUlz/[,+%u<r|qk~E:b(JΊ
	H˭SrEF,fTFM%4,i=6<D$>lصXracp?	;pN_ڠ*W"|Nk̬Ȥ^iJrx?'N ցNrDrI'Yi7'än13ZPyUGx%2i/ۑv:y+}A=z&cQuE+
y,oIO*Sn).v؏N}&1OC=-o'>'uXBԧ(f-i:`o^^xyxue[&g177V=pI'[yyaK-7kXE?'Óϼ 7M=U FwcSF_%|8hFgW0"xrxb[?T=C	m{3`&om	[%lN01>a{G[f8Х0qf\WLp1b{xxFAo_eSNqJnS	pޘ[r~i5V{mhhiK۟zV	|Mٔ'I=̃?Ly[;6QA6yЈ>G_~KǗ).uφQ޻~o.X~ܗ/2raHɹPBFX$Kw{0JS6DYE۹^lC#dct,ɛ6?!Fwp;>_O!.Sinñ\r;Zs
߄}c>hݫk|LL/;%#7`,xV\He#L|$UXyl$Y{պ]-o@6'"fy@cOP
0c-yW-h_fڇ$YM2 -fiX!88ngaaD9#kTr!m\qp̓+Hȫ+odYr`|<mYrŊTp^^02*,~VeA@ :r'ň:~TXHYvAʉSD⑷{*z*o01
I'2CKi8?=uI¥34'8lE)>Ե8lU6 9|lcJK>Gre(rT9ކ5;GV2)ΗFB']}=XbDJŴz~ƅa8?{AW``kuHn7ʋU`(0Vto"w#,
mC:a,9?pnYxB)D.b
I2E3{)S971ami"upSۢm)JW>P$66;xo἖>N&/yJÖ"4,0:?!]Y;W}kȳivQ&ټ\蘓_CYQ̴(	&o,gAu?o1UZ&\"SPkټ"o	c>}/]S%)m$96ٹ7YZcc 7oH6X7tauѼ-LX6.l#>-`v8`RI}.$BH[?S&DFn)?p>*?]f
|X-hoΦu&7l)~*p8ѽ1%YyBMs|(_|+R紹BiAo@B9XaFtP$/iT}țM@=Y/yW_T 1MȉhYlOc{lH:i۔7	A[ 1R[7>A	G ~8Plcm",:R6|-7fgR ,8m@I:f5V=cHƓlgcMx>]o^9wp+[{-g 7岕0iq~"otȜ,\	~to,jCg;Qp|6Cۡ	`CN~E.*,O@7'Y3ٺ᳐ۂA<L^3n b6\i[80\8X{^TƁ F&-kBn_%@(&ǾB?7כ-[	IVDcJz_/KXoZe,퇟ܴ͠t+ߟ)M|nIyzo-D|CtwU&nB-y,Ƒ>#&?{'m25v<xpŇ7_^4ʋąZGt{.C<z97ԧ:>FR2rf8ܼ.;&_L*q|Us>pӋ9*tuR}Iڞz"B3,D=SV0
C-|Z$!^\lfW 6vq)NJVB`v
pm sg|^EcӖD v7xh\d}Wl?4vpqFXSXө+:YO#)ؔ`Q:Mn[:Ա'VFu95qzjn&Sfڠ"=2wTX#qЛ1i/ȐPJ<.IG_f3>X__ʣt>ndƺ_=>S]bCϐy1aұut3Ƀ>^~FM_,H䔖7Cׯk OXvMy;q6{K_^!&Qq$6whWQj*q*lThħ?FRoΐr.N?_tK^\hq4Q!|t~T[3rle(o  g㎶6<:H^GۯK.ؙSy'u]h>otQ*;b|tayr=WعlO&]柸uJWۥ={4 f)5	Nfozx˘r٧_Yo~t Stv@|z~nSp\ɰb3NU#d}.*Ϝv~Y|Q ˒Q9@zq×k=
L؃O]ԿW9=yyS91onGU 'W]o4=8^wp;Rwݿo_2Lp+:{7uOݏV~x?<M`j|02#|7n0}g~sͥoYL
86&uci&	AOW҂`f1M)JzҠY!hmy8M"	FZN$i}{$m,G8PdşI.iT\荚1c3ƍ:9"M!d䇓BÀqذw[x/FUy3r&'GV_Xк#E1nY0Kngҿyze{z~ag(. YHN?y8h]:(ngM{x}*7Ň@Tmtq(~yA':ּE[8fi+g!0oe()DW:\YY:5w*.
~2z^8:7"W,rxf\豓ktH*x½ @m0t): q}v8q]kDSZrK4>WH3Ω!j7+s?&>iEO|Fr*Inl3PYX4GT6x<MA.~c?"
8F,̳mJ#-<*do):o+]^8s;<p}1c},r6x2=Ά{8 k }o2>i;I6` N#=gϞk^6$^׏J9ƄeƑ:&\X7M8Qs ӇAT'ǧe<F`fi)p:krdFL
5rR~P{p*MH8Cԁt:W}ɇ77ԮГx*u[g(yW_\}ݮ
Ӗ繏h7ϲ<qOϘclDi _ɠ= ];QYZשAGBJ ;9y[2PnmcqZl<D>dQ̻U93s!3整]dfyOOރF\i`:<]9}7TwDg~/߮<N2r@'25Wn]#r@|	׿{J/awp;O	?0`ځp2-~IS<kza?
vlt̅4*zStl_eI+N䆕HojI!Ep&7'?_sBI#|O[>pѻd	fD8I烿9ތI`	vP!*Sn6:Bhm"P[Ʃƭ+u}?._No(O9S?57>Oc `PӮ%TA%x)-M:o,Ty@A7rIt9S|(N#X2En`$ru&Ńdƞ޳$yGE~,P} }لwy+|\nҨ99zdm%ؘ8h<||x~ރrc1z[J^,LWW/gJ=/@f^a?E躶IiI^pR@RJO&QJf!';?H 
6uY1| TEATsDㄕuS}s<,7!9#yyHLD_0|Ȳȓyj{ڀl&?N)I7mlY"IDtU>60$6ˆWWWsuRRiܐY-|ҙ6On0,'$|$}l?VsgXуl_Ô6ט'e+}YeoG4u?	ϟk|xux|wOG틲'ctS;uX1?rF60q*-
si-ۮ<`s^q}8*lQW_z$xlR[@!:NY
Y5
Ykq-u0yǊc|2CD>_yK7 +&BgO|}-~r]1FN+\<㮆Q1`=0i29E>w'[$dA1)\雄SO=#8dÌv߆M~1˦x>Orᠾ!M'igCB/B?:ȓtlvV'<5sIGyZv'3|-$S}=.灆H/_pzk>eO?Of̱:lIC_UX͋;VyRضsX`r7,|>&b<x=FMnaHy
*ܧdׁy@7>(uRX+\n}}5tg1zPyTntOqv|G34k:=x|p?ux?<|}|&p;]߽:7s[oqxU	𾿨9m(1{x{}>	PoS(Vswzml{Wֈ?#j&ȷU䖕4{?_s>GOEbbh56u֞FP§S*Z3Jv@tEJv8c)
='l64gt9Ԁ
Mf	yoMrj/7:BrS/[>z䠧7yJR)D6Xᦏ]2F#8 y+2Sv>ԣЋSuni]nڝ$+O>Xwμ@掯WݠS%&fcNnmM9|\츳Mi >ҁ|@yHAXᧀk(އgX6\oio'ˋ=<xxMGFzu8SGةtQApl=uБu[ R1[7n_?\%ٰ7RNerN4xױ	'肕ֺM
Pbm<<ρeuI<jr2VVa/5FQ4	46OW>/iE߰G]F[-IiN`M'I]
niXdF~м*7!XTdш~X?gwBH*_v962*ӫ}-VMa}:XL~|~67^|`9mog꧚Y zinGDY$FJDu|>!]|+e1;#3ͪU;\߆GsHٹy\7V]w(Nj/xch&++u\8MN0E~fl@VWJtlg9yKxV;oRK.ǥ\ⶻTB"<<0h'zJUא*-( :y~dAYe\	;x*a:A'IέUaQ|oO_;:HҼx2r\lO>lP<&Xe@^lldc2A:Yt/}a3	*k~[Ktϙ$E*(d'0 8ӜS&ae^
6-rWe<H~
[l%H	r.Ć;	uo}IKx-mh۪:/mX|:yDGMJ6i}nNG3|cLFsM!";O_ᡨi 	\(OXH\LpL+fׇ|VYѝrDz;aEϷ9JNaV֒Ao>l_33[rםSw{l:kLc]\߿޿cc
stCoS@EZ/82o߂c5Alׁ%vl WbOB:;uǬ9e5}hCXW(,nTY>Kƹkwo0cC:Am)Pf	-hM)1dhaTDw#jbFco^yuZ/ا<7a*s;(*S(P0srΦ[ȷ -LYEZ	0+xZBqYgvϏuuN䆜&q_[:6֌Ilں?N]NIЧF4˼}OPsb۪fH2U])1
8,V,_Ħ;!l⦶τS$=.ن
ᵞ*0&mk࢚2(@}w#!I!5$)7f ͋,s]7io`X9ڎFó\-oFx8u0Aͤ	M7Q8{/$dN(~B4=[Po&6{ێ;攓1npy'hc?Of*No(៊~vo3x_}p]_9~ӺvB	tᡌP6^K!SQ>,\L[&q3M/UQȤe o߱77-7m"H,h@SldƠ᧞"iSP%5F]uH2nJ*#|۬$p:DVt.҃EJMs|6|Sum9iInnؼyʔ~p&	XQlܤ/^\^xܿįZg$ʛhY4`˹&Gwgy
^+zߢx;xǸ!Tڍ̞&R,LϞ?b,cKVV^ԁ̐o?.pyW%0DbXkxK\}::!/kFY6קk)1+~OzܷRSq_c%H2=<X̛v.׾\O7{/|]gYLtf$ʵɹsCb3_~λׇ^[U%ڵ2Sx%wH^	H5iGPMvt_DA9@*i늧|pdA_~us6c|6IGu6GttGo-4y$lL-
@{V?V'm6g4s6j9'3Ft5raZlbUa#-<O$JȫxS}x  y{}
 l~S>Ju4(K-ZS7Ģ'/ yu2B, DY!#C3N&}ز8IvY0,0sqcĦ_8}$GZCD#V'M]WތKpZlt5iu:?`N2&A_o(+{VI%AwFQ觴sz,4׭yđ|t\|]`9kHR$K\|oUzFw^>:[%Oѿ8o&/ %)W57Gr+o}.NXJ4gX߅RĽ;G*v 
Lʋ+S]|eux`p[ņ9w䰩cxZYqJb=FVV`#~Tƚf ݆l= }ߐ9XoB:SݘgIs@(S$,2)#b͑PZߎk4잷
 m;!VBoIvI_')UF88)@Qfnt?1<+ZYGzćO(&KVOl"-*5;p+FOS({uapXh)ڧJqJjޤnNr"uؤ;̨S!&:?'d#aLyC>
Cl.`G@YНrԀEP}oU=J\G]D;l.	{#s=ڤi׃cw@V2BamGV`	&T"nw훭>e΃%n\C&Y/dŅ4ʗw^;m̢
CO=Ӻo%nxMF?X?O0	?U齐 |%ұ^;_sE7갛@/?'Y$UWք?F@EL[GERsӜwdBQi{zG'E|ΚyVndq4gl)mMLs(5"fijc"ubu.G-:E]/Ѝ:ėN A?98c?-Ǉz䟱|D}'Mpq~vx
^ qɳKN`e$x"o	dySoP-R+ѩ*.q`<	_RK[&|?:iw)D	'kɗMLbKG:W,U9Q쮯YBzo}
3J^_:eAx[śC\K,)->oZk
f2yϞ./dj~N4ea>#|8\ʛ }pxP;cc	cmLܦsm#u62(⸾㼐ym9ۊ^nad>tՅ-1Q\zug,|Ƹʟs^q첺}'%=tƙ\#NYK}=շ\*ꠁ~қ\S9BrћMCh'Yfls~~H'>E]`ojZCwݫn3{8x {o`3o#B2qw W;=leHqT,zcha$Co{GAhub|t3?c[s>,O?zl0/^ sh]?*a_"M#th!6#J/uZ}HuK۬	#[דu}	x$Fuvֳܲy1c,1#m5~F[Uk졿pNy{XC
+Teajb^ r"'5n_cvѶJp;ˑ_CFe	u]cLdBr8m^ܮ Yo	.	VMvGpa'Ց=}ǃl`nT| 	j{ʮ-$sh'0]+W2l&.TEߐψ]tݯ*Idns\HNIn[tX-8OӀ5?K?KZODJ1N)l7݆S~7lu)UNu	Aˮ4QXC'y9?ᏀWzE;m*1]EjP	xq\5_rg5hkָc5NN?wQ()>ZGL+(xR.Tg8Q4kse8h6~bJ%+/1$-tָtAX(mvT?EX+nJƎ9>%{\nū\3`R:}`SXnO!n;7e$2XF|IWɢۋdVn֋'d&7>~+_C:THሔ+%܎R>7EetqfO>#*yp ?.(!HɩM|G(cdct܉r }߸+o~C=yʓqMy)_C-;ЭY^JcdCؐۮd&cI G7r&[}g -ho<DѥS\s󎲤3O{!갦q@Q$=Z&b7" =sۚ&_RnOèt9d6r_K.%:`q&<Pr[A9Ę:l"uS>]%\2&Zad]ЬKv~y?L'$l$E'C-sbƑgJ7Pˏt{^ӎ]tx3Iޓs>%;εK:Pr,pC^AƀJclOA}y@1mFz7^#<sG,=f(G2c(c,;7*ȣm;6qձm9xCĈC6^
y`41ȍ؋:->~_c浜1.o+7<M㮯Wݲ:,!˜ siC6CĨ/0~1\oP:(˭fy?<lm&O}]wluMOݺN%\ ~}"09(;ek1~$t=%,=Wv[ҟ~ɠ$KRlA>\&v"ܽx'wdpnk^^9滼^JCvw9JO'q_!CV
w+6,a5"VX>^E5e#͠{:t p-5cĹ(JJ@h!XOsṡ>?\N&М1ةSPId	ItY}H|-cx6H"./.7$˸ߦ%1sE6|0"}9aXWM~d7u,XsU`G$80?Q2 BʸԐqxm|;<ѻ-HnY>lOEg)*$Ʊxv~oX:mË׮%8t#P62]7A6O䏆t^c4m9=-BXLT|N"m6ah>LyL/ՐzU@f1s cZ>)X3I7|;:{48u99lpS݀0]IVlʈEF|é{J__粑ޏqڴd޿	ᷦ^'pm-hLKr`h=#@wKNi q(e9L#f	o%\nn%Gnh2#ܭay2?,["b26Z"
~(3[_K
B
wFd)hX$A5 Ԓɓ͞]AAS_43nޤOy}rKsJo1ㄺ%3e	I0	[oq[yAX$: mP>h^T0L91Ë-:pkhԃ00
"8H`Ͳi8	Ô}ybBB9H'bÔ4nnF+:?9z^%4ߤ\ySe6K7Sk M'r3Ƅ@`m͍:8Wsx6=^x;n7\Ǐ;Ë1tFEiJdzGd}TgC;s|\O'g1<Y֡ɡ*/`>4msު#ڒ/A7AG<6,CNSύJt(#||W2^B*<QʝWt)j	qAQXOŪ}7h5X(?7BgL᭠}xEw$i[9`!g箛Ku!)]ť5?Gʶ']?)3'vj۱_ݖ-"_6XӵKrIF	glv)aym3pTj1(	AVѷo=#uHmPo0eseoHOC^Ԗ`o,s]JxI2 Fej'>ci_%o!o(oȗkT0ofQLG9p*yṋM'pf@>a?<`eu-i<b^I̱L̯c׺\+Q:7Gawx"c>׺mKo8j?o(ΟH4e^*Ιw9|2߶ɇ4ML<s'aZC6+|=՞GRV,󳌤gIIg9L܍n;&[פN9zt}߼v_첓ݞ(QSf<I]orŵ8޽ӛm@+}gY9Jy(є}GHC.\ܗݺUra,3[\P%_!YL(ۀO\hQ4,$8y;Cs=Pi˴g!CMIS-<#^}U`S5Rs>_9DM˒02;5e-|Mk&O	 ?9I*d9VaD9^%Eצmpx8M$g150&kG)vgbVWu^Ѻ)oPCa9/uk>>c)[ưh̓:XJu޴0ȩQ$R.7'OiWbdp_HJQ\S42Sɢ*X҄;eOzg'V#4Id7f Xs>ƩO[RDɡt"$6XHIW)ߧ)vDB7MV%\iqI?GG`8*=c\@"'.C1@̛s"so>ӽ$)ү/<yPzV:ǉp8xZs!Gm3ְQ'QX.^Ea!>iְ-s'5FT砯!m\{\#+rmylWbmS? fBo85EZiTUb7n09a؅]۴wvqxtpE7L'Pq"/N484N٦t4C.Gό@ET.I9\']hlt%>)Ǵ)nWrz H
akn)	Q ZS҃7D$.eʅ.c\bTu"Oj|3Incw{gp'%W,sYoY"YӉۦԽm	_$$g[uvldq<]X@_/p؄apC<}Qdy,&_{<EvR.~.$"H\r)âzߘ~rP#,XP9!TyQN71vv#$L-IŁuJao4>|C+77[[$4ŧbP<>|jGShQqy}e)M~eG,"T-s@>-l<JY	F2T6c1炉cyщۢڊ,G?%8HL~
K$q+=[z)lY<"c?׌~'{b~Vց[lZᗃxuC5H}D#GkE^ _t~>C@1:qx,6NDH`ctoŜ_p<Y"lx'Ųgn-EαHƆcXh$'ro+x)iɛAem`B#9v9\Irrb/"GXV3=ְ\!q-|HI҉&.X},Pq6w.״oѐ*ڶ䛷uQMߒW>cUᤤ4>hnH@WgTljPaQ/Y/{HK7~.\a-J2inԷ4LxgZ/B7g_Y!_Bq6hXt a9jBeaGohUA!Iay?C@9'] 7̌VAVآo*_l2\ jwb泄+=7 L?+,%Q䟸td`B֨sho:BߒzAƑ|W[i	om95`#@q欖=֣O>>F6pOi2jM-u{%61bNBӇ0Nʺ3^PE[+er^dwtts & OzSڹx>V?ӗ4f'n
gtb:8}Ndڀ2MӁ㗏6/Ȯ7If7~[7Ov,"h [CFy@5-~jB 3G*hB[htOT҆|@u$/:ADG	lН@>|urH5Q-?6Ixg}4?x,JZQ$˧OMhǟ<O.=p-t
sۙ3`rw_SJO&~7ߐǤI/M	rě>|˚m\?trW
4!Zc}Sn97v>y6R(}F(M&9ݪڔӾƑF5vzX7TJ\	>&M`TDOL?K.Gv+lt#R!u]znUv6o:%F&6Q>A'uE8 EuЉM85OfRܒ_6VĆE,51ŋDp$VZp$lL|IoS/ԣ@8HkiH 8'|KYqb s/Kȉ.ۣeC6 Fy>(^=tkBoM{aG2?ϗl%L6h^::>h"1{~v^(b~)ŤE#:-:t F6x=2a)7o6^oͳ>e9-T<Hl_R#YEԝk9
R q2Ir"o!%zD8夫7a!u/=Uױ5-23<8#9ތQо'x49m%yy@p%m
z( qdrޓvoOcoH|?CzI]5ƼtJ%*Y"cZ\\rZ"[|}W,)Vlo	T Wrጋ^mK}SmlcAiiwŨw9"h󞱛V*?956zbl:a(cR}n&heKHG|Sյie)ǛavfNՍ?Ϙq8ve_7ݟ4<?e$qtԘza~B\k-ڔbNC+,zi@Y0;ͻRu:sTcp}RmIPOg_^h7M&NXxuEr9gYU~ZOh=Uqԧl蘮>BVy^<)79O~&0oZN}˃FiFK6x(߸n҆oOi)x:g3ߋN 9abflg嬛z~s:|vco2aÈrRȺCz(so$4xD[G\Sʤ9 6sPk8Rkih2r~Yr9|4[`aVsimoۃdR,%#ِl6=lӃ)㜇tz8͑;\|	M@~;trF<5E}ܻ<0B99@0F]q3/Zw|\oK}\gg|ݔ!R{ǎtD>+Sȓl̔k'm߹&c(ze+S`ʚE-
ôEɨ/חR9GB?-;|i:ĢcBڸMZ8AR(aWIcJP	f4Azs=]WeJ5Ԑ#¦/@Η M`}.\EMˌQʓO_?9>s9c<yz8tRic7j؛ #o5j<w1d鋽}	.ts#5\G>|#8K's#Ǘ+]̵,Er]&`_F
:!PކF'm9XkڟծĶ%.GJG|B3gIv"ʿg<H4x'bEN^Tpič y:П?YaNdU@ Խr:BTE2,`&0K.lKT\_::zZSї'2<f6)
NjQ?BlI_
JHAЉbE
U2 l|r1&*|<FӹH~Y7
1ɔaت"N u6\Q5.Pt%z;zPLuZэG>wtl` BYc|Ǎ8g9&E&_ϧgc9x?	#!k9zx{-^S+X%Ue FR~:Q|9Зtn_*oh蝟-USG&Ir8H vךda7f-BGEf?O@zbg3W+-Ga]
獨t[HPcԦ4O!ɃC4àa
.sDoEx<Hn.8ӛ(u`%䞅NWK:XOӚil믿7I'I
"~|{'ߪr	%g^PEG+*)|v~vx/<F1*Ū|>'t#<Aj*~KQ%Lnxـ1;8ClnaҜqjO6S8GEρFS]Y=bQYB:ch|ǎr=Ob_Yo\7NU#)7
R^ҡ=λ\v[@z|w3EGeO~"y]h#RW_({c_}qx߾L
K6fMFdPSS8"PYļr/g.Qut:Hׇs_s%zW'_^]]+;ꈍlJ*˴QeMo@[-<jDK	%"@Y<͠*(/z#χAt*7vE/SضUjmpzϑ@o-?Ri$A/&_;S㇏[cS8 cg&t"\"|)3z۴cFN! !¤A&s(K@Fc]ϻL|)<k,I?[VzLs]f
vAF%[mOJr%&Ps
ίaE̞XGg/,җ'o
F7ѿx2:Qa=|-fRm
W: iWlĸu}M6I* Hcעtʟp!Z*q<2 7^ʝJW(rk71;J:|{_itm(>jjЊVtvs!4%3 TZ睿<pHy)j.;)D(YIk,nV3 2,"ogCU/4'p/AN捣0F0g $왯7.//=O!3oDs-2__,aMus}V/w4:M%?I:VwxI6qp1pߍHiAv^ :Msa+v3URk;0Y7ˬ<m7hOܐ ,I2&NhwBjS^{	c7kSo05kI&tt)/ý)L/|_INCah<A<1Ǯ{lI>7p:ٹqb@4%tMUa][!ș>C":bb͹8, 1'PD@I:gi脣fN`i-^|s:m-bMk`C_}\q}UT	eY`,zbGk$IKSD,nE%|
qG\x,&d27U׹>9e^-'-LY&d%œwoX|{xb&@2zObq	S6"S=V8MԢAOqOB'5->QE4:3´u/zm]c-WuIB:/R4|ZHMӮ;MMK_?_^d7񑛲YDGleT:Խ*)
C\SШSOěrY-H7͊=]|Y,OG̱/7l2yQ諈 jj<;7# H>Rd62'v\NHo5S66QCMy:S,БА%?<,'ɗq9屭Q}sej/x<~B* :f0pzKJޔr'd吥SEׯBB",f3*7E.K6p}yP@.ș]2<{h62kH	zu5@5C?P[)K0rgm5#(gJyS'`PQP=7z[.+؈[%۳	=T9>NpM~ٓÅίs9o(su6OoӇ*l: ]o-Wz`MQ1Tuc?<WMBBlx	iAxM7Cq.<˹Dz෧\Ϗ-4Xaey*~xדz}޸̙#e#HGeAǛ[].
M"JgMVG_ɦea|o~UD@_ꌼSw&ϙ Ff@Bq1ub-o$M~RV00kNE642@pK;?.J)~c`h.N[lǦC<"UpKCZ/ozb#r.lJ %a6~U,4E=}ςvӡ?\1j;
W$[ڼ	+us&K̀~:Jʆ(*%M7TMoH;0mtNt"jJ[̫SX{#	is澷x:YpҜ?U><|gtŌwd,.l`7[l(h_߇i  m}3vfU9s>.>|9o9=$3/{yXAG/=SXƝ6][0BsI:9tQcei]͹(?qTVdclgenM{C.׫̛SY8Iċy^a$l-h6E4NBCh͞i	IFt4nNv4CK8F@Hy+MGq!L4N,OhR{?ş;_5М>	 &NZO%7:O4@F7(N '+rfP	eIXm=Ƞq#5]qQY\^vn<	z֏8D$ލ^pՔO@oDd7N߶cA;8ػv]uXK?#3'.}x![_ulItSv>ē}:~$iNA=G!M%98	>
)λ"'ы%L͑aYFYQ,<Ҥ&6	[Xd"<&i
,e1:te\\v^r#X/it,}r#biRIyRc6'ҎD.
,BO-r/CdGB8qcmc)|ƶol͘R_c2<ӓT󀖶]~OVѹ&m6iWIcre0
MiIݎyQOuV"q^V\e=Sy6i=FI'W|ܸrctwvoMV)m}f/pBSkڞ^ݸ!oM`y!Q\.4)	")bf̥󌩜g$w_1c3lgn<
|ܐٽs%mkڐ~ƛWyA73]+Sߛԗ6e	]>(:p[~~/?LڋM|dP%
ʯqam{R?نI}<?Tg\O$R1^'=9u.y͑##t+Yzt'P^ʐ<Fxr@sbiB䓾a^	[űl͹I);5g3]{q
N@Gۍ&}/uMi-lGHIO];IӜqnӤOW?rjqu`c;nh'I]%kǡe?"ߴK],_W	3:Zs<,2XdO~m"!~z8FRG)6LY<\	,UH~YqnUy3L[)VZ3H@ڙD)k;ד<~Vef(=8Ы0ќ}gVr8%#vF' mH1gI;% H4g;f@#8DEǍ%+-OB!a|졞[ܖ\sՖ~fV)'O>XcP<n`'%dOꑐ/FY˕z?6akߩۡwX>]Bni\73NZ}4fKҫʁV楽y
:PO0~oQL(ha默νЗE@].ad4i8ڟkcZ\S/./oP=IikLg|Z7ę7s}< :2y/0Q$נO$G<E%êe֡5wr67qG>/b#Շ93?`r5.?ru1.ldN2#2+nWA;nΔ&<&6% v%=vl7rr#e2Ĉ,_o57rk)`V<S@YVZ5_0:I	)\L%5  ,DccQ'S 3(h$eA&&aVNhlH|C`` ʉ"a %Fegu
?+hV)ߠn3Ȓ	~2]׹62Ȭ>%!z*ϮO~|1g -IZ9緓iAĦ|'AI.(:asыn)9mY: 7]MI}XPɱ ΨWi8$=~6ME1HMW"/`c:c+MOZ$@,~cc&9,>z޽K}>äFq!K3!oǶX3A
E:b`a{9g&w1cBd| 뱋);aɴኖ7|Fh 4חs	[ɓI[h$E,u^|ѹHKco<8Ӑ>,/GX.NSx
8iwJ=>,59q9Ϊ$W]L@p1`?)ut=L\oĎ6F'68]߁:ysVDW|qpme^q)*:?24!a4GЩ,9=Kҳ!yJ9I>?x8)<̜$3fvqZgI&1:	dɑ?8!po6@
cC_`77X<V]0bȯ﹕$W`"kGuev0Lz:~*K<h{$.-3FK~3[z]tH/&;{tH[g>z|(8y+tr8W	ԫEE%	'{kc]3]㸾αM^W˳3٪˃!+W~~{XlJp.:N2K-Q|/|8\5>Ѝ<faG!dJ=çnvQ*[UL"WݡwUEUSyk,\,h!XI{?[<At!q}x	],T+l_0cJIɴMP
#:(1^;g\R9OKZדQc!c}"rk衕oǵR>#.1`9>o(W:D<t´_''HLqXΈf琸ŢbVbPd<PITB:ϹN*7eG[R}tD=YO*mTAf4ݱ75up(vOߣi{^j}5Z	pJ7hqa'̧grmڢu|{	{ښnk=_8UgJU)yqV>|"냬6/|h'~B9g+/.󦱜q4CggRD~p#\.s֥9(yNtWӹ_>߸-"x,Yw:<w; DE5en+ ǆ)>e;]7\sRĉqqyIsM<@\L۸J3]˂oE׍}˙$ôEn_=ZzI8.Go
pBJ>°}WltzDg=mc6,`hT)]c̠n.j	#^IS'cMod% XY<O~$7-.FwE[':GĂ	t-׌M7DaM,t݃6Pia(PO#l
śʬ܌Ɯ|y#3y!Got1"*"K<GuH!ׇ]vd2b1bHx)!]6I.<ιuP *uΤE&L8\hƱ8iڂvW~E7_UF
g/^>xܩI_EOm&[LX$ך G/[D `L0T?zpxRnqד|ZʊI[e1	#7mEM`i~@|\i
֧sb(3ado*>FvMV!)x7Qa
K8*1j֫Suɟ~f˴
R	||(DiWl1fAm0Eey*tA?z	 }:1Iz.7j)BH5A(Ə{C\tِyٳye2#AaD	
Nc+@zn.g7i2v6&~KZsN6'G/r#("Et
HdB&|j|y^@VX60ボ׋"e<|uB7P2ʵ'YͰx=vk7LBgCؓx+L#c%Fy[eGbIb#Qbtg_//<.RD?iӘؐ"ky?KH:S_=T)>^||Ahŕ@h"[a<"?Ӳ#_	>ADm-F?µo~r<|);o:Q'W ae!# ~_~t[ȗs:zOxzש{6$O"??d7"ף*Ϋ_(NrCcDa&p?%+eU0S_lS^ʮ(>'֜5sF?"C0q}N}NR|Uo7Yy u;]zu}w[P۷hBIt1JIIgm^n#B 9sgd<n04!4(ڑU-S^/>39-@ܜsz8JNҒem}V*N`lbMs;Z*&V歙X%UQ|6M<ݴrc;i칤 M86泷-U$񐃙SlػO56oiIhÒMz3E.y'GW 1UkT%HLt˘aXϵ3ø:יS@y7tt{,zy{96bX{x`FlNo&}EG]dd5oNͷ0&3Sr_jntw̧y!T)G6U!:vLr}5~M#Jhdx@*V-ڎEpMs
&"pBH'i8Vcyp[kGHOY&쮮[hWOńK|:N2UgCN*;`B^M_p3	` ?E_yx"wkk0X">砑fCq	?:Ck+[F&{_(}`W$7o8<F4h)WkON(b,Io&w+zH*ye֛YͪV:L%"0_C'4)Lӡ+ff&YX	┣y+D9i!&%;чW!zvJg=O@Sxrm"cHoFW5i$Xe\,}*J:Gsg죭e,Яw~;-NO~ԛ`8_`%u(`b[+/_.׼^ 1F6H4!> $w{L(!4Qޘν52^ |N$gB텡k?%7Qr]p`aO:[cНP'٫04D+w[8s^#~tQ)s*mz?N& jע"7!qaᆇ~@5][h9wɽڣ:"?={ǟk/0N?`Sߺxgn+PܖGt24\L=l<7Ricӿ.{beAZtFMYɱR}{	+Ae~Hc*>1H،1 .*4$sL&G%on4yl|zi}U|mEq0?e抒IzO0!lӧd^@ rrWG-cH2
lVJ\o$%+'07adK[䣏Mc\ϕ^o.?;'^,qaP -Ө?W92QM%7{WXc{/k3!ʏ~o_j\셍nuc!qDu o5o4W:XaZ6o);iTj'Mަ>6#Dۤ\a>DѭՆ&TMl( ӆk4QT):w"@Yk${.SR2yΫYO9+o U/,q`R%`hK׺=2mui1v~O'tK1FaCAlUÜ.@XEyXoWzoBwm1lm>SmHuԹfzI=R#iPjRڠۡa}V^SS- $\F9N?σژn#rXN:
GЋ٬y0-bKxX.CYF>rX;cd3N?x?[s4mp͉n;Ʃ:wS\O
sZ?9^Z[^1!'Ԑ|ޙy$ȵ<&y$\i\iine$y@''~q=!+~	lw$Rz֋XeRzo(6~Յ$l圢N)7I~1yJAM=uW$%+J%h6	&vrZsǖ~*lX#Psc7/ JJzP+a=G,W0E(fWFVX	272&!IZ4ވdհV=nPTa4$h"{Ԓ[za'n眻+%tfPI=ύS6s~?8ǿ_J&TvIϤB 7?tdz2NqV+\7)ΡoD'vGEO1>AӿC*(4#ClP%01R޿CdX3zӷ$m6D%]c1@;}TzCtnð?.:Sga&yMj&|%CGNr	$/"[ybDP6#Z,3ѡfu6Rޤ 'P:͍e!.$rסGOps\&P,ɠ<5Psk0n<	 &U<?, GENhˑj7fjh[Xe 1N;ry.ќ~䘟'J,2zO?P?g$Yy҆Bl;rT^<N]eC++Coeo8lŝLJ^~"3if]v:bg(LA]:hv~[ym5eO6kBArLɍ<ڎ7HAKid\s1Ԗ F[;%ܠqٖRY;Ag,BwuE`?)ɂzb{:3M~]*/du#rCNQCdfA;c&ex,'HIG|'︌#n+	a<fT&u&JDc,Dzma=.SH_v٥櫜, {/[=NGdʑ斋MlSe.~v`CO9H(UC|l6T+?|QR&H+᫟@%\zR}s_T᫯7ƆHoDO6opEWW/_:/۶??ƵZ۫뷖h&@~ %YR7y	ړ?@>E#ť3=Q=/HrsT9ĹI<*Ys[62Qϛ=\Te0LߊEHX2NVXNxqd£OEs8xy@"1y?ŭb<u<w170<}$G)XO{i:Ueׄ/K'A$1t/,bc"@IWz**ZYA܎6L蔛lC48|/[##$o-*chg0D)U.oAÓL5K!	HKSXHSB-?TBpBq|P	;Z|;hiCg<p #sN7>m+GggW (!zB4[c;a' רpyԊۖ1MVujw|@kždX'@5*|ṛ,bbqVs_|=|+H˼5ob<0d͕!tzW>>>lh/Hz(*.O._귓S̍{|k|qs=%tO_hͷ9EZƣK8ns,<T&,$gxQUVӚM>
dîE[5Pl=oBNZfll5L8^"xNcU)\`_ןP^?Գ0p}s?vrq~~<9ޅ&Tu;\πÀI?gM'ܨs㫁1xzD\31*vTx|(l Hd横beg@nL%,Ŝ۱	"̰%q'tkɕn8XNCq)X*Q
n*|S\z_fBϟ'/ܛڢ+\ܚ5!(~p*TY[]L(8ϒ&%IpZ'7y# b߀bn=eҐqҗRnK3ڄP??t%eH<)eȘ'mU,>fIq~>0iS^>4f8><<>~vl$NJpχ~dgF}QBP}4DefQ(!cp&:T%o3ԵuE,&;P(<9&9~Ǚ5'ߴq(t$7(}μyƖ3|PJBM-2^:m#BAwjWAyRoœ|O-,qpc0d,Vgd:WD\&f Kl*ȓ>|MO]\\~y,2c?y?{zqW_~,;n m\Rlb݈.KRs!vx'\.0|7<쟘,qFX@P@mXh#"u/q\^m3%C䴊wI=IWS_!Ǎ'tH|hG)>Bތac1CyYTdlco0ʤȓW//\7-. 1,bG+sk)J}K,aы&r7'
;\qDmIkA3??a?φLx^7$c1lp1LԗR>TNEۈM_}ν*Gm$RbTֺ>Ż~GO^JGt)xc"M9Cq,>
_|///TVcX[|ڭ%C(v-Be?o}s/lpt%x`U
)8aIv~#z2)EwU$[r==FN=чBmsNnh"TZy\ɋ|=9gD\I`,!ۓ7D!Q:eQ,u"6 ?S9ׄ2FBvN~?y2Z	Ч"Cl" A!ӆcI퐃?B* "tEns7VUS65<Ax6BFI?2.dGpG7dT 5۩<'ᣂ!-ZyMcy5mh1;uʕ)8Eۣ,:fC6Tgov1:gsyk6x	~Hcx燯E:x5L!tW?ŋ}{$UO>M^'`+cI1d6rt]s*_j5k?i9*?J7!;z4/1x5*\fhζ1n yK	c!+0Gf:u	B){B
#%)yMlҩ37@G86edM%Iߑgta8ȡ.=ui&97ne+zB&SSu37<d6{oziyJXXQ&8+Ph/~{7^`Gx%f dLW+J~>O擾xj`S4J"rThc`]%n(m;@o2~Ց3YŹ^ׅ!uƃS4it=B⋈1ڎ0MTjc?)c\ɳ.=7⫛Bnţߚ'\WκULWsc@%Ċ-ek$a.U*+\r|˳>~dI^{SP!SmM!`Ēy.q9a-$OQ  
1`qHח>>PΓ<)M@7<zK%/YZ'2&"-%NEŗ 	;^>((7vdIџFi'!H;XZdioMU&,^+!15J4mcoEjYK1ä^-(9슈Ak,,+$olG\$}nr;m`;y#lq6c32(S_W9a,b_-Lpu?+_w^RAx7)^\]g,,g@[b)|V eoyO?3ctvp@sQRNLsM>Mӳ&.4z<̡D!B`(U^7ЍB^q~*q4Sh<PkjdeU_COpT*F^^OrZ~	 O_ oDV|o<N6elOfY.3CqK{^ϔ~Aި|ggŷzoJJby^89ːv}DSI
+qdZ
ZJz,\7D6庤4U)䅗ʌsPMߥЋ/4*d3nN:_`>e)9B_>yJ~C_]tӋf%O?1U6 ?_\Rʄ*l˛pcr/oY"Î2}.cpeIݨsD2'켁KHܞ\ʿ}9D?xOl+Nㆮ;,.C^H$l+Naq*ZȮEbn:q;r 78"Pg=O#RNcTl 2o١ӈŝB)!9M\c aV|[]%n2ou7UƉ]*n4rV..d=LCQk{4ma5U3QjR55U:\KS>$bv+B=+!68ÚPTp׵:??̘74y3c/bl7i>'4J^Q6_u}0ח )6ЛM_[/@+;)4\./7{:iKI!I:$b_|21_*`gsS9|ts3?fMYU,Gzҵlͯ{ nm|4ė=C1KנvBn%`LC|lQk'dO08td;RBwWr	=1Dꢪdn8AY:cr񡙮σI4xv9?Fӧ3*ӎ.3O&?xҮ(
Ŀ/_?OۿWV$VɅ/|a׀e 3@Hq3sa3y`[=+*ak`|+V;~z2<%XrxFG'?	!Fh	Ca;%Lt@̳hۦN^J̔^_0mK?KBi_B[`|d7WW!&ML~xp^[vz(âq'YQ5L2 5F׋>,e`Al5ʂt?	xWi=ȕqE󔢹/4Ƨ{/c#mWH!vPɫvlwnz㟰ӸH9N?_QDK.98 S	y=싩/mlu1*i3A/{A-{IG;ʩrrQ?$&cS&o-u#ʎzQ$?JvS`DHtOo0y.KgYOd7k7FQOڌ$x䧋/
&@2|Iz4x}xRn>IgĢbSga7u<@Iz8oveY[yT5U8b԰JJ+:0V?˹IYusEU O+t.Onrutx
h&Z_MgCA;`b\q.Jґ&ʗk7\''_da/$vai6{Na/:ռ䚐u4L 1[:`65qכ,ؓq=yd.O7?qMAݺOyYYOl[]v6Q!G-u!ކF,ngS"q$Cgܠ'V`(H.$Y1x!~CBnNZ-:~Koy%PEdJe5pl6r[^pI`8}Bpya@&tѧ눺Wݸ|ڃ1hUIO[2߳] a*uV]z@v!3}ƗP<NCu&@(qRzqA'x#9c"+oR'hEI:Mŭs~<8>6)V	"Y@\Zu_(tھbʯA8B3?$<+~\v#g+>>
$OVo`([5|"7_3_&AǷ(
]KK3q[28=ENے~QFqN.^ÏNaqr>%ʡsm-:٨x 7/./=2G!=4QD{$~̯zlF=*mlsAE`<K5ldy9%_ D䙳0/\L	_?"y0V#f9 q]۰/g|jk^	v%vVr8>sE"%*1 bDԆmcm
4
4$akU=p|O&fl$9VPmƩ (wRO(l
}?FD߾鄨q:8;.,fJ6Estݭ$n|=T>Aݺ/܋,#?pyӛLaE\7/7Rm_HŗSa죏2lqӛLb)~Lx{qg?<pΫcnʫpʙ(*OrDr;r@_OA|e9:΅KpۓȕInɐ󪋤
MGx}>$\H/4}EVur>6-v5F;ԡ qhr}W<.&5m)Tޞ	Y DV&t/DO~*rinCGCDRt9P+Q޼|R7!5Hha$p) d6RyͬG?h-Ey>u8VA~/q|ڑ'`܀dtLWyULҕ~ YA줭9@9(HSq"FwF|s,Z2#Ն,n0o7MP(ET&nhG@Feqz!&|X0n&6XBZ%![[/:m뾒~B[{b^s )伤f?s.q#,вOPͣK1l[΅]xϷ;5@HGu&愑%|snE`I׌#,{T@ް<MYm/XNJ/@R?97Icԁ/I;f</2:~3uy7FY/dI_<*;uN6lj;B{>qM'Lu)b)JcȧN&?)>}2nyo-y4\[FlTK0XWY(+O@9zz>ŧL

]"q,cISz䜛
iQc>jZEᖉ7ݢr]^o&e\'Gl5'	ZlI_p_eSf3v%'%MHBAE(bǑ'!i|:WL3U͑_!Bxf̹vbyKdvt2kP#"1ݶj7?ăo@8ÚoK0cqABcp~L+C9	WZG\v".2mob2/Hpj*t%@=u{*F`VSb?-| N6}Z]v<_z5TIKOa+Cq8@[|ZA6ف;"dS)NC!O;(Obk8P\:$I*=fD"Mk\dg _/lEх{~@,1[>ym"Aߓ'OsM"
\{
xcK9xP =ܓ6xkyiE6Yt8k(=e5TfʀNcQu\{<^2HuyIBˊntnu6Ίsá#n?r*ބ7	)5Q8u
3ВH`WQV_wE'5rN,2AKZ"NQ )=hI\	Qq
H}="ÝN9tsď6]·7U0\9:5E$}ZRAB&L_HGg#s$m-.}u	Lb]pۋPeb?Whb[](t֍-1sDA`cR.> 5Q'#_PcYtAp.Ecl;[|T4,~KX2A ZxD^ciz V|շ	@<t0kbGYVitV!$~T&9`xVދTY`mZelUTT<CSY*Y	!;0e=!dY#| cD94㄁\B.MPx~lL+P` 4Ne:۷,F{'Pj|҈UW`zDC
SC839H$`p~cq&ұ"2T}䆄mMu=AGO.xR,C5)p(I{;H[J<cD;ׁV#E)?)=5sJ'Jjϫzm5,鯽	FBXcr:d,	}țC8X~~#l
'4KG&ee#opYg12G緵aEJdmw_f<1s%~y`Pǐ?k\aq|گAH':{~.mZ.s\ >./O]Qnѓ}%N	HF<TV냄g&,oHy\Gof3M<}0בʓ:씁6}͛<DPgYtp_uoG-0VՇ"C`RZx.D#KS[rzq`Ke}7R,6[:%O}6}TnRJ[<Qid|8cUatnif쎙uͩ)H0mT%3Iz濸hldL%l:vS}Hyj[9rj'?r]aBms=UDraa##?ԿG~η4kQ<W_+jc\sWD^as3S{
([t6}Nu\O'H`,AUO99lOtb3XFv0P|0廤Kq;	W}-[κɥV'Ӝ{Orݡ޷2UMęB5>T?IuElcLR=d~Gy89Q Yn<XUVy>\o(<#Ym:"CpT`4aߡVܖd݋OܟKr1'RjOX[>1Oc9tk+ixHC:gø\b(mf#Ű27Ϲ5G3zsGsz~V~@=o^gV:, "WQls{5N1v2 0N{X|x*}j^)'eGc9xKںCCot*B`BFE`^ ,ϱ#2s21}rD`8pP4c\}Y-DG
q 	XnodQ {+cH!'|c>}iqlJOy3'd[HJK;9=nXJh$M@gM*k	()]u_QY*e0A+UïP$gqoc~]|Od0ȵdEM/FMB˟mdkf91S(t^lpDXHh8i,83.&I߃Ih2n1O8U:غz1Y3m>~un-');JP
y-u>^f"u|;-`MB';t=!CX]c(t/zRGAtN6 z4sS[BBxr'xzcRB#JϨP c9u=ޯ]ʂERuPzGޞhy%:@A_L7ga~U -4YuƵ4tb3}ʗE	s)N0r8A)?؆^2CB:b;P(zPBp1'.E(sy"XĤ-lZh#f^n1Q|'sXx[#X'!8zX	Gz&ϹF77IrvoVEڼ-OljrgxKl6Pp=Юtn aׅσZ4Ν6MC[uJ~62~Un)ڃ:WhN|n;bDr1N6<y,OЁM57E|[/^߸Q,Zk!חeEZTNQi*"Ydaz*~_,cI{ډzaSno}AXv,Er>$"Cc~wHd"৅WV[*'mGQLp2#:6de%?׋A>E)f/Rq2Q_ޘeucP6.&cjg 9Cj|rٮNa88xgCx	&Z_Sro7eic}#uD^=Eyul><<>{zy< \\x,jF;0EuuVlg>>^|-nNG6vzlp+:HsR=B0o#3	>ڠHNa}i?rȣڀp6twO=Dۋ8;CJkhu3ke%Ib!pu}'G.)\@6TC>Ë#MHI;fhC
ٰX7 2uy1:S_<~oXk~Xs9?|[U,*tEϽ-4o5ky}!y|2\<[M5OAhCz+/0|}Qe ϴsKv4Bt6QJl[5dE);_{P94U_GW.sDflh=)rCo`FM(2TlesFS({`ejzG-/~	;v|JZ#7A.gpx~>s*>Gl"q7;
d*}~Ūn|Xa/<[zʄ-%MުLp7O'-S@%SHpB?;?_ Ϣ'7i[O\ƅ!ظ~[ M\VЈܒj*9dRy%Xh:)F|'$[S{!"}ˤ/2D\Fq*UŴH <EA,%"ֶWqO7Z3CtGtD
zfFu 5>Pvarf3+4064TF r]:l"ΧaQ?DGQ<q'__GS\<0
SLS%,8/҄ɨ\[Ќҳȃ߶>ϋL9F>8ü񥶮,9)nNJH,C<gc)1څkFX(-U0d$:dߠȒp)3Oby\^2ἠ^/7/YpzesuM_n|XH&&iS	:_ʝ8mNvo{M"TyCD.6Ix^fn.Dg1K7^N6@<X7I4~PGs\a?[Lw!LH=ؗP}7|O@<
eRۺ>	/ͽo]ͺlX=.Jmk䩷SߤEfYE K+aw6ΰ'R)"|DUG7>?*l"V~aK,$eMh@Gpql/ruPh$>LKZ!e.>}i6Fa	6efr~CټoO)Ybe@ځy> W^	∋+^W^XQi&!-*lI>80Jx-53BoA1>Ocz!P9)Gu.Vr~Oy}uT5;(-uHU":z+4?ٸq6Wgm|&p9G
<'QǓ쑠t8|}ٳKlP?<\?>\^ɝ뺑$nlϺ/%O	uxȄh`Ĕ{[v"[bEpE%߁k$,Bs/2.lhiAf1V4No
3vh+7]6@{ڦ:0ԕp%NSOcsP(ƧJE"f~ndMrB"rq-zGHvV*">*
 D':^ƚt܎h꤭;]J6fݯe$"qd9]4ʵyI\ss'9g_ͣq-[F5/'_y׶;x؊pc#1GЇp?܄|b7ts=a?1]6ߘ%E7JcZ8Z͓l3,g]	v0TEp\~aR^PHͱ/pu|A͊\Y> -FՃ=WD2U7mh	'eFneo|o8mZ|ӎ}I]sǋ@dNioo	u>ϡ:ǜ9-`xLR8x{-NUQڐWBΔ@ZtZ)m
NiBхL,cL#ʬSƀu$Lbn0gTKLd`1쇿_˿d	aL'شRsMŎ2h|ױ؀ZםRykmv[2:hT6}M2Jm#6oT0F&d*rmPQ')2oGT1`xp.(yglg-jqIG'6y3H93OIn&&Rվbz_D(rGatkzxXZ2S;$cOd`.B(i\4@7ÊXD;§%]?pB''T÷|6ĆL7?dAV2x/<Tɑw9-&oװ@iY㜐}y :kIXةVxz3t}Wl<'LVF7u@!n>3CGƈwXLH6C[Vb6s%XX5	~>Do.ꑬBς%od7pK>F\M`uC#K6E<542rkVrjNAl ЍSs+n)g*ؤ_7L?9#̢ٳ^dD`!n`[I9:^lpDU&_=<ol7ѩ#׋\q
SZ#S(3@S:N@ބ>n0#uqY:hGFsbWc#x_Ûld_L^tglM2ys]6̲I	\-lx ,>:W>M^}b.WG~۔Њ*PvژBeh$pKe˖ؙ{oݢV!ArCQF[t -Y!Dd!YCrUKh9;s1"bε<n4X+f1cιVҀԆ?>Qe+:Θ8'vwx=]'6}9`Ҽ@2)~[Q&uSh~G2$K4 A7^8Є|O^On$֘"yk̳ǑPWܾƘgJ"A>JkBꘟ8sfGCJ?|"H~[9#8MAs#`f[l״ (yCm҈hࡓrC	   -,X  IDATTcK~vRcqΣG>{v36b`?|D;0<
;mRV *Vyʽg}# HM%θC5sd5i%h
'\༊ c. 	U'0cc+o?ڈyw~가6"5>z-Ƨ(q%dt)889s	(ˎڦ,ʁ.^צ76CA@D5Z|f8"uiHVhDz^c3&9O1S
:@]*йa䵳l+Ŭ3f!o֎,2A\ZqC_gbW8N&^<}|N[<_ww&,^S*p0: 8@7z]F6`Kl>M3X3EO|fp,
e+]1Yb\H$6`xVjJ\ ]!'5|L
H:gЉд{mU8 (g2Q6CK>8\B}87=PCjrt*fR^{
н{S4(1͟b.:=RM6qU'!烼SIe/1o0-7V"r 8T/w7UKno&' N6RIɈz xE$X6݀q-|Ta9`DSm	Z+^=LX;`cڱ / h,Z41mTNPk^ B
l#]|bɲ	eU".[p<%X|L$6%r\,ISЮF/`lyCx c	ڛxu^Oֺȋpps0}Y3s}iʴDAxŐ:װ6u"6AzJ	ЗЧUoÃ{wET\+˖P!'*ǢSvfg!X]E`N"ZDUa^/4;sF)}] @\姑><Wiǵ<Or7ƖsHUG|Ƒ\l+g@\l9y:8|,_VtlHuœK@4&Q?eϼ=(..^I06_HR44(}_C||kq/?GT{.ߩԷ u'l=7чtVbks7M$`b.YꞘzyz>	:Qi>fA)f	8}ÛܨKcԣ˂7	EQ5'34EyƽyU~"݀)Y`R1c(GӦ"B20oh@tTh|B9Tz8	7?_:o0RAِ@Bq+fC8It8@EGh@t3u2)8~<gƋ+jIcp9ґ=':zZ"7R`Ǜhϕ?9C	S6!pDAxg]#-Fc8>WCBSD1Jd)v*<uoi><~|?9/'Uޠ++sD;j\&\)ih(L
jzœȭgzЗ >	K@v`Wف9cJT?'Lmc47oS㼷JB@Jي)=@?aJh}]؄V8Ύ+k̀&^ z~#&}9bohF]8T^a%Ăycm+u,rǲi7R:'O߆7Vpԋ<|Kz4Hb}]WrǏq~4ys`YXxT6F#,N G:)j\Y%sKAԉ]:;N-iH
FR)_iN+ch,+.L0S@RCj(Nv?	:5>	׉Ao0bQzmi|qҲC[xb6y6ЦΩCbq`SQ31WnA'jZV'dwP<X+G=~Jj8]
B!vCx=ĆjLvљ1{?tёMv#Iw9	"ZcI%i  2Fh$#6τtF?ƈìqXs-
*=dg\{f$lx
Hs_d7O,X6(:[ǝXf_x-b՘d|P8dd9u@| mȪn^6{u6ͬ+6{aK6ӛ']5d367sٽ	m(wۭx8!H4EQqGןw.g|3ĵTp&`K64)5CwBeR{٤5N-BѮ"ئ]{<&.vt~^ڄ|:mnr ñaUPXYDt"]c[i~켕ûT#7wXx'<7ߺoG^LyQ2}s@zӌenҒ?&4Nzַ MKy{tSڙ?OQʭ:N_pMS!Vd:d(vv.\CIt&?ف<%FtvO/[M>5=;m|ej|W(OcfrbHX\ ?-E#v S Zt=ٲL13D GG~L?XcgFV(7DP};lR$9 }7 Ex@0`X8D%6@~bd m*2+;?GOY	A oےot6!#n(=T7{)h_y- i	%QIc@ׅ g]06yͰSz6}Ven{[-Cqb+W-[HCPP)39E]EmwH[ꏍsZC̆K4?;ktJcc۩%=VJ.`yA8'/<¯8sc̠?BcPz9

QM
_i"0BU칽x25ݴ ~ys9P>bT=7`t3ֱ%5/I:^!s>cޠmI[X`+I[P eF7f{^F>+P􅥐ڰ$si7OԧSz+*[ s-|7hG*Mtv|uH]S9B9ܧ,)A	T8)sB{BH[/k +9Wuiɓ<MQMG.@Z*yݴt0>	"svα#Y>cO ]xzkj@l'pMM[$X 55q>~	Vzch/sH$p>t!b&-WƖbw4^2|6ЅX_v+xE]tTmWnۚN2UO2<TQIBHe:^﫥CjvbH[U!Dr5giw''o0`
dZu\Pe0poOם?٠R&JFZV$Ϣ\fPnN[8q'-i0ȃ.#:שqbWD>`?ުnM'IMEruK*; PXbmQc0
a˛P U ,\fT}[;(*Hvs'VX'hG7%NhZ$'敬/Z|92JE>ԏNP> &޼ɦO?Mn'JmEA6<m6J2qc@M\v.h3dB| p-HXe`oGm*7aSyC_&!VlRH7ͱJc&$V>(!MI6)pays< Fg67ľƀ˅+		K.k|%lTz Kn b'J&mcuALg7??\<)׾lR.d=_HvSpcPވ>Msy'0?mkm<mڕݾfnF714c]JkT4-ePiXy#_T'7TQ/4(lHupצk=8KĲo0I~u)Wlg2cK~%վkl@c7c6H*A},P{1?c}9	.n1>-_O_fs!$$o04˗Y>RȻ(ݍnuZk"=$`BCi;Wk^Ѕ\| ]ipF_Vƒvn4 m6'R_;kWhm9@#.IC(yC2|򎃶.aD冃MBwMPoaC(san?lW=%~ʐ*?<Id;5
&SρU(,2(6^AFZ@6L}P
 }_}eV=-ls)o6J49A jVpivʆI3Kԫ1edO3[>8{ycިZy$
D؋w?vx[X)ˁ(Қ	鶐"7q2 B}Y6hc۳Jnc-FJ-MD9`dxy2 3ߍf:z0~ i=tE~?&,1tj9VS8bp uv
ir@|,&ޫ-X$=]'R lGpB8oPpmR?kUuLxYI82֚nɯi#d2JQN;XǦ&](P=ePzO*66>rN1h6v89VO<e|N5~ԽL3	ڤQS@M;=iE*\>x`lĽQ9g1CǄLk@O'I_	QR&26Ch3;'NU
U3%N44pC4#
@*'vR+@NAt8;]pF<>JP9]p>>'2TFcUy yVchg*4r $۱`Z=8CaV}h-c3?7,e4΅[x, 0$ $S09Sq}"RoBV?n
HDWN,y
F]8ad*4Kcb9o{%7'k4ǆq3lcЊ.$]mWt/$6*̛Wu#KLU]Ok9rxe}(?'DZ6f1'<P27Q 3@Ki I.u}|avQZ4={ͅg4VD?|G?u.Rn*vBiM葂6Ϗes2u} SFfc{ 	'&9.</|nu5-l3b	DOr})tQ1qNaK|"]tL*#Alχo좎fB?7m?|0ږ~otXFx :ݐCk[\%XٜN;J^oIUxl:7y}AOg/٘4=efsBx'C9ed^S>eڸqmH
]Keܺ$jaZp~$Wi:WP>f	]ۉPA2&Xm։c
>tGfwl7uEkdhn&YBaJZi_
wL;TIf?J|QsJT\n+NƤ۩u AC-ވOA `?k_~?ɫrp9:pES+}NqTi4I!(7pc*uJ1S yF/L-#ݦ؋.\+t-._ϐ[huAk\W'qR?:V[xٙpه9xϮ<$6I:uҢk ae6EIh1lS% ~@<
e̓iԡu;d>CNH=Os+k; Ș&&S33knIY/KO̓f=̧GK֎UW3sidZ(
s-ao9tha܄	J1y&t`9BD(0@4' =4DtVU\rI1+4N8`ل6.Owq.pH2&PƆ)^Z~<L5G0"-QxF+ 1)\KOC:ikXӊi|Z*}:krok\:I.ܗt\tjׄGS|ԡxō7ӦL6V>V;lD~j⍟d*0.tԙXJBtW㫡3K3 VPPf3;:RAV[$WbT_	K?+8)LJUa,DÀ3p>>ۼYQCRmaAnt
҉k:
VXͶJgfm0L1$e{  ;J]W<ϓo}Vsޚشmjm2@*x~Ƅ2o8SIt'k\089*$laNq)֭;Er`W\\8#NcՖsA*f"q a4b6
IyChMty^qzƔ2rp,	${AV7\3F\(櫵tjC	("{="!(4f?'g,F2K.zfO.>B|q#MH;,iya']j?]mZSAP;dZS~dWՈX_ǚ
.}1pB5b}١}J~sbYq3h&(!+YI>	xVm瑛@lSG<dQ6wۦ~s@H3'뛪orzo$xF_j;H Di`¢) :ׇ˗/^L;|R2@8ESHb~,ŷo)/aEwg,K{XW1e։^v8G=th< tVV1ݠKq\~)H,XȽPQ5~iiăN
xɜoW23-(O7>VTl2ejZG*mQϼϚRO]P7(e73JϹ]r2l)VPࠃs 4cbr?7[LM3k؝UA4
Q0{'tAK5JT jk배0b.h?@lDdb+oXԯMc_;vEbef-	tCC#X>tToڇ}M'	&!
 2 uh5!:BUrS9g" I$7	L{+˷<O[J1׼@@9dh;ọ͗s!!чFǆ؎'+ŷyׄazH98J3tjPWZ:Īi#	Dv:тs$bŝ-NXX	Ov
>alCx	;(	syp_QS
8A AΡaTs@gmt~V$熩BН.hi}SZX1tYz, m3!r*F|t#C~
]#.UAK,&}U	@:]tB÷Q ct&tCIH7|?q̹2ax/~1Nƨ"NyQwC2ȍW@e`WlX?ĝ:yjYLOXt,cfmTtCQVP^48Q@tӚi>0+l%pB9wlp	B JX- 9H-֒^DT'Wʦo. Qk ¿&/Ũ7bfsPU}yp
L$ʠPrI9@Ƣ,HoVZؙ/4g_Oݽ[e#'\*eNPfszgb۶,c)W?:, onJvԶNClؤl`Teڱe"7 ZPpʑKYq	Ty@Fdy 0fXHH66SdoA]	r˓®ZO2?q
KJ߸/I%z$xC_2!Of?.&r.Nw+NqIW)L$ho:ˆ21~A1p{<	9w%/iHF!1ĸꋬ[}P$2o"F_@Piۖu^")|(k~"/>/@MMLs(y+1a1U،_.FӀ"#V+s(T?س߶,Qt$|	0~\99~F?#y3~5ʣ}\Տ"<g]1c#봢M>??Upn(de<NNضTJ973`7pr݁/q;$;:?֍@4lZָ%/Air̼B};{A#tNu`Fcl
oqTYgvT(5nQSmyw6u[S6A*eD1GBIH$\	tlbk1gD]>ږ?*GM	BK.)l% xMСb');$mXQ?L۹-xo!T rj&SHm"`8ɷry^c#iÌ&밉;Ls 3-<}0XI23'ofŘ?ތB5#9JŲƻ7oX	>sNI|BK:̹:!mgT "E>8`
aqޞBMuƉDO6ŧ{8 YIuP}. -Ee#uE1(n3(Z(Bj΄󆴚$c!RkU\E´B1I<pbp_s>.>}:Zh>>ڡ2X8<ӄjozVV>& f[lBQ;jj`/6X@!*lߓIY"+|bB4ڽ	NO~{/K7pME*`rLAqr+mnStQN[KS2`v)0O-o+	UKð2N:qXlFRLD,{g:A$S;޳WqZ|$u=VI"L-ݞ'Z
bI~@5fd^ize5i(NlOi]m	4"!.z'dLلz>,0Մ/$)N$A''oYʧպFݣe0&H24adYОJJ8rN5(x?-LشcUM-P_%M>&O6&.y iћvO {lа)H,m(چD`#yrv:nTNвaioW;;,eVM܌3_I5:MHvm.§cZ l,U2},@tuhڎƔ|G$5"ri?0q͆ӧO\W?<y/G[դ_nJ.sREH..<oSfZ6*ixʗzvrP#U'3L
oQeoby֚cNz"cL`J['7gV[єvBtGARty?ƮX2r3, o@7P(|S*"rT*7,hPn2Nw;aY勗֥/_bQ<Ō/ʦ(]VQ<eWt]ooܜO=J|^m	q>KlӧT&	3lHK/IԍzC E9$p@c Ӯ }6@7%m ^sHVec76IW:A^5鿦X e/['W)*gօ-b/.9[ܼ<3ņXܢӴ	[͒̧< +$'3oG`8+{؈^'6Tl.G+uf{BYv_X~gcԡX["WC$PCDo!K/H_~,?
.:ZuciC絿nnXN"y ^]3C&{A#x/7/s&Qp%SV^Bڄ .dp})jVtt%<&Z(Z	EV1e!sptxmI$C4?|[yK}~62H{~>@_Gʻ&c
~3H6`ظۧǂ>
n1ź8直^FтOȇ1cWz[bۮE)X[ͩ-jXFӗ]MbxD[2?f#LYF-0O֖6 7N_`wt ZS!
B&x'`A3IìU6qxmL7y++`7Q6lԕ ݖiXv΃zZhGo0=7-kB]9#{}vcs࿖}#YA>pWrFthT`KLס\G11q*9gƧpKw c:>}H?ਏFYv54[ x]ЅGޜ+>I_t<ѧR{mc&@t|%|D)GNN&|FdR<5gG!8[/O6X_uZrc@\VXV;-:LJ3c8͔i^ͺ)U>:(Nܰd}Ħf_ASk+Fz$ο뉣5*ͱVc=0	9-K<,l@DE@Y-Ɵ|%;b\)Ӕ9ӎ(]a 7zoGfǛl/} G.+}n.8u(A
A"RoD/y}L2՞lѦ$ԩY* 
|7zӘC,zAl@"{{$o'!'yۏ?<xB_s}Mn+x(v?T>wLtL?m0]63%]b&P*ըGYOn BC*[4\YJ6_?#ڴڙNub5ш;+|wpS$+phK-̉6#o zLPmw3[9!6!ؤmYH_P{yAQ90_d.bB?r\`/GD̛$1IvJ_.G<g]|:;{|xX?獢%&Ox̩xꙟ+u>2~c@2$$Loo^~v1Nw:p ɍ,ʎW=.xyKLz!/ 	K*˦|l~ Y[u[nwڜ|es	qSﭵjCJk"AU)v$9tm,؝_%ţ<G&-sK	sn;InQӬ-+2NĢ3`r
qY<u,ǬkY'PgMH+lbk=:?t&_oO"ߣx uO@ ?Xs|ʊexL<4K{9	4
O,s-"}l8	<n ~M Dv0gvO)N:7:!4i4!͇g>>?̳U(yr\iEGn`)Ƕ@ܴ
Ș`s}d'+ˈO /"nO?;<9zy:rf4kMxxf}OK
eaЖ6q%~5>]w~SE5tuh/3=c$tWWÑcws,b:kV:-DsH>Abn `eb\05Y) evņHAHie^a9ayJ(^h`-W( (ZYVZQD#enI):6e؅q:4`WHņa^q)"ø1}_؈OEh27fNHԕ?'ZcOt8S,nl5	|{=;qx$)n8]B:'oĐM{{L ܝX-^J9@&_3QN&9 MBˑ Wt[:
-DC݉M$յ-({#IrT̓8'uf3k͔ER',F\؀]l| Ak+.hV	B`%hAB.VƸ3"̴^'@r@l{ #X<-鲰/#{,:?{nQ6$F5wސ`W9WǏ~xO@~{x}?Yf2ܨ#UqJ`^a&)xN!\Edӧg?zշSC%	lyI̛GcZزʿo ޳Q i74(S1Q׸?h54_W.	[ȍ?	8qAr~TCh]vz1D7 RGOX ksqK#k5?EK4ą!TY[7%7~h
T69297*%Mq1.J,qaެ_|~З%kTHkKȟDPZH@LXm*3<GV~R&Kl 'C0u	 qXiB3̸̍8n>ɘ _[~cL2>G#B#x־cYB׋>tJtڥT9I{c

>;0-~Q
< J9;{eSgC l6oo|g>Oݿw?38c,|g(Ky,
#9Ʊ sK:DcbwOȟ-k|B0ͤYge-J`C'GR]xpRŇ1}UFfx,f8m(/pM5?XA'F`^}=Vuc@yIY{p_WCxF~1&PKku[|vZ`ª2| ;>,5&&o̻Ljwvh1xh{MaUC'ms7 S0gdS2SΆZ-~څkyǢ%c|:C6*q0;x&|EdSj&>AG|o{54=6{"'ǺħvtWR6R۬~fXsiqeZ@۞I\'@tT<-ߏ1KD*h_@%P	%ΉgO|ӎqp
Ep]q#Ac9'==Ds9stq;UUNurח5xR!s5B6c:f«9Iw5d'^5apwՇAed5PW
/΢BK]C}CZ>}pykvx:NGV۸
J6D=F@ɍ`	BfCdDBߝ/[xc߼P&0W-FMi:}h%DA'TJ"xV tibtn.SHWPo3x|,}NC.@'xT+,|dC
T5H7c4"F?~	@z6AE'2RO/C7OT4p]TOО@4Q]ރ}FcɅT]ucPBCbtQ'GV-s%*Aiyl@9jRmI1u˘X㓼Hl.b<+[.
+8DPF3IGAs,7:CHo@8b,PHXycӓtIطj%e(VN$mˆn p57 n8RvxÅ>@d30+zJ]U6ϗF~bAqܜ,SgθQF8y+|ˆC1GAk-Y2|-Ao*uJ٪Njاefg&Lojn;0OUF}He"~"]h}3|I"H+PCڦm6_c6iOk?RNA	<-is8cƒĄ"'S1>\%fq$]ʓshH^a1BcN9**n}i|B07Fڔ6v*9>m[.|@Z_sY&'?}82TR0v藏<7l$ڍȻV1lL{Z&B}9doDGEr;>%Wű
A`N.fU/_{Lոr_/Qsz,$]tg_yW}pE3/%(<r-ҟASch{]|̍*=+Ҋ3ʃ=W@H]LzWޫ܌tT؈a<(#k0l:ׯ4z!?OHY}6=zlȍ'u96=|^u^<|a=l oHIBARR^/9,1QsAޮu"҇~	
鴍deG(d#fU26A8>z[F8ɺJ%}y-uܯM;<`det&
4\ qls1n܆J{JңNm`Ti֠(T}!YT-!%KXM`%Fg*xal<wҧ>zB+v1]1lRo l[%6i 1𕛼^s<u@럇n~yTs
6WЭTaֺ myAGsInVdXAm\4~І+afUEy;5+leM-?Wbz<%NWdT}8ϱ #9Lkq_&7ԟȑ|=˯9[eOB'Q6[x7o5vMs.Jsh64R~%+噳ۜS:G67Rgg簋aukimX2\9t󓸼Y4yy':͛άM#:7z^vX`?<xRGT_$f<
5ĊTu~ǅ|_~YCԸq6GIR=Cum=$cEGƀ<cL?Cǅlds\<fз l`\mpuT<SF}P+F:.yǃnMr4L8N{ z#~cVdu<ƋGH_\yK/y%If5$f/-峑k:ʝX±
Xfpi7LVMl/n3x~{;i ѹ͇{wr͉'_$ЙX㢞XuK*[:Qӣm`N<>lM}NZ=)'s}%HR}9
L-p@K^#|doI݁b.z&az@Do8)%.̲tLHUyeU;X j8u<N-]Q2dqDN+WаC\SDH~sހ*R⻏8D(!9V<"C偕|˦B6'<ba3ndھt(;(D%[Xs弜p^_ʗ|	jŖ)?9F	H<\z}xKӰ<u-,}V ,0SBl>ěSUϖ'θ1@.<S{y<߾ZIt:<rf;ɡh"bY;X	&;My'J`}MW'BK)W4Igr-<ڏ\ 9E5"N6}F6"{?mՖRbRAqen6tv	|e=+7i`S>&&ӣZcmBvXR~EKd{sl.vEuj;T!7x=7*1> A} \/&OXoOBoUn7VGPas[Wq,Qr#,vOh=(2I"ew}6,׫-Zn\e[e]} .tPMv}(>b1y_g6ڃi26(TNƌ7bLs+wぱOYR
<v7x<||s۱7$/=.ڄ{q2]kϔ(d`h:P' 񩛞Icޚ`Y8>a;ؐv,CQQhe6Z}~J =H|
BԱk̞9t?j2 Z_QeeN-y[WA)cs -\y~e#c0q똮Ƃ~s.sF38?R$F,BeE_U;s+u2&'7Οk6W+\ s\D3z\P.bIcx<ΧpǱܐU`u~e$UNbF7>26_Ӵ}B}P|[s^łw&f%6]2yeKWd9>vh~j52G6D7SƜJ[T
_+tSuM̈́-ħCȞF~]E=tUK-.sn]P><}ʛEw|N5k>d@*6 N tnNÍr.᱖ oo:)fцv?HZ5F_f|H^ 7t,9q7yFu`Z	)c]6}ry4M|u4G߲'V2.=.:xE)G*Ɏ>t2?SDTw`Le\E.x	%c\:"m:x6Ajy-ֱU+܀9'N8}m+<IΉqKڱt	lmoӐRtͨiIw9|lr<P}hD]?g'fq:XӡB94M~jgaW3s07§A"-i72߼T9Y\#U-O;䟥ɀ2zɄh)]vWɇ
0 r'>Ar̻b+9Юֽ~
5>j@X|aM|WV|kOn{1b)iTe0$|m8YE[McV Xx@;ned8M$5yq!,<^mQƕmǇJƥ($:hP&AFO=?cM`,*Ћ YjM*JAP60Uڛ\XnEN8~ sGlx\"NggÔ;s*6;li^߾<GyGk׋KoL|'XMϊ	l
:WFꖍo?+ByًëTE A#_/sr@XJho!Rv6a̖l9Ƣ%>e#0*`Tچ-`vA-8eh=BR>p619uIˤ7 o0*0Jc[
a?pyU[si?6찞Y<p((u\s^ũb1E)BS?<>cK^ISL37>(|&)I@õ`9vF9tzLLH?[SyӶbi*0c=7/!t?lyǪCO!}М[}F1ܼvAp_>dl<!ᗬS^b9I
'`Hb4 yQ&oMZ2ċUDt _a.2VQyHF
-עtֹ;B(R=q`>`M={<Ig~>5<^|#sc;?Cy@|>T?8s/Fl츭ħ^
7TlvZ!ޱOdBj265^Kqw\$߼=94Լ|HOYMb#40_l*fk)`WqYWl9|Rɟ2< 톡YU<*c
O_KμVgϞo{uI*pUm1R5VԀ ƎeqC@׉JЇ\Yd~tO[Mw5F.?~-t5,g!*oWK;ڟ5I%O6I^;,ۀ1hsN
Jp^b2Ż%`Re"D&q>)kC{^f{{I7sIɥ3l.}f}냮&McnaϠNie껞8F3hQsx`k qЖ6ix.su I}zM C]<7s=6M@~A{V!o B>{=/_>yZ84kx's{SH9:P9D>~7ӥl14o:u*F1M㾭qγ}=p>@s^W P&$p8ߎY[/iwiwp6 _:,
me5j%10m.p8\AcdtiSL#Aէ3z>9U6Oم7iy63=}mfN3*=F򚠆|m<w{fJ8YxD\Xq;_yKmFNg7D$ݴ_~WUJ|5X&|(f򉄎J{Q.>xE7Yq"DL?~JC<NbĞUY,z <9JuvĠ{XosV{J1sLĄMΝXy̓דFPr>MŞ&`7JO7I|$B+aaU8s:yMY,F#]1b@V,b.Bs,:XRbA*mp]`/6[}|P2Of^	H>?C(,6}֋G q/|1 _i|,\*ԇRETp/"}LO
o	;T<gl rرŮ}lMEק Vy3zg~-_u,k76}A`v'?Soml'k><@$IXP*hpUL|"/@Qp{M`/>91^6?++~c(69"׺eJq^b9E891iO*t?x_/u:3`<l2 _mLr,W!k``\Ɠ"GO9r#y	+IKcvMK?9wy~	EgcWEm+xdUU5}I|3\d{v^<?dƍlV?76)Ph19}{)[|}ESmC/kI@'UIE>&Y7(s,J;h^E[˜9qJ:;T%`l 5z!oSR>(7K">>]E-7tX/2Nr5}¾Uaö(HuSvl9?V:7z3xv`>bg)etZz|dL`Pr*IPQHƁ!RoJ׮gΏ-hBS= ۪M
hv܄R+Jm\Dw9GPxJdߵ]_"_S# w<lrn8F֝<Qo09o1"O{,b*qXf>ZWi+Sݰ 7IϡXlo`fa#ǜy۵r!^YQ4%kHs~D@
:Iw)ꙏH]'|enN]}}-sԥΧ;,J>3Rt8@}ll^tϱE(/so^tץd3')Hݨ,
^ȧ )``b͹㑁&$>+%{\D~三H{w%Sn"qG/{|^(sp{'nxk}_v8OZsA':'7t9v>ɟg|yãqn"}ZlPw%?!Pk(_.1EqWIQq(O@ъrR~0l6T x.`#[q`bEMQ'K4<`&sGJ'XThR8cpR5uMuyˑr:qnKvCh{Rx|G?˙~,c hڳб3$ݰۜ[Rjc@>	Zu湟&[߀lR`?*grSZSn1 m
>YqcNFg0CPJc7+'5а$U}bH:WR5$1aFIr|>%Ls[@'  tנ@Xx6WIELHI@w*l.eEZ?%
 x_}E,PYб	wo"ojU,}˱>`qbh;i6z'γۤ $ g<d/<aKm(uZ
n,Ii8nw"8`\Cѧ:; ?HU IIm!
!ǅYD$ǝ'=o)b.O'߄"_QtYۈK}̏,?]եR<^WA@2xtۛ}tI!60cFG_bLdH'9]~"'(PԡZ0A
V͊6)9>~
#f#6}Ŧ1vHY'io_%W| 7!NŦY1y1"+Je|hu q̜@62/{37_\`ۧfۑB9x8\;7q_ƊǼR;lHxK]Ͳ᳎O<{L܈`9J,3sѣ>czfKiR10)JgOH|AŽ׆%<6SsleNc!Bg	>OBUO߳Ibtoq^U.0oe>M1pͧ)MW19v~pgHu{&qSu]ɡ73Ɵe"C9D|ښ7ŜWrf26mqؗEIyg^Ar= ϧ鵍)q0Y_ւ֨>?{ş1_(uQ
$Ay9!絛!5w>yY[NΦJ_<^UMleðIRH?yt\gNl{H,pܜdi|A;RqW*?u˔zB{~(E9mj'Zͷ>< h!Ҕo2(_|'_|d1|O:~s$Ħ"$\\S~H1SsJrO݌8z>L慎^?^zcu/4ӍZ[&e!\ǈ8O9Gg_"?rܤS6lq԰]'_
zt	{&J@*Nnz%'(tyz֋z CWy%2eq_t3ףõtښ:bHޑ95r|8Ilcs\,H.a
qӎ ?|F"v\Adl3{^O˽Qкs@̓|*XءThgXW}Q<b>Hf=wC|A!9&@Q]/)6a>><[såБ7rHibHvJpd x {U=t\pMm}$eݠ+4+k(^|tX}X^ZSC[+Wck'WZV7ug<0vAW8cĜȀ.;p^Ch_MKCKqH K<N"@/#SaEXL ;\]3CчzN&O{s%I&9QݿExoqn؋Mgr1F 8¬Nr
UXepCX:UТAS\ߎI)`pOyhG7T-|Bӱ)/wujGVw
0hC'&QP&,&e-7]^lz;2$+dUm'NYlgc:r&e_qaơGXXy1\XqRJܡ`H99ᩖ`凇	;	c9K- vbCzFŠ^7 /y*1^pwbzUqNlVrS0[s,(3ЛU/9M^'Z6KX}Æq~B*l6SiZd,E_zQ-^Qc96yjMcH*+{7}s1B ˝yt< )وew;M6T=Euu_NmݪaE,jRhNKGd߉ WleR;`+|b&4d-v7vyTwUnKѸ1AƺIoC;SAj4+rp*60OU;Μʓ3?Mw;Ϗ1*y)l4z2g{f,xN`nن־ٮٶ7UYHHQnꃮK.<%i6$G^PG>XFt7޼)O
!p+oTr27Mx򠞑"KZy&C=pCn[G|DݫT߷de@LY(˖2u`!p]C4\Ց9-рLyބBd7Sݿdhk|y>\O޺M$M$.!?yxdl{DEmpsУ/Sk/i ts'm$tdGm	Ns@w3*8(۞cQ6q}sSi_ʻ2FEq>0'lFz*-Bǰ0&. Y<.N!f.\x~`"{	]f@|ں@D<չulBhT m<<S>%m?^'eX`m<D]>| w0糧s1iܖsf'%QYBtEU}sM.|!_Sт؆ƹ%s2fމs22"iaxCz
^tMZtwСtձ>b>ݟf<+9
;IZcvtiQ3mƄY3W*_5=./ǵ+cXz-1C[{HE}QF-\+?.EqC_8'7ǪW	esw׈]5,`ٽCGZh6Sc
.)rVB}D$c#tڃtچuŅs
1}_[NmOr>e'uKd@k1s; 8xl1?AvWJO'6p(c4?~O/sӛ;\r@Ǯ^x`* Ĵ>m}T`cjj+ԢQ1c&m X\H=,Ўn ʨx(~R=Z$j->}jBh`J&.mUq<cӤҧ'ϯCkHs|#)x@@ί#K4qS}W9B	kY&o)0XDhq}=캭G\P40g_}Kk*a˦WEzafƗX-UYui_u&oL9o:k2fDίrB	'}rQdq	\aŔS,6|A/`'.b=с@ErɑYh3 |ICJY@[+U	.1>w}@?Zܴ!~'8qKR Ԥ/
'GvYxڢ 2AsS`Lp	*Oy)Hx(,bpJ+E|n2ٰ؜G'D#R1sY |(Pԧ6xMT]4@-a/2;Bƿy@[Y:C6mU$AR*u(K<Fjtŋl/RM,F-;ڛ,Oc6gDB^^I߀iEBS!17>\49rZ	ښpyBN.7{oԗ*oW> Ҏ/G 96&U{ЛK:/@YKueV	w=Dv&BPlSȞX25Dq2AuWVvRe_M%U{lr(y$&GxcXglJ.s1ɓ.fRdW~+O	Kr.wmoZC6o0hy78'ܹ睼;iA./v>\gLnCpkȓ| kF!@Ew6\f8DkJSl?d@%|m6F͓2F޹is ib|r<6~ɔ[U>xzNSȗf?[tso\W6a0M9Ǿĺ`<ai/qB%$oRstE>Z;n۬{l!?GBt0׉G--}rv\72iiZ DQe˛isC<!MHmLl ԗgJ<CJq99v4Y[40SGoYHO,YBmyI˼<$oVh q澙=Bg6:|98?<̮?BmcSU0tEJSj=aͪgE(2]NHq˼`3]u	$r>Qli-q̄YIw?<ɦ(-us*&x-MiswF@Ǭ78'xH6}-v|sJ1}
.4H9̸aM@{~Z+|S4Uek!.#zLz]rd}^hͥ~.QZ9ny^1-̗:M@9ΪX+QSǟ"䫾u>K9.nJ hs}W+;3?ۻ{i	'OدGMXu{yG^E(:}vhz]Grm4 v٣dMxCs31eu"l+?y.PށG<lP
@PRw؛S7NḽQS9pWǡzMLo ]8+o;t*U\̒Vg}<&׺Psrs9A#dt-q3PғMU??o
y٫#=+N-qn`|?^YۑQ_ r|.W:^HOOV_6tFZUi<[r#/wR ٠AӨ
5j63	dXKgIEJ?>ɋ:b' 
Ӂj0	Äa/PvضTG |N@\+AL}ǄEuؓP']}٦ݱ#w)ݷ:1EE.G܁@!4`= 
A=+F<O>qȯ^@Cԧ |.[|+Ȥ>Z(	&^INÎCo@٩eq.8@@$
nApEYfJnԀxLO1'j]Tȣ]eySb*7m>7 v>ӔwoYL`/rdu]%:G?1&N
w\U*]b#R7R<?ecm#'?Ϟ?f t.2yqY|21}+/	#6ʮ@, X0hD*#yk~fFt@TJf mH_<xX>:ri|1:69rQi.lҌ=oFee6hh9Ø%Y7to:3hI`9ƣE֫חo=:~ś@Y޾y8{7ꓪ*h9חIG@٫3ӞV1YcyBvr]Ug*:)b:tM'n*Yo?㷛68@A⃓)7|iIOVy̗L}T,bJ +dӀM,[<IT~ϳ
o%h?q=9^9*}H|C`;#ZїR@	oBiJosPgc|Po+~ZeLJcOOpmh#7RƁk?uE76ybeuC\UP8SPg8s/ȝfWu׎!^$OJN1U?u[60?I[XmD3wpڄɁJʱk!koeg#"c֗ftl(Nk Kf1/hB..r(nqay{3@[#6:תMd	vzwiÔ9<UNX' F'ZheJu)D==5R`r?7oa]|ɷ\à,c?Ν|{Y7hK/]"zG6ix1l|^EΩGx9ԑºm;h_d\T*Xhd)}A55W&ʊI'Y*)co7YσyaM<I:~ Nck 2V=r^E~%༅?P|ҷ~Xz# "&~D:p!ӈb=cW:	;}"P2nWQ78?	9~p=٫#inm vR{0NX~uWt!yP$sP3ɲE_[e*wrk6;	狜9r3ޏtY&B<kHh0n6Ӎo#`؀pʇ toASۦM2D~5.18&!6O "Ehre^DmuħO8=eXqϙ=2m9!8ltl	c1u>rS3o'_֤}1H3N6h3P]"4(hy^ۘӰZO
TDTY%o/t	Rkiiq9G	|lX}PYoc"{CNu+֟Rgsm?k}a D8yC&Juˁ#](|ޘdSO?pCDnJ}Ycׯ0B˗'h=Ap/J{Cr	M>h/%
7$o&Fzu*dѽ2aHZ`ڦ:܃@=R-?-"_y&il	_+ )OH.jD>B@c:g1%\ꇺ$8!yc&;<KRVP@ڹl++W t{èq}~*oQN`[~J]'@ʀ~K::(e$o'AbXey*KRzA	2;'0٤|맦˼嵠bcvdYU :G ɬ=oSΉC|aɟsa6~؀y/皋-]|9˯|~-lxuJ]խ*#pa̅wᕷiYw_AY@zu+(mB{0ݮ̼Z!udXlM>"[Y.!sOWc8<9E{~짞#9|cwlCZ&У_dMk=4ϏfdRj[*l26Ǖm_JJ񅛳o/o	/|.^nM޽f_=]XL'|pfm޼8zCEp D\>GQ:st9MowPN_Lc5,DG~_8k6[|Oy"Zʸ4~lnC+h<{3MbM?=V~)ȼ:Fݛw$.3iןҴ37>}| )I͘Qp*$3p9|gA3y>ᶒl1'R7E;	_Ysm1s˗~ٔcԼ#-TG/?_L÷oJs~(j<kYH<yc%7_g,RJṪ9뼜.IlG@}e/tM&Oe:z}䉭lM627`G:DK1サ)S}qy,}M{!H; J8w8}ƶ$
GM|)7}K0|z|&Q0aYk>Ht8(}.ɄW_Fe8^~V굸-4Lj8S?褼l[d~Zy4zvEn1둍c~7UNփiY0l/kpY"`5| [R."!n	4q.;t\@yܧneut޾STmg\K΁[iuWrp4H	smZ&}ƃ9a"-U#>R T4OW/!CH̑}~E.аΝSW*1*eKu2ٙ37W΁5uzsuշƿJ5M=}2#vfsz(n oڕ>s󝵧DXi/VЧahYތGl6%."]>a0ۀ9c+uM.%Luw x*SgzE<kRc	iK54w]S^3YCT!9m)CjNlֆxT	*Ѱ9<-/7+-iW*@K3>ȅ!oɲmJ56N&C#ǻq'L)oZr\=2I7 <OHl^'d<9CoYI l-SJשm{	Tnp7!j%8$ŉ!ta`d1TEW6:,DlWbtTn0N7qxY,,yAgY-$=*qp+<QQƉ)}b$4/,?<eC	%.Hgb?k<}<Yqbދr4`I=HJ7'd9OɴoQ9Eᔷ/>gء_(Ͼ{4sMChbC26cqoHS(l
7[756.r, x6<6y>oxyrQGMTI;vt6E-R'N*	eҜ)oOotE|R-_ꓳ*s65 mh|._򓐼]@}-Tۯֶq"ڐ>؅Yq_!wto!49/	e+.9%7ůL1aFQć$Ulpㄋv.of[@OIa@bY`es~{!LU&Қ@Tb?xܷ8|s6xiM:64o=z˯y		΢KR}kӨC)A=~kc6?h&t%T@梴mg09M57eQRuMns3S9Y'<{Xy{Ӻ}^>r7||>h2	,/6T!eoDybG4F7쀒٠_a; &uo_?ԏǽvO.w~s7_Rxp.`B!*dlYn=ަ?h	Ay萟C;4gf+\IƀEΰ%O,!uNDΔҵO}wӧ_q=_3WAXklpWCH3/4s*c̝鿹:91pH&bҪ6aCסN': "vy;g縐÷D/1L)乡~[?O0KK@i}"UL!7xӏ:74εڄ-y6n0!Ezxx*C{цa	=N33dL(e*8dU:ՖzPI+z]zcn|_m$߇||q29O?mR*Oc]kƑ六cugtsd~#DR2o,>{Ypӂ^Cϐ}ZҟH܆lD1<`1RTԎFBDN73&zN]㛵!kwScdL!ׁiedl7qH@2z= I[xQX2mⰣ8`h12(Bۭ>$atP~Ïe(	ɺ[(#upls';(&>'#aO0)N6VQ0:-B`DfwNF	eջ7ZS>Zp=oa>𓯞\Ƽ=,1QYxF@۵#<~LAҚڠ$08eAOKimQܫW	Αx1N,u<K#T0n0#cHGwgQSZ\#zÅeKsW̢p՗|aӀ-$L|+S>`P*N^H|tJnr6V{Gh{'u<!&Ǉ3&gJKT5ֈhYb]l;__-:LK)O.-G[S<(}ЉNW27L	?odޛǼyxlz1^Mc,9Gr!1cڛ	o%^lxKox?__HO`1x(^t*J(}%?l'~4̀.yZlVd<&"O4y`.'sh4=v s&ZO듑ʗ79cc%nX[f-BD}CBN]q~7mTxY(\ܰIfQBiїPCvс?d4`]Q3V<$
JߺmeF^>fLdkls"=mC4-@25+]IDm\y7O jܨCdM<fq֍i']y&M+U27ԁySLM&o!!W 4VބFI'gH~pOXoCbu$'n?|(/_0:<~? `v$U
: tltRE ?E /A	H`4),rxe Ɣ|%R*Ɖ#7(#[u >#;xóS}tɛvy@.@96ͽ5Oa>L䥀@c}2|%`A#pW-Ab<n:MD!e1ϞdҞlG?ʹAtncX7pu
4&W4HɋNFM7$ܮpVU80inS1845x;gVn1~maԩ +]Y뤯A˘hJXDP*ӧOSG_V--؎?eQ!=o8rV=531BF?Lpipb0姄Fn'Ws { _?}B1VW7k>-cv(]B7<֡e h7?K?L~s] 'N=Pp9My) }:ā`bM"֦Y~k܄L16Kq#,4g^73s#:ZY9SH -p΢}o @_FVz~/ϔo yl2?
31_}L ~ ~g5=|s::"#)B1el^<''>2Oiv+.XpyP@oܽdY.׉|g]fc+|]z" r$.sme:J;-(\[HY+Z'~|:O~G#Ҿ}ՇE4;MREx
x#{C#
!hf|mmj(Rt 3%<pKx'+`}78p<mn2ᦽL;ej=2muOYYv/g-Hyyb-1cMS
FH{]^cPcǇ'
Vŝ~q^{>zǶ}c#@KzV

D8.M4-ߤU ^_&J]IlqJ+c77 o0_XYw
&|tJAT>VCM"F#0gMؑ}Shsɩd(YE[;[+'
^Е؍աvVR}| Dg
fDOi| Euvv}\O4+J6B7&.iZ}(D髹ۉ[lJ7wч(u<i}ȍ-{*i.	l D&qN+Fad_h`9ʝLt){c/O4yHv^>:nVpNEKI!"M.޽ o 7M\
WO9ОvZrEN_B%:d="'ɰsLfv"cc'('?P/<Yv(7iyF~m7ŮGl<G4YI&/MGɖoT
Wq,"4)oQ6^tG8|e_c5ÒVLMy8ϒ7̄xbXU>3@z[DfS<ٸj."=n0q3h9Wbq~o@XHo}Ϟ_s w<o:})JϗwoxsX,lm
|u!Ogd=Fn#BJ4`;L/$Zz},ssoo<QwÎؠ,epico]kMs4DIfS7dRȓEOG?><E,7Mf91<] 뱙CH, zjve5&(+C?Oh/ %JUn읿<VEUF7=~A>-a!^yr?7K_H/9-d8PzHC#\؜/~9SĎ^4tmhJr,K%ĒɜZH8gOoԸlQ
2Qi|"	sؐ%k51MwyNVrzsјmRGq6#K)gT7E>º3!Q}>	e}6~>ߤO~wqo[<^ӽ-r @"],OּD)3Sʿ#IQ+>0>ysl":n>yP%sj{74R}0Rhc~Cڌ֔G(+?tH^>(<``7\$h q!(7:i: wc3ZAI9i<_5y'HnF;AFDgYWS]ejiJd'o*LecC%0@3m<Ц|zM[>M9Sv
H26M@julj;"#h"5WdsO	:MJ|QŖpR o@_a6!`5*@DJ_~x ZJS+h-"+J?m B28q̈́=>~*(n=#Cm"p"d[01Q<nz@QTGp9}}j5Oҍbٳ//ypKc=6R"t6t˺iH[ۅ6w'D2%,,+=arGfL<46,}t$`>hSHc~y64M}SVhiplP]ԸԐ8xPպq%FAd:D
t/Γn=>|~vׇG[(SocY@yZәO%:5iLF$"on;]a)YRfؓP)Qbf<m|
L"?9rI4@a-ul{b]ŏ[9Ɍys"TMh?4A8OgfL]DHg~]?}Ju=8ops26C^U&vJ˭6cs	(ef\IPR,ra?ked"!1J߸3qz"ˍ6_D
wÐNl<6h;4k`b#fP<҅vRFp6B検Sltr3f)#qU>XF"Y'Ľ[o W8
46-O|Bm !^p2@%anHF y_8ɺ.vz#6mc']}BR6d9uYvu+y6۰A~3|)nVF4}E-	uM3e$IDrelAzhaEo8zJ;)!?F]&k,~WeX{ ~;~hS{GXѾw!3x%|.=BۊaI_;?f`v(C4ܷT_̗W;jxʇ٘.u|M &DHI[|o1TveտO#cz5zίcl(B?/!)8叧xVx罤u|p^"`Pdhh/E/țQ0q['Kǹ7&\f=(KJ\,g)`K'ocLi$Nc࿣.ulN.*Eh)	ǦE|DdnE`΃y~m>6]z(kXQ[B])տsr+FH$@(}O)/$b{uh<tZopn,r)POn1~u7ހw
\2yϿ3_?s/zY2Q6+X8@Il$p)l`<;r{,=U^\pHPZt6-PS1#kvt86 >(9]tB.9x?iWIӋ$O4A$OJCW:rƘjx<uqQ^铺&_Aw]`i#/ұ}ك&R^>?.30~E:<TV7- `fAC7|w |ZŗWѨD21iB-zљҫ_ӄF4lb4mcZ$"asBd	4 dWE`#?]Jۤhי;-Vg]929+gI|;MT]p)9 w4lTRiinR&Lr$?'55IY{HI)̿Ru.ˋiy^)GQH: >۴>n؝~|VCŵR֨Y}uwY&!	9.Nhm*F3/ۻk&l?сwUdػcH"h8(Za=XDAO@E#nŃp78IK";+Ueh\N 3yy,oS?%
NeOAՑfחd;np]nѾ	K7 y?ɡ	OB6`Eոѵi4Ӊ/fuE>
Inil$?8_!~5^, 2b7Z3xߠkZ&x;@5z7"$2#c//ot,*eԥS<&w_p/bSi.>cc	eYA{e@Hv#O^Du]Ю7.7u|>xi.sBŵb#qSG}a/]Dak7ձ6ͬlk:.*;RJcJW[;hkNk?ū!zxZ&ݷ26|XxojҶޘ<MQ.5uilC$7ґi(14jMss-2Yu>aǱ@Bg38nWi<ɗ|Ghl/[ѦG34xc|- Ŷrs)zlr|J`7>lWon0	(]gmlHyޛggOGim73L(;;mJe$@IIN#@+"C3?A~5r\|,1S̑Wzzb*`ǩ792.g6^]ier<[c@ʴ3/瓞gc*?g}~&:qd0;8P/*1  GilϽf<e(;56(p?|uDV<	C
 G{n0q^)ۤ|oy9t `kA35 "w#[K<UY{i~j2v_|[<Ő(k3-g&mOP׶kC6QP3p "r"&if	Nτя$x{FgYڙuË/'S7)ΗskZ(I޼ͼc?4;׹*97K7Y8?7hհw?S`5$A[+,h+>0m!mΛŗovT8u
nʍ|!9{;6=}#Kآ>Z/u1IX>;֋%/;-읲	@'2GxPɓ3g֯/Z(̋nP=ѹs>#c"LƌrĘ>KY`"R-20CN=[N3ryk7Tw̍E[-ԯҧ7٠-9Vn[n Tib`˭	V൜;%QVuYɧl<v 0k<Dm<%923hĄC+CJf+MhƈS{j27G'N<چx% J!-o{pz*-1d,,MLbf6 ֛IZ`m+@,V-hTxI{hC@w?l2@bNMfy`޽}wu6>MuNt4'Jܤwc-,Cjc6&}S`w@$G-aurj)%^o05h+MKN`*LWq=/φ"B^-Y:wUxӌJ6:OtX'YGrxo$qCils%Lb[i2 l&#hGN4w*v.X)mAt7zMAːt`Ak=ELɯ/<R@l6̋%!^)<&)?݇6_u'"PM%+8Uם.D+S\da}nW9i(l\Hl(v6jiEGvOGHMM&ʃ~L
5b5?x#"nM+&yOn|* $!
QE}xqki"LR0j\?}7oM{ZǏ\fBuLV$-SAfSK?趿6f :9Bel_?VI֛ZhTD;r.M(=FqkNan]a|7w+
;Ɔ=oEGznѸ'GEC#ݷ'oZ	 Fwjc}!F
&[+24Pg! ٣}Gg>s'[/yyRCE7Kߑl]`Uނ9gL:.3J?I{ObNP}G]ܜϑzK4\J?sly>̜E7Oy %vJ=FI<5CxnG})'I|bY fT?to0)|So
8şmsLpy?]I:֚V0k<{jݣ2ΐF6G Kf{XiHMئ6a)JS<czM_xr_.g=W},VE&9PZ-	A]o0Փclqv+:ѩ Vn~FP(2]w,E;MnʟLF穛hb>A1MvX? Hcdԩs|*1^>_dvz_4xٳO:D#6ASKbz#RD*i5zXpȘe,S/ɏv^i'cǅo	X70/':7ry*m9GCMr(Pt>27 ik~>cjg؂71;>b:bto=fkQnءaS-0chH|Y^cP
`WƗǌ[[y(:RAh{ʣxscu.ʹ1Ξv9c"r䰅ZJt[
dN>%bc3xx}eM-XFc':J[>-u[ׁs(L*p ;v\!$F┒{&N]-N87mX$i+g2g_8=!2Znd8ɀS}K.]9HK7y<z->ȳ*/mj^"FpvT`iY7ʇ;,mDe\)_hA~zܮ2b%,((Y`SLE8",x vv=W52,&b[nI|EtK9:}5MˮigS[XH1̻u_eh~E?ēlyɟ4~2NKʏE+͘=p g$A@nh	R;=q>~MCۏN)^gX~Z :;R7Wm9ڳo~p41ċIhQ] ǅ=~	4;}hBR(J,VX!IfگʷS91N rNݑ!
FFi"9xQj41BAcUGn4;B[]76v{dZ7<.>(cD}h}-TOqxʒolnn{@d2ǿ\0tǏӲOY$e^a_n.Ǵv_R8@*']mpZ\QLJl._d,dO? ,>~P	*+7$j.(7Ob-
dz!𥉉W9?C+譺onokt<;>e_d.0UpYGxQښ~O$s,c'ء86Z
mYy_|P{7)eL~o%!J0߭~`+G_ky~QrxW~0YF'46fԿ=~B|GM\ZmCil)	:r}TnbОs.'
[s*>jL ԥ,my@LbrX\|I@u)r%;C*lRM"~C1UǢ[\VK6s<WY7X?2=%@~:'(/qG?>=9'Ox!l&)֞%0g6NvVBAB!hU$SW5P1ICHJ ¹C(ݫ@1@T&SfP ֙a0|)9cJ&փ̥ѭϻ7	9/1[MbC Edm!=gǉ9U[tȜ4'}|2Pяe[6	QǬ#";\'u`9ȃ>)ATF	
3s h:"7T3w;ɳ`'Y2d\M4Lq< 1L._1dBo9V(M'h#A2t]ʎ:?',%>9a/0m&=:rPu=zڜy
NN r,|+51b|QWMw8Bk "]e%,=', SesԙuzmBQ5.8' xi+|v}Y[%jԍc[hF(|">mն>,6Ӱ/LWN06(*t_p2R59$]yc.b#"+X)y~G;b6qtz9 7L Ng^yyxf9Λ8Prյ.(?S?c 2r^)ֱv0ORn5*mxq}{g|_b:t`TMDXZ-vsbaniI9]g<pׯ\FeploLqD˗}xȖnxLN	-Uqn0-*LڤKIy_L'xGLQaO>'..'.xⳠd1:-
y~ꀅ7I6.贵j|zCi}s<uxq^ek	lЎ8qhY:y}S'uW 1uW&Apz-,Q6@Dh[[DG~Db>c|2OthNeU16Poz[LT:qm.Mm_ԟg[<V!E!N<?Dq{@	~΍Ma~Zbl8oO]IW}n 1>?$\FFOm	u'|$7yq31|P'kc(!hWl<yC19H`e'Rߑ}su lPyRNrԅ7Fީ;[y/90zQj+ 45ӿ7b1J ɥ)'bNԛ8kX^G{/_>WFCu9-v)YEosC7KYlnƥcEt-R׾9%¬rXQ	」ԷuI%%qm0>Mܘ17T*opӍKY!akLw?Jε䫍,bcU~gQn<rKeKoB~VLIQLRvm6WV?ç*O5lViarxu	7MnCi0^s *#7RG>`?"ۑ9dVޘϼ8LR&Xnjk@:6c#wXϠQ/=}0k8|n6T+ 8Fʓ9s[`\E4CWZ&c@Aɫ9C6էǍ	7/t0˼ɤ_qq+dm|ճϞz\5c3JvּO :m2&B|\0<l #!6ViW@P&T"YB\X)ǈ欼4o:A4HvX7ڔ̸"/ܵVc3sgO0v{]^WA>
)qha; Z	a}x,7}߾mCQ=`b`prO#Թ*MoͰv g-Uu	_(l|isG~謼O=lh={|׆+mG%C2mdeJq-8bSw2|~puRw;ʗzcu s's Dnjo~|zPe(KI.(\<>QOp&#Oα]?m"o}яſǮ!Te6GLʒv̨O܅c+PNd(1 E_ת(@1!\MmABnFNTrR[{
ғL*bH嶥UJJnvBNZ@l %<E}mmz]2"mShжPM|ltW-66RmM4D~R_Ù=L79x)Vg.-3ƐM>byD`^f^o{gZ+٢d[>3>8z(<a}9Rk}&_otlyJt(`V+ul财O]JPs)}ߌϚ.nxαv xѧ!ZƥmҎKfHҼILk6po0Z钔Oiv:@>z&V`P]h';zOjމ"NK4ķHMDA{'??
ӱ2SE:}KZBY}AK-XcaaA>EB_3͂c!"=?|Yrٟ8խo?/\=o+׺xA_?@!GtE~r,д`R˵5zj+uRiBpE5 2H(@&D!\PdAa.s't!NN)e	\,O2Od1`:*i]ɴR XK/_I/NH;O@3mE5A'yX{.ZYr`
\P\c[	}Sߩ ^bID2\X_ 9Ɗcg1/CeȦ-Rn4vDG>xr؆O~ڝ2:42 y鋤	k$@$mQAUWǩK)%{+HL_>8NN$|[E: K}~O!G
qHqq,V)Ȣ*3'} OG_<ǩ3 z>57I~"XPlOgQ\6Lp}mpBndi$9Won{d]Wt&o\"Gɤ) | #v[_Q8~^5
$R~Y:@)RBc{Byّ&d}P۟XwbgɠExwOM>ICAr0G4'z|3釤ۄ\X5$Bn(YcBerYLHyo4d5,02I_,\đN4{T:/	Jsb̚$Cxႛ>!n#ڨ2GUp9$苗/dH63#eL+A*NAx獿pJ7@0XHԘ	+O:<pq~qxoނ:m3fז0Xh?ysShI`)CYӮ"֦ULj\{w9 ꛳<>9q,R;.M
ʃ6[: 8Wp훵C40q.{#Ic7@IkE6|]O.<46BWav*xӀϹ<V5U+y]AjOPCebSS)/:/Ƿ0-]DXN'X~!Wod937G@_v%YqH
 '8o0.y{(v\Nz rݡsڈqpͲc55KtԮ*>\/G{#)9I%XF|BCc"7ïIu4@[?+lS@Y[`c;>AZ5 *r Җ+X-=)Aǃd8pZ{߻1ﲦG페>47M"m%aOaQGqo:,5xWg>}|b۟n೿|zX/8y13b̫3pc-΍m7}Ϳz%ه{W\2IyN]}nDɮϫZWk?̦?8=oe9~Lb~Qk(uAt-S@hx4}d5f[V>dd&>/{=z㕮Ǽ}ExkC{%k__ͺ#O2'.+#Q<xLbb6\Gp%n)^n5Tx{ɒ¨k &$qWHL[thw+fm0C uy&V4 9g[9ӟ&R	@Q*N$!~*<_.1:ҹ٬ࢎ?66&Ot?4J_+~#o>o2i0o4֏K~KMIp<+T?	lsBl?BT%jKނwxvRa8 #{
%~{ޤoda_̺o0`"7*$+SC4WrOc{0x` +V_ ӯqSyÖb%m6dqW;N~>wA8{Jq,_#|֭_goodq3
=|C~KqH~?uWGIn=O W*B
`s 0Iѭ	K~r8<?%Sܹ'n=/6o/_?ׇ7oro7$[wW>ߓ_ظϮ|Wt25kH`R is;wJq	>Ɍ+2&*&dBFܡ!Kc28&hvϻGϾ@f./_2Ig_}u/ϟ=+{
wV 3|*-*nL{p}9ձ9Jy~Ӽ뜼+2b;>'<}t>޽yy~rxo2S.77nnnnnnnnnnnN{쥳:{/>¯^<nȍ'9hE jމ_psPFKʆK~@|Ʃv-HpwzoRwm]}r9Ue\|r)Q!NЈ.R`"H$ʇeW(-Ei9`Bcil0oUu}zSN*5s1Ǽ.Yq\)is m/1Dm< պn`Q?e<KvZd[ͧ,ܜO_w_yZ?~_P<5ğZ>x(G8PxO@*>'jHvz_N]
s>^{`ZqulUH"C^xuNz'H{׍Z3ZȝV]'Ԇθ"0yU`YH	!@Q[\ql)1pv
?PlgGM7>G~>]>?N=UO,B&!o1}SDԋPkL^X<䧧cG''?WX>pϝ{ﯼt'}}3Ydآ$:`Ulɫx9y+lW)BG/l%9T6r/X	2(dY<+=/Hm
*#`KEfOWBҼ$9LOl0VXf zItTΦO5~77%O_`+(ش7N=>7?K=r4
~hF1vp^ӎ+YiÏ("S._5"@F=;yo5+d+(ob+uG$4l<:6fYaqL˄DX07`ͱ(u:X -~
3"ZxK^>>;;ǏNOl&8u J	V>2cYYZ)&640Cvzɫ{ f	RWEo
p+POlkVO<'L~.>KFA,	wHS<a] %k~,Q%n<v:Bטb6O<SOn#Ԧ+)Dރi:9\=MqځȼeMKj;lP/]N	%!dO i-RNGzZ{p[H	ZfL˶&jp:?Ki_^͗rˢH=(d"Cs7fC{hJcwZcO,!gCsBnh_izxx3?l``````````````````````sO]s5ŝ
uNDBldu?RxqPn^s Zc4N`.FQ/2E7r7ƪ x:g?؟h:Lɞ<OWrBv;> t+sC%g^W/@6`J:Tm%;:ؙΟ?/,_\L''"Lm3MC(Ntb1*h-qt|Eg;E5ֺB^d7$kvC,J7Qы$,t~v6=?>=|x~1]^^a؁tdtxt$Mye\vHU7eŨ5G MuD႒SGBW,.mߥ\iYj:_WE9J#ehwR3̂xXV+{YX/0mRͭU)ts~ƫiylI/:]MRnlx۳O1+t|t臙PgQYt:8L>xZ`	,wC	k$I؃fkUQJ`v<XZƂ=Yt{O;- u~SD"VaDP穼[fYbxƽ.:>݈wL_ց*LaY`"^%S+X]V<Msu}USxd/TOZryqpQ2yvlz~y'(|:=;sY=S!^w|t<U{,B=|p:qpzwMyU?<:D>^wUzU`+?8IvA"TLY۱]tjJǇ.m4uXy =ysk P+6zPYJmM;Y`QbU,%m浙#c˔Eyp#u;ZSH˓Hӷ䷓pg)/]F}ޒJFVb!E)OĬ㼒/೪y\	&^wyy9]\\XlG'^_ߛp/Z˶qҏ?cvOop`
o_?WӴ/OGSh^xE0Eyd_~ˇݻK4s#o./_ni͛iiw צ3?вvNO? UuY-zR7r?RZKe-4lbh+ڄAD+8FlncXZœp~gS#B6͇?k?GjIVobQ"rvw\OHcY:0VY?;W|Eiljz/k{~"~=/izO'/_7K?Ektե ʀ)da+s5Si/_8]iOgoT&޻?tw?_\oys~3MŤ$| z;մ"8L?lzsON7Y#FVd˺V5Z5mJ9eJ#EIX`y9k.,~(n"sPEnyt
y
XLm'Hn/];ztx5,<Iɓ\xd1E7y:?bß;gtw:?=`q	|_5}}v'QW{z}_;=%?*?g{caЯCY::9Uc<6*;ǻo}0ݼ;ŴOB`Y2Ayw````````````````````xWL7Ox5ʹsv/_W_XoHMD]oVgOZ /P^9PxM5JvziME^x}+v9j
={hh+ͨcZL<Z3alG)6U9|ł2]x^-ְؔBRi]7f.Z/ӱ_aw;=9/v1s?7_NʴUo3y	?gbbڗ<Cݽ@u?F`7L_{ȋJ	A<L_xxqf~O-}1`W{uKV5- XBV`pIFP(kY$W5%& EP9ryqZ>$QbzVIZx)p#j=^Ǔ;~^F,^\caH>RL{SAa8tx	ƍ&?CN.ٴSFvBvwT
8s8bI~["|oSM{XZ|}@nTԞ>yp2vs#W]MD~g	_X\}/~fE,Q/fA!֑E>N͋E;{^`-$8Dyx]F*"HHrQCfX[
}t#{SA@*}S{jdy:'k~h{J⿖vSI~hefDT<J*RtYzls~J/6=^?ٯ?6*_g_Ax 88عn0}[bt|`fPr~.;?yO|N?_LV_&_Ϧ3ۧ6}u?7?5iz[}%~oqߩ:_3KO{*ͿXo2?N_zƵڋCos(^"9=dFgtrE$G4{Yjͅ~>wO05fe~X`M	ja$;T2宮Bd, 2dItqyi}6˶yyaO=={zSgoL;O>1='?ǽ+=^ggzOr::><|8?5~ʯM&x^
<ŴRN{ke>7Ӎ3RՉ~276u{5ߞ~?8KX)%~0Sӟ4}l>|̧7f-ג>}d?dtio^7t[ZUE?3N_7']
^%UiTwp|*x`[f
C5?3`CŎA(X$L픋R,8UoUĲ
O0?hǨ2Yb,P/W Cm[}	BB]+C`O7!ۏ-bP;99q:c
37[dSx+d	):V5mgWtY?to|ttqIbg?.	&O 'VOՓBO0p_?ؽxG~boz?VO?ŋ}l0m$,ymoy޴??<ng>cx:K,0iiEp2;[~j;P'<x7q+O0y="w^`DܰxuTnL?t>{+a.W 
,8\t`nw,^iY~/*إ(Tj2O şx!<)GK/4#
N)[t||짌dYۗv,K
i?BjK9WLWD}Dxtvz꧈_I_>.sIq2V"d;):y fgB(v?ټʇo|m:/l]*>|QB˧};N^=u_~!3%^RZ/.:=/g\B|X\Xp4=s}ÿ4껷ӹ/|ƭaM~ԯRI(QCVِ6d;Zg򁃢o&ϲ)kfB;^qY{,+mwA
s5.Ok./.Ţ:<ĂR,d!IɃxu`~:%xPm!œ,3.^]ͶH0`џupԺֱ,jS>%suO;O>ۗ?y<MԋO~Wp,ټ(U?_~JbD
_6|[+>O?W/ȼ|:~֢fxҙ^z>~z''WRLԇzSYwa@uy-8La-Vb -ڶ3eXrPWWW7ߜx^Ҋ_;wQ&B]Ҽ÷x=o?DSRJ%?O'$g)U^v}7=<eo(xHE*e',ﰍ*&FȎiJW|=??|O^M;|>ȧJz''D/zOLv=O-OMm~j:qvX
gMӟFͿs
; @?UtO/N~z`t7lhM8nKrQ	ҟ L>w+U}"$Wۅ_;NCgIZK}i[e|G?ĶJg*ܩ~JGQ.|vqӇ'vM~wY(yio}/:O8Ntuya{G'~b;::y%_?4S0bLns=0B!2xw]iI+bUWmnxoާi	?꿔^O>}O@SOM/=V;8[tLM{m>4_{9I_}7L7ՏO}^w?toSNг駭|`:j֋KkH"l:<:3@}͵X-)F&H`J|5x݃GSi?&^[7AH&ũM%XdH?n)Oy%۱eI;Zv0t>ݟΟϋDPy_g)fB"OI3 W&uVO(k*S⩨;L:[N+'v{?tytV~5|l=igz{BX\xZkzaY\lO`{^
Oɥ|_gK}1gcqi```````````````````W۾ueWO*lk2ݼv6:cϦ𫧳_..	;烷ZD>$Pm{6f^Y#)xnk@A+JL|U/p/M\Jo#c+e!~=iooēJ,(DP۩nztuyWsn su%k/N>Ykir=
x#Ç/7R,T%^JQמ#[;^iϧ"_x5^ g=_9?bΏiO>_?^ibw~Z<_[O0-^Wv!?,_?1IZ-G?Dzak^WDzA_b/ȟ8Ugi50000000000000000000 ?/~MjEW]<2f[`~'ݯ<t5nw>_P}簺z}ch%J̮Κnga\	9J7IQɛ/vM̆@6Cٖ2fEoBܡ*Em^A^P.T2xj>_}SU7S/LN<Et6\d.E%/<|0=xp:y`z0OFZ<26bKn^C/28]MWKg~\`mǢ߈D]g/?<?2@__??.Ş*L"ЧY|俒͟6X,S伞oߴ/j	<7?oEz4}"wLz.ymON/}t1}b:l:UޫhO7OMoÝs/ҧAŪ(Njb^;A?Xi86CV4|6SNmYY̡_fu>ji'=pjA^uf!DJk4֦X-cQky*z%WڱյյSJ<ēF<-'u Fe`0Ba1'?Ũz
lx~>]>Φ+btaʒM|:>9txp0iG	ܼWv^'j;|:Oϼl`k߷CEL_=o,}}{>ꩡ铿xgd^Uֶ} AM?6OSP*=V/6>`[oE-}f}3phtXzA'?6FtS'y/olzuޟP!WodkuAA8rZBE+֡NB;jSIyVj,t|ؙmE`>^-Z{3Xc6h&oЯw}LQ8Vzjȷa6sG6u\h3hŧSUv)dO5e([S,J(pΦ_O$_8ݼgjM\޴>'wɠmoy^ ^;I''zq??MZ߲?I>HUo`sAzeM7ޛ~j;ׯM/}kO}tDXrO^%2AnϵdQ\.Z7зYZYpdmuviӵ6&>Z?s:]hc1XG<kH?z+cq^t2ɢeb\B7^f"Rnt&֝E!u\wή	<MEy@&#W?&p[xG\Wo޽I}3~4]O+x?r{YL?l:88NO&Ov:=== od]b/l%+r'}x=8oy+;Ic)ڮmAWʀ:/{_f'yQkmIlk"b+^
j8a ?;=F]t*(-6"b0PDW	JyN7jD`EY
<qPKʋ/,t{3ݼm/.ߛv?ƭW]}
2AS䴼LOVړ%Z0fGmV-*)l}X /(֔xѱB_Wh~kc{;ЯYQ}CԬH6>k 	ZM:v
^ԲjK??>3?ī^L!/69k߿Ś/_nn?|'yDt^f@n<ɴVksw0ǚ٦
׺H^qmX2c]%wVg\lƍZ鳧v%vCAaIin@d鼹~,,ttQ:(V! :KS;u`:텸WzKRy˯;#\9HC]KEw9~jyt}?tpǯt(OZٿ__\S?r߿(w_wCa!x-35뇇.񐙆~.IdЈ7JNgdA/r|Ƿ}˽4=peWub{Z\b]ZXV<tZ`ŕ3qY*JKHvcⲤel,<ܼ#400000000000000000000EK~J(_@:quŤ7oo_ LgM[ogwzC8Ӯ$7/^Vn%Xg1ҚRvr
'kjML1HJ0M;slxǾ)O#26G+1k}_AJIrp]aAJj5\i/+썪'L|Oypz>hgwwzty|1{f:mk]
e\;tX8I !!;N'ϼނJƶzkmJ2㣣`ߒ}{^|S) ۋLʥQ3bέW
y]_ܔe7HFuLJD??Go\Enkm[xg{sd5iUfq3+w)zZ.Yi*E3{P {UR(KZV_PF`,dX"dK;VNN#QONNNǇӣǏ,gi?"tiw?ZE$x%Xpbu(ih
~Ehw;`+^\k`k|A;]P7!~y+k
^+xpblzJBbzY,/f>ǷױSGS..sw\]^Mϟ_LYعO/qz,ل?~lʂyXStﴓ~B
	;^Rjk\J,OhtCn<!q@a]٘9S#glg}g``````````````````````3_F|_Eѯ [IKwPr봰
x;ڷ;WX``X]Y!}^[zuu9=~\Ƨ?=>{6ƛӓ'OSgt}s<7ֻ...~TyBj7R'N'i_M(?xEC?	ttt<=Xx"PE^ՁJ?!e/F,]9rUV
DP<mz~y:|q|t8_x} =}Y70Jnh!Z4J,buFm{mS47j;Ÿod.m$-P#Ptuo>OϦ'OzT(,*=?(zɓR׶<1Eڹ򟟟{!*PQ7	&?ʹ7M O;Y\.KzbWejWFAwt|2ebASnKu&g^i٭e |xwNwnE͋ w{U _j4:V\eж)x;f×E[&Yy4fl|A&5JYpNӡs$S	.n##9H:ﴣbANt/,y	9O?xZ~(7gy?bgI)/:,FX\w~ǏM/e^zS,-Kv_R
^ۄ&1r"b>8Is|Ap:~h:ӲM{s?_aqa,oDkod
~B,h~+ؽz/qxdmgd+%Z0EVVz!ZaU2',°Bd<t 2/h;3p(+#C(zaʙax"x^wvv:]|EW6uyy1={%M\Sov9a?O=W?/䧤wr^۷裏jqzg;ӃmÇ'ӓxkGB1 )
V/Xe="Yz_(զE[L2\@ڊ5[!\PVֆ",2x/`UxČE)!Wxrh҉ɡZbBt_gG\\(a=GPJ2E'ާȊV9gwy1]<>܏I"եmsyqo)3^wum%y"RGq*X3]^L|3Kj``````````````````````޹|>/~b'?1}קNgq]VJXUg'4bQ4   [gU1  IDATiETrEnXFp]Z=(:sZ`W,U=r+nPqϡkJ?˲AɎT'N{{D{,N'''1܀#S.ME+ho!XRvbzqtz]^Qx>yo*](yXls)'TG|?ڟ|7Uzj``````````````````````_}ӧ\Mo<ln:ĞܫmW<g 2ڮ)h%bRdcֳ,ls}t%+Jw^?d 7ta,Htss'{>y2]\<kXXaT0:)jWxaO;(Vst|2HΫLJ)c OISzYꒅRzR(i`C^xaan4S,]waK.Ư{`z嗧?>/JWo\Ozr?<C0<<5 _g`OOd8=(5BJf6d`q*k(u*O`ł{JA,,1(A_y/,?^x'qu@b@H@ě{y"vΥgk>OGN=v뿢~JgƴZ@fyiȶ1Bt}g?=2QJ3Ba{[st9,{i۝ߠ:...9u2<7v`e&_T/AX j*xf^ZC䬡qMmlZXk|G?d۾0Ϋu4b6Y
9z;}vw}Aۋ!r;Z+spJz~Tȩ3C?X:=;''xݳg6W޶L##:JJ6T9Zkն7M`GaH,nZt~q3==.YX-k<üJ[}/p^
QYݾo">eSµkAGf݃b"}{份$"h.0({+U";k~. 9LGV>8ޝlu5ee~-e,XIK,tfP	'^S1UgT|%+fDmFXeNZ+?i#&э.q(+XCD[DQY͹lP?(C	V[tp+;򴽻*mU0ǜXvR`	bAu{e~WB]ncVi{Sr?շnsv?㵍o__~%.",Ȳʻ_<}:ϵ/Y@򷢳SXC屐D>i_PO1]]t#>fLBD]=
^ Vi>+'dts1iLŊc;O[f΋5lrSc8Tؗ\\D|]B=x0e7p[Py畩Uz]#HHQM>4HJz uK?AO<VZ~|T/&DՃbL圞D̕iW&'Qik${|Ӵǜ/u0Q)E.u:>>N=^{_Ӏ<Ze-RFv i䵸Өg'<$.P܆˳@""ѢKk(Qokjlӳlt\K#)Υ}MdOK;~ae|<Im˟?bl+{C?"+}JeZ$icD}uCU.ǯ|ܱrbA}~tm=SYOʳ~b"c|TC
A3䳇PiPjo.H/n/l8_jY>p?S?chNG-ر|i#Sxr.,GYG9_;21\{m[̟'"70"ΟN:YvħY1MpJզ}؎>?ڐ1n}cD:ҽ|:c}m.=+W9w0i'PM~<w(.G OCJӣ"c#p]Kz^!ZxWD3@Zgsyiw+&#lja[lV6FsRVu,E{KD_߮-|
dÃi~w_ή֘?t~\sT__1_vܲ`Aq=#8?=}6Ͼm8H}sݕ[cbȎkS 2*60'?#sť@AK5:]p_kߑxϣܭ:WLK<a#͹~]7>;?OJ6㉺9&uo'h5. 1]([D:k+i17
T֋*9oh&BG](2_Rp;/ɹI*r/Kآ*A,[YlYWpBNvfKжb4l,mBi6-]ĲF(A3}:k(rS3ws9eшƋKNQ}}.ù5h'@/a^K9d=ޙo5)hlFZZg|,+MlWjwiNܧj+b-|>c+HN۹T|(_6ڒ^~?5M3_rlgο<I.OXCyȭ_Ltbu\ntu z>F&^a9!:/Hыk_c^pavێK9{8:k"٠)|ߥ5X67$M?;H2صxe&U	vbC,r_Tv[qcǗ}wE7W_br#}3տÕ;%a5 8REٹc 2^<Ѷ~&Zk enPV\|URZpmuTMѴAHB|Inߓ6`
'Ò'^PnՖO] :A8L53$>PNVh+j;oTl+ WD=4L	mvZ?o䵷\Ia݇54)3tR:	O.^$I(> M3yT.2bf[H;e?XK)gϧKV~ygM̺h-J.a:t_FtO9B7A"12VEmQQ_ez1ژt?Ì=CJ52g Y4l!|j_\cqXe歜	
P.7ٟa!ڝ'b9Av8Y/q|'?	f(ֹt)?f廩mC/۶SjޯEGŉU#h7"\6dˣ+sBvT閚Q}]W'{r$(-ͭ}l6[uʴCܔqnHǔWJy?qNyMʝ#}yO$șc5|LeߜsyζWqpŲsEdGS'+i6*~58lEȨW.F,n%mM<g("XtCѭ;ܒ7МS'
5u|F]ʏő7CgQL9bX2d>w&E6>ȹ͢ҭUƦsMu#32N2|;m.x\|cГc/]]\y!tq~!F*KX姎*f|׉*)pS$2f+:;D>z ٮ۱nGW,rL^_K:ƕ:.:
2@zxUЦxkq.ヅm+cF}%8vaE<4˧}Pn5m	|*I}h$B34+ZKsAc1?H' e%}qhm='΃?=?	5WT.+Ba7>fI])s?s$i(gOFNVn$vlq)D-1F17Uy)^ƝVegELϑ[zSgAڞEjEՋ6<axF_6w?֬h'ݑǥG?}rg-^sU<}siHfwH' $~nB7PW䵕жɮ'_ĢkNyPb۴"S7RRo:Cu!sKtw{GsĵJAfc6H_Y<bFZƝMa%H<9z+=g3xkl22bVӇ:bXS'16G,>ѵ>}>#FcȍHKZkA[45|/NV6aӥTt 9BI6Ȋ	+U[>1w͔=W')qk,ow$@dayT9>/ l%JTHu_n=m/}y:ǂyzޡFF, X|e/vIH#&ڀ`1􎐟]ȏ@h/= {r=2pRD߂)wr̂f!Ce3,\3Kb%9%EXIkN^1)w;h4Jq8c,:mAtarS71yU*`k[emP{ҜR׈R}Q9m@JkZ+>	d{>ti3燊9){h*]ōҍRN̓9riWH+Jd_Qq$r[+݆JN"AW+'cj!}+n`oL:%eOֶ
I'muƪZ{;׆?Q,<}z6]^ɛOhF;.82I"=Cj99H|O6[5B^l#ɪ(re
*7wU6D`y^s߾o־inU5RޚOM27+%7aVgs1 'y~yr||䅱,"+~#L$bZ
Yb\|~B'y/z\4gą:uȁ]Y\Z(E j
, N[-vf8[Id⪓:qW|LƓ'\q(}49$l`OqbʣltB(76P>##TzLX,;j~18KwHzէL`6u<\и݉;_UmqAJ]Dn\s.Hl)|Elz9'⩣ur޿sP6s|qWզv(*?}SUвsDwA(eKJlvűc|< k1^AhVQxn^\X,xU7R㹸CeӥmؕB|ѮjkSZoi1=}s/]_\L疛/}9y1Se`_Xqgfy{?.W .ی+86y|1Ca',sY
}<O2Y.|>ȼ[79<g5/x~D܄sP1Ǽm>ņ<Ћ7RjP=։i4LChiEđ;(yiaiu*gHQUXlu%itL2')1%OM=!J

c	=WhYbcC{^12z^L&D1)q;y^ЅV^:ʴMʠlC+- }VisVYxz~9LyDeYtNˏ O}˾|ƛQS?핦yq;
S$	.lr^eڴ}#nұs
#sPnd}CiF^OhDr,ɷwic[gª>U1?c6ڦX@FB}j|f&56c~ߐv e4 {k4&ri_f07:XTc!{}Ç~JԹgzMK<F\XaI_#%:0vXzPcEi.n`Yg@,{Bo
.YlrЪBV~hhuZ;},2pWVν9朁)̦1Wٷi**rNA-t+/2n<;Vv=`zR>S/nQcKsjQhvж]V}}|GrC|咆>&7þy-dBKJRy7]mlCh`3r?T_f??܃C9yLJ/{k?8ĻӔ!6NZ(<)0,HHdhȗm52:DRaq܉H~RZ& %.*ԙgJ|VrSQ~Lv_'ikE[v;3J/%$kxabD&t~REz+eȚb'
ᵅq3'#|>)n_/.DA73bzS׾x=-&֚ރFl\.hMjZ^Yvzz>={v63/8qSF.굒nJ&fUȘ}a8m"v	{:"):}Fq닗2Qo~1(/X5ny_xeˁ'#Gu!)ãWF~	(1vU7cO.sF>pMJVbx2#B1O. F*>ٰ8ki#txu\T"7pϾȼC||e@}<&T.NSǁ틽xОd6"ӷAblGtm_΍#mKsyšnTخʠzZL'l qqGU!Ͼ7]}}c^9 jZb9ȏ.6c\;vuDcm$]~#!cxOt6rWoaʦnk}٥&Ni#6͢.^OxыQ,\w
+_\"RJٳQWr hD-PH_Ӯys>}j	B@\A!\pъy_SgBv*z-%oLQK>A̸bֳv<|	;D(\h<َ2gN
T6LwWDtycо
݁_JegN`T0}juVtlSC|*^(1PcP6-tۦu;Ly놟';_=0V2nY;~4ߒ!1~~gL&H؂r}ha=3ū^:>B' WP8,21&hcǸ9	c p\?	vRv|
)lUh`\AqkiMP=W'ն8FQ(NF2;XR4@YlIr`b~\,?q@~7O^}"Qac?ddAjԇmMnƣG<{'Gqԓ6Eoo''~Rߢ|9{[<ߴA{|:5ϛ,u}f5RyCߠM{Cx@,rCYrhʙu]_iOHtXn]VD $KTωA;pN<9Ιyo`1 z/,{i]Ԫ`"/}}C$11/uzc6B%\uؖ}'׏6؈!ķ.>"لXR­Ǩ%	Aަlva)@E oDq97V@mD%L_Cr)̏FKr,}ǚ,)0v*ةx͓=lG[ꃝx|E
's֪7cEfWu`<\ۧ(>yI8M--x=Isν!~c/T
3mqx28$߅:bAU2۴NToS3[h5[`"O?Is2 |=x},0<*;y:"M⺢s.vf9̰SXX$^u፵zE{B0զ ԱXE7+@.m<L@z
+
_ݩjhB'5`~!qh@,u7LxA&}_x1YG"c}SFs󁛜mָǝbgJ% KaMmMA${S]>PAz?6sv7tEuMW)l}[)A[i֦4uՑL(AY´C#=f:I`ʎ!	(V,~tvJ/iwMro0oѧ.eK`wr1R\T~%I1'<$wi_N@+ Did[5q9G=!?θx7 UuSA܀/納!23[Om۾8V^~e?񪙌jv,7- 9Ir3n<0Mg1mH3'|V>Ї|Ly3E/ʔ:.	bM(@L<Vjk#l pPl6}!rߌ%HNO(tJtxc*kt;Y}ܬ=Q6tT#t憼}'19yvȨɱ(2~RDsZeQy=(0KDcC },a3)?șGs>t=_j/EOq΂N?@</	JC!ϗ1wc/o+]Wh#ur:y󁃌ǆ>HJ%
ku8FpUIGj!v*-g)?K0slX?wٴ&3gnt*q,1!,[<;8i̅Yy3,XPFz|ͨ2uxc}MMn[M{yR' m):!ve¶V|82BinbqfQܿyc/aZMP[XB"KT<-3֊C,CV.tTC9*"FZfZHL̔}g; >h`E`pO{.&ܗpXKi5ܼ<cW~xNN6[pF[8#p^C:ʹI/f$vJ^c#1[|KV_x}̷U:'P]Zߓ{|h[2ص@LCӞ9x4}jOv6u|է9WIϫ<+=:3xiR<kYb&1&e>BHE_qR]SqC&?th9v/	v@9),X4q؈afH;݌/t5(D2<T2`廁(3l6R]M军nntSmִa OUo=:Ƒۘχ%zrFq
8V 0o_E7PTС9~
TyT(Ik=bF^",v%6	%m*E+*}C_Xg1Q2cx;Z.EDOaxJIˏF#霟|dԆ+\C*){OW{1R >V%Xrضs])miZL4,| BV?W~ԑK͸'VEXt^B6E܉]K>[Zlڈe% 6P[Pf.E͖<;uhk	$AҘ`&(pH$eh?_߼}N?yb5Oo(*
[I/[u@w=NW#X*esRfM؊
H:E;֪cױ>Tvط5^b|3ٟeV(׼!e1:O⤦(Kw]/4ңѣC]?x@<Yۤkv*X~m,Uì$D6'OL8ϴmDO4}='v&NR7T `c怆n5I*WFn"zRS[ŁslesD	QB2ٿ Zp+F-y	՗mXyͯ@{]K'ڊuYɢm&8jY9sXΉ~͌iY_iI8~
GrnI6^%tuq)Kᛉ*8Ք-ߜ͍ .</w?IӥCz(&[IQfڲi-WE8&%T)'b~zXoҗ80<>EuNQ'*88Κr
iQGdl@ԗ|'oBfY/lEPN17ZׄR!nF_IJܱl퓙NJ/Z}; h?o'urNY`Kʸz452\g.lS2l|za:vzi#0N缎6&ǥNVSǭƠ_8n2;Qy%eB}(܄s22,.'=,:,7lǾfZ~\˼QRߴ:OՖJn n4[vî>-G|hhn^ cIVO5u$a,.iC<o*Ov>kR{鹮$/eHxaPqliGMu>G8׫֥5)j6BRү9&zCVBnJ)"tQ+^Jy3ࡈl }aɛD?B=!Cл:	VQ;r%B#mP&R]}c=bi[muRVRAg~G:0$#ܴX"zǕoqP{s,KΛR4D#y?Z56 Jao]bj?إ,,&Eѭ63`ۮ GϘ=Ϸ)@e[
N+Zqt:e?8@Pu|29sEcɏc/i3LYFPO.ʧo0@OQ)lq ϴ+weN]?zC]Gd?+׼ꚱ{ۯ9>sd\㢏9?3[&
e/ؔ@eeT,a.`ʾEXe/7)yd
EUgu]`
w}5PX,`%٬fh獃D"&$VPEW\kl)yV7ɺN)'gv)㍊o@>j|Swkıg:DLzD|]}bS*ks5:Oɻrl':Yr	aq"+aza{@cK	U.C8W}1k\N)۳󂵎J|/Pd+?)kϸH;s9OqMǬ)FI6Rt͒|<FDPxGQΛt1],KX[r77, &Id/APhu.-zQJ6Tm[zA)Vi,bjiZ#?_g3XLk`'%fXJQdPY?dOxsi +K[H;-VSbK#a46[fktrRwEցYyҒ\؈X4!"͖myQK¬_(Q48NZWG:%^u(H[?H+>}vRnB+iS/>KMsQcH,xx312sxy%N<f Ұt~zIɱqߒzwjMΨvpu+9 6t)sNJO;"6怛  _XJ7 ;7:}Uay[\zU'Q.=M%&<',T!.!Ʈy8_ҟUpZNoyW^ Q]؟ >-' ip '</xVQ:p%ۜ(1\P
0i?hV_/+:12}v"%pc[з<QܸX=&MȓuΗG	6ItF9WT"*Uj?RUVeڮ`HtK3~_e[ʷw?)DT:dWs[aA5R[r]͕m;/\1,ϖEI&Nio~A?	$EYNf{K*Om8EFd͘?2od/I5YC(8UŦS8Aq?TsoBzSAhH
EWjBEřws7pgH]1u1!]Çq~yN= vsg|IBԗqʹwsڛ6jhN~,pY޹^˙O<OTD:cEEدW4&=(˓4GKnj'x^~e@ʇꞛ/-?|՛>RhTb}9~ ߼Hɿ*\/89ط)<a;^4n[uoSK+bO}J#d,/qkl:|*X:fn"Tb2ֶ'
`*s3Dinm{
g׊#Z>J"6W)%%όԹmZ:'!Dy@{\灤OMSH~lmФ&GcWV2v5XrsͼĶ̕pk}h#>i=4a;֠6JsNVeyOqyyrG]c&cIYio	6_~:'"<41v^*m[^s_+cCD()d<>~pzW02os]A&,*"S,F"ԣG?mѨ8*ڔY,O*Cg_,~L9?q$Z7yA k~A욹
4Qy66H<u=i	IgZXHSeR܂uaa[T|ګY&g/b2/3U㋷4mצG>}TB~˰B_7=_څK~ѺBʎ>ة] N_WUց-,1).薚-4:!`Eb,[M]jL|}y1)[>57s|(76\P/;y2Α9N a	5yyv|$v95Ecʍ"کc躝W(Tɂ}B@T5~@͓@d7lŢPcBrl}> WpH;XW~]Ydw('fJDuh'G1cl+Rʶ&$zE^hLY'~}CH\4yuΗ򊼿+\ڱzm*͟.[ΨkH1#2
<7 JRʝ"S]w%&˷&]&V8lfouNi.(E̦EUhПhz<:cO~s7cG_kba^$f"}?ǩ"I!\,(;L^PW鷾L
.,7sGA|&ŧ`̓8K{EfjX<98ūiN<LuP0d;a{+=F_IJ	]j-ߪq>Oخq+92tT'ܘkx_/Z#8sU/lOO4P=OQgl(0ՠLڑ1͍fnrcOSU^Hϔ{It@qB:6G5c7^Ip_	&NT{m**?RvgтwR89rI.`Im۾YQƜ쑍61"`(/ڡ1$	#oNFqyXkߗwr\vfG4Wzn~R"2ůPXƮ(þz|y0G{x~e)$y8T&'*[&5|$	h#&og-*'BƾƦO|4t\9<E_	<k}B/=']);G/<q(qG_->|Yا^dqWp?7nAs]lj*E羑>mT}R'<OU=7үb
_tSw/(?h?7>.3CL^;ʷQW78M2ɒ77ܵ|lv{)hF,R?ڊ1v9^Jm5*Wwr_eCeڃ OAS/Ɉl<C\>z3?\exSmߊ.2]<%eSqkܸk0|/Ry3'flޅ+K-Gbʰ%0.̲iz?*wɡ7SKԢ.O(St><mHMs&b>2"?(D<Ŋ]/}xdY] ΐo>-H=V,6cCI3\#\_̙s9`:BI
qc#,cmIU#;S3]zQh;7|ފܲx/<q9^K%o -aZ TBd.K3gg~\}ڴS{qP	LYb14xM>o09:暗:cEn'%[z դ+i'exnnlk[o-*uHJH̓=ld.W++WiI2fVL5YkN[a,XbhSuJ>\1s%ygCW`ǎs@W`7A8Afi`{bcVlEte{eytlom٫>A#Xl:`sE%8oȤSf}wTRFʠi}3)cOXH#8@D.^J	N<6o*NwY}Nx @}mΟ1PtևcD~Ksjĭ}`YxG8n}m)yd(:I6- 2;'c`1+a(~܆j۩˵1;Up%a&*s7O1u%UXTV~tII/
;N;яz@oY6g*|R7K*S<6?G{- 
Vk0GrM|YJKC -Po;yKheIO|rʂN!KJɂEg0d*uae}fhvJgv+4d!oT=X6AQh֎Vnd"A},5(b	tbI'U(Po2X=׾;;7ʹ-Cz5զ0)`G7N/)f;ծq>(NӺq2G_\$K^9S<Rq˖5fNZ	(lڭˠ/*ٹFmOeC'[W
c$Bܰ}Dtӻ_~u[C)}=Y9=)k}EuRQc]H(Dqmw/Pg׶E=UvIq,XI}8Q88c.v9I:%3-@!mS+堿Ar	n(?~%ב^:?;˼b,ÔB 7ac?gNmX:lYN8"&7=Ƨ)mE2iA`KN㸆 h.Vwto%V!-}/ohT3

fGYȌJӻRgKZtt7=<vFAdgsߨ%qطRw; &[}C-71Ynh1<z(M}ƹI
|yU_/8|CؿxuL	36F٘,\26lǢ[ݣǏ~c}1Au19?%?(O^<n﫽S&>	r?.T7m|VY)cd,۾I)O}LJ
Fˏ	ra0wlO~^<y'\@ܖN!)	<z}QrXlSnrNz~!^DNCJYe庻e|F
sZe$f%ϛe'14ѷ.rK=\l؉j.1f*.ċr3 ϨDPy$ͦex[Gd<mlBȹ
+98cQ	)ar=/^E^eƬCe?H4iㆲ%s>qj/2㩹s皈ӟ~c
3%1nfkhK(}~Rg@,sϙM/ҒO}u<	)h&M.gZ%eϚfoXtW<}sv~6|m[mP^ߕ'spJ7~g%1mF99AA\۳+QT}_~T2t^r;JmS3hٜsۇZ\'ϞV1$18JF4Ds/}yr9{cYYt2tۄ[ReFV96z,R_Hoإ`)q4"_'<xpzzAx<3#fzYPy|g1!?BΜ-B	u)pܘMkT/y޸9i٘TrV-ٌUhi[VW mLKIBNre.S\2[I)ǁxFjį #dbҗ
&pE14{u ]؋oY9y@C.6S&s]_U&|fD8?_C3F$o]Y\6 /62\ԴKs96Qa%}ho~\cGC-kY+].`F.t?EOߦp@~[5>ƺ鄡{D\{	&`
%A` ~f1bVPd|	6ҡٖ>5NST-~يW渱^ Ì@cU0EYH	$@ب.VNO>YAI*'l{tOXX;l[B@[)0Cg6a<v7Ow}ɓgӧϞMg]/2V[GR7~wE'?O@B8FqM0+>_s1Ʌ,qbĮUG*yp8	Ci|f
 Z<MY꾄SӴq|w\} }Cѹ+0>S'Vv$yb["`z]
ְF-epO@Γw,F%3FXsiѩ*h@<za̐r*+)2JZȔ:DLeI4T?6
ұ^2_6ܾV'[ZH.
b(p)΂ƭˠUQtJ,,#A?;'c)8tJHtƈF_ɨSDK??'w6k32Cc9x)@bDPkL ̓8X<jd`A}]iɮaD;>1_z1q~IUĄیyT7syu ~i3Ŧ>6䵏	3/P$x[/m|vLdslLwҧoa}NYgW\Ejc#=lVCf\/q/i.@@U<6 9;;KvVud\
8S^8 \JILVqI}a=dcۙCƙ+[3Ѯؤ\;y #dس
~u(x=a<]?~:˹q+7/ѡ@Měvdyբht?!7SQ'Oc})Mژ׆MV鋍|}>tPWC;<>IÝ<zܯJ'(4^y͍"?QȘM89<yǹ6y@&4fTz\C!\6u\yUlqnٓ69A6`T-|/lN>ָ.{~!w}+pF1`y \\ڔq9|C3ggPud
/ r%oʉvefGK=w(Ċ&v|j+ah!:)/]q؃WyzsUbB=osV|8屨qjSKEfbdp?u}a=%4VFDk~?e5g;78uW[6`!ߍ$ָ+Qs/(JT}|O_؎gx 996X_$=R%~ζĆwVp}>Z*5J]|shLQHFldesO:+^ ?gl%pj4Yє>#{+9<˜drE>Sivr=\b=<r->) g!oygqKYt-EE/"
>xOYcBwziqLsNx?8L٬@o3VhYqt
,IoIP]W7ӼM5lXvhlm.0	+/Z`y.n+)Q /pLߚvde<|]dӲ ǻH3^X'q؀HBҢHJBmr6肎e'.38+kљ lڟF&N12.p5A /j: 7G6ۂI Q}D)-mؖf"u		!O,1[#'sX.U˶[Az}ϫӻޕJs7-+nqp9!K2cN܄nz(1s#'9DEPAy.6
n|?4.eH2&)NO"N׆4~ƒEԁI؛rb!-"?7>|3ᲉǇ>s2t`ú8|T\w:~.g&~h@b<M7L/|\fo%IZUqERH\q3{K37#Y-^
LQgn"13냞>9YQf5{JDƺ!ky.k>HE^jƀ_IN^-mgęF-mW
}1}.qe/@N){?snL}%ݕY$o-Rw[9eu)W?Qcy37Ir6>̘d<P$ְoʌS]E7Pܧ}Km='}c"uQ`㜭O>Kɼo$_\eM88F=+8"1v#`sIeؓjYq.>yj~Ckއ	̵>vp@_^ ̤~XܬdC?:[?q/U}[4i17['C^ʱE1EBI|a4oJHt1<!YCT&M.9,"EGԕK8ZG9
8#Zu@o._踫:cSgT=Q/ 5o
JY C(>o6!gH*s'γ-Gɏӕ%L4c:hr>}d?IYD	%/kEցR/1ƙdqIq՛s<"my؟oԦdW0/3?(0OG&4٥M:Sy&fTtCmԾF%O]o[sxףːW&Ym{s4LP&v]	_2%%(?}qY
P;-י8\
lk;b/Eϸl|yʜCiߖQ0+^~]JOv%++3:]oWٶ,@&EVi*Qqs4/*.ҔN~LN>ʻ|hǡJKuخ+Vۨ@m +%GGwbjZwvA[ 9ovoi|KFc&"]|Wt1>?89hyo;.v~ƒdȝh颃v'h)ouGVmPe66Mȳ7>t]oɪ`MWXs8x'!'歕fPfRMѩAz.e՜O<W@c [W>emW6I
'ܡ9_$9_MFʀ*n1	|$LbsdM&=Uoљ3'/8;9>k\Ɲ!()~fQn1iA6URuh+YmZilfA($p
J
.ۜ*co.01O0aՑ`ix&ZNl~3Ϳwt}8 I'vٔ.>-q=BV2\6IB
w%	l۬R3ȇV@瘍i
a듍/w:yсvY)<}pOmE.6WGˤL+HtfLeJ۹cɀɯ'1J]o
^$cuI0rBl]
+<=ztb~4O<'sT;z
2א}ܿuT}no/.7yEr}6b+RGub|@hp0fcCRaa,]OgkIX"LHQd^U|v:(u_i,=[xvnQ<&V[`U+[ר[FBnBs}%!:
R7e7G曺Q'9u]J8;3;,&!c!+U~2'ux_-QP:jOMOmQ`q3$yV =}JaplP5dbȌiֆZۧaE^#QlV#]󞢇J?g#[6i5cOlz9^vuHr
i6s,G)^'2Ȍ/3+iŋG1bi67hK̞1،a;ԍ:˖$8ʓ9dq	}c)W߀KܰUM[g<'Ii_XWoTgnDהEj/~:Syڨ5JxWTr|*NN+	0ǧ
yO.Fu/̧sy(j3Yܢ_>]cwNtsV}8:ϺEf~:}`=]lwU6-oU
M<L폀<18}/a\uZ*%_̰f2ơnehivSik¢(> cPlVW\kg>R|-U2P,tf&-cE^PqF+X4*3Ep,'#6rxKυnZaʏ.gRL!cRn#ESOa%"EeXm(MT%ԙOQ9̺y;b51VX"_x.	Rm#O1}kccGj#ohP2)^ѧc=gRS|xWtGlnmu؄kۜjZMtk蛮d38dՓOU;M$uFڀ	SHp .2˜g{MkIIfކsvu2IlI[Ǿ\eaqs!|=ˏaܰQs+Ombv`K&`_uX;K:*փi	ik
M!2:^"[,fA⹬fCg6c
zE1tgԧdWIMlf]r}=H,X|<rw`CJ	k9y+w =U(h+;-XK>|NCz[WdKl7XR'W2Ĕ	f%YL<gC?}qNuҪ=c0ƚOU[,6-QZiY>V(VꝾ(n)}o7ad_LY&Py{^	)g??9D:?Ud<>#hU<7qaPl.\gݨd+-Vhдf[5s@;4̯]'%QpO1Yk&;@M~T{5b$&]`aQ11w
3Xb%|SZҼm;Zn܋|Ln\I3%OibE	<8d1/8I%Ο{?P:%%K,4DV'7ʆܤ'dBadWיO`^`:y羑IeBkD$UhfMcO;bbm@5sQr£ngd9a@d\[S2ڟ5ʸye9H)Z#,OӬdj֚,XIm:snDX]udآKPPvavZl֓\dHr.yJrP_r^gdOmBsRb/KHgwnpo@G;i2y'WY_,**x)E-H{	͉]Gs\r
qAi/u)B:"I+&kNfW29.>~΍TnJyS,|TN16}5)ު\t^s.VU6/~$Y@a8ql`p<]+OgN\1-/hBU>	g.ʷ\IO*@\AU zz79guSpY'(<ҋמkC>ǐipSNכta|#_%#eUQZ
;c$c#{d6g3>6@Q!2牻Ap;Hs9V?Ed^LǱ;_ڜ;: O$Ym9X|-ml3BzsY7󶜷jm%DL÷s(Ffm$k`3Uuf'3zA_hILVms
!02W,Ԟ/Y_0n^Ԙ׬rN]pvŕƴl&\ZF?n#JP5"}j>cN+4/173^O^y9;>s96s̾<`j_je-<t+x)suM6>A([y+*\b'w!9
>u53Y83jVb3o<EƘ>}.cq@sK<v81c민}QqDCA|-R0­b1N#46/.VeV\r|zL炌E_=|pz/顭vqhp	{ClP;4>I=٢k^*_%W!lum,4H{]Ti۴@dsS^)HK}YgnUFЗZxF']@yQ|)ʳUǕx4'Y6H۩ʷO\'X[j YfQV\Aneb|4f45ʾ2!Ss>%:;9hc',C\sQƭm>El
ͣO6/:֛y["Dyn'>=!X]aZ	mYAzߺɛ>{y5stGy8&}s ,`kw] ,I)';TEk6dZޠTL]E'Ѫl}	-Lk-1ݱEo儛3|QUpqNPa@p/vd}n*;WСNĳ#xzdC:
Zn{^lsځ`@bό%m)ّ`V[}mo7sEz#SlsHY]5`E_2qILV饗^DyV^sw|r5/uo\7|;+.'RPkܸaQ)7qS_P¥.UxnK]S.ьD`8Da`[!9j}w;M";-EJbTϗ:'ٝ*lU'bU9.4gI-WJTbly-ԏ1ꓖU=9tp k {o1Ierv2;=F^| _d/r$y;>c>`_ھtܠ"sH/^`:vd(Jf?eqFߑJ"?!h[I*yZiayޓ.*:.%[qG#5ESU$sIb" Ϟ>	'Js4co+@]bܹ(qƦt_09M&'f5ogQx's˸昁jYV\MuxusߨUǦ/Wʦ0`SS-أGhKzޒM_	RmNF(dFwAeӿqJPb%zCOOU>z>nGӸO_z^R[k_<_Iߋ>-ew~̕b<m JiAgowm,V`tW,C;6('f<xڙA#M[
EJy}2_co6lmFl͐zHU1cjf$n#$.z47/hkGd/$I|Mdx_|1>)䜂Gg-'WMm^s%3Ɠ>/")5y#I~karO:=昞sbS%˦(q>)+0=WHƼm}ҡ>?S`>Ǣ_9͝^U1xѥҝ)fgc	6X1zH8W|#ݦծږުWҞ<H@S`6i-.p'hC	!/W:+G|z#I]+MyG˱]/y3]{3_3V^.=u4zhдaHbڹA7/f҆#:'TXiX׽.oR3aءiڡ$MHܓ.-<i;噵ʬ%C
#vM6vhD`rļ6	P6sٻ3)0Hi4kiF!U.πnb67x>7YWLu	9siLf^9VroY6(Xdݔ[ɦEqԸQb[e-I}\ [>V|>H$Zgc6˫\>esO nST+ǝo+ykH=`:e7k@@g}<y?~ȩ㘎rs98}}]xз-4g/t
O긙-_2AZ&ci(TA2{~ɜ4o௴A:y	g3dNALxkWNu~/.|EN%5~	7+[s!I˗]"Frl.鉗C ۪|2z*EGeE)UN"4;1'h'^ֺ%ur_mt[I&+m{VP^q]7ڝůW`#|_j;aьxh%5ef{na+7t͍B8J(YeY'$Ϝ.g(Hm2s֗ݜɿ.Z#]hR/"ċbXন򒾯'/V=u	Ҋ@;eͭJ/k"[dQW+Wg@-vM؃SfY*0pUCI@Ta[QqLynP.ҧGMăDP]rkC0]&N!__dq0רTAy-A		MND!_!~q#I1,ޛP	mFw%u%>IE5چ:n\Q~Y7g,CXċzEPP*̦^**}+)G_ uGl9mW9o=ϭG$U]"dNMJ̱잭4&v_:@~7N/:g|nU259Q?A#8 6r~#'~gt?yɸu{`QǏU\6܀Szҏ4:'B97 sȩkX'-v
ۈc"m zsHP!mL3azstknqy_q1>ׂ@KVU)ޠTOtza.SHPX=AvD X3(̮P:
ah=R( XhLË_{1gߛ1[P}m5P>BmlC$1}<w[Cު̇*}
eʆet`q>]W6f_+sŸ\7G|
PU/_rĜr;~\m?s-2̧pxĥc:>Erjʗ#8vnnyQv;/y&:3x7`x:?Ȝ1yz&ָkBm7+Zބ::BS>p%	0ǧGUep}	4A
y=h_Kc"_KISΕq"_5Q
>lpɘ*gR{ym"rCOݖEϼ&.Sυ
}OQ<-T?䇎yOc^ynC,F,E6Wv֨38bsxJ6Q", DsjƏh2l.41aǓEytr ikOoE[eN-^3Õ-@w9.ZmumI4uG/٬?vJbNi̩bcMɃCT)qkSSɲoWMA8|GYٔyA4[4>vӌ{4z/1kM;ݎy88]i{[mWp{C;#MpH!D!s(iV#^2BI☉aǑDUn]uZ߲:lO/|	1"?,}1.;}XGJ/TJ<n̽_sb6ϱ>uO?~\3g `]ɌJRmqhg }np_P ek7kLV.:No\`=xE
LB>`#0~3٠NT/g1;''4NDA+tAei]њ-aE+Zpkoߵsmj@Ms-Di?KܣCh50^UmjHL;bV@@m5%%$)^W[O$qaǜȟkz7t!.?xOй/&36'[<9'ۜ}}'<Wäڋ\49.9d.ԯR~> OeM6t^ ZV]f`̺&q"n׮̶;t.Ϻݾ;A%;]_\ȯsɅo~L]9*&s|d"?%u"o/u:tG_)|࢑gya<c7AQDvٕN~q }sV]QXqB~L;'KucۊB>ک/Q~
.o0(\ǒU)r{W"Y^Y?%!<hȝf,Ec鳯VtD}87U=g/E^hC}މJmb-adkWj?%^<ϓ>b~"/k}Q*|)R]xQrz㑹cR]lmR|~/ױG\	!o|*o8n?ru~wE|yn
_*er%}\i:"/4UP"yW9Ǳr!aP`獤LRr>38(0&31Wb5dn2'-F`CҙLf`iQ![Qo0JWrdW2n"nk_6xN+
+y|ݾ1Da>|D3$k=)9C8}ʠ}(_!膏J]ʦ^.]ωc<X|gRxfg駦
'	0EybVi]xurkʏMӧ~?t|Osc<kqQyZǋP[σ;l M>EYz9ß]75C{ur28>6۰rsLIM2sR\1|YpGingh0i?pUuY`_O9Fs ߯|BtcO)y~Mah<pXv'1KA/!y`lfFHpSV؈Bn(>ӧ\q+ o3 mE˫4 ;Q.,cS[a9Z3Zα٧u{1ɦ6YU)ɚZ]mlv-[p_d[q})a\<,}&`-	|![ʷ͑Q7ͼ(cSbr8tۯ52v	eFF S>8iFGaN<D3)[mC6fX沺zEb6*MX.>1U5O:[+$4yfZ:.ӫ5sq֮2mqVjUp.CB܏἞c쳧|la=y^_xc>܃,~o|5]VyíZmVn^*g6kP`1f 0_ه^ڄ$4v(P?rmoÅka>ZI9m-tEUu	ԩ]E,)5!$ų2]Om:7o#
Ů$x
V8ȗ,".]fJU6:c92YWB+YYm)'j_Niڛ_s+'J\<{z|ȹzVhjX)|H(C; ݲگ|/R}OԍW炕,lQ,Lhִ1lt֩DѮ|MڗL¦2}r CNѯ A$ng,Or s?T6o`T\DQh?ύ|AceHx!^|}.$͉qʡԠBJ[1'Om	orI*}IBK΅3f69;ǂxV9Z錴[`By'[*[Qj87ZzNXp]J(}sd}#*RH6+wqʀއY_de|MpmHul3L6F1x?$f^gZ}~̯Au'xFouOe??;bnN]FMnؤ?m_6Tڷ ɓP@Ƽ/E804QscEtAn򝞝棟ύ0EyMyB˿X맏&;7Wδ&,.;Mځӹ9/}+</E9CyWym7DDrgGC#1 s)>w^辆_QחOL(/BmJVp]hBm݆eYm=_˹:W N?V</t~aؾqZvJ؋<~NQд8O!FfH\/ atxVJچS%Ї,0y>'58|Z:Pn7hG$<~g͍ǎ擇͘ŕu
\?'RwƌYhǔ1e[l\`.fIFt)ǳbEWJs"2A}H"kX/_R3}@hA+Y [-*,/@ČxưM=5'}].#ӲXnҸy1+xͫvOD-hJ ;t<˂K^9;g
 ;6rW(~gNsu|bQGC3i˸	g4H\1hK{<BZϣ́xzc10ؿ9b/Y>_7P;8Nk/ ҏV=^RE>~8y'cà&ډ.2eэ?.wxڑw͔RR\(c&Hmsi}4Rmyc2~<9Xڎ,庲.Pac^y-OXJ汎lӰ&6dSn2 lۆihhjQiVF͢u|L"i9lER,iVhcXg
$ymI(9c6s{N$[eq|a=7hד9+-Oyt MǢɡRUv 4u%8?vHrX+	b@DjC:ĝy՗<˜9&@_m"%9'mȧXHn nMQO)R ;~aɸ\0sH;{aF`.W0T862[3,&Z<Q{c\cs;;9D2~DF?$.*- EoAdIO"m/,z|&gYt(Sաt/=)m9_v~w~OCU>+63}RCFLɭT91INupLeQeOY(-2gBQg|XsmJkvLZ}cyț|pEv$;C٘elYnzTVy1d9(8A7Ln*,|IJ9sZxkD=a]_gOL:?r&:g\pQp>~/܎,R[[Z)G{D,ᢆ_|gR|Vױcc[~n%ܴ)A.p-rՅA`I$J+~\p{6EoʯP""g&'~9+B_y'ԍr@X8k17I!1o<$߸f^ɍᾡ3X-P۪Go(` /J<w{+޲'lsi2*]껺I/}e߆#_g}7c_m' /,<}vj5Y@C! K0#m+Y&E.di'ƅ_Uَ ì_׳B!3Vg2(^$r|"%j~=w +v)IlYkm52ہοv4щ(I&%7Q>zozܼ6_CsLiĳg^n0=z<F>ycC<FC.W!c>,[A}2} jׇڅq̹8mñ̿e[1ǤcV@Dd^|M'd;gC}miUl#2We#m#zaGmTe)܌Cp.iWyN>Gǫ>摉DE sRrgSPZ*TyVYaÑnHJ CZDǯX6qR3֣@~0r&O:skM/Bs )i~t(e5zweѩ2C	obts%.;
Ί/WiˠMt|yq[rLd~&9B#/=4B["EJYAܔі}1kIu5N9LCnJ1?1F%hx8ޤ?rQh,>򥭡;:bq9}}k"POEy6oOFa~䘆\jL6&eUeIzׁ4|rHe߂Rql=&E隡۔옚o<ߐu٢h kyw;D?	>ektKU?ycmKX:sfǜFkqۋ	Ίp`(#-[=]VAxΩ|=Xf{Y|}Svu-\Pkml+}DfW;/|35粢nߟق:-9IgKۻO*E"1"A̝j ^et|ax|kJwiH/|?8R~ul?)ϏHJ\1ދ5+($i/yJsj%v9TYIM%F.(FdBk'N,ip\k|_(_1zֲkHr/'5ڃJ__dLbmpԱPj|z+E!ì55QiHD엜gp¼o`\1gGP-3b?j
6E[b()t>$X2@M`߈wf'GK.3ٙ۾Ū؟o];"ϯR
?ir`g)GX	If%3;ŗ7ρ;J2dQJ/6pJ1S>Y7;L`dzetX,'XcǌoXF.ЄF6'	KlJ
տ)q:pJH.lV5VJYY ֚1e7Yd:+#t*OO#k-ex,6OcT*oiCY,?q;/3R(]oʌbWz\ÿY r8>ρ6V%\mh,Ru%/x_bpҡ~q)_>iȣL]/<`B,]OO|Zcd'-e>`f¢Qm+fwZ(>RL)2uwۓ%JΦښ_c1k$z̠BJx??)}#l^3|fVR݄w8yM1'D>.Y ,010a{Be+R,<Ve.>txJࣆ6Lc_ʮ;"
k)l+o`o4+$c	QbuQ#oo%G?# 髍	-913"&CY7yz1>褒>eNi^zǟ>"}+RU5c̫=f-;}߾esۊ4.S&AA\B	RSm%1v1ePK6H@rE"0mu["0]Uw1\}f˸s1s1k5ߵ^?FN)%=lcHKzy>1.q*82drxW$[WwI/ZYK'^yz\9݌
Y֘JL:ŶI23>IRxCmr.oрQ|@u%Ǽu&Ǎ[.>x`(\D."_WThh}bQGuʼ;P%Oa}a)AbGObWG~# .I'C9.Rqn{ÇvlM~m5ly1=k^{{1sdƩuʃrCZsjYA75!mōs3BtNPhÒ	Q^Hi׀=Ư[gd91YU&"Q%KeߝX>!;S1ڐ$Q6ɋZCN$s%C@[WɺU"}#Gc[jM9ƭ2xc~yL+.r)?qAt-cODw~awyr+cn.wKY8رMZ^<Ϋ [A9\<%zY^ǲ2SO*ORۅri$~Rff	Ǆ<q!숃/xh%lo07h[qV 6,p[-?q3]20K|<./Ur3kxKQ?<&t<T|fLJҥfknC&u~u9:T:iYd!C2
YǄRA
#jZhK}/~h%ͷPmzfh2l=pR'utkj]X;}Նl	3o+yƛc#@g#M@DA_$r&Z3?~L)(6YAk!+G2,|+`I|Cj*8QSilm#X.^Ժ"^[GՔ?駋l_<wغHik{{$ }2ySJ5MvݵC]cӆ͵"?dmHrs b\#<*xGcsx"s\KHb乢6@Nbx+I,+fc5y5MLőI`2}OgL镶3裡)R	_/:?g4 LGĵ*1M`Jcb I:LEJ\twR˾8Ai5/NlS5b0 33d`
]\r'5cD|bب[YyvFIP@A71񂖷>?.|CZTkq_>\ܹsWzE&^MfjG&?ش\,		}
??c~"n
#Mͯ;6G<ƔFQ-},ߋٷq:YQl	߯θrF_*6#}_.\xx4g֏.&+_nSț-LLwWJ>BBp=[:K:2kJsK7aӛpڢ śͦ;~_lS=g!3WhёA~݊s)D1Ê~`+nOC6|͸:x,#5>zDwy<f?7A~mBV\xmWC*T+b!Cb/ԑ)+Ո5xˠzxs
m/$OiZI\੮|CߑskF;7l
sӬ;wx8:MYWXFon=>>M;7':|vD}u?u?~*I<Ҟerf9czyFa`RAz_0>[x~B,#!p^7/(y_sS#C<B&˫vC7)yae6)M[|.է ZA蠝@V\f9};	icg8CWLJMN>?|_{/9-a

PM0n&##n}GR~cߐl2(F9S9)W	QU+1]sّد:X]d<-BW3hHE6v
%g㈸ )CaMM.a'O>+^eߺ.D>n461;'c_8}&:goeM>vN	MxyT61iC'*>y^b;%SHcWTj00\6ZC2̙zes5{k-  ?a׻i.d뇙'm?mެRz#eT<	ڳmB˛zɧ|KX.*oh)_/e8#ߕz|O\bZ<_6[yL8,o@Nv&7 >Ƶ\{s綗\z+UHDeVunUZb8,"uA©aVf<,<Y'Y&%ƇY]cCu<~ǹ5#z/7&5Q&L\$$Yׄh3ڏ?)tc|qSz]-(KoNVP?~Z>O_s?M<sɏz,pacS9]6*Koo/ac1 (&슮U⇘朳zޜz*NJ'kfGn(a|#ft9R|Inʘ8X/׋Rϲ~G|ףړF2fR'mu*2(h|]:JN6`!yYjU'&JO<m)İ澅u>3{vaU4uNh&o=9kvs?q\cpMz%sS"漭4U<k \n6e(1LyeA3PNSOYs(}(0%LLL+LĶ=?!Z!}7(ϑu/i<.R}Ix.jiLA9tܪIt]j%Udj7CX[ta@^:r"qT>l<i|Ik@zS#Q`m͆g2eq:$(]}3bxw\B~3qQqi)_:jL<0/+ p҉ցfAzj&-f,PѶ	\-5r3%'AP<)dIn䈍\2cy/NuyP>_KygS4
DWc[ҜDEStuE6#7;Ǟ?CWnƾi<ͽ%R$NZR,rPNɌ	{Kْ9J"TtΟI?y&϶#GR"/u1#YxZC}_7v+c#2afA|C>}y:/a:6T:_őMBq_}qׯSzK:STF.[Jg
b)0p-tZ04?8`ʍ4&d0AWD?rE~l'jn0!Gǃ`Ni7Lda<3_?M(ƐCi[|G&Zǐ4.-7Ql>'y7BBӿU[>np#mYsRβyÜ^~])jt?~̟Ֆvr\xh+lE&.6Xr	Λp};V>H]9[o?D~4lz"y˷6EI;mIH|<?^>}C6}t眈ʑ|2%_&5]uDc+7Yw;g=r
kKuU ~%zq7+.b.-Ǎ?)Yua~AatS6ꓺqhnXF[F<텔܈OmP=pAKͲZoJ'9q.auQS#ZɒAbdK/	0vWsѧC>EG<Ny)9!\ta u<<]{- wK7ͱ%GXE֡E{~OC8X6+}|$Gx抽)k8^iz=뛻1Hi8W {{nf	@HMQ~0>1V<W}T\Xqqz7MoT{/~ȓ/.&SMzuZBW%L`Wh.=UpZY|ۂ>3MU87e>\YsT)cflJ!튮t	7/ta7i~
P'Ie@='n^v;XÎ)':zp)si9>./_t\7Gڨ0z54c|<5!%pvʛm?IA7x7yz9ES~2@EP2 GWsb,R
 c f fmg^ŘsWq͇|%idJ : JsA!ԐϖgRsAG^F5U®&[Ti[1p ,ũ>OFm	oƵ}	$i	SSqy5dZ@u$O`r/?#_DWjS|ۡZc8eRV_:[ǚ[l#1;ouk6=wq~y&],HC
t*<:
#t^nPק[p.};G$H=<?uQg6軾F3"7-AR- հi~Ô^Ƚ =c_' 8bJ',0DcSͤLBG&(׋L=֖tuS>vԍ(' 4&?z{ Aհc]߲<҇eJtcl3.RRH9#$/Lb(7Kı9¯ν~0Px஦#1PEY"P{zgMskGb06cd7<ܠA'>q/ .ۀ-&} E'<O.(?~iBu1~%K^D[BG ß3F!*($o~};|ф\@qA-c`%?.w.}>';k,+̟5Flb&(}_Dq.I+u>TTrέjNPlI~yA/©kgS5Ibǎio+::%G/@%L	DU(<^7HF
rV*u2X)~	3BC◌@NcPIķ7E;#Z>3ӡA8x40&mh9ݦ<J̥zE(0vTJ6Wۆz;7ı&mزT=EExQxТZU>EJr瞮.@ܭ7T@A^G=FyCH];~'AT 7Bs[ds>!	%4k߳6?1
sNMNo:}Ös=|/ZS~Owalcu㈱}Qs/^ys878Fkxݶ|Uʜ`>z}TZOxCHɓ̉u\>46eFV1";ׅ_%_|xW{T_ʎ7%R+Ca.;%팭iwmֱm[Qq$C{OLQ
Bν7W-z
b_Qj0!BTuDi5;s>6M4ϔAK#>VI?FJα臧{ҭ1ڊWz*mc}r]< u.z^Wk~eȽ{ZS.خ|?f؎}ڋ2>!ZuH
<d"5Qq?-a[א]eBLgeT/+ZPk̓z;_6ESB&hx-?POQEØD*JXb	u;+x-O$PGeCϵg
2);\ŅmaT̿SB<sb8 8oҖ~uy>+g, $aT6!}z }<Rd#!Kw-Ҥ[Y~0|Nnc7>|sfﴞy.y\^^G!i0_aeE/}r$oڎm,7nv:I#
y2JdVtuR64EԵs9K">/f$C'ٹ8l"ze$6O΃<[s]sN9ⷍ&F;0.%!oZ闾#MYoǀߥH*$Y~ktyϋ[h#E@ [yUPglHp2Owؖ3n-lMkXuɷK;y#0ƾitM	6("6NǊei)sN̵9Tx9rອ]dB
w">ʞ-+եIK
	yɆ P^'&PgUiohv_u_}^@RI#mψRQ:԰R}7VPvN?\҆"
}$ŐҮl$-M|TS-2<ө2xqfN`(\7ENa\Qے[7;l'-F%Jyb26rutXq1BE('/F|)C$FgYE80s$鶩p0m)HB&3Mc@a=-da,}[	'of/6snWTO+P6b	3A,a>asOہ[~aqW#cy-G[ ܶ蠍W7IP"/7|RZY>%O%ȓ&o Khb({:f,ur-sS&ŗG>7Oٵ]֗L;/a=ۓ9PǤ`r(zL="X!JM[pEt_Q~^vcö>Ɣ*m&Q8nPjc'J2|p"'7f85D&/$;}(hm5|J#@i	g.LCEl׾30u<Uglk4ap%yYg{]Ҡ˪z.70嗯^}UD]Ux͛lFa@S(^c7b5IgH1f*,TZ=囗5@dcO)!_$U|yCvcƵǡm@W
UQɐkJyKb+ލB3S:;I|dӌ*7eA:8ta ¶;-amua*g~.e QO^8s*o~QWi7oz@9i\74^%'dǴtc¨tSfTؘ+:ec=~Iq^1>S :>'XP׌e_A5#Vn+lȃ/Kܶfa|Z{(RARlxj
?ɷ!y^bI9']S/QZ׏m<o<E)96MdtfmG7˛&207MdNk̵'87Σ 1a׸8]ֲF<z%lȑWD/fe))',IUK8ecuLKqC%BrdtR0X?u:ڂZV>\
DTyw{+)q2X-
myk{A<5+k3db{C_ǼwA[|Đ?vJZ"'^%7JP`&_O+{Cwϓ\5u-;YE2 as^L7)YuʘY;-TT }Vfrkz"|o3?9z/U1{va^˸L~S/^0yR?
t!8OskTu?B>Giu@}LXi;O	 '4b+B=؈}&P®	,9PNK-Df${W 9k(a꺬p-@tmsakGڍ:H颙p_[pa+[Y<E{>9͟yx:F)!!1xl.џqyȩ<;Zu(֜k6BeR|=ܸqy=wEǲOv<SȤ?T)1_5QX46)>&<RNLbr$
KguEË`5(&|'pU&P`O>hn<u&HS'L.}Oy_Շ˞GG|!]!|bfD7 ]%L ^"T2U\lg@%2IELnqRf`>yLݧS&q#B`s:HG٪=UDl)̢2,et>#`!Ls\XygLWvWzI&Drʫ<
%k267ZwGlɻ}7@_3v숺)sH>̳?q~yo-RÅ[M5wlko-Z!	s㉉;⌡/(#Od<`,qE*ip#
<L4;YG;:zNub{ܨP.rxM>pۉυ37%yP/J- An)j8HNlgOqM='l$9pq~ŝO֓|]g9=E378~vBTT7vCˑ8~KsÓpp()N4#\ɱ0$<;R: D&?s}rY}HIc"$}.:jdHN}cuŷi)7ULq[HFM_u<}r 1|^gsҁLT'ìƛNYxC%oNs\}vo;c;W^u6u8)]p8jJm.,Ɛ1q~dQgj[6?yε|LdR7!|CG@Ҥ3u1nMAZyBmmosNaH9^ƓFym7s?qIWxJV\W7@y͒t+/HBvOܜwǍS^s8ϊ¯\"Yte,;x'.TT}3ࡃ1Ϲ)?ᢕ6/Qy`R3⚶%%8Nr1uXQO\Pַӫ>z/Z^_/\ݖ+ t=5:m-,O_.h+O.uČ%I{ZU.SQ֗3=stޜ9HyAW5pn}CY+!dGiSJePWĹ/vT}#}_n}c^'|n ?bnCcRW{zlBY1/:ɒGl?ATsf\F6)WKU[kcsUx6=sOz aֱYW&\Ea3liv;h$0M#D9SodrU,Q̮%fٰr/lW=b:P}e`o߾7Sp{뭷tM~kٟT=Up`Z|zaA|'q\+ȉ	з{<&P#װ5t|k*}5N}Z<c92$էǺ		>T03_H\ח:>n#>*'Vxmr?vYy@YIz$}WyeeRVF:ڵb[z{e*|㜧#e˼p<J5H53DeCeFeO̎6+d=v{ޕ~_	F\X-F}iSƝ8NGzDc#,|]u#2_AǍ&l^KWg~aL.LJs*XWrʅaɂx܃	W_}pM{l3/v%xmz$SŲ.oFyw᠅`eۮ\Dzl仴D&6'#Ӕ!­	:~Ax3*_BxV 2O0% , S[ʤG|ȻL{pinb{Ű*?ԝșHi] qG	bRf:V䑟	铘ԂrϑcDtJ4IHxHilt_zHy!ʍM9۲
IYɖ8EvN0(3a.**	bwtyX1?V"_'. 4Vn q#6kxm;Yqa%DŻ@
PVLg%:ɗ[U!b3a	B(<sE|E}l/
w>y#ɩFg׈I[ E)z#Q{_g{.aA+Y/*G^JyYNNXo}
~=k$>,ɛvE<@y)r\pP-Otcmt-W-i@p^ְ#F)S^$,#%--p<3hl$UCG^g!"ե/L5?\J,o\N;*^H2y%Cҡ3vVYh_@}H[[.rBrgE*srUR!%Bi$K-w,npP!',Ɓ_zP=z.Frdjz!
_*ϴ^yr}WT&\k$,&%dHu(h;nli{Ozy79˘z_t+oz?eBei=BT&7Jq[Esݩnwn&6=7iIꗏG5=:&͢2Ъc	gn.PY{<%b}c9|\r$h朶vP@mOU" >xͺKNS
ﺓШ*Mӌks+y_Z@tO9|&$=%̩,꼩P^Z79O0ub;rRzPo|>b9ϾrsW|LVBOكzdܨe-RXpTSY}Z]հPN_#k^>͚
ȣX1~gGǏ%bSXlDAF(EťW*\唟^j?\"K>~ .zJ4Mv 4V2Gg̍nw_?^47U/:϶(yg1 (>qH:	*.\ӃY`R#RrCn~NISakZN+<z=ʵt6"cA)1Ô1OUߔ[I'/ze7=UC®c8xEG%) u\6:u\6wsS9r~2WoC@﫯^#>Ƈ.vx`)(;8(y̖Me9鋝ξW~|Ɇ"縦%}T#q~rc%|D|YT>gEf;%5em&;o4.St|Z@}u6B823[sF!{̬Z}%mf۝:Z-t*1e"XH:]q";cX-ivDTR!:㥳bh-t1aVxс?IV]H<.*^i?+#N8(7Jc
1x^!ml͡:r{r'7|r~W>'<H:]:ZAsG?_(ˁo@nFX? s͸UH;O+ Fϥs^ggrx"@^\_<$=0QqtEdNbuSOc1e*Xy7p@7w;L	by{Χh%&>vܑ
+u#"_$_FYXORrݻ:d
i+[k^>Xdl힇%_u'hl[[!):bˋ~lxNkB&M)]n5AMPpYʧ~TG+Hc4DNb!ȢtI1s*Jԯ33'V*/!14"	l1s#=J\yS{l(E&Gq#'_NI}\䓍,ͨy 4a\֊N%q#=>u̜IŶ<QybOVuͼ+ĤY.
w^>p]'@/c}f=7v h9y$>q@l&#9#9~!Iԭo@am{CŖɩU^h+B]RIP.Y,aP4!.DG	c1I7´w/˯ٰUlNl3UD6S~_|TvcC69ض|7ͼړGjE'~ƕc
R[܈s@ۋy^L['Iw=9-";wSj¯iYJ9饇{cY(]~)Af;w=;u̼]kBGbBB3k-eLH!ϥ.FGh#h8۷oxJ"XQC&}Hc\ /VP2o1fϫ1aWj74al⧉HMy`'ByN+~\.MOH]M	|kt2vYgNZQ[Ô#LN2iȍs#`[W_{:sUyb7erru؈,#Tτ:l>³P4aSl\Ș辀6 xfe3>'똷D@>=u^th1#y|Kaň!_N`t	f)S|zzR1Ǆڃ>S]9L?u`ɧ9[.e*	Ӟ[: "[ru첮HYdNrT_AOY_#Ԙ(%N]e:'ЉM=#>5LK߼q~Gc0~_ffCJҡNg1eؠSds8|W_b+isR8_\Ib<d_u~D9xK@֚<zyEQUQ4e& :c֞QHMq\/"kcz[v׹b6#`0ڞ'c׃itr0^d7NѰtܚEη:sN,vxӋG:ڞbMsp1?lۧ/ 8}Gd#k;ɋs mReGJ:u(&bN^x^e1s}ΣS-_ZX.#6Xcyl$IDZqݢYԧecQt4Q~aZQ
.\o oI;y%+_F>]Ǆ"[ATC?B4v,W0in{ZO%ԇNVߨ<{u1zb+9@z&myA_\#MȻω|\ G;DB|[17џJWV23޹aҧ}}r/"CN3Bn3ˋG~aGKM"dpw8F=$71&0|/fm,RaF$<#bu"пߊ`]'%qQmӥ#hY/ziQi|whw2WyIzm(ZsVo:Hp3!G|BA)q@CIB hs)fl4&sLz?&	]ʇ_Aw'eb#$3b# ]/lI$9T}k	3iu$65	'._	.QuTxϮ^$#^%nߨS@`?#rZ0^Q]qI/}(+~Zکs:gQ9(bB!/7WB!zuFxrS?MDӯsQX++o[un[u	}"zT:~IE)ŧ>R<l :`E&pS}¶dQ7NNH)%ol\T5b'uwv%vFo'/^pSUGxtw ٨q1#Uԏl0~&mNa}YZ.I@%2tBI-w8x\ tީ$	-_9ZO]闽 ﹍j! ޽jcC:n׮\sOB_B*M)(q*Vq)2;,Kq`/t2+bמ\0ufv}*c9˖+׮i:{_>Ju(,Ѝmd. 2N"TșRGdo޾Tc2<~dMآ"fxrtɷKxoF]ȧ8 DnKJP^XCkA>aGzFU-,F46:2S6'>	iK!	aN.F͋1بgS,h!3O*K;.4^~uN]CWͱ%(eJ	D0A	*6"9W\V4qs5U>:lͪ.8:Oxs77H:s+6i65?9˽`bP^^?J;L<an}AV=_1hQH=񼥶~ڏ=vaύ//pPGja8r+:\87,
oNqʉQVEowt-|[VҶ-?$_LBa'VPV㊧a}㬱%\2GSM>f[駬WKu~E%\Lc5Qd7sT2ՑswWb&F'y %y)L\SB5|%;6[`~lA/e^"vc8iy'q'	V*[SKY*^ZdYds>kҜ+r>yېt`s֑!_Y,y@JwX-+oJMNg?DYɠk~#噐h2G}w,?ϯI`QFH%s \Cb؈(zܾ QCT|?ݼBh$Q哂5s%&-]w]g>|4a(q(4CX>VXe@B=ŌB
H!YXۖZAȼ#k',EGz1
Cs"!kG/XA 臞nxN!I
ǊښX1[DmmH=9YaQjz-!+
iw1P^Bᑣ>mb`Mײu"N:f>}Psͺ	:Nh
ִQ=jOǛCx5u%9tE+ #a/swV3L>{3e?hԕ^^@")*x1qW\\Mʇ^V	]GLMm0Am3L|%J%N}m;[2kz>np;)1׹3uZxv!6u<PcigG$q4K1r->ILe|C>q1	9ʂi}3e9*>:J/6$*`D}R'-Iؙ'f22 qeOlP<l{\k^~e5$O
&߶!77ɗ!A5em;w=&9zHFrc'mN|cMtU<tY=_.C;9OFH7"t7myg*y%ݼcx&~2زU7xxGI'^CKklu&?N: )F	w]n/7/WsϜ@K;;V8|{NpQxKi{$]&A@뢿a+YUxpq]l	|^'jћ9FV
t1?Dk-Qt}q|M?}6<dBAM( IH>7(#;ao@=? z
Q\"l45di>cwƍY5
H+=x2)
R.
=+#2VZJ9_ n0Uzzx]ˇKgW+<^]-x>zzx"^`JgD۳$n/ԧ<|qD_Ty?	HvIh2at*[eDpN#T=&\IcJ$9 e9i#:R'9dba2nsLs0yLE'2a#=0m9iGfMKOx	3 %Η=oѾJy.Գ7`ؼU#W\=\&lҹpy47cU<_m0tԟS<1|Dg鶉'pÎ.HrIى6~¦ݛo:~D8q)?X61/O58?D%YHݔݯeZԅ-ԁmXvA}ϖ0Ϝ%^//yOOɑ!\>uOIܖlSw5!'8/tf)Cma΋Zacsz({co1$iO`Zl6 ,(H؂|l I	4kҰHlP傞PtV0`zloF}ʮ>9k ۷=C'OKM_dI=O2fy.a铛Ns錭J .LcWu^E`e_i-y5'ssC<eN|gd170t ;(ܔL0-}Oyx!|W{KO6z>tبo`[U$!.zjO紗yJk)BS7]8(r9grC,}>픶Bo{WPc59>88tmyWD;Gd#N~?nAHsRtsc[OH%uhʼ2ApDLwz	W$d& Wp
SǘQRb;Usld%.X[R2$=2Yq#'zCӾ8ys+&t7*zpDl"c}Nוq۶ƹ,/z:=(͒"9SуWEGx6T2cwA<Э8	yihSէ~s7͋`7PFy}\q؞xŚ_3ƍOjʏAy<Hq@ωǲO
K }6`*?_w/+sDOwe#zJ"_p6kXy)\dC[D$.ЪX\`mz$]@|WQPXq{Գ;BGyyiؙ`@|1cBDnTPLl뢞b:\Ү茙N3fYOLZ8L.fM¿YW%(/fOcPOO[\"cd%; Vh:2I}LK&g0t4a.峑o~[^Pڗ"*X_ZGutXZ<,0~BVLb{\R؄LƖb}<qbcq6tH:bKE8f.b6^LzuwSl0+'9'yo*jQw)TՇ'>|B^%ژ'P~zCeeTdM)sο 3;\䱹ȆQ Qr%.V~NG#`,扂ܐ#5eί'y.IS)D
lޑV9/oNĆH22&,|lrCP:LM#{{1W$N4mDLJ/[+̇D
"Rῧ9677V	D$6&7oMFx$?r%uBz:1}~ARm9;g{xu7Đi2"{	'[z)--EOb(%22޽}ۛia4L،,}y"?hXΩBFJk73Ԫ"s0Jx4qƍ&Ǥ7s`öGp2OnrēPoHz#x.a_ƛE]b mKBG
#׃dR':|`a+,t
dؼ<J\n.p;(i["į9wb2nDn@p#[|c{T?ɇ>bӺ1@˓~1}LТm'CG&avqb5 )/7nз.	#/ ۃ w8Vcz|oFJlQD]/4>RDNLA^8R#D`n4d(?	x^J{mkId(СaNs6}:e_A;Qʘ|ň(auG:9:{qmy7js޻V\-O$6 `>Zm- ?dq9rӪM%PE&`cP6K&⊲Kة626ywn0Q{sq~<؍l@S\S^@ߚsΈ&p: -*QI('AhTa7RPJ{Re&")iqB6h甭
Q6׺yhPMYP*4MMlC!u.}F⇓#ccUGb#*ЍY
3mbܔ9	M=&Rf!m_!`F1rGZl.Q1ƤH/!KS17 9dLFW)FCtT[nlܩ/42ڥDEEGAa5o՞'PbHT$h=_tL4FB.HgwEZ4B1bDX1brҡp
pˌԘ}m tCzpI-'	FņYv)?}B<k|l9iVkYFns]_w܋>yElʔXHy&"cs}ΜږN=hF:Ǡ"%Az"{+553сlw벸~HE$M|bc|GJN`\:KdN?L(LxöJ7yNw1/r=nַᒷZy@ owF.O!6*	spW1Iۍ&77%X gńkt@8|obA/YNS~*J:䐷ϯۯKL8Ѯo;=9r*p&, |a#پvy?WD(9|Au%hC1i2NAe6(^וtީ'׫@Oټ@gM]8eo+o@<uBn,Kn>Wɇ_j_BJ)eQϯJ|T>e
y,}>\IuAz?]:ubO⹈¯/,ņqm/,yb 7CCⱖm+Vl8>@Uڗt1eqx9I~;"!zh	
nFRTiTYGߠ} ѽ+}rD`ii6ܷگ~8$c܅=ؕbZil7Hc&~`2vv-G>VrAQZLCtv3oڲWFT1F_5IO<z1M{Y]eŷH+?\3>FZD$){$T}g곹%jϞG|ZPniKG}G@e0ݧz!}]ޘl?ͷ2JSXc9T*%0yMc_b B=:
vPR,Me|.5 /Ϲ)d|yS4{-9'`:^vgh}2<J^qNs`Ru+eȜg<C-HN=' ?rG=zy/Ǻc/z!>VY_)]m|C'"Y9R浃u^cȒ^|b{Ot=@@ ߯6>Gi8SU8lڮg,]I@Se37p~Gŕ簢$w9&B;SlEX4Px:A,\C-;%K_cb3]trt:eLT
%d2-,-Ljcֻ=ҿ	i%g>#P+]YsU>23q0/ Շ!cFTGn^f8fsr{Uo>R_IO_C<-eo} u1Hyl1S9߿\O)/icB,g~C9|8NyR.mb!鱬
[FnA
&_SƔe 0zmb Z<
0뜽/lbbEc%RSEd1z31.Ҩ)ױ|k'ֻ8cH`C?(M5=OٗcL=A6bWciˌPbp'}_t(u^CƎYkSey/;-nru/ rkjYA+`FJ<$3po	lTF&d<EW/29?kYӴO]nUinxE[~,(-c(v$>8߆o-o-J)ƦZ&=^@G6DEePN!}PqwXѲc+-nټW
ʪ:Ml+BKFxM?>6q:/=jpз<yt1wy%QBL+SƒlѼ9@C%$v|qʂa:4EZ@	R
咴Ȝ~˟.0`ib15 l0ɪteٮQ+G2kQJgb礸U}O֏涣)Y_
FMhRB&MW	nۂ'E7:|>]>!<B@}%&htЕR/i3sagBɀ-xk:'d$o^얟:ȯf $&?2t|\jJl ]rz\oĉfnnZTmy^bKű eq)ݩ[9'km˦IdO?R$<ꔼ0u@>n;Z1(XQ:r+.#
tw-M*G=؈\&;r*YBX}ͥzʎ/m6bsO\>_;mGaR1FH}O17;}n÷.¥@غ?a)Y.*l&H[Э⢚v<׃`~Hۀ$e8ByT0Rg>Kul{'%8Ya F[|d;KH<DGo*SE~#x	[ň#~Ìftp?{);w}3)5eeG`pc}Xmg=q!+Ʊ%cZ_A#`<qN@CƤt:vaYjKT{J\ɤ~CO>&s lP.A}#ێ㠻('>zPl19Ey:N6x_n<E*CwhnӺq&SHss!kunasCnl?rI?\V<2^(f?y}%9^ukiyk/GS}*ԛS'?&(O]eS[>w7}Y-MV
涡lo9ѝ-d .^#iJ>
Ķm*G|O$󞕥$WcMK;6=95H!%c/9_#K`{@/`Td[]d;G>.jN7DQOc䟸LGu@;bV
8l^&UTF'룮KJ9[Q<hˌh]-ϑJSbgCGXeXۈLIo !7hZJU>gZ"}9~'QRhmWu%9ViѯrzƉǋ>	&I}:_h1F}3\ヲ1x.%7E{NR_ 6X c贁mC%%;Gp ucTƸ| ϛ|lBGK{DzeoZigWaa `b9CHTASK]e?NnkxɭƌϹY qR:9'>~5h>㟵ےsnmG+sphX:-?q?$=Y0߰5c2H){?^pֺ||_k[ɇΌE*2˔rSGlS^}2#nDlsD &'KhET8J`%:13*+RL=.8>9/#]XQ}0&*3C3tӋ-l%$o[4ތ֕\qt\H#=ވcu𹩴q:2̪pBQ$9)ZұsT8z]`T4ulzv>'?m,y26&}Y71|7`,d<yևF;*Ì3l,9\,EY>\Lu=%::M s	Z'p*e=]O4u#uk+L)W~GMWiQ+tҞK߂]wƐGzKu¢)P:|$K>'FF.*"Iduh|R7ˆ(	=\	Xvs[ye?eBڏ$*n.,@02I\hE"͜4릶\˧2`bƿ^ɋ!~3/#a%/`Yu|sAĢ.*YO
,\HL
U&>bA@/}}<dhE'zyUqwdzr]bolFB7)LG'OdC07Xff	( "oQnE>^\n{!nx[C"S\Dpa+t=@YnrguCOmnxbm3UGx9߰x	ד7*s_P&tg9^	<1'¬'>7:雡O_>^_qq_Ӆ$v㕖_ssOLqpST#u'vT};k0#m>P%kVr-]mǐ-ߴ\2kFd'IeCk21͓O٩2nV5\´3Ǿ熌>G,O0@e\0YѪJ1K!&sʤ*FdXR
G$@z3]qlJK
JW{|/%2y[dh֛Lٛn|}1|Kؔ96Ry
żǷx~>ӴhK6"IgE%n+,6E ǀl!"OPl?t)mDm/o)-^oH)[xr)c=r˜cט)Ω΃ȣ>@Ft̿wϘ1y4skؑk
ۥ6M2zA|\syO9o0y[J芣L!)}i.q7Ls^8PF`\S6 uJM^+w@n YH;`/#K>8m7\}Dn+|.D
DD'W2veo?yt>SysHPtuM#MÉltT܈6ZJMu>h$}~dx	0;<wh¶3bks#lHWAӾw0FYh|%:zBre+o27Orę,%vB۷DnGnY0	v5OPm)W!5"냜m]QDv|`4lۋXMSblM2hy	OSz>d<.N/ݧ<5U:FgkptYs>F9uscNPwS6 	#\%3:*-t~dAδYih"'bM5cDqc=s=zRFnE>w2>vċf]qQuq~9Ě<pbF`y6kM⼏`1RE/XWr@ܬ%C璚J}I/y(6bl3wt̧I+͘5ar0i]ԡm*6O&V-Uq*~Qb58gx&BNC+pxEHh+_mJb8}<-	W)CgE`(4]x*K'|p"M]ǀ̻)_+Gq{'k\sh'_޲ɻe31+hw/M]:c(A^.MU9}`*h}{)LP"6/L6ln+a*T[\5S3.W*G%:B&a206x,ԃGa](iq
7K]5o`}휗^@fâ%	 bϠG,bX h$-lg
%8fAؚ/}H.;=d2.Ƌɲiؑ.=L8]+߿ՌLڀA45':ӧI
_eELܮh~u6۰[)]FwYxvEHh7ɸ
cs')7n)Gr!	d.w{c}~6	aS&kyhk❼yސy2@fŎæOqIIދn鯴sok'˝wߤ쏸3mƷ)}a݄nκp7]cKa]z3.F]8B'6$ؓ1=c }ýas]}Gn! GzA+["669Yr(x&ٌ|Gr1sNDC$BGUo2kdh3	x$>\2 	)@V?UoPNߠ^?x\Rb&;JR̴2&[0Y{aӎעx3V8΍ǳ334cb	8YfjRr[bMqE _b|,׽7dS@0߽w*Y\hВ%67/?/K?MQ\ڼ%<9<<Odԧ?:G\(H<l0W1K7<??}";C<o[O=Ks{:Ry/jkB=
MDf@t"ԙlId(ϹS9<tHߪYx%nP(¾e*{׋7s/ǏwPEPK8wJ3lK0jlO[Y5mbߙO	λ8@ccfU9*S   sWLyKf  IDAT-$0.!Ep,ǮI2pe*(C-G j%|Q\i\'shC:#O:ot0q>daJc ]RPjVEatɛC`e?«K"\=tT.͉̕ԃei+"uG]:&1uMԱDXgM#yLEApaY;"Oe4(J6z>u\u
kqW'?Yخߧ'ic$ZG*2hHl#:t 3sQNy)1"+ -|nbF("ӏ*\cJG5INdo'z]~O~-;eN}0}S5\-R>׹MFm%|V~ӕ}Bݤܧkѡ+T.9Ňy1BLmWN_*N⍏t߄|PtŅUn(Vf V~Ы(?}s0:j4H) y)yRf[֟Iz#R5&Z:n7بanoʓ[,¹Jk5gY-IuP嚟k 1rY75ڙ0W~ms"ZkATY<jN#}?
ה$ԝ]N|`л9l'Nzȼs<~ćlc8Nr=h>$06VL<	oIhLvf:e?WYT&
/|{#ayn7F.m3	4-PIf0@V9,e	֔$tKM0I2Ȅ'mh'03(YhNo"1	D`__|µؕ3!hpe!)IL2|FgU|MM"'2W| V/=%uyCӐ+8>!_`ŢT]zq:iE7fY!CW:'wNd$'~ɍr7.׿'\y7C|1p鸡xox\]64xO<l<7q~>ky Nȹ}m0qC_Z׉G0
\V}l>$O>v	_Y<!~lϼh։]_YDCO,"a-X(,Kݺy7Ȧ7r!cMi; %}STLSY(^oJ҇bH?zS\îr7LtྐྵbϬ}I_Yxw߻{:,dl2o0N<HzNo69?t;oSx:u-
1vBU(`	q؋ieO(ZR!_6ATwq'>XHmX04oe.eCsi،Mgnkwlĺm8w-'eǘVBaE:{+SqE$t/)uwsyaS?tכ%k	+xcc>um޳pW9/Y]oxN2?gY)3MP>{JC>?Xg~ϫu7߰<o@%miyc:ACPكX_Ȼ֗UgM6\)+k9+^ San-ˡˑ'#=uvn"!=7l,@<:l.2ÉΙNwL<֙.Q؝{@z"~d`}߬Fa
a7Qۂ?+WN\`}~Ɋ֖r'ex-SW|{fY1&h\GeWhcᕴĜ7@C{ur'paQvr"o9i<4Y2lP.Y
J@7{CE*q'q+]>n	!DT>YX%g 6d=?ħ?ٌ<ud~NGyuzJyҗ:'?TACJS0&Tֳx晬\uk G݂I;y%RPpu<ɨ̾:Ul36,k9wnmPEsCl\>_GV$7mq.a_ϑrqrӬۆa$_ָHZ/nrǝGH-:p_ěKPݔ$(Z[@2KGږg>%-8oPQ&#2mQXF|$ύ5(V3B%bu[WR_iJpe3D9Z/ll>'h)7~t[dGj-?]Cag0%#*A(a!,sJ::w,6ǣ@^2s)\SYZYǚ$ȑ3S:[DhCyv
B"#J9kM=-m7'ؼƒ7Xc#DHnb??F`Dh1aL?M7 ҡj
-6
0pG6BbMɠ;7B̈́8'XQjX|sR~>2慟<H'_VG
k.'ڹ yCE2}&&qaCO hUHk>,2@	&ObW!n4_H؟黾<AxJ [eoFxq[dY\>[8ol0NT49>Y43y2af8TPuG\s(a/nqC4J_#"7>9L`n୎mڅgW(Sf|xhP/CO :3]'?}cVI?R_G0me(Rضf
>Ure􁄓" 1eZY*雳ܼ"7ɇǘͯPS׶O~|\	.oHq8!\gxF>}-_?T^≲z͔}18"0>Ҕ_=Vʦ(7	2YYUDrM a'ۉ;聤2?r-46	UTn+C%6TSp:$.zgO^MU[ rk31>O|Bqbnt7{}Bak)@iK=yMuRX1i-Ht	JkA'?qXQupr66`_
c\U?R>s1gڇ9:7QINY]5!J~g^G},3w-Hwiwc(#rCya<fʏO]0ϐc<ҸǼ>l.Q7<|Bg
9?e>I|(MlP:|ʓ*m}lnh1\n;<ؔ/#k:('le0$eɚu9ږ sGG,#`VWdTȼH܈
( Ǝyh?m>EH<ec|X5siWh	&dq[>ġ#IN:8y2j$ӫPǑv/J$z MuΥEATðׂWU\;Y+vL?4E{a*s pH	ӧ<ka ?e?KcOk;Ky?D⻬6H%UUOg_[rd?X;9J{Yʉެ5dm>Ѳ΢'"z^YcVjѰ9iYyCQyp7*SM'uG?26gb:Vr8_3ݡ5)tfK<n/:bX(_ocFϜ]g7"Hj7U$i;ˆ(>loDt{fxW"mHnJ߇a<_YafXS[Ձm7c@}קseb*Fmbq+k>pdLf\6bfAh\Z6m92RsʖgO<R"!q#`d&l@DO4cCCŪD	 b:T8>?xW|x
U~y$H-Fl<F͚!ڼ\h`:~g~9ց7/lQ0s\·}χs&su"yō{Hy|ǋ!ֻk.i#o"/c\UwԽh_Xd:r0fL1.N@@zK$6!gxѦrZϵY'YA'#L^=xӏţtx~xE#NwfJAqtpߑn`c93 ~a`;cXóyWVOwT90'|3@ JGncO5CSP15qx"γp*c҈J.ZXAD>0rhpA SSvmQ7){ry[Hٲi\h˧\KqBrQcM*7(FoqS>Nr:Lrɇ!)bbc/;e"-r1}щm&sUhsnqr;ٰ80ǿ4sk@L}xI	˫p0FCG"@Ntvz:@F3ofx4}A(mEm{QΝ;΃M 	!uMh7nJj|B@di3láOiQkY,F
=o"v#mn*|WcᥗAY,<d7,GkcT1h˃%T)'NDTC_(t:EH	&cnSf'nx3J6:0$G_i'Ӗ6MAkpIM<Q0GڞBC_7hq2g1[F6_*DKJCW<Q;H]{3Ci90۷o\16$MHv5UHGRs_a<J6y98RD|U
"-tHa_(Mmwҕ~AYۚ<>HsA6yùO^S4M]sJo7ɴ'׊`a+wMy٨&oJ1of+Ξ_q>WU9d):cޑ}J+'!*Ҏs:t;\|$W|`vdO}py§.oH۱vNjrn)QI9,=޸$ܴ)6(D#Jr=R/|\@x5s0u/i*@ik|82<7Fdr:[&e_$3/iյ%WH;6paBCQĦiG_;89ĶW>lu@gӇ{^QeI<9X#U:yrlCSv'm9{&֠O#_GU>w,J] |V"m9ŨMYc6C6tbCPJ#϶zq=cрļ$h6yFcꬱ3s|}V0_5Ti)X(kr.uPδcF
ia'OEO"cBcLq~[=+I%K83;\<Ag^[Ts%"f|BEmz1ٌ]R2>BNT1a+~DW.1.b'*IpS%[JЬlx"$Fj.غ.;fnU}|  ̬PA?@_}qkFhG\8[yES91{:Ntǘ׍"Et$p'sKiXηxMWGBcI/mٔ)Zh"WX'9>V3S؜%`ʇm4Fr\^yA\3Q^Wv񢓺?Qvy')?⺉{]O^+4.ґ_'jx$p6kzʀ뎑2IHsrǨ,--KR:س1}3֤0-6qәFƤ7>?th,wr|ո#:P8=֎odfH'orN^3aӹmv0'QeFH;dуXɄ>N.7"XqX:XelCU9g0M7pX0|qlH^YYO^rsӁR<@l@F2ګZؽtz?X\eJ')MMEO(l<2͓?֣<%7zCN*#E2Q6\8%}(.3똛D	?ɡKW;V>dZߓHÓu	CJڢ[ɰ<͙65/r#:Fc?@?b\!j6k;E%AָIQY)u8<'~՘S*u\qXbTb5ؼ?"ύW^yp}svlޚop0`}47b#ܼwKʟy@6	}0vq6$ӈ_en߹uqC>B=Pﾁz&37ujQ66ٰb"'%eRiP<*KiA 2H)c-pa˦ijuǅ4dÃ|JuIƎmPֱs"Mss@=sdh&Ji|Co~e(&]:`^<QqȜJ F1\]ߑIG9_Pi;^қvf^:پYϨ#B"u6Ճm(~
=Rg:ξƪӅiF7<t
 9-6mj8~}h/u뮇Mok̠Z<EE;͠li,޻{g-\	M4/0<oN<YxÙh)s0=>S9.y6kءTޮgR3K1A9_9QnCpH3\!c*ʟ5Pfnb7hk$s+u=%RmJynnR6I|L<2w{T]FEKv:%킴`Xi,?D"bSw.2>HW*ȯ]P1X| 6<7z,-mS9C7ҏC;xHvVW=셇{hwC|c?"-uv./ϩ3%Ds&mȚ܀vf
\.ٞ_rbEJMGa}qXIo(ΩZr0LB$"8;<s))rג넚C=CQZwG ސcnZBȜ"@kkn4KЗۢmnB oRO9$o>>ϼ5up\϶;1xPù'E^gv@M%Lc/FML'oͰڈiU_e_F_FOɗgp͜y>k?)9/ڌuI^C/ӡ}*^[DSA[CJCEǎGm撩B"A_;46ZAwN%:Ł""תHYa埇̃%tKRv[̬R8)`,l>L3ZWЂp)gQ%n|s>;˥# ,h?yan#@:-IuZWd@^[N;nXqqMW!!Nŷ8|ry8iWRFܑu%PJse >uJ,sE&~Г|ilq>_և˚*rģ~ԡ풬H<BsRѺdavէ?g[':P%]W)_7ւ?2yByE+Po#]t:1+IZ42n;_/@¢XҖH{V4.9i4 ǙoԖKDO=-_UWmJZTǔmbѣA C.娉 ܠJQ3b_P0q\1}a^vY4aJ'	+ݽ_	߿.|MADUM.[瓛o:6T8Wz}d|OR	^eRLt]v\^$9-qApUfLň.D|s2	q8~~*L_C i^Tʧ&>
_ͻ9ykjow"ҷHU&l[EH|	,2FKXЩS4Ѵ7ud2ǟ1@OsSe]x<嗵ēͅ&W:I7rXZ}.Z@xc\/ɑyfys	Bz}lÓJEZnqW[5~ozrcO7oXHdzq\ri ƫmQې9DG(hɾPyA'Yen;nأFhԜcH,Y)ȉr#B[奟|Sku(JkBwEݑ7W<sjn\2v}҆xRf7&\^`L2kYc>sl2 
f]dF]C3
{C7c78T ͯyUqY }cu䗱+;E˯5K.JN'd4Qw/ËH"I]&^|;Nx`rQ?X0u[JB3͸z'țyΝ_)\&Ѿѭ9o@HkFVit-%aramLɏ$Yr<X+89@)O47-Qy&(u]^__\3Jr9+.Y)PSoWr?vܼ̍oYs1w1e=,EJϫ;a	v%φbr1|)~՜\cXpPi_1gXtA,oGԢ7kaٌ}k`-;Ѭ~O &jcrZ3g~hK1#o%mJzdhWsA|(jj:a6/:;L.;!={7Rq:\~}hΐy3"m~7K"؄#J.UKZ1,(16
]Q?#Uꄴ%DUj_*ȏJkpr(
Tyvgx~Q^7@)i9dMA0?e|d+#]fӿԗ|	CUɑ?A#)I@hHt:t R4L	vK_ ^:XJdW`;|TJן3,Ӵ[*(:l3ׇ>kZT}WdcjC%;5'˯yOrA/Ȕّ*]3a5Tm	iE¤Tvָjrĉp1GnkK-ix
CTc5yRGo*opd:bOG(p劙+uGkka(u*|lP̘97wxgݨ􄧈k]xӚGS̩?9d1ǰ/ssz|^tRUm9TVޢ˦ĀDFZ˴7)Q'^oT}V\v뫎^&bڵP>!by׻!k-J=\Pr]^O2+ג{-3 W#1-W
z GOL̱E?Ӗ/}C??9?	PX'*naLWp.>!%`r}*H)`-r07F4h},<.;;p /ib)=\@:ekY\L)ZePL:d	472x=T
O,ҁ,^?_%GZ&	_OpHM N/\F1ܔo޼yuƍ[onǍ-Qݔe7z^TSP-8"z1AkP5[jho9u4W4IsɚxßvכPqـ|>\./~ܬ0v}
Ou׋"bيnfuEcډ2( l:~yGydӧ'u!yn*A[_XD?Nnr'wzΠ%ћܘ׸yЛDz<Yz7ZO-˧~"4y+j{iҨlY/ܯէGc<)×=ׁ}n|mnoqxm|sO6<UF2P/,~Zr#}/Z(F"gt%~'߬$14_źtQF=(tQ>-9
2(G)pmle\!Oy3_un R"km9.&u~O>8Zo9F8R<2>,yp!Ro?ɤ:vޚT<Kt~w1HHߡy6nh;OƫTP||;=V;2vWǛu6z)WdX|ϑ#2}TpuB$9MakɒvhTxv@_~C6<-y)F_ە:7߰%nh`qst<DJ60v`uW&X^:I#pAѦHs7d`_6cQpw5(/uvv|UIH!4<5up*赃fݏ=/9Pym&O,Y?eC9"+lю`D#._폏`yRyIqRS!vMlx(6A6/6geYXlI#g[se|y$
4&,͆)m?6N]]qQlPX}u:>s磲h{=7(B<_) q2`qeFڤזԉYyoMVA2y
L'5~e6"J89@Ztv|>mJ[.8ugnǤ~#NGFaEGf,J#d	@@<	}ͺyEKm*n@/RxƟ}>O<z%M]B	:ǩr:^d?m0o8d>?΀YN:/ܖ뱁쌩Q+ΙcP	Wb~mea(ꚶd}M5XρnJolc(xw9V4kVZty̤ƭBɌ3@\	Zeb;m;/*lå:>9	AwnE;|4/^	Ϗ9sQdʇY@%KBTt8D 6&cb愢X[cm%uf|M>#_mk櫸+&`83#A.r1$唹m-^ć*9C;< $YǺKalD::%#xmu¯0̏^2WEO.z眻ɩGyRZte/@Z#k7|u*Xzpf*ctZwٰYlViX+꫞޹cit;p;J&`"IcR0	IzkKnB؅`J\ïL9$řc~~HRE`*CH!%r`yY[<iiˁlwx$<'~.wzg@H)Z!?;ǭQ:Cbt3ra$kr39DZJt.%̷tqsͫQ%-Exzs]I9<1$+ȓV -t432I'\&bk@BvREhqa&.N	oxӇ禰}4|-=i!8|JL=i,zZ[<|QHxo*:L¾\n'Yq͏Dh#n4zp&<!]Gސ<Æ7i >j=A1i@Ul@a6tDN^+^y&Ro*O#Oۧ,({);Inݖ^n`ht%M'/OxM_~%h[7n;7o)$.!"@'x?]^y/ZֲR6h1k6s~&ansbŬ:lS?,%c,}Kp`01x
ug$&<^2x+Wbe],\\6M߿+"Stk:/R(6xO=hKO##wYsߕ*%VZV9|w0[r9RamJ۹ɔ%Fkl{)"	΋`V,G)$ˀNPG;vF9i| <E(#;~w^{J"NӦC[8l^OwM-,7$<ddJqwW/[oF%/O@%J.dT`@v'+z U:u
J_t3t[sT'pt1@@~}gIW
ˢ?'F>#IˑFz|~n73Ǝ3c	R;Z7A\cCz¨lM.یv]|.{n-dT\HYrēl-iW	s};_yG9Gy)\躋.^v>2q>up`B~s;	*-"VmCW,¹fM9 }<&_;#^ݛN8}:-!Ua7+"| 	P>9M]DvaަM2D@p]y^R@£-mN(Nk[ZaLv?^89v&#~Cwl NdGk#j>9MO2'׶rx[̔S8NyM}0>XH:C߬3cԊ?0F.7XDviC1OcO4H/%9EalsC&5r0H' aN'jTFʤ?t|zH9rSƈ\Ub"x^$WfhWQ5_V%}؆kW"l[h[RצrtxQ')Bu!3$K:oՅoCG#Ah?Y|E}\*~5hިIG;<]]̿kȲ$ls`v86䬗ɋz<s(-욵^4 G.9b >2"9E$Cz5hk5j_u5
sV0qH8[
EϏ13dͅ]^Is L?el?䲊^@$P'q ymUs "l#Ho`.vp#Fyo/g[yoq(#0*_Շ?ߓ$!zI8I,؋%Ttpt8TT >Iq>N$,2yOtVqV!~k#$ILg|h?o8g_~ŗ}/wرcǎ;vرcǎ;vرcǎs?3#GpWr+s=8Jy98o>I7NC/6&dCeoj|c?1Sv'Ev)@Sy_Xt!K	?'گ 6@y+z186%⼙2\TvGD>*IԴ3ZnǸ(ʛ:c'.,ҬAD>"9؇&V^o9\}@EnJ8$]nRVT_}W|龹cǎ;vرcǎ;vرcǎ;Wz;|}OfgW<&oMOWg*O5y6[ታl.dëk;aI[C_ ނM悤ٯ$޺39yFTF9χs-j9("";?fJo,)
Ii^Jdc<f'XWȅ̮fǖ}t"c]Π -MTRXE _A,͟:|wS;vرcǎ;vرcǎ;vرc/1ɫ}'##)+~exٓɩdOv|8~ӯFyl߰F'ƆqiW}pQ%B sb.K/VAdK(?iEr_4Fodqa*LWP#n;*Ab9N9ol>l3;X]&q"0%OQIld#J?_׿;vرcǎ;vرcǎ;vKww|Wp}_O8+꧓ήz9=9'gٷ~ӯo߾O?`lO1##2CK9J0i-#%j7sI{(:,~6Ql:sQKT=pxɏ-a*
s{C)u.Y@<0,/4~ۚ	f7vQeEҎ;vرcǎ;vرcǎ;v|-|WNON|"(8wW{*zK/];K\xo~8;}/L;ܽw}?-E6N%QB#Eod%jQm\*4qd:t4.{b$Dw܋jJqV6i&x`(kr)ցX͝Ѵ|-x{qTtfa 8!vرcǎ;vرcǎ;vرcǎ?z
,ꍓx'JynL<čx['xO={D<Vzދ@*}eΛyڋM`!* LN!:O0}ڈ9^gS+6j7;/a#y;dg&
I8aîQ,7lEFq\X6/^gvOٱcǎ;vرcǎ;vرcǎ;>_7yD;;;SN<J">9;~
JqO?9ܻp?4bDk׮^/l}޺3xzjb@<TBoR>&'Tl*rl	ZA1E(?%+k_ߩSj6HMNA"~r*LNeJ8iN9rh9R>~ŗQ;vرcǎ;vرcǎ;vرc	~Ѳqtv|i5ڵõ$sVtz899=<yO.={,~Zl0;n{|6NOy{_%_r/[o d嶛~d#ZqdW`m6aVzydc3`j 3eJL8L].t`,L|p1yG@[\9mrϺ]"OI:Ϝ"Dx5F<i؁ݱcǎ;vرcǎ;vرcǎ;>qnR;>HfW=zNb'.O'8Fo?.j^O;{qcÇHm`{#{ҙ[D}ěEcUd(?^ϳX(lh\509CTmm(b57Z_2,c@N_m>8,8BsL5Uv4["$\	N\PVَ;vرcǎ;vرcǎ;~3?3oo=ܾ}8[w8Oy++sO?uM7]c?3.vQ/7[v`3oL<qu;<)!w=up͛o8<ꍣg8|︮?+ݥeI{':ᙵ`H"`[G]؆7ê+--_h޹#wEgTq~]iS
6rιܨVMapʅ^+SnTG졖Zs}p#?JC$qfǎ;vرcǎ;vرcǎFD&om2=?i܏ȏ˾78|e?я~o<yu~Aoc?c_.ڔtF_]o@tһm}&?zo;w=yWC}p˛HȖݺuK;;wn'Rp?/yɓg~q 
y,ub~zuDӊ-	!WČcc)%?6gtĹm0OqH|"3R=۳SsV:ĪXHϖۚg_~ʬ_ezay-0c.Lp»)'/V^˄N5PJV6_;,]tgS7%hF:'#H328W&l\U؎;vرcǎ;vرcǎ;~1/t
lpfo};~c#7i뻾kw'O<}W_ʯJ/}oW_}n3ju?C?txW*6Zhuomo@au]_lJ޽=~䧗?Kl+$+L/ˡ=qpf_$!N8;=.N"?DL4)t}9W>goC#a-s雮tźF ʖuh6]br?EFIQq%.ӊ2#|"-]&G;+!VkIW5
dCT;Sї/NOم&:cةߡ {>7N[tT>8Q~l=$kiy䑰M/R&a[lvرcǎ;vرcǎ;v=)o@aS0o抹_%_r[f`lg>x3ƍcjЂ36Vvoo?/!wQl$5؄coxɟINr/}͓l:DǇd>x_c<k}|W8,\$6ECfe3D}B}]t|ѰZc8|[xdMcΆUk%3j͙ڱӺ~dY%FB]>vKɥAsupllCoj=i>{<{5|^vu3Gr=͆ϥgOiKLzƟ=uV?WCX'TR篼=qmz &K?v	R6	[9_#bǎ;vرcǎ;vرcǎpΝÿȀx	i?˿-}g:)!O4yl}7~}<R?Qԛ;͞}__{)|#p^'plV|w~o53L!r%!qSK\B֙\e݄lcl'~=ÂZ&c4<Nj4ZVB@/g{>;`9DN`u=6FrTX ]gR%d*. 1fmZ6T8ըtUsV5Tm6wNW\;61RJ	Ev#^䜵0HBI{[pCTcǎ;vرcǎ;vرcǎ_"~?S+nioi@	|nfӆM~G|˷>Z_u}ɟ7x4Uo-od 7'Kv1m><oO0a׺E]Y+a|'v]0)gHNAe8ՂZW)ޮvĲ1YދQ}d tg⬾B}=fK'mOi[ rT9fS-2.]xobϹ!Oȱ ejRw\;#4áER,j&мm\B Fg_Mg'<ɹͤKul/SJnO͂ѶMͨjsf0yQa6"cǎ;vرcǎ;vرcǎO%;B[W_}G_U_e9^Cf
A?GȎM^]w]~x׼t-؛7K>?O7o Ouڶ)xz[|!#M
so/~ܳo@n:NON?[`Gc
BuhV$u*LdEEDꀰ}i {~%?G}j)&=:!&+$f|ĨPWjJ`0ϣcvlF1go8p`Rd&WԽ;xR?TN'Hy"DP3jI%+g;+L<$9"OXZfǎ;vرcǎ;vرcǎAy396=yx{xc}:.\?H/2<ozW_ñC6>_~~/T_~륟`S=xpn6/orq;܆.]O2PxG<7aO!'_}D-Q>X1&FɛӠ-'KbɍLkS\Zl6O*ñt]4.5?F}KyߑIHLX<O;sl4TJQ'bP[49??x͜K'g~٧'N=;tx'xå2>V|d/Ox|SJ#8𾿴cǎ;vرcǎ;vرcx,O@*[o#7n\E?S?eO	~կ:l#|~\FˉMlf'^j]ѷW_nͮiS+K_KϮ.̽^]ul8RiU=|ul5RL\*̯OSL9Q_:cIYR=]MQ*^E@Tq5EC:ņ6xqOO{w%G
?:<?>GGrVާKXFa$G'v>k䫼$]p\&i
رcǎ;vرcǎ;vر~~b|?dG>Oi'.ѯõml[[B?ˉWlƦя~O&R>=>E;(M$Z:;=+ȆƐ\ŏ5!с̂7Ft
yg.g S$OμtfɩԳtv899F?Nym˞ÖWUʰv:gwtL!#<}$.G"(?c¥@e;_`<{zxZO})I*رcǎ;vرcǎ;vرoB/OD_雾'7z/#wyO0:d>:ۿ=SBl<o	>6Z:\A]_#q&N]_>y"++y3-6	Ļ}A?8@pV1!dA|ӱh("܋[l	;Ym@.};><t+^㶀`INϲS_dj6%tx-y `{DjaRS.l!RP.ÐXd[t A(2Y9;N|?7ܱcǎ;vرcǎ;vرcǎ;>p}SQ/ƹ=׽HdXJo0uz_ňvw.δSi6N CAl{}"K8fT&NQGGO(zB!جy*>Od號~ɓ)<R	ـz<Mސ
{Ia>vUL/VrL)؊)ňo ,n#
:;vرcǎ;vرcǎ;vy{FgWཉC+ޓ` :o?Ƹgor3r`M8fA2F/~9?)@8&SdQaģ@l&pfpT>\Iro.8Ro<	cd婀kyӫ툵qb2Dv[M]b"A.S3FĎ;vرcǎ;vرcǎ;vر{1zK_KϮ(tŗy!DN3%6KLX7'4,H̓::%b+-PL`&YOw@A'Oj*NwCbJ)'O~ҩzOoz1K"b[&P~ucqL>wtHXRwOcǎ;vرcǎ;vرcǎ;v|^{SԭuTޅl(J<6rޒ:t>n+d"pt%ՁKK3Xdn0Î[Qszʘ[.4
OKBDO<%[_xa-+X&lWk|Spߧtǎ;vرcǎ;vرcǎ;v%}\{˗⛎?%+,PB+XVYO/B/U-tWՈAt-t:Ձ5,lI6WFe6\hDB\HW̱\
4g%7vkXp* e': ȉ6WcAc+Al߱cǎ;vرcǎ;vرcǎ;>,e^{zB޹rw䒣9H΃apJ!
K4Iw&&,b*eN6⛪oNXq`*E:tc٫?DfW湰CV)@Q
OQMc.z7H[P8W#t;vرcǎ;vرcǎ;vرc;&QݷoԍiMV#v+g$zhTz:%p}MxBٯXdXY(c,s0_v%|A@ټ$q8gx]66rr+-)*;Ā3ۇ$$&l8-l6Úq<@!wرcǎ;vرcǎ;vرcǎ_pk~ߛ$:Ot8=||g [/JO-q_nE<0q܄m뷧;4)ď:kC.lxSߥ}Ǉr1+:p|F'6 #W+ UhS+L<1y)p+}x1اq6".ksSԝ}
\tRD̎Kvѻ.Y]'yMrXO-)b;ZL&% ZZ	<e2)ЫdJDh qvBw:=|{{眛7رcǎs3;!X^C+??o_^/\.?|&\'N_N<[1#/
{K<&btf~!~T	UF2
,\={\x0[>xܹs/'OZN<<$\<X߻g#i-|%9Cc˩ӧcǏ+rYWG'QVFt!=|aΝc`[+0 H*1>}L7N?EnUC߷nr:tExoJO:}%eEP~#uҧ 2R'n߹x=wev(Qć?aĳdh[*]S";NܔCp'Ot[y+-os<}rIqLǎ,w*CNh@dr{oW m]pA)A	?&9N>mOK>Ȼy]\'NUv¥Kjʀ|޾ykyEtÃ|<}ʲR[2qWAE-}t_tKއ2؎([R#r=sN3g܍7ٳӪ_+]:B1'X_%B|103w=(IRA4ishhcfʲ7'x9.g`)kS#O9ގ?twTH6;}lM'_XNMSzXEts_}~OvZD\G	ϻH@DD\lNs.mÁbt^;x;.@\?wqf3|tRօ. nڹu#[?syϣQ=w?*b#O9g\(F܄S=X#?2Rٞ;wvy?ƻ3V%y5>>u8B//Q M=z''Z3={^>@<PӾcNSo0y&7Y_Ҳ-bqԏX&պI|_WˉF/s}N06#{͒"QxܤGѺZ!ڊ`XݤKzJ4C;uYd"[L%gAԐ#eJSciq 6߁蘻[Vx|:ۚц*֋/nA@nw_*<[j<TaK5vKGa޽㾚}kg0wv?Ѓ:}cIChp\DAC'OgO`nիy<{. ]K͸Wn5 |%@Mx&?1K=)NX	?MB۷>/(*OzuMfc&z/}@'rs}sƮ#Y$'},O xJFwqPCqE8sKR˷nt}XDϡ8HWYvXMG̋qIcrGc]ƚF<QoBF&Wz4;dG:OCGQ&rQofNS=_zfhITD4'N12UNҡn0g}8tM_1g$aIAkK/Ij/4e(8'GtuSC4gv[Su0ex&}{Xm͒X8QP\|$vɴt<H?i4;Qp.'l'hiZ5]#)gإ|3>*@sMXSZ#0>#h.`.2gk"lѡ9yLYM\	'!<6TvKjtH]#,kHx~@v;iupnZ6ZQ*0 <ÿPӌڅ
S>oy,,NʤI46E1
CG(< ͊C9/(Tmxs֓+ٴx³|rrv<~@U-">Yphp	;I 8`⥋EJL0)8V| l2	۷oe?RV.exvo#X|]B--76i=Wz.Ap4JgE,ب^QQlՄ	`iJl"8%St_ä6WrM~e*&4 tdYCª8?ыA/Ӱ!}A%lǼ -h2§C\g?IByeM̑'l6E8$DT}ɓ]>Q{A r<`Q#ԉOLZLE .nK=C[Ov~Uߡf5iJK|ʑ$?Ϝ^ΟcmT).wG,1]yd9T|˩ǴEÂÔ=:n3fc!́jAaЙLsƍl}e/A,;FTRj!9vq^2`\Yҗ?>uU-qabE~ӗ;{κu7s%J]MCׯ]3ѷFOHc&ylY2R2X<_P|zCyi#'M~:{L	Pzazd'cJ-LvF).4S]^D2ǜwm ܎%F)AHl䆆:LZxF&oAMn!YӖnߺ 5ڌC1 &LUd	'h"
N?U@E_@Mפ;Yojc,WA<DEGlrq_ oN郉LOƺ&>4Lӷ0W|ݶ0]XnaHԛsq3-®fO76iM_MsvF ˀ8'q3u426'=&*Ohȅ8mSUXq@V AdSFq&d	$<i:'d+ *@GDJEVE a!-zCVe_27ycĠxM#\#sH_=@T~>tr#~g3L|= 䩜Ĥ^z>R3Q
?_x1Ra\}Eu])Kn.J[Ȼ.!m72bCpyUҊ/\ղ ;Gxq}ya}LKa/piSC=!^/uf\{i]BW6]"eTa-s<a
sCpNGK*4t<y͛7Σǚ?jA
EPʵl/7^rxN֔Q& .wP^71.9ϹhZF['R
q	|~de]ZE[a&
Fb~u*7oFK*>sycwzFۨogڴy𣝣 {! {`P?9eʍ46}ӝtC\.)
0^<_1Ѹ(¿p JF=&^.:kRUi`R6B487f6:SXu|Y*nJxPztL-!Q;tQP908Mvy<x]ǁ	mD4p@q* (X䠑,w8`O<fծ'ؕdt)N"nNPA63EgJkW`msM?3K?:
vn߁R$Mm)1FL3v(LĻNN'yi`9q |@ a(`ޔl4dˋtpG$Iӗ:CҩӲ(B<4[@p  45y]5&w&* F	?\r0Dx٬Ϥњ%dU>ɓI>`pѯId Sca_NLkpu3|GSZH9IIش;c$6Ϟ9ƍ˭[7Tt@$'֒' R\&$6S+)=b;9MIWd-@AJf|&X%nilBg"i<a5ZT`7l*<CUia;&?&)/1IeMq.Įyq!D2n{cL6/Im&#MR쵈ѤNHz#2'- Iiug}~aM=eE!|Y#9y"vMudE9iy1ڦq:y\}6hh`Lw :
n&wԞniquI&puQiI1<,AG+Ae{rGʐ7nsR/{]e/&gҡ|o^06-w(O6O"WR?l,N9WXO8uν>ɇ[y-YqHSl)e{C:%-+܉(kj(1@/]vA<(n!A@i!?Aza[|/]gо;32T 664b];}-g<52J)mvAP/nZxGq~9]6fGCX!=vW_zQurZm<RL_: d׉bRA&N.a`!Iת&o<
t]/buH6Lt}zQTuBf^U''0:+`s< Ĺw/w1G> >s՗6}	\#,H|7?oݐX=i9m.u4ݿ{T'<Hd_9Jqm;>8"p],Qg`?#^>:IO QwG	]kq}Ħ}$D`QSֶ@JWVZn8ow "8r&IAG6Q9Mԓ,.gm4цJ&Ԋ|S_T.8?GRy!9u7oh6q[
>G/]n	6I)2׮ZaSnb"nn喛ƘM;ϝ'Z\[s	-nw4eO~ ̨<+rԯeFT7=Ĩ.K4]h5dp>&	>7gCed(094<'a[{POrTԑ/'ޔ(|QH%0Y2e9$(_Mْ!~a&Ci>d^{iit=?iQvF>3Ѿ)7%-訳
#&'{:5u#?rE} sfΟ怉4[Ae:s!7Ǡy`:ƲyonͰx!r7l
<LG+Gd>,Y^n='S`BP] ʾ!>P,mvhK øL5!?D9$M>y|lB<ۆ ¿3f7ٿ]wlcd|#QNM[.Oto5:LQBƚLxU
+
?
ԿP>%(}r$?$쾿jI"x
(G9>ȫ*,W}ĄŶ)A88wL@:-tvBLc\3Dim:{nj?t~W
sk<d	x@RE?Pl) :A>EdW5`Ll޲_M*{LĠcBٴ	I[Wr1kGIVoX<4CI(]z'6'`&5qU.иӉ^ƤWRYa<<P-'9p'Ԇ#*"e/@f>Xȸ5qWf&>Y)lJ.fW0_ᆕ N@V~XGZi*'R8OnȦ3P8/,>@o4XRCA6s^ u 9X!998%0dg"ίd4K.7p@]=#-6',bdnwГ.2so,c=(d8vD:ok@^r*q!soJ!	bwyr+wGVCSʟbB`^Aaސ0^ކl^AͥK,J{z(woRiLFg	u|U:Stxjw<dF|</~ׯ_lIrq7#OLA>`otJOByy=̅܇{"kf9tv$9|A}]wF ӟp&wZl}{	Kw$ж]%cL6-/aﾃf"vB1yeUEјGDS> _^18#Nq	c*ue-H.:݇IUXE	 q$D'U
7how!ޚfp*P"Wܧ|>>!}m>7iOyȘꨦe`F:.-S'yEYoOs` ֧>yY>J=.Г	`9ZJzy%^0˯ɡ?t	ur(9 Bg}ɍbtN]܅P3<V ,!j.mڝ8TNIg(&'IDr\|4ycXg3.^r
0 3.w<'ܚAs9xڙ#aї),/sduEg|1hC&]EKS.]t{DQ+c-x&@1k9P\СڝSGb̹0]pNKt_bi^ӆg*Ȕ1zv_S?\Ӓ,fey(E䥿_տQ/0!;l*|7btM^kU<f eA;		`g-.OMOѷ=?0OKZچ.m Y<5x%חw!J,Q6A~SF;&ø7k$rݑᆸ B)5gnA,1rPǺgMy#9Oˍؤh] x@My #2'|O:`~`UN%"r#,.Vq{e>AiW<Gq]XTץe1o a	wcvN0dF֋XtqO:1q#)w*9K+k[O< ӄɨWX5͎N(0@,gt/'|v`ùu0G_lehP=^ï~imMUCTTe.|3cPvs5SxIúlJ`+&/t7ݴ"lr/O}mMܳ'L_Z> JC5I\ň0<N2'wg< ,g`CԠqy}6Hڑ na3p*"M Ϥz9_!s~#Y8/"6wY80,~&OR3ĪsMaGň֨ Y{3q;~Ma̆QꔐZ#&xeh~l{#[1?F[˽;y)E>ѹ?'4a	oY[cqL9$ŝ@tʞݲPeԤ,  K9
H]G;(uS$ʊOSw)>pjݐS|)=H;Gf*]($qSq6 GGu}XPPq'5{c=.Q7ч"yQ2{SDzho],k!B
Y~塸S(<'
ޯzE
v] ]XY79M/s "	|e_,yB(NGشq?bWN6|9Dx?ʞCf'7#g#~F/B:;Eܹ	KslW QH޹c37+/lfQF͓N<iFery\R09Xh))$	KJ}g*rJGnCC{:Eeю1䃿83Lo(@Fy/ʆ6BϪ|DZ#f'n38	)¨r1c8X~2ItN^I6npJ
$.A51.-*bu$qC39|$2}C:[S!B9g ?z oqS[dMiF3a>Na o`
x|HgIT-pHEj_UZ&=#[<2~F驿&Ο\AC>$XO&&p^'.vK3M
H<|x9(Dgx¨aUܻ<g ,4&;Zv!$~YιГ'2ymʞ: W78Hԡ46%&u ղCfi_%0ھҧz/ZAD*\;\y4*q_D~j։ܹa;o,Z s$s6Sf#pTy!LM?Q/3P7VVl:E@;``sd@*~^
wp	3zu>q
$|@%xs#p'GRy$xTpRܬHj>_x~Ƹ(r;B~qb~5u#jXgyE,1MG5#O/uxj|e}_K}84Ňs/2d\DNNhytuz^]GN3>v )akLo'WIw vډx)E˝|Qay_~3 Y+Ŗ6LEް!FD& ^W 31qhk̩Ln9`Odim_k׭'Ȱi	?IPw35t˩+n1~* EDg՞GeѼehϓ)DkX¹S解cNMGp5bA#]qhtX`
\g^EC80;;X|btD PE׽o=ɉQ:f0@ȅ̝
+q]% $N62&
BUlЖdE[!o0킘yRJn 
rJi	l`0>-zW^Z7,HaL/]B!ۈGLp	m9SV(\lFWJ	7ihyau<4ța3MlL5y<v~OJH?;Fq>;	Q⏉*Җ]J_Qd'xnʈ.yfѧH
ܥ
#QHKP=+<|,eV9	?MJu>Dwo1fI?d7r,|z!@KX6?b.y<ќ.AO|ˎn"h/z+: A,/+}wbh܉9Ǘ;kgO/-9\&}xUb'1I¢2YeOM H+JV^K>cxZӁ*=&ߵ>ג 2oc(k^]y0]PWy}6sF,9x:A&7kWYn,*״;qlq&[^ؓyW臛s2Kl|py| yFr*pD']mT><S |8w\yL{`$x1jamvT
␐?zmT6/rJcfk6g5.]dCvRh/<-x_NQG}vͯv7!2U$P	/B`6S!i|9Q? Xg3}xuJO>:˓>7{E 1?P7金m]yrrC{}Xye}-~Л|/cc	gl rDj!l=(7n.7H.΋'c93<+xL }9ڙD_[~45ܶe#ebmQc-0hWTsYX1&7$ xWG1햇:L*op;ibOqmn

\O>sh `b0qH=C k	}3&O
yMxޠ`'jcD}uS\gsVdoLHC4SK,'Z4lvDʒ^><D
'_
u&C?8e^>5qum׈3Oۇ0ʗ"*0t076<$okvt$˱^*'t4_P0C$>!`2ID_޲}űa7/;SLROtΓHq|x|<Ky\OM:sC~aIU$=0f^ty/u@|7y	CgyLDK4xXo6*y~!FnD+	!Dt = hK$Y-pš]7@;8|-*Ԃ-W/8,}7'=:l?8K}lGUrml7ȳ7!;*=\u,d,:4|8VcSk^#nf0y |ui6n/K-C;$9n\u M;a"8T~ϖ?&~)憾i5pq@jI3ox:> op{b]ͱ=20'Snٸ8`t䕞`婟`L|qt%,;7:&pM  $&Nv8qCۃJ률duBgw/OU[ y IϰTqe"I	Lߖ&Uybl:ˬ_#/
;&LMz2YTHzqPԸloi0dZu59{X!?T,=uf;1Z<Gy7=l$IC4$̱y>Isowp$iGe?ح3AS?پZuTao=x)xl>xL 8^6~Baƕ5N(NNB$tI:lxvL'<6
>Xh?2,NDU>/yqXzW%jаnfPi?V$v\>*)tZYlLhT?䅃A66XL"2E~rOr3cL:<*bsL#{顏 `j_ZBR?8\|i90ddӃWևQ  !ݏgOdwh C|f]*WJ7dE)vW|Â͔散`9s>z~SnhM_|mY}4W!dcd!O}lN@wq\~YwN_r뛀'SӢAH6ERfPH\㕍S8^kkaAPߨ2Cֹ7FݐM_l7`<N.m==}^H=m>rGyG(@6D[1)뚒r3
 OztflƸw>H+27=aKgw~i/_knyu1iOx'aS?wIu"}dtD{P3gAG8'O>
~OOA7M@?wJ-g48<GtH	q!V/dh*WY§V>+&2)~д\:zJA1MHatlW|`_a'MCd$nCDSW;8^1j6Y/\qSrgsPo:-?>%`8rOp
_^M]:;In	f2܀oS[w8aƞOub`v,'O"|IB;lGlqS5xh`7>Bm.
:'LU&5uLMwwi!e*	7$!?i tF_LG=pVч7q
!.з@dn|2vuYzCl3g­m҉$iIǢ:i-/hm4ؒMc>M7+O	"Fff]u t~I+u,}ejCDk͖Wh%3u '.@o]l~Ds|)#ČkhN*6vUr漾: B86<4ӭrʡo{oD>3]UI_=(#|"CZd9Бk\ɰw DmCwmN1u0š̡|ps`-͊%ϜO^/Q#_F}hxΈ}[ 6姁Ǉ"I홐9Ǔ^ͫ܄9CTE^հ=p0YAO0;~1
&{)]W3"<ySR̕p`[tdR^PBAZc#khY7o#yyC~
;T> I0	&<aqVˣ]oZ&xO>v|y߶|UaUoJG,}ˏoXB8&lf2ha^ 1I,~]@1Y@=o;G7,_"}$=u@Y%ص1F~!c!o;\MH\9eA/mx!o0:#n6>ʇZk'9IB@X9x3Ԥ5ݕ\ަi?'^$O8[uPmym60]F354q&`u3}'E2ʹ{/$O{7i˯S[:}b9ױ]{R98MI)/E/2#ud8%2|,?t$:j㠎s$ĠJt_|l6h+WtlsWb𕔧#gB^|5ozY	zڥXΝ9m-S)ІTq^ dh-ˉYb/pf΁ `W:_Q'oД@5>`l)?t4+sҋma5(D3%aIFz`~tфw30_@,rd=6Y` H,~&'UHƐUzC6#AA((=typS/ȴI'WJ~	b9Lv/Kq3V=:ID;XUd!qӗPv''Ly3~Jh\1;5+<E''!:e	nKEX/\tf03rݸy]9@1+WI{K}E]=x7Iݑ{jy=1}+1Q[06@npybH˭αsPvt>-`҂58M`$|A%4GT4@q|~%1?Џ~~e9cB^JZ΃q@J1oa\1cu]1s睞7T8Ql\Vi*M2psfp)\/ /K#Okʓ~};ӢM¹\PܯP)U~#mؼ߼wFoDRr2TpT>2C'o :D?
EruU5Hi"OJ#/<>Ҥoya΅/]Gu4-SD!&7O9Mʹً+n<@9Ki݁(*2A~`3L)E(;o<5]
y6Vr>I <VҀKI/yO+X?.Ȃ޽ɔ.取-~ɆBȶcoXtLat.'-a!CNcpl^:6	Ndw۱"C&qX=M1{HAmXu5MH@$Zpy%`rs>DcpN['4!k:Ү`v>زQ
vZydM8sOk; v>{Ǉߞ]"?t]
 s
T~Z|	;]8l0EYqd\f`
m^;zn	M1>`r^tI	xB3g.qd]~;:8f$,[N&W!#x?B7
VuiғVfuWV(HkTHLpWsP/n_|_Sy&lhI%.pf1A{gAX1[|U˗oX^\~߲|UˌH|->A}7/_e9#_ l~a y?+/;]=_~}u7NAVĔ[QXO^@:~>)$=bC(k<qcx2=S;+n .L'gN (ߵ'pD#PAğZ}7>~2w0qՇ
*]v#]A%rprL|zB͠uDܾ~t680^|Ϟ>/|ZN~Rql,si	\|qK x .\,Y|	<hBnf&L-a9Hbq|J9-M^d2`4 >FG,p.{,Ϟ95 _aABB<Sc	"csjywB7oՇa#bx{ʨ:%~Ч`ԓ~E?gG}to8ͦ1ny<1TAn5~S=!^q)'ޔR̪AĨ]KrIS7SNdӗeUl01BnAz+d"Ox@8KK/w<@
pWw\6&JnO+W,.\r8-4qSYCtO_~)oX^ !.@{O}M-<}_#ȫ-٬J|tmǈl!}17#ZE+E_}ȍ2D~r5˗/Fo"~~jSiI|z%V֯=~"$ 'd/
ݙݮG9t7ga\P,BTrEA|Q (? rSxS6u*C>s7fTst먯I~EeJ[da+W4g?--OpМ4E\MXI;!]3qJyUxIcݔW``O}Wn 4]?Ͻ
!!B'*mP%#yKOAOL19(c&a\s1Gy̔bL^Z_(y$¥Kԇ׾݀s|drzB@psi0i!Cᒤ"(^AC-߫.>:\8{)eZi?Y+D|Owd!Nd1AxZοH'!@4Hy*m}sD=#+LMRc	V~܀{qm<FIqrڑ4)ԓ͓g2'<n!6D0s-nc>-d>xp8ِ?.nK
E{Kz
YN:/~jN̯SwLXFq<'_%9WC`#Py۸C+f4 U2=g g?Q|ۘn!=׾vrEP''xq&-،1$!kVyyvƅOc~&+:.Hp*1J,咀ߴ|Lzid+4ܜJwq:˵rWphRXYڿ"MV('[n+>tpX+~`1'I⭸EuW??7iu;W}Ee;YdXzrH'ׁГB裖o}YtrOW^;ayg}Uĳj/^L/,?߶|usGѲ|'mo+~uNm-˛.gogՓOMW |˷`ZTyG_o|?nO+5fy{EҞ_~ߵ|P$o
x+	Y]WZAr!.Sә>܇Ds#& u!!mX@`;9OBeCx'ʫcƦptC6wh#cFcEF-hg,i#,4C<t#H(A-StG
\tHs?O{  6K/g[׮;o')[X.#ÊpUO:\ti40f375)[lơc1 oB;{{]/\UqIr$͹Q:K|W;<H~"N^zzau΃xO#cOߩ24B/!m'+L dBD韙=x0!="z~a	E}ppE&
FxP>x,AE!ENPH^+@Ѕ|˃>IwDRAxu1-]P_#,MbO 5Y!u(枻),?>6%Q|y$(I=#u8lX5֓1Ȣ-#'+/~]gS$()uAxZ&)]x+z.v0Voy8P/rϼRw{?oV>}+@6fy-<u3Oȧ6-<!ۓ2qdt7<Ĺȍ7`o^>)z6.^@#4黯<%^!ٌ浪;Wﱐ>|WOo~gU&۵	0U\6Ac(ql܇"HZxmzQ>cǄnGoJWSbfYx=U)6BӖav/7*߳g @^}\_EQi6>4ԓ^7p?/q@H39p)*@k'[H_ 5*'$\tb:1_RIh2Va3'3՟TdB֏(w|7|!7sl&/ 6<qDw|p }dB>ʲ8+Oxi줈7ʃˈP;l9O%ӎhfڸ&YwӔ)	C&HT7=%zД~5eGΫ;S/T&*_nw3Sxڈ2IZ.T)ٱeN2T3qVnim9[79d?08ڷx;C3)kB+=b "p/3H>낸D;6ԋǐsۡ}'9|>Ӂ8NO.x9vgT3Is 	j?C24|$|$plk#~96r8)pqA?韓B8մBd2Ҡ1/a lyQ0v`DkjkU)sf^TxIGa
*HxaJp$ub!0?`5q#B?iUN}4␿Cӳ&2O#G{[W ]eBR0 dPٿWӗ7._׿|<o0=%w1q;{gUﱜunl)⅄{bJL*p}ZW+xp˛Tˏ}"ex#uxs޸9\?C	ܲV8嫵P_2>*/<IZ_|d=Wu雧NM{^˛Gr^׺cЖ;Gb#R'\bxqmvXCFɨ>PSlj@aHqqPyƘ6N[)ӛ:\ΠCBB!pIq'8Y 9dG
7)WCeιf3m7:<*7H7\ܽ6`㑅%%B## Wsn.a~@#?ʒrLҋ.Wb("~|/EԽ3i4/LLp@cc536Pᡋ7Qq{lfӾ6]_q~bqR޻sw^^ܹ3ޔ5,dRq=(lW)d\x)~dk;e̢}=`r!l6y:r97EU_r0t9Z],`t RƩ.OP73zW=pUkK]vA,Vw_i	.5;Ϭt9zfYi?5KPIy=^EAʎe6\ ̽u!lp2HQv ׼5y|hyRlDR?	0FCEz߼\&14/? /zIj0qK;?<&\4u	TiKҥH>~EBp!z/'ϝ=:sJMJ<%<$ʊU{~w|"z4|R::#=E ']y,v;pnEkt.sh"WY7KY$*ǥPѱ̾ҘW7[t4jƀ>ipm~We0E`4"**R_tsD@2Fǀp2GT=T#Ms'Ck OɪNrtTdn$ߩk*h*I06.3[\RS<0%$iWQ%.X#>QrKV9)a;x-;Ŋ1k?IV8ceur:W܇$躝:c T=ǣ.ƛ>(j3#\gTd7ut+L-yu#Kv]&n52	ðc ַ:<5~^7tӕU˷FDPew>W"c<'1ھG ML֚sNn:|Xٍ6e6qOaqK^ִ->H"z'aNaYÚ ]S%TM:FYe̵<|)MǩF<<0`'|g_y0;Oeu<v5zPhOav 4~HO34|jwY9:|B#Kz4u}_)?YB캦 aڅ{u	9*l}<NMcH㒉>iEجjͽġu^ MO))*-0g>?}򵗽_5~{%
4e$B;"܄3y DƽZKs8RaG58BZydVG*pMQ鼚'8XjU;`;Y b:ݗ7LLсP5y̲ǽj'u[uғ^Mߐ|-W}OL=g|7~+L/?鿰ϛ)O},{GAˑ/C~߯\;qZ]T:.ߡt~4 [Z̹'FB"wV>䐐e"Uq3]yaqӿאp@&2>|_W TeQ̋E<Il0 <}' iG>.Ĝy4CUZĊ]SZdF= =@fT\&Z|\<³ !w6pοYfm_Uf#=}>xx9L~JIUBm^79^aK;ܾs۴և(k^38揝G_ÛyHi{ސll!xhćC-@fS$WϛNO㩁;L:~z@gϞu<D_}7O 7$<`ЍnxB@@xF*?@&!I5ş>*i^xx|06үDOޤkݳ $3 ƅL6~䈁 ??pش73O[F/*TKπ#nV嵄<w5.iˁh%CYPhC?ED8Ie@e@=t;l,,r,_k_ZaȇfHv'K{m4!F@S-~3^ؑZfx|W8JWr7O3囶yx9։lSG9VP}td֥#]=O!AA0eOfd>Ȋfd捧\.lwv
8/x#Yu?pkG4b.F0	[yeOЀК[E1)7G^ҙB]һ˖yNH<1 )Hm?RQwԅED1qDh7:5 yp2]_a|HJK	{ xuo08N#;NV'4&f6y_uGΣN-8оqaJ0i1zZ`JBWR2y~u)kK(vl܉$ӿ;q([h{f#ÕafM:ҜaFAfLU3B넀('Ѡr*j-C'r`8\:v˦|0vSw;Gnű\KD)ό]+J`#;GE^uSIo4G^]nc<9n#^&t<
0fYPS;:C)ܡPTfz՞dc2:>@oꖠ듩$ua6FVnru !4ړh^OGX8Eлev@">%٫Srna{=EO&`>RyN*=>?ucy!4q'm׊5HSʆ#}W'!n̫d\dN`zW;]&[Nd#
sBjaj1t=֗YS@εO6 뢿!pGטeDag.
v{BN*;J07lŭm;`
*N`̄t^AOۙүgF![ZP+xl8Cg_]>\?[~88|~\~MA\>ڇK3<|(Kѷ.8ě0?/.;~-_⎅[7۷4nm-ʽuB6qϐoVr7K_^5#vc{36K1M@-T w&:=Mxµ!o#_J?<d*>	ǏWLM>}f󄍫6<K.7qbJ,b1LDq!bL2f>q="}{X}pp[ 
 kI?'qkpk(:rrTj^^>X`f$58e&ARe4qxF&eke.gZlJɁd/A"|EvQP ]'6u	M*L@}n+d =&j/W h0+b+1&+ o@B!ۆܽCGN۬ۏ?'`+߆ ǐ=fH8ԺQ_Y<J]prEvʏW޿{Oey;WdlP>2rQ9YA=OC܍YCLHo"}ڛ#J qxcP\9@8 7>ld07C{I÷`z!$y`ӀxZOǎ].^-F;a[4tc[ږ;n<J8}_x'yr1rFd)Tm|Pϡ╁}9U|0SJpcCq9^σWbN*+	K.>ҷo
ʇX$bX1>@NBIQQ~> C( h 1Wc"\YDS`Y-V.39 <]fLbwЅHo9nHE;Ej/gC㚐ĭiw:?*fLcF)'ǫܔ)^M;r*]9K/`m0Up$g/+`&l{[bj/njw?)`|1/Vv}5Z1%y-X % vLg:S_oݔ}ZlnD	)Fn^[ntxލiGHU??S;ҮCz7u?1^E4Oaຖ"nA`xGvcF.	V\>#WqSG<5jCMDԽQU/\N4N{oݚhb\/\/U_\1S9#ybO9t8u90n[7r)>nmQSnHVV +o8.
00Ɓɀs5*n-åi7Kx{u	:Ƹȕæ o'g.eM٨th]6)Nm<7l/4M]BbʏV|Y@7vU{iY7VDڽ@`7,qmFhW|y݁%5׮~,8?qn@8]sӤؑf@Q]V m?jNm{څݰo.j3fQ e+Zy0PGǴAsJEnӐ#l>)ۼy^Ƹ	lZ`YS{Q3~\ F!Fko5 ZG	f7;VDwneHds⯐܎>dnouYnqPfohOۡIYLc¦ke;ܸJ?E'@M'.tX3<?%X޾ş]yb2Lk%o~<_^+FJ;?h9w[>>kcd&ˏC37꼯ߕyۛW]^ L e`-o(ޜ^{ȷǾ//?_'ԐOM9'<J63)^{čN	>8L0Kn!M^b7E.Lr`⑻cNzcOk~N:͹h$!N@2kQj݇Rײ1^yF74BF; ]GT6:sIlڽhH6ڷ݅]l͵` ; {՘O,77oCOiPIj:k݁Ce]z;1M8~K\ FY]'yxtv!:3W,W._r}ch[LD"X/W!=ZʓVv+m&rL*Vd<ML 7;̾2['+d1AɐW 7nng5w<xH8vyyׯ(DuE<nnvW_sZlҾA<b+#?H?Qo´>
i"vƻle&U62Y	@W}P(ESRTOTF``QbeE_l P}xe|{Lw8Q8ʥKd$Sڔ	T@M	u]}:uiLSOh9!OI*3\YU_3,>̳?gW.//)<#͗1+rR51Sn /m3WqEi7ǲp$^t,y^׮-d[k/PtٚY-"u:n&˔`ޅ.¡ћtd42cMѴ0	@b?D#'e$8$p/#Mzgz~h76mǽDxNLNls7FlbdvaaGӁnHr/K0|W3,ܤqM91M<wYDr9Xi?(ܤRgΫu̼mN@~ʬ1xWx\`XmbM_ $q8"o^Af>Iyw?+}p>xR3+dl?smH\AÇ}k\ƨ%,wЦǰw<I%ec)?~	z~\)c7|M'ҵ_NAk;Ŗ][g-Gb#ʇXX`*̱<8xun<59g>Kn޹}coQ<>(gmΓtuqv*3с:2}m
8yX̧t<UdBaS1LFfD0io~,dqAQ1A®+vyc`m1s84*D
nm_yCb4O٠r`+
QڿK/?F:]v`; sڿ_-̼]c=	A((A(w\t)NWijCmӾ~ť+i+lۡL m9˘/[Ɯn#Vˎ/fߑ,ڶ;ZYqE<˯KV97Ԝ172gN_/yյ0]:o A]rȌfSKx"o2c0W*+ۿ"=4&848	1
or?q5[_G01psT?ܶx.$hr %N,yb$Z$+IGm9_U.Gy|vyAXM(In5N,X/o#}o+}C-"j컟n56])O0}g}?gP!K܏[xk.;?o-M_Q?/[K<e?TT*)$|w$c9`b
syǁtDw|A^hqiN&3z_p7YW>X`E/wZ_x~xr%+k8]NY<fƂ4l'f81ظ_yF64)F髜ʠ/&Lq|UڍwBzU0
aR1rB7uI5Eﰕ0lZyAiHd¼#pmRܛ3O_*yr_Gw6Xl`7(B0_AD^bW=+cj$HtJ|\Ëv:.תsOJЋK@i >ިrdQqci(<dy-Q?_	q/±YGe]So}92eh^XDYFD6ªХuǽś6R;ź`uC,5gζ[Ě8zRˆ0Za6}Lzd/BfBo,:<!l3Nd47S*+W./}kw{kwnG<ŝUޞWp`$Oab3MuK>LMQOO?Sԍ6ʆKWo 'xnyJ4OA>p֏1Ifi~PxQ6*be808Ȱ??F+;,*MG@4] ՘MvckrO?]KNB*zM6ntMNj<Q42ON:,1S~á/'zl	@+p.k.	*J ӛ7oi,'4PSlD0LI,3..蓩w< ICOڔۣ"x+ØO%q(wn1Ynky}iLɀ='Up}A..g8xWȓӧd'ܗ/<sŇ9ώ0X!Y~UOUXh}ڄqyU81'uP4z/l@'[	_(9аo!x5K6|<?|8a:T|Ui+s:ZA`;A [|ƐMCAs@t#9TXRׅR+E<r#<#cZ7U/9@ b˓lWYgrxޥ9oڔQ"epˁ&׹@+7:qr@khdw`\q7	o29/`)ެ6b{sp+uaudp6Kr>@$\,U\BrD7ug

k1i;rB9|6'8%bՅlǁl&dصgw.N#qHcEɶc)#bv5z:cU^]y-.PcD?cc%i5MhWևKq܆b͉h^du p]j藘0jw2Y6޷`>JIdmyK2P.mGzrcw\co$|gߎp z|.#z~?Yl-pOVe\JL:z@6\lfg,~V8<7n#EɰAAEy«MTLv3>8R4܅3*!'8J\bSѼ brN?pA쭀'L5ѽW8LR7J1ne|b[.?%fos~'-{_|+=M*s&5߷|S?^ց<є'MfZǭ/>P?|:$*ǽD^>|{?!Gsb飖o~_Z~-KG><EKhɴYdIXP@BW;PPh"~
jlzq08(ʡQ/t%9W!7ԴI=6x5qh7>!sW-8Ui&Οݔ-+F8ŷmaӥ[Av*8B݀<4Uʖ»/#x%PG@f0-S8)W-9!	ןStN٬2&A>CeS4Y9ҵJL6 |l1?EWi<xRehK䕸L.fݞ\xOI}"ŗ|ۣڀ6L{	}db`eU	Q&Ego0*	c?#QcV0l#h.IPWUx.Ա7oO,Md":6N?8/
ep	9Olr8`\
o;)dw;wScNOH	h at1ccʌ Lk.ڹL"BiDswxUd:?O1.ptNcOIҧ m^lbsPB9{|c9ӽj}c+cju]?t册 xdpv|l}y{T]<+o˰(P!efe CȨo^#5x0`n2m)t .q*OS7zkzɜ|Ib#	M)GY[eB2
zIlu?{
KEw@/t	>qwuf+ww]4$M_tg.سف#~Ck]W*=!3^i@9r]".Ni@vvE@'}3I@F;l3NзQ~e۫<9=okJlMrIp0ܚp>52Nq܎<kqBrtyH^?HKg)U:O$xut3I/š}-i#OgqYć x2lUle<@gz]2cr3H>PRߘ~%(CJCcܼ{vnؔ'8$b<(tN6g8_5cڽKdjyTM.Үe%Ҧ946)A6"جuvbhB~znj+Pڙj\CXP,7iL?Q98_gf0in?e6:CLƴ#h"eau)p,BK%;^m.8@4[]p9m &wIw8ۥۅ
za'NEl:x{[d|5d6Qu(m|Ƶ?+c]^_5]{B' *t0uctɥh1;ƭQ3fns T'"}ârdC	2^o__zH&/-?W~[72HGON8en)5Gt#,>lΘďI7	'`,=caѤ9 bЭ4yXؐޚJ;NFg}Zo⋞EJ;i|EH.=g]3ipVeR'[?\O-_.o)SX^6_5?ITNp.h}./,o/^~g}zby]|X⥺3pǎu@m<[!M?fywmA˯_^\~LiO7}G?C^UaynO[˗#e(Zl&ou,bYDQlл>9B,iܙ+3ɣJ օx*1b(wBnltErz@I,r@aϹsgvS,Js0X&,m"9BOǕLL.8%t)PЯxSL5h6|g*wU.v9v:n7r\yK~T*jwyh>y!޲w`l RN<pJ<7u	A2W]/Ot>_/ol
@)20MS	"7E?kϿ\{}<trFuKdxr^uw!ܽCYA>rbWu;
)P6C)K ltECvhbN2NC>M2aïIL[.'R2I
ʃh{ UF"@6fa	>!Sy*4@-vz5@*$p4ְbgPu^?f_Ho8X~m*5{A܉] s2%X;o\s<v`xw˜;%-{l<q'<N;eAAy2&6Q&v'70OjZAjl.芃9.uSN׵G_p;%X^	zn]P.l~-ʚ~cƈ39et'OjN2t8v3\Nvi7y7h#/s]y:=QB&aŠS}CN{tjqP6b>"PENSMtQgՓ8З࿯zhsz8YOTwvr43?z/X{zy'OsLYK&o#O'aF!n	rGDwrK+j9s髙{]<k~jCk=ӧy>Μ@Y}d}>iO )O{ Sr;b} jޠf-@qu!n3%H.c esc}>%s?;T@>4F>EIzMr?^3ɝJZcy	72"z}S uQi&(nY7T-sJO ݻ˫2Q&.knw!vq35';&g3(.;vev,SOi6*d2i_vcj~C²:sγ2teC.[_稑>k#mGs؎|:Amj>}zo6-Y0PG{~3Bivq:-Tl]{9dM
H8F_c)#ɴsu<Jt\'{B2Ȣ%5[h#p{*W`지I(.6bnDqp˶ 7>cf?En6cxTy.3!p/F{TYm_7MJE6Kd{eA6poʌ1a=fm5kIN&:!T4't8HMU@@[!
(Ї+,k1F.fa8k #BuR%SqT
ll/CoIr602	kR@	5xAy0ҶHTt8T@qW77b8[S*w`::qEA!C;W[^y_W%|a9v^e\Oټa!Y4.~qDIQ@]uEþ,?MfAo\OKA<1{1>v|g=(d<	_|ʞWe<xM7>J'6O1=˯~|0?g:W#	'rxaѓ'|4ҎFNLo&IW6|n&N!E	!Ҿ8(Ϧ-Ek7kZ]楫˲p_./&6m~M?7/R҇0rA]]xrQ~qfJnћuC?%F[2ĳL

O !~nrAL}L`HVʺ5%R&:AkwnlUn^{^R "m{Uȉ~0%u3gTo`5<)1G5k>ʓ;|oܸ>=cJғv<iO7` Rul@eir&5zͳ..NxܽtxBcDh'r8wx S'$#?zOR=|2![xzyR΄Ĵ+a︀h3lc}0 ɛȂ2jɇؔ-jT&yjb@Xٴ;pBDO[h ۂn5۩K-Jg1U;`}ja\_K},;Z&F=%{ҡMx0_#y>7nzȍf5@j$[nڎ܀.棴8dA=%^'Q/"HM?BH/$\+=칣2$wB2;Vʷ ~,))h9T-HYYe<>0nez&v[GlȨ3J24-Aڎ2s3HB@Yt\Ǘ
qɃ	:pXNmP
a}]W\qZ09܃!V	"@NMS]\fQ]ęG bȘMy'h+[@?ඦ_W܆v%|6@%כm;d1PRYzmbü~8}<)[nڇלmFJ	Cg##߽S**yZD20p~.K|Ҙp`n%mst}E<oM*^37=Fyt>^r&̠xghG+6ۭ{*64aQkHO-n6«,L?AɁ&HpMxrG8zAJY<S94uUoʆ@ܼ5:#g (IWawh{Bp1TOF0(4&1/(F22y%yÈ-jHB[ pW?fT6}}nﻝdU^JV꽍4ku,`Ң?>v-ašP{pyOWoƯn0ɛӞI2m,zsAb 9f1~`bfۻ̬an//@H*]60sF T.YkXV"ڎ7&VM7J\mMnF,ZM^8<Ev Pltٵ^(Rw3}+tQPM}b~2]}6w9,q1vWȁ`-IY8ݿb#ܯvDdw%zW/mU=ȶ*kzrKE<0VMo^#11z0gȩ<VΡ0ZHQ5x`= H=Λ	o0;Ƌ2Y\r 5V7 Bi2L!GF4hƀ?'֣
8J"T.[w{k`K:o'8U<޺@WW.Wm9n[A}2Qaa	kwA#éIys/f96sW/_AW^I7߷|[x˿y/9cyd>Zzayd(o^F4iP>.;|7Jw߫	&G//_|#)>zyW{ewEc>}m^wrCcTZ_IuPi~ItNX-tv2n1evURrh?q&썗2wݍ{^rw&O`ܔ"vo*G;,}<6rD?2pʹ8:9	2QZ x[qqwxď$VҍI|nm6n}J$ 9rONƆ=Z"zCMf띤n'dʗ?Y6RLY.C뉺#D/ٛy꣱INZm3 \?z1":?g0f_).	kW-O-/m~b?%M:XYhZЉR ~f"Pn/a78 <t.oE8T]U4BsY*`#~*={ }IG_0iFM39,7o?RF
BFfn \7Q9t0Bp}cuJQ<ǄlF@:>4~!Oݹ9sM(=N@:1#Iu<]AVo¨}O˗Yf$OȤqd+3		'PP;jHNܥ3dAOC
Ǔ2rO#ؾzy}FV1#|ʛݘ Xd6#裝&5"w|(3nb@db-%8^1b5+W|o~O\qچdmcu0sd~Ǉ%e}2,/ZONZNm-}l:(0'x0Z3JDqIvo)\x#c_HYBlN~BkAXKl^I^9_cMz9txg-721psB9fOXW!BGKCpAd7wt(x
_Q۟`F]2)uɬm/m»e}$,1{f6<Ti=<9"yƵŁ>Xbs7y"l0whӀL>^y`vشklah'Qgfa<wf-w8HXOqmkǬvN]տM7@)Dfc5-3#x;ʩ0P@8F2.ScMW:{/3Ѵōyc낓Mr=kh7~@)'>J.5!˴S ]?QpxȀ/+tMiS0AǈӰlrD; Yvt;?WсKzql`>{B2l+BvŞѓk7ڇ,/nO0G@!өm;4#_F&F<|_}8ՍѸ𞛕*v=MJQPωVf!Vd%jNL}5j<{>s[a|y,Kh])$d~B^LޜeUxX3̆5q.(0Xdk@a2P1@c7͂	3۹1g[ʲeų Nyj*`G:E`[UJ2ĤtF\qcW}O׃ƻ1lòw)mF_+K}_7ohHkݽhW;7"Ni]y],g`O-ܺ<;?xˏᗖ?U^g/\jCg.\=^uoyQ??|=qytG\'x=ŋ/_>ab?|7?/-o2O9S!-!E:ٓ4\1OX\ڇLK{dCWn0I/`خ6.-J4ءO ̯6@_zї0p.Z+$$?fɃ-#72"EXR{"vTl>AyWmL̹QgI+]<8?VȜܝ1Uu@S6R
Ӌ.͝fyLD+;UP̦4`h2
=NpcNqؐa>>B0T]E';XsiJ-"'#r#	8Y{|Ȥ4ˍ7_|qys/W_ܼqbøHCiWcQ	 |57oT+cTn	 ]6!	Ԍ@0A̓ J?! 1wh|emOA-.6]dE%ϓIS@7	k}]v(t7YB#*"m]ׂM=" OVDf9H̃ߙG>u+폾"h7BMq'3l7$of6KQY)+ڳ"pZʟM>韯_ӹke	ko,xڵoClJ.`՛v4ѧx3A&1^-E9#8u1͚Uܲ'c  iznN*qxGqbpʙ[<'mjC_%׼oCFܔ&j znsjNYebԄl_$O]lu:cz,~6<d-2`}ol&1ioC՝|Sy;}7~=61Fg7{鳙wi2|9^W+ꧮ2xT;|CF2ǠQϝ@d)SN3GPq&c	#?u_q*C'2x[OȥO\T>[;w*{K+f<=~T̝8-"\kT#!7ٰv_'PJnW[h2-okpɷ5f2&J:[G<q>#Wé̩Vva_xLiQd`r)H~5Qu9 6NAPb#b+]xo4umG/걯EFK=]uI<جG⶧2/al݇?Λ8׫?P׹g2QB"1l ˤˍv)~qunDMlYlXii-ǆX&iAx	neo!g]av#0ܞ8&<43}0vm	Sl`tzFc}lARf{kza͹Vӥo7ro`Ohf|e#ǖǳq''uД z}~nmef;qҥ(撟ܘbbHRzg85LNCgݮC&ȸRz}Ba1Q.X52^1l$p?eQsBXgQ)CY\J7PntG+tЄOx*lDtɻQy[qXqЄ'+lp<tSp7)ݿr=Ͻ\+|_rz_ooXg_p|_6zt^ aˑ.Wzrߧ1â2n\?ffhno|c6/"Ƿ'޲Lb7ѣXO6嫑[ЏXkou<t-w,o/[w4}xi=ߓ'~SfySMd߶|ͣ_%oX/񽯫|e]/R28xd1w/((</hS͐vRL=Lf:GJeV<('Q.!?6}eJ^@9#MY&%0W'_6I!j{3#XL:y:cK~h6eE"r>Om a1_k,Q3{(:C.3:`H,):D""&lp0)W[(ȡFHccbd䀀36xwr\Zr"* 2bAזl٨92(%/:kwq72iI:A{9<QC.b1?+P"Rq!F&(n`<yڊ})ʀ X_f#w]0;['0jAه kfHBN&Q6-lqXl93g8VhA4"IެK+Fm-0tR|U@.w^34`\7˂?yM8i9M̥ FĉW57 {
]x<n`s+#wǯBu뗶fD(ɻΕhxW\84H:vMɋuQq- Pׄn]zH<c<!{Ѧ6OT$zQ}8-~((}%!;#/l4c#/9#x*J>܅*+ţ]Q߂&)W[eIQ]J<ܬF_IMt?M+%gІS@S Tdi S}l{OBeu:*Z)q>
bx+2^Z/Χ=/QXشەqW蠑.eI
<#cqX?Sd:浠h	rqA&O4+Z)Ga	: r	<2o`\:A?HFGk4o8K9!enԖ]&bb0U22yskЅXG@ݥ
M,7Ń_uG[b<?k   k  IDAT>Z>o*keMr-;y!9d `O#ݵ	I)'
iɺN#ǕY'hD6XemGn~:@)鲅f_@eIPe5k+0wM+@8ʚ1n$2Pʹ%0_7{<mM9-q0go:;PbqX
tK{܍#?O	рKϔL؈w\FP;Wt7(vb|..c"RuZ^Ǘ' 6i
.8{@^%dw3k JV4^1''`]̦`a_!Nmebڵn)@X,N/'H[>cIKqds
޸K1fiv`0}zPnyLu-4ou?1sa0,p*Җ(V 5	:Pm\Ak2SۮtGl)ѿx~n bO%f[PЁ31 ;w01!$'}Nt&-O[N×B1ltjۘlV( 	?,nsbf@NR?ğt(Ý;X\-,io=ބ,gB*ä]s(G-K/O/qB	5A$fytCϼ^\NC{SdlCu+w)6|ħS|#u˛Lwr8OqC<s.-%V@jxa?på/_Ӑ7!Ν/𖿴>\znOˇ7_uVqY|'L_c˟T9R_ˤ`bD^I1һMğEcz.;ZWvСKH2ىDaWl<N<Thg >:yIcG;5|KW./W"#gd_%qU&YZL_}Ho,n}Rj֍;(el:pÂg&	ٯXb/QX^]~᚟u_[6Xc wR)wUZIYZ<i6]uJÓ,<ѮE83	S
l'M3gUTx-~m	Oϡcp|dGs}L0,;
(93x iOṇ<6ܺqky񅗖OAF:]yYgd˰#oe˩ǝL'd;mE$Mlz
~Vb'sVv 8]XfmtgUNh9|D!`O1T>&yeA q"BeLfmZi'Q<u1X$ĒqHS9y2/6"aÂ-QF_5Qރ?UO/)g@80%]	d'`Heu?O;n?ytd.@MiXC'5^͆5,9Dٚd>%ҐQ>qDI8~\|~KO#	k?¹Of:l@.dEQ6ǐW	(u 9k~e;dV}4v2~Qn|_b'<~1-9x]^, 0:r&j2Iepk6hPkN2\tqE-ץn qe>v̅rV) orxJ\A6D/Ah/tNR%=Swy|eӇ`Fߠ:\9bmx^vl=|Tp6R'eG})Znl+A<_[Y?qXL>?Hú\	G蛛A)@~)n|.⢫꣔fqY
L~4"L5?W8(cDr&zN0+xʈnQ+ ZIΒǦʂtRvLIťF>l6B@i}Du;?kxsk?^WEY.wMY{{2ݦ#u"*4Yx=]k6m6=#_r5ɟQM?}}C9o<93Fl#n𧞺̙P{ٻr{U9-Y}7GpS[o
ϒ?>7Acί!Z_%C2lhRuWlaTi ,#|o8=:.420ݻqoݔSu+<|O`1DO;"dRo%ahi࠶S`^,&'dzxG2yQuiՎOZ)l7VhZ]E MƁ&&)!٘Tgnor8W3;=NtpaM M>Si@p\3{~',?o\2Ȥ}{-(H{6+!{وjRt	C6a.@0OPeg0*7*ܛ I4&)&@ aVL
/;m(U(Z O-}|k-+LL'ΜBy!l<|'{ďDaEFTfU\wcZ bN>ebY(' ?uh]*GWPyxFƕ<u4(wr;w]QyC<f/}O΃_F//~Z>	;"عOo.ؼH	$lbrg_
)=g;T"/` y\q
8e4'/Hܹ^A~rF:f+GRWWON0td⒅)r>UWS
7TV׮r9E,d82)ӧ1%rUe0%3{ԇW"kcAN*4
c|}nA^T0lvrv[ vNK^	{ȯ\!ʉW[2fO@NkʆuCM!3~HD7N qursOd=~VoWq-d3rxe]^h,9w¿ej1ȷʆ~hG> g|[\P!j vN*dDoV݀r~n:TDym6C^L߱A?!.8SV|_iJ:a:7|ȕWW>z~"OܐHmJ1t\'}㈚3jVie Kqa^D +|NTn%6h=Te(z4`HۣGsە8Cֳkx~<7_/pDfX^}QZпKKx"X>nx1yue)P|AkلԠJ^Dvč?i2ܝ[Ng|ȓ;S]tJ/YoR>970䕯m'TOPw`衘O0OZ%:c#˗}pN\&=Yqçf>IC׌-)y\k-3`Pdzkl{Tk>}}UM!JbIp\N'#UOo6pWQ"vGӟZ"0,:Eɐ"|$hcD BGp6#|90bT|db<mMJ`CݧLa#JۖUWhP&W ?ehז^$0I):wfd܁NL[8}L,ڏvc[W-c(}rz</>
'2OHD5 5ƕ`}j7N˵(o9g$LFDFx
 =\hX7ww︭17D?}@qѥAJܒ進nÆs]]:E{đ;|_09g =!c*vƢvs!8ƯТn$Fбva08@&.L;-Ѿiځfaȉ6W-lO8HwX;F aOsTz2{_¼UcMLSri{'OIm,eX]@dmO@M4fZ1	fL$OqWɳRIPW͟VԂLphh]'l*
B<濹OPLMQ$E^/:Q-6踹̽#	bT"=cC?HȔ@A(	'f&[X'oIwnj!M6&4YLCŗ3uXz׭(W,WCjZ0Kmyǻ/[^W@^o֞&#lJ/ܩGrwh&HlmPiRq7՞@/YQ벮IY2DybE3H8_)w7仾_&]:(/Ž	]E5/?i%[Mf^[GDݥ"n.dD_~]21[eΔ0	_y4L9Db3oD<dQLiLH;PA_{eoMZl:!78}qGЅ76?#FaOYA*S1m`B~F^++)\Ycvp	4%p0ؔI&A˲V>&PX.ldfC|.|U
>D*xᢟ(n|f8M~K:0Ztm5*cE)oS/baūZ8<wioz<]O[&/px_ CKIS,C/)\M4lчc"!38ݝ"ri[S|g!zUvƆ<)/ҢmQx Ҁ:BMP8s!~;=Ɲ+T
ÆV1WCt.}%};$J+:qg'0.y-xOFtCI鳐w/LV:X/VA&eSsλɝz{|ڼ"%O@?&ԍto`8[8hp?yr Y.{
D^FzkX?649\b_ͤҷ|;`+ʻүTCTbÝv.AYnŀr %iN.N`+]MO:ɓ}|]!m^W@p7qsV&rs'30q(FPgs6lNs06𕡬(o޸~4|&tqԭ ?bnyϯ|L)S	. $]|'Vs9^y7uz!Μ/}_\]3A_pSFNHղ6h
)œ|C?sU^r7Ө,ĮhX%34wT>϶\P~\.ۍ|A	umb}|0C	A:]7Q.:"^R,upP/u0er3&^_KңmD#Cp\p{9,Ƕ8Bc1}ܤ:@y"^Uy5yJ4)/L@(U;P-?}<Z@	.kD3]{k[qxu]ʥxNi6:0C#'(Ē,	]'TGnh2g@Nns<	˪Z9f]9+빔Fqf|sci&M[I
34	Mz9]A;LCA&N#W*,2r%=v.7?eMͻG)7WwqtRvN0gГV|&5oɷ-S,KedL_#\? An֕+8=!~{Ї&ݬg9@t$th4M[=pxpcs3њ!3m9 SD{Yxxx(Vyic:,vy:I򦉓K9zv칎ls0AGgvgd
eVR W$jwdxD@+CοAMvaݿse@_5ogY,&}G|QH'I6PxYk&N>XVF&Y~idڛ9r0nT,c<X1Mѡeyq}(́=x"#'/|Tל.c`c]ސb2]AtG'4-jɰ7e3[z@G4O/xrZ7?~']Wn|g,e)[IHXGֽ'uԦhO ~r|x#25xrH]3uDFlckQMS-{Vu0eĕQd#qܶyv4SB6x$lz{!Z:'0X /3;_NMG
X9؍m.d(=ѐ@펶a2@aY߾!atᮣZ~x?phw%@3"<ԯ>6u0ub:lvyt-[\2ca ]/I+86󸓙3FxelG'ԕ^T$Cu?q9 /G4tAz>e?rSO.U{Ç ZGѣTT|hSdd)}CtK7Å`!&m1H=A?hL8Yz 1v	7Q;r(]AOp#%.'6i䑍Lꞟ2E@Fiȴ_ZR6CDhh M뺤ѣO	S>&-
^(Oe(:̢d-iGW1&ѹ)oBU>gq% B{(KD6M9Q	d-Hw w=DAO(.t1HΘʅ8m8 @V>:6P7/|O:D2?TΓ݉RNXs'iI*5%sIoMpȃc)mZ8&꿒ݑd%/[c.sUGhg'?mxt2q4 @I#5&EK(yBe8'N:pxrS%u?a\S6lqN*߯{M旽^O^7(xWQtIZrjc9d84TDG.wED@mtAfl$JF<CCļ[m]="<벣[{̥	w"?w՚/;E(Y!Yx%6WpNqOXF.4D|8=H[è0V\F[6iSO`㨉8r/xX+̫D)7X+qLDVc:+6;\֡]	o4lhiP(R6z
:_}$>296N얯a"ہ]	̟tpF |吏wT}`iAشS݇tCje|֜rOW%AnElU?VıSũK/#	@$jIVivīesȇ6=9]nv- M^sP#1Jq~Ϡv&%Xvc^جU}N+g2Nuo=uKcYyex}0犊7'ky$
~|/О#6n Reu4jus&}8QZڃ) PL5UfZ+hyfGL10E8=9]Xq%ڿNH.ݫ999J>/0?d@7LQ˿O-"j=vSظ%.1lݦ(W ݛ/w7D2gZe؅2@c}o/J:vq8O{f@,~cLdc]OaQIк7C;n*LfbҒR6)M,ds bN?&T^*4xMZqb\/		t i+NOo2g☱L_&nm:pp?=PK$(z@"	Mube{S KO&6{2pvy_eA\̋v輯M(Z *>)?,Bu<Tm=3R}Q=6Z$@	"qȦ
8,؉xφO=_w<
j7`9lpēS/TJLnsڨ?J=GFI,'N_N X~U
!2;!Οc\ Dܛ	-8pM>vЏxcQ_	[QO	5?$=	_d>\r ʣ~lnޛ
H P`"7uYuuFt>q]?ѵ0H¯h*Hi<:&9:y괟R\^v
w?h*l`ur:֕Gv5C KA~`jxs5z&[o-w_y7.mQ_:#}3|;F&d'6ş;.S%|p "Nw	'w?CP2>mˍjEX$[-KY ;\*	A9fԺUWRT^ٰC#2'L: nBF]%Bb+8tAt'Ѿ/O<ʋq+A2q6}Lq94@I/'iAfpx#_SwpSD)>(-<t_>X BWڦUʦ:u>0O*oQGCIb*51t~Y2"7>v\o}gx0?'.a3Vټԥ!rSfS
Fy<T?P9`bOPlyGHC38$8vڦ^ǡooBvj:>XFhdsg]n^y4&ywĢ6!%r6p9w"B&$%5F\X6vyЎ0'\+1t%;
*H~A4IFmMh<QV,`Lbhm."op o2MahNl[._xEz1z<!nǤa^UPnDR7(%-[eVi4̹]+~߅}@L`cl]crnmz`ZV+eٸ|3]soӇ~ !\67qџ<[Fh.8w$Vk
SGIv~˭sԫq5p$$)ނ3Rf ʎOn]XNPk&ĩ8ĤA̭WhH'2lotN~)*9LR.vÿX&i}A%YS޾QSGN'N;2{>819OKlK"?y4m
tx}[) nCL9;ƚ+=<tg70.lfdk&R&C//JL$?bP\>+q	@gd ~K{v_G	u8=~mH۾A[e1q7}4Vp 'lU6aF\+?Mć]8|Ɵ|d&P+wyI<9z-Ο{٬|ŗ-8z&F|7`lxDĉj탯H엁zg D&(|Lʌͣ>\߹uKaϫ<S#IYX,ׄ>oaKcc	;w>H䞍1ohfp=wo_>C_Ղ !#n=j1t^A8@:0v
Zi&F|Pޜ"6b.O(ƳͯX?ʕ+KW"lFwwt=L"[i2@O9~E]~|>S,7t&J^CE6]8^0	;@8zbG6J6,pWFJ6-9J,?8vyR~%cǆC>Q'>2/W<4kGӛ.[R兀?<G5>WEj!'P+Ìd·r#|o2y$X/DrΟ/zn@ }?yү!>lpvK\Y.^o,,'.8ŷGWґB$pp
tsU˃,;}7t._r9JDKp3RO?`YȄqۆzݿE0Hgç !eȯ!-3{'%ݰO8^d?gSrXn^.:~+_P(4)#6}G6}˜#h@NU\'M^b37Q<	Ay rpD#sg<T)QAUC lVz y
goUٌnD~tDu07
$~g-+NG(1'B^mN$'E5$e}zXܦx]71mPfT_u8S7٣ʮhjXYldK<X	;TH6䅺|Y(|M`ɓá`k90EIgμN:-}F"P;oys>IƖ_d{IZdlh~rE}<iq]x̨d9	7o/7oPgfu
*#U@@mI("DB!ɲ%mwqw_`ne$r@ve%DEU#k眢@gkwv_+x$/Lg<&d3 %H!yɥ9dp#z܀}ر|W>9j>p:|h
k9S8IGѾA젟~%q@'()"/I"QP>A2Ɵ"	G
m7?ܹy| &-8ZE$9m:e/?;RN6T3>vt\"Jڿi_R؀ʝ1wc8yq%AA3,9|"gbG`Cz/:8O& )%eR*ZȸkS4W@cFR񩣾!^xyi[|+N'A:F<rՄ3p~vi[_ǆ2ZC:ώgqC5c~H
+(Ǌôk=տaxՖ8l&롵 B5
Ze1k	ȡ~!!*!e}pb5vDT'jhg=CƟ8MBU5-46$Bm{fJe<D@}PhMn89]1f6bEyb# mfa<< cLόʸAs
NjnWfR`6kz8nE7]"6T]bDѫ ]]4%SF!i6n#W^YV~ʳ:nЭkKr@H-DVBBuPkrզ6JBڛrQ3q7F~c?01oz@kjoMtZCCW@M~w!jTMW?:8#cҴVM5n|ص"ouhctD$ii+:r*JWcTڭ\k;ncΪ!pmѪ`zPo0GP,dE͜1FN>ܝO>7xRc #ZT5Q)tL (Bgq|	?tXĐN'~D'W|љLQuW脙DD8r bb) G#̘	,ѹgEm@v ySUUBG*rA'TXv+2E6c՛Tɻp#?@)ߐ{rh\6ȓ|˯x[=&1 ߵ`ch,b7F5h?[i\v' #h9.j6gcicCd}5|h{X&m,HdcY	?hx	"O"Qǝ6v$T# pTE:`h8?dfF#nB$C9Mڇ( >11rx]@.cxٳW|F
oH2/<+TUNcAv1d%z{f}L4,q/x6S'*ԧ o"%G2bԨ2t*[I^9)Gr	7lr ɃU(x`yJaE|TQ\PA80wX;xƌh#TK-]Ns*/җH',!;&N=gq,R?LmE{ł<vE:wY&ǶF^rQ.+56-~SH_83,v§O@#lF!|2kDNoҹJ>ͦ<C8еք6M,+Cf3A@Fz5vAZƎgyv$^R	]8B[ͷh)G*e3u5SG4gO_M~-t4ⴵТ< jAɺɂ<iƀvSF̓V6+Є;lM[E^sWI iGbAr]'~̄Lv ;uLAǲHLƨX!/Ɵ'H!@lK7h8,^;y-gpC\cC>(ڍZj@<8=A0o:ɍ=7IDA[>Ys 4fFUg6Ր+)C> .t6,C9pULS<LR?j+.*#oH6qC;5Bs(ob*{ӦƘ@vT?K$wfX)M{Kv.B(Gmf*DX 6<զC'=A;4(Ɠ4LΪq'D0Zq#?W}du5|
-@W8?MPhQi`´*OH8>R͆,dl^7< xE$`ǜ
YN'ZGɿ֞t\ѥ"7mhd
vfǎݪJ\7CpaEm
ٱ {xXCsSTw1?z(9d曈
]iM&C7e4a_V%咲v[o	^
d]K~A;Q3!^Ԏ3C2p`0wuqp@E=|!3iS}n1eeec5 AFhQspp %1W16v+s-<c?*o0Zf#ЖYL<z/KfkQ~=2!K)~ѿ6\EHOEK]S~bSk<*&pr4nm0hD;0A(@Ǳֆ~X=4~U@kIh{/2cso
]@6m8eIo% E<H]a _٧NZUKU!,|TXzPݪ)H=I2+-0^]4Co ջ:g;i ^GWr_k~0>zQ':~`u(`
pDZBu'BL?_v:x2ug 
7R(ލyaD3?";A<`rTG0JKpFqb,pC#E~]@x1i+}CՕxX"w)LɯH;^#T 	ͪa'Ѐ'}X̥1;`"ˤddxh@J4CSA4ACӺ`"}@l`;	-f euS279MW^A4}ZWuyx_{OÑW$:>)i#c#:sVG'k$]&">q({Cɇ]WM4|R$|^`L"gLW*EL t5MH">R6t] u|QZY&АT9Of?j"ɳX)69%']uJ!+xE=<ͯV@rY^fCi\	+?iÜn\gГh7zr>Mbȅ@iM68chaw.(@9gmQW#uF[
u^_޴4l;td M2EnS&!l޺ c1L}ѓvh8Od|HKWyX[<="%ŧ.	01ֆ')oT.'Dp%iTM?M(`d&˴Q(Wc4o@"odSx96d2Av⅜3'Wk"6=¬PլV=mHytxaM<uZz9c`5`IEɡWCMeE?.d,QM}gpFyvR7xƆa^P^qK`SW"uġ:x"KIRc76*E&l,,YY z,</eƫ,e<:hFmlVhsEțsܠfb}=fPzmO(.ex#?b;v5}}<W`UG'	iNt?VRP]4d7jZp\2v67<^>!,Y3Eȧ)4]I9"ΚㄥUveAnw^ť1:Alv{CuCK_ԋ-ؗ<&'M#
<F#Țywy!Tb{.dJ
kWpvt'eǂ:v~;3	Fymoi c2J/VIޫN8 AM OxCP@K?(Dn{pf+]Wа
T,*zM͔	T+A>KJjXiwu:[F)-XP ۾F2a3` Eիjبq68TX|mv=ѾK-oRNPvƌ[ƍViYb!ㄖլFQoYȣ +6|\J
sdև<_>f?-ÆA	O\0X
_+~.#twU,nrNz'}C94JWUyE[G7t=z}5ݺz~t55^WY.՚zZ|{
Gr{3#f)2`J?W:t=h@xUruv2֧Q
U]ﮞ-کNݤ%bw(ӣj̳/:
t}pr!Vjq s MP]{i07f{ӀiJ)S 
W酠Jq yݢzn[DZmoM	\ٓ{/! Lёp:0ڄLxf*hRĂEKз.B/u:E464I"DI? 	F1PN޽eR{ʾ={m"2a8隰ϓÒGLU'_swP3j<wZNP~@gh\j r2B5ze"fc'_O#Z7oY<
0<Y.ؤ#88F|s+RԆDU@Y`\FmO!IfM#\erS\/<mˑ)$e?
KydPO)/2gJ}aEF [cv2Ikvd^]7@ѩO,V#U@zW7?J75ߣ3aw(SvIߩ:۶(R,e}ZŃӮvո0|]@>e Zʏ]+۶oK
P]/rcjP}߷R{WڳwFcPЯqT2۞1(? ){(O9妀[zaGe\7K=KY{̪{!C;"1mgW"~E^1JuPh~,&vP嚃EvkߔdO!MJ
:)>J,#}pc1jc]ǇF޺Ekxlt)~č89ʧǌc<xdxb̢,~FAIN=rqZ9Mz>m-7	m؀:FXhlۛ8e" k<M_q0~U'!q-~"Hw;x&7$/ι0afgZw6wǌ0ԭƲA0R:ݲa1
}9%h_=rl !l,ϥsEhn\ڿG>C@7!F9$MqvCoI+Uѥ/ɍ'Q=?%0;rv!*CftDrA`jlfD#~rrBQ%6&u*']o	퍙rm>شƟ0j1;.4Xn;"KYqͦiXݨUg>v"y_);Y҇/>uf@S追@E20_e;al%@Hٹ} o-s0m~/O"菃m\p:l@8O"A5#ڟK7ahlkβ{.?Ƌ񐭘W+31/=ļ&$/Y et~?|)=s~Ztϡ}{O<ZE|OWqmwQa_c!R=BtِڷeԾP?({|}Q1
9Juv3n CF90ȑh:	gJuxLEBպRΟ6K?qɁz6LmЁ?rMrڶ
E?~1==qL6Qs3J:s-/.;O!*yN~X{t )ܭ۬i9$*{W۟PGy1!y#So"Hm~vIK|TaxpOD'UKuus58fA)f芲9	KL*hcU-p1T{}*3TTSM2}7u|R󡬊((StH}@#}1i&B(	M?C^-?c4m%?8L/hC)ltK\v?TvvM[ʖ[MB}7oVnVvҼ]0>jd;~c;adGͭƎi[xu9C|z;I$t:f8.VP*N5W	inKѠ'L	Wo{87
z} }0J膑zMCj5Q֟"Lb&']5C͍uCWXRAz~Ҫ.SA5m%cTw+<X_@lD+N"@w{Ӗft9bM[}avWK_QPe5a^HfЫ*YkH5= U/0ЍqPFI2	ʹ,7p;2@viĚo1DǦW^N:X'*#; +OipHp5bGpb9!4B~Jŋ'5(9c0"xhaP*dŶE4Uʦ'o
0 8=fI	c0M7eiWڌ̐
:rD^i	$'_񠗆_~;S5pMuI0uϺ]f}rVEl޼ʨyp9bç#gS̝e)HMhƍ#'ow-cOZ&/l{2aG5d	(?܉oǊ{˔>fڤq&O3:&		iaOQE<Dnz!5N4M)keAzÓwߣ\pM&,9*ˉ	̊o+OԓBEg^d|20i\=e.2P_e;>aL?ʩ^[lSOr%SQn+۱/3lDn޶.AF a=_@yox[e~v26O\&.Դ eP|~l0-~=صsG:e}ߪ{腗TGlo6F-Ϙ1c̟Gbio}eraҡ5R&OR̿* ϵ޵my!rBe%&P!+ ox7á¬>Pt,Zqgb5e2 PMǣk~0z`K~p>oBxqwf0Ϛ)FuΧ(NM*/SN{RlhzNOi"5B~IvNU?2O5
iCWe晟t< ZGacm?SMum٧<ߤY/y|N,E^Ul?2k|2MEw>t#֣=;\+evl-w{?։'3<ڄXtF56y?,y2 ;D.2_uY/;C?2Y}ShcC8ᦥ/acr{V:bB'!j=nX!%a3OzuFnYz'}7 g'~D\DHUO&٧]fp)ew9"?nU	@O[6tԁUNorP?:ps9/1ݚø/q[2\yŉ~L9b<S{c\g"%lOqѧN~@Qy.O
6g_4vuUNXcs~,=.Mզ;Uﵲ{ʸi ʦ󻖕,>ZॲʤK>lW)5QhwʬS/q~Vc7q>>},֊ƞ&ҹɣM	\j#0ԞH7yg\e/f0f[ɋW\}2fᇼh.=RYr&qws-jz0cN xԨ!-7 .]="a2FJ.!{kshe:g0\ aݿGe9ed1o=~սZCi^eکXȁdX-eF93}RŉH⿚+?b`Ϫ˸
{3Xc$/OP߸S}nb{m缷ԟ7td>e1o
g7W@&=bl
4FjHQn%tÄQ@`ߠ2"%lZtoVt(6t%X|ۚo1A^7cMM9C"dre=6i7rcl'w9!l^&FT|+ϸ"|k;kބsjD0Cxd}xCʾ2+K{f$60V@5 Ro B@6GZ\A@vFإקU!R#\DJ{0#	Ezb8
]k6fʖ˗X'6"Lo
> +㐕ݲYCBnt'rE	fِ>	GLzT{!rд!BN0ivp;UFb@[Uhñrv !vl@=rSHގ0 ].96;wY;hqǖ;vzLSLlBv&niȱbp"z1ZxfXB1&Izt6Gr#}QcfEҙƳ?C}
'4mV%۽klXLRF%. A'6?~Kw`@]e`P8GxҸ˜>)g}c}55oXPI`S{]rSaqoǳ>X=2bE
]>M~9/E.L=-&#VM9JOVϹ(lVH=}gCJ۫r:\׀~69fʉ︶pQvN8~Xy[ʄ<B^lL4{8}5ٚC^(2:FJٶ&U&7~܃l0yˣ+84r ,t>n|eӎlV|Gg\Oػk@ȁ:ɷ&Csb$ǊA屖5ӦN5oߔ.lڴٴSW'wJW˜ss?r7@Wesx}p6<..<BOmSC=R^qg$SqeʻopUo,|cO&nedԭ/Ģ6B{琲oig]~E1
G29Ę,6G5fP\Dn@&)y{&\mtL`UWfi9I_NPڶ83)'/2*/ڈͧ(ۍEOE~wN'hs,U><Q<wO}K?=&ZkzxKnwGp3d
y{#RiK.h;m
}"nb_rR0g7+8-O\\D]Sߕ_B-eBh9'W}!wYm yy\Vu}qVuod(O\9uHͧBf@ju4 1cso,YnBК`Dͥ޽{|qMllL^`IF0\R#&?,ior0coOV\n:e|o& g,5:򡈩'_RӎM?eʒe𔢭+zO߾NӺ$ƭeE\m*4Հ0Kȓ:qݣ7<H\Uș:ˬ>#NPܴsS}:Z?11d>Q4bDy_)SϢߑ`䨑兟0<<ÿ(Oepc.n-u)>%vp)/>qkyz//>~['xH;cnvˌ}^X69bdi[qUYحe&p:pNh6N}سK>DN8cm6]Eq ٱeɓ&{۹{ToqNN%QSf%uC	9/qȐv52&̋OSY6^'	4F9\+|kò!RwA7̄;.ٽ>)4\ٹ]3pH` yJ?#])l@Ψ-~ZZaߚލ1xBVc_&	wflJ|*<GiE 7oͩC&"~TMo&-h.vk%FBo84^MOEچg~<l81e<bwhN^jVR^٘ajA('F!7c$
ڹQp tჍ0׻^9&#!!"	Q^m7 eѺBF1O@s LEmIJ/3&ƐT6-+?~§gs3N`EHny>%6`H7Qo´0/ ,sϼ0XP	7ՠj*C]:{p;Pj1AvPah
:aJٗP\qg|x:ʭ`:3ӯr~38o%Ȧ/p^\>u<͹n>o	jɄSFM t)^b'f㺔@k6	Ｗ-˷~7eK
v"]Hk݊6
m{ܸP-cOgc{07& Q-1o8$kq§V0qlOn6v3V·`եE\vN
P9JUOQǴL5HBA7c/'L^n
КMO;x=:Rikŕњ"	@PO:\9JÙ,v"^I3pg"]ʝҡ{C8fq^ٷgOٹc[`Q5MCf:1cǔӦ>Eg֣eI̍JtMҧin.[ӛK HB Givyr&2SȐݻ/&/Sf3Ϻ7Ɵ߿go9e2!|I00+S.+N[rIh'~LX2O|L911$L1NҍbcpҤAV	~\r?`ͥs#dŠ47垏uHЎt{*~็o)}7gśK 䱹zcww~|yʫe#M&_2'}"+r3y˔k%`&\~c]<[JEp6-K	 h#gӨL$3\֤/se/y-ۨ>KlJ9eι8>s+ͥ,z7@0Yxq,<٨ŞwZ^q7P8ٖ>c5kˌ3FɔS?Q-<[|9,c\/eH!ROl.ͽe=O<^{eK2ViEẖ0} 9ƷpD.e.·~?O~tƢ|+8ΰKˇO}7\h6&-Jrvo|+6O\=yK"խyK΁|c ^vD^|nZ	4Y<^V&.L>2唏;L
̔}^n{WQ</ܶd2:aЗ<Ia17j$ VVo}{6؄jRY&o3pz#ktE[iYGh|xʃ!e7R#"2KpYOݦ~wGn,?/lQm=eת˞_iG(*\<rsy˚o*/<rSٲn/I]@yReI'wMqG4uhRbq/R7࿶ e~ g^-qۏ?~ZuXFysixO'~,9!o<%O\:[ܽ(8MewIYrzkS@BAجG-6pgl.9%2iFC<k&CFڹ~c᠟lW9sbcƸl1n߁"8s=(V6a'suY"xUe1K/s^I_qǺ'ӛKX^|βs kEq'2Qc&<[W|fX(tr
 veLעα%s?_$@79od|0;|ڹsWپcgٱcdߩ<޵KJs5^'UiJ,b񸟤 t1K3w,&*V̯%ȚrXіbr]ݤGkTg>X.@}* ,5~{xƼګa	oUґY7m(`x#`%6Kfv6)H7hGy˹us=P6cxrNfCc$?lFbs{1N-IK?j?-˩3ߎaV$. .a&PGdS5D}BV,n
d|;xՂI[pPyS';l._<#$SFJ#gQjf~\/y!,;c7r*; ]%R񳬡&#,P-ۥg{Ib
K15Jf53y\Cٝplr7jxiݭ1lW)UUZf<׍)JgLmhoϵc 9Lxq5$^.ٽ{vsHt%317c#Js0{KZ9Xy[C*jVC.qDIw&7yu"U{@$eU=8khÄ m:?TߩqT* A!h?TRJ0dBPhzWKңU׭a~ple@Fe{ʻ9o&mYq7{v0	Mnjʑ)nc|KE_`Lތ`9XKDAjXkU;H? RF vĪvӁ>16D,TX_&x$p6``0hInD'<awDSLȓ&IDuZ1ãCEHZ,(dSĢMGSuP$;j/nI7hyrMH;8tjtB͉@x3101mM?N<Is~1B:cj -dH;tT>/AOs{;3~Oʨ1d4/yiO*3x-eWx|#_;Qyf }'n*ιyT6D%h7=u<Nf G&C;W%Eٵ2RhMdaEo\ZM1Yl"n'h"s4<w.O sNB,I _x6ԁ31"7x͓Ëj.ކNdSohɒ:Hln_<SN\S,&b3`>uOyŶoze&;|k)k0jOXtQ:5%O3Y޳W^d&";mǤ<?Χ6l[yo#^1jBN<i˼wt^3n:7iW9ٱ̧$:=,z=<,',O\֞47`B;jH}VfiwHO|?no'Mm1xjx`U+Oj]2!~6=2Ƈ!7m;mN{gȲLty<y4l0aɄtsm06tnp8J~d ΞUy'-!RVol>ә9Oxs>]^T:)e巿mſ۲wI.-u~rAe<QHOĆ9Ta6H&6h)'<[LYvR& d9II6?qg^<E,d4UDox^p= 93,jycvYךT~P#qsKT¾_pF|YNI
H,r2nVcRY( WսٟM9]f[S?6LdH߶TVD6'Ll0D+m G{@Y@g)Ԯ٘kY~u:,TS'p[x{(S|ࡗ~#7xWTy-?^|2hӗ]Q6=u{zD(ܰaǗOUN{u	H}tdٴ,qd'Mi,z6MIe78T?%'~z+vʹQ"nW/A)mGQb`~elˣ7ɒ9E,ϫ?m?~Ce¸ƾ}6w8x6XZ@m|6-c.y[kqk渹$wWksN{2T6c=c5UK.<e7I'~Oq)7vwصz'}lZOF	Oh,S7)}#M!	RT4wR.;FIUk\{WdF~3whl5An	Pڱ
9)"`~ś1GnvA1(l^&,I.ze@w	
~F.7c` cjl_h%57n3N6qoCʞG6ʛVS)ndJ &r\1n?E"`,̡i|ٽ>ߺ"8I`cM9&Ol"y?eV~XK9`hf|Qspk1;qS 071N$Q~$hG۽oM8ԁ?vD9I<yY6'|I3 ^Ꮹe`E<|~ i//ۇT2> u ©
< YZZ%"=TTu@7y tAlЪA!B7ح\g2n{uO0vJF2LtqY7x!6Yta<ns*=rm^n<.1Ш<u iv̱K{q@tF'u\@
tdB?r 2nxPf~*DPӟ2bm}$#nn0VԎG?"
pHz" xPpcyhqNn\7Ae&@.Σ^n{0K@p06QWJk\lsrlezR'@u<0z:x]a,K"we?D@x
-v:o\b-9u7@N9"D޿nl*I2GM&
	^r NZ0L嘬JBIySݨ?IACb n4	HH\ u|
m.M'qxf?4tOa0)c2G8* raS|?GTGmL|i(̴xDFȉO6Ir6zbћ}9meiW;XШӌneW5Ȓ	yz`ʼw\_^}h{[EL D/mOQ,,q.w6 S>)w޲ٻeW9Ig}=KSe=+3Oy@-a|n}2= <59ل@g럸&Ĥ8&0aOO$??$۠5Ygёt1ݨ#NS5D|BkHyG_{'n6[VW{_ʨٿ+(':GcDԛ/L[v$c	`c&:{:ׄ	LFL\Faze҉6COpض^M?aN3=`sҰˬ3>
7mTќs/z}]wd{6=2v%^d߱\yʲE)]׻?Tn?]䴰P,~xe+\9QgeN5iϔ!x:NևTnbR'̾1ʮ\}C&-a`HΜDOԽy.	S$wO=eM?=%v=wM`6l ٢^Tyyo;|>ˆēpH~@J_z/&MT/O[oDo*eg@e@}6.:S_|[jDnM#6x[	nDē.2zR>݈CBV;վNT'MW?,I2x6>`b*?y|¯x"/n~d8ڡNnx>3k9ϖqs	1W\4^?,:[yp̓7xS#+غ)*i3]n; 7i7FYFi<Cq3(HrC.۟|UxϿ&NE./Ϩ[ ?}DO~6=u6&:Ny5N͛KaRjPFR&rEHyJG?!/Nf_|ϗ5we9:i菶=}{&Cɉ+$6_եA4DQq |2K}}u 61W6yp~I<<y{YtբH^֧	XQ>Bl=Vc٧e)	\R6=}7k2+L'~lx17ǣO"^|2t'~Mڢ~P{MJ=Y2U6 	mwABҒ;bƱQ ɩSھ}[.np8S:eS<QCqV%d3lنp|8$pXe5Ƣye,d8lx>HAE{tO36%mwvwMl$6qɛRwaM#n$Cn0y_DHO 7'=Hߧ0?8.[nTy} ~>oE^];t%֨VgHOy `z_M}!'lβ^Z5u@V-~IHa?>6،6Erp6tl &xҏLUB]b}V'Y~Ќ+3wR_e><F[ҡC3<u,ϟĈ[S&cAN9[ld9^s]I']bo?ל<ε6<PfJ]be
|#wp%|w	ژ+tQ0LR焈؞_ %{)a3BnTpX:yZe1L+!i'ogrJ	>qDs9ą?sEynZy'^ |g[!Hm=}J`]ّ1{fڏd_쯱>D
 <}!X]	A:l@u7bz/tyh~zxQa0.>ȈPVd6`*y1o2ǿƣ<`gaz#AKGҁ#5Gtߑ40GL;8TzzO8G뿢"궇aU-R8m%cc
l18
!9sZ[DhٵV[aToYP%c 7&4 O%B8l홦&V7.)u,S%h'HIH:;P0
(c#i
%`Y㹌QG#RΓqععJ?4&nu1m:
zs28xavRq?leCGe_,VLXa1OBGS
cnE}ZKpLfl>?*6erUgM8D^y%>snv_g7˿:P@yW@xl䡠lnP|x#vd+'E
clD ``si:QSpbj6yl.M:242^~7ϱe˶nV\zjlfͥ tk,;r۰f)fs;<b*_cO0SLQL\r1Df$Blw
%Ib\˒s.κ;2K3(d^pzqU!A[dIy;6 NVYo.nٵQj azr\B6?FB'NL/*5Ѣ%`=\yO!7tuª2KJ !*f4aKy3^ rOQfn9}
`SNZ*2Bf~_
i v>{{\>vC-eӷeEˏ4d-7kwBW a~u~+csM'"κLO6'D|ڮ*[]0<On3mՌ5=;A~Wxi:j__2j>\ K?p{iӣqޓ>3'd&dAƌqG?;eAKcSEPl.MXzoLwX䈓燼7cn"fc7ysi)WU}0@ߚm2پg~7|ec#vҩWW;IOMxbiͥ^	ֱaNY3eyFE`	22nxЙM/z#wKUͥ QY-}Yg^S/g%eͥYgxÍ cb;lg9:c|o{F|t yFxkOl.MW_;+4+lܷn>d/<X\6tGSbS)K@Kl.<ouK=ezc	tDP"yi(Cʼs?*S]Q&/=)#n:Ӯ;Cʊ7!OLiwHXI}̻@Qw&+.2se?_E|h2ͣe̘gt\kdgc` ͨ\ZxvW?AdL /ٛK^VcT5UKO)|K<bx9sf5{gΚUMq77C)ЖmK1>l?O~H}  ȴ"W i"S6=Ӛ^u?uO @z>ipbO[N9d5OSlиޛKVM@uFah|$omqr\ݲYml.l^}"|Ƕ:)]hإ˭Ro3?MfkYF'ܬ!oKl@Xg-uxucZmY2e*']pUެ2!Y.gs	CCSv>6pE<Cw 2/ֵO!-&Nsk8L>9[>#q YJF][Č1<!hK8\{*6 _:q@sNOGG?OTM`&Ny>ؖ&SiMߌ3ʌӕmԩeҔr{8\2Ot]'M{	Kb܋Kp1m3>htMf܉FWzeOjX!~T=֐j9"W-Hz.LC+ָt2Yx. X?I8Ee<nTSE5ה7W!8/ISVEĴ::oyB9i8zb'npqdWV) :lAGJI89GnFܣ9Tԁ.~.z`>"bnd3NVm"DfI);A)`~Q詬O9Я7fL6~v~D=0/DF(b꺥:N~٫-jj:.#nQiog]l32/ȲlTPh02gC-\?<"TXj&^Q\-DPou#*L 7"2N/&&cub9y^霂!00"PVSP`W̨.6ݧEi0iɜ)`y:r4`KS!ҜtAra5`c@T"B:@ny^Ԅ7.+O0ec4N3?77B yiGdlL&H8i`?϶,Ս	vsv)NhW[oKb<L0bɜ7'0>y[):ӯvF/|-H;ɋK~KҥJ $b@a`&)%^)[ظ|ײm~L*2a1'&ͨG`&tb1h0g c&.gSqѵd,5RsRCd#7H/@Tsv9O|K:yw^x]y,'NОW˼./̎_rG$8y\:EpEc\9]߯L.6'rhoIpC];}[-=;L8
If
)S}&Ka>j'$ŢyaK%5l7+2F'NX`MI߳k_HtyW`:[oig_l*:z/7|-Os,7$rXtey1MbFn}VL_|ބ:V'^l<iTĹn|Byŷ3wL>J/۟iooL=ހX_*ûwF4ѡ] ~WǾ8ʦ^2;L]<$2юo)Mn;QD!aP<wGl]!lbI>QŢw}j^dɟ,qoXcb8%y|FKwhf5(#e!~o5v}eO{KEAKӤ=ƕ[$-L=2,rE$䑀[	)mo0L]rq0~~:C
ϼO|Qiz^~L'ٱIyq3	fSa42_XߛpGn+KΉ[⳯ycAA	deb2#Wx+R;V]Gſa'a	gaoq%[QI^]dkFZ7P6>2<nE(/>Motyo fH9t@vhQ^#׸0w01h(?9`&r{k/:n崳>6qʎ/O?_'g-ejHyBmJY*q*x:nD弋ȷY~+~O>iڢG5[aa{KO|OӇ676C;"xcCiƲKicMQ??qgy>0w>9vGǘ'Xiɋ:0^blmƭk~+վWbT`72BAۛ8[hxc[	O*}xooNSDJN>#v66=}Wu:7O|O=#V?>?_EgZĿ7n.wvPnٴK¡ޑ?^vp؇F}ٿ9\!88=Å5~ïwz;SiKVq pC|s?j9_fiCgz|%c?jYxjYVI폭<*gWexۧNѥNn'{Va9ʸ j̡XB6Cm]-44>`M.k!4bڸ	W8)xr_IGQiIxg	NzCWM_Mvc4y$ch)W}4|3f̐ǘrqo5G.pJzky̲=tBj	7ʡFqp0BwKyʗ<#JtB͡mХ8r3rS/Z:ثc^ܥW6Cir9Ap̧^jNiz՟
WȽ$N	#.A3]z-5KR#,كe5ܜN0NG@ZkOh'wc?ȃMEqgBEFm:6bKnmmMȯ'ht"XsO)mt%;֔$zHw;GxRDB 'U?t$%6)rAB$\:N$&o,c9N8cq{tN< T^SK@6b
'q7Nx>WSM:_<u;>0T
1+7c*iX6:ndHoK	`c!e&N'B oe	ǫ1aeW<7`sirHBX>sBםǞqM82+eqM	'օ[\gb)\8Q,Θ2rTe!"Rql.S/!7o<|89N@UN\JYpg&.O9prp>ԠinHAI7 Gy2Yٹkg	P].ıä5~U9靟)']xբs)sNL]դ%xȸ\6$j>|+(sDҼe҂i'~=$H=u }
` y)6Uۼzd#h|H6x* PeצM nP[-RQ2iyf=oܣ͌:
oozi[2O%C* ;*-OXv.|液o=e7kkeS7Y^yjΓ'ʎ,	BڼQ.6P~	kzF-J?],܌qP~%޼&/lڱ][LV~w>tnRp7M5岳4K/$6)~ly#2Tg?C;nKOO4 e}6`piW·?wP[%+_4F[p}F^ɠ²ĳx:+9b^tLl|O)76֒7>S6*BR>η4UX#֏qF̴y&N*'LME!%`%OڛH^R8Cax{}\#?ڞ~sx]~}@N2UjƩYfO[Fm؈9ae@ڑKه*}\K9[dyl3m~Z}"I\CQh 4I$̓?˜3?Qr)WZm+\v*p%g}Rm<Ff㖧Gmo}8Ӣ1<Y|,K'Ml.8+I4ʭƢ/[y# #~/enh͘5)Bv+n=hҢz#kJ@42)`qP(MQpXx.O}"o.1d2qq,$ٓߗK"[KcͥϘ'6[?[?}GMXa?ǆUV_ԩ)'xoDr̓>XsCȶHQE|1NUFX3Jb2\*O>>dUژ?f'(S%@7'Ҹi
y~$qUdivR;$Z#LUcǿqI(3Ndʹw-ڐ`,0U9b ="GO7\x6Ufƴ<q0]ymID#Gr~qjx\?ډWNs<c8\cnS|rQ1cʾ5/4(glq\RAڭʆEQyݗҷ}X`?bylƓ)es
|.Kȫ_C&/e~w{.֭[ʖ͛lߴqSټi݀;wO:p<*?܊<G$^Kaw),o>op%F)\g֧6>{sr92\
@1g9Pٲk;I, WTHŬY*PN.6Vj O,XgpTzQ,2e#F9Ʊe1>H
G=yAr׎hҮ240CkޒTHrcQ^o+c ~zVhHtv!׺69Damt8hFC'^VZ	 Ei\'6.]:,\fHQI L3Uu5Jlڼz-ڰQ> :Ro+XQ@&CFUe*yĩAT@2jb~~Q{Gfݩ+1YKCuTN:a,p[Ӵt:t*i> ݺ~jZmDu@޺H d2p,.bE~V6Xz5zG4^D-`oL&(ѸW 詛=.bګ4%<	'_y5DōIkr6M'N)N
3<~8b#?{X1/fOU~\AЛ x1҅ wtxsGIp;RTɨAʈN2Sm8A]HK\JoRK*g2/ķIrhpݳ{2Y#M% 6+'0!;k"+7*?;0C/KvD7ye݃ߒvYo(kq7=~KeC7o:^x&=eZ
B"i 39|ϊ^ h۰=?~|-}&ulȋ\"7[N`'+0_pYSY	=pvsTV=|Kyۤn/k-W?yew.^swΝ;ʌeY^'sO;28ଫ³?o~ۿv``'/ &٩{3KQ1BgҾӷ5/|L^ʷBo5Q/<o|<_o<bWC꫾ZI;0xJO!Gxv3|(%$/Lrs.n,-&6D0GMeNl,NfQ23-s{eqֆ̐K0%ad$w|Λ,c.,`HY/٢et6^|etS ]\ oh`PD-M,zMiF
`rt]&ϝM}69 IasaOЪoyfoc|>纲[w>ux&ɴ6z  c&]rsާ,bÁ)G8j{OM5&N3iDlߖH!Ȫ7_w-͛G3C*	H=:|Iz54gTSXxQN`Gaým4@ߛ[KʟUyNvV/+鯤Wgeܿoٵ>]e3wڛ'ȷ,O8'nFAP	JxMVe8o4jdpW},83M Tpē46?jSHKQHפ@ʹp
=!ް$=L\ѦL+O>jk<ǋGe)|'Y|M;vw/x~dݝe9^[4ڪA۟lVm;Fcc60+&s1Έ+l؜W7>&J9ݾ;QGo)zT.a˫AB|f޲+po.=Ox~ٶ{>2Fo,1ǉE9-Q!tp@Mع>:ͶrsH=e3|"gRrۇ
l	BhաK^ĘDQ5@Va֏E q0GJm$8.%cEښNZv)p>j0-+_*P|6.ٜykC@R#7x:5Fk*yV`#8c^'Exh_)__L\ci&xP"TZ0!nG}<+}8:iܠGo82Ojymذe⏔1>|[K#㗨]SKI"nCX>cW\vۺFp,] ~xwxll:~{B
\B9klDs۷Km+;v({w3ڷg>	
 w<?sG¡G>  <,3
ї9wvYS~eǊ8NIR^Fvp(6O7\'w!36xdx(G1|CUN9@֍1̽jV!5#OUmGamngy؈Ex?l<M#xéȌMha+xIp,*Y6:r~Rmqmݰ0&OP0GeTy-x	\$!LWݨrRd$lʠOhpm'2] nxE?X=GB7Tpـ
4A;	4ہ0}rtcR.MPk݁~=u$3?̏NCW֡1@Io^aQKG^t@^-BERel*GTl+Ơ^d=k_HyO[wUDa>ө3|TpkoȤTe8Jw[${RnЪB}d%K1i~ x"-Dی{ݴ^kgD-ؽ]9|{9jൣ=DXȕH&YC%&]m	c`AS'(/f&{˞={J~U,⡸Ar6$(PxVxʊ'5X0a8-0aߋ'CSJȭ.Ue:ϺC* e	@ASleg%y
"	Oܼ]\iOr$;0أI+f߫GoE |>؝-A8#_K?Vv>}('llvc7ydaǞxK|ch܉-c	[F̹He>,K
Cǯ.ǧtj<0~eEY
^k%K:|a;|)*MOm1w/'NtI'#,bN4f3v'	xolU۫Iѝ:eoP]a5͏'~2aErl`C1_,ɹOQQ\^xv88܃7Z8:OF@Z^&>+~uC,~Ic. * Xqe,N<.\go>q47DxdO5Qx&f,OKyiۓ(퉛[LլdN|.29r;O/Rh?-&*^l[~􏛼`Chk f-9xds`NQv%.3)ȅ1OY.\Pm<cvt͏Y3<Ko5gHPlČFW&U4qŕmC<9zo,vr#O'ҏ3[פbvr?0[AoHur4kʒ	$e/ZVKnX|OhV,_/^ CzpyuG}t~ޏo52hO K(l[o ܸV7o,@>,T09zLX,qk7Z/H_?~pqUE\Z/~wFmUg9[f+UA2gM g-6{QjEroh?V۾KLWc8+偛woh܇KlDLՃjaW<8~`g6o]Usf{H3Jdר&Z^|*z.:VwgeIth~E{h XeCGo*/j܂ڈz2Lɘ?NeH+oW=:;	n8-T778p`L0k3[@]2vg(o&s?..L;%<8Sgg^%UG4P}L\ĭ!{	̎S׳4$rn"3W|DjiZ]"SNJew7M6Y0F)oܬԸuvQi?i#9ԏMg:C
+LHku4qƊF'.:0D16R"}{=^x-G^xP<5l.5Wc扸lWZz0@8!Y,7E ,v;(9Y c
}Ro !c%iH[Ɯ7+5JqH~nNE5aЈt-n^gH2~Eeee^,__~OJ/2M}k#Oyo7{3mzsu{?rl4mP[!uo Uœt!5)!TdQUM:'CSwXCdckpK3td܋,W|{vc0gNÆ:7Op^Ip(ߣ|L҆u]cLuس{E>zYrJ ȇ(`=]p'}iyזݚ۶oӦe˖-!\Ä@'&}jv=fP3lᘱc|c'64&Q<>Qȿ0tيqq{H{5[WEm]o52Kz-8Ohl&S}uu=܉Qdv(ܤobvr$nu5 W帓ǎWƍܰuaTùa5߭vcxxhq8N	C5%*TQ<O;|ۮv0qh7ߔ1Zm5 7;=A>e~= S8xe0;1SgK	Tө[ )>p}P|G4n@.h_qjˀ9U*N>'xm )ic^=#tk7qvΣ~	Mam	eb­ ~um'﫝y\tH5Ly Tٴ!+y^qK# ;*B$ŤVs%|nD~#*i[? sކ3}YzuL6B1'и3etj3ps`	5		Rkׄy|\q(ٙ,0CegJGAJ#q)q0#b` QBP"㟪QJi,qb1F=pE.XV'p^So7 7Zo%,htBTRF̍= S>I	;f>;|k8wyٷb{wLP  /eN8%6ve㷔ˮAܑyNRAs"ww!vh-H_c!,G[콹\j!?j>ߎӚ
2f%{C8~op u=_K݃*'WeկYV?pCx,Xy_FGNo]x[M~OEdNr`цߪw	VZgs,_L-}G㜲b8a8u9
T(eZ.ca/7/Ȣid&\S.T|YTGʷ^3~M)@Fľ_Y<Bh'T
$,M|tQvv֧o ;\MS,O'&ͥI|鴏-۴$lz[e7M}^qx{eÃ_+e-eד7]OhD0gg__:/jj)sLr?U ㉉ JM7Ȁiu+yZ?@="l>Oxpx2zy.M  c9?xPqp^[&pM׍Gs|KXmC>C湺^>}d|Oy;p"$Qofoǋ5o!7$36H𝿧&=;G9@%x"x &>Bg(eQUw} uԢw~d8C,ˆ$;$c6yDqj$Y8c0FY{"3=ӿ=wySyBqطg'?PeRsQߤd]vU	<r?xӗ]M?8b1plM]Qg\)spң]ƞn.7CNn
xr3ɉ2=h?Xf2z+h?>Kˌ>	cyg\oH͕N?3Ofźi.+O`.,\O]8?YI|s?yEȖyE=Zg7ZC|eӷ;v_tqm+"3Iu͍D?h9fl7qv[~xgyMh@^\^s|[츪ˬ"nac<)8>qPchf҆/w>nFT<QXgßi牼q?ק[(Lb6:uD;]~ )M˿'б:ҲAͰe<s<6iGc)K/VD9w\^xմ͡̹KU>EK@.:,N{C)v?D}k/XewĘUu<R_ވ4
/"~ݱJ?"S:ݟ+v={g/9smssFw^_Lx طVM%#qH817}3{X7/+DII2Q,(nW3&MtDmeʾ+K[9?Nȓ;±=w~>8q c{#wjֆnP>)Qsȫs, YMxKfd:>6Hcc7H&Îgb>?kS,o#g-5t#Mtxޖvv!Yxo|>S;HzV+ ߉:]
8T|_<FňQ&MXMVfΚUM^n2b{ʈM&Tʚs0vVU'BڱK5^:`-iM'،%	1uld:yaw~O\KfwkEp|9ztq6TJXrĉe	&*[<T\wF߇^2?hYJU0(1eh3cGNѷeBoay K>8?e(i -;yY:}#X#?tNt@*`	USCpndQ;aBZCdU^*P$!><jxTŏ0ZUKmԠalCP8oR
G> (4'k(~Lr4p:`sدUQbQztʵb6	Hza"xĳb1$կ>z3j72tS4vCҠS>V`P;9#fJ-ҍWJd:hrph%P[st,c@t6J~į?wH\P,p;Nt\]xn] tIèS(XtP.#E'VInmţZaG`)k;yA;*S%-cv:ܣ`K/CeߪsQ45ԜTG~e~CO yϦp7|REA~Ԣ]fxq׳w'@2D.~ve!F| G76D	<<Y*nʃPA1A8bz5eē.91:"n6K(10e`\[<.+d{V, )K?j5u%eZ.4̜^޾moQ&tЧ>m'v06Xď7K$o&7O}f!c8-&<kM#(@9b>+vԩٲ[vO4-6[M%<7@8YC2w<hȂ\wwgOTFHx I'\vgߏq})L8~K۟śIYL9֒yF˕;0ē?^&tURѿ?e̒(ϪUӘTG~" Q.G5qSHuy\?I| ׳jnt!`f q-**gD;DL /UʭI^=Ѝ0'Mb;Pne	3v
.|)W-,`vώB}ON8rhd+scBi$dMܦ#9&Uik71Q?tlwԼi
0in1wT;|?63v #ڿh+R)όq`~Bv ȉM|tcQՎU=J&w'W ߦ? GPrQWmCm۶eK=l[y7n +d	p"p
(YX{^`>mlsr\v/$t&ol9ڏ<SnTĺu<mcguN"8Hkky.餌Y6dʌӯ6|iSK>q٧-aT?>!ʃшz4ax*. q r2,Kr׸zyc]?N~=ɿt`vk۷}l-ܶeFּ.ɋ5{GCo/Oo7Wļq
nu0vjx㶊z*P3Olx@rĘ2:9g")2(k*I'A$T_<ÿ(3g٪[2SӀ;} ~56@x1C6HA07;-]w_e|l9.e$z`m._X3ꗽ9Ol˳cϢo<?_t7nܸ2uʔ2sL[T樽͗
dތp^y!YHWqs NLXz2	|~	 ,2x1X!2.dFγ3Yf9s改sysU}=Gޘ;wbo.k%ٔ|aǫ"2 'rƏy>9~xԝ֧O[@iƌeƙ6uL16ʸN^Pޒ7Xö(o2\JV.Й e0l@bc)N sƛL<AX`& ~a!SU*D9{?-.U^ *'0&N{2s4s^2Vf>2CT0$'e,A!cM>IG㇟`1~|RDFzx~ه(Cj#AA&cɗ"Nȯ䞸D*5K ` 2_%i=@㪼EЪ!ZAXK$FhͶV"f9ʆʿj]wͷ=46wDtol@1ҝʀ0fٙ 5Z.-%u`7Ɯg0Gk\F)PXУ^jw1l 0j[:bUL{_Gt@%ROt?N	%;ICHcƘ(CKic/-eBb+EګwTӴWխ_3j eIG Xp}q:/uF	)l'y1b #S/e۪t=;;EMgg!Wۅ@ QY! FKNܐ⦔;qctP92f%Yfj֚^ йoP]EuAZ~LqkƐsO9]]Bl-X?	nN'Ch JŊ&3 @
,A4!]U-d]&?haxaQ&4-l{2 _dsi KvGd^QOL:y"ʒ#~3 ue#7XZc0HB	,N糑bӜtܠI=!6٧_-Y0&V14v&nq,'ʜ<~Z&w|-z,&Olf"8LƼR|FNCLdW+ȲݤT>wwR z<ϕ037hf3x똲Mw|@01ax`fn7__㓅L[8ЅV/X<>4O;&Uik)Sme3l}   NT>HAOf	t#o=*R}&o6A3z\W/e[@ݴmWܑR6(g}U)@2awg9J!Peɻl8e@ǦW ܈n6 48.n>LNv 883nռu?L?.=2U~R6,ŷ6tmze_fs,Aq4/dڱ",xŰ^bA1C`<7k /f<B>|d
`,.жJV#I<!7htD(AG]v={v?\vYvm.|7{/_Kk?Uxx˒V/.Oor\}7dLvmO&OSԓ'M.8;.ǎE>^dY#E݂v36%ψ_Iki!a.Wy;Vc3bH0s*O0?¦_|2[+߇/Ww[\	Pٽ;&NM8c*OK<nNn.W] 5EqQ_(?uּC7L_⦱U>OH2IG]vC㹴']\fHm[}+<̱N>[CMTmO)/<wu}eҋ8^1>q]{}ط?^ S~ץ6?{ΠxDeԺu$3m
c ƍQ
zgnjϞ<Ѿ'O7"wx}<Tvh:jlHs0"`{^Uw܌dpgoݏ˔?E#Q#[g3'cS{7߮Pf1K&OuRLʍ0ߎۿ"]vZ;w2m2+#˶U?ea2Mr/dwVƜv%jF/ԇj?s`s3c $ fmSJ6gˠX|<^u7< <?M-!7p:>H8A1w)O|66|gqcIɓ2ct͚5<>/8'c r#tsx+5we~nm~|'+yX;yFy\aWeL9זg_]&L~.+lyBl_qw\P HEqtx(o1s^x-OGeڕC  CYB- KgVƋePIAHUe~h1`u
k^</Fo2XGam2Dǝa/6^S_c|6Or,8_zg\vWfQgzC{:9;~\4Gc:-x&	ot!4K6W'a**ƿKOiF3kjs$sc].G@:2F/UnPb~S!iЃViwПɀD%2I**5
zu'\huG*-:U!a	{Q~.b/H-#AT9IKZu0$`TӇ3*{i<;U>*
-pkO!^v_nT\ݎ d)"ic:8	qԞw)O?	W԰5$N؇9:)֫FB4$(x	&+QCDU]' l>s!.aEgϱ`O`p2 UUp[ok WO\Fy.|n)ckA5ߋgoǇ{?bR\CȞ0|?½/6'^R|[2zٍYtqͻRvE{AVAe/>Dko1.۞L^`m~./Ox>`"]x4xbO۞o<7;q񭈉K/QB,֏vb/"1(yENa!wT4)R;
dfb7E83wxb0 u=[lSʸ00Ǧ={x"y)\X	|>?ֱLSgOL#29=k"y%DE{8?~=iӄ2n)q?5ۈHe#7<k&?08<?5&|q4iaHݥSy|	$7x4#/v3y137*L,lyPe8>x/ii6 q8^`aY}ldigQEELv-ͷF"A`l)xߠOٿ{wd12L~/ڻ,NlW3Kyh#_V~^g~7(m_|t	6zaƙr]͏!-O\fʟǃf3<nKɑ~hCPqɱﵒ<N ۗ^H7nҔeWY;0O1\ŅXl":;PHy9J:~5>/F];LUD6#n·s$VIJ˺;	;٦6h>|#qbWwjoL(/Voܞkiq8vnY;"./ۖ'<N!kA c=_Y_eG?BjL^Q6=o3n\vdK/SU{~Z-GoȓWU7Xg1T֧,Ofq؛7ą3M~?zYOg<Qv.}3IhϾY$Y3vZ2=]܎ As=vs{5e#7y'|	:,OOܬ:}U4rk8_؄P>qc[|#G,؀#G)Ʈ;Gw(ٻM7nVlL\-3Oc3Rh~SkֲKgc֒ˮ`wO^64ݦz4Y	0~G\Me"ʰ ].xh9"aFp֩bSf̼4DA,B/c>.GU,7c<F~dR&܊g,3Rp' C7ז/a;bsV[eפh\sezkZX>ڲ2K˦+3rzHScpWcS" o6N7wʅv0c=KT4\t:(\>lL
$P#cP[!/o2}'u|s^gNage9X>L;rDz
O0ĸs}]uhD|Wf`y>8ux>}O.YCy?,y|,fO=5"?C1.U#fS	zKesڗqJ7!2;5k<'7Cx{/U3xC쪲8#^7P%MFq%BAr5l|,č0f2|A >hJy@AoQ>gʊ;1Mu~1F1ƾK^mdx/7q7h+J-_Eca;}XS f-CMzro 4&F=	PIYQFZdj4=Ǉ#ЏuA[1!!Īt?Ѝ?c,Nz 1㈾}0[/pEHLw!U+?:7zj făjZRB7hCБKG}Nhra-H%1 s~	!(Ћu0cLrq,j%\'Fìt -ݸl-P+f\C|!	)\˩ҏv<ܐOMIW?| pUtJx6my#52S4dQ1yK.Ovg)sI?pe,ơ	 IwAl?>NǼ;LZOx5}hq"=Oů`{5DpG?yw2
K:|	a;q:.xNP32mLX_}V*zo	`?5zҚ2M\s<fgج44T9EtBq`Pg/qJ?jp(z*M. X0#9@̘3 J^(`8Yaw( Y!/rzv1D;0wWƀTuSÓ'[>E߬01;sjȧ)Gb{T>P> H3'b@ ]X^͸FC|jIw>2cGus"=!`T~5ˉ`DI<1zvprxG`5Gi9LpA07[jsof |mte&mhy<FM˞/<"mȅd$h#@5Hd=dcn05x`bO.9)9EVמ巖~t1#9t˶
6Ukm;Lxyt_fbH0i՚p8B`٠bFmd,Uq@P]Ds&P>e.mߑ#6o|/i)WtјF9\z	@^eM&QbJ80%,#p؍F7h\T=>}4\,kqQ?]`Pd̑_<!Fr-Wm.9nďj]4OLowӷiq) uD rS?^-mu۫6w|6q
ݨOd][Qo"qIVNl4ifdur)Gf"Uf1V`mDY xnXJNn,PٴXrg<?mliNbze6'yo8坟U9g4p+6Kx #5;9B,kX(e^aIͺƙĘcmRlS</.8f>\Wy2?si՗H?Y8\w\ck`+2mʆ{,x|yC}&(Q1P?nO瀄phs#L*@5{'dn\yW~-eGD}I_<!? iv!겠@lC_,Sqo#I]c*Y E^ȓPSW5ۅ}(m!(gu18pٶ2i/0?4N儅lh|ᗅ4al
\:_ 4HoǛYf3+ߌM	M#N@C" syN󏻝ݡA(S:U(_l\q(HԵV?ɒi	&l|GpwG[U=v)5R71eS.9x)7y|Ҁ6c9iWWUCz"ƍ3n".6=}oVT//+><z'D6K(e$Pӗgڼv'͖&	nU"mnK%Ǘ8>m+ҿ˜s)
= 3n7lsWo!	Wn1?zGYνkRÐ?ZrW>ʣ*Xa	TIn9%Py2vfѣq.;N<R;ӗ_AP	-nY'dFEKYv?|R""=2qrcЍv LQ6qsg*q#6-;ީlyocp˭7{dAOb^
xCb[WcF6yk+c"o8S~{̓z~*x&(A=!ׇGt0	Ɯ.t	+=_m/fe_\ic#u>(^Z @ǣzФBk^/~I;ǁCeAas_]̄[>=bGҿ{@)քv:$[fV!ԁ|Dp(zƯRN`dnJHth6CQvV?l΂k Y3'~~tuP]?Abi0#`H 
_Z{QeIluhcbك3r?D'/3Tuk^u~\+]%1~k7l	QP,"
nԡNqGx.7,蜼HΤ'ȣ#9F8+x#~:Q&T½!p+j:^i|}4x<".:"]C0P'Jd`@AG"Y1" @$W 7l܉H(҂H\(PU5u|IZ()d K5Ön=b ٳ41rˑorab2&38!M6@dx/lR>Xhy1(mbTL)*CYw d$,4bq|̚g<%}]&$3[٣*ە@LD5R:xP=uJlJGhY"f,2СS6mOUH5Xpt6x)wRȈZsNvA9 `6|H(?e$ڙqP,d	p~oўs#0nm!ǜ9xS!x1ߒeϬCy ɏhR^(4ߋDvXU) -Cqm#&e$u \Sd^9[AHs5|=Ѳ-pC 01c"LPb $PW(Ayp'q@wLc a r&x$E]ȃr[flyp\>!]s~0:A/↏6$oyBJ94% +T&]R!~w|1jZ9I?ht͆?la 򗰴e,-g<R˚	YU{(;Q+]]?NO3iDU&t;(X'
BZ;u)OC˱UE݌&J<xA}bܨb͸,iƈq~a'Jic*C0vB_;v,YRްᄿ2?p7d!vFTI"Tl){CA奶cA>g;]Fkzۤ1xa'PA	:=.INd"{¯2;d~tn	MZtRAhK.0?\IvcwO_b ,m1rc csN7WB.#]ƃ6V7C4jz"Ù)Vit Do@{&DxĿa|3Z#AX x>xP&f]c~!u?ON:x7|jxl'Q`(W6'uhn.	{K%3e.ge[ȔqW .0u٘RKXG~GFk׆-H/F{y[tZjC9@琡#3ǿ5pǊ{`دIGw3 M~xsh0KO
NyJ[6sh@ky|?Gm:Arj<>P7  \@
0SW6 B$e1ϚGl0-dƆpJ{:Jq-OM<n|3Jc/[Ns16NJn.EZ#[FkjQC"IYae KZj1]|N.NAXG.=̠x@+K-.M?G hAS>4ێ
Id07r)Cm!QGikkGmi7M{%	~<2[M飃	Nzo MBM7 [@">w"8-,NO1A+ڛdQÂR_H|Cb8sѩgQ!QvdrPXTSS9/A6ډhhN8h]ܨn#1Cv[A	>dR1Ѩfxg	 S'xt0x{*~t[Ctxހͮcɿt{؋Τ#D^	<!>]וfH[3ҺaKd jhZp"Op iyV;.s7+df~s4|U.}eƏSeA>iU+6pc ;-匁Q&	9Lo|(PSR9e8;?lHP&NDw4w("Dz8͌auodso9RFQʮ<iLXr΀tڴeﾽ lY@&!v<4jA<I
:LNQ/a^	(5mנ<Ȏd2)'5A+傶!j|SWn
[ͱ
Lq`Hm6yLd8-4񄪃Hю<&6|&= 
dp҂\ ruEv|h^ךqjy
Rݫ
A܎IE~Eߘ<g^I&NAS``=#{']w'
Au7ln\*{PN>'BuxFJ6ˆ-P%eBu-072>RM83w»ͥ6tf<elh!ݡq]@.y݀?&a?.N5ibyFGBeQ&ƅFu4 ǋL'ME<A[x2ybK1q	N"&%zEu~LqZZmM$,2UN_vWN꫄]qa-XOIņ88MFEDk>y̷Ky-|tbn!Ɍe<p$nۄaJy.М?XgOP*NdL#h@$T#4m^p{tpsvJߚ0ֽ5$:G[# TGغ!C,U&Vzei{{W&gmڪ9ȸ$>^jT_r',`!M]aXHw2Zx# ) 7E%~Hw*3Pdz()N/&3xi@./6zbưß9=|/;e̎y@*/7_^='MP<,BATHa=ӈD'!pzB-eu ``A/#!iJ;8v7Djz<?}	ax3oXw,oDs7d\T;
4?)xn4;fpiiF]Z #^W8go _:u+l&:z.Md@?uA2i~Din褧 c5\8l& 8偼d@Rs9t G {em06S̽3Nn^'qD[y3.e3.mlwiذjW6O{I:94XK[t=>2P0j߁#wo5 S-t$nƇv(0v˘F[G֠VAz̷d`ᚈŲ/m	,MՍt9"$jFv>n+AK[$VhAކ2G2#@S;Kmm;z'HSeh\dw@Cy.::G0[A)/)mp8OT7!190 HA
77YzxoH`[/#]cTAC>~Iv+&XC@G
kZ={Yڞg3Awpq*L+a7Axg"!MB;s!;]ꇸMB	|8cG&.iG˂;iV?2*tZO'OP N}Pu0H Ed[;=)x"b0c"	ҋ<		odAc	Wi57@O.='~!seZ|`'^s*"XޅR'?\QSFHI*ȩ<R7&O8Ģĉ>ċi<-$LHu@D8NY4eH
ܺ*&Eo.yBA:|G^zeo0M0EX&u!ԹiS}ó7AB9v7y
/9}vN"a#Fhoj*# bőLw0U<}O}d`8ImM}Kp3W\qP kw}!New9!lґldjpm!ڃ]?~yAalWx5DaSwk
` &k>.؋v ܚ,聊Sғ6$.6@4
v?nMR\YG-Uy,yq?O3I_eW@o|tTl8&>8Ge\	\oy&}B<bDJ[Se1_av_".yBICp_lFO? qh3S¸>!jėND9>t(73_'!Q_@,<eQpI{ûSjqgTvٴߵcGٿoǬn@XC[L?EgJ%cE~
bvm>uġ
x9ELʍ";0TaI,P e(a:'q#<<c!;8QL_ʌ!z%dGxŀ~>۞,>ʫOU/ ot}ؿt:V`]~@u@ue@9XaRDa BV+LxH瘏4,	dcI`čS!_Ujɣ4n_2Roh=fNϜ=69x:#];wᶄCޱ@,i;XqHwv
H<Vm>ҋ(JL[~;aBǈN7nڔN20oȋ0#adKH&ϒǲGG[pXTűD^cKy9Wf7o{(3!XȎm#X!D5`@86`T6PA$|WZ%oc3'k2 Nm&fQ@Ÿ><xڍ@d-ȋؐ@'E`][d!08_mnSHg5k7Gنx47{!Q0Oy,OɌ4<c\bxqȠ@gnz" ;0mhQOFye&HPI	9±J:c	B2gh<*jB41Ocv*U`bι/Wn0Nٳ< gχV\7CyHmM<oQQo:7?5xKTGxrucTcU_j<@\H#AjC!|4NĊi AjGI!CB.@'d2DQ  SE}o
]o2]`D/W4c'C r`ڱ۶=̩Ⱦ u>{ʞN]ѪE _%܁hq@lHh:`҆lkӭM+rФ!e dgB@Ɨ!fiBOscB7g.&m6n;'fcQgFsB+uFL3e!fdiщxBg" >a94Hsu*^a@5N|@+9=2l	 6𽓐ʩr(TI[UykHCCG~9ɛX`R3lLj,@ f,7MM?O|!3c?x7@6S<ˇ1#mt 510i	,J|c5dTӒщE,Vcƍ-cǎu:Ge .4*r7˫pr2dZVUNL$䒏~XI	-̍.|6yd?gO|âܴ4Zq(3J%^z)nQhx!de0m:F)׋mRҒtiQ4D+CbS,Nv䮨_ӄ4"XS= <QZppj @U%`p\ll5e:ƴ8	ӞpM,sA~H׈\\::MQKˠ=ݛ *?&gda;.IV̉*xjlfu$-6|0]C%rE {иUM9P@#Jy7da!#URoX"S/ۯa'4u8B,msꟍ|iIE24E\7j"as	Ǘɓ&U5~ dm#ܯPLxdviȄ쐇Iڡ{6Ҹa-/"v\vK\31AlWA.BHH[@*$%wѰ]0eBR0Тzt|23c==oyN>}s9Ƙcy]sXK>nDEO>u ė-.fkd0F;P$/ʅsp?s/:02n[eJVßZ&ڄyֹR7	&".kQ!Cɫd~ŗIؼ+߉<K=KӾu|0ce]҃!2#qVCؙΑ0k*	f]V=:eE[esi8I7Kÿ	, r6Oi`ȇ>3I'UkCڇ6XA7Y+avzOu}M*cOqq/l卍#sKa9HkJ"铻aF"2z7BE
GYl4x1)#un>-e/	51_f<K3pJ:}#֛â- 8+JeT0ayWLĻKZXi.iIlm#=25ھ㱔g~@PkJzP	Eza})T)RLA[0o=7Rin9Zp2M;^%}.0-&=@@)Y#P6ho1}S )c by?A('8ыGYpdfldMQs%8xЃ%bFL=Ɠ5s.֑sG\^ׂ1:̴oKx8nqi؜=!mC2>#	OM7)q2?bW եI3R~9݂Xue]ԲjF:ؔ[,"^/#JL+dŝ/%&I&wʸ8_!7vZ/$ULW借vǚ͌!DPqKF(-ǕM9l    Ayu  IDATGQ
I~MI|ԕpM-\5^EҪMe`>\yOXlGj?7xA&VWpa
H	:,D[wiDM|L`GCj~O,uԡ;n,ɫ	>as 20^" C?(@ރF@r_C$|]p|9yuU|w=q0-#O0E&/Zkm]B4ߑ]\$<^dT,NxFFeì
+Ҽ]] Â62ATthr@<Y<f66nݘXȵ_xz	>^،XS5g䒋-<z좄)$Uڲ6r!-LCt tȥN>7xaUE>`??˝{w'f^"vn{.H!,?9Xk0]h/z%@xe~Rٌv~+̸KP(M7x
8sL*bYY*>%E<J?A7Oձk0T=8%	zh@bƎ.ٽ59bTutxAНNM#j69B8¤n>ad%.VBFp_tjg"kI8⢗94`hD?4g6|7RNjOS<IyIG81Є m_cip0d<F(\~ȑ8wwB;0pQ`C~<ɄiO~[;CgfsL(X_$xN`ƽf_|Rѩuo;k$~go3ǆۄR'
s1?+6vX}9oL^Kc8M\tu<[/f)k1ʯ뻯#iG:nH._V	Tr
TCYUxVr5~&H	3 .NzC
؍
r.:`g^=k<izE ܗ{?>K.ҒM@#i+ڎEN|V'X$%]	tmHYsq=z^R6 [1tȏ/3?f5f.4^fG'Hј=79ƕ%1t")Dv]"sXx,-8rY#x2z=1gYlxIg3@O
ݠE.<$+s~ŗ/$~q
F>aڵv2)`@xҍ/>yЈzʯ7cnR<7|5!Ql87̅ :M;iMCpդT tLCN}3zIlJ<I8c?2&C哮C`/)]z5x8 ΋Kul7ƚ#]*Mvx]<xO<u-FZo >PM&Ӧ}:2?O0g?<7YD>LmJų'`;+gд=D֟Xp~sXyj#BcUüKF?I'H+J^K;3mrҗl/ )5OU?dSncWPE%CN4D_
/]1/SfOtxe\
h=jq$M`pR7V:@\O
	oC dIt	#`dW/m
$)QGh
2&VHL4A<Vp=\;`x=©1;ʿu|vpY(P]t}Pzca &y/0
!R.0UvyEJ>d $Eixr"PY!]68tT|Xq. )+ a5=6b71OC.n'Kfؑ;[wMs /0E
Di۱XsK>l׈"J,Hn=7'}|ʷ]P
O\ {@?'5*?[d<? ~
٤eܺ]Noq$ilK>ǾE"?bf'mA$pIxm;{=ROX(
OֱetRElq0IApCC
eIBԂV.'o^#&E@	<ؓl2=a	DyTIȁL(O15EK0>Ai
sdy(H5IKBWN|Gx9
JJ<T9rѦz|L q,;ԩ ))j<W[P@ikϫ%h뼈x)L>npL#NWP
8ox=vWLs|9u~D*Gڭ h7Rg?.O6|sC@5p:_=Ǐ	 Fm3Nt|Nyu	w3 Vc[ (6SOeM)X7x}Џ)ke}t-Y+͎gfkw45ylpm7Cgɋ<޵'Oԏ|[λ?0S׭ԥ͟99MN^Ʌ7F3n8~v#N&7%5/~&n*!~s9w+|7A")	-"O	 ;f=l|aӦ:f"ӮgB^ D]?y2Iɜy_gǓ= zL\479x)\ö--@##pFO<n)i-6v-'؏vc+Okro1[7Y4?	JЁ*4SFp')l?g.FmWqyQֵ\6·G~o>!.bwIke8/g4pun/J\t:TV7t۲q6ߵkvƾC5>}uaƷcǻ OywFk)qR')GP<x>	lH,i ztF?LH=?D?(M:u#lkSYFxipf rIȓX)_*?s<ȌX hwlhOH:S#\1
lh4vJ	.VK׼}O̱]h-
^#: qAz!Ro.0,i@Z. ;ǯE@+VߵIk3('7Lsswx_|ݗxkwO>qMGUU^;7Abu:_+f6>4OtɓټY5jF:R:<iA}l*o!O놷4dA<qKG}[$S^dwE@e C=hFca3yDZ|aMI|eeY8%5:ɋZWmpUˈM6#r،R{1$tM`yW3&~==pi#Յ<&h"5ױANh>/(`?:hr)#cLTak{7wttY4ԙ@E69NY\>!gڮ^yh:6em!W=dR<Hc"3WN\Lju`A9ƼtN,AeQ@yW~R2|Y~7r<Xۘj}賋5,&>Fa:X¶bXx4|[x*lre2.o+u:(`'ȂۅC!za]7?WoY,kr7jӫ%mI bv$+xL{[X4&CaCʹh*^_|OgfC[4U/y,pϸ:7Tp%BeK[k4vS2h+\Bi]%*u-퍏nv?~Po>#78INPVEZeоӞщiCqOT`i;0HKl^x♧ZnAO6葅uƚM}zQFY	C#ZWZl4Ə2/,=>0$H#<|l蘒CK*OzQCT)3m!Z/j%XI=
]ͥBCxQ_~a/f TP@湂^ep[+&a|ڕ#[mo )c޾0 G6s%j cqI'xn4	O>L;ƣ/nNL&o	.='}6㵜\Xj&f˗i-ä!Ky|b5"+:?^	8po$(p=)={c,Aj+eԾ	C9&y(dMˡi9'wu'% 7Rֶ_L?OS}n!M.Ȭo%w}g_Z_nt1"zmk/pG:Ę1X{,3nqmdu݋yg ȡҢ):1f;&ھϣϧY)>9c6w뛤khy#	[He?M Pp?Ȍ\M"v~sG< N^[{c Ut|7U6%q\ iW'p?ɐmZqt'x=J:܂t2Z6x|E١|7yU|(tc!]98?4hW7Zڔrf(ؑ&oָ=_kBw/F6 tu-kjƇӶ:1ɏpP9O~'=m&Qf^zFi+8-em)B9d,ׄYo}P)B_{;Fq}QХzOpScqWah!#$L'S Ǻɢe?6([js?ͼV43`AbD兹u\W.T
aƅ%36
.3>}ӏ?O} 5n|qL;ik1iw˸>^nk3ID jwtg{~5^˨g~{/9'V 7pRssG<:_۲i(	6=lw06gYۃSx1kGȃ7ԡ{EP5|2Vqׯa&5(nh$Kx	=ؓ zko2{Z\( %^N[lUO~?_7Y8/bYbߓ|_D=6mCpۆPbo^pKDi )}?koO/&^2G>&GS61I.~-kfU`|oI#Pn?RM=n!M]LuT`t`iハ:9^|,11E?.i}쉂:S^~Y_W⫠>NX\;'t7K0gQv虈~'r@yf2x$09D.-\PL4"e#&ii^'gI(!a{dasR5: GJ}1yGѩ',y<<Q⟧~,~g]h/w(4-V~-bNp;l/y]OdA  EسX4#{bc6Fk::%֖ؓ̂Pw	(qYީXOB#JѝP C4c*,F)[o.o]P+"~})-cTA<T'0SM>3r;`lbr]@@7Aa2!n.tmCr;: mt֑f5th<&{q¤@&L ~mS+W)ᣮ)sm bsXR7ID_Vhy][V.<[D9v|ͷOF.p%I0 >NlO"s=0!<Eڼ
nRpKuR"aO e<Iac<v̉/c*̴|%s~;xXwUXm錅\a6PÿV&PLW["rX4.X&ʾw|NLĲkat'1Dl<UNHN%Ӿ:AzF"$D^7IC62\I%f7} 4S.iœa:JJq1RJeg~
r(FF&ZM^k߰&P;q?G	#S_=zb\</:}z~KE 4SN|#w6`C۸t&6d[oDKnCǜ'ɏA:l~<4Pykgt'
{`j6;}&i^5&65J.U#/ژԛ?81ްm]3|e!)7	`1i>}<@ڒ0m
FG^bǵDkC=j0WFB%Zd L
.zI>;B쭎ՙ-Бh=ɩ쎁ڦ6|S_KnhcBcoO@iK8`d6Ol?)oioҟ)/z6'VaXWSuti0e-)fe"*&'=G9~ca^Ny5tJ[OU,; 2pC^hu&l
}bS`R>
?U<q+:yӎGmχ 0UL9D#ss+1#ti_\VCg:Y	e潰Mz(rs#Oqj9;f}G^dyo{2f vvߺELD^pxxs8OԔccdOBA;tlG|M;.M+?DC\ڃo0q1vk	&lXɋ5yǾ퇶ƘJA_3q"H3N\^`s/k6)q{+$vg.xsьzDr6PfA釟z)?cpɹI 5.x{(%>WIDpzluq_a;6gUOh+on=Hf{	_9+늻'R[/b^/u$x1Wx5IS~[AcoD,k A2>@j*f.$/	6/h;*kćm㔟z9Lhy5<k:
tuj1ȇ~2ILPiN

ub#9ʜ/` d`̠U2 	n|O0zwo ^b!AvF+8QOP|,x]D
㈣J[Q䝧2Qi+t.PZѩd(B둆ĝIo
bDt֬F&rӄߒ^`/.R,5)M(^4Pve{ኍJQv،zDڰ=6<i黹?f8PI][NXdQQ>:_axc_=-GçL;T2_RcRoCE	Xq=|aq$wR0Ez#hv	!dt\|\--28).+{b>Oz~Iyá}lׂYP֥n\-;p[]J^(r X8|q`B*sHt@:,n5җ $3Ay;tգ:X=Pmݹh sri=&R^+8\!CC&Sa.n0QGR9eǆ,lݧ|reNvI`-T"pQvryv1!9AzKLvS+mKl\=jc+眴c}׽񆂁gsz[կ珨8CZ[OyG6e9;UiCebݺ`̕a5.,qxK+At"9@>>6a-WBm֕9-lGaM׳kA5sS!o:r/:q#	6NyIעrYh?}'~6|ml ONIc:K;M{2^鵯/dG>{6CSLɯ}r<.H7zּv;mIsLKjacI8$L55B)kiHЇ˷~Gsźti)f8n1"*$~9<t;} |бΦlIp\|&-@
CGg	_l5q׳,S*IXsw2w#c ʹ_=z[dY- 'c	zqM{u%ܤox'i
Ejk& OPCS~Q,ecGB	X9=:o@ءgE[xgǧ=S/'OWVmo0[lʑДgacU-9v|oD=iA1wW׶ȓ#=qIܤЖXFys{5y@P\aNiY|]nXK.0y$*֖{Hmƛ=7AOC!NnfM +C)'% )iDZ&8oNlnfam]K}OD#qѕd~7~Kz1u8oŘe.A<!Jv̾y~뫃`VoMy:F$	ʵC۶ss\сqc,oAB-1g2S+ΪC'V*l(<#m/fsPx4ߊ7nrs<2LKPBq8^CZ
-qb5Ƌ aZ8mԗўz<~..OD$P%?K/\}[U#S_CG?$>x,7z<yՒЏ%̀J`}iKu/y\eF?˷1]]p&mCf^?.<_<TTeZ7 M啞Γ+s~B'ߥlKB=.`1VN(XS'BF4? к0/V>I&zve;ȷa	2Nݐ	#t4m`I9y|.Ӗ\ '&_NyC2Iyc3!P])5a̝ w?'LcC'^abWOZ6AuO96lk֕лvw.P3E;H303.Iۓ1K/jUVsMA/I{2O_+ML|a2a0ρ|V0:ݕr9>&Op#M?pȽ
].X$IYJhzIO ۱mL-- KcOHRO=r2[A=aۖ8nډ?]0An/0o&UE B]dqkA<wjTK=Y:,aAp(Ί\lR^?Dل*w~_mF8u'O{~q' `
7kc))̏ #!->L]6i#
һ<DRn_xPmXwߦgl $I]\<όw8pN:vki{۶(]p$*Y;U7RMN8KiM6
.;~G5/0ײ=u>OȐAcNn҄#;Q?x}uu],|)_Lۋ	tcobAo?`r">M^8p;teol@<~zɷywGgma'O/t)ύ)X7;WݽS؝~kvmzD[^e|MrrmmTe#DkO^9h3%2-k|k- q1ɻ'@{Z?i_I~҇ p*uPG=cz6ɋ0O<t#-ͻmzRBˁV~S~gI./:@5os.8Xj9JB?oew%Nz_.@s뫙i'$
g_ڿfn4OOV^RL_~nc#][m<eQAYIJpSV?PvG#[2 WݠoGcx~gɏ1/}&+wOsvT>4}QLb0ALukpw	[ m[(3l|dCW%e&;͓|7ZP:WXӉ9|hH6 tDxVƮ؏13z&y-h׬:F:#='^3wNqfHxf߾C]%|+jޱ.@4&L0ՊGCd}7΢s+2߷_!6ssOf̀'?Ok4ڍ7esQyǭC?NΝS\9LysL;t@XÚÏh#})W~>^`"/ʘ{m]ΞR0pw ^kŗé9T7pRTuWTî}
"DJ>Mr2g]ėåz3PNr1$VM݅^w1ʷҚrD~7:p?Syo?d?ɵL+HIױPXDP"A$;Ǜ2ۼ6}յ%~O+Bчz8[8eZ׺+?P\6"!3i' swb]eo Qމ@3%.'X1)8ᄆo0yiAM(xy^`&A~+X8 C&7=64&B>k_|Zi`ɟdh! :2
Φr#z8^Ucsc:>{oن 0<'ǤљC?w{Bw΄l	&SY8.~ohih[.m߼#3o=ԁrDxmcG]s2ſ$]JhC~Gf:eJ 2S++=?[m@<4W,MɁwĀiDSe]oR,HʫF&ĐnJʞkO5G!4A%q@??ZQ]@NNS3twR8 {SO陾9j_u"Dy7ZfL3T`926&)
͡ɣOIlx@(:Fu>4O>X;m^T=PW+6@ȡ2!@9sB,:~U @[0907q	HAaGmD8?l0br׸z<Ӧ*MrO|&uc}݀iFM.-۰,sX7wr~9LOdN۴	6CG5Hm]ɏh E<8{seK'p6(XWPg~sӹT/T_|-
o;.jEOq=a}ŗw_?wTtTl^~YX1^Z|#uҧ|׿Sf!U^>s'7]fb@wl9Nsô}=IK6FbS;lvkm9"uGUt w|Opt/tlϯu~l|ēYRiOr:׿=?xM5ϟpC:B9d6$bd9/"Z~h361sVK?]T\1<HڏȑX<l@8t`<(r}'XsrkhG&wWպ,l!5u$˻t9`髼2Inhi/m{7a@ks*iea`&rL_DOq1uoh9S;ly}=@$㻮O|vmLP,܌Se%tga˷8	[ ^cʅ&rC t_&A.m>CFZ@:e:6tI?ic`[y$#o#۟;*m?GomH7fup8P~ANf64HpC{Y?!/@S{a5[ϯ/
ZX]Ac߆̸U$z'G!?i߳_ K6\H\6|LOS-͓I~CZ .|k?Ɩc&%lډqï$i؄7u%эq'36SʢKoOO{<\-ɫMc#}`WMEБ,l]ځaS.mVPxw]I}KUy:k[J rDUUCoCW%^ЎS=Pxs8^E'd	l;X mqod<S}_=B`Z'#ozch]⯨HަK[aPN;ޙqVQNH,>ged+}wboJBo7<5}q{Xޓϲ%z;$HahIŗO]-?Wv-.6?+`r`<rf;@r g3$ɏ?/ߖf?]2Q[=3xCLN8j7xRǀ=18	%h\&&>]zN/_B, }[_ɉNWNx	-sЃ$ƝdW|߅_PzO\`6`c-0]hhU>ǿe0N^=-.Py/G`O)Gᶟ><(mOuO4i	OżݼǏIz&ɧ9ﰯd{8!(F/pi{> kJ7rqh\7ܓ,Mc8环Џ4&~f,#7-<a(8&`!{ǵ@.o+4}_8#f&z0^ċ۰t7|VCΦf#;l3jH'GWzҁ|ʞ4?ԦlnG"ec~1 	Hs8gy:FwP<%(>E@/#zO(nчj8M"{w\`'wCOS^pl45P}M-z%L5JphҕX	 рΰ61Y%u?eoiikCxOލy}X3<ɕ] *,!7cȁvG~[#ܼ~'XE|:[v|>s'OyVlꇣk]g=-LaGHn[l}vh_bݧ~ {}7,ÌUEγϴl;q<%tC<}D[~~[bՓ'&BM?En7MA7>}&FWd:w
jy}(ўikH(zu"lR7R';VRW-:NO'_)\\"跿=NXo>~o>t~p`Nf9 `[zz囯&eNShf/bGz-'MȺn&L~+3Z[knoEfoz.oMb(Gᤕ쀫u3c)OME)jT/>Le%X@l1( 7l\1y!Sg~AQч5O&KK={') AUE8·2HpտxSB>p}7kWgiFL<	xQh-F؃xm:1M)dBEW81MHkz'im	%p-#Wۖ߰$>
+)mb7>lwѬC<dʬހ䅡؊ΚQ8xlߠp=7jd	3n9+swm|а'qC;axp]p{rP?~+}޹
άm\<ᅶlɓ\႒?ʘȅoԑ)kތ37HBSHk6oN;
5,e&c(O~n Rը2_PC/_Þ<) Ynӣ;~O0Q'=iLB|C6J3 |+E8lx|Y0",_(c;5Yi"/ޢ#ű*3|-88l&4?_oBU".%)l?h3?1<ys#rd籓7N=pw0$2+ly"p@~x`7^׼ѓdP5![,bEBg'ŀWP ,po	N@($x\7DY%Wr.?BP91. խo0A}]ה\#W`cR&&2gy;N\<DL'LL?x1
hs-|%PHDGNtM8y7# dEcҥQ11W *\~{Iau!2LGΈWݦn9r Gɿg.0KFPfmvȁ!~{ļ'lnҶ;?>a9lĢ<G6^*8B1c}:,*	o("w#.VI,=$DM<|ppvf"(@qBe_EN
'@cgƢﾛX&0nxu#X?q͕1)}'~'M&|<>0LxltE[H2`wA40.oʹu `&~}[G؛p\Dz׷)Iԓ'OE~IkބГIwB\x'~
h/wO_Bfws'vcH2n |wP.N\b؏̒ O`Tg,'gW_"7ecSsho3*$I3$a!%"^`KC&654lD8to""#;xI!D<1qC>5<P&s3v`rF۹1ʾa>.`llC]q27j4pUhye3,±%oAR6iM/ӯ}.mwM'0O&q^|e)>W0a30sRS/l- ltרjq7q&F^?{nlכK+{*Ǭͺ=O3?csY|궭 L"\"}cSqM dP&'OOQV(@~[Bm73>{X2dCw1o.0icQ' `#@طOl$2Q.Ic!xF\˓}*K8m?<l^GaȵxX~I%¿vXNְ8	7^4ƨ۹Ju~N5V;Uυvi'Ua4!!?}0Dlz(V<urYSW_=k]yz1Ѽ>Z_>y܌xM_Țm&~RX&mcжh7n>xUʘ@5@Y	aѼL5,70'7towo>7z{!Y7z"Hg\4ER/zm!*cNܶuÔ/'thS|<Ng=3K/x3@捎7PnxOb[q֛|0>8ؑyMuN^x~mM+vdlCoi?%\#Pˁvfdf
_q@NXVLpN9<q	G:Oo-HvVUs46~W;W}z4oe0锕 cdݶЇ}}L7/vB}XsюOΉNDoۙh#&l>$RBafb.Wwh+62pn0JG- %B-r#>~r_NyR]x`|㋨}_cWFJssA9ix%jЄK*1!8s:B放w5M~Xҡ?(	&XmaT	gI0Cz9diD͒U(Rx\o8pBQ7Pp^8/T	OhRw/	kqo:jxtlt&TP4&68a}+iI|SH7GUlHuq(˛L8<|} BnXg!Evňo gGL.	Ozd4̑04-ae	ӥVv%M[wĻ>q+(8.e3 ^mPS>Dbv]!![^c;HT4n@ArJ
C/OqA5zTv(& qU+76Wf:[lHJ~/?)iӜhpB cБw?HLxU>՗l:.6p}'4@!(
bz4ƛT5\	@\!C|e	-zAv1p|tN,>x-^h9sR_^P*cE$1q^d7ɓU}]/sG2tIy(-ƻʦ&9kQG'8B<.0qG"B:5!e]Ll?ye̢}O|oǳAP:NE;m56)w}l1ݷw9WfѣG^ȧ=X7%)/p(O`񔊌koFPDv).zr@ԩwZfԏ'V?3]p@?'m,y/cK[︂5xj$-B:ɈhΒh]ڿ{il`ʫ-5g&~N6
埈'8[$h8կ~tm4i2OҶei|ɧ>D+!MQy%OɃc\N^.fZ+JћL/>ʸ|Mx{￧/wqۧBCOs>pxy+'FWʋ^bcz};~ptFu>E`IWۚ^VFzqQJc帟""ljG	h+o$Q:[~4c* [lwIJ8NpJ/h2ZN,T-n_<dmq
GrO9`es -!̫i3	́8e764CBA2:?[|ӌe铴;U_ NBo3Fs7ry/ֳ~Mkߘ^6d@@]ڈ\v<sđgmZ_^[k9B29<z0ԍtOAmO	ǽkZxհld|"Pd2Nzz>¼{R>2y'ׄ%为Mxu?n`'Rv̵)'zAS֋L}	}~NT5*??T|hv}Jp+L-Jhlrw|0vOyǧccu͸MC:st@**1vDv/0|s/yYO̓gdb`ex73)/8N
Mq؀mr7H`Yr^S_'~1GIˏ3~[76ؖt" cŤMs@X]o-0VT$ˈm<)^˓|ێ{DȘaSƟnZnh8"z/N9*͋/BkP/CQ7t/}[$py-]L3
kSܐ~a!$ȟn3 6e8`Wm@O_ۏ}EsRSPWGGG`CKM:	W(RO$A)@:ew;8/)G]Q߁F,ч7PI7y<`h(S [~#Y+zyA$݁<ya<+"t,|7k+	[~$XlkXT3$^t|ςY<$[^Gģcp,ҐRyq"D6qSDcVG r]E"@ܗ?odt+[w_S?%L_V+X(vaD ⌒X]㾺	:8qLSH l<xR7rC#x*O*0 :G9x4jgk`B۵"y<4nW?s ̉_=襇#	w;,s-~	W5Grl8!Dpl
ݶx)@7`)%L* ݆t[zaAm>Ѫ*73wE +WY鐶%PДaIcZٓߓO?T=OO&gA6ꝒK ,@|Tv~޻{û?ٗc,PI/PpDk(؄VlRhSc[*pգp:uJ}\(Mq >~v[}8Q<d7*#p߱AAox
O6F%dZr5+~I'2ϸ{n|CaƟjl:'A?oܼglסv<&6ѭo2ɼnӶ<Mc%]\ >⋻>BnNՑT|6ey],WdaM5Q/zM͆}^yŸč	?MC6lh5<,;~ /zV#㑂\`*/:8>ۺ
O;1:A;Dute/?8Ocb'QʲkOԡG'(w\ ό۶n{q)uz!Oi/Β5cPq CmܴL)6PO~sڭM+	xQaS݆Na96TM>BҮ^bE"I48e'ϴN	9hCG|pz~g,{-c;dțcA>>;s
-6蛌ƽ7 -4Kc
:UkW)Oݷ_.0цHǅg6oͱoӁ"kt"q7$/#,u%M%ܾؗ>JL\|vJki؍y>zǶ~[X@r>K=70ZӰt<<ʖQG6\wG5eb\ꚲcy405uLHӉKZO{9Dܰ({ۮ|:z#kH>1{kйk&ڃeI~lM_I̷ o!sxzCN/l[n7)-:q e#nfl<Z/0}=i?}Dݿ^;u
Ήؕu@]%br 8n>_'ςe&mv{O~sAp-\Lu )cHo.V`ߍӗ;Ƀ~L>0_n"C{*\Y?q't./zKi'	Lu]@T_&ns"m^^T8^`p7Mڪ%"ܗF)'Cڼ,Hl6b[{!~xK1&D7w-xa+*Gr&> &> *{.P|5<xѲX.彯z@ t믬	o<"o$MEx_[If$P7chNErhzgNvoL09G~*+Yt~E?ĝŦqAgY
wE>mdH{%,@r#A+Nc pa	pZe;>'[iST͉I]3m	dC361H<j浇%<6hx'Pp={=NbeDoai. '߈ϡ8a9
 *}! >xi`㷰'Dn8o}Lu }|h"-R><Z3_^k,F=3[׈$	ϟDS
~~a>2>,tςI<K[ަ$8!p[RA2'=ʽc &^'Ox2UK+e礯gRKsFLsyк#l:>+^+#b7$6*DγyMT2W&O	Mm@'NZvd +̉UzĜ>59ӌujݰYmy(	LmhT-IߖMUw~/n\l"vyxv͞w?\lQx%>O>q3H[	V Q`<#9ik\9Oo~[7: } Q{NEҗhzxUt3Ro=ȣٖ39n|R.s7<miG,>Kenܾi	:$ӗyM^	n.Kr7?8MG=KrL4£s;,֕؈k6)43<F~6<1@@?%I2%mzuzm+x&qAuMiyz؋NЮm?pm;IOiiQ&P؜>Fm>}}r:٣w@'$(.[G*U^c&Φ>gГQ$c@\Zա&?´t̆5EQQ $cR_ckd6҂pAoԦ7maӇQl4kWoЂ:`<ֱ.0+z@moֶK
>}x8wˏM`
@HJ:K#fҤEjy: &d́#|D$@fLMYp*`@~^cDT/ifqb蜐&v-k?؛S=z|÷탨][5QB.NxC["<A&<E+ט )C٧>fbciCY?BBuMm)΋KGU;r(2D@w%F>UD~<v\$+ۃkDO_~RvN	9oz:s!i<2@kz8y&:'@Xu~!]H=Z>x[q8`P^Sۖ:k5SIC0ѧͺsǾ|;G.e{Eq}R(N>H,z];c
GuX3z!~O6-p#ka}ͺ'+\?Ө"dO4e6vu9SvE~e)S Џ 4I/&5#Uæ gtndM֟ys~6`_HJ=/%p/wҞp^'vOd+yМ؄gz׼oJ":ΓRg@z^o8RZXhèH|	j*>l3N|P'TeA24zAFxHt!PږQWʒʰ노^mM#N v6yYmMUnYV!S)A-{tfxTL'P/ߙnFL(4,\X:.0uW}K>itKw P_C¤/DCty1a	kL`3)myF~؏
J=pZLU.QD1B]$a8:qJH@:`H mD(s	MG34]gHh#Q[7s&	?2Ϧ)24hT@NYxI׊$5pGW<퓅?w$[7%:փ9PԘ E8f[7I6i4yJiV8]mW>8l<M߼9!kx7x}"KN6=FoP]hYP\6$`gk;]/0uq?p:^S\O̓>ph$Q.[l|Ǿh~_ë8ai< opy:&O^n[qm/hzS.Usv$Jt٤k3/7Hq) 1kk͟؜MOm]˦N/:C-ehZ;Oloυ*䭿fOTj0qK/L[39GRMqQMLAy?!\*p56@[NW^pmUI;2hM߻g'o(bOإyzҏo|`zx/hl0ޱ1TӡӶ!)HR4q~x_ұ2>k~|c^`jk.TzBǁ} y<w,_>_g_}}kT~F%@'^Ņ&ʈ%rP75^'y12y<~):11vmm k#| ;6ݡnZ:y2F@K:Z-s#mO)9oy=BDKX0%{OǺ%JA٧zvH-+?dB Ço(+es3qqP o_*QK+*M  4|pt&$MU/5BʁG7XC&okh'n_u8.u?}ӏ>6o."U[ܬE#<G~y34f0N*>,# +[Z'z-_ls#~J: <61=o=5b6 %?*79H_X?,k3rSBg"#c:2O軜qj֮q	>7G{ o>O@F?ƿwCZtAMm/0a}ݻw'|1MhqM&/hSI:|[܂&jkV{B6O2ƉL)cW}U7GKRrɤIݯÌf JBSB:1~^h⢮>-~;|4ꖹubʅ>|Ź.m͛o|Bb	Yv|:,$Ec!'OO{p>j(mSqEi̛FmڤspΙ^o,&0iW!~6cc{8oўёm\{ϯ[M?DǤjb/;h+uG<SBL/>&4/4 tmI[W9wκ#1
kb',6ŕHm_
N@ަ\HVmqb/ixj[#irq'uYaGjpz~6[En7짌q᠍.z7;[ϔU\P7UiOZGil=ǼQ$T|>۷Cs!Vs|+Hٲ@+~yF~5`^If5=xu]@=nhynL-#2N;/yUx{ A1_+I8qię=])=~3«.SΧ8}O^rH}̃z	LxUc	0e<<t-IÇ (Iv;ڬ!&8AI!z	OBZډX~.7"&\im؏Ŋ!+usZ|,lhBh=:q!z'P1Æ'UYȧ'w+eJg#'Yw7Y>dCɕQdP͋܍מ?L\\8I8r8FgTܺ̉'7ri?R|:	!N]WЀ|	]xh~ܥl98)aALy?'Kasų|x<niD]/y)쑜6C]	Nq
8cLÃw.Jo`+x%'>699ݳ0l''NelN8x
wɧY7PO6zբzN1|)\,`>t޽{?zzzw!kmva1$rO?	0<Č<{w@J?7_(>㘚ғn2-/\cF@NP+;6h #|ЪF'Q5r	3܈i66uØRd7<m'~^oJB<Ņ
.pҿk%hB6q	@~Е 8a!O0dmC\@gP1!y&</_=L_nOs.W>/Pz.TOY~O/AͲܴɉNwOwySA8}p	'1ߦ}Bihzi/90#:"uH!th~\ٱHCV5vܔIH7SWaJL	h9vނhKϱo hԑ7{Afe"pzg D4\lykc889·8[*댮cuI"p&OpE<uҵ+P;foImny5oV'W_=+?Snm??\t^6vŊgl2Ҏxf!1-My/цq1	%om&#~U5z4Sd'itЩ6o@l _\vpM"냏ff5f\,|I;lK}0뤑Eixzb=Cݱ`x8/ct<B 깺{70d69kz8VwA)b܌성i&Eܢ;,TƼ>>Mp R`O~n, 
mC`	orN/oVaan}gplfՙ?< AfBvY)8L	'e x$Q  dz{ce(tG<B8ENQnMn>+6?>=]ۓGԖ}gat}ЬqGCҦH"˜3nm)[E<dc^ @^	s<uÞo|qƁ
QF})5pmG7qe8qk'Q!/tM-7>e
azW:Jii/R./By.UYI
~c{8f[&fj]t}7m]Ƴ/p8ɟq(L9%>=[DΦpM@&4c̖VڦXTcE
7SBK{WpQI-x+$FW_A3[/p\Û*R_lXZ4ԉr:>wܹA܊k.3з0}r-Y`8Lm]_;rX&!><:hן0YQi+s}W%wE0`҃gh|NڸܭkoY\Lgfb?p?wTx¸Vmv afSEpYx༻M,n꟎;xX>:JZ7ZqH&U"sV]=r_,>yr棷^kʝ<9azuN~S3YYgk]0EcĿ'9!IGK2=)_ʅ)w!<2yspdُG=5Sqɗ~\u|ӫcC'h	W}i;qˏNqݪz<7m0y5NS?Ul:]׶;ȰiuO1xPAa,u9	E_3F91 ?Cn8il	!a=	pí30α{/AG]SOOxG?҉#;t"<ԁl9Bc˴]SmW{򧳭^ym#Z^ݳٞ}' cssCGs3ǜ0sgiݴK)'l;s2?$`3䕌CtO9\Sllucli9SO@qmkC?ipx%G&Gaڀm(?9"mͶc<Q;TNj)&9[G}oZĭg
i3_;6m> ͦx;)ʫ0ݡh7@HQz!\lݰiC@C+xS"Oy<aT}=e`#͛`g#Hݵkwo}#|yR' ?{I
oҟ?vsx¼Cz/FObu)6vS5y qr3d,ef#4zRϬtؑC;Xky7kD.irk7,|Co*a/짼]^OXPi!?ZqM+<$9w0\SKzYI[5՛uSm1hҨ/숍]bK;&ܵzׅ7;X~z:n}_c:F+.D>}:ڷ&;msFW5c%ۂV( y{}ͮIxMɹl7|Swc
'4ڐ1%yJmcp9#E8o;//VFq˛08t%q5΋01^IPۜO;}sW<@qԽqSIR#+OMQy-M@KX(؛GeB^Coc?y-GMS\'-a<igDY u2Qym[6`04ԐXKsBdu$pM4OϷzh202MWVOb"qE%7[,$ lb{)N$7㱄~u77vle/q_g6e16%C Lhd$̟B_၍~q"<ߦ]`/E1	܂!zS߫ArF@)$?r[^Gз ,$/vutg G76<e}8qrM9ܒÇ7xZ-xu^ap?p'nq/j8u:CΖp;ݟQ k?U$5T'[ S]7 O0бa2$g_.bi
CO34/Ǣ3e,Uv`l7nb&>QYoY8/]uH|$#Bg Dף_˔C4NJCs@j bdJkAf:Є&-Qg)Oa/
wLp[LcP `D߼\`CzN`(,P	kY g|a,zdtD~ørHl٘gr2Ĺ`oWɩ|.z!LdLf"T>6fSrOV8iy_}I0.0;K 'J_ⱸ{Iz#@_9{%y\Cj@09w'x=|RDGIs30u 
%rxՎ~ w#/]dqGiE/I'r\cݴ͜ټin<$N281#k߶?mFyA6ωQ<9nNfA(h%ݓ6}G>SGOEġ#".v݅6kL4h,@eX4HƆM=$80>a𻀑f~ͣa9@v@Y]gCe?H(Wd>vrx`j'Ʊ'xD9x{#sAXB``b÷ilҞȋt/zJv\8Utn8o"8&?:@RʗIzy"A[>է籁v:E8N?'ғ9ю7ΘC>Kl9,|\V.rL#Kuy#B]؄a=3&F <n7N2o_M7^K&į<4qz)<x<I-!fA {}-c2Gxdq6e`އ/ܦin^7Ni'0Wpђlb5iznRQQnkJ.Z>|S*{!47<O*ʔڃ<}6z!YGIe.,Z$ztꈋ2^]DscB9sҾv]i<^GIM:3w^W7{Q)iJǸh(E33VgT$6_e'--;'}zi7!]C\1XTuv^[ lRs8WϾTMSֵV9gߢG$;Y^7#Bp?a
y[~e֊_i7u/@
t>hZoHsHi+e|D#Vț)uA;TeF/IoLL̈́ls16"]xZ~xF[GݸDL|.p'?iUK
Ձn<ϡ&m^\SiiFkzmFq弁uZI5ɱ_rV\RW3>3#q
ǅ@.S+i:ď%h`<Γg\C	\'~$Lo^	)7(I/$h3W)ϳjfN	T_VIXjqEpN sPRS\E[^=ļb7 }܈yivP/&.9o6OΗ]C0qicj6#5u|H {YHq7'ɍxDC#f#Ǯo+A4q*<jS[1e܀G@dW_HF`Z@}z9n^'MP/YMaܶ:tH9G +|C[ױkO8yunu̃&ߴ'zOj6z~hy[ߵߍScEk*3җol!iC=^tsiҮKkũOl6o)ES6[ sꁫQ^ S0\%ЍôV]6d_2'i=YO?k\G?fpIܤ@d@̤/wj~H? ;&"픷! 6~#ouPPuwaa5>xIAZ/Ǜ=f"J#-啣?_ؑL Rw>"^ɂc&6&_`Be	LۅrVos:wѷ>~!KNX@գ~]uئڋ#5(lzI<Eu`?T7/V_G'BSqKxN96Vfhp`349N1"+a|I'{'wq[d1n\$	N_æks),zN^	9B⸀7Cͷ~'6&Ws@mv;E}JaƆe;Q}e'GShM4hhA<H;3ƆՇxYħ
:M؏:DH~6"Ml~A&Hl.n.&XE~˴edl3p +z4:k{X;IdAS3)5s'Tf0^K%|'6'	8R'C͞97e܍hzCEuovlꌋWSCDC7v=֭,.ܼx9lTBMrڏOa|̃0J<I=0coPb	wc76ٹ@24}xzDy68fs~ꗍȍ3px[ӽ?<8Toao8y؏-7u@ۥ.y"u<A?V:?=}|+ul}L̻I 0sO+g a{( aHJS1IAF.JaҹxC;i|aWQKm.PmP:Gf<w~<ɏ'0&}"!18^{f6 6c>͑6Et6y gK规WЂՋ~64/Y;"GG:4h5k moBGlKY疉V߸cn?F@.[ <<aOsMNet϶M}c^Fcl23ՍMރdÁoژoh&RgL;I$KhS%BI9}9OqXG:a uڞ9:s;q?ojo`j 뱝`$o<Fճ(d:/ 7)&/?tv8Lw]bɴA|c٧|C T D_yV҈(#q>o6DgB:FQkc!m뾸B#mf!eܫ4ͱ߽Mg둱v7ɇ5OQ̿8͜@$׶s<oiɏF㜅\A@6Mk>9SÎ,$\B瞡-sذdOz8c~?aYP~vgqK`Q`cPd4:շ-6in#c \'L=`
&L98n@mdB>S,[=᡽
1}q:˹K[zd"Ktݠ
G^t /-}
1uXfY{j'<A/;x(b׈Fѝen>и_P>LtA&qi+~NG%~<y~c{p:P729ԁ<_H[w?[;ǿ_nO&_ШG
0EorIkoʢ%p&pWm@0D+1MyR8'i;= Z?t0)YmxRiW	p8\q
MDJK4% KHV=A4j%?D$p,4	v,vEXe"!EXwYbȻ[@WӰ~p_5!:N06ށLS椀?>L{G
~z5Ԍ '(,LL%wA ::
ב  z X](8sz4guųWƔwҥ1 .2]?(t0{7r]xNy,C{E5qw)+jlYMp~3Q,47~޽[~jGRiag w#=t&iԧSڮi?7^x
L"}R'I]5[~Gw*\}ÓbL=>z7\ M=)\wH}8+b_]ӯg^˓&Bw/CC9yB~ˤ,OD	2
E'Y3/:SFeCҬoB<50:ǊM"	U;QWEfg2pRkv=^@!>;TdSM⫇-yza\mۏ=\8DWK;~lĸxehq6H:'LlTUyc_USރMѷӞ^:Wp|OZ녾㓀cC{DʑCƶĩGf\eKx.]x(Oolы ЏQ3tqmU	CÅpvu.PǄ'hqPOiaGGEb4ÛHfC&+ڜ'T FbU\l-H:&<pi肮7\wW[]@'[xղl) 0K]'vM.lN!/vǆy<[vn6!֖f08{AB1{uM_!^#ۼAZq$o]_ 1wr	o>ؤ7mߴ	 cf;,ȃ}GnT|)Z;R:?9c! 	1lOyOB 9ia9!72@mjc7,VGpGʸ8'mز9v_s
8qn_mGO;wDWGȥAZ{M"Ϋv0řoMؼX77[>!A۴a\`
|'AFye,c瘇QvemX_"5"y;ЬX9='Gpw	P'CH|wi(7~l55rGo(!zBC:`pz|dhP<qj%37;ymO}svA8(׬R^(M#0cH^
TfRWmR׋ K>?lqzK ¬Ѽ*|9711u\S&Ie
")o0'f	X78&wROBbm<fviO8s?҇ex-k3a6Xo8r^#d5pv~K~SiB񡩌
5<wXOhƛum{{G8|9$st:P$Nc"c)Y/n2~^`ʚM
8r`Xqf y"Y(r:"$,>G]<i\/ٖF8O}/nrʣ]K-!4܋4G}N)컠fж_W֟E.4#A{D'eXp?7L(j!RI}7ye|IC2B+J%.ԇZ5C$1i]s0#.Mv1Y٠P{4P7~I="ugE^~2,>cW:3tK8EGZN"(C>Ύ;Rp]qnI,;O!aJZ!$	'kW9&6;(b㭷=|87^~eDypRdt'ֵ#eIP;	f9.?oNFo;Ƨ>>8ÛvO|lféDWvmmASfFf[/	*Y=zԋK<)}?ha	H򫻯>]x/umыWq<2<ԞTi#Svde}tiۯrz9)yzA~]]Sx]_|q,'^^	e@?f}Ήu`^?9l;Kk<4Cx,6XS.4m5|W$dBӤ'X_"3'$l^.xNXϝhfxD=qE@Gɰcnw>{S7S\`d;Of(աdI\w@0rQ BnHbfllӹw41㷻	Kiiyx'5."75/˚tEm{'p 7^}/}1l1O?yާ!Gla'I?q[y;拸3d~_}zHYi_|e΍.i[KЏ~o5kGb2+Xʍٳ/>KQQH% *)n{@HΰiÇ;4?InEM]?ANJ'jڎGؕ{$6qAu=J0N#g}GyzDWr?o^ԍhW2GV`` ܒEۥ-銐6Q[oe"kcѝg:k7cY?^[^yZ><wW\flnmKoatufl.}1{p<R^^t+Hna%v峟ذG6}E#{͠z8ڕyzaM~.e*"F]hDCj.4BSXzTbxm~W[-H!c J-)?I<]/5]+'=c<ЦvcIY%v,Bki57y%YxN10s/:*KN9QKg+wҀ[6(-uΘ7r @S;Payqq9eIL:],$\%z_'Y%PW#1majzfǦxTqɚ)h9g"Hi^]w}W~;ytpS^ƽc1|o@8ŷ?ڎOgM\mf$h[I;t<Oe
vA3upFW5@|44AJ1cy3!;zt8jLp[Ipi,UA=0nJJO}aM
:>/Ic}8=f>z~5h~yYƧPOcK61/TFI30M#.t$q8u~6a诖_Iݯr킪/!uau.>i_ey08#m&|MG^ey/zws(&poRŹKNm`dWNS*.ჸqK4eohOȵՋ?Ʈ'^yݽM^$P\{x.<RtpH9|v}mV<ՙ1yǸLp35khy-c}4cՆqsJ]?p8Nȓ^WIYQ֦r
^eoy~>M#rg* ~,ɶkE3QqbŖ<4i5da6't/ÆO<m\}}EF/Aׅ'l%&PB2oy9̯sw2vpqkL`Deb3'o/<XܦL)ߖNT($@뛰&^SFpKvp"I7L"4f͏48(C&tW^#no=~C}`_=o=2g0]$@  "]tF"A9^K^&zW+畴8]IWЮߍCm[^I߽λ>h).0#2=~ȋBG^$EǄyɾ7Oy*q~GQdm)?3$ē M
}^fQn>QwߍE67!Hu&8iFye:VNx	$H&Nl|nȠ,{{4>/lĝ\dzwH+~q:i-#$bE7R7rxM>`vl%zn8uoH<qbGNDIc`@>/Rd3fP[^vq1펶Op.BXq)mm܉OxuӺbħO0vyՋOg/#7eG<NdϿ:'73\.~7x~/i'noZ78<u06}ZC}]@ػ7}hasڎٴ~gm}m%85	7͐'7˘ߌ)	26^[.Z2
H0o8tp}Ǘv s<yrPC9xM[22wwS~ob[	͏-{Ԏ}XǴ5q?/0m1~};yJs y/p36>=c xlƤNȏd
ӡe]#<Mn+;>hF
PgFeiٍssl,wb'hwl9F呪0ym4qidJQߵأ.~뒵\`y).۹q/8r({o''2`QwIz` }g(W:IL˲68c>2Qp%4r*	e<MM3}B?0P%.[.ܰĿ!8dO57w=]qy/gE,8xmHQV5Ǚo7Q/CnseJ͙ O1(xKWoƲ)XQtEtz˂_L	¯N@.&6z:5	#4C/"o՜c3W¿q@JR!_sXG,ڬmkp!qpoHk(Qo9ɘO:_?sדͣeY jn'_edZyA%iFVg<KQ\ vߠMu OwF};2s	,h܃<p:t~zk:77iZd8`.qłGeAs`˫Gp|m0:#L72dl"Vָ`lIѡXC1\LO=c'W8nso"k4\/p޹]#Kݷsς5_ܞ~77C껴ҿo@en"R-7ش-3{pN0'qs^1jNB_YMg_0~Y˾[v,V:fM.Gftvv2-zs/Gx}xۙNW}5Ȼw92![)T$=]8;v`BoZO+B	Ǎ o|Nl"4'ϖ;_p(P9NhX%?W=:8;Otq^w:m+mxIsAq@i%ўӢ#ĹD$Ͽ{^\~ʀ 큋E<97{4>^` 62ȓ<oe1y|쫻o={|p\w
6ҎlodbgQul ') eA+^NV[
DЏ<O^)'"|L"ҴSh%ro0!}ibG\yEf1}\0tS*4f&cO&סYV9P6O.p''?~Cw;1c'(2Q}u{sٗϜ|a83h(m3.},yy%yTDN`q0ypӧ";iG{^QS6.@m6}l˅#w.P"JjfA_ԇCbU7WiJ&3Pw|\Tt<EMX2iixG{8a mCPxU2,d{"	cd(d\ʘCPc>o,XnHr;CP>K7)".Pyo7F'Rؚ.dc`S<r0F#Փ)Zcc"ơw{w߹{'ӧO?(}}9퇎S|wկ~wq9ae:%lYU-G9@p>(Ӵ:~^~G"~<SAqy 5 @'brm{=yħ+f|@ ><T,&,Js	nKI?3 ]yBZCFä58H=|9`^&rpXOPsuyO`Kv-zv&L\3,OhC%,܌ͥhO}[8T,UUx~R_El7p$4[rhBbnesmy!}v|JZ~)}J-߼ti'~kאS9ԕVdV1~OLkZBnj8?ͧM8o|f =)^&Bu*VR%QIa4<tBFy̭;.F^.?ꓱ*&rd@ndGSH["Bh위6Ml;.T0eǁpNo*ўuYyDMWD\/acXALT jˀ}b!ضtq#wc#TǆBZ:hxo'Lh_&KF[()4'~iCP-',E!}	T~%P1)q4e+oK)šJJ3mb1.yq89_|ѧq _7 Ϧĭc0|]|kFX+7*7Nny/vG+}G=&0ՁԹpůۛ#mX9Fk6ir5|E)ʷݸCCrSkoNwo4g^YҼ`3uMA37^kxA3ev6NPK5[?Ǎ\>=I~I6^mRgP?G&4̽^ߨ2_JdAsZ K+p`Q/"T(z|<:oN_\^&E>l2f=z㉇GJ|T23X<#1sO\=o;AzaeOhnL8p$	.IC}&p^QE̝fVBޝoC=z6G
h 1'!سӵ]t´b+/I^Lnl|=,M .#L6|#&f4<g_pm'^ih{'9_sKC~.(X״q:yqFI->5z<h%>m^K.>f؄M8.}P}3&KkO:4WtG_HCOEqlh_ɒE7Gb\'Oxkd~؋,F'j"7CMfIwʍVwڡ+ ȟI/WmJ%*(1vh\~w0~C蘖)+2bN_{vd ~3r,̋z _}>aчc'DRGm/|.!g]Ď
ڻ'Q>\UG&ySi?1G4ȇz||?JXsa/uqI^XDGȈL sy`]~7 C^Lˑ򨯚L(Ű"{-,v696
:S8 $7=;*iz(OyE~oR潸NTH~N[А+:x__|7>Xk>:!}}MuПO~yLyuq$Vg\*}A6\_Jh^>IA⌓$ِ#ڞJR}~rɳc1Ɍ8wc<cVS&/@!QqmBZz՗-cS?CU)JmQ3?i갴uA.i4rN!@a@:|6-~SO@>A>aJ{o]mFcHvWY蚂N	tLFvSJnN[+@NڭxBr92ak`_'xX`56p$Uޙu,Heb^a*!-i7nJŶBG?`>`sb gg|Z aLwmCv<NbhDA"x]+?ҙo/=7	M>zP&'$K%Z(F62['B,FIDtv擯.#$qb1~,m
<vb=@7ڗy1zjѦp|v|>$'O⬟X!q>>k]*.榽-ּ~GcX!.-- ^G=ցX3oPؚyNBr<;-޽U;I|#~n/otzc+<m>cc z_T};FTm}xifZah#/IO ^OJdHF= 7{h[XE⪐D
N?r4ck	a׆nni"<F_QHLX//sD~SRFhx[YK2FqHe plE01f{>2кפn;wxN'^LwAӎop7w6CZ.%mˡ\t4xxWw?{0VZ/@lCIxƉ.6۷&'>07Co	˻pq'lw)bW~ʚޘ<]pMp90
Mmh9<0R܈;@mp>o=]:.p%gO|wTN~*03!#&1#p#0+iƕ,rBݏwo/~6qлYT),*_~.ÇO2x<VPƁ/qqcF}cL {^Tw޹_wGt_>ײ}7}Zw#>Ňw~> û_}LX|xջ>U?W 8׶F`A7\&y+(ov'6$G.Sq#88`Ҧ/c|K.ȀvꞖkB=IIJO{kr2߽ȃ,jkVῑr~Y	6Ww?g~뤇?}9,eثqcVO?}>=o_=6wzwJ&)w=5n}iMmoΦj\T	I	s0J)+Or01?ccLNVX@D'| 5,l9xptEvOy*@˘%/pŮ\<`iuQ	ii+<!S0?ЍJd'
=qhB3van @Ú (6~^fa=A`&_t%kdvlʅM:'a}E B]7iEF?rEw]7.K?rvc_[7$}Z>ŝ8s7iS\|d,^E^pJga>)#a!(kMKaɋȊmsаPOs99d#Nqj2 >n">"P6=x@>SaS؍\þO\ЁI:.଍j+nǵ_tO/>yJco{|q'L9tM~
yc7Ex,OY).0yrXWBtOi{XFSGGˋXL2∻cȏ6O	&dm\aݯvj y1f|Ƒ[s8N&r$*)հi8`xǖ'D6'j8Pq Y/l1m}?+X(qPTX'&FF+pQ-)ߦ!7o`aڒD_mb#a"qE#׮\>9|1k\sWì0N?4}D&Oꔈ4c"FB7X^vMi䰴͈5s3W_7Wh5@賕<(T!h&Tɋx.B68_yN6X0~q1O
p[@gz|akzюXOS%޼ڗ.zSM|=IZ1~y*JoG@-Lm87vD0?e?_ xj~wE=7HK2[ڼvB@.p>gy.*\$~}ձ퍾Q(eTn?pu7'*s.ճ/㾺:/%_E_~òbT&~{tm^,kC)o>vZk8hq}hˑi=i1<kiAhcA>YmW
4~X 풽@~3`ZL_ݑ01`+`.+R?>iA1"8odxAN>+ke0l:{1`xnncv,ht#mOg9/_&Fڰ	Z717yc\_ג.Pr/~>R;]7p&l#"&8ImEZ+rM>\Du&]qWNlGǸ{`8Ҡn"LG+aܞC[GzBQ={'wOs'xj;4d aBpO>@cu,t'"zx@$=gۻ$҇xMON,2Ohy7\i)_U"9hl}bq.a&J6v	,w蓩jti~[`#p#|CP!Le\|@= ,x
͉gīވfýdzT}#r2û'=}5rvJyu?ֶcIMDg.2w>)３>FW/=~ȋ"<}8(||;O|r9С't.pb7ʻl9~q,Ål>Yl>3_YX"%>YlM;|Y}༻q^`l2PyU;>sq.'^8E'47zpjf".8ѾSx$ͳQڊQAZ[BD6иDlq&<)m\QAݺ1 }"S7}u'('雅@e#yȄaNCpr6aӒd3ߘEyȡj{9|7pͽ8psWыiO5ZNNohu/n逳;L?0kUaIRB1o"&@Av/![QxMm'278.0qQ\>o`ݶ=2s"CiOB8M=ljï2Ʊa\{2DdH7U̎k 2i]+}"ӭ3T<M,cҦc#d #? $(dO~<q<O@~x3񩯶S"-~JҀ#\TyCCFFlư(ӏ0x;TGFoZuE$MwD*1'XۈTW-z9)жh]&mkɡmGrR8T?gKU1I`M;˩:pz^P/dv_:twz?F!n$Pn@r9	9XϬ*ϱЧ}p%!9*?A[Qc]mz|.UYǭWTS+sT9\(cK:3x-J\ۧA5/!׋;Yoxk6͊W{A^~þ;ε,֋ơ29U\&ώ'hPm:Qb"Sw3 m6<	-vN(Ri)GiR0)G/$lßj`u e4S7 yʷeTṲWπy/i[XMPPѲk1(:KvWT%vmׄYx}YFp'c{p;rMǺ9粠Fe8k=P8DNk㦣IY<ʤm(S7ccYJo.Oƴ`	BW~q%xni;itm)	O'j5_	sܦ]z۵mp	{tl\Ŝz:#+4ߐv`^۞N(sJھk_d0#VW/O.Y/0l\8`\wR,o5Po2:^X0p/\k)酳L/u};I?~=Bk4k/?ˋ^uWH/$\l~f'ލ18dhJxM^+k|QQ7L>w}O<No4c$t\\?8ʱ IOvℙd)7*|N{Z":`ZGmotA<+fr{}ɂ\IMe\ʾ2=uyؓOm``iMdB"2qPH_Z<냤&OİS,/'A%\
NڋB\?I^zwNsΓw.>!QNlΎWSK"A!W~ȉh|Ctx[	܃/zON;p!+hng"Mgϵ}q_?w-']hS۞	SbYzF?S<K2:~>vC.pKד^}¦c^]=mcK׋ű$MiCp:n!%ꙻ5aX'h{^Ў'uB@= I'" a}ч, twn|62ͫsl;:hq'npPCex%QS-	8v@83z-suAnA!8>cs.Ɩ}lulnҺ{6kx	'Xh #NXU&\ʪM`Ѹ4,0FoA8ݰ2n7!	=}vߋvTpN[MSOTo6AݯG?䓻3q>K"S/pq>O?&A]SD}˽E_n@51o}
Xelicf%F^8g×vd<C3dU^NI&յyTSW	kgHBƊėD$qd*7FƙXpkNd&h#m"?WN9׼湱窯?A Th;V9;o+AƩ|"q%puiD![Ջ<xDçsQ׺ìBW8xm)? exbc-} (7{>5M[WOP0-wrH=mW0-:2Ti/ۮ1x-A&O֍s:u44:`l%'7JȆ8ǌ=Wǝel Jrh\cT!Y&|e|җԵbO5e"q5Lʅ.ix4͞mͻc(O:7ױm~?/717to>O!q>[}^ȣv)^Ԍ<2YO+/w]Yu"&Ipy?.A[!uV$B|;0u}@kC[۵_U_;?x=d8-
1·vPELT}&Fq։Ky{~|i>{kuqsϹg;ff	2O*haIU]K^jm{5P`,EHA*ZIC&(w{~~;|3?x"bǎ;vp"TʞwkWUDB>"[&*L\O7+LAzobf_gk;o0Kd"k<m67wb{Gm~ϯMi;/&Ց11u#[2Lݱm8l@^BL<' xZ) &`2_(˅=sYa;Sk4c<<?#" 8y8:WvGlrf`wq0,݁eYª
;S*'XrW9SPŇ(!s)15"GrJȩK=`-%wb āA~): |YxGzw:yjު,WB.'D0ՄfrLm&Hmux"P~※u{BƆf]D
\H^\.sJ)Ln@!EA
g"Asy\fX0{4/6]%Ld2m&}f"wI=bw/&e[#:AG)SS~Joo_G 
n\}/ƥ7x+&.mkb	M>&fBa8A\9L!Lǎ*O$cͫxfwoׯqCl^"BZ HʹOtA<yC`hky>[cwy5>Wa1Ťq'!br|CۻqKѦUOŊEsInxCOߑx[[,#yn4dwP7*dkLTYvl_)烤~bZ=6R*'N9rNxQ&Gbw>8#܅I61M9Ҧ/w̛GSǏy,Ƞ\Ivӑ)ld򪭻J-4$]mf sc-FPY nWԳ ps8ȁ
<x̲L@FvθV>m2lQzĘ6Ez^4x"smg@m}iOE]8%4fImޜCޑ|!s&/rLC׌OH+ Oe2uwI%03 _f#iHs	x2ͨbү?'τqC<w͸Yu]GG~w:OD۪_wqazrS6}>\?z5n 0<I8`M3iƻ@/4z!}nTta8dlkNݗs4>_{Jt
<3W8vʓgl-/y":1yl.:dsz`?Z}E3A	fK?5ai<geJjWp8,_I.x1oQį,s](0\.>LQ9c/-
KZx:]Zi[BSt։L6cnGQmG78\y)}Tsjۍ	-=3S5Vqpyïe<Vj/1#qIqOIM'ozΙ?'6V`AdHCo@k{C}Ť'Odu}L|j\J91鞾 93}qbz34{D1gjbݎ
 ܝ砒?ڠot*4AG.븄`r;̆wƖиAtQVrlyE6d~E?=M";{E^i)ɀ$ MM񔝾"n&p~L!*;e6!oG`߭AZ~d Z\GP,οˡv6sZ'p]Eao_f_$F;2K2ϰB>\Sb nOI:J( ׅ>sKMy*נ?YrW3i ќƶ?^/@CZ_B&[v3V9c,gpݜ0m7<S2{'.7VxYa/2ܴ:27حwIhh;Ğ|  1Q#"FaOhXkۙ*2gQVXK6_']hem&vx-kS`.2^KU.U2cmuY0l2^;uPlvY@3AmQe*ܣ`NYsL-iZ#ct@e?8W/VcEc/=ew}#XU`?βG|Z7}s_Jtdh?[04`e	;?{|s_')qbZ˸="7wA	#cܸqw`x;cc3߫a`$J6"=-l3pY9ژe"^%rǆia6菁#CyyfDFlLǂDi%5󝖒	7eva*XHiM9CpE q<{9t-OM BLdw5`@]r7wj^=^96#j|%*1'EJs'o_>'&_8~M4weU_:rPL1%[7?k/ZYxyxÿ:~ߕ뽿x|򲳻vpa4dG˗}6iyts˓U7TἙ9w2>EӀ']G]tPa"8-^CB0@~_f];LioOgΜlwQrZGW^Ο,;I389ϡmYehăWR)-է/}io rD>717R6>* }Ies|&޻aZ	&!߅202W8y˕&m ݦo^줯L~ѵ7ymd{]޸C/qn7K/--I;
yj(cY\ȼG8RɆCo5.3A7* IзCs8XY9SQ ϊu"GV|WO)oɰ"L"5Oߠ[Ǔ͓8+x ې#a.^'OK>Ĳl$$GS?i
({*<b\
3[<r}NL&Dx\W[I[s?xE8'?J3ansx(9B%\S©ǔ1;&S<f:|){t/"pUN+2Nr]̓(Z8dyԜPĦ$j.RRN=8a>}?c'MCg]Ákmϓ;{vD$?c4-lѳP!qBhA] =?-#ƧoM2>m v,Q`jx*VqA+舾χmCKfH2_x͋'6D^-v47Nlk޿'|lSo?V!OiOXD"qE6xC3u='S8~[w>%1Y9ej;|\.ԁ`L'r	EWra^8
NykϝE[1I}5lys#ȯ|v}$ܘC{綿!vnn%KڶạpR}abnD$i`>t#([:h,+\DR8t֍'=S|	bYe\؄1>ANKy69>^	ɍ܊ɓE[v#h̒'yciO/A?ͦ=CxɌYtXg[vc=8nS^OQi 7TܦLlw?~C=r[6y"`Jh)NtWC_̜R?^/:͍<v5tu1/<6Nִ'6g>lSdde>e}3x͠?8ms2npȑ傜gOrB`qJ,7Dj˂⺠:<0{<	oH<D3]OmM]<.wҖ^ʇ}K{{0<O'J~ȼfG^n 9'\A
}sb .ZFs3Â9奔{sKks;_]On.Y$CDBgw=ApP~PZ#l*GaOdrDWN^J=x	1NOpP#N } Y'qIs뎷1
C1IjùIH6ot0^)f	Kb0Zg17S`{tTk9A\aLK[]c YXG=2$\Ew
[t=
^S%(l:VT;q4dE&__[,tqB1%4y1L"֟;'.]58+rnQC⥋~j_g"' g`fP!9ofďOP&4g3	@
u[7~&rCF'9r3!o䃎QP}&蓁oL]º̐t7}]G}_+at&vK(B;E> ofB.4tByMa1)aē0Lz<2<}k%0}y|/zCϏ7Quh|_DyxN7~rURua?ӟ0^qW3:~jRR߻y'~}d|hб9ë%tG=bF+|QA8S)Fmp<&`@q˴	O/~Lך/SU rZW{^2?x%*z8yrw-f=/\1p3W/EA&|gO<ᾁ~17O=Z_;{sKu.?>L,$fhEQx%wxj*Sv=}ԯ -hЧuJITR~+l*)_v(yDlr0O?-ӥǴ<-Cn@oެ(6Q&
u%Od *˄{YIʰHMLmTF=)cO>i/^'(kQb (a/)T-&] C)%PY@a(4wa',n"26x/h8ib	`Mm*&"-plW^[Я"9|[ϯ>( qC.W6s-s'o)-mֶ;v],Ck@㘁U^ysO']_ŧ^rP'QVPUZv&-[yys$*qiC9إϪk1E,h%me+q>{O^<U[p[}8
cW.DWwY'mx$d?p
J@RMZ*å+<[/Koyn^:.=9`jaS.¯A@<YiӀn.<,=2NNh[uuOTG9ЉS&a9
~NVz`<L߱dt <:=FO~=MhӐg՗S$O	Kg V4D-h'LT&65~	
~Q3MrQ!Ml^s3'J@v]UuAo~VZTJnt#K+x`!Nn՝<)O_/L>A& _~I+	oU|mH	LtlIC?d]c$QCϷQбoؤjEbBZ׸Kǎ)#M3%E~	F{9g\w# yq.q%%O,9]b~N4siqQJ01{mrw WtVr&_j]Z!1G$|C7O3*MXUe--1nfoUd4p+bu<o@Ƿpmب~U8Ǯ$Wc*~̀[E(cZ~d1!u:J.KFB:m(9=6;Ҷ7Ը;skl֦lRGd<+|26}EE9ɣeyF|ٙBJ^rRMrmm7wH6ș:JˇzSJf+3;Gښ
<"^#KW,(hAw' V>VtQHjGj%caڠ§z
֡BJIEh?KGƙBiOԺw(+hՀ|g~lr£saN.'+b(K]qAvѺJmTL|!/ LHlp T4p<O ,N(V-Lq2}xI&ܹ?rb:2aM.zaӇ6=YS&,w#BfǗ,w?Qˮ1MZ{IܐbSd"H[yK)ċM{~֍HP^ߵ{n||M5L+&&R9tw{\ݷlw"񖷝UƔ=M_qtooS89_<3.btI]]Y p5*,jXr<ݽ?G~xNrh3_0}W0[w7E+aG=bڥ|sǏ'u%K/S.^F&ʮ;Bpp_G>v/s|CToxsE|Xq\x_=0}uNˢwvqq|4DpCk=-8^og#ߝ}O	:G"mBdJܾ˾ոX,!;egϞS=d )&y^3\Σ5ܡ/h4^tC#;۪;ýAo}[:@5did$ondqU޸޿kZ^6а9yVxB{
ݦ^|QQ#3r L%@<.i6=0IN^9hMv?O@^(	$LdPge3:daS!^&hm O;K:&DAڏ<m9^tz]׃W1ۀ,KBɕY; hd|"P%!j1!Nl'yBtPh]Zpf|ӟ;<s.K^op:ejsOs$&dFr18˰Ƃw-ҕ|sP',W^-́fͼ_	o'Yt
el~N;EsRp{zU!QJʹn'e~*?$C65x7Ц[@7BYnq}f%fd%0N+M%Ɵ,6FqitC=>PDOyWC\65yR~O(:|ѱ'Aϝ4Ms6 .
tۺTQranwkN>q~m/E8Tt|}l1"?$=SC=+^ڀ^te\>{uy=tp=7eyp?G>`R9#ޤOռ!74v\8`\yy07%ꌐ2lp!J^HD&/$Dtyd,N,>O;Aa͗ bw@'r_xήq uܩ2ޮbET8[0>8"BlsFvbxT=rIsc_}O2?Ur6?nor'A8?a^9S!a61ޞz)mFRNțɉ4{>K@E8F1'aMLt#yMDn"'snȉ,փy	z*5҉+M&s#mm
ERgSOoI^ 'oi+rN_9GNx;dnphyHʸӤeN1ܤLh;`_/bKhdy|wnbW8X>F1ϓE}qJBCA=RpU.'Sv/e-hV'ُ,<xu(4ӜGtBW,SZΰ2zJzHl+Wß4?~|ԋ[J-{y9 Q\]QN,-S!`Au|k.X]DpKـgf#SWV:`9;\#u@*,.7`f?̔3%v=z圼m뭉GÂcu\FSeɭ7"`Vɀuu9tK?pI[[ KtͯU2+"K5X98h*'kяM]ٚPp8P	cactcYJA3=XBB 8`A*<ɲs	E3dey_7t1YdXی'7*57 &w֐KE:a6& fPa RI<Ik]O.3c"^3%\凇L[g"g0$PmMgt+>Kp/8\~?>}D<,H?^޺5v~Os<xrqݯݱ5qG`r;&~t[`C&ڼ/}Kxm_>?++t	?>~P׾/Vq~{~|ƗjKW:yxݫ~e|ԯ|c9?Epg?=/k#eR~R<-UmuW}bJL=lgRw$0⇘t&b'T!_+-G]^Y&⡶"wfD7@=xcD,#ΰI9!gv]zg'O>yJN5[yKsGӹyOZt
"}&buIgN9}qG[aם񶷽iqLh1vOɧ%/eNr[`/Bye=OWlmq@6/xw-ϥMca}z}x-YhM7Twa.Ç}ʯY$!)nWtpft?ȋUοz/MB48AIO(/!	iջ[z#n6*h(ӯiV5Gh*$v!b:wЁKy[fn=VK/ bi>w.0ozOvhMDq_%+Л81vm*eKݡOƧ6l͗RYx5˧峜Ko=DCARbZ^uoݸM`KƇ[&.H٢YiU"M{DP&sDM:ِ0mhoNVu@7jlw㦐7.`cQo@KE?́6OM%ؼDh=CFWX	7^4>x3_L<$ 6a0_{8H1FTK1H/9nI椱2%LbRYzGf[s~Kca)}7\fP
7Kwƴ֍A?tKKK&0F;Firb&ye~2 p*]Kc9Df
SvK/J5S]M3tp	 esA[ZUN_	O
*~Q榳gz2*O`y/ݟ"-̫F_]I<9_U9&S"&MDUOovYYF	6)1'n^6x6;ibF	&+NX$>Pc-%|+Yi#7	CS-7xY(hId-='"o~AGHGExʊ"ͤL;'3']?;ݏv~*F?Cu[-H ESa+n5Қxw©?#TAFKn!k@P>cW=`.s$,-<5u)J$_bW*nr+#dydgBSGS sޜZ<WѦrs<a}bҶO'l8Ĵ6Ίt*ބ2'$F*Y n|eKPw}+\}'uJ(3<=ƾRCslS
SCϵr|dZ}K'
Sn"p*Ahx}LO0߈qzބAΗx7w]>
R3E	g3-u"^+!+HJKX-0VA86c~0KMK9 RL/,
JkLA¨{H5Uș{eK_@lK
7""wFQ,W&&
ztAh\r^HhS~ue	&ۿ JZlw0o_52M.g+81d]~
oA{-$=- Թs8ZH7ZŋQPsKRAh11Nz [De>q׵+WǥUM+ǁxg.dF)FvSw[	Ri1&8MUL0O;s&)?ie{'>_wҵ8^Q9#?CƯ~/37}k|٭fxRdSvu|Ǉ7=>/O4Z":rik9㜍>p;;k	Z(E7NjMPh"@m0 [^
6#	 wmT j~-r<oI>A6	F4~9N~=袝pßۼrgx>$nT,@g$C_E_[nRWneI>t0 R##D˵Ex]KW}'3@@I	=*1gUX#'m5ټkS5GA>jSpuɁaGn:d#W֜yjO+4&xǷ`#x`66t[aQRL~0c͔oylgn.rFn1z%~wJ?Aɫ:aLKe6S}.CԝH/D.rVs;up m]Ж`6:4'Ml~;?Ɩa>ϯV~w_^ŷ8\ro'OQgz{:|`mĻV|n˗/c(}:EK/<a~ء_.?(~'E	#>_{S!۶P℧Ԃ
'vPSb(^Cw.O9W.Nҿ(?-!~1W՟\xO1M<@ե̯L͸m6 i穟Mfs\n`}.F7ioreuC" ?rLnqTƩlDu6Wi;ۛ'&9lE,/s}TIC<'|눫
$1+Ro.krǆ:Gt] 2ZˉJ|sqhwM#W8Uy3n@=1'q
CM+S@Ј&Se~[eӇfa2Ġ~pFe.Cx"o#ȡr~!}h+2h&Xƿa]\#GL E#loyxn&9٢ۋ.¼2nxIF%n8nd#7|Mcj^m2s|KCGlp-kL흹gr~ʁW0S&?~5p.RQvVuq1y
1qT]qia.p\f@^~\Yo!+..
O2{ތ.=hkN/67[t)em郱x3O?i= r =4o'rDJoJ{vRױI@r8CmW%S䶷u'&uJJq@CX#']AK#.Iw]o8)w[0,Yog@9e'i_
s|MW2[tQ/dr08uSdRy2>m(m[yȆV!iW?_zYcpjnИy
^oJĆQlQ~]ˈf9Dؑ_dFvk
pĲDm#"}	:y=WhQhИ懍ffPf f Y6q6MWt4ؖ*~`I%y7(qr.Zk A/w"w,&XH%ǥmՆt~L͂å   <i  IDAT@YSb;XpЂiKf5Q$,Xi5%/{Z%g@H:ȄШe^/m`~)^?+^U}CK0nLOrz8p"NCOsYLDǏ`S|p4_ab≍ &z#.m0`[И0NSã\*Owa1,8beÓW|s$o=	JNǫɆ8|x?vy|{^3yz	H)+x)=}~aau-X`0$fbΆ,gpH1IcEeҙe877m|b=?OkٟM
:hĜI!aӋ!]m?-w~g?1HC&v̻Q	r9ƼSٓHill"x;PA:ɭAn&,YLK7cKL=opMh٬CKuUe2#\Ƈ+F(&хu E2a晧\/tJtDwGG+3~pj>ltٴ%$wY#g%u1dE~;\-uS>ǰᅈfB^|ȤxDZX>0_"ugJ#9C@0`n8N
t+<NF>XP/mM>vgh
"|B;7;1vwUv\Ϩ+2AW_db=Fncp]kg\ }1_W| ,Oy;xGfT&<5],V@x?`z]*"Eewh\z9?/_|q6/8^xYO2 1!MH0%~-?@&)iu1hм7©;6|Tv xw2;̛mx`GpoINJ:KmQ;>}Ws'ξ8ν]FV=+;w<I6!MPE9$җl?A@MݖFc9uen+5<-[)Ӹ4G#h}`fe+e"eaCW֡cÀM˗(>t z}.sR6/26&2ى޽If}ysRo80Hd¡8.`!یʝ16ZI߇F2<il6N$/O0Gr|y -ݓTWriZsۗ 5<"J,%1Z}6'_2)y\gcWrNo!@mݥ9oMQjӲ?c>staLLFR^~"?ia҆  rOY6@# 8M!ݗ$Z6k+[r[nOT@ׇ5s)cm|yWIt2B{Kqrӂr_vid>lW;~OU;;~cO==hـC)X|=xMeʄ~9.0a\FF\oQ&|#l\^SIz|wNWe#p 7c=<p.22?Annqp4ׄ6 q&S.CNݡxJggΜq8Nθa5瑃'n, u~@ܿ੾ri(Z̗f7֜`{СExqu9HW$3دM*HaIXȂipL]huA)u(#sҏ.J[	Kxk7Z	|ਸ਼JMq$y 2YJP֊MZq'Ez0YE>1cޥKK!i,C` .F'դ,Hx1}3=pܠu]me6~̥Wޒor/2+%LR9~o	'v.Q_%'&#tqZ`*kܣXE[{i7}a?WKL?1_ɚfAWeX·	
v6]A"S9Ut},HK{4h'q֍ KPpPZQpd/n`!14u{eKKȎD-JTnk8P%f\",iBc<+XFk&,BmzΜA+fܙ؝
I/`8],x z"HǓG`!]~mSizw2!#>y!PaxH($ͤ;߇K 92w_ϟyxgƝMOqOK95o 6MCcgwwݢ]po~oo_|5x)8e2"[?~g?3xo_0c>g<a1|?+Ǘ+>s/ln~[okeu|}-6;(kƞ̩e~`o_yiv{ԛ^LqG~_4GT,ב-wxuZnha3vO<S3'ǩZg85N*pyds?6p>ЇU·yWm[|o{/unŀEX@.i	eE7,KplF%}>Y Ieֽ/HMNxH_h:y	:{6xE\kbd-t$4#?}O}*Bd,'ek,%|l4DɔqJ^M~{.*U,ǽ25ԩl\~{\sV^'v At]q+=u95حFUpVT|')WݿPX4	<Q2Ó><20Ģ~)_ցS:אIBdtXOp=7qd"7XEt;Z\^|y\z͕Kd.:wn	˸1g.<9	~WML06SlLmoxCafD(].Kd2r}]Jɭıc?~{gn9<'|􈱜fX;վ{u$DҔ'$3u;"aE!R}_%y$dp1M|SdlQ»Pĝl1FS4F=?w<}Wٸż/Q(cZWDȞ~p۔#nң̯,s8tr_a0.td./}2vHr:&V^&}OdwKx#
©뽡RГ\B8!el*'ʪ_2.e?4GwG	+.u6*`hP?Qꉙۭ\:cEꗰɯcg]Aq-8=1XFm3H'Ȣ1}rZF˂Òtmjf?iwX~k\W@2s7EIGD!-zAgݎӖݦUGf\o]u2ҟk6]p75^J6}>S?I22T:k?rR).A3SO?=nLӢllXa[mj'r>Sn)gWWх^ :ᡴ&FLdY"P~4JWslh'E?sTڙv䇲~'X1ų/Ύ/M;/OPqe85`tί	UN$.5Cu5>J.[󁄕x&tfeUxUdsc0o)*4?jC Q+6m96sH#':P[.]t[opp}p:zZ4r0K983āN?#nn`+p =mm1{DioOUR-SC2}vS2t@K[i88Ne&,f@N}s+q<m09g#)iAڹBD22Y|-IN	*Y	pnJ;e|v"W|]9<*j7eV@b#k
_' S7rXe9RVj+Ho#3^QvIK/{. ȯUv;B)hmtj;Ƶn*6vWuc-v~(vzw:~t-Jtc2O0$	B0xz %4?Q(JćG>:ʓ&ހ$FmQZДG4$mm[>dg9<<'9=Ň?lpv 'lty
hy\rN<8'OyA0M}IzowOx8z<0mn.mFZ6y~w|{}xʏ+yDR^׍L~oSP;ɋN?B/0vͧoD=+wh2Й"'>n3Hi!g}0@P|0ůf$J'k;rDഋmnFP^E<w'	̼/w umD<5TبA{!4yS|Tw懬mn+p78 T{oa.ڣzr*2RnOdM{4YaGY䄴Saz
i#70+ p>s.~K_,ܩWm;P[#&^Z lkR."/Yl1qǵ#|rķxc0^Ղ?>.CB?6r[8H&'?@BL/ߖS:)ÓRI{/)o}cA˘O9b#N:E/@'6Gyvˏ| 9f_P4|%	"t'~Ïq;DiWQlTghxŝWAÁVR~#%J}Qߒ6SE['ٜq;s8~>LlȰtaq'ɷA\@iujJS4O
D˯68S|ZopGJnϏJOkI=0~X| E|AwMStٜ0-<I |߅:1"+x6&p^ {1בm$]q[.7cX<ݐ\'=V'yfo;}O˰|C79A?X#gّ\Tu^pXў_C>(J	3Vs)};y9iX
G]:9?eM}	xT00G܏N1^uNI:$ڣel%r2z)>Ynh/怟2?Te#͖tAO|@:tyE!m\vfdBWl43+ts%}NFCw밍C<]-t[a54ߍR0o8xu#C$*W]x&7$pl<d7o7/^,nr\ꮥv㬏.~thl.Єv	tJM0ێ1%-cwS&@WWdR<q+1.O!3e#O<uL%m46F;EO)kEK7ˉۑg
KV|e/la&,Qr0rZq˷4ϰqkp-qhG<mGziJCez)*O6OTzqy+o<'oi>s2'=2'}p[6yU3kH[+m/S8)׊ު{DO6ˮt<c7]٢6m0I+j*c<J1&^Z\~}@(cA8dYe
chAe@,A'x5DBkaα&,q^7H%"΂%6ʶ
$	[Eav`s>7,M:&
6k7ْ5Ds\
аto(Xs/^ێs ;Nh[p64^@e/ئ_ZcTNA;i
8r{@tu	LW*Asd~IyI EÀF>hxĶyf6L-wqo`qAs4c _q+>lzdDUtCFEdM;*_*A< +@V2Sf\F剭u]P76ԸЛlʳ-Zk~\'QH[zg_7~lM_AoX=9~#ڍqy||/|Ǹ9+Oㅟy8>o׌Tc/.3*OLmdNf3j-4M<~u|$ջ|?ߠE@9LWpaY;'wk$eRM,b	߽Q*,R7Ν.+Kܹ^/wc_._*׮Zo\фzhGVnRfx+ᩃHL#;W\s:< 9>,O'L٘m_hϴGlfU7)MWy+7qItJǆ5՗.}Fn ۊʃw*(_E8691y^ŷvU|_Ż_*~`mWIAF{J` _Sw
)?Է̳OU2|kb)YI~(rI7koT?!rrIçt^q
gE1suƞM'2$}(xG],!]g۔|;l 6IjڗFAƥ:$':,]=W
Cd68w_?q8pg!hdD.ׂPK^c~cN7C/c25VzG1E/<Y /}u6Ϲ:.tM?eHMu:!AxNcYVk4"rfarAX4#RV3Y7Σ6i[_<xϯ^bÜ߿_Mj6F<nl6Rȶ.yѡy*bI9] Op)w1vxM~g>!ZJopSZܮU/#?.4&ۯԘ<4p3Ac2TB^X(U1>{s㛷
"	hx.:!CHLqEuכW>65S\pmн*Ũ?hM]/z]VyBabhoūmޖ.M~I'tSrGD^r0[(#^+ p= oU+}ѐS$]qn#~H	= Rc2?ؗ>"&.qn; C|fHI<tqp8Mkģd{6e'd	6#`Zp+㟂7*qd*h0A̛VCbs|ڂ(oK#bRkx!O>L+޲m>$@D-H٭+	L: _*8'o)hA#'lu], OWӗιV[*h)R=Wzpg><
vjZYnkzb&;-C?}O2_vNƱ߄!Q|$`Ny[glF>z3.&nsɦ'n)!V]g&M[H/*_0lqN*ϻsmBN#xEWUpH`k00r$TWE
:3f2S4(>qu)y({_mI+Оok߁`D-))؅L: XK{aULt-6S+Qu0ʺñ+84ni22 m c`=ڒ|5 v`Azwּ˲M-a }2,?2#WqˤS WGbaFK
-?Lgb⇸;lHx\,Xyn .2S/_HW,-Hￗ}()cHz^kpPy'C6K	uS\6:ȋ'w_Ǚ_Olm}m9ز^5聍CR~f/Ii_?a>c>gRWS{7?xh{i~ޙ]uuaz/_"9Yodǧ7ż[tMY6͐Cp_yx-?4>҇L6>㗿nCr@QF$d$|
81f!8fA;̏aR/9ʁܞ}>w0wun1y&-z^9Ylc&hMfI'OZ%_ذ}u`Є3aY?R=lr9-il +جbJFL9(>uvm&s6?IOşC:aMNoXLȦ:K9.!%z&ʟu:~-r^x˟]l;.l;[o6џ2
ou;kEN,XUqw`6\R{)O>|),U=ck.ɺ?ڎŜ128|&-cn4BS)gplX''!3J/ybx#Jv\uqNljѻ%eagAܢ6hLl0Ez.c*9YA:CCm&yZF=TߎO-R^IĦb`;-a{SbZgrp2mӇMŅ\Q
> 1)j]J:9 AkaX^mqtg
~rqUrؓ؀
7cYBXr*2mɳ6f#:'§W߯M&#圎K?tqm@<.2Uz<NI|܎Vir[.H Ӷ,S[8.UaW.__W]e.xlz|uxA*X&m{,DOfMKd/iU	O8iI'%%->[oJhLMgOߍ<xH=9?'nC>0"c;<+'ps&]zFݎ7SCw<M'AY71vPBRO4(tOy`b׭*W_@o=^iri	3zptrJ>2ST\\m"	_S1^`>M-Ven`c F-$-~޹t>?dc|w&iT|Gk(h}	>-f۸&3zA` $^l+qߌ*s71dc?LRV?}ʖsEYP.5òI3&jbSsA}%%*3ӵpKְcӹ:[cuB.xtѹ<N!K `6S&|`>S~HNι%qlAY;M]$ej8gS.G@3{\M&A-H
[q(HG_	FONu){b5	^eMQfSۜrsĞװ[ |x&! ]#a;8S >< Zk{ݽ0-H
h%o4KVJ/6	Ʊ*`MĀ~(uB=G!&.nM!e<)nSiua+NJB) .>\ҸOֲt0#QrvX'-?c).Y(S%°tGtG%X$rv;&Y`߰}}>9,G9"<KàA!bs =p8kƸvM{j<L hAUXimieTbwܫ	 =W863xDS8.!a>ܰ1SOBPlxȆ!rid؍|^ׯ?u;,^h|/bW{cg;6w>r;"8qB7Oͭ-Ÿ|x0Ѡe⅋`Gl f;wg>v7b<>j`ۭ<q槍Q=qϏ=wIx/Z}|}۷\VܙyS|c}*ʌwPox:6,]?f#ݿ<~⍯{Q/[Ƿ|W綶D?W=~LeX &a6*3NQY-<<1~џ9sR2Wv$".m?DmﶙzmpDn\NasY@"'N<ǑnU1dļuڗ6<PX</)#^1 =>|6&Yшd?D'ңoLXP<2<=7lRN6?D^I.I7
Ѓ(O=)JG{ay"|;wuĿ"х۱zsDeC%&=UzJގOU=UӢ.^4wPE7ި<}vW4@jl}3Ȕ!^Gf('y,EA1hȗy6G'Iț=X-|="L,T'+yi2؇^ɞhwXw
g_>_T=fC	+E|'TyuCG[ީWbj񈠖˲r.ڟnS yכn%oٸ-^ntm#Umn t\"3w{S,p;eAUٍ-C6$[QD<wʷUƊÃ|(O=qMM;:%Qxn`4&}Y0>mN!0BS|e4hp
l+5uz6˂xl1!u,tAjJa֕pd[:qB/P]BLF~xڅG8xҶ8<tF<
)f^<p<}RBjExD?2c weKA@0voDq8q(nKVtq]9ݩ@[7v(+ڌ4^m3iD	%<&o,n'>cH7wѯ?yq;⁓<9oeRגh)C o^]<&xSOYM'"qRBb6e!_f|ATu.]\w:k$1ɺC9?rf<pV>㕸;~2%u7\*|e\<DŶavu3w<ː[uź'"&9/:? vcOnFӧx7+@Os+W.+2xٲ>Rd3VoOJ䣮ktSW X ;@o0^rZ@gIH( izLfRBeqǦpz;0)Y˸A8鄹ۛh2y_ɦfYƬ7$G8qmBUk a ^>g)=u x/eMpaCӼuFiҗs`J#&}0D^7樎dخ9e iN&a;)umWnN(ꪰ=uI̷6MOpB{4R:`HJ}$F₢%-bp3Ct>;@v͜k;TXrƿlų:֯|J}97>P[[FqִIM-ˮ2);Z}ɰFuJ^_Z>! v*e5<7m2ߴ<!4v>9WS-'B`Yk'
GQ/=O/%d\#BgӤ
l[X%^_>>8JsIזn3u=%J0^JuX쥎y^mc1DC(V>?J9,wSY`ߵ%Fτ>ǗVӝ#G*@kQ\^ur'w*_~oܚŊݝ:Pep1FzJ>r"~x=In9?G7B`Ͽ\9| 8XDӄRMT39<,?7nݴ^o?Ʒ8>0/of<6f倩ub+y;zx0];o]vݻƩo'rGf{ĸq6x)n|3M &, {7ޛ'珿77gCc<'(|7i_oԟ}|׍oeRyox4>_=Gn|k*(^w:Wƿu'~}|O||^ixx݇}xʛ
6mSI}^wUzy?c|!k/&n&lHcw+uIu$LL4ؐ9yrGwmn|ԟA2.D26A>6X|^xYy9>rv[IIۣm(O0N;rzs1dX~L߇&r;Ics	aLRzN[ mnMM}2^}D?@?Cھ_坴 js);|*P2,dyųl<5^ ᒕvPڠ?¬!:Oi>""yWysW=,觳V!o$,Yp<<ܺέ;ArI'ZDOMe*gu_*.e0gy7\7`	8lEQ|ٚ<'d,9yVPJxR#9 Fn6o;4<	{|}^8R2v"o5șlȳ#e4Jܼ>
l ctx-	
ݛ%<еl^\\9MLf{.#0NFHbw66$E	'+pI<~t_6sD:&<7ݾ]s䅊aFkrhLe4Cnt"b钾?{
ͱMa;~ˍ[$':1}P*ҷ/E'.		܏*yrs^[3+ԣ$%@'kQUo\ɇdC(d3<D;'Ψ?unrzK0M$w|t5ov}0h{{Ǉ'W/^E9ds	)0f0gyGr	ѩYD=7xluy=fgsqRܜqA\(WU]ױsڴ;5r@\L/_,4|P2/h+݌Y9,yяDȌ	Auҕ&ygU#<i	-g%tL0Rhs	
ME8ޞ'#=f?(ٽ	./XŨn_`xyϯ<&6?)!yQ(z[^Ӓ/8ѕ-yɩz̢.0v'e1Ate-+IsBxϑr|Qųr#uÚq{L~4їSd*m1$]"kȖ:qRz7nK7<#ܼr<ı|Xi߲G	GD|Y3'x;a907oAFQWdʁ	s5%md;~]O阴BGnQO9m>Nzn%	;wʜ	?{P!35SCxM2Q:o]Ȇ7Pg g,݂w@Ku`F,Zʝqd>n-iђ_YC\y}#qpW8s3gm=AdBt́sKPN 0C*C%E^<UY{]8C4'e?C֯mOommh-ίӋ-Ч\:
2%XCY3CZ@{Yup()ufrquYcDpB0uMB`t$?婀%)A^?>MsC<5m/G6b˶O3ױ\5fGD(X}-aѨE](Ä%XL< }c<O:gA{AַwEqpq|mDhlK\3/,]v8 
牬h봤A1LH<(2=v%<e&w1I	 oh`ILvN7dKZm&)/G2vOdWsݻl`k.^!Ɲym65ibb"xK:|qM?;~Ͻj|r.50ac`blŠ>9G	4#84n߼p-B	G&!u>LS>@uL:n9XT^9lJcg?GǯOå*ĉMCGp?x?w1Cp'?O_|: ~k|q]V<_#EЇA=Op:&&L,!lnO(h,b.\<Ν'"iuL1/R;QHeD8ax>h_3䎃kWx*p2v al8-⋞E wyssKuUy%<QA{C/޸Pp'7yUlPo޳𢼍<8 z}vn}R=R$qŇ<+RX2٧Saolr=K{d4Q/?yJqKfL߈.3:E6wRh{Mݰ%6gzA
 ~)Ɲ6}ʋ9].[Z|kF'?]oLNaT<DP\eMG,\߽ET_!9$,R,mH8R%`Ez!ׯ׮ݖ}rm_^_`7W36ⸯU& C>Kctx|oYQ_Sw#v/|;;|Tt_uU;1'sbBn:/Tsv:p+nqږ.SҡMW!6mbU]>>:PG:1ʎvDoܾ:]ԸkSg38?Y{M( cdљ#RE=Zfs.ׇ6TƥSƃcWP6J[σW(QxoL|ʭ\rژ?OoqC결ӯy=e8w8w8sgsxs6/x>\".u\zaްG]#P(?uf%8U4o*46tZ`GbX ]秔L 2P;etA\PpM늵:p2⑍|KR?yj)R.ǅsEΎ2sqb΋VOkG˼Pe~I\Py_Py_/2|ktxOMNϷFn!gּ37dÐ<`~ō97Gg}lW;"ӀvȮJd*" ?Hn[7SJ~+ޔ^9\asWX^P{<wajϿxv'.Ϫyy36+ntuR7{ͷT֐~@a"OL{G+!_ڿlzk~+Ysc8:&amyZ^٬g[?iy,<O[fڕٴũ`>e(2/ڱÇ=x-W{|Bѧ_O<eϾ|<>w]{Rf&]aíp;,3d	ֵ8gohg/)L'7b6#ٿIX	2͗{2%c礟8Zifyl9T8NEL殙klnmm>3x츗tKSiW6lex'z\pf%s-/!@8uJ32&&_lZY69eb'mcAU>à922LN4.3n=pAirRFΦaFEn.{Ce.L Ra.%qq	} ݒ,n3"	A29SI66885aoOv%gu0އZDD<nNaCٓKW¯5L>6ղ]y$Q19"
Pl: ?Oq+wlxLJ{	I$Hq~dĹ\<,hp|o,|-\:{jڡqOH03`њd0&ytĹWar˛aL/ܩM R85h^X<KXx>O0)zIdE3ݵ#rHf*II/i~}SLlXzfK O0}{M<-(C5rg#ex#zŤ:l@kB	7lU8$a"΄ԩSDgazW!k:~'>~	~u?_Ǐ|xi:Cm|*׽߾+Ư16#z<w|SO?S'l|+獟zO$}*sQX:4;EU-v,ps=&xLXau:$ŦMU2IpDxbE0QbƙBBEq;}bLNZO>94#6v%^$~U[ׯtLZy]@N_?q\` A6#UaCUBSYa&#:9C?fP!ҟ1f]wBӆp2AwOx[-w[],d]
W7~aև.
Ϩrt>/s\c~I|% .yޡOޏeCK^=W>`SJMѻ`UHOu/08]8L0(r[6uѯ~K<	<`zI:$-
 H>?ftBiY7	D?;'wQ{|]yZ<~Mʭ'N;wy.jcF'U46&4n*MHeM}TIxC\O6^7mߢtZ+'^#I~$%>el0 iK'y(#	0])F:B,[!ޮypu_xy>!,·pR КȚ
|#<CiI8N\1Aa7}4@Ƿ|Ŧ7ʐ]rg4\ZFJcs"A_TtA8Ux[ӏ76ȃTmqyީ=oW2צУ<ęq_ͣGίe-\#	MzCHu<1'G_4dR#	2&U䛀@ϛM~@/w@	axa|[8gnsО841m%X9 \/g,Enydٯf&Qly5z<GAKR"kFWyi=ʃE+zBenz_&x<~2 <,f^=\%Bq
_7	&t"/|+ǰHن&y\3x7B_ejTNiԧu LT
&׌rA&8hB[ZwJM
Z2ʖP_mcXf>+W=kA=c^a{,ksvz:7+.f
P]L	:
	oG"u[1|[H`Nq.t᧟yF0%&-Ubúo9O0)>
G-mX8cxY7TM@STK}<1G~dv@~]̋xr鹁nK8m,snAq妳/
O껽Ffʹ<yuWng0'6\fPM('uhcaʈ$9kP$?HxNzNX"4eikfN^+/e2C$t,gfz?6Ü"cBoq[Bj̘yk	7|(֎j[|Sk[3YSf@ҭ::h
jVJԋR/aYѮH1RJh"g.),ֈ.+p&|NԠ5@T@ErK乑qS6s*~@]pKi:n=]t,K
D4YEZ	^n?5p0v	h:l87g_3ގL.}/_}Gفu>? >AzT3OGNC>}Qxg E:GXD&)Wxi&:j>NPj,lH$1}|Swb[Rㅳc28LZE 
%Ձ0؁'`Cf&ږAd>+ yόs㓟0䯈L}|7
{n|DuM-^^0!U0YsFF_A>-ax;'E
k>ڋ/SC>@.OyV'zC 9Yz06{X0AE'<b	@O;FJ'^>\ӓ\cwwNxǫ{1
 6(rPl6nJf7a!MY˖ܼ~CΜf:Io௟·7D%#Tg~O@M@ƥKydp<a	Y<%,+Ix:g#:n0)E#KWR5XOڔ5*r@M;w8\ea:&yxWung6D!e=zb\v%7N:z
ΛǢ󝕲>V報NrNAyKcFyԓ'ovõ[~2+JFS&~e omF/ʘ<Cύ!H~!펍_m#?7Z<.n;=^D>`w!@;Jd3aԩ)܅=n~YBl(=Lv|gTur+9`>Jl1\"N="~ytd |Fl
 jӔ'TiVx9rK34v^PPBr*S	Ox \>7x֏r1l):dGVx',^C=)NFIH?{O~FMݢVN_<8)U)_R?	AԏX-K.tφ'S&5a.¼3Jk`o2_ʷE2JjÅ>`B2n&m\&΃Ltּ(LI*Qe'~/^ݛ/.7%'c~xcRaSO)o4ft:RGtO<y7{~Jme$L~8Bř`~_x2$!t&c}c_(ӤNAMH_pԿS'H 9}D	!.k(l(29.G3XHIءD!0sNoa~l  vcqUuXr}Ti/uC?ύчHW]ssD҆B҅0䰟}u0df@ncM"Wp7.ECN< -t qG	q&xI#3+$rnvt5v"=xt.<Ӿn1Zk~vXox:V緔(0bZjHf|s:IMgKЃ&sLD%|*Aa.DnD :YrjвV8[w&3#;xDu^Li.Sī
#tP|s '휺KmD|6LMMʧ*Z7&@)p4׃}""\~LӅ6	ں^x`q	VÜT5\IfXo 43C>k%'u'e2-?al:j]7pјx9+#_8"2踀Q%WOP)Oq90ւ`=..xDNӄfe`H3Òq.SV@8Į3]OKW|15KPǋ.A2Ҝ,ؗU`Rנդ>UK'3d@A}wUA3P1 VC:<NtޅO#CFr'7No!c$;Nؔz'i!Kh]7`:pxٸC6ztg!_ɨr@RLݥ=+Cc
pWEnKQʖ Ii&O1adX8OpDUOdCKM.U9 Y$1`u^L
p39Z'Ur?;'I;u6qy2dq.MMjHMѭ͍qq5od<pR);Cc`Ŧ'
Cέf^.T&p`ID$ʛyCUu׮^xD%?r:0*Yt-;mnY(aC|eQۏgl/@|t'1Ck>y5w_QLZcH[֟rP7i^Kn6b&lQomPwYrNK.j<6o9m2?HH9u[:#5]App.K eE\dF70Nl,_[i~5jw<IR>՛ZxS[<v4Oh4eր~B?O?,,4xo	),-ZMtO=K(k6|q8O ^r6|Yo3Ku)Gr8'6&U<dȩT5Y2;^SC_B}Ku\a0w~>mˉqo_~H}U:®ҕ+;ẏLJDGeY%}QNd,#yVaɸAfz3tܽ{ ?yC'	iin퉮h:܍[J-cFM	#vߊ\S!#e#~Cq@L2zAߔλ<{9`"[S&QNnMerCá2xтN0`6k$<zNǵzd4tB(!`
WMQE v|֥ɢǄMW&mpi_9i^̓8r~C&:vūC˥W\ }xz>3 X6ťXwG'y.U=U\-7pK2p}
8q^s[w6w8`ʫEkkW͆u#CC.<Hx>-7>~O0''Q$hd:CϤ6_"\c\r_-6Ϝ>'j¦_#3aç~Z:w؃83\|C<2e/{zyi+U3<Y?L;	1':Y6ΧitA-UE'(N^zx0:>|c".9X
&z55^Ғ,S;e5KQ@WC^eao24Up	58#܌*-c]Ǌz'T$i<y<W8~IL:3mt_ZEc
M_@aNI`uyC6袎j濾G9yݦ|BD#%ˠsH蛺1W٬KΟv~-Yl3Ka`萑;M^uxH@0m!cTǲY,9,Ls?FbmM{wjB#u% <)N`M<]}9dBNNYBxն. @?ZqlvNr'3xnhg5˒rz1DjA m
ŗzu.IO1'`N)\piG0+7}ΦTYyxln~e=|*Q%5rk*`
8%ȏ-F§r#8֚p܏U
&ule8I$2Sfh!q8E\~AER`mt^KCvhʯ#N>Ū[\`"^*i	f	y,CᓈQLF6Y@>4~K |?.U>H;ųy').qd,U!#wu{i_ Ahs%\luwT2I2؃zau7м{$e3ik(2i17y Y/Blٽg͠*mkEj&;b3(aLLl\p@rK|bNso`@,Jp'W_yӋRÃ gl^G,"IUC'Aʃ4c@!*/L/f~D6[٤O`R9((irB:Qc/jOY1z%.F<|<3/c1puo'duޗ;V_][L<aWElgN"oɼdƥTS6)6oToFPUfE,۾^:&3l$7^diY 94/恜A8Z/hi嬿E)6HyKۋn>*>a,f|ǜ~0$^N9LbS_	#H~i xOBXlrQcǤOB^r*܊|wrk.w$KJ_L<6M|@B{¯vN܆[%mںP'OWݙVr*Ҹ?.^l]fL;KQ3&o-ȓ9D$y;,>Q29Ɇ`I,o,pKrpG(m/&ڐC[䨭oh|S>pJ%Ԛ;D(	S$ \o\B-O8ٔ׌eGo.KY ѾN5QqD=HK|C'>'v14}	RP/J&2K[4յٰȓ1خvz_=qM}KV@\lpV\)趽f{ax*r/w4s\ː913/o&\z}BY)uEG܎CƼ*&-CL{,8K8ZfCdƖ.yt}Q;yuM'G\lꎔBqLzj0AhEC޴_eɸqKGv%?km-m.iw\/k^BHa65X(]t$cŎ]-ϔ	uҋ+e%a
'Q:gՎ} |.60gs&v3XݹQegsk.w({ _DęmyQˆmy/C]6kM}T[^ Ç,넧6EvO'$mS~W٥c2N5D"b 6M'o,X]e"spF$Ny@Sez:o?Y|,oS_ps'}8ZǑ!e#e[k>dEO\w8vܱYajw(!/ǏW<U],TvP_:L5wn80FW0W<+cƬ~u<!7XYFô?%i71q[94\t
ŦCO7ocBMɛWG.ծp2ˍDp҇?e22o^[1Yu<=ch&,`~v5|CG#olahfOyI:a_#\/2Qa 5}qMi2H'=0N/{W.Jo법+d\Õ4UC*s=6q+aវ-LۂI% 7/HmݶDb?6P4EL(b7nğ;ތGq{Ήg|Luf{`Z@`10`H˘|S^u7lmp07SovL&r10q	-aBSubڴ׮%6X|c
h`YEE\ڥ"_bN{U^Ŀ4@#1o-ӛ3}K I1^+LŃ'"Ifs~c.wNmnP.F62y)Q6K`rYF\3XB.Cޕ_\O9nKUtmzml|㎞53!X l_şVq~xOq?,[K)OϨpxS`x@OL/?Llf+|)U/1MJ5J"ߵ+CwfS xf;<.&vl(-2yţxr-	H('Oy>9Olng\j=»oUvLO5q٬ĝ<8grG|'P:͓ L)eC)wlKǥtŒN9l"O͏CSFdG<x2 .x <Ή.8 ʔ~jE"y>?tN6<PUR a	KСK4܁48`RLE?|xWr.W) 9 xŭHb!Jn]EIQqN!mЏP<VRNwpD^Ƌ9MS?D^O966?<O"~Tq=ȝ{{{n'l5x^&OV>ܾQK+,Z8.2>ܐq!QqTbyݸqGGFr"?|pG+U
Ov]CC5ʈon]p6m1z[R?<ťE	ɒ0t6z!} , U:Byi.G#wګ'|s9~=HpO"fE"#=^s\<|XI2\lno|
Cr%SV'w5 _PtA a.8&ʶ/pؒ˲t95~^yXq)Wo/7x[zoLdSMoTPGVf7`6^fEgwh|Te4ʆޛEĳ?\˒<%-CKY)!ʆ>f$Ň. 	-#mhS<uoklnd^<)Oe$YKNU&6A-oR?sw>2ōSnGjH$#i9!K^zJ}fpRIdrO/S~Oh7:e̼[(tH#2yL,?z!bhSp?qMy`>M$>QģlRgi4+(Cn1se٤lo'S2;yHիW.S+nxĸ=Lq86mʬ兹脴}-zC<iˊ @l҆q'3?!=%.To@e:}@	#94+L)?zg2F}j6%hQ)36y	eh3i0?ikWV45`3l'BBU{0;qIR3='&k,pL\Nn/<Ma-Q_L[@ة̭8D [6oP1H+L+iCmNcdIOrĩ+nシ$Rӧ'_J<~4kca5eMDJvxRȲ´ Q`mpRƷ|{bǌ3Shr,1Eo^򛃒oʀT
[m̌O\%AgsV7Lib4K{=n&;^l5DXjۨH*% (I4Ef)KEb`4	B3+4pTqx&ko/~ޡR?rEWdG&+E[WZ	,,,  $CGǉ']pa,'tB˂~ lľ&RqoZH+,
ozI3)JnriePU4*DNK׈5o_O)¹P;_$MwdO zKs: X Ű&00{4+1IJ5L&	3=&+üv#-w ÔD56xe#B'F\.u`>L٬吂}裙aBBP3m@Kзf>-tU/^w8a'>~"}Ug6Voݼ3<Hd]fl7`=wݹd 4<&Ll._ۆ'#
&91igSGM a!&de ק%)㒋seF^ 7;N
q;滬80cs-QБ40/	Ćߍ.ZdD'Μ' +n@lߴeP#G60HKIlv(i=1?3'QgE+f
yb>wh#--<Sk>{Ç$OMR7Pċ>P!C@ß3艺zC 0i'VMҟɉ x"9iK+z ] f^j9mFz?-=c48lM9آoo:?uQOU/8?GC%^奼M98Db}(ν;~Z'^w
wѱ&Nt5D9<#ԷfsN}CvO_"<ޠHlƤ ݀rWOg9ɑeR}Xಐ>\,u7c߫%^9Cn8OቾlT~Ml~ꁍf@og^eM=m[lLnw9dC.$Gڪ8}ʂ|zÛpZԎocL5|2JtKc&jbKX2i?ݎ)?q8s|ڐ?(g6ȻLbh:t9̵S:mwx%,<{^fv;EJ?<d
6#l;ߢlڶH/^StNp)7KhqpmwQ*>2?Aa=OEn?%Ib+o, =ꄠp'/f9c+@ߎyDbNica鯠4x$prwµLel@Ԅ8DYcf]reh'
/z̠]2ه;<qB̼єey({QU=;BnjgK!ZԡHcĘt_q#Mi>Dhh}JGؠ1f}P1tF_nj12|mlprHΧ-aQ@Ṅ'6Hߐ aI2qc"(y(%y[ҰL2w@oiy\ؐvd5\)1'\qiCLlxyPPg#q$ُU ri6bl<.<0ݺ(')MTe21>\tZiΚx$NkO^h<KU2G.ceeQJU0}? 49#6j~5ѾUs݀LӒ	NCWp@5{\xpo=!Īi
'Y'M~C"&uX97&cX@	-I"LGCm:;GSPY^<62և4rͷ	4=)ǝ{=/cå_+8)8ٚyN^I
oKmڿo igmZKF.N%[CN!WCV.d$-Ʀ<E7@BV½0Z8&'
l9^V=2  (e!njlpx5)o\0	$GL?!J>(clUFA$n6Țfldx׋axDX7Tؒ#FiM㭮ŗ_:]ʀ7$dHM/PL(rLt!C{^LW}G@[ex޵+M2}:lLEwNxKՊgS[fS ٰflPH[z$6q6rg.8r<iX%8*qx_:ߙqyؔ<<!u|cl*O;'x<XҿǻM%^rq_zrF>~u\=:C7] +6UzO=Uqw7 Wr;ܺ5n\6m2Oh8w+q>x- m\wzʑQ/Pꋟ\Ңu@e*CE ֯_SA]26Y	#\i{Ӯyrvxʈ.<Q0{CǕW@^OJ]!~l^Wܢs?dㇶ7k49P6aspwУۇ}a}lrPOsFtl	-tnǽ6]@9Q\TcJC#ؖΎO/i%ȁX-I (, PtE1]՘7TTe'ܑ܆8ɐ\=;[jiPy"81y
2w/)V7v:P[P7ծܾuO)PhlDsñ|Um{#8R`hTy\ƭPNvu麉?u4vp<qA+~FqT吪,+y8bE SY%^!!-Z`-xUR,0..M8hFm5queE/Z0c5p6t-7_Wwuiz>C5GOGhCmܘ[zS.x%ʤa?48Ir~Re5΅u/;u;}3 3	7 jN̸.O:cLӧƓO=i]9}qC`hNPqW;pB]88ό_U޲+ z
s/h-	W!ܯHᴈ)d_ W*疑$kpoE<5c@lT8c
0v+|r2nC_X}Wm 3gvoIҠ@_u:-7{ڤ|m;̮CgWy;q W&nʽjƞDl'Lˢt2}QDk449 $9LƑFM|*)LtM6T )ALgˎ!5Cfn6䑶=Oi"c[m^ifbb.!n }m/)g-"Td#&| ;䊖>
+ێO'+]otX:o1oi qg6NlrS!?%>.ex,M=e~d|#N:umZ$<iK~`%ߋ$,ybKY[MIqO! Q@?QC}O9
h 	WL?}i|??>CA]lm[O<VpuALb/6V&,q'VmsR\j4kMX~8ɧ>\h1X/	0s\n6cyNN뷓\$pb0CsYrm\úp t# 6w -TG>_- ^T=4|sxuքZ=[wtyMdǛŘ{RW7k3	#_y .; +qo3KNFT$Ecm 
Z-&x\ʃSFx~bF=W2֍^6pa&!eϓyU:1˂A隍?-dy z̈́zlrGItkXyAb ,RG,Ihɶ}BDOyzlزqGg^p=\H{ykscl?&rbzp<T>Xs@ë'yͽ۷Ɔ!	-VN#Xp*Mtnڶ-<q%m@GqhD|(fC>+Ecs+^֢SRN#)}A:(iZtyɓ0|SKbz'6)36]7T~"T
ߔ嶟B;pzy"ă'xws@$?Y8gݻ3nW|t|Gj8倉C%j+8(Nw_ݟx|럸mг,+xu;0bS7щdI{XLƒC"d<6sFrss)lJR+stCuGFL7x:gqMVD߄Ago4);ٸ0i#:[}ԗ)A~>ҶcYdկ݉ͣI6]ڟڼ·OjQb ڠ7+R/:KƏl:omNu&oH=V(^o66roT)vņ6Ok!u~$5-CcOyc!R/1i ~O".P< ~!>7$t֫兩z ² o	H% ;>)'q?Se
/{1q<>nd/QxA86ƍ:ȣ'4&^umk~>&yVO䋶Qc 7W5Vqġ:2d a9t It{9(<P9dA	&E#]3@Η2`&̶BעBЋ/΍gϏg@|3(ȷkͥ/ɯqMQ[K#j.%Z`o2U?2 4.C,/C:ǈ2C ֟өL=%
>4cԗKݞoFs@{ō,AonDbŋ'0>RJ_evj_<~Efr@; Ufk +~i$C2!@&t11ڋf-5Uvw߈Z~b~2i=Fl+C
9Wl?UrN@}uupN苘mQ;mK^OE_KGgd1nDū|8`x9*q!U\dm9WJ3ː/zJL]:Km_2 acR)3EP6mx`DҀ*Av)m6iI00ue<;U2*GS?6,tۭ<!*# )"?_8SXM~ \K5,S ,Y&6Av뒿sUFe[P.!.XsH/Wހej	RD]XJ˲8bIW<nrL:<r/Xg"bO~9$?:KM:ԨDgG
}9\Fa\~砸:{ջiy!M>Z!_`Sٙ_w}mBe7ȿ	 K Q`4 m=ױ5^b[9.%XmfMjQ\	W`@dŠǓ Nt- ~yVl3O°6In)GOXf$[:$6Jw玢,9,@"6[gXtvVfסdjԁ
ݙx_Hp6階kC\r>+.3G8ōˋ#g2̑FxCF%s;[@خ9M<%"q*}/Im6	4η[U:b{@W1<]t\t|OI1nRW"#s*O]OqC(o>-!GtmoozÚM$^'wwؒ,>RV*0 r6G:6atzB ; O)"')/Ai:Hʀ<p}>wq5GN&>⠉7wΜ9#˗%[4@;{2exfm%AY:㰄K?XO5xPAoQ<22?+t;MqC?7lxqb==N펓ON<3DZL*ɫ{㟠il썡~qAar@Á?`i?n!<B<m7Etڄ)D-|n75?0<)qHa3(+<a{]Se|W/%1|ǥ*>cx?ݽݱwrWe3NlvdR<p)?_.w[||CiFy|CuUy#'
i$̢opwI*0let.Bu}\^H{Sh.
˄:#9OۼnKO&ѴWM?2CV/DªuH7j1QY6mv= eQ	8NR<Hzhȓ/[}@~krUNSBS
 \wӞ#:s9UKgeNl32TUPvƤ<OJآ=خ)~mgErssnsȓ5p\m^z:6qr)CÆCNOr*MD&~-
W |xV7u#eieOϓǢ#ofџ~"-k*2w˗gÀ(<N&ocTcp;`h'ĒTTFY@V K6AJ 2qzls4e-w"2e.3d毋c3/^pBʸēyڳ.9'0ē'<e<u)[e
m9+Lvvh!Rq`Ǎc2@k^irVh]m <CkC26*~5R-?s]OjwW؟x|'&Fܼpvhr9S9b\z.\ּE/&`\QǦlj~ېVI#zrQCvẍn$E)L|Чi|SO<&1I@f>DiEnabKNy2Yq_<{6eVdYlNu<>f6D灵̷x̼'VȓbqA~Y/?i(^m#?L!;^^);O0Ng%AYx6ٴ4*rw[Yuz2}!LC"kg7Z%}!a}[oTؚ6䶁ZfȌ]JנLBto&>cUo9)kL OP50)Av]9ĭL{6f3ZW46|i6]c집6_r^L|m3:i]w
̪caGJoY[kdZE{|?sc\:4%_YhXΣhm{V}Kp,lVKKXX-PO2yq	{=eX츖%ya)AnTK{>$!ԳdVp)ZW N"no R4	@m&m7i21]
JD\z ^z6Vn0	bq?C!/Wx-5w;QuQ' dIA
X^b	·by?Xk<QPa)ec%L$Oys`;dWxBDس&V7(7<,@EZMgB!Z^kW៉%lP?ؐdUiBs8O0Y_&_	Ȥ##s''JCaMpȦ5`9YqpA^؄޴+x}ή+Z%6;~<x*W]zH{8^9]ؔ-n% S|2d?d9h2qqi?k?[m>9M˿}<0~G7/~9R>NOC~'ob+'x	7r=ԓgO?xeόge/e?mOǷxx٧_˟/yV؋mgOHoo∧r@BmmPuŇQGo4S≕?ZxѧAC{NmQaΨ5l೩zTn.MqqU5O+uzx"yˢD:$buTm?ъAA0yIDra 6xuCZ )`q򮺽bR?`DJV8XYl|ϡOoo+\n}7EY@S@
֏hG\o;s;9Ӽ>.
Denl';yZ%m:*{)M߲iD]"woqWqո+߫~[_qI~SWZX%~u	(Kw11Re*^:_$~W
xn}eC7n]\)_
4~	l>xl-/-yG،>Q{asK7}`=5t&tiy?mqUSn+x^hO(>n{P틱;]R?*xq:vCuwo[wpI!O<5N953gl>MȈ4DCOހY~lxGnT^-CHPS\/F~p^^HP-Ζ8:l nS̻(gjӊoԷx{yeο.VڦS* *:ڠ7ְmOl̽wgE[߷39niQ0c&9s<3c&(ETr@C7ttw{mDܙ~UjժU®ko{o'G#W@u<ʌenC<H$kӮ6`C3b+Lʖi
\s	yC=t
n0\oKe?aqk0Zn-ܽqBG<ƶayh!jc_ulW5lRF6yڳM-9'>ћʒ22
Ỉm4^Sn&aIQ&:r^T|,GYGh 91 MT8<w$H#d %4FR#s	Ï1!62 ~lc{#]Môi)y; څdVfdQwAi_B.֡MwS&6fY/_kX~O
]00Xl}cyǛx}8@Pl~'r:iT}<4erDau^lJ;v{nMnֆFz:]vهͫ[D(on'MħcWԭn]c7߲c]fR-dG(W/;Zp!P$CFW^Prueoq*޶q[E7#MnlH;iƅ0 rtMtm@+'Nv#x0thrXg3PNܪm^CdqCʀ=Mi;L)\*Ttc^[Du4NC&30f;hA
A.$vqMppL+zK<hUŔ~Ӗr}I)؞Z;`Ր :Ȯ'J˂-:c]>/ؙdh-Ó,f6LcvXY	;M]ň,Tv EBr i	'y|2$_^x520^౿b+g0Dxp*ԁLnlYXgA|3dE%<+`ѢEeyB+tMMr3٬|B<_I};:,P@F&+>^ehSy_nӋ;n[l0P6\wq53f:Ozv 3!uzy9zÇ!+WbA>.g:XY'c?UpzӒ=lr+ζѕ|1ebʓ+VFh(ｪL8	Ħ')FmPhדw}uęyv]*ݺ̈́Ãa噻Y8ƛ:Eիה|tzYDbAq}Qw> 3_ny{@AyWV^>8@SezG7Ke>E,n5/YdED4Im+eXo<rWʞz~udӽbBCe!i&95ޛL_qQНcʍF+}eݺ>y}G͋1Tv]dh=w?`+nJ:fԾI~vSgXՍa{/1ok6]ao'oVxZle<e5k7ͦ%'IboGQek>i٘ yɢ.0T:|ߤF=w%~L;,kxݫS/RQE6K7\_C^X=<G:=6T݄v̽{.){8Kmvxm+73^pWQJLyGYνs$7~4¤wĉ?^Xfmˡ^0qUaqɁyVGǞEU!#4űx6OL2e^&:?-V|1ϐ>l2Ms%u&߱#.o]?=<5O2恌l䒞eW]%w_]{G^&X +6SEZ/̽tV|_G| x&qPhV{F\jha[Y,Sf$\qty3e;+I{4tFMImc^rUb8sv^9j7GGi$nĥk"dDG2<Kvzj٦]F?֣0X@piM^@>Aq)%Ӫf˺,]<햟:cA{e%x+OͲg	'M{*'J76}LueE
޶/7t!=CziY:DZx/ܯ6p;,+Jگ""аh`]v{ݧ-iax<ƴ)Ԧ`kt@]1HdUuպҤmԾTg<J /\MsX f|pQ<+B]v6xe|iUD.fDi쏨 t]qvU@ǕIA?4&Uvp\ԍThQ~ΙU:k_u!ȈWS5cR#];+[SY!C%̺&W!z׀hENQcyM!VeJH?3`H#".;7W~V4sl]9c0ސ퟇Nb\eOi-O-)׹dWcCC8tPg'zHTԇqO#V.xXSn+}ͱ Ĩ] rvAC76G΄qVPQ"vN$|WT.?F3VY6v(7̈f_~ Q0ݨw_8<8P&e!@=NC$71ThR{NwW0
#ox@uQ$:QdCavE!i]'6u(#1i݄[GT>n_5$ǯ49<GD?k@:;9;r5LVk Uv:bĎkBvR&"Pa]9ktYrT|&xL6Іta0@a_y_|m_/Gk9=[zCM)GS??012Jw~GoW4|m`P}n6^.d$r-	d `!;Tw܀Yh	 b0Ij͖LxF~uDCsTj`0Q8lQm/~rW͟Ma,D8Duq|w88M'QD=vhk#g\<_l0~P:0Gtl1 ŹeÓ(cyrYGew|	ۃ:)ݫ_rSSUoP5=`C<\`U4dea{:i$sN+ƌyԃRr7B^.<຋'[l,S#O3`\'8@=Z|(da77_Q./i'l6U'y2U!PoWA8*EDؐF\'(ta?A$nVL~Ǌ2u헗`˰,'*=?7[e?贉OqE3˄jg<r媲Qu͇t6<Y }loE[ݪĭz2Po%]Uxo(Ɖ!	d]D≎	.m~ƯNLo"2X]&|zeן&l[L:e\`β.9x72V77lp:N?9NpǡPll2m޴,²1ٿuB2KL8+󨻜&D uSLWƎu}ŲUe~uk8G[,JϗC^iވBEQ!R㎾ed /2+_rćTx	}'7@ySowyNFlv
?<tKj<ȭg>/+Sz฾qC<뾬ܲ/xK9q2{jI/*
y*W^~Xro9EG~l09my߈Xl}Ă?M<϶C:ˁ=>#Phx QN;M֬]wF]~Gn`*
OrglasƬM-rBl䅶?Rm-jx|Щr;Uv;Op=ߖl`HPm$6hWquy(szA:2҇F =>^|ӏ_&%YFhDArWN?.Nw]UyrOs}&	}+W4pO^rJWY3[r|zl0g<20f2JW?1dg|s(6I[AOfC-S4/.SxoUxsB{%3ȭ6˘Kc%I%,e|{m>/H@4{76iwN87tȻW&Ng&p'ӂp<9NY{	ѯel!mG@M$G_>6hwit7i|jS4i,C+	H_+Jy]yҷW?H#=	wtO<>hw	CȰDmrGr2CJ󕧃;((tHy8 6ȺUs$d7eKȭ&?A,qJ׌[IGHm5ǂ˶45dqؠ;.Z#-Jd;MPEqmh_Uc $ԡmD^p 5vS_}wkٕs!MhL;Rh!gM7V8,', 	"Kmj'p%ZZx^Koo7mZeLQ7la,Cm1gn	]Dmnm5uVsq%hӀnP?nF:#Z,+/o<V>l&'8,8d~;A	{A7\n;u!=^$i6Ѹ568]%K{)Nmмj:%v5l%	#~
\7JDP=莧	@IMzިYܶ;xnʮxD	Ѣ:;_8ys7i^FO\eB .ƚ>=PF烠ؐ&`K/J;Zq12L/MLL:nmFW4g4tԻ1z}	r7?|I*']m饫4}I8֟Qox~(igNw{44߰	uL#991G`赳V6l%Q$[M( 7'];Y44Vw&aBX?Ձe:藅l2,;<y'~r|Ϡ%`b=q,2,6`#Iv72jn:Z2O0߫gx>RVBnSam+e? Bo(yכXʯY[U6&8/aV@DtԐ ׮&V0)xOɳ㍘	ޘxK·Qw94Wl+q>nܴ<}㥁`#?e	v[y˼̗^ieժU~]"Ś~JH!r8@^ʰ]L*67C^NuwŊUes􇔦Sb97Yҏ~Yp4{X#ʣ^Z<B~]SU\pCoLٱ2f.fϛ
$X2_Y$=q9FBOIݏ7@k˔Y-&N+}*kC-aI~BzZr7ni	7P7Ree?D#$qIy)ŊǆKx2_1;er`3"fV<2Iqh3,{cv<'T<)O0mqDyiќ`R_.#˼|Luˍ|"'y M}L=X`i|xcN%7+e)ZpcsȆ-l~c2r4'aeJcXSoX_Ǝ]ռrOT7<pݗ|:fcݿ.O+­p>_f3
M6Ŧ!5}5ؐ/Um[9&NFؐ3~7pnV>'}b|/C7m>:o՛$?^zv=}6i滼jˮ5O#j:>_<u7U/N"1cgﺪ"pnaeL].A#O{~^BF*(9	/ԟ*wQi7Sc&C2N?Ss[yΠN5 `!!7Nh@Kry~Ol={8uM!ťّ o. Bp#>`}X__Y=USpGŚk!OrdS"@ybVSd#"zsiֻ)ot|d/?Q^0NQbcgX2ۿYv}|_n§<ft~e( hpcve*->	W{#JZ/٨1cˢ{-;>oxh#Uh&?qb<׵ܟk9-*Rqϔŋ=*_ ygqppS1o?(S:52(XZ6(<W6LFe6ʒW=+=②̚iłV`2&*kVu#)u/H|I$ovޛ~po9.c<m_@/W?2Xͬ5v=Xa%u0e3Y4y.^KGllZ΄	um#?ngC/K'o
c)Y g#*;:&N:0 Zj2sQ`\rh~)X&S?H&	3;XGY x/-UKM謗	Uu++̛ GJd+E[߳2'"&7AIQn~fU0WE)F܁P Aa]}?btOE 2u~bG8xᐁ_'x#'<P.a+|7MO<J"dX6c<GQ#~RcF xe\]eizUm8Akt^r-%Bz!)\Idlksf4~cao)7v<u}R.*#%Y  @\F8m:<T#tDH/5\("dXÛK47bSdϚxJSuN<n9ۅ5JVI^?)>W$AK/8BL?r?5y>`0]\n`G}8zr`ъr_/8h4ty_O0I((,)cظ!OX4UX4r	aDCU,Ԡb.``M6I`&q@0,=5+T=かOUqc8	C6aG!&:oL:̓<! F#,x) ,M8ѼH8a	ߩ)fn=l0l&l0Z^[U5FƤ+	1bظaCY
֕l̆'`'=A(D44M>wY6lwO2/,9yrTnG|O{!\2<ʫxH9.ÿ{yވaQ]wm㸏dp\+`j.*_uN>,FQv:HZ9'JOr/s^s~ǋʴZqcǔ'~G`/S10Oxjx5s_8Ϧ'7ɥ|sG?vˁ'm2ڮs>XV︳ݖ8hWd&O{y6N/E\/2(x-W%L>4]99ýO;#3}ã7}!,/h"`e/H.߱A'Kﻺn$R{xeԛŉe+_[&:z[բWPݯZ})k|?Q%d	RV=2Q<r´L<'ϔ_^SvO/iLEm^Cb}<UlRR|ŋߍׅyOCiFA',8F>uͥor/ҲZV0ԳЧxI|ݲ4yjKYtW FZV^wT^GeH8Q:ϕ#3t]\9
H 9Tqsƍ$'7l~qK_,DF#wsnM562/g}qe!'~]'^Vw=Gsזx7s.GipIn;6TX8I}DzP>zWGe/2wZW߽!6ƫHv8	ɳNC0,V/vEos3Od{#?)S~) Xԧoz#pR7.#_'s3r)#UtuRf}RfoPS>n _O"'G@;/racWSjm(3pĽ#6f7y 2(o¤ѰA6.e=y6ݱ@5/^8}S|Y+闣yBr(sy]lQ_iϜ+VdcV#Lذgi|UߤC*6׬Y:%gd*o`'6)So/$E:X/ʄqG/}24[kv>'=9^xeÏ͙OlpLS]+&eӏPcn=ᄊ^H@ 1R]5Mh"kP`'6|hl^$SN)_OXx=\LlhW85p2ՇxHC68F9VzG 
gy̡4*\74O'R Cid3Yr4qt	|h@D&PϪ3aX2}]ZՅeBdpV':e(ܺvZq{6ĭIojHv2< Y|
 ^&u9&
<3s!n|֡.n/-~MXEc"A9 i\hm+kH~W1fn	׭VhW퇇q@ \;4I/r≌%⚶80f9$@]OlqkI&ϲeFXDOR!3CІw;@HfC՚00WF2nrɨG K)\Do/C9l/r}&3f̬JD]s`d@!@VK@ӵqJxFCa"QpHLhtF*u"&:*]dUp
`۩mLK9iٖu/42ˑ;Ԙ>dD??	AAan2LnK0H#8ހdC@R~|`¢z- %K@~[[Oo}l/Б2>t5ALt=0.{zI_7_9]kidP<=л{AF~-?L02Հ0^6Kl(V3zx?6n+/jܠxRGQ7L}\Uu'd%ɧi+n|OÌ뫡07Ha	&_A=xpf&,2e?JPJx	o>L4'x	D9P6Gl?-'?`zݧEd1i87HßoFCs tlΘ_'N95{J<,L-7\Zf\VxUƍˢ!}ބzd;cv;ꃺY+Z<zcr@'r)/²+k֬b8/{u<}֋Bm${`Xu/,ojy==P=hUy̻r05y;Uv;=y-GE Octq+{Okɬ;'^/we>2KN^헗V<YJ\&؞e>Bln0>k>$ՅZ /2s\kV-~r&|2q:[~A~X #紱+	`-_+pP!Z~eז,JUP.V>o0I|)5_ &Q|@d$i},Ay6ymߨaQ[e?T
\q.J:烞 aVya#>xx:^]t7*a|RyW5U#5.{▋ʌ[Tv^=ȓSp1fO͛WyX"|ݺM|(}ͼ~|']Ӂ'2zK$=`-ī>L)aҦO/^	>ck?.(fs:"oڰy̣>UG,sob9|3/U7RuiJr>_f|8<`Zqcy膋ʴ٧Z-)Xl_+{O_~L==c		''L,tq~o+~ʤ?u_7Ap> ʊE^ƽ?]^LpA@_@ͫ+hVf+#cǏuc*x8 BP	ȣuX@@8-?--_e7#jLXjASo	I{ؠܜftx:]:<w7Ǟe;pk?Y}:|8q*rE+X{R}N<}L94KL;fĘr,}q2ߣRǪhk\]v:vz^=9<}7˞!7_^ynC{!=W|Ժfb*N0m+#>uƊir^[UwWZi9c#5eC9;JW*tj#Y0N/$nKn7^.׵?Njn+ҲI([Q&xqJG^&fu^\[vSّ.|:$p y^m"G6-8҇<o~`7%;1 R`D8@>/3oq\`;i-Zc{g{:z?-Sؘ^펰d4NShرȶ_TK
1LyOghSR=W!=N~E^Clиͭ)3U2WݠK%+:K{${T,VL۞^Ȑ6,KR /܎|[odt_Zz2aK1×2{C/3ItIy3"C@q3= 0cn"Dސ(N"mxDrn)69n'mE]9k.l8|~akr̂t)_H ~%Lt,TNP_$uoa}@̻:i:VdKĺJ,y_ypO]خ~cH=buN_޵XAH#Z?ɱ</E$xﱧtɒ%Fz- Z/L.L}CKJ4{T9F /	Mr]%VZ%n^u=u/	I7q㚁KxW	0:$q e 6$Te2ۺ$If#+~VzF5tujG;EI;! mXSvh\boPJBM NNƲ	ɛ/yu\W㱏DPē(lWZFng&:dH]V5&+|^k˸uI/mˮ++ٖ}Y|lTFF^mYWCĐ4]{   ?CU~y}f*n+֕_yP3}dI7r#0>Ă$k(hIe"iEo.IGT>lp&L!n#@L^4vx?e͇x?d8Hߌ\&."y 8"z=$'c00x"@
3	_K|A/beD/jr98,	O-c2f[ʘ}Zy[fBV,7g	l"1?Na ta+xN٭.d1O:sGsV,RP\!Kz/O6KZ^S37x$F<jIyp`&X}NZB1w"˝|܅WYǋq6QOS֤G y.&yJW|۔'4as)Uu !~.>I q֭L(O۷[d.91vtgk?4`97(󱛾V{s	Xw[w|(}N|Alc&<Q}ʟUSL8)	6
+i.1+pLpgsȺA NivY#(^ǝ]8W1質:˄.+-g>^ir>Uye!7*^Zr߷ʢ{!ܶˡg]Yz2&sS>]{'>\ͥ_i#÷\Xzay@^T~qy<lS'+cEslB/70p}:h&`ʵev]Aue
ޛaV))+YteYxeYdidzƋC7\RBw_$\|vK߲9VlxzsZM6?rp?ys	x@as	x֋=³Pv=̲o[*ʾlk@%Ft6T>7{gO=ew~fo0dTj%4V<c*HIH^7ugqىg_񑲟~//8}&#>	ۥ<¦իxmޡf}1}_}m?M]OW]~tFґol9>>kFp7~\6(0ͥ]U˦[o-P}_E1K|)HNZJ7u(?ASw,lKcUq\S{޾w}~')ɓo+B2ok4e#>`oQ0gsiWSWza1K/NʒBNi2'^&t)z=E+6rqPm3	SNfKPII20Ɛ_ei\bð9b4{ͯb-dal1M~ۮsNv.l°A66e}8GnI,Ňla~cvy(;GLW:|z 76ܚC9\ЕpuMevEx4BMo7qcpb^a6U܀@*%?MVo)WacR^ ٬}.ay@n$H墌:|O+w28]@ Cyka*GrD5XWh {"u7vt ])J/;IsO/^** t0Hn )QT?v] ;uckxA6&d5]z1eeA<5nT|E8ˁ~y҉~C|*DNkǸ!q2Lv+<tڞZʈpGDuHz&DtuZ\*|vl(Fd!'⹯Cc8O\V{n md*  m/)8;x.tvʘX : 0o pJ$-6Q',eVʅWqjhcp: ~D	hmB^|!te;JF?^pCxL3{@
UoD]+@d^\xQaA-Jۍn֎Z
J\r*54<:5p5U/6`G`ZnA%LoQqNX	4'h8Aڄnx(,:
|U+p_٨"C-=|j&p&pi|\keFɪ4QujDaF.2$#IUim@Y鴁4b ؋(l0()\&s1iRۧd$|Sʴf"&qN;1!&	&O*5ʺ5k)cnfڵkl֯[9؎W!'8Ŕ?(Oe7Od<%̇_{mY˺^?YYO˺0?	OGx~jzh|%uy䓉t`sw\Y:׹Eg$HF%`23̜ e{y ?uלe̢> 21O/YvT<󵓞QZ}T$%ɥ*xs	*o0H8_wA9uD! @Z >&z;eYg<zK,T=tW˂.-nzy8-F6o	u$G(4	9yi@'olYpWj,7ƽtfmW//Q`<#+I'Hbe|
Pv^G'frЫC{Ѳ*vO~_KUeكהcSj}W	O-n5OyYYx7jvp=d@lXEzuaѥo2N6jߴRgmwOO'l%s:0	}WPTBx.GI]7v=C8L2MsLj7}IGקÎ}g2
w>]އ%do}YF&4N"	52lSIK7<}8W줽FN3(`1}zu'`ʑM#YHVKeџ.e7^TոчM]ƌ^8S>e's9굟Qt9OY'~ݔIAŞŉ'oV?ٮ(JH]8}Y#دV[\~䅹n+AYC?t;q(=&̃rN&7^r-0,YZ.Y 6Nc2aD S>1fmYx?Byʒŋˊ+#^8zD2cC/к9t[>[pϖC2^2K76!ƴ~o0R?WǽzYMZڧD5pՂO(OzEy]	\v>AM[e,g!>*ʂ/**#v/?g7x]\z#32S,~J*M+Wt؟.F!w_mLU^.y{#0`QQ'Vh̷TuN1QUyI:rJc(k[|87}xgt`ƛ?c?n1&"iRldbZg[幹)sO/	xS ^E<Vs׾]2P~3 dPi5f{,HQnFq"hpʈMfFek6cs_7y1s^t$7lؐyIc.dͧ{	҇ pWkmK^ǉ"^G	%;EY/M_Ke]e,#sIt zqj7- _lz< {mn@Me>惩3Oy}h<x}늌lc7d\1>=P!$8T~&ey3N>1~ո1sH-hӅX*Om*;p}x<ZӐ6hZXh97)7K)Jk7ABw1.35c|M+8
aPi8ɖxa Y%*86khUQ>m\(q5Q密0nM-
*}g;1]ݐ!}Pm,$׃Ӑ6VE}	6m+zۜ^%q!ݭ	GuW/Z?{!%rXe>(h_[WD @V}>87niȬ	4ڎj WmŚYg"t_O*/iC9 Sq6T7h[57C8{!*?lқD۸8H3J^ٞmGcpC:10 4cg$+!&u<i@?闔4FApX5NtjO7Ju8oWUtc(Hd	}9׿VTJ-n%MO+tSD2='(Ə*eX'>li嵳,a^y~e<K ~:Af*ۅ"|0ۡFbo$cDA#%#ȋpMf.l*Awܳ9`<-Lx*.5qs_W&70qz!-qVOէ1L'#->$L}
^PF_.4aLRE
|b\fo2ʄ6OwL^(O6䰱L)⣦6T|p.7 ،AM`bLXcrNd~2|r׸tQRQ`-Uy;L=.x*N6M㰓/rk?^Edײe]rscMc ٵqŝYh޴)j1.H>Rfg+-1l4W
ݣ7_l01bQړ(T$fx~9+}SM0z2fLl?Fe?x}o\͗w_+w~ËeujԗZՇpT>3:nzGZtiҾ~[w;LۄM^·Q$ʑ\@Z|U69	$ /I݇SslT"潿&,{e=WGo+OziyFyYx7WQ;m9Vny/ya}ѿ\R7},|&/M)i܏Gj#\X<ӱD/ʽIuX(Q7IW {8cl:7'lmQ-u'_#G'䦏$D3*kSG}^yK]F1]>n/ߠa9rE =hy֯Yn/hj~p=s{;:lX<uǕ#7Q!㗲,漯L	SKCw`ʃH4p9+yxEʕ},{~Us#ٯXM 'Ag?yEgl,[xa$_N<ޑGfKc]o"w_?7 ſ{>sd^]V\S_[ϸ_dqU~/?g3A\Pj_V%x,]RY_dl񊼉Oiie/u1
c]*W-oPx5v{bl,.?'c`sG5p}eѭogU곁?>BY_y=+O'ozĳ˂?}dțzLnO*wT7X>C$ }Fشlwy~_$F*.W:L;4}^27ʏIG^&K%`ɒr//=a ߢ[]CbJoܹhJҸl7K㦿!q?q(m[DIeZ xȵ,6|㇍~&Өj'1 05g</Y&Owv]ybƛe'Ѧ:eNk6X}Wzh9O9Ə7|do7獦NwBj 6
;6xu^oݿ??Q:|<@M깁/ O}`+zz&DEF.yLUxGb\w̐0 -ΐ^b'vj*N6Dptlm^%Dh9Rt7&^/D|>@A\]i+hTP\sRu1Bq<j1qRp<1|q7:΋"0$/ҁx~ UXC64H>;>~OMy
p'Oz<BB]15E`Ȅ354Ni"eѷ־c=5$ŶM1]a[8l<:Jcn.T6?cm>*dw /Gv: :86NAv+H$0?=ꎰn^pH~;@ՄqCF64	%mWp{gtڂl/xn
@4`^D'd7XϸM$Ԗ^ 8<m)eFXE	W L&iԞ-MP^Z\@jOV(V[b[󕑚;AS^ԫ[Vy 4dHR͵:_ݶ?ZL)lO%mHLw-ڊ{uD_yVqaaM@өnڜ4l0!Ҵ0ּLxǱ˱RTuryˍ{9Ѽmbې]3 U	:?7xB|0O\3BI$&m(M9h"L	@4	5)_i]<=qXx`
,uۀRN
'@GTvd'IPG?JÀ
<xR|&˄_d,BAa:"Z¡s?Wl-++^mSʗt:i4?}=qev3X'W'n4ҭn<ǋSWGzBWW<@6zlrL[l*#1cTv(j{>{{uF9s!>z@Hp4}̽{W%(\>O6Y<XdCӂTyzF
qccWNg;E_l6j5>qqQP܋$*x~U{2/񍗑#v,K߸2j2_)G+`}.(wKްC@;sC9e.6I_)'O^	kǌԉG,'\IhuHvY[]=p|89r2~XW<Yƀ Qݿb97o){9ec?Vv?#e#b0hk-x~؏<=2OɎdЗap.OiStnjoQv͖m幛RvC=7n/6cFj3髮xHvVlƷz4{C-8/N$ۧ@x5ZCcxsb(6qn}y/}g}>s^Y0R/"iE|eן/|ry.w'%qKcݏ5Pa}Pȟ.*H[»UϽ,	Տ&P}8si䙧U7S~wF=ߟw޲	)srorg
u#,nGl0Eޤ0ڟz&̴j@~l،B_,=zçE&ND9>]ew[7EmPBWnDi`Ur3vLc&sE5p}+.q=.6GJyxesW/`ǎoa}y~:"};qv%OwۛKT?"$Z6;'RO+?*ֲb?]R:՛K=cF'OoiM{1B"E1fg_x[x=cE=2Đ'S|.S<!}2#_ <Bn[N%Lg@x[W=8+s>1'`7͛A<t٦t='Ndq>}zm dU}W*ِatI@F$k=]į* at|?	hJlha"_jpjq	z6Z@"m8KOEYrϦ?.o}CC,߱+~
ul"iʋqQ1F-WuExCV?\DQt]s\V2cwqempϞqԤ)d(a\[	%k<c:/gB
<na;NJ0=p}+tb渀~/7;)'،NY";AͣQNrZ0DJ'g7N[pf #N*M[4"OVNl*/C+N*c2]+L[H;OV#ySMar>Y[m4.9^zIW# hFk;p
#ʴe5?N;	<)R::/p{}rc7&4n 4sLCd5l;?k^	6 8{dX\![	M'*E|\xG?yX{SmUT=M	gqhhIх8f9ld˅h2N4:ڣDXuUu@dzz!uI4v$	/ʪW׍=mpʜ9;??<|ӄ<\yF_ C8 M"2B	
)?"n~1#>*>nM^y|-QL@hCe\fML҅O&ǖ]6o#LK5tLh$@%+nFUW@\	d#9/0LT(HtU<|c kt4Ҹ',QYʪ4WǉˊSwmYOˆyPW`οq>Han^,z~p5WFH>[w{1qcǕcNԿ&"=bC!RGeEǉu/l)4S-;wa9u7wOoj,lN9xEG9s;:,B"[0`4Y'ӄٯa deM+5'/}O `ك)+v}z٥nxx9e֫u\dŴQ#w5YvW+(Ew݅W-99%vsG_SаEQ*UM9&+w('l8mGOI9䏗#Sw篿Xqib$»(Sf@fotd wpPt"˟{EW<vFӓ7]TW6ݎec#@Vx88>=A_!d k+91иd-!6z2#ļ~_xlr͌_RF?j[){ы'E_+=B:6BF'aն8ϔce>U}cy4go<wklZZ֚fqC3 Yȟc7^AapI;'5i?/{%2=W6OE^[&LȀt~M_͗5gcho>_f៝2J=LἪ7ǎ.}}ԕ7l}S^Ȯ60VͿ%`āｺLWLXƫpl*'=/O]FLi#LҲqidFV^U]8QɴPq̙~Uͱg^
`z.3EuxZ:_x7Fuݩ~qڑ,SeWU+V5VjeW^_ˍ~b[ƸH\2SJw/G{KuKK20AG;J\l6@C?ej/E5|ݢ{	A^||<~et/)O<}WK'ixF6	}}`__Ǘ>GIx J3myXN9i橶B#-3c*6elTmo\vM/ .Izago.;βۜi7)IZpו-cLaܐs  Py'7q~h.vˍ1(:'x5N#'(a%&6bϠUݓG;v}sj/R7X'OC'8~XC yU,SMY5NrGjE:>Im.Kۼڑ~~ۂx &2PCW+ڞW㹪䱺9Gv<ffLۍ#͘X+VUSuKs8Wo֘x-
_HcEMeIF0'jQ;A)dyIaǓCrlTj<SOU͟5ꖾ9d!	'm@F:1*&5kR! ZZ1ة#Le@ֈYɕ$'qҮgYR>АQض&Hg6iƟ~p41G4"PS#h.ikj<~Дu2jMt9!0dW8XQxugo@%
]xCU 3dNBj{ZhAtK7%	qWmjI7Э,x,W@' c:eBkwb@5~1=:ưH}̘QdYy^b'ݡjqwq鷻cwv@ҥ	hp]n(ԝXB@եg&5)u&̔{fT	vw-tC-Mo@pבvWG=e@z;M%W^2AIe~׽BYT^@8GSV@dTib7XT	0¤ :diw/c57u6TH< 7gx(_q]X'n2*9HLC\*\oK'ٗ]J5"w@m:,   [m2vH  IDAT|d=Dn+xmwO5v܁uv⭘wnZ9Uz=[ʃ%1hUvq10^x1BPyԏ !U{TeM=߼/.ruCO>ߧ 7]WGrO1E7tyޝS"mBz xyqS3I'VyJ?`z/A ʳ=k	Nճ|46qۯP/|q_)\'LW|{ ||Xm6f|X_*W<'>ꬲoK,ɩygQ/tn˛6mY(K^mw[ p6`
'WWi+H{@]ߐحC7~)C6-جKy]eO.lX-6]`ysw^Vv:L@s}ה=0rdr_z9zD94}eP=_	uP?Ni7'^dq![Ԇ7o-~>N	mwGGL;r_L}£\yC;[<7rїi,æV)qip y$HKe](0%K@lL t|4#yyx֞ǟSv;&N(U!'}C?&n<;8|Qqi5e9bV yXD7'F «L68u9.yENN6ծ~}9^GU&Mo	.2a$UF[|m╫1	]mᐷ|Oa 8t/?/Y>^7ߒ	=\4d?<q򏟱y_,{8}zv(FI+ĲbO?qb}<r㧍ZBqo0ͫ`3	 1_zoXOeL]&^*uY2X +ZFuH6}ϔCWoY6 ;>Ba;e\Q>MbI"Ktgxw_v|y/7YT^d]<~=N
2=eʜxnǜYv=33Kd]x-+6,[ĴNR2eV._^V.1,{>'8p"i3w_]!ޔ/S63}+[:Zs|Y2GQOT6F;7HgƴݠP"韛&ӿo18)^=ni'}+;±)1D;Tv>L7Q'^N>thR2/7:3ڸ╄`2ߖ7,Gn7~ἂ&iہfG;71'c*>`~,W//̧14p$<7clTnps,Cm46svC.
\W093F8^</q;i9ͫi~d7!l6;]U%^v'tȯuM>",M~	yM[╔9!-qd~Do誢$mbjSyO|Vz;^M1'nQ}	rᡑ|pu^	W&D9]X/|+l?LSu5Z8x%52q؄wh+%sI4X50oǿ	ǃjl0UvBJDoeH981<&MZh4B7LnZbO,j:AS7~H:oT;yʺO0k1Ww@>ʨ#	״2i*g
O
;Tz^:M*Yt=EC8}كK*^:`^&VI
SFX ߂FW|ďx@حhphH|&@N",LF0<>t@=ucFU7ּ9X&\5+#ișv	i_04Ύ5Ď;]KRw:X{T_rN.SuC2D
ʖeH٦\ႈb
۲THw-rb}zDV .1e|u4a\9di5LtP&[tVT 4!d;W`X`P77u5 ֠ZE|XG}7n"2;]^Z813Ƌt
wM"BNz
l2v@Q$<ŠEx`x ,\<$<7v4ypbP#'#w	SKd<`A7x젉Lĕ_4:w`<~x{ӌ' Om(cu&?9l8->brb]O>ԐwQxe,8lݺ^6^av>'TMQ|K|&,>;z"۹{+~ac p1,ڌArqLh6VfxN9Ȏ	g	pƱ4.S*_N}S./N.6Wrr,tPBDtUyJ؄ ͗Qo㐧#^Q2rʢWY.zqTft	sz奪 E'j<MdwtMl^+7\"Fo-yZ$-'ʡ|LzsTw_*aoFMހ>l<ԙ	YS</+~rgJ!l 9\Bw=2F)8{~0/eWxHzƲn&݃6IknAaT:GBzܲYjC|d_*	>v^'~R$kߌ,yxrtȇȍ%6eO.<lӈǁ*6L╕;ѧ(Co*[TuutSg[:ws9N52X{[Yt7yWo_y3H?k^һa(So0v_<uekE.0?ݬ_ί㻆lr:MC8NĬ[m?me.3k?"gLHW΅Lj<f3a$`BY7jp|p:3*nL":>/~y{dYAw=|fS\V8,XDϔ,+I =NS$dx6`c<_=I#@Th75_-=ݼZ&2y2qj)
ǟiOI](pMꨬ=`yoYOty##dgK$	Jy,*ko .gif,{6S]_l}Oj/x7Y/ueh2i7](~3'keo'Vo6Lo0x{qz-&D[ЏփPPG7m~ aaccXz{.3.Qb3th6*Q^>%>c>_֧0x
lr?yt<6v-WWŏ8 m>[}u=O2E.6V>oXD*z,/}L]G5$fn!Xa	>L'y]0>dH\]-.{?"L,R18Ά@nL=I?Fv	ƏF!x̋i"*}zzgLmu=ۗjS=@JL¬Гe\l8\lN=4l 0?eM,bCcRc8t1<dr^~+Ti`nW:ɜixt;_Λf9;76utc{D8+Mcչ>Go8O}_}$n+̪usZOxtzpeFDgU70(;dbHF>7AH_eleOlvR(sϣFqWTOMz Ov?M'~8!ɦ/noD~8091	Es^yXm!>cZLcF<hզn)qLaid﨟?!u6@qND
>Q{/?a	76?y(ǹml4~@.A4`b;0qlܦ7Ent|8y@'8n냌Yݕsh\l 3xFh	=qUIoø	nϊȝyH5Q#ƔY.cxҭ`l*-*!Ѧ5M&:\ը1MJ S;!Ojj=Pi@'[8Q2Um_x?/*kR7P]iD[h!tb^,;36(MHJvc8ۜ_wݙK:#HyC7݉ugW+.0(4p0k<pp|X7o=?J8,CӐ6r#7'qz?>D<U!70g Dc:H૎Yc1a>u</Ki#6 1xh`z_u~R kqr @8&YiLbP  = gW]Uc pyKˣdMo<&C]XyG~'qDT:.7R(w:-]T`4-uIcoUxYfc&KL$0pTCW#NwQ<E;?x:5̑<ȏP(<[k4_f7c/mC&f,a"J#Fͦ0O» 'H`~F[N.;ݍz'K>ّ^$Ef7tw_q!"k֬~ǴuK=yUF&&`kBi?{W]Poh:,WHg"x!lRqʃfs*
=	&f:@6DAN2ozwM $m۾^P:ae}W'~/).ffZӋ:k#V]aSYbmYduYd]Y4V.__֯^[M2Fr	qjj&5zQhci7!LSjyb)zp`у,,~(B>,xPqu1'tTm,%/f?6Gu1FXnW<J|^Ȣ噰AmqzI_"W/f72N bٮGv<*oݶI^]yI3UzMILPw 4R~x6!BfU/n?-C#mwc*^s/	_xq^]D5S[ĻV?e#>_ce޿ [Zv^{~gsiW+9>n0~A:[d/:5MIy<!s}y٩e#qFQ[;%p;ʌXw?,/Wh9NW2'NIY$[cGS*^]ݐń  Жyrq䖲O;L@EsIR[q~}^/:xં*=pXPX>{Qz=?lw[V=oM,{e!9|!)+7jnV:U@MWL/7:cst-B6Vbs%&<u4M|n8ZF SjLçӇb'//ЃZ6yYlqm٪)+6&R)L8 ^Esao)|i >pXc;<͊ۑظZmnMo	9>#35+Z2~)o虝]g:/wfV!k
mm#N?<'"Ĩ'>su:C"_sp9T]g O1+cy],x$OfqKy:̒;6I .s71RG2,7<ĩS}$cPU߷>8`=Sc]\/ul_ծ$#[YnV]x>cNqQmDu	*LT8CFyDoW̦Mp&C!rZvִD-PY3acJ<6x^eД'b2$<6ÑِvFr~	Ґt<KqH6c橓Mkxtpl&І[pdn21`M=3T7QetT>CeCǛ:m@Ƣ2i</~gu071įeяf?qe=d]5(um;Ah)&Q!-Bߖ.Y`jUx@iIl6CAF?%񋰦m6RN8
2n,_A%>=}}IT{'n`Ruk Hvigݺ/jwaȤze"6r$d\PAnBs;ǮhZwLB:vp
B'Ó6 [4=RL%䤺[Wtd~yPn^Ox6 l"9˧>:< XSUØLMo]L sXYzKٰf&4T^[D7	x-kezy :Θ 1cp7v*A1Po ؚ.6Wn^BAd 9+*vF">;x_-*ǿ<!eUՕY89#{[52aʹ.@'ʪ{{
s̪yW+=2i,Go6	go'nӼ>7O1)Ҩ<~EeW[֭][6[_V?rG؋[+-{`+>&.җқ
3_uZf1PܵtI9jseRvͫTPǍ	4bԝW2PQ2<0sQ.)1wƉxBbw]l^r+V*ue4]gHZRvkGw_qmײq7doPc4ˇ'@VJUזe'~׫V,"tvsdZλ{L|hae_+uF<e'w>aHvoTv:~𙻾Yv=eueՂݏ1o:	+,1yK-9֯_	u[/+2z՛C ']6z+2qb_3zx͐{^meɼ=q7`X]7NU^xeg1uR"/+3S}yjȲra?ik`0ZM{/NPy*γ7~v/);:KeLy쎋3b=3ҲE.νrrd[v6lXa;l-O=xey?~ϕ9Kw}m͏5חZ]tqh?>$zęn?}eYuɻߥ7֕ЯY׭կ=f|q焳]iv7hG~z~Z~/Vv=WI3:B#Vp`<ZeD۾Q<dtp0ex+3y\}wn'x𻫊}\؍nnyG7uB|'{ y?.Q㡞H&YWYjvs.G8|EEȸ<îv{n|Iu_L:L^"lP/wO1->jC'#\|5e;qFE~'N|v͚]nh>zM?Z_ۅSx}^zJDeFkBͲs5P_Xܝ72M}ǧ"Ї|vNPAzǺ`/}eʬwUspb-R8^fA^[|RQ|@
.6"#sFbqh0DJ6'8=$	J.OmB@WA[6	`YrO-|WV.ȹ걟f^¡ٔ㯲#5VVca=FFN0N1CI<ӤF(k0i:ުy<OQ~AmtA@CoT
\菫Z	.8I%%HGq<#E@uw딯9 '2ZfFXX Gg:.9'%9I4c>	wZ	<JO|ѠWګOh|cK-< x?7)Ss rW*/h]&PX'řDzLJ(`QQ"zMeqG2|u2GUّ1ej1u^2Aŕ0Ж!.ĭ<M7?dPQ
с;XQn*db@|1lԜ2c;*+ҡތ5گ9OntM&!-m9bFH[&id[.h5blй-=	[@|,*YtM>d0܌p7N\iAZ-ycs	c,5~MpS)qþ#}fZ Yen+ob9W!ufjY:~'Û,X,ۨF_lY6۠BT̮W^R1[I#S7"MUA825vxTSŴ
ړ!Me\UbH)ig7*";4kX(׋hdLU͑us_l_уڏDp}Y#^pzgh_G/Ln|8k B&K& W[BNi9ET【'lԛ.AO\dOA3]|)hʫ\rDx[7O;tX@FL/yp%:r;	(RX\F8&ӓ'*Lg 0H٬Ym6܁Dv"Ma`!:ďԀůO/'%I>Xv( Yq&_+ɒ	)<_x<! 6~S|ۉɶOTgH=qELG+#RU
^7q!vpޫJ4|GI]Vcȶ|cǘd7(H~FQŴNUm<t
&>+ʞ몲+>"~c2~XOxYug¼*96ż"L|Š=<r>GxL_cG;QaZZ2_Vfʢ$SO&_\:#YxA/#&5xuQv(8#,OͲ/u˻l/2rjATyR/_,{y_4>lZt'|_g}aso\R<r*6JDd3w_STyo5qʀ	9uͦWyK̓8T%Kfo0yԇr^ʌ)<I]I]P/wU3kY>;/jSV"r?|weCNS]_r>U]lL;}d- ]h1sOok(`ϓWK<ֺMnI=ib=FmHKW-*K6A]>pUm̻n0TF
me#WA ߪ9l~h@u~&֭.	&/ntS?FՍgnͥaų\(ݝ)J_gjןx8^>QnAR}G7&G͘oe]pr xR{[ԝ&{osʧ[DlAmPeF]E>6JOLeyΙ/ƢDMh窲
.gׁhSb*)yU//;pJdI2	Poo&JD/EA@''%'|
7v;Aҧf(=+O }Gź>HÉe䠠4EznҊ3\f{cU[k{v(Hvy'ZFr{"\0y\5)ig`Ҍwq\OKQmt`^'j+~bfXycx'_Y<9Ns }[(t3{R0]X26,ф@h{-;֞j^~,>G4jLR=w*dܿ'N%9XL@GYm{%3l!,cOγqh\3iIZ<E{ Ȇ!ΔY	<?d+(x-͆N8{`H9v|i05"S1|ewc? "Տ\*,VzM8-!	5 ɇ?-|{Y~WL^.S_[@7Ifn-bx`uÃæ(f5d[K?a@Mw'I	'hPil.<1f8?w8hB73uLxn7ȧB@191:B-!M$4-pGy=p$.9c>sSi
"a	'N|H=;yAªTM见;<_Ng5]Τf;T~w7Be]IҖF]qC/c;A[:ŷg\Z/Ag^?taw%rD}.Wzp~s_8yS:nDY0MZ/r@tF)>}$;&dr_%Rx۰39C}}t} u1v|¸10yнFG>cp`U_ak6q>r5+$C*0sa';-r'd	lhX@r*l(a:Ku9j8GԱ?O@_e7Po	Ֆ zq2oN>wWpŶH:3_95}a5~[llHnBrn/Y*D}Q;C5Bo?V*;kFM3c|LF8ݷR~a'6D){$2X@lɴZjˏEvF*D'c\R"H)f:]0D\U <qb:uy3Kl09{@t-z@^}_$@U7/;|_ t:lo,%l01%<+9Ʉ`b*qݐ 4nxO.r CHLJ)| o->U.t[=Ίorh0u 	Q /MܚmtU=qA(h01 _7mMlyqI6.5kA4)ӈ6j&+arX(}aj̂3)^		/@_W6[:,s		bq2MLbq
l2~n.9\*n#f퀬NŅXJI&7@Y0aUy=ioN*Ee?&U;򥲕LL*dbΛJ%K~&e ȑ~NƔ48rff,鏾`M|gUZc	;O%5pXǆ&_$4`-C&իI|3E'L.;͍gK߅)o2Wk!e	$:]-]B|I/&'/^<o+NZ=o}6H(x2b*K2@	P1I,(WQ~-qzMxK1MUFj?Fy}q#SG,G֬]cy	WITSnc_,}&xq8O| oʏݪ5NN0KAɲ2KҖqf]_ֶWrWĤ>RI][6¡|RL_&)7n)/,Z!v{U2\)xue6;%E6鱸:;?Ӥ+H0oRلGy$N0i
AI#tB56XN:^I4cQxEzGό*|OQL]]Tը/ODdG(Y]QK7N[30KH'<97&"C2q#<]LYpB7g\X_#Me(0V퇺|XCl:ć'DL:@?ֱ#0y]Gqs1ekvNqy#}.#'zbc}rqp1J+' 1&Qi)U 躑ʦS>ۊt0S3ddƞH<O̫Z{TǎQ90N6}VnTe AzK0M=!gBߚ&t(B	u>ЖO?hSC9L%@Wlx @o
is|57xa5鈣
P$K}˝54p cjq}}kn6Z> On҅SbF3%D}'NJ?ÛTF*y	udQɐ+Ѻk*wCӺy-yǽ+hN>|ˮ+` *]]bӀc\RhP&DgȓKmV?2Jo
mzǜ8\xA~Ihs#@txmCխ 7`w"߱OEБ'ߒp ۪ۜ w%\LFn
I}a$?q!)t#ɷdFq5ݲޑMNSM_j;9,GekG|c>n8~<HF),cN?)	@ۍ^rd |hLdOyX, E,4P۱jrvpvTA,+TzI JCfY
H܎!+"dl<6sf	6& Ж^qȑ;l⁚xvb4tbbo }B6.NIMFl -ɓ~|kh^Cįl[iU6Fov_N`c+՗
{{ĨK&Mi h#W[<P[v,cFzSS<VP=G[q[vGp$ч1D*Bqv헂kT3U~W4n)	=Q:@]8&};UA+DkQуy(`"<2B.;q`.59xԖ
$dvݩ8!??luqcڱir*>UR5Go"c;m^m;=@߬E^n@](Vwm[q\z U.*>sAw/T eKǮB[ୣH@/~7;= u
}
M4M$ꦟ@*XhGFiz]^l<, 19ro^yRI2)^N<q"x08M}s-j.`v2#=yM,ΦCk!:bac8&YUS	iO_nB WFA=鱠?rʧuBOF95,wǆߕtRA7\GxBoφl$QޜYvƂ,bN޽+db9رvac_'ŧsVZ[6(뗓j&+p$mݑt	iIIW27E nre'߲4'v(c=cQ#QS8汁/OpS|a+~ۋmflnsN#[aW&l$GC1ҠlqHE_6/xwPXcƎ60C#64>ﶲntmҋⱘ)aI 9>i%ED䉺pY^|R<1.F5WN{;i]ib6$lHlE^(#t/Am<&lh^+4jqOp台@.3	Z-?qUz'oܭ>pFs>oC<Im
.mAvd.eJ{w<:M?Bp'>6򪼰ǸIg:*#]˨oOG 28է4屜Ȇ!C4.ͽ3yv}P$+*B04U^jR+4-.ȒU;y]ÕA2!}}<ȯ,3Ϻea?й.XZ;\,~?qc9Ҧ~nBk\ݑ7_/t:#Gy/bQSe:nlDMXeB.1ȸ^0~_QVAEt􂐢Rc{dPm'S'4WGv+/pL	kеRd<Ì\7W-ǹE݌?ysVh]DSO)^gŸ-z	*~H\t]wu=T?&@Vˢ]Mra2a+ M0A5ybΆ1_GnAkлu%
x{&csơ9ϷΕnliZ?.ïǀ0чx0y 2n<E_qŃp Sv#[s8!+-o]۔avs/ݞMa D:`_6>s*cX3Y|;3yzMy, y#ܡ>J~$yK4/i8If,+L<f4MeUzpBC@aj@HOe~M@+݀T3S[3:=J#wИ\	٬a:v_)USjՑAv#,x4R|JW5:Xt]<YݺaaLFRszI59F` *, h
zX! 
U^T2!tv`p@74EB%]~1@^A7KrӉ#gFɻvN8ۢ1H&[i7<BG2TLܰ<l(o~IeL1pFV\S~\	mcBYfXmMnn^BZuSte8UcǸ,yt#1qp5(,ptYa- @w@W<I+\Bǿ1ـ[p;~tT,E7S LZ 
Ul0]r=fL 'yCȐ;cH"?1xʺō n/>`u]IyM&㏁m,?۬D`5v,7^DzfM&,*yBBNHOl	->bcR<)w|8M(LFhY 7?]M`0Fq34#POdqD^,&fٱ1gf0[rFc/6bӅmw ~+6ud3qDia" '1+Y.&$YIR&L/}}eĦVZ_{+$7(?x2YR&U(m|x1Tuyl&/A)g#  Ʀް }KG7lT֭r>4ORG;*GsBa)(~3J B Ey E<nM-hdLUOx1T伦p+9Bɉ؀Q6aaus}&{T)gls]UjЧcc[e OclEJ^Ex0!Gܓ<9w[f.N!EOvFv F$H%DCp_+)cƍ׫oQLbc35/tD~l)u\LCޟOފP(p0v9a)eo٪~Eo7T#ݱE^ˉ6WטKo^'uu:;0.qb^Ƿ2.DaM?r%m(){ìTϥoǆT~4,A $..o᳟jw-n'`ؘ&>+"|eтŀW ;a^v>acѠ#N&WRu~YqBפӶ"'`XYQ-89ݖ5f%y1T[IC~VkH<֣pCN	maʮeTND0PG|w͋JMpJqvMӥqgqW~AOlp9	Cq;6転]pCM<桟=-Dg?5<m'}^1m.WCsxD;e v7ys8- ܾ0_F
UN<jkF:|i=oZ a~J>W36oKZ.rΛ	rFDL$P	JWFf	>YW[Ŗ4Gs{H}Ul@amB<	.xั5TZ-~J \S0A'lyP駛|{^%䰱9xqyK?~!ypܑ&[Ddߎ'?0ȫp}q`uC( FC|B:|09F!~5oEK/x4o۪1mB48O<p;OX>I/Z<mL,Iocn;ysi]c,)tcެ"t#H?u~Txz[yy2|cj}t
ٜ?lte|*teh& ;z.4ຠpCƠMZjjnq٢@NLS&jJ2,1)J+GњCx⩤=ƆC&:
*r]ep]W8`;,0a#|FJBR&.48(mUdȮ?0&.p)ÑK;03Bcs	Ӻ<&̴]=TOBl5\X1BLډ62Ʃo>q5< 4n.4QI2w!X%^vCӯtGs|Auwap
Ai=U`: Xe"8g#$〫",eѡ!+W)?l2AkS;,0X	t#6`yĬ/߱OVxh*q c3A7_xEr5Oeo1UxmƱcn,{ӛ%A2]IӈUz|Fh+XI$~ pCBV5^H-dB
BP2`9^*^DqSW9o يrL18eu} 8-+TZs|xʐA_sֱd@2I@a&N0?upg@0hV̼WR/z!kկ/+W2S<#ٴNCᘤ7}i]^3qN<'OI#na"IZ,~wl__'Y gM99bI2ɀc
ГK>?bPb*󠒱EB"|LM&قhGS+>d'AxW^rbo[H!euX	-YpWZAru9nx  ϔGNT@7y&΍	&B!GNZVLQ-\g!'epo]SijժSu::eDeK2)m+h,@BoςXI<u=aK6Ւl.UZz]8ы$ŌK}Sʇq:7!y'u@L3iGgt>yzX\@뒤5>ćH7'-,^B&GWQU6nXV[6щ|ө+?89v2G}eD|T캨M8HA-71YoVi	*dIݒ֋=ZeKH('Pr37~OP :!HhH,!UCxE5jxhmŞDNJ%0}i, tMY;lh+dHz%4B}ҿ'$ᖬ9TԭҊ|KQs"w<#,v)۲x{oqJ#(?)n =\ď0$s݃DX؆;7HÛG"o#o(kV<ƻ_X{ݨD.`Rd{6B'- 	"/EVl|7$L)dv}a]tf?8Q:2r!wl@SN{[yaeoA*05+u,7)S&r	5o!#y˸i]swOS	J/'eL^X|(7.x+*觪Zvm7kyӦ?B/]B>ݿe 	yWcsɓ5˖5o8	lfqu,+O} npٮ%H>xBPvZaPck5'`^%<肞= e^9cH#YQ)#OȇUw'^'/iŽ=QOXȎ27syMgclddǩ/<Oeȫ1ǘϺ}F+OAK}#WR4?yE:p/?rVĥ0F蝴-yvlx-	1Q-Vc<!/ڜ"YܱZM/D}HS_b1F@`q{Y:EZxcY iIa 
m	PWx$PҎKБǼ>CV'pv_/Sz[ઉxI~)9__mE^~ȋdzNdx)?H!Εz`C|+ )mCRyQ+7@A%.4IO^@"	@'A|:߮h2UaRe=Z}4N>YomQV)zKQm>|>_uH$8O豪j'a[7ZѾQ&Z].Ȩ*cΆQ>HXm#H !\hdN(#evH~N)6Qk|C~PNH;up"0.qe<CJ%h>!9џ.3X6i4(+$5$F0(;KgҦ΄ɝMV.ԨN73qhԴtd][0><f=@k?4D2AO|b<!.PщNFʴ1#ٶ/
̀@ZX	U:C#[7DN!K2j2еzI+Iv0SS=wЯz>_ZxdYh@XmM,yR1qe߱8lr/j҃G4`A: -8-I__P!F(XG*nxV&8m` 3ia"Hfp(H	&&'QWeQoEjnM^TuseaE5ĕLD Bn&ZЂg~6B7=6pf_Eo,j a(}gEf(x,TWۺ\N	76mb^TzBL$|?. cᜁ*aĀz>OXcC]ʰQŉBXT)<^AyGYlul뮈 㬞jh5ܡGn%}OLrGRXY%1$/]<u\F,|⻃qUaÅ?p^P\dHo]`<PQ)ʀorx0fPWhg2#9WۑaYVnZd}Xy葪azon6mf*#cЩ|04q?צD" [\fDALD$AF qzt3	'}
L=öD0gRW姾7~z~vD]U(|*|@׶ni"LKoaC̦!\!6IW$9y-/d=MAJ(?Nr3H6NXn.ѱc0#(,+N&Âi*ٔcMTHxJR*jτ$.	v9q\5n -`R,[%Sht]#;%ZHIP\ֆ<Xt鲲|
/ԙƀLKvm5,<ۋ8D7N5O,I։ĘUnӄ%cGS*SvVve2u˴w
[{v)>|d[hBҌ
O0iM+WyC$O3~5eh+s"-#w	fmX
ׯ0EY
@lq2	mZg,2sI2RM#tIu=4NAOz4"Fv.2~߬tƐ<':{Ը1.scƏ/c48P"޸~w4o`p*o,7;,thFN\ɇ9Rl8*zJxQiAKY{Ďpl#N?`=T\@H^rd9YT,xIIQ,6?«1/(2~W%Aаu/0Yt7HM9No:Hs@4fţ!H뼱|/̛	7bv?
k_U
 JiPv/Z=,pC&	k	2\MfRRF6(ryr^C_ቩ}eI~?'n	x̨7r&cmTM8MKpn4Q Àפ6	#
mj\qFt<-ċZ<1F)1O@$m~1w U'A'tL.D=,$r7a=Q 2 c= &.!%TA>Ap0-V:3lLmc*nD.$u\Bn8_iWn0P7ncJK]CT2ͯ6sIfh9UC'&r5~Qf0qk-Sh9b^R[6`Tc8W@Atun﮻ $$~Ң҅bbp1w4@jv)ꏎ>p	5X0hf1k\$:/aŕ1h% XT0̆k^_Tv:̙3 xdBs"#_rWlW~[<Al\k zcbMY*3̭T9
րI	:d<gjl^IL 2yzd)esTc&Gzтh᥁L38rh5nGG+,m,wN8XYe^|\:tx:׶!:t}.xzMʙoP>8f}x{SlOW:I5&<6eŤn3Pgu@%7 !WPyp<x66~O987܀/i|aWziDUxPcU&~U4rP~!kNHxIY3k2B3P /6P(W=3	LuC ɨ"sK =X_Z>#+
9B}RٱC;d년S
cj~=
meLytl(agbxkFݥp	/"BMN9paJ$_LBቡ<ƌ׼">{x>zul`	E89(0a|&tZd]&;@lP;H]PL|:)rH /7m)²ҟ7Q-`W (a=fʉ;V\a?oi;agp.Cc<~>}"ׅT%PeY\N}	Y<doғІec͑%*

nIZJM鳠ay2ۭXT`S}XJQtJ\/N:I\/0ɟ}(%mvne~|mJ!˸%imqm;фLvCy@w?Ri?%-t:YK
3D\+WFL}k#l,[ƥt2J dU=A]NxP]G˴u1K^ok*Ƭ]N+Ϻ _/,+c6N+©d8DAq5k}|Ωf{iM7l(Dω|N6lqgS-	bҷvF/@ԵvH|ޤ7_Gg5-NW[H!1j7s~0J4q@2ft}3NqcgԆ)3M@qKă@\ȏ7~l\g6{]|tGqrʓӢDk
d<#cl;F2Sp$3ui/J\p4D)T.&7Cev[4>>-Kۿmy}л휦OcJ$$),0@wBQ̥BB	V*[(TR)!@wCU[K$`JE)8g|x9h;9c9c^"322NDs,tML|!4p
Gַu[vmI9<sz#`2{Tpkck97^#i@|ˠWc"8`	Y㿎\`e9gm1VG85ֹ7oOS\\9n="x@BKi(&[|Zq_Sw= 7."	]R¡+lw0	`0?mya|3̓pma?H:--mx^ǹ^,q3bt|z-?~E4sQb5ܴBޒCd휒06mG}UPe	1;PEO/QuaގBru2N嶷?yc?P8ǵ%RSrAP􇅈
.#o#*Po`XENf%4>>pb
#Қ}+8 no8x<Bu;9͆,i@z@;BS_)@}g?;xo|z?(!]dIOgr+4=ul(mo%i K[Lx',]X*\O0
_=(>v|36A#FW:-I?Oɿb[{BOoi9YXeALU?˗E+
R3ȷעLMlX{蘅(2TO~6Yt'܉b9qɇlsQLt'nzu_Uwl\D֑'zѫvyQj-XWuA,nctxm )ቜrcK@C!(sz#2|(?:͢r	>q!CD}U໑[v➍%9wRWB^nˮk?a"=B*ë(vݰʢ#?bwG\h/L0|߰ဇShtÖzGtakG׌z%ϸZ_7 PrđqՁ
&z\*Mk^E=ȡc71-jҽ^8ݽ{7NOU>x'O%y} QΫ (
aԿ_Dw_? A5&{Md6<m䅯ލ㒳jnx:1}Mk>{VõͰ#/&^5xm]=ݸձR/XSMqoL1S<<dK?#ΡK𓀟g`4GwIeT/ ]oA!3rq;#DxAf
I;&£I-a|QI78$[o nH雴!WZD'IO疙5u\f;4O	t&9&e$cӧ"k0Nd^$.6ԇD1Β]וf{y3ƆKık9o3MIu| m"37H8	t!<`aʥn耹K?'JoSZ\[HS+Qhad]*Ih{c]_5哾	OP0 /V͛sn׸YP;OruN=\D$Pֈ}ZRO#:_O+r3VpAis K>8q]G+/(iv^悓qqL"ѥ,ȃum16 ^397P5=%|F>kżFY0FQ_` ׼zFa֜%	5&#tz91ӵ7?rM:|gmPvLϸ	eʍ1ٖo^zvJܘd8!/H𔏦޼A<xaԃЕvGh]Ue]Z>@m:b]y`9m%P6ԧS _!~P1hrw" SȘ4%U-ZM| IF$WGԍ񋼶a\ףGo\AluCX-Nfێ14L~K0T 7z@5ئIQ~gtUy|ö|_xڧǲźW$47mٛVqEѓcjK`;2Rݵ!#{nok\~.-=x F/4Ń3lxXŧ'aeXݺ8:g;n&\t"V֋Iot!~ɻW3;/S2b	q6wD%RJt믿9;@>{$2e1*˙=ٴM6hߕT>ȑepZP[`|q0!"AMѧm[UA~'?fF	9תOH~/97Xi6B?ÏY/R>f-.$Ic\G~o;Y1O)1xYk:*߲`ʂ;;cP3Q`aG<cwi&޹!]M1^.T<v<	)'|:Șl8qÏ8O0,_ޱEFYbCO  2n80P_@nq7i36-< ς\.ٴg]2u1npnUGКE6M]2Cp,иÑ
lWXh0蠟n]D>lV޽l, ?z,k,(|ȁp.̫C!AnO]Uq=
%2Om7um`9:˓|߆Cv y_?2ztӔWPEt4̐_n@c?;L#<it
IfGc¼wВc\͓|);hQ \ i@'1|E9rnRw<;=##x k<y&<`Sܧ]Nzxw~(d^/o]	=RmGY fY9n0s0<y%<hƢ~O=ij}鳇Oz)ǧc	Y72'ݹp))8t]#Qm1'iOe<ɫgv}2㢶0<XÝl=
DxnT!7m>o?iХOfNwwo??zj`Ԛ#8TD̥7o];}{t:}=LZƺqpG?4mqe?x膉WR>CuރU.Oʢ5Dp<q0q]_ݽ߱ >r>YY^c/؂,󃕢]A@~Y:ʁh(Jai6ncͷd_@sXg'a	:9[)Y#Ct_0u% H1kd U}LJPG	1֎foZ{4o߹k>+ξc9&Yk03\o"cX3vL7ƾw& ⌞l+\B QY);0>8^+3~;ۺ&][X4úUOʲOiSO[Zf-~'P7O>W|:{'֍~/X^|q=y=<	}80fKs/Vox+w?vo|vz1?+st8cV18[Oܱ 2F~N?f2zdn1s}uc׾vĈGi*'>c^X~OۇÑ=XC!aƤQ&igd+@~Ob&|'у*K|VVK$!6b =z2
M{3{ѧO~K:zzAX50+W+Ck a(7̫(73pqmW׊#ıU^UВe-6}%^A<_?ZY_+_g-Fuh?QfLxh;tbc)?v:>zq9)Bfj'u:W>"x%>)}mBݩ76-z_dX}&|A\cRB%t_VHѹu_3cע/MnC>fN=9:%4:ĥ>I&`Y@>e$8L WK3³=A 0 8 ;ya'iM@PXc}ƆDIvMG1:pI<`uo6|Ug}7w٤3p:/$zB[%"M7$ob6$1l%{V)_caw1L/0'}	?Ty~C&ɉ3bo_vr~%*/癷۰}H'ͱf,|(P:W`/ۚb}P
}LW	ߋqw*9[q@eTO.;{9ȴ~!A	ozݍ96_]2'T	!6'{sv]Pz.>	,K9	Tf4nl214;x1Cdy^'L݄O0*[ÆY킋	?$=`C,^pɖ)JQ#B"| S\x	Hl{2N].̧N˪_^a:ɥ@P?Z#tO^YG%3ɱE<t|(?g>Sh{YZ?!^l$Fw._9u;GБY7^JѻAy-wС|.@g nRV/uQTr@k8+-bDH93euR.ܒ+q1;V6]Wj?p zℑ^#k
Ue\׶A:CCkydrJO"2E9U7m,вYgΓѻ9%^yG6FVWO(>86[OVPn5U]dPiS).̌  OvW7m8q<HGArr&&l\7oGw,NøμF6_1je<<h|O[>SgM^mq`ԦށGQzp&opgc*qH_+ɓO^ςl^E.^]`S\tyq,[lO@:PP ҡUBFn&֭|.vdHsѢ1_>5WxWw6aqY6-;DV[ZP>@zvCax'r';	0BwK8CPx:z
+Q]9cw}=@ BHxt(?+g&U'[ [8j+o|fNR/ĞQs#uF C:cvN:0`Zҗa_Pըvԣ<:?@bJL^oo^o+n:z{k{0Џ)o^T җ;˫?8Os8UUd-}S_i=/qKupxa?7Ixt̟dc̃ˬ9׽囖0|Vع pI	.`<%Ig9O &>
ǭ3Lt>`<>{j!w;-i<I %4&%~ôЬ~|~DӋ̫\ϵ#G}&@s):P#	qSXj&"l52V?37^:dĸ(Cq RY~ct亚33k%}䅧OnzN-xȻ+6R	腶7~R>o\Nc[k8>k-7@O'DXϫ7}Ivj3 ˠ+|XFoǕy;zO|WG'Fn
@I JBف;B駌M ]hZt⌋_i}	ҋEse:1(sȊ%h=`ۗ;?ǆVky5^~sX;ANsN yIO|ڕz[Fh)o|3|S?;G.{42xk[Cmf$cثk8
yƱɎVޖM	i)ѣSsoʐs-2x7[Q?qMBnƴlt18~yR0~cd0Ov<p$[yg AAv|DٔAߗY܂e?@gVVc:!¤/= s"\1k7dtV=~?B@`Smy/[e}9PwN'o%/~#\&sͬEwDthˀ\?7%0 I@҈+4dJf9c<P [eíqiV lȕF_z}pdh-̊dg"k!@9<D]*aHɮ k<BG9sTac5dEpǤ02N,YPA/b2cCa@&w7%h$1G^8p]X凯C6l*K#c颣=勏|Kv+n~ix.p}2A9lEˋMdE@O)	04At	-Vِbf<|G7nh5>9Hq186lݕK.J3RfXW܀i=B;Ds!dG3ҐƋ,ĹX,D	O)"s^|@wSo=t/RA)=/橻6!On	 iԾQ=s0?Sq2<0}*y'Afsy٨(|zͱyssCpSNm}պ~OsQ2.RcO?w/"?+td
OvP)>d	Ηv@7&eVC4r+OK.]PtPc3p6ai/qpp73웧7NeyVEtNhȧ&#g5@Љ@q#SGFv.p-9;vi E1pr9m8),n~.)3:xF4((ʯ锋=#=u(WڎƓ|G> c[@9=7[ѷYRrs/MVC,!maٿ/|y4hZ.u0'ߩ;.NIPMZY^^ ZDS>-Ͳ=B00636Q汅bKǱ<(/$.@WpB|iN:I`*KԦ@3MJ6h>>Mǌk,0jij8ojI^Á/ O.z_o$,:qV_?f.	>Q8pa~-8öoj<ADI 2^NZ`@?@LOhF_t*?<yμ[of,myu]/>2?ԌAmoY3qqN=LPW><A}R'8DӺ0Xcmȃdk{>m>jַwݵ+_ĲIOrӸw=ݽz<EEC<9x{-,@<+^iy,Opzm/i6킽r6y]%}I@Kӷٛ|w+TkYkYG?/R>{L=ueO73_Ƕ)^|O+/^<ڃYQvh{lr87ЎcH6o;17:?H>ЉVz6Md"#eL=x5#X_a z23=mXw2`{o@ƙ?|{OBi5>/9"KE}B'm}=|Xl@<l"0z'7qxYlGll&yX7ҡL~NAսAEЊ ZajWЁNKWw!IF@ߛG579C\1]Ex/ 'ѭ+\WcldMc>	0jȴhGs>4vosI/mV\ao5tqxy@@2]R/CTѵLwMqS߄O2ޗwmm)aR_ʩKV FV ESԊ`ü%/l1[bmrψ;~ ]!Y^+!0LGOM	mwpTj1!cWr!D$}oxp3]nЛo8aR!{Po9ЏOR9HlQUbs14+S040H%;1s|enu_h"˯;$TKov^6;v Oyjlp}掿;N8/$!׾+gO0OfBn4ln&&ittVɠfUi`$.P/ө0t]<S]tS(o8:HW$$_ᦡ$6M㙈:my㳈'\?h.hK~LXZya+'.ީ.\nZfc2!CY\^]Q;_=	zNYಐ'^٨!yXέ_EmzB^~)E.2blEg]iN?Lad֙:ʞX/0qHTww1WS\;21N!FloXȟC0ZQ{@ :EȎ<,?ɀdh,#2gGG&#,YL"А:lOpMYʥtdsC'&)e}0!3HXZ=蒴m-^!8M|O9ldTdJ}ϸAa}p\tx(IO;)69 lH%O DN/׵,P6],cūЪCKFu5X=s rɉ̈́xR#p-8ʆ1-$͗[?芺b	.~GI=Ƶm:!u:,Z>6r:҇Rw%<G䁞88mp9	igxC>\X@޽[?GO9ݻ{;$SyX먞S	-sc.a	vJ{'p
npڍ 4/yM"ꗺ}tdWk7/{1θq&օ7K:0Iϴc>ٟԿ_0m_):Aoپcgd"3(LIp0؃hg_>Bjԙoh'pnT= hKV+)佲6Qj-ZM/ڜ^C[}oA}z}TRÆjUρIy*: #ꌾȻ/X1:@^t _~ơ惾V*k%<[m-4q)%?pn$j'oFOFaz|ӆA<%9pe栋.zEO7r(O0&p1ujMb^u/'Oj':k1>c_ bb\>Ӷ|I-ԮV70RrK><:^aNڋ:_ {7eG"{>r~wFgb|Ϛ>5buӝ} N0Y|CXT_RqO>;=J=?~zzīzYY;8zaz#uSт4Ƶs7_.IjxP*'y*<U(xeXBnݽs{wkWS4zl<Vx𰇄;ЭcƽfV֗qC@) 2iwڈgI<29wمo(¾UpzcM˙sb?p3qwGvbSrz}gefl;B~=JBQcmM#BKԅ6J@=4T26H`1qscYY7sO-' :zvYu!xچO^h4|6I G.ҝzˇqxRFg8m{'/&:23?u.h3@YpҌpkQFỉuPV_q3Gfښ9ԛ2'xl2adD'^OP}W~ԩ TodEG<ζ<c%zQf2K{}v ζdn0 z:UGd2e[M8`V~dE_Y"tٌ`~BO  ,~7.PEn PJut/73+|fHz'4S9Cł4F_g* \ԛAu"i`~]Ă# ]8K)t8lf."o y2`}dګ2!6X<Pgb7Q"Sn8a}r{t?e@Mz)z>/'a_},mܰKXPu m6D&*jɁp»n-w}􅥋(bdi`Ქ-.0zޏ= S+!LSqҨ)L&YOׯgNօ,"BMV}lwIE4Rn07't0~?|NI͵|q6.s 0P/`XdN48>IN]lQX0M2[#]^9z pAe@3 h6aRqAppYxv"EEh&.%R6t,tz^yJ>$v*Epd'~	 >zbZλRbx%/.&{{89t6N!4GYh[Ұqڔ:@
ِ?AN uI?ize/_۶h)S=IŲcͺa-<h.xdxQ$ؠIqd|@|XRl%=C+7|I'M5H=XK֣
B1_C2Icٲ1]mOatE7uQ6sar\ Kc-b颶ƞ:$F7ītD<0~J"I&}'"GܨEhOOׯkEJye	K6>x/%Ø+>Ì%mp!i4Cf퓰1FMW{cB;%/mH(7n>l#sy*WxP~Tg]pܥKF)t%w!SӤ(~yWaI4V+lmzs` vʘgh+Ga;Cmۥˏ|XhK.xQGG\(~@z|4b> t̝6=Kta,E
2mۆs*"цIu;Mה?GÊ7Xa
WԭD66v>@U>c!|}8e&c-Wri!撀MMpx';<81րuYJ<)1`h7{JW%O, t.[ÃZАü[Int=	qoXV¼Z|ϟs1ۢ5O@ȟ[ՌE37̅)OvH'v:w]CZٍE dF7P2b>?<OA䵎*d5upYvBFp5k^{쎙	c{S^>3qq		wR$?Ox).`\Ɯa6[uwlu2XGl/>vD2v#{IS~OY\"eWa%U^t侍ɜd~8IB#GgqdBS\kC#~e<	3=O<z"߫^x!gXw7PgH@orh_'%"^<(vz1}O\)W/ydܫ}Z$a!Z%ڂmi	@alB.o+ʌiԻY;>KiMG>?SA42ko_hXY!ꊾFR9AE!Z迺,SgK3֙	&{"`+ŌY[7{Ǉ,BǻٛaP@)J8yگWzާڋB]xm1e@	\_a#7	LW9 >2ԑ3sm <|X+v\'h͙rceߺ6:HnPnj< ʲک(}=_>m˸̜!<DP.nd/	Sa9
M-[c\YǑ5 kڃ1ߓF_z$g~3[fg3?z,G~'8i~Ǐ7L{-_i?b\Ħ5+'x;G'ťKot<r$ϖ`gJ
ux,td g>_0uJӔio,@ ^bZM@ĶC+-۪ycBꐾgc]/e\wL#.kBtG>f2SQ<NV*wKX0~ n[񊰃 LU:W,䢞 DS&74'tp+~-  m |44GxTE^čȋ/ƀxf%NNv]3ÌZA;F -l 4{w7UdAVx;lV#G'`Y̝;`GOk,  2S]&&B e*CD8t!y\-ʄѣeE?{HXxpxyW`e3~X{74,@Syg8wD_Go,NXp\$hOeҶ8v9S?G~^"
:d`X^hhKe6F"n=}ĎfC:.Щs뮮'?rR&|>;fOgdKOal9`e\:V-X:d#	{겛hڕ6mO]t2ws4tǑi'd nOáC;o7]gcxClvь_Srv)[H8? ԱlΓ};XJCiO>xwY7HJ6Ae\rQ:W2W2~П^ġs^+5ym8uey]{1DԎ˷:Ȩi~Ԛ3a!eC/$*9T:˦W~ӵ̩'o&n=@4)4ԏbq(:H0 ě&&S#`م 45
6#w),IXt+~8<]+۬9H[(juҮ8b 2gF'>4]|+xZQt:n1'wTX,o"+!*]P=urS;p /̿6~~Ho>@d~{yl0.Oqh~Oɲ66`5%[q%le÷
BtѝjA"ƨ=MѮ׼Gܦo~V\ҘyR9hlz5V^#SYnuftzOF}|a(SE/<}"*zפq0Owim`eN =g<_:.4tAvJ8Yϩ%7
wݽs>:~jz웟>yi^Q'Go>g}:ެcUGZ
uEfڹKVm|K\iFIDהE똶>MX	|%@q,W\lΦM[Mワ]V>.^d0p,r^1[(SC[	u,7=?=J?G=:}N\ܣӓ9!g/tv,`|VoY?"Zb[nEUrVH ɺ=4@)C	i'R]̻	ޡߊqCNHa8ǀ9Ώ؄c<isCsX>xM <Z|RV}),a;P<'GΩݣM}≵jGػܸq˳S*o`jozt;ηc-.Rv=P#V4lWq`"i0L`іb7жX2IڄYFc|5\\[KC}JW엦Mlg\GJnjG0F]yc#qC+|K֩z!]Kl/HLˏ9qaV=%7:x]UY%$pdoķl0MoM<r4GvҩE4:	v0f<6Sl1aqqV<Xqٮx'Bo30seҿO`koёKhh$mtKe{oB9|HرpdRӶ5L2]hNwX,?8ryJ%E7[þ$`cZPdeBdW!lG/0>drS:<]@F$?,)#AeC69,A#l$C.Gɘ05UJIs>z9d3) B]L`0]L\U;/;EJh:!#xIHSw/JP9ˋLt6C24N>IM9\KyQ4+_8/_-@a32mIO%w1ڐާӢb r09d&R4h\*7mާ_/Mm{=R_
0}ж3DIsD"g{kx# [3%d!xbH˷On:>D>mxGqغRaҶ)+u@5N%Am:U)\h#ջ,&uJZm+^cEd'	K{)f)[:u09xԺuo߾}-crCTO
elέxDx\hB'9кglc$Me?0KJB+*5PhIVBPW7/ޜ<=~uzՋזɁr퍯A/OM_<O_Gwo
T6lJ5Bi?XJxBȈcScц7)vwY>: =ݺuR~l#lgG^ vD[gʿ
NBmEMK بWrOIǕ{=:ZtŽi>I?yE&# u2lQXngLG @d*Y8N@mXZ5h=䑍[Wt%5/R^dOx;C),d1>u^#~6{߆?#	70s)*{>c;n1;ئtAS7u⤣Sr0fsW6K~GNd8&zl}9o_]px\A˴s́=awf`<EO<M?(*O|
y1ETJYHu4ӱ#^Ra;;7>Sf9zfIqZf	|@-)ԓaFrXZXx9s+>c59Ì1	Op`|>-a+Z=V!uk;gY8[O=e#i;t:9v	;0O> ^<L]'A\c?sƾ7	ًŵ"~yV2co'چZdmڱ7hO6˖<b+L9qXLi_>35!<k-}UE'iPt֍Ƴ~b/SC:j;,8d#+Yc21_L~ܴPX0c}{/Nd2k1v\¦9@`~N~@OJ tEYe}?pe"#<{ O5Fgt0mUG܏bnj;?_O';闟H$}d ]0'?J(IXvЛҶسvEGaM³rf-']zn1`>򧞡&\4&Z8Sʴ.MV	 {5nO}~)[e]R/: ~I1wcr)4;{`eN-/{Ky3Ǎ	uS]oh[bw˙wߥ$ꩌ	CY/mD҇n 	>ЬJߊ^7 |SOl>Sec];>B? #kDYOs\	ϘCC]#<:[D&Ҧ&qGXKܵxE7eNyJ¬%P$oK$X}ӶCCpC-4	CiZu9A8@
"q;e_!S'q)}{Y"]5pEgq'ouDks_ֺwpء3D]"1xށ=QpL2w sƔ^?0\Wb'N[Xl'x+)Mڒu|<ۂ4hIFe|`ux_}+zO,xUVkL}E^c9 e woU`C^7(+*L/*ug𪝚1??c`KT^qN0oGK-w\)EL^-Çɷ-j	?-mPGs/𠤆Cq$)֕MZM%"]ɹwӺFdf26^bAKXPC`QGzx2N02Kx@Tj'|X|})f^X_Q	o6l+!OEMg}OC[B>򲑞ZX|꧜I|kh[J@hcxT߅DU5`>rh%/|A"tE]޺W$b|~H}#,9wMH`>}	`1PXܺ3ڐdʅ96H[C\9, 1"F	#v84aҐ:kKa(O8dsTvN9}6\:^w'vmlB/!o]CzƧ8p^vBDS~u#G܍oګ>ޝ{֛LD%,_3_WQQ&}нrѣ''lgO^sQ{Xod(V^>pȍflw];ݺAlBy?]^C;L6lbş{xn:I3}[[3N`A3.cUG[c~d|l_iH!i ZcO6j!I֖sb qjh"egp~զMZ7=DGp[}ȣeXE9Ek+s(Q6׽?Ȋ=JK	9Ʊb}/%wG1gtp=\Z819zDC!$ҒG@`ȂOh}}~+4l}49vK7:wEQ5X$rRZe^;~M8pCj#Xw9pSEtL!Rx鍛^`y<|(=հ*pѧr"-[8\u-j66	7'Ah@B]еk֤qt- 8h\<qy53>_C3NO8߸y'q\ow3kf';|Gg}7 !r7ud}8{7(;"_ڟYWZՃ04߹<e=H=9,u}?]vt+uA-㖯C(3qm|AD|sbf-!CHt螋pz!)z|8J=+U0ygn
}/T<3uT>k(6>2*RW'#8&ͻ73بy#?6 ,7V@?c
p:F7\\/pMFp/6C0Oݴ7cs!K]/o1'fOzP;5LWW!uΜЖNroc
r>'yk^,C6Mt:չS[`G4aôs_+\C9kkl5Mm_%o;>Nd@;ط>+l!ȮGaRk׮*uaa<noH:;+4+x]\;%Yn"?*BWMg0#8Dh+WP@mؒg˃w/3o@[)@`r%"'iPzt:/'˅񎍳6Nmi٥!?YKLQ#e_aǬS7̑m_nИAG cm3ݯ%m߲$n:om&n">^6,ƗoI#gCadXzHWjY8$_ק`WGM2'p&^JS3w<VwpbprUT+ysS^\D%P;n"+[A3nGi@`^wٛx`yS.'|fPmCC%q_j||!ԟ0Vh0QK9+:,F,6 _Bg*k_Gy	
%JNӯah^`kX$ 1Q0{mbg3vSI<|.|Xtp.`I@Yhɕ<LZk{rMWwC<
b2aQ;#h3z L΂wܔ5j h^l ɳ7Yx*FM'u!!=c6O9g3#mɽuj}2vAH`n9pбPf-rwէrR9S]Ul=0Alb#? ^?GuGY0<p@<oEE;-}2(_]-2uA쑎.9j<@FY>~=bC=, } <Um=9-.g~酠P[%N(~]O䇞¥M_$dt@=)	Qآ-%2AiiASds#8^2(?*SMo-% zRȁ}>?<D  E`0zOt	dmfL=z W`$go{ts捫۷z-Kvv̧Cw5K2u9^	G1T|xpqz#?O9qP"@k
PWi;K[ 2i6nlF\>nyuʺ^>mq7nG=e#
.T oC-}a ۩-Y_yC:v|0F6&,6ngΗ1[墥J;6s([J`>nȡӽ@y,Z*=ů <nhCaƇ6)ΗV H;$s}722.!sJf0.%uD x2ZpCtK<s`YAam%!PƩC
-F8wA ㇂q]c)Y|{cvdO? #I]^.̳q hHo	-<ASE%:'Ϫ_VpEG?S>G%x&y~]+Ki؏~f@[wncmƅ<{4:AOh̓o.AQ9)fK[ {k_冡WRܛWO-=ῆb'c/1/q˳^W>u퉣^t"S_ϒ"&<4<H _FNaǋ=SGd/4 u`Lqe]`h~xά%;5/A[VA6$XOd1Dv"Ȅoޤ<\wSڼ{z^g/beL=R?Z".PSk|7x4 κmj΁۱}hg^0|ׯ>!l&9ssr6BNi\p9y=qFkg]0749~#k)?EoїmJK{>l%'n݋2g #k<{H8(Y`G97.#/gkCG=aIY}Cyc?-Fd<j`  >ڂ X#0F>}#>2$v=}4>vWi!"dO}+O]'xzC`JS4	U^K{<䡎/=o^NrΗq<ʇ(@i-].]A&Em򜧔v<Wc kd.,9GvC!u{CK&I\)
֢1_k-W77"	?ʶ_ŗ2|#qE/ZdL&>uBA?+<$ہ~w/|LxOSJ|${He~]4I.;~N * T7^r"fY?VleqCxX2{AWƀ\^4&lQNg c(Ype?a~/ЀxŖSv~ 	ab>TBK8+Pw|pv^`B1Wl6BF,H&5,T<輚<Y ,.~kXf#
	xҥIuv)$ @ك.:!NZ5
p&, "3OeoxN哄 ZuRYŇn[&tf
peDai>wI8JB>{Olq ҸIˤ!,',C`V]y3P@\x~Cxo]ఠ!O]<YK>=Xh9xu }
?֑r&O ~By]>l% W!<rӇ'.WcAgBqH!E^Vߑa!ӓ]EJcU{ȅy@9`KSať!C˩/<kC;X\^@>:h)^p^@
O?7""N>_ZWOV=l$?]<᏾S'QG);R%,}8_Ȋͷ,."o*nul-'$LMWfP]?8 vMxs0c8lx&t7oraq^1L_g)#mkR,Ç?zB61v0إSDd8ز]o*s/ħ(оPOzR(Os݌$ӖU=CrNJೇ[攏^+UT xP%&&:.x9qxJSͱg2`O-i\|GfHn^I|C)x|E~vz{~4E<"cufgyjMAO=qٱK#s|>?{BLD?-6|<[Omf!ixnڅEh>bdI[p@oha8!l:mN$彻;c?%oߴ/>@i7 ʧ:g|!|VAę+=Dv~bT⭴d7z
H}ً0U=UfݠB faC'-hIb,wب)nGm+O+hy>-5-̅Meb{d`qkeILaO;;`Dw뼞/("u[FǓD\8!i_h[hᏌ_!rgF}@o׿	I}"<yt`a,%x(eX^'3&zu\Do8>:M@~6juDÀ4wb>It\itjoYC6u>Zd-5./"t'q0w婒-cka ֹυgl-t\T""kŬSpJ/e-mn(̶~+<KЋI~'Wߠc3̙vG<<Vۜjȇ5d$̕ȓU9	L~]:x7 }~,'4ʄFzB##D-w@0B$5B!Cu.iҕ+'.!m37|CVXEOKز{$">Vf.qkMkFb|w^Sk ،N% .}%'mB[8cW?_zB[IE=k`K>&"c
qmH/vdiّ{@}	v3z#mUQp<L])LVa1B
|Ou'5k!K9	`?lqGۢmz'Щݭ 81x/ ,6ޒ(j9|&aP/@;io]kO۫bWx|0%Se`Ids	PNpEi&Pc-#$Ըpsgҧ8,dNZ;.Y|g<^DK8Vؐ_J.遣{E+}9,(.nɩnr:"xx@OGaS3$-[SXȭΊv@d8r=b񅤝wɸbFwЗfx/\x7/o3	T©Io'L/n/'PԮeL;7 {w8X{Ņꔡ9N2uE3cBۙD)Zb&쾺	0ԍ͋aLÀcN3 Ă.U
9-e/A!# AA3o$|3D^Ɏ`Nt4:hJ	5Y,SȯZYᕀı;ɷk="0tl$hvUiFr(SeXdͅ]P?@U:}wl(>yԍ6aJ[	:AieOD=<Mms>Uő_K~_x!ײ`,xX^YھRЮ{'^>? i)͂M%f¨wH1$T[㰚v5XhA蘻Hl;ŉv__mA| 62vC^YhJhNco./0s@E /(#:ZMai8gE;W-lCKNbAC"ȍ.gvc&_Y.<a}4φtiXe71>!o7 n`I~|kIKF~7XtJK=i/)qJ L؅eEQBZ\(+?fWk~zbؔs$76- {un!<{֓6M| H ]2Oy10: k/;CmڜC2|B!^t/*yȻfm3>s4[B0IV qv0k9l[všo4z/u4[íZzlIA6$Κ{à+1[ caN_sl6ɋFp`pb2(E.B͛m3.ųV8	y/5m=1Ǧl=ǅ31clɂ8d"=t'k!<R&n5ePL~Ĵw cIn%S]?Z
2.iˌ%˯K<}vz_?{ս:R#GXG?8Y 2DY##kR>j&nxqW0oc#.lsgM8/c捖UP>dʘ0]o$!iY`ٹ{ mEhs8/iS,t	շfi#Si})̅)9XeM.~u^Hc<a!/,'|3|GxK @Cp7ȋ[cÌ%ik=)ۜ7s${7oھ8w0z'_Iw>O>?=|76FB;ߌsB<h/|ݩmmI'>2*|%1IY؇rheY0 	Y8vM(g#p.zQɵE ~\DT1YuBܹL_|KS}ɲh];3bpoFϓ?uEt5V[0ejr!9Xm]|,u4>VoZݨ#o:aX m<<Z*#⅝vҩy\aBDs|\m0m?"~m3ZhxAKm	&-HüI	BY]вYs*/B]q'8T?[~=_Xϡqd톊gH΃	%NҖU..e]p`?ҨC>Y¨<>V
oኗ<J;d#xHWtŬ_/{AN]@Dw[nW[6o,	G'}u&4ʦu|:t3,^pef; %j>;=4K"aԟ?}ΫΜ6_*x'~t'0<7oW,J֢	-]8]LpÉ
7=@d&ܔd],d9H+.~LT`H|Xf鳧q+)
x]qմ54]\Hx~J+avxrAypEx\Z.QobYdw!ʕ@Pw-Z޻;}s=ِb0hr^|q9AǂJG(-m\&"2{.@aB>dV⼐{;}HoYOlО"Ll`-+-M2s
N	wi-|/Glg6$8܆P6l6 M4!8R9t ?G8yW<@4y#<\p")aۃ>i6i+E_$v~%hl)J4n_}h'&IEm+ Iᐺ|<bν{0K<m:&TOÇ2*7>][#iNA/  ^F݀x 9 i{pmP}=mx(7\k޳x\`Cv1oPo</Gʚt^ē?ÍڊdlL'P+R&?lq=aokyk=$=v4]NFK&r+;v0?^`ZO05P4zaجEV
= mk9Z"_#3<6j'ꯟzu|X~\uۇCG'%yIcdE(hļ̜}B]qΏf99-8^[0U~a怎eASDcDuUk 8;(	Ni7IWh[?qhM.O0: 9DI['<WØUD\tňȈ~)aj}ч’?k߾s_gZeAw^iyvb\gx1~D"LљKS~W9_ ok$L`LQG~']'1Gkd-Cuč	s_d\&+Dlax+tXBr矻x;10m>|\o'E޿皂۝gziu:q=뀖rb??wvsA!r0BλA-20$nu*%cCQgijZ7~ʡ3DV8^F_b1D,?Lhm.DN:75Mұs^_ꋽ2o}Gi+o9[p3 ^\Y213w>G^)%/<T5{/?M719<dȆh8`mDԾxu_>K-ɀٱayN{5+(ھ9}5a]+ЙnKT|rD$[0$POz!0*vY׫}uK	;@k6¤GܬqGIÃq~SNXv(nIYyRa϶_8vdoݬسcv.6{A*aǆIK6uA +]vͼc[(w)P]SNV>Q_f:,|Z~#sr^ZzfWB淰,,	_ԥ3ܬR'dƘe?+K1mY=<v+)gtꏭw|	bԾAIq@};τB<DF=_Ksp
/=_r]+&hiW,)FN 7*Rc8AĩH`+iì)Ƶ}\\?tr)\v;DJl^.7 ~wG0ùEY߅ON	kua+6ŗk%cڹ DtEvZ9[gk)nc?u'<Ox0C|NoXUތ~X?8w1x&d߉?A~Â9m&qxcR:SA#y38qф	II.A|ĳ@<7,_%t\hHv01I?~)+AKx׻oV>+<˭EEp4[UQ=a5"o>Ӄ$F\ˢnda^XX:#0m"iI:]M|&$	*Cx~!|w#qջz_rw$s;#/h?Ú\<)}鄥]3ohc{D";e76Ŧ4x)VF6,zwEs08½;ulzw۟x*7ԝ4B>xfmnO1~j×]7d۴?.|/OqH3!m34[<U"uƟw.ks{zz?|jw!O!T^nBIƻ"?|mӃȏDɴJYDOse
P&q?2iIZv	kװGSløږ6SWp[7Gga\K/9KװJԌӣGOóOP<Ys<8a}Bޫ}ȇ8.]"0ӞuM@駩CW=@6}ÔMGFJ<'qsp6R;lP	4@QFii~^g,eh_~uj̏aOǉ_E@h+m&anK?nӞshWlw1#0mK-'k<A"PޤĶN HxYlhblb. Mi'/-m,XWxd8Gd;nM6g`+,[KMVTd=DְHqGj2$n:&aMy%e2/uEݑ^4\ <gmћ@[>@;dTM7X5K
#;!o9=k	"6֚/~>Lt><4c	8}zX"/m0C
YV<v:|Ï>rN>ORc22=r`?4!Jx^""#eM«nܺuz<]P\fKHk1y֭'S0|-Qe/.
`̱6x#Qsv(л#.Tv犱%<B8sG@beDj\-2SWN)6k)'u)ԛ|rcih7}; /u`IwO:uBȈ,8,2IvyWح#edbbJPRJ{SkbF3zKiڙz|Ǽ1/ܐXū(y2M.bض*8|Q92>#k6"^[F&*8%0΁>gZ/> qmg*_AyvҠWv <8{J$Ń1!ʘ4oGVOdFڪc~7zLB9^hشi`[w-<DgyaO}Xwk8WvKIda	g;R(J.9Y5gTv>(~M_aʶ|i[QgE0OCƮYȆ¶&YKFڲI>@t{Ѳ9
PQؑ.e"'`58qr	w+cAIk-y'c[r7o^gM@fW|(Tk| JGe7IbV|tkCuVt,ʗz5paqrW'|boǟ0t?+6~[2 &mÚ:\ʾoΆk1)P<hA:/e WT)҇^'n7i8G|Ǔ[v](Ϧ[򴮕p+| =ձ*o`*2QpI[\.nH.X%ߖt1!O'+N1;对VL6<MjD~SΟ. 8+_w;	\4%wI1gcqtV/9<%Lpr
6F}(PLFl@
X apvrM8?."S dePZ7 YDQ]^jddXrF|ˏ䣎H'c=l8O&!Na.M'|t5deC[a'ly*b\L$u0m!*tY1m%MeP-2e&a:+K,g?]".Ot
e7
|{S0`HM,׬A:ud5/Mc>KOONW UkȍX /IBZ_lsl崠7k1<l t PAN٬o O[&䏣Li";y8L	6ȪG: <NMKnz\i	u:ʂIfh*<u<;y'z:t@u-Sh{#F[&}O(R5J*O{!uڐOt9Cm!OD&|%zsl3CW6$m>.<=~p@ǼMǶ(8WѹSϡ0 _pI/B6qm6l),mxmj/O>*]7Icv`@ZnЋv3f<&6υ^`2oEL-9-3M8bHGcE7؇ #).nѱvێE@=B3ꏃ(U[x%V!N{lSB_6^ׯf,E۴63֟- Nr[-ty9r=PLI_[99Џ9k	c.m81cQ0'-&tM_qKRL^\ӎlB3碂]{{z}-_Gm>*̡9cz-|-\8n՟ psJt\:l
oMvzox|]b'{rMdZi>J<& @44TlWdڋ63G>}1u4r
<UO2'cOR⌥c01O3mg>#O||r,{I.ʐb&ϴo!Q;hɂ
}>?7Ŵ8fx1zsB3ѳsK1K"Ion}DYE04x6x~z8r~^!XLAv˳a_Y{QpxMakŚ͝)}OƳ{^DOػc0z|^>M$8.^q3R'D;tE}b)pi@nw㛰y<Vk[K;nC15NIG?7HH3@TDFmRקW l[>m<%8K1}W-忲n$68]8nbؓg'x*${w`U}dꦞNm%uhVi$_ʪJ5|Z1O:	1v{%vӣrPIGy'=-z5mK>bdF;c_C-\ɷD`'ʁII[֬1qE&Mxʑ<=<}O漮ێ[QPʨO<дrUHog-M\"][<+tuu>e'9?[PXgS]ayro4L&m	`~(`r b"r	W"LeEcX}`܂$NHv7nogc?جݯ B ?%9y=u[~IZO|NΡ8᣿S|*Ǟ։h$'"^5߬C["R)ga(J#8 f`^{,cA&~gv$f]`{g\w2Iԟ,"v}+R}GOm[1q*ŕaBy_="[`=6bdcȝqg I-n@I.5&œɌ0ߥ$U{|&T6!8.IcW=Hz 謋 ,S`7u_~7I۲$-FL7GjEgڕK>X1AtQwgQ`s9Y$5:	SnO^`Jb,}.Gxs+.qÖ3bXLHB²1]lY E,Zq\Vyz᤻h)YV( 8 DmUK'ڲ8X$Jolqz6q5]J!G/%VWM.	^Noވt}IDܽ{w&:tAWJW)|hġqsє`ܠn㐭uCAlh^A?.>w%pG[MżyF{GZAkjZp\%?l5_qAO/ ;cK^>ց"`.6nA3qr#aL }
 uCf +Нto'<})5N?F~.%O*E~>k!E|t`	9֭wpHx12OOb/+8pOy!p>}0N|cskSg06țȏn6 _l;y-7|:&> Ɯ;h#IBCȈVcF@m*Hh%)3NS*5e7Anj؃=8.O,]	7oy{j ac"4%c!lɀ>}H6/IR,Hй"}BpZVYiG+ZY?[n$ڋ5~ʬAb?B/( :#<F=ʼc$eӧ0Λҿ3py#zx4^`rfЩfL,?rਣ06ڔ*Qg+@2$rwarsa?!88qjӬO<CΝm?:\<~W17>a* Y'ɒosX8gZH뗯ؾ{ڊuh]ۖ=_-Yr(YO{*ZaǏu>D%[gL^YWǏH	'|"q'}y|4ʋUqJw_>HGi;:R/6/5,Bs{ߚʂ)]/Xr~'s,wI.t:S>#/+gҝ7Yo޹{;;"7A6bL[>S7RΟW=G=+|g=>gnYKs37)hs>ܥ#Ow1v$nvM;Oݼ=@pO>UgV+/C'7kHaɋMܠ}ŉχ1CgʢW9˙4`=NkK'>q8vg̷-ܴ3/Qږ^#X};i_/"%E"֚{~@gis)}6A89z]A3*?**/mH? -w꿃+K?D^9	i;Pnk"xm~6-b?q}[Đ9ag\GT|ȏn\Mm Hѵ|;IݬH]s)0LF<+__|ߖ1Nr|
KoSvi;J"O7npx/ko]O{upw-!'ӂzO_"蛰"HaeztO4l˯I+M=@$N9W5W͍r =-mr(c;6.;rajc:c⃭Hܲ+^x_aUd4~Y+3ׁ'^8<qaC2x$m%)cA"V:; B瘘K4CBmn~څucr`vXm'W'6@p_i=&X9n#P?sRM;'5Ftvv2|Gbr@ŉG1
ӻ2vu%EU2b a "N!\,C_,Y$XUF]A^,!mҷ MC[eL|`[FzvX<,\|M5.s.uZ	ÌM%/|\Љ{	'y;o_eqr̆ŶB0'`\.ӮlYc=xNfŶN>XYtb{m;lx8T䐛W7Zd ES=O ~ʢ<yC7Q4JlDܬ?jz.fɞ6E۰ G.Fj6onq!e#P~n\"w>qlq»CO=b`+ԉ"ש)v2!/㎛G6T*j~cPFAҩ,fT-pAMy:! 6") m`wԙqͅ_yI";I~WrJ@4`{E.tS_6<!~uӆ(Ȅ]!' 'i=[*ArUnS~q}IcǄ;ӣ/_uWipPS^:ěel|iK&ʡ>ve#I;ښyRFaP=6<2 =d<9mՖiK l~q "m_D\qP~G̀mn"h02zw5}<y-orspSs\4$duDq,caBb|[3GpD:^I:'qBf 8 s=8ρ5g[q#jSiŀ|;B6S!>t8.e&N&Z^S	Z=&ްTM: C0w3F6 *\=tK';~^59mm\fcl~npupp;*MD_M>,rp^L'Lם'ß
Wi\xfVZ]67s%>>:J9,Q.k(Ua%ǵ\C9\<b^bfC?@{d<`EWYYYoa=0ֽ0d4`/h_~I׵/A֢jD=eCI"!/ %5=S3F0.3J'{/6T :lo/I(3 ؕH57t1_+q\q.Աf:,?ȔAg~ ]~5mOԓ+,<׋PT!@Gvӭ45?:2Q'Xۨ}8] NI?ԣz,xZw⮥L5q\|t\\?{$7r{"}+XE@ta8t6g <5hSp54w6ǎ99e.gZߝ$$@?( ^JBo|gģ{6+r;=ssDoIF9KGFwdΈI`/s~: W&Gև=7qBtq4xeɟOR#0a?qǊ{SSiK1k`G SWٗ+dK
mr|~,@j`^e^!.r)}E~\@8/m.v\c@C3>pm2/,*4z#b"w2u| ۲"QԾc>,x#M燺xHT)9+ޟiPa?r-t
ln9?+-R7Q^^pD^iֵF~<v鵇 T/ᐙ4P}i`y#.݄4
3h6%nA"o6,mYq*{POz ù.~k+CHFNm2!e1 'ظAE@U$gH &4HR4^W]ĕ?>=ۿ{N2q-	H,y
}76Ir򷵠Gԙ):`Pf;PdZ'\K*r	*/{nD|\H6e.>"
(X,mϡmj{"r(ϳɢ,g󯴡&Ϧ	Y$͂NcF_6v¥^=gpfbߡXC}D~MOrD86pnXW,oK"E((SkL{rA	ecb;c` =+C;@'U5c!,	s@xyXFYlz6S%'`0mF}#O|dCm6Ȃ^g \kiB'6hpw41)Q>q3n<T:iO t4mQJpl\`~.RGdp6(/#H6o2]Ӻy;7~qdƔK7	$D L?
no?&q?Í8/2F>$Aœ=pqBxQ_V78$w?ȢMF.ٌ<3H[19F$-x&o?iyÍH~r+:pODs Wd(+9ǰ/FVT}|xX=E
8ԻiwOH/.ؔ/HzIWDeF   =&!VG>  IDAT#4v
Lm <[j<ÓLkwirqɘPlnѮ9b8tziYN\횶榮ʷd[id|+tqᛯ/-KEE0˟:=LgfNS \zx| Si+Q`	֔]p`.$W֤^9i6!X8bQwܶ`]>&uC>{(b<V|{|M?
&nb=83!
f|gh!:@ٸC\Ɩȏl$Vs[Ȅah|C҆-Lx^Gȓ%\@CIl|>Z^#}*9|cII.4)Ju}:.8-)*O!=.hܖX֍tusZŋ6xZ^hΘ+N5{XS@Ll֛xºȇKpcA\p,vWP+{,fvuSNkam;t}*:Fόho{[fME ^1]Us};c|_EGVx]zhEV]u9BM N*,?une۪W$>MV\q}q|gP悶,v!Je棎9_n[=cD;
~X%_=#Y}{)#v>RxkG/}5cCȱ@Y:>+q	Ap*K{T6+4w˻ 5}~Z6 =`%+`X' ꩐4;9aX+,/S¹RiY&>d[nCNv::`IKzq)|zcQwrVǦ#lȜc`?X `JЇ֜ݻO z3.8;UZ9k¹0uW.CJAN>O	Z? Mƃ큞K¶9h}07SJ#pd3ˀpx_=)iDWNsFM]Vj}4]Y
>t̲}m]`B'hFB7z	3<HsQU+g8diҗ {\,96< 8"nDDEM%7X0dvc׍D72r034H#{8jш[=ǚ"xc?9y?tGP6;y'^?]C?N$JBڕ>=/Nxzqn@~_KOoOn\j'NW]$==Uӧ?֟ݠ]( +?NO;QoY8/Zo%k\=}'L/f Tnδv[A׮uCJ)k<sHS)d/r`'ܵ9Q劏r9rd
!"D}cYO=Sw>q엉`\˹L&|mf[:}<%>ᆁ, }uANx5@k/=ncKW%6Y\\nY,rSo^iܭqwѺA6_61f`ܝO a@Ƕ;2ZxwilIg3 =bۇ>n"lGؐFaK}Yx@CZݵ=9pSOtڽ6O	jo}t1>2k9m2_8N6?dPO7K[I [.]ej}	Ka|ׯ]~2n-I&`/\آ51CE8,|.8Pu8\.6A#մW/+)<3,ӾTл|o@98qp6jH^|}]Ǎ,)WZ>I5-ðXJ%H<zwOx;[]q	k}
mbp*64F=RUOfӇM$WuwŇ6C6< x~}t+F+/d4m9pХ~dCG|r/cbǏ-N|e練m0"f㏵&	,zkm6|IE\ϖ(Fȍd|@D7OnUcxb xXc??tE~gqot!e\^q<)=cL맺؁E{ĨC](vm2cIZhk:yX:ěmkCe3VyG#*OHYi+ 2L+v[7\۾:OVk'}ȡ|*@;ѓ:WjRmyg&y/#<5F}=o<V\`8xsDuK:'lܽ<O_1Cum4( ٨{'[ይ.w$LDV9Ǔ>|^<Q3}!-y  !?Ӌ43yߧ#BXũ.k#|W @??^#k`JrPV*{"4}F+CF_spA(vj+nҴH)qWf٩/ԇ1}Txp,MXt^?ܯ4w׸mwpGWQTe[?	Kd*;zco9=͸ƓOOOXš'DIeHEAof麮m| (#ΆFp*V-t^vJ:6*23rj$?zu *fU\((?kf]3:3R;ڝ0zV[ $ZTa^`b-toF=<ؖW?^U&jv<(CgQX]2ϖi%,Gx+o7&KCS$`ԩr5=F:,&XO1q&I#Q>:[>40VjĐ:/{	o쀞Kަo\P]-^79&VPQ$pgUÃHi_}R
$aZ3 Iv(ǯ`w/AAړ/`m<@c+j}3UKW+$?Q8?o=_/WA:pLd8MpϦjb+at,ecBi|&.x$Tf}7O\F]@$7nrqb呾UV6㬋0:SgwGX<'.@cpç <U&T.ӛCK?nAIQ W~>kҿ_}z;~tӭߝ6~[~_t*ث`s|z_ÿtOۿxߞn_}=է;;}N/O:}?pz%<o_u:,՛<=zqWߥ,>o>]gutNW=s/X/Ʀ37?g|O>CMtl6g{߆'?YXQZGr9I{vb|hW[CSw4bSh  u<W?""}y9119-@PЩĭH9z}ړz;˼Αh?:]~d~0eБM xlel[xΦlr <HѾ;cl P*&ZtH6 YuJ޻k[%1o݉Cck)]xyla3)T8Y(nJy1WpZ7:DI2o6~sz:۠>{zszᔛsHٌ{Pp9KODl߰>sXQ}g`	6TC@n5-oBfG[0 oF= V{	Fwiw3ycۜ+Tlw.ԦvP@xBh/-Jj>VIa:hƯΛzF2.Hh;f?tD$QƠX4~nFIlk[a(brdM׆vN_@uY (l:#hn1+lYYƸU!4zH?c7[{@Ȱ%o: B}VvaٶF_KHYlk˦& QLx׶w~ !(Xc"+iAc ɱC.s k~Ѭi-A؏VK'l(P6[9F7X~ 8Fa$'844ݓi7X`VYC㆒*KP,>Do4pi".gk_.<qH|<%MX!qPKc>5§kf]&xeZw?#駟zCxrP+~"{׳~O:{O.~OT4"٧sXC6u%eeAI>{@'; Sp:~;kk.$4O6
/6|/pC?{P]qs2̘Utcm>DRGYǼJt_F/7/&;EmϬU6YzFH>2MN'^&uf^2O 3ʰx{xufqE0ym Da|~6*~mL&0DKV?\Rb
[VR{'ᰇmi!2cSwg5>|,f*tH(m; p`X9.̤Q66ER7>r4R#4܀y7!GPi7.lgXi8h?"-w4S};,lyjGi܂	T}Ь=%H觿qҳ[&՞ƗRԩs!#@w$	A{?:mVf-YA)xTz_BGbKd\\¯pF7Y%B,(sUXOZzCП*}Kh٫0bWV-Vm<Y{)(#f<WB;$wwɃf,oIp	5A빥t(lIs(j E<Jfqp	KL&؍"(!
H8p@$!>[oʃu30vſ7^HOc1Xqaߖ?o=j.0YqNgY6d+t/;+؁Tw"@`K,,lye&epEv=W̐(}5A,h@zd)GfN|8n`̑YAUkI qYU.B/]ŧ?zzuYџ?]_9t+_򯜞ont+uOo"l;>OW7?OoOƯY'No~n_{gϕO~N;]џDK{?_9=+?rWv#$;@Gk|y6#O}u{o<=ˉӽ?9}{p;tq@d3ħWӍ.иvlG9X*<e/$7o2wF0y>=c/{^ iߋsa4ٔA6޻J
P?Òϻ ɟ:q+ب9FCX+ 9ؙ	,ˢ :0M( Qh>HH/\ve3B!oȗzӏ)?Z|aozʶZwoVz%@܇ٰ`)| A.dic(8lOȊ"	od9Onݯ˚E(FWQ5]a&e)yCk#\2ˑ^B6-.qPBKlӶ~H;'⏹МEQ\%k$	${d`BSd|u:J|>(s-wn³h2.9IM>MadoMxg QO4R=}h+㴻2HulP(J\l/s>~5v>	wLXiV	g}@|ˬLɳkH;"iIxӾ쌍CyrBWnƏ?@kAyW'FF8O)bA6){j&	ivDߙou`jn	8w䫴F<|nH[bɾqD\p >< ;ଔD$"H-}Fw0~(lG8fansg8(>}xJ>+'|V:)X[c tuN<s NXgs
|SsH_o[U{cp͚uƠ_o隖-!ƣlR$/r=VWp ڰ%Γj<YCf.(;')kV@ϳfJ͚'}2Gَ#?hh=쾎= eBfxN>ky#O/[{$ <'#>3,m)T~d_u?tR(ެ׹)Ls;:_9^ቸ>zh)} eL}2ꁽ.&;Ys
Fl@|@>ӽC2K&8R-^9WL%`^+yi#N%<^f%D4TMN]=QpTNc~ݣFVnb;2Zl=lǟil*#x=Bмyb׬ =;=+Á'xZݦҷoNdǸ;R="igP^Y`]`vOLgd>Ҏ7hs_J93$gi#@1Ȕs1@-LM!o27n\9}xSMt숳ȸKhgoQp.w+JXp1KQBrٷgx"hBCi'ޕ?*dx,wNZ X8[pFB/d47 [,HU>$7|+R1Fcjtnq÷\v@>>vJ!3C#3`;wv(ř"@1	_Hs-h.I=&&iwjpbNJ:p<Sh{&_aڮ)uP"Mo"Jwm!EG\08ui;+[']VIwe'H[҄ӱ> SwM17Go&,y]OpcL,Tt4Vut|ymIamVBGMqa	Wleˢ	-+l&hʚ		WةA_ӫo#B.?rz_8=U#uA5_$N~ÿl?O/
|9\#twF/YH췞~/ONWܧ󧧛G]W%%뗞woGH_mO?i%Z QR7^F7,:M{qӛW?tz[i=8W7Gk&oz.|gO=o7onSkwybJ"mɳӓ𦝱˻MiKf׫7	=O9+4 ;~jd;ɃC«:W"E;Oѓl4yUu=qAݘtY_"P7^ETt	9Ea'O^AMKg}~z&Y _saq	E#}8?}(|W*zhY9œN0U~$T'.FX؞`=2i(~82yŵ%\dl	*^A~KDE xD[	+Àcg3K^`'ٛlӒ1E7 8B+Q|J'>ڎ[y#yErۆTCB%+Y [,"©]
B7ˍ[ی{sQj\ƬkQ]vG65vaг'OZuw	f`b&10$~^-ٞX[{[KX"OE00 Qqn9__y2+X('48Ɏ9Befvi}%]fdBv%4=n|'DBG3b#q=S!.s ~JP(tPm+vןD	H6Lpth}%-ޑ}CR̡VOkLl kS0Ъq_3mCZۇb19$ VQ鞝DYjW3.dskygv/oOK$֑>EwF~߅D0?|tMZ~;hIӖ3`C3^\pl9y~L)ri۹auot=zucH`~XP;ִztxX0p}FR"~%knNgߌIf>u(e{e=&dܙ/%.7QOr>,IgL~gMJX3p15}pQ)z??)s浦~Oq'<Xfzz/J/wmc)Wq@z5kuQph8WWe~9cڜ50ES׿:hkYģN\|7.Lх1M<nj6n0_46 }cB۹lu}2U%hs6Z#PLSGuEp	\?xy&J9'\kze"#quֽrS?zkCnS(@o!k{ϟ-9vv3Oq	| -4DѧxS03ư܊ }|_8zM|{omI*CyǶa[ɻc.&>ܹIw~QʋG^2s47w?27o\9}7'O9sa,`>cҧw`&k5ps>B0Qh+:poǏB2}hѻR|ig>u9@Օ@|\\xIYbi_B	g9*VMY\fFxm"5cj'2op=VLmV61~& 0\wh6!Hxw`AЛBUQ8dqb-:vۊ:C?4r~\@bH?"γyǟHE&?N\`
Q'8g߷	ܤ'ё6nu󵯞~$)a0x3]LoDT7ŘFćTmMRoÇ^se$"pk"	5;oJ&?:3Cǅ&.@P\򱡑|{Lpڒβ|ǟ?94/://<}۟?9?tzNW؟9}C[sON_ǿt˿SwzC/8]t<;~.t7Kozv~,?uz?s~+Z=򽧧?OW=]9W?nV>ٿחk?o?É$qM6ƪ@GӍ믞[tNٰe`Hm6KXE.%+5t&l)zAv̤$tI^.`K
7 ݌(4wyS\&m69ufbL^~(?86oL*!xpV.@ݰmf𲠅m@[7Š|O<{N6hiy'w|s͂ }QwƁZ^]pq JkY,)A${xß6tly],`.32QW#7?Խ1Cwo ̆?
O:u`c"d>#'66vFzyhO=c+qVvi+ޟj ]T` N;trWpJ0vt:c۴-Եz>KxuWett7'M -}at5TڧBs['ıK>t&6baÍìz.{ͩm$%(tn` 8#'؍^on ~VxOD'ްHU> c.7Izd\@۴tilߠ.?><HMc?Z4)'t'/cb6?;uLy>ѲW
"txhkҁ/\غ=xN0~":Ra%W?;Q+po`ıOm2#ѡ`:Nȉ[LxQDDӠ!$z[6WXs_9JF1p" /ƾgf0-=D]Α6%+oed(t%d=hXS$W@Iamʪ{%͹0 H6Mț/G'ͳc-'>>0@Je7?OXs>uOo7_hh 9a0k[&J&`ìA2똴6uaǾ>Qe_WG[8k3xUr.>u)]fO=Hy}<8C'7$y]3֨n 򂳬а/]gc1e}Ѿ+ԉ7+4?%hmߧ>U둉>qV??YgϼMb88{9yG;c>2w6Bڌ'nޗ쵲aœXϞ<Oc}]pϞnN/EmGEq5(gxJ8>OHT})r'fT}XO0͋7<mwͦ]@ZZKoQ9^O{!EWZWM7ĔX>ãԇ!13vL[xV=6d\2FƀzO휴Mj.P&~5vcyQP*x Y<O
.>:w+X-R[o-dk^`ۺ&<PG4tğ>8i?J2v){kG7xs;H+G._̊	z+m*h~Y6Q{[bZsNf0O3ЃX?8}f1e6*nAI0\Ġ;UWԅζȑ@xq[ޕv}82:ۋ!.C+X=nB`ȓ>lL?~9Y<亸&:(4Ͱ%8:gUvgx?,Z؂;'B9Mo?#gp+vJBc
l39@rBϳNo~&߿{υv<kbE28 \p扉9H$`ٌ8>>!ܑƄU={xғ,*Y13OOↇ~ͽǧ:#U~{L/WP0Ov3tD7`LfW~>=,X^N?a_5[>lu{<9`Ǌ JI
r`𐌀$lłD`ȀG [(6AͰ$G#B\s9~kUUf͚5]?0}_wOw*?4\e~~	 3~ĤA&*C֕N_rmGZ/i._Xp}B>a,dA::)C&td~<af9%Nyʛ܍I#qu3A>8A.|_@e?ţ0^!}<n[aLBA.N^3MPɩOD/-*5?ҋ tOz8ⅰ㤝P>/)}FsK|^?ho/Md-*i'	4`kCL]J֭ӭGӍ[9A<W 5[fvw 1[uүW8ՓGצk&z-@`+x>{4y~<m9([ݙlxsU	z~!:ȝeȽM~:8K!8HUC/{ö߈o7x2`Sc}>۷#+]~KeсYxQַo̻U{Q[(iׅ"cKnEYHzT}ݻWJʔmě:Dd'rj'|d:fsCy-7r/*eW@9vh*OaJX6~6x045B$@U72k<0f&p	Ȩy}ܕ=҉@(W<6ύOFIU@^x97Pߟ?6'Dz8xxMrup36-ķ-:jî;H?	F^`H#ⷳ5IQk{Ho>Qԙ\vsUf? _#M	6͞Wsºtg6MPe݀uQW y][*FnJ09IWoF
6gO?CFȂ%?9/:0Y*wEkrnso0/nIs/оب*bg<m!ڐn^dODc=wMn.:<:njΩy;i#{[<_A
+6U{Ґ-E 6虳0Cϛ8|fNƚ0W4r)t0zWPmZfUd7 sY|OƍαVX7No!Z_GToPS\V%Rk wd#67 +qwrx r  v1Ggݛݽ맬Ã绱$߱<UyQN)#\9c@:)3 cC?yb堮g#:v
1TS9px6V驳/Vn~['k\!i*׍B
,MsOڨBѶ/<hBMQLos{d&eHW^w##tQq<|UR)7@q|K#Cg,C[oHB$f&CZA?S}h&)užxgFͪ!d@X'N& ¥!
W ^P9IE;u߲s0+e*e/)Gbcu^uF[/'a0?vN_Ⱦ@EK@ŦJV:Y잣N ޅ$K\O\mEB NAd+T]Ǯ 'kͿML8*<$O\w:#Yq1H.ch*nG~bք!/vGlA+EkhVgZw?]D%3kqMa!4_w@ǍI%긝&<<V8a**iK5M-j2QM`-XC5c)wd1cRĦ
O4M<BecN/&$'i9$"{arq!4a2LtRhÊLX$"mW֟4}M'?ִؠ(_M/~v ={ִ_N}n6lO7h;G09.?W}0ʟ>M?OLݟvrznO޿/M[tWiof:lzW'_?m|ViǾ{}>=tO/}M{?;֤W-p AWyBGKbzONgӧ?8}ӷ_tSfpA8YyVUcB_6@(.GqG!u\[eןQ7xJŲM5hM L^ ):tgL-&sSOy8Z#l` XmwXGy@♧l69`oPSuϝÌŁ@}+7CZ^?$i_i	{qhD9?y`V\(OyX8*3;s:r0Ql8}BPӇ92 32m;O_p>@T:'ֽc/R+ҷ%k&,~V=a2puZhrrY65'iY]c!0~68{}p0mRy!݆?,>m
}t׼b
Շ|Vhy=9{܁HCx NC5as~t8\ڑ6)NL^nz-=8څ	mjzw;iʥఓ&rĽwNByI?:|Lj yh$Ut-K墣>,6N?rz|?<0&z!]5p6ʸܛr/[h:M6wmߛr`l0I|x"3<ݖH?nN0˕?-״2=!%|@yhy@N}?č	l<M@,Wxsr+sVw(CӅ̀ՙ+7嵄ܡ.o8~tq)~HLx !ȟ|)>W\	eYqb<N><D؞1!8A𞢇q}]k5v v8 :n@^p&3ѷ%\5+-c!"i4$
G)AAS1^`3t:
(@-n|h/)e R]#PTr.loc x%|\ zH=Fu%k(Y,.B
pu>d2Ϯ<t{6M.͇qT6h22Fs|sJͩ7o7NFnH$m vwr W~M3iS1d~z|  Ύ4n\|)Gs6<P;
HY±.`mo)~-SuZ1SzJ.逛2Gyw3enmC4n
{]m+_<?<L?MA9+?2nX3P6*dlK=W`Meo*dMj!n<"xm@&䧀u.:䉛N΄Wᦨ+ue@'%\|K=vz-]֐Oaό0:J&iG4xT}3vA3[%v^}SV ۮ7[?}K8Sp>elL,4_!sYg.-Q.n m&EZ]pk]wDO:/Wwߡz<Z$}sIjilg}v\`tl`э`Noi'8>(aB?)9eJ]3XC HFJ/%+Ō@>Fq'U4|Uw!o&wBH XBR5FД-a0Rb\ڛ6:x<yVd`3DM8DvB_W;Z CȈ	|7|ϸ^#UrNa7po${@r8؍K<q lm=aN dŴh9Ek1`t)c=I.i/$̗8/ԱV_3WT-qgb2 h?
(ѬAV+I%хM1C,d.&t] &<Nc-Ć3H&E.u(<rNW6 	HAw; gbЯC #P6Wx'2tO?2]/~	ߝξ')}yK?MT+>m~WM1T]ΑِᠧG3i7|}tl.y'_"0ƹ˧G{MbO?`7LQwz?7}Ӄ/O_Ii~~oi|uJ^9 -~b̋2Ax|CΜ2	WigERx%>lBJ7WIT@DN_zbɝ)_ofkc;}]&0'U/`A]$ 9%l ޸"2t~~Ű ;n+^/Р3^<fOŵ ?6`<dr$^:H&ʓ6s#<Wh<s3tc݉.I.e.o&>u%Ob"'xE,e6}xOu>(n`}S,#M، 36kOh~wAZu!LQ7l?QŴ1,]Q_J|E)*nwoA-#Գ~GJWa®zK84|OHpN<eDJ*%.^DE]ys_UGP3lp"WjOs_S^mԛf3V??Q4B$o'%A3LP_ `簘AK؍77Z8,x:#8h5Lt9ЏCH0ܑU!$)lkn!c[G>OVj՜Nwәۢۙ|āu{$7Ctǹ~t`7wPJM?]ytpq5OPz֍i#IkoݚoM;b^jn-UH<UKJ_Hf.7jШ]44_k/<AbFT&qKnwMJ.dxŇHx,⅛H~,.pב	\]v-FXY#+iZW07輛Vy7_A/5	k< M[5`'	AcHV9-}E	e;`hzDH+-L&+
20^nÿ92=<=1+/,(nrƗ%!\Clh}YASTiOtqhV]q](VtDoQ\2E9s~l^ōJazo,0͈Of0>>r&/7moB>sǞ4TvmсL9lވ-]8lCd 7x70wE?G	,IH-NOG֋DDX>C qM|SǺrS͏4碜0Yjf3Q伸NvюcPrD_ai#'egWYPWX#X2>0WyŶ\NO +dv@vSe1 x.3CA;aya'z	c)p<7Ok+a^9n$FP8Pz.#&2΋lKQ4AN":lp^y(0)e:9+szWoP+|o 85OyRsT}朩f	?9nv
aʶ븲Hlڟ`|C#bq)Ѕt#9ۣ%Y몺ǼӯaP?)>7	zkX~	-fvX$%ʧHMPb̵W4-s'k9S#@-3+R4M"cAǤ"w_fK2~'a_36A(RT`\si-O|i(a;h%<-fηbcF6tџړ@1{	-ݰ/1!2-JA Yeky%Sh^v{o X]24p$+]H*qX0	? a*wXϓl|S~Zƈ޿ƘZd:%虸rlyo+p/0>0k^7=dkʴ8%xn׿_a>=:~wO7L}<O2='|NξTva҅/_bP_/wM'[_*|ꝉ/??sOM4-l;F#̓xqɳt*^w- jӿvze;aE-y}I1ġ2w zDCl`qK~t~txmSheS)nڞ߇L^!^k绉T3qd 2nR'}r)}+D+Ux"܅	hjA;l-}ǀF-~RRn:v{ו."S<͇uorH]{2,%E`I9eC\=6ҩGܙ-1,r^W>Ri9d:i:<[.s>QOjzcn1Lhb(D7DKC-w*u[C[#x|S}B.ÇÒ2:eAO'$P9	@K],nWv:G#/:DtCѧ޿>WE3%Kt]H^BG78p9xm;&ORԏ
;k%rYw|#nI?F)m%u	秹dh!+'NTo^iEyH8;-vuy- '`[\KspY{hCgl06ܢ|.j7o6tS2TJhRze~+_zu	tlQ2bdON7!t睷| AnM7v>֍[7ãoy<vvTӍ;@q9m)koAԭoMG_W794:R9xڣV_HaF2@qnNwpx4ze'2Pm8')F@]Ciml:Z*'+{1O@9z\P[6ayz,/<E!-}!VJ+\&`WP40K搴0f箒1y>,8 lہl &\>jx%i2ʸ`ȥmBc.L?nL_{EGoߥ+:TNdAq7'΀9VaN_'?sq].qs%
#m,\B׺wLeE6Iņ<<nVп0GQ;s<a~Hz<ΡSo6KO.x_'$75?S7X0H?c{:xk?{>w>|lmchm9?hg,U?åk3>^8e5Լq:߱UqOd䉬!n?f3kB֭ۚ7I|7,³V]'$_rc)S#NT='qOux^[˂+n~aO2	ݴ6]7^a%cĲ
"lhOHt A0e]y73v+w9ˑ:OZH"oR{$琑vdyYso89kgK$	-	JƵDsfLSc엃2\?PƤoRǲngǱ\#ZR*pK yqϰ^}'/I OiKk6a*J#hcT]Xm owۆbEqJv@}}o	ՁcVX|E~/1 ;BvKM$p=T
JWeV8[ܳ
䶩xOMLB\LP`p7siWV$M0,m|cɫ]7ʎsq4Ma7_Y?`ʫ A)+c>.FXoɇMū+0҆ G&kxO~ֿ4fRgg~fUl~sk_d[.PduGV@"}?)0H*(qgk6C||RA ;X `GnO9`3Ǖ>(}b*Tԙ!Y.TBtb[JOz4`7E*K*h!7u;m~WL;Ra!$TDrǧo|}ӭecb:6?^4}럜6gIٯ?~<ML/Gt-_?Bմ[˟9ʟ=oNS_5+g/d}#enigoO[_uַiS0>@cf'o>-7|+h@z/%~ts?1<ƗӕlWZQ<9̖m_N~WO~ϙ#I5nHCOpϝ>9lQYTOJɝoEL
<_Aƹ^֤iW&ފ%yDpoi&98Qy5`C+$(.l4{'%qb3,wH	Y1tlnϴP&I,Dj?`*eM~	O!#nb^ NA[Er)ʶ+G¬JG]~IKt p>
\ŗrKN1d!HNz@	$AYH
j>W0y١ter3paQ>;;UZ4FSd~7e&)I=z:ÄۇH֯bn6Tʞe*߬ }z|Gd7 k{Ric[4)J9H3I|"Pk-@DX1<#k}8F-@ĕbph#'Lxz^JO:e<}?pC͛h%/ܑ1x25G<w:xb4!W[TSWɣe?))_ԛSH7sW|0l*g&<Cw*i<lư)2g#w3ԛlI92c#OO?.]޽M"7|);oylpD<Pbev,;>s *DxM;Ѭ11nO8^{-M|FȞt'J7((=M]k3pSqc_	&+ٴ.e'+*d/0y.cʂD ]?xK6?mdt7qnl:u+gɚx!ӟ=ªѯPA?,
ޑ=.1R'``:u|%̧4B^83/0	יp~Z:4@@BO!zpDyf8B
N?e0J퀐%@ic8@S/lRcGs>AP=T1z^EY-ŧ<^#ʂ1ɓ'y;-1?Py(o.dd~zB1dbNx7X;$ԩ=)~В:'=$įhsi@F̓S21f2K7Ih=VQZ },7'2J:)	> cR:1]nkL5i_LBϐt~a)A_VPDQ~Xv߀Ki(C?׸*Uۉe-7Bh=\1葟lpGrȫO
0V3})jŧV2c?a/0`ȸ;)}8񤋌="+y!y}1/AFti	 7@?ʼK
$}.pY3l3F,u{r'T4FۖVGe:Ðbt]e _7AؚHPrS) 哟pXOk7݃b v̍1ִeS쮓킋6fHg+~ٞJg}QW!n^,LK[t2Nq[fQMj"-]!__6Q& 	/v`б/suܥt6tFƦSI_
@C]ҶY4|!\.I9.u 1#kkF84oÜkeFm5b,q _ao.3@#syS3=eQ֫NJ#אj@R5wy!!I)L6g ȝ$dDm2Y&8XS*P|Gx g?339D	 Tı8ӻoxt^UJ`>x qig󛧽LwNӳi}ŴOƫwnMӓn|WM;.yТ
9~o}v?'q5<o,!YE_yǞ9~>ts${7 <GoL0Xp+"ɯׇק?=hC"$ϟ{S2rsTLTޚ]Λx*ccWIg	C^1U<}-ȜȖ3JE|(~/pL@紡q=̌"
u,&cB|@8aC1>yw<?! xʈ/;\6gy}ULh͛G{^59|ѣng w,yud1d*~ʉMynA>l×;L[qx<ec$mSn9mr,ґ9^PF%;;{5	:^͹i:H*RM%bz*r_(0wf	mW+'~]pYq?ǰ0niǼORx yaJ٠[G!~׫[79eI+ؕ	CpWʨ׆u<a^ES;|#t 		ny<3Pzbn1Ƹ{q׸K'9k[2$OWFo\:G莃e9r8<Ju`ӑv~[<Hѣx

d\-8>F-bBVTύ-Y|s܉ԋ8խs4n☧ˆ9_T}p|ۍvyϹƟ~c Ιʛ%nmO}Ww>mIYF7ʮZX
F	='+#ʟq_S/ϐ@}&pMnK~]ƛgyMvͯΡcxbO'hp뎟^тG@[TIԊcs)VJ?_*qdN괯@^B[`#zCxHx58Kl65laK;Ae_mG tv 55/쮺hW_G_`ǝ五kX-Hb
k)2ŏ ̹*{),~I0n@25
q_\"brA9~E*Drdp@^<MEqtlUrt\J%@.7(wXtu㼊7%dX%NEʜ"#|ߘx֎1yM}.̶xT#@
N}G;Qy.EORǐSn+<MEaC?܌~.2HcKѿZ<	8-]RC<770{$߻w?\CDXė3xaq
A՗:/2v_t+֣mh#0_PU5afcPJgN(? =e$IR,7,)t`<X\lǥkeb掱m 4"OW]GXʒ*njPfĿÏ>7\0c<4GnБͫ!E0kJ.3rR)hmČtpSΜ٤LSO^ EOsi}+ 4ӕ)l7}L&PZpqU&M.ԯi~EߢMm7z0#?PWx]o>c'?M}:qhڵeGեmh_68gm76Z~nZ;T&kiA	48zh	wa qm28Lh+q4U.3w?6sxaw]HXxU~C޴ƃ^cƱ?fۿ\$eH=6_4YJ݆.A=\[jz_.̵pX 	03'B[ɣm4XhEۆ0tG
q0LRأzC1Psh 3dnTu$t=d0bZEa$7BxGK$_	Xa<Nd`"Ģ¯@B<]Gf9~fze_K_W/kd_9vxfcd6dC6NYfB{^;ꌍSo74i߸}mڸ9Dt7]>- O~tDzS>1R+ֵiBo彿1m}ʟi?7_RB bB㺋L|q,&g?{w7ο3?m鍿[`{)kʖMBȧJ8^oK7wxГ/%>y׮w9INDyH|&lʅei~Q]qw)zԏE+ߒbP~{ދBۋ]Ěf^;y%P) ݞ A-.IN-:.s/\<yoQ&oʏ ߿_Q^Wн۾+;AYGw0
ϰuvPLj\:f8YqHHf v%F3:.y@ଁ*/	m,-?fiD?shW8!DXx0m|i<*=~v<;^i
7ӤW0ow|e^肃>:n]0JN "PXjE8]Eq!cąrfze'LJVv	jcϚi0NUZ)LW)]@.eE["Dw<@xdt}?z{Ãt=!Eeyŗ3;1*Y*QR&&7Pg*M?5KGIN^+V/;訯,+fӫٴ8[E);e76ո(va5cG6JR'.I˜oSc#)It'R
E9ZCgw=iwo{;'Ε?_ zϿ?}l{}>/ȍރdW+qݶdRRly;q^c>75;
3&$
'H%:zZ9W3O}eL!SJ*o3Ƚ:s#lɗ%h]!̦ ٱ0tɏ%@.Uq$-ʉWp3|q=2T
մܗ6mR 㛉Bh0]Lt~7	Fz{Zͽ6*%\sPѻ>t90g.)mS;>\v- )GN7GI'>`VeĘB堜j/^)OT_7OqSif4\>n|Emx'&	֞脹 k 
1~	G~wmȻuO
a) "aC4RK&in|OIOeJ0h4hڕjIiimiu/t nb5ȒC8tƕRJZk@RBp'ņW8,< [o8,}K`I
yRwXwweV`	D_1QR$,?v;c	R<2V32lL NXuTQ^qaN?ui3v`U^e\pW|2} 8!sg,G7helͲ?ӗy?`%7@{{eRL]ǁ7݁P\EC\ Ѥ18g{0XzorEwXIN>LƧ<X]l݌026Zj=ɘƓk~plj761%O~0	HtŦ`'¹lFt5"hr$n\؋3w40M9?0Pna9fumuV<T>+ð*@:fC,3Yn~܃![H*(+EN/C7$|£|wѮb\ 	rdCrsYJ]r/$LF[UcPD!@v[<08pF9LP*Dq++
,A'ə BG3	퉮<'̙ /N'3o=m_2~o1mpM?2ǇO'{W/xIĄ&$η'UAGӝߞX \E7L'I0y/iӕyнe_2:|:]?i(}W?Cp>s7^?2}iwQg/SYN| <^m J]ɗ܈F{P&\L؈G|농6(s&'+wߟʷn[i<Iz+{$2qy}NI($|Wѣ'rsjl(9~ĹA ELB]-.yrMLd~t	pl6]Y$LGՅ|&׍P[օ<i6x:<ɿbns:"6|7-#!<IB[DJԤDTyI).~t깛nL;#Em?<%)ngtG[$_;
yz-L6WwlksP2O&^(t(H
V DnHzw+l mF7L((\$<؆L7xC۲ SUm,̨_"o_+;fmz>·*76ITarآoOue?W#iD踦Mp6C?agRIvj2QLS///Ae&z;yM_1CAFa&B#rq1tg'yzc?yMix&O2ysE4sM#OUGL)PuWsx.^m9%?oOOlNnA#6r>qOqAF+d"|[rޖ^q@˓3w/(xivb@>
8ڣ{?EO6ngOc-<?yy4un_e\䵟CC9)bE<u揵3^ TW K{&l‧9ۤI72s=_Gy!}
}?I-lD]UwL.ԋ٭EN^cqB@~I^ox3(Oal1rL6lA@px\ )GB>dTV工ŋS/36t%O2[M/ahIQr #+!ZPr?hMס%@\rE&?؄c-t۶Ē|R7)@tI=\Qg`<a&7w*=9Wh/iYJf\@YW0=,E6ne=}q$&Yyr3<qāao|ٴOLwV@?onMW~YeeX鵢{+yǽnTD$u]4YogEz-&K<O\T~Yg58~O7盼`RucE7,XjG:8$*O]$'mDezW:<
z.Ȳ6:f=ib gO 2}	Ƌ62ߡG&CO8٨_qh
.86$O񹑑tew/2\b1_nh&CA[i"׊{FʧXRǉ㹏c? Yw05-4-fortXӍ݀1gaͻOsD^`\TfOxb7KX /f7t9\}I܏K*ig.eWR#y:%<'pV'D[a8CrE>eցs0k[2Wy/lpԂ7.Ln;tZ3kwmʯrsv,?PyV~EzǑ+c\8$<un"^%g(YwEWy8/YGUt2r*& G5%*̈bn?cbqdshva\[QTVj

޸@kL.QFlXI;Go$2P~tm:3^w_K_M DOwL_ͯUKo>۾ּ3!#/}3-yp̽ɓG~	dIAث/3M+ߟMM_@=WN_EzL_*wܯ??1MJ_OMonN[7AEEӽ?>1zfL&x*LkYv^['bFE*?~G6o>3\'ΆN]nO<+41>Ѣvn!uULn	WY_6vHGsb퉧*{C=6	6F|O=?}:=b&DJ@>GD@,KX(ep¶Y'
uuy&<{y*
+RQ<x$WrRϽfYV+/|+C	o	F2O6NWn6+M_+zxr=5@6$4>H	tj=[F6:6M䠌bq`yދ_l lmt\O5)>c;0H-)jAF;9lo⛌>8?I+O^_fXpXuSZA"
;^Q:dp`+]فJYWRu[4[	D֕z+HͩXrb*9kՇWxO*mCg?}#m.%VD)^~ʈ\MϦ{w#^y1^?:| u]{ɡɋyoRݹuO?#~=k<4Mnr׏	k-Wɦԡmj ?xTyۼ9ms0Wi{1JM8<LuQ?	xB	z<{n+O8pO]xmL.h캶~zQ}߿6ݼqp'4bGu/el^2r;1_q ȝy
BA>6ސeQrSfxtbMhΣqW]̘޾#t筷;o˨ܖxFL}[oѬ^WH@Y%~~ɶpTq6>Z6$>DӾUzo?Ӱ~*Dt+U=B\N1q`n(
y<kY|=M[^c]YcX %VQfaŏgf>WyD>ěJ\@0dӼ7\El> +i}]ռwOడ'F51ˆKI	pںn@u43ܬIrp*"uo2`̍%Üsp|Sx[xwϡfux8fG7C'šuhk F️$9c,Ot3Wm;?\$"s֖<K?:יrJ2gX4x߬ \+N+~\hTD(OPM"OM^p(߮WdXĒ8=?@JԥH |ܷ3ʐRXoHr4Ojh0+4ut6~OJI-s^Ƥ\chr|>9:?q8X>\0+q헷_#CkO}
l9F!)<ae fX֕aIH9H=Ѹӯr>nQxCʒme_f }~
vfNfaKIzE= vzxrmX%T[{[?V}M$wW{ ]X_3HmzLl=_c4j~m^67n7ՂOy!2-_g9*Lcc6&̿f-(٢|,8eC?['CZ3/] ǀ	E-|k2dA7lCa&!mtuZ}lC>a#WR!`2!Vx_0aſ m?!!KXS~?-;S	]TLXEcpO=}g~@<<zaD>JgAIs6Vq+/ehxr:نB6zF3*8R¸Qڌ7q,{H,4db}@N
w-_:HZ4@9U9_SGjӿ4Oٰr<vNߵ?JӳkW_GѴ뿾
%g7ӕ/m_4=[p_5sΟ?wش=1m}1}i~۴5	/k~2x"#7drBwֲch]U@=&"еlJnmX/uFiy3	e^]˔	Z铅bNaX
R+{M)V-ttz0Nz\XP:D999~9DFu8x9&LчS&[k	LODCذMz |!/:+<Ik!
z"LBx^	&* ?=}&ϫ@:0;HxR .:}-+pZe @Y<)Os4_r'ESq9~_#}9>̼||Ս]20dѳŢjzd̗W\_Yb[?r͝Ĕ%u<*״ɺ e 72c-#Iya7U7ӮEO"Aހ.	TT 1K,l.	O<!
%o!l^\^?r߫=ar@俿Ex_IbгHU8+Ft1);7q+#ԗ1S!砉r`H_`<ڇ(A_KID7K?)_}>_LwHi[Zػ/:Dt*ErWEqS'<'g>"cK/~i(_J}-xC\uI'y8C%^Cwyc>B\$҅U+2q@͛ԉ#m11Uӫk%_U3qyoTvW1-cL!t~ܽO[1cKN*ys9nR|b!  mDeG4y.eIqC[zˍ,eI<7}\Iċ\!84%^GБ|꼵c܏HSѝxYO*g8uD8&;aQq(8My0Gg8qq$[-ަ)ħ/&MF˃̘0\@9]~
)<-Eo7%|	}_n6Ay
ϓ*y$A`<(}}4OCqcJ'7nL5t?sʊV-s]DP/76 6J#4|	p]SGWayRst>^_qQh(1Slmx45Пk~L=}.Rn8q4zޅ	Y/X<,q0P&ѬCsEܞsVF^ZKF[=oux'ԣ9WqGecZ/i:^2v"H?mM[k]ReHAy/eBOt-WZVup[zb~\+ea
nDgÁl-sQ~Q80]Z7ܘItBVn$<DЃ|sd<D:ˁuyNyvۋ(	|ASuftN?>ZiOVjz6O&7vAP4}ub6N.Ox<V'Bv
?@UZiVc0UiCJۛԹ-!a!v'0aC%u0m~LvT->{KkFGdV ry3qa6מu1@G1x&.F@901ڱA^fH54F7PeNS{#2F9}8EmPkpq3W9b[OƑ>$_w[q+ÄlG\-TUM~_OϞˆD6Ȧ,^AVat]FZs3c|g@#f&HV`M(#YЃ'-Dڶ}epӁ ~Z8p^dgsE:ZClXe2h10iZAm69#3wgl8g%lr-fhA.lxX8cRÓpoh@Bx]]W;?e/%Wnr9:`(Ӵwm6RI=jTi{bmyh'O.G3 	O!pB	X xV$8~I"g&:ɠ66|rXaGAh|DOGVGn<v^hwIF$5cLxҁ'HoS8$=>O^'5{,O>q@:#U=Rʒq̄wtaU\C?/]{csńhV6#
X8Ǉ$, Ih~!2%GRTNP5aдD^@ZDK
[%|/ڤsIxdtxmczHnϘ&~˨?Mw}Pĕ!ZH~wnu>dL2[FߍD~_;8/}s8X`rr\vfPn;n+WYO΁:'Yyb'Z|'aNSǘhy߉
~SKW^T_d!Ŝ
W_O~'NJ|m/NA9^EO+P_ʏC&={^wxraz{>	wE_Pm>?ʚ, <HpNC^H?{^IG=v	^lҷ+.˚ߺ[tXЪ8+dI@i+={e~iOslZًn>+bq[$Y'^%kO>yra@C~+sdmZu\m?œmz+>卤9ntmT6<q>< Rk$룐ǩ"t`e^0=<Dz4Jy1ʳL敼VxWJW1n tB
Max~hJ6>TI`zv(F@Ӷ!OPhGghN,d	(\yak&H@_a:8/^,eI.3N_0 tO|ޯ2풦ӥ;q?\lTRE~Gm'ArIW/]j5oնhoO>|xo)2Oe :q +(-θ9U(yb۷_=}ofv/]?%[xH]ϟi+[<,Y u0WI
}FǏrsfw>s /5JܾFMhD3f/tƊ]x{Ɍn4|/Ixn{[~7@a̦o޸1ݓ-=nZ'/7PvٻΦR\zS_ӝ=lfġ=ynn&ttsx>蘐β4v"5w^;㠜YQKy-CM+cˌx2/ވ  ,!v	p8I}uۭtW">c-kXPuϹbnT/QܯI9\dͺ_<ϵrvU^>?am.'
Oh1H1]8Ϙ9tZ_mo(.|N|K4;8a؉ 7hїXs΀Fvp5*GY'}|zRKݘnؘ_wGNה/{/~%hLxBVe1,\f Q\i;'-~6(R lus¯O{ptJ-͋5 ˦5A3a"
I:ڠic-eFeq1cGqjC9"}`q`SKw3]Kn$S]r7? ~L$s\_G`T./u]賬B,43"N|3Uj`"[aw&jps.ي_W~]V+Rε5ܾSCTꆱ4'm x?< 1BIdER( Ip1VLEH6P)	"O>_;̰;opЁDWYMɫ aă'I#&~A(0ٓ]F؆S&<--'qD	7$
JD ]/Ī޻~̡H ǼJ
Ym,z8@{}gd`Z(OTWΤфE7L~z
ੲIZ#=A;i;?GeA2_r=ے޶чtW)Q6	'&|,mε:furxzGdI0KجbL'|Sދ+$$;!A"
^;p<IDӇxRsOygz߃aZ쒽#glOUfW`DNCL/#L6@@ ,.Y@#+2GGYwL<^ct0>Mc4Fa&tHĹEqƖ'O0moڰLZՔL[lZM-K΅z*W?mޮ3K*hnr9d-S ⛇ݳ(ރO?I[CŖ$mQ4jJ~=EDa˶Cr;"-C^P]wug|Oy"_5fΧ9~-S<dw_8,{C툾qHDlB5/%NشGTv!wp#;m(gRFãә8cӁfp egE-g!K~+蒚Rj<rE>!	ؾUppH!y'v.^l04e⣻1sJR	7a֓(VӐC=wWZ3W:u{7Z=^٪[kRn^tqヂ=¼S|>~M'$7o(gB崙+vI"Oq<"}v`Hfx\E	n2NO=QS蕱WNCǵ~#-'rf>(rdί芥;!z䁶7"vd4/JRZ `/BoGyF9quY`j]ȃ~g:+䓳 *!(v6y&dӿZP"2/:Q .3ŷI+m%ݵ.(vcF CCN\Xĺ!O a~@DmC~Q8FpJ[XX=1F0n&^ݞ=yqBڏR@8]z ܰrRYwP/yvC;u|$yO>?nЕfx;Fn׎ H约_SqXpuSQfDy
ZWOJߤp9MD }e'\E^w#Y`@hiEޘN'!Ø1C|q7	"鎀ց\ėX3} >ҟ0XrAݍ1w1>X$Oy`o&y2f^ˇ3k@IxJ xnڐO4Wr=5񘋩UhNLF^ ȹ=C'ev/ډ{_Au鄿7iC3&<ۭ%U49W}ܬX7	9Զt`]ŶʦoVO0#1(06ol;fe#Yjm }c:
8JBYu\LOLjN. Z|4O{UUV]XiNmṺt7cd4u+=Za!:jI2?7s3tm7@ٸZpBP9*(?0^Ņ[?!?	+8/	:x -WŵpmBnFO"wY"\(wӍ
9g5(I.a 1u/L&cG#$JGO5}<tvHf7xHT;ҨTڶӅb$+f6@ٽ0C4r
vk	6M&]Mlt9Svy\)C#=T`<9b3tIC ywb՘XwkcBܼLj7F2(YŐtLD!KC,~t8ݾskvŒyՋfC>ᱡ	ؖaÊC86сC8vM17*r 'LgGƄrHOR0yeD	9%Au֊,-6%0&P'x|m@>X@Jlved#VTϟ>yO=jACl%BDl<w¸.Důΐ䣁MdAǂu8˱ł"ΔĔO6Q4񖛸Ȋ,s|G,_J?9$3?6D<u}3Y(Mn7M_FiWYT	UJxC#1Q%,t
p\x0ӕtE" N;uO/-%,ΫK7T2V[;_lFe/ sO$^p吉;ٜ0B|ӿv\* Ph?";E~?d4O)}KSܧ@UiZn|8MĦō+Vq,M_rR'wtg1}AW3x@gѵ	SGywZ
l&rs Y72RvD&op)OpB^ ߅˝7oݴ8$>Dzq::8Ȥn<^]l9pFKk`F"G:f'>ؑ,ެ7\گ6>97M Upp;DoGƭMenO]ă4q3icʿ<-S]ΓC'nc;M߾?+dC]+H;2 tiKS[W;_7`, tr_X0oth٦``z)oaw.|!"{Z0y ᙷ
s_7X!p{ECqJvm8eMS`l'6B#77q~ ^eQUŰEx[-⍠8B@g* g\	܍?2Ͷ{>6/Ia49w&^ǷaNzФ&đ!2|G˴,͗xوL&´L%dzpA{M^ۿ<i4/~nᕼǼ*m3sxw~x]ƒ<'}Gu|WXWY'.&-.Ýf.UtCu`LbƎ=mo>7NnT	0q`@9X<"nYa_l^	΍!?={8 ϩ-It]MJ^bel!i|b)i{6 =@
!vƟzЀ̔%2z<$Ĺ [vB;2%ھfuZK(cٍhϱh7Vfmqu9mM
֌G/c"q.] 3/Vey&m*q<GM%*|6dT۳[CLi7Y@G|\,~13Z딺^c_3SEoSydBCC1SAmt0`Əya_k>Ɇ}u]m]OKdC<r>!nI:j`&X1ts&} 6@x<n<4MgB`lU)9.Pxʗݥ͍
4\:HК{zaOpՙQOfE&BtGJ'ePrO~;Z!6
U񛏌]2=Ϙ{.cxM=DA{<}~42zh
7:}_"z6|6;7?'q؛P!_厼4L#{cupb7i}8HKwW{(O?E$ &=
(\=`zW4Vo0y׺$
PaK%ah B;-nhbL2XD%ny	$SFwjQ4J(4Iѐ3 E߅m*`3?iX^в9Φ7MD_&9aEq뎆G"8NyaIM5giԒi|uCC:CK :Eze 7D̝/9MDYJ&Gj~iV?ۅ]af##hl)LB$xE`{te5`pAuQeJ{Dæ bO>ɓ.<s7$aPI-<LS1i7 詃1w6ShAV GO/_;`l]4ϴy~/uxS^UxKwX70măASO_Gr˿@aw|@jpaKϔF6عYAf:Ϊ0 [ȯI@t{B9Be>)9ⱩS<F||ݸ_ڀSgcޘAbN?eOܤ{1XъˣwdENHi y91M`x5i"jdp~.۴3n<sPS3l
Kx%*e¦F]=}m^/uttTO:~V߂$QZIɋܭuC lo?#ɢ	w&J^	''Ox.y٥rЗ'Ea ҷ'Q|EMIÓ<X^zxe#QhSh;Z,l ^ݖ=|l>O+)2|;OuKtrc$Q)m%'OҸu7z<yb85|)mR6eRnri-;,cm|X7gC!rȍ^(sFU-=ѓ8"A<Ocӈ9P<'Qu>b&\\_j~"<ynf9"c.GMo`TpT]V3p0BO۶%/y|^>tzw%i.u[NRVn?xy ! 籯!N'm`Sl̃Gwȥ@x||V0.̢%lNT9$-] :`ä4zc]]M#?60\~p8GE<rx~Gh~wO-j}HySKz<~Rdċ||}4)C芛(<+7jPNV^@}a,_v)HFXɍQ*ϦjJ8ްEdz	..-r8u˳n+)\oS7NkBie6-:'W8*<WR/4&OBr7$+ .vۏMEtwe튞oЇ}KnpgA]It2VPy&c]3æNez?s̷BK=P!wx1wNf)*o}uޠO5hOuvMKlF,<q~vnrcU^_BcYUt|XW]^YHwT9MN}ɕtHy\Gil2vJNoUmΠrϞ (CTPA7_?Sv-84K7 7p	+8O|ZVёg%^\N:Ҝ,ml-1LD/\U^/}1'([<,{Dc^!oX|>+k0֥_=3.m;ZFیy=eo݊ozA6xQ_Xk-g^ik~[-^0`M	tğ0aI:?yO2_dB>0NKlSzL@F0(6/Q/Dr^0v|Wq$w*Hi'҉W)\34Kz6k4{$^n{@n4	3i?
6O<AGVs^ݡXwDRcqM&^4pţt>u-j@Ҡ|za?|!1&w$t!b>24~5d*&#W-<\n2TKzJ">9(eHA1gw%bJnׯ֑=Xvx"5]qȖ-Po:::h:b٬,B&8,[bD/U^L #|MOǇ,T֦D*秏O'+}WE^"3aywOby2:u<1zno'ids,r;Uǲ'RI =Pd4ɥ/:"]CRVR-'uN(3tYvbY³Y6>1 z/>h>CoJ&cZ4N!jGk{R	#a&PFPvx03vJ`AHA[D^eDKMŢDlNؔ?i&trxF-tlVIÑS3=Zθ˰i.č<9dϡa*.iWm|7$G<eXr92&OΙdaSW[zR66tgz/#㻒ڨ`{>P21f<E?ʘ1<mEYlS2๣Ñ<]sfAO=<#L?xo5"j޴f::N?DI?So}fɏrR$MW#.#7Jq Iq&e9\(Ʃt; |x#%eŁR7wo)-ICU'OO,3>OC+o?pݾuKi\uyZQ;
l~B2rCSnl7PwpN8K'NOc<ܞ{(Of2n{|}ho>%bq~.ne-]xFѿq7oE($@,l;E9Ț\|U:v[h[Ё&Bg1(H
rLu\FnCn(w$/KtMDu=+ZCmx-zx&-Emµ?B{##.ɜ_6r;hg։U|J
,䍍&n^`7:qsYFig|4?Q?EfyO yLVf/K<g
t^uzmo}G^GE?j0lKiFu@K!HgMm*d{]ٌeW3>PG2%blfÇ6ٔm<Ʊ~)32W|M=uQx 6nO˚G `trm8e˧|w8ɖ83` +#Ys?t_W4RpdǊ53.n{zE=_te<^&InS|6knIghap#cOz1Emr*h{^Ӱ:`3~fΑ
S¬EYгed;БZ:WІlr`;evp'.`m M12^{o>`}A*1}
J7'Enn`-ttX++ :-ke^CnP$^^ %B=kе	.[5Rjο|c@KB2ENA?a$-.+n@]~ k."4s&#A2oP@hHbsJ~}45 <hmY3z|V|2&*K_5ܬ&x	
OW';W?։5?u	yƧW2^Z#h-κ1>XrZYfu%+@<NT&>\{Ў+x۹b_&{9`XŚ[ \W#;72A~TQ\~݉x`"OeA!OMKK(*\RPa] $~ؑŘ`1F詜=p	0q[Zd	dOc#(/pd	F|x!CF'eݝEu.}BK!8`}g.,eGRdNyQ)}CxێlqJ=$t\(0E+y21ctP]npCN9Hxt*&S=ܩ(+^}/dYgCM1qczd:=~WMUnwӧA""HM} tk>ی]W︜.Gi&caK}ޓb +}QGtA^L|Qr3q$*CZhAA@/]}ހ)y	S^l*´2;6'ʹӠ;}A2>:(M'@XrOvsZ79"(Pf3RN>Ƀlҗ͝f;0io0QoR]@'[0Z^}GVZL|XtUۂzL;DyHzǾ;Fy
c83e#.!69yT?I+C}dRc\%֋2^ȈMsB`'w.ۀSLRj}wyne֝O6=wdQfl<drHt&wO7ot~2O))wVx3R5Rn|~:>*Gk685OKUSSѯQxJe#6J%7fП$!ьpg?P΢A.|Jn*nʏЋEsxz1tDWO>17'm'A#|Ǖ3'J-9nߺ9\_LwK$Dͣw*CoݾJ)}
(1?s&z^8 *S/R(0>7CGy>_=Nu빞:@;\iW9 &NJ4>?ayZ|3ߍL$n7\ļVinϔ>0oI0J\sʗ2iAPiz9N~@+:EM6)cGsp	!=/R\Bآڤשc!shi'#=Q.SgY,Mhm*۩_YB8f!m?%b"HF|m$atJ8|:~4]?|m%Iϸo܌XԛެӧcIy'e'y@f}^oA4ݎ%}ie?oCTH>Ǹv^n8U/-O,s(ٸmDc&O$2<RO]]pLaU~
G>I4Q)_̂:
ƲZ%Up|l.b2+$?Se.pO&gyh[oH
[W"kY2Bsǲяy!>=v]ub@"7c} ^{Or$.y!E4o`k=(}G'׫v<t2O' <6!3wtHSak3/<?[lnï*
7h(K?.
Q}HCq|:b^wzy2}:}@t"Ƕ6䎔ʏX\sȌ=8^<A`w%}WYn4_F;m6};R$Gک-L,C{ɾ7G4Y m'`	Q|άvـltl'_qepN>aYFOhQF=;ϼpx^:n΢ͦ/	߄3Ǳ4MkWW:̕KHpq|=ܼ
<O[CkȃeW/2Oci;I÷h0޽o 'zI˕hipJ)uMZ009.`L4ջ`AY|o7:ll:fV|U*9|vb3Xy@shMJsfc%bfv.(HM3Ğ
!Ro+'%q3 KAy*'Ǚ*?CR?iGOCALj8#W>0HgCGܸYdOc5H_c=CXݶb!N3J:t⊎:6tJDC/^)ܙON	GneWrP~LFpҹU=]>*:&/^QiѩrЄl<ԃʉO~sɅ9Тųg>\R	,JU|QE)w:KR֦WyҮ2N]a#O2]A'-y#K> W|0M~],yj	790LM)g%Inalv63(̛^$G& E)2IS\&vD?#B#riʜLXƅ`8PqL,~1<10l91pd<chs|CUx~oJ<]sݥ/].\<7}Œ<	hwÒ]<RG|/7ÃCo@Qyl@o@&"|l2?N|G3\* WU&#}6_L/8QtD+w0{1lhx>%v,A*'? <tOdR.gxxªx7nP}S_vE<q^G;CEO] 5SE="V{˛\1poQ,i6yXmO;J]a|L;l0^s05ڿ,W&Ï0EoF6'Y`?>oZxY)֓3*h<	0S)#7A<_n\7C<`I<'EQ^ܹ3=xpz·~-+Wrc۽<C<[.CoQ*z_C<HA<K܀tG=I =c$'c~d?$N>!]bYguƙeCmId冐#eMa9Rê N!YB~ٔA,F%<?9o,uM`ve2?$	6֘; edIyR=GB=Sf#Kx
U9P(eN<Ӫ8e/6Gp6޴SWB'[?	w]| sdru|{.<@:YE:yig'7·X%3b>+bs%YSUF}`x[&%D422<(:sCyb87jp#
7O0quwρ,yq:ݧ(KܴnǓTHCz^|=~x`<%6q(ʛSdJlb|`"OGmޔ=@Y}4e,W$ԏ8Rgb.{vF7 inKaRe.!.D2Z<vENn|KtNW!C@KF#E6L\̲t4@Wvl ׈|=׃M[IO ]x>ǔMY0yOhSG%:,|lP_U2RWژ C=7a'NhG9:)dWxAX:tN˿l4o[7uٗjiLɟW`pm~% GxWLYQ|ӷ={AB%Nl7T^`yVZ6 gxjm_7pSK#J-(I(OnsrN~=20JN
^<Ia [NU5߇s}Dh̋s"z'q%2W~;pA?b]O|Ȋ,l9'u<g|X4DtG_ڴwz?AChY¡FBp$W-"%@qC8%oKxL@<c 
@GW[L? Pb1p4.-oo	'ce%<Y)E,!Ɍˀ
2ysh	ZmVk E+U
i5N!ri$o&5x2d]GO`7h&u}O:_;RA#N:%xExHϡt]iO+Oܤ+a$#n0 -46(gz&t&5AT A	17xq'_:B҉#O0#vGy(e#l*'^!K:X&؊G~}®4h)*,m3ę,{['8t$<بйk8o
5DN9/OLV. ^b)<v<ҲsETE50h!%Wuۛ,ĸ;^IdaQ6ho4N2"?r,XT,n\f"g.7Zyd9Z@Wxr,x즼0N-<1mk!'N_MgbźO W<j1?3hYA|Oa^Ɲ#_4̪+3La'pi`n>͓7L8!}L8e񺈆Γ<G#"uiھ
$S}nK2mW݄/Lژ_;{T3N7L߽徔>}>|z]L(O(H|{>ֹ@ U}2'TywOT_]ڪ<J=B~6춸ADdP]1lQ+tPxVZ47t uj 1#sQ2s\=cUnZ!^v{O4pG3&-*MF|TO;=zXuS3VgϦu}5DC_/0\_twS$!;\,(Kʛ~HܛY!*BNFYbUE2)z$P3r<gA~ʣGIv(ׄ<m
IOA6eLZmY?Lx6F׏ŰSo0٘t	 ]=(ʝ{Gme,Ȣ]yd0당Py:UC9V4 B`y.	Xʗ9twa@O]'`pFE < ;QҞԽ@fٸP%SH=4{<ƛ*QN~ |qv{֢8&*?(f%k'unT;!ݻ9ᛥCkDuy
u7zG"ߤ8~5 9Z&	e/.72rF2䇹#혍|2_]8Шd\uUe5,c-yz7g2p9-i#k dtR6>$˲ܴ箓nCE<Yx3޹o=zQWV1 G	ShPK٥Z m~mMHF1#9&_nj׎d ]ZGcPs)-pcp;HfTq=R!oBc+lР{,	Plʈ;ék]bEO9gh;Isd]D,0?>\C4MP -h%~ `r;wq\!<R-}y/
Mr+&eP,%N]G{VkHOaȠpu:095G6~ݘ8z}kJ"Sْ	/P|_SW.yn5J6q)$±V-PZ&鿺ؕ2<\O8IlC/ZG47A#*o3/:,@zu	wjc*-ŧg.Cƾݽ}V%'}$9OHg8sV8ҖG0mxCb^z'&}>h^۸SB߅duO	.
z|_|#s@GN،CLV_+6)6h5i`LLU58κq+_3p[4xuQ9̋:(.@!NXԙXv~)fSڹ"4dg:%A1lO.OIgB٬dC<6>'@%9@ fWx}s%YY%{΁M蝄a:7B3S$N³Iכ^Zx&A@zr>qH,N !eNPݩz|dNI: L̊-4LB2 /K6Ƞ	,+nkT $$/x,C_eG;
lEux|G]\@]酛
MQ`!w]!etx4^D|"O$S%3|DѯFr.TOǋ*'As7Y
_(4U\89T)4raӖb$	^@׻zmH`qRDcL\/q|߈a3p'9XA V<OdpY>~֑YoQ)/QNr?:a¤?kLx:X~7W<.oibU8פstأqer̆At	?ģP~p	<=AN&<Wm952q؄*9dbO\w^VٻQ$cpZTx6v'E!lhln).4dϫH**>tC2!Vh$l~	+1t%sug?&r#8CR*HL#<!)FsFpĂ(<+ݾ8VczaPR,?񉷕Ͽo)|[OՆ|Hޚn޼!y+`,t#lXę77I3߾LDx&u	1-.
h;qB;<*LК:#>䢭`]S)9<(7偶A0IuB8Ծ vR{3\4@6(S^d̫cK(n&7P
'_֗♷uubX`%S&2'aHDiQp%38!0GgrwylTÓ'.쏈R#x8~8Z~FW~⎎eW2-be241 f'bGtOy62GF g.'A m漤M<4%Ã'{iiT8TvO$/·JT7.=f(}Cd	%"ΧLᣋyPeAu.3o^U?EqUW?y~|x[A_	,!H8DbώՇsMy 	ߞH>WUAM~'sR_4̃BZ(*ľ<K9Ȏ~/9MțvghYi-Ha%߱WE/|[:9<k`_F.sUTΤc qCq$ >O9
o" <_qːA].1Nט4+~M/^e˲tr9%:H:؊-A67[mhC;~B'h;/TF@Yj[<iJ̧T	Ė$lՉh1Z* 9Ozbb(KFUx.Eީ/Oj)aIK`. l j+Id֫bdWDKpư4s '!Z\.ȌI-ھB/u xe7C	ujXO:~7ɰ&>W_VҤͳnM
 nh_aNC*=,YWHơ.kE&r5`W `j\|0kj-602B`e1m]^~A-k|+ةwo2!	t=4bAέ@70a 5(;2Qo0i\U4K'ՆJ+[0~ ;0~ևP=䕐,fH0s-naM&i	!^xkL2y`ɡSwtL*tD9`b"YSyb><6(.8r	]͖ΥeD޵PS ^2[|䳜M] x|'єA=f,&K*܇L<pQ='Jo B..;ڃt䉸\g%t,t`tuHXN&3?L݆j@Ըԝ#;F
 l.g>tZd|(29ӫ,:j1D8|`g<~=;~UzfMz19=XA2L >.3y!LG!wdrDƭsMWgˉ:AEۃXH"X?!#!kvjyY
V$)Qveʍyl'vYe`now*\p&i;!DOҒ&_fc1zuŒџXr޴-m[$|'y7	U20f`^ m^d쮾7O_{՘`K@g/q/F:kҗoŎa d(_ǷZ=6#p Dqݾ{]x6f#AG!鹄T	|=`sMѽ={>		:[|﯍1an<'8169XE7TKVv2(\yz"19zKY&6T%=;AO&g*&ʍ xMS}GON8'Q^LY&wޑz=LCn8dXOV,XйO^~qwd
F1kL@YBO_LA$	Φc!D/ܰ07Ȣa@]HZcpq&?:Ƭl!6k3?1֧>зM:NyL#/~̎u;D(ŚsUղN#2,Vvhy҂b$[s_EH%uzn΍zvr`uf.3+;1lGq*kn(% q]h:C}E/絊t(vO@,H֩:t.QY食u"lddkzrH( q#CnAgI9ehDc"ן|c=yCn}o8E :*G'4_<>'l)>j\:N3eU-;2ٔo^Qn
p׻oS)W*lOty,#<1
痛rW5"/*2?y0c(Wo/M y2$ΟK.Bѧu
_S&$K~(E~*OK67kh^XM}?k<u+Mo]/;yKfh/12( K OغdhY)cMvg/|RDhp9c_SoXR8.D[B7m:
sHBXXy>Ƥ}!WU+72;=KQORTď\*TTxҝPO̹I'` !ͤ4DA o-r0iGp$Qu`Z"x.EcwG:llǌ#n8/I|&B,zRFe>C3)5b6"HR1Ҿ*xC:xloF׈F;kv#^[4{'qr(qE].wB\&Խf	.;~y~ڪWޠfl?~ Icò^@ț{|O\ΚH-AamZ6Z\m3Bcccօfe}48ɾ9"s]tHp=7	2FԦ\˄)Fav8)24؎2Kt,D hJM_=`:]ӉTXR'%j4g
!YT'?kILTKR#xp/A	 @6*2P@ez# ަ≞:&&S>Til@`#cOj-N!ǯXy**S:1E0PƓFK#A8O
.A&I^Lk(ǝ'2-ZqΜclJee.rΠe|GBI
9_T=]Y~"[)7Pď{7XThlׇlDB|?gCWz,XtaK}JMSڿ.h]"ɏ0sq:Pz? CI֕weҊ]7aA&x33i)\П=:\	ʦǛoM{y֖A,܎A"ю,rxR5cy)av},ŦB6NT-Vn9>w;R0Ψ:r:*	و?a3^qr}?">6D6y%-]c3 eRn3&&Г!&B3 1KWn~ġ?尀86+=mw0w#'M9ǗMpo1A>,Z6}'"
(3؜aTQhiG;ՈJFgϞ}CyO<%7OWō$#c(Dj˴Ѹds!^+.\~L5o7Deg$nC<hEø\>$NO x^N?WMl:c~Ci!,n#/Ĕ~|p;o+m.іiCovh!~Ih?~<=PLn>_uMaٓGO|@voQ'_(W%E"s[0)u%ϸy#CDa9yy|uRKY69AQ>ФDGz2|2?"{.4RɟF)*˸<ƴ-{培~WN_1zv[2H;Pv`?YW1\[؀jYs&|S1(}4`e6E@kr%=*+hf^X]CO:'&B	.>IA#r8)8Ĥ}D4Yayw<Xvug+żV%^|Ƙk@*ݧ2*p u>z*!A?dg#>s>wy9Pjk/ΆW[KK|#O:N(֏vE"klSۿˣSTF^xi:,8g Fܤml:}n4| , ?)I#T%/?:8zd#h1 pW1qE ؅
7ȏKd9I4Ivtؖ\PU\ɿl[~ˑ0lŞExRloq+GE?Od.?d.m@Qn<ONKӆ,b(?.[	<Hl!9#:(hět
j_)oƠ߶cW`{Qr!	q-xehh(Dn6árWq|-,{3iwvHVVh'1l+*ˍpHFIM1	8fu$ȪI&5G% ԙ٘uosd~.@=¦]f-7(87pCsobn4{I_|hKq/iA
@rՀa`n==ӎ.7"XRAekl`5_bO-Pиyr@vsMl=`\iJ4 &rU᜸<bHRL{8]ȧhYܨpD4%|;V0".px"ÄM h:f;ÂbEXwI0a94`O^[:'McH߼eJ5؍(Grc^|X	bт͢CW۞Ugjw] gGu{sh'2)+`Ca,\K\W^H tcbG}weꉢg>1PA1lG27v13N'<;bJ8:]z*yp _&Dwņw>f Fn
,/]h[((\98 O]FL琉EwWK(yzeu*s 9@wDT֋mO$Bu\*ktM[t*_6w)K]'-A=Zq X	1\1	Vi.[ypo0I5/S^S&^r2*XWig6牭le:CfƦ4I\OC y*;\;@5g^хq	<}-H<5JfRH}8*{.{kU+($<C_aoЛܞෝ~:E6q;>
<4u4kfϘ~C"}Mg32فOMX|ŇWݮ
;z SW^	~,y2	T4r/=!4B ,DeKt\fJݘ#wL0x6!L;l jޠOZ'$[Px^htC^TO06bA|rp^skDWJذI꾐iAӜlx-͛G~|0=}z|rw֭郻wUGr glElPW̵4*OАOCo<9s:qʆCL}@&-NGUTjH8| ,_ sM*MMc,u8G|Ƕ{μFsK}p9:WpYP r?z!m:8o=tg.Y@_lʲ,6qm!j0*=,(Щ˵,Vi7#<rR2]&D!X sP2ג@pmqSಯ>o3ڤh612Cm KS'pZ%W
/A}p郑g;o<e<SФ}!t#FOrPW
݆ v2j[/4&eDI\֛wG~'c$]]k{t׀
[+Fq'%S1C}01,]LqW 6?٤[P&#qMOp1NTk<WIH[y!<a7Q{>en]T^VI:$ɃǱ$+(^K>]-a^][0R \3}η]nŋHYz^)Z2޸|T]G˘FzDiO'ymq (!7\[h_f|e6o\J7r [llq ej)VsD/+#x~nd}Oiҗ§놱lN
S0ȥ##$*2do\CjgJ}96uL_Z0@ć"Zdן,e@==:QoR' O.:!^LKLZCgAr(o(U5Sx@	_Ej FYk]ŤpK2A#7n8s!ʶbCԖTHì/C!X|etZVv9U 4fqcUVیpwlD0f60TX\2S;ůf۞F- r1` H^&L]t{"5O0CRcSm.&«AqظL)4@08ILiJ7 93/,tؐs&tAk(Ʈ\;L3aړE&UL|&lNp
V:
ł=̄D0tNLS;:pղ=,qסE@+IP$RybqF7qwxM@dXb-qg w$0&|e>
[$&"9sl#oѩ8Z9XfӧCgܢn,qp&T9/xNwN221G39JCO
1	"G8IgN]4;],tAcgC-wܤӒHz_t^r6ȦncqD,_]J¼h'_x|\XO@/MSk!
Y0ҧ]nlUmSx+xי#sGΗF\Mk@^iC.X`Qd)Z/,xu¥fG% еc0 +m&7&'2ߋHJvD8Bm/B	,(-?ԯd7k>m~mR'[?Yl&?xQH`>>oo
QC}z6JgO$pXœ.NC6l(+&<CnS6FHgSc {P6iZ,~Fҧ|	S;vw)kf5bH`:ixz<S<Q&<eF}(/4jpC64g~" x6Nw}9UWF`okzуӶ/>t)?:J]O]SlT*+0(4s\߱,[Wxʱ /EN]$l&<!}qz"B~f._s<~WR0aNCia=>!iW?>@[Zވ)˂@LO}]P&LÔgъ$}Ԑv88Д7D	,7:PGѹ	&WIG!(޵ʾ)mz~O/p݁Xd1(NρF	âmXKH닃'._?ܭsȄ6QlZVr:@+@lFs:@&y|O0¯չX[si)r`+T =>D;E@}M^xEߡ|;A?s#XC o]GO2	߲CC$6mt;$]nn``<%'kK>!zx%YP*eV@菾2(|` ޤ8Ř}D1#
@#-'򺝰N~:Pg@UmgL$J#䛶]ylc ~܌t/>i?2SdǐOibFivwMW ^}k9oƱe".#[^	K݉T˩G}x+w.(ᐃR;&lYwNo6>;nʠe<~֩(-ڨTj+<߁ą^27XAo!Mcg@/%l3~1"^g\ zֹ۲y&ܼnzX	e@Zj_.hH? v܁v:%pCns<VsFeG& ee˞U^aφ@tj2ImS~ wLl^ݚ6yBWW:&ZdH~cf(ˡB&Ų%<2p18c{c>h]Pz1q_֌۳iE l'q i'ak P=:L K#2@|394ۗ'A.\x4oFڀmٻF~bG>x4XBȍ7t|yږ?68M"לi0$M=GoL%횴(dh{`D^_WH= ],6kx:O$p	ፊ ;eoS n%&L3PΙ|@ypmR#xƣ7kBڄVgpvm߻λT0	WQ,kR4'Q6ӓ)D2<7D>cbE7, l*uG{b~$&}/J"7IglᙺIYp&'Px@'43a}U%iXBPnZ>}㝸,`O^G`]a]_<!'   `%>q7;?c  IDATđwQ&y1O Pݼ^w|
S։Ymr'O*(][9hC^<!7~w{`ȳr7Xib0YlBoM4
0z&.	L2 >"<pYppca㖅aڳJFI__\:IdyOiǃֵӖr|K Ʀ+Cŝu-.Y0I߂<l)/ZBԚpX3R *x"EQ;ltBZ&Jp6c|J@)c.SUb?=uw^}lwN^-I;=ސ[?<q)J#p7xr?]mv?cR}(R8s d7)-cC	]	OJ }.rλljn7W}yGltCGDr7>U?#!}O8#68Dba:畄=?~x\B?ɓz5]y%Dt-|pmk,_艠-[u'w?SsvM(17T$wDksSpܐm4:#[dtp.r8r]6"ݪvǑw8,3RGw1!@Gr+EEhΟ̡L/"tL=^<W Rn.NDri3MYFWd3#+9< 7tZ~m{Vv=G=BCRWďgs=tˈڛ lw]{{{{:cȽpA`@+"%3R!L%Cp*R#ZZVr@R*%HYHpΞ_{}k^z|ϐNDOVHR'DQ|ƣy.>	#> mƄ '𢵟8Y.vO~QϢS:zp)7q}=w3__q氟Ӻϣ'\b=770VP_qQpLcTq/J_PrV>>Uz>9/q5(}@qoK?_㵿|0x˕|( leupJt)u9M0s'A_5=B]kdPY9w0g9veX"Hm;u^~XPَK;|fic>`>ŎdxħtO}:x
-o-T<+;9" tKp6yyh-_y^~uR_S!>Ҹ8'@~e+Yc̬mM݄z~iݬsװIwBfC!ͶP>zUc[uJ@VS"fd #k<S|zך`(Jjwr`Ak$A~)u<q*6+/+5qlYqg]>жګGPI8M=NsXڙ	c?u]Ic͜f&4 PP^+X;!D<O/U LǏnXseenHy|iEt9#Pr|@ujDǄ污e 2Gǆs.7%1wBl|Ϙ4%@]dFEK]
:.N;3kWи_ǤOH=6#UpE7,8(8eu[]`z;ПvS\`sqgrziq&`bJ\`dBM@cwMO姓us 6 p
tn?e8(+:AFJ/P4`4tvpgB1:42څVGT'xF_%M}h,QYWy,`	e-X]ODh0q-Smil=(/'ZM^g8v^sb4-
DAq74u9cل>¡ˢN9
f%\bS'RԉyR>r[xciq,Q7sk͎	4^8/Lʋ]xY~/<fR)3w۞,U>i,y^4+R@P{1m6+o
#&%ތNp|t^Аo@`׏_LDaʌD^ȖqN˰	is'}`hǹb'itD~wCpCOd^(4+}㴷ܶH_XW?y_ƭ<9}ڗp=KOB*+xʒv1p/;RatL[Ψc`A9ZVv&*_d$Fz8i8ӈYoyӛ9^7cniw; 1u {UĀ{H;JBw%N@M~砛7o̶~7\1:"S3}ٰ\ =QhlV1xܛn҃Wa+e-Jsbِ+0?W<(;ЖyY'ݗ)(-8/}@r$^VdRt~+Jg#=Im>no`_Cuw7HwE7ήwį7z%nx-Ļ|.B~zRg7-K_D.Y5 iK:	!'TmW's"q2!Ϙy	v氡o<2fvFW6EؔyȂ#/ՁMZƁsR z;:&4K_+|gFH]PiO$o<
r0ш
 vۢ/}po%_OANB+rh8CQ^Zι.y/N`KH}By,o;qqzz|cD.rDqƬ9%A24*OЄF>TUd/)\r!&=+HnQW^[V})hnL!/.O~s8iI"<j5]lrczOJL<IВ'ޮlʛWz(ws6;Y?q_0dt.edn̍8sQ"EzL-6܍,{^	)Y&kӦpG׋q^,ϫJ vs6r!i(RCw%񢐜I=efSE0z+~&hV)㸌o1Ekz"Ɉ% ,ȹ=+E
t~9OWt?cm}[}<$IlZ.6X<z,N]"-lem}w (=TgjMC	Wiۖu2hC?fe)KipSaW	N= /(zm0nʢH^ʁAB>mSjg$kր*,,5e!<?i܎{>uI*~|<o,7ۇC9ѱ-
'X#\z"70p𮗢e ÛR.8Mme4"Bv @VOl̚a~cpror"0Pi@ӄb'xpEGZjʵe҂7nxtr㜋L S7B!L{7g 
Z98q z},%ys
Egr΍+?:S4!xF.唏Q 92K#qB9jπ[WE[* =b| ^  Mu̿dN͛[a9A[~9u/p)K˒W vAO1h[&'c+y4/
"[bwN""sLb2Z;|;&\'Lr<I9Ji)W\
	-]2,hA΋)x5uݥ,w6th;.Lq]ymsXo/id#Ʌu0TTpSٴ!gB$_^He]e SqfꑍM~^+"v:LK~"7]ғUa4L0vT{͉l-zèؗH2+r+dAja_#@@,XnC%=	sLTD۩GX.rmOv?|觗f[춛:h@as1AWGXBwRg::yO0qyʓv Y%Qx&>4m'y<sk߭?r0<8H+X,OHC|x5əJ^j[)}w">՟|*5S%8?:@kJbûBe/6(9$^.t?oݺ3BDbC^5xl2E׹]~wa R ?oWm~|G)tg @|	<mO.tr9anrg^z	lj	Zxkx*e=oc[l	H{6?у57%(G9VoGee5feCͯ|~jto<`?!Fz{L0͉dP1
BTalRۉT;u}v.\`uo>RӜNhG[IYk%S+K&iH3	8M ¬<dt$2yO:9ElA>?9%8hd1H VcWօhE>eN_hB6 
ڠӬ<5k7K8:!cuׁ\^W5Z!R׬akYYdG㦋kD[F|QO>Rxbq|*zxvxEyLJB3PԹ )mi*͎v)$kg58Ti+q^OGYfB74"&W _lcP`,x9HmRdxzZѯ6ҹkXݏ̘|ٴ3<V|ߎ|oO23u~HuI;@_/DopeRN;7_.H'&o:|3%Bz2n3V=S~p6i#
QI	4tÓ|0P@Xt}3	3
;yŶ45PM'lDC#&|Wu P4Z2#	q&!|v	T_@b͞a(oRyć$qB`Wv<)Q?|'?)|6u#ukFy-G(m 4n}iY7//.ٯ@&8͎{LuZ&qǅH;b91k#[;S}or==e-oԘ(ImC>o|5	},; b/=7u 2XӋqsҽfW=O<\JA~F4i!l͇lWI=!,Y&Xbßu䱓Sq`1)<gcXS'>/7ǆB]%wSblxcܖ)̖4QZ_hgp}H.)#@=ժ}Jfk3jPbR+;cu Z|=+`&"*DI(hg48ӚD%}0HO=yNIY04u%WQ/t5kf9֋@JE?hoTR
d'	]1IwFE)'h	dSA{̭\`8<l=SoHX'˕b1dshiz <,{{rS^H/d-(f,l8w?b?կ7cXD$<,aG{_>N.>/~to`ς/?ɪ7$#sSS.%Mٖw'|Lް$`	7ڰ?9Is[/'~(uR=M8Ff'FsѤT6oF/9֧ܽ+<')3`ވl91`㑲mV1zl؈S/q'?TtHA&q]-]ܥ3D[iѿd~,s[W7٨P:7.O9F@˶	H!i80eRw>ϝf<gYy_cG#FH9zȇlA|@riE?|!lgY/a|s>|h{_V=N9 - 0Pa1Զ#<KxG_a^+넘-%3ɇ~Hxx_P؅\^!= Og?\{
-],_׶<ZMBx)s3͏qv5ViA4ZooY(M2BrQenx+zjvNEf/NS[9
IꇾuzOqElt;6~=:cs9w}ݻw[1<un^y:x̫j#wH߶fqп2?"ʛM,mБw\`Zdɦ=sˆ+OԜ	3PvDm`oqrs1i#}̜m'3E_^.XKL>S^; zR0$8`M9tm2}Zv~CrD_A/\ <uZvB$<б`;)$cFlJ!eDO^&6lѰf2N퇾LM&6F.@$n[q%WD|Gr#}vn(h"P҃W#Wk4cwۖqs|lD"ܔ$?<F=Wf<ؙ9oy:4s)1̏j.Ɛ2R(۩C?/i#yҶYSv_`Um<ѣ.7K|97M+݉? u mUCL`<1K 9Y,va¤}4vKX۽!mVu?}Az
e'oh7WX^눴:f̖c-*5>p;EN ۪oG 	=qC'Zɘyn9	uy( GcG~M <:(򣬴%A9c6%zdxJw'|_FG̓hE5`ؠ:o\Se`a ^lzz7q!J6XKF[oaO*	J,X9O黍T᨟Q+w+N2nGֹs"J/Pl))+?e͹O0(2O"Cq<oɷ議~}i剣8ݨ><rBq	%q@Lb&7$Us!%zJxlNeZOolg{A7]H8Jmp+L?ئNeҙ:~V?
Q9	M.0l%J8*L$zԏyT'J}Q)'QY)B7^>բԺZ&!XӂXZ[4l0d7Uhf8\@ekҭo9L`^2TA« MSt|U2-P 
dNbھ-EN`d'3iɉV(Ol#Wz`]NXrq*pIֵ}D'Ʌ9IBО'E^dHX銙.0/+'.ԐwQT)>o6f\SZ<q{ȉt0caN,ӶYNq.B	I<&NON
;ɍv):])kM~-Gir;Ek<8`MWd;ri!~	'*ec#|ުi728t/]G@{}DA /zf#VaoY,]/Pe.=p2p$(i-W2#Y
RJ̡ PI% ѓO-UsjWr4|sY*l۟1#~M4rD 7k/<t:nc⧍m) )H`3ٛqUt(`X"iw	@`/}CϞņON	-nBꏤKj}v'oiWubVAƌK&=ti4~3RlȥLXq3y?y6XO-hzozC1qrn4'6xtl1.kzR5?^KmTk\a\e R#:W_b<.$c37:Ѹ}H<6F JfF&c'$/Oʇqe6scd#CϯkuvU?œO7?0' RezULH3>9t-e8ǧ/sQ6᧦T7~ijkn0`(xʎ23<~ؖ5ę_km>D`Quc\;ḱa?@YzTgn/BHG>0cN@dn~XHIhXmٔF_+ceP9*OH}1f(Ћ:
f:܆NH'6ӌ+UX$lc/XJo%G>njA(Fw}rTvF~6׹7 : uOM~jYz#lu$}H^D`tS^ږN1()IRHFgd%5\?F.s/K_1vșr7ɀ<OE<ɘǍ~d"<"<Y6I {C/e%{NhKp9.UMi[ϴ]nh1Eʃ}	{(ݤT
RAIxTA#
r&q	zQƕR\E-`Dqd{̱sF>qJ;_r2cw_`|j<̜	qt&Odcs~ӹ%ʽ|\Pap?9=r~\YATqyS@J!b_ϴڈW Bfa%xic?e*o")sd|0͙~6>ˢ_B}υ0ҲtTv7- Ŏ,@X1KջfmpAO0=ƅw_D~ݷ\^D܀$5ta5aoiC/j8(vI]QDp7@O`++ZF?g#4fX1}QSg<#Qi &=TBJ#V~F$ӻ-89)рe.".2_cEO,MVExY;xt<kxu0}Q?nE6sPq#!mc!X:XFAro++rKO%#_K~Ņlŭp%) m&L פ@kdq4w|aT%@Z8̑ԁ+\`j,@{'fLęܠҸZ.m'(Mjp&hE'&4<@~
VB5`:6\tͪr[|l &DG(:=	ٴmG9ϛ?wǇFgdh4?'tVYdі AsBV'45 i&)am<)AkduEuɴSZnF>3l=	Y)iω E7^:E,i`XԖUN؀(6ٜ	(~4rq}O2nC_R>l|s.FB1_㤓dÌWq@zZ崇=,hK}r«;	%`݊؋*lAOQ2HOXnV3ġ?'ۀl9&StOP)p}GOږO
-^DWtAǸE_-/y@ENfe-YTk$bQq$	5@s8bhQ`ǊTc9M^W.)^O0jzK%rk	_!zlᾮ<rg[{,_$$Ulc @6q=.f`Uvl[	.zɗ#`u:1oIE-HՖXe,x/}1O<{ݺ})MCc`y\ɝ1c$tذglIl/%~гSJJco{,F3gaӞ#(V	}?4]n\PA/"8l-<2k\/s(٣Ö9@c&iSH	i'L	g,Mnz^'⌕M}~25ZI x=9K㏢ŧ#u){;ٳKܱ﹪l @	-D?6I4JۀRFyj3mnި4l⌳)'-Ǟ/Unz},GZs( hg}M!9t5>Am!ӕ7'gh"7SOFeR<276F؊'Z).tE&1'\h 4f1zzzӖo1#`)h?*c4+	Q8@7g/0~<#k䰦n#+GZy>h)'\slfUCks%2"¡=65A	lAW?8vc05mg-[pdmr{)tvw[<b>18vcs#~F4яkXѷS6oJ'apgC eN))"nS:ㆊ|gyyjv'ғ>WUJGg׶w}!\3Nv_8Fhw'O~ClHȢ	Sw˶!?L-YnR\pP'.7Q MABJ8lB`{_U2	gߥC7 EĚ/ly}b/l4]\LINFU VnV
V>}#;e2!t خhA`lƞ{6!v]P/0Y?W`9_OTD8cp%l\`eB^g>+|g "EҊ_cr;p<%߶ YW+򸀜)77+FkW͛W=.cl
1Ϛ|PZN8e=x<tnVTR?0Q/'8_dKuCܣLW7
 M&v2z<QHt"t;fyxyk]e#1Ti|i#DZc4'꼁>L2fE?aǨ91y005ǧΓs5Xks3p̻sk|8:˸tؓ>
PW^
ְ e䓏]F\'`C0@(qG6@flO["4ATv l`F+;dQYPP
7>C#RQOAQ`9>'@sѻ.&#<5=pNĦ#oJr`iE?r#N=aEWRObaܯ+ylÃ0x 2wVT@@ɴ+l%-'?2ίJE#9s-G+-J^hqaoi`"	(<	*58^=)|qx6k:O{:Ʊf6`/49SeS~Hao?_<Rw5pɇyMN8!e7_3rg"9fwrupl^lFq(HW];lg]e}HNߑ+x;C&m;;!rM(H5ֶs6p jKT@7Hޘ-U/r-Tu¢mJCސ	Phײ0]&PcW8u(G^ -zK,Py	&6FR/BQ&syCJc*MTSQy~NC*gi0h̷1"JgzLA@b>h`+%lU>].u1VrərG_ize}<6JU(]pǉ,6و=޸yZ,Py/_<a~}ˌY=Uo\Ps=cwn3~=y,?.@3Q׽`ϓL
7As',DlΥ$2I+aOJڍ}Tn4	ƻlŇڹ^lrR.6C2S1'/<f.h!<hkŨ_Ԧi9P-dܢI>)i+oE\u L~<E]=ʍ͸lK9c>6iS]=r}/
cr(@Xx";Jw;Mk̑=.2O;x
?R'mtW:Q{msiʋ|<|M:3_(/t纔z`o֝k`{'auI︼e%Han,		e<ٗ:4kxy|>A"I&hZD5r(h~5&<##W(+#ǜ#2g]L
Vp\Λp)'5^_N27d@w߃>kk" H#xE:لkU<T?}<@oyw! c_=. (M?SÓA5Q*'cۂdI^# `;w.~{=B}=m8mA؅=9Dyzmz+|[M)>0^ymqCqgr@}F.:;eSb^CqMsAq<oB}ћ&yO6MRız!]ʢ/NͱÝ.2W;x$uȺmm̑c# KxKrP%c\O)?/ f.]\uXG;"-m>rцBRK2TF22] 9ğ2kiجE&9r&88p$`"0I|E/J>q1NbDAFncȺ/4JYܟr%~L+#ygQCQz6( q+P#h%t U\`Z}.0]=傽3eײ%Wk.)θtuOe\EZNCtX5ylK[ 36 8j	^1|mORjyBi*)'0!fgxiRcS' M:N51q, B,'y)@eWs-q1T0>c;t@5.qaU2s$ƟXcH*a༁cn&?=G.q3GWb޶FiDw@q-D=|$$:ҬZ v*C= Lɞe.H/dJ7SLH4:]:f8JS]SF$xX2:d	'JA{ 1W𐡣7FY[ds"#tC>݁c%`ոc):ݘ~ ":zR`tOĒl4gȯC֝
a;̿ g,k(erh w,0R^p*~0kxq:B!'#^Paf	\-*b8a	\#ˎ}M+4TZ[>^{K"srFPV[cr Bn8WiWJ! Pq^]dL'v	2^Fg1\v)%^cԯs|#\6Pt'\\h5DIxRHrħb?M-8&E2!w7JP~}N[nhf

lʂ`G,lgī%gh>#ΥYc9l;Yx^	z	N%1T_cF!$WY:,獉6vN/k}Y9c ;|U~@+#a[h凩8t-F}z}o3/2VqeF{mY0Ɗi+lM-6";}/Hz$M,i7d,ɲN;G,0" }~˜kۣ7;1y"hel@|ѝ_?7ВN,o\^%>{:x1crbdNUo<э~|xFYXym1!9NޜgNISMTaS.$Dqx&}\
Ü+xrơ9P<p+o(/cۨxCXTN9"t|^;ۮ$5^o]s',nLᕁy572<+[QwY ɎvA=I2gP'@t=SrK\ydWvyч"܎QыNfE%:ԝu͆ :S%mO,NN
<%ɥ1(̥a_S={'W#).Ӓ=w!攣r<;҅oh{)Q([:UCGԥmRNSl3 *ȵLEToOx֞n߀<l{>Uz)p+Sňn:ZW4*Ymr97r?=/zZ;"۵s]Ig`LI1vv$k'@^uJ=<01U6J%<8K@ɘ ʵ Ú.p,$	+Rvԉؒ:V{<aeC#NlаK߯hCWnş^7QY;(qU.`<H?ڜtdAmGqN|;ҌW:.z=ܾ}x.^yGDȍ:|xh0g6H&Ŷ$ҁ<N*E-&e;~報3<ۡlΙ3L]2nql/Y·q.7x6$kPu<ӧӯqK줣~AĢz1dTv@j_C{2V1h`)b }ȢipIe;.CeN\I+Jkz׹D¹,e(Y+^1>m6c}Ev!<Cϧ{se+ې~cL !NDϙ钾B4H~`2srh|zU,PErS.76_%nW/]#]gtҦT쀼Գl?oO_N3( &O@89'c8VٛȠ`G{zT0a\0b*r:ԁcRfciT;ϐR$;43*Eiocf\z/kC
1Xk?}p#i1бyR?43w0~As!ἕyoZ`#Ǹu=|T>	̇~9XPǙj!*G|"GӉ/"p\`r3t{&mנw`
قٰ'd`L#iË"2pITаH&75PeKj`+4zį] <QF &'GG$Q VO%U :y&$ۆLeӶX)Y?W}8Q6Rcli!\2\U~o!<yiyGm>TOuPHNRVX@B>'rȌo+60X 7Ͳr+(u@'Z*GJچ2 E*cKL
ˡJ<I̼??6#ugw^LsL*|C#⻦pq'<oR\F"*m3mLrT+	~[
x챀[Y<#K(<OeaS_6PpV% fȂ\ FZ3._4+Łlg,Q `$\uyod<ܫ|:8K=쥺=ѩǆY<ck*o{Mv]N*@h-Atfw7@?cy@X=CR61%p`#=3歴~<,ZCI'veI;Ûh tx»]E+'|d	nq`"owj+ /n;we%)>+B(6э7=q1~5'H҅1>tg~.-^ӆ'5^-&V~l1ְ5c.fE%3/ɡSzc'߹K?6,JÅ!_X<Ћ_g?~Qڂl('ڌK9z?ɝoؖc#:׏X2\'ZHC5PKuR9l Xp[W&2fAAHGu&Y;JWE7n϶;w:_#_^J^t[.7u¦*mvCKqClLNy"X/O1EZNU 4Khg@JhA./{'w)[҅za~I݈7Տxl7yОɢ\ָi('~4N>LF6co<.GٲVg2"&uRn8_ر퐱Z@Fh|+2XhiACM補Kj&m{9E{7)8;	I^UD-'mvhh
XXC0kf#q Ey\5Hr:OIt6@>ql ~;n6X0|DEٸx"ʹ,ؕz䣓k,JĘ̛"x-*yx1+sNW0PvKb~O~6`V-<>泰gKk|c
bTj: 
g}y lq%ȉgOLcاm(2V緖wS8g𷉝\8sBo=L[kBtq/G؛yÇ9>ģB#CYH}Hsxa+i会<)8_
`p;R9#CgTo4œ"<iJH"
c?<n؝9K'u|w z33rJԡ>F|̚:OQ%\ģr%2zKtpi4b
Zޚ2N60Svj Ø5	ŁH#4WA]sa,ܗ"MQ@vk3GBEG@$5(i5aIbSV8߬0zkLخ4֐i\b=Y9g16Fcs|	Z;³@9EEXۘ^a_cK:26DL>n
TX;:aP\"^aEGE%NNl0jL4`T8xrNd4QS_AqC<f`vj\8&KA-eil @+Lh9BCAsTmZI"[:Yɧ1׀c[ʠ6GzL'$'IXi_@Zf٠";8l7$}X=$_͛\+rE|=cc$)Ug^	E/X>}r_:rH@ht5%,Pɓ0:]Wn˄ic&&7ݠbόɧ[]~?:I8>:#Q,7#.Z]}/Bt }&'~]=yü]'R:y#%3cOVִHu2R,T[׉7E-xv`mç`3?!/3VX_8@XK[bO=cSހi*^3uH:Ac%ࠗ%X!L<8&ԙvjyjÔdpC<"w2B"Fh~c/kえtQBSڝ{Е8ʟ vIBʋX+7Th3?ѴxXcܸa#Px;'s4a3J6:,*5wp1S5# V89bye6Ӱl|@MdWGx5ss60NK4~#r4̽>iW>"3o	~J1I~rU6	VYSh/をaF9]̅6dGK-EFT>F%!Ǐ
qrb;zR -Uaʇ,<MTS"e(ǅ~xK?%|B#_)$X^:7HdĚ|e-=൬Jsf]ƭJrO5!/q3\BM.Fk6RKx :<?'6>B]"~: G^xP᧒Mq:=6Xy=cyD/ch_b4Ƒ§1>ݐiw% p6Rn8.r5zO-Ｈ;vތ{<P8=.=s'ycmZ𑎏)UxTK]g7k]fLcmey$O(Mchc[a6m2V@?љ?-L9eĥaMFf2y1[`9j\ u5[3W,2`[e'f\R0,u5|Hk0~Eii\FWhEz̘mxRXyL'<H	}By	)x"xiʹn'X h0oK@w;noߺ>wWi(Aty
(0p途=q\bxMѾAxzV;f_6S̠?6&䂎tB1D	C)ޑ\\MO<)nC>3?zت5|{muۈ_#w)pVͽ$A):BxHC&]zCydlmqأUc+̡rtB<v^.+ʱ(R|H2b?,)1eNh:+la!?/# 2]\6oQxQ9V~5vGO	juP-kş|:awx5|S^m	ԗmR7m-_MW1Tn2?7D<j@tL_~BJ$O>Fi\
˙}1a9W"B^fbDM̄9t/>p&uBW"~c6clb
HqXjs33g	] d Ӑe.|]3j0فbς#kz}
Kjrz&ůo0Xdr8K,L>̋sfD2hRb |/dP{5׫ge.ig\D	֍3
&tzbOgp3XFlVزގ<xB799`EOeSRMgڊG}9@ ʛ) 1:N5wYXD7#LܭK:<8.VL$ksXx/\Qx;O_ x|׃!ۍӉw[vv_Sؔda8a
d1orG::Jا/,ЮDq^ų@](R̀qj(^1DEnM*GǇݳWP '|;1,r%/.SKGயd^/w*?ᓾ"_sCxivF
</.
+>O^q'L䱇y`(E/p^_t!8׿Kt:3Zg>aYcT6=R+(a$fiJ#}c1N. C'竺eะj{# SDAW;̶18
%k\N/3Hn%I>"\6.Y,Ǵu=#:Yݖbcc,?Q0c3៩(~<ev9	Sc'O<Ny}}Ysn+g982j| }"Cq!1Ol0ߎr037 E{S=YvmƱYN\H6.~nwҏ\d!=QyZc~b1'|OJFjUFu*	Sޤ[iM^E&<yó{)7(<FۚYD@x	}m|7()fz-ϥTкM	{NrX_}N>i$}ЃDޝ{أ 5?lXөNT^W }}<Pdľїc?`\{-d}J7~y^@[krzNK_ZtrЋ|JʊUPaxL^:t9|htC^T>x캨H@Ɣ@?On8c&
i5 s$mt&5\'>TVkq<yiܜ|y#FQ+"<2~*c"&BpфhF	ۀ-s\Jƾ
ϒCyЁxgW;M[d.v=>۷w}1XRqAM{`fnp_L{kCfۡ2@8DVx`qpEc/禮.!x\rT=w_s,QN9' Efc0{ O9HbG7˪O@C@q伮
_(=,nHSH !t{.8f
m3pTX٧IθJGy̒T8\Ρ ScCerY铯4:8T\	qoRl؛}/NI	q)grfօA53<Rl)3-9eާ=eS;?7Ce!$ED<6:<}P0jrұ)}#;ɭade[z|Ykgmf-i{f^:x
/Ag8ó!oJ)TvaR
ONX +y-j'ܰstZ"2-$!CxG#`QD"Tゲ,YHN2d0:̧:8ѻ_	<,RpFD<ٳ	"< Cly\`
phF`XO}}g(6b\ÁLJ.r`8݆0eФ֏ ^4%#VJ*XTNu͂X7Ua6q>8-dVTgA'fgYo`#,u	^Y,BHߺp"!I6t͉v34	0Ĥ	E,#6x@yV9My"N 5aۑtB%q2*ٲ(^Į3bwB%McC[mOt&BѷމH~k'H.C|g-)O|<ɆCo/1	riƈ7|co09'=Gl{bSz	~ͣL3~b?^Dm$4|N ʚPo'YY/mCyLND`,@ ,&LWh*z1!vS@5ǏWБ|gtgu؉xWNs=?/s*(v&ngOwE
p#.:%#<9-Z_x*nvj[+Ox'wM/đ_x{\FnX/m>B{54ø`+b_ƫĸ2wWDxNί$	ܱġ˫͌>zr16'9zc	 reԟ'pㄚWqMVsZz"/N1V^o3ױ^/P$Ϋ54̓susuB}rh+Q@cE8lFE'Qͪ-Q*4{3 5d\8@g7zI<"8ǘǓLl62\`(,-2>}!Z.a[G..!sob<wO_t=3/Qe~KC%~q:Ҽa:l'y-x.xSGum77ERo'vlD:2 D	s cNIR2hqsL22֭/$;&-TQSiirsHNgE4@?pTOв@.;kQ|ѡe;R*#fTMGbg]u\y8.]r$G.4#GCA%a/@Ze.^VY=Rcbb?t:T&0RcBͰҬ"̏}!>C?pGufۅly2AYhȗ>O{&z8qn01y|$LT_8#B94uI
`iCGWٶcC׹Dy>n1UF7r?xpQc5e:.6NA҂H+h9AIƚE}햾syd;STv IX\<g  cxu$cW";H
AGi1N/{p2 kڄ"ҲF=^]هHb1P7nIA(rܾ Sڄ{o>fMK"	N4}NI^+0-i!ǖKC{.G0XvvƍY)18k`_'}80	q\p
׉2
IsLHa8w%L\	&n^ԋʋ㼒̼H{&<.:NMװ}r @y
#՞_0IRo?hA?봭	ð2[ 9 Yg*y[xt9^2yK	zJ'r	L\k#4783 +=or\^u=ɂT9HVp JFϢX)/a\p5 #XcZWaaK(GtorP9'K5kOBp\onŏ;hO}ql6E V2pKLTpḱ7p:$ -toyr&><r&]@	XB5m4$Z+-d&v6Xl`z0Ӄ^ 8%%6"=NNrq=0_M9=Iw	wc.ꪏfϙ!ZHy`7t]
].> )[ o:8/z
';MG@, ӯ@|z\@E0,|BAA>c19Iֽu#/UYEoexCG[Z )3XG{П1e%ےv~M=5N+cǾC<ϟ)j'lPt%xOJ gSwھm-}ٜg9lZ͉ l7m68lb2uGouspȕ5z<H6Y,pPf!Lh$^CrhIMcKlI c؀aqz@tPKI[jeP}>g-sኾ;&ZJ&=~Ѳ2ܦk^Іۖ<px`K9:QHW~W6q96b'n;-<{?8W>>Y&?Ҙgq
i]^N^7IN_Wֲdݤx-P*]'m-lr!weEkN#v߅Z [D\tB/OzfM|v8ˢ\82M6/^Ϋ[x	f2[ Ʌ4ʘrpAqOkKE苑c$ˆ||WXɸ?t-ۗ3ʂЍ:SwW_lǅ[:?ܾPȓKv%CM p{.&gbo˂MÅ+BJG*_E<udHlkLyGS@og*g,MK!W+'le,{n?tI'Ch
^A٪+kq֗8סahdJG } mS}9E~~ G$xiN|ס|Ɨ-A^d܊[O[HKȇzJqt)R5`L3vFF,8R~)yn<I8cYǺ~=ў9ٷ{﫝*ĘqX|e󓳞+mKh:ȏlv_19ؒ5N>o.#7}V7N؄q]Β[<,*|^#?o@=k[G?C:2뗧# sIkVR4rArh$G7-TxZܯI@;bWwLT@LX6X,BaƜ&E+їԶfwl/]ǴPtrN:XpNcS=DN.Jg}ĺ"H|t`>/F(ux9oQPiӗ.枌Œ<)ɤ;@ߜP&:@4-vIO0,|uJk; #HY:%*Bzr>k|dĘ.;L3P-@BVC7A Fx쳂>vqtR@xa`g&4i؄xկǣqw|Xqr3TzDڂD	~{:
7>?>+ }}Kx܂O{myLD4(61WD@xI6"bk ![0 ,9yʹakcfeƏn:u#f>.!It.0Ub<Wb-w).]$vTP,q25t9(S?m[d)9!>~DUuJ_=jE٦,rw_/估
ñ(2j IfP`|Ή/`k]"-m27Hǆ_͚,$𤴑EbBj)zJhpdDܹs~T^Pi0]u`$`YP/,lh:pXaÌ:Lnو'qypRECJuYЧ a`#<T]\UkKEaD}!B"dHA4"ȋccL,n嬋Z"BûEt-âfn!\͉-qH$R*	F+xۃW2]Wүzc<Sn"8u9yi[wފs\8-؞jN 8" 'HQ^]?_!h}o󈫳ɾQzHPc([1@4"΍X$-+!*]ّ	5"N.lg:x	Dyr2d'
&;Cs2CAJH]龋>"Y}bMYݺ3Mg43ʩN
W$+W('|rXk%W;&_Te A@J`}9Jok0Л9E)J_d7!Y廛Ec2FFW/n~w~_E Զ{O]MS&Ӑfl[l4k]?wF7');ݸewWھ45||&1&B=
Z6>zDYG	mH6S?cQڜ~z(xGXz~y>d<>S^_G9e^Xytr<{"SQlҜ)'֘:/:.ұ;<9a;௪-߻{u]h)w]}%pƍ_v4`+h	@'ME.]TevL60v}֌=lڪ{EֆgPrQSp$klnFoFRFm*6MP̭)r =CӺ^;_p H9ɥ;Ƿ¨o:ŧHnRy>^Z#K	Vj@k@oH(y仲Ѕ/2fhM\@ XiCw?^;*4t~| /^<S[	)[%*_06 E)ywt+CR( K?2pae]*CۥZ<Pۅ~5ǖ>);lx{YΗ>t\ytM ʍ}aB=s] k(6;xKh?e!̫J{|v]}Iw胮ۭ[7=_ѿ/)%.ޟin|K.=~t/؈L4e{&>*px)'ORK}!]hؓ63G0?#9q,	 =>З^P^~ؿ?vj\I L5'ѽ<|hcwB- qC5\ ~ot ~rkp!)|m8	L< 4)Om3!񺆐 0Fdd>C9̃Iڇ_!Om 
ےY+}>}A@IZՎs%eqdcA.s24@a˞+:&)>DD	qL]jJfع} |ƠZ6Ym٤:wmeCir꾴@B蒷<W~*/Oke?'抌y٩SGOd|58ĞHd.6]ҏR9M!ǹ.>c,}QbqUt 2C ڴnrhSu|-nGq*"d9f]f4 IaMpzɕxFK6hf	Bf3Hao$aa+WYy5E>~Z$sHo9.Pk-z[`	n233@'W@+DcwYqT״fW}N"PE|^$[9]]\$5T!.6HAhJQhB&L$@gI봼747C(4$mJ}r(|;-,V{@_Zu-HPTr=as@:_7?:$Yx`hBNNp2`"{]ٽy)&@䮀lcr-##rz2zsEJVJAm@Y.(+q/G9#m#{tp =xBki>Uy5ʁ>mQ~e/9ap鱋}O@y#x5ߓǏ8^'䔟^ɭE_+J~MN>@ d|8)ҥ2&Oȋ6*W_N+<+1NIaO' j]%-lh04b_ȠlpU%|>O:gdAV],je?6*C_=r":.Zb>Fd8s]99QAYٙz"L]9\_Gyn?9]uI^nw9.|K>h<apFc'žOhGُkFN5yiQx2w7+*<')ey\乮?e_-]=do	H=SР{"J{D we+ZdЮy}M{91^ _0ohڤ.hȢl؝5]6Jy*LE82Oy2~|(R,e͜dQ<|/$m7Iwrʂ]khێ+rlD)<>ʞuwd裏֯\&WEbs9LR2S/܆ʧg|?)~bg.H87WgO+aCc*m%ہO{PzevyLf
!kc(p>}EHq'Eu@e+_cdE+@G'|ʕu@yO>ڝuhȃlhKd+?:g^a  H?+Ȟ~¬)A.J*T*0R.4M16$~9XdthF꠰SB4 \ה9<`4L|,:St$=@DsN.+Ma'G̝1<¤U|#89is$|&cE%y7@CdѶN\L>w]ɽzMc`Ȁ<8Iڇ񚒱I;ooWj'~r2Wfz<Ss%Q,al\<|wQv̕TwI2n΍ <1Uc|iFc*YʕaJ;[߁ߪsxaXԳEWm;ƊQW5&@N>U
:;Ώ,KGɌNedCX::+mٸLb֫t׺x(Sݰ'aٓ>S8H@To3tE'զ/:fNsGȆ&vCx6ozyy GluN㵾/VOnUmeʦa#xKkx4 iWek%_Dz I}BF&VlbG佘%op|;u(N\?rGKW1eO+$
>uHxɯI
߮ G$,)tϞ
h6 9kkڪY hJ?B/y B-eJ?LuikxloԩVLphjKz5i OM6ȋu 501.3vS71FyR탉b)Cx (
A>{Yy,ڶs20}$9[	@Z6MrVAPt4fK4	7_ߕ\`V_
1_]o	OLC47jxT'!O N.]8!M4	&Mf^˯;Xonc<bgqJPQkeeAdo 8㧳u#l d~ > `ST/C<D# cer-^J\4ܿ\M:~zWrL/lTNSS𔃰q]4^~91"҈*"Z\/1陰]`X3dCvi7ynC["
xb`~"wњ.ҝ
iIrAƯ)1$0;ocSO.L:Q՝USgPCW0C{h-DZ}0h)BAǙ0F@4Rl5za]@VʨwRI^r
nO=8ƨ7<K~jӕm:(ԁ>y2oOZx.7b6 9ÝN7O2"/2?aρ~re6HbZ.Y
޼yi{1uN4z(iVz(^X);]X	ۖm7laXSy4ƶYXР_S$op7Oό@5>y<zP~J`9+q#Qgx+su_iaVlAZ43W06S!7YXpU\4.!$C\c}E	MoFr'\.eí7Ù35/zG>.L4^kBl/>.T9%OA~vl{7#]wyQyR:O㳙٫ٕڍ+*餲؉ltν;Ɍ6m|g*tweNxJ9.che:Ak]eg.,ny^~/Eo;fݻw<1o8Ѷ@Nw!yF:a&Mm9/^ #14N.z#a[e؞|M@h3HR0:r6)}O.YG5!{aCeσrTK~X]>C?)8W\4 JH]vFg"zT0Jvѹ?"Ri? ǦPG&ӛP$q_rIC1Diw&;b=YrwEԝOdR޹PsU"Ei+`V@_Զl>7)<WC͡Zд˔/P7 uC?zvvz7T
):Qe<-?1λn޾sdtܻu;ay(z1%2KG6s6U{mM:a<.QﲉE/726
]Gxl/2SC%$M@8Y#k5~廬FFq-xucۓ'xMLm$cɣ
'#m:A.ЂÐF0@>PwdM31:y(8n>㢌鶹Eg_y܄Cۧa=7#%'pe&M@Z3&@I7ƹ6=0ί\ldOgM
<caȓĸ>r91z<E(21y:BQ: KXD&jr!@ĚhgSKL+[ޒSJ|~L^Ϙt_I
TtkD5(to!`!L.߸87P.^s'Z}Q-hq;XGHTm+UxE^;}Њ&'A-}Qsyaf\srqD1k&/8
3oɈL;MP󭬵=f| 8!̍rîwiYӑ|OKv1n)`ӭ@ZiP
;QJd;/.讥"z:Px\Ѥ|;cr:0~PL|!!7=1uQkuX;ws<%}R!0EhCRO~se(*ڄLvI,z9iɫΥh5|S>M+p=<,1_БCag|B&ܫ^n r}IBt\tMs@X.+apL"*zaCߡnK\7Y@VV$-14s>
>6,hg`{ӰGO
1#$w 6fDء@+T1ҾJ혔}9V`w[">)tǌɏ_jQC@ㄎ9X5:3-CQbm@񅋏D%8E6h~T8zkz)|9A-´N"iSN-T3n؈"_G̌^V	\nG;>!}fG/z˼WKLW<>Cg\_-|ף178a~c$rH^>zw^W~
b	yN'l`cܒa^/eӯ`6E>y]t[]|`$<դ(폶tL6\-1\7e:p<A}l
g|.\~^6=7}xR~98ߍqroWO;Y9G`ɫ^}G_yzMn }"}\}DtUدTbW')waڴX4JAzA%6E	"%s?F}#ϝ~H`'Oiò;Ɔݻwo{;Wyy-!y5|I&O41Vrq1<(Sq|F!rٴ͏2H)Yv!$V)ᅴO| XWV}zT{bFdc9'#FqWL߰^ٔc΋[ٖqqcL>).KA#`mV\3`C,s-!B|7ñk00m'X!Mmyo캯 Ұu;,E(UERFP苓jfdcqْx7p[=W=u㫌ʏt(G	_Csc\nf;$G~ݶhkfnC3>Oy9-I:ƬSekLtқ<H;.ْᶬx#֕Mr8Mҏ*;N}~_y|Ӣ|>X/ YCƛؙ
GE q;_pF꨼X1Ӧ nɖ~@>Mi1C#hJ<+5!آמAHIyF	DTq:ԸvTm\.Ds7XB.2KM*C^A iI@xlG;-.o*(eM܇/=''/,rfO<= \Df؈ q87璜E'4't`|`)up``27 ]a!w+$JyrIX_w|{#<5	&o34O^ EIjXvE0ec\6Ou[߮0^nU>L;L`ou4}^9n]cϧMpm{ uUAɯ;Zx:š{B˚saSל#~O~>ǲQާRsFy16,zTM $<ɫ!i%0=Ի敒bw]׊@bѮ"{!I_% 	IM4L`1Gt^Ono%ڷ<5''5x[Dn0W͉&W(!I&ڴFtzw֒i=0؀0|P3Nir!I\ɐRB|͐h6­! t`엧JNlD;øWZ	|HْIߑB+<k OÜ| -?8Aik:IEuEhf9FD.8p\vb LiRjآlǅ0i0ٟ;;)U"kd9g{yy>WN3xc΋hC,vReI|r1Pi0i9YW]~rcC䔴P}~{	br+esivTAzXWX>cq<1؛j'mĆvЛqnkҢC-}B(l$qg`.:K,S.l7_ӣl2ty>lP73	UQ9M*u.d%QeC71!g"y96X)c+2#6xCǞSzMAn}o,o?ddZ;tg{oPY,ؙM/ĝoҶC Ƣ4޷_$*R҆"oJpg:6wwoz>L۞pDsrz\=+._z݅uxZw	\o޺t= 6h\!KIƅ9(b lx<ҾRΝEFTvvLeswm'OQf6	)l	BKͻNrsZop̯fz셿
.C(sodG_`3ISuҏt |ڊZ+?LF_F݄9'iK/482Hr xGP	M`t!֐@_$!&y4B.)[	f6qL}2edЙOgWD"؄zm_Ba9*^ChaNJ)_vLzv1>szfmO=uvsHY7)Et-udNt=O_Ny.8G.ԮR}Gɬ_u?#pYYrA9z,L9WƥG '}PZzCbl֡WEՃ3hQrdd{HM+@_pg=`\'o5tmZ=<Dѓ|ybMhnR*:hCH^rȓacN!rYF7#32:zYqBH(iCv*;z	y~݇"ɖ}WϿCqÖ.CHAqJy}D0@JbĂ H#32Ƶ#fn\ᜬkڼej
Ug¬;jl&֌a:!X5tW_WHv[ϼEg>	ϗjceQųMA^cčikWY춟3En܁>/q|MgHF.&OW$뙁% \?3Y2:u	8h׶ctz@3|]Y_[!-rb؈cd2Y)iڑU	fR۰Ҭ7CS)_1SB޴~RsYryv64C	7,رĉ%{$S]|PiCyͿ<},( ̶p5Vd1-}-´ރsK0˱<+"~[ Ysx:<^WΡx|5^7e;GH31Kl{D.oo!- !jͣLPL2ٌ,7Ӛ،(Tft CV|#7F\LRxNZd-nDFMo&n_~=j,՘_^`Ry&`'r-R>Eb`;'re6灞M;&oZxLFV>>}42t+:*dt6ZX|aPx/f;>!r Ti[ìxcgf:2sA@: 	J'#Kv/Ù\qU8Xy1O^7<09w?ћ=ى/.(z[]RgQ.2QS&߂aO@BK[}'*c,,6$
IzKm0sC=h4C9	3p8WQMl:]$x:_
w;.
2+,7X|+AP0Pmwǌ8Q.0qOJ˗.l7nj:1bs,2&)bH^K*Jp9HNv+])qj 0X	k{㐄q ?wAS^%wYT֯͵'OtL5'0%=yF#/Z'eR9ई20狝ӴUQiΏVԝlkg׶{ot{ﱤg۽{:ra|Ee% ŀXdԕ-)aIsj\
Xqmё{>|ty3sɧIG(@ۑ9Gm9F(`~ˇhƶrR_|vҏ53^<74=nIeI:r\$iUG;oq1;QNcr4op'<]1iHw@y_Rg'Obwnv/|mC%,˸M5a|EI7ir)D$Ep$#Gx 'yfqw88d^r돤r)MHhyrYoE\SUWk)_Ek9HvF6,yrv xń>Вi]MbS:h|9L=i?$NQ}З+jHs0'y=1.>4oF n/$琴ټ.N&POP=QCVXC!D?"Ȥ=K0̈WQBaO)QpOEOd[ eW~zT9NO>"FNP"q/X(Qi-v,#1N	:dWL}Ƨ
S~An+AS D>nygr
abv`	. H+᭗bMHc
Ne.9mxۨr\6((<۝(qLp5R{x/UrEuH_=.VSիY3p O)5md ;ǾIB3U#HS+ϘfhRASh!r[ӫ;<|D) p4\`+4-=+4n&t$̡cᷪk/C /GBOKxBz_О<+;ZΡ44H.H1VuyezPt=>CJ]t=/ J&j1vhnUqپjkH>xnYb{ӖtM`RwzÔQA'{0G`:EI+Opkl^`9u|(	h}jT<¶Gcp8^{^Bݤm;9~}8ת$ݓLSN\0EL\+It@W2$3ho o0Lw[64wU:Qq#qMZt<SgzAGRʀŃ:l]lB{#ԝ'Dp)Ÿ`AH"Y&SQBR ]U:'>A.:B Q,̓ACwl{#ٟY-ǹ+l*(JZ&cћR&
ωﲣ*V ^>9B??a&|S>iB&)ufrw.Mvg̫z!o|IwAU`2>ضZ<Ņ*>I['Lm;qJO; }&cꀮ /X>: qkZpM&9'|SMy:2zGBx3T	TQp[ՏpC6|qL,Lh5'L~
'rᢁTwo{pK++/ +݀Esl^AF=y㒉 qDO`	C%hX͞"JܭBNH5qفLI>x(%9iz^`NyhazjQɛhx+Z5yvhik>*_)JQz^z0sub(YVh7/_>nݼ<GU˼b7BU.a׷7G9|5Tך-8 {^.f k
'Dg:?%[=9k߿Aoυ7|WwYQY=M?|u{]OeA+'];s]}uuz?~lmOYbAa@AA僯*}G?oOrysoEf|#WՏ8t(Y
,S+	lЯϐ\ ?.
-:rClD.h#ER}P E*(aASGe]L?>I	_E" H*;(\:>rʉM=ҷ֨tHx@C`;1cIQYM^vLZGۿU`i>Gkl՜ޘi;8Evx6~؀`r}/ɢlv}8bP&[F򔞲Q?nxK=\/-;ccc%
t>)F38࠳CwuA	V Rڒy}n͏Q˸ b&s'8 կ%I`Qd A#|4s_CVq0"`ZiHAo*n*yV6F1>XzHXZC }H	uZ<,#aO6mCWlrqR4/lX ]x֯WܤxhDt;ސkG(Sѻq>mGNAἂq@mv|2Iݰiqc7t\ m1}BTV qƷVUf?čO4v|Ec`7h3j_:9&Jrn	nQp1iъ=84'Cy(sm/N<ZtHpH8|n
O7<9ҜOBْ?ǂdmFk,"_i{eǘL;qsc\,uhk,%&~L;#Յ,X*ͺ4J.p>9΁!%EZҔQF}lv,փm4:v+rP3CA':tڈ9w N%?	JѸk|!r4`.~&Cq#+BՓ٤ O~G`T~>qc`cAtI8q<cE'sW-tBdJy*:_*I08voV2-tDHO	˵Š܌! 1Aq靓Q)?ol2rBxoh N&&~
9ܴ=1uV&7aQlLbWEۥ>D!+326CKL|ȉ7 	pLʟyyW14W\6-a|-NjJ+zʄo <>Q$ҷm3KY7//SZ@&5و"fm}SbÎR	:nUeOewMVt(BMӆ~Cnġ$XV0UF==f(@PB'ԫ]$eIE3hC7RtD?Zf4! oOwr_n|39yR+u0ơvX 9L.dgǦ ^§E1&@F?܍]q>wY)zx7
:M|9O0cNZͦdgWwNm'Y!XDBoU/.Ͻߌ=O8ΘNIt_'7N>s-_xt=.[NOƍ~u<úϽAOY}yrA=o.)߫,l
5=s7s2ےmOّ#soͿ;-q 1x='u2U;%	E7Maː^"G:xm-<ɤ&]sqW- Pvæ
wgO->DBuΝ<yE=^Rc>"Ry~t`W6)ǅKu-6d"B{<mJ:{S|:캒Ii'`e \֭q}2kzrwUvpX"?k7R:K픍nO#[6cAx\pGvҥO#$#/!x܁:5iAK<@xV66P < Z(͔06;?)r(9P]eeV4t֕W̱?gZ9q@i#78}@Wm_@:kJ/+f_%F^\+TYV]J/\tsP9G,әË%72|N>ȐCHē>{4$WXYit:q"59cxs'w-q*:?u0aU:&χ$~Im9m?|M8zRϔY?wr氛7y@agԭ=;,{n mW>gΞ/hZt:?k&Yixov3}hv}|Qƕ'YMHyzzz+k)IIsƮXSVu{XDaPL|3L[ju$NHG۠n,OKomO"[}$FNp jT#:%~<M"Uw7g6VX2^t<0> 4Jurn'Cq"olU1Op}|J7 d;W>hLZQr o!<)Z!*Gop [靖H1eh	:d'`Bz. Y;я!ZN_m$FzlX*2k肭F!%
+Sش*m_ DX(0{nSIӧ?,NiJ~79ї&9R
PAMWLehzȂ r)4LԤ)Rwp,=2^m oeqpP.e!Ƈp 8IEX6j3Ym8Mq2ؠzTvi Ψ<U7?I%_?#FI$6c3D_ͰJtCɉnҭӜHf u+_Z%ѓ:D7s!xŠa@6nS6v&	;u8YV{(q]9s"3$W<C~3~G^C6D5[8v]$?G@ax*ǈ HvڄO(T;%*`S6x%T@&*4u(i&0F$N^F]$`|csvX.0m:bDcw.$ ]1_ߪ>e<[(c+rM NM_!pE"Qvϸ8`92tYEWnt_dmP:__,81;rOip"9Q[2I6>Ù;Gzt]ۃlֶ2|1BQJv֭?ڞ>~v~g)<y;wl1g{7K]|	[DQvc/7OutT~nB:AaoGO</RgYK<	nуz>cil_<,|(oMq'Ir5sݴ`WθXȅ%TPHlǏQPRzr	@ooQ}EnOnf@]&Г6ŗo|/ݖ~v}v,Ҏwt֓:J{n=	=kvOR5u^p4=!8&DZ $;NP$e-`rR#d>0$b?=e%2Z"#Yey	R\5W!M}io%	-B7	˼jOoΧh7YÞh:$#\a4""^>}%|BMP?p9/&K.xy}ӎ0BW9S|[IPv^+ocnO9S/|}pPrkszk3"Ϝy]u0؂<V9c=xеˮʏnQ!]t8HoRǹS7:78stߜ~1ٻhyU*7p44ʦmRat#e\8}l`a2;^ĥXh&PN?9arˡ?Qq^U>ŘM//m|,?h=7 }Z6˅L;vR	: Ə`q7ǀ~3.	Q'ȴO0ix֎4?4ˋQyKZ߼xKAFe#4]B>AXkz(S#l1[SҎh#3rԎ-Xs7[]90xsCh!؏҆h;oK_`iȁTPr{'jRrfsiɮ۫CosԟCX2d8&-gQWCn(|>ˊ24s|@rAM2;98ayK<:*,
u.5Eb*R 1Y\!
J"/0ʃih4nn@S"S>o~WdYD㗸EN ω|7Sa&FB:p4 Bd{:u:Va'Fpf/zÔS(7W9ni#Xq#)!y3{sAp p+ۏ۟?eGceb/RL?)/E'%ZƶOeȟ#?<3ЋӯLdQ{wrž{*ecQdc1(s\ҡ%ßY }۟XQCp䇍p׀Ȧ}5
倿mݹ?Wgek)r#ҲUxaD'yjM>R}(͋	I9VrXL| Ԧsر=$Z!\l8nWSH*n4`R!9b@	hBmQ&="`ͮm#aJ ,<6,r"'By1}~6+z<.3Qn8@f}r,xv. Ӈtӯa.LX<aeZ2Lن&ENK|&}C"F6EAW/yDN^t713A
kzec9ٳŪDEqW=hcajC+phQ%u//6 6+߸(M%7'O{۝;w(5z%[%Pݻ40
s;ԁ"{TuxQy{k-JJ0R|\z'< &X1gnǍ$Whc[N8d6џ9ѥ_Rߺ]yhteg=ڈ^x }:{B6y&  wUϷ7N>m89xC<T<=o`asb7}r~g7=\߾ᗤv;*7O_R=mۃpU@*"TrхSGIGHF.edހ
DZ/2>ꤝۮ~@URL7mPpCL^;8`[IT᥎Ð5mo3L]%LG/[Lnv3.	lPy8/NԗD,j=^=5 GOvuA`O<lk+4Z؝[_.	F")=zEV`0h&Z&hZVXsiɅ>O372Ic^#RrH#wF&+̿6`/LǢJNyK@!Oc/AŞ? ɇ2ίtO]s}mh )"&'GT7AJLU MZmoXf1)chkٰ^(Zʛ6g^
O#irPr;A-9{82uء#ƿ	(F?Pde݃bl9
a{57Pk.%l%0I3eCEK@\>]̓CPv	܋zjZ`V/[P58@U|^c=Ua"Ov&Ԧqj3~z|-vOsIۊzUyd:]|k  BBI2fs׍i@_#`iU*Z&?Lxc~)B c&D(#l|]/neSP᭿"	"R
\U4[sPsEA&\Ϲ(|h:7,hZ͠8:AA苣;yN,7ξ3 i¹ N">Sm=\'
;ʡ^}i	G[ۿKh:!kM;,O6^hra7u	{Y`\`p"(!fb1[2#p'.DGRȺ4x$tdƙHP8)_$A	+p㣱Vܒ 魤L
Ns ,8AzZNd_w~ǯݸ-7U{x}&slG	|I+x/t}7~}׿yf|I6bцxv64դ7$jɇ/:x/Y'r;{= 6Xdq'21uO'NmQm2«pjگ~/{utoseN\.BӟBAv|@4>e:Q;?nէ?(/__=Bqہ{o.؃1A7䟰?oھoߟSGLEj6d#JHC;g.K?Fmg?oP6H)t6_DY[\Vȟ~C86C%,ж6XF_|tXRXطҕ<NJ	;#(?׉/0e7Kxm\`z=Љ Ol|CJׯcΜ0LƁE/xnV+;(:yA(ƌ9 -Հœ'=Q/ j@+^3_SSemU\l<\`g|}m.DR5c]_Xa;Z&]%>q|l{2QNP=kbUܾ/x<CbI	1oh`'HCgoH˧W>|ݽsWvVF(z;Wg;［ݻwoH4h	uq~ПLnnux-͕ny	rת7z}Ծ6NۧL\h[`lM;)8S6{nQ;srA
 ^SH__7ζӳ۝?ܞ>z>zMs4Wv6zNT܅SϵƱ=IDv-q!妪OPYqYh-%BdWB>LD;B3і82e}{D틟ѦjBGuo\=YA 
8e1CbՋKa=D7zJy%H]em>}&5Z܀I;])+RvEpp+ĺ~kӪmnWZMoɆtԬGG*к,dʉ%97'ϷIAB.@.Yie :ߤLeB IO̳.wFg@vf*@~a!Rޔ_򹀓&4)zٜvLk97bw9/9K 	:iށT8EE#2fz/ZDŀN?Ȁ)F詞"mWv6hi
v7m[sȥ]])D:_q"d8q]m8u]	_Ű+¢oi3]-_5k8ƅp^گm)Ǻ/d7Yl+;`/x{:b}[5\&l 5_[|sVD	#1Kr#.DlŹᤉyx[G]fh^etLF@Xat}.Zr3H֭21pq!|L˝^t^ɓKo\O9R;<Fدǖ T`~H(ĐC:R7d}7A9x}]C <'<H Ʌ6cF8:?F贕
"k .m]4
oBB2e$}<X>Zo6DK=\W[~	Md	B\K5iO&kZp?/~N~mU<,)SpS	O36RkqH-ҭ`Ii.k (p|igj	>spZSSw7_d/\`ZXw CHWAt)̤JRLъw4P7߶<r'Xb5p3yK|D,8ǹGgy%NyiXL'čK9ѥtA8iJf@ٳe$% 2y>}RI#^d}Ӷ{??}?8'aA&yuOo/c?I~u7~}nlЙAPA9Nbu	j±˗v79}߾Vټ`DC	3MݷlcҒA%[׶?߷5Տ+.Є^ikawl7TM-G߿~gu[~__~?[`QT(rO7_~OlL?ՖlO?}olN
* [?u֓fl~m蛶+݃w_?ےV/pfQ\`t<4-yBYo"(*3ulOr4oz$Д&C8ڳUN &-y"<OМLէC">'G3*pvR%^P3u_It.pK}wOx\-UP\y@oAbl '隥U!W>	RǏ${(Ѫn?v7n_q5hfD.0Efhl;o (0n#(s}: Zӳk7DB\@ Gz^fN5G~Nx'..ֱk2[Uoߒ>̳S<i7ud0ֳ ul"HYZ^?D¼|%9kI"?6J9?yAKa|ŲivvUˉGOw{Ӊ>zl|{x=
rW1Fԅۂi^@Z<l36B/].Fkj7^<{a˖J`&Lv^(T"Cfz-zbTi!hs&hY}M{W>Ѐ%{<%^1@8iWֶiKv&mr`?ZJ[m݁H:vo^<J׮^u1{M?-v*3nv]a;+Iߖ{)7qaZ}N'(<tD$)ou,cp1TrxEQL>יk)r4==W1:
ȇC8D&kA҄NX8J:0y(KJ{%pqmr 㰌E&t'Iؑc@Πdოlr]9X)H귅 -fA,5.Ge>m%`S+ʓ@m]#0öINɚtD#4rhl5	v&ŝMg$5ycNr!FX:qDBX@ȼ"qXIxmD/R9?;ebLl<
/Zm/R'ۅoʢmh<ʓ;n8¦.xĩ7@^mNw\?hC;O,vQf4ʒw`sKJ؇MD\ͷvuX3-m'wyJ:Nܒ[I9j2~Rh9V mxb|#YO0{(Śr(L
2;(*0Cy Ӗ:tЦ~+{h2߁$S},snekiı-pM^l)\ 떓|cUϐly}Ȗ0r]|*'z)PYZ^CIɣxTcf@MU^oX|¾IUk6y/	&} ;ȷpH}q Z`hveO:L-;叭,r@Zda;GFGDܩ,=)szbsgE&,RF[9ϵJpdpц,TC/Ǡ,
	>͎8Y3"U^8m;bf0&ǉQZ|Ɓ2 W@$;&?en}}_T[__oI;//K]xrwq	?>y{ܾ{~c5ۯ?w獋K7l4oh1)@bgw(8lN³]ݾ_K_p>sӾmk[LXB歛|Wi]ñc_m?gzzy7?󅐿"N)S^su9g/j
(9mDW&?	ڿyl_]w~lguIׯܾ'_~wo7βy7@ax2!?y)4(o_K~|mi=Ӿnn~?gmE/,b	$`ixsFy揜V?x]v;g!GX<
{p%&h	 Py8xqIq;Npg*nmsSq ܮaX[WnE'mx߹{'T0]/ Ƕɺ1|"W㐉GiAۯ s>ȠٜpҸYN<hn,S@5tQЊT'h~+ظ8-*E:[);w>򅰇npn]Ըw)ѝ;#;!7oni~!373lm|dvvf
tёv.¿۽qu͔jOe'0!B~<9Ex'~%uI'䢟zszzz|E8$>
5FDzkݐ'eN^.	OޗDå>XYtҏuE"ɕ+|uv͊~ySĒ}%:sd>/ףGU׏Hru-^ā8waٜ5P^mKPiƈl ?og\yd-7|EG~d;/],GG&52>8dL,{Yzo'䱑tXG2vr~ eƎ(?e? vۮ^|)	]JU+MrATA(BG*E)*RHON۽yƘk};dw9c9fokC[ b.g(T /}QE@v܄nZ ;F8_ s`Őq#w##+OR,>z'l9}r9}Znˏ}V o]Qgi]~O-*rc؄Xm>VXa@r~9,8nyEAe\&9@Ȇn09fb{6׎2/=-C{)̃&brvn ;̩}Q7'e/3X/3
VqٽB/)i^JkN(\$\gfi۞ K3Z66~DdꬉDB[qC$O8	,p#̟O&[c>jw|-ߨ(UKWz}{BCh,>}s:CcsvUa(I/tPpǡhy{HG4x5߂4ueoy{-ެU9\ӓ{nScF4 cdup[5D=AIS]!|D#fq'W;vuSqm 	Q1
i*{l(	4A[60b(kvE=	Pm许I"o<5^5ߞ8yҟp&c>ʋ_m#^ᙗ0.F~ݹrQmԊ*36a40?yI/<A˸xt@MD  8345l5mŀm9ßzn;3eH9eօʑcQٝOkZ)w2Ww?\-a2;K. o/Sd*+4}|/h$iTHgC]{V|}.NFO.K.>t&V׉|!oN>|qߕ
$]KQ0ۥ@7ț?h7'%`{7t;={]̻H64IљIj?_/#ǡ1R0^.ꑙ`=J&	AL8پ*AIQNY26Wh|cn=!dH睗/\~l/}[,/qp8n+,_gyl:O,o-hE۽',-w>\p@4Opc6dn忣0h]]xatݗ/_Z߼>r?~ty֧>_y̩/S^aĆ'H. ,~.K,?K5hUlХATOnhzYPymyыB6{J8S)QD/M|.GP[?峟wR4/gİd욖"y?ܷ;5??_w>uȏ廾%ˏ_Zo髖O]0tߴgF~{d(۶+Sim8zqe'|ðˬ{2}6Ŗee6po\,Zuxa_i4Ŋ
U~ڶ2`գȚغ		?J`lI2:~RI}iw e@,eㇵÊp nl
a	vە\)2WYsДVE$LiOi+Sa	+pxӕnpB
#mAvS~
Kp3u*G'zr9{`gS0Lr!`yƘ<Z#<
<P1q_>>3V'q&Gdu-ҏ1KKM=&㷅_Wu_L^Gɭޢ<QurSrPdߺ<M--Ep'ڭM-foܹܸ}kr8I;3'"Ֆ$Mv58 U:
debKe>o)('67c"Ee!o<}ʋr69-⧅W m=ހ^QoXY/Wn2a	Ü
c/\EG8U8Q <v81U&|yVcmZ^w -;CM'B @7oI'ڍȖmA'Ƹ_n+DF@alm#q$kMu-V|TrDt^q#/KKB\C-ŜMͣ-fS>&dl07kzo2>8DtYodJM5'N\e=u9okz(u7M-P>6ۀi.7mq O3(k8wg}KcL.OY!ӹF_0gO@8(=q֜<UݣPf'8[|ЀB^?˰1o)RL%~{,t` {?72(M>d>pK;DvIĬqp>H^7AnM˾@!ZeNT 2 F~N,{CFTiSI;G6[e%<l,r^9hρ;~ccI*_%Ô5SbS/Tatf^\%lx!Un /ƊGx4v:.;e~\y	C+ItdEv[>2epc'0Pa	[QnkFc7T6n	'D0aV"Td?ml߯דgUz}JN}aߐMxܮpaռv5G8q怨t|A+o8}C.5| OxA3q`?Qh#{p$7S>dѶ>铐<kPԧ.iaޤre=Cn]' ߔPw4_TC=!4x_Qot7_OQEsmI!C,<XN;_/p47*?vptmph`!\@5?&O8#O4Q6.*vc?VC.݃5J=lb;:KLдE6xT8&UL27*aS\L<~KRiDp1eUxȦ4Rr#Z)	iPҘo75s95Y >{O2x|[w/{uˇ|лsEdsIN9Af080'lm4h7|EJ#:/]^ӿ'}<c罀oO>4sSGg[>CcӿM]_,?_샑,r	_'.gΞV̘w	<x"&󍟻?~ͷ|g,ous{s.Su˛gYGf:F'֓U]?fo?7~[zwj^~<盡lyN8Bԏ}?2|YOmB>}!,6-26ܡaLl&x48!c6W٘0I2*|sDAѮ!{y5e}v.lg!1lCwӄPқK[CN6n/GmWM:?mɦ0?Q;$x1A\pʵqG,߸T6$ZK,z!2,D2c7]ɤ~0⮡|[{2|&cYm"ۛ\14LF670IIQ#02Q$ęx&LtN᤟CyH`YN>90a60w<1'iG-/d{sPXlDi6i"qq?=`xkI4tMo)8Ti7x2NzN:a$+p)Zxpqo!	DEuH8ް9<zxJa$jN0w_qr\%l&s8</WÂ;Iʃ!8.
1݄쓧8dRZi4pr	 51ueZ6'G~O])[^ԑG~іnf̕=}ӸL +ѯNXYz[6D`}_+397䡍'qNJ_I8Gvk4ɠ'!~"4-)gk8 M\/$rZqIiqCh7k^__\|o෹"5l\<O}!;Ļ=D{ p<>m ԃ``)}jC/rZlh炚@wBʜMdOcD)p1 q#^7a;.ȋFU8< y|Q?ԇԌ/:3%kqɔ.K=r|tP<}yܹ劼qY9t9
MՑMy3$c|}*f+PfNo5l/d7tQ=(>K}@X2eeCX=HAL0(t	]Ý{c3rymJn;QnGK)KU|=1G֭୳sy`v5뢕v-~"}kD?tq8Hct9mr햡^c|2%1p㱐/M:__5y
}h/m|]_PN<:@GZ_R.a$rwD'fҸ>P_G{nɿ1ۆq<u1t{Wn%Ktٸ%}WL_MccϦqe<j\pO^N:94.xY_<qQ1'qٳޝM?8Cf\©;G
A˦=l!#Q9ğ3.A~ǵF`4	y/5mء-+v@,vjf;mY
u-acNF0W܇Hd1ʙ5G_ᦿA|q]˸/ڄ"S8!KCGݥI_pW5tyss0uC`D(Y	ov_a8{	!Z/9؇C/SA;k򃍵4୐W萍pؠNu[_M3~ Tv$+Yh+kHŜn(gJe&\.45lRPT;(V:]5LeRIƃ";'~Nl1	.aTd*#4.:g6;9Y>||Oo\:ѝ̜(Ӡ)08ΟAg _?>uL~et`2!~P<AMFA0 N&:wv{?O/1_|?sE8Pk>_;=-RUTAcM;Z 
y^|G93>-G#?c1?g]'W%?H~`n4T?쩯+1Ԡ"٢Xp
Z*?ڻӌgӿkoy7|;/\oeA?bPavbc.\=$뇖+mCw`9˳?$^Xxa?ڿ߆Ct3P]Ld-mKeߗ
2j6|	Ӵgv+LOFx˞Ӳi$?e\e+&Y<.iP# :O<ȓ,xBGb{X/f&mg#q`LڙE
{I&-0d{r7MdorH!eQYy[$2[	,7i_!	K9r)&6n[B'40^M;8L5AwL$}0W6T	F:%Rܒ˗.-< tB߹ǰwbßd$ƂIOg#&zQ-PgΜu>ȣ煕|!:Y/X8H1J?gia,4ϞuRNP7yu	FV<A	}
3>t(/w 0"<,}N9E$]he6teDܤ<dӆEN[3S(#>dbQz@u}Q*3Au;Xʖ'/̷ЂôeuL<]TG[Sd~vRRܸq-2Q
(+q$N[.6Svq 4R>>W	scR GCa8
*rg Q&5%{0nOxMQ~]BtR\)7\&Dt<sΙ`;Pr;׸0,&)mAW-.]^_<؅+±iWKޤNkKͰM>SL'ѽ *s'qh747;Qʹz+犆p	%rZvwWlwM60E
cùȐ&W0M9ho	J.>:x7sh,	py Lo-_X}s=qnw1Av@tJFٲ6״WM).EHLF= N]$>68/76
S9}{ig,<0y7l0l3ʧ<G7;<ZbM=zxgoBVqEcG%~< G:yapǄ4z/i=n9.ocpFAC<P|:v2/9>qq¼7f+92̛1iW<dLN^Vo.5g*5RKɕmeZ LG[4ҴLr*sdox.g -ƂiE&rSC4DX̪P#&(F2	nӗNSOtm0D"D}X*oϥU|IOz bC`~"y02|b*$4u	,9/d5fnϜqάIAwEzԩ^SBmy[d)IkbSGnv`3&MWd%HOceOxI5N0K*wpfeDDF61CF[x?񂃟yuP/vL[
C7*Zx]	M%|+Ϣ1G頯|)^)d\R_m55wL|E><1g*7%<YyU6>/V<M+n?؞kE  ľT[
pO #Kt9Xr\@
aE]\O;	WɵIVw.	HFdEdD3ĸa(]èXvcCIdI2LWO7 @]-o~p}^|Vo'~r42|3ƕA8:;on-LMoz;ԏOgAɖ;:6uOyB}?o./yQ[Z?sÓ_]^cy~RQ:O'd2ٓo-_yLD/}-a=WsOߤIu_AIi29PI;:yl#E/H ,!p^9ٽ	"R>TV^_=Kox-oo|˅Y72qG-AܮLHj-F}IwOZ)|$}>˱{?+|"φG!	َ7`I%zIo>7m	:*iH}86àm#eJr.7fֲNeX]'=n[m
6V`7dO'i%4Xo|xsrDnHSI;Ne&,&cGl~u#=lnpܲ=^]PnL64m t`3hR.g]zzS @f#lHyq ?lZ+GV1/6<6o9f4N^N+o>uJ~SIF?|I>>\krLP[Gf 0\k)xĉsc*;qO=:b=#OS0,@xH02WhlEƑg*,6xA-?>>>7w@nohIl65\&hS7⍗+K]4̂ 𡃎d]z˖<>s
7*vI<CK'1O!mzi,6<3	?Րj.GR6Y(g}@zE^ʆ̋6nm7;o"F9Ξ9@ڄ8;!elEXVi\_e
ΐ=*=ϡ@?aG5nM8;Uo6ZuD_q Xn>tP9k[	׋eKRiAd1~ ^OJ8;v g̩ut?6Mrm9H>BTeG,#8d'< p1=l&7aQ앣=m(yn]ц2I=˓Oԉ}eTF&iI-eBxc*6Iv䱎86jĀhj!C?NI]M}zKk3!r;6 t+$)So+
6#||3D+ܤ	9o	Ά䃕/>(wiЖM@ЎL,YAF7x]r	w!IZaĴ "{W9^ 420?A+:QeNюMbPHH8qֶiVfxqVn'_PLQFlۉ89.HL\;ow y,r^8^A0imioe>{lz]}PimjLm:4$gK2{*ىAd!?rDmρIfX),krOm|9_5GV_ND׶79G/tdY&xoGxgF4L,^S;yI _x*_cGyNaLVÄkWx{662ė,L4:xӞ\2.%m_Pۡ5??FJ@N#o*alEb~miX[NhQܹf@supc=aD7UtR&USy)܊(J3"Ѹ^^V_*#S@]4_hM~|ixEA_%Iwv<G~6ڲ{dLոp1~/Mh9=`@m	`-mE#ڌn$ &J4*-(5Y<ԗc㇗/-oԫag,;7I-z=	wMu̽0^ȑ5", EfݾyuW,M2хPL|-uQZxy~_hw'y
&AJxr[x$Er74&h]W4"S:d#V0
s̆e6bF<Ot.֓<t٬@w6Μ;$OwX?Ƽb%6j(_dx_svџ0%zĵ,ܟ͗߳w<oy׸W!ҎTx'Ԗ3g<c -7DpKǇU_[N0MS\`/{'$IG[7=Z,*վqL0yIEiՕ{r]EA+/>w-(7enO*:%ܕaa@5.^- `aNۭ+:*]GC_4Y	sxBR_[ը`laT@aʇMǗC.αr9&O1ZhGrErG&Xg;yX`rLvdpwqpHRK|hi?   kc3>ur  IDATφ~^xʋmN`Ko'ev pu4LeaKPeDgXJZ'Xh=^gטkcAuiLƲ =8>SDE۴a7P=~pp>6oIZ٠7R6<'ȸ?67=1O?O8Y'l~Ц	W6.7ڡ,!⻩<;#].<rM}>\~r[.Ⱦ!-t.d\x[kyMCG.K.J>=³<&=qe_<~yI.#HKY޺2V}&]?AFQq3PoN`#up4e|2$4靱Pv;UUęy/ 7l.zo*퍺Ee!5,b8(s3{&Iː3e!<v:muY0~m`$YnI!yw'Ni?Zζ`d+VFXo ?s6}0">6+1"32%T,ܢ﹂\qOSY7p) zbЩ_!+pǞvc=]|*9hR*H
kal?(P?yk<&8JjcP!Nn@lWSWDb]$Rl!gF.kI=ceĘD(?9G% |kƀU)xQ`*]7sRGw"We<pa{s7\3TdU3}HYmQ zCr,mB;arXTU"<@e t^wb	W~4 7HLmcdaG|hN=7s|
XZnns[۬yZ%؜'m!q=;_[m e8SD]-vo)*[L{(>m7M旒ALJđ>ƲVѸa߉p"iGc<ȁO6.'Sq@@90ogA0sVGT^A Za,&/gn8R1ܛO1_AԮ37	%lEfJteOg]q	4qq SW	ۘO<|'?I~su/uM5>0IsmJȇ@ڰhxHyL_$k͛(7xOXk	6+̽8bXS3^mΐ/ab==,4DH-4&=ojάro!pfǆ6epgo-gpmֽVCM鉴$,[~ 78Gdm]Fvm%U\5+M`EėͲ)]9voSo\=`{aE̜b9'[~yBo+f9

5jrtr63,ELaR r]{ä2Foc vUIw<c'c$.?7S,ODLno|}{G~-o>cyۿ囿I/&FLV,8PrS-2Be0o8~O gd=Q$m{l~_ry'D~STH߷[?uy뭖_{.O{)7p݆6Y$	03l
]?w4gb67.$,ON\[=95CC^^9a͞ff1}{w./\mwo\eHk|GZOrԉ_5_US7q*LF𕟼\?{H\O-*K2Tam[P4ޖ'!/6bpW678ȂF~>dzC-؈,'CeLmHGܦ8'Ɖ.=ٍ)y-v}IiApYe:cg|SX*SxP0Öe6LzJ畩e޳IWDMGxLO]fAљ6Z׎睵nU.w{ׯhZ`m6>0|7Uw>4S.On1vk&&Jơm|bcڟcI9-~y*N,+QVɖM_Ml-h	U;Py๳g6,4?#~a<{b5 ?A} B-N+*> 4pWepWV/R~iNDʎ;Z`F&a͑V}y[ˍ+Z0jsxh?	P9}rHׅޟIÉ,\9*d^8q9trqasd"#K=bCR9ܩG`D.!^j6@=Qu7G*!Y^C)%GR<>l+m]<u:uSx6.jR!x|.\|@13̸	MeN.:lJ*)ʋ7|`(BQϷONUgL6Ix+;ey|>mMlLGENsV,낃ՇIPsq^=c`FD|oa-ln 5-;1qd#:ys ސW!y#کYe;z+. ~|EЮцxC7[<hwM
itM{_9 6uqlrf)"}J.&u$4X\7bGb
Lzz,#}<go =CkttR7qcʧoZT>PW_iNE~ty#ihw>)/]/!l?Ыܾ8d"HedS^[H>I@;|"AEO&fx^J?,lXV s)fĹ2.+:Qභe ns63yC8pislLg#o9)6t}hC|67PJ~d39xodېpKodԑ0+u@*5cGjW}l2̹FK'іgH195읐%<`B}溌AAgJ<eY㒛|(1~M8u\ ehL.JKm!c;_d#IK1k"AlaXr[SȶS2"e@lmH	[ : ~<|ƌCN?pr|Rve"d򩮴[*o${ 3/0#S'-T:^Gx
4@o֋⥮p_ތAVu9#>yym&IY$Usm4p6p'"~'o-2&aK*!`Ѻm8˽s="k
Hiwf`p`P,do0MffiT49}K!
&1i='m^6s<ħ_Ů(
~f9p¶a7J`m.vL&`,9 g݅XyoO#P6gѸNW82f>݈Tld@m\QΎɖv[hB7|[oSK|6o<ӾjQ/<끀sL$3	\ Jb``p~b`a3ή%%Tl]O:8=U,|?xGKѯ]s|쿿?ߗ;\^~	R|T'²|̔LЍP˛,/_P!:FquYܰӖ嗁a36˻?ݗx}˗~w.{/=?<yd;2VZTa
Gq/iqK'G~w,?snk/SRwMt8c^\/ywYNg`jٲ<_{@qs!rg ydBaʖ߃g),fcD^^{Il7,2p{#L&~%ɴ_Z'k|05̋j]4]+i[^~NؒVWϫI ^]#ôum8
Meƍpr;mMxYTThrWy[lBw|$@/t@[51-Oti-<lmRyzwы<5*si5/amiK,kb
Û嶑?
/y<	nS:ho"4H6ORQŢ:g	\=~\}R"򦭌+ếr ,}q'seLx~Xi#擬r?")28mwq,YdгY[peS|g7k8IN8e2Q6x@tʹUs<gd&xNqx!:6'4:"V!s7>%7s$S:3Aګd~=yC芜Kfڽ蘻V6pdAzxوd>zC}Sy(-_w.ʹ#}Hϡ2uY-Pb¼ Y-}q4жQ~)$&<Ham[wǏ4oS|3>PCSd.pp5"{6(}3aQ泓!Tҕ1+s6VǺgLuPx !K1R+;^kc7<k\r>hV
b0ejwٛ~9Z/똰[nl'@38XeDk6nȰl+oMp!rSǵBr0@(\N*<t9p o-RBNx~s,J	QP<U0Bq&
3SiK8z\og2UqGV<.Z?f^ќh@$s4FW~9Xiw%Lg|q鎟\ks0ȧoJ#Pqt_1Ug}IZ͊j.āq7IMm	v2.,'A}3Pkbƀ)r@D!:0b;"9+_y^RNغrѭͤ]v1viM/;i*|xcsڧRIݢɯfUΞR\Fi3noҽ騗$3`K<i?|(&oas=ʛx&{<9j|$:.,l Nn1ۑv2x.)CI Zpbwچń
4t,\ě90xVn/PقrK"=!z>C/TPx\[p1s|,eo*znZuPpGUMW~/F0ώhyMdUڌTzzbMy֘&kTBf6g7JϖjUfMP֮v1mMS$/V`142$ySm1oN"~E/Pe@TL{G)#l޷	sRWc]Ư6|o5<6PN9]MWO~>NǪC#fhr`ҽpB:۳	ݘ_lNR'CGrbB Fq	<4wdy8æi	J(c'Yl iy7x;g.[>Y_?uyl{~'<Aa'^<	W3)r'WO!qxA$]>b.(2FgAe
&KObcAY8._iy?3?<c?x/N>|g[>(sj}L}gx&=y'I@O+HAC눷u~7~O	T ui)uQ0>K!nKLg<×>i%K6 	?Lطeg~G.oԿɟ={/ons?#./_QidqbhQݞ{D\=kMo,_fi;`G`3NhxvIm|6,0џ0f^W[IDo+˧CmVp7>qHw8cZ.ᩏ7hvӐmj0}UzĽa(0MG4BE%ψ[˦f%-xQ8ɧ ;M]{c@v9XlNDndD^-ZK&ۅ_z{L/H'æFhd?{Ҽdm	|Zf!7ҥ7Zp^q'܋lyq4:
ҏz	Ļ6lҕk(dqhmK/,״H?{7,x;77-?НE z")8Tb~rB_b7fx-ZpvM;PinF葴ϛxp-8(3|xɟK&ڌ<3XP^8Lvb>q8("/ˋ.3r`SOQ|F<g0%K'vDBhF?*.]ㅳ|_=ma3R6}aQt!N(C@_V8,6\"t)D;7ͨ:a^HG'yK:YL;*>"K;#gΞ{@dv=&P]m˚O-qӷğP2B%}Қ>׵[sMBlF7xKOtx\҉Dx[jy^);|DΝF[FNl_mÿ	-=)yqwߜBvus>,ڣ9$yjkeގ0ti7O7uw0 )OpNi?}
IK>aO(sSU经5f?QƲ%s 
2zC.2(&}<F`IHK'J~9OGs@7ޠGRGpX#լdRNSmn&O)~%mY17iL;v\3,trm92vAo`B̃a6ciLE>L c> & P*Sw(] ;	4+OMn]^h5AڃeRWC2찘I0/ez<-0iQvԍ*fB[ \(zg~5d܇i}fΒ9'ƹK=cD6vZ=&0 #'0I<e&,1@@vMG=aQG7lCBnӸ;?4jfQoȈk!*,#xG?y~J2[	X]ZK2va^҇@7W)"o3W|d'5'y-o$!q	lyXSЖ
&~pl]֜ʤ<|@ۙY?3\#!MZ@tIh䲬ՄhZ솴3~K¯;	э(!`gHCҖ<2"!x(Ze6nSk	Mx*.
1lIMh0Δs,3Kzvgw}óɇkeh;6#oJ:ׁ'^\oCMD_tT
8uS˝k8{@5D&~5'c9nJ{MIe:yslE8n-_x~.6yxqyMЙ |jOq!	 Tlƙ9Ȥ:|FrNȰ9u~7OoX;O>}EOUg+}?+Λ,P=N-委5H4a<f,瞜foY;:qlW\LҞ+6;-;=my^*5Xo/X2ɇ/P~=}!nH|{%?^싽ɐg|{*X\|R[3w_no?}j?|G}'T2ckhكVu/C;5͖{7paibO~w|Fm|n^$';c!>M22'5偅߲0}p'llhb"C
l/?,]FpҮ.+B	6NMtA$-cvbRZxA_L	 ^y~ysmͲrG@vU3"rfRCJZӰm̴Vnԍ8yq VَS/rˠL:o7ۡZVTL/{1Zv/8n8V6	,xq7Nhbniu-oxBz%ߊ<y"U"[ňY;-y6թ(R2w -m9\\tQcilrxĦ+O2^S8QZ-O׮{EA!Esyz@p7Sy)yA⑹D6߸"^>wH&[d>/@@m&o:	"uټUcM$dZNqǈ9】r7eoH'~3qC]ңt OL<Lf@RNݺrbl;f{Xϛꃔ1xPu8 C/yyD g-)- T<.^6O80:moİAAIᱣrW~OQ"k63D8QrW	n㝍)+p8&RfzI317lG5H^{@e"zyV@HX0~="ղZt&Z+1͝yC>IG@~EnNSQ69S/j5rVp2ݤ9(񈆰c8H7&Dt%wɦ"LA i !5!^l;>xщ8M^qg	ʄ〝v~_ү~LNUq HЖsp<}Co_Ф GNd}{t]L72_IqcQg xdr`,DdϒFN6sG\ѵʃ v
o"4H/MR)CZm1#CP15C)oҷ]aK7D_a$i\/"gH#kzlBhS2!Ͷ6D._ӾfPz
[T<|.:cl~En9{+}?Hw  q4
#kPNS|X-ۨ'KW|_%Q=cLb<c}s7{~7%lͱODw/?+yKTو)by r9mm<zAo(ppDݍڕ5My<܏hevla
'erVr\MʕA$v¶_͂~+:A(3<XˈBy#.}}seBOH}QBc%YwX#Sohv^coJ\Zp# MTܱ+4Um02N>aOe .{Cp^{c>үBfYo*Dei=eyi4yr}ed!v#R[WjǗWo-uWn8~x9Dpr9" ZW/;׮l3~TF.o9sulV@J;wf_U>uw9sO}'!T	.IC &r__\tuM{图3\_82qcC:A.;c!myu_GK:uOLCt#,?HvdB}է./h˿1P~廾/\~%XV:+^L/.W*Y,^^>u|y[?uyrp;)uN
=/_>KW<kd-|/?|ֿFAXUYx?|?۾lk>0o_kz9xInXЦjh3~]_S힤+/,n'{$ȥί~ u_Wu;a;|P3R"NG%{KE`Z-^$CLa!WT>p9ˋ&;4Q}q$-[qkmDj=YfJ#Zz,7	RLw9g3!ˎPD.#<LMk>yd?I k+(a&L=/3glSC]r9(;N>G
mϓ%^^Ɯ~B6}ۆ7JY(M K|ҋ?=N%83)x60|rC";l_CD0Oaq	é/}GD0YX@i?h.~r nB%PJ@&<<ޭml&;Uldza3O77l:O_Aq	#N:ԢV]M'?Y	?rq0P)h~v͙B8˪yy+a=|ؼG|혙OH|ۋ0WlO?.]6mkHz?S75.YUzczA'@6dYYѮZxN87$n;x Gɗ"mɶ-c/A~Ғ$7+yMY Eua3C#\kߞ{1yD;eʣ1q*D.ߺ-'O۲ndU*N;vĚIzuZ0jIVѻ}ٔ"ͷ8~RB6nD/
l'൥8Ha~pYpo\.ʀgڢ[WK!&0dbߵn]>\A
생+9 
U|ِCdIr'=(o>xB~9u(|qJnȢ8kG~ȨJmH}}?ПP^b֝P3`'PbIY+R y^+s1&-Hխd.Y<n|o9àmoI _4Ho~99H"܇U=&Kr|Dk|Vx5UA#e$'JԢܪ`୳%9}}C.5ƹ/_`)om{ԇs٦@mSCțgKSv)"	޿P#;ԯ|Mʡ#'\@]խkUdᣇ511. |wޠk]<Hui#}s>C9`xݦ!t^G'ȉ!!0Vy(whRE\?$}(O(2̨<p2hp@rc[M60laY/C8Di۬!X}N'h\сK|f3UEA'ߦe[`T Ekk֯#{#h< {U6fFeʆ1||J|=KD5-VQܧt`7}+$=~-?ΘssVU~5AzFMmN;zzͶo:r[<tk߲WNYvj~SQ.O	HE,$P|o\>/ѥөs'Ϫ.\;՛ŊK'~C!A.PuJ&1T<2rɱnǚp8SDvF~@I*|NVhwo/ҍ'~WoY~۝ɖ+0sAvB6A)%>\tuKq xyY%iBtIt7W^2e
qrcrxPt\\\~~g`xBGg3?%	t~w=`پ<Yޯ^>!sx+Cͦ	w$v/3;__O^W,/?~7ş֌hM.gefmqZ~k>^^;W+#VwG̛4[J<
_.ӋvgV:௾6r	A2p^˞B++m:@ Nˬ45L0oWr]8җrLSM=q$IDc9E#0:K&wK?I׍~4Hr`<I9|x&W-}>Lb#Cv4i4q+NNyɪNC`ѵ!yox^hͦ@ڷ ѕ8y5S~&c^hY4.CB`ځ2,
\:0!p3"s!C6{I>o*6ٸFGtai*+֕ Oߝ:s}[tzۓZ;<>d)@<8 dmOޚ&erELy*<awX0	E%ply>t}؊mXv+@8G2y^~5nm&EٔSF[͢%>ǧ,X1YXQuTǔ)y@7!@~d:ysM}/2#גےPN$O;v7k̈n,o-4O=!l FM'AE{ґ4'3zmoK#wqѤ}G9~0K0u%ǞO>P8e&A9bBs=QeL%/w,f/ $6<U{#gԿ60t>"kw|˟,S{OgVYm$\_!|͋ZSSl瓭DCBn6oM*;5\Si	p*Hcww|c7i#?F E2:ZP
! ksy/kr8EKYnG"=o3$Pt0^!O{}v4*;}nV6@ƆA6MyC`(J:QF@}@e[ՇU,=cK{`3 4D%̮#od`&K)?Yg?XoM_s¨C|vC|IOR[tÔ@8o$~M٥LW h_2S7S2Wn!!YLRVy	K?ٽk	s>]dd$-M	A**90ذڙ<&:KǶЕ|W3Fu 0"$zX $&|ađeRg`Mq!Cvx.^Ee^Ɓ9=A,7.ߢ]Q/KUuyX*sy3B6MVu/c2L;9v/<<vS=E`ׅq$1}h$AghSV/u9x{nmA WE'O<P?az]ҒdvG.YTn21忙yeAcp(tQG&BCC8&eoc(7%oj۠]ВlS.+";A۟}V^#|m|0%jҚDu\2$Lut٧-9-?PA=Ey[tNP^|eȋй4ob氒ztieB1=1'N_lև7-A9U0o+ul;Oz2I	a3V<[I&_2t@xy
ZjQWh${[_Wu%sb.Z*z`&|P'&lMj  B`4\-Cf'<o˯,I7<Y,i`lqnK-HzMw;M8ԁ$C
 vxYX:f"&;&-7{4wgA+"d8uygՂ?7r?x¥v'oębimtyǧc*N;0@ܾFhZwC~Lɣt
G %,02cQ}#["xhikXiw!jaK$S#_׺`X`DyUL$s	@Wc&XO$w
@dY!_ėIĜF1`Pb{Qr.>sĮ@sE^JVpCjyp`:}j8`u{4=Oh,3r&	S:=ߤw-T&\i		+Gtw6h~0qtr@6d om@L |L\<aFݦ\G2`UíoM|R&\OUe6ݲIF_g I.VU7G,SK231F<O@ob&9|3(Hp5{e	|Ҍ
xgbb}X>P\YX_>zUqQ=ezSiCJ"8F>la`Vwǯ65Dbs6BN]#[_X]{ND>w3b0Gm#/Oh!CJ'?Bep`zRn]ȫCvq!N;o-$!dG4ah-H?XU64>mhuu~0~u@CNW=vQ#B70/2F|^ Vmy/ C>;A ( !ǌ51O?)#jIx~o?iqdZ_̭sL.J Axc`7T0Ly%opG;DOdC"Icgײ鋘#γ1 "C[Z1/?u7987vF[cŮ_hod ! hJYPLcV溔<Ff6uJ?|@b3g(dG\ᵓvD7
5T?2W.e7G݆)_6H1,%gʞ1Ǎ:?HNʅ82:&X	A\^qƎ-[[n|K@wم,ސ=}K<_rѢpYۦ6RmWFhZ t|t/@xÜiS0r<Aqs-\zG]=Olt&~Ť1\M<tY6oKP);OuXsQm)M9ӻ?	HzùYn1}U
\kny4A鄋>۳a5v{mc㜡x-)=pβ.arp}	7`bܤeIoPd<ZUz˝SJ[kZ@Ʒ?c W%yPQ$O?ǲ7H+}rSx(@A~II_`_sr	#yHϑ߰׉lK,օ#6d$~:mk@	)AcE2NTU?@s9t	V!m\mVW 8 3<W6U'a	<veCES?<o-iCƉ<?4Xz/@aw=d/z˗>q_pǋxPjwM&;1u0Ǿ!(M5ۉA}y(dsӮnoU?J p%ސӧ>.xVa.Kq-U99\4 H0]ܹsSo-	7Z	+MEL`pxi^iC^sK1dYef5ҬlVjNJNDCM!$$C&:wpbyVNAO*p8I<2㣁Lq!tȂ<k4&'br'8LO4IVL-|D1^ oS`pӵJh!il:_釅!B_A"Z&xܫ̀S7@|\ކs[,[7ICs7>`lmm
F5]k?q]Cdp} $|}Ca dts.'p#Ga~Ўx3el4kZ@VC@w,̈́?4(O޿</LZָ<aƁ,k-`/YK.@:U%FN_Zibcl2`XHkݘbVZ+py"׺Hi,XUldSP>PIHmEB;
m/oa篈\&>eJ?]ST6+(>wa9Yg#O'i82ND>d&ЈA8hl2vz.E=[w0?gFO)yƕCԁ.oo*h΀e'NvOPv]Q	MG-Z#o+~^qXg >Fb~:|\6%ctt#Yb#lFw	)"+*0eTr?RO&.k#/2$\xe.uTa*t9t.%b>qs!L,6iO/
Et#oI; Fek4*54gF`,;PY2 =YӯSGf%WCݴ5:pH>{|$\R<lLc.|T`'.u%`fHeb͸af3ڻ"mu.n;TT'>m=a x<x3h<R^d^'n]yq]n{hy=)5 ׁmu707u͇t |MՀzOr&ZFCχ3)TcoP/*?ݘH&X)Pg*'2EȃH'rc<yhBlA1t܍+Bst\utRH7G/ -C	Vx`{*u((e
ID0Aۡ$_OGkLۤ|isV\Qub(D|	ԇHZ6E#MAG%BNux(W;Ί "#.uKvO:kx(9hLhQ`%pa/~ d4`|mgnǅ)~&+5-Xn{NyO?#eP'uOv/ W>"KGrf;큾<.U&]31eA]?Ér鍔-n\0daMσpQѝm@UjU::>+Ʀ]T29qt0ظdY'&\Ô[׀vVT/[(n]-L	0޲wXIDI9ό$jB!$<kk yrk=W `Q&7e_;SS^'sA~XMR )Ǹ6Cvm3]#`nȋr5&6_yvBrx3-[VM3]lrzO
n:C49FIۥӅ]ɎCć#6&SZU{@i[e7<*lJv|oXq9bMBP#:QS٦qWă"Dظ-C;iMnHoʇw:0߼=hԠ`DMTy*);w08],X|b@2}@oÆmdd :){r?7z&u3&	Fh`xsE3atO^8kK'_qTYn}-c~Q"ͤ)nG_]3δD4<"pn^6$?@~ġ${ұ!&=yHcheu'm\'k	Oo<x>Kc!w
 G[qj02w1tX]r,6"J768ˈ^`1SaEdG?
\:KzrJ^:Q4OlV?wg!2BFcmp( }z В*fẋlҥ?AF?[m$#MC2Qds,O'3}uy+=%d
er#pS' gX(yĘ Z>Szׯ\^wU'lD 'Γ~"=l,6HR7St:r7BߝvtdY7[cK|R5Zːݺ'iM:gv.dO4섑vNߴ\_BS&(n^xv9
 |5f-<yxfQ%cW>Ǭed>~*?Mp~.Wq?KG&$ϛ?dI"ut6Zχ2W"㼋 l@M{,PGm`ǖVʾ0aI L==eDbeJ=W'yhgcrzx)z*Aw5Zo0a:*3 o2x}R^&|lL-s(>or+
3.Z7z#TaS	11R8VhSFmS#<W Tib^<!~N$ޘ	<)ypz|7F.st(]d҅?_GOHy<8܂ۇu'Vy3]+X8~x;P#)jʻu=$kp'<ХJ?HUՏDW'4SvӮv>pC/C#Om4J~}lA+o-SVԆu54UIs|uޖȌ&Tмatd\0$n΃5~GƩk}`iT̰ȝ =:nĉn#$څ.0p]Ի Mi0oMVO$6K2|i!Zzi]Dr"?c ~uڑMZqmMK,5't@wN޲zrg;z/u8ۤ}[5"OZ@{x:V^7sCEOp."-<GYзG6i`R6abM-ZٌDVC\q$
GQ^GФZ!!m&-¶&>pq*IK:=󂐖;zAZ
"򠑿ejt]=5k^Ν[v+=f|;[x!wC.`e͞]})
4a/Z./'&K#>\|&o;	W"3'YAtGrDYҭSNup#
Y	ŽJ`07H"6}=2Qdq,[Ν#3Fyɰ'- t:rFm*{ެsX4L`GxpE/x=0^7rC]V}Dg|ˤ]\6PEmF<SsG5*ww7@߼Zt*݄``u(I@FO	*%zҷR41YMbx7zB@$ME^Xo_=~a 5kXJ]La;r\C(1[v[L{lɎǆ7nIyZD+`lt _
M n,-lz#/:my{c \O3ymі}
N}:MqJ-F.Vu9~]lf@C78xBmMW#yhP"I'gK':ʠpH7Zy@'ӇgV1Arw&@.}yI9!9nU Vڈ>GuxZΚ9>`:tR]4'6d yݢ	b8Yci`C_4yfʘE<EzʟoG'p5ܓ;:&]1WpH胊urdΠ#,!UaIxݝ6\XYhw@F}kuny(:b?|X_X'|$}#aǔ9*ܠ,.T
]L&aPF?t欲n| )6Y>%O^gB:=#~Ϸ(bDc^
~lϝx7y}
m'i?cF?hW6)06ˁt!tPiH^ϸM?>'k3IaBӴqc[oUw7>ޮOcQ\e| s]Gs 129t懑OTTw|BmC;hdED^Q7s^%/!|t>Y_x^xܟA}ΧD݄x{Lfh,11yWʐrh61>1C_H('y0Qߕ<q/o|l]հJ.y_Àw7`H/ja(flu-*Fԫj8N}q_,d#H;+c	>y ^qSZ.FfcCtc=QyL\Ec!_{uðSB?e!v e˕q&R@,Ua.?߈ZvAΝU_WOztkY1zqE7 F*go@O_8 3Ɨ	ol wP;8sDM)]._뒛~er頭ܴ<*D#ݙLʀ3!69"]a5훯ak
|l&@^p(NE_m@qrK[d:
V9+@2:7%д?3}^'Ҕ',Ȁ}JQ!}~l0J::~b%R]aF6PuC8tcl/.
VBC{M+GҺikL{]PQ*4luk77;p3t9>:%1soսbeA{
(0_]]TP>ު53!& 17"d7(̑&Lb/c<՘2a-}%U9_>wGr-[&|vt3.	NzkYf͍;䍮tFhz!CVMsɂ4]/?ܢA҆'vg2>&X4RX&Y@e@-JɲF?;_5lFhd3!		.@_cP1@Q

d|!Fx?}io
sCX<Hܶc6 pޱRY2	vyb:ʓ**)-MzZ)`;|6pn([X[d@5q%r0' l'M؜mՙ,N;˾L	4.]/eh=LrxuC
R
M\	~!(y	z|BåTF,ZMr4E'!}Dyݬ7,(yFn.ys #<>+JmږMp>]Ǥau"B?f}h2s>HQ 7i>`
s9SrrwO  ҈	h=kqUJpEace[L@G|;Y[>6M/6%˛a)[XSQn_ew>i6c2Zů	wh6!(GMI[#q@ى7?ʶL+=
aT7TÕĸ~LV\}SX-P>cl6v`s:qUzpFMG <5q)[|{as9 ݡ-4!qG^?@l"m+4Fq|AbLq>'N~oo3-S,_$țwٮTiHA2Vp$;!ܝ(f<]CۏI
ieLy+˒~l"HyUs@ 8J(?aBɯyfy$p`\F9N[ǝLA8"8$wФ)54Wl9?|eFxAPw^`.'~ :y`V@#N+kK~8x7pY#g5|5흼Np>B]m'$K2l?h%CG>0ʃYr[6zW1$b?snx$!54&jH`Jʓ<,@f<ECAA(IvC8rH.<0eyW.G^py;CtZo,@!!X5^wz"7uy\Ǽ۸knGC.L\M|evoȑ)mmd|,F0.!{ Mе}{g+oW:&J>oSAWD6_d.ӜKܥK}t{>Xet?C0chu)m7wɮK̕4w5TP$R{L%ZvX`5|38[yX 'Jx* (w!&/F&I:!,b-PIF4iS-mۖɰW
Ff=OE*C_ܢ6ɶV x:H؊j{3)0ͿJe5̡w4[!ew&3.'"	逩b^^>j ǎYJ*<!`(~.		qt]B[0>afWo
؉{	v	6]&_r	=](8oK^<BP!I{&=YwfbThmX3xy?X]-f[JB=&=XA2Mőxl	XoXVy2&n=΄-?6&#׭ĩ_ʛ\;^MѢ]W̡r#x{".'pAcE6t:N &88gC)s^7,-vmbw S!0)uM)m&V^#W9njݟkON-E2m,RB}+TCg>˃lJ q+#Ae꾅2Ner}"KrVh}L4VFBC&Dh00'e;1_
/f$G8P/jNYyʇR2 ?|twlrOLrqEiLV$bj u}tr])8'?z@ˢBt}%oPSJqc2od1VWicDF{4!oO	ڵT+y4E%Om:.#<+\R>O|k<zm?Mc@8C:\>R  vS!-$$:&pA_q+l,̐ϔga"w%Hpl&n4N9
yJ[iG
k@lHpJ2/MF;4+?cE|%,(OpכvC3xWJ7B^Cگe'M͵r LY`n<;о &) k< w/?&Iq#1;"3~=\zݟ6;ڢ.ȟ8rKt!*<0kO璌Bˏ2f=6qSLctɁ,dFnƭx y"_W][~p3@k|҈(WPuC 6s.qHg!vMiRx2Mj>+۟}Xq塀xm?~;u<Cs~ʇn眊ϳԔIMA KZL__YȀIOP-72Ry``;D\B_O :Ha}`&mC⺇$_a;I"K^PN<}x42\%;myޑv46 dqf*/<p6tX WdQ6Ñ[ATVg%0jį;9W_&rͺp}},/ڨ;IJ;G6Zuro 6Ğ^~r8.]|=ze[V{i>qr9ϛ

ncE`c5KG<5̷XR=4/oHvA2]qs]<>Me<YcǏ+Z'MY#H'N~5ʃrvpL~Ҍ7l[A\{C3I}$KHG\,	k ';_ҭ	gH, F6m*[DykL6 L wY;L;>A$uJh6SoZN۰Wa6&vޛ/XqG%> ̃nT JNozuI97Y2XFN	Z([q#Rhh ҎN`'f6ͅmwS<4~-9G	5Gy,7c";Ծ02KyP̄\m
lO,Qԝ,
Om߇Nۆ#7lQ,7#\F`/5t@d2w~,c6dw&*ŔM_dM݆NLh(~|OYt[VmTDP`K?	lQ&Dݠس褶qrGw@P=ptA"]U*8\!ʟ6
F~Hch@ TתmsL`oIﶟ2O@I҉3ƍ^Puz'6G݄h_CEVA6iZLob m|?o6zx0OώIċ^<]x*GhAK1NRlpyÎȇh9?`P.k}e(RƔBP>6ӿZE;L	GWk}0%ØQCHlIuK	g(
ADh瀂VS=Y d! dK7n 7;m\A~Yxj!)$`⃇"<fq>Fef:yNM&.&ɆL~pˮm6Q"ݲq:-ഷPN/c$~eq<xmF؄WY?8OR5mE^$}p0glf{!`i~G*x#w8j^cHDxK^2SܺEgܒ^΄%pS8I:Q1C?yL6`-?~
?pI57cU]:ć
q#TB==Yv\3:F_{@קU½`Gl_~)o0/Bo7x\F\')Ixt,^h5#*tDɎLSw	AGd繓lyyio5=dEqHFxi͸lc^/gVNi]%BW	RY4`ƒN -iHfI[︜?5ANWפ	}|'~H3N)TV8d36nʑ1 Д'9xR3Fk*~`
~:Jrhl绥QNS-w	-z9s11\mo*Lڀ"V8z1U༊'^?y>G/Eu>-b1/>н-3ͼRCD᮲FJNz3F+{%ǹe#o-X)\̤CC2`ă5$U?)S8]ӆh?Lbt=pa=Ǩ[g|k։8\5z=\ߟ;yv[~O&t\>x^,x)fY>QMBJ	^҆|6R.yuͱG'җ(0*uP);d/owBo6
F{ћh;ӻaL=
rBc{"[dYB6[E^N}!ސ]	L]I^g?W\3?x&>bV[wģ[;poC`Y.7ہ0)j\gdǏ`I)zy͍6L=.:nӚy KeE@.g@r&:9mC}YFQ>:q:~ }-{ʐcram r5fՑL64S'<I?yFjXD++uQIt"z\0@#GԂ%p&U~#=_|1@>S$Qy+Y$`@2%M|ozI{,D㲣<I/P.wy}.iK=XQ0_	E&4~n5r܎\0@6	*8t@<w$<1sp7ڶn-GlL[6FT}'M 9ebq 	tu7r"pE}zdS6f=8ڄD<	C~6&*Mڋ+`qP@v{pҀN!72I#MeMV(ZUN<Дw5y'[IK]Yt8yΆ$)0]3{9Ʊ	|. ċLpԃL6y̆L Һb,F;;\6C
OaHS4Y !:Ϝ\:|Nr7|Mrdu	ǝɓ|eEDۢѶXP=rLH;[?AŞqK!vmE<X3Vrg !l|W:(/l c6&VS(8Hnډ]oGӏ+˹aוM0M}t薱gb\txܝO}[!lƴco@L.jCWS#4Ngh#x~imAvLq)$vL-
ÚgǏjoJl<0g@o8_l,>B_aע&æ/`6*vհ?|O %dkp2\M&B2*;`IƋ<̋<2#*6@n\BclxzeTk+7{BCEn_|п3va8AߠÕ?my;By%M1aH,WF6_O0]~Kބ}҆y	c=0c3Kھzy+]M4yēNeacyq6H.\t)$J_t9NAm62Mo^Q-wiruҮW`=4NZA-H>o$]T=J|ØAQWH6mD g
>|ƅFq<>qSueNwɗ~0\VR|h܀U"Ǹ|#D)|Ѷ3i6
/&e(( uT,W9TXI6->WvNۊ[xuP7eGG~㠜zD<>{Z<0}+_PؼOcD=8`7]ˆd ^Пt{7e<zQ?Q
o#z)xd}X5F>)>mH'N? %2^@FWLb7}L۽B%vH UǓ@ˑm\wrk_>\)+5BOuo ' *>[vAoCN:[TƱ0; #+/ҖtZMP,9։dwpL9K1sۨ;n*	=㽿b71YnW 9`(ljqJ]/	ݼAV:WM9}1,PlW4\pkب\B\؏d<hpS&ɍR";z=9!cka,w`txCg?|6)/s3OW[]bq9	LR`(fAz{DuQ3P2&TnO4Xzݙ[tٖaIai6m<쬤mc2NN747qɌ&lĄ,I]b0o_`&|Nn9e^3'x]N< j(^Q!ac7O/m-~i]	(nh6`bf"[e6tl ACôdl=M'r߆!vb8R7RJ7iOiaE-j.<飖	-;py$Fy'ڴɈo
k-Ȫ~ÀC`sذ/k6T焍oL,g҂n 1[!&ˌM7mrW)F4<sȓ|\6CWK~B)hx{RT;9t(:r䨼BDvsX/on^Ct߇C*h'8dş!F@SrS:)ZyEOq~2~w3U}w'}ɯ#A qH~B֫$W<;-`=ZavSwk΅Gd:~x-z$OmފUN!b3q!eL+tޖm=H8u각r$.E?[g d -vXogp%6X6x
!]G.4C;'V>L.,7p%~;W`1˥o"~M=۳bvm~Z6~VxŬДmc ȟqm<~7xM>>*)r5Gr]F]kH{ T+ՋsnJNr?dZRidGcqI܆MqE8_7JbG2g$,=u&h@-t"nv8+w>!'8C#KZ: |_0--_[PpQN`=2u=àۈE`gZu\ea]Ƅ9Xx-ᶍ	+ϊI"3XNC^x<d|!n$\|
@4#:y.ѽXW:wт9!p4w~mv:|)_Kni둱ԏ s	p2e  $ I~$n[8PBAC>1YfSӗ˃~
)Sۭ倉'꫟6>10Q;w9a^#x"_mS?X:{e2aøA%$#\GR[{j~KI})/ E>I\VOe  -ˉya'p"}!$?>!D8dit67o^߼BOJ!U֑RNnRS ]Js`t@M"Mc%0CVZ@  ԗNcdUR8鷃hCfg)qK`ۛp_0*d
K+n{I=7б?uhP0D^q{lG"L	vAea&rԑ릷/wFWhx:T..I*N_#V߆@f' E1&U?7~ؼKPh2ɤs5_,AZh萪R&4#G״ؿnY|+\Edj@ʍN'遼,3ItLl#a4ytI;Mb;~筤H.uI_YO0kt]1iɳĕu[ ?ڌ,+oOh34 j`#l7a{l\Ժ/aL4̸ڎx2XV<A]hL3mL 0!7OìvGxЯ[Y]nna39m nh?/'@:nT7pEFUm1e/U?ylD&Y&w4.PV<0WL2,N2Gg <u;W}B!O=i!	ƒ1z꯬ovx0:,8J}7e~IЗ>pSFy0@8F%e܏IV}4JM0P,0.Hg3cyBLg*>!mĦbm)noK5Fv:@Q!\?8]JNAC<qF>Si3R	g-Ն.\gye0N}rָ[XVtL0B:-w37iOgCXɀEZ'Sà7'-wE_ddG%!qrde-k7	CF9M).r;~d)Zv:MYG^|P+\t+wx	<eeo\mS+09m~?nj?rGC&`0<)	t/w:솦,#[a7gPtڕ)YYε= 
J
e$uzzz0Q=L2`6Vo6}0/7d]bMF7⠟:F~_][Z0s&a}h7qg~ksBEgS lmOQ]8MIqʟIn6RyՎgdQ{/o՗X)Mu}7OBo'F|<[&4N :ٴ7),Ӝ\HTxs	S'H4=-2Ғvs|/ve|R[hO:dM=!- މk:k1Q7m$ȍ7/\_MԼEcS >r?qk=3J[dtծ6%rHiK&ͭ<?qY^cBALGTuZ	ޮ9.9kiocm<~-P6+=- }pbz]eM()70\F 	sYMG<+WmN>ܼcBٖv,O&A&FB~^g#8g|xK]cX@}\}\kÎs8VpJI/W?k~ ?J6q1W~u''7W+Ś<6W_rmzr}	˽ 2%F#ZN畱&-{3Jy׍p,3<EW'E}rx0U'/дy2=r."Ħ^p|eQ_?k}o/3%2kAKj-s<Wz>u:	s`A;;vb4WHSP~=)}яz?=8Pgcex-\=Wğ
KlCߛ񖭨f7r_L~+t@diO	xzś,dX8``6F'6ݐi<"DƕB94[nj\70$߃~SĹW1mtNJ$;`֍(ߐUN(50dn:;q'f9Ƶk˕K?$㉿<Hc"]nC' OM$؍6~~@:`2nӘkBV@@bg? Q*NtGG6c80DOt"v@@g6:}9PR'oF2/\lqEMaS=IR wChmɿM
r/1҇o0G/W^i+=0+೨t3/9;8oe.j#Ԟav7?: V5rYtC0xFi%鋟	-ʅ?A& Ӿi2gј,e.LG mIe&=Bk1ٌN;!㢝)77/z2eb9,Ө)A6
}MՆ[/&iء(RwJ, n@v}7G	Y&ߜ/u2::h]5KQOiD'dՓ`MO&*m [=w\@|.",[~+9
O+lEQ.`>$sEeh\]JP_rED=/-#.;Ty..K2#O#63hL&+c86ssuCǅ9e*POӻ';˄44Gx%;QO^ak"|q¹O~f;>yGڰ*Y͋e~ܖZat<iA:s6OY6ChL0C^ĸU[o&JI6@Eɓ'c.b(U56J8(vKihW\]._C$ڏAq8Vt%N0glް5yE\۽Ey#`S{ݦCus} jگzzh>22_Z%9Pi[WQ2Ң	{9+qH~?UM1|vG%6cr}#xdcxE@zNC8ۇhGld?v_'Z뼵_}U~J&&c_E*?K8I2I3u*aڀ_N?9<F~
%O#_rE	t0I~sĘraM{ =&lh&?l?-DI(ePaE6
>UYV9&Hu
5mplyiAIlkP z {<S_`RU?*iJ`3!CV h)$aRbc5. #ضW0{y:кVs߸X+k;M% ×03rJDѾȄ.u-y7݋[@JYFyC*FyY8uPdЇqă4.p!O:!0O@Чq^S,%7tK6@׵5Τ}/lsHSy qY0ݥuw Ĳ{mhd|χJnN}"q'e}/?.yЙ~]v.YVF܁Ƭ2S+{-eD ?(Hf#[G)?P%r?+r94r:3ko>eK:58c0r9P␒<>F ҁFoIEYfO>e /Zf#n *Au]rЕr'u	pQϡ9rap!|EC;a>a[(Dt<Rzb;Wbg{ҷOƷv[tq<`!uLecP',@,įQHS3܉S	iZ6X}^]}/;\	w5=@rf؍DDEΆalt˓(leJ	r:eN+k87D}hhYD	A/PqxruYʨepXctc i l=reV ߃ѱXwZe@ؐ+ݤŋ?&[OL5mq',z᎑Iwz.a䪣v xDL,сzFhtx&CP?w&PT2xxb#^\X2h_sJin긁r ґc݁ke!VWPM>_حwb 瓳DtP1C6,@;pJTR/](rJ\;D6u?z^4ҁv	}xe	ELJAӤ\HP7CN#7]'~&XG&8v?v:>lɑǜSWynS7H ϶ :&nt  xrc!m"7,	v˸x:~<WwxMteOh.|Z'e`;ozz7Ҟ4%7SvjF&|tځ~$qZLk	e/	S,#WPbHH$) vn)jwƈ "{[P~)c](V%_b	/ܮOtǏ[qSAQ_RI;}BNM@{  [v=Ayh88m]lDzoBY|<F䅱7ql9ؖW;ckm`7<
3e׀h/躲tJ~-Ue
]N{࢞B7әSp,#TяUoމ(XWWBIzXm1<M٫_nREvO6ܼ͂uLq+X~8.7:7gI6|VteM2d6޶K鲳XmZY wP}b8~uqݞ+}@eo`|ʞ~9Lbδ"fm| Տ_G8,2Sʺqר)h
i'e! ;!T4+7,[`u	u^<9`]!.7EBj16q>goLY9vg|xnSmcd7t|7=j?x"0&=u7m8yq"q$m0[PPMΰN7 /\w2P>WU|Ф4pKMvS*Grc3gO,Zի?~o.p{7H5|t	#V9 L 1W<y GUQk Xvϔ!2nafU/}H!]'}`uǜǎyĉ㎏k
oaA0	xc1~@;|%<uv#igڞ(L8U.ԏ}vyqI|[y18ltclN^uL{{{: (dYӤz@nk=M`~b彌ON`+ŬÉy%\%?L\M$$aN#+-9Qɦ= hoJٛv7p^pM_Af#0bz2&~N=ttއŁ"RT:-:WS~ə*8wp}	oWҸwnrOv&yFէM,v)̾`㷥e}w.Q"f] r1{1 	C촤[tA[qAd1Ȧƃ%Ωvi@	*6f1QuuTUR@ ;|ˈ\NWN] /?O?P0
%1t$y#uqYGT>E0:$_f
!hp[
R&0L_I\hA !(něOS,G(iRܱfU$y`W y&kP\ф$815_:WNX(3;'@v!7`$
78m&L=TОor쟾g,d|U	.Ot|L[x"sP@5n#L`v*=5i\HB	@
yx)կiRǢgwP-\\i@b轉C8~ˌI>i䔅k S8R`oXևJ=?xPgc:6Z\o&G[~IZ8}atī Cyư2=AnOz8I#ЀZC[6E߸DzbL䑃\]($cX\kWiдoD`-Oؑ|@x7aNaZ:;Q? >-\"$^2"AgLBhw܎0,C8mZq:jy!ߨ\YG|'u2Ύ@dF&_cg;PmYrY ,k,Mh7 '
</#st& aT7'`Hd%s_ܴGcG\N<={i#4iă[U(2';-M p!|{bŕj6uP)]&oe>$ͳI?7bp5
Z6\<W?R. Samq#/1^1N)-8/ n;*B(h#O<٩~Z!CZG-^<=.AY2$x[{#@>it3
⮱<ײ]XSqA@#kGf'o3NUB;eɷQ>\#ˡ:tl?۟|tv%LEceve0P'<+ЈrԲ3'A{q@v^M|t?މJ85c7*E:\~[6z1Δ]2.JI!H=m|1Ƀg7|<X}&xɁCǤϝȺ{lǭt9y3WED+aԹ̛MdPv?q} d	)73\&#`dʄ&y40/Nҍ( תXqx*<ݰRNyMno ,|ݤϼXe$?u..]6o7<rBN5c)N
sxpJ?@Qgzy-(FHP/Ԅ	[){vސ׽"Ѝ7q`38}e.LVkW.;G|HkudN_acxVCA(_,6*AثM#*7C!|Vٔÿ}9(n(TJ6$X_6>3o9 nPÐ;s&tsM'LrBy[751KtIf%w ?zHAO~D	A2-P!f&EO޾B[8ޫI!'!56	ML~k]?'vUZkժaW޵[=ɐºՑ[W۷	Ig@S/cѶj"jMRpvq&zI.~I)tF eяpn|<\t-,x v|H49OC
ԃoDҏ$n=27L'n@R^(8?;yt]VGOrtc Y@hCho<-\Hbh6S%?s	=>, QdE[rkq\a࢘6MY׾d*|-:)C+b@v3:qCsI _->Ճ:wg 1S%zdk̔-/,	<Νgo0=pd\zw\rW
&l(?fQĹ|껠d\dbҔzZ(rdra?2sГD}5bvL=46z{5jL)]GUVAEM!N繩k<eΦ/i}"g<h}C>p*ɠpFȣbvI
"Y:D\lp9&c5"	/"nb!PR['V_1Sd1 M!%tG^ŗ2HGX[+fЀ_bզs?"Vw>S8IeT~B\җAsS̟śh:a-mDaE`\0ߤ- 
^RRj_lBEs5QPߕ^KWncڲiKvKhAP	K;udՉm,Mo7i;R}9탥|:N.E?Pn,A"tڑD䒟o؟6N:1Ο?*yP9qmcYoUDaٿǠd\\_~'hKm	|,s<q^Ah[/^dvxI>`lgR-Gu	0uI]ԍ)Eg\\WX{BBbGk[7ԟH	&š8Fmz;f,EAṉ&X8e	Fx('-̃0.H\e:4b:iƱ*cx䉇V,e",]SgPn(PG*<JF5|!Q%khh)XޤЪ˱3z-{
V?&kHs$~&5^pMGe,qo8]# ]6	աZtVxӾ~Yn8
W>	w<ǬZ[RSZxsnu!|l(W89o0i~!acU'/7^׮\<s̩'>t#mE/]SǏc'N
%!qsFݏx0=mzޜ*W#@QcoK\@0i_l7%0N㍯|"; E4WZ/㹇^֍OB{b0mЇ$_xYmvTaZk,j>?veuh XQ!HQ_;؎:[Ţ`$BB `BKG|Rj=ke|岙yȅe½!skMeQ5Gy皬$CF|sO]hCwzJ ؉!vH:s<t9'S6k95:̏+Lp?yT3	9.W/4aɠ`rrZ>dL53'̍6xJM e^r~vKFuV?iu&*,>願'BQR.]8y:N@oB	DMN Nvڡ穈D){bUK#mMC^	_H7˗6L@ O}h,	+Ą^8d]'kH3A00(y~h0{	)O!n ?EV,~,ŗ/շǒ:gJgqlҕ8]_۬|&?77\e+jů
J>G.arh؍*.e`җ/n&mݹ(}	'I~I	rgURRS͖%J<Iۊ] >cV)v}@\ű^՗Z F>MFO֩$L~,	p߾ H Y2*tnFbd'p,kAGix7CE6ظV{z~+ߛJq	޴_Z[q-C-1moFS
G$@YųgoԕoL`Ӻڨl#\:1\1W'Դ>W)mUO`k9"G9p_ OtQϒsO>nWˣfzp0$6w>;5vƫl| V+(_8aco&ogih93Pm+D'к Mg~q3cdE̡vuE= '@|'-\č%&O(
V=-̟ǂ%P˧LU.ŮP_rHַSF0SK/b]s¦`W:UCO]MU0ǵܬ9 Κ*Upl22.׮ݖAއi)s40%ػ2V ӅYpg,3x|/_RiUq/ʁQ0%ZG}U$NF yd5:
:q_ɕ<i\w,d:yu<a;lDp7Ӫ|9h-$Ǘ|5+׉й+my	:kȧJ˚5d'-Jt}	ֱt ;;H,e<ɽ (_!I~A`FaaLy{V~._Rw$CAP]$9eW;P|%Q79/\J_<DoV|׻|ABɘ8$%eӨ^9/EIԀ'}ѡϒ:GOS?U$7FsXLTl0y-A{1-_NId<x3Bl
ҹ_~x$<$f|~k|z4=~<\瞇7O$Gg\h0v^<|%|dmz'F+IN06`c&"<~}Ed2N|K؝o|ݑ\_sK=O4\tvrG:^g%,U(oy=ICt9VFX}W\_1Wi\//?@ƫJOcꕫڍv:G޼ORv$~m+'[4aN/[o%MM%QK ^>'Ll	'mg]G~鑇	&& o0&) 5>}ʠ(J-:>cP5BMR;^DMFoH;*+3DLRO(pQ;C5)$ytB
n+ H-?d/7DRVi5 (δ<SGOD%?&u8J+E/sTlխHe qgΊoZeP'	MxVX$&DOWahbuKtfLȬ'jApWhR:K/:a:]mH=ʟAS0eMyQX嫨Cw,ViA,zYSNpYAhkYوtγ 
9XmA>4}Fk>#r"iͣ㎌k1p`;wx4Orlsa0a\ϙ0^nMoނMGcE&/.GH}0~x|#FbeOa٧_	ef@H]~@j*z1y'6:<f_A_m&Jf7!1!z֜.b%l,nY;%3/,6D_;&e+;G6(AҊY>M=
,:Ҋ3}+NQ1Ҿ[ҳuD"#Vqh6~bVP
KJ9jdH5Ȗ6X>̹n=5v$xN9*iv-Vχ>=#pí384Kh-<y#`:_0]W߉L+yXz6^Md+tkY#$vv:bWc"MH>)$֛zXsv\M4+-l8+s}yٹ@77HKۭbT즥qC4qXk5M$Sz7\tWTtTY5/DW2Ժ.M>9Wԙ;Ah>E	;Hy~2ǯXhet-&f?o(I_UK|~F=y< u=1GqnaA{C\KN&L'TN
%?_ֺfzqZ`:zq(uwvS?0gvb[ނ]>Oܟ`3ؖhyCɂ%GdV#h?o"[sJC]G4>֩c?iHbHN9grs[<lxN=)?4i_|y\rl班rGq{81<[sS|<ȷt/c&'<la	csBƖ}!PV:!GŽG~D:Ur6I|ƌ I̡ؐqʛovmzfpӒ*]?|>(y(558_NRaGgdLWq`QZ>/^obs5J8c9s*ZBu!CHtU?rwnN|Ϟ;Y5y9NdLc]s5lf\ {d'-HL;H"i)oXHLm0-?+%\s|e4~ȐOl0P]z=3lIs	-NebSKl0љ3eI霰s	wwgE?H>N`#"GMZG2ˋBӍ'=n}OGn8rJnd[GAV>\+x&'4K0%EAjVy'
_L6yɍA!*^p= Ǵ;D"Kvo}NdQ
>PG{2y9pL!~Ho%0鬰'j2WKݽ ,(جz6&̈́Љ_lq /f64ʠzs}Tq<>Ի'O#Ȼ|U=qlLO:	WY
GK[l90{$E)cҢ^1,694۪K4giop :zоb$Vs¬X۾gc.\9`\*7OB_x\o]hf\j 2˟7G%BVt볭_ћ$1ָ<xQTZwӍ"ue,XWh؝#2<Qaa?ˍ3gz9iUS9SYlFʭuhոs
O8g[M;WŽgv*,1	\JW;.}dU:v4Zgn膰rb+[fi0HTtUJyw۰a%
f\un5C³<;*;~O^~cw"p?O߫CF+|O{苿6S&jsC_Ds&(m}|(zwe|.Bz-uG5Gyxq:L<˫Xj/(YGՉv{ 4*k><W٠5uA(񜷾bNnnuֹ]\[&y)jk_ύ7[Lşzʵ99{l17"
cZUGh'l0G^G=~>kً&/׃旛onO.bԆMcJ ([n{6F6>Kp5>|]A\Q^>W"ףЏY	rsÑRvpLPHXy4q.̓4ӧt+!QZ&Ϊ@rqj9lU:zmv!Lztٱrٰ͒rv0<As?='7ii9S>sfz鲜>]S\_I67vu}˃M&׸K'cNʝVq!޹149pop:P8z:2x__Bx9~U^r<w<x>/!]|U432Sa&	c']3uUN.[(JX]nJMcv5NmؓuZ6mniubw~)bX/:5hT6@%Cs`Bرq:֔HSvYzkrʂ-됒M\N8߲Yzvҧ9\mʦTfMGV1ZC^6~bj9lW)q8hDUʸt	a*E<f҉<:G?M:k͕Ɣۓ|_>#~xOtnm?7w*5<tN"o Hf#LF4-(9f[rH\n/H(E}[m:]?i~G7#{N#RQq[چ@TNxvA	iX8(;* E`POʤpl	}O:	~OpGEsu OܦjEP)g [! 5@cYщΛƐr`*!~_Qk
D{<Qi@^IgBbE2=4#js6K8=#x`Etb  >BA+EazM1'[CHȷ>_{#:)qn'~z+H[<$y @k==Vȇ6G+OCvJH;!BQ.+*3c:OREI;r,Sx\})TV^UkaZ;ԉK;.
+C-Q @*ĝ
+[$/xMcqE+zx<Ytiٴ92GK\)EIu.L㧹)7eJ\XFo@`xb;G
(7qHi<k"7qDOx|u	JޚfU.:&NkgeȾ2)|Gw}1p96%N ,mAKڢ>1v>:gC6*˞gLkR荖[#s?m;o5~cW_|%Zw+RѢ2j=e
S΢~05[Yo20fU(. W67y4"јyCk@0uT$Oi|!e'[)i}0VYU=y\d<&'75۟]Wjo~P@ɛCC>V3Jq	ߡzvZ	3\q+F J\c'Y]qϮt]š%XBყSRYf1r%I)c-6yrm{zq;,7e)c3VB Pr3l8|E !=&.CsHo[65.kG]n9mE}#W|n}I~3鎛us˧rjSlae)=5s\J21,2}:⊯Yζ4LJ؛_DZc6wO<p9s*MI1Y9wN>5^8WbZ5^z՛RN>%/KjLuqx8ԩS'ycy\"u
-K=i/{}(َl2+o/z7z?2sa1_!g}Z3ǹ(8E"Ǣ/:cU>vz!>d~.Rm(8RCP˴P؛@ڧZI0_)_<HԼ臏0^(F|t9/ʹ{d!*֋=[+'Li-->\ g~J;z1={q

4e}:tl%=<'f<i["ω寤p4ogӡʲĢzpc>r'oqwP" B牦aR:4_&|- *Woik{X	*ݝ5j)[AU.v\MNn`'
gro}r{!VIh1t3139Lĳ@+4	*]FD25[#四BJ]/,f;owqc>",AwzfOI->JㆃV fvr	>~LfAWFeqJ`r+5KqE&qo*~Ƨڴ
Y<GAw{S1ڛR/3:ف:/ uUi:|q~ܔs)lqxdh}3du\ޘFBa	.0:[
A1/O	.X)$^6vIlzcys1xK+wx&uD~2iM[NpIX˙;.եos9bwV[ɜ>cֶB6QBhaeV.'9BֲW2շ B}cϮa]trrƬ>9nL#?~Aw7q)6ܶg;1.Im㿗~_9Յe>4cY&lΟv`˙9]K@tҘ&TL: %\'gR\];d#Xea=b{|Oa9cgWxH@[9i9~TebBZw|
#I,¦Hewc	[2j4'`w#E
Ȁ	?SpQSj)rSa|!Es*}a$T_-
)6:.L;\+*]^4}ɷ;QŲvI$3ŭ#4y	>r317C*y蛎$jpV˯婃>D~mXJ<>hֲ;6H̆I+Ω?#]׍a;ݜ Li$@Mhn>_!XkleTyS$N͵7%M]Hp*s	.>+v$Oم(i赠_ʀq+zJ]p7ƍ׭nl/$t~|m&*c~oo\Μ9_ ~H{t^i<HUrl`
5A>}\7Fy93˼l@_,#G9{NfӌkiOoD*7|͍{{K$Y0VpH%0SwXo80PI'v`G~.sP:'ʹC93	(GCJj{ŧKzp
!@:ڭY~˷}>T鍃rCit{Out|oʷa0~)+]~1˵51epD:Iv0 gjiZ o:,SO0v{ %RtOOqq?qT%i$ځK;hb&41;bIַCck*|*K(bLB2ivR<AaL*Yi[SfP!]?ЙTM;z_w$vLfhÄB\DdRa+OP:,5`kbqcN;ࣜ͂:@ԫhzSeCwZ]<˗}>X$%u[[&"=7ZjG:,3KZo2u9#!aT³_r/AGX6ycIfE`Vs۾Ǡ8$9wiuq|.h*ݖEgcM5U2B>N<rG	Ά7'Uú*
Ȭ>s1f>ԣ/JrW[%Nr1&Q޿VS]U	9-QVSa<jsǾ艿5_M\aTz?rt̓g1i=?VdSBO@zx[kY6N{-g7VzRONm>tɁ?Z%7 kapo"4a@{3j~I UHģ$b6_'Q-⢹5bx'H7$փfX$
96A773ޑ;q}A5ξ^ϑV_`Kɂ)kpgT|K `@7񮳄w`;Pܶ\+,w-}IJ+NN_Crp/lO
S a>5܂QeWt٠
;~	],mW)`\lDD:4z*Y嬲.a%uء_ہ\x}B'g3KNal HoT~SE"k%v5~4NT;G+k6$Z7=,{6lTk%<aNKtN"@9D3l.DC49)a(˛0@r!`8~̿^Gz9ydNQz_y[p/F%b
iD'O=L?6^Eӛ>Oڦ-:JoP65x%8֭[\BsCsu	u".%
D;Z;G6yI*zsl'*TN5&]VjpE>WW5~Nb"/x%:Aґ6=axl`q8yIiI=8Z4?7i[PzQgѽaoy.D\k.
.huҲ&t@Paa<KҠ+Hfv:J||Hթb::uN'ԙ-/wƁ.}?Gre|3k~r;> yKE*ghWAEءS>a?NXǯ|vS۪,wƅ;®sMݤudܹ0)oN6ln/V_k:>N;<STo (0=n?+@uP"4ѯXeoYܤ'>,:$LM&O> )+<Ά/V}l@6+=_=hns`6vH>^ր	?(c/POɿe&	x"M.;zx 6Z	kL#|XC ]̜VpXÍe!bIA.>qq䑋0$]0B$oIsA|FjԉoXS	*hX2$NӆqQѽTxtrNf񝍽:}gR
* 't=p\B;|6iT25+Fh5y77}!ojt/6N5#6O:1Xͭ.ƺzNbJ>lϲ8$6]7Ϲ%hvs8.q;V=.08 b/9g\[5.ʜ₋Fy8JStNq,ӸXFolie[ڞ}{Oڦ%=iSʚ ,~	ޢr&-FRg!)MvQJv,s(vf,1گc	1Oh1ʌM\Y͹:w3<&;ԩW74w:dxlf/>Em134lآϱ_﮵=0r󉱔w{17ݑrueeDOWeR+P>N*nzՍj,ZB\`˹9<\g5t0Ce*bi4i$`B4vxhM	}|BȜ6Izו(ѼrI_xߖ]Z%clJXA<-\l^mci\y\|ef4+ZaB_⢳VzmkڭqX*ՑO$,PNxV(Pe浰\r&"05<n_")ltwzwuҟү$d+֘{I:K);>_aqz|$iyasn	s:M(&3#m՝qk|F_:(aI[$_'ē{ӟ&Hф\fEfN>A*}7Q4Jq@|w\aocc7^v>wf<sR]آ6W>׮]S3٭9k$C}J@7]:P&6a(r[6)Kf-\!CKbJG@ɼFP|}AuXUȣۅ|oܸ>]OlϜIo{Ъcex@
OX+͒YqE:h',tNEAfБ#/W4<B(AwgϞzKmuĹ2KXȥsZsbM62Bd}i~cj.=Pa9bmû3%<2-]L5Śzi_.'LFb'K:a>8aN
?2]O[p,yCGm}HǭyRz4t3Bx^8f4J:#Ҥ=Y 'O.4!*mQV_H9-#y.dきKŎ2uDt
;|0v^:xNs6MAvxILTgrHͧT'F ZƧK_xJU
 Dmr,T]0QO;~=)"J"_t9uHy/?`~?;I:G5:ܾ˚Ok~d4<@ABEplwtL\dl\6M[~z?Me3m89k͘yf@>Lb܅St88=KLuo#9m,~%kz#	5~>:!~KW^p,r;9exexiX/BG>e:&o#GqR*(Aak
O]ޮ\#κ7N#[ƦֿI/%Fծt;ܱ̚c̉#f:K8Jj5T͚һM5YYK!}r\?釢IʰJ*a/8_Vt|]O{蓏2	1ogwmLAi('m8;wn/,ބD:P4r6h07r5A*}@ va7tټ:+wΏHѩȣJdq\b<rk<ͯޱ=hTHY2FQ~/>9o([zD\4%ѡǄԗSuESRhdtn!ywyqknNi&RB;|=v+*^h{(BK`fY1*B^3"O6*~p`ڰAzAt}x/]SΊԬzatᚵh00:N$R93&1Nrq6Fs렯ss׆6ڌk&L'iVY%	t +[F$2Oq89܃ߨԙn_U~8Ky9yb^yC8uyxr(1$ǯZ/51|"g7£)9>KGK.KV2×/]uq5Y溨ڼO&oԹmV*C׮ԍ^>r笏HH:r>+Da&yWϺ.a~;$EyP&ဣz"00AЎ:0pPV67p;Rr:ڔc4 %ԕv[v1񷜳a*§@tؘ*($߉dtޠm-oW(:?WNk8;פgprsPh=/GߛXu2Յ4jdcv\@ 7:MH(./([8KbUt:_xw8ڐ5\~ԓǑ8Bꛌ`߯zkvDQz2J[.Yl`Iu-	InUAcyKÓjh}7}S.8Q&rd4#V|>iLҎ$G/I]䆙ʙ_<LL^4yQ/$@rƎyC9/@@K,L5oYT,=a?KwFyFLw0;?eN-r+`'`s8wKێ5*+S;$3"@|PVY7y-NޟL;y	K0D8^a~6'"S~j>ZC{0C>֩"sx9Z|UJXxh7F99ŋ<&%jX=հm'F>Vtc< ZP ˒Pvc2bH~N,^7a-{YN&4Q)k/ݮ YBs>IhMlZޠ}c][ځNP`O?|ņ4pNՓ/`q1Mpa=]q[䶒nlg4~]le%&w;E񸵟Ydˡ-ߒ.4XBr܊}:J{,v)\g~h<j~J^#ʒ\7F_$<MBf	<TpdYlxz$;)C֛Yh^3j	J4Ͻ7Ż-^^jz\Q~_~zRҥRC17MLUSgoDOm%v`kՇSV>8(I;s掔o	l }H(7yp)_34,mvk6hnS+^E)Uf]lAҊU  a˵Ȍ6g5irI-}eۀ:[]OS턃]ou
v:~6b{TuaU0><5U!N_B\tT$=\+\D]8s{*3~|w5)e
UshH\!k`=yTN\ŁЍ71ͳ\דdx]~qҥli#w⃟Fqx;Y"r\0F5|ܫ"_6X/xn{jO9=Ξ;:;))t,|+b6ǎ&4~u07ep>*q)*?fRQVj%"NPTբ!q._~Q}NjK.x_B[[$i0`AY~bq].=A~}"}Ē[+4ă!vЮ3/(ranwKWo}0'ttIˁGb_tZV9ȧS`0MUr}?:8׈`LU?G]'^&%!<cܸi.}7T^7,i`C	$%{#Uǚ|PD 71yvJol" 0)B;4˭ڹ;UUيJuUWXLY-U1^4ib`ТɪN.7ߚT샥##vUxɣ^tp҂Q8йED	XdŤBǯ{$S}O´PCN?+	S]mV|)*ŖԩOzJQaT媨	]YbgiMsXx/'1s+q-3%ep9
-c 2[HiNS*譙6!d{'`Roѹ&۹:]8?w	/\YR̯{Q<AǼ͉+=>8EOn0Tw](?xE;fB&fS(E sxOpʳgKdsxv (E5=le8Pa꟏?f]P\E,.++7vjjs̋vǲuS_ÆG}6|$6^8^`ʧT;8-hݸ k;t-|J5p|D#p&bb@_XXӷ؍[4K#mA0sķCROȏ8hnBcfBi)A$6<cENUmzt¹i	KZ'?6NJA~Alj[RPx4̢O]'$`<_r)*k{Y}1a.Px̆qks?	}Yہ]e	@tv`UxIۇN|i ϧX97|nIx&Cʢ:YJE$uVMh>^<KH6Y~*[X,9x&4#U0vsJ`JI-7;xS#uo%j]Gu`9ϟēv]}w}"צ/U:H,6Q[܇D9_ޢY/_akE̎rKa8V#Ξ%3F~⼙ț*p3o*Ɏۮ'_)~\knY˲H[Sw̍Un^z⺱ج˹27oʋ_7]Rj}tHa0v5xj'-x8_KJZúv[DMœPy;\#_ik?tl?	Ey^JYɻ)rvaAL3n\I>GWu$i)Xp._n״9#G+K8eHJVAݫsh;+PS֔}|&.<ەO/T+hє*U/NsʌX5uhm0K?U/&9?Yt\O/rxaSE8k0ҤWu6(={KX2c̚q`	g6@3S)3E9B&΃ARqowoޒ P<ix ~|W?EΟ??|'i<iY"Hpe7_P7s'{Ƒf_<n|G
qg.)ۼ'³Ƒ_0~(]{'񛯤ԟ|T5[_3Ꮜx+<;1~`jOx|xsu\Tܺ_vO xOG׸79v8?>?oxɿp]`CwLݹ|g=[oo}Ӧ~{|~tf\o}YȑOz+ ~{g~xwW~<5^]1|?e7^A,kΛܹ|Ro
WYipnxY/r
yec~)|8+^LN:0-G<u&񢵈E^d+8#Unz_l\}E>2UK!2<\Eon.s#[$oݨP.@,|>L
N,4^qV7I6T~%$L#1_y~#jC)	5V-k<gk	V]؀2V6)'I_4!cɄ^='9OkO>LWPL"r:Z
R7+/NDl0pQE|5C߇p1re<kyY9	ԉXʫ3q1uJfiUZmyva=*:&ܾ?Xu]b1Sw,t|RS_+=qbH+S9{XZhU>bhs.@q%۴%Wnߵ쫞FԚ
%ֹT{kK㲡 m>B[tʆ_H|2{dwf;oJ-4x5[v_D~M'hy~GMbkK2VCqKw;{c57<6jP;+7m]׵ڥCNZqN+W3Q5K=j8rj^-Aes,~`}	ߐh'д|Ǉ6$$sZș!721Fŭ~E\&;kzL4cDթyCE-d4!nɵnv߰&S\[. &OߡϤ'7or,uErvooa77km"FHN$Whq6I>6AmTu`6o!7U$U15rԬ79P'f¾IPKY!;_ʏg9N[CuP<pazS5`)
lT̜[L
աq}W>/SmM{D\e[R;QҰ#!m,v%G:|989gȃ_y`P"c)8?>
cf'3{D+HCH/K'pѵrÊA<.޼qmapa=y\c7˸)k׮L׺.Ԃ7mOt"˵0q׍O[꼼=Ki@'CL+?$uE_?UNܯ~ih_ΛG8dHzU':]~d،sYfRF'-T>Ǖ˗3Μ29`5#\Md#-.3$վ1s(
J{2|}GNQ`REwWG;_sݶ[҇vDr@XlE%Cէhix`R5](NQ&4ˑyN]Ѡ{N`h[!T}ҿK>eˏ#u=W**m2:{Q(x쁍|:xci/C3w}hnʧJz	RWu3P*4,z"?ɯ|$;2{$o];).]%:Mxc;'i;şq%~vPY
H7oyԿ%33\W_g(*Ñm|3;~OxKf&h~vo,׿yUQx".jn})xs?'+ٕvņO7獵2?O(GX7=;?iwGZ40@g||xxrqߧW۽@.jww<8!_41IKv	[e_~ޗx;~A~|g`WWm}xwת3~J^珟7;^֋h/(l}sǏgWm?oo׍[|x߮K+`%	󌧿mKċ~֋Ɠ_U''u3).	VaTb Ĥ&cZ959Bs~2tkϢ:lCdX%fe]N-t⏧h4Aaܼ=¬NlWJX7g:wGuH	7oq{|Q^+X	)Xщx!҂f=(rKC.k'm0FAWjn+ZNz/>0L޴5eVOQ+d2Nؑ~Xy\::uY݄Nxf&tC3sV苟`kF9%tA-10]b>{Be;V!U1FWmyOnWfP.kk(kb8nHn0FƎ\2ζ;^~}_i/W"{7/y_Çl/v\fSҫ_e2y32JεDpg7r:˹"H@//.헳؊}hH/hQfe[6p7q\uA%uy,uA̮ڂ,)9_{\:DhƼWrs}CqM[%xr"nfƼ1	>_䧼[/ނ9bdR,zOcA)6<vX<2Ɩƙ#9lTx`/]8,Bj9"Vwɋ0NTM,|IO6JtyO0۱gO0lH5"t,Dn;/>9y;s cAϽ:i=AC|~.A3ӃK?h*5~h	qAobA&a2sNoxj܋{J\--2wZ\O%gzMP8u:u	a8#!;l	𓳿V<fAf;"T\G7zO<zc2/g}M~4+G-Ri?gcYJA`tHCpGc }gIzc [n1gbۅ9k1~ro.'Ep?vDĸ%x߸~T)<+YnNQVC}r0) \۷uwe\|a6G[7o+Wal.I&<}8c7sWgD,a3&cMku	rJWrKRޱ!e&h(HvѬƔ	vD"U~1`ǅ%fX$L\m<O+RU:Ύsg:}j\x8}9%=9{N?GӎgΜ'NtےͿϛ-{M7֭fs>}8~*rGd?}l)geeO9%;?ysC*9sSϫO~GUSWD=银:{ƌΫ<FKMY[}nhCS
X+,`Rz (xΗ!F΃躈=q$!I΀ 0SD\m* % Q[>ARes	QF Fq<c=Ke'Q1xO<4.H#?1_4}ѷx/x_>aɅ}x}xSg?ye\-G??4Yi&ss>E6֯<|/㳿x΅7K_\o;>ѳ a]gx{?q<ceDzK~X^:I\/_b=믎v3⯎7<[ΗwGk|sJqU29^G>iF_?>7ԛ&.ɿw~9c9ge'Qq{d;_Oo<M0~kP1@MJZt';O\8ȣ<h}b<3]D!钋(~'*%䮉{;|9$ץfq'`AB7Qamtuym~{hEp7v;w؟7|ӗq̙/Nht^kcLK%bK,sI'dS4oyv{	TO<mI7n5v.m2eK:$V^l`F	:=h	*}ҿU]y1_S iyțat:Ē9VL>\xQ.΢4!|K:~]Y?}D/2F¡56e]bX[nNΧ3KhF1P`_2(Vĕ38}_u(Il-yo6t%~wjuMƕ7]a\EW#""<ۋ&#V2.翃PǾ{#v+`ёnݾqW6w29   E˛f88Xw  IDAT䋽}UرZ򝣋h0({:AI()9YoluQa|0bRTXmt((f
vRښ31%j00'uK6FٴRmj\qZܠrָxW9ub<pzָr_c~c`j!<_cMr-'Cv5͒sJkNLW0OVie_:^ĺg9GR=m4۷3mFdL$TE9Hw#:ܹY19/5y#\^fWT.ɧnAd[,"\ŋw5f{t!/V3vI	_8~JRv%nBs5^XVM;QrQvA?#?}9uo"vO-}ͺʵ6@1Vhc=JNTOf\&&c!sk5&tz ܩm@'REM`[^K(A9%_̬+aI:\ 71dmkJR#XARG>su}_1/9akKgZ
s[/}XN?mwKrpc%s(vW:J)[\Nڗk}ɍW˗KsKQJO]OzNeu?s=Ulf3gNn:|C{U([^u3@ѯ;˦ǩ3CmO5FŲ Y=q_LQژ~ҶZR+E5꘱bArvE0k}ؤM)}H7qם|dZ=νYze l̐/l7kB>{@CuU6GU>~.l;{V\jk}Nb36_lѿi8~UMc:+lӧ4NFOw/4ۤ(79$=}5k]H-I^~zl>WU{} ɫMB30SgPbM||	chr?ma[ AzxpZIN-Y3S:ٝ?qGxq&OJ:l|&NPҩkqiAзg#z	~ύz7'-lOwt_2z</xóy\&[|[7DyO}	q~Ѹ?i3sq\l`w׿;Rʥȋ[kwϽT?젿`|%O㑷|ů϶v+zWwb|q<5ƫ3~?׍K?,FywG^6Nas{݃7-R|u1~?^Ywhڷ׼hz ğ?aA\/O+7goY`Ro6?gp|=<߫za?E}'Sn7})㟙CZF}$8ߦ.B6W wpIA?f(aۣbҕ e}LxG);eGbĢ2:ֶ
nc.N,8Ozȕ*b'#(k՛Q\{-(-P7TwG΢Y{LS.=\\qq\]
sXxz*?u#KIG7ci`~bCzԈ}}G:]k:M,s1NnI5~K1zv歛~kwcbE蜃c6͢!ayE(襾>xsReJ÷H{Rl{dmVJ,5[1C@qQ`M̪w1Śr$K{"Ir +`R*ܤXe)S.D_8_&}kH&Q$@>PJr蓹<asuUI9Ÿ\wi[ss؈.9l@n-<Xnv
}Fx&>ҠU;ڟ!=Xih`":wgb[˵ׁhhW@>sTnO˺\;~'Knc 7xԸ|7xƆ'{ڵJW䱡X'Okmup
kȦyp@-t1ESZH}P[1*Z]i#7r=,^	qCsFоEf_Xqlk ؔegX5l#2"}(F7cs=b\??93N.(#&_7v؀{ Ah=`JO֌aX#JdL߀'鸙Bʛ'X[]-\:ZD3]ݴoRWnoTRPcЁyEg.aqZgyqy+:<r}E,ҽ{ņ`g.l9WֳhDms:OKږ][I8]l[LHxAZiM^)dAlfCZ\c0s-=Bwnl#j>|Pcc_pWگȓO9J_;7ԻM yB&r9l3M84ï׽i+~eumޓ*իr1&"Jg
fI;뷜\܅
h<6WpEzt~BQE\Fz%m=Օ!H'N>3gmsS rStLJT<sɂHTI~Ip}!}.*!t+pPlg<͸jnrJJa#6W?u_utoȧwNt_6y=iWHccuYe{~ɇ8:_\|"dM}Lr}	lb.#¯l< _<YNBC{h_A?
u0cW^c8wa7onx]Øͺ8^li(87S>rKp%s@"yS9<06K?l_.l"n7ԩ)I"|TXmSmk:K4t1n :bѴ4־OΔ_<o1B'o8"O~Ήtώ?xaK~,`	įL*o荤#wb<sU26P^>'|ū}⯎o5+&^I߱cGͦonWU~߇.?a|ʓ_7~~T}xʫ_4οWm(/vQ~ߑ#Ga|?o<e	:}x[[u_BPL382^lzox~8>׍"7b~`~8Ot|K-o~x3&|ğHOj;w~|z3P{OYqw|+~||׍|wxs?Whl&*Rwj'_?2YşZ])>Cwqwhr`CyWȏ/~N(ؑ,Èp\|3%F	0L礟8Ü&gԵlw6Jېnc	ґ+\<Nv>ܸ^iW}fq`:sq招]YܠaQ˅@dS`2uڶt,\k(>?p{m՘RdhtG7`"ş$P.K`XD_zN˜c[r{7_)bbd#>x~s:Zd>̙O;~待6NL5^.$OLL ]{1u%1h+(@ܼN;N-s)1Kdf	+ʹ-H]J:d\|4Ds]=#r\_刭nLmJAē :*/Mg_ e1ǀB7CnyS;clp%ؓ"R+⶚Щsbmp!q-J;u^:<NC9y"^_O53=%e&&b!m+QNp+ӶsSqar?cѩNl(k-wJWd׵X&Sm4kBe7V#@06aiPִ--}@h[FI l<뾪8-Υ}ѵt~uuYcf
&q+8R*Og]˼¶f#y-rJg<7{uIXd(¬j7tn*V<c:qKډd-n0e̼^S}iGV׺jW}Z]?M{P66z~]t5	sز+	
eb;8s4kyc7E;y7T\o*amgIQt7kPQn&5R~-vI\t
փ<N<blXiҥ违{QȚ|ƵYTq'gS)Bs
7ѯl0s.VU6+&&U<KgnQ>7E;ڄ9Ux@4cd?ի#P>98oS?/nFTa9ֿ8&\[dGszd܄R钱	5oKm[RA9xevMyxn{	o{}7]s}O)9qzMCR?;lD2Ĩeuħ&z'.JYuh]z3ZYɕbҘߛ|<4M@-Twu@9$O]_æ6rs939|ө؁Oq>XF_ ̝oX_Wo kvȝ"N!W~8\oa<"κ98)8("|_qϘ:j52n)`,	|ͽ	Y_?ݥW6{m0eЉ+!|il0D"OJuqI[sqΛ0:t^qh=:	[N^:Oݿc$%.1)FNxi?mM/|u_/ƃUz/78ͣW8<rzU^L]6~P'tN]׌w|Ooԟ!r3"oO[E-T}{x_5kmq|`iܖC`WOyڿ`:>>80}|7WѤzR5r|iOow7|wx`zΫ/`zǯwo7OsE6/_.qg<7ο%=E/hqn1R/sHP~34'wIo}_QzE^AWf<I2^2rwKG王=TOH]x?WRC:Զ>=ݚo?4~x\f_GG"@KӿN<-z.=A{U]DAOz̋9nnEx)2Ueh -F^`S2v-  #yb5搏CfNݍpT&_;(^F~RL`:sneUύl.LSyc1R53TEREl9^N/VKDl&5^dq_M#sP4uǀ$_&6S``"CHcA^@}oP.DIPQK-5tXHBe~Dg'*쳵R)/vhfxEơcGh1ɪx-UԾ_9US8HQhK)J@qN-}sA3C
L"N5'I?II}p^&Ps֔!!h2@[-w2aXFc7@{Tr{ԣY]/-"9Oik̒vԦ)C 7#X$ϡ8m+MY-N]Q6쁵BUN~ ΍؛^m:}ӟ
ܮρ0y9?)t:586xU<ůc]81]x{/xr8fG5+&϶}>q}`*£ dAղEsׂ7MhL5iy)isf2-Io^^e[`GVQyz\yQ<A[pt3X6trX_wPOY
*3Qp\Ԟ5l8&2cc_S[7GgI|TO9Mcڌz/Ҟcz;s'O zu<MgIcu-Hr?aJ3&=pL;T0`gL_Rt(qc3<ԛ-Oc-߰lкmUl)Au|C\
l!9ӿxK2o%K:ВRZ㉏_L\++^u;rLaM]l"N/nFN{ɲ%<\6\<׆&Sl*цmRʔ637V΂iI9EfxiIf^n7xsŵ+Wa-s~ig
+:|O9<8_RwŃ<a2]iU B]~C4$5xԄ7Ex Z]4[CeshucFM cS~=};zr^Jmt'XJ9s;/+sҼfpZa@swH$꓇ү_Eِa]S4mR"Z@nfX;tд]DM, aUB.®Kx
P9	un>rVO,a΃&,֧m0m!)#u[@]ߘ#<3G+˪Qv|Sgt:Prokڽp{պ+ә8;< ޱ>5n3NcZ =O?W};?U?fҺw/;b?;a=W?~q͗Ion3^0^/oxqOw~r|bқw|xgV"w㝟,Ʋe|Tߤr.N7ؚ7bQ.}#_uҥkY(mSYo\VWTO7ӣ/<I/p<b@ezO98^4uo>㟍U׌g쏍gܫsџ?>Ozx}qͥuz<r|gƹ9*WxCl+Ώw,$V8a!U0b<[ӌuVpc)@IpCkܲS3һhk|Y@l,ͣŊuL~rT0{aڢ6cSIt[U[|OM2.Bjϟpn&AiZ 5OeI:|`UmYjBr.i!ww"BE8^@fq׊NǄC}c	8%($^-iBȼ'x굫aN>PrKZXӄ+v㇢R6s>J3˳Eq$=!8v T EǷ[RY[L*[v`L=C\lia|\t(;_AOrE{wͻQ*m2-L!;j~b^<fYYzocq`+B<}gug _;	K0dyE6%vfJxJncy	N1	}#6ӯ_xwx:5RxcᬅlP&ʘ	y#mX|N`Bt|lkg8y!!Mǅ砎uJKr%pV7Ъ7pb(ˁo]>}@D같hxhCr[?;0{Hz8Qʤ3Ʈ}	mt9G$sOק}CҺ=?;0&<`kAMbE^Wg&ؘ;hk<C\oTX%۫	.kf!­DkKJ6!F3ljpc:'ل`-9]|}cojm.Fa]b%za.)ry"qJ̻uq?.<@^./_:.^_wߡ+RGJ8tbsIx؏阇}@?>l\xoȵ#=}{{^˗>)>svzsw
Srٳ-/:8ksʔF4tyPbaC-P)<e/< ƛm}3ezz@;KeWf,Znó}XRZ}K`H0u˹_
ðܟP4(0}6>Ã\6SSG?&
cBӾ>'4韋3|<ߡDs'Y!q`zwa(W ^@}:$>*o;#xyy[&a\2g`R!zcɡP8N@71yaT-<`,G9A$PUSߵd8wu0`/1c\zGgƃ4Fb?TMKaD	௎>}</s#/uO 1{ӫ87V+ߺ^,IYw|?==\!u՟Vy7o;zI(xǎwyyŷ_jof=pdb+2'0=X6V}@a^kx0kǏ7~_RY5oWf^z}~t<g>鯎q_4?ǟ-㵪>|ǡx׋f+V_xq\/uwW8gwyf<NǮGD8!U }sFK %5lʗ}'x"]-N{ŏ!:fWqS>nIoy^ٕM>3Sy"l|f2_
aQ<ς6rG18b%D;gB
"GhbW љP;q4nP>w`_Pd+/AXyZlOWĖv0?^ژvOj>Kr]ә 2'E cL- AzG\i7q!>@cZlޒ=8;4jqJ9sѯuJ98m_y~X!I #Vb(aϞGu[i윐hZϋBu
LrE﹛s;0Լ%}#MC}b&
LBPDbB[JNk}R
k1@"]nŢb@B'2|S~ݦV5]w}s8n|;2e2KmՕ-<xΥ\ͭej|2٢9Ye;|qR*_aЫ=ydC]K2-/L:3&C+%Jc)P[&gJ4fuy%k"b@5HsR:}~P.oMnYb\{:zqb+{=6}&;4t%_LݟQNBR%1LjR<]},8ڬkޮt`u~u)WR89ra
]H.Î٥~9}B[bBc(&-"8ڷ+T/^dc-trX7.fNt]{(3MPj^SKj^:9;;a1YtXh%)Y5kb%k*t.Z;jl6(8gNcsכ63<}t}UNj-沌ⴎMfX20Dt{6]MyZPEgܣ;}x??8~z/N_I\s?
FǕKǭd$Hy>Oo\#+U]]nG.vpƙg]6uuWQAhݓL_Q~BlpO8lxQvs](+iEO=9=b$aѣ#	W1s䡧lPua64Џ=`KEAیH'X:JT0y*p쁸H,͘*}٨<}:Il>8֐Z~gϞfds1W/7ԙ=*^{bQ_=<}mf/@S]HR%ZW7Csѡ*SҪHrkMB 3!|x}~%"abmnrf)>HGX36Ɏvav70K7dpstmsb;^9v3:YJ5Ƭ H{x(<	B&!l|^ 3{sX40eNh9Y5'gGooȯgozxC.uwiBB8g?_-G_.2pM<׿ԿhLFg,LAA岍?8~Yl|qm|xk~t<_g网,6W[^7j|ƃo_ݯ9?#.|x~d|'z0ZXSإD3xzͲ9/1}˯@o֥5g^1¦r<-w_~`>[~Lba+yFl0OWO{ϏZpo_1]_H׽zo&-.m,'~+`\g(*-LV.X8`hpu(.ә2{+Dj>7YH#1;T|&
~GSW2ކXhF˼nvWן}c!*@9&;n5#/D
tO>'#>''\v:X_3rЀB	C^As?A<Ư{QhoȂ?825BB![ LAA3Jhفn3Ǜ v,r>dqZk
-72x4p
Nfs'v,87"Ejw>&Sp>[c%[Niiv8=6Ee%3fڢ;0g*> 6xI6GhRt6}F9g7u(])3f%fm$踥9ny~{ MӋ'i"0&؀sd4ChB]ȫ| =62槷ki/:kͲ74RdfuiD#5t<O.׃3St%7 ltD0'1ޔt<у:U :cZ8fe'eęݒɾ[PչûEW,̡j/>o	#7ؼi˛[([?|sԢM;5;߲w!Z-{QRT]hM7On
6h}?P%^ug?	\з)Eqg&p!ꁱ&PBOr+,T
]9(Tfف]_I{L'<F"̨%ybPf>iڮ/{+8zɜ]oϯ(1vgL_dt~LfDK֡f+u"_J6Z&(6zb_uFx(\g.e$#J<^+\$h)'G:q8=<ύchr#kg*^CÁ-j,^팝m?U7/#
S>'λ?}%?2a]ЯOt`&#5=we7@#|C`}.cI#>^g.N9Px'"H/t颎xkeSdPڒ_USJ`Vi,Z-:I4O({҂9QN'yk'Խ#Dq_:}ҲѯԹL_4tYtoPzETfNa;SUHeڢ%{(c+S$	[e-v.jv8]ڀDT i!7tVG؋?hf   NaqֵR`'zk\:eb͖dģ pd,9@<l1>+2aZNB'kMч$YR'7SݏğUcqI*+ßlj`Ax(Shq31Ư^ȗnk+^mgfKoLBeNs+O'c6e.o<ß|oZ3_0^;o/~ηˮI7;~^e5Sm3h%:~>a'Dʑh?ئ5YHWWW}|/ow>_15~9o)/qa6^4v*@Я4IknT~?5!{>BFi oxo+cJW=x3Oe ROK}%8]>ECmݳgƑ+W:1JV٩.ЌMėKxqC;`#ɾQO(.7pܭ
sq2ǭgv^)~o@܀[:6R^'u*Gew*9_]B_4QmLF-TDz؈n3JІjz'_Y,SUeEX*%Ќ%Uu8\kZ2~BI=x_@ްH 9ʭ<~dZW[}c+mvXZ_"8QFh<`ѻJ]5Iqd5>VGxc~3dWh5bA?рUFΙEF^H%5ʇҗϟ78@8:=}BrN(M,yM.x>lS_f=yS5y+7\]r)~z@yh~+|wߔڴɦ<g~xEnΕV/	`o)L9D;a'^oE-`^Gb1G[վY31SJ&iylSKYT@uOiRr]xmo楉|ԡ}akɌCz҈/J)n̡yAxg^禎<-|FINqn,=!W1I(Nٙ_qn6ji.8dY"qpܪB56#Y Boir(};E7r`-eIysϡƖ8 }kȮ<];x>U͢PmlP cK6g&in|݅=h|k:1Z*w6BDUjpofTaknnQ (3MVv[&\Lv(A)C[az[8])V`czXa-)K~Y!ξAY<{h}<_g0ǳTsX16k\$qTN=/F_}o0`)~U"XͯxӼ&:!sΝ?I7lyTG~wֺ{?9wv9_2hG6٪,n/@JeC:	kC2[~@\وfV?aS3g8N99z6$Wkȸ)n	h]*i mE;yS{P~~@h<8BZ-uOljJgӎW{׼gnw_P>0&R?ߔC]WlCaS3;RfM>AeJtӹSohN	kfb&/Z9
=,^ƚI^4)0^1!j8L4(c͛<}QOJN1+ϟ?cKl.4i/j3` NLhu~X/&TI^NZ"#!!xǑ=6>4uщB?1?i^%;W?jaMg|a1/O??o濙( F	?}G׎W=wx7>=^b/;|s?emTg>^Jq~Ѹ}_6~/5>2B'Ǐwr_D%R[7/{._#c|w+?S9G^[~[&;Uޜ/+/|ʫP-'_7~k?"W/_^X2Cs|s̋'sa<m㳾pWOI22~?Ϧ]O~݇>HZA;/_6ط>ixB>}l a澰M`5&`wgyHV<SEQȸ't76>5q܄1V):tlH9zbmpwmQXEV%搓r.'Pǳ(Emƍb?a}hD:\ya^aي_Q@AJ|yhC<qDy	>G@<E{ƄC'Sg[3f޾ʓQ,z4f~"tE ˅KpT'9؂|u+G(Up6פ9C|QSaRgv\p"7q@+nݼv{zm%)'ÆXe)'O1>o=UƎ5('.<'ڨCtߖ 5V|h6,cEK'ȱ PA֥2.bkLЙ95O9W>⮶3yʨU3m=8;gv?E3:y:LeǹӯACt ٜo+s*vMrӨh1!!D}_昤'-%W|8I }XO6DtqFH^3d
+B"vPW@pDlbBJi]P,*NgM8s- y^(+2}zLK;6xBY Ѧ-C7hngoCpVl}Gn>MӻCټ3uNn*JZu	x3Am~y[ͼڕk#k^VHf)x}^"C~r؛>X.sDsI|hAÍ}8StpG;7<WS6/C}m#ti<vA<T!AKt0Ljco Zu,&ڮ[p=SeU:qqR|>FM	
!k5Ź܏9m5!B괆[%ͦ2,=ք'MO3=}Z\nYoEus2w|SW%=r٬5#^P~R_%K`ֳ v8	/*4}6ȫi6
W!F/kp\~s,'~@"-Ќ)NFvmga4cK_{dJKqq>G?,\ϰaMqs:`#ePe啥}Iq^4$3}c>swgu"vKn(,o#la#.?yHϟ깄y|a,o\q^t7U_)QiVѹ9%һvuUxR("~9RD،#3'}?L2a-|42Digv>r9qE
TICx,:%w߄WH("BWw;;SIk8Pb%Dw&Ue>NN&}^CcqS4i=N~N_vje@,\ѹ/U>B/+`RGj3lOz2e;7tOd^GV֟/rrםLܽT8?uM-`.<pr\Wi;i-htO#pٺUT_14@ͥAN/&Vy	|0w:E|GUl墊-^ 9i轣MɉVj'teQ|W{vt`gN~XZ>"N9lvb '`q?[@R?ih@y\$]kX&tdQ`}8,,?Z'ں3j#Pf z(qSXoAzN[!ħ5_ti1oŀHX>jMvXSg<0Sw;BmZR߮ bK66+U=uW̶UvӚs:{ڒ)DsW<Ljx6qF/]2ݟ8b/7"bFTK2{LmO(Gԧ>6&xc'H9*5)M'|nf<39q5R'(J/^BA^D`F;(5.}$c-(\6)f,>:{0D!]Lpup*%3N<5ō$ڐgq.7).dԩs<\&MaS^%b&IYXt┇&.vDr]}	oaQٜ+پͤcS'چ%9k: 1N{ߒ["|&1Y'	[>rf$o>q}x}Ma͔l8B!ȫjПT\\[8Ks=vq)ElZel
vi͑c6a8'[H% ah4uz6<GhD^D<oNܶ D= 0oYlYVe8}bh~X5in٤d@vnR:˓y$JQg<sqR<p8wx'+ǥ^m06D/vy7Ә{ĸqLm-)^RXI`+(¦1Չo
8F!F@:e~*ucq7KQZ4fg@g9וnW|Et}lUhUɯT3I{Md?YFg&Cb>G}u~"d4s6ҷXm=R:QM=X}\r
S>01_ʖy=kXj(k&=-⊀k'	r+asbɢpC3,nw;+[cʌuRHu+ysj3ozm5 kt6nS癿C!~C!1`ژXxpJ_"} '._Abelp뜖L9p9eTG^(U٠skF+,+\9wMGNk;8Kq%LA2X󖰾ţ4tIAݝqF5?~9><}Ox{\3N|7țǦ9׿Xs21XC1NP.3Wt%^^EfX>#eG4pлoo%u׸fUhY97eӧY/b:!KD_&	ϺYAʶ~n1)^mC}|>J7TaGoFt"Q=jq	N7?8yIjKe.>XjUAbW~5i~ԤS,l
nN[;/Ƌ`-?CJqsŧ`_B$x9!;beP/|Ю\W8Md^gkl:V=I[Vr.CWI{?⭝7	t|fOƜԷ'6?[<w^7=&7yٖU!mMSq2xsT;i!ER.v-t55W2Pju߶r.
3ү{d08jzڗZ|tp\ÇkG\,dn-
7Gg;cK ځ},uǑ&t>gMI۰X'5sɹO.~P5+Z T)_E6ʹ[NÈ/Fv=P|Lz&	!Dq.@J+mk,&ڗuEoUAIW^#SAW^HA)+MH mo)@R>/Qb.u LSB:7}%E<Tq+؎	aɵ2f}M>^s"a͵ĊұB)C8#t^ [7R){Eۗt/6Q<!KB)_0Njg6D
O4mCS[os16;gc7E#ɦyS
$0"$k)tS_9ű	lZ0^qVX>cqKx4T>S,ƾo9BI_m!&Rtd;ux;"u-Z7סp:OZy8ʯ9}f>uzu~>Y;eYtXD\!.C¾τlu=޾BsS8'者nw}*+jƇFWpf>9nC)%q7b]> zI;Pv@g+:3%#<.Żȗ/qW.kZќXOaɯ4j}μ"5y.y;GUO'ԇNI|ܩqW.W	JAh'CW R:Wtޜ
u8i0NP\v5vLacUwv8j6 \In2FyLK?,)R@ZCݴeRPޅ~;Υ1:f+J\N~'~STSCqw6L|6l(Eaz9n3iW?њ [WnNʵh<qi?ĠUO6-QkskC=_ߧ*I%C_=9ydrih<e&/<!ԑC{;fX98U7e6EMEcGkOM#ׯۍx%z#θ)]DC=}M2hڄ@rጝґw}*[xclu̵vbuMN7#lp@Ef[Zo+ylt]tPOn;c6I.{o&z(hz`ٳ;܅~m X<sN3
_PX=	T\5$+ѓQ§/߱Qk:t{h3Gy
}w9p},ҁp2Zcª0lL4w`1a.fJWǔ=<_}br؟OG&N8Im0p7eLȸu7<"fAѓkR<~¤# 8aax"`;Y8cÑFbZsX?i&z&eIyY'	HLD3TE'ڭgBWZNM|Mo׼I˱/|aG#::eCPr6 [CSҁ*ŒW9}'c|j@*Nƞ mP"jHvV+G|l>p]N*F7քXj2lȂ蚈=??KYj2:'NR-ρ&/D'/NK5&cs)ҹ)p|L]Ӣic\[ai'40a3+Dӻ۹AZx/VZ8h14"BpXV5ZM3ps>PA`ǂW1W^,ܽ: hSû#ϱ\=MrvL+T}hx&tڻ IbxB!Hu|/|3s.bF{s(@rmpK͊;OES!fWv/unF$g*#*7|K͏?f't}2މrip%}+cqY)Ke&@LIx,c+`Ằu[J`:l&p8M$ZVJ!NH3ߜnwٗzܡ;	DB(b!DS>d?e weZHo>)O'II]7Yć]nG79a	e+]lLpnð_)aCS<0y%
)ۂd\)G^ƪNgQ3kK	qVEV{4v`ݷPօ>"'s! KK<0?f6PQz0}Mi[TpvL:Zlmk/U72~s8Ғ86_V@+l*7TŲ˼⃿`ၤJ#uOy\=ܟD2kVF,>IG|`]rO%e{+L`_Oq!L w4n6+7M9;zܴ|Kx]Qsx较?Zo/V9_a^(:Z_ƐFKq'P0q9t`Xs
οcӄṯqqα3V>EwǱ3o<,#\Kԙ\*|vvTz]4ecǛȳ*G@_o,F^YIdl{+>ýjUj_(jC@+*7sOAQ>py/$b˗/K.G#Ku?7/DRA]
P;K8bVZ
%`Ѳ!GǪSoq1mO:Ox7Qփ"-U@?܅qW)/FlbVgΝgϞ F)Y7piI6pe6qd+tÒ*>dK#G=Z^N%f+\-k}ȸ~^8\!&ƽҶm-n_lRu%nj}vUi89J9˶80?<KnV'6_['#c|G{Nv䓟k`zfdN5S9P*,@@Sϯx%J5 oi8agKIyӕ6A]#G]N;`7Bʨh|/> Ckib#]7EUfɇ=(>K!XT T-Wﾄ)>[d?cƑ9omF_
39N)!̦.)ZsX_*U4-#9m;!X}9/NnpsUoLq|UtO&Q~YﲡJW͑8Mޓ[nA20|EZl^Λ4Ū6cr|J]['^X՚#}*VO'qy5s/(ve-%+Ni\ 3&

FyY]9͓U,bOⳜH=C	*ٖg+b(!XT6f~=jƗJCmNo`"3cqSB.* LuXSذ߇tCIpܢG"%Vx*2F-"!8ϸ{w,-}0(`Zčз'* gAjkV%Wu\mԎZ:JF})B	\nnuDA!6/3zBq*@, Eq?-XĬJNF"p5xRY7-MK]LedȈU#Oz缍x~96>1TzRl4|4ہ`@S,sk1d^D3(ґ~=Ɉ`4s}Mղ6p7˯<m
b3]vͭpOR #K9\W\'>*lq?<D$m"(}h?9N :yd|f¥g-v:jz~fr|5E`{[=VͺGE
Hf81aBnAbؽWHrP]	B	 n)R([i'fq͟~;K/AKBe:SB
q^C4l|fgbu6SL_1ɼ~yL{`'OϝgkSO'$'Jvim)qx{([{@NF7J_qP|9<P|g" ,0ő9+*,uf9-sz6h_D.y$ND$}4lw(Ggʰׇ<unpuF{3o+jvҽqkilkUZQAͳj+gWvʕqqEahl]xq\rիf0}:6>y%Źk/^4*Gz7 ٸRLvGѕ{p`XBi)}\(Jގ[~?O>[Ki6Ovw)賿^z_ -me1>OWN;;pLޤY/q x`(ZuZTE㓰N/qV䟀]	::|WK8Ypw7GR.,xL ƍ׽Įsx.rN:v=iyDFO=B$A1='e%p[k|q]9	u:]cM^	ȷ+8m= VvAώFB$-e6eCՏˤZհX7J&Ҽ΁ \2~@!@\VN$֭^8,/l1AbSڝq䑋:Gޫ._7}SLޮrbZT:r58~)OQ/2}~jD^rxǩsSɥkJ4%`o9P%q!·F$ݡŨX6	
b>ӹsRGmO#hXʙ]i^^n,xXIzxcx_},1Y'tB2O| Q6'yET^<ʷR!E[%c;O@ɂ4.E&_|^~u'狉ΡXsvX]1YbwaI x7^ H3=t(F*0ϼ36m|j6n5J r䋰:_HpھB[i4"(請PI􊃅2BP؍6U]	Obr1B氎GF\<+6ޘ.es
vXrkZ(MQC\p|/4OױsgvOû Gpu=Ow\d(nkK0|5Bn_,ipQ}QtX|Cx6<vJ/4|5nUv .zh}&kagk؇5	_P.U|."4w!,ڐz)n>#A`m]gO>'xӦ$=GAY.:Nj[7;Y/^~BM㼹#x!.=><yC|@ޒ]KT)L(.vSq!T6}S?b_uƆ<L>:-V`%" <Hۼp=[vA*)*fYSC9Q~uUot|qu -;׏"Kۺ0bu52ԧEJ){S&-zw<mz6/.T){%8I|-,v8}]g.O]T_+::*(ryZx=}[N]WDl1]y,L'YXkg
vx^ʇ2f&\tRߴ//B4\lBChL ?SX6k#7QkXIe]'~ 75H}'I\vY(dҲF)-r<nA }T:xʼ zZ1c훷ܯnOHXFpvQ?_բ#u6y7΁~甮NI'ĩ~=}?c|;g1k`]-*Q꙾'~Uq?c*^/.}3`!8H٢=ہN3&wy&X3%Ӓ-R&ZζRs6,F")ugk.va]%?^;Qi[lDN[`ʅ_e f^[|.UzDJr-Sx*-ѽ6	4؆A%(SZk}ۖa{JRUA,D`W`Zax@0rAcqBc$!Lz%UtBP	6B2jTD߽7;Zks~|Y{5\sn>;X_ť\RކYq0J/%JZ=zXgMTRؒf[2r?8?O  0}ŵe,M ^oLK҆~jv(5sC]s8p?pZJq?3XٕZH)7&ƯX0/2Zd(^YNU+/zS_XiS/ɯax\?	8s6<RB`,5H"?M+>l僩qR93/낇/v"7r㌓BqB̶ mLm`Guf>KIڡdǘ{/
ׁbhyN}Ss>	 fOٵ	gw}Ya?x[B1,$I4j[Ev.q)w8HdվP\pa5x:;eɃ
jjq,]t5Wgu
n[6Aܩt@G Px3wNG6=!Aۡ639[MmC=3<Y!rLGНǾ|Ƞ֬5ex}Z\r旦O/@,9G)}ک/Dobyb8㞋xHyU/9.`|TXK7@:&_@l2y1nG<Ζ
ݦV 9RA %w(Ťt%+5O;VF̩9 elSEIe/ye-|%65t{	N_;jqBϛGn%̅<ec5CyJ42=!V7C$8ZؐoIilw0+H[Uۥܿ<ǴyuQՒ9)+jI0!CnO{aX J}86P\4n7.y[g	i7n\^zK۝yu5|9zpv὇㇏'z4L.[bIᤂyE^͠m7a-Gk׷9o"r>&Ԭٲӹ'FU@Bj#>z%V9'8@<`85G8 |oi?C!i;R"95b(n霑5%3x-:o'Wn3z5 _m)vqSx5h5U$R*e2NoKnnotⷶ۷o»s3WHdlGi^oIxX$<kƊPe{W]8XF}LtVr?_ƛbgDcx<3p1gŜVZl: bZ>#k{`=69tƹMH;~ho-33W>l2% oLF2,uɏl@E?cmW*H@BdFGztyB~RkHLLEdӓ#ƂEV`mPJ'F(Ѽ#qZq&S SOЋ<&F.[~ҫ7}rRaP,*SfFՀX&qa9S;^gRIWnO?dOR9Yf-nSdmiAˆ6t:t#h<d+s{9/GZ2f7`#P\'Xi֒Fgpjݖl;~vqafC+=!KN[*o4h6!y`"a^dbnюԞE7Z8eFfj1
=nX4fΩ/zAuu;ܻۜ=EA]ZPdEzm"Ϻ3(xc6!jŀ, Yǽ|
-PҢ'!װqm/Xj&݌js^BV3$BPj=_ݪ5IRgO2zϼC6yf|rmb{kU̞lW,eݵshh	Yu^
gͱSʯǀCqA7,mPL%&SS	t 7%V.E;6A:b:`U44RnXU9Kq?{U_<Q백At׆BD;ԝ c76ys͌ٵ\b35q*l&b^g> M׶-콡:T%`QiΒV&D'1#ЬA%qYCW	EVQ;lL/G8bS,,l٢a `]$eQoW)dy2/~s|?OͿd)3v@E
xjVLO?!=!j*m!4>(ɿAPɓ(!d fZ/!W[w[W^Q	>(Ǽn+LB״q٥?s_^o{=|1=D=_a
wB\Y}stmǙ1/|}mc5]vғnv1~iH{),S &2Vm@h}>G]G=d8ɳr_}ȼ28ox~BH~TޑҪ8ĎWXFV)5t09bfFi	?C\Dc_^w߯__ezï6%7?OÇQl>	x	O{`){"/p$*7y^K> BSۃq82
Z@>uH׭A/PI/g_w#is,gxKxԱmJ)Xdz拓j3m[q#z(;H$QVEzGH%s@Nc^2G?%{@98V~!O
dC۶qI8p?~s?;BXS9鸳{#GU<u #>4[CK>gKDm3;%\)${,҃}2ҍjQp*ߩ%E="8GL=9)&o&0=~C67B}lw1R&15f/?wi^;.~itP>g_Ej=}w>Szªj/
lweK/Wab$\WRP+y(e/>+p	cI!O'1z%nJ)8@chٖ<BjaEl/d~A>.hj7zZܣW;ZTX>7DK?Iˣ~2-WD9F$^&i^E}QPwZM^e_b~Xc/Vh7+OC6V:yZVmwA׃Ǖ"X2lc*ۤL%7QO|]TM~|2<yvNpXJ[J{J0ĉ,ś5	QNGh0'ќ&?eT%z>ѝ}bp[:}^Z !C6S4ʖ^C~b
Daszw qteXu%bۓJX׎'`CO!Q'MKyˣ$80\@kviO|ˉnW옣N`Pd%_jŔ#*5":Y>ɑW'^,Y/L[Wq2}moy7'#ySdI9G4X]YOn"@ژ=+(ojLdy*!, O^ ]x8,@OaWlLoVށ9&ڗlɖ1L":"L[NrL)[&/Й
.*O@;: B3fIG_iBh~kj #g7RDB+Y!庘ۉŉ}<]jc
!/}	~1sXtV;Ply^P#c!94QtAFREjBG#c::|L$Q(j$;VPXsE%ޙQQW9nӦG>xp eHF>K]wj/@z㕿ٍŊF0|Y3My.ҥ%<>ry{
]c}҄MX4gAb?qP朋pǾvw(o1t澓#)pƯnR>b'8tTm9ԩdZFEmc.)v0-xTk&+lڙzli y5^^ԥCGi`
it}S]22WbGkN38U	L*vef8[ga/7#6韬m1s0̳*|NpG%#z#7˕|̫C
#F̵l1!ŏ'5*!>+xaPv)qg]φ:8\o7҄N4:ҒvhjtEw,zˈKAF5:6+uci̟W)qSG)`UòjOd+ -v ݓPe2qE8H{'uv#Mz_%۳/gs{~rBN?`~I:#<ٰg$~Jdt9;|88L!u<8p,x[-+zh wjSM#(ߪG ;mf
Ot/;<md62aL8"mH	T4)/;q"Ղ_*ͅwN%Wnoڞ;5lm.|[1O0k/MI@M%+cZy;Py%pN	Z6W$D	ՆxA5R^fCy5Ek%:jwZtNC~J*^kӮs|.%[<ӂݍhvSt0rX1xf,Р,%[WOsɯ[̵ɸ㇟$_E'(_&ʛO ugZLp&Rޖ;=90Jm3漈wX9%Oo͏<`#L-^vZ!sK;)V.BUG-,>6%~)@%25/:f{ߛG
nCN645v(t)s
f$Ǥk|\~ڿ=Em~&
%%ԁ郰,msb7e|x0\pa浫Kj[N_R3#+ٴga+؞@(PbޚDvJ\yN޳6^:X;-\|_YU л}_i=/vU8e
w_62cbTl%t8vY;(Qj)XiSyl:+tm:*Uyh+ۏPr)R*l -G=.h
`Oqk6q%-g7kounI*H-6A6q\m3@Ogv>m⁂E:9p6$T}*U_Ať|Wb[kyU- <,bIQp9ǷhbԤEm,j]fIAXШ*LL8Uf;m<W*_ȐYcblLNMUQ]nEmebX}yV}NL);Ҋs+1~i>f%nhNc¥*u}dr|,۶Kפť8nf&23:u|gyh~ gOnTacU	|}eSd
7ox~$UVؕRGǾHkyVi6xO	~PR</
n3#ĎZ l6_+<}'koސDj(dtX]7$fvڱx`WNbsAr#~vlu;UC$M,ivz3X@}Z
s^(P|=' sJDg/g_^xt2[Z昣ScJM8*4_hde	.AV7HV7>aaadUDs;WkZ)ɥFr
U~Ϻ8OO:V=X2vq |O(9Τ3b1Щ=R#Lb1S	䪌\N^"]\
Hm/kڑ3A0Q0KIβ#3rW;`逝S@b;%A2Süd>i*Y0ʒv%!#?/eO6P@	3z{P3g(@o>K7<cK;OEm,n|TR/d[pA?OZhjNQl.Rm{^Ӓ~D{hv^~eFbB,TRD7xdO,"MX+&Euᴼ4>҆9VT:v:=~ksfq/=}L'Dy54.k޻yq{D
y}'^yzs-ffâ}nby8Tz8} Rc Of?|ںFL	ÌiqVJ}i]By^ě}8GYz1G:b	.O s>9z!V/|v=y֕\T R#NQ q69q<ÿ~W`[;L0kdQ;8@v|lUhKgsOؿ	)	Wک,]dFͩ̯kTjNeXp\ 0ok-3[9:*2sD'1%Ɖq	[l+;sզ5ZF&|I|6NMa8,k.|I3e`NK%%1[6x`^]qWj'՛97}iRbX:|k|?dOlxr۩[|HSZlܶcɨYAK_?d|oEy]	e*,t%*w7/dU{!ߐ8xw2#􅋼vƕ嗮l=>кSgs1GܰS)e|hY_9mbeY^baӯQ6| ƑǓdԏ>ɅYyy!<J:qD]W87Bsjw	Gwj=Кk}ԝS/5z)ik\#Bqf5O"أ4a.c_\u';vrE0(Ul;qP'	,9
v^Fm0ݼ0@7'~kqj;ڈsƥ^ʽy̪~}+y&:kSe6HMaH'2l	h[mh>)KYfNTk+3AAJV͹@tGі{0:zR2A<،,b:Rei?zaET;'#?s<Wc9D|?u|w}۽g_2g^^?"7ɝg/Hix&o^t^%Ú+Ə恮6og>w+dY|uYۓsN9m'T-΁	-oj?(xI<\;Ǯ5IXpJyh>\Qr)3^: l,uf\_^+l8$H<XįiWAкB{<eCiF6-T0I^9>?6sX@2Ռ;9VXJ6rÏDge0#K8yW1r`=>42F$wZ25U.ep>e1y}e`8ckn7HH_VKB<\SEѶN1:$޺ᒴc|3زns]tPa#u?/n0)[t0pΗ&61&p;Uq#)rZ&7S&Ia~ 3&*βHqg4CN1}Xa]ث$v"M'>af'i-
)1?r;߸u;7^_7u|}boS{W	E3hbҗEA}q,(qNҲ`a
09m9q6Ł׹ ,'`1cK:."RTx	:JQț	F,Vx3$c:0fH\EL{fLzXeLp"ۯOjoIVCuBB;4 />fLv9!l%uye,HǼ1*fL/Kѥt:,6O,(V	Ɖǝ:9B n?ML,fT4[M1n%]`9xu-H&ƒ4IE1hPFB5bHW@b?%MepCɘL)fb5~mؼRˍn21`SژDccs3eh&nz"ek(u[~k=x.iE71-}SYī
,3+dp.5^3ԧ:'n YW/?e@F'*n%?=<RUQE2ɏyhZ8}B@ǭwRʕe[Ϥm$zo1M`y,!}7L9U2Fb
Z$%11[	FSqMR>d.#/LzQ9ƈ,H\X2q5ǃ)xނƭHd>	(װ.XfpZ<#ȉd)ZeD蔌HjF0e)}ł惦خH<EzMPfؐB2c޴3BiWH8es+u/GnU{xy`zƽ'cIF^#]*7Z_qZmR箓	B@6:Dckd|=0g~@x8=eL>sc}<|8<s(7Qc}y3Alf+Th'qEvXj~SGa眑Md̯D'dk&+cwd+HCu؇P$?xw`CRbRIl(I	f4h;s,Om`WXhsش=碌 ZؠMy}.k;K.d|'(^iq))ty|Bݕiqޅҍ.3dJjݶo]G?l7;=dTCVta*[qGqKǌi?s](s(1ub[Y?KP<_y7r\Yhg˲{bo0HϞ+5}3IEnC}crg>|>\9EƙϼsY#^>Wۍ7ɟqjH;](7AUۉr6i7Qq?t+\ꓛ	=ۈĩ}3TG#<?O(~\]n޺ݹs~}򓟴l귃rȠW.]c/m32Tic_|eȔի:ZV+{O7:)qv:=޻cs#_]cviK`
H<WN+kr̯\ƆOSZ^W_X=錉ㇾpm|鶻q_o65cv oOIK|_/dQ&+asGzcHFY.Xm3긋ϥL[amI97m!V)it!yZ!oBS@Jf<!vkQ^)
:X*I!? hۑ	2AėځQ_=*U>ጄdWcݸ~M;AMu	vt(;6d!vݨAեk[5VupYEGYUƍ/ӃJS@Er~
X,V87_@*&2"|aJ>?#>o
Y-N@-cRŎ}.TQipUǏF]>>'m"5[[`aľQqstڞ7
.jf$!%B[T.nF,o9rfYdF}a8/ea>AiƘ骴}K^Y4UpwL T@`#kO)p~S;Znu\"gӹ{E"7t1O9Z\ł<tJO++n?A4VYR{i;Kh(Uԃ<Gie@tΓvh^]Q`Ue<l'buv R엝Ny֪wlBgX1A5@>O4x:174"=uy^;L,n	Cq;ckQR8Cbu%/~6(k䳾SjK!/ueɜN`	>(/sΦ}{:5ªOib:xj{.pA>
/|Z&56_<N|BՃͰ-ZiZ<{Jmpw\T<|1L<Ss?	\@臜r9QυZBtCMٲOv5!#`+Wa޶R(O |8iGݯFG_D L溺ԁ*eK[+(Ҷ\fjgZ!܎ѧ N]$+j4v q0{U|ZY3<ξRX}}9l"<VMG0:Ty͡<NoL^buM) N/OĨa[[rr}q]đ&^ȃQ\*>RGכ>=M<10rY߉<.1.2sQfDDwmߊt}"N6泅Ŷd!Fb(@{l7dګtJ0
VdʖMBJ01ϼh*B+u$5҄k{,IHJ9H	imr"/(Q^@nx<7\&y˵:W^<,96<>|'6 kKCxW硛KzՆe]J䔋7Gs }c{Q@{c@.|I{}Rj5MxzmʎHͲBXDuzʬ
]yȯ82=JX({?7mˢG։Fnk qƅן>5|˖l2.c<D"0<x}?O!xľ @~ee>eʾMk׸	*<n0%[@LM7on@75wl/Թ+n]}nqAD͛;w^܀|5yvBnR^(rcft3AӇ`{{__5>dB֙?3>=}_^3Yɮ'd @ʤp)r1FvVoNzlZΫ%qo$ىڄjLt>;Zvhv;a7q{h?AԤNvH6Rwjp? !&^fLq&u&t&so-Q|=#yЈpFPyC<탫/*,e_AYL3_[O,E+3-X2
G_OK#Z@&8& Yz2A*JBxG}T)W#ΧAv3yܜҿကrwNś&HRPWE@zPahc梴X\Yܮ4D8]4^*6sC?e]'-cc]]哄iIAze81"oF?Qm:^N@x))~R3lJ
Md:WGL#2Pg3bJ>SSɎ*ߛ@:up@Y~(u>H`&S.3F7l;IiI=ËxS71Ŝ^]VH_bfQ4O!YϺ,೟h<=ȰG{Ń0cpЭ3wҽbZ`3a]Yw1;,1]$% >h_[JSD6GN:{ɑ4:j_%U̝tq;t1ad<CixdQ+_T2Am[薎G7e&~(6H)mmkUr\nr6uz'%շ7|D7l(ֲN3I+4HyK<%@
sIծTX/v53`-|D?d{̘?Hn"h\~ y̭78ױʿ?yI&f3_Kۃ϶G
s~;:Q՚էWRtc6*):t
YtC<kU* ,~DN؞HxL`0.2Uxe¯YǤ7"-fCpS
	usiR>y"Y	5·3V_L?;{شSM+/o6}w@er!jxNH@٪bLgȾ`/;}Smz퉢ǟ爴}UOx⧁)g\(B4.Iӯ^w)nuG@jqH0
kܘi|4<D2K(Y(%bWWldv-f!}p1wnlzsjQpW$eRe`7$ZiȮ^ڛ,nĹm994q}<BOs/EVns🾾oa?}x.XS)%th@ ģ-vʡ^)Sr.@Ӷ<1|b?|z+A8rSȿ>zʯ5eI_FAM)DoR}s:x뗝V\Md[8WN^rNnoۘm6P%o>74҇KڶG됆+fQEV3V}MTZ2XքVv>Juc.s=d~ݮd|<N11Ęᚴm٥m84|ʢ^~LXX|l?0KZ[zWz]Aĵl&Y^sk'vR7f`ݒ
u/$)¡޼yr| n2̲/U`G:L6}h!XD3ƈ4 m%xpV-2vPC;OL#l}:j cHt9'!j*j@bI@1yiJ[II}Mh)!*ݻp"_Ga
bPzh|lo+|c'EnP:6+!Βib^iz%\ϖQ:LbKsML%'NnX%}ɢ;~"IIcx&?-5eWoMN95+VK1|=AvH'8
]	JnilE,::FBo׏e`=bW|uEV:c
X8=Te~w^pDcѩ1	H/;Θb_9dczNECFAqWTG^ˣw;yJ'98	XFI	l4"#˨=mvTaDc(O-$\xixZ(x1R~Ͼ8B)viە+@7=,۔>+sAb{17?3~ݡ><	Bt맍/^*8ƘZ@iȑ3;yoJd\驗XOVYBcbio/fe_`x=26d4$f5|%@O i=:$H*pԮ+a:rFJ̪{qT[tZLTi(&EcYi[k5L_}"^|UMe#OC
Q|2l=}ȣO9Tyt8{Rm42NM]#]T
JRs YƞJ$	.:n!>3JSI!k[GKOw巽`\h0h('*<Qq)Bn>=8YP+QJ R#;m^qTFݬApဋ$\,}>2uya*<WF~<7'A KztY!kGKLK]*O+/B<b)99zn2tG4g/^|:[eݗs?KHzW[*2ܤ}wdLL.M*yxnCI˾׎xTN>6f^yUyHٜ0|fbAyDЯ}zlH!9g2G!&Ap\dO+w^bwHv%2;
>qŊS S'oĽu7}a9=n:`EJ	1D}1əϛN/>X;_f`z8tzxd<Ϻ*<UW/Į='sd?"8o CL`1:U'~}_~O;K'N*vйi)R5-Eyg_h8I*iT@ICmK/2H+ TX%}v;ծR8'G&m2 1⣗Sz6NZ6ڇTt*i1*:[Ԯ6&|nYF]OT[-7gWڤÝo	ߊ7G`7^~>	Mgۃ{
ʇiO1<q:sM}_To {k</cJWZLf>+2%cb?ySQ"TT,e_U;scܸI
dQP<@ݾDXw
.K`٢3]A!os_0~J+#<.|ЋF+ZxMvIŀ۩5yiXVwa3͆bTzQJ	d,>q 2`	I\fW7cT!B/w)X47b8M]*RHQ{Q}Xe($i$oz4U(ZOuW*#9o. "i/ss)7
cX-c
N7XlXd7BOb/vF[)8}1JRO_xQm{f10;eu%+ǲڀf_!2Шc0'^gdbNh9Oㅣ>飚'*3POu;e8ӕ# zG#6g>E>ٷ.mWoY:	Tt9}2_ц]|,Q{uI9'kM(|܀~J룅.a$_3PKq9[Ju{ _J#'[!4/{`Ns"Z.6'1^	,*b	#m/YuQaG.vت_m_65ρԒEDGz ?Á^|>ӑZOxҩwBna,3Ʌd싳l*Hf{,X JOZn,t1E_<РK|3K>4%7iTn]=߶ͦYm6ɺ)v~}0i/btvK}mx>1f@^~Ag>22В>@K#^q1-AfRTU@
sۂ|eQ_>4yK߻w7؜z~9T<r9	M^U9Q%b@`!8̀}8Nlޢxue1IKu0OOE;.8vN;qQ^1>k8sl)|Y_v0#nJ;GXobR>P>xP<XrӾ2Vk PE^	ڈ9Nʧ8NOk7S6'wQQ>~dw6w2(d[h{cӶp!WqFm+6,eU2}:mϙ/$+u`
3>6潉e	o%:'TĲ5KSOIŉ3 mלAZX/t(ҷ&N)ؼeRKO
{+0߸c#qwpc!r^_#
$_)FL~%A97rRaަg4V1s8ǒɲ._rlIy=g.!?:9.d<Rt`.B7y}4~R#4&{*߿P~|/F4&<㑙x%rC)y{"C~sWܱ[qnM[_^6!n,]zuNI.O؃!fR22B6'-8O@BZ)yCm)%F4:(Q'+N!M+ζ*8gt}_S|Ɛ'nMǡ$)vi[hccK':n3sJ<r_L uh7`c]|}k"x(`V	@hz}sZ"=kOa+ʦr.fʢjǢHieR6,oha8Yؗ"O.r6lAvCc}3IPXJ̫=4oxGP׮^>띯loPRxP0E9m[]+Z?"MsL~؋~G[<v8ޡUeʿ}:zrZ<?Ud1KeX(@	$HqWu %n[$_&*!B<X%g\؏˼bW/ͥ =g'V0
!ѲַKݮ&|`~[>h`R4	|©|ˍ%M5y?DgnEhKU	_"MWt4av5Fub)>b(x)}0BIp~j#'fǴ5:[uzzxm&ت{D:ǞJXrZiH)k'%͓-s}ȫXer(Z1q*֜#L'>'9yB5-FqZ)UpqюƃRt89sdͩg.9j3AJ9@Jҿ\aj<!PR5!Ž@PTCK:4y(O[N'LXo)(]#rl%S:TuS;Ε$Ն6N/t,&!󦶓QQ}`(Qglʧ09$JrQEAlbXhyoJzg	&a}l:@iO(z ]!qڵ"^$nVoO`q|B٫*Dkwh`yW.6yLďB8愸rot8Nݿ+hg.Ǚ'#2\tu2v9i:ܮM`%rS:otZqa>Z:V=n0ujFSch):nG8J]XotnZSĨDٲeSQ5FirXjyI"#:W`ѴYX1[6o$,|mb%@6gbޒuF|Aq_UH|LXbnQfFlٿ{x.ѱnQE?\l2|.sM<7#
D=e?z5D;IS)mF\aj>Rr3BbS'cEgDK:@w%Cdt,oY
Kw%Mbc{rl<-d)Lp+sه?>J1yw3*NMcw?~U/*$
đR&אχ4U?~-ol7_nݺEq&E[9/P3P1YnhUbˆj63UL~BPԺk bRV}|B⋸/ȸ'g_/C$оph{3B& Y~DO °N8rRgPc:>I%K CEnW<Vŧx>{mqR*׶O[aC[=T:h1ƠwgYUxƵԋ~! 3pI 6o?Tf7S:!?%JWNwQ:<dr'VYFXl&kn^ݹus{+o{i{啗۷7nhra׉1t"TA#® *XTb:+=8^4S	)xЃdh^/mׯ_|Hdh23<@+k+Kf{L<QQ(A+<
ViѶwmsQQcbNs1Nog#wr/ïp^]۠bS۰%TA.{EI&:(S	N 54?=n>gX8L%b,PL"f
SMQڢ <q1sӓ5E^yOeG}~)അ6|EC-qۜĉS)!Ek>Oc:ev
c#0H+}AUt6۳',Rx=-5Fv '8[pA|1~ľ0FjVM|;-J5RF`t°gň
orU[G՜utX1k0~IkɜI9QK`Ȼ+PM4RJoB|p`Po{LF+i_ڃ5&r}~Z-iĖ::,<ۼz9 P$[mbXt@tAetܥ=C|::`<Δ\!^B:=6 4s^`;1Sy+>0{"o!ǩ%NHu׻6$2{]!fxm,Lt oGZe;tp>8v\<!PoPCE$|q _YVi{tVy^P+8j6Af^cb->- ՆVtmbq}"vW >KEJ6ӎ$A!ҷv8Y#Oc5|J-1>a+n{]363!^gt#4btsqީ5TmMp"amdslNDOQtv=>NT=}oܬ2FFnBhqʮveӤ@h4{WZ/˟v>913LܙAӡ&HBFB1E-^ICSojªӡEڐp/7Q(v ٢Xd
m|1"Î"[co_)HY~ud;M1sU]FP?h787XbeRv)/,]x6}AuUY,7?x.\rv2[	p媩7aD7\$⸌*|sGMZ/I?lҎ
X?]+3	Y9=]h~E3gV+S؃ulZL>(Z77msZ J3`ō_⠨
+;T&sMJkrѮvSatT;?SnʤeK]TPe+.7mx$N]bF[u+T uJ
\]\GLMl
GA?f*jW5߸~e}ҝ/0}[֍׷7y¼87n3GMt>p$[+k YqG5-rq%|AѨjyFk\EY0x5	q@oM<zQ@^~Ja8bϏ3Xӓoў/Ѳ0fyZc!nebn_4
DόN}pD\;TR>g`gI 9LJ&TNɛE/ُcՃńtYȦ/Jeq/6l:t^:8;]` ^j
_n|:PCSy׵>.#hSAy)XQs@d/i,#mt=h7|ds%Xev*Z9[Cmhd<ӹݮOb!0i/'׺Nw
v(trM@Eá1KL>$qʅi:sAd6ukG3k={yJ8r{[aV0x`1ZI0ݛ:ZX哅auFaYmu%Uoޜ)EG6fijJWA1:0Q46CǬ{F|ӴCU1h9sx	teiSA(|ס<qllIkMG1"wi"f( z~D:K]PPVľ%tК/B'	ơ9iFgj{Yd Y#0p'k`^#دrhk1Q*nѐHp6Xl_X<6u.T	siαs-/6]=ZLW
<pHCƠ28'(2GD5!kX齬b2vg6ql6C>Kh>]M30ދ:M8G(:>_QR	I4՜9WOHR:-ՎȖк;T#vTnAtZ3͡M|ys@Z yP3F:*(/Gc>2{c0}1UG?$QǞ]:zRk2ґ2'H)bShLd.h0%[Ou)9jFhDY~:ԼЯ3:t_="t|&G[$]|OYyvޱCLY%qwIDlXvs ڞBa?B F6+gr!7V̫H%.K**0o(-:6ܼ|Iz:O^(5ugÇOS>+5!G߈bbnJ_kWNe|STov^_wn<E']W>AXxlo	s{=~ PKt3Y\3&\z]Vm{'09GL˻tIN&3H(T |B
s6DDcvABpZ!-;ia
	x]G|N.aΈ/J3֣Ht-CO@%ޅ+cĥDv8/+o}f]֊BN_ޟ}wNwΔ@ZIqhM'X$<Մ'3+/,h`=.(MCfK AX}5_1Ī'k-me2<9zH 9@`^_.t{n6s&.mw&#)}@B-'#\餋_S.Hx%gď<&G"䜹.ޥl5xǙǋl#0Ecz%98M[,hMA@W£ۅ]uܞq.gFȩhO{G)FPG)X(}pnWh@k![ԁzϒjHɋg+Yeȇ"ߴZb? LgU%`J=W_fEC/h5`hn|;$#V=JM~Ap-n懋گ_/^т23ei~m3ն`>~(xO!OpT=؇heM\%7M-2x8_ZJa2zf9u"P'N"1Ư<V񿳋ҷV\mE]8[Z)!thS(c?XhCS#Q19	xB.yeO1^<G%NF+,M@MW+%3֖FD3lZ8D|+[>"i+O<ri%8Ed5t,F{V/SxPGqDPs#ɘ]5[|TQ{CU/Fm0%|qj1ZȜGZ󰍌˲Gg1}X\6zm9s,~`Fg)W/~$DfΒ]▗V+#ƖiZ[G\꺎/j(_oo\K"mK{/8ԥϵ";"';ve{v~/g:^~{av/`ݻw׾SaZѽ$Ҷf#k^k·́6+IdrKxTȯHD<~fꛞCOhOouΏES::NYwԍk⼚@j])1 ݇!>l.h1<ͯym'0?sKx	P)jⴉ}Dx׋r8B^ki׬30]&VsPֱVSB
X;FWqN,%gY߀ÜO4s#\@K&-\g=3UXϽS2.(3ƕoI Ⳍ}|-CY*X?_9Q̑cj>۶Q%̵Zab\c|WC1t.0:|M8GIp?Sl]Վ9Ftdػqz{^֝G?*E>~WKxp]J^+(p"C9zs7tJC$q=I|8`<uG(
i7pIEo<<h|;'?~u6|$IխE*d_ =V{g_U*4VR@ ^aG{1~sxY=75y<1z8K	˩Kcr ~ }B].qI[90CdpxQeuB{>?[mz쥅6+FQ(5EZ19Փ:Ʊ|O #(/ K99i8=a@;+lJN4v[(z]'-z.*oc@)5KcuO`CitZI?~	+24~(AIB;F8"8DFCK[YLB/Kv:oت_J6ց&:.yF8{+~v:~q<؂')j!4=vd&>-Cs'L<љ@OȇL,VJ''?Iv &PnKH%h4җՆ׮q6}%Olk MQ6nl<K/p1KX|, 0lv]wv5ms{{ƫ~ۅ꫌UGl˅ȮBqz !{.<Z+킶D{f;,YٴÐ/c2_ߺM<Gw"F520f.a-_k=1_'syEy Usܫ4^p
Im~{\ܼm&.X%N.(X9:~}Q<Lζ3}IhV0u/?ǷD6oxz3s$3oO9! 腅Ԝae_]7)ZQ.dƲ)$#?e7awV?]{a}6"D"%'g4R,S9ۤ|nRWg"yB6QP:fŰh}˚	q
xF=;(>] 524ģ2U]ۜ mΒ%;!"XS4vhyk|C< 
+-)ѿU`E}6M̲cAQ-'z'3@ޘ"&+B'|T6+۾EAhX_08L>l8N5ʦhSѫ֝*ֲdp= Sުza].-T[{c6e؂r"yYm@m1Pv!:C)5㍋S3m8ըsϻԧ<$E>9Ien|H{TFYn$i6JdϾsCo0Q7uu,M϶Wc%|nB6*}OKUi+Q);b=l[|h~Js,@}B3m\.eݕJA. c{_0TC6g*%8d cj)M3:GK?$WF|sQ=7G+<X ڭlvmV۰or6dL^|9kz?p͹Ob\XsRwwD%\
=G,_-7M+!zRZ>5Ȩ4rz/v+&kulD-!BEH ܡ2tRTQM{,JOrW/+ڬjvՇǗYڌ0ZEGQX=Y|k,VO`;ݯ9{gL|ox\\s'ܘr@g. Sr\gn.^sGAFٺrMk]D.o̍~M:sW'7s,5Гޯ>x4cN3:J<X_Sm<~ǲ9ۃs+n[\ұ
 ˼
o	
*:\m/0[m{U_ړU~tqK2w=yPnlꇏ\ݖh*Pe,\ƍIGb_q(X۵?ث۫8>Ӛ
۳C*)fD!_0U
8S޴4M.Adi;]h{t|H.pZ
CgPcǦ0[g_jZrF?)g)_e}֫{j^ m/Z&A|DhN	y.Aqla1ۑ?ÕF1qIXKZU[ҭ/oOΗluX۶m4Kli!Ǆc<_׳gZtsPl4|"(S8@+?Q8?gLLk nv@v.9] D}-MLxf+kEk24<f+qSl5pOK+u2yW'9fTsCJs1J).P<TCmm9UЊ#c)6\PR ]521ۮ5E軱K%c7$җiřۣG"Yo}:CطEntħ%Pތt|4	===}RJwq27p!RD6:/\B0)Y(Szml[ 6IPd#;EVUF{~鼅V6M1řWFEC<*mg݀M!ԾT܅֠Y$[+DKl;3X)!c4qh#)h~B.mEJvnP;<@Q]ɵ¸9@jdկD<SN[|i#i~EL Gl9FzsPʏ,$ܛNWHjv-{.{xm$A/20b<P8/2㔜 H_fMsɘb,!3׺gDvY,GhI0ڔss%{c1౯%krqc[GǳP?t+$][<:ͧLwrξ<th1I'ѡPq)ZZf<a#E2tg	+ʷo.2z8B971Z&7oթ8s?P
D|TZ_mos[G+|UAh3n[9:>(/D{x}Ni%Lŉ|`hQ?*M3>1HC"md<Qa؞R5H9癴	2Jd;IUa6mY\ٮ\ίA\aƚsT΢vF|<m6=@xA=gΔAW:étn+uV):B#
SGqƟ`1ñ_d,z0Z<<.N_@-ሔǄ	׮_nݺ_9r±_x-R}"7Afaȕ^'k:OO!^zy{߱]q X֣ u/_j\Ã|#ԻnwdkCFCGDt+>`N+(?K؁E;/=_H߽{wevخl$ۧ6GQht 5+c'϶W:Ղ{Mlh)gΜv2ew`^ _.(D&imo%Sک^h*	%Ρ^Hv*]4^0fzvV^7Kө`-E``DwqJD9Nˏ1.M~4fNLˠ& yi3CwQUma꾤>s].]68 q.O>p*QJU{d2&/pxc-XrrbaTJO_P!zmqX>jp}vcD!bP/YtѲoႩFL(<E28:7H;Lг/xΤ<xUgy!Yi
ǒKisf9NĒ	NqŜ9m;
?Et]=CXӉl6iźSOaxwn>]i6MwXk RB/vs'Bv#TfK4]I`	Am"W ʥ:.cuD)x&|?O	4FXǩtL -SaЎγPG[*9Ygn"X[9۲6}IQNyuOqŃo\3I,t0Ej;\,N..~O?蜧D+Z y*
 ڵJpAİVk3hmB񝼼hڡ^`cOQ@\!VGu臢aķqB	>c&|P:(;5&OJ>χ-N(6:60Cz_ĤĲUCܛS1	+ĳ,4OA?9h/} xJ4NS od2vglF_ż;CH=IHmas2|Z2|d="27
րȬ_bxNMz֎\`C23|cp3*킬ȃ]Gr=Ms^C^{k`mX@IXxнd&S93L;S;b+(V9:Mx6WdB7v	abC@w5KUl΍zJ2x|ӳa?xcY<oR8fX9]% eeR|OQՙ)Xҥ9I7K%mNRyQyL J|	%ì˃q.,	v<Vq!r"aK&q֨6~%ȵ*rzF<%"܅؞T1ryn@2:c¢_igQ|d朌
믪 H֏b#iW/븩)émɳ^o;!-_gjp|חڒP^'5EҎJ\ux̍EK򹅔<_.19\|>OWʜLoKw^Ar>7nn7	7o;<P+uJSІknVu?@s,NZ״xk[jCwy-$ 0FVyi7<~-:QHƬaN{GZU9f4@0񭱡z9cOL#mӁ#Yyl(~%>!|i
(SQ0dz+(_Czv񧜜~VS>ªOpJLŷ6	k]A"'iFǡ	K)CzVN|t>i5,y"L<poEDs2GsPwXeN\n`D/؞_Ӣ~ Ŭi衲%'~ȸ;DGG<hgCş=3nsI"Kă)Bg3&9dLSс43h8[|u0)|U;<1+/SExi:WAЋKO'n&	-:>āJ40@i;N+l)u&.
	:kڟ NWP@joH jA.2fk(ĝt3IwbIut􊴜prMCB[^qU8LU;m4]Ӑ@kZ7;|byB
܊22U?čN9y<<\ҺOBG+pZø6kh(lƓ딨3)ݴLm;8{}<fny=?IB̶Xssc!mw},su_20*(#:U~urڗCiT@fSyis^7>Z3;Q?߁hlcm͸<}lnQO:rLt+BSbKtƟ"z.eSd +;t;
N#9V4@-S?le60X93κ'W0Nc5.Eiuc'zWٲԗG9'U=EjN~~5{/-~%QVБ[.
.e(!㸙T/ke]<Hl;@W~tFmW+?{λY﫚ڲ,<GCQ=!FX9Y.\mﭮ`,*q8/ Pkٖ̣M`<Cf:ъ䭾igVee}HC@%?q=y,؂)ޡYCH5Ixʮ@#~?'mE!"b|Șxo9f_NXܶgm}(@
64Rcyf̬؏J&#`vrW`n"WN 8O5pfK)`R@Qoyn
9MSƳy%b-UJQi9HcI~)O&9SdLGTz=}d{0SSN+ WA>;q\_AZSk=n\v7pz*[QnI	e-F~oOO[˦n߾ݸN(_*n.t*+]muFT#8(:5ڕ}ǩhK~C_GYkBhh	R=U^liLTښCVea:s/Eʌ֑5%ڇ6A-Rf.q70_%Ϭ+=nD:C;V}b-1ʕ92>R|ļزCf$oVa$PJL>.2嫘qʦ5B){aҋ|5Ȕ  ġvU1SAޱ4d  ;{Jn#<dEN:nf tHA_ΠA'x'?ãc5-W|N.4]j/&IY.>:Ɗ,;m/CV.ZH3}꒚'W
ژ'X0;YM;D֕MǬR(0}&t_
nHBA<3
զ6<`ϫl~l9nYފZV_dPn'IqF^.m'ĕ_DG+dux.lDmahu(~#:N10Rlcx;m:m(aS0MoX({kMie	:262Ų2N,8h°toC%Oı~$=G	x^;tOч\#8`8qNt<!9\Wh8*XZlcA8zrCu9ƚ6H?e.<<9'۾9P.\y$k=57uo% b[Z(xU84Lz1B5؎cdW|K`{V*qm*L>;=1)Sc󟎋o29cO!]JN |;3=!i'hba?[[EE	"̨tF8%xȅ$פvT>ӵc*}ޣPV\TƂbI1_y}؏c"j'2	z{Uk#c g~ZyJithc?:SW. 9\dM\yKlڶ!	mCPpĹ\/tVtr>2t66LǦ@8fl~um,Uh%9$xSnoaͅ+tϰoe.Tu'&8ƶMhg1OT2R4P9)%dЫP̹5IA=B'苡rD)Z6ɺ$光C<ӉtEF#513;<
 c}vB|7J.#G*RڕNsW8u䡜ʌ>S1l6eѶt3d먿ĸQk\wqz$Rǹ8/s1OsxJ9.]{)>ﹾ!če[\zjyvmq#oisƳ6.&~n:߇뜓Q:
uwɏ|'>OH`\W3s1>CWCJg ,n!wG;^ӎ
P!A5um}J7][.!,:NJ!	)P:%nSG|>zb_%lSAS|8#x>/%comoMM<A;w̿}ۙFAy9a+!cZ_srRESE\&}r}*wV@^sH6?l۲ӓ9ǧI?EpWƘsqhM+9ưih͐6I1(/^BއBw!*rJ	KPz~I=T}Rj':{& n䧷'?ӟLG{fepFV(˧Rvoj"=Ё'LR8*fb;޶mwnm~$v*lq AK9YYl"k	mZU;>	EHk 5&L 9Bif`J%6:f4(>3/>pFƗ4/\4Z8V(~ŋkU#S/ޞ-%?H UnyҎJR^eĺ}rY~^tdxб1KH8;4>^"><ʚfa_`25#9yFǝ,o,:Fh#4<5pdVQҌmɹxeԄ6QI7O|3E}fNfX=q580=k.2'V}tŭ!>cү&9y+sJ T6`NbM:&V|q	mY!16T֠_	te
"+xtS]mQc@GTq҇KO6##o;N}xNZM̾C6 E_2^'NW*rtq$u~6:(O(~ي$}%8OnaAY0HN_ūx!f8J0n:ۙV;_9{DuPX 3<<Y#ifЉ/Hmfy-Kf9,ZNw*cM"i߽}D<FP7ԃWj'\DAzI/Y8:"qa)g
%8S8xStxK	gJ8/SMBy=ZtiCs9u񹴨$ +DM@Z]۵+SWVmAO !d>6ջcEUsLg'OS6ż>#Hlxsvƛ@[T S
vĞIUWFŰr2I,cCMj͍wN5Ш>ڲ#4⾠SC!}[H:"{.5>wJxE+BFoPZlD{(mO,0Z:\\ zW/_SvY<_FM|%H{Lzl~o퉲y,fykC	3lU:u34ehHڎH@SP<ۡ-;n1K+:>km/߹!amƤԺuWnݺyS˾ym?'7I8/AKvX{
pC c91?Ե*jǼvWyXPPJUi \'!ZKDpSyy-o8<u7Y+}fu(kr7>o`!!i"!!* ;^@6wlsx,&U	ʚ
7@u[Kj[u8$8s?7.u|
Fo$)/K*r)7|C{y]z׷omu<m [bd[7Ňqa>Lv8/0۫u[)b=F;m5n&V֕#jAz[IIȴk`tѐ>{ChչDglQ4̆n)7	dGXmh}	'J[
KDws^J6
(úM{!	x$ULf:sڶ\ǎuթݱػbd<AH[f2r$aqKLvbaOeftI) OaDT:rmY#zS#^e"Z]VY'TA,&/BDcem#k_0&x	=sӡdօ0{l/>6 G.l?+,C"ij,N|N#0:,9 bޖaМ=v1s30+;c9!'| )Swxuk4*ZZ(h-m!=kU8U}!	B>41'm+\/tcF'P8s ӼRNZXşɒy	U&YV낵j+X.emBFw6./#cG2ٓ
/ZmoIST!LnR>$HN9N_	%7*d2O3bK/&w|9	Hв]̎&R`M%){0_ޖ)nѾ͜{bվ	r7ϧ ʐ(~T0<oJ϶RR@$w8M9DSi;ڏ-t\t?(<OzQv=KoS$J,iJ6=rtb3X3BI
b8@	pxt/%֖j5Zk|^3W$@K.
p+\ϼ~3~#?e~A|觙w㱣EDa&<ڗH|Uv[/}kroU%:xw|+tUM;lШ<ț}tN>_d:.2S&pA䐍nC쥵.%`4/ˉ.:T_L2WQt[^wM' AԼ~ɯ0cl37Z'1mZ8-ޘR?2yjzfܾ}O_,B_a$A^'	\t)ږrά`J核##ĊM8O^TK .@lυy|WH˳TqD{ps)lVxsA6(c#%9jfl7:%#8/ԻUSRi3KVVʟ1E<Zr9s;k	ϫ=|ݻGyA\hn?Q_~-p=|3`77WaM:!ɍ,Gz.A֢~0xI73b*nxK]yPK(=x߸'+_? ~ˈڛb&ŷGv(.+$&VQY4e`-T*?|sx\įÞ>y7=~WiJٿ/xQ2|K/v0ddSïǵonOҁRI}KnN;rfܹX(:=b.|>xޡ'3ThYqBa7@!@56qPĊ|q\Q'r<4hl`< =Khsbn747ֆS8լipS>icnKlt ~go^]GI+F;O6Obh98*e(*䀊*uO·yI'?(ςO\A=(/ii HN0~. ۅ:mW),KDB||	e;d-ǋq zpڒ
K6gs  dIDATVO?=w(S7b
e$Oq9OY5clډDfY8䟧7Pՙ*sQ^._5u3mlm	 5 /Gs2FvphcC;<G8R0+thb H
!:<Ty%MU%[ϺU,ab~~SBvkڜ, %]t*x,$dD'64^|tKFH}!A=gDjuk+s ig3B9T~K/Oܽ؈mcn'.u*c=]@`#kl҇=qRZ}HwlT!H,aN.вQ@8L/mW+P_*V/rS?ʹp>q9;kQ*C[JRZcbI);rT,XX|
N^''ظŚEk:b̓,[׵/'<^NOJ(	@!IpʛAU
K\9آ`R*ߊ#$'4e+WxP`9vX-Lv>Y']wuјV Ip-ettmIUdۥgcm0Ǒ˼9A:}0	jO~ߐFUgut:
f`%q,qT9K[(4<æwͣJ3@/vα'pY0)'[\]}FzM	mt";OKd<\z=oW&~@v#ȅ,?pv|VC՛&Z4{3ۯ7NNVrtz}a:vwD!^cD0OS8ZaBw͕vEgTg8s݌q#rcj苋{vH6<1=~x{~c_\:"7(sr#oFI/\''^_~'cj1j_W1r?e̺+dnRQFO|ȷ[΋x kqJ"3MKl)+JQyU!:=P>9m6>f(ù!oX9cy߉UgnZB6Hc5kDsώV@͛W">΃\`?S=##}=V8 7aS}l{^_(߬Rf\JA-krI]MgYdƽ<Dʯotǿc`P^؛@aOIgZݡ?%Omk8s[ㄵowB:AboѲ=scp <	vU8B$'C(i_㓜(^F-;V	k$*SC/Dm(>('?+ԓ@g?gn~oϵ/Y_ڞnnGϷ?{_NB/뻷	9QR_񁟷&.w_oo_v'og +~{Rm_f?ۏ;۶Y6Wk l{ϟg~\;]m߿'_}G~vom?.kBd}}lܾ[<n߾}^JM[ۿ{_HzG?}o?kV1zNw~mrpqZ?9^[h )2n3K+ZT}oD&dx99h*ߎ:NmKX;Ugl$2Lvab=ń:a噸PzRzxos|dC>@ut}L,h)8v9{&ꪷ7E8tBhk%OK.oZlWtbOY5Yw~e2fyż'<DmR\@48sCȠ~?,^X?GZD1O1ry/w.nxg[8H?7 bxNZA2g)GX<DOfU?PKp^MsBB;"}h3N9^.΃nbm"?@Њ'kKwlJ1őYT!銃B0_@pb&$juI>^8:B;BeL1:Ťk<D*U#U(7zoP|FqhMٰ~E.l8_OFr=Ri\^H.T7bx VjFy%3Vl/Ok&%fRJtFaCiy>jr`{e\̰ya@[sƨQ}ꇋ7/s|w?QU\'W.o7oZ?^g-r5ˑq|bϷ;8G}>muX'~0)6z_\MMoy ^q_^K.T/jy_8!Uڭ[V67}UNMlǌ}/bĉ59@bqŮ>=h]ւ9<d6˒BǟdFKiߘmo{Mm̔xϰk>,7lCo	O([WBOj߸)UG0U[k\ɰm(xr۪G8wxOȸx)lW9i㊉2d	X7st%m1cL2wy/ha.xcdWzs_c;9E{2!˚_v}Xs\<Q-[m<x?9)C/tz͹!OW;F*Eomùj'3(%qb;йXQ1XX>	@e<d~e+ȣ(:q=>͛
/k\߸h<RkwLRKs6'}|m֋WrC	]qѝ2񕲈UaXxRE|Q^*=yZys1y-;e}>F6<Nr n[^qMmg';aڒ,?gWN	eF/7Z:|ǯVxܗG~։K1ǨFf> }ʥ5+Z}`l<e}QQk:y.RfA}EKKvl303XV@+}y-|V<y لb)|{S~H=:i__ȴ%/Abli[oԈا=͝ it5Tl0zEt/]P2Rǩ-Dm
ɚ`$Mz$WJ?5:9+/m.hb10LF8+l_monk?u_38l?H}"wmߠ/;wίh<}_Q}~ϷKphyH^ۗ?}o
s__=)1~_m_eML6~Ø){~>k'ߡ1&C+}7Ѽ{omބھ=i˴wBֽͅc=۝nwݏ_j>Tk|ܾ{^e^
;PȉeP-z.ܻ==1iݦUc1PdE
DjVaJ86װfNG'}KroឋN86u8ܞުJmZ3]["#qYʱS*?,#^?(T<sh=h/$U O1_8kJB/b^8ץU勇Y#}I<aEZsHM8[1kJέ9mV]BX2XB>@ fzDq܆ShniU3/91ݸq I}YN	N6/,vCiZ؁UXoCc@z7\Ҍ60AYr[WwM΁D-eEMQ>y^R)	׭$ՉN3>6Q_rf;},<IN*D^4A }Ⓜi^{:yO"LƉ	E$uTҾqSVzO%DtTw8M&z,%s?+Wͫa30kr*]-1$sZ|nݹ?as玟>qg^ ηk<1ΕT\	^"J;M1/n*m*O9=M<3H'YvCAsvfPA)Nl:-jq5̫bh+/̛*Ǫ [(0'^mMPZ]q.*]l
-kF}벩<3d'8{А}kg7H'ЏJv_~|ݽ{7enOcLxqb\-?chcgVd֟yrBrgIOd-=mj(^inT`Hmm)Ok\گN4v]۲a!^wøqBYkXBdf
<EA{IqYW&Cg\MK+u~%;#qڻ%ëmZ\sW8H9˙BWIn6Xc+Iz^+*CsqGB}Σ<
	sؑHQ;SP"}츷>/k/l*7IkR?y`}yypEHc*X}G&Oh큙
(Esd5(o>;Rzŝ#[22P7%(5޹b:t	po+KkHyQ7FbLߔ=Ӝ_Xqs2u6I:7dB6ј0w|t-|њu⃾B4JUmh悑&^ѥ$اHOմ5`CGGh'7WnrƓO0)3Aqae8Q-u̯+TX!NAOl9_ɶno}-mj>fO_e_6w
+OV}On_CA+~ڶ}oE&2JJdIӆ>ؾ~`9x~o^׶_-rzwۗo}߶}qC|^?ԅ:k6/?uۗݾo|H~o^a{{e{7Yoovko#|Nz_ӷ_l_Uo_%nwv>޷}7!@\9ꀛ{m}PJSk>K~iw}}8v7-9W:t콻hf㾕fhc3E:٬U5:`o{`y.FﻕǻDi&H`;?Qi6qu(,QNƁ?Zi~Q|jig5b6&$:<KhP.Bi|o	|#􅫴C<`LX(!ڞL#L?m:ywhnN\c%Oz]cUoߥO\RMXLEDǝy0[٢Ǎxnt)О,J7
89>6E!񱞇t"g#ao*۬k(GeYYz!A|'){@YKv|)aZVO5&k	~%RUvCöqJ8?FR@gSFtxCw`Ό|H9!crcQ>cfYD˩GY/<g-E7ۡ6CIBEWrŹE\iEw,Wqb'ycUN#Rt`"P(0
t
֤97MK?S,HIݿuE6E}M|YgTelK xbnd̰-3/$WxMP;AzS<vCV":p^m8>e]>/\3mmx}=P,f;
{m:,Yz21T{U6?ɬ"lНr>8RUF| O|u,%ʠӲ頸zI%JW ,SFcYSPdbmY#	3H7V2I#d?)!4 _͐ONǴжï5&^e`|PjV.@RV%K|em'7hKN:oMWF7ctp·]".~5C憐v"Ph3Ѧ8!3 j,Uu1om:֧O?p]R%\הW&Tj-4?r-$MGv@~:an,10{	7tݻהWJ~ckMAiO+H-sOD e=WW^XB깾)qV[-'c1ҪBImjuC*Ts$ln1>JiZ}iǀrK5mfV>,$=<PjWDV!^}IXrIo	)IlSgHG_OmúG4mXI}c#lU%t+KD"9:RZ~SZ_`W6_J^#uci2a]ϱ$@YPWO3?Z\ǤNDe;
$.ϡ7GU cqJŏ}lp^jy ld7C?A<ڶWۻ_2~ݾ]>K^z_}l+]ۻmwyxE7o}%Я۾`gmE"//kVk߰?PJY'S|ZL=i;S_}gok+?'d՟o?4m${?|_׍U{1o'?CyE}lpڭo۷*@*>MػJݺ=woW:jkۚ%Q
c7''JqWrG-S3ØIM:3 vײ!e`iRxE_I\}X[wVoM3,՗q\C$})9lE=òcs>\Q{ (a[+Z^-z`x<@^1g	
/n?~wtת<{=S?4Z@A|dG@x}T*h'+:Jd4үiњU#UWZ(vxDT1zScc_Ai٢g~bǻI.T!?eoZyBuNh<);OvUvǏrQխά6J-Ҽʂ2xOƠǏ\"/$C~|bz-|֡[VSQ\KKt±^cz2g^7q@2ՅѮ_i6%TҖV5Pim&iqܜMem<M1L>|Q֯V`C~X4Qrk<[gڑq~Мv+F<.}bNFrXm{@GƠ XWmx+V?OzW/~~|{\voݺi'>	?&Bf_y_*>:>wAy b΍+wϟ1>._y͍.>?p/v$ 92S`w|\'L,PvB};yAg/cE/ʯR(V*wR۔ jVpRJ|KKهp%ko`cc	[GQ&m@x_Eha[6*07i`ǋu!mw* <jye'ř9jn;\0Fq';x̺#_Ucd6~øJބZ.u/YS2vy$6vd*,F20kͪC_ro)Ol+m}R\{xJ4$XCy3-:^:c(-۱|xƆsP@,~jmhf4so;y@B#}Hz_fNyHsF!#Zgn:ӼrAWަCA!*I}a|~}g1s[Th,GlOIs^FK$qvs"QAR6kÙb3z=n1>:jĵ*踽*
BNl-Zv&Dw[%6~aQ*6&+ʍ+ʰ6Ii7786۸_yO#ú䕵85#PxEޙXA`q/X+Gr".5\mQ5C 2Rzy_d@/Ș!Z"W{Eg	yWmkN]H\1wؿ`gs-!ޘ{GO<wl8*C*;z"rB$[$/	9/J|
d
QW"Zΐ0 ;ж#K8+3L@(]bFnOE~m{UɯJ_n|#۽7_۶t{7&E.7nnVj!R]_rt{靷kc/|ŉI''_߰+/oHKݾ`{'e/~ݿUگE(՜OA
T`7~v_U^K>WUW_k۫6wHmk{m_keUQHD?I}Du{_j~T^L?[jn?zӛK+mt[KicNq>}A3⃤ 5ջѼ,65`0U!L!
6ާ#}ZqVst'2<_v:pQH#LSj>S}ltS'£C;:¢dHlعtNxݴUh-EkOxT;$8}"I'Oо"]'!s^+W9ndN?>g%LT;'c*K(wٖg.BڣWJxuS	s.a7t\5R*J?5e1Ė߳M>$ur)ҹǾ0?:$СIɇ22]eAڤ*dmgu".$%5mPK;gjդ-v0nz]Ǹ䋤4~1f'_FJ02X3^,iI}+y1'N;fMi[muv[}xy7s~rHܶo_i0#Om.d.ɺއ?ے(ue~N7Urz[TfDk5-:U=g%|,/ѧ\d<p&].F$/Uw9>MDlZϑ)-NO;Vc!I5>T|oz|u$[`m	fll#7̅}k]ZSѶ 2	ξ}1P>9>j?W<[X+ҜE],ddҶQ`yYE᧝<B28*I\eDףa肔-"<]Ajh~'3xFNȶK'uTe\OZ<3c^rMj6~w_x2Js}͟s{HD{$p>5E	JTg閅]{rIuIY~__{QnZ?+'+5¬0QYhPz	WI=qlO6y5ȯ=62^vHk#^kTny$ekׯׯ+lWuݿ_3zyPkEv{_餿~1[1y+_
vyיGt)rDeP.kI..!^*(26lI=uۃZ̚QIƑ ;)~g|(4j/VHMnji?wUA>"hGv7fJ#xagid}˃s|/N/w)BWNT|g4HwHjRv9MKI8e,ᴽc`z1-1[D@)$76//;MAmL+0|ņ?(0xʄ*.'eʗ&_ ~&cHBSꩃ	`.7夿?WvafR?'kܶ/YUgm}ؾ+C_~RQ;6>i;oUwn_{T;o~?"oYI;/~vl{ply'GK=j@R#`}AW_rxo~ϟ']7ؾ޾{m߶Kߤ1"j/(on_kklw#k_|=>߶?}Woȇ~JNm_=H"#7o}e>$aWPy>~SohW.i"SSVf
V$6VA!jߞ)!g;t^w0U^9gC.ZdO?̯"x~i{s'',I3%+V tՒktJ8P ;5ᥝHC@v{ŋvz6(xlC!쒎>X#ͭb>p{LBȋ"b޶]zm?w$庸06!>t1Pf2/ʗk˸nɹ?U_;rGQOLBCsIjҹVINʦ(ERީ\jȯ@;fQSKEǰh[UhYҹ/duƢtSPl*m:e1&3braIwu]>n}lg(	6:M=~|egp(	t)myd>{2S)kgMiOib}_2J cE|_al8A1c.7X52v>clWƺi_/1кK;(]r;v\zNI{2O;sf̱4+xNS:-;~'$*|;Yϱ>'^+? ~<Rbm@Ʌep!P>rMړ9uz+l{%	ƈ,kg|w0/mNyVއYk7KEibXBB2JF8iTUdQgTʠ(.;$.KrEL%b\ 9ng9~{{|ǘc|[tQ*Zr棗^XᘷXZ4bpaWC qq_25~\dW5oCdH"˒#[1s'!31 ,}I*ӚNO_x^Ș12T,LوDjN̓L+]hOŰ(kkn96෬3y)l9LN`V(A%\1K!s$qh^Q.4	Us&йHa+X+/%x
}_+L+ܠyK/r33{?5Qؒ۳icś)W5ؗE? 7(x.1t*7.ŋ;oow_~{]ܽcbc x]xV3c\<z?GBao}Y?K.k@ƙJTV=eM9 e]BYCDw;r =c=y	T(PKq$x_9^N@TȾ6Od~U{d>=t&u.DPtƧ~097>vUb
}Ln)1/^0on~F^*6ԐTcq\guۇ{[!Y.mÔ[g܉w
߰{fOiTgCFi8O^$;JP9ᢂd4߽ps̞	BU'
9giRS >;U5bYn/mU'lе\孖P(l?vXIR/
'HIV\gc͎eIv| qo~h۾{I>qo|~2_өe|{Yxr>OO}.:T'_o{?Ozt>a^}~g?uO_wnkOju(O~AҗV>C}_%l쏊UJ_>Eh7e>>{f/-zkop?'3ܽE_}Ѷb(6o}2[X˷s9lKUבJoT[Alo^Y;`˚kbdLԁ	fס.BҦqTjmᤃo`(|cܳ74Ä[5N^FK.JM)<D2.>܌m7fh%pq1G5^OvtC;-cfnNB׬'lWZy1:VW^YgxC>k}?M-%I.˕ Z|qǔ񨲅u/HW~m;;DPiJT>3~+daE"^INk*0s_ {.I,$~D/$~42ZoŰZk=MRkAYA޶&YpkD41%LW &%[c02,YVxB7jGe%oM|獿9 k! /%iv/`dʛe$ͧ\H3<tԘ73Q7
}0k麟o
u @{H7{cx=vu)U%g}c3᳦O}.ǎ4E #ILA?ԅ TxLGٰGl r۪T|NzbSjT>mI!+|.<EJ! +<jė˄1p+\kw[Q7P47'tQIKYפ.n_sRyN^HC9Lu'shSa5?O[8rg%tjzC.Ionj/koYؒ*oU>?eo=WmZdcNV}%mǜ!oUsI:
YgMvJ砿heN&3
)P(e2Y22[֨ "WW{7X}<Ե0z^7z~Asc^χʑl^7lGk6҇POv[ūOr*AeqF&G@mYǙ" 6_yPWccf%MD<{g{nAB:|i噄͡SGu]ΥG|WZNK7ޗh#}O<zHC+&zMם{<f*=k
KH2EhE8mڀ>6~6i?pR-| }h+/L} #Cz5((uPrGK9ɧ}x0:w``U.	j;1VX.#J5Qr 5\UtH Yo0>ȥ-ȉmpEã?{8Uw?d 3=:52Yv~t`_KG$'UZem~Hr 0=`,<g:~f#¸X|uxqQl?.-\uh 0z#~Ah_(BYZI,O<+%8
ǝWko*Ս%R'yts3O6Ħz2D7[Ǭigm?|dwỶmo}`]_J@˶}o\/c|?~|[ۛ?=9@?@?u{D'loLs㧷Msۗ07~Wn"*kD3]_}n[r(3^l?/7U{'3?ۧc)`zNovH׶SHB/~O<JL$_Y :5ïcY|3^E3P2DMa(tr;mzL*1zs$feL:.^.<h7=cђdsu0IV*蒍vI`;6V0eo;P gr*	0CmOeBxpr[+w8xQGm7'}n^xpWs!ɷxěd埝Gx:'h].K}Te|?3'.oǸ&z0ُMȘ'2'Щ$:70/.j܇(K)?/>k}3ǮVL٩rL~(UCqoEd5*{ZvN|ꋷiVm3ӄ%Jf+h5~
wI!ӇEj(=4lgrJ:BAnU~,vo훺17INe>AqV\ƿRڹZ \Ak3!LѲ!_5~\e?1T&vݦ4Z8(ґWÚIz|V{{\8<-
R/Wί@xXTT@PK-?o>9?=(aw|GS.w ؚ62y$~LBïK5\e¿u@vZaͧsh\(f&J32Vjn+]0~l-ИH&}bdquֻ_])csy]"ñc8p!s=2FyrlW	T&.m=ѡ%ќo[ `:HD&Mծ~[ȫ?;jf:Pp`mcFbq\;de~qA\RY/'7&^:c6p^k;Z>	9*0nڙ5&齻wN<\g^d7^tG)Bڄrr/v^/~\V:hoí+ྎmQ|E^"C5ROg=aKD򩤃UhI9fPdg2nk'CƜ3y*>ķw?vtE|ӉkgǤ*{n\hR?D2|Nv̛~L:O?~P$6c̺w{=6!CE1~@w]CA!u'm@SG5XK%9Y#殽cxˉ
>uLg8[!ޚ2<{خA3>c Z<|g{G"rCZ]
WX9=5	yҥizЭPZD^5$ ~(\GbO.)xkHz!L E&i롥u'2yEN8_^FTEюGҡ;a`1Z؜P|! Nzh /'b/phWvTIU'T&L0|JZ,$/pejB㋧IDmvT{qL!X5U6vn?\:e /~{p쇕~HϹQz C+o>~yȷo}۷_/\_޾o'[Ii?g_cs&O~HWm:8O\/mzmn5/vՆs?/Od_n?sC_i%}o/KSl_Hw^jml_=mHNm=yہK冷aCd*}x1WgUJ	(Y{ΛG|Du4%ReW{RʏQ<vU묠S'2®:`ۑ*Ȇ|Y~;܁)A.n,u"p&ip}T55mNeKe4ӂ$z6Vcij,Ǹ'OJ5fgy~35>
of]kHgRxݚ!F?-6;:MA)|%{oE0GC͆mKt<v$Q4f\%خ*aQ!py>zL@aCIz):,9,.4ƳxMz`/8A^/u0 ;t3,촖?ί 1cZi-=[ƻX$@ 1=B77otz6Lg{nu(~iXqOn>g5:Ra*78eoe7{=ov_v]A%_hSx`ϑȣ,o;}w7rsNYUwbe<8~ÓwuuWxs>&gJ_ږ6UR[vόn7#-i\-/iWj/p?7^iSn%z/Lġtu71o\{HR?tw~uJqqF(ȇ#1ޘIMgJ`9?}>
	}!!'	˝|ڥאN{AjKU&)Gڰu2.o{
RaG138^*N>UAk5ewTʁ%Cd5zH۠MG's-Iy|5[ͽb]ä8:bٹjnsQ%۷a˘cE<4PXyk?dݎo4)Zg>FN}E",/ǚCּ3t5{cOvz}9yP>oqNc]5VEy8vuک)HoyCVB"Sw8{C~IW.x|F]i8A߹sR*p<2(<:PLL\7AXh?ˋ;~v|J]R_X}+쨋\NN]Jx>oV3/ό-߾xXfι\<|h{F5g"}A߹#<2䏟b9Ory:ndfcz	pRm@
_RTL܇o:[@Np=*,?A:|sSHHԓNV+Ƚw׎!VmYj!^2"b8&6 Trkb(+VNrFJ-;{c^{mw5{kDv׶^]=g1K[p2dR8ɶ$KYyQ@ϡꃏ;mb:T{i:mT-un% cayr3$x(?7ڥo,
09agasmOV=mܽww~rՓD)x ԛ0*?& KEqağo>PrH_3}(Gȱ!edX+VK$qD$xk}W~IYwßH%<jvo|nO]B?Ok79m?~_v~s>9^.Ko૷lo}	߾a>-7u/>g~x% ھÿOo\:?߫QQw>{du틿=ڶ?}¿}O7c}mhw
"}	bzɷ_maE|?uO;u//'}ڿ_rcouy8օU&q#xOԎb?_^<PZ~MJI8< npXJ)A.'.~j*3,@hـVڭ6;峌BgPֻaP< Uf;\jPgonQM?mo\Hc7`*[J燧ݯN⒀9B>?~s߼伒D;>i|\Bry-(꒛ғ}>h`euj ;t}c)eعȅ?@<=tb{WZj;|..ly蕏mb6'G8eC+#Q(7gl}qXEZ\%WIT7>@ڦM>9::	u>XVVڗ.'fk IЖm.V<6n
&[N#*j@"ф.{j4{ n"1PɭFNUyȍB5ħ ĖK9!
u@`h<IcL?a^T&3QP:Vk1nڐ-=ȷos[`?R: Xv$屏_t[(ǫ|sOc7*SEn
?˿[<C4.c}cK|b?f(q{['EWjh߻wk|\)7bunxq[j_?uXSrbl3g<F(0f1w]~Ev[D[ynW{VL$b붪~ƅKԯȇJq%KEDCK0l}31{1XG`ĕ<` x?'>
q9ƃ *Ϊ`㺺Mɡ<thc^Ͻ?yMI=B ܟ# %q)J7>Aik BUUv_\*6}*kN<D}oyaKLLk@~\hnRPOE?@߽r#6kCK0aO2T9̻'5PVr`,˰ c1WT5fttV/Nˁ=]yM)k={(UR`O;A&3둠3vmpk)g~(`M}7_=xXZasſи`\x*I%㑟&Nͷ0=qǽǙq[T 0嚂Wp{MJNT~~(wOZ`:bLq~)qu2Nx!Ϲ.k#e/Nˢ^6[\_K[bk7K#b؁-+AWbID$K9g~`,h[oi5,wUӧpbLo`G0S4A<uRi/:U@U>pԙSԙid
]Be7<x̹XO>UouG-A?yt}@:3܈?L0Cn a;1n2a,i\;ydB7u|i 8<`Z\g,h|ԥgj2I%& Fq)XW9U&7L0HV_Q[uYxda*>?߷m?Vɢ'Čy~_l߱oϹ.?#ba~jw_m>o8_l??L?ń|/9W>m?WE}?-M?OI׿go?=NPp)o>|)?lߺ}ǾoϿ}uܿ~S,6}}Ͷ_Wv`uObjֽ|_Z-Ϸe3k>|/}m֟?nw;UEُSj`W(Y)3?c~_s~-I
Db|./bs !m_ ~ޘaA9M^cg^Ê5p4l8쉻PBe 3	/:Td(UPXx~ι"73JMPܼiڬ}sC6ڦL$ۗw\cZB)+136a-߆Z V~6 5<Sĭuoy*:ބ9uJvSnP6ܰBL΁Tל*P26)b0^tsAtzšqe@Qȕx+:ƕ6cBjLZOA<",)+h#X2vA;<,2~i\mT.}oz̆nx{p!XxT]p,tt;pkgX-R*.y%U,b
68\M~}16{5GP$	NIXڅcu5z8><`,TfSPcIdƝڕxŶuV{d.j~m@"0(|J9n<C$Q/n6&'֛e훴).o%s^Uч	B[50]N>7&Lsͷ縁G#9WPj0dTd7dM-Ln>O
wK\(dH(h<`TqpgU4/'C8DBVcMY
-B@[ZwpVEОܴsVc`
b\<8WX-ыqrJ=-rsSr;hDk$6y
ύ,?##%f3!ܰs^bt>@N<UFДդ1:z^o7h7n(<$EΩu/FB5?)v "~y(9Y1Ԇk:rXז*vO=/Ը-7[|SD{ڏ;BcywmKoQ cL0kȣp.
`5x5xz5L^pG\s{bFtڈ=@ݲe.MEhwk0"OGYBOt{^l{CKqk_^6%?']kC^fzqX'ޏ(_ozm!3ObcM]Pァ2gJ75/νK&B ~¯?/@Q:ػ%`/Mk?8vSJgs5]~޲/~+А8,e7V+[][\"ug{?9r)M17h<,?x=S%ʻ1zï
N5P5`f]X/|af1ӑ\_W{ײVY}xdfǑ{"({~7R_Mo
z1>qQ ùXh+ҕ}i)k-6i;(geTN@ɯA2Y	j^ 77[vtgjMno0%`>	i`1x E3~2g,
Lاq :Z(mL#ytˇvY^T!&XDB6;n7꧷^Dk]d n8gE-Mo@+W>!i3.;_ Y~U7'$$$Nnb[,|}ڐwnnOoO}?-8c2@7{	p WX,? !GM}e'sX Y?3+LqS )<E>$]Ly
M&`y(|RZ`'DUH2*G&e{"wy.5M,La,\)3e\â[ł.IuP-ۅ%7InjSI2;z]\Xsѳ٣'~ԉx&aW恉/cjŗ٨y] 0ؾ)a.("ԚT*bMxl̼ZlXsN	Q>5O6HSy`lW'an؏0ꭾ`H=P2%ixŶoL~_:+wb\PD&c,/Ҭй "lCn,5>!cQ?Sڄ/4{	Ҫbe,S?BE/3/:ݹ?3=M@n1uM3`n.cGq	Dr=П2p׼XJQ5ESx+򁃟8;"uqobKĆ35qUf9EDԺ٭*|NGfw0&]dPǬ׻9z}o?U9GX{=Y^o+..s7ߔ)9kCiܪ_э_Xkso36	s"U\:ONs\~o06sJtn#oKΛ8yQwL°)w0(9g|Xm<2 -*^bT5]ˍLl׃zD%oP8kȕ`iVzŴW4?jߎq 4p@p&^<FX>qCQbA47c\r?}7X,`Vۤ.qFۗ]H 0[4TO6/qs&ϡ7 h39K<7ó .#~o7%Jy4AJǺ5D@Joh<zgއ%F83k#gܳc6aQɃy-j`P} -ƕS|<TPQ4C@1tbZv)7ci^CV2(V/	ݜ=%#3m?8haU)Rt;1~>=Ʒ#zM/$gXf-h|C%;%fSgwu="Ͽ9<*0q{q0O.48#ׂX90K~RP˜2nS&i7ǲǜ	~jk<||wr%Do4Bb}YcjTssWR	9:z0uʬim)}{~ˌyXBʌ)QS7]MBc VpR%P/1Whځv@m4PP_'Weq?^@}P⯰B=~lr|߼IlÙpx
tfH+}xTHy9NNP 0F[ِG[dXY, ʢ+@'ojG6L&|N^UbL,՘P	$-	Hwʂbs6>q5K7~Wi|M:{ʡXoCD`5)4<Ӂ	w`%m &;I/
xY7pW?4DN~Ο+6{𘵪pPLO.KCZ9z#<v@^ G7k¯'KJ Q"p9(TўcZMKD?%()mM lX\1 *u* ?ڼRh)l/5\c oO!κo״ª#Q|
%M,b 
NDm'2'YKx{k7r5i5נ.dNc So[V
	BSl-'AhgR~@熠7kL	G*8JoŴR0%ulb-!N?p[uI`8~Wэ=OF^-څ-38#2#9i9"9l1-`_ٝh"얁ʉ倽$v}4fV^m)&nJVu/0oq#s1NygIx&qɛиXq'bH&e)-·K8:6RKgV'w`NּjSRq_zfO_d쿤~4=|B#6ƗoFORBz<]qR(ߔ)0"(~G'#/Fw_\;"N<\NئiK 7^-Ity_'!y-')_=^Ot3Fye\[ƶy&ZA:sԌu(a|SZڴ
wOjY5tpZiT4s.u OO
PR&)Ct>@dL	GU*EtpE1];>|+^A <GN>ͻؒv*d)aZ,e~>Ep/tT6kj>ńCp!*T[%K!gƽf圧5x^ɓ|[ϏWH}+ّRbvH{16]`|茟I<̃<(Ri_1+߬i5OZSb֛(9v%o<y/K:\\5v}oݪ \iڋ*mg&In-B(hC-^w`[ǟTxVZH?f~*KrP흇c<F%>>((odk)y|*.B})iS~(H	ML,M֒՝h5q:nTIGkr1 ?2e~C8x}?OIK~v7q^u_-I=Y*q?o=#{G7׷|k{\篿ͤX)\{:|/WNDp|X9K1QY>\:$_'p2+PFSj.x* BEOFE;	E'O{@<0L`'6_lʲ1NsyҳZ&'W4#d{~u^υߐ"O^~3.hS'(bsMkRdnڿla%`͟M4}
R|̨@ټiPO :1sTZA1>;(`e}jTk /Q"(e1s>x;$[)C@NǤv׷WOK©7b$/@-cuȪz.zN0i}SG37Sʷlt8b3sӤC:/:+ڠщM1Uhzkj8?λ'ZGk4G?-g%O
,)>3rҡGǃm3G;<4#6f7\sM)Ğ<X/X]¡-p8@,ۧpnK)D6øZL=3Z6^<?F"7(I-9372x)x*8GnDl!s&Nm>u&oO;kOӎC]]z$痶6ǓNGz|s K5FF 3':'gPM_1!_xu\U]DF~oP:_t\~gWc63Y>3 haYxU?{"JG{ih˕_Ցh1>S ;!DNՊ?`yoMCGG˼M}<!?F8onRE#~=?uŵнS;!mwk9ݿdn>nn%=و;)u=ʖyh7Ԟι1c?qA9r9ym9Pԁl#NJ4XI#Ӷ3L/PL <b_d._ 
~ǧt'`=t9x/vPށ\(=qVʢxt	':h?6Jf=,~Lt.8n>SLϐ/W?Nk=eS%$lmKWJ$6[kB-rV|<Tr*uU<@@dd[n:+(PƬUchBЬC:9ȷ2oc6b`ǀd~p<,#$Ήv*vу/uFn19YAюMzHGXP 27Zv|;RG[u޼>;['w.p3[.c4VK0Ɲ@{J|<ƹGS_s9j71,?+P톸]@03FjYD$k7JW_=Zx23EiKoƆi+ }V 23)M;Jm7b qF.lF=	[k! NrpI^<\?Rm`j6آDyJJϧ iS7fnKUg,A}3R}0[aEX*9wlh3}15CҐ)yZ.ىCmZH;|}OлTךK.{N8EF~*Eg%'h'C۪|}?mFJBtpmj?ei)۟kz6htaG=OS%2Up1yY{fڷ7`.+J@/]b¨w	KudΌ;%b )h9P>RtLL?j3@Gi{[-&Y:$dC1KDko'lb9)']էm?v.P"i3~Unb0e6@ⵜ|0p"ű/(om^_Tir8)&.xMIoΉ&$=RaW:Ip;zEHҎ2兏rAYǸ,+]X-d'$8O_ఞޘf|1ĹAf߼A! yrأC 8z܃E:=n17r)2&||8 }`2Qk(IPdBU}4e9-Y3F펼J)i$ kM^р.01ʱ {c:`: N;>Yf	&нjm\`S3W!0݇c_>^SvWB*0.|ڀ@nx{;n&6qnJ//	9>hJ{j}d_q])2ƞǟhEtXiTdeN3d̒쏝v_OݵM:VW*5˝/b5oRfr2G*5$O'Y>K*Gh9`Û>3xΫE*7:>.|\Lo3uVa/@ZvωsuFnFqu)&8פ'\>й!7/]y6]'~uV})/ME> 	4nd;0CTCi`64ݱйH{㈁m>	%B)gp۴BDN;Fzq/t>a+N!p2y8gE5:k=q XA'pd?zF[`4kpD.] B揄xKuj_D繭=*dBlon72'pџ/Ɛ=V@lvc4Il,B [PжyEOᚆ)p'`ˠy e~aoy53*2O7<oRnln[[O<c1t^^J%fll\}it?%E=~Hoe}q] vo1 `3/JB+$=^#>ޜj4Y	Wϭw饘~Ҕ^l3"cK`v!rTE6t,ug	mq$~ɹÓW$֦)_C`j;ޡ;Y3@Wo2f4/C>LJ.k\d֢>*}Q sRJ@0Eѱ9fW8HeRN6Ȍ=heQC"1X-G"]0,>6H\8K>v4芏<G;兝폕YXp 0	#\bNf(uwP>
"/ʶ`{漡mr@Q!e-]@9˨rT`.q.w'nS8[Cau G|rԐԋ4>YA;y?v-['LCsTFc櫓y+kycoJ_":I>?ӶدLu|7:<Ȳs^mTmۡZjOʱp
=?A,]1.QK+
A盹ò	YY@wb8_6m~|.c>f8ipֲ 8*=١#~KA͍ڠd;JXpW,&VܡJ~jFGUsPz.>c: ]lӂhw=@JIqx7:2ꊲ3y%:l'tym ?,?PtYА+&ΟŲn#vI1'qp˘r^.N5We&I0Ơl5&.W4E9ߌth!'5r#$v0b=Npg/q|+zN^ϸ`Ò"F~bk/ذ*?WWΙۧc,d:9C6gZ3l.B î窰!:z;V@:cy(5a%cJc9owʋBC|a7\Ї:~~tmCzջt ./ئ^S. Xo?d˜4).<M[PCC1}Խڢݼ0hSz05/L8n݃ N<u_p@1'N@ˎC12΂JE\'Ж1|*uY淮2Qcaz&u]׾_k,gty1ŧi>:>O:54!:`kF3u\(fP< egNUjyRf%X]J³>`ٚV8<Ne΅Q((hjn'%QUDkTAga	0ۀDP,ȯ d\MFD\ZO\Iߊ) o<۞<*ڏOE+霆m+᧿iGo?9{)u>ҀÖaťlU[Go?>xS֛ςyqksR7y{ii/=
6.YOF[·nlεTa!ג1\vl'A*{4rPxki^bZ4.z`#s̧1Ɣ_kH*IJ1m6hyY~͛$ }LT17w吵?,OX!>ҍcK%6G	cnQ؂Z+Nk"k^%Wv;(Õ;iQWfP`; əgK@]n#M2T2EvIFŘN1d%yL07˾k*A#z5`4]\jqg~o9g9W^/myh;{
JE@IᤌJ d˕aD_pI\zIy^O>z:Ns6JEw6#|.4)4IJ:iqLWR|#OOrLoo7n\-f|f̰oƅLx<Cw
'L縯 \P|ZHJ$bPfIA+gp
o_;!tZs`7vrMU`(<Ɵpo`NJ<FN]0Y_쫠19nA7ޞ<Ȩ0mjAūrֶiVG/Xo̷eXHWq69T*dnMa<s-:nč$gE
cCTÉtl|%R ~rr2")_ׅ6 ~n}bRTk$7*8-WIYw{[:~aXAJ'Gu~gԞMÝ%[eNHƒ/=7k_7\|qr\Ա nA}(~vψ/̎ 8=8y5p
XL^[<xMTʺfѣZB3ף\?zapԋ|sP&S3q~vǿ=_?~b}/qꑒCGN?M:U0Z6q\gM7o/E?'vyu$Է)mB_/W۹-= v06(R  W2j\u,2L'pˆ_^ׅ>cuM2Zqa-Y2B&Ogl>rE+14dЋ|:=lXG¾ok7foWokUZ@RC,_YO}((#X2,HNz#0g0#ZӨapShzM[*JgV%5 L f5ޱ5oݫqmLi DU`	:?5!۷ }i߰}sCTBq:~s-ǜudoqv]T{%^~[÷=x=}h{18xU5U~VZR_ +0meV'ӛϚ:KP?_YFy都!p畈Ӊ(GAVmͣ/Ӱv[8q.ve."aSB;ၱgqQ *ʩ>!OJ2Ϸgn
ۅڴb8ťNIc_|?'S7,W	fIkXe7v|~	Fv3u;4G]3).'83	hPh drqٕ%sݑhHS.7(ʟMN#Sܨ27LiQm	g~IpVXR6}h|MỦ.GaMrPtZtC8Y0	x鯾4t_=yȝ$:O\xbQ:'ԺI(J~Í!4zHySoZ}S}I_ݞ}gm74n7H5H@Hʍܔ9SmH
/1
P:[H[	 5NW>CZ;a{H}Rsv؅wFpȄtisPj]R7䝀5>U}PϫVe"_Kf2a{@~_\󍻋S6G9k+(*Mg7+jj#YP//R{Sr7Y+~ q_65fn_#Ѻy@/v8M n/-c*-ZS]N-urQ}S]Qm=k0AQP<"MGo[+JoVV]>"Z|9G9oژCdaˮz&iLkTz[˨Lr{i/yhSVĦƞC绿Wɽ˟|v~Ϧ\FZut&NAdȻW~ŐG~Swd=>;2㒏̭j@ǺM;^`GW"]'ۅ;[^O^/)b	eBiLA$|g\><~ W~ıb6S<Z&LQpLoq{,E}a_˲8Y؁tZo%X2j?2!:z#PEnBA{RZъآsƭ:=!iqװҭb/SnGX5aг6yqz`\8!{}ܼ%EϞ__skݿ dSQ1VJm k'NDz.c1	vyNX8ddf*u:Pu|{\CGر+&`P+:+jޠYͷN3کjU"K%y_+>hrR'WhWgաUG|χʷnuL?wP	[|~E&qrsv]{szo`{ڞ<|]=ֵι74?^Ù<./Q@Up;p;ՍJ%/~UeIfЌ#h䭺sp)%pxQc/1ψF{}=+3>(о(? rC!5OhJYGcB{I&,C8|F:Q%>=	ǭQe|[*~("kMKf܎4a`jD;}\tWM%Ʌ[)Zܕ<I@w	/SewզFnZN$;ҭD d2Cw~eYINΙeVI?6$(PUiҍG~e{Ym)s~:^hʩS='%Qhv҆?>I><kt"G
]_\hg0m6`z1>yfIwAJ9&p=yvx_+ݺ=Oޞ}oٶl]6:T!@9^cfY9qǉ{+0H;0(+%o^+)]\gd֡apig^m/$ȋa9W;̦It+0V8K9JIk ~ y;,Rp?>ͱ\lUY6&!~[1x+,?O`qid-4%%-A#zcQp8O'6`eQixdo#0)(̴q.ls~،Je3+c>s;GZ%+_D?g,	P;/q@ީtW4 {3od:,K`t\ 4Ԡ<0zot[ohHGz?hr?ʥ\. 'gv7saS 7:i߁z/_{<0Ua Kh|z6>M7U|eڊx[xGLNVJkW,ӿ`S,wίp
|{]^{5GwfX-s|G2[pR?xw$@)30if7Ϫ{߅|?Ec91-Xz[Ad88wN
v]h*x%ؕ"Dw{YS(y^C9jM)~jWn098qad,ZNp&ү
Vy/:?hbH[xHj QFO}9p}ns @ t^rrwv)6V`"K>?.E#^dG"@f]8wޥ+哺>QkGÌ@P|m[;uƆ+11-s7i &
XW6I:ۢU|&{o _y~-&txf~f0?tsӹ_^vڀ>vCs{$ä(㔩?}Off̎Eܽ)hـM#/,LZ.;1IF京c	=$责=HIp	3gCЮ͈V	\J9&j	2W8$u66R{@E=)KG61sgl,/~cM^r{35?i	݅^?s%vE;?Bڅ`z?s$!`¥C\ԅ6ISFw}'g<Ӿoʗ`yd]YK %/okۣӳ.+>)Џ4Ȫɤ@XE7=@&.MK3y@ 0|PCt֏B8GDg|:gA'M\4t<qS'}궽&;JQtL}9Iֺ4}L/MWZycI7ƖʲuR$d#zR׳ZǴ1/e9J|8$^iّ3ůM~?I;o7vv1H3vyZ.mչÄS?'Plo4:<gLEְNuNWc\k<
ZugVrv|JwN:aeGٺdgmk{V=SQ%k榛ym#ȍdu/%.x̳Hn5$?l8yh*=8+[d}amut=ux_45EZ)²a$e.6e;b2Чv22N\!`?yG{7Շ)%G9.y7I7;a+F<kC'Ƽ07a)sgjZNP/e*(@+w{aٽEЭzsjVFJ:p/fXr)_*Zxƃ"JTI=H'J@IJ~{a~%	w~Hӿ,u"O`>U
n%'e	ڜ2W9׏n>xkjjdtdmJ^b69Zb~2{c͕\烾y
Ř},~J[8mZU\y(;~2=yCyƅ{q?<H?uCZ	o|򔠤)oh_oP72!O#ئH$+4EOonɓm{oO6ҝ*h8 m⼂^G^@3@w2TFV:6q# ߶]> a7UJ囲G7lvj"cg߇"^*>c=yx+?Bzy*?ܾ(ȧnllhb0FY6P9"^y[IoIVp7 UR)d٣<z0H߱b_ǲXV<l)TW~?8h[ĕ]49*1t-SZk?q@Z\B!a]^x1H%qgG9)^!|haV)LmfP~X}_n-$';ݯ%dz*qsBYdXU9X..nSIEHދ>z}x:I6c
J18FY
*8_8^5/g:@TY5҈O2}91N`>J5n惜iaADתfOv	 \#_pjTb9Oqm7;^ꚕѕ_emXcnsm-0TЂG^5mxh+Tl<H7OvGq*<ii7h{ΦʳOƺyȈ~NRc*?&a "αUVʤ~$cS<!KVHj@,PMnk>Qq+0<aƞ16+K,5jj+wmYA04>+aΠZm0ɴo^:Y@%}p¸F)Ǒ&@}#߳mݿ=ׅe|ѿ* n'c#7bg(Rn6MJ#7	(=hO>jOڰp~n#5X*l(TE&-rdVNA)F
L>yca!_qq>úAix#wwVgr`q+؉9BeЖ {8WRkS@C*۫1	]s[;9A}n'`wa~Ú~C7J7e6`Ч}Ya:IO	|`9V~umu!|Z+iм}ᵔ+{Ʒll=CԜȬ#.и7&[xڠ#n$j{>sw>~KJ+s.(??>*)o+6|oq.3 EtwJ5aȕ&_Gxj);)/oqbXNRV},r>GSm%Ei]H1FakF=|1\f/Xq|a4XKbb{	 S7w 'n4+#X\I%nz+gMu^*}89͒KFՈHr4>2p>~G7d`':X@\F@-sU9+7?z}萵D0vc񜟷g*1VLf4mVB3(ҽq;.Ǎp
6߻77<<Y\)+]钆:p\eg>$. XbDB!6j|8R n?,ҡo5?8;"VQ7>W9QyXobJ~7pb&u3 ?(j:)>f-*oΫoK范w׃ySՋ1q64i17F_ÈBYn͉"WjrPxވfA\ݼERZq߶W?s
Vݼ&˚D}Yˌo>,ilj˵m%nW)s׍?t<QbB5(p8 c+;vOr5jFc,i@sT=)vmi}L} '<Omp}ph:L-`Ɓ;\Xg@WP~'Gu5N|2cg<ь{17W^f]Ƣ0kt.\lIۮͷsJ%|2;j'߾YXc_|:{=r=_:Lp՚4:_GÜDzR¸Hpu"pKSd6 k$wojW
D^^@Syj864sJ_ݹs/ uΥknQs7g#Ph4NdckO,9<@Ǿ2_wE(3qP'[2TִzJ9Y;8IC<<>k䳿1~m٭վM^-sDy$-֙+7Tå/17."#G@#y\WҡIԊQ.<:FhɂSǷ``BG\2).!5Y9c@؎vuP+ۨ6l0|rPp"I;iL3n0>HaX~BCٷTJc
rf!cI{ɅxLXNʧt.x/.onmm~[~*Ket )w'PtJ@@u;PwkNw  m삘u; t-,wh>B<im'HKLx1GEN1>H{=Ҕ;K"	LDNXkz7TQ5EyNX/j}pU20AFB~wɜ)ofk?H+	5sFoPo-_+d*`zLx^)U.GQJ4`
E1ˁkrIE׷}-,e١<9dm髍7gEO5f=E\.dZ3%cNYٷPۊ"?`"2>RuX^gN_70tƾUB^8<O7MJp;n_~>1a/uмdCSW	5NKj/o.+r`'[7F⑧%h0@ed)0ƸT #DKj/Q٪gMfp:hWr 1XIt
O,Eb~*fǧ2A|3;>{5XBSqUy.%O@23-/^.13-
!殣jR]X|1\e'2Ե:ǚܺp><Q}oy)־*~W/0C*MӁ";^2% vqs C~`K OV2E)}=ڝ7FYuA-s*g,5A,AV75\}ȚVe*gO;ݻwNWQ/4ӿ'(k:TQƒ0!{>Wg:t
:@OF/j.uoȋ_y߰$~x/'ִ$ϵ!lq^ɞɆ$J2-?z[U>Uj&.n_\&F
Q`%<][OTfn1V'^x0ʱ˥]>ʖ3F))#C|h#LB1qGw,qZ\G7SZmSFG;AS 37 92ܾzύHO7W.Z=Xysٳ>n^1˖BCt)Oc!]es1Inڟ14`gAYH/,+z=LWiE
zsU	,ű_y[=J ?ʹk7Xsr9w_L|s	['%HKN%dAGhInVo?8'cZaoM4MZj7fZ<\ԪG{o}{]@=1ǀ.w
i{d{4oS6	_z^: 2}1g ?|~h4Vs@3s.yq%Pr4F_WZ2khGc<"zٺdU,4xpriJKgJ5csFC5LZԴ[]ج\5+*<z6:]Ktyp%-U1^\^c\y1w6w57@9xzOGh	`(J%@ׁeC`Ι1V=ODmyޝ҈a/m-3|z.CpFE;"5+HE;z8wRvmd0Y|9hT2BٜW@M;j/;X&!߾ō+lȴޓs~ͻ0|&s/iǚsa1_+!7P;g#RsQ5Q~77Qύhy$op}# n|q#1JDca-z>˺W6E\n
]Ch 6̾	<oaA%Q<>u_F#0bRȎ+ r((\
Od`@[ҴS1UCOZ͇蒃# [}:#vPqO!z7K8Ҵf.W٧_|rf>|)]lf"3_XOƣC^l/S{-\`!/@ƝÔd\Sěv1qRd=W.|؋3E[y,HfФSb^\11:#: Mxh^X&r'%FQuak:yZ7/.߻wc~S]5ikӊgG	.*=Xd*%ydI6<
;BYUvBH@~\6vէe{{ַU7k[d!Y<nN1m&(80Q%g8>JñL8QBz|{&h5␯vW?(ڧϑaGІ%sWSEe+U6/s|y4B9q]$?K>c0+>yN$2xp46ko7۱*yJ?SnGܦU'ab}'~A}KbD±q.Au|BqA-:OȩsIiYۏv^^e10xݕL{8kVx/=9ًB@w9hmN~3_n$2Ϟ==|=|d{YEFGdd$<6ᚄ1R>!D[8̚CM1H?
=>r%Lܠt׀b\ɇ@֏}ܡ^Ǧh'Ì{p
 d8N9"PQDc8k֚µ>=bDtr.7mrq/O[͸'Rξ{urg:,ZeJŏ>mY-][@fɖ$1%L큮h$Pq>^qdP^jw[֍_aׄZ*Ba?{0k-4rRtWXu7@w[_mz4/&UF4x$yR4PN0j
I ]0!dE^?/Jר
yħBL8a) Fc-8zD+8D05=)c0@"ux.}kݏT̸ȄƯ7\X }F{5vC167wnmo?gs/퓓J'O.;),w F7v\	qBܴs 64]b96.f{Ai!rvPa=o:莀>-ϧI)/c>ݻRFYlUogS1anpV0<Bٛ*Bۺ!Vrש!psz3?]m-b(bm䉬8D'#cMgnS7(sG	+2\vW+1)9n-SɑxErPNɡEnEMIl
v$	27^ٔf}vr;a#/7-iMk<6/Ҷ]꘦M&&(~
y+9mfZr2K]xcS8*3
09C`&u2(Η)+ץ[cUM{F[	Lmk./ݸ*j8F6}Ms7Syx\dH4^'ZND(% jtgd:Tgfp0mo,2#QP!=N\w{07ǻ2MLqm0{|e@c_G/s42 zmծbUz-d	~S2`]]w}zu}Giޚχ[Pv9>dO o35rݽ=h~P'9uOnӜ)A@IQ
5hI
W#W;}j]yuWW@>Ws_&gmiE2bJxokgGis,	zؿ)	p[]<4 f/q;r3|Ϙo@(m&\iHx.T,5wFp!C3Vl Fq-{{[qsJ;OCK:aylYzsl0؍)'ߠ˾'׎3ɯuJ|^%65BA4F ( U϶gx}-=Hi}1dtH"C/FuaW +1B:b zCz+f^1jJL#i2E!㓟sңGO+~ǿN~]C y }l<|yjמ*_)ǤŝeÞ1[ŔeCe#fŨrAfENRZq<j񤮀>`1I9^%0ip[|ځuT&ea?XGtccNk4&1mulPQ\TzyRԽ0 uuX/~׺RE/'<ț|a9>_aRߟA/}0ǈAfO<`6j)w2DqRd^[Gί}-P!DxMsLv/oYҵ#nh6mSAiP4Uضiؤ`6悁 դHo-5i SB|5йb0eMv>{l.%Zm	>Z8z<*:V'Okr\퀔qxb}0xωmۿ7=aGch|<A+I/U:m=%Go-c|U쀫%ړ{3<R\ڀt-(dp'y<]Ft-7: 1KV#خRV*^!~0n%**;P%I5J*hʧCe92O26d3O452Ogo0S<^'/(Ϭ]\^"D.%#oJz^
@|ȫlWOz6K} 
ȲN/q͇^F<^7n:;-PB\Vx@KAX ~yh':G d-J۰V~()7	v O=gxo_^KiKj7I>i+̃Ǖ"&`$݈ߨ`͈vv{58"8꜈&7}X,ypC;36/4/W5mF2^<<e|.yFыEtsT^\>nRot9&p8Z?55iGLg];>.2fWYKm8p&CVkT?@`6j(gEXp#R
۶ 
.l}aMJc>Ժ;Nb5T}2#6>ovuUzUYF85>YYyx<$~t=8bb~7}5Q 7v၅`㦕)c ǎn~IKJ@O>CBbE0,=dc$s?6-.9zѲI*K2n! 2!87Rn]ӄ.hԗ1>[xJex'eb߾N5	kh'e']{3}=\
򺠴6)_P{7]pRz~ݶUgYaf=_aj@_F9C$]s~užstUF{D|~e^FԅzU{{	?Jh#©^\sDfMIliPݬcwċM'@@k")9)%O20& uH>2MsҾ	8ɯc7`oqa*ׅi{'`\> ϻ%oXT_Ǫtqt[:!(_kfs3ba|w+`c@xR˹n^Ss|p^bmIYȐ5Aޱ3|:|&:KQws{qcvT)1!2Z\z0No	X2ж"=>}g)m:Y;"rBd9g\Ap3R;}dJ趴c9B1@<b㩬ؖ24Y9G,^WzL7*|L&i WDؓO8JBul+h
C{@´*Դk\A)Prc84eZ+HDvX#(h+5i ǉ)`Rb"ET)MO}EI>$IB\H[W|yg4WEtB>ih
g|ѣ-=e;_q.Ǎ0<L[:_(cP".c#	P
RSXNA-=H;
Nu!Ro,IJiBH[74RB)G/Zp4+D̵q&'St 6s{.^yp·YZ{^=~' g7"1~ғ&R~:>43rS]3SZ;@L}mn]%|Xj\~LqbQ.:ڈ_sЅ?c=}a/^K(nJf/!]o>;D/b!.`Î`Y㇘k$`nc]礬<-e-a/:0&C[ɸZ[*ChU
f/\Z1ϴ3RӴE=]Xsry7'c>@)ϩn0Ij*q%Aä+$0{	o}z0åt{0cXzY<lрTQCKۓ6]|z0n51؁ODc8)?i餦0m?T 5sNʧaf\RcRۛa%tyKGc3F´n<'D{ܬsQO)q]G_.za.6Qz_chFcɭ4IY<)xzGU*8c?e-3Ÿcpx6|y)!CyMJ2gCp>0؉I'|K?q#Ri|n\8lox$s漢=NϸUO\{NK$gk],v_97](c+D+
@spjfv$:{l6틲]&L6E>\엲^R{6Gi%j8	<I󧤏nJLR{~.
:P/;'[ba=vVd鬠=|t.h{tVMPtWpz{`e=hc6g>ߨP($uaZ\IY><>kؽw'OVPt[9A9zP7>ˇDD7Aｊsҵ3ߤQZ,#>ϑ\5	.q@F#ɀG'(el|bOB}=4֜7'5ݹ%zX ).| LtE[Sվ#Z(.ߏ}+ӟWln-ruѳq}>xҎ?EуuVB`//-sĈeH /1
"8ʲ#ȞQ8
Ê5HիM$1ە!B>w}\+qʃVI菻(WLD9\WɛыuRNJ,"1$z_}kHC&֡ùSz,et8tN8,z<]&bHOPfr0Qe]lH\u|ឿEmƚG h,EyC6yM).(|S+tn3vd#Nhl>2C::*܀,`@Z
3O\FAQW<Q:zDY~V~FWޅjޭ]Mfm?|МXEjgF?{O Y.oo=x=}d{oH.GtÕo^0'}!QR2ܹsG)D\\A߮A~[~ 䤖lk}ƻp.ȳ\IGpbۜ}.0f1pA>(	:h}ۥR{rH%ܦEӶ$oX˥DG7v<47e+GYvAYj"6fdX6'maK6w q Ӧi8h!w	c >qz?Z01jQH^䗶	`J۾am8+R ٱp8Q{s&N#N`wju5%X'.XD?y`zC	z&k昹u(dE^#Z_*e<u8^#lc,ܢZրv5$UnSwcx1DoڗOc,9x;[~<k ^<[qCgSbd,)EW~Х7$R!| 	Nc,E~rkax7[ig^ rۗ}EbsbIFA @li@`36<>ߣ/{6w=ߤ=~1vS)yC`FYJ7c!5}HQZa].skidG:?9e/7_U$iG_eWyN?dMfk$ּL<|#Q+ې"dQ o9PJ;Ү{pbh{r5vHKb ᝖~8CkcS^"F*ϯt?j|&29oe,\̾]{/BQ̥$ tI1M.&I3Hyd(TYmO"<0 ދ\oEI^D[H:NOoREpAoYJt^`vYg#[99䅺\cKE^=z0t@xjm#pXsw`	cthfo/Y`:mDGW\Ě^,s}#?WcD/Js)뜗R;k逭0Ǒ_%ڠlԭv|QVɌD}Q\;luTn/IʜP{|,o0P xCɏR<şh-rPaTؾMQ(tgP_ުp]Cd
rhH\Pk	G=E2aQj<PxVzc̊):@ tQ[4aJ.hm͢!'r6pMg"/7y zihyl+n@qF7pђ42|*^$aXiל@wOw{Q#HAb@眬/Dm(_;WSU^	E׺aqD8'N6dX#UV&hKƅ/et։rqoX/)?1|r=SGn`cL}.Fw*]^ w.Msy<BM
j̞s3P6?&YȻ=<"D^D\÷lfdK n;uwkLhF2X-c5Ȫ.jgyL[lɦ'UPekO!w'D8;..
^Rtlmq2&2PN-&[
'9Buj$և
İX(9|牍3!t!oV?wJE>`c9@Oi5wet#ipM1IҴ4/ܼ鵇|ggTd+85gpw bPDG R 	k0k8c_6"O	Uc@x>ùR6uSr:l:rF
VRJ*Ǵ$j0&1z	&Y6*X3# >p|ִ;.hGNŵࣃ{hn
{hmÀ=DE8ҵK,hږ6`VXb	tݶ'2B(uB+4>pŠI;P1,}{mx 0/ǒ kG)SfOva#~gr ̱KDF/yt]FDh j}離oIy4z&B7(n?q>*_tQe\e~'GteI;QMܱ#Cw=7g$C 1
 V#m|VC=B1a*V2We;#
746RSc˕KBQ:dXt]n=CgCwݵ,jClH: aCe<5wm#;r0mtϚ+}юSvd9;f@rh^	l.Eҩ˲u#݁WhZ+vޖe+%
T8SzH\O<L,ԛg6 v]RuUq
a3A̷K3'bGX]sNAi*s:~P-A7 wNol7a,*>{͗~/ls䜣D_}<̾^ a@+0y Mm<ܫ2}N2g?\Kb[r(o0ܶ39%/f0ȏI 1Mн(o['i($;զq N:)cY{M_±1Y.i _<&HYi@DdSQ뉢$픉d@9D8M]plPMEX&'<M|\rS{x=\ɊmypJnox`;{4+V|>D;Rt -'ux&St{/U鵶{wO|'<B&_1;CcÊ%:|W/3j@xA+z=h#s|Ny˄vyݺ>lxOl+e)'׼ಯ1=־'ۓ'3 j&1}. jd߾Z:B☿Bm$l\bp<Fkt߅G[>Nǅ~|7Ȕ-4}	o҇:VR@<#%3(lxˌ&M$
$<P7V(1 bZ؅^Y,c~uE[>줃Lm|74wf3ċ,7XKbM?1gnO ^V@sޫ?ٵ C)=Q_zBE	&u繂*oQ>"A=ꟾK~Ï Z	[֌lK,]N쇴Lt`uX5ǣ4 !x.\dޑи_[.Б :s1,L'.ܢ5ˢ]>/Ԯ\0Ӯ$LI\\&~"OKB{S{-&_&/EGsuXҧE-Em8f>d&zsGuqlqŗ>mnZRhg#8Z^sh~C.2Ҳ=1V@/	6V$`-5ao-6伜}cٟƮ97PVnjuH1w 3	J޿( mdcQCI{^#][?@A;Y"(nO=rʭ	;>)=7/~^B'{e
*8	96
;#Vxѿb%^WuӴl`-Zc5VGf{M,a,٣j" zq
xJhuSN#GQ3nZ\Oø"ĶI?~:>91|=+m@y<b"ٮ,3?!<洯p{+`ϗa1uoӶJVF夡+60fvZx08Aq`A{A{zA6p Q4?f!&[=ysUŐ54{$lS=c}L[⤎v> VM>06J]k-Φt)3:rPueSM(Fc>\GĬؓO1VkF!@.s_)E>A/?c%˗+.㸅}-\'SCT7o%sl{Í|c|dH/ijC%LyEH$D09PT*0coq+0N4NOx{T߄P2Ǽ@İ
)+8s0{xR[4KeTnpDiðmH«*/iXӀV8֬N1s K
Ҩ	S <i"U;JCfr3@K딍!<h~;5ӽ`cbQ͵xOqq{e8}2ϊ ڱǏvvmȯ6 ЮU>m2Ojc\	ͯcS1kP2l<%x3)yրK҆76O}RYJͺ+d8U	Dzc4nqYAS?tzV(x`<R="RcP+fz"Nbz碑ƪ|zm0O4aC<///t]	lrSv͞6XyJ{g=\m^u'lی*ڈe+Tȕ Dh^s;e.*ӻy9:V.
mjEoä}agL?Ǐ/3X{ TNraN>bPy!W	<q&"zoťCvJ@)qpOU:
Dz^`D'kj/ͯ5GPx Q"qomhpLژrawۊf\cΟ/q5q)ҚZ!1~f=eUk>[ y3<fЍ\yn:?%Z/)(yDƔ\y/7T=1C7 l^sԥ~QfK}q/ӟ/=[2 Zp:M`E0KK&X҈S@	ľC#:KCNyOC1s09O/=9V8[`'Ə|"C]c6cAKlpunι1e^>Ojz0yF3Xc9WO:GݯMg*609 7{4xa|$.Rv-fUv3M
Fj=砽 .!	,|:L*EΪ6hR!+<+sKtCep?«iu.>+YLg\ܿiG>\ˠ_Gep.|6\;е`dņȶWc\ǥyG]ªr^6w13U0֗z=W]OAUa/__ҏtR+(b3E12`6[IvZ7rs^c;~e+Plܦ))E
_*oJ&cmvyajW4,.I?Jҙw=T.նLcm,¡ُg-OB	e})0I;K>BνU)ƫ{31Sv^ >yyNpxH,bzPgȽo>K<yϵ>f!zQOsrջI[3"/>&;L #ꌼ"(-JB5Dt&7լmw:Bb)*E:ǗF;^T'C| ,?:BgAJQ࣬ vәBүX[sAm'ޔpPrcP$fƀp ULB,fPR$:aLΏ/ݎ@,0>kquB@p	>NX
b,)iI937~uh5'NUd g pJcq>F:z6	vyH*/?y?REkNW<<~$'jc_V+Ž`{MĖ($;TֱVC2yfI}؀"';6ѩd[|NZcafEz!SM}l)y6Su~"y j|lR|kw3BJ#<@덙߈yï2n'|}܆-s>uSښ9ğk$60*<~x![Q.};	U(>$9Q<sa|O=^403|sMW5R\mQlOp4LxǛdr}.:}趷ewBݳq/R@.Ŭ|PھÎL_,,#vS.P%矼B,|%=ޗ;F^''ե%vl<xS<ON$7vbm͚{ǗpQϩ>u|9~II;l_SbAX_C@XI%g.Iy.52h[rr|:<|LKژ.MYgt,U(<@eih*zio;yiXp45
y`mx\yvj݋;QdO ׆:
):WvI
r'ʝ@uxT*/`ݾ)7a0P_T)O3fTtt!EwG*}uFnw{-Tobfo(>5c gn)m'>0yb&λr$=IOg?,wP*I{=qK}8K@zmV;n)rRDn?sqr
J.*Dh&fˑkMOFCаgq*ѐu}L_`j^!?>939#^Z6~\kXGWۗߗێ켠Aj%wׇK5t{b4:8o4axp0t"Hj:"Fj@b䰔u*7y8a(;AAyѐy[33?vT81t]mt˟@7۠\g!Jh?m}G6G0n{1ħCָs</gWU份gw?BhA}P'aܹ0Š2*;y/	)vw.X+m, 	|}ĘJJs#E&:$M4l\ʘX'%|6/os!@WO
ǏnM6Uz<`r=gA
۟dųcqy+I]) Nk	(M}	RʮZjh,bmn,_Nc2v!`hC6lp:逦ˡ>IgnP7/P'ҏК@AL
M<t*UI5* _2E>V{:(, qzsfM>B1i=qg %ƌ4VrxVrTٮ~'вh5ʪ&xN`eBrjpz@}gvwVukwfJc%A;QcR0`ՀVrEQ|C>aIѿ[ׇ̼nȼ9&n~c{뭷0 IЙX?E=
`N%хPR@edŤ|UMS4]c[7A7>3}ph=QbOSd1[*njQ|Å[%|Cl34bfV*EoVbDH`eeԘ-j$g\|ʿ//y# >k~.9:wṵ	iR8}`z*X' -IQհZhh6\T
CO7)9yѐ+\pM+o0!~֑	I	ȷ^,Wu3Sx3&YnFoH~hަC
5Rnqު>zǃEVnnE..Gې#7(]*om0"I'^绊7Ui!Mڤo0+$?X#V_T?C>n3Q4)h@"ٶ6!K|%'0"LGԇh%cˋݻ]=a-ڤFIgc(Y6 `,^;`onC\^[c2a;}t Vm!ؠ]K
6V-o㠎4QxG=ʏRhߘQ|ߨ߸3_3/F	1ڡwtCVq944mE꜃RU_tdXG<b&Ad~	>*$I=ejOt7+;c42E_t?I-ܩ	(}&VNcӊǩdZNk[UN6	ƾ(>}>
AL9n*oxC@\NaIm:ž{@1.t<|G#؇)O2G6ç?-qnN{FW|ͥ|[LO(Q+{]LsW;O2J:tn~9B9v3lb2l#I=,j9X?@\ЩN|yjlǔօ-Aπv Ieo$2<rZKbF]vV$bU_ƚ1,xULxIajjJiFe+z֌IKv-1p[)O>]TxPC}ẕѕO<?~,wi 2!	>J1t:^e'1BY f=&_na%?]pcz }`#4|	a
qBA[`*́u<a2 R|b2pנ1f~0Qp^h:@	4tZh/mK>'2z*,q
LE#<W9p
s1Lsv6DMO>rQ<<al'&&p?w4QUAk３PHrј#ΤZ(Mɋt(@+sh<3!}G͚pߝ@dvp}Me+cu3LigX;hR sA'bZyL;&: a_	MO&uyT'LZtdU_PNv?@Z6Z+'l]RΔZn5tthjtqx&$8-OS14_+Gabf1B5rY{fNŘ@7x:v l*bUTxĸ>~c+zίBڑPbqSIr3fӜ9ȯ@Kr𧬨j^|"M&gCkNVS:"9/أM8YWDIۙq2s4gnwn)ˑ 8T->įʷv*E7VHQ(x 3kXKř_.2A&A$;BMcS$gvZm0kJ~\k<8UWz$u)so@1K%^Q\0.y|s9祢Әss"e}j-"p"%m̦% mHiT ʪ¶M3c2f6}0=ߞ~ItY379&F&pd9,!pBF.01r@W]P6]lpb 8q]bty˽V\-6PAY9([|qP~a}Tp^Hf>ms|zmq3`md1,0&h	'ƮhBA"3E~KeO<
J 7u̸dKϺƚk|K@h_K3O, ؉H9.^DaE1iӶM6.M2D+h~pu1*)pUs^C뚃&(`_̈́q;U>0hrd=\},8%~;9Q{0<Wϼh#e٫xgXVSY9\'}޽?m_t{_y@2ø'ՙ|{e
^ɳƠ ]%׌?HPj&Z%ש~qR}:G/8yWPr(_΁'6z6q^#3r25jOEw$8q\R È^{6kd蝶nK6|}}Xg*݄cKWc4ι5G	i76=^v}QdJBձڐ&pqy)u_򐎯)tA?-)s8Ϡ?JK<^ӘP
plػr>Z'u#Z5/uϴ': U<`aIM@>gҥB$:JLA Q!Į2 O '=c:^q)u9Fk22-׫.(g.}
SwǔF9.⁁'|}=>Is΍Q~"7H3[ 1h;$/;S6=pLC'k+`A%X`ѭ`'1Bصpa+/^e{~΃1"-|̏BbEp^sDL4](pAj1m '|VH~`hdse}ÔDOlz~f8Ϟ#7gxSAz) NcE`M[tFE@m-9AYlTV]IVp)Js77VlLЯzd](h.paǍXp lE>h'ښX)%,vew3߬iSƦMe墯TI:kV/8arӦm1_]BI×{8Â	h9Me$6SLmWI*O;y.^Dօق^ y&_\exm_VB8
^F;fN[cݹsp'oъF<Y6"4~	ycn0yw0#Y*~/<]XU|-G/*qT11g{䊇^j}qzn56yxrء7Pd@ ȉy]/3.Gթ(}ʧ'-|G͋_;n_>\{pD)6H<SG6HZXik:%3/i+S\:4mK퍋6Xľ&`YEl.{u:)ZHq.}&dG17?Y93tPΞCn҅(M9s]W>֡[lLbW(}|xUu}C3.79M{~dC+'(dM7ȐZZ9cLdz%1`/6jƈry{]mѓ;7|ib-bs^PG8p뀻ЀL!V<2GR<\;h5]/PhO9sv3G_/l7<`*wc佷9\ۍPߙ'VH_Ȝﮥr*L܌2'7//pcb"ycbaUn~g}WAEos*R2{X؊>`>y~$~"+Dj@^ciΧ/}b:lIƾڌXz]y^/|_cogu1Q03\UW4}x
HYעpZv+7;o_p>R[Fc/Q|%1'mǼ˃;m~Y{*A{oZĵ
Yu,>
ej<.P?^X3x@i?7'yyqF}slk<FzW    IENDB`>/5x   PNG

   IHDR       `   	pHYs       tEXtSoftware Snipaste]    IDATx%7& "wd&"SU5խ1F3dW4ҏ%u&d7gr=f&Ex   W_=iO{Ӟ=A?/a  Mܜe` ߙaշNyԿt烲14q9@ F7qwOp{"~bϴ=iO{rCr)ٺŗu?,ƨuU;׻@N&Q]!݅|@#wܹ0w~֢eBDǭwauzS#`9đtDD,t93i~Y?D]:gW%P{ӏHvi<K|IFkk\/c=GQz)<g@Oa4`atqBQ-ְB^jKkw Iblْ"6j 0[ @FDy:~|Ɛ `zxCp܌~O{R%&r{ݝ0jprnտb3s҉lX$A42Xk\s)?(t=̛z$w{~Ӧ~<gK?DGNu,!B-mڴ1̱TXC/$b}MR쵋qñH%`vaa)l[+k`m	Dd:VB@fDA`Q8Œ$k	<Dm8xh,! XGx$ 0" Vvo[iO?gE[yQ&AzdFD)$ƚV#`k#RmC$J3TzvnBB@޿vӦclO{	$a4*w[ag}	~yŀFP肙{PG5qYŽmnT 4b[;F7pJo@D  !&YZ[p6{`- !׶&CmOm640ꛗ`  B)mRVyh~|>@]}C+@sZ D7חzsUPIeA"JJ5'i	c\|yX෧=iO{Qi(Aj]0,[<Lܺ|ltΪ	Eƚ:׆C}tݺ(7GFV-Ec'8\G^UQ~9 P7-LU2BZp`"Տ Iԧ6et-B)Q{n| GOm<̽QZ>+x琈j
l]|KW@ 7DbgЖ^=3".ϯ߼)\RfJJ	,
A(eIZB$J⋯Wk30wY0h}qeK[}]`?=飠;CNEslk5pYwL=Ԧ䌠RŅ.v~]*+!<T݅٨]ܞn5l|I \@`=3AQS"~؇3&1@Y n- TE[|lisJC8+:H:v=3 d d?ђx&<me\P(4.I4kPa_ּF>kޞez?Q iRj+̕60QFY Ȣ/_4ꓓCE\ 	/N?dO®	֟w姸Nn6r?hO{Ӟ!(&3hJWr"_NvH}	 lgnՇiv5-ڸ1@keH.	u0bE$8g߅sZ}qoWy
wC=ݗ0z_;!k\!qx}C&wo:72
Tjy+	X'ZjYN)%T2̗W׏N޼yXBDHBAH&~`צ8èlGm[w`[y=iOݲM5A4*]}PQ0kL7$D@|>Zxx3{nޏ={z4(-(" k2qΒ@ko$S b0V;6[E_.i.zb%P=ݗBzuhNhx*DsG^>_qf	g_u&ܝc[d{###r<IZܬj6"(` $_e%HHRI	
 !"Č#76IA.srpӞ=~__[doKYQ0b/ljݛ H"cc%?؈={ `͇,w8_w솜@{C  Tn+N(,"Y#$- ֎aH	K
R RP}{@=qρaÃ`7*`a|^ֻ`! ` dpAH/4%L\DL#B`4=8vu{ͺ $i
A\UZ |~~9VE)Xk-BkuB)BdYeH*"!$aتZٲ"Wtݫ>$@aiO?)EcG1D1kMxQl_TW_~`a}p.݋[_U5B Z?sIֻGn>Z҅Fܺ;7뮮lpuZ`jjߤYnLl;2B{5/g@wb㩭|D]>Dc^z=5@T0iV{DiHNgDDxW[\Ȯ#N]#{a| @VQkMFo޾z\W.KABJ$VRVeZfZxʥV֋-$!B)D
$
	n= 5zA׋>\?}_E؞~ #=gH(eM/ @Q$uy۾vpW isa䵀;կxTGԚs}FӔ'3p	H-vɫg'1NɺQ۸o{[;)vqSkCf@H
25N@10}^ؑQd%8 ~*!L4P$GWs"xϰsݍygz''	r05ǧek,vF$J!ee/t4"frN hQ wV[ƚZ[{
$,DBJ!
AB$H
"ȭW=H?^Խ$;;~O{&)I c.+@4w5t&DCE5}}ޫHp z<OwTAtZ;y'bU!njĉ8aM5G81ݧs88e׍(wYP /]EIlI  Pt/;K vfHwД،^5?x'?O$UaIw,D?Kx@`UU2Qdv(u}<$$)%uqqu _$Y煒ʠ)!h2M#f@
m˪,UYeHdqA  HU) 

!A2[vcѥc/"~GMt+=iO{zO4bB@[?]%330[u{eZ6+T(_ữp/jRI 87^8H>lp
[v>*ZV鐴֏Gݑ1'M4} 9#"Z ߥO6mⰡN8hxAk-;4>π@h`>vzC~~dSAcȀ+B"Fo[I5@8oƢ4CU-{@a$&n"2֘RXyUUz2OcF 2EOW/YkD!|u[EHPR,J̺WzDt~pxpxx0?B*I$T8mX[Ve vrHI2"D""$(b0T6u]|__sV<wW2NrO{ӟ+!P;ӯ9䲫nTÉwۀbNS8:6 |医mc4?mY:$0B&$ز.ݬ΍ת~BA2 ԯ`bw F\::?mTĦs/mE7z 0ߡ4u4Ŷ	±W׍~[Df&
-5<T_Fy'0 qɡZt7)dѨp=O:u/6|3W&KC3Zzw8uQUTe^T4ꪪ>::PgLذ2JdY:') !
2I кkd&"RIB΋W/L&gRdb-	h,2ϵDB HJ)THQBJ$\B!xAsoy[0
8i '5nͬ.VpY+#\`4JB-Yڬlj+dbmҏ/9DL _: :lzrMi7!;3N  &vݶ.m\H5Ce8Sp:G~X{|D{jX?v$]c )ria|͇T_ur]7M,3ї;T}t$HmS`^ȡ7+χO#򢪢" &ڨBl#B/HXkhI 4RRq||$,-?m
)R&*I4)KJ
JI@' ́|m6Z'*ǧǇQF\UZWUY VZD
)HT!HdD!<ƹ%HJTBHDn-iP(ǱaxE6>e~SǛ?,HqѶ4*Cm>OloX!L6ĵcS~F;hC\?$фpP_Nnn㯳ddg
H<k|w;ÃM*Doƶѝ;a:V-#n$fg23  H^UmTV'%"F[ v]%g
S^&.ݮb^y⛃"z~6ȱҽO@;[$Z7|2F9	QV-! Z ِxE*!pPo/.oG^z͍6V""`^<~ϧY"Օ*_TLͫϟ7}\	v0Ud.Q*dcAdͫZm*J!i2Fj4*J	I `4cl-jm)u	qN+p0CN,K}Wt'*i<{'B-]|SNg[W~'un9ćǮ{ӞvGG4-6>UkEuvjp;`&Ѓ[j+][@̖%@)u`'`lhmg2FAR:dmK{P2r6&_2BRpàE@Dn7Yw;"QІVvw KpRbkVܛbg<bmf[ Zog7o!ۛ!$0_bp>"$RIHHX""! H
!	_xq-ӓ'U˼(*˲j\.|[骪qktWMZ&'W
ƳJS*_րHsβ4qK,[[Y{]U75P2Q*M2I2dI"Eml-X=3ֶ#|E$n!_=eof}[a/<'cv
nⰃ	⃡754խtVobm=Ӟ~qC%C[KE,1$bu+S4
`svEP⥧sqv9}aVcQ67E \K3"3*&Gk+DOa~?x Vw%d dD0&coC$ A@1L~NTMeda)Ӄ{b3+Z-<6QN xGY;ҎM"~:fA	kLYEQUmU*9??$NNNNJ$MR"H0uYA7_wثd2Nx22TcLjZ-Vb`%R%Yfޜ?cfo^-Fqtr&) dEaGǘaa"h)H$lFIB
AH#DD->q=,#j殽c2ܝ?evaon/v?E.EǡE{Be#Њ57 Wk҃p8'čUo:m{Wevo:Nv1,FѳU+XUw"VZ¸Th춊:c;G<J!@Ƣtgb5U^e׿V;0M@M(#<d,22\6ߔp lU;%}./|&` V8wPUqvы}ŝYX܌Զ,.5|l#𝶋  LWUQkS"i62ƾxOt</_E2NǓdHO&|BHDZk5XX/˗FQ6}O?y|pp8Ɠ'ggB%״TUV+c*_oo^|bZ/nx<Fq$I6GYq"G(UԶE!"	
a1Vkm|祵|$H)edMF$4S*;|o',5-q@``2#anZ|״A>0;@DC#lp`oݱ?=0?O6Wnbs0_f{JӞm]D.!ql6W=?lV6+] +B 82l<jAS0rpkߺ;(G`;.{qv]S7m{;zGYԿ0s0F!x~!`17&}iZvk56Xu 'mBh歽Y #wo7\-nC;-ʬ/FWepUUj\::>>::B,nojo޾'ghdlvv|xx|:FY:N$ND ?7Wju\]k]Jkc(IJ4UJ,'LIRR)	%	R|l3z2cmؘ|y[H,ifiBHGG,IX` mSIXmZ6zY^$I )J4IE
%I\NgvQ.5rD    IDATؕŽĒ(݂IH#7g^WBM]c,v]aI]T	/80P#+ǰuP[	G`􋚽(tXw~Q=7Il ڭ$N|_PpӞ>5FA+.-fn$'>kmͅ  ,m0

!P6.GFb!vPO4a[RR>-6EW( :"(B&pᣪ0>{ `ק\B'콨qeDChGT1Ѱoߢ8Q~.#p(N7D[C3,-[$RZ,7EO',3Ui.rqs}[W RmXJ1}rtt4&Y6&t:~/>Ӳ*nnWr^.<_E|*)4R&IfY
R	wRjΗU\UFH$x "(TJ 1(,[[DN|Ka
de	֚
 (d.;@J$Q#(z-dG?N,_ˀ-<H#DQ{OÖ5r1ƕfGjg[yanwӉh,b}AILQhm
+逊!]AvlZN;=iO$-`M"su_46F*;3[MaXK;v~0ői=^ޏ
@9A;C;nX]ծq{h?$s +܆ T'+?Ojuπjw=۲b	j"?`FBBzN8j;-R+<cnW5Q~˥h\Xj@ !TyZ.WEUU(MdUrUVeYk4./V!$IT6NNNNONOl.D" ֥ѺXc,qDP$rʬV'$V7Jkffc&B 	aefx5ڔ2ȶkEUeiu
%#X D4Zk	!1VJidR)&gsP#[03(#[rvF1Hka@'Û;852!TZk6cxflamav_0()\[@Z[hu6 smC$GcQυۭ"ޢ",M@ٶ=ircӢa׾jr=;q`(!aPeJekel̠yڔK1q4EzzvnkVPo
lR yU2d@@k
u$(vyR+g J4C|87Q⌾;]h`b|xa}ɪNǊܛ$z1
ǐ5q?J vy!74_::/V[S@,eX!MƳŢ4v\,noKs&$F㣓4M|WWld<>8>}'_|ٗ_|NNH,Qx1lQhS16eU"!ZD5%*A6P>*FI:dY,˒ %ID
o_sUl6~e6g Xkt5Lh4NIdt<(KWEYbw"LD
(5J3$mD$c!-00Q3ZƘJWBXr] Tw.2X	z#	ר-qG񴪣QXhEl^`BW,&5#rk#1~tsӿ2w.zhZP`SXi=Tx>L<"kkEM/(oȌ\s
:iA=krK4n	 @ޜxwZ`ApXߝ\'f?!" J: ZXѥ?|byRc	y.Ik^:`˶1y^
vԉjXikj.jgzU-.vXmc@m~cv] #ռ^3!\/.i 0UEQ0s5 $%"f@!MU,I<J~7_x:4Mt<QeUUUEYVErIϾﭵu^eUDDBYSic4='O<zDHetUiN{sq^V7V''ڌ&,7x˿5`6( VO>˿QQq4)Km6/Ju;I)oP
!UZXR[[#_w= q6Y+]k)}w?9:/Cu-Yz=^3glSН伈up DDoL	ƺ -fOыZ_ekccc;}k]Ǩ{\gLlq^]3N;χӞ4D;γ#iB˗zQ(ki\qAϚmy"lw@֕쇐AՍ0վٝ==|$fWv6J-ZvmyhJ
}MtCx5ѕ+ݩr]=8$ª,uQ  Dl9W,R8+EQyYlmUi%R2cI|41k!)X.糹o߼9=>l>gQl(DI*"6 \\|\`.3Qli<G#c/nkdiRRY	AJ89t6?II Rf=z駟I8/|m,#|\땒
$RkD)uYT@$ک= X)bTcl-!K<!Mɹ]C˛Q[D[=ըu]`o4^_k:F쵍<9ols0oyڥG.a wwoW=utB)L|ܻygF+	EZY8jbÂkXVLV"whM_q֍,uI8pCUhx^g2 @rn?`Oψ/7ԔZY ﯻ&|h+kbC_PxUXÚ,H_wIDZ̒+cVu^ 8\VyQh6Vk$Z-!4Z[]l-kc$a|~p0Od$Owi$*IƓ|:<:=9>LƓl<!F3'O>?edT"K,_]i3|ɣd:edD\i}jqs\,&铧"'|vx8׿몪ʢue(+ `$?@/WDH鶫1D`fw.3;oa$77ӓc%%0 mqxrvrMgHd\dmA6vm( h[}sVqA;20Ul'ԁ`6MA-q,6!.)0]ݶ|<1*ћan 8]S{=]i5k/Auj.msAa\`+b7,j_]SI  oz+y3gall 	N$oA ~)	-3;efM=@X/^hm}M<_6`f ׾|h.hmc;L6~'N6'Ja#	Q+fE$3jZUZO'!z],Jm,sQ̶T,QJ*_ϓ$B$id#aKFkcd>N'!Z]]]\,ً4h2N瓣L7㧿?Z4]/nWd2v&oȝYO|_E8<>d>?O <M\\_Wtf DZ0їś_>%Dk?OX )fLt2zu2ΎONNNOOҦfD^VI$ yXV5wnR
3u$txPZ[읳icmU`KS!uֈ:/# Ҏo {u!B=ZB&FFCuB BjBv{i:q5V=ϖzu
{bv؝- D9lnWZNA~nq[af[nq3QSQU5 - Qs||kՎj:ni_Pdw$F-޶sdп`fH]l6Tj.a,S,nՒڸ45]u+8N,s:sc\U*	$Il"pR%I6J¥?	$UQ(Frۥl-Ж*׫drtt|d:;8:뗗<?r-j7|. x6'tӳra]o7_x4Nl:MU2	.uY"	 r;XcR["B>ggs"21&傈YH9Sl6gF||2|RJ˼Xeyxp0+֚S{,g4~-nzz$Eat
\;/f٢Ҧ )nn?A0ZOu/e7
l?÷xhbզՔ;\~W؀~lĞo:==4^*{|-DS>DzNчX6G-wWZJ.0(I9~x5uS =nƁ*4+lQcDt׵vX4XC5IܞpW#P3:[q_0!7e"jߛZ- 1|{{9[ WE d>c|uU5lmYUш<*4R.BWUz(ɲ,DI @$dH:_Y !1 nV+":<8XQ6eJf|$^<nA*߾y}{s}0>z_?zψ/_zyY]]/ood:l<ei4Ie^JF"@I u=0fӃl(euU7U3ZWZk(MUUYg"KdASj>?8:<LҴ5#ug{
j9)n64,n'OmP6W+yIw _[ǤFe5@kN[Am|š'?,9iN}Y5J}}sBȠsƬkmeoNnxm?־"okoքhpƱzX:$kwvZ=ڥh %X_֢ FȀ֟a-ذG>!Q{& KArKـۃvx3o:f[a`	xn`H!Myt]zXYoӜW6܄uM;\K`vz4!=ZWr]TP`-*/b<Ɠu2_33Z˦2U$`fb*ʪ*k;	I4'ih  H4x-[5 (!2%R5",Q߼zX,^\|O./^?/B%_E~}uy{s}RJ%駏~/~WjZ]_^|ﾯj<͏NӓGRGӣӧ_[c*DLF%D"["1[ctMUUyQhS;Iodg?{EgǇ7oNOox4%z(_kHuƗlٯo<	XS		Cn]q ~R$,y-cE.+A޴=T6qp#eh:gxW=ɉm!`^MjHݭͭ 6xq!\V.qc-ipp?~|=)Uhn)l.{}iOQMcn[>!ߙ4Dmoӓß} ^(6*DuΑve6"IAmR"%oa<FHg7~>Zˣ w=/:Hr St60s)YAD̶Z/u*(K VRUbJV!MheYi HTHiMUkSUM?"L%H0fD, kѕ6d.$R	"і!GG2I׫zNW7o}ϯ/߮V4akޞ!|H|Z.n	y$I|ѓOXٳo	@H<xy>υyYM(t$*I~]`D"i2 "\jqjy{c^yŋ/_۳t_[ )fAtZ_jc*m4_'-dv:MP@% $20[ د7^t)0Ry	D`-[V#
)E*ږ,>b8'adGܟ1J5D~~eZ7qU5j3i`>@[k>70N<QPmWqgXMz˂Cɍۙm 	6.ݼ !u@W?Zh['G-rQ,,l3^8](fdy=gr>;=8x?˄P_Q`@A܀zܢJ(?[sk?:6;?ru:R.r"{cB`Z߾;cïh7[BZ$5W`[A ژ
rqkF,׫DdbF̕Y%I΋RkFT*!!ʢn$r[R ABYFkw^<E-2"	$	آ*1It4afS*/ϟ}rȋFJ%*P.eY%܌*` I"Iͦ,Kv\.jE^ a6$h4E)1"w5),-sYaZ7B[Hg'GlM:ʤO?^2I/_.reʲehlE~5	H$h6I)IHRB*)@@H"_6_͵R)XWi J%IEP~Y9u/(AAݩ]6=p`hk5_f/VZ w7Ei4 1`ۭC(ka?]#E|9
PE7lH$qI>Zv&3|=}th@f}<Vyfmn7|	cqpFc<,ʛp(,:u(-޵[^.u,Qw/*7\c8ɫ    IDATmv5@B]Sa1~xXkD(w%ƝucTڢu8Y42/z*
hGٺ  fB[7oVe	̒(Lt:/h4Z.e]TnMc 0ze& @$$0@J
!eu1|P	F2LEQ*)T 	S"kgeb˲Z-DLJUUz\	!nWѕ Fr1L7odNd:N營hc<W˗^x'~/fye9/
+` (K ] Y˗nˋeQfs"J
,'O>}#]uoK?,+k `k?w'Gŧ%euu	%L J)$eJ!QC솤̄AJZ-?}~'O&7/لMU 3	eǟ~ƍ ̼8װ4n~I"N`F$[VK;z0TVkM󑫮
< .oOD,XC_En4n}~CnYzi깧= 756c5"CXP|oT'޷!ϩ5:. #@SDA{@ላY&釤w:jpyA]":4`{݇z	!.?QS"T6BCnw;qLnѦ%8Զq~jA}&c.~:Mj;?pr,hkِ %@[ՋgoK^.˼,瓉̬Jh]T^^W'Q5[gӱBI9ʒB!hono(;::BD"!B$BN@!.j]m>ۇA[)he6>+VY[JBktU*AI*M%0heZV
)M&gtfɋhg)">999:> dՋ Tҝ!L4 V+Y,./W^\.˪ޞKa:޾yg/^0L:xzrtrt ^,V(O~ϦSUF35I scƲEDJ&Yh6O&h"ق4QGl]\x)"
ӞzNR=d6ED LL.KDA3ے\Vϕk(-yXKDtAB[3Mnr	V%d{ZP;Zז ䷚29o]MX= a-&CK	S3ǏOPҳځۇ;9Z3ԇ^كsQ#4b#@ꪽ@zCz֢<᪷DrhG6i~߰#<&ms=xGoFmFtd[;5$kF>kAjW{#cx0D[uOvd&'AXW3Bۀ_py}KV^5g|ĖY+mbfHR,yW/^>ooor8=;8cexǟ,"׿+mj|;!6,H.z-	5RJR
@ I b&R)|""	&ňlID1ƌ#`ְX$($#PJf)]x*ijWyR7EQH)Mڱe>s'\^,+ĀJ$I4giifTi$=zW*_(貲VkCgUU}7Z)y""	Ü*Hi4٣Juʗr\UeMckhsQd4td`kY.Zd(M3JiQߟ={t~$\.o&ɑx[zr	3:3A鮶9v$#bR
aؖLV[1s0w>s@j}Z~͚= 1*ȞPS3NtoE7OE@V۷<xG.υ6>j˵2(WA6Mv-{3;GNBG">߲G	-N@KTy̾44nZ~-m_wp["/@wSv0y%͡ϩk=ktzb}'DǸ5C vOPh$*tuyβ[eyy1Z X,o_|(_s7o߼9~ *KSmlTJHX p@ (F 9h-Djc*cI%m1Z5,-*]iuU9\hJa$$R$!cl-"fi
U-}+b4}/Wd\i}}u'RPYy.4[ dQiQuN!"	Jh4ǣxlX%H`-Zf\UI۫4M\6.K[UZW6D"KU$4~_EXUYe^v߿~<KT\.y4N	X SUFׯ',-3%3Ir}}ʗ,onN}2r˯~)7bיƭaۜ^~[@-?uץکx@ؠ<|d-.>?ێV0飬A87ì5߯zwt	Tm݇Xzy_=uhp> 8K	uы֢Vk53nG> h۠g~4I<13#ʬbCj0Yi1 
zГ/w؝3MUU]Uq;2+N_FxxxxxΗC_OP/T9|MCTUM#6z	.7x0K]7l9y*u߶YГu
f\y~ M	vN2?{ެ*9XWEQCe۷7n69G8ʒ4w^.3HuǏ/4+: ˲4Dd"hQ4ω,"6y"3`	{A  QQc P:H55cu&IRVuh`CIChEcX$Y >{ǟf4U
cT\泋beQ~t
 l^׫պ,a8ƥ&t2&d:'yq'^.]1d:(1pXW^.E0XkųɒR ӣs߽pXu0$oo{ܽwzhY~WN}#`U՗>b<ޛN:glrrxz*KeAk4؛{n_W*zAЪLi-la<󗤡{
(J ;w ڦ+nˁ43:Y*_~ׄ~ggI`84àLOsC!^ zm%`wSlak pNްm+ۼB[[(ݖM7\˃@L0QށR C׃W]9A6
m(^SM~2__rw
-hڋ^nĦ)ډnu?z=zwdA'
h Ｊ5Oh@ǩQ_G?z;Nny/ϟ!1UEY.EeIbYT2"oP#PWeDlD֋h]eUB([1I6,Y PhPb]W*;g(jP3 @*Qn;3T!Qf!cd" M
7Ȑ&Yˡ0:rN0
T$q2s^ȗht|rrrr'ɻdVU-\K1*򲊗>ׇ1'Qne䍻糋Ǐu|kΘz.Z*'瓣 1H FI&
''PU"mfĻ$;K±(r9?GaB᧳eZ	GǓ%&I*jh&`	ؤhpx:_O _vx_؏W-{Vh h˘Ҿn1v}ڌy:Aߗ8׶K@~!7Z0ݾw2;0̣ÊYaUhF{|MjCޞGIŶRV_hv\Ek뵖_:5AfƯ9X?G|FnA6}.5_WN;F;G6|v:m@g;i;nhBݵ~okw9ݽiFA~PcKvnHl/sdpMLty; UcH%>}v>gg_w0^b-%hz^:Ij:2(+U C1Uy^6^$if6_""ZCQ)kU1h-!u£(購)=1i"	UX8sd9; Z-tax "`$AXb1_/xrtcUQ!!
@(O2y>;e93URTD55j
 !yX:cȖK(1ZCuUhS菕K%jlB4Ej$<ٓ/c]-w}{}?>ƣjb$͒[""b&C@DVӄWUpܨK/Pu{\uڊqaݼޞM%pCoʆ_aGWW?v+g]=+7sEɝEm~[jրh[j
ὢv=?XwE	9>gkW7v?8;dx7*^#9`H_!-^nFq]6#uв-]W|^drǁ{evBTYZ̋'O_޾s鳧^,aLP4Vb^u<yz^Ou@XU+(T:l]UkC5U-"%NQc]h`ުbSQlIrQȨr"b(7܁@!D1 ցE]UZgr]98AD4@#3*grxdK{ONo'uVEsXPl6޾Sz}1_/.g!Ԅ$>rcl-YUU{߱!jXVrX,fUU-b!YGd<i@q$\/Iǫ:q9cTD d|14Duo}޻urUi8R4uI#2H;fo3:=w_UFL7+ndhIo|u:Ӧ@}~[2EС^)\튀er~.j\{uݹ=G?Żk`^:`6f5r}	?/:	ۯh^KG7 \P:aL`'6(!vzM76vvۺ]vR]u85nu$/f s;ԐزmPjg_Ao
=$Gf? ×(=_@B;m-g֞ ăA&@7A{LZT6XCty
\GGXΓğݾoߺoR3$y>LFy~I>8?/<E!zU "@HDd ό9$'֐s.I|eӣdӜG	±4F6e SoSgP%F**T"7:͌A$Qڸ"Gj]/[s_0.A루*{tt¬
Q,PcL}Q/fߥI>Gt29=9uzv|lh:OF*WPW!udQ-jZr1]>{v~q9[,Zb[Yr);WݻˋgEQ,Wk @]Qb@򖼳.Ij8vUU̱dl, bvw7ˋ>Ooƃd҈¼a^]Zc1ι<|[Z'""2phoioxzg}vݒe_|?qBξqRk7IsF!m~yjs"iIȎ$ ^nΥyJC{#¶x.~RuV~ajM}bspf7w<\%f"i4VhW_em~!A P=q6 HW﫣^U{վuv1ߝ>t;]u,8-#~בg'FaR=pRZzώeآktHQw=w_JirsҪjyDH7n7 f^}?/	?O|;j?f6i"rr9xu5 2z^W*lZ1&rkd
d=Kۯ 0Hh2Wu=_,4>IG+jlDk(*45U(몮C1s}D \% dH!Fc\(Zc- X
Hјcꚅf Tz\+C]Wg?>Idh<iu'8A% ,ω0sᣇ}GYоV"wG)<,BoXkLY,Zr齻wuUe9ǓI#H,ʳ?uG-Ƀ޹}v&$_YJ!ժ0nn;J|Ckk׈(BDofo}Popz1;ktKI֭qw*6qnZ)lz|QOt ;Ukg~<M_ufz?u p0j"I ڡ¾lô\Y;ev 7ΡAlnW}5!'iB~ePY7 ~Gk{cKhVJl0.xg2uܠ~?4{`ߒL&5,M-#:o І#f!]e>zۨvA]!UD^}KU4" }믝?GUfUxֺgOO8dV ]VuUE]Uxy|ǋbYWe]1*"FyoZcwb&NjWi<Oܱzg *""޹4qΚ( 
"#5&1L"
  HDEU$XUU;" `i7Dd4]g!M؄Rbc]*
P1r(u3r.>Gӣ#gs>I'1voZ!Rq&K(_M
kL^={    IDATѣϖ:,=yUVr5*PEY/iޅ$M8kjlHȑ4}$T%zLSёU"5f-	Y뜳,!!2~>Cj/)Dms;l#|!FkozOh-AxՐmY:7pN8%.&,ԭ7Z۱u7۴4Wޣ3}e-f4\֋*Ae|E/FנJDl+zLͩaIn34te@ P_*<l1dP @Xb`n-DvpxƴAW2C'F{x}wp{;΂<rm7! 

MtvA>)QQ5D"M";(="* A>_'U 5'Gob~w}?Ǐ%!j&wܮbqy
32'xr4N{;I@Uzq9VuP2 ډ fpQ,	yXuhFiYd P{k-nf56K<o1D*#! @Xo,溮A֠!Tg-Y$FQ?!{Q!
 7 "dXk(54*" ]}kmSsϥyے$ɜ%?sḘg~7M]~Ԫ,~}]UƘ:gE;90>zIey/*ϲyA!Pwn9>:jF,O}F&iTh9 4|BU,*r,q$M\%[ Cdn hpwca7[ mz;ACAn%/=[&.5% *5ʣ/Ouмk0NU՚{
ѩpF;7ݸִZġ~kOڜM0d7S֡NżgRSrM,50n;t˦2bJ6/mSȱICb'[mX\^nmW!?V:o^^NVy&
dC;_5"^]촆uB ku~caP2b!! b&yXX#f-l-WFEwSΎ}?[s{q
>%21dTt}(t]C[bhVQB]rMɘ4!bU DhK$56!@,(w"{w'}t:Ҥٝ;ws轟/zBm!s ,O,i,VX^<5A>M;w_Et.Wr\;k5Xxuڒfr8G"p\,EY48DQ❳>UTCd'pS 0XDdL "
Ϋ:UC,
ƣI&&ch1F lGd,YBcUT54H !k^#WeBg3$"k!tztdYVEQ|3(*J<#hO'$Uc'~}?x>jxg=:>{5}UWDsĢ*@Ut$TU`V4fK݃h%2\gՓύ1ɨ<M<gy6ɬ"6]Ccth?aofKf{n<7v&|	J`:͏-89tᆑ6n'0=Ku&}XApt2Z36uN6͕7]ǚ;ܫVoBq'q@-6i(}Vw96L`~~.$N_eWM[|/7n>]op#**MZrڼ|܆ۅCx62  0ǺZGfN
̡u)1c#QI6J4$͌K#ǡ^t=2Qu聭};	;rmwhHK4򴉖 @"9ZE$FcY5AcO(֫PW{Ab,*{@$DKD֧ޣM(O}bٓ>~g"cZ3ܹ ֘Ļǟ?꺩.Y!b[	(!6OHT.:xZ{|rVd:9jb1B`6hDbK*4:kX# QQΚ$M}+PdlfL0k`!ab'&&H:4B ԪUU
hl	$	ˈx #sUB !L4ϋ|Xea " r	45D޻4IsιjZ.'GGYBb>?RӣrZaT{7㬳de TD&cqEƒ=XN1TUf1JBұHd)ˢ,Cާ(RιcȒ֚VjiQvnmDۛZ`{O{-Tۡ5!pzGmVԃe_b޷Fa{d3}}th'fzf^<k  P[AF;XgwUTTvwk8Mz2Em^5_;wk8U|jC;7vηRkM^.=!4>*Wk b>U.*ǘ8|r4wGm8n޵I%mpo]{3{קv <6o
}K`mqJXW\  1B*UafJ  cU4Gh"]4DGY6ɼwos]K=>>2zs,eO	zQdΫ03y9( `u.a[l@bV1THG'Ǔ4r# \VuQeYIDB FE*E"f<r>ֶyfIjPVf"$2b*5DHMX 6p@E"7yEATY !j>u>2fY"@1DEBCHhL	Ѵ_ Hd}fnG U1r>H4Ec ǣѝۧE
u1GrgP;(ܽ;=~c@B2AΥi#3I iIcn*?66oEjQ(\zk\'Y>Q>j
oXK"4h+誗);wnmBdŤ}y @ x@ ޳u6'n;&h5l+s(EBbg47K=6fn9h}!JH,}֣ 5]gظn~$' l&D=>lAlҺ#
PqнssK&;=t8A}^EԘ[D!(6.\T@mGZ7ZyUGԒE<_/|ibɢ>~zBd= f\={t4ʣRD07>ZWl OטY:롆ו5dؾHt ;?!]!Ua p\/>XE5hЀ  $(plksQcXbI9'?rYWWu5OuE:/N'|Y%>%0T@@*A  c-) BU@D޻d2L<?Lx^6h^UV2VjZKk4i$Ku `6gYx 1 hYcYV	T>@\ΒcQɅu" *؆7H 9g
16jU*@ UAh7!Ym kL*И"+sl⌣(r"*˲(KPq!c7,OOoBݦ*uADgDdt:\V˥NbQbcYQ*[w=SVIM|< QU527x[Cd T8U 9"Cd[(0r~ӏ?̺eGeq|rb,
YeeQYӬgn$xwfk+m%bE|_L!tٶk l
qX@kj3_{'nW[.;.}`ѳSh.uVBx) ^odr#}5l~isn.ӫ^ N|ZਮiXE@`+nrW+G{|ЈOh]%+,;!YgXHZc/UYxcFY:hEZhIs]V?[gi626B7
FޏrC?5rzeT;k-w߯i	$~øMqC6X,M bUuY,g㺪BueѺFB *"E 5Q 8ǆ0b*ɘx/_43Xr^˓[{/3YUQZET5x"4	B  E-)")EY֐i>M|rd17Uc]u]"%H,˒#%IB.ɼE4d6heZ	6(R818[,43ʑ#@Ovy jR!i6+ TIl<uF1C-Uee@+0;!D}hxĈ
z,,,kGx2# ElSkmk111Q1D!LGޚ[.B3y6IDx16uo/g3PIH(O>;[.~}Rb6z|r:N"rZ,ޒs$MRSu&Dxᮝ0<ÿ~,:3x{?kia	8v ]ha#knUG0Y|5;fv]_F~sMٝWϧq7(#4_W
7r&VP90 a$9n_73˃A+=bm}!+xWb)r0ov7{D761N= UU3Io3RXVygiboe5y>>qΐHD
p`υe׻nv<^һ\_pJV	@h~][rrZrBccknɯ
D	YE,&1&hMD 1uʵOdzzvGHf.Vu]vWE]a=6kuAT@?VV `DKMҶ9"!""EU!: r\T)s6$g:o݈Eİ,bJ|4҄: 5#cDQsHꪪF'hfrp?{֭[{kr>82w1Lw΂j^40rT@Uij5B6sDh("]=k 0XkOF
/$I<#yu±c"3{k HԨB ;2Ygev䜳Y"$cF[G.IC928pE c:2T&VEb]k Te0/gϞ=/?|]4vttuU.,PYY	%p,%%I1DDHd-QDZ%Y
:5mzb ے~}l[l!>h&	o6=,eiGy`o" IpHgvɑ Zh7= ^a+!䁞؟`䰾FΙ7|,ͻs1ޫtsmwhTk2V@4$ދelHU;_A?]C$xʓ?L~\.(BQ6֕'ܾ{.fŪH4K8|䳱( a3^MdѠޣ pK-p6ѐ(-x/tv ` YΪcPuC$1 5OAY;`pUGkA.#PC$1X,?MTUZ%0GV0V&
fUA2F 49@Gι5D8!M,!EU&h8'ӑ`Dc`f8F<l'Ir>TbXoyfޑY+uhw&[cX*jRԬQ#HXB!5#n2DdoID8AYSVq.IȢeQ?;odY:3,""elbc4 `@E&4ƚ$Ʉ^`4kpu%|㊉" ghv?ӳӓSS@ʲ~w"G t1GE]$Q>}q;}կuykId4Nib!Xr^֑{$ɳ#Y`QaLBkHi'Zq-d[ \y
AH~M[deJ^a+n6UG	C09lRG඿ᅃΟ@9@:6~۱ǛLv#CK5C~7]wo#D*o&3-׎wUѰ_5mTs/J [U0Iϩ d@.4jtQv[	 x]("^D|V'J$ C}r||??[zY"V:udh4z,Q)Pvy#$ijX **_э"of:!{uKT㬕(`Q41b]l~xX! ( (B)*GcgĘDoVYV~ٺxxb{RU|<λպ,P!'x\\.l6;sci1U1岴6R?)tdbS]rdk&  (!4^v݅,2|<9ue9B}>:d8G e14ɳԧ''}OV*׆)yWek&G ιh痫eRO(Ź# (I3kBX3ay@ 0)
 Z@,Q|mꗎP*Vh"uZUU&fe,`U&QDX˜Ǔ^zZ,Ţ+aZk4/9Cq%Bc		|o̆(O\/˕(9OZCIe-_5U%'kv$s2FZV`̺&ǿ~_VXp?;GYkPbw/mc "f{eiM34jrV$lKh3sn^C⛢}E/eq6fqEښ7qnWӠMB?U@ U -n<ր[uJ&QW[qMi7ZEfT'؁x39Tj    IDAT*-7˩HqWD!0 ;`کE͘W8nw{Ks3h\SӾAqtivDT._%7o|pl[,7Jܭʜ=Fc:?f@c%d,c,F"'BXDV¬D&I^${:ʢpdKݹ_֦tێv3^.9e0;7o9/]vI?P2oh2mڞNH*^\&P# :q9,, H t{e @Hg'''3Gx2c˲P(i=zpZo,Md֨(s\>ii(KCf5;B4ZڮZQα	U f!PD$BҶ
T8uC=GqU]UiIԑj-i*$ɭ$MQX8UM 9k
k""jH,bբD!ϳy #"*jϗd<'ήV˺UD$0@[(y+BTUai$&VUm8{n ,D,ud}fHh1Vu-"y!FѶ*K58On(u(e 4FnV FF@'EUeU5i@!gmO'h2I1ƈHQDb\bjڦ UUe&wOKSu:o3͒w:ciEQMyy;IG"ꭝ.?yhѽ{YK>	!qu.
5U8yk1l':z-IOB^h+:L/6;8X·ie{XŊkފ?ls 3+tZu?:rm:n:(uؾ/*(v=^\Nψk
`0jw=(Rrj!lݤZdk?k1@{m)k7)l=&ܠN:ln/H>틚/i}{7z
f^ceZf3p/}I'"Fv>=:XBb%c0s]U}h&iN(Z 沎qmQ6꺦f˒4rK9vH
7׽Dڨ o60H/7;>!6r~/;GY ^*)XQ< u~4Y6su
)Y4DB*EQ~'|6]\Te. '14KGY:2,Xqy #'wY۪	!0sMke"CB*"̘e@D9"HYVr2:e5狥pŹOGM	(;wNBYpDh
	rD"uH[(m,+n:.5:]VqU*0\\N4I8,BE5pYTUͺl4*
1D5TfA4ؤ4MXe]WhWCEb,5+Qyg:$*b^Kܕ9l D&+)O8_?8gw>ɳkK|<n"!,MLd:_fϞ==hvyX׵
+@YE<IZ F@'׳,*DV899pgG 9h:}zZu],&[GkZn'gމd5Dɪ?lΐd+dvKq0(PcB:( vG.:] (CqՕxaf e(Y#[8+jknI'?`jyp/. `D{j|=K4N=B`moagua67R-i+P$ӷ^nϧV,ſ!좥M*yøKHxy(zض%s|8 0?E3ߛf痗fX% 8Z* D C Qg}Ymj  c\WX|4e;T(|=m4Ͻvx0־ʯ}*΀Ll~o;7	7Ƃpu-10 X}4_,Eze,Đ8U Qų»ٽ<I 1=y>O?"juqPePY"Z-gB!o%izC9$y (#h4+"5gHΎ$I Xc l6ʪzK2nܡRWeYU]uX̑9뜳ZbxXwΎFi*ʪr|1GG J2$11>~8Fu*54>r#gYg~<=in..!F&2*\W%</+eUȀxqy:bLGDֺ\FfU5wIED$6л#   0s#116Ġo0rH Pǘ%)2sYAX$6Dbfe15ukP96Ðk\Jd4g޺}v[_֮b>UYV믽;xgyk^szgｚ$I@U5$X"]͆/ <@NpDBN `	;MfWefP'FT#<TU۶p7777WOSUcf# YW5.D\%̈bLۧYqD{΅j5?yçb>/__TRί@U$1fJ[ҚdEb.JjO# r-m_`EnpֱIsz7w
qi}lӶlKG//@8IFAPb&ҭgWKo|NN\yVۑlmg޿65'
}Hkb)!Ks&q%;TŚt,ζӾ{ ѸVhAo~g} y-	^XN
m$kl(@X(g'jlz!2̂]r d)JYR[ّbD$2}{B""}lݘ"U
p.C_At-kqڰ>[Z7I"	5ժ*	.7"'OF $EV[cnꤙVRbl&$"<V+l\Xg/_=}3@VZolgvTtqq$XclWZ <ϳL u"ba:Eb1ڦ:z'IgZ+anm: 	,3J6FޡR
έ a2Ey|@ѻbx) ^->{}l4-/{WuUfZorӶM"5Pu40*2h4RZoj3{͌v!EQx%[a"$ۀ|1ꚲ@	I*p\sbq!8F(R"  1?B>xYsuU,1itM8b@U*
oFsi]g 裸|X=}t6&6ː0FыHi,tvpxpgZ+D"JDs)<	$чofybѨ@$aMhYmܘL+%!8kԿG߯Zfeȑ(J!R䈀0D\dGM{RRR*8U	!yOj.ÍBr[oP; ɾNWc7NIyvBw]xodymm8\{&פgo}jn]eEP 9;(</fצ.A zi<,OW=o*$i;&\Iw?;[֛@|s}~8YDd'zSqx74aD_E>Fhҵ@
CCc9((!ty|TEm;4HN o+c|x<6#JmyvUk+uگN]]Go}DfSyYFkp	"!EqP>( " GnO9$Ɨ˳iC;zG,ڶ]./=ˋ(
k<;:<.ݑJ)EQX)cL`ɳbDdlfI#N^/~2(ȭZڬWu6MbFQYEQ乵B@
&nڶm#)r:Oɬ)붩92MH)v>{"2^|uãì(MT91)M6D!6UA!xg9C\n "sJ#&ӈHA8}چX82s#ni9y'j*{03Ga	19eTʵGr8_/BHc"Dd<38\1Fu6 ikȼ^]&Ѹirer5M:}#H"e\)%"s!xQH@k&BJSbVVMUm^J)$Eb}մH+boݺutt\pkl}X7ue9.^`iB  Tǖ ,*"DB"m$7baI}uo7:,u3zshK|nt{:(S ޿[;O~wtD CC/8z>@ٻSn*7xi*[؇ݦ+a~;.ǁ!kw{Z/DIW۾8yV~Wh"	?v՜~X}+k`~άk>]ᚣlE !BH&`vz?ǋGr(x4
i}8q"H96F)BDBZ!2TQs4ZYcdzXFViB I:^#vWyhr{}(h]dyA_]"a۶?o'׭{޻spp`<CT O|g4;~պN̓ai(<!~|v1ZaSV ``
%*.B)m^]Sd z6!>ic0rYEfkI6Ňض.xG)(9Vj\bƤYi/^|t~qQ7]Y?@L]Vht2ͦ''Ƕ(Y)&ƺ&i^VUν{9WK׶S.='qm+̂Ĩ<6gw;99999<Ͳ,qr/i1$u9jcFQg&q61yfsDk QTw@bP%yT:1 =0&JR{|[lMۆȊ9GD!u,Z7M"jzZ_u d2'QY}Um妪bdct6Vm6(*˂ϟ?@mѽ;OoLﾧ fpεmX.ΚUDx:ňn&èmma5*JRQ990DHJkc6F+Bl_墮6Hkc&	]3o6x6_W^<??;TJ[<F$msFDb!8-)<tybHg|~sm&>(#{uQRc`W2X^(n);C[ܤ[MW\]eVkw-R/Va?A/ń=ޟr}VؓpI۟hJ*?Ѷ.^ߎz{٤w営a~7wK$""7`fv%{ޫ6/%":90)!)l( jIڵx $e&e18+ƹEfVu^|M&e>>2FS9nv-k,a V~ě[WBv5jxop\^,>?dyYM'ɨޅB00\+3y WYEVF)P>F[[ikcA>affkR:W R)*4#!JE*i@Vz'6bxGO<}^ok9F@Q<ʢѸ,jDOgA<16nMϗMC J_|˕69C4rMHe$3zq~8?"6(2/$@H ڦlfTVK0=:&}U8egq	srTy!$:aA`GBR #$';CvdSaʌXSdYDGօ6M6y^m]_^D$D+2c릪+dNFVY5F.4qZzMgt2XicpQ{mEcYgŧ}FDJ,H[oZ޽3L֫cphvtxhgIJAz/F9ιcfvmۺnjSMON&xg
kH8\,Vj6|F	0FRD:pţyd2YRʒ(,J[֦o@(1e )1q8@ߏz{߷WK]6&,[,7u-6=YO}.MgBC|Mf!G&P E=ط_T]n~WakA7"ovޜ=?pdKSg`wխ9]1CU[64WMתF>۫3}+^~;1}J+B7tn ] }a'έ*ry =/5(	kV嫗ϟ>}2+m|J"  [RV06v>isJۧ'EQ,7Y]c9::~<(U]q=0Zi<ˬƒш:2hfzRoB:MR:뷽Ѿ1KlA DD+gϞ?w͊z6sdvj\WMSI>5!1*c
wC	i  cD%(DĂYEX+5T%(9Ř1I H
7{a#sJIXy!¡˥L'"ujqqjɭl2ƣx<*2jE1(b	1bi۪7fiqmr	\pJ҂#&!*@R< E]rdjY-Eejȋ89}Qpp.zf_mbL/;+lԀ(̌SvH*J!ɣcH`au/غhe9F"* Ucy?}>hdd<TC)$%DHD̜ȱMx(t2L8E]1D]QH"	cH~DhETJfZ/6/cMgHJH+'V<ύFkkJ)Ha2v1̒*-2cPZ,Ѩ,XmmiQشr=ͦl:%$R"Dmۮ7jliXjъQiRYDQƎ
;*ȕɔZ1)J{#]6pNmlᲩfhY    IDATB B?2Xw]L;T'nT_r(w[ 3b";;I]DL?8^2koOz\	 2;S9CKOd8!nG "wi>K5j)ohtb9;o4]NZ:`[lKBE`?7pPDG("R_g/3uBtmlMU''fZ8*cr煱 %vu8{ïǠJD1Fȍ>}O#4ȵDYfYn"hr<"'׹`w&V[ⷭz{S?pO_ns'Rm~zScfqgzc۶f>K#)""REwHU71FEe612Rrd@AQ=S8DGZ@ "pdP"o@]2(DHp,(si EQZMūWZ+sfGw{h<O*"M dZ$eͲ:[ׅ5ͦ6Ml6uU7ut"`T;&[}S{פp2p%wUR\Y/`tVx<Fd<Ȭ}w>4.
'{ 6cb!2icM1 (}:+xd"="!y_S]B I,BHWYZ\J@ds9Eiz}mwCc)rt:)LZRZP8%>JkM]}u$h!Sl"Ç66],
hrdQVYkљFkPHYMդLnhM 5f\EcjڪnDp<s )T·9Y\Pn][UuUu]kc#3u85Z7G2ǣ2/GfƘf:+le!""$9q+wVb6DۮmxCj4wVϕoaλ`.>Iu_s]"1 vq.}epZ/}% [= _Cj7ԖvPZ=n{CxsD?k  pZ6:Bf 4Jx_[K*[ud=&֫+_R^x},@"U%.'蚟' b)b<L'ԃ.^=ˍs֋O5,d4v߹<|alzTf}ErXz`dGtѺunڼ<;oǨ.p6Mghlf(!F!
\e/gBcv+n7_? ;kfaFF^y* }mrqPf3.2ˋT$^Һ GFl\by֍ʞR 1% S	D H6"Y"0D HAuX{0+E1߯z~qY/^<::?G''Q)Eͺb]A*:_̟<}`:6a\kEDg(գ c$x}TˋbX/VW|O_=HCӴ>hM㳺@"`B$"E2c+U۶M]|dZtzx<-몞|GWgg[]4 *"CnaP
IÐ(YbSECAqNQH)B,	\p}UU{唂h*-MӆDDR{cM1u5/ʔ' >[5-!BH`8PԿ10d2,˿ռ,l4Vkbe1Df\Y|l6=<'eQy5"GMSu08.JVkE F鸜|kMj\Y>}8;<9*obX,Q/?_G~TU]V릮6U[^LO(2[dJƚDM&@C01f$.7PsI~^~u.sq(ŞثJ]:w+f+7ן5 6f-iROXom"ؿmt
 vI'vVņTP@ `|\SLw
O'.`q'3f9Cٛ׷k}oT)/Y)&I2^i pv-/%M~_OrA"H GM}_TG'r1 
?{G__=tbz>_nYEa`w!4M[zif::>!}߽8/geE1MgG'GGG[Ǒjs\VHDdmyeEEQDJX'έ% R\W?tAӭ oҖxџz{x06N_O<
=r U.j]-EYEn &	3Q$Fcl1,%0G& aVۭ@xZ/[0eV8D#Ҥ;~)Đ\u]3Gk-'T$"/_6?NCtm󲮅#$R*7@t>_$gXzT[,)	@|SXURȅPZ[0{7uCڞܺs׼sя>}Uh-@Q3[k[k	Q @HHQ(D R"w/hMgh4;QYy{M]]\\<?_\|af
#" XJW_b`h D qV
hM@'z\!HY\*jڰoEtWSNk6J$zheY|Q  vMUA&Vh4FyQ(e>O_x#_ӓ֭}>ֵokz/7M-d6*A"b}{NOoO3"[>yB17YQOo9׮/|GWU%1Xmmal>磲(Gr2;Mǣ
"Gen?䓟hm>x=",}ݻ/)2# ǘRU#5:mQXRuUdKc/	_ԝo]zm-8{tt:q<ë^[p nT}^Ԕs':Z wh
vKwd.kZ}ۢ,=g;-H`ywGMٸi~o܎M/~MwO5LiO`8Ewhڥ@Nv/pε 鳧"ϲifi,GDZ-u/ݹq>
pmizg13Gx]mڶfE(u݄Oo.%7MM><<>BhCDP+J%kTYL)CJiEL`@f`DuݘO~dP6mƭzvj| c@	W&!2y| zכ(
h:79H`cW'D$/,x<E#RE C.LNꉣ=@}9ffA*,aZcˢ(QSWuU-y^9׆۶2;Mo٬7meZ)[w!6Fkk16UI!a%Y	;"^iT9dE\SU"E>MǇeQ|/^:h.`rs! "ghJߐ2J2kE^`6RтܽsptT7j޶M۶m])%$ԍH
|HVݧ-8O)}b$"6ggXcEqSUZClK$0@:`Q:G@ƚ,@b|=b噵Z$d殘HǍ' DؗVTVT(K਴\!ÓƓ8f\n.(d<9x !] #DD2Ͳ3b!a?_&xTEN	a>kHελ=;  F5)h&n*5 p]WQϖͣǏYZ]~K8rS7u@m1FBOtPq@_7ZgM~7Ƿm!W^خv][1ʭ9t2XKӭ5x517KT!׷kiA=]ԞMW6P>|U6o-Y~*;uʱ;0u綧AoWmM:4QJ1Z(>d\ܫޝ޻,_z,yzS}գ21ZGhVJiSZmFm,LƤRL)  eQ7Zqέg/_>?8:JqIVHB4M몪^,4u꺮1Na<S[eА##t*3OZc֞x	tWMwo0[WRat ιֵ!8%>,v)Hڹ<}>D(F	8ŀq޹D$0w	C8&:sݣxԣ;,QDu*;E""H'!9E"cqխ[.GeioV/=9{R8z;}QJ\۲ i}P/ϝk˲̲L Z"f@Cl@E	E82钣j㛆q"2 )MضJZUg{ R}t׫b~d|gwf]ۜ],|uvv*xBd(Ld !0L*$d`z4,Yu̷NNrkJ)b1+
MZT\xbbdFBRFQ޹֋ Li(V[ƄBDN "s#PG+RpaM<y'OM?n>uӏѓ'?{ٌR9}`aYdFQQFea!*DH%3CϾgo?|str>񏾏fZMdTs.󋋋WgZ5M~l:;:<z`^xQnm`uj]Qݺ.
Zg-2&!mU<3E>*ˢ<Fҋl8o@Ϸ)Z%{6s*n4$KmG$htmھ Õ+}[މWFz㑔
q{ml^5=dO<QDĆj.r}z3}/Q[쬔"M@=lC:kaȮrCM꫼Pݑ--spVa*厝gя Koob}?ӏS:Yt|7s2;9>ywݽw FZx`UU]ei"e,ˋi[6gf
<+Yr5&
sli9FD,jes1&v6YA_5m:m_<Ŧڀ2XTi~pٌlc1@D4=}k\G@n?cJVeX֩iegwxDDPIiE!Jhjg駏>
,F[ǳ̖7냃96 Q13 G۴PN'!QC  P%=}rmSm־mM>r3G!3k'Igio]]Z$V꺞kcֈ<C.8#	C"Η), jM(H7MtTQ Tm1$/VEFk"Ed{a+	&rǲ!Hҁg/_<SE9fnz|O?4+<Ϭ1(!HLB I\C*e0Rg 4m]yn׫wn[׶sAb6!&zoQ%~; MB  DR4RjPnD"s5 "i1 `ҨŹ%/_=z,;99G:9yO_"zyuv1[""3,d:>=&h4FDbV,ʲ(L+Ҡ1"ϳϾ{?O~3h<>9<8Md2"ϵʕ1xVfnx
jY^=EYF#D8;ɨ8Li}٧2k2L*F:yoݻ{{:fX..hcMn2ϔ-ZNxX0]4({:<&Rn:;U;w(c&54޸c|nl0NPǯo~ښ%:\wE7y$i}ual[|%uif
J ]F6P2<Ƥt(]+/i6}-j8~[~u`p_wA5|s%ܕf2=%Wkp`X/\a;y6]b9=n/w7p2۳#r+C[lAߺQQ_yN`^)"̌.L~_\\\Di<WJM rӔvH)}Q$h%m`}4DTU22"R} (@3yQn`br(1Ǝ̩ Y\mݗ&'ǇǷdyYh<#a92t4G?;!k4Id˻R)*uS֔T*Q!o;+2b3<;{G;~~|>Y6Y^&d2&ZgA/ (0\fQ" $49
4Ej !TˎΒ0E#sL}
Hέ6պn6u[m1JaSmVU]7M"6 xrpx4ˋϝZ%<}fszvmCڰo#
#͈HI*ȧDC1z6Z+Qz_9?*Q9>lI16&/2*3Z)J!)$9Ne8ȉ$GM 8y[cpMcܬWb4F[kCY94,Ӕ+8F}!])J$/Z1ƠAA$r(Hmn:ƨCyC4B"ibq> Zڶd:pdI8-!2]RZCI p!  QW>_([,|Ç_s-A! ̚XWkz/2k<+OFɨEAڪJ* 562Z[kRD cɭ?{o>_,MӦܡ^218x$1H['`Vyg4;.Ӳ(FE^"F;LN,1/^|'''=<<ݹkXmdw;RبZ)RGaTs\[cvK!V؞ړƶRɳ;7ʮ+GmoFLs󉩊VkNՓIiM^[H2H    IDATEG{4P+ӷ*78[sn7_Da/=s:='N=ƫݜh.Kzv8ƛCDF>7:W1 *يoV	v?-Jϸ|Mz͇a^˃۶̋xc`.x:]-1߯wǫj^+mBm9NBdC1Ii J7}dm*Lbe1Ƃ6x6&}]B/iZ#"9Bh[W՛j9X-QEQlv2*[ )@PtV4  -ß6ۓOz13V	tJHR0a#FNjim\V`ŴO}7}w}h2;W^>{'/^yY:?6
BȲ\),S@pQžV֠we2dwHAM"	y`L)*!<=߰C 1:׮лfYa\ΗDMdimzwx4*'٣_3!iXPg0J!H[M*O pD"aIp5ֵUg6C+̬	1Vj{4Yqݺz/(r4*2ˬ&R
H c)AG "@dDH՜SdRY"3*QJkI)9MӬW$iBʵm۶Dd%|)HJ)#'cTZQ }#HcD FH|&n['"9k6Zs:DL&(-Qd~O$b @J+݃@DN8 [HdmE^>RƘ<fO/[&z1"4qnC8jV8*l9uz֭XkъVD֎GeYj "#Ñ>_VfSmM!F;66ⴢ"㱵HԊ&CVlF-N|cک">4D(xY-$_|y/ǣp]r`Fc֨i:@z^V(ݼrT/sz'U% @KI~þ6e%&j-wMur+쳨>_9Á{J-%,׸ Ol7/{/kL7i*hƁUd^72l#2zwh_4#߿UDoiSWmˠt[euǱCvoߓv]Ս}-#zYҏTڬ^z[WgǇӟ),W˪nVy6.W̨h:aњ]h휋"֘<4m\oK1f6#D2Y^5&+Q
 X$xn RޑRӱ&q*1(ŋ_~~цpr??CD2;\)y^^_A	C IR޳"f%r	m\۶zqTD$ߴuyxzr۷ו+eH`C`<N><f~G?ячNf$ə{uWa7䐜A"A#z	H/ADgM6aYKVVr׳ꋙ<so̪eUagu\˫պV]xI8%pdY!oGbL_^kq"nNeZP D \c@`LiIG\׺9 hS7Hޱkn\uUٳ!șG{{Ʈ'?B]
(Y% Bs}րٺjV+e, NZ}6&|ч}<x9v=q(<+zsqy]G;c]6MӴmv}AK~%@V$= @ED
82 @f*|km"[9F@L&l1 z׷rI!hm!Y}ףYBd#&M
k5ZDB1xƐҧE?|0˲QyT|@Ҋ&qgHڠ҈(I hnܖT3mikڮ3Uno?O~s}tO̹5親MqDH RLs:NHce]mX;/k'`VV2j-".Dcq]UP7gYN6-jBpIp!2N@
c|c smbTj1J?8>p?_|ɽtb  cL2 MǾ!އX@J/Be6VDٙdt	]l+x[,1=$ FRޔ(6ݙA+m<*4
n ǭ>rNglُ8|`'8rp&N<rd*g?n}kDxHuKel_j#
CI۠}ہadݜb؂驲5vn3-eD%stywwߟM cN`R?}-v"пi&."/VR_wyXJnTe#\<a!"R֛ӗ}zūϟb8>>Jm޽{]g-Iu{{{I<IYNr"GtVqLU3ZHfZkjcIsq?^^LLXbD`+-0t^q!$,(m)ރ|hVke\]MZ$$-V"e3b8>;<dȴFqQ}KcR  1(A9Q^T>i"jxLӿo
j:=ApwNfq_/zzڴ_??ͳb>=:<wafÃW/_|Y + G?)!BdNk,C;M "( $D :.˦CdA8(QDst|2_5}g,1rB.D^/P}sR4wM!
T"*R6ѽ|&MvZ.7f7z,|rnHmR?agx7{߭j˶}O.z z!BBJ$
(D@5,T c 8( RCɲ^jꕶYVt2N'<8aivZu]WU 1?YG}'yJ+Z+k 1 Bjr Є47R*ѳȢ6֢R>D9u0JD$C" (fE|xy|reL4v2'q}#[kt2#DX]ekS壽"ߟMͫӧEYkm|X,(|b";tC ! !xN#$d#20w !&d!/ -)tͫSufH޻ιԙV6[bDR!F	]ښJd! iMThe7h5'׉:¼e ' 1>@Thvbc6 v\v7\
$F#TRvma0v#:i{̙x9/niTj.8LYC*`^/m^ۈC!V$k;?wWrK!n~odp?M!KPF]=8n^/4[-ݤUNXggpv)vm@OFi
	=;w#-l]soZ=918YEh8?{O?VWM\Ru}|NDsU]k}hn;Wt2YoI[k>އι\I
n ' hX  @Jy9{e r1  <JQ[lp~2\P;.1d-#Q`!}Ymoӳzc3kRPkT&aB!SʨPtTg 4XCY?WMUbvtt4?>8j!ED-iu*@{<6OHX0dN`(󑙓e'#4GO(1tZ-뺹˦׭k^_\}ge95Z! =z􈅵ͼS"<@:opAЎO$+#=aND[[&@9eh1J6l$ ! @!x4 Eb E)*BY"u}?)KD$elۦiKium`,,gBm3mz#Kl6n.BHj^.WW)޽{g|pvy9;˫/^~ypWWWMUwcq]y@  *n9gIUm"m,*MD,L"IEePDL]D֊$"h"19}۶MTUZ,ki޹w];RvbaHLv
"3cBpr4Dm^\.O4"Ř :M .kWڇ#$*AMSu׵Jk"e,/ˮw˫<ͭ!Lt۶;Yn!gEqq(RșNR0g}[7m;?拽bo:e煱@e0 &')"5JHl:w!H,QrCH%:Cz̉.!B>jA"ˢHSW޹dF"z
>d;:>ڦ ۴`qzH\eF@ "͵)vܬ`.H*DTERzAoIJkٝooo
pXȵL^Cn<vo֪Vo0MqWnkyCW-Nua@OuwyApp5x@γ ڟbj']Ex ?{ä~! op]a;pw6JD\d__BHPR 0Jxpn E*yd}:`Po7>|ßDJk&[7>xeyUU(5rU!d(9i=[Wmd۽xCyP-&G?ztR3]b!
's
"ZkǱb"poFLhj(d)"JryElm/]AyI,O'{OHDBCN&}EWW?/>lB?巾ˮ4XkRE[0D/_G{zVEO[wkZ3$|AهXŷw2ccݹzzyqyvzzO?m\~?xLN s:]f wb	4_+puHAJH8(\t$,}Ri;я'"Bb2f$Ƹ^skPҮk˫嚈&@TJ[k<'V1ʜ_s^MOS@k9}j\.O̦<Şw]SUF)&4Z֛S"r˗컿?yuzw[Pr$BR)mWjXk1Vkc11 LʱE@)@ !H
BiP#DQJDtιm/..TYh:/H`ozZUuw.hIǼPR&
*1D
 {\5x"B,,w]RZHA(Ս R&EJs}۶Y)M^dFbfGGquyb$E Y0Z
', 0LDDڐ鼑~b81j擢ceͲ,G{G'<<<8[̧ei`rjLNpL&UBJӧ.
2k3EXbh.FF$YkۮH)k$7(صm.3:˲Ue]^_^mRdF\6|1|FAL^>ۢ@f$?ʭfsk1Jf1VیIvuEɰTAxsܜF5M9u.!_d>-lY[x{ƛ0rK֘0
v;(4|f(ȗbp!&kwiq4-PMC5n
w݌~a)ɰAPH=(EWA4Ąǒpne7O-%lClKᵬѐR^is)˫4xV[68,ম	6ʍs5jǿq=4;b؛E@&Q.NW:1"Kat:;9:j>&;vޔEn1F)EdML'Ӳ,]Hv&:EDJ md4``YUp1%2ay Fkmlgyf5 P!
:3CAT1L?}ޅzZVj|oѓw~;|[xW|Y;.6kSARJ+5PLg6όF)(1D`Za>?/>ZrO11ơw3RAjfGmcQ]UIiD<eBI	F9  .޻ﾛ>inTyafzz-DDA$;vMaBd }׶= d(17f1ёK	}]C-rrڶiڦ9t][71F+MjiwJyEڶMzyTsF	&hC캾kms!]w}dɋLG?/RJ1D RB
I)BCRJټژC= tnlE9׆CYkVcf PZ@>Y ]*#	?6F+>B-r>Ǐ9^]].WiA4RDZRJ "th6zɭJ4@LDJT&@HZA  2;"L5"FߐkL,м(fn_W#s߶]בZ6UcfR8)0mL=k1HJۙ)U6Z5e (xb6pyv6_<n[e'O=<>t|rP %\1 "DV!)&Djm3Ί<
m׵mwMdT"Z̦{{{̘2fEV͌QY0;J7>9:;)&˟}'|T$ itnh &(9k󾮚j]U۵/_\.x|tTBD"ƀCn2ֻ@Vi(.1ޖ
;(utƙ9fꭍ>R)<9w2Rh
NE5l[Mtvh("p͑Z[N[&SIծnFX@Zia|[-2Flb1ܵmnDm(s=#	 <nqx~~    IDAT.K$Hq[fI.mF┐5wd'wD`@׾;-,rTwc\wܢNj:vst.E`}ӿџ7e<gP,DOWWgŤ,Z.r)EDYyj6^]]c'bں^7>uKr)&Ӄr:Mgs`7^ZkάA"36#%(8\]$Ch< {b"O_7k~wں5m[m6U|Ŧ_M.i'ei9Dg̘֚6 pSw?{{xrnjo~٧__7hUB1ڦW/N_:;=}uvڒBzObժmȁ RT
Dq1  "0 RR Jh\+ۇȀ<r9#8{P^0aBj"6%&\%o]&'fB1$B.d!t>mRU]^^M=͕-&d>8!Db2}4u۶K\_UUw}߻>u%Muֺka$`N+J`"Qb)B"M8IbʊQx(?g~tzvDEX+mM"Fkc$3 I10$ffS}GPJk	HdsiN򢰣z"ab@̈$uZs>5m"5z r\,ˬYeͲca!6mu]着r1Ii ER8rvf @ uѩswCaτi($BmT+J!8 x糩
|i){uwMd$ ,@Bj)HtM"TJ!pTF&$1q)wч*N'O?{g|8/Ã`6_Lg|g&ecy׫+f΋ɽl:-Lk$RH
X(eU&WJ3)06g@+YXEb|?Ǐ担Ͳ|QyQ{?
!&z7 !!)mBpoj'?f^W5phib h|^7mD0UW@+Y\9aّ:oF鿝4v;on܊%/Su@{oo$*ޥ17ZwI|iik"oAP?x!}Q%!7z.p+/	zۑG'%9RFw+nNxKzC'܌1޹/	ҭeoI_ŝ#[	JdpW縀F3qO;P_]\-}B@vӲXgggx9?|v8fHDZ	;7]77U]Wjɓ~>MvyfT,D*3;7;Y9s}kR ZcV%p "0q!C ·ӳKk *ED b>_YE>-"뗫u	\]]m=NUմ6Z51H`A\GfgJp״1O޹wro\hvY(ۿoygLMcdׅ/^_\.Wզ&m\?/rxﵦb, )ChMZ+LuȨ4cR\I- GF$ce}M6M00Ih	i1錁0"!ꁎ,DDQEHϭ?%<Hy	 &`|dP" lT9;}7MeYEfV.*IBey^>!lW/|5f֩{ur "QbSa#|-.H,SY?~~O hU
mB)O.1xdZGj ![DZ!sk=Jk EQ|sc )10ҾBS0 BmmQNd2Ee!+%  $@F0ryu5LvFaQdD.$@,"[Fc8,>Vk4	G	c|>}Ori.  s%zYVIcUiw]cG_  Z6U[W奵YgY^bpr|<fbX(iL;999::>wIglj64!)C]9Q[cLwfWYyQ{ַbbQH:'y_mk몪6+׷?'<=+\)2|ǀZ)EF'KJlM!䓹w|Gm4*UxKBN( u8D fexm_h۾24W~nA6w5G87cۃ;^7 }kRjnPd|܉o'7Iۅ7AoЛ'טw}7)"yf_?ójyYWk9jc](c_,yQW>Lo\ׂRVU6]}~7ެ7z1"`"Vb6?8~qwDچK2cI
x r ieܦ˾-J0Aw!x~qtZVU[WEEYŴ,ɦO.(,V;+lȋ!߻9 XC-PSrk THY@
 ج׽!EC]{#@K Xow}ϞGLݜ]0 z皦ڶnӳ?Ï>Z[~ .} Eik+k2ֳI9LM1 C`&ںmEq]W^ j1)7զmmO&vcD8<9ngIA86gfDóDRP ^!AD0s:e F	12# ~1hc WUbl6Nd2͋rUQ)*RfR>rSu]ohmNFjrHdFTj9c`@GqQX2c˲,ppﳧONOOJ `l:sTcSqc	4Ȃ}<A#(kw!d=?;8;l* (	 \`D,<O}5
$l}sLoB89P 6M٤<@cLY|:O'"{Zn7UVzZĂ&"7jyUd&2Ri ٶTg,))10GA829&ˌ`;u]uM]u]+yf<N^ c6}۴]'HEY ;dNz̌ byCQD(1֊:8JWUwCdR69{cQ*m5 Z^3]N&/{-"/t{dټ:;O~ӟk*kdR*cdcLeEMd:'L$1*BlkUDiY|bjJicm@Ӷ>pج^zuݿwɓ/>ϳ7$4Z[kPi zm(L S :5wc$nshۭp
Zu'2t;~w%z$FfcccPet6};n_hx]d[jTehXanKg==	N4mcnYwD-7x%Z?l-mVI	^/]I/OqڭqD7ns.	OzM L`zyv?3!	޹w.5&Fİ6!j>~ztx'Oz4"juqquyuUgޑO>r5rVp~p\LfD[/ "Vx+TF|lS"M7XD%R"t;kzYͦk[k,&eq||۟8NYC!Bc F"&EをN{ttl:"A"(A繲E>R(%Q^I\u>to}?xIŋ~bPZ+ qLD,˒VK.+J(k"q(cW-Ζjij(o|'''E1qާ0snS-LauO>mF[QGvq>$yf(&!II1Dj 3X 2 3j 5
 %ef F!24c&1Efh!@׶ZeA=lzlڦ)&5 &y0`ئO& p "˲o~㛟~ӧ6K2f2gEYpSo$M67F+۷*'"Ik\SsxZM]?'O~駟=u>ػbl*>IxIYXkԠfD1Hjv(
%@d$'c5ѻjIfژڼ(GGOcιuU_]^.Wfٔr:!҆.)TBZ8`"3s 8۾p߷Zc,ȭb!0c뻮Zwu$I/Z D!EaRc+=2Ug2~1;b$fZ5Z+mIy90K4Q)BԊOճO>RJkr2_gt:O'b:_rVYe]ufS]o9iYX]\\w]u}\cD]dr}|/bۦZ][WM)"L]Wgg1EYf&'O3__?xhoOԛhu|xtx8+'|! a
hDafNUW&of_}ampT[Ǒmm䏻*N֤^VhxPoeSYk<ɻ̠l90߷ۘ2mJ=8ʩk!T T3I`ō C:fde"Py P" SQٵ:kKn7ϝ ׁб6ҘH;'wL{&ͭ_`b.|` v׷aCW)_F
>pP.OJn6bp1ȉ'e)-A |zK"ʳlZN&c3m9?8<y8<&/Ta"G̃I,`
ukwGF%b"!e\TC\)2E1-^,N"'ŴdCx38)Ƚ!R(RI@ed2,,[<aH3lE	 fO|BeQ(~;߫V|8XVWj{X D	ܻc$<s TB]۷|/}]mVr^o6jl1L&ÇYbS1Ked2O>~Ewe^	 KcmP8I>L©BL6+GV b9rWOJY)8PƤSc*yP+! 	iD1Ǒ	!j8S>mj2g<KIcMw,E
$
#$Q8JG>yH)]H)I޾Rz温",2RyIU(
h636K(H2 hksmrcf^ɤ(
xo~痗Uݴm۴]UU}DD{!vk4qO"[`xIRLNQD3Q9{c[k61I,{y6W6Ii9es12J
(;Dx20TDXf9!y6Uݻ^]mɀ؄1r۴rZ{b}B,"GAJZKeZm &liiEUY֍AP"6Z'tcιs.
!D #X0IG̢,˼ȳ(˲LgdJ!E[&B1ľk7uմ-H%x!01{w^~kC(o
@gYgya&Bm 16{&:kV,ˋއ?$ 5+Bm拽tF,[7.&RF+Ę=GR.47eg^i7(]wa{u^־0)qog\Kzuײ`?ko/pcц+C<߰;v]z˧@o|
nSml{=("rqvO-$s<.[%m3{pg7;ʶ7.Cݺ勈R{>L.ɣ/>$?ϴRrSU]. ̦Ãw{;_8}w"ʭIUyiLjɖEQu]ϔ=׿qQ9Q}!%] H$Ma $S1vE#RPbc:
GM N,/狽t!De_c
adAʬQ4 gYgZb`:fFfD(D((D  @i= ySt6;:](eݝէϞ]_4m"ľa)؆9Yެ{|\(&3zZWˋ˪[7]SWz:ϋl~|'<yCh 2E>ߟgYNDYlTc!}oM:)cVmAaIHy$E5WD!H*oH""(1(E# (CJ+m^Ħ%&EBeiJq Yy 1rEf`D d (	@Qb@!2sL&sD }wyϝR 0HA)כu]"pfl:)ʉ6XkKNt:Nl6EAR&EJ';+Cb1''/ƅ}S7z5upirSu7j:l6s1DHH
  nj˕l*k)PH"&4} I,˲(3}j7f>1qNE␉">J!8|;XX*H\uXk˲(ڶi:"2ƮViiڪelQZ%!"3yF By^lo2Wu6{i9@1BQJB> ,sEaʢ[2J)};׵R8&I)TX;Ne^NmeY6M,ϳ,+Je6h@(Ci^ U?r}1oIObl&"1z"̦^Q}5mv.qO&ovpfnƻ7VūuΊ|G'CTiզn:_V*3Fk6FEJ!te   CZr2$% ܑ0ge~)7 /o?L'"1޸;1Qx0п(Zտid_;ݏΛ5ˏ(:z|;u"I;DDu{I7}]~wky    IDATqs 7eɐo͎6s<l_Bum/`KbnW7qge=5}N?8;y9/GC軾]fRYn\o?o{8uZ+R %XiЌª}׿ijʽlq nIYRm)2f۶뛮zTM[oڦ}1XX! Y^""ܿ'"Z`HهA9GJ	'$vJ"!#@%MRm@}Mu" !lqoVMuӟ'WM]fͶ$yZ9ո3ީ	`DS9Ba#
?Z,$@hAt3渚\k!kpI!dwtS;++vV}WȬP	El6=<ۛ_]+O~Dizݮ]`tY7??yw<ՕP)Fcr競dٳgKmtR ""߾Yݍ,78_dHs!-=II%7^JӠ/B9E(SbG?Feg{~׮;1
 3`dT!tLLB>D$0!JRlgP
U? qDJ+,Gǋ_|:  GP˿lV4>Hj:16я>'آDDe]A v}~~zvyquyXƬ۶Z"<3LFZ兠BmbmӶͲiVϿo~ӟxZ~<잻I2{/P P6p R&u]{ycUH CC "FȔ͈ǈ0IVcPk6in 12笳Z˲ȬjW_>H1 *r7*C1 HQ
 uU]٭
uۮ8|}vct-K&F`FgneF"L`0= 2D9 XVH6p`ľmΚ뗒?J)u;EYNFYiSFi1*ƨ,e5zWBw! SV3KiŲm[1s*e!xl:F׿w{/ĸZ.ex7=l?GQQon !c쓗e=&8
  H(E 4@5 
qSA	w&:8Ʊ;&V	I6qo]x>o~p@\[؈#nyI/{AO}?򶃔dVU~KKJu-9pP{If;qu\Z[4ٝ5:bAv4y[wcGaǫͶw{o3m[bV74 }??jy対RQY)mKa\,;:~/]VHQD.@DeUE~4_^]g>ڟbȑHD@a`djC ku;gWWVjhn})QfXY]g	'ׯ_z5l,gfhh8ȍF{m "0Ld 
0(1PnV( Z@l `6" uN[,U}o~i1B^pUd4Rd2<=9qEe'Çȸ|2NhgYY! "]} )7e/◯ON111݋DfQ Z9&qZj-t@-	 &͌J(0`$IB$LEY=|UU7mGDκ"D}Q<@"L"ZQ8	 	$JF $z16lE	2̰!PMX49~i#c].b5L {J_-x<|'''ۗ (cFT[?g?>{p|'1Z8DJUZk4\ke<ȲRcz9[}"tGO~W]%F4ծv!<R*$aD
*TaG)I*/}\lz~yiZz<PsBCBDf(OF0͠F EFhc\L>v1Rt]5ƺL9:LD8zDZcNHQfH"D1xvm;!Η<s` K
A	(fa&f,dt)8#hH812h`a"VZ!=׉8MGx2Gm^Μ5Z*Jd9g1y/+Eft	c6Z)ֆ)ZDDkeT۴h2-r^_^dYV~ú]}k_~" bc4,'EAU4c_/+TE^ͫ(I1PU8n+O\;Q2r?JdNa ̀[]wg[ڮXŭ;[wr=ĽG5qݞgL	\t1WO&f{wOSVMd}7F،z`cO$1 JտI;mU](v-;{=چn}5p2ƬW˳ӓ~鷯_~鷉v`(d6(yVϟVcm`7R֘t:?>~hTV lX N;❠
P]@!LwmZ,WgWWW˦"S6jkF̋l2Nt7;hb\5:)z\-Vڇ^s2s&1c*T%<4Bb!-=V2PȁRjS6*fMR 1\~D%tRNC]j6?8:~у'-j\..E'Y]Zux:;8<>zm#C^O?O>=8W&%>z}>ش-Uɨr.'|~4MU8$EH8- C%6{cܰG 19\t"L&ッxb8=y- D☪62)ĢFUc !9\4}# )%hIHm۶mc003GbB>|yQ"Rh4ںweC?!,@p2F
A؇Ca\?Rfu4m+LyeeWWeY)(Ge񃣪*+Xd}'X7"*DA_H$854P@$A1xu-@4(ߵ...y(1aT  4sBkkpc@B.D f
}k-J%"!;U@"/ON;Y`Z]We^`6:?Eq(lJ,*XojڌHoUd`a @A8.l]E(HC}۶ggQ]B,*tM3M2ό1b=<<ꫯZy$hcuCWKk""S>M&t*:DRˊOuˋ<!cq<_`&A}Qs:t>z}a0Y,+"ϋD4mJ9Tz w2Q;صc?|G&}AC_MƿE}&;La }ܚlڈaѥ9ށn'뵷_3`s {<8eo\wGNݖ]%ݶ{gN$]ݜNT5]K14Moͷ^^^YZs,@콧h~ϋ"<{_z\2FDb\V! "ޟ>jhXcrLQC1KT&JD+d%Figmq\\]b1oڶkZf΋7@;3Fj4ͦt2$IgC4e<Dj}9={
@h:ۛNpƈp̴ͬof  )f$
 (* 3E}f\RZz A cRJ`Puz?:vX\./.>_g?<?oã,?7;<&e'umۭVq]ھB_Y,Vjnu3G?G8F
kj0
Y:
@Y,ְ@y,~;r7 N**IGH&l6C=}7_W>O@a6(L,XP \Ā$aVD۬Mw
 Hb$|m}׍bKH*̜*A5q%?99_]eY>NCߵeZ,shCˍ1B B`mD+ 1,,me캦iV7 ܑ)'?a&61J/?D   S!M֦{.)x߭Wժi|yYiUeYUmz*s F҃T{YAkd@nJE2wu{~qBյ2\Z*qYQ 7>>(RE!!ZCEĨg*+SM"%ڎMCAJ0TJz@	 IZ<!zuuYUWUQS&f1Rc"=OOa@#*0'h4Ltɓ'"/(bl|TJ;<2.Ow"r[@k* Dfjr^Y2.d\O'd9m5j0ƀC ٤O, 7,#qvkw`O[#o~N1ݍo~L.u3{ME˖Zd,ޖh
R&64#o?@PRz}Fhͬh0ED6Y(KΧԯla!fu
:cunwH҆M^
㿹xn`A2dy6Y3Vk?.}fz`Hnֽ};.~uvj\1)MA8]?z裏?Ï,g/_4:6}!}Sg]@ $ Z/[^[`9{F
8}ę53eQd2*˲,2gd<5ڸ,M׼(*d峓/Qiu]U]eYYYld@ (  ʢWde r~MU7We۬=etV+kVkc 1P\5}k:1ɣq}OzW^|B+8\/?}_|Ѵs>?}ZdVP4<{$̢P)ch6{ptōƓt2-r6WU.ƺ&'Zk-L72J펩tS
aMTAa.]@DTHR TJQJ9_xsw}W_zն@5  	jcɍ;7w,")m
MW)"zxKdP@@@ JS)+P=G߬2g˪:2I:DZVJ>xyT"1V!8H۬NU$BThl$2Bw!xFPXŐD̨5&B ٹ\C0\\.Ï?yyv:k6 y &Ѐ6=ߒ3]5˒1*"	RJk#
pZX"E ,!F QBrޯWQD)h6+3mZ.%QL驮m)FTٜb$ a&c5Z؇ȲX,}UUf{cqUE><^ӧ.ϊ,￷0+
c#KdQDe+,t&Jc0m	(%x BzWF(Į}\sNb(ue~Jz̤gc!FtZcR\C"?<8bN2!H4JY)#J}%$ CltB
 TdHP1ϔR@WfX^-zՋϾ3
@P8d(kѨX$Dpy:ߟ`:7L˃9*QTCo y˶]};)ۨ7Pnyo wۻp6Sa[c)(Z
 ݆[!riWm-0 3I6 t&7eɿUk|VC%918B6&BS&t-I@sopf(<޴nݞ?\R
y9LYiRO8F""ȔBZGW/_
%- D|$c~gTEoi %@()z1x7Oc/CS_,Vm拶h0U2 UQ{zTuYEQeUEQXkT\>˿~b>Fƹ&<Qr*2g
J>5ksfQYZi  f(#2]#adBkT](ˢȜK.Pv]Xh_U}}CDZiIbL9~|]\^²^>)уz࠮t9f{`NV Ӡjns d2ɳ/z=LE)( < x,o{ wG@Ŝ޸ׇ!-	#)!"@% 1MۆPڢ,˺dH'q<M$
*aF!  ,L[UDIk61'%dCƾǬPTG^,EgyZkD,i;{vz〈k["֔eXB^,y۬bTV)`f}XC@&ަ\QXL"J,sY3QEp4yMuy㫫y9
 Bmh@=
{"EfY]۶!<9c6Vi1Y^xڇ !DmBJP50 toeU2Ve1iE5mb#1B@%E BCL B,cK2cU2ZZr!|~yq I)S֣;NNN6b* UQd0Qaf`(o	1@!°(Y6WH,rbnڮS5Sd2b\c&1w}uyYWR*|DѨ~|Ijuh!bQ$0*1G@\t6{qU!r-㎈(5
E48^@Cy$f. VkR*ə`rhV6)B<1K/_Yfvp4xlXV(]Vhf`=!1    IDATy}?q>gV~mޱd6.]l$Y}cJ no1Js,u܆fHT2~wԶXH[݃>~}_[Lkg-ALwOewhfuvCm(멿^o?toDRdoXi@}7Y5mUyurzyuC$t,	W",C凇?\^f1
+De0qbfD(jN~GZ@#( (I0%Kc).>v(}3yd"}Ū%:?V٪lZW &j Fgd'?=<,RIZk+FY	:|߭Mu1zDeu.˲l\WɑSJ1@@p`[(DT]eDRtyYYf_rVAzTRפJvox6kuj^ÃG(D+ J|yq4曲<01Sf(y	|.ˋjJ'^U^`""´9
6Zg5)	6]Ur])6%1IUE)Ebjk#q"3,H>a&'zڲ/%&-i%]v^kBL6;ZAj,H)otv=B 1
4B0JE$<ϳ,8ƈCPWu=skTW}ֺ,h|y^5*()BH$"  (uzp{.KcmY)R!\xJ-Kc/f{xXʵueY54I`vժ	'iYmb~femYVPZQg"V(c pJY[TImCDgMYƓT#Ԧk(LțLOʬu]ei	RgW
ļZh2y^]]^^tm(׫e6ª,V1{Mx77'n۬7M6~:N fU]]HXx\.kŹ \ӶɉڛͲl6xSBQr1ƢR"&ãc֮؛eeFQ%rANNեI2q]>:Pb]EWϺAbX̯xtwqyQnYOUg5"⊺ǓQ7um\2 U Xorw>oX{@+=]{^>e} o|=.f6658-o`sr  ؠ~{h;s"nMw7t\T p
KMް^ܸ]ԳcUN%mlۤ6LfM[v3.^7Do%A>mi˰3*v|SK&"__W?ş~UŅ *cDDɻ'BۯjXk64
XW(X,}_w?п8})?(< @1I% In>DZwb>_۶mEm*Ԣ7·jIeQdv>X<r6*flvy[kM>=_g?uE) 8k<uUFu]+0(a"ZkDj5_|y@,d<*Y({ŀdR]$9	b1\7MϪʌs=<ܟF8	1tx4&YYt]X//(QB$˲'^|gOՒ9ARٸ4Ƥ>QF<fLULqH1E-,@߸ ɥJzn Dh)&Y\ODD	wV([I d2hO=Q۔@P:2ILL0$`4EYe⯧-rMw3imX'#Fj豶E"IP9"'=a1
p1UQ׶ApXx<E,/ _~n:Ѓ
 ,}1lvR".{yZdFYVe c޷]>_\NYQ^?y	GTQ~Z_.WIpR`4<y~qe겮j}߇aLH"L#$V26POOO_|ifQ#sukNNNNNN/ Xk5FWB"@m</2+,rg1". F(ӽе
!>G>׫%x%%F,T]1l	构$0B
 Z-ś	*bX%tn!`Yׁ1`b~u~qD=]EQ]{y~vqvY^8+B٬Gd:)CuQh=~CDԛ/1E"NIdtX#beT$i	J!ɫ/^,*_^^^6Q뗯^?|'w޹/OOOtZׯL&tBHwf|]e9Uu]]QWun>&*JHF	y7~ý÷w< >JsNēuoe{]v{zS:ts};[U@:^^CGq5T7#wvjgA\6xѝJTgMᄍl(6uAN{K}6)nf ]ﶃaֲ܁޳osj^m$/+D!\]ͅr11r&$Lug]\^]gE@1Xqb>Op,yBHKp ,D,f=>kmAPgY? ")[GS"2e戢Ux\OFuaƴ].l68ˊ<Q89?1}ڶ/d%FeyUɴ**˲.hmZCeUey6?J̑|_|sks..]YEY  CZWE/~/v/OgGUUOGCN$ ( 3%_ɾsGX}?}oP(ɓw_ϫooo}}r:W+Dyp8ɣG~e"694z2GJ덬v5OD)"J9x-9Do|fIFHu; )ѡD|dcbXy^ɏ>!1 1ш Q 3dBy^ߴ$ʖ/AdCEDQ"j)"ƘM&c({k@Z7W+rEQVgMle%m)rc3Ƣ,]#LQe!,Kp|d}Cdx?{7/H}_d zj&ϟSjګ+ɤiڋib2FQwD.
4@@Ȁ@@$t<㬳/^|2K9˲dǠmfjuu<TUʪryTG/
9'$B,򒙜uخx=~||tQڮfg Һȳ,Qm,rY B!Ipx5TV#yNa"F@c:bqyGVZ)ϋ(VDBz[v}!YM uNS%rʒ`d\w.h<>zl6MD(P	"lFivF[cb~nއPYJk<o'OGE΋"gᓇd~y=~hTU{{Fk//...]~,r'nL?O>[W:cu9,6ˬsW,wh%ad&ƍTl-޲͉uH6Ǎsxuyc'+<w;^
wiw+e[~gG L%^wnc?6ӷ9 H6@Юqa{seVruc}yi0on].7sj20":k듓ׯ^i9@Dm^7ohDmVm|7g''!F5PÉE@5FS$0i|ɇ]Z.IX)	7VDCwmY$vy]z2kgMjѴ.z@L"sUUUUEYѨ.d`iqY^YMlOk-"}>D@}W}1vkfBR˪tUeYFѸʲ(Ȭ3eEYf
mk*)6vݶjY\VJ%Py]_gգh<NUUUEŨ,uF+Yu}$!$ثO!|>늈f}y heج(V:p|G^\.N/ϖ˲B𞈺?;TeygX5:Z+T#b!E$"Lx- ې(&nm E{S@5`DRZik-6kFy}ɧ!xx<t]=8`2"10Ӗj!0c¡Zz	ƾ;6#2Lb*Q
oYM$Z!#Ih	@6XEC!Ηk}9J)c5eY\6UJ+VZ)Ԉ%DbΥRC2+*cz|\Wggg9?} ZUuEYY!ڧ,uޣJ8]vu_]#mY
$2\Y٣GWsu]vchYwl+˲pYmvrzX.h@DqpS$Hľ[19gqYUY^8g<L&B{|"M*,sFRcUZe1DD1e5;xx:9kiZuۣxR9_7MQZHV׈z@A~m30ǨNzO"s$`&iyE1	EB4Jz[&fV۬>K`K$ YQe\;!5kQ@1D!)﻾zW]GGӽ<˜ 1oJ̹nȳEUuU0wm Xefmbzz˅1:şzYՏ~U][kCTڇ+6V;k+6v08Mirӣms;DyŲ>t=C/:F8 oym}YM.߷&[ṳF;h'07n ng"' ߲]'#7X&}So&ClC}n翳h"Okbe4k7GSJeyC<8gbm1s^u]!EB0
O2<o(ݙboD1Mv}^>`xOYkoWi^E@/VSͦd:EVg.C;k'g{EY%df7mSW|{iz4M1އL<MZ\]4] ιGx2&Zc2\Vdyөx;|vQ8F㺮,j#}~"\-RՃGG{GQ]E\DJ+H+1J+TVipzrZM-/.2HAiQb|vJ8:xO?aVVjy~O_wꊙNkg5:gɜˋ,B&H,D)D	8gjFezVw~2]Y68YIZ=@]Umy9?(Xog/wqz#`Jo&&KB,513ޔ1!w,enMkuL삜Fp6>|HH|/ B$ژ!d2OFuUeGbbI/} B2q.ˋ8WfsUn1ʸ<GuJjM׳ ^\\zgϟ}o=~p Jۼ6'bmLf^[v*̜}b9Z,UTmM>00)Qw>::>N럿x\,)FB`fSP$ϋãe=}/]U\t;EjUY挏b\V+5Gd6Φ"˜$H}ۜ]}߁ `,<ҤUZxλ~t4ZoպY,MrT8|k>RDDc4Ÿ!zMvúd{ &v!dy^Vs.aFYX|3u6y
n)L:gul?˲l~u?{,I*TʫZMc0KX]5'7r`4FtwUW[uuP~G[gYlǭvfdt#}8r{j^=ɋ/],wG''ZjYOჇ?'?}G̳bj~<@vM3j4re}{{\-8:<ܛȆ٦m0˲rO>y{:Yfh24 l7~_j`';Χdɽ~ޤ]-w]5qF4_{.N{˥~w]@Hv}3C&g0`#vН6i,ΒXwmX@ `KyvPqtnytg-/lc+Vn_;[C;mo;aI;pik
˗./'F{ϜAjH{Ő%Ơ'T!6M#*;N. HdHj:Ql6Fh\6}}syy]-)Giڶ4Fe*1,B1c0i=fs5ۺ!FE!xm`oc`ևnڦmz=!BSE1˺Y<;{/"Wx2t<GUINyV9gB"t}vQvTM{oGӳϟ髋_|["ʜǣd2FWT1xbPEs򓏞L%n\·^-B)\,bQG77٫<ϋx0}\鐼59KtJ)K{)$DI(H Ĥ m&ax@ FP +qӓȜyUپkH!Ķmqd8?O&xvzӟh2?<㏿^ mV]CH-cHPs (_;_=2Ն2ӖܟD5SF( J8%R3m[?x^fptYG麮>ZW    IDATL+ᘮdh:U, $%C"TG"h4F(h
_}jD\UiK8H,|Xy斷7WuݵM9#֖qQVYJ[3g:>>ޛ٬hu4/ouP/ÃckM#[/,˪.n'J+  bNQCZt,LiLZNZlfvx{syIm"ˢlz71&m__?✺sF;D|Q$˛z]uӴgϗgX7L>,vUsm$
j"
A~o*o￾9Q'ŒJkAY\U,1 { ֡͢VXE+$p N+g-*M":,P]kWW>?sΖE5L1KۛggQ??W=,ˌxYݏ?g~٧u]gYQJbNjefb::9T2 WUߵY&Rǿַe>><?<FcPlv>/O Y/o.]"2/JNcdfE8$yV)C&/񦗂4!wSObm}<wxTSܡݶ7IwVW/<_|WY]R .w9X֍)*rr_L{vڮ6	ֶx?*׷yV0 M?)덆\o	sn]ͯWye[wM?w *~jD(23]P[3" FTJKUʪ*9K1BcL>x_)նm۶I{S$)gલr*/mV,(;~yzi%Dl&I:;M#!-t6ߛWiY˘)m)@Yc\Q ):;|@ujV
ǣq{bGDo{z*ư7UeU5ƣQ8rֹ"c L,7u]7̐ɲޞ#
]vYZVgZO&d(gǇGFaΚrqq9gvVC+].s,KbiuGXș2QԪi~>ezq>Mv}]Swͪ뺉)zM,1ƾ}̢RxB6梘$ƨ"kJ4(#0jƄF6{ԛG*DcFkWZ<|XUec$ibuyyEn>e{fHD$@̲`Q20pJI%#N`Ƞ8,$ӼIٓ@ˆd4fIć@ A+S ChDt<y9i\@D$cWuSWR" P)x$`B@xn˶1NC^iP4Xk}'Te4"  
/\4vZ-6	BL>*pYygCkm5H<3mnnnuc3Y^t]׵m(""{g6F!*|QN l^2!QPi$>ZC%
RfX\]<:k<wYV׵P DFLڢ,*kcjq{}\j?,1Vr1Gmʢ>P$i"܎B6knv$^c0hm 0UW(3@E} vF' &( ,bHX VZVx$f5H1er4VΚ<(F7V7g٧F{Ӳh2UOzմ]Z52m޾E@)
t\	sg?h2t+PK>탇e:ISkQ	10`9`f6#Ey'GGEQLs!buuu8xjˀ	0ݐ	xA4vz8igmxuڗ8c_%ڗ=+-ov|wʽ~^cw,~4ygd[l": x*wkRM k5Ok7V}	t{Ǆή޵׶}wv={bnˋsw(mbFT̜O\+^E b*	DlYS̜Rhѣj}}xRh<1&FЀeQT6/倊D<QӬӔ]}WQZ5&\fX/?*+r<fãIUiA K eYe4 Qߵֆ,,U!",/.kZ>~=}h;}Z+fh4Nl<*sIlY3WF H녹\efz^]\Ud2,*eYi	g"X̊R ˌ|TNln}2s8VZ7  r^\\.noWjZVM݄HD@L,bԉ#RBF}V+`_iA7E6N9ш
22Ko~3r"!mD8MiGzC@e+62H,BI["QwfFTIg0zvF [1x7n9in'9FH@\DHpR8@
a4:(Gr7eynƤ0Fk,˪})nѺ F'?5i8kjHnpS+̉*ab߶ۋY8*ux21cQVaL~0%97m']-fGGGEYeurnje&ˋǢ`CXHgywp;6TP| b$yq  "jw5Ē1:fHy$g*s DY^(cuJk%2O>|xtpP%3^_-iۦmz-, $t]iPćE	y&$[6ը[7\z$N4MYXC>c1@!Zk1P6Iq$V6Fg3F@$I$`ˊHu].z`@벪,r<?<88Ogx2999RRhX\____]5mu\____lRuotp\Qf.wF)`)J)]7O<)Fㄼ5YnU{bDkmR}!0sj˟W}[syHbIF+\e*c6q,^(Ǎ#v/hǲ</6MCq;6y{fk$o+meCɝ]'$~vgl_y^`Ep|lvY<q_w&ѯ,D58
/Wl0 _7nޭi,]_<Ji k	}gһ"||t2NWًCkL|/˲&1
?"EeM&l'`]P  ,c[GkmQYBgXwG2`F냽t:;8:yɓ|9,d=G;"r֕eUMfY92.SZ'T)LDOX<<.-<*|x|8/^z\՝Xm\wGro/'?h噲΍F,j4OUUqZ9@iۥ>%RE<x,oʫLv\Mkˌ	FO?|2Gb\^:/l>Ng `<BʢȝJirFh 4by~q⋧ϟ}/_5mg\hjTv@b GkHcbhMۙH*:Qccx KBtβpQ>7$dl"GPtgO?]hP@I(F@ww6xM^=ER6Rp$_."Dc@lV6Z!cfhQlo>;,Ͳl\|4y9B	yHD($o?O:#}Hv} T<X#cL+jWj~uqyU:5hѪ*{O>y#t2
zysuլW]u>"Ǹn{]S娨x~}c~tozehv\X?>G]D)p " uy]] @T~z ,+ը6+62g\>+Ԗу|߭ˋ>k4^gYB@hon]kKJ(!]e!I'YBT06j@ b!3R"9s>hVZZ״mqb!tB(2gEQ)m6"B~R߳z2G>,M׵Z(7{.O F?|Ã٤\t<~ J)ir8_gO{A?~YL^mH]߷c^qXP   H!jDчqYfJ^:ǳGZrL泹Ӝa
DuӤ}uYgIҶE c72wێy7MȀq3]GCOAll徶^MEE5ۻdwO9|1p;*㽄a67Fݑo j3|ץEyoʳ] ܃m=yx
	n4J,i⦰$y;kazm{t2oM"pNW/nnQH% v3wV{t}j2M^/C( ޼(uS]9IȉNx6mѨs cLkեoJ3*ɬi023B߅Bͮ{cl`p2sU	J6q1|36f<IY2gPX%"'ڮ},uS<;;}ųWGGȲ󋋦3Lr.O?27_]]^__	G Pj|[#~yIYj 0U9¤̒kѥ8g6)"1ؖ Y]U^YQMmRJUݔE;}m#"en6WY(L Psw>iW}ًWu{u}1JY:NRDb}aoD@UriJgлvDP 93`IswW/G㉳.QQhNhV"eWRHX$
{)yf BCE8gh0F  r{	6	
V~{?ϜsL6YQe}}ڷb 2yqQ\VHJK2'ˮkflꆙ"̊)k1Lr_^pP  Q ۅjZyNNe矾<;]p1DԾ|Uux'</GO(x4:bT;l4
E m @b׶u6]jX4z^ֵhuY6|>Z<I2IVD';C,:i|<EN<If|:yQ^7ˮRGNKw1@E0C$BBsVJo^b33ISx8~CJDiɫDzRXmmVÀLDDw]eAkkmC(1Z@	VQ@P!ǡp#%mh=Xa$ۦ"'ro6L&e5R-G凣>sfkX.e26mb Zi&֘mo˗eU/:L}.I#%E4 (]Y"sbuX߮ߝΪdHBZh #sa^7O<s"/˕2Y0)P$;l,ͯaǒ͚I|!V@[koymה=w-P;p䬿wzVn+1qFܯ~m_vknF	m÷.}{۔6`qT/|q=_}lm7[x}oio^BwQzuqqѷMF)4C>:sM}u'`4,Z벪ʪ꺮oS0JhZ/MۇQ@PL2Xֆ"EbH!ˋb\UEYs)=!9JimǏ>L'HQsb6Em*ǳ,˳k[K(>c1^]6mL1/NF]"C ak(1
ur~֫e!E# 2pPJ'5@&qOz	6|bLM!¨*zIlpGҶb"Ag mWFɊe9Tj:B퐢Σp6LG5Dq}WZ+m֑C>O>ryyuy}}X,2mU
o!@b>`?dXCB_UkfZ/ ڄ.^]__yI)eZ'*DTZ@4
mN!M뛣d PB,9 7Sвޒ/DN+X*SP"&BqU :wv>tm۶~o>/<yZK2R B1F#0iۼXka^'~^/non,&QcfQ¸;[Dn-PVFPڦi|>D(bd|߿<;_\_1/Z("@{ɓo}[?<UraZ9U]
V%dz|`f`cVmX.ooWWח/zX.k,ϬQIk@@o
8	DffQ֖㱵)񅙆drr|Q]]^]\YRY^LA%dk}ߧ)H \׵>=TiRQƈR:E
nSE $8KWaT>-rLպ;gIr bJ63J0S&чCPF;5"|TP޷m#j3fOle <-e½}{m^jA2Ʀ1Ѧۮkūd2Ux4L'rFK!skM׶Y?ά)Q^嫳m~GO=O>s.P=,	բD Xo·`Zȝr4l283{ڹvJ) F&H@oVckZkN
'.6&@.o
0{{]%pSK|[e}g/;|K>ks^]~߱_حپ:ku&Uu[8,]â l<Ν=oYO~~Ͽ߸P;Ro39MX.Dl]׶]Jc5MaD&qQ<ϲv @Mk#qݴ!2Q *b	AF4YQVeFeb&
gV7(l\9gөoVmD    IDAT232eutt|?ͪ\9S:'l|wm}d?L&%d#%
1Q}O'@`Wׁh>aGǫbݣGA97>y1F@=|^>Řg@%^];%(\Q`փI?uw!|1EeV:D&aml9eUZeyffHije5Z;kF
11kfѱD9{uųg^>x\15ʫ:(%&E*]!o_p$JzhҚ|o׽(1$We1^_/<<M'l>in+$J\ԶvxCxݛ8(hNv@R@t L1xXoW{yUuDbbLbXX21Pon}e5 MJ  Dp B(%` @t3KH lONʲbfիt(t^.bUU{.|(f{>zO?#ƞ89:t{DccHNYWV#WTRHDMu}yy??/ΒSX@ (͂9,j䶹$ATj\GgO?ժ! ֦(l6ۛF.
cjjIC],JqAI񅉴֨ CM'$Z ЃkZXPњIE)c1
R뺮'U28h]QB	!$ļ(sV+`T	! ]w]7\< 1YogKTWl݅{}d9RYY{ͫ rY^TcmQ-7O>yٔ?~}rg/^W˃Ǐ'?ɫ.FfUfh4 ) `&%6t:{5M}hL	^c\WYefֈ&s|\u!M^.ۮDB `\qyY㪚YU%b6AaJ᝕% |euOm5O_۠?߲D9,}/!A};rp޵)#&9;iZ7>;n}{x;ڝ]n4 H}~`Jz|*_ϯ}"5*8JD 7FcZ "﻾kʲ3WŅPDD 0x/O֍X]/)F1QYk)mދHчb"g(&rхqwUUj W.^>_]SZqUJ@VU])abwhj`o2/5h#JDRJrCU|pvp<
G(gceV5S}16FxǏD8x}ssr`TzqvZ\c0
!I >˿`?"жm4}RqރDID քw$րk3&'cFkJ>C`yɓO>Z%"DV0`1 =Q1.fi2&"c"@QpmZ#^qO'?!t}Z/?ӧ?{˦isq54T1!< Kr!>XEL)^emecب>mD	+@(Jc-hDUN}kSJ%#К$q5ĔB&ED%'ڲ$I%S  0KLy<"ª$3
xu*\A)tT1*BiBw3Gh̹s DPQ@qLQ6b0Q QQh-}ﻶ>zizN?R&YU!/VE JYt?<|/l<Ou.(F"ʝDDdC@A	 }𞙻Ɯ<|>Z^_O?Ut./*Io"QkZG뻦IQ7""bL5?|o6~ۛC!bqZ,/eYeQLGYS9ZV$Z̙t$UU%S@BW{	ya(mkt !(DrB(
}'̙huE85ҔJڶf.l>¡N(xAQPP1.@QU92HL⻋W/W[R*6%f-Mh7*G.(
|_gd?O5D4O<y?3>3M¶]S=FESI#TF37*xb^)m1e#:鳧^vw=:<46C3׫H<g{c#B5MY-NeOFcm,+]
r"B"ֻ
wM-A`ܕvmj%[}5w7vU)u_yoEߊrkZAm8q#Ǹ"
;`Io &j'jphw~F"KVM}n?s=Mзӯw[ѯy_N}k (

3SH
6Z[!* A'^
ReY5|ߥz3YVՊYژb"K"@Wﺮ^.&{{UA7/׷è,&h4T2D}N8+.(t4+}=:R*E!p߶ֺ̌ýd2rYƊDRhO*(1{GF<ϫOFU9C]]]_]_c>{4W`3b|6~>^<>'j0
 yPHEnRvQ)MmDFYX1)S"3bVEp Ā }ۄĢҨD)aFWQQzyۮn8c\.2W<˴B~
¢˲GG>yb>yqyqysXիm\fTJg8g2QNPj?'
DlT0͜=±o}tx2q%j-%	VkZJJΙ'D`zT'B)B 	 ϒɋlRwZ6hS
L Iybw[&;*1ںUSW7j6iO$ D&  
	lY6d"ĩZ4y.̨ H eE&Zmz*be	"c "xh6fum^,۶^%K/QK]64N'ڲPQMtTUX`V)&.!0ҚiAoJkx~sE֫UӶp}ssxppxp谚Lg?ۿmZN*cXX FY!zlۦ}X<Ɠɤlvxt<*˗/?eߵD  r !xBh9dXks|6'"ߵi6ODszhXܽa!^H-W8mBLe<uVk]7 jC!FI]/"9f<HH1Ķ	 (T%\Ye42rKR*u>6mu=fy~( m;!rF'CH ` XB%@L$1F3$٤٧ýQS(x<FNhgPiueJk@nMdn9dYVUU$ck1KݴX.F#-drEYJB+xҮut|rxxٲd2kikO2eeXmݍ0
Ai}G6SؖBbx6ȷNwevN~{t|{3_C+ߤ:4eMe'+j%6 yN45M|)~;&G|}q½AFu?ο.o*-pzۼq(o;M;|(Sו"GS몬ZTapʢ(s2#Q׶z^E(	|O!HcjE}7]VUeAV7L(˽nj6D"Ĺ,r4"Ib{5QaTJ'sZWƮ(Gi9͑Hd{19Ƹ̫,C/N_d־aYb^7mUU*,p+B$BWK,]|u_GEʃn$7>a6C슈oon>Z;k5 % &f8q&P@m!Xk1BjчZWej<)Rk}$`*&@"҇ ^H)| ]rt^<;=?;]VI0y!|!pC)FH z8Ugt|r|U\,ڮƈ1j6Ft(
$3C+ڦ;6N7 o^F	8T6=}JHvޭL6G"J{ؾ־U֫uq>5	w=$?YHL* 11q)Lϱnw N	 'R410ۭ03PV#  lTf	jeQ*^!Q붩YXEs[:OΜ{C)'6 dȤiD`{_ɒ+Mpצ}˴a73!ǐKHa2$V`g%l46e^=/52m`4@+͛q]c}|WRSZ6;A1}G!x5]+EGv}f# hBieLeyQ*C]ۆẁBTU?`4u8}z#	)T*?0ʲs;nNyfʲdYYft}4mӶDCH1AU;:&/R6 `#w]vm2Ϝu !]B7hp֦6.)
QKEYFIr8 DھzｐjR7czA
b) IEC؜s9j"e7L"r2dպU[heJ&Jmn,B7:%7%e G/Vz<?wo:s{@nZVMcW:s3un;p05پ{r}؛,˄4yUUBi2&IbcV:}.&s{E0&v;m_oo:wo4>r,onRJگq>-_k;oCq}w7v:l~	;gcn.?ƷMvx=ﰻ5o?,TTUUwb3oh 77jmO >o`ռ[cQ֓42|RRUjVK%J`1s1x1|4u4c-qt>"'j w!s1FL&
\ B_ΔBJv`:Mzl&h%<chwѻӃc1خY J,TR(ƃHYм@)+!]tӇ(@Y)8lb9"
("J aJb42Qcj/|3;;k(`Z7׋eV~wvjڔ4`HOd'c (2o> $-̆J!CUH(*L9l2)YUŰ( x|ﻶmdQ1Qzr>=|uP
D\/NN(PLYTjBƘd6sY9鵔F)DH:`Mۮ۶BAR}e{?1^]Ͽ_]\f/N^ίg]7_͚f(1>xcĂmb:?N..j"WRs$H )PJBVd[,4iͥdB7SnӏB0I`$qmčtVq`/ 0Z靷ι{h<ZM"Sfbd)R6ډL#C2KS㯘dDQm+3B!hRJm^-?|>}r^۾;;;M$5K!SC0Fbݴ,
,3M]u]e)	ޯWKk{D,ZJIJjKQ3LBi\d|<7]m4ZD&o;C7] UOt:ORR6M\͚B10Gh<=8<LZ./ŹA)pd	! kUM[:\̥Ig4eupx(3cMsb6) $1u2	Xh-0  )P
D˧ 1s>ɁzVM+Z/MU$Y GR,Jt/B
 mc{K!J#Ie 
i( h &)fy>L! 7c[yo)FH癉(x>G}躮R<ϗ2cL^egUpY{QJ*qy3+)bzH)m1d2~C!ZJZ;kӯ><]h}N>?xO>?;;H?˿z4GVQ\ @VEY	!c</RUgjw"`ܤ{6R	Ȼl3($ȌZόagߒ_:_6ԯ½|ۻvƁno63t['f*_.u`e._;ګY߮1m%.6Nշ_ooۍ=Dt\6_7}}ۍކdÎ 0iYVWU]kR]RΕUE!/tOHBP>xfZ'{"cHE!!FNQp` HB  1!PH-Dmt2ӯ}KgIi=L<ztt|8}]YI+1`oh(d>eaC"QcclZ	 
yQ( T''AY~OGɃǏ$%Zh4u,HVڀP"5mg 8M!Mل7C@-:bH7C1yVyizm7ji۵[\
}mڮ_Vyf@A=F0+`!BE=z#%t!	dHԴ}n u=ge[5m^ٮu!Fc!*)XMSU1@RHmieߟ< Dur떋^,`4Gb'ϟ=[7]Ҧ kCBR
H!	Φ,qfrrG
bv!,(.
A ;x;I')F 	P(U^փyo$ IG{\e">E')@qcsP"R/3h(bLpkN"K)UUfV=zp4Hujpg_={bx}    IDATeY/?UR+,FjFtoef2R*ȔtY_4rֆ d& s]VZk g[gãc!pXv(pT֚zv}o].8IHFx<|p||ozpT_gmtYVYI)8B[n$BtXEla҃@bp],$
I(XKYWV!T&L9G1z!$Jm6@ܾ86`"WZmZO`1`4Όdyʘ"y
IŨs6O2tJʕUUV )ٓfHbY&WY^{F]Q|B}ץ؄:+(J))J+)ޛN,[,E!{GSY!A<'LAet2,z4:7@1E!s4"e&#?◿DǏUUeyYdeTB(x71އYUj4/_//Ͼw}~o\BHz>wW<3Ef<KIB%Ekd7hi9gWλ @ieQj4!w;O u3NJ)d7UGCνmuNn{o7&_sn0wD-CJ=!`k^?cr ]JJ*6q/Kx~ڠЍ'z'wMxY߽[6mnaty#?owr|߃+ƻ5@i/m۵u]3V8DB<އ໶,\I<BM[UH1$0S&Cf(~.! R}Q4׋y R&ӽ߿?~=]&P:b%@0j6	!"Cd{V1AJJ D<rp~qq~qٶm⢳~[/weP/\VJ)%$*Q!ڸ1qdb:(2 "kSx "jr}w5U}[7vֺ:}}TpPho7u t)3TRe*2˥Dֹ]B !"-|^{z8ͺ],WUbf
(0SD)PI1GӽޅozR``ort|م1/j8Ms!tm4M^eYfF{ۯ''y$@D)D1B !ɈoEcR~R BCD&7oi#\+EQlI;7hOlb[y+eS=EZBLQd2zcӕǄw%D(ps@V۵-t7~Pr"
$HE""B (
Q5\ƇG?B\5]۾R Q(e1dBidBZ*)eomom^QV ,D@5ebbǘkRxB𻴼뻶mQ}m
PˋvE9+<3J3@}nu)dEBt:峯9ey^Ue]K,R&
&"t#yH}B{1ZH($wvմ9!b>HfuQhmP%#1$4n{K)vAD"Nh["{EPv	D$uamỳtR*ϥ2pt(],(K4 o2tDFz+1d74QZDwp@ٻnHygm>c1f.\)J	!BG'/OWu[r>WJپ*+M^,T,CTD[{yu\-22d He+)Y5mh VzPyxUAJg((ӘV dUUTBar~cmLk<|x||kˮ7{t}VY!gSQ%)-H\Dmϟ|^ArևUܘL{E5mյni֍Ļ?^ߔ6%ެ;~kѿ52oo$0o/(>)x䷟vO^޾7;N6u{ho}8FJ؁Won6ۛƝàܖr]zPhͯsv8SdRɳ>>L
:kcКB1")fYuQS?A 2XA
ﭳN	]r)rLuDglL1mZ-#(0/ptw?zPQ}kmKFz(MNKITy(u {kIMI	HT
R|Naj.fr	(2?O!SR'NhSy' 7:ƀ :ˊ~bn6li6T wA?!҈<AYBRpYE,xT{g
L]U{Ã{GA7E!DSl@3wZ+*))q[ >bZ޻ʲ;nm,ԙR>s ()r{Ӄiq\3 ^VC=ԣIt\>MUiLYGEfm
ɓ_O<O> )lK[V1aA +RIAG!=AғK@0'd COJǽ\zIId@Al6% w;HG
!2^	|p!F
,9O1<	}і%tHD	o!MR ReN$(nLFJetZP0 ou#ǏǏr9ʮڮk{fYpb=|,r!QIv}omj:C&
DRFʢt>]j<*sN󞘼@أy !kފ|A);}Ӷu]3b$N^8=yLTI^.ev}oc(J,ˊz8Oz`Rx>g_~9XTe]UYcY۴M6߇, @bJ\)UJEVZFsŢmZfF)s1AY)|!	!RN5HĈB+-1`rn$lbDizݬW+=;Ώ'Q^&+h{KDRRE=̳\I0tHY\"wTgV*ŀn& ,9w	Fo z}:BTݠ*\JmJᨪR*Kf8;}yhBU=ߛ|z0Qynֶk}R4SJ1OޤʋggONB?R|2r1ͮ./c!RI B,/`0c{ @!?zvD޹*˗/OR}Qb8_7ɨ.3DDJLI
mTM߷g''/u=hx0$flۯVO^~7Ū!\) <NlMnL"z{c;%~{n&joF?o'UAnM77(;Wg *;~׃)oNߒze;{}̌5Ϯ%M%y  xw[:=f%
E@!v([^ۏ>K//>ZR#DBiL}ۮW+fVRyuGGEQBHdZTQQeYeu>8ki[!Jh6"0  3JHڐW74s`8w=ֆU:#
)S|jS& { c.BZi.;ko}vrjj<͊<R\f}#7JWE׶c$@Jw}'Ż?#au}[g 3PиI߻,p܈"nN"3"7]߷]Zr>/isv]om| B)PQt{OFú@rGǨyئdmV˫+t"/"/,?#m-<|TzfWZ]!<Эu 	 1<?1?:mwxt<J'7qP9Wg;JU*ř!򲪆r\.a8E%HBYli)1ik0cedV!1S703冋4Ns2" 1f	""mYކ庙R 꺪<ˊb8<~_Ӌ| G>)F܂nflsHSh71U&K韘]$fƼ?yуr8AUU _b:mUӜX-j]P7JeYY	-@RA]sX*yu=[,/&qQV dA"eYsiwsectyulJY^T]dZehBy'O~_=
(./|~--*s$2FMp4Ee2`ʪ?/]겪Yrm۾mR(ؐ?qs0T
}"l	sAnoDHbquq)EU׃z4F,ϥ}׬b/Q*Mt}$ (d$@ѴMa H)j Ut=^^_g'f<*E-phI򢬪ҚQR
fH)Pqs; (L#C"FACnX$)CR 9mbIYE)ʴ;n(ptRJJYE`!F/f=|Y>E !e^Ӄ{Ghx0H:uzm^]ɼwD<O:9g{Շ|{?sv}׮WiVMZ7]YbLSbT} ̫B(eYU@=f] !O~~(OdO~/<FaYUG=|xP9ϵTm\ۮ{{h8d|uu_73Zx2몒RL|P?9:*!9p`P
	`7Z;*]qKBI&UfJoC󕡿!#ֹ0єexmI~e1}'4W7&Dx\ֻN䛎xWɴoy&n6 ~CMybߩo[pM<i;.n[NO.ni\kڛfnęQ''/>⋋kvw% 
Rj.x)h4Ƞ1"
Rl1B!HD%eeZ1Jݫ)%&ޮc>"R(dgsޮ'b]]gG`m2c)e+DS@D^fI@ RgڨHmYfJe3>ǏVgϞ|lkesHD>CsG1*" h.ͅ(8&a۶ι`]hzH0_6uaD)RɊ<+3=QgB`6y^xȍQbU#&R d&/,><??_.1- 3*ϲACʴֻ펖ˇT)JYeo{#'@>ԥB\hb}׍??b>g'/_^]]fWY^CH.J`I`^6Y^\UR_+kFNy<<#Ѯ"߶:`@n]#Z*uΡe;~׫|>;::~ g
Z-OտWh)RN/)-n L3ɳe 7<!;43PJr>g?w[̮.{n4^_]xl *<+G{e[lT{?~t7˲bLCQg[||e"x3SŠgպi2yY*" \uWWjUd&4rR)IDm..1ċT|#1Mr>޻|wp(P$~gO>eQV:k6@<+L
躾m9"I#$ 0˲<ϤؔD"`J	Jd&LJǎj1;WEYAfx?GOmf\Vi61JҴ"w}b esn\cLKت'eU*) 8"E  P;>TFJ	6sJ D]Z[	lDbH0egh)⢮*%zZ,ʪTJyk> #בӓEQN&t:,poohsS]YgTLq8B!b,"/33C!}sdHL1?o b k-G7_xF ,ˢPJ}Zz!D! ].s~Y1oVj6":
kVjevzVŠ3bѠ.6_fD+&M!ddx$L7[ ޖ|oMXrtq02Sd>ֻlk}~6
ޞywT!Vw{6֥ctA"Sq^ܝy0,I	܅Vvþ;Myük;{nm-퓀]N "ܢA[]'|rvz꜓JQ"3+)Q4cV.+R)]Wp42N)VJ B`ukzgf!8&1-n&9-m7
R*UV2u0H>!iBR*si2sNcr1]fBȭI/BJJe;,j1??9rc2`<Mszz5tA]ߛH!bZ<z=@캎	M7;85lw(]p9zI0$[wZr1_,R2qZ9kI)VEEQW*`u1YEGj8uURi]&o. Z(-0FcR BIF`wmH!h)1)u0ÇŲmRr/Ld t̂933fE17}ߴ8eUWe?]flW]^5MӴ큒lQ$:(<|3X5
qyq&   I#=޴J١y7 	w˓cR<H7rabʪ,W9?%NAf>z84"}X S"MXVNGretӦnf(+?DJ69{??Y*˽W|~Çj>w]g$JMw5[F㣃,sPѣ=~.s!U`|f|<$I	!\B	Dժ靔B+rͮC8{yzvX. *t    IDATfeWehk)0V-)zP~߿ɋ$. J
~ڼHUEZ(\Iloju}ި
g(b^9ޚQTRJ[ 
db@L1F&JDPZ)\1j1e9z0u])I)Fktc}$)QJBDbb
1&l\)_hGa7+|"fYV׵1BLz(}>$`>H6(T$eEb>B$vw}]

ƥ (x<HTj%]۴/KRʘ*fJ!R].\EQu]"ST1YUՈ8cTE!VY%J"SdM^۾(x]m0/'x2J	qxAUd7,jzjѺﻮkc/_<fpuUDr8MƣkRm+B}ߵͺ,
bLSfN|ILqp+{kP^n|80_OuOYx;A~݄}ôo#jD?ߚN{Xx竻7y47~m7!|&hvoh]m[ԯ*7.!L3}Fl"_#OO^ſWyQ9#-3˲(rDw{o b(܍(RA,
@DT*@ØIr)8N^,X%DkAFRkcL^GbCyﻶocJ@0y#V+%J)1&Zi)QKF$	H4I reZicSSDϟL&eQU7}y0|#9gh4  c~ J*)0zD$G BIBB  c+>("hQq]{1\YfLm
bZdƘL񰮫p7uLt#dý`\͋}}Ѡ>:?ߛLqQVuUVe9"f\j}yyq~q齗REQd<?Gy"]-f׳lt׋d1Yw_|~m//\1>Z0eV{㺖Z0H(jJUyWd3Yg/>}\2!11naؒ B> cZLޭhO`wN)iS;Ia4
[&%B	zmmo}k}gϤ+}_Wwӧ,YC8RNg	lq9_x񉀁12ͣ)0ǏIUU7s~yX,v&i  K)x|vqy~?mVsB{?OO?.`;ׯł1T6Z+c̭BFyY1[\%	ct֮ڶʴw'gWR1R/vm߮s鋓Z7RuNC-2wS$RHkґzLd"w(9?_^x~0LԶb'@)eUd2J^_/gOW6.*A=9u]UՃA=몮S(61 U)# V/7+ԯW5E2ZՃz4;8?8|"m7>??]]f׳k"(m9  G7ZBH!Ii3H!/ZeZ%nFFv8TB bBfya[D0~ Xg$':/)$w!} 3:3ZI
!m=, TŌ)&B 0IY+mޭr1T{h<&;>?ʲ,2+@a*2caLC:iR1/'W.P!eGmtR+!~~zqv4̊~11Q>8Z{_5yo/O^<}ˋ/?*<oQ|YV˥(Y^_Ϻ6'>'3lSbi PR%>v"؀@imo{v<+oxm?=;^mA:۴wwo_KqF7&WowZ	+]|E߼ߩv^w?ZCV^ܝíkY0 lPBocwfq[jܩ۠;ně<ӫՀmvn];>{LQ ɧȱ(}4^<99Q!QI9'p4yAD1c(%AX ʤ*R)9/@RRd' ƦR"6w  !Y@l*=2i뺮Y=z!&n>_$`FD `S)H)@DD!XU^YcS>RɳnP{kzY1b@!޾??y|6K-FJGLSօb8jۛZRa{j{4M׮Wv^Nk5G.Eb
5dY),LWe9;Ī(`0222?=9W/_<G v\<}u=NFɤhd?01uZu]M,/B cʲTyx6C;o;w}׵+%<3]oJHvuyC.w޹7Y>(r
{!fsKNӃaz f׵]
!J)RJ"7ӳs8b)R$"G}(1a$	ҍ[TSFQ2EV$QIBJ=x΃GuG!|w{y
mt:Gཇߟ-z\̭~QJ "b)e%іʂ"RdBQeB	%K^dIzXĲi9[=C(@	 A@ Cr3Ӧnn=sﭚaMk>3Wf.__pLU9 /_;km	1ʹɻ.!^)~'7^_܆X"J?OxfS"2PRH 0inhK<!,WzY]ySs(kR*˲m`{2"X7m6mEY?~}?{9xOVw^>zxnivm6M(Dg'͋˗ooC3T,B޹,˪|}kxuVO'u]UYEaLQeۮJ{H&o1BJaV(`\7ۧOimVU5O{šmZ
;(BRC4Z1QYUUic
CH2̀ QǛŲE-`%r!:)RFEwy%.F`!t[wBJ@wb0 3~JcDf1VkR޵ TUwI!ֲBxcs R+)dYVugYVVuYOg񤮕RB\H*	Je~?{g}OOy(;蝏YOrYok+lu}}s}sy%C3 @BTJ9'yu_u[-,,[kFA81g6@jssu5Okm3=yTt LDB-W7mM'`}w"A{vp0yF}'O}+	ۛ _9ｂQ≑ysoὑ pa(ލ 
/nh{$mKshw-s/yQx?N?Wbs?4Nu;7?fV{8giumb!
kz:BTUcJB #To<"bL%؇FMQR	9VHHa$ީ3CQ`!"laZf+ edtjk$R*M#T(#1A"fh9!ts>n׫&zgZiZwDD0	 SVO=~G|Qu#"'Tx<aQ33CvCws{vm6ۡM&Q˫jB,2c62k)s[dRO'Z)efTӣeE&"SJ}d2c(&u=ʲ'UQkG$ć~pлaH3mڮfFI5%}磒2Z
lEO tL)Hv{uXB+iΏg(<4q(Dd]vx01|v=10J-r\v]/ J
!DҖaOvq(2
c0(,Pȓӳmf󣇏{DŤ *mҩ
\iNQO_|oc7;1-FDmRM2Mzq)x:^/jr	,]t6@bœGy䆮oS}Cn1()\Jb?e?|ѣژfCv*z"R@<ƔΓStf4mw]4!FTQ@{nC*jSdV
(0bOHi)һ}B͏Ί<˫drtr|~eƘ뫿wfUR7zi!DZM'|6N'!iy&ͦ4@)RE5Ym@iilγ,̦eGt,=˅ A9ȃ}m^XRk}r|t4!87]yw޹a臮KH*B !(B"@ FJٵn66ɀ	bD!Rʋ (  t3 䆾RPf'aH""E@kZI)wc1T<7xBI9)U"&ˤg|R ؛>z7F\]E^EQu]EEQeYEQ乔
 	5\7lROtRWenJ	C<JeM6sZfvq[TSoJkcn襔'FI!֧{x~Q"1
}Mni[v;n\u]'{՗,%%$@NAuFGR}|uh{|7~\o;a~?yIw_.!dݷ?@>C.twx`	A=n d?ކ8o74>̍ƍO$?ۭ4_C}w]mَiq8[B{4oXRl?p+"֛o~Ϟj@nXLgӓzr{ʺvrB;i'6  ʳZHB""Q `zGr"b FI4a}wc1wm
0sMV]m벞ج@IH6˴JQK5 `eeQ@p>*].s__bPrlf2,mRDCpD$
1:>}Y]^_i) )cgŁ <&<}3EB9;罏	B18bl6v]0`QUQ<ˬ5F'#*LUUӺRkev6H* DۮN'?>zXܬmӴm|wb  VE^Ud:Ύ&iYeY&uYf몜M5m6]n6-o%Pkel:5&d&/jεBJZ)n2ڮmEofb̋x>d6{pvZeeػ:"H,3c0n7`dzfpF?*IRB]7:wC|?S8"Hoc)992ΎO<x'I?/J!$%cP&f<իWZw@J!Hc%@"Ns)&}B$ޱ@jZXDٴ]^J)J0(ǀZ۬, BH/@x|0N_]^ZUmiL/踶,REm-"DMTZuYYy))rk3'PJ>J39=C1pEYn-
 з6i4HkųտMkX۵7m3b8=OSbY7{kY΀C|bRW=fW&5^\2x!uZo̘ȳ<LB	dڛ5iL
{x0bY &.)@	DCu]EWeyQh>y1o;׵M"I
!1xGᬤâmd6Fw]ckc,ϳ,JDPj-Zc^p$($La<vhOJJ!]U1F!2pxJ+g!fy#"Tl.%fRb@$ɥY-S'1Ȕ$@FC}:Pz2ԓӳ㣣4TJ+eYjճ>/~ŗ_Ѭ(,ύR*) ֧'LH5?:Y,q]3+L&+c6SDDN	1z|..on"2e0zsus٬'WbTt6(ҀUaZ)( >|[iD)?w%0ck?q:SKM|ǅ|v/t	S=wms!Gb	"^Nf1y	Av#O@Ok
Qf'B (Lǽ$ho}W;qz8ݟ^	 r۴.Diw>Uu$:::	F@4}g3"PߌajB2RK9HBsƌBJF)-xwِ"Q6 @1xw|sƘOφVumtV)DҾ+en)F7fy񣢬Rvs}u4?/^VZ#%\OŭI>;Oj^DN<n !wB1 k6d9e^O'lW/^YmNZeyǵ*2ZLXkZ؊bd"Rflf9E}Qbεml׋ۛE\My^3T^UU=-몪'u]ד<Sbl2M&Z>BD޹D颐bHA 6>y#3"hF	SOf'~	!4ճϿ˯j۴p4>{= )P"2p @Z'&-ʣ'1O=x_}yqY/VJTs1t!TI5JHBG~`zz/~	B$` āQHR-G@}fӏ?WLFرw+F)<$>)2R &"qnO#`:r2K)eS    IDAT$fEiRJsđ'BF!{v_L[b8DޏNƌ:MY@m3-1""u <";
ācoHFtgG@@󇏟|.,8ΦG?kz6(efmU|1kׯ/\F2F#" !%BiNZ묬2m,TеyTNNW P̳,ʲKI;<G$FFR$VDa诛kDVBdEUTu]eYf{vnv6ۡ>x`6* բa JDߦ1hcf(!w1:+J#D*'h]KуE(D!)J
1!H!#"!c{XZZI"޴Ts+<pmI!6Z
RHDZk%BX7˛ۋ0@fӳO_CW_rq|49>~p^e=ˋrc6F.EYդ(\kf	!,W+C4g
!Ķmva:nn\_]>}j6۾m'O>p:Vf~I KѶv>hc&Fk#QRH-&9rGcZ[$Ģqg3  ]	ݡDN54o;o(HG~ӵE?wN۝AN-Aoݍp 7nI3<caT
؏* =@0.+F1]5u7u}]e{wW׾](pw &%F*
k4u21yNDժm["βl>Yk?R䩇P	E)&
D F-KF}$k)
!Βox@ 3^u4b$BQH 0  vrðEUդN,+j40Ƥ ,\"C><;Ÿ]/zYo6}w}s{ywJ)hf6ey.V	HDS]AkS}/BJª >P@ AYiF @i("1B,ۗ 9zQYRMgetnFfDR%T* y1,ꪜ͏ONj#
Q]|$eUYv=ϩ?=i{nzzjzf6m\fY癵y2ˢfI]eeYcF'q!R5J5fs\7Rɣl兖**Pd">z|rtM^S'"ꇡȌJJ)Pf4#,ϴ77WG9Nl~b]._]Ri$Z[Y8q$,krbB
q\Uɇ~87\]]-f㼃,._FL P0B `;m1`Tf*-(FD&Je!{{Pf H{9"M9dԲ*R|$)c]۟?|pzzfzR?~+THd,@B
&)`4rY rtʻ790 *	IW
SFLrZ)_\ʭn說&t:Ezt-R)ufV
Jm5ͬ5$DeR)Tʹ駟O~|{{n6۶oۮkۮow·ajˢȭZ2
d2#  pMjiTT Q˶\]].Efm^&ˍͬR㓓SDеo (e**hTJ)mT5&ˍ6YfrkuޣBc8 q^Ks62"q@DܘjcRT%s>#
RT*@!,uR7w7D*-JCPB@(1Ʈm6]K~hϿFUYU]Mٴ&Ig?/w⫯AH&FE^7ݬ=|P1\X׿<A=;*JKaXkfEUefm]G?hmEއ|0pYf=8ύb^f~qs#LcY#q_dvX1V)7/3蘛F+23F)-J>&7$=K:p#hہ=ӊ;M@<LݗwwoJG7Gqpq,&{b|^&hm*tC9dr;6O,AtxZ~q;#3wr?8zAʲl7ɤ*<}:W')	w	o(3D@R.R*C?CP.13^wtd$ExQf}cLGI}7Mo6zY7e=5ya-
7 FI咣/f^vMX.u׶0熮nWt6Nh,stà>=;7%@Z}}/E?B #HPBZFia@tRYdC׮n)Χu]Ubp9Dke1|@
alRUmd:;*2E*!z6/\IWGdH:c}iև7kۭ@DY^RJu]eQeL+i)"֚$P*ZHUE*].W/^4e^V|~t\Oj%@123!T[ՃzZi<) w \p{纾!>ӧV\yYX;tw}]-no.^xrujh>JL,I>M :?)).oo/^60BF_ѻ LQ7)QH%J)bI"#"жwc C^1]D Ci8<1yan=t=8a_QC*D"LI!F;f3kҲ'u W7fȋϟy"SplTG1$7V1"o Fe {1kdTGOvXxo J*@D@!Tu 2:{u=t}SR͏뺨z,<36OhHe&1"G1nzYomm۶imvm(RTx3AK81}@J!-8F#} &meYf2k6EQؼ.zO
c"~Sփ5@L*
.{np{kOd @͌q@)鮁{?32I,0UA s1ik;Rn^rJ+TRCbNțQdb#2+Mlm6ˊӺ>TE5ɲlV]W\*E>ubq{nF[xzϛ;>=;==fl:TEQMZ;7D!њPR"wVF@n:-Mmi&z6x?ԙ5Ef7M^iQtZ֓r9}ڃ֎Zh	ZKeJ+N	\uhVCa|=b;Άܛwv=Pv.o9>&'tswQiwz1u<wO7lw{3lg}Q;rp~DM7UHcC"KV~&X"@1nDJܰ\Z%AH,vvK1fRj!1FHE1ZjJL;Cv>͆f޿MW'H3 ;Ml '˔)C! G@(Q@qgv7̫E=OUU'T9}B`w}ϽwjZnWmp.;DM\_ܮ!"N14:Pxp޻!x/d
@B&˅622P9#O[jonۯo./mfg鴮f.ϧ m.|(DhZu==<9:\HمA>mzR͏2ƨwis' #D?2:;2_W/_\,ms}[MQNgBa7fByZ{|z>giQZJnfJ!bf=G^~mQ|?ON,Χ$FۦiN e5Nsk{纶}m5Msyy/~uqb|˲<?IUJ[Y^YgyQLj2?֟}&[^]\^=}ꗿO]]^ۮYR!!2Y&¨`zO{?l:nSyօPhBҺ,ɤJw]6Mw޹C۶9`Xf1៝8"@`쾷TE@`4bE)F1"A !u%RD!&InV2j\^߼4ԯnּAR DtT̘2]iĺt@#D>&=j)1@;1 9a)I  /\.12/Gz6Rzkl^YUӓGGuQIP45TBP g?_\7TJY鹭&HPA\ߵ9BOzyyuuuՋ_xqyy\o6F UV`R"B$=F  PbŘ5fXaIr c^nnbul~t|(Hznڶ٬mK#1F&d#R+c(rb{ҦcX8jw"G@<A)ء14kBt/Ai=hZɺWmNiMSN!(
y,wwR^9PP$ VR3`8}]E,rk<gf
Nk-.o_DJ晭J2=~x>L?6ۗ1Rm{{GGRzv}tV?G<geU09B*T"{_Vfys{b4f{"Z L=9n7a|A9NÇO>>scܬ7Ua"g,fl-37]GmRZ\eeiuJJi%L(&݋Jy	<$̣dpN$
Wn{3c{p{bb?$'P}3oWo+1{`tHă4C )ރ p?^ۥ*WDĻ)@aI2]AYx!|fݳ}[*qx;kE|o߁4H@"CͶm!z_VYlŋ}"`<( Qjd(!'v6=VJ11făRB@bJsXKy.8U<v1*PB
H1} SQ܅$S"u]ǀLFKys\ ={UZ:纾omb4z^6wCde YUu|e4 eRV}3j^*!D
Xy9|pdK8|Jk XcחOŋyͦSjDy+mb\۶Mh2MglZϏ'ّ"cCt22s+ D|N5ff2ҦRnD8;>`2MGjXMYd9gdֆ֫嫁чxssyuw/^#ctЮ7B^O~ϟx_[^'}𤮪(1quk6Bz2{zy}2l]fI]O>}Y?8!I }.æmؚtQ*gGzOlVW/~g_>}VK̍LٛX -1@!_EDcQiُ~>SR~_~rXE $`@@)cvTFMѐT@CG?DP $(#RA$#(H)q8GI72K
oT]&Dl,'Yݬ)G~})@0RyY+2/֛ӓ]Z.{[3)ZÅF
kTp+]HYOqLČL3I11{%E e~mr1'hMw||~gWIe h)Xhf
98?j;"p[׷im%V)tusC+DV|GzC
],ˋ//^9@̴cH!@H,]PIJY)[ B[c&n.W HEUd6{izv={ou&vsCEDvY^1f~eA
$"}ҧbD9M>(ٌ1JPBڳhBkL!@(ж@R	m<('R*J%	J: $	18c`f3H!!1ZkBB$욠)Ÿnkuѓۅ櫯~%
a&)~r_̏Og٤fTZ1PB*!|]/7kONϤT[1H$E-EbJk#i5^=*7?'|wݯ~OϧM;QDu0]l r$ *eB)՞+F;Ż7R  Fk ;76_;Nr
cBcŮLk71NZ }ƷdW2 ?^ȷI'!!rg~w-	|$ ]Pнγlw; %ߝ{@& fg'?g_vֈ"x~||zzmVFi3˫k$ݸNb`&(gY^)8Fh,k cy N֚9&%zHIBPI50($1F
B!K;@d`dލH1]z'usfdz=%'|K&uS@$5G#Ek|ۛ뢪>??w}Z.Tn\q*tTB3 HzbEfc0W~:7$x(輋oۮ;h)M'NfӺl~ZT5DO"B#D:+(<2)c2GS$p.haZtm#<=;WRfyVy5֚B=)Wެ^{uUUO*̚u#m2>M&SBjABtNWͭY^fg/!$3ġk>[k?~i5e]]$RUYM)h:Q9C<3IHr "jZVDEfdV{?/7f\\sQP ;?9?Z]_^<{4U2Yl1F1`烵2F1nBjpH)e+2K
ĿFz`#~, Ǩ    IDATqIǪjFqeKFTBH2c$db`DZe%!IN	l6mQ/m}Tɦmv\ QGIKiu&sK~Iޠu8N1sd@@!E$rn [UL1^_׿;37mxRdOO>mME o!xW51.X ] Yi!"b-(f>:?BF?H2e]f-sdx߼zGY
18 JmH|б(K8olMyG"m_(!7j(ʪmJk*/ʼ<s\3!Jk-D!s}׍*qƸw2r㱠n`<ϦiUYI!0gɬ>0BJ&K~F˝s$|5=`oZ1ݻђ&21{IUU1UD)SK$V L,ӎcDF!0|Rsf{s{+뺪'E%1bZ.gX,꺮IQyQEW*"ϲ,իWMI)<z 7a>ƘD F,2)&F>P\/o/R
)_|tfBJd6/!u]s˾J[R:+6J!RحBo}Ɏ-%D7>8^0XtƔQ=ڗ`x3HfITû?1xw&o᭽o?{. 	{o=Ak3w{~ڍè'~=3y6>D;³owaAJk?M?&>>:&SefX/77W7?t\b0s$Y6?S*){DoJkːey*b[I"B))d)&u23]Tb8g7ٖE.\o)'з˦iFcfJU(|#))	 GLz:]~}uu)<>=???߮W[CYIqpLR13HQH%ϔLSR`*Z,oo^>r}r|$X+EDs]߻#b)2tzrtt2f'(*)ߑ9=È m^u[F#X%D!|m׻[,+?fEY#puz^GEY-Dﺦfyy'OޟUTƹ~q{6$ޛH]bkcȩ2kjv7 ֕t%_.`/hWa˖x)J.)k123a-?U&5<xTVĉ3DAjZ5lWEk;tm)riYUuswmպokۮvAzHyqqS<$Ç0}WYb˲<؛)m
۶XVU^`cf@JӬ*OTfYY>m_^^xɫgz}z~X/0%Bof) k<zY&H*
a۔	u\t8 !EaȈc@,Q$]qΞ7c]ŷUֹExO9*+ "?E58bP)|6._,..\MXSccY_5M$.^mAVZcI2kLh ;T&Jt`{SHRTW?{_{{R0Yvpx8Nʲ}ͣ{ >v]׶MYo\׶08)<~^V"hd$T9"JiBD лl(YWY-MpVDP'UϪ<֝$A	B85"|@D$!*H9F5unQ܁0ƵBfq7~Z EQr:̳T@)"K&=,۞9Rh| .
7h5o
X 6Ib $-h'pa;8}!0"EFGEQr{"[7)h(*t<tQDnyW B p@lcp{tr||iwM*lo>%رm]og- $I)Iy1ΏtRN&j9??_VW4ˎtrp034sm{@[BiY$i6JeIb,UUgMp,5 R`ϧ oՋWm$1I t,I6DxS'{xo<l/7vɝ=.ݵ^p좭߽)f*6@^w}Aw;2AeP&Gg_c7U7落 ;p#Dd]y7o
4p6o7g ql'?(~uW~ݴ-zR|[__YV,K7j]D)d*D̊, (D b"O"2iVI"ofo8̨Ѻk[g,Q!R	Y|D~i%ILQy 4YD8ˊ$Ͳ,/C? lZ'/_VD>RE{gTuRC Ww.H4PA)Yzˋox6PF_MuIiãl4Qyn򪪦Dt[ͺAtVUe$	u;ǈyb,ھ;}W4j)/.ʋ(p''?|7G߾=^o&o6k +&yYYJ00Bpև$)d>ݛM궿^4lR=|]l֫:PGַ>O?^+Ŷ{/>CD$٤*WWַy	ޓg'e9uκ4 E'㓓OޛL<|G׫͋g>ɏ?Ǘϟ7($ ΋?ƇϟYijYo|(͋zqmyH5`Ѕ;h 00@"\0!#ˎ9I(z%e@hNJa`8w#/a#H(|H$I~T9HL&q֬!xAD(hi#q!">D`#zZ|rB8E bYA)g7T@nAjW/_ڬWtkM[Uޠһ Q!ii aoHXa;= } <Ͽ_c%Q8H@$R:0}g@HP܄02ߘ+ƝlyD~L|R@DA6u^N_HΦygHy[ƨTQNJ5zz'B	V{s*~mϯ"h~Fv `wmB`E1&D-,eT@wM#fFD%/0$RB
 98	^%6.][+>  ET$Y[\]E41ιL{y5MTu?XDmb?UiUYHbе{O<9>>?KFve躎jcMքu;Ҥ5@	>}n>-E$~UQUC4&ק?泽 @٣G?N,HZ!mv7@p#!ގoWdt,!Al'!n[.w.n]ֻ`o-~mgdLcGc?뫎f<  mmmPw]0[충}s9moALǤdzD$y?~Olz\_7km`nxo|D26;%-,	)ъɃ0+ D0`2YX@pFH[&_w );?{Ӳ(߷}?A 	HE*B.DFd[ݚl^^IRMO///r>la@<u>E6V}]W΂g{=)}\`	Cpue9LiUUi3?xtt|R f\{&˳,3AĘF)Flk9k;0s~ofS_/K^Te^y^ut];) <;o]/Ohqy4öm >Pf\oҳE[yD2`M>؛&"cJRY̦巿omumC]۵zSoSy!0"{$	nN$MSct}v];kTդ*ڦm6u{:|͏<h\\-7귟~\\7ue?^~˫!1o&D,"D
!9k} @J\k8vK|eAn
k1d=i cm;y9K߈QO8DhN"F 7k`mZQYuA39tjv
.f'YlD($F%Z'i pAnad{텆>   ;z8,Yz3<b̽Zjm!׿<}{?8/iiӬH2t	^Iפtf;jn˶2D^z{}DG=RD4Vh4t0+KIR:M3,!:Vu[G7I
zĉ0BDԊcB5tUs3G Q*
XF&n<B,vqMA ZF FL!	mU46f	WUYo  hqԤ)pαZ4VHFFcF-zu]?h VYdY4QD>= h"#IJDq,"(
Q)D҈ v`D+]wcǕa!<QV5ܺ}G*l`l20Ka^ILei$ͲȋlRO+YUCi6uLi{qoã{4,4McY]uu7m5m^S({c6YA]_^-^<aoGJ'~C(4IbLR*m~m+.H2]7. BRH]`m⍧	ʤD+<Y}@"avYnl~--//s_(BRpkͶI3­{oBBoG:ٿ{nyo<Acne?𣶮ճS@ܶIyeY"= i *Rj	Q  0]@4Fh [(Ʃ l%yWz- "t6=9>L*lmmkc\CHQ") "C&$EiizZfIrxx0tZs6~@q>wzٵ$fyb4/,U|w>,*5UYfYff9dR=xpj)ԤiVJHa|z?T`svp"sj.JyZxl,Q<PUp7/^<?>>9:=O>ll[[Fnci i&Z[k)5* dA QJI2t0DpZbR;k*rv6M5Mf^ͦim34IBϟmgY9z98kh@ʤщщ1&ލEYUUsuuK;*ɲ,rxckmSfZ\]<z^Y'FOO>o@I=<7df&R1 6I@B%{s⓷`:'.qύnd4)@W6Fig'&I;Gi6m3*T1vovGF/00!Ĵ9#Lkć0bEszľ-l$1.nz|#qvI HJiMpV˅xYa9u]?gϞu]xxTe}߆Hsn``+`G) gwDZ)Bhȁ	@?	MEkw0R*T郇z; Z(*a	-"&:rP)Ai00wYap{ X#À$e0-[N+H)n臾uΧi۶{ J,K353D 
3$6"6"t;EQm[}&1`Ri˳$0{"BZ+6BT㑑oebgonB&q%$bFcŜpR2B#O$꽳unv`N4Ͳ4<wP#K=,/@@8k7l:ۿ5"
$<IU%I" !0#BbL κ`wsJQUU'/f@'@($>=O?4Q]߷m/_4}s2߇p7mpW	|zyuZ6m`MTJim1Fd6Y	nx;&ݶbT~s[ٷ_Ǘo|?pwq+{O~l  w
ƻwf	֚xoۅDq싾8m$b\,Q8ϳt:K8J֗W0;tDZ"O6I#bχ@
GWTE~bHI3"
;rA#w{=R`?CF :L<|eӴ}]۵m["LYQeY<K4 ;9k1̒d$˭(r>M'գG'	1%q^Zm.p_7Cߊ;u}MdQh븘yRӪߛ,;ضmb#/'O<y|2<8M-ݢ&I$[c.`fkZ+&D" !*E;ayԘ<LQ o~ɯ?GG?[m۶ýilHT M	a6TUYd}ۮ>;<ϕ
(OE_&cDO^Q߬]CM
'N0   0y۷mS֛˗Wg'GG'_[wzzrE(B;Df{UYYfYbTY][7`??:<3H{,+w=C*\d>˾ld1w>LL@,"LMb@X	!ڭ0KKGn7ǗE8`L$N)$2Iu$HHW6΅$I,&Y^_DnPiޟfwvi"	C$P4    IDATq`gm,QgZiJ8 Iѣ^) ^ [ykEf*> QZHPyg9J|RM`'e:=;7?>9>>}:Ԩ("왅g\;<tbD+F%b ̍cLTeT:+:,"iw{	ο?F)Ǿ1a7^EuEQdYT!$
2B+8zK:;t1I^JkNM 8(3LDEi	BiV$K"'fy&IR nha譵H)̲H4Z)軞4EIb2FF4 uEZkj8  `amۃJi*Jo2 "gt+	D6m!{3Fa,&mr vc	 >IJSF!waXo6z2E-$iYL|ooG޹f}~yqyy6uƄz  Y$id!0iãt`23J  eQ<~޹zqi 횶ׯb4M$a5V#`gͦ-y+Dtb<3Gt>z(r9oA$BιjI_#zyk_pĝ;<*n6i:7q+ո˃1Ƅw/Ɗ]z/;gm.GVFrm&}i"tvϟ}XO뚃;:'maivR0/bI)PjDX!./Q1Yn',@ F ([C4FoK~j{~{fomWo6uD|6GvM/zEUY!Ƙ<_-QL?CJզAD54x"qzB`tMg.YpPc9C|ɽ{}պH[k0di2Ui@aMSgF;>yѽ,)vbcFq{/D"8$ AgC߿xl8?|G/^1Ϊdڶ],._x6,M@F+]|6)	 ]\4˫d:;{жfz8gE!XbXdI᭵ZQet7
cs\6[kn2&Y幉WHDX1@$U^Q 
#"`}կ~ӿ{f6&cQn4M˲L, jRfZ.R&Y>X_7zB<j2N$Q՟?/~駟5u]5)Ei($1UY &""[ f!<ow-"!co(Z4pxz]_]}˗3;$?8?n4A A@!C"1&Q8(Ef	c9Dh5؇މꈈR!x;J'bTTo~KVJygIVӽ}Y.WONN?ɣﻮ:&y[fiM]o1y$WluClbnZM9gaZ7u)x/"GGG'"٬AڰwvQEkWY	qa6umYk(=~ Ng>/..s`NSSeQEnS׈DZy~ LM6MҲȻфCZ/Wk@,j2)I5dVC4f40+B8*m֊N$7MQ)m#DI|l7u{5"y W?P,jG[&1)H)"4FVaLRw_:8RoBuVDZLƚBpE69A򲬪|~sEw]׶ \@iZM*{wZ |7E6҉2	!SI,IF$E5QN:Ka^+eH)"̲$EVz\mVr٬WЖIj 8@#h6e]cW3.X/7|>ߛMd0C3t}S[k	[-=o~糽gt^AUcw}wb-r]m<1Glۇ-_[Tm}ϣnQXpoDmiqpTn!RmuPewFy`UmӼ툼m𦥋۬oˀsșaO߶l~_|_/ΝE04ͦQ "@vʹ@$2Z%YZ;c#R#1%jVe"cKTF"TT>899i],mS$9>4MͺY-{[ֺ,,ˮs):%2I!|>CX2aa\H[/K"q4+N*Pj\s"|T+堉KBٙkioʲ(vpm6:T0jXfbю#2<N'Y.9|	*urr>ʋn*M1z3MXҺs\?ª&̡$ɤ*'9w}uAZf(rN9cηm eibADIy,M43aC/·, `E
	4Lkw%\4 "MIJ8w~wNb$" "KeRi=jwD$:J(pf恅.*RDLL&-u	bՇ~x|tO///_^\^֛jNƬ@6Hib8r-a0RbD;u(,o]h!8z~2ߞ">2Jx14h-!XkI0!lGGH6rgG9m9>|  s}I0 Piě*}L1`W2qf[Փ5uuo C#_*Dt}PyWg^,TV+WlVM&UUMj˦/~_\,$ϳĘ</E(B\Q'iUZE5)]Mgtm@,(ȧ4Mȋ Ŕr\nVˮ>}l:;>/!x"4]_WKgv;a;.0ngCRU9
.I$I$1Z@T~VSi'#i &1im|`RJ!0X뼳M]uYYz~pwtBvC6Mk]u;T$*" qv`cxl 1믗fh!32P#?PEVDڛ13@#Bn`t>fFu!-l1Q &c9gGQ"ڦi˪TUYU$ZX {7a\q}%ŤLe˪(H4EPj*A 
Qq{3{ahM]mݮ7릩R;D"jd2y(Eh{FmRzUTt:TyUUYeD ",aιVl>oɼΌ/ݬ;hMc77֛lm5s߳MNeǗ97ySNߙ~Ug>g7?N@[= <sk;/6ۅwNvFR.7uo~GCRfX:=/?</"r9?xBAH
PrDo. "*P!B(I!n$"RH`Nxtq"<ڟ ʊ(*z!y;wwxx "9, Y^UUBozy\H bҬHa<X+}o<ϒ$m6+cLf6Œw:jœWJ$ILi4EuӵMl`]ދ"VEQlRSGFH{ w,mS)cO Q7`e8Ȗ_Y^YY%2Z#p~ȳǏ5MiaX,@ RT%y^%I W{y$ze]]/W~#˲jED$i 4Nf&1:~qNRc,#ȤQ$b+o)ᄀ(JD<z L{E`"*"*<ʢRE N&4ˋ:ItYvƾ08gۺC}MO'EM}\]^-^xvjsQM# A#6(^`	@&F@b Qm:3N.7nDpѻy F'ю³U(EѼA;76/,yUr2y^ A鲪s7Xj5Ƙ'&@s{/"Hf[YHQ?i|#jŇ(B\~A^dLbϟ}wVF"mI&ˋ#^ jݶmUI]t<؛g40hY,&QI%jQ$Y4IJ40+J7jnzVfuSoڦT+H~"ZMGb>/@Z+fCWȮv0@I"9<:<>>?<-5&KS@7ڜ:ږ,/2u|xm?,$6J)B1́bo;ͬQ8>t4-"IҼd:4*@kmUhRk0{@ #qWbJ`aSFR:KLI"R;?eElQD@@BB;[}z2"`K0wN)B1t]ˁVI/E@DжwdooEH您p\)"A !I3RZ!E$F:D "U<s${z\\_kcR F)ѣ7#!Fz@%A)݊v_\3~|zs~p~$ϋ,yYMm$Qktðl tDj썱cޠAy	*XOwuǗ:/o1(WHKRoߵwk<VwA}^Jo~eV	U]E>ngw9,|'c{_}g	@{gfU~ͦ,Mw$֚ADA2Q`n @	I)	7v0xJ)R:&EY/2 B466c6J7Bؑ  !JڅVz2ٟ9~7Oٟy^fsիWjyg_m#ژ"G'aPZ>.nιdYO<*"?1
Ax7XGˈ]~Q^ƥڻh NAX6Iw}7IEz^tMfFaTZmu!0#BL@-u(`l~pY|\{"5ͻ=?;u0خbi}HeY0j2M,2Tr]#|>,?tV,f%B"u;>4b|" FR>ضm]gmڮ,?\gBn͐Sl2JMiڡk TT^Ud;<<48;E҆A#beYͧUj XQ0ibhh96uYE$Ó{O?jZoVjy}M٬nP<#;3y8+(Aڟ;8&4! ;κ|	 0Xwy׶ >}΋<(]6fZa /X
P`]ΌD>gp,(0(A DǗQqJ;@`q(~X"Z ,_w~|-hZ^^N@&F|o~rrRdɺn_6YWAeTU%?,˲ȵn.f6tVi`4Q0:5",iEV/_ڡ?>:$@*j>N$+! f,|o>;Jk!8;VDm5ؐ?[ߞپ&=tjutV9ir]&ISJS $b=(x
<X}ZiR<"daجϞ=?;} (8'"P!$Ƙnᬼ Qѳ: tf&˕Ic6AP]|`<"{QBy,a,~Ds>V(!A-;1"&Hq"Ͳ̳?ϡ"/|::UbyYSowDXf6=8888<4ϋ4I( c9xvCjYo6ެ"EV*OSwݭbK3m];PIv)JHΕE@rwFx=ݬ,2?;yB?(Wl,1Ky0㞾tG?+'Э6~kUm	we _r~8*)6oRD˸%v-ߵۙ%$@B\WWI͏˟!ܦ>~ZTSw0@k LH7YɄqGM7tV
 zlɲ3{LwMa3a H'(AIG$b~k6ĉ'b2l8d~R@s 4v]eUejYzQ?xp_I9g5vϟ_^mw^Blnv}?M^@Esݮac@IBim\]/-&/
m3B1ত3cUEY2COiTbC}UJe:9͋G7 RP88XΫ^GPH"z)B!DRH)LDF(B[sU}_W#c;zr>	y7n%rU/eUA>2]URʾEQ>8=>(^-BI!@sIftVM" 
b>)S(\a)d"n]4mnkf4mCǑf)8Myf֫rCip;eJ	g1\N)Bb̭,L+8:=FCJkkQxkFjfgs1y@+Hz$vVʘ|$*LK\yxp9a]74M;}S?LMgXI!j%"HLsu:2D&{= )|uA 	,˷ R 1!e 6{|t,!2Qgƚ23r    IDATe!I >zhqOBHQ1@Y)JB2p[:ė0D)OD@)&q,z\={6Ó]/πAic<zGJuyyȭɬڬ|$b,DH9d nͲ\h 9I 0If-f{~vʲEdcZiy)J 2bFHB@ȥϮ.κD`ji(xfP8<x=.rǯ/nnXIqcYZ+7!R $aݺaH`H!D3R&dml$n/]8
 RBV̘i@'BD4wOų'آ,ȳhn~]3M4܀ZbF)SIXcMNwPR%q6ihTlB$k@C8\t'fO6Ǯ>sk%sNHIi  "
Dfg,˗sNJeF"!'/·_VGGk6vtO=[o^,WţG*P B'gm͕dF)@#'sލ]!"dHԽd !D*JE/*lӶM}V,iN>pWz. 4MM}2 kBkÜT <Rw"׻qwqhuUZL'GʥN2a.k~7Ys8^x;j#ʴ^o9"b~w"BDƏ|vSߝ7J)|wýf:w4]8/5#/fWWW0Px{sCJ+@BTu}}!kw0[]e<8Y-a6A즑6`ɌI<HA!0,ˤ6bZ˕*eYe]WY^!'OlM$(\	l6WWiq	D`I@ Ͳ,iabX&u7w;|qԷ˅r"
>'49QHZ	V<n~`V
(UUUa}ߴvn
]f*zpƙ+)Lٷ+"DVͭL@H1FhRY^Ŷi6ZnJ->TJm4MNI	Y	iY v} ѽB budYA8Y X;4p1ðC?tͮvfO}v]u]ۍ40֖EV({ 0L~?6! RR RLiUEaB C &)(Cm>(Ƴ7EfȲ,FԕRJ)AHfr6D1;w%MĆZ+L	D#S`ɷ80hqss=N~[(S$ͩă8^L7!@ sz뎜l BEQHmlR(+csU]Eive2\,P &f)}4muRʻ9n4#3K!)8	vSsɽ0k;t)D#༒^tn1mVGG˳],VB޷;@1 :/@j>#QH5
@VɪȼCCd<M~ OW%@D>f\_]h)h(R_7P	c fBHey2B@J)8tg6חC"S{vNRHxJkc>ɋm~d48coE:H"a	v1Ϭ*fB:R,%>{@|rS2˲<GVj:>L8N0]9/u@A}H0t*
`JrI'N%9d`"H1$adi 9"PryRew>k`  !{|A 'Z1|p+"Ϭu(j }B<<JMΏdZ~{ƚh:9].łtV!%
FF\6fi"O2!D(] 	(TJgY[k,
^|.e`w/G@ Ϟ?<'""pLF$ACDM:xyMR`yRq΅4nˈ?.W` 	=J2w 0 Ə)3S{Hxnat@K?ss6Ye=dFuOs(nE칧tկvQ&?<9"]G"H	(Gʋ,r`<ī893ǔ '7Wy ,@(w2 d̐3 !ѱB(D54yly^EVTy}tT@4o2~)߿/3ٳwm6F+!TI LDYQemq!y3)CpE#*m4MgBDkGw-1(c͓{4s.waT RyWUiB\<5Ms^__OY:=^h;ϲ@TJ9fQʗS `3W,J[D!OVIy^r}矏ӘWWRӣw><:9<?{qs}Ӝ׫,WR"3NuU:.<si
~
8E>@#A!.(@3%w0mn۶~ikq5yf<ϲ˓ee::]_VEQFa(\ H~w(uBI!mMVDcRE!05xuywFaYdeUDs$j%TRRH)/~gݯ,xc!$/̃s8C?T_ofBp>"BL9e䠗D<ߕ__y^9⼚1!GH~.UimӴq)`YY^,3*J	ba^|Mw]zUZa(r@1D9]0//$Bj F$Iyڡi~E% jLt]plZqڡ@`)%}{uY2@׏Z)Ѷ+L61H!2Yj}"P#]mC` 
!1^!.rc9)XRk-`fH򬔋Ja)gOAiZ.
k/.7mHJm6&MuUw .Ξ?Ӑ,M߶8E9NcppDaQd1HN&2v*J*x1DH
L}Y%Qa	sCwMH.nf[hwm\J֏HBJ(l.$"ʄJ	RKm5"l70	3"֦*F̼8ug& #G"W|_A20z(Hч`PL$ER	8,"ȂI
)Hif3%&b0-D4򪮫ZԙFy訮G 5gc]IK0Ifɑ!enf LԮL׉h4Z,+rQUUy^W2ӹmծP>~yVvH@H\o߿Od*bR&0ňBJFxXP!!}^F~$!,)yD_p΃C,w&$Yo!,S׺-6ۋ7ojo~Uܖ[o>֝~ݗIfw;n<  f2+70ؼ*H}C`FJ҃	!pN6D\ѣw˛GeY٬X}\o.>ۯK4`΍!I31R,Fߵ4M6u]]qq͎P]WdY[B	B))Qً~q~xrZ_ŧ|;l=Qq>Zm5H0-1FB) 4MggZCmVeqoRBꚦ<^J}Q8)q@`,JIfXTe[PQSCv](J),J"=#2:{1&2/QDҋS1ee2#o'inw}o7z}|
LZ*)ofӶNIb)a>{:9=:W/ד!qq [SjK9(D1 3kR1Rwۦvcovn)*D"?~ree]օ-|X,bQUEq·Y\؅7qr^.%(Ʌ~ۿh9zl:˲Wug3e̳zU-W/../_ Jk')Ve49﻾FYV}n`bq^ *!R:	/v{w}˫Mw̬ʭIm*dB?GJKR` 8(%?~Z!1߷|u@R:˹~	#>j9}c Rq V"1JŔH	#1^Nӗ{c
*0'V` QIQ%Eo,3œe-d@X.'Gv07
4ZV[WeQWEUy+ !U/̪!Z+4j1ojӵB&"
CtPS4cbj0GIEGKRjXIhzl=?~w<|睲(ơW_8My-;9w^,81ιgbTb `%%sB(m,H!!iYQw΍0id{(1Y !D`
ĤZJ H	425敚3@ @)2đM~7ߠVyYby;y+ <N~t˦im&"RZk<3j@". }#sqiQH&PI@0UuObA/d
$L1䜵2J@D!$0'X bBȍnr8ҙQ48uU6v}녟F7Y#fF-ry|Zf*8|ן~o6n[/kCaJ".B3B_ m%]Ii2ɋ.Ui,+˲,ˢ,RBU.yVb8:l2fu=F<`Jcf3<?O_h"K%QlZ#3%_RN!$NS"kC,:s7DYx}¯$/o|,^ϢfF:<F]X|x~B*Oob>ߴ&ʻw_;|eCF`|Jrm)Q i%?g?|CahBJc
6Ji)PJ@ia!RRIBFyHJ4
o%hl|X,heB5)%0#}MNOł(^^^4MwB?F\d fbZE1cvRUEgac1`Q7B i)b0X%o~߶])&ۘ5-_Hqn6mێb,XDYikɤPA%p ĝ;X";J[cB,J+p&ƾ۷C8lkv쇦iwM㼏@!?Mv\]q!rƆ;Z-)jF)~0ٿ~rH
Bsњ82@  Rdn../4i@$w,ϋ<ZTeUeYe墶ye*+"υ>9+J!>R
PHeV)BcOC6S
HRXe2f6H!͟}k^.Ӹ<:^> @J}N7=}DK2?Zr}>>I6>x%d"LHJ>ƔE<'DG?o]\o^8{qvvu}n0JI5FKHEwKI "Jytt[a#0IT><NY+0ԔP !8iˬ[=31H\"G[N_͵1@B5K;#1 w̐<0YrR F.6Qjm3e`6XC/Ak]3/WftC~\߷Z+c8,r#saD)R1>^D&)^Rp̏0eS0ʢT*] Q$P0ѓfzze~8R<xE^VewS4!Fu~e H9*HƄH9 RZ͋rWfKk~L4NtN
̓sRJVi@rs@<3fRb `$eY !YDǑ(N춛,sktYecf]d7؏89M4G<BhDPH1&Cp֚,ɄLDI@3`- ޘC[HHE!d̳,/R4E1RgX `t>icd 3G6um|?88)6T@`
̚8~&n/(h,@#ͲLMYk1fYfR+w) bspF7yŀ[L<`^'俲Hi}oqJ `5R#!(I_U]x^,m^.WkHvA?o2	 5d%N
j:4Fx%iuoHu~V6Nd}(1?)|3y~wf^=b·uwׯן/W2"E
D$MoR"t뽏ԏwe^Z nv4X!BPHpr06ˤ$mq0 J)D٢*3i"16_zhhL|r ȕRegF+%Lna'b\NNMۅ˲X-ƨEUI)M3Eeu;AkgjY*LTewHBJCuR"֒&'뺾Y%In܁$Ʒs )2QP>Dwf1޹ionnS5Ue.,XQJ%aЃE`M佭JRum76еm߷Џ}V;1SY-cpc7FCDy-t8C
}(p޽^dyλE7NncsRAһeSt&<"@Ϟ7sQ h(ir]N9V,uU%?rQEQeY.biE^VyD<}ۏ<S?\\_/uQR7JDj>).> BJBÀJɤIo6)郇뼯kmlmۡkv뫩EUTez.e^dL3P!D> fn#Te޻>M{\]^xniƍ޻8@*9[ZŁ	~Xԋv~e&!
'&0scT΅S|".EfdIA>"RΡ>9h»OJ!L6)ƺch.VNMrN$BDe    IDATfUU7MBbfD"?8ZzQu]bfV"PoMd})dJ؏c>R F~j(NN'$Eât7HV&D	i 3K"11L_̮Vݾ9{
 y>WB!RX4䦶m@5ڻIicJicJ):5166YyYk2lnufm̴(ľf}?M/=S9~D,
)HL̜rIhSLlB L R"f5n9)C6R)Ƙ<**ڬ*S /OA780DpL8"-\Dz&"ILU`HȈ|@1]B E{3.t]^R(9!${a2E#gHEQv}ы aD`c RJ+K%Ř!~eYH)8%j"@B%RscLe,˲(<YU&Z+J7hd"EM;L"^#$	3g?|wϟ-qaA)H8Ü#b2PR]4{#ٳɽ;=9r9j  x/ra8MWNv~|Gx5sNo͎:~2f	ss(6kwD?0DfB@tfFR	`inai C"O>.e]o(bxiftRHƣm@!8hݴmZ!Br{./v'(u !( Xz߿o\  L^Ic4J?XIAэc|dbϞ>y{ꗿx6?CD1{0Dj#W|qo.G/._"H P˓{n#9!:u*FbB$BPuyWdb3DޓCtnq}ii7]kOO'N~:SF+HB$L3cRi!~sv4]ߏ\)JI#n@kt!WIcag~2-M4xuyQ 4E7	J
 "br `ˁ???Gmv4=991v]wv۔km9YYQ,ύ>9>:*ŪXTeeE8N}n6}mv~C{rzG_yeq Ƙ,JoˋW.㣣_|щPk/{ڝ{wSv+4Ɯ-uv0ɋntůmןw;RU\,EU,_>~lnv/οo~qEe5Z!Q$F42H8tݧ횮505O!tqH4}U$oE\bnh
1RCDftd,@ I^"&9QK^dLp $n	:B$W8@)h룣bRt@!8)!7gW~@sSRj!`'&8}ߍ]w@˓=IBҝoc2AbZIao.Ͼ?.l{s;)郇?S)DvЇ@H5var컯*rF,j::^.eZrXTu]V,͔RZgO~8h범R267q1^\\^l.ίnn6v(Bd
ԉJ+)B;$38 
!I \Z/D&еmo||
 J
YUUX,VeI<qۏM44MBPRcZxR<#@
H0" RB"1yZJS֥Oȁ@"$L(vX*AI
//*<w>1h ȯ7}8cRZ+BIbϺލ(ٵз|n״>3F[j^TyVg(>#U")S`vΥ[RI! \^ݼ8;GE^H>Zء2)t*d	^\__yoCSZ2T	6^;Ď|}霞dU̯BL{~u^|W6M[ǒ޻'֝0, oK ߦ+?ױ?s$ pݷ77Vk84M.&3RΕm^=9^=/XrCAIc:*q&qpuu>CdjJ2;}2-˪nۛ&**+2\M;*$J 8&v]<ov'?mߵmsrw=ZΟ093;#S*v_|q^/>Q)yj"Ea̬9::B
!pCra"fƃA#z{z[ȄS1&+CSJC]״󺪫ʺEU6+1JJFJRdj).d֖U\yvWW]ێ䉆ﻶDVZ7Z.9Fo5nIJQdV+!4
{%Gˌ6ZT	#&4=a-"~軶mf7Mw0VKkQ볋v6h$|6ʳe]ZkQ,/W)
$"ݾ\,rEQEQGUUynaVL@JBǀ޻a֭ٺi6ǠUo{&-EQF+՗1ж(zC)8C?J⑉a躶m4z]aۥ"4i>y2t]UڿO__~gðu>~޻<~?~<q~zwuM12TLk-RFIJ> #UއQ_]\  $9J)$$c3uC#10R Sq􁈥bCLTcD@Օu[I{s(( ̼|*Hm2|rvv33y[#-fWY(@̉Ö z1DĄB:*)PWyA
%0,C P(}~yW_=/?ˋO~~^g򪞦ѻz[HNgqǧm^.Fg>{룣z,3'ٹ1ۦC¾|vVj!xy7Y&DY"Q78mn6Wۦˋ늲\"Ȭ QcT(" RJgRx`&\n$8,eiMֻfs&~B*cƘE]eu}n7MяӘT!)!(Dj $-  F)RZH^Ezߒ"
3!%&aB'?#  1 NIQD!̈́@@LՌ.jN̳l5M)P B
P*-EfUqBH}"-JhmmFDXk̻ӏER[2;ZʛI%YVC?Ï~4i>}qt
i@M]U^
)o5	"@.]Jۻ`H<rb_P0<HoIFk~7_1DǏ1~ǻI[j4},SH|	on{g$ 8\L!F DIZic-\PHU̪''?,ZmM(ȻVI6lɇH,wI*-) "1hcY];C J϶W@LYW; mnn8M=Z@i[&@DcGO_U~Uqιi2 @cbn~1J|<譧IU-EyC@P$RgI%H AfA>	 +	gWw@DJBHct>1ד;xL䦩66ϊ(fRyYe1Z@EQ )iqk;g3(}Џ];]ܔE(5+2cRh~翼b?ΙǾsWeC !]86;qql8MXvݾiǑ"*md&Y\,׫ŲuŢ*ePVJADfǏJgfoiUBr\.ȋ,2k$nVgf˪GG{0LC?g53jFȭ<Mc'P^h4v;ǩ^,pOn8{qbe]QB,Y8S6N*}+HRZ*-PYilϟ?~>h__\]^^^^]Mӄ \JȀ/|v7B`eJJb@!A>P Afqvs_ZI !$5[یϤ1&V:xڢbgY;0l( vWVpN
"-}^"Bp7m3
N EQ(e6ˬwz\fY܄dwB$63g
1$3,C")8<~DK7- )&T<"
Q!o...1Yf/..?lI,SmƖ{]e DH?:ϔ!9!9	誮=32#7ʇkUiይ׮9zu۴eY~駿|yuI%y뽳jqrٯ~_fӼt	B ][6ͭwNH!A1H"u$;8B	(1"gKxmnǟ◿~߿zfN*@TZ(cL8@TQRD"#"
DNպTǡ#)ikD@LCw	( bWY^ȍ.<siYUyO>`i!@!PbT	fR* #USc/,P]gJ!z&$I(ukm *3&l5V(xߴuQC/$0E? BI|R!ľic$P
 YV8)bVTUw%I1ѠpvP<,JdY'&
a	y6}
B0ScM#íMdԠJ)u6r* ,qHSty|~<2vcYGY'םD]fږ~ȖXD@g>un6^.<JH|a|@LCi:R$C"Zd2lַB}CMV}HY{vzREuO%DklNk)1yfO"gRgV)h?yZ_~j;5EY-O'~zw]IN1L&eyuDv'>f	1j!~ bcF!M]|ط6˲]$
'ً|a_ݮHȈ(9	aLƈƷ0a!A"EDFHl]>mI@HƌH
RTl2mZ)e}߹n^w6x"پvos4iC^62h އպd>(dU}ݶhZ !zCBZߴfc$`M&ʔ_o67>`.\L$hftyvz+\̗d:ETDeR:1ؾ!<|q틛͛}m{MZp"ˋj2)''j2Ɋ2
%X"˔eiQ&_-BLn[7}]]R12b9;5n?nNJ1o?|9_ˮw9d2ND"!9箯.Nf/΁n}k`
6R$`Dl-UYjwןoYyg1bݴɣzn67뮷4(-C$d@0
cLc\(V¨˄L@@	Q*%Ȥb?]L="Iy(C3PiH\)`:BZW,|:Evn1Y^ViU!fTCgH׆MSdQD#
1 0VY#%ԩQԀQ)3	k_|91,.˳'OO>0rl- pMnk Oo!b>]}Rcdb$G`%VBI<8IPMnPnR'g|2+ON~(?? Q) #fZ2O!|aB( ajJC.U^"1rH?bE1't6Og"隦]*nFbd!IDQ $maT>܈d"2
@(*clڶ(l3EE L>.J(ր*2:z!,.FNV	E*qp"c+nZ`PR!"R
cbxfNc}؏-2if涵6	<ȥ(sA#t2G6ZkX] R"H d^Ȩ/J%CB"*[Z2G !!Kчy(@.%Tq-y 轋>Wy,Pay>	==d8$`Luwze]8F}Tx_x/x<GA zMkۛBZJ4> ڦ`cD#tnqѓoR<Er/E
d:{Gg(RZJ奖"BqzĶLj(k;ţgz?J1v^n7;۷޹D*@AvLg?/UļM׵4)rzÐ`Q1{" ׻A/i<$3vus;% Hz(!K-1ف1/b B*=-	"'F꺶}O1Nd"a)!"!rQ:t9˲8;~s5*ΦonnV.9JG Fmj)rM'i{13hyпR*gD9:GLhx}:,6xlCMu6`RPy<URؾZ]gّb
Q F,glZietbjyEYMzWJ?x,]mGN?x~_~WyBʂ)2@ȫol>|>M'Ȅ"N,ϴ"yD0Y~zV=~Rd뺾Z
n_~՛٣ӳ\##|8뫿go޾},˓Gh%VL'e޻WTevڮ	@1޺~/7-ɋ_gwۛ?/~_aﶛv6I    IDAT!''g?#ﷻj}yFD]#bJ1FDuzF)~cZ B6!bH7xr~#!2]0D!%
B|@H|2v< E2đ(*	H=&X1uiQ l<g΅/_e<GtwM8y82C@BD)0H<X\ ; V@@,}ݷ1l?|y(?O'ө{${ۇC~J2>ǏL1X9xuf_w͖bbzs콗9@)1)BjVdV*	B
Cvf<o/^L̏]H 3<D!z($*(DHC8@xJb
 ӎ)GXCdB|A }h,Ze1j2ɣ<ejumߵ]u]CD)PJHrI|RioHbˡS[#~z5hYH)QyRJ jLsd:]oѣG!msب0% DPjPm#Ʈ뒀V6d"CR1؞z/.RJm,z\B(WGHGRzA$gDJK`4hB2M=%Q@N1 P@"?0H"40ȁ^ڪ i;kq,-	cTL`؝j(iŽswnҞw<Fdw'Oq~~_ds?Im;']p
3Glk; f>:Vǭ.s2pp~VEa@"D̊LYEQN&S!N (ڶ1HDZܨ}׵Y^LlfGo._|]7d}oVbNIy,E9
 P!3x,7v7{%P+Iy> 0XUBJ
hL6Mlcp6Df&
!x\zW08s1ѵ3H9	{Xk{{}}}ݶ2,EM" sdHxlC 9(HBx`!}<P$K1]N
C08 BIΜ:=څLe/sVhW_\K4yoڶoכf׵! 2;+'LQLt~u}UmӴ{%Bх77e5qw]L1EBIySo]DR]hz>BeF!
)ҷM} &˴9
1vMU5_NZ*]j"&DjXKIPZgwPӧ8;9]'fre;FQSw߼:r1/NN0Z	!<BtbN_1]ɇcggoM[z!rYUյVRx)k;k/_S*ˤz 캾ʍfV&/boo?'O]L1JVUVggߴvܬ^]]_}sų/^0R~۷u)9߶JIdH3E)##24]"M8t׎EI1&1 *m=Sv=κ?fpaȸ ez-ՙcL[F9/	su9%cq	|^3ŁKa/eLJ5ԲԐ (9&(rNR$"@ݴZ!G=_Ujߴ]]͖JcXg5eJ?veLAܘ޺ml5L92P\d4b)>l%MD:`:N4$LPB-oW/[]Bd(11"RRJt1=t|Q$mR$Qu'H(0Y7x}o {F;6M$%sڶV+&v)G  $fʲ(B'B@4ZwL6FE~Y?87Jy:>]4QcB*Do1/K!nWw]O	R)i(A .:(mV
 ڮ Jf\ <%ឭƏ
woaJ*R1<(12-ws08FR)z!E2y&ChK>!_B gxqSvK,C2!-}zXHW;%G; ?7尕# GA7F!KD rN]32G H<>o-*+<Ati.õ=RAIĮ;/~pG7~t@DM*!]Kp'@Ŧ] |ee,ӧ_oW[DZIIT:)"|(2F*2:9xsyYwl*{.jޥxQ`BBw~~O1ue@BTy)"H1s	]kmuq$fC<T6ޱD)1!x|1:cTBU۾mzd8nm/ B* CL B@2M|wFNI2>1za DcjJwHI`Ckfft:;;=],{"Uڮfvuo-(<p|:F:+|y[:
H(9;O(ڦ	s([ @1&Ɗ1om׵.D#ҨUI"<$v}׶v^H310m[k}o{6EOI5ɳcL&uE5W,+PJO{o.\Zc Rb3d[[+nsgUw]6M!1dzٜ.D dY	+"3Jz4u׵9Y]rX.lRN<3FzvlvcNGggc;Vt\߬wfoZu-3eyz>PQ"ʲTHZfK`OcBPRPmu7_}ݫWggK߽]b"bn1FiZ#F8%h<)J(cC
JIu"
1F[w`>jã&}G:s0O<c"Q(0:_z1y LI,PJDL8`|v2L Ǣi8m_6xC@1 Ed&뚉_.EuBeY{38bRCWWW~{35&<XYu]p=11@i A5PtZOG`:ޙ	Ȳ,m\.'駷j8+9FeE!tgC2d umZk-
R
)AHI
IbιxgaBLၪXTR<ˤ]ӥA$iLI` blm1ZLAHD`&㡩!>I jzv1WeYU*RB*cLQ	Rt:C1JNZ 2+;W)I]LZH\qQ	f
p1vR&S	
YJG9b{hCSTXPHdG{ߡ?yx&6<.ze0)ç70)e?Kᰆ!?Nǝc懣ǣ4o8{=Sv#Řkw/#_2 ԃthG9:
CJa`|߆	rʡ %!kۜ1uD"fvJeyɨR</{R_; heO>ۺ}k.y%bs M^yv̤JH7gOfIeD5!Zg2	B~՗_7]o}EY̖K@[{'(2)Q	CH;gKWdj"6 H)	t8rζm(ZJx!2Y}躮dfRW	I۝G@jQZy/1F@))moGRJG@$b"3+ȑG~]2ט!6 6G1mߵ2;kwuo޾mCLBR+eO{(:@C}drrɵ,k1	8kϟ<9dRU~RHc$H)bjRy!JDUVRge))_~շ̧ͤB  wm]k'E6Vl>)2-Cͦ,i9,~^)=)J>xwJP(ed3E>NQ޷wvu(`oo}ߺ	s%\œ357oכm4 kvt]gu.OgO|?l7_}͛7ou噹||iV͂mݮvn6Zxt~o/_`X,7ZHZR"yfvgJ)fQeD6]e87峧Bn4O?oWVB$](%zSSDΐb^zFw=,'CL@Vz;^!P>W. Ʈy"3#9kP H}̳,2Y })2jct$	Вxxo*")g$PrkC "	bCM۶MӶt:_ɊGb^SGI`v}wR
!u$Q.߾?O>띳w.O^ ,,%!3@́X߿^JR+L1;GLQezOjW_-(Al6B췷p.fy>tRLDlw}_c!Kt]^Wr9TFKedIc*R0 #Q!դR4h@!P绺)`U  Yn*s%E>坵}K%1:+ 9ylM0h=`{yMtW_YsuHd" M>lnb9!0@Lm R$)R{vweYY۷uExb{RΡ:ļIHyTz<):9t0izX!
 fLcq{4h=AX!YI#]D8r-i## @B&r&y~p&PF[|JWb'WfK@Ĉ	!1a?sC	t}> 5
é@Dsg?QOy?nix^+9폖9޻FΪ(;Tn0}>(g͗(Pj)td>R  TVplmhmw۾i֦6fX.ONz=*CddRkmifBj)=~gY!f~!۾c1hf!6UgB/EiQC%2:;s!)!R$Paq?[&#ںo7[d6-B4]kWR!b׶/cJtl6C7TJIMcB$9keyѶ}"`2RiJٴ
W+⏚OIY(Bq<7(6 0D1b1umwMynvu{{suӸ'&˅4MhLik]b f!ĳO^ODZk"Bx>y'zt 5{_Ube
ɀXP6_|w}凜'KDq_ۺ;7yQ,泓,rl:}tq>[gl^NYYs׵NhUa+eeA<#b<"e&eYf8;vM6mr9<:y1'e}?nil"m!xA on/PVϞ}'ѯ~+g7}uuZYe]oF	<VՓg'OY]<yć(0Us%^*f&3F28J `$ GDmQߧ+ /^_}}y7߽z{U{ 0JX0fBH)R	?ItY@yz{PI#Ťc컎fFk]%K-
9 %uߗĄ.-K|^Vp}}luQRK!Tb1u1'
qLz25R&:kDx	\^B҇&Y<HH$RJm4Rb[1*Ĕ'ei|<6) ` bf!9x~=2,ˢȁLsg7Wo"xX
n߼v(DU&Xk3ͷMcEL[k;k To}-uv1oևPUl:_ g?yJ(@+}rXovYd:jιf (H":713:3f]V ((,˴1F)2c:CP彧H*3.Lm 1z`S   V$Ou 	e!3R>XBѓ!H]Obч|ŗ.-S|CӢ\^^rR)bXkｵR	DJYJk۶{eCkB)W!r݇umsFDARB
Rl!S* RBIp[)\fFum~XL#J]8Ę.k7D`B!G2
q|fPsj?TJQlJi fV16L茴	HXCy ؎/"G
Vubr)xUp}%."0O|@d:0n)ݩwUQp+9Q#¸web݀xwk5{vͱq/?|wUx-?<}iC(R":/c A1))JERK"u5nnm0L2F{12 b
1"q$>$|9_񳲬p9ku΅\/J(ћ^)m!$MDι|ZZ,!$A*9R!ɈR.DM(dj(08K[]up\,D܀w	ADJ)br}(t\.:82m읇dYgL)9\8</ffsGC7wP$]|	CHHI/al H1:IH!Peq~vVd&R)=͌Dv6nmۖ!2H$6nJcn7ϛz /^X\{g&>pQE]1xqx ݞ4DQo}5di8x/۾Reir뺮1stZ|>;=9=?;+EimFgRbHR
D>y3zODBiQso|6;Y4z!h(HRF	tgUU:uMMӓӪ*n뚮kWzt}Kq|';(;۶n "    IDATܮb:N&O^|z#̴YQVdqr:_!2 8Rd&umcB!,8z FT͌)䓟۶^YVv;#yg9;	Mf҈1}S>I
 (Dκi6fFmv4qh$L  ySyh |91`V?Y,?Qʬ7W_;탳Co{)Rpv"@7b,xAV8rS8$>0P*8Tf!p(dH1	Iz\	'"Fd_|O>ML^H$m:k kWWWks1i24NUw_dyY7o\7UaBilʢd֦%dY5 h%Zkmemm^M!ȨƘ<ˣw;QJ<y˼(ʲ*~oV./ӓIU1n6u]owERG7HgZ5 
<zMgN+eǠŜ4aSP!gɨȵD"1"geR
!eӤ#5m Rj_uݘ,ˌ,cѩ *ls|B"1$Uj->?=: J	!\~[;;MCz&NIDU (Q$bQҺD/Z0ZK)1EYWňZfoy]R >SO (0EI \K^>{Rk#Ñԕw 0#
gR?-MJ.cMDZJnSgK!{} @~p܏nv[9b-va(5>I#xH坠m8ڑui\wh Z-1)ܟ1 "3  l>ixڻ#^10>~c>?tGwdw#c!9$64!{c` erFH)e4w_>4Mֻ%~TJ*U,wbXyryzO~,ω84EDĬL^CL1C H[޶u]THf!2T;ާxj%B]14)X,N @0
ovYβ|q~vڶnz. !GǮ-2]||{}̀LEgJi!UֵȀ T*3RD\+d2"Ek8%itQ!}#LbPJeU$l2J*mnVoon7풮	%$dvM6] "?3,]睧xxX\_5mQ1ھD8$AQ]	-ʰ~-s=WWWgeԳ,RM[v]:ɲ,b1.'ON'U55yn&\,2	MRRJdE"̲L,ଵ1ӧY?^_'XC\$BU1RQURoW~k}l7ۺiDNt(PJj  ۺͿ_>x|qQN&|M. 1"*"rhN戠EI>ML'ý贒!܄۞`!%'LaJ<<ԇRu18~[7^n7횽=1Hژ@`]eEl$~#3f)#e5)fVeqDc|\GWRIp#\bd@$Y>N=M<onGW)$
Mw"H>04y1!ql
M!>!!LvJc T
 bRc$pGYceydVMg3T5)Zݮn|aU	f'mX۷W+oVyfl՗4ͧlXmw]߷TEQ* b<u=Ő)ef:gI[7XF1x#qRG!@p|Wv-l8U5nVW-0g3DqZWn7u?4Q!r!#JhayQ&P^<Z;6:l@*U٤U)Swc2= 3,3Z4R.# aB:Ɋ]n;*gӉwӪ,djeDQID	IU.qBݾNr<{X̋<nEYMI%q@0s9zkWmtRJbTRyN 21Jȶ 1̵x!3y`.D8F34[BJBJJ!T0f
Ƙ(oo"˴2#R#*b9-G qATnrccęMHhi%Ui"atFq*"uwU41~FTh{&oQ;N9S^
@1y(	Hh`4N!4C[D^w}n"VqWd/{9MBwaw|wi8q)p\_!FJ!eaߴsR+tr!5dґ(ʧ^}o3Js+mNNOs)B zO  -ы?"H*(1$3 1sۦn= 	(H1$TBH`jM_n'ZaB"LgY%(R Vi1{z~1όbmҒsYo}d !Bj{R
LFι9% ژļ@ )rD17:(Jiy$PSg
R*}{ x&QH!֙p\T|9Njի뛛nh}zrizusvtR>@ ׷gB$G4-L~nY.|mܼyUd{k?==$+)R@#%{}}ۛ>ˑea5rlL-aϕpxÖE;HJ$g8=n4ַ՚]?ܪz L9v~@eeefe<6j\r&_d}l۟6k$*ǳ2-9!v]LoTUYΦ|1N^<x?Z3!]^J)ʊ*$'<Sw\<ϲLI@]<Om6Zk2Cp{i8f\*ev\12ΥM67ԚUR|O?'>jϞ}ӯϊj4Φ9dҗ
!LH b,(S't?̌Rp@#cq@" @  @
S,7AKm?t 0.Xr|e%G ]7777XQKL19o1F= UU5Ng͛m۸KS(304-Ljr b3r'Zr9tVv38F㋋G~GC[?yѳg~/؁n?`  ()UYDt`1."F<1% p4C[:۩(; I1/,##ċW/VgrYxgUUUUg0o^/˪:[cW_r'٧}iqU~X9
зCc,_\Tپsݮ&a7Rm_Z73xp~ƹ娜L'i^@͛/kw?_|7f1.bR"@%Z]<z|~p:EIvm}yV*wg "w;C(F#"H >]\:n (gAr&Eg#(,}]!!g<
b16vg.j2j<$ru.x0BK4~^f1"UU_8ZՈv g.R~fQQdH%3%	9O1f2F[ӷ`\2xC dJi7.9C!0,Kc (RLI	fB^RR**ظ٬/}]׹V}|q6eJ<a8 {YJI@6r @#DI<R9r)Sdt KGq?t{R'aFsD ^{H]3Ǚd&8E_z8O[J ;5;4~!cv7x0ex1-`:.~G\7|F@@pܯqz[3rg$2x09v]o}	L\ kMCC`CȤҕfǭ1fy&1Sl,S|Z5aO,J)18Gy@%2im7?9RܽB*nn/lWR*ϋX+PY΅^].!e>TRWl6) ቜ)L<`1t뺦y~1b?~0i
_J,w)E{g:ok~4`g:!2M+Hn <"&_P)=Bh:q& vR1FhU!Z:\{#`rx23dqQx2WedJZ]VmE,3wׯ^mBdBƓl?oBs.h>eUd*޼~8?*;[of͕1|6.8}D	xH|c!D5)L3Zk~՗nY-5J
hTeߵ0$A@Ԥ,t2g/\R5fZ]b(S"NdI#EdBi*C}x\yVTjzt]4ۦè,Bp>97Q#"gtR˫zZחWכ]þBgI51^ R
g-".?1</GYY˶i֛MJibFȘȔȔJx2Z	+&@ǟft>; $	 29oCRpq>*3H
B$
 gQYlg߮ءEYU}kclvvwM;&M$r<((+&D˗mx	у   +acO	)MJX|ce)ڡ.oJg}sblo[)x4Xg?}HQ1=Lr0~&qAH1ǐ3=LrEIcHW!De>x$ҙ͋o_|m[mYM'cwcc\p)!ꝵFHɐ"Mo6j?@ )*;>fԙ\ڮ_\ovuݴCߦ ;!ЛaZor\3%,t\H<˹6OsA't]wuuu\ջޥS.FxRUu6uI]0 R*839Z %3%B,!F㣷I%'F@bk%Y!!2Ov.˲*l2˸in3)9n=g(}j)?`}
XgoooR?3k)]u:x/8/2">c!1y"@v8
C-
{CD:b   n9QQM菜IK7O_g,2-g\H
)R?EBH)%"NBM4K x	 ^Qɞ  Z ѻq`wpă~8HG=JyXm?9
om
?qlC_u`t,x ,@}w=O[%xpyRzo{~ۼp\oBtөk K)' qCDbԴ22{bwrD>dZ8r2U,˲#7%@ƌ1Ƹ^p9!f 9cb<=sxu_oYQNl1LEQew5"VQJm!<C t]?l"@ B$~RcZmp!J;9߮C.Dq|B4IƹVJ
n 8B )}9.R3dq^h<ɋ2QJ8O"@TR&@#@y_k0ڽ9- s.ReY.B-l"0f&XUYRdZַKҺ|>}"<g{UU=nr1Fj>_l\+
j4fBg'D 2DIHc}7$D!Đe|f6P;%E~zkBj4L|:ˋBjU	 }W׻E"˷'ǽ%cL0&8I80ZGye5vJ.{R3t0Fnǣf\-WrƄDC~9AJHo*MϋOكR*$ZKń1.d2L,.Z*c$|>E#ƐRMD ΐIAĒc'ýg.%b\px\]__o[h4M'X
d1}/<IQеvڮﻮmJ1Xk]o6RJ-amڔAG!Dw	ˉ_D@{J[R.&%B^M|:eť!x3ye
0},/dy|4vn0cRodB`"CDj%&0{2\  dIPJP@ҏ)zﭳɏGJ9j믵R2+2Ӛbb<{pQ:kR}i0΅}ǹJ :#R
]tMJ&l' Hr|UYfyF`vWM4MSC"q"RVMݴQI.̲LIu.3xu481.̤YQy5|6NGeE@mlV7WsJ0|4) 1BSm3LE!8rz J{cZb{Rpgsk)ڮ!3y!,+UUUFi۶axVe j!/
71(Q}.XyJri7o2M	!ڶ'nZkd}e- <HR09x/EDWH#^Q¹JfZvoS'A09șs/}QB4Q{dS(	 r0Pt0<>TzsW/]>6S:ԱΧc{}:٭; |08yy}wO_cNt{Q3-E aR% ޵§T޳.,=Is~Eku}ԹΥ.rkM`BgJ!=VZ
dY.qYd    IDATbDзp0z8?q5k3)No_zYF@L*):{p'J%'qǸn~`{QS7A\+`8猡˲$âȶvWk%J0	,r@h{w].ۦ6}C 3y)< ByRR	1 2.R
BIȥ#!YT*%&Ov,M!g(9R:"8s7fC@ɇ@'LѨRYGUYԻmm_wv4>xp`1}w/_y:'LLy_~ei aJ(jBVŎh<}ُtd }Qp˙9.%0ac娩) 1"Z`awm78Z[3fu0eU=8?/Ϊj@`vm{yylt^gfZ-Wmede:JRH L#qƐ1b8l>EYkzzJ|~q뻺DdBdZGgy,fZfJteH$@BD!Db1Oec̳gU5>?YD I%B!Dk  i4#Ԉx|2H{9,K)'ʬ*2˳(~wM~كxTjh]-_~uzqarC;tfYqy^n|{}yDaO='LCiG t)&ݦx |k?J0F!b$ȅ:gAb bE5b*#&D 
ط}>StI(18XD!xpxAtyS 
>fOq/NH1rεk>aD| %8 =~}/^Af~Sw]QY$yD1mn[\!p5BTe qxB4`ylWwq\H+ED)m$Z\()9iV3g-cȼs>H8SY.v˛/5_zC!~w! ,Ul6Ϧl2[vDfoo^\;gCo}yc$!KJ{*IY~pZG.!"h%2ey>"7]c2ƅR6ugY;L`B ,.Wonq5Ml>aojmyEb٬mk]b#?=,Fho򲪪ɨ:Ji)  0zgeBEQ{8CXc  Y8cӛ8cL+Uh(MիleYYyM5Cot1xwGzo__nW`7Aƌ Xw2&S
%*c6DＸ'|k#{sޚXK'F	!Qܿ'Tc걇<y"褙cV9;.'C=g |Lýs}o
[-e\~wzMJ!ִ]Gt37xz\s_{7}Ju%͞@ާwY7l6+|@lVfC7o.o~~z{} "δҺ@tfxyy,x)vMktO'ᧂq)Ջg__/y*N&l6OgZfY^]ഒUU=r\]n7d"RyBpMAHXFι<8gyܐ0r>E3M۩RL^|I'ZfM۵m߷^::9}V)ťB aG!Gf+`ISIU#CLA&ĄBK
!8T:\ <k!:Lg1,GqeEYL&?| fyђ۬W_onW5y߶MӮK&D*ay=o7mYd2W~ًM&S.;+  F #0MY	mI8R^%hֽ\rier>yE1=Rz.//۪,sZɦ&F:{$2qXP 2%%!d0WeYjMHF\:WƳb8ӺnE.y<ɤY$>vS7vnv;ome!KQ  $M۵R_W}>
ZJY%E?AE8]۶5h2d$a{O1QA6xkO6mWrJzgrϿ?֟~7oo/?l:Lh<& !J^_߮~:ϧ</ΔRU5JpwT?n07W}r!5<Ӧm"CB>D"""rAHa>(1b ɐ,ˋ"ϋ~OY^H)C)e"(YyQ{_}gh07! Bk1!9g>@Y=Ds;!@bNNtH?^)5!׫,5^JC,JɈjUύ޷|۶*vkx|suٵmVEgyh1~hۺovm5 ceQ]=2I\*!e<RVd2.n0f6UH}"0&84H !8cHs!(!YQ^z^Lrګ7oR]t]?Xb4.EYJ)|!Mfsyuu\$%	L(ӌ`LLiȳ(ˢ噪tlwMuiۦmۦn\K))˒M(8皶JX 2RR9 C͑~|͋Rkx2֚ˈL*l꺎1h%#d1n0O&8!#xikOI	!`23797-QY| OY B3CֆJ/) b	4)/8VE>N/ h)
b4?Ϳz+vTd	SJi%D!{Y\;·ah_\O_TE YBbs^Aolj$4fBv%uaoixSU@=	`W @RNx8w=os&-DpQHD{Sܧ{ "JM]|'λGEpY<YL
͸.Gv߷bƃ!GQM;i%z霍;kzgm30ʲ" WO`)N#!<VB-lV"ϲL#'Tv1F!>FDXC(8ۧ_oin/U#M٬(+w18g~ 3TZMX4}/oWBT!+48k112d	Zguu]yum!N狢9#@<O&M5u4{MHYBJ+(8D1UOWDKɟ|:"A1=N9B8'5fiڮku1Rzf8gJ
|>L'Ji)x<LMSwY9֛mJJ.LʲȪln[7<T0Ɖ	!&bXVW(O?iݵ!FƘs.xb3^FD7]p~臾E"(dvu-+*Kݮu-DȘ`,/|6MGq>˲bX-/1%B*!NX$c8Jd;ň*32`D\om/FIirZ1X=	Їxuu}q6jvu{aUPRH"|lڮ,>?e5J$d."x,H8 mvIƀv!C?8{;xa&i
3ðw1Xkw-|><]<xR]V޼v7(V Piѣ.(Ԍ1"ڮn3!8Bo5_z٬Wƅx:!FMMDG+2) KU'"8zAޜh%OByt~mm[ooNk-D)dRIUUΤcsDjl>xo!P)B¤.#E3H`籉m;Ti؟DHaobL+p9G.$\p&4MCdKw"wȳ./?zwOWow??xkgB!zWY1sLgZ)%	)Ǔi50`OBN:RL֚m6[ciaRpn:t! 3Ə8$ǤQOx2NȤEYf|ݬ.v.,l8MERB,˕w|'<תTB+2&$0^(! d@$q\$npVr(8~0f1mn0mummZczzE)BdtCR00gYm7Z!BVfZ+b<Z|VzB.Re	͌w19s@A%,Qe{=@RW.E0 @.YJ9DZ9(d,1WWWv1~T=9gQw_^>6.LrkLbt!X!ƘqaW׉	%vp$bRx^Fb>'ˬ(RH@ߪ)(vtʻ&ڭ#֚߿'6x]-@{[_z<`{`VF۞#	=3hA6x8_^cr~d<ΦN:P=EG7SA/zQ= ߷hct'  0jy㽏s&[>B0q8Y.&UȝuYhdw]7㼋1nEYUM],q^ɠ{Wo7_um]Er~v~vmg&%Pj=5ͶΘ
)&'=(=cKh	umKDY2Kvxά11xt1!xXJ~};ﺾ!!89JIDRaZ1LV]Hv "`!D1 EHvy쩰Hf0ھ1ƅinH녀h</!*zm;=c8c}ͷ_,Ȩ,\ޮmO{΅BYcx1j;g/_"1L>|C\BsB2	< !8cb|4TJ)" u(C2!eQRx<av^yB!lq>EGJ	1k?$yCB	J0B!D\gj6@1p>w޵zt:{JkfzƘa\UlH޹j9aȽs]uui !{%L(xO/ 2(Qb$#EΆ})Idm6v(yVy׶mv-MM=c19%  Rَ108O?OQWyb}"X7ժnowzzt<JyY燾m}XkgáEYUe >ﶛͳg.on1#)6"{Etrj%p$CĹ//>xc]mu}0C3\Rz<ג3$cuEY;q>H1&aHQ"ߏQO)b<ň  dqCzZ-"CcH!i\H{CR5{4E1:k˲w=ÏF12׻?.g\)-8ƚۡ9CΓAYi:RgJ(oX"j@3 E p35 $.k)^L)d/ăn!&}yBEyjmw[͍~ &tv~/r	gѮfGd6y<Ee3.ܰv]Lceh9]כ@pwn4fַ7fZWͦma,k1ZLkk, ac,@" JgJiջgȄ"@C~!Tj<egZ)u~@
aQZM&Lw$r 8N=Χ6&ϵVO@-0E"]n>Uɸ	E{;B9S޹<K{EcSB]̲"8	"sNЙ/?09"|/G!RJ),r5 OƳd>L3-jM'̔.,+Kޯ-t7 蚩{o!6N6߻a@L;'*cۅxw7#'`rwSӉ' ^)"వ#t߻~3=C۰!,Ƀ,{$}ⷛDhOep~awX{{{`56zOj㖛YUe^E.v6jfn]n751xDE lL9cŃ?δNJq._|Ytn9LUUUv˛f6Ę|D"q.FUJnm&G.Y 01""g;qUkDgkdiRZkS0"D~pe
J)&ܘ_$Y2=;Ҋqad:Ud(	ce( bџcwbۛ3-ۧvЛuȘ`B>(l:*ov:)b>go,lgs6^j:!Gbߜ;zfRYU#zyWRmB`ggR	䂈a/};os6ydkC$GwuQi˛Ǐ.geUu]\.׷0@!98'.q}
@)H;әHD>t6&RrHZCmu?f]7ƅƘgϾF ],(ceYrf캁3u5&8KaR1Ե8''?|gT	A1X^]SƘLJEMWn$LnY\١M(·%_~0CG!dJ.l˲L\[й/j˿v~<y|6e\mY_y_5ϟ~u&d}\^^]XJٶ՛gieA",SY&%
5	"ʀ#!/77Wյ: |@hi
{҈o?-CB>88;g_()._4ܮyZ)&L&v!^    IDATQ(+9L:˝MbE)>+YwnÁQ޳a M#c12JGa)#MRI&Z8	Rrܮ7{1"gY-&OwMLQ9<Rv﻾q>x)j^gHb>L1  Q}F8w !ERzZd,xϸBr_>tk;7X眻G}g?GZI̐d	fe]y9OǋL)]Vy8Z˲S0< 1.o^ڭuH!1RSm;X3\_CODJIY>3f5G
3cvݛ˫ۗ_ǿg~0(3=y>!`(8OfR2&	ԍʃc$L,^x(/_b4gGyθtumvuumP3-S	xYq>dZo]kHF." D9)D~]>tRŅާ)gr8묵-,Jɤm5DAJrd<iۮ>D'ɑ8Y_^={Y{usCDHi)BƔRpRJɡ7 @	>2B2UQdZ%1vm]o8?t]e'<bp14=ީ/)	Z4}NW8w@:`<%w;ppM?%_S8-=%]kp7qy  t%01=N: ߳	ZxuNAO1_{Dhy
SyHMqM{<Z5f10דּn0XC.Dc]зu2u`5mqݶw}u@gO"(୽|z4#kxRFȅRJKio~/Wo!xgtXӤ3IeYQeR=dIv՗X3#3_{gz!'~	%>	I.P]ݵ-_.z3Ӈ{?<Dsp׎ٱs"Yҝ8`8䔒R(Rxټ,	cN_}#Fe/ "I e!qk  11J*U2)AIa  PTKD @IO( <~|ا<|ݶ+"ϳ> F#b:L&,˘bZWծ<R)U"%ؔ`AC"/na0NdBBL'H۷ HmY
rUunvrgt4]9 &1๮*="!16selBȈO&yQ(c1eYsӶUݸǀRE16'"/',q IxT$J80%NQuj]jx2%]+ǣ,"b$l4	&\dp>4M# a/Uwxc|u"ѣ7e:I`*95Wa
1R0C ]t]۶m4@1@λmEw]ߴ]v] R<Q<;O󳳳"M͒i	U./UUUMۮnhh:NQQZk!D4sm7o|֟}駟>~gx Ri.{cۮo_]!eC!He>ԯ$6Ϟ?;ۛfckZ*r~w4MQeq\mڶc&Y UHSb	H@ ?>32|@+Pb )EvJ:"%e*Qjۖ(S&&"Sa
&b5=QZ&өPkDeYJc,%()"0P !τQ Z+AΊ{EP|r(H$uu!̬q}jyw]TD>}>{?)S-eꝃ!Ē#L~?$ +3kBTz[TFG0Iafd>dYVʹvv4j_7{T^dr2ы~/?f3rk^@aRIi2SyQfy[-jgHo$D'@uXUUU]cdW;czTYicc":1ksDQJMy$PJic2%)<ɩc @@I6i"'t!V0ɉa#VJi=si4VH;`PT"b5ջ{gC  kpAm4uw}x,d}ۿs{w	VRRߚRz `r}7ZR
dQ0XZJݬu॓+b!T?`j|xy4WNx|Fsk8{OYqh/{c:KG'Ͱ:ߺ$38ly(~͞:"/mpo i,"_=,ӿnRsʌެ7{<!sc1C|10ƀԨ	Inڶmۡ[! 4<,I)QJg!{8q۹ޮwow  0ƌ&ӄ M]B8J6ˋѨ,"R*OR (uG!b LOI9;03FORz*cmi8$8`SD:8FdfcteM8qB Ri!RN'#${J?DEW7pa'wQ}[-W l<ˋޖy^,< \n]]UuB1,,/fiJaP9 " fIY^F8 \I9G̉4.gY4$wif@`>SclRJ_͊2Qq9!bD(GB1=VIfdOgL+@f{KH7hq*زL1hGhTFa ޵u۷]~Z^\,u]iGeYEt.,us{ߵ ¬dX=ɓG?'iԮHHRIe #` h@:л_owwfݵ-GBp>:׷].[M7#B)@iLU̘d.NB#mRR	agNN]7UUW\nY7]YeQy]R&s)pQ&<~Z*GAns}ݻW,NO,B21\n<|`>ݽ{w}W|@ӄx﻾B'(-a:cf &c@& GO=uuw{nN@jp>tuK&v6:b&X)9"Fi[/D6"D$$!IIH`IG13'rr2dD&`L*gI!]R~ۥAo$B!8`ۈ4ĨwQXlT]o~jcfbBF㦮kOI\JRdr?5	R)!A)%(ʊ!LR4&m[諸vorto/=R)d$d4O>O֍R-NJ>omh<ͳ"G7d`{m)Uqc]4]>Fm7uJ2bwxӧO^x|]}-Ş%wifڼNf5sYE<u*cъJQZy.L鵍CeSgCYQXiA5F1b䥞frZ)s9R252>Ew}4nTEYbD!@LRJP
46V[2ٯLialXh!<ˋ,˴!Ӊ D$L@x}gm]QbP*>&jcLB*aOJgZU<WP6*˥ׯgO 95H0	p K W}/=>>PI5=?o0J @{um	{p\>÷ݟ~=ݣGqax?	ây!~,<8ze}5.^N;f7ѳZ^]]>iCt΅|!x1?|@H1z;W5]vS̄&5V˪n:D|ţyQD۵o_ӟo8x%BY6NƓ1&߻:R Vh,I2˨Bd˄1Ϭ8@ۺ(2+Oh2]-WVg.TZҝd&"	$T&b"adu
fkmYwww9"{!F)=
I%{7þi,R zwzS7uHEVEe߼EYț'j}w}BYN'⫗?ϽJ}b&,{|yvݧY+uq~#:_%Bh@dyӓT`욦32(F$5X;!2Bpu.)\3t&E'D!bbʲ, `Z ȌR{*!4R׵yTJ;Tu[5zwϣ}sdzGenxER޹iڮ)C1FB0${p?go_*9 KIbX!`zd]{vE}߷]׶nDcL]HVj6<yɣTVr<m1Kb_3Xk1֘tsTrzuw-yX=8?[,rn)xTl6;Q|vuo_r(޾yɴ1Fi+0s-"AsNJO=[޽yD׹b.3LH,$Cc!#"G?ǣQY7m, ,p 32Z^^3CĨ* 흳Z3"  `AF &x\E`8;1p%(S=A+9H	BHrRhTD@Hcul6[f}7e YQFm,s]Ubqv~s. F2d2黆|bc~	Ih݇C[ubQ\a"L^bA@Lya?GSrʚƵfWio[HH.0Q?$ݬzGe}tqH<h9u}^we׵O>˲l<"1	@qUWWm]y1NĈ>jY=?g7濎}BژbT˼0yqzv~8_wCxϞ&"ύ1$d>a)mR%ԩV*Tﺮi0x$b5fTh2bRNGFI#!w][UXkmF K?L? XVJ_7[(6m
Rvf L1M'HD.H[.Ϋ bef
<|4޻hc4 h҈]8?[/?|ӟlVwT!
uĤ,rJ$F%T2i4Y%&-LAT@\߽3??B2^2`$K|{Lȣ)GU{vIxs>7{$v%-a_5K;{:14?68>~p-C_k:-߿~/R" Iqᯋ싇WoZ\w7ˡ_Cq]zgaN/)onn˲RrRrI,*F׷	S{Dw}99l =Ei҉9)
sy~s\޽z?=k2drJ-g<NN秋K)0wm׶JdJkۼȕZjiX*-B){%~I.,AH1^2kJ	1Enz[dv4,0~`.6']]UJj4h,!(C{aQJj4
YPBi!I Lb.">}ǧnl6ﮯWPF~q:{Q1ϪGfK|LgCz%?{'߿_}vWhtyq~85F;ACx'(|q6BH`6RiMeLlgg&EkwU1&VuBPZR<Hcew}B)m@&_h٬&/rcDtfB06/"ҹČ "0LfR4qM]u= Ťvi9?y,m߷mzQRXc"9M|`e!-j}z:_?gOY)6o1t#Ze4A09bL1m7ƹN)mmn91˲QYQ(cBUU3b>{ѣ'x4ҙͲ<+Gy9.ʱb
 *RQJE)|Zo]d֦bbqzbBDpbzvJ_~eX,"wk J-!<R]={
wMlv7Wo^zWj˵6"u.!JH)UEď>}O))ںz۵m5{Ҧ #I0cUJ(t}i4$&& 00!h^%d0Lb P$_|x>*ݗ_~.x81!zd;WUUv$8I(aYFZcwKk3:|^	L1t6?Y.oQIimE	!$(FƘʀb$L5pfK$)}OQd f$)҃ B,XH$P,$IB	uk\$Ȋbqvqz(kykR#ikAmU753?ݏ>~T!onvM]okw9VwZV!v	,t!D "Ffm3^)=LW_|~~~.F?'sŨ,ۀfY. c|2"3zjd6wMN 
R ʘr A	 fˮ=xmE^1-,Fdr2ƣjW%D])N)eF3"FA׷4|>]\fe)J))&z !  (db;ngm5ZM1;ƨ˱P*ϲ(m^r駟_#1Eyk~7 JwkLnmY:ƔB7WW_tm;x||o_gdo)pLdуwz̎0 |=|߼'寡5{2öa=|hY GdVqtVsH8d?}yCeNޗ txAgc=;0?
b\{/Y@ &,    IDATxu\<`ÿv/xP\V>˷17[|LnGIen2k۶ԯxb'P}xPSBHZkdRD,V]ۍ&3R *m=~VjY{猵y9*QJnov!2-[IHm1I269ETZ4kmR)@$mBy~oKw뮯oΈ)#,]u{s q MP(tmc,ro5 IU+b-I(14R7~4Oꪺn1F#eﺾmں1ۻ[-EQY9m:˞<87֦&v[wM5}]UgYٷo^7MDZAZbhtXLg'>Y.R6˳0Z!"429%F Ekf"{4ԿRֆ1;ޔɘ.F!咁OOZI]0Iڦ2tmՊ(ǓȵRĄogfC̚ddDmO_U@*[\~Wtq2wQ
uQpԌ1yV30c&"@&fot2zw7RHoYᔪOEE"LI>xoLv~q1WWo߽wM۷]񈉕Z)%h.h88_,(rcyV$wo-r<Fw5H#C)cLEEet<ZOSO6oղ,mYkx,&dϖ˻]U]]Qi}FD6Ӊ7ŌHy!G"vL^GuMUnmzq77]9z'xf[V] Z<Ābjc$3UBEzd"LI(0FFRw0Ȥ@ x` L|.-Rjc|6O]9bEC^
3v i=`̜e6yGu}MSWuJ53gr4Z䠈0̆)59e>P:aG$|"01":YA$O1uE@DCJCu4ufr<N0#t"VB49眿6rl.vyp]@w>  @H$E!30
S3$d Zi%ޮFkuwLOd:@YmSy6J)1(cʢ,Gھdi.u+~m
!RIAҽOSP|ߓ#mVyNNNgBDeYl6k.Lm]R
R$Ajib<rtjL6J~7TԜz}vݮ}@%ȓhڮn˥CUw="TDF
,GlZ-׫-"ED#SyDCc@Rq_2M1m{}}R#1ư]7fjd0r"A8C#q2P7zKzx8nvO+P;Z{h@N5%&z(?P+7]?貿돨b z
{(?-k	V
_;o?m݇&R7>C{GxP oVUeĐR cto۶]Fq|w!c"%%P:Au,B
LWLD"&aͬ1xY*OO.'u6Z*R0sѻv{ R) +l,jm@$""bdqYBZ k%O2-	"*B[1h!VJm˥FkeYR)$&ƐMSW@DM]Fe>*2!&xIQ&˳bL7ZBR!LzRTfų_\n뫷w7},3}/cˬ==?}r9]ݮ˕r:ECd2ĐWڮc.f|6Wu{UB
<b,gghTvmf-FBFEYܴmQ)X8 u]E1 b躶k[ Fc!!
!ԾbN2k/̻jLx4yumJic}UU- \7x:fIf|umun<߳6c"|]]y9x_WwxևED٧?[MJYȳ.2C{nf8sʔ ??2lWM0@꺤p 2"RSx$d9HZ)m9T2,R1Ff"y~8ӓӬ(Xt_/b4ͦ(7r8<)b4*66hcb{m58-NMf^5mYi;\޵]k:ju\mj}D@Čw!`j@J<(`V̦,/Iz{ү*0FgVWMUfWo_UUuݴWIyvv6υ2]m֫fSUmY+)q39eB!N	$b"p!DB"dBb04I"&(qd`|1N=tJN&EʲWegC`D 6Z3QU׫m;$abICIHUU"
 qVmS1"R|@Hb|i/$ !:Rp& oB q7ǸLq(@W@gBڶkRLJff} `D[mI1-ՋOy^5/?gBAf;btR~WHz@/ Y%%	AȄR(
 jJkm횺w9kh<fyiCPZWuK^ $Mfy9!k]b^LԵmC)h/jDZ*1FNeM @wmޏcQU;A16]gJI5Vk3`Ne罏)Jkel1ZZL6d^) )ﻶۛ嶪>"CW_WmEI8M.RJkf m*ehTh<VZ~	`d	#adP.Fچճɸ,G668
xϊ&W 9)!Zcރol>P ގ-^XP,{}P;=?1>Ƀ#/[N4c L{׎"#ؼGB#TVf}y<b7}Q6tIPs_,p(-_͛wU]3QO>{}H8F͌TJK5;ÈY0ژ'y! 9 &*/O/# i۶FJceTO+Y}Խ򘒯fl6L!s}[noZɽ !0P]7Y$(cͥޮW(/'#<ˌJxNO70꽵C|Knۦ'IٲȒ)2F?af%Xҧg>ĹڲT,V0	(I=a@?xGv߼~*%lZk1~~Ǘ}m]}%>{6}o^G2z]beE7vR&"ae!H8Ȋ"1ؼOF̚t4hmU	THM#? yv}w	")L~!5Z	FDujNVj!2)=rX7}Z\-gYWqWx4x{~:fy99x$m^]_[V?mmnwW/_~3#>H<OO& ޾y h!	
!/~G?"į>-HF ';
]_\-7Ul>*x\#b޽z>[o]Bdjݿ 	^x?xBH3ky/oK)eެW_~͋-ͬ1Jkf\߹ E\+cdtψ99{[ PëW@glMgOt}_Uvk6Qڪ]( RkgQvjs2Oǣ̚x"xĆ9={Ƙ^o06o^QvOnٶ]CRh[߻wts	#BuadYS5`,މ85Y^P
dBAIm_a<(&4jF%QAkb4.S5X!y_o]J*)J/0&#b4jz]Ad	B
4 T6;pB/ IZ|v I J@J ,_
!9 fK H,#b֘jN!W)P]vZOP
0m^/^|ٳdnJ\" Lۂ&8/
  Fʕ"eMCȳZ!FEش	}pfM@"}/IƅfVX
#EYvݬcggg}sΥ@*D!6Km6FkC'MNZBđ !egϟ?}__/NMCR2yQeY.N4fsws|Gk"Rj:.ȋr<g# Lmǎ8!F wջϿnW!DD4rU,x<ƣ23#益mꮭeYX1i)%{60RJ-X!:/YyZ6smsaD$6bxx<bA-dHgUG7܋E@xM8~g &jRZG<;|N"kО<pE?"[+[?pW߻PA11ˣ08('ž-vB쉼<*Ǟǉ_x\î_[ p|qٝ#h{͞{/U4?c|B C$8ORuJBBhe$Fq3*sgB=,- (Cƞ]\~) $"IFE " E!ϳ]Wիۺ1F5bx\Jt2RVRkE% TL0ؼ4Y)m[c(9)(K@r8hf2躮J,_/h4NADhT~ߙn#BT*$OXԻfY9>mI1QH?'H)RlX:<zvڮnbTN}윙,˫wﶻJ w,Ctɓ˗/Qx6,Fe4nCg/'qvRJ}UU]%Z+cTBcn;fNҬ,F>R2SVIn7U`0J$2mA*`TJ}P۶vmhO}fVLQH%8J+aZ[kR#"yeRtZW;U!ʻjg~>kmMۓӳcz?NZw}ߺO*Dmnwj[ݶ~OdD.ջf6Ův[C^00f>$H)d?ϘyYS ^p "FDd%ǾTj[UgBZoonC|/x{{[u׶Ii ϋϞ=y|9L 2k3uYeJkT==?E~ٮWDRؾfys?x<=9l2;fX#ۦ1yfTRe~M'Gjڻ뚻wBt:]<~W=2/~nLvzHZAiH) b"GO~ofG/wѹ <%X 2#"$Sf38PJDtB~'DBE 9I&jD$ᢈAHɏD*Tft9OONmw. 1Q)"mwWm'@$b)a0f&RApm["ba"APk֋R3LǣO2DAr131RrOȿ 1y~^X
s "lрjT˯~?/^\U7[alc!1!eqWUV+hfkDL5/|[b<.($$JPBĈuz BLiGzyԖ뛛뛛l
B&	<=9/ΦUo߼}{^./6-rJ	&i(6ezUYBd>],Rk]˾wd1٨1B RVFK$I"@A,Rޏ<ň^bTI9H,0ZgֆuhژeQ'QV/dWf\nWm>PkdJ=@)YR:,#E_7m(,t:cfBd@tҞy`f#RN@MuUQ<yI!1K R	 !$  &BC@ft!SպWI0ɡL&@ȇPU?d~@Lܛ5Y%ag.Ufm`fAdHtOoU]Uy殇fVu50 (ay+n,'#{ޞH< տCCY2;1>xFq_#%c=!L#4"(z(ȇ!p!7 O4~&?
??
 w82HL0:7v{׹fݬW++)SÉ2+CZ1,O(QbwU @Jji&Z"VjZR23"qlVonRHDC &1VI5>)E>hK<!Ҩ0JL{7cn&˦BdsX?պ(k֪5C;=Zkʲ1w)UQJuX߷1x&  Gnt1f6o߼v;) 	Aӳf>fFTQ鞽ټ*cDI۲~͛W8Vus	
qVJ4}OPP(G=cJtw߬W(r]׍Ø;+b}Ru}bB+QU~R
!|   4߃@cR*qt>G{	LOp91C18}'Ml{(PHM6d,bZ)- $J9^EQzۇ9-%4
qnmTu<=Ky q7/]ތ87=}z~y3q\Jnnכm70teYZ1FdQRwv9',}ٻcRY?ccsT&ʢ	R$(/đ(cO,/k[U-jnqR(E5z^F7r8??ty2˙"R ;D&u{ʜcݫW߯Ƅs    IDAT9mwZ￷EY7b\.jfuTu]|V7ubbhgJuUuevw~۝GH?z|~~43kLVR>$d{z߶f^4 *7!a#H !6R*$P/~~ַ׫zZoơK@Hcs &k-+m`B`TUUB
fBӏ.{pBr-٠b"f"3et&b,q\R&8R6VJE1ofEQv!ι4f۷]w(5bbaL2ND1%!:CLmq!߾yBh`n[,oMLfQÕgqk>>,}pEF&bqy-Oӡ1F)Dp)eV8'}˗/wzqXt 9%
{08e (u&fkvXTu(H)>D"c|VU4#,L)U5_,Zf<lVX+f
SRf?}vC}j;b1Dpwv8IY3ZmL41%5(LͭQftL)>d9Ȍ@1ӳ]F!2Q̢h>0	)"̓n^fl9kNN-Pf+ҥ뇾aPAb7]߅b$`D 4*Q(-Qa]913f``8	B`ZNAUR
JcF)B!rO1E8GĒ?8QFI)$ QNL^<~!؂wnG}?tw<48NÑ{`\!n<~JK? {2x,~p&A@%prM `1z@;dT|,#w'#~sC !ѐs{nx0jׯ__nuw{.+!zhc!B¼G:$(.8\6 b @J`!%E`=0۾ݻnLZI cQJB
!)fR9	$G	J
27	DH!q{FJ)Yb%eQn+wbQuYUιcԉ{n]^FvbԶZ|tyYۛz&Gsuaūׯwue T6)eQflUL{ɧO=_^T(3S!F&RJ?~b>DbX noC:71F%ma@1Jʬ28	)RX+$G+RQy7QԸt;Q|pc>wm 
9))SBk!x<[,Odp@!d.b臮ꦩ
+ڶVueRw]7כZk?^~"smmݦm'prжmGVUy7f<#DD\!&NSuRGg'q@\&LcW~yz}B1epqu۶Z/O }0JDk[mc㏞>y|rr#٬(c1%Q6g?O?q>.%07w/wmc>_\HգǳkfQYc)xt) 0jsw]b(M9[^^^]ϛd;cƓ.
@7huL3˓s+SHLY~46ODJ-ɓ?W^|׿W^u}ۮjR
c]@RD!NO:$2̑R=8=L@̲LD 	%4򔛊XKiJqbv^6vu<  N.IRR
 6t0/5|]6W UӔuvBH(x
R7gRNbRDt|	2#EV\cbޭ`lΑm~@ lW_\_oн'$tSRm7m1ձE}[ݝ,gB0rGb>/EeZ*ɍRˋG9-cp'''eHq~t{9g08o)xkL49g&G翸|lZB,?ynzv]`]Wu3ua	0&
9x`"4B+ I
B-0`p`ZݮV]7X*% NN))$)iDvu=UUm1znwfYo*]ʘl,B 
!0 Y5`)i} ھ1EJXkaܷ<"օjP pΔ!"8!F5;D *1nPJIeZrLQH!1@Jp]x܎$9RT,& !2~Rc~۱(S#2G0"?<Dryx<GtJh^3|\p  nxxގ8Xv@4xodB;b >v}Ѕ?H?!a[>
 d8UNLD lw_>.bLua1(d&Ą޹qއy}^/D㡩o!%}r0ȓ6)Rd#1qV'&"]߭n&SB L)ErCJm
sO0P
CV(BH۷n}b#
 )	$HLQ͚&?2a~kl4߾fŲkDVO=[nVۛ0x ~_Λӓ(׫/~R[Գ3iĈrzC@))19ܯWR--S
ލ}[ֳ*gP7v)}'6@ggUavݍ!jSNj38ɂ(D)09G)))1&ܤd&k+1$nz{MI	RR1 J8#HP~nk2B
ޅP*%)!O ΛjbJipe-"[JwM]WuiRCצ0䬇/s$~.NO~Oww706ۮaXnSJ·ݾ(6{BlVWU"x{{o[qVR("gui+7
9Ĩ"[s!1@)xw	ѓ?99=7}ˬۛ~\.Cn1u7o7}̜fWWW|IU躞XXSUeYBeI\\uYutW}WM/Oa曯o޾*fC,Ru6(+mmid]|^E]7EUKSYZ Jآ^F7HEYkDf7bwv_7Ef.lEUbUF+%5"&JeE
!+(#dD$w)u}6Z_~_y{}ZmCׯonRڢRr6iq@dC3b* LޏoYУ#21JmSr}_}n땏^}kJM*'QY3)`{\2RJ(<=YgN1.z7}"JBRբ!'+PrRP> R%Sd}Nb3PztrA K.(8G BJݨBUuF۲lu3]ŷʔ|1&` !nwfuumTŰb
$ʈgJZX,'/~տRDXJ.
[7MU.GxݽyvFG7l@FFG~9;m,gMszϚnwq~XkMQJ)SΓZ=KSHޏ޻|Blmtn\7Cb Փ0 !.=:]?oUiΚ*+QknXpB.+mN1HA)98nV֚b6/

 8%!@!6beݗ}b]:STA^(#1FKB$-"eU7T*9f.gXK*(FP6SH#Bց=o!F]cMZ"DDH)K?M;qD}+U:eM:e!pJ $!UUZeGAp x@G/8|`6=٘|G?vD| B'|;`C|S]jbd0;aG?x,f<x}+`|7Au#ARRj%o?ͯw77]fR*1d~tλ AHZ~'3]pf1x﫺犲0&
N Rxﶛͭ*C>w 32Q <b6zBHTZ)F)SL0&!Ї1\II$"
`\]ڲfZ1&e6rF+miպaPJwv{X[hœ狓s)9 R)@kNDJo|`S d(e -QٶzF,|Q9.3GRBNs=6&_SQS
y)e/Bhk a f$ rLT2BGX?aCfr"tn!0s$*7k-.3&<" Yk%U5ɹqsA9l @eP`.X.ϟ?oWcuCw}C0llYG(*bv]׵o"4EBPVg1d3"1J(%9bbэC>|R5f(:}}h~u)ySywsPl6?;;].1# EY4SI
ZE[eiR_nWgJ
cZ4|># B"ׯcJQ:)F[k˺w>TX]żnfƖdg\:^Bte9@HU5?,Ő/BʪUUcJ)	aB2aGDF$B!@0
<F z뗔gOOvׯ7vӏc߮nrJ`Uh00T(0G  teBB><LoLnTJ۷͚}nt;k8]צdb8K<3J&[2TTwjB.q4F7u˟lZ^J}q~Qf D>SrHAv \tHǙx!'>]	shrTM<M)R)EfH ]&F%:ط}[7o6k/e}kRGtvv:_,*#3KR`臤࿔bV
)]b>$:"ٙE":b!"8Fbm4n'}r~q1 Rh7ׯ(
\4Zw/ʪ>9955%B*IiB`Hqq8ƔF|^ѥK\oVwqT h23m_}}s6M4um%H)1$+SqM!&`\ufU]Q5KT'(@)"TuU0,R)8 ׎m 0$$FR	Tu}!5eYh8ŘRԡTR
%P*PJhmVF)5h-PL2 .7CGT)8x # HR:Q	mqG4K?#mx姟TQ>4ӈ Ƈ·¡;x»|R~PQu<x߭݃*}rx*9e>G9܏;n&ہvpPK9@-P)tpW_}0K)V@JĐyơ1S
 
)tVNy-K|{d7"FӛM;d#1^^]sB1q  ViMpR"=lahVPfa*T*)rcv%eeYeS%EJ2D)CR/O"h-C2eYQJYʨtNEabcuu}v~EU&0pxyxt9#ջL)f  RR]:RL9BBZc(R,!%DQXUJ!|r8CȈN)Őy)7!r8Ƙ6< ,KJ)L1L!q>~LQu\V~(Zkc1fj	a&"}$g#RHƚR$G!8މE@cQV}J16ƘR>N
kڮ(b~ލcLB1k;8?\Z5#s0*ۻ53@)  fыXʹ~1	!t$ ,1
L}#1St<R*?Ff_V}snѪ,R·mm+Ƙl65J+)-ʪEeJ!a5UUUUUdm_~NOϞ=}""S1e9ϵBH!j%9F)sVﯯaJJIC7M7mۧ˲**ټ,
;xjFFY!"KJ)-MSM)OM)A)itTx,H!ƘbLs!D0g3fO'C6˫͎@G)B@`$c":(  2y?7mBъRv{*bc|	,=1v]۵mq\Eq]A >z$"Yb1->LLI)qs	&0eC
")iF)fЛk ( hCP()^~la_6|.Rq
bqzzjbG3D R*1j'#f·LB p0$!wc
ׯguXkS
br`\U)B(ۇI]USdk׫ۡ+)ʢآ,Eē'O;>(ɏwm:\L)E`}s0]􅐒ϥTaU9ϪDD6d8<	C~yS3@0tmV|>oj(pޔfYMSuCSF똓O4&B
FƍbmBcL2?;ꙄГpZFHoZ{wB
)R@B2lJ{`d:M<Ӭ( ( hR!RongY#pEoN|}p@qv8&!?~wَ;C9v;Cݒ7O?O[a) mM;޿~ߚ`y    IDATJBIYZ_ov֞,w9vvm:31	mYϖgs,1GCBS)ܐD)4[NQ!/d_?}qTU5/18Wu?{>W߿y{g<
)3&3B)T֩2JPJ(ȋTR}
#S8 9hT(̔a5MSLo>?9xGWCOyt  ?YU߿|9l-ʢUa..MuW/*ovv~>k꺪ۍOSB#y$K#D1:h朠YR9IDOBJ!apkcqϚWWEYð@$C8uV(y%RKDHP>1΍}glV
(gϤRZ,B;"IQD(1,A!),LUZTJ);Ds 1J) LQ P -cBʺvpZ?:?+ is.(eʲӟn77ׯcJO//OK7{	ʢhf߶)Ykyk=SV `Z+RB(cʪbnSPV;="ccJ2d	z3[\>y~ciֹԵFb?z{zcߏ>x(@|~~qzJ}^ݭON˓B)(U"VRBֳlZ nvYm;?+ CUQ`&1ʐxDMi~Y/(%?MUXEUu=kkjI1jH9I]42d8R%DCJSB,YcVș8C?Cnշ/ ӏ!6>B:<B(DTHvws{٬m=eu~vӫn]=n{>裫?Y\vׯ_/sk0֕ RHI$"` Ҕy#Kt   b$"ӇB msS++ɲ0^]^۷1Yk./΄Tn|IQU!qȩL(? YpSXFGmo|sx,$쮑sX8҇c|"D̐@)-R
aʲ\~1n=V'WVuq<;=;88?Y*C8ۮ胧AT,y"!n֫zm J!@Jj[آR 1ĉ@+ U]w= V񳏕o˲dķo^՗( Tv'Y?onWu]ۮZ7K.לȣvBvs-ǟ~:sWmʘ,rWlq/n|>Vrt0)%DjJ12M4(C0MU 2E\۶fkfʭ&,*2E'CJ%@B$L1WCp @!(Y!뺮k)Ҫ,˦iчi  JY"xP 1as!)damSRk!zޔuU%ߪZ[-ˢ((4(c-RJeQXm̾y c`$!O# #3(BJ+e/_}?h'X[!s I/|aTpU#;na^/;ۑ1]'|"b+8Y0Nd#Nx7z:椟tw2XJI/?/֫Uetqve2nۇA)%tQg.<;z2;9/0u?t!RY8xǔ %9Qth%>篾Rӓn@~XVJIk"zPJk(BJ!SR)%AfLY>!2fȄ BJ  з{)|Vo;ȘSz̤77·'D콯
9@]UF)駟~{d]W\nQM]|n8nw{)|>_jI
% $DB*[Mi3/42)D:da}1Âe7R"%|?H5BJ>1%Ȍ\gƘ<]x9v^HiR7),AB6yoZ:I)2.1m1FڶJJCk%JF۷"RY{`MyeY*N~&Q FwyubqY8)OU=8K"Q(SV!$|bRk}߫nP.OϬ~mUǮ3"CģQ 㠔JIm"A?vcV`-1[-/LY{.v}{{v߹q̆%`=RZ9WUeU?H))Fm|yrX,fyz<Ϛ(@Y" GܮاOҎCOGB.͗_գUSe60{)Պy3+kLiggEQIU7'ggƘn}0ϬQ3 JQqY)!2F@(!MB˓DW3HDILc:ҷCf6o)QLR }*~ş|Z}on1J)/..]^?{'ϟ3iYݾ{{͛7ooW.xJV*P0Q$$_ `L,
@!r9ƗN(orVmΝrA	dNB #FfI)n)%<x`u?EQeX,>Sk~^9?=J1 @ĔH݉"2Cn
ECD@*LCdH4E	(JNB`Pe]UվmX*dY]_},
{vu>x.@ߵݿzF*-XِfqRY;EYc97}}q2K|MOĔ(D (TNm>8H14֎> E)*K]6	DW_~wuisOwoߜ>Z"r7wKB7v>  )%dVRV|pJDʘG?_y#FrjufSRbJI(֬V!ESʮkaDZI"12tW-!7MH1x熾Zc޾}kxjJ?TM̚YY5h0@R*#<iBLbǤTR #)ƴo۶mQ"H)-2DFK@)<&@4ZJfY)bi BH!VVZcZ[cܨ	Ф~HAcAJ?v_ʪ
''nAs|FD,"|[zh{<!t:>G}pUEQf5Uf;}ly!41=̜|y}F"Y,G~̤B2/~o7~v+ )k{JO~߶mLBiɣ'.NNϛcJs8nVz}>C P"4?!fw+m1la%bZi+EcNN"1ŉ:5!3XUUQ1ơk(!Xk6ݰ_V)bUVMPJ!C*LL)&eyu}YڄpPg?ǣsxDd!6R٬c)ʪ(Kfnk%0,x" ]7wh!$
*cB#
5 b0B S~RJcߦBH.D(ZH!w^|۶9[Z&
*Y>hjr,7d@RSǏax7cҙ7ö(1_PA3`{E#"+%
ɓ'Ϟ7EtcYi1];vw#iONNRmܮmeQ&C#6ʐbݮVZG4hsJJ%E1A9R|0>~ھl9L->JI"+cjV͖B"40jY]f1CYYվ(qj+ʦl\Z#L(bJ)E`~6Murz)F3L	:w7oij[8F!sJUU={-LލiO..|^VcTR?K"/Y(V)J#gm1۶#R!A<nۯ;R꺮wN(5[?RRzv"f椑@!BJ4eY%X.>{|3c~~qn}?έ7d*ꦮӳ]<|v٬qv׵n{ZqR֘0RI2~8pO? NցYLYn)1!^f`,,p2RJZiJ*wB)effbX=?J7٬)q¤)|'ÿ#]R(d'3oD!}2Su?1&{I,=V_cͭiNWl	b My	Bə-2###W~p="g(%
annfnf~|!Z!,뺢>;?WJ'cPB"zNߜl#Q&JrƼpZu6F@B2T0 OHL|C$Y0Q"9ap!,Deyw'S:kMUI5]C{oL׵i"$S)QPzÏ~'\*Mkaٰ)!*NM۴t23$s,z { FFD}e(s.cK ,u4:/z6"`6Hȥ̳|RUY2,b$ipO}+bT\BrC E@ a29BJ!BE5͊"Rc9cjuX(L
֥B0	ćc"㼞zrrr|FiKp(X1F`mׯ__]]2)vo\=}Թ h~_ny$$@x;||*5T﷐
غK ˨Ѫ˨8 ߄;}(vqH?Я#0&>>c'>#zx0#txH9nQ:xຼGj%^<D	@dͯ/W]=L&12U^51~߶T	UVMˋg󳋲RDgRJ*SJ1Fpjq)uR 4Iw><}ӧ|ї_}uss3tm5%2qυʫzZ^xpJfˢ"\ WoHMZ
H1Q>`i d| ͦYP2%J)Ά~зwwֹ>x1yQ0zFwnNO.nʪ*CۮXkJ;(Uyqzvŋ(ƚ¡R[۬޼c1.N΋\F @8Tzu]G߾>˲dRO견!xJSn1J#;7}b~TUY\J{gZk66)sCL#uj)0e1 	ɅHx@p#b.iRd?}ɓ'0}!*U9{m(C-
"ZsӈxhZ@L!+Ϟ]<yb L9gonލR(iw7+.x3$HRjRk!"?y4xBHb\s&`%TTB8 ȋ|9/EVXn;۾ݯF`5qt%8l*lABLU|ZOt6/Ogt24!8ov;7FJ%"`CDdA$cB9g㴮zRUsv<ON˿/_
w;,J?Ӣ,b.ͤ)875޻ޅ cEKFRY;u:@@A|0ð+ēg/y^nښBDۡmZw(A&U\,0H󋛛벪~дzk>G fk$cbBYQN?C 44Mmn߼y_7۾뜳9-1b#C쓉ω )@AF)RJI!1D B(㈐"g!P**2/(ҪgEQ>SJJz:p [QT~{L?%J)2}1<W!>h"bGk\9FH9ŃLiIngtp9,	=U=]`
b0Of%!;?h6{gݘ*!"aC2
1BcFZkc}D,lgY>"3#;h\J$дݠ̪bY̊]\7mDg0ƺO>.Co7;F	lVwͶ=P)e&eTR*)BjG?oSRmbr!8Z.Bpc >y/YqnFp}p>xR?F@Bɟ1Hh}rBþ߮VI^$EB$Bɪ*'U^0d'\P~P83 z$	}J%T  "Ʉ;La`@g1tSTY4ΘRYU風jUBe9e֦$akmڦazp!MD$9N%ABLZ?Rꭽ~_9E^	!k󖑜!C#<AP;6ǦH7=~}HR!"MA9
(u''>!?tc<&^僒ށ@b4ek	`D < =9G0F8Z}A/8va~:1#H+嫗|Eŉ["J>?qfd5&B~u#6xH:x>x<Vw!@S(!R8B
n7{Nl bH Hy>z_g==e </z:[,Be%utP8$zuOEZC)ɋ'n2n)/   ~蚦kqn:ʪ@no(t>"}m;c&87͞*<,W~p'wq{nߖeѶ×nL
}!*T`6CW9{?h3h:oOݾջfniY8^}122CޭkNId=\>}Fkk}xD&# 2+Jޅ$/%f2J "2
-A^^/gc$BT*
s>XܥCLD/\`.ǨfSxV<ϳL眵7Vءb*^|/r/    IDATCTJSR'O&"Zks@~5l:'ĮooVURC )3r:7GbN˓Zo"C׶f7}%Dg1xXV>D)l>SR}6z"*yɲ(z<9+<˲(/z*Ub45f^*/N%JMr	! `ъ  q}J@*./.NNʪVFBgwUpFp^UfU'/<	:8FĪޛdSc,k·$yu4ι 7R!R9`?Ͽˋl^ʇзfyw{{{7y)Y-Ws)l6?/1~H'~2D!Do!nutmsZO~OO0w_|ov-%qxz#	@#` 8hC~B x/d6mC̔@D.`ܾsQD^ӳ'O=}KC*R	(͋""7fR8 H:"~,xFHDB 1,Sp~?b'>> 8DF\JkXq:W*!4Y'!E[Q)a
*̲<%ˣLCXސU3xRd1*mc D0Z,DQFC״M{^MOOO% $bp\\\]X]oon֫U4)310,ɴLI "ˊj20on^?=_
noK>^<:2Ϧ/^8ݼ۷}6@t.x?΁ JY$Lд]@`9mܾTEY!4/J)18zBH)eUUYnw{xM\ir-?\u'Ҥƞe !3Q ?,]8>ll	R}K)eE%T&I$	Cc&i)2f}M&I1'˓rg&{\pO͛7_}ubk뫫'|;r(Fjxo43qMbz`ƃ</	IƘǋ7F{q\/փ)Psxy@m=n`}	tу8llq#(uCHpza8~.L2iߵ>R % @J.R;}7m=S
@BD (C%DsΩ~ٞ,Lt9uk7w{df`IO 8!bBK1'~DɟnޮWwQE9,ON|^`Zg֍I(	R56)>1L'!k	!J"Ww]׶mqADB:qHfI]޹;'f\.v{6qb9y&cnΗ'dc@nfmۆ0>NB6zo^0fsrc[<Qmt&e1*<MsΤ  2~p
)NN3@$m4(1CX"@Q)%71!%x'o@HAKP!oYM&մ\+# @R%),ч!0%k!@ iq, Bhv(拓O>h:i~w#l6uUջ۾.ʸ;yQdqgmu0y.3wo}#.OOwmۯ-&$RwD
?C;tZE*|>_*ͭփ8o}Ύ^=΁Ia4Yw>wN[K	0JUUOz2ɕ,JVeu\yULeYnsslc8trI}1Bݮ3!m;V	2. wyQNgӋo>煉ɇ}O8=pt}z45Z`!h.%эez\:w!xKs'B)UUe?!7f1	E,3X}'·$	)YIwA/=2g}骮tO{ծiIU-l>;#kֻfovoz
#9%rNRRDΙrLQ0FG(=̃>H&U5O,doھ>|e<~vz2k!DWtʅx{u1F.` $y[XH~zv	 Hp2
s!&>  064P{)xi"]
1bH! i8ރ!ıw>VU-Ѐy=>ytCgr:q!ZwfZ,FO 
M! ,@FƄ D#Øxqđ #hG`DDJYrEƹ" Ndiz6Y&Ӯz2ִm4CDnvJKEQl2iYթV%pi}7M18donͻaRcX,//fqz^E~nv[JɌp8cteɔ2@##YkSY&2e5]wswW%@Br)jRuw[SY4g!)mu><J%%0& =R2.n PJR -qqp2|2דl:WE6R0.3yL[i?aB~s{_\{+	F$ b(lh/?EQM	g>!#5wp=?} \PȁIƼ12r !>\}wlާA`I!Zy|[>R*pN)F!y(s<d;7GD(H-@/1]SB)!n_~_W~/8+<uN.Erlڶi~!\G`aњFx4֩B `s8 xJ]hzauflm0PJb$8@{oK J),൉7zGB\|4/e899=89;U=RAF R1BB:y
D@tyNrΫrB1ZcYM2cȔ,ZrΦky-jevz:' #c4US'zXHҾvsf~w6˔sNCsdd߅5Fkζ]#Nbf>$-4EƄ2ECt eYOjF)c4޷鵵;Bp4NS ,BJAbB ½;!4b@ )6xKN)I\1D,UVՓ>c-bF(  1FGݧf}1ң뺼NN?}]bL&B$v֫f
Yy9K k;=!Ƙ,fws3N'eUm6ۮ\H @(~`I?Dߌl.BFK۷ݮyn9 H[C>0y1	xYMft&8/\幐*5Hd>B1Ɛ*mvfߴq0t޽P0Yflw]g</w`
!OΥ޹v˸/Ol6w鋟?֭`L)~Ft7ޗ gںޥ?#3)噔r2,e5I<|$e>noۭ1&pFU=	B	 >9Kt`X01vXyvf)r:ƾؿ(mji_7f'4NP! g~! 8ϔJeb%]m!xDD:J O "t2eUy2)Ezdy~~O~O."_o_1B]oa0zq)Si28}ȳv]ER=1FƴSLedtBHx]Ç^88vGxy8X{xG1'9d:RUuUU'OQQNE5\p:g6mC! #D#$@rG>8JaLMiO~
+f=TFDXD4C_5!$Fzr˯l֌у.T~yp^ð^n6Q**ˊtZՓ*$U#6Fojv]J! bTVTդLWvۍ6SJJc؝! $)&ƺ`B%m ȋ}۶i,.*ɹzݭEYfy^֔?J&4)REYt:5͠4RY!(P{_lCC	!	{T*B"rNDS(eeLI!rA #IS3ιB!8/ˢꪪ&t6N%0dr"ϩV_+u^e!H!w7~yYMǇ4ۿa-vS}?{|r΃ IVP׈<H}ea㮦O>]G#o>&a<PBT(1"!)${$/"#5@H`%JcvNQ7ͿiU&Uɟħ.\p.8$[cݮPe`q
#zo )Lr΁@":k4>8r?`.UņA8e,PBJf`,=I2d5Yy_>{~qd<NgeUIqݾ;Ɔ"I8F5Ƥ4>G&NbBc\s5 d:wm-bD䌆)%7{sqy>M:	e\]>LZm9eyZX!(8!ysM<!p)Wo1EQ^A;眖E1)D}!߷mHq\I>Mb^Q̋mf}b1N)!Da0aHIE00hSPhdYEBĂ"PR F'"]BeEUˬ  ف'qZ |B91km9~˧(D@9_ŹwoG'e^PW_|ԧ
U1TuUj][GD5vHhYVuUov|yzJ]׿딒@} "b YUu-e7]q>:gs{BpF~Xk)>csί4s$4(-|JJŹH3,y]U&#cwwmL0m^DB3ԅ4!@JPݷ߾Bde,,ʊ}XPJ9ΔfRd-?ʬ47C]X"!fZmֻn,IY>v[c)P M>R!q^d1&Y@^_/.k{[ćUUY=TEun׫z{{n6YM'ӻ7/\/]+<wuUeYzn}7ԃqZkL?mOKF bާj!&lXgR<{>T*[m_|7W~(!0şW䗿gSYVR&w0n/o_~[N'ݮoj&$a8犪*)(!~1,>!w1`EcH= Tt5>XGBҏ,G!&J<!dmpzrB#N꺪'O,'.tAh*H:0FY7Mt:bH <xP@mW|C4D8'}%1jm"OZ1.拥6f/uso6ׯahr!̲˧iUO\aDxV@9.ܾΙa:#͛o__cR Sϋ!,/.KF껶ieYBPetBl3\r.3sA CL~Z#@䙒LfmvTyͤ*x{'Uu=N~tzw
)xJ('1I#r1(8=&ݣD.(:Ʌ,+ꢪB2!c(R*RR`\()<+.b^{wh0a#p> 04|_H,D*o%;ɏ/= kc4KL,JɱzO|/b|G%!{xH8𨷻"o cn|h>7)$Q tP  ZJG^Z }pAHW% JiRJB{/mUDcB %Iw	.oznv<L!|LSc0c	z Ҽ 9ojm	yo!kV	)څpZe^Aʲ$ SBd3*ӟbYc=}Vy^yQ2.C]c 1g38 EOƟ'!M(	,3Byk]cFsuv#lZ{﹘zu"dOSJ	)ylqeh%,)%M{ݷh1[W(eolV+86_~GEQ0)~v%(B;'WY&$ƈm_&K%c1~ДR(
uîj/.ڶ1J|yltF]7~u&!OuG3Zgj"1( U>J))8đtL>r%"zXN8(A 9ɣ7"MӶ]g8&XVĈ{Yx䣏>M^*ßzɹ_}W_~"e!2JfY^L^ñ!@)ʌumT*vZey.N'޻k' dse(tmLd2/zc>xo7xךaR*lJ
&C!d*"s@	EVd6OEUʋ,ˁsj3Lw}IA0DU0.N1ջÏ9\}Z?:ʲ,,*1CR?R`N7]!(rJ`vsڮ뺾kncO=zv=1FFY& @8cY&Oӓ|9Uugd2ͪI^ϸ*<$ 	fggXz1!</ʲ(L\"e]'ӏ?}Q]ӵIE56ϳ4. @_ITӟ3.qA)B#aD 6fm]ZWM4on/;|jPJON%sܭ!&ϤOOӟ?{>˪2
?    IDATazJBq_<# G A	,	!̅8YwsV0j1F;g!Hh@cMaa(P@?=ZL:X+:.GT8ྲྀɓgJeL(kM{ʨl2Nfby,{FYO|7~7~״-@LNI""D^i$tW<:!| Ц1N9;n|YYݬVQٶl̲c2+r2gWo7k rX_yN(Myrj{ou0}1:x΁~'byzzqv}/>^)UYO,+BLkmo1Ʈ̦3!`2㙓iiv^g+%U6Mٖe-3	V#hD@Bs,'uap9TA% B-%޹I 8I(J8@GH$ ! 8%RpԼ&UYY2%Ry)T΄LpJA2H\J)RBBpYVyYdYQH!YeQsu=Lιm5]kjn#9g\ =<e F(!۫tv\6D$/h&/#owxwD?ʑo9%Hu{ >hQS
aDޣd)	=
3{ضŇx<
T<:k: 4PJ؁=3=jiJ19aX%<1z(4z7~˯o?b41N	#)6(b,猆}AjT0(H0v)	B@Rv!b@"QJc (e$<`#2R#!0xX˓J(#f
)ed4}O>&,Kq 5C%w;d1."2#HoH!4~GӊbґhA |]Yg]Yà[yM&٧a @?Lw@ nno;cY?+jv]c(\lyvI~!9O(>tmTٻ- ч2As!hx	aB(^eb`bF@\l:1j5hkLYc}ֳTHe\r"Ek]rLF\(Ÿ	$#*R,rΘu{810l#9~rｵfoNps(:G)g|otvzvZYu_|j}7*^RʲL1|u!xJ	9睃á<ư]-KIUnn,ONUU=XZK%ڊs8#bQˋˋxgƅ`([Hyb΅@TJfY-<gb>ՓiQy+q "{(gG}w}(Dƨn ?Yn{ݫz>]8X#,I]))e<5h<%`Nemin6M׵f7M06?۶m`M:$RR+1.8/|6.d6ʺ(d2R F}.AKO¸PYUeQE)c;SRJ>X3(H)LIRRQfpxO5p($GoA^kc̶醾sOq̐@`FYW5nYVmOON/<yvy'|޾};vmwCn<D_y3,Kdr<˟FOl׶c\o6>Dg& 1qKĘt#G.0o߷cH0cj9>N4y4	1t6c>Obzp9:k&ϋׯ=X,)H	Შ,˪Bc !:c>'p>';18#FO1wt:UJ5M(HΘ޻i3is^ԪEe={n׵(ʼHrIf\)hvz6`OƄ itzv~ًdzrrX,H7o޼iV(r)5s>|X"mz^ݾ:}6,eJJH(/val*˲2Rt]ʋ\B2trSγL10aIĈ	oJ(ciJ?	B(%Ar1I=	9p)g*ϳ(UQE繒RHŅ\B PJ# 1$kVEYeQ(%8k- jxN/κ9q:gVkg5LHJc"&ބ~;ӥBs59LGNvF#$t?zI;?=n9@OrZQڇ~6vFg<q+ȃӚ~6=^oY~(, 9W.KdH(WAL:2Ka86Q.D(}//~P
s}H1J΄B*iv7h#r:]t(Z) 0G( ֺ}H6/6P#!A3!
1
r^?%_cӖ{Er=	HAHpK73왶זJw\C{pH,4u1}?!@!F]rN,`d\EaJ12RXɤ;k	O&,u.D N0à<Y MN}0.$#><-Vbn<)c"! ّ^HH ð^|>ϤQy^ea[=yrQeYXcL5!YQ>>ci@wZ\ﶛ5 } }UuQ!mrd^GԌz(Egr)Z1hkKb[ץ1Xgѫ|&c:q.x Ң(x]!>ժھV]i~@Lƚ䵗xG! >W@ ACBȼ@Ɯ3xhON^0(g1gY\(syeYy clRZ>nv\NS e	!2oMYUHM${RvOj2φAY6MYQGu]ڦF|./˂yzzٓ#Y;}{Ze6hz .DkQ)M%Jq'zR/O'eYrƥ2=<!Bെ)2+B $l^^7e9[e.Rs_\UQl$Cĺ'i :48;#HSLA HN}]7wNv]?i7wU04>	"YU|6;>^Ni]Ve!󲬧U=gGqDafqi"x@b(("Bp@N9g5eSH!B^km#C@	 ںZpn'"CdBY>AJAъ#Ʉ$iip1qmj?lN'O~O=cyZ///onnWvyG\H)Eӎ͚,3ֹx_RD[y4||%_op $xHSx¾I:zÜ8:1)/DA(guIIBX @(Aa'i@d~D)\$97Țk9|C:>8G{xsN'>T{F$ t[s|6|ɧںWe(*1P.r2>%Ou:Qy
@% a7ޚzɧǱ,degϟ:e0^_}zaO&u&ei"_,NΗˣ<~M7vaPmEqJ)0zttWhwMÅB!дiʲQUn
)2@&ZDyw^i9(9طFｉD<.<ʑOq&D"˲EUUUUygY'5@, TBcN"2"e1*eU]eYH)	!ҡq?@W{R6fVz0hG;CKCqt8 "ϟOsJQpx!ރZ+*US RO''{0_	ćxpo;=8$t1Jy?ۇ{yD۽Q JNDr|CHTÃhCdR6Mw3yYY1$F'1pyeEf{}*_?d(2&EC9Ss8$_ΙdV1!X=9g @vFO)΅,$1Etb H9;ÐkHßΨ`cJDʸ,cD`=q.BN&F~P/)"//>jjz%d>_^mS?)rkV}rf2w݋WHCuC?p/.Νƨ3¥Y΄/Šm2 2eU uq	&]l6+,/YL[o\~ѳ<jZjLdM;ƹbRLtgUc"RdBH}m:G)s9@
|VyB )>D G@j$_h>H8чv@LO/P3J)eUe.)\Qfb>	)m~x	/nWevsZu  (HAw˲ybw[B@Ȍgy^z9'vVg뻲d2_}'鴞(bv㬵Zk5Fmq>:K cI]{t1!C%yYimH]Q.&ɯхRJBH|$J_6ݯެnCFWtF7n߭WGGn^bogg'G՛Yΐ/ft4GGtтi]QA)G? o!ϲmﺶm]}]^^Ɣe٧z7eu@  y~<2TfyϖGb9eY,fRN&㣓ryAbƦi"vj%J(-l9-ONɤ(\HC36HQFۖ6ƅ
zF5߿_~(uH "#@a>zknoog|tz^ <˲*(JΧe1Ο>Kc(ɩ	t٬/~ۯu61z΅*I]@1p}}n|>zvttZo!~yO<FIɐTeje	Gｋ"p0bz S?Eُ>~W_	$)6FmuOb2;R$OFrf6.L&S&hЁxgy^Rƽ($R(1	& Eĝ >=>>~{u}UUm?xcTߵ@ӏ?R:hDcCRUe t99?& ?ODuaHH \LgO>rQVUQm۾~oI)'u]aP&zGdY9NOΧeYO</-yg+oZkl4(
3d<B^ðYKþZ5f3q@(EB5H,EX۫5:8 <FRCp1+<	(xEU(򢨊ɤr)x)rBH. SQJ 8+J1J(	J(Ud>M4 !!zB	@cnد]f?H(@rk[   Yv_={VBH|Ec>a{(RݡhݸC!7i8Vwӓ!a|g;hcc  GX<b;,j<|.xJwW?*	|x1_<ƴ$e$2)X_oYn8!c9 @!)d5v<>yr|b,Q8~?06})-xsZp=g	*
1_rH  7\c>@G/e1$VEJX!&~"{|"$D#.-\#Ύ1\!) qEJcjZYg`7_|-WJ;,|\@)=99mZfD4B)]޼yIlRl2Eqs ̅Bʬ Z)#
 sw۝&啥Hi+cc<{gQj	ktJ<}rۮ2y}uM9=9q>ÈGѲ/Ɣ
amLQ7&2JCy % F@}!)|$@EJ""w>·̬DBi=
#J)cb\.O/WחWlQfYpŷ_a[~fQ<g''!FX=C웾bgYg0x cAi o;d& Rp+w~$rF1ϳϟ='uU2}SJaP2	ƅh3΅0lHC8y|'w"Dε]<p.<%PAse | -Rc8߬~o_elx3!<υBA}̥tu}nwM?h|_~9 gge1Lf㓬(bi )P}0M3j6v^ol:}<rucc`DJp!	!ʢ8^L,+ʢ(by4fYUOd^k1o[z?\|'z2!%!U.OnW0J'e6L'IZpFc!uWCp6:熡{}M$XK1\\$Gyx<;˗7ǋ믿| x1+l1Ly%E!cĝB/￻[zo$$l\̋<co6~!,8 *Ӫ~G*\ IɻBM>@;й?c1Ӥ҄Cqx?Rl7q͚sdizNcT'V֤V)A:Ƶ5M6ڸ&qDãN[B.$0|$btIȥuYPJa/GhFv͐<s *i,CBBAkCp)c,/|ys"Wodhc$AJ D|ytrv~~qqzrZW5cT׫j,j29@Pd:=?;yY<RB\ēd\6# y2( }۴0ymWeLN
RA    IDATͨBD&bqj&M!Pq
%PRH9gEQLz2uUR
)E.9BRBiPi3)2'  #H%<"/(L4!DDH(H0-B;;I|O㬅<H w?s.kI'iGs>GͦYQQ">+i_{H}sFQ# zzP#x  ɸCPeh:y>8YwчA*9==K!HpNf/~/B"RBwݾ;(Ϟ}l:)K99#aΥp*seyoXXyhBǆ"Z묵&ѻmrRw2<C<P~Ќ@VΚSE&e^V4"",;~E80!"##t==" $0ƦϢ)[׏q?}7mznl]9MymBp!xXy8Moo]ø @Q,z2e4ZyQQ̋<xo}yU@3f>Bd3<Ad|3#ZYc:.2|TJ\"/r!
Bʲ,9穨H	p(cFڶM4cg'㼶ZGJ)(/8A#Bc	&5g2Nk$Rs!ƾk\`}cLlby~q>ϝu]gR</r)gQ.GY,GGJ9)aFif)"/I])m"B{DJ'%66q풿iBJRm )es]6=E̦cY]VH E\82Lpew0v1p c"AB 4gCc ct]su.}bJEB7~^|l6-@RVd:Fk5 I lQC~@y^ECΫs>,lἏ! @*=)}wnۭv=X,f)"lJKlOg.4Ae]u=9^Ny=崪ʲEmv׷nY?웝K+!}3֦	 Z,h0]>iW޾~lbϞ=zW]MGUYVygO%4=k`>͜HbDDX]UGEmW/aXSEtlZWueEp9C\߭uF+mbZ4ӳnPo޼}r1N&A}g*>pkPb`I!e}Յ>"H[ 2￻,{azР;.PߌP >$1ַUsRDkSAʄ`B&~Q04M۬Rιx]bxLLZl2D1PCz?;ݬa  e,xVeyYUY'1rAHw8"  D.0x";w_m9wt]Ie>bqz~8:&S$%nm6(몞LʢJwJi'ˣ(K\fARJ"% DviCP\朠"8uvJ\fEQכMP"KBEI|)BI<+묬l/yO)Bp%Xd:dVeg'H/H@ A8ɣKH\gEQeUy3#\osX*x㭶o;Ω1tO 1oH|$yﾍ1jcˣ'O11AXu-?ߺ{ǥi4!?ˎz9~.cpG?
cHnI=*A=r8CT8ɉ~//<954.Z)d2cv<rxӳ?==;?견<26vq?	m;b!X9#o9ktb4QABi1H| MqA
P"޻umˣ,+ "rJcO|ctph	GZHeV0fm$S[橙Kȡ Punybƹp:Fh~?|-	)<?::Riu{},pBJcdEjEF(ާc\pQzb
Jb|ֶ rθV1. (ovy)>ٓB]xX
XM{{}ݶ-D(r`Z5)-ȳ!6;@LݟdzK~L1H"gcJ1<y/on6[cBkUUuUWm뻞 Eq|z'_R~Z]ZJ+
z|rrtq)7oәeYvMBu8oMQt9mnhfm[Q,橸-;(]1~t|<Nw땱6hN	Z5)EZ+8ˤL@<""i|84w AFY& 5JtAP0:6ZEEL4h	U?׿ۿneYA\/GO>=l[J!YR\o7A,_BBRq>$Td2L'j$kYѺkwjuo,R)u}s^ΦXkC)(3ѬL&e=)<<EU5DHUzY~V?)g}~իۛaPն>#EyUV`Wö7Zw/^|.߾v{!dU˟~IH_|U֓j2ǋt:IQg@ >Dg7g''e&vOJ<?9={e^`X̫Y`?{|rq񤬧x(yQ|oҼ(: .-QgjY''?+aP׿͟9gRi8&E=z1t]׶"!zLD8`zEr,J"Β{A^*}D1UDl4 l\yPƸR
! JauwnR$H>8a0q%G$cӓh,d\k>Xյ!RUE,c2c1F$FB0 KA "ʐ7ϟ\γ,_^=dROl;]mwvRRU9ʪ(cmu9(+hX2Y.4@$B
EviݤH,\&>zv`lpn0!yEƙ̋c1 .jvͮٶS>$q)#aE /ȳ19Bpx\.yQT`D$N"2(#r
YR.DPBRB)%$]֤ɋ(IUUFACھknΚ!Hn $}@.W}?p2Aѻ`m#+})adi-}cw0QAxx ;q}.Ff}tvFz  cH}; BAUAw(`ėl$pKCCZWͯR{tyCD|)N!Vw}3r<񳏗'gdVuYVE	(B|.I;PC1F= 	LDD$x<":p>xVz;յnCK	XAVHc8	R8$0hUJ[):7w7棏~BG 0FS`RP81XC'3f:$HFxUza6$bص܇I]G ƘDICHH&'C8YEEڮmbΨu5Ys\2k`4b HcLH&2
B9p!ʪC]۪zHT4''7fC&ewJpD\ȳ"J7WӺ*]	 3fhSDJY:aX)snVWBZP
k;c;cP !H)Gs!.hm;81B>sB?WoRt꽿[om8N/oo/Bi}zz\fDJ{5P$ż`œ'gg~KkmQVJ)Jʢ,VjP9D4d:9Hz}wb\ ,ދ37àՃR0aB(1z@DV!(JRo'H21hvB9mt)2/r!!EYY8n/"JzѢȬ4/ݾ/9 h\18ZkO0h\="2Ƅf(rKa`]vn}uZtztt|7ml0(u6I$-\"e2"}vjv4Y_/,o^a!/o߾z:/?r>B8cY3JR2NwVfA[nWo/^][ "sJ	!Y!0PJ<E۩v{DTPBdY.dQSD'XFEVygy^=(QmͮVۛ7zYgz˗/^\\)mB02Qj6|\lr`駌u`]>}vv~]^_-Rfu1RWoީUbG@ DABRHP	!D!?n>B>xD
 9$"6$h?;;EEYe)(B2]y </J&^톶i~E(9O5j1!N=c2yD]UV\KIUQZ琉VVCicbHȇhhO`{&s501M/Ξ</
F۷]!R$")cR3ƥ5FV:@j~tROY^$BĀ1xHl EQ}Ӵ	S}&RgO߾zd_Τ!Y64;=,A"2>>lzlmj5$cW)W|8>+'"/GcTdJ#0JRR'SE#ReQՓ*
1kz547o>D;$H8{xq?<QFCQ0(",BeQ CH\ǙBp񡲁C_Xє~psKb}w=G;Vl;84>N Cq[1K!)	34v;n3t;9*ϑn-Iҷͫ/^V=!yC	aR
B]ow0D&O.Ο,O'ɤ,̥RL,1S $s:H)uɉ	'#)|9mLv]mlVgeGX\!ɏD¸L6OZ.T;5~>uMƘj,u6F[=X5(5,qԋDׇׅ(S&H9tw'.#	"myQ$} 0.gZO1$zd'1ZC
.(b31,1x6H)`ie/$2`Ee6Z5 @ ѱ;BA[{x^UZb,Z*IݚiR
 wO 1֘('M't+'5e)LY k]<5 ]@(1ȼɧ}.l6m{Iǣrlx۾@5ZY&gctR?}t:5mlֺt.Xmu"0't2Φ-hkۮ,bIF	Y:3;{#1 $8XcT2Oνi!HĤ@I@h0vs!i)-LƨrBl6m)ktu)9'HrBmyCJcuz̒c,"&OH t< RJD,F0Z?B@pNkiv~h>Φ㓓Rfݴmk6zZ!J!SYbN
NW6ƨ55],>}\,e^T$zz{MC'VSS囫ׯ__|>ϟ=Fv6z0jf}Zm6vu{Y^kc|)1	<Ϥa, @Z[s݈hcm"4"!	 gBEQVUUEQH),+kFr1/PJumm6f}TWEQUYvmsyuEYl{5n'LybQ0A{d2iK!rAG-+eARƸȳ!)UUs)a!ԣ8!CM0çq,8gh}o=B T+C1EfIto^	$6WbH= PdE1xoQ{UqFS/d(GL/D#fB$S@Qin}QVңtvrzOvJjX,'u]UU^R1@4*ynns^aJgX뚡kRB`H(M'Yk!eX˼(eKczie\<wFgCYUQ3ЮQB|J7hoH<jJ)bUh׷o.oooVͦAfKȉˈ	D`?$2dr.y^ӪBzh(T eY151ʄ๔UYuE&{(kRJFɀh`Φ,K!`r;*t!yh$4F8qBDHut'O*F$ 471
  GYZ<ؙ2y0ǚw@cCd]ro_PJOKpᰓJx5=TWP:^x9D}aB5YXon^|wwF|4R1u)1֛fWӳOɤ*"</Lrᵃj<~hiic!{
0v~߬7ܵM][=L.lbށsH][!D烏  :SbL)B}G)n[9e,F`)mu[T3z0J0#|aHɀwɣxw4$ashuww,$u <τ1Gb]08gR0(	@4zNHI^)e1J)K!I8B_lC@ʋ ޥ&7c\G*DQJq!S]evYjB@B9ƑR8'2MxSZk4B
}ߕE|a\fMwgyYcRaDiBDdQZk,?9;;=;{TZ    IDATvP*yJ˲<;rrry6~xF+M 2)Q0 REUO,vTR9:>H!@Ħ9>5ac)Sgd:]߭ۿN+}3(I!8O-8C
"b\I$h #D09LwFvPJ )KNuWo^zHpH ı}! B@Vy[k6Z$!Yz">{&$][U;12 d:	X)
C^ݮvm۵{c,Fy~vv:Nswwf40BZ)qXYE.ICC@)⣟|?=Zj_|ͫzr^)ms)&|67Mmڼ◿ص-J5yQ'fY6Mb.Zh7חMW}5۫]4FFA\JI{(`1i G3ﺦ=s.xcdEQ$2^,(z2Mt:7iٷ;ik+"\]]4M㜏?so$u	.GRY E$b[y1>#k$J Zsgss#3(%c0XVdDݿVBJ烐2{tvruU噙N'Wv>#51I!,Tdf I*mLMghj-!Mˉ.ھo  J)$ ]";ѝu@dDD!	= t"&]ˀ`js=0;sJ<n:3gw)Y6P    wipHЌw4Kԉot:f֍!$9(Vд-PLVZoU]Oǣj5?:N&e	})!<{777E^GGGˣ|L)%|n[wj"JșJʦ/.<2T*eJ!HR+%"qc̲l>rmtEJ10 e(SE9UMc;5VMQYUuKը(GfcL*%T]^^w/^^o6u],( [etxtnK%d:5yfx8Q@}}J<t2'JE1mloiB􀠇 uطD!|`6("AY"/?=9Z	1jL@  H0mUw)t1DbuGůW%~[ηqj}E;owN!ǂp{.;Co;C6'02$|{afRJj}wojv3J1ބEQ]޼[=~ώ.Vyr5Ya{יSD<Q{gM'j"!$ X'"`<\Mzw;ʏ'd:0cc E
|0u}/:fr5vSֆDmluX
dRSH1 P9ktyD߈9	d;{czC*v_m9#EN4)"b=GOڪ·L+|hI R:R"3~&˲bL0Ek  tiBF	MSCzc 1\zٷͣOVrvE9Z,Wu]_]]	5L߀JuR,7Dz=LD4LiQځl!ƺso//gYy뜏$:+GrYd:]Vk["&Ŝb Dmbu'?2u/oVh4ƇvE#qLhB vYo?~{/~fSm>I)3~\0"{$3jzYkmv]'T/bD{'q!

 :/=}~{fQi>ˣS4yvo>˿\fY()x_5͸eWoz'u]u!`,Q.)d9Vn(	8x!*R
TQ!\8$Y꫷oFxXma4-VG''']׭7F<6yf<JJ
QJHYL_G?dXZg3%g_Go''hWz8OU~rvqyy_|\<:~nScV~_6nnū/mv!r<gFT`ℛH-ϳt:͌11X9&.1OCDQHi1llXƥz_n}y,d<|/gr:?{4L{F!~Oͳl<yNhNgtTL&z:.segZ:Ϟ	D)ePZg(c(5JX.ŋl4ARY0# P`⽍!( DkaS),#J 0><u$bA!0Co^ N.6f4*.$\`L7e"!.;|w$"!E|a*MhiTs =13H)cO;=}Tv_^7n~\>z|qV뛛ݾ<yt~zlZFj\kB>>?WJ6U\#r"$J+'@  Q)uzrzrh6"W)!CpTeY򬓲}'M y9Bdjn61	o/fEX.w]Q`^]^m{buRFO?o7_w,QҠO~wmӶ!čB  rL.bQNF ;nkʷ;o
DPR3qM"Q$ 1F J0C;=^}ӟ I*'@Lb ;' 0`uBHa$sfRz 3D/9]Ǿ_RxW)AF2I9cޝ]ğ0r}5}۾ .9MÍAJcHF훫76ϊ}_|I,DRF+sw=:>[=y6_ƓYQdey.{玘	"wC :%]"Q:76ͶnmYe]ۮ&"
O&BJ"`E)JIY`!dJx9/	]-b]om#!>]O(tBQcD(fihBcL^RJ&7uSWQdv!J⁁-dZ 	!ζ])dNBJf~)1&3	y{"o)z#J%:S&3&SJ!rvYwHg:hmȊL
]ynQQMYѶfRM,L19;?7mwmhRSQmN/*XR	e"#%%1Kd̦# >;?O!Ʀ'ee9 N&l)@%o,,{7/GGGE'Y[$,h<.}B9fFd2/Vz,S I e!ίFl䙘b!4ծZ"ZPB$FČMDL
d{RLS?''g}?龮57޼heLFhubX&PQ~O֗!Y @BM?>}tvLT,s Jڦ	g#Z^q`"s: 	wB\_zv_!Ub\.ѻjv]v]g{O51*JOGA J"rT?'??ruqo߼7ןyV3%fW۝*'d^yo7M[?<::!xWחuUۮooo}v>QQ MVJsR*ѣѨ(KŪaAx<]* "bҀMR)zټJ\gEQx<L&t:Oƣ~?|By
!HdKQg|yuL&爈?}'O֧K)%lz}{H[BdHx\eBܼR6ʾwN
J;;Sd)DJ\aHA
F*AdA؄YW5,gӮi{-6Zk%% &CqhZ<D7{j=jmɌaZH'|zbx4z՗_ˣeF~oJ͛7o~kLQ,s mRRYQ8z7T_$dxC`j2dZ BgJ+TO=Bz'Q))CTJͦ<KBY@ZчyH*%Zwm1HZ 
R}x:/?f{#)x	tWb  "`VHٮi۝NY`L8jxA_=%"8EH0 ֺǏ󼴞(D4tZ%ę#HP
אָvTZ,ˌb%
(#Cel|0@Zb;B~ϋ;v=*ݒ0|S{w!}]a{!ETzmw)MFOcunWMh8^?Y]<Vy^ddZ+2VI#scXȾYDbb!ACUޮoJb#?	pD,SJ)8Н}j@)EY]uuufy&	I JP'K@Rƈ 0GǄSvR(,˥ !t-GDF!CQ`&}x̻}UŨ%UmoLfLJ)JI&QYn< B%Ο ))eImV{͇I2Q6,ψ((RJEC2!@J+Thc˕Z}]!R:뚦V c]u]\S[HbpH B	,K&FrU۵}߱"JGHiB"3zٳ|YrgyFֺ́<ϘzOK
1&/
g]4PbNT:`PU4Yk5Dgu(Y&HD)w}Gx#QL3H]lw8DpJI d>Z=yÏG9vyz:yeȋ|b
|׿Wo_!H$ Y Ed AɣQt:Y߮.3:˴QFCLM׏'x˶2cUeZ|lE믮6ۭ{B1"(l6Z~Uwmc"!RkeVJq" &
1ON?ه#b6MFgmn1[6onۺd<]<z<_,7RrT~XK_Ջۺ]i<*gZ%t1)wۙYH0wh22y&9M)	{(Z8TIbH~"^	dy^e1Ѩ,Ge6~_R{Ja:򚙫v>eYEBK)Fi~:xl \ݴ9gTZ+gbL[	ZwAF 	BdUv1d2~g78XMxBgC|:l<=)i%hvY!QYH),4(|QdD!Ԡ1㩖e&w)}/&şCK7i bf֚ lڣ|fۿ7j2.˺}8ҩ#y~2wvOb5t> Qq
V <2@l4ic 1&KՁ&
7%,bdOb)!iN{,q#Fr>4} iuJL1.8~P % PJ3E[yT~?"<8x<σ!F
#%ׅ6QRA7]IpIwrߧJ:7͘1UD̬z3@d	X(0A}.A`1w  )X+aL RI-B
LȌ-%vR=82~[Ðr?~8_e 7w~Cz{K-򡺙p|{Y󅇡(H Tye&/'n,K)"9~n;Ξ>_>:-BVJ+-ӎ\4 o1'W DDv ;j{ﺺz[׻ۛz骽n Q+t}ɺM	d
DJ))H!YU)ū7G'Ib<nm.xPJ`)!!Ĩc.P2`fRt1FB"(BC  f!;ӥ	@_[(0Fy.Ri)}r2k]N*EDJ [u8yA42\_]V=C@!2*rtDSQIJ+!`n12sRYZ۵6Ͳ|<Xk9ˢp-Qo@,sP2sjUm66?DdmmdF7Mnh̉ J|}} %Rj<+CgBi"r9,,Pm_\:k_x<N!ComJF"Rbpit}O2:xsbB G2C"&/DsD!)eQEQ&]$u-j`yN2<KV!x?pu-SH0nfR*R(ly|rdyrZ*/l6˦s~yhfBRWo~z񙠨Hu9m`mn{|÷_vMAB`ۮWzN&'7MtHB,
 7s$$ĨLQn7~ߴm1D R*c2Tܲ#D6(?op:VRZmwM[-8LE~}}˫7]
ǧ'=znh<^_umc/z/\o{uUU9xrrR
ʍjm着}6pcyb)8%%OZфTR142X !R-+ϥT2Jv-,;;hꪮk=	SBvϯa,Ϸ۝R'G{tUfvvڶ!H,KCv2p
wQYgm;V    IDATGD`DQYN
\iumSi..M+oێ!(i0WĴ@.H kB$NJe>A)!7
wwv, Zߠɼ<$*1B:g-Ƙ?ڮNQ6*/Շ}(^ySWZ+]fYTmSUվBJ$5z1Q!bZr(I9`E  \,S޻nYK>@pgJ,//&̨(fP"@)S1ۮ9b1H6&+ʲ=:===Bdd&(}ׯGGeS1Hukvj6FO'j78BHf !@=t̻UV"1"JL4#ՓgOE!#'$D,Y +Ad&( Jed` Fy1,Q(R*ZBou(:ZKaGr@W=_Wn߳޵0|##>|߃L!JJ)Ru~_!  )entf֦W׷VM',12wuGL_x&8(bLE-D00cg>x]u]vU6UUUm㭍C$(AUM)fJ2J@p :*|B#ԽQm]׶Y-˺:anzvև`)ifG(z0ML6P1  1HL>a12@ʌ};]xRe"$!6Yk6f6gv~c֊ !ZD'p>66Re#AwVc*p`)J%2	RJ
]w4JRi-%j	,6u}wrYUU׶EyVeKLeY&Ir4.23 NOOGrVJ	pzsq~EgRA??>-Gc`0	.=1@,ˋ2y3VRg(DV*<0g)u۶!"ϚO^\\equ4(ԦH1r1vϋB*$D~Bp1xF}kx:]mӰBkm9UZOr4
KLC ("w	r#D2Yz煌y2-y" Fb$g#"m)={vvzg%I`\DȶK2 lٯ/>WR1FLI@*3+PDd#UM/TSɣfsz<,!n#PWUմW77o^;8O}"@FfB1!8xL&O_(oviOiJ
CxJχE1>z䓟\<y6_VDfi2lɍBr2[ΏN2Ϯ	lۦ__]_/B*|ݯk)l:yrI,kcH2-,U{m߼\ۛr<f@6!8D:&RP  zdH=\3gβT`cA1pwNR)Rk=*$dչ@1OLw"}z8lwF2?'mwolw;4A PaȀ1V~˲,.$#9λۮ>{aߥp	8+BJ5 lL@̶T
N m-O o`CP)cLϖJWuܮ﻾(ly<],r~r8ZfL~o1н?/k>xbpG`17g &2L4b:wmCmַ?|Lk_Zm޻D1}7mByhՋ}5[,|<k}vƘLՈigSBA.+0QdbP@!y62it"&ܠTzc$Ov]߷Mc;1Fj<[NdyYQ9eBy
GTJi՝`4RM"Q 1sCG1S$]lwRrimG2I zK󳳲,z۬nnmQL'F+d>cpJވ98"" PR0CHbNIf> H>h?tnig ,(yB5QԔr  i2 .8;f{k)x/ϟ~Gǝ=<d bğ
Ưx=P O~+^G;TQQHIJ][l2Ŵ D! x4Z.ԶM][d:>;ytuz>/tҴ:+$a4xL+E"C"R"D$HA E}gu޵MUM]5M]wutM{~1@Nއiƨ̘XJF@c9!# (n1Z)坻JE{7M)FV[2TU	d:!s%b/@!ׇ>Å?+`H]*1p|7O>$&T
!"2x deyf\ھw/6J΅2JCӑoQpmm+r<3|QPDZKDmt=G]یFs {M^ڶ뻾(rS"Zk8*: v_$gT&OӅR":Oտx'\Ġʳok}$B2 R>`YGG$c۶:gOŨ~-Fk oJCq.H)&~`B@P Qlm[8/2ca\f41R8&)xh]p}
	|g BDJc!<|?BKBeL9'˓Ǐ'ibL:SZJfP՗_}϶	Ĝ<AÆTA BhZBD"F[ mj<Y~2͗˶ڶ牞E 
pDx2yi|>ʺiB%XZʊl6].WGNN/..f2ea檮+}a ڮ/.߮׷YѬh6L&*+Vl[gZI#~4/wdT(]U~s%(-bAgJB*)JJ@B
Yf4|(q]Vd )0Df2JJgҚbJP,,X	9=~Z#I&")j:i)8+VuݴŠ@yf" BQ\)d7fM[IJҢ $9@<1mF̑X bw= Gb>5Zsbӝ׽A2IND!a8xӣh2e1uYYV(%!cS&(ExEn:ŉ-8xJ@)w}?*[w) ˷!Oo*yg	n7ۛkGx2(ں$eeDԶml6/KfBdlQh $(DzOM+@Ri(c"	#?s#)B(%2skZiA[|(p((!-A` d I*BZ	!9~fy|v/?|['lR|/6뛗/뚾mmqR#wޟ%j.oO)I@g?x~~q!% PL[8}㡛	gu*	R(1e@.\}۷M6];HkC0>ǿmݟG'g3C+wqד_c= |X7jmhpK_ox}OA3HM_%2]ۦnA7"HZ.,Wn|v<?{rru4LR,?$Frg K$ӕ zxQ=!`wrw]}Mwnkk])AdbF@.iV(	]okǙRR	BtdI0W`.QYEQΗ"3C{\~P*c`R{0jËb@!A A-:=|z
<fYUJ+Zj-V:
!Oڶ7^%),ˤ6Rdd#yQH}R1MӻdPWJ(-ZKA("x	D8
1sk릮Oߴu]2F%e:6Bx:t:uܮ,˦C}/scߵ]ߗSE ˓Xk!v+,Ss^ǧ>ᏼ,2yMR&WjuSHcDLTUmbޅ12# K"ZQ\w]œֺvӵt2NiyfRz2N&}a'%u t
Ne4t"nE8gY_H0"gY6ski`ؾq"Nn1w)֣|9=B.
DR(㣓I>4,p0 unD`o~}?M1J!sL1!eJ@ !*[$RFJ)nA(%A|Q7M6]ӌӓ].KcL۶I& ژr4l6fEzl>0T2re_JE9NgGgǏ.iuu}􀷛|fF]wׯ^m(ǓYQN.hˑB ! 8L& "MGI
Bf횺wJkDZk:	A47:"'eyZWA/ %""
L
ɖ81JzD4sNACHV?RgYsQCKlL#gWװl&뺮)Fy&7,Sh1)z `4U0C!e(eတe?es9 )sM(J01<_g,}$$$1x%"dNʻژl6LʢXO?}rvzu92F1޻P炳_}QRz{Lz:A-M'!u.ıɔR1bCHf(bIK̈ht1*Od|kꮩۦYTZ,ι<(k1ڀw늲$Ҡb);!J1@>@P5Ąv&NI!YRk9X*13'ў!5H1UEJL(F
T	!
	X"&RH4 RJi<S"2Ï")&π(5">?_^6_~
(qCF?UR܃S̙ i"]l`JM Nux#gHQ&m)-b<z"OF"iGJg]WMSWMۺv}:EQL'l.߼s)x2  q,ݛi%3ꠇb0B>xw]{}Ac{rTi06Ul6릪eh "c`1
!DkC4K/^7h?zv(	 RnD4Y;x130{XA#{וּ:w}osεm4]ӶMS5վmڶﻦrwÁcR(%) f*w}f4d#Ft/C۶k'bYWBдD,2۬r!Q(?^~ss}UB*6FC)f^BrBrLQ"l퍘Qʘ<ij	!2JgR'ef~/7h:{PlztF>4(d޻Y &Jh+*)))eR	@H UUM=FwY<RF@\k煳)oon?o?l4m{Oon6t:>yh~6ƔeXx</4xsY9Q'Ϟ= F#Q4BnWmc%NFȄB$D iTJXEo.	umiq^L7[D}Rc!SrBή7".|9[}߸{'KN윴Ƒ;D-vH"!Szҋzv7*%g0]Ϧ=z̐K.'f9?<\_^"L#"RV]:u#M-9
{XI_#s1e! +\*U壇u-pW!|9c`xv {pHl$Ȁƶ1Ug2S.끱z>f[
)vVa" ~M:gs!4#2owW.RaQ|y'=>;{t|z:gJJBoW}͊_ɣ''UUu]o>/_,+EQ/jeŸљrhwoRo^ΐ2 ts9g:˖IY%O&$2wnwM\\\àzxyu?V1!1Nyg(s	cHq.9SJ*"0M9e  "%h˪"lZɓ 2\ 2gе pu}5X3B\D
 `b! b]VuZUUb}?.2.LB*f~gnOTqZBJ  JVQ%hO,,˺f&1pxq}BZ~?O~} }o7۫˛n;v]kmc$pv׷%e{QNWzoO?b7ѼR|b}?:G3߷ݮigAJ="
V|VVՋn7WهO_>o`#6zBti~>Κ	Rb02.D=_E%!`cB
ƥRC38 qe)8r%3  Lh!#\"ŅQ2B+y8{(0A*e**6.0]/>??ӿ
Uey//.!Ggg_|"SJ+P:DB*|#3ᧀiFXRȫ*R)T.t` s.~~Z{) !  J@?j`S!8*F B08vmif\\}{~ovv rx> T/O>m1_gyIw>'x}hSoӈMbO%؞-CHxc}-ဦ@;}ߵ];FgM 1(H=go޴ݰ8{p.Ge92Zr>'h<|{w |wuGKԛIygvfqq}?}m}?c?    IDAT\H`tH" 灌(M.ׯZp 9Lvssu<>B:w>8+|XdZ)_zqJT$ܶcou!8YZr D9}/Z#x6DIt1#Rg23Ɂg:/ڮ=:>o~^o^隽Ngl6+Rrk:PJqu}+G=!@Qrb$)uYB !!"ycg蜋1:P\FZc8ۍnZ(FŕR!TlֶΌCߔ|VϏC('?/M*>]hOry}_4Xy]}lLȈ2㡵
B3ë/v	Ά9
{; KhB 7_^^;k! vc1>:J%}"1`aK]fb4:} SJsƎmۍ8i]w]p@Ƅ  @g-"KED-1@Ye)/V''B{OxZ1ך!Fƚv _^]4HQ0qM<B @ `BԳ۷3T<ӷoCU=1p9 P%?!^/3bv`#UU%2΄ȫ H..?.ˋ|2ki"/*ˢ˪geQjc@q{{B[;FRo޾ڶbID<~ۦit'rvAQϤT)+90w6/+SywY}6ȬXVO~^)l D&9C @#RY:Fޏfmm pZP!kF!!>=_M005(X		\0ə@  u.F&*1yUIɥ.$:SJeYbB:gcZ"I _	\IA1$kG H\r񓓓|<[;^=}uALRE y䤦i"R RڇȄLo(x7AІ8ZGEQe9r<:-z<8jqyttYn LD~&9C2F!0)x2ΪwmJ)FZsc֎fD<(R
=??cJgLJ>:)Wnw{su}ϝ}:48TJg-gL+2X.SRdY̨S2ȔDcyk-'Ƅ2Qb`ɴ^-u=B*1!rƉqɀ3@*"$`bZ*6O!EQER	|wſ?w"X.Wo޼?ɳg<8z  F__x_VV0<o|,H@sOKERgȇɩ1R8d)Q$Ekfu]UYUYUK΄Ȑs$<Nο)819Qލz}Ï꺾kzz1MybBfYtN!, bf׶con۶kv^\n6fovks@$كO?x'ONf~f^|>>Y("֤7{&6qW|t~D?mb"Z=-7yWp	)Ƃ1fa7Hq H1yq*}soMb.gbPERػ<\%2ZK98!v  T)|~kM?8ь}?}7]70}C8X3uS6zrwi |pswpFkg3VVb"e0.8/9cE:sd#>~;:p N㈔cJ$Sɦ:!¡c)N1H,J1ƅRgBI.:Zg9$dg˗//v;"rAQԵ]1'z%ʄrZKUry@@H!30	B&V܇`'"d,˴:X;G1XǋKس?(|u׵<3a]U''Ƿ];u18eygȊ}rbJrD=8YV#z67)7>FsT|믆q`1cM%=cs89M2RvrQ0X"@e:/8DaxJL+dfZH`DyR9Sߞ͒C) "蝥<OJp{PZgEVT:|uT3&]4-b0 |7]YYQ%;Q<h*mqzED^99HȄuUu] H)8Z<ϥ>јʋ
|QEY*Svz2&T9gK*m;"Eo10v蜳!8mهYk/ο7_}8jyR-OzZ?zP唰rw{M	(q nơ<{x䴚!x笵:gs9΅RuR.b\u4Yd,&XrKj-Ń,qi')sJcGc,)g8/3)b9&\JE>"@efFc2M @g ZL9cq-xgy׳z5_fټj҂[1m]vM"mڶi۶%>,S @ʪ*2Ӛ(|vp}0!|U- @$8ϳ\k%*@t
RJU`D5̆c6{ 2
H1"xYi$∿2DY~ۘXBD!sCOBHDn(Jv 8<1]p.EI0\7'T*<:[RjԾi}3'_t0i?cWu-j>/+UΊ3-""T2M;D#B'%XYfyw܇("wmki3ʲ(@Jdgq`3Lƕr	0,xJɅTRf:әJ٘vlwc~e
+wo_}Ƀ,+ڋ˗^?Ogu]hx2',Bڭ;u )"4Aeé7 M0ɅdIuey"B#rALN3y>\(ۋw۫z㳳'=fI 	0Zn)'wt$dȧd75cpCkvfin?c>R(VG}ϞVE]װ˵~6hm2E11wlSPprGa'S"Nj;N?<}wY'8î77Whb!9 zb)W eG bBovt|5[3)DG&q,PPJK9+yU)xwߙ!Z` !I3D1z[g8f!qAqvL( |&Yv1CB	G?q!*SZRJa^,Wy5KR)D>;3\}oZɤ-BIٝ1tiʋ	M1Q=w $R,tOyJKj,E	E@؏~t7o^\_n:O1t}u_}_'ERk-:Yeygւs J@_"*y|j Yg-hM[KL `*gq1}ӎ㸹% Xykqn蝵?Ӈ!҂1cI|"FB.8W//?x|& Cu]WǕc7ZcD`2R0~22y4]%R0I)3&8B9C=E[!UU#Md gxƌ<JITbsD,A|':hdH,	{"EdLJbgdy˼꬜IA{Ƙg@r h*3%_ZJW%b޷T{RH8g''WWn`Slι
1K"˴·alڦm|>/˒q|dُrtrgxBE(zq0Bιfm3gbrkL7|l6ŋo^|߷Q:g,x8CwJ	΀RbcGvqqΫ8==YPw]۴MovC93FoӥReUUbVj/<zxt|o~VY<3{cG(8IHR
h>xcR1<Ձ"%H!%s	 
)q Qi0],ϳ\gILC?VMPj`" +!3-몞gUUicCf˪ލd=S*1t]s{{}uu͋yū)!H1^)9rkng- !N,W<\c-$#h%ټLra}ć0еͭReL*G
> S2[*cHzxH-g>hԡ"zcΜsfZ
DQgcm? #J Ry__ "0NRpTKYeUXkkb޹4 t:\|~óӺBJgRJ
xm!#9"&uR
	&BL0CdCMlۛv^góGIsWǅ3Bq%29蝒ak7M[1Cv컿ۿO!mgx{{kqE$Κ͵ w=10ƈ@S@~@K"ڶ H8WZ))(,uQ,G.ᓝT,/! T*W߼y񕵆bRc=8`k JJ%uƅ`1Ȓ^=svfo7vln6fif]f(jy6gy=_.׫ON,z+)u1/?xڶmyU,gQ  I{O7q.?<)L*gwM(-~cӾ{J0PJ&D$F=1bH1Oң.[ 9I:ȸQCve/UUYʅDߒUF*N2h`T*( P  4ΘƱǾm0CmmӏƚѦ{8eX>y(0Dt"WcTJc珟<E ʶ︔\Bta}lN2I)`b6?8=k۽\+"	!  !BD)yZ1F`63ә~#+JgYRiJ)RJJ%R
JZr%v ?,<({<ˋlZes5w$<`P[}%3ːO#͸mfmH}C0?j~ŋu~th'O7!N9۶K'O=yztXgz<hRE/cp@q,K%Osm1횝j>Ƀ1FCqTdY~|r\Eu1y:)B!8v Zׂ1rh5 (0׷[!J~sEUR)  #"iqN! c,d%!E t^eu}p>@JgE)vܻ޻AQJJ)l{΄@ΙPuY,JaJ8Bt糘ۉCpu={N9>>Ύ jBdD`s.2wi EF:CUDC0cw8\pH~2%9ɳoYnCo5fDZ鲬fQ$mj}_~W_yn"_RRIƌ
D+D|7jD*#;Bg\pnaT:+.5 Qpfiwf`ez;-铧_|ֵm 1G 1Pp˴"\iqDb4&꾜bZB`Bp.vHUVr9 $11fv1dUUap9Q
f0\__sa\h? gV̊ReAGr?s۷/^:??v8r3׌b9T$z:^l6Ugfnn-dKi<SJ*)%rbQ1 ci;@@pB%ǳA[EDHoguoH+*]ь (9cJHlw777u1  stQΘv]Ks>%HEJ镀(|֏~+*WS"i `Xj}7*EVy%HCDƅ?o &8cOD8C5އzBE"əd1cOLJ%RE
JkťI@bs8c]Cm6Лql۳vskӧfnG3zd,+Oѿ7_B"Q#@}yJ;)eeE(U1ɢ*cB-!
.=[<b!16D9WYQ_<W_}ysu%p4K2/
5%3Џf8];v۾n~o}n6ݾX罔,VlZt}|<^WLg9O&A(RtUEm~MLR#Y1>~\z}*<|LD?~t(O;Aݕ\a?  f*h<|/f1ͦ;ȸ<k !Hɗ+Pn" 2E$rɄܷxp"Jdч0&80Cwcl^UJ$f)lb>Ʃ'=wx!zB3{gCu`xCh9 C=0&#H'+24hA PQN끚uW_JJH)"Z,z兒|V?   B!E :+u*C`1D!C֛b2bjaڹbjY~L`o),9s.JL(ńTZPK@E&<˴iasf!%8ݍ!wͫgygZgY]r\EŅ!N-&L";;8kC%% #r+
P%ccT2<{n7дCcni|r qFG>JǇ1`{y~^VuU]{u$y]_t~ssN_n*RtΎY>Z-k(R,w%gQƓEHWB
Q\*7}׵m.!ROW1qs]}?1VElޏPscsVp$yjOPA
˪{BƄĉ.K s[<    IDAT"*(
k}=<!X3zcLEQ c@Hb ]4}XTdG"{ UR!E3EY.V룣#k5A*=t]Qe!2l6UY%:OCJ~9IIDP).oчf\H!0~}ט	ΔTZeI3CDޓv쇡2ono޽}bX,*<:GOQD̚W7"
΅'),ؑ,v麎Yu]W13vnno1CEƑ}KLb!hMln</WYUuCWEɄbQ HHfƘڢ( zCZU|A)%' ɫ(Gq41t!۷8
k>eҁyCZQꁼuJt]룣jgܬ*ϭ1<76xk}dG?۾o۶oڶﻮN@JGG|\HY5
#atޘјь6&*c2&e(s1>B`,&*$pP$"RhQ)Ϊn-Ɲ,;ݪ|6gZkyq
Ia%S샏{~bLNGD!bma!zbcHso-L6MA
$hBJS|@)ȉL	.`\:ﭱs!^gyQfJ)TiɍRfGd8 r.8Cΐ5CQgѻC"öm|'O>zca=2%3q;c8f8kݮi>9Pv~si82]U='U]?|xf/.//qr.p' &dBS@"i(=z DR}K)J,ϳy\lC, Z:u̞UYO~89	e	P );;c~mNiv3"]uVWxZ/Ţ^,|1yYY^L!_`tD& G޹`)E(R1х~AL3tG#Y?/
j#F6<=v0tzLtwZ0!웽s3Bf$IF9 `,Cƕч*:c!cзmmΥ:3Sv]RRd,o=1#dcA*l[kf40cT}ߏ}?8gI90 paD=F	STJM嫓Jg4:k7E?~4%"PJ-WGJ;D%))<IY{JС2hdH p2vH|U#̲"ˋDBHJiDJVdR2D}QqkVw^1	Ɋ\?~W׿W^&[sUlqtt^ճR*Ft]w?5eL9gIw(MΙBJ( ̚q| cY>Z_;횇p6{^jQUD`AĤjz>ʊYB&z2XݛϿ~RMwr|_~v{}JgyQT5r6Rp3#q9ovUDeZyQq.xLIId5Θ"|$Jy1GnnapkuLȃz7N@1&/JUViRS Mb}ƘIe# șMEs^IR5="dyeRi!Z	m(bU!Y2H)Ï!E)N'|X]n$lQ8g	Z9$_s~杳k)$#1ix :OȐK0*ĐB(bono././f2Є)dcq>'gv/_Z]T,r8M`V!2Pތ޽}o|L*	 M7C & nB̫,
uweӶ\M0Jt>;$3?nutιa߷mk]3@	3@ rcFcSC1D4>ƈZkPJB 4M51)" >\p>@y=X+Q!؄!J#b%T!'_GUU]۾zͯoߝ)zQK\Lg΋fn7qgm2G"SLk9qqm4C?95ؒ'q0	B!)X
bD2ӤN<ԟDKa߸6a6RkBRk}82 0&Mu!Zxv1e=vo뺮m[clѤ"@ĉB֎È 6bhSf;Tgm4LEibH[Τ9'gD12Ƅp9"")ݞ25dΑAbgٷM߶Cm/yWs"E	Sr1Zk8ıqɬڔs[k}?0)Fw2ώ>O~ٯ_zyX"7<]H1Nnw>kyEU,KX0 jo{M6Θ10&;|d38fa4C8˵ 3c,˲,n6miM6]u}]?4qn*॔YY/ry^=8=Z-YQtQdJ3VugJ.8`pɞfy 88gsXBpqv{TۨmWhz]|J^ԁ FW'ҽJ^_ooAbe޿!1BlBN9F!:1FF)P$F\DQ|xwj4?u	ywnv4S7P	LɁ;Bo  # Kygh1]w]׶h̐Ƙqt;YRcWbT2&s!$EjVgyg0()Li%	縷ai|Rp)X SBb׋vwCT4yM"CfO@MBʍH`QY^H)cs΋ߥ\sZpUU `" dzx,S7.埜{mu(ΫGO>X,Ri p;> p[u@fq>)|>:onnIHWw/b臗WO(뛼fj`_]]"2T/z5c01fۿ~mg521ZJ-o ݻdWEVͪLKyrzūvB/YFcY]W8VF"ʢ,
St̳Ayr,1F	#r5kxcƘn{s}{sڶsާA ;7t(gDvV:^q>F +M*s=t9"pVE΅Ș!8|uWYBȉAq7m4G=<;ݎ#@u.&&Q`a#1ΏNOOn9nև0Hs ZWT_zyyYW9 hɀfzjc;眵kCUU;.߽}~UU/qd[8̼Tɞ8 Hv\Wd몮zTʫE/mFKy% tl}JcL1YS/~BDB.ʐ|INP1WWoߜ_<֔3]aټ]?w}|aCW]wm7CJq @
mF"	 sN@ITN_}w}|}ɳ>)0VHƢ#)J`.3z}a
PZk+cFiIq! %@ 3X%GFP"R \ v=dm|.܉9ȅxAush]gg޼>8Y/'Qg4 ]oG|6V?Gժn֚c8tݻfs{{s}8"!"BguyzQ<MD8)DM4|+$EH*4$À{b/Z!#r13i31%?t+X|vֺiq/$'Dn?wsN˓ӧ/>/H!!PA)Bik-97EHJ< -˗/_̅ت]Vsn6!MEX+,I5|\[}{sիb\̫ZkBT'v1nD?s
9KR!q  '?v GP/s/(iy8lf/v֗O7~vp86[ml1ƶs۫٧O+*&99G+{ )OM,ٹjUDڂ 9EX8SXC &MI|xXTSL}"Wu̚flo޾l75˿m̓Ϟ]w~7vu0t]?!c* 4zxt}l}vz\-f3ΪrNT;ex]}@;67|a7ׯ:]-ON93`)h>09r{]{.)b~r/	|/{oIL'b JVeFe()0LRYNfm3~z\.q cjYYwWqˋo;g>ESeb	p90ǲ]]?v0ԏcIIYеK"2]DTZ8?*p @k`%YraE훺vRT9WU5%IXg1s>=w!*k߫y)1x"*VD=Y!3fyKNૈ8ӴJњl]ZU17kiݻWWX7n
cT)8J)
 Nn|ryv~xv6ƈHΩ\ؖ `bH1i8 yJۻq1F]J̫2IaOٳ?꺮77Zkj;'^G}?l]m &emu׿̬ۛa@j6?X7}DY>{6-)־훡u肻hR}(v5Fӕr&`cQmFk!C2Mԕ6rV) !Jqnwusqyyvz:&nwv!ıIk)_mdgL3osU]ՍvUw@%[Wdl%ʄBMOƸf:=C⌗q2+Q-gm۶VŰ"H_wrzrA()ƘҬmWE]ww72gn1)0ϟ=}rz~,77>Dc"")z.i0bL̤0)SW7YQt:k-)s
PbS,Ӓ[FC2/|}s@$a.8o˗ޗ*䜧RUqs68mmw躝fb>nVD9۽{wL+`<eU5}y1kSΜS0V+  "m&$2~'84 
wopzzvvo}Ϟ?__ئ1Z cS0ks1R>T]UV1
+N(Q82Q圫kKD|ctSfcl]W躮W弩M=oꮮ,T6ZWV]}{RJϟ?<_7΍w_~墱jZ@5z?]{(~f?m8UD_9R	rqv	*HWhR @V*FNI0gDE#*UĂyN3*4hPcueMo(Ǉ9Dbc{ )cM̙9fEf?yO_\D|!eohRi&(RBFI!0wu*1C|}Rxb1,Z~7tXlۛw|_X a;RjK$0CΩ@2a
u^^^.g?0sNaa8v91xɩP*8OB9~<!>G﻾nwws]7Ȑs)%d~wu}=\-hM|ⅳv_:olh4Yr))甲"FbjchClNbYS8Ri0F9
2yKR|+s21t8D 䜞8qW󫷯>_f;x?B!3)mIk[5quSb:]OW|jf6+W9g3jҥIPͳ7鄾);";80֞vvw!}2ً |oXzvi^~2]}ԩ
ۼGcɝoŃ EH!3@aEDUB+cPecDZYdߧCż>%'@f@hDm[N,9$G8j%/2nPA?=I1G~EpDX`JD,)(y :YPYG!!vޮOO;yVYDr1x<tN|@Ev]ws}ntUh~D "P&;E"X$GDPVSvS6fژrL;SUΚnۺuZrduP
*▔F&] RO>{bU)>LCD@T@<h8s]w3"RHxz6]>znij=}ERz
/ջ7/_~W/nqsU4m.~0Y[7[N/
@f~qy)j!Ř=k PR𘙜bN>RᥔN1DgZ,Uwvc\Ր9kaҶ
pnaS8L"h8 Y9MkX2Kmjj*:zhA@F()2#©TƘn8G)\F |U֕{Q9uW䄈bR.jkǱDT)YX{o}(+K3R9)cs#qfr4]*)/CC$,182|NKԸ(q߇ڴ7vw9)J-~WSBDFCi 8xO
aǮ]]u6")-iݮ֚Y$b4zαX)iRhֶ0bcߍ+gJ5("t	SbKJ&QJ Dw98OO^}Cm%zS#iT	59*c1e4ld[eD_    IDATJk!B~,lof61ΐ1ӦX,}TH颮SJD$/iMϞ>[1o?G?ɿ?_VMC8)]?a}JIl!N)Ԥ1xӍ>4YbEp˰Dx13r.
*C2T>Ř]- oU4ƒր86V)3{

̥nH@Edwrv__W/
&&9WB)kzT'Ϟ/vXڶm&?pT۔ۦkMb}zlnB)nWY+X^'Ful-iv6꺪myS7UvX)oS[bH)K9ǇlW)tG!&BJq7f}H9yijRzR(9mj5e8uA!U3N\խ1κ|flټnm"-SMZE13!TLˆ% +{2*:訩THTC̩LM)9gLe|ۛ뛛ۛC?t}SNkY;5y;+j\.fsI&#(WTƋDwb!g-(R07&g0{n7ηW	!l "~Ǘ!i_,g< >2x ,Jqy2B2[c8=f*e}dv-\me\Z.s8owcT4娈*R*)er8ȩ9쇘{?}~a~q0%?cPľc2g)_S @<S(<"fN R4@Q6F3"*Joqziciz[ӤlSJ,^|~a:@] b OB"a 33kV %\ظ*"BVU]f9kܺZMU꺮v.n uI,
SrӳO>#gzYH 9y?~cL Ť5  +x%ETDJ ˯|>5"/cGLxAP
CӿqZ-a9f7r1OG[R_/7-"䜉i|X,]]30s9ys<],Ŕ999[f7۔sIqJ gk¶))9.3 b~1-vnon6WZk4*Q8DꦩAe@!m1x_;iY{_dZARƪe?q. ~1l\ָ5mU0edC)sJ4Y]Հ~~G?BuS! b>94-QYD2`;kNONNO}0=%9HbH9srn7}wP1@2i"ҙeZ&*DWɇq>YYD8G
֕6sCwOl"#2
 GD\VS	s<1pΜSsvT,R0D q.fDto p/.>rի;D#>j@D9|)9Yk3ZVGGdE<g,.cQlq<eFXkZ!9j2o
fQgg?ԕ#YۮOό6W77o<}_7wB&g.n86ۻa?C18|G؄P@g)eIDp+j'C5"MJBE.w',HڐVb@h9E6Ү 3cƾ\%T3C <ӈ䜉{cO޽{wss34ϊucYW8aMD(,3X!}t~vaf8s
Y:۴mӴUqU]fXϟ?{FD)ƔBJSd5Y"M%r\Ζwꪒ;"RIm=(:c.`)L3Ffwwn6!8c1sUYMRrhc64k|aaK
EH)h]BRJkv:9yrq:;Ex\r
dDqYRJ9%轏1	˩DY)Xȟ5rԤEXHS	jc4<+"g
!e}onu>їlm۶i[W1YLY&4[8F9xXsL#~gC:{zf8_zW'Cyht6?,G۱||W޿:n~1zNF:LO)ƙzH>|<" +yH %GXbͨQ2J4!(?ߟV6/~|zQkŢh1_!o> Z)x`Ȣ%BN)1/I~}W}?|߻Y_>{Gjsw?WN)RrNEWs~Ժ*T~ֻC^]<}1M1J)DZ),3)ƔRIl/~oW_yߍS$)K  geԇ4-1 HiT Pu$Ԏ-mfy⚶r6T$Z$8HDtz:=YmU78~M+ikFք1s;G?&EDRbw8t9rӛ)si'>N(:
C!w8kS
0eMn}O.$/>xS/׻/_ه){k7wss}RFE1Dz>׋媮8Vg^;s:ظlCBP%8TJD$t{ND9?jngT"&RZ(FRLV,C!9#"Z.g~Un_7uLdn\v~ Z)bRLXAe91c4HnFKQJ"c<; 0ֲs*; Uu[3pu{W,|s){s{o~u1v6/ᗿ嫻ۛ~wًژ!DE""=qxF"U9\ ![DEƘDtcdX!'s|9c))Lnuv;ktmї28x3'`A6Q*rF2lp2W1hƃE95b!hlul+gE]!q)?])9HJ@YmY[g9'@Տn9}PBq(TIAY8&?MsG}׍}gƑZkk]JH?(.SP
>̈JShZOQq1bi BsJiY#/՜D\ig$n1O~>{c% FɓO>g\	/믾j5cnw1%]KdBrUc>Yf=tCN9	B
}Q@,2[[cuUUM]YS7y5[-j[79kYm/n_ܼzME
38P#ƜϯnaTJ(@d}'ǲ8,PDBD6UUQJ^Hwwŏ~G/9"kEb1fk<9=;}gϗ9)v7^^\z'您)9! *)nnw{WB[ճburrzzz\^ճYU7V"Sf-fef9)'?v/o0$l9Ӗ"2ёbR)ŔqavC?Le)("2x/֘vR  Jȕ1`p;gEw8>fY)eDմ/WgfuRr;%骔[S,Dy~c~tO&KFkMڠ64i]fkR9*ӥ88h}c*"N@X6Gi#v FJ><B+z?u؛ovXxl
~۫v铋n}n1ėGZ!a1~
o8R^/#cCo>0|#ޙXNrg<Ge .2sPp&LB
A+*\.ͻ'Oa΄7ۇ08cG ZWf,r$)P8Z!чg?Z0tؗ݇?/d*&7	J*6Fb"sFڐqFpggYu쨉BڄT!%5t" 8wj777o߾zf݄S*
c)k T	o3GAł*F`TK֓n*j"Xc4);I'R#|6ME\U
,gI9\QŲ1ia,0~"RX<rN) \vHaR:DQcDj2&v8,п~0|Z.n	1RJG&W_w)F@^.Ų	s?}7CZs^7u߉@UMӞaΚ2bq!hoBB.2%|
XSuJI!RZ'OR_7MjHRy\d9i"cL<8DY,OFuU҄ pJuxйG1Cl6ꦩQ޽oSGNj\nQQr1+/_moȸt=k[|~vB]<yZ7-@N`uM3'R|$mkIubgJIPQS$wXbmS	QaG`,Y! % !bNcLB);cJvT̠T>>
-^>ų!o<=$#S(BE傜]g3SRFZV<'5#bI !sb@g4)5cgZ/>3fsmqP hJ=nɦSlQ)gl6B)U*b1(>}@1Uݺ*ڀ2r)( (ؗ@8#3gVrn?}}^u۶?O~?&
4Yk1U]u! /_|+KX?_&HsdU RO	iҤu]m5l},qǂP(ƅh4Mj[Um[M]@'e/UBɏ>n7a,f8t.<nE8e?tjc*g[g5Wӓ~(,gJXdSew-9R!&<x*RJIiRZaF,&sVv]]H4wɮXc>TMU5U]f )W_+ヘsucZQrQBK 7R`D
S9{}ʹmruiu겛wj tdr1RdYl>,-َx0cQh)c?ݾg	I6<eΉ*Ҧ@@C(Jܴۻ۷o]_m%5ŋ>^UUHcN)O)1!a1C
O,Z*ǘP0@RTYH !&@1&⦞biS!fNGAXLdEIf9>icvP<mᩚ.c5+6Gۏl#c>;њ7oE'=pN1(2Kw7z(ZmeSt_tACǿ]HMyyƔ0GqGĳQYBh!HD
gM97j9sN9&U~:k]&E
%gIK<Qk
1Xھ}}!0v'RDMS͛ׯfmZ-f}A2M f<ݙJ /Uu#؜BTĔ0!*WJa1W_Zc拹1Yg^	+9)3@.*b 8
Qk\U7WW7ݶ;RH#(@A`c$>N,L$u] QF$R1hdՄ=zՔarrɅw9݁9gs=?(a>!Axx"]Z"PYDZCYDO]# Lr,s>wEz6k1~>2甒:D8tݛׯ߽-nȼ|VWU11OQ{JXMNt/BeS %O
R\(]whf3k-C\cR&-*x{}=8"b YE%&?[DHk"H)tU]׃pƔsic ()w[fL%U΁et66HZ)5ׯݽp6ZwӓlflZ I)_~qs4u]Nr}ߏ`𣿽GY_\>ysadf"pU=/a139l-16WbJF!i~1k"?^SCSJ9I cyH,etC"Ib11)R9PR6rɝbQ	*&ѫՉ\JQ8g)\%m/.
zP)#sFD5J))]Qkc$[?}Y;_z{8d,byuXP"qdO"EGb(Ak" 0//`DUz$WՅWb/jr!"*ЕToNpMD)R`4U6c:;=ן?}r>=],|TΕ 2ݽ}ŢccrFP2e.uF  \=r¶Y-KgLFW8SL,jVV[c6Vkm+G*TR1D?qw1R
ca=Ǿ;Bw0r&Ħi;P~1ژi|}6p#Z[Ub
Dwv <dRIH>vS\U[goRM]zs6(JkC-~ټnY.<6Fn췛# 1sUMLB
U:ҦH&SIX 8]2FN)?t*4"(;:KK0 !(V+gjLǣе
&_b!g8wCU$r%U"	g @&)i |2Ν]</n~&=5g8K^KcF_=aL)1!ECQ2å/91R)2F S;~2sNR;\ R bIPM$vJ9]&Hi7%]iغuUjj-AóǱC_Gw    IDATUw;](EnsqJijGqxW^X}GM8z6|>n0-g	JHu%@IJ AE,c!10":Nl 1rׯO9aJ)5n~Y3GH>X8O1ccu8q~h*xw߾~e?_sf8P	'z 2Zk몪)2H
drJ;eYcfӣ,R҄G/yJ͖')&W믾Q*>!Y))KH[1O-f[g7]ȱ}DT f)} p7d	nDITGas?C&YP
"Z)5=̒&)sft<ӌXn "rJ	s%>P=P~E/JnD;{.|nA,b\cN	ΏʝfS)H
%CN^NHpC68+r'U*JKNoy?~W9R=d3+ 8'>&8ic-a"rUQk cr$17L"kOy͈D)%ᬔg!Û7X[UYjX,bJoKe98ǐr?5|.Ω;RhYR	P8wPǮ{sglQ7M
ٸ 2Ui>V(þslݗ_ӳ/> R&X1l9W~ڜ94B$X놡pA03ovb c
!TΒ֑9+@)Ȃx2XȉpMU 
PpV@:N69f`C \M¤ih=E>]_idPY4 G%
@Nq|Բ>WU3_g>n諦uUZ-?W_oq(CtɉA%dSDOVqnon6۝s9Pbb)Y1ƘX9js)  C($H\H>IDa臡h3K,hDζq6''?/W'w?/~gM,NVbvzrR,H?x>G7۪im ѯ>߶M=_&fh1/kLBŔrΜ~1&  cJ!x8߼y3fٳgO/|r:]*7/5J!BoͶnw{{sv߅q,UsMՕEz6n~g'ϰ؍FS)n9;=)h0DaMz<.>2gS׵R}~>F?cNI.W&}2'PH+J4 A$'''lX.1Ƙb	S71;,8wnpx{'9N*D(ݣ83v?iHJ,ZýsndUEfDfz?)& 6Fw^Ç@UZ;]ݮ6JIIRZKm]MJPy7:lsH*LӣY=&ÓyUhH(($(%wf|?@{cۮk;!Nl3r6ܷr[PbLAS&gп{7Ӌ/QV@j61]umoc6u6= J ,!$$`CLH^^鼮JcTv\_]\_;4|NC-QJBB錍'Z))z%I(R$RUUf|Ngiaty~]c/W~?}UQ\\^߾_ܔ3K`
@Ea@s27߽@vB@އD=K
vj"1(Z0{m@`ڮǝ MgRY[r:G&rZ*JsQVetn 0PB!qGoc;\r֍ڡ`sRvhX=><<^]]{犲}/c$B^\+Q
]֜6W96J!	1ƔUY)1|nL<eY 	#3gLRBn|!'+DRoc^wwYSL1fqn#Զc7@(F!S1~ⷛWUmҌ SulB.X$v.!I Rk("rA޻| Ǉ7/ٟ09i&ƘR,)ǽ"	qi'Ǉ1F,s9
A1&)rO>2EYh-L@Yo'on[ .;֎!&Hh%-QJt!BҤ
CY
	01ཱུi4΅ݛL1 e3R'=x"̦&9{l!1JQ8)&ѿ$DJ	RZIQ-uiON]Gu=,*]\H1&wB" A-r*&ٴ4ZR]q8
,V⳧WN߾y!귍$U۶юBH Ei)Ƌq@*!FǏS<C\Z7)pڬW0j%
Qr:&nR%@DQf4m7
 юð#$F:FqM1p
`WBJML&Ĕ&("H2}"f d;`VRB
N10mUY?ie뮮րPؘ8?q\o]M}GOvHCpחu]h5\^^^f!:g5R]۞*}Yluam7ZC@!Lw eJUȉ]w@ơ_-W۶1!SbJ+m0}jt!hSL2?b"%V2JΎf|lRzl6MTZ)5b	<]
aWcv7]?)D&]۷*2崞L.ޯN>'WV04MGky\H.D3RJHSVDX3M<8-iL^ח˧ϻg;1MRgLۿe0>Ƞ	 e^1"n&3F+%@Y;$!D!R Z6gn޼~'!ơ'Nwl6߽UR*	!D)gZ, NN/JWPO?,+;HQJqzzrrrYhu	 23wDAB()!O,5;-RhYUEŭJ)!B"#n5Kٸ8?NY9o cpi&KwL1:uY`>\B\m HFTH ^ RJ}m?\L(Z٩_oWvym[gֆ:aF'G9	Q bRVtq8/yQ ,3øY\]_]ll۾mb)|JG
Qz!V	 }!#䎒#T+B77+l6=OIb̴w=ݱďQ
l>1p]r)1K]{g-pgp2wah1-zJ'?~̈UYl& Ԗ9*s: HB ̽S"-(Oh"FgV)m7J(]f7CI! ¢8KaRpY;L׏0Xkwu·@;q|ûrypps gLJIJ)P`*3/;1 @H*taaR230ZH9G72t@f"B엿揿nVw ,xi
1;"3\dCzQ*bqzwM0|RJD7WW}@J@b٫''{Eg{4'ːqYw{Er%ψ^1T,Iise0	5;8'-	#sۮ߶8$dYUژL ȫpL)\2)T*ju>k P4Ei888cQS{D ;	N_ Y։HuU*eYx69rsr-LQJ!HĔLB*ARѓC}nvMb kN1ڡ6RiStR}.wn:(<z?+Iyua۶Pt:
9vjebGfm3
, r1ClϿȐBvY׉y3Tebgry,)!L1|ȕ|3d.[b"FJyf=;%*4ˠ bTJJ~~wJya$! Ib2B΍Cus2ň B&xU)rc1Iqn>?ggE?x p8NjÛ/]Yy;ã!{c}fR
Zo"bl[BJU% ,8!#Y~K>.DmPCJRd@b$I
պna1pXsε0Τ6eVKWDTEUO1w:Jgӓ㓓뫛חBjB$!ʢR,oSJRJh-KADމsĔ8@qpǽ\RjmLYSvkN)39Zk>\eˡac,sS!C]ޚjZV2i/.^|)>P+YՕQ>x&ݻwWW}+3jnocAX)3O)wD1P) CL\U6lPL#gt2!(qߜ#>9FRB089BZ'O={Vi]iS$Fn;ٻDB;;vGl/BJRIrU)%$A9R	)D<J\PJf1~h7~7aD	1Xa޺g*%N)w>)u]VݓG!е苙0#o7ԳEQTzy{\e%\\JB?q(yd"I0x9V@Bed֦gdZUaLQVE=ʚ0:ogj٬Wۛۛu3t8u{ ! ;=vUZ	RJ!$!AȻ s- P2;~Ht?mۮ7͢iɴI}B%L,w}RIͻ%3<q/ŷo~<:lYߋw|Cxwwx;h돳cON]~?t 4Luz.Am{yylzppPS  p̼fTwt)`mXRNgzɡ;WqĠ2J}BfAyK)sR)ؐN9&0Z9SNMFg0?寏NNv,tbykؕ(۠h)H 	qI$ȺaSRd8*b>l6YatPi۶{!ww喌
֮V␤\g}̉='Yf=tnN  eJ	 =!s|]GLJ:Ӣ?sn-Nvdf~* 1x!ǈ[g98|Jq*)%OҺQػB"6IݶY s0BSuU1\b<~hm!DMQD䬵Y^@*_.B*)Q)f	1g|RZahՇwq2R&̮Lw@SRzRmۺgSDt>j"LI]]_pm1w;VgFv)霟L牱0Κf{_hZz	sd
:Xj霳)! 'g__䧿ﯮ.F)888<:*1x70(,n4c~҆RgHqz+3ir^aEI$Vof2}S@
nc2,&m A+U"=Ų	y}f@{!7Gc/dn[	;sgw#EYeJ1رm6׷p臔0;g.?tVk ̑SSI)mə2())h^~}CUBXn;Ab:=ڶh}a\IREt}Rm 4J!$F})/B!;Yd.
2Zz!VJ
B@S Nj5c>1CvD-vptL+Z-H\__K	t})!'!snÇ秧g|!$gGk-87m6}I)BIERIdCN6vǝ~cLaOR)+ EF"H1	D#"
HoC&>~X)%ӿ}{ 񸪳  EA#P?yъc %gfGD,|qtn2P(ERZf,|>3ڌ֮WK,TA(
H>&#泩TRG! +Z;YUHB+SVGG(Ij ,(H4x{s3PJurz:跛dɓ[\k0B 2FRRA^g}ohkSeQwJ)Ɲns ti4H)uCVqM٪udP9'̗߬nd:NU]׳y~X,ι~:#;&AT=H dZI-$eUU]uYՋ|>SѯvnVju۬nm۶]ɏJ))Z*e^0ϑ(Q(ܩk
\;;ⱋ1q@ ,^ٶmK5YNG!BYy#}G&	θ++%f0^^^n1QQ?U!}u;ik}͛>̈́~k9K~@n GysBL!0Ngun)xRbNyJ!)?|_x{_Kٓ#1 ,"K)eu,wX(AqJ͖I p+0@qe1B!8u:	 b)1"Ύ`y׶o^<={xtt1_*L>	HH2DRBctUO)l;kӺpn4o_0WC_d~( zbI0 `DDVhM! eHY{T^bJ qkL
VBJr+_dd$nfPJS箯Ǐw2&A!;gvжз9LK	wI~ƄD iFb˿waJIdtqi    IDATڪV)a#ꦉs~6bBa>23D!ћFT
X"Q=OgkSMY"'r8qIFBNI
_Wg(צ,'b>gEYyYrQ Sqh*1H@Bz:;8:ғg9]ͻqMb>|
|PVIUզ(bs!|"&0ȉ=~߾fcGgkwXua"1sB*&omy9umZ6x{{;[,vܬ׉yUU8@
A\z	1q6,h:0 JXe-rBg	bh9z>bnncVD),)$b.	aD)COD1%I |,8fYޮכB ֽ~vOv|zx0n7]WH>LB\?_ص_v] d_|ҍvBT1f3юh|6i{mDIȘu
"Cd  9F)(6Jk! |he`$1䣻^'Oo.>\#ћW'G?/..7Lʲ|Ϟlo~n۔sH
n|q9eߍ9Z	甂!Hb>wS!@;vHBKŇZX"O*O<2_#&=NIx7ξD|ۋˋj2=?{93 5ӣó_؎YjG¤T1zf~pZ;v= p~i6TeUO&Ǐ}٤ȸﺾ|q=K)Srb~!l[)H}9')EYЅ$>{>{"VO<~o1kfA۷_7=,}S<)JE$Z+FVJ` 1m 
@Ƙ J~LC!D)(FlFB\]߼~zs _y8>z2tkHIJRM؇ EH]{usjg<>Ƀ'ϧYa1ҷruq6~2ަ$F㓣ãiYE 8yMӮWz6zZ,Wr}n J%*ҘjbVJImdqvB	-%t6 RKABj)[ =;k-RJ,wMQ=8=>ͧw19qH9?7|D	>]^\|W?KB
νx}IYzQdz0=糧?>>i|dv۟3~Hi>K~LyJD  p޿oW|./.kfklm,IiM2wZgJ($4ٍ$h
DNa碳n9k]1D	p"
wWwI=%cekeVU;\*Mmd2-.>tv'*RDd YQV1q^^^_Ud^spW2dP3s$JRC 8tzvNDΎ8:S)뇬^π@L1?#
!h%uUr$~NȌAS%tb
"( eC 1HB%)"R"c" )enfgf6eUUU-JI]0/Dm)3mXrI;^}vMuygm!bpyHFmTb"B)VsIIdl^Ueyǡ8VSJ	!LLJ	;h JJ)bx69kif3ͦu]?{¬q3zW()%FB)%"!'B@Wy3e6BMa&YzWggϞEa#j2vѺpQzz|ZFٓ狃vX\gXEAR02ׯ^f3\C!v1DL)gH{}nuf8В.sIb^O 1e fq
1f$Ʉ.&@'̹D'12Q)S
2H)12qgcCH + @6*Bbw(4eQs9ڛLa]eQY-mM(Bpyyâ,.rY"Ę'Ϧ)#i\,Jn7޼|@RX~\7<<xPjno/>999[8k}1quaU)BkLa'dQJ,0BR`<\cR	2Jkomqv1w,oka>rI G</Ύ{ݔΣ'ia̻ps{כaGkS~RUU-1D>z ɒD$3CD._
	>^Q,Mac>Sp10fy%@iP"ˈ?>.KVJb>qq@s& )i<yzyun	 B	!(%mLk_>8;{݇}J*%	 Z	)~_km۶ma!ÈHg_g⠮'Jawnh폿t3;k77rsvb>ɴi6,˲0FKJ*1]H18Nr&%FͦM)I)CU=8+ի/^|c4Z4MIMR:ʲB&QuiVM|+%IHwB RM	gݒ#w]cB..d3$hH5'óׯ__\^m6m?=<;;9=}tO)$ޅda@O_ͣ'ONNEYOHH}?cۍ֎bH	=L` (MaǏN&`1ϪT)1JImv۶z\V٬W:cBuU.6TEUVeUUULG?R @	)TP,NTx}StY{oC?svv2gtbߧ4awpxF B;D$	?ƑF~5F9W_}=_JU҆'.4|ڨOJxw]˓Gx|K]NFnC~9}+=ûec!@R23 r!ޮ/_\ÐbH1d-e[)	k/_7Ƀ|R"	83E!
R`Ӟ 0AmJʔGJ @
>!x﬷֍Yo{I\bE@!|/~񋳇iڶf'ooD
vEyRR&2kD(zK$*j2!KB@D$!HȺ!VE5s㓓ãm{/!HB"Sٺ#G$(qvj,Z %!CsRie
e֦0z2))
RJdQ=#EBji)d?ҾؓL&Ӳ8.ңw)N	89gCؙf$B)bYDS"@N	 Ma*ejuQVH]uvl"DBDcr}n7jm6ٔZ)s1N	HBH)D6$1")vbLRjS1vml!L0㼣`N9)r]+mUUm7k)RClTUU{l~vfeaMw]FkK$29'8y?s9Oxqp(ElMwve?C߇1ybF[W% .WUq|rbL񓣓jօ)lq0]8j^<Ꙡl6 b^ablê0RC^j	1dsHL:!c<nKcV#
!H9c3MorȘ7Hb$Ī*(CB)ߡDB*˪!n1
說Rnۦl_!؍򒐊H!a>xr.1#NON0f:NӪpcW]PͶBgӓ㣃kmono뺾nG$"D?EQ(i	SQ)]Vʤ@,10'E$bLsЦntv!b,La)R ><?ۦ휵M]G''GGGPIaBIv///ۜ;HkS
4 uގRt]:L@"̹vct>fT@, 'i)ީ{	AQ
RJfBLQ<vN)Ɣu,"by;GƄ'<pmӓ" $@JMG15"<8=r18w!(
!7JO(J!)ɤ^V҂HBi&y4:]?xSѰm3,'UUUUYRH)@ɴvmb *mZ)I]}2svZ.oH4͍RP&;i]j!% SdaF"GY=m8?s~	DގBIJQ2eBABiH/dr|xxm?C__]EY	 )$B6B/_lx4uCWu\m֛0Z0+b!)ʔ)I]OdZMgl6(8viٴj۬6f^6Mm8!z2;j2LdRՓ4E=-(+RJ*(w9,80Z-8ZH$IKｵv;18gqG띳ގl^Uމ?}v> I8>:\W%=~Sǽ|(`o%/ pN{>=~*t?0Gc`ߋN	Q,þ_{x;g D,Mo1$HKU,/^y{dbcNJ*%d<T1XVڌvM&vR18QaT74Y*z+)}1b^"hGlsOF+S>/~rIR=zYz뵖e'F5"`X;*mz$jRgR!@`H
Ab6)LNNnona Ó3߳uRVϟ?},bRD L΍;*FIeu"@QC*LUU!U4g־. KSJ!$J$4F)zRNtZh41QD4C.+`
cU!Ck]Oĺ¸OcCKﶫ|W$bH1(&!ϸw3aRF)SORrmF E+B"rvmsuyݬ ! Đ̞w5A$* $!=,	RʔeYVB9kq,J$!IMi7~Rɤ^.(efՕB.ooϟ?fjq}fY|2}]۶Yɒ?/m61
!z*aãyp/_xٓOߍ}׏[Q=y١0LE&AmfnNIY!hbJsׯaPJe.2f';q?}w-jS̧b}h+0h!dUL}SBNlrT`m;CĽ J"`e Ҿ3w"Q𞉪 b}a !MYOU)BLH6M^L&e]nmdg'^_]'6FRpmvt>;8<8g˪̔0V]/_|0+mٱӓ'qY]l[snm㜿.
9SڠBFkTژ챆DRf([UHRvUcS`> N1})9dˏ%!#|7|o8
ތΝ
!C;X7o߼_g勯#B-E
m}۶.C!0X7ooT/?8!06qtQZTE!<SZ*1EY((~;RBJS9f~`ΎZI |ttw}l߽yS8eY
 H" ̕@%~~7W1wnp|x{Hi>/ӓǏ=8	 m׫۷o߿{:R@H@BGggCuv*6eUu]UEQzUVr|B`N\5=(z1O&5h~HoQ+a!DB\Vz9_gemYޔRZ霡@x̜1Bسxw|FEG}m\Ƙ(_I$>=<
U8=3=^Z=A&a]L2[i\r8KrgF(ԑW~#j$)e1aRCX-g1\]]y~ss^
!Rp2	E<p싟3Mmf^=PPb6?99==XNT"eqwClnUvt]=C6M!&Ƙ*zX.fj}r^׋l6YQTH,*. p΄x 2OCp7v^o77CH2d1}3n;}tCNNVR |o5u8&lyrD(y?UJGYBW l;1B^:-R@GAw]9uz33)wl
~]M{sH>sȁGXJ @(!9ӿW/\`YBХ.K!Dy6xz|9+)ADR*{ H'RH)x)ARt]+B<eIޛL:6ƌfGcΨ;+9HMR_~?7C߷O~Z[cИ`FҾ)㳹B >9պ`~CDg"J fYUqlf6u7w݋*K}詔s 9B-(D~CLp"1Znwsss
TYr>H"f?Bd(VYU,eY\H8<ՀYgRl#)LY? Ǆ0[hUVkvC׸RRQJsw1 x3ȘkQbfp|MW 1(w ?	D̡LkRHŅE)1εV/cmQ<8Mlv;<1R2q>Xa0<x-RrS! ~;3}Xk3؇aBBRΈR1eYzP    IDATէ'\8)zEzͫop!O֫Oxmir9ON7_}}sӶ}V)!)OWr.d	ޗe\g 287vHH!붷YeƎro[-ns@'½u~qbLF/v۶m꺞Aܡi]]BeQ*%p!P8M%ﺮ+(sJ	M!&}DHsY6 @"}$6t(!V
 s[D)AʊBi%hBf)Kti)'ӧO)|~fu]huh[]
[@7:<3`r0NqV2 `s&,a1QYGش8,ڮm.yo
aYL>a,xm @>#Utg{M9w{14&3vj9wCwW۫_ɟ=}ٟzp1Dg.\50c??>YM{#t!ƜƑRXwho_oӟ^!xddLۡiͶl.b!F	eIRBҺ(%1cp:gMC{\m׏Y41p)FO-]rs{SjVaUJMhDEpꫫwg\Tu]pN	Bhˢ`;g_onnno70~::@Bཏ)Ɣ[0P!dy{ILtݵܘ:4J&er. ()؎GR
 ߼I)ʊ.TR"TdVRJ)&JF|8;Y} /_>EQ()X.JNp$DBCv޻!!$PG[Jkfs/j}Rֳ'}M?];vM;kM+98cdN*|?SCva8ءU5_>[ONO/NNϖzcֺvsvhv{6n4mo)QB:_,g|XlV/E5}]'xw6߸S}cF/gƸwﮮoon7m"hɅ8QCߵݻwof3.~.Wk!X7fBB)@
SS#g={ݯ?OJ IO;XOa(7Ĕ0gw>3I] (8xB ~3%vǾqk]D;L1.l<4E!~5Gc#BHCBs&*>99uԣgJ)rS1x'#bTH1XCBJ at10:c5v03f)7WW^.]\]"bкoqBp@!@bhR1έ1]ڮ-O޼;)N}H CI\ڱ凜lm4ՍT%BHy{x!'CZK	ᄌvvhQB}PmB0ƥP*˲ټ/Bj36N(<߈3(%RG0E6fꢬf	\qޱTR{(!H	ጆb`J'#HiH@c$>d	(η\tΊӋ]fGnX"PZjQ)LZ,߾JbbheH);d]MIBb.0R\:"rƔ9$97o7n:>!cgw/
Rzl6:)WRGc^~ o\m;GBѣ*]\]E:!],?<Of"%	vv>_ZA}Egơ!Ȳf"ߏ@):ol4!d1[5mḱ d4B*:3"$;GӴ8ZFVRJYe?YRs1(%WRwE b@nͶ@ce8*gxvS!q~ܚ&p!&?a>a!}2;PJ+7ZR
-U &|E۪qӓs8x皦\(Gc|ZB1Rus]Քrʹ.
 4@\_7GcR Ƀ,|9}׍àH)<b~d</rl0dlűYRJ)SJ0 zyw;w{o΅;)dk	 EQEY(7ofgq4֘~״0.qSJ)=ug}&!Gިc2gz}ϸPo///q}2 Qt,Ef̟q۴muv[gz/q&EYJBRT\H&$@4uǓa|ufwu}}uuy}HJlB5H)fivE} b"H9'OWw[̧{cmYr>cC4vxhnnChqSɤK91JdlE~BdȥbfeLp!C$"wH	0h5t]j)T*
9HfkEB]]u}Z.b\.Ks0D(QJg0 P]>J9ޏ:	qv.!Hs=q.B)4!*U&!<T֙J견~]߷͡ZUTZ(˲1=&&kL7!``wD[c|
]>xRWrgsYeYVլJ8nhq۶no7vߴMu!L*gj^.r\U]UUR\ʬGBth^-U|:>?~1we)BB'r1?;]_^7mیҪ(8m}w}k_,9.V=fɲޣ4S~ZG%4~AȤi$)j>t~ssLҺx9AA8}9^~c̊pG;fHw16?5*=]߻Q1>@Fner?$Q\.)e,꯯y<ug\	# B:P(D )">;=s3DZkB08]h]CVbP" HG$,,/.~Gdᛗ	ahC=s	5LȢ(G\6 J\>8GS)b"hL;w~Jt3e$embUe=_VjU/|.ʲTJ,014jYiG$RxkReoj6?NȔON֟;b< cJ	AJR$΅Rӈy}L@m 	͝DI)xWm؈ WJ+]p*TQH RsXs60: E!TBǰd6S?;1NT%8>@		2cq!35Cn粌1fzHfyn;]!Fk8߾e볳by84]7 <b9Wxx1SjдƘNm#f	.=!2!C>[sF1jc~v}:g9S18:㽓RrƬ	n!N΅J B1L͆)FlNj$xsue	!gw B*Dc)aaRHECoul?~3!q9}JRF&Npq,A 
 04zur!s*ɚ3)x	/f\uf/X`45C1j hgYc3es1z7<]?̬)E+޾W/ Ro޾a6-sDAq캮	λ嘓  K mJ+D!%Fid`	;xgp&8|p	18g>$g]EH;K$JtQJ)W/^lwf秧g՚QZfvsvb4j1?6mƧ)Xgg/.^gΙz^-ϟ>)L\
^2pƮ6n?8㪔E]ԥV\5M,
RJrirr5g^l $Q)F3Rivp(͇aډNOH.1KM WœǏ)»woڶ{GT1ݮmpl6ácL3^\$e	%PhF(VˢʲO.^~kCӁuˋpt٤J qFct?eWR}eL&B#q.V͊TR	)cFs{17<%ȹYQs9b)2ʤӍqn;Y'\[{gs9{D@ՇlHp΅Z+8+ŔϿH!d8 Q RBi&nݡ94mm]eQVօe!e)%kM?0c$$H4z$Dd<=ᣓl!vo7vwfhڮ>$ x=r\.OjXgŬ*K](]P\PJX Mb<FkݎI'^?!u]d\e۷ooooG뀢`%!v"5)EJ)W*)t'u2y &yX5<  a.U3._+8{[:L>:rQt0N8{}÷K#}9	L3}Äyf!xO{GF&FXRb R\_ͯn}x~>͚V#zvVRf
oy'XVe)&	21ɘو%g8)$ @~RCkqb=IQ
i֧/8uvv6hPj}2kcmӶλR\>ƺ"8)IwmUYUU77vR!ggqcHYUBo- ex
ΎC.$F * 0u^W;߽HR
ɍp-cͫ/SIi%4})qF"PPJ袨ryvzVz6U5+A@9co59Sr^Rw$NSa D8e?%߾z1]Ɉl$dY9yu|/  "~;LrTZUJk )cbzgW'82wB9_#$%pX	Ʋ-)KGgs'@&%PCp>Fcgg!@2	e8 (>cy ?U7l7)*b;WhuzzBGk͐Ro׷{$K u?{v}H1K`BXSǔ޽{YCիW>F9<xtJXrPf97ଳF+9vc}51v/zƹ.GOo]S鲞/%2y3aBͅГ/?B6M6Ƙ2	mC(0>p&MJSfuPV7n#
b
 uhi<t@0JC$QM)B~41ryvvvmBB5ޚXc 9﮷jXg3fL
	);PF3o_ULPBp?^x1
YJ`}w77}1~?C1DH	s0$}M_|?RvFcLƳ%$D&ZY#Z7cJEZWeQֳ~Fic~7O'}9)e(o}_|Sh!}L>g|?{t'&`Ӻ?_3<yTu50vDBIR̇ޭs&2NG}rD~*޺J1}q`YfC		)
c4D~@pX.}ޖeiq.E  iw݀gEYŷ߾4ðvn~Ea	1%AB+K]We5WU]eQJ(0>[,Oÿ_a`3`}Boqq`}骚յ.tBjmio7zuHR<2Zjb~ln.߼nn9g1g͡9 b2 ңӤ|p.89ŝ3KuA{	p޺zf)|g}Ӷm{}}Xt!3.=·8EU|gѓg7Armm׷fLlnvwnc.糓jռЊs&J2ɻe9Wms>}g|y|@Bz_ZǅZf7m1?L)=J:%rl!b>1- ϟC* zSNZu!.j ?/UV⴬hSJU^}Gdkt:<8RrV;WO~<Q,^;v?5B	7c{R
\|{u!j\+WE]Ue<zsuu?4Q3%1o߽}CLI" Rql)$(5.a 
@J:gw>ČZ)>7%<^N9>Ʈ׿>x8Zjq˕f@Iwۍv^"*)Wxxvň]Roms8 l6R"ft0)!b&/y8vݬ*IItܓJJ1PDJY B!ĮiB@HKQΗr]-lQV,
uΌ)7CN$2Ւ25n̲Ϟ}^qvBbpCֹpb :\ȏG8ղ>+&Y3jUT\JK5)JHh?8;^zms8da]WHHތ}677z%4IsƸRUZ*)^b2)9NxCgBF21|v\JI+8yQKH8cΌ~󲮊|ٳKB H60×_~鳢(=}r, 0YYWe_ɟ=yYV_>D ¥2c氹"3%*
=wmbu]L8IA"e3	Ҕ~Zs~tλUX?01K)!Avs!\R+5Q@D| .DgsCr!q!qU)Aﺵx7l}mg8W4@icY  K0b	bH !(RuQ{    IDAT2"儲 <@) @qU^n4f0&QbkgH`.FcG<%ژq×!HuQcnon\hn7pss䌎CssceAG$(}$$!!eU?eܔZUϛc?v&xWkS<C687dg9\YB1&&mV8!D"@)J9g89Q*w݋d=
] !5vsӪwhZk˚QʲJ}uYJ/7jL" BFH&N ;JH	2xq S޺<9\W<!B~rYkmY?}(x[EoF@8˧.Rikжf\! B=EyK(-d˹V憯s2:Rf@SJJ)guUUUYu]+G7(!ЂlDښpb\mq%%!S4HDC2\ݏ!$m]W\j/(81rDL 7^6Xl\W~/$NMۦ  d')MKƐe40Pn(bi!E} 1IDyb@LH~4}}]k$Sbw:k<@m1Bs^̖eYl1feu!tٙn0a?{cƦMvaha1&ȋǋ|\VrȘ\ed4ÇrSKGׄ~w^Tj\|ͻkc=!D{gfXNFB\V]>5%o RїB_WwwgtqBNCAgSmČܕC	${ ޟcx': ǇI}*|[}M9;mJ=ιq}8BNJ	!^Ńcl6RVe5ƺ1{70JBR{"2L>7J(t&)D( 7@'j7!4=oI̱PtB|y>8Y-uY|4wPjX,cM9"!cd΁9؛7%كa0~fnkLߵ)e (r٘1 ǣD)!7:fR*9 }?SHxzsm!B)u~p a	E'|gsUτ.RJH9x,411jbC! 9B`'  U1"TbNX#ATRY笵`(2">(]|KHq*kfI<MH	BȪ颔Js.Bʌ!GXDky]oqgF3CJX23cvٔJReÕR!8Qp"/g[|p H Nf4RSlNt& NW_b^} EQdxcм{n}.r\q!5M{QB,ꋟ|>}xr&lvs}u9tMrYhZ$uݴM"&M~}{Er[b\%!$hRQB>j&T;c&8oXusﺾe_h$!BOw\u]T|ɔi㲄 ,;Pvy!]6;UESB r2g/:B9NVҺ`z	Y6O3Jhf3J9#ar~v(퍵Y(譵vta"Teka0]? !e=J	胷ƥc四q8cZKBnwucuQI)ubhfh!sHR
1eG?=;/"kj/޹mC.10JBx91\3,iQI1E!g(ŭuv5"rF8gBəw΅୹lvdH(G	1(!J*)ֺ IBSp	ɓwW/^/
%?/9bB)DqrN<fAK㈥w9k1$g5Cvw>8kADi p)kF3# EǊ E0B飋k#g4B;0!	@L	uTZEYWeYZk4c<c	0&(:"Y#UQhB8}jBhYEYd*U;aso3ňP*8юfj6A\x4e'̍`q4c?]քb1ܜͪ={=!P٩OJ)V)&BGde"qqR	Ï{]1 @bHH0!P0O1zfoá0C%@(a\dBf&

3Z,gʪՋ5g۾mC4]{h5~?Yۏf0Y r*]Tz6_,bZ/UQEUhb@6ʼkﳣQw'ZJ%\iۮOYYtlB&_(r Y~,cw?A$0xI~#A mJ3FEHw¤|1ai'sp?B?|.q?	L?]ԉL1֘$& Ia001λ2>˯CO<:Ƙ|EU$O(!!a(bJX۵v-1)r"MfAJA	^ͭ5&&񘲉S#4x(ED	P}934巯ƮjXon>yv]no<?R @lׯ d>na	f.8(@B[IBBL8GDݡ9C.
z3e34 mnn |V3gDrօ#e|}2_|>Lj-@0	)ta"dB b"	0ƜG;爼YkR%g:״M=	!CLTMC
w1砘 \cFcxgҖ EYWJ(-JI)syS:)ðX,>_r_^^޴͡klb
]vޓ;u@B,.J!%cR!i`蝛2\O	rJ 	Pr4&eB.89@WO<~W_9U];x5֞sLRl!v\_<:?1] R)g9oo_e BLJ)}6bv>޻l	ŹZgC{k-wR1^jƨBfIRM;kq$i$!/_UG?U=еmi1HYI0!FhLpL)7Ȩ~Ʈx{\8HgX.-n$HR9% D6MFSTE4Y'hHHB:1RHrFi"(gf0&T,7f,掏cu`j&2RGp8lnݼ{c	8^^]]ΪS4ArǏ9cm7X]S<CL߾;4 nzTR[	}\pvGc'1+Xl)FLa)Ř(eRJdf~`u{!]Z[cm8c"">~xZYcV	Iy^uHL) A,x ϭO=,x!ב`)	FbKqt֦ƁQ#A1YkHJfŌPAVsj5QcZɘf4#:	 $Ib,~;/. p2!ۮƨqJuU몬H1r@(e\2Jr  I\]j?yPh{!$S^@zcfw@p
ʲ&<?kZv !F ECGl-Ws3c	*Jm-zb</-L% y0L"GEJ	2C4x!
" M41ucwk3'/GЌsT	&8SRl>[ֳz^WU]3p{v}MM}u]׷}gb$ON֫d=gl(RJ1	cR2%,M2?K	Nf8->	ͯGf?_$G'"֋ُ
9Kۦdd퇦90A	Jy)firΥ)>}Ez_GGܞ?>HIF}zVꮿ_(jCBS];81~F܅&Od׈ȈAG3.2梃ϱL'$#r $Uגk,ydeUu7Hf@GEzx?[~,E|Q qq"oώJ雛]ӹ@4a 3Bvw6xW/?ᏔRq7<zߴe͓'ON7J`i9;C?'OB.DmOx4C/\p!4"8G8"1C*kSOp=꺾}z:｛+{W @]~lnojܺgϟ1,><wDFO*Zڮm3Zj8m-rJI$CB
#nmCft&/$	cJ&e묝I^-Nr9Y-:_ԲJHq̖% 8"k]eY
"b!`wRqnr DNekd/믾/X7O$rHwApB6NfJ%)Tl	EYB\L<+JcRJ)UfdyES(r.9>}$9i z ~˪̏X2|QW.J){go5BH"ҥ_MmP,+&!j68R>!]_^]׍C_YƩղ>;;Unw`Dhyޣ'[f& r;;}?~x ڇumf4"7__^1dY~u*3ZK%8&kGۏ :7M1Ht^[m@S| "g-	NҺi\YzgUWE~zza8^iHg :kaȴ\ c!FdB)f~?99
zo1Γh-!rswXt{B(R)6M1LbLjqc+ @ə"pƤ΄2iK!< bB1cۏRMu&}qO>퇑_n	@`awk bx嫋KO Ջ^Q%2u~w`m/"Q$ً	zvu~Gm(ΥH@g0aqLys R}Rp-|'2ۃ	dBp.)TZX)0$1X b\09~ Bowc q?<ϿWpRTB.PpsCDιacf BΗM/:7Z,4SZԘ5RX8}U1.P &)aSF p12Ӎ<P?]=뺦m  sqiPB0\=ŀ"9p`(M.A2LDك`C1xS<1 qVdyYXMgۛ6z8<\!|&@#t ˺*Z'Oagõ^̴6F+)"yYWEZB޻! @)jGD&]Iɓ"OC .c@Iţֵﺮm!p1q"d\+cEQgVJ&kuιsa/v4isnhovMm׍#2cbZכU]/E]d*k!Rr)SGd4{M;[;enw$y7|#D'8;;??~C8gP:qn- r!C"2_ DVB|!2<:m{<_}nL}xO<y,L#lZkd;@i!|)dU{z pϸ"FN)vx4;%nߴm#B>e`<1gZ)8JR$8~uzZqBH
E
Rk	cژq"JKUU]vFEOݹ,5h.EV x;Xf@D(t!\_,NJc{=p8xZ8V
<i99cHnnÇ//.q1#ZkáZ,a.$c"	1FF9~SRf&|SH!&8N8eY8s֍j]/L+m\T ni%Uro9Y9p׆#|C3Tr1~y܎{M$PbG
&Y:v?FVk>chYUU^T\*JpPc2c2TR< E(8?QD"f%gao\ۡcJɢ(7䤮ysCQ^V5U$ʴ1+
us88畔yCPBo~,/ȕy&s&WE!Rs8x粢<Yo DJ!ˋϿˋi͡Z%7k7z4!H0༥֎wq抷|~Ι2FpC
^JYVUnv,Ե]YfI~ǣm "*ui8Sȳ<}Jf@bj*BDc$C]ׂdmӴyd8[PD]
c&yTKcټ 0Le""
>$;rm48~&qƀ(ɡ$˂GfSaLRۦ麖!7guUŮՀt"" 瑩 /X@oovvwB]2˅F)e{qV0&9QܡΈTK9#TUY jQk[8+,˳fެOδιnwۮavt.(	p'(&Xjn $ȄH|R{RJiVJ)!A&G1fyn[a2C}B8F[O~>x~֊187)ي&i{\JrKSa#J#9uyJ$bLX!6,3U?:[?1YsڄE βTԈ!x;)`#$\\ߴBLkL&tVeKkbH9((|zYHε&I'D!X8vf;MɦjˬR(,C  H..(dJʼ96% z5_w'rDΘ\+-    IDAT6Ӎ///R $PFi{h_]ݬVE}\>?;fZeYyhΘ9iXb3Df$WTf4vkkqaw""hBL+crS&/sμwvnڦms8ݮiڱi:bUUTb\Vd\-M36Br%Ɇ'zuao>7GO|ߟ 9	)?X
ŗ@¨!v%7YqO2J)`_q>~)'U;Yg:ח!G>ʥ~{뮤p럿0\3[;]_Aߗq
O#
Ά7z"Jд@,lD`uXSٛf\Ns>BQRps1R*d.C}*2T^z˵c`$w۲,94m?JH_X8f0s,	$x[#GmKMY-r; 85M˸j"'Jr:40\.>|8y~OVC?<3Gg0dGx!xiV))C Ɓ	B&ޏ%
Γ>,e}rܜ-N֋媪J*1	kη8z;%q»ˋwcG$!@!j"=#wt)t'(*蜵u(+Q
\ƄȤREQeBhåR:S(<ύIy3fH)jf,:Ht>~+Eٜ=xd}ZVR*F>Xk>q&_%fZ"Qqa%X۴R^Ȭ(bh8D 8@A@vydb0y"	!,8>s0lc/5qγ<?i鞦pݾ~Y{;;r0YYVι뜳NR?	D8N}>F{ RAևگ'Z;!00H̲!Xmzqt!&'gwB*vr,
TQɇzgLd.&WJq!M$d) BE>vwH<%8G @%q
+hc\&(CّwC3͉%Ѧ.s{u)(q~L7	;JD!D>< Fd}; ;7C|=Bنbvi:fiho !V2p{{{u}CJ!mӴu]um}#ɤ̀3J!TBJ-˺,WQUe]W,/-<3FnmMMiwL>#6_yER(IX0u9IW*58"C0$OT2MN$9#9ܕ.BQJF~}vUEU0T '1 asv~C!'#Ap!D$ԘRB	 r8vs̳l8&ƄBd1!% C"JcUYp&1䠐#0bdBs2"!8sJ
)܇e]e6k3ﻡǡqSzmɣ>8;DJeNb2HSR2]V{Dc^+5c4Kp-^ggM\_]$4Y@! RpR, 6(]dʒ=RH"-),J<!zrs
'iP*:>8ｏĤΤfsXd󲬲Jat14vS׶Msm6M6CsC]gDRJgE^'Z,"˫<όҌs!0b<h_wnxNGZC}WB<xHݳg=Nh} $R>
\SLbѩ>bӊ90%=8}&OEmN8ۿ;o=mߙ3	CH0JJār(d".geQ=x'$?7W׋Ų(+y׵,!z0΃vVeKŅY96{rPIzȳͳ	ѿEED ^#H 1`!1H1u}Xd8ٜvw{sY<znZ
;ٱ-1 	<d۱''jږ	Q׵&!l.̼"Ύ \b_ H@Ɛ&ȓR\ yիva<ֳA)\TVb`X,yRI)1Θ\YiYE(0:N"iA3"8KRp&">;N֛EY|g^V8(9L bd1k5[wMIiSJeQKi2362mRMYdRpTMBq6G
 ZǏ~.=yi]W>X:~+㽰PҦoVJQEDt}fWD?y+Ƙ6!BanՏpƜ)L Ͼ1	,ʪ^,󼸽mIHJ9,0`vzq!0YNuvM5??YkV sԴupzd>*Lvwâizq43.yfUvR8畒Rp*U.x&gLC/܇8pzӸ^]\AJҌug3Luv$.PFJ)
$%"cRF 8Zvl	ĂJkb4mNJ3Ƒ\qR(yf4&K';M4Ecls]b:Szg;o!unBYDIA'ңm~v0M B	kۗ/^Z.''EYEѶ4R*C?D<^H.&K@:ʅ^\\m'O>],gكs<oO~BJԘ}ryW`Lgf攆r.RMu]t 8@GQ/L猑1\=`  
!0X}BL*!DΠ'?o??>ܫ&!ĝc[!pd};Ek'nH(Y)u~s1yTL}⪏6kmQ0Ù	q=a8rνmMέNz8	l́ӌ7L+!r!D(B]wuqjqá8RZE]%zsZh蚼(( 8z}c5:"ntW^,{ɺi? iNLj戩D2qLl6OK١m⋦i*F"꥔ژ$nO<zxZU	#5"sQ#(622Z!1a2fnC7W,/Y(B׷4֓KiEU/^˥ȏ~5C};wvimyD,ˢ6ɦZ.,J9R P±#bGwI @-cE,:B0[M7"Ljgg#7//TUUCv`xu}͑d\ Wo-?=w=juyuUVGٟjUU 6~ŤT'BwMJ/myt-{}*o}%1 ǳ&c1L֎Ą jN?xY$Q@bB ;;nk6Frvȴbw}	D4<RBɆFm B^U]_n @DAx-у%+#a4,%CHvnuvmp?ª*2އyw~nߗ	FF
̬?8t"0XT5 C!PB0a}RƇ9wc	 &
d	ϔ~ыW7W7777:
U=9{0\kōG#PAiȳr9/_p?&TlZp$-~q\VYVg_yi꺮"R(qpΊ:͵IFI'#;"J"dy"&ysJj<Qiw{&D,˒\g]	,YNrT&Rpw:Û?5;X+GbHDCL1innn*oJU1$ÉnJ8ea"EJsKBz?=8DBk>NJ)IVq.i$DA1S 	yQ/<rDDa,<F	/?2b	 q|EeEE\ EӶ8]/uvwc1nxH4D
gɭqɘCD)~w/	,K]]]_umJHϝvŘ@ƀ2Bpd#wf	UVu'?u"ZrG{zvz.U2)*Ը\p"b'(?՗_9] Q2GEY8N)\,ʲ <w]&32}}uuZ-eYC6\߼|,
mskTpkz>ݬ-/._xq{=yhu]UU^Jk hϿO>싶kJk	brT/|L]mȀq<F  P$"
;bREA{uѸHNV>:R>!Ÿ|7/~ɧ''	]Hi2IZ~qdGx<}@fw$HT}dSYeuaÞN(m!2s.B HLt{^VQrx,8K,
Sl64O?o~,<# d} ԐBUU/j#*7YYdLH"!2#8ڶX$v!b\p1qxOUQ,i}Jhk`ZsL8d]UUQEgZm!,˪f;;॔!0ZwG?%EiۛaƱzC$@((eY*.bY˺R*UbQF8~0R(),dF#5O0vonsqH$즹n]s84mgS)P^,j}\zQVr\UYR)Z0?`GwdA`KO @TW2uan"A=nB$ ߵ<r/V?ǈqRJF7~"F$d<
mkRw;7~ק	g!,??y3_?3S,wϴ0~wݭ|nGa:~kZXOPonx?1HRd@1Ҙz1Zq*N
@	,RDjo!x"i1!qLČdM\\H'ZIC{πBJ벪	|xx3ؽ78=D早$C\]y&'=iɑ3Oi[ιLHJYv\6g_F;1IX1L}!pb, 	OEMH0hE#9iRl6fnvwhphUobeMJ1{l'8cO!Rv'_<4ȹJ%2ZӉ@t}s-BwO?dQ/6gu]AL*=}J|I$x+0EGTu6yaL.\2cL,3*d$:J;"%kBHRq[!fs<"i4%7\Ls	q[9@qv2G܏ZcbD:˲uv
Ce?G3ƝsI+oۦ\]>=ҋ'U6yLsBdbȐȄjvk8"$-+)DkOŔm./.<|XUDJMRq~N#dH,QZ 0Q1##l.Uc\d<1q! ]^_]BH
11"rƥ>%Ue2LjPc8jR1RTobb^'Ym@1c6\*!2xcq&Ɣ(J) 4dnbB0zjYR*4N͉|v7c晟  ;D,"3{gY'8;?lΌY,eYE<{7_g7$\ dV^c	!VJk!2\@|ECIA4')OS6{#b!@"^0p'E)Gd=?uU=؜mxUV
8gSuRDp6$W&M4}m0h.ŹwJ!n_r>YoFǾ;K03JN Ga &1FKZ`i1 Du_O?5J-:y!!hɌy"q]oNT]㔈B!6T:2m"q0M8ucזeU׵ɋj;뒎r,C&DZp"ϲLAD۶mXVuYVƘ #>Guw]bh~;dɆ'9r	Lѹ 09veEQ9,LfL2Lozsc4y&SYaIQvkׇvwiJ\^URcʢr:9YrY(Yǁp?Lu/8v(Uñ|?$" ]W q% 2.4Xq`ʍ>tsQ0h<o?_v'9?i)b)|۾6,|77ϊiR~/t{oww&	go_vo=c'ric2A)@"!d@8Y'9Gkyf:B$OBDD"ΎÐ8h<|Եm&./	d:7aZs^rYldg8y<%ۃ@k	`DviÝw7n>Bj<ym>ء{Rp0EFAJ)RAj(D1K!w'pmGPL'A%^LnphzQK)f9{La\njg9b&8 2!xsͳcRBJDN1$cbÞ i%EBX39t>|)jWlZd2FVV6jF"r΅Kqs&uDSZbB    IDAT rfEXkTIicB 2.xJZRhU2Ji%b$C쭏(ʋ*KcR$=$@D!`Y?OiQ(GٻWR!Gx.%@k8K$&}@Vuqˉ%vvB?8JdS"lN)$c/^]KsBfGߟnُ JJMQj"fc✣H5I(~?ʹ6DbŋE\P*3fn[U%g<&CR )iaI9M\JL`z"+TMQ]^]^!H^qf&>i"c\
s.M<Nd( 210Z* 2G
IJ4`Z֛_{$HƏ҆h3@Qr^U%<"@@Ap1Y;1%q#+\k1ۛme`K '<CD)yҳbbQEBgR<ϗu9n}W_}BEY\. xnz8,7JjBڮK|0ѿ	q8p@1a,!5(B)2|#wN\-`].~oLm1vLȐ">w3{[O4cSx@:^dł-'of{%h  dB2\]6Z	FoD"psիW?N!',*si<3UgUY^^^>/b  3Zdأ2&d,v;$Ƒbu:;mΘ1(KbM#	΀	ƹ`Lr'u]nGdU-RH RiCR꣏>]U/./a!rI"rcdJ$'*8dx9\C8Ҧ,B"/ 3oy\rdiCpԵccu]~vMY0.bl?bQWŢXTyQ.*!PZYG;w~1?p*ߕ  $		Gh.&K&|Gw{3
"#
)H8 DR~}̭4M<+,RH)ď7>iựGB"3'_>//䓵䟄.wA i;,C:3c6	w68(c/dw] xb># FȀs!"B$o@QI\T7E'*
I^1L):}]W7vr>q +n71ʲouFtYf#6F.f#UMpSc+9Hpf s!fsdVzԴM!D?L\˦I@b#'JAdq
C1?:lq!?y9䈀"cS	1<^p\0 mqh& F
%Wу34ٮ/./EYTj:?;W')Rdλ~;΅bgٚۛiM.u`	u7!Fs~{sno!:
~1$Ƙ~})L0笷L?a~8"r$Iz3M
+J*-4)1\gB y	 1"ٙ:1zo۶m+rQe<PNNC!&#g"$
)¬q`D[$뮔nom^Jk
cS;m$j0Y|)QpW/}%R89Jt{U1EMD8}]OJj{ƭbr>WY8&Mk1)D8oLu9!$ۦ.//"lN#BȢ/7ݮ(ʪf))J>"p$axvLH^c_vm,K@I'`,yϲHcZ)%8sle;ӿ'!-MaRp㤐uJ"2e뎢%'!z"I~\-Wa璁βO9XYEYE&C
6M<C1h8UVpwm@Bh=ۛ>qeb眻Z[ ,$I%`9?s8Fi3譺\r?ܬngg"YYw9o~vYrXYҰ*ι|qqvkg믿f6bv`lV!"eFWEgBa3ԦҨ1(4(Q$GbP)2cu;!	M>f!
!˲O_fs{[uu;ӹ6@%c>8C%&i9:w'yZxݭL#"$:"	nFTjyzi?: B
@ 6M_nFg~ŧ8;;/w|n1}.rckfݻ7oފ14!E
A*rn^7ՄTU֛fz6/*S_WScc߻qa%ƺNNNyf2AQHeY16='DTZ/r"B;7{?0v}ߴG9J*J&
_~e]ZˋI~hۮzޯ׻fҺ(y=_lV[,+R,ύ5
1	y0z,ĝDHdOOi$yhHM
xpD#y<a*$808| "KY?~޷[0_~t[E
{:bD  GL}n*~WOGyQ,ۻwF|>o'|eKI&L?QI၈x3t,M߇|,	I룞A(Fvcou;]ݨo߮v3_@BDa	163Z#r0nceιm*uV n{Efg'Ih>$ ̹޻R,	 TA B~<7pJ3$"#j˫fyٓvmBH)&/(C4BDu<#_?~[}ZJ[ vt"K>aI*B"H#jc(pnlqONʲ4YFi@$0$//E>ҷeUUuYEQh+R$}j%Q$DE" {h7mCp}EK/fum;9j"iʖYD&pR) V$b<!&rmm֚Nɬ" 韐EY.Kgc!vnoF"4*9vuO	j
HV8)"${7>B`JB	0URǱfl>Ð(.mv]YY¡	_f?.z6f(i}Gu]ktze 2ABtnLj˫+紞/Jv.x/U~Ȳ>x4hֈݸ==Y!"xsfkԸ)	`˒R
`q<IpB%w010:#ĩ -19YLȧ? "YkᝢR4m !C#+mVg/_V9CH&jZ+E.fd]!/x#3N UHX(2sH"Ic{Ork,o_JQ]W!kmUUD4C۶̜jQ*	uuZ򢸾QNR,bWUݼW]׵}ơVdlF<&sx-ViyQdEQm%FE,b1|;R:Uښ0,ˊtcｏGl8Р@#HsK$1hD*F1Z慹8Ӭ1rJOX3!2F? JPpą<a '<"ɼt캾Ǌ%g}?H7C\+m7e=*
8x5R(,V]^__߭q<=;}<,{oi&ĐMΊl!mfͻw}v߼|R+"<Q̱G쬚Pn:hY,bB2cǡmnaL&@;NM|H
?9₈Һ,򪪖EUUYij&9gǡiۻo@Z1!,#mT"&%Pc{]hS	 QyEY]/ӓ}ۚ>\]tMm7z}nM8Iꙴ999)Wӳz\-Wr6[Enڬ,sBkRjy$ģB (O[shOM#tLcG\- )q)'	1'JD$AD>LpDR@#{}#'S5"O_}w4]QBmn*׳g6/K${Gg} @NT|zfDTIIUEߵ]~s{orWϙNC$O?AKu?XG0o}c |LZ'Ж G8Z|6g·50^+  %euE"%gY6::(e))۶%ۮk),be۶$   NL A_txdUƚn6Ynl7 (̃pgZ	8R-i	}"u]ӕeϬMvŢ.r5+yC_	(Sa&q?P an{ss7Ϟ?{\)
㐺yQUB{	9Ea8Zá==x]s1/G10E8r$D 4`ILbf4|cn@!PO>߿ܯ	'r  ,1tt	eQ&t)"!^&zH+,eJ00蜋1x0&#K"PA]dG9K(4)	 (c8 @i(u~$rmGBXV"?>QhPy=0Xk_xqv~XTđmBeY]7z1ʹ1bRԙYӴlm)(D<2kmW*:$s*!}'}!l[cTUUZԬ4ah%#JR;I6Cv!D<(E0^m@>zf甦;IJoލq9KT9,1Ƴ.OyBQ|?<J̒R&6{Zb>FL|?DiHq䩛F0|0ci7o1ϲ,,S;BLh!~H+"$er`Zi<m~p8U
*xW2E[m!8n0eɍD!(m(2vȨT%gF	R9rd,!D}~,i'4ƦG|?|@
@$P|8	߿^o;OͺG珽;B6ĘG	|G 8 >hp|? 9X1*U3G?95$}퍱J,Y?<X, Djif^._guU:7ovVht~Zguasqq[;o~ۻ;Jk93qF:999??_0m5]٢Ҷ(򬜙?]l}솮~G<5DLnuYdUUbQWT<~CAk}{siYo6n,v&>Ĺv	jBJ+F+cLlc"ʲ(,ϋ"rQM W77$7ۮk7D=_̪r6_.W'rZ͗+[En3k6$1m >ڙ>s 2>>
?^ñ#	U)pLUSФG`~1wd,D IV! M~P0iMųs8P>u}lolVeF%?.OuSɯDj,O1A
wH|w}?0Ww˓E
WIdN;`> eDl?1oJ?c! tr<|ov]eG
r|VZi!xL=_!F1fy53Y(Y;!Ȥ 07f#3O!͕2GuP|(|Dr>`~^9)2#i[kDHJ E1CqW_}I*m<YJ٬ R c$)߽ۛ}fu[G !K$B $J۵g_zz6~F= FbVY>@s.,2EHi-)y@s"J<YBPƒ B ;c*(aZ/ϟUQXo߿7/z߿}{ss ic
d-.J{CˡMu;*"xX)ɴJcZk=䉜< z;?la,z"@ PN&MZD;RSJ}BKjHD"EȌ@2:=r;lҗ0~C_};ߵs'IPXs`zX&͒cꇡoGR|o7%ZgdOGf@uzv7o\,I]M9}]u]gEQNQsJEђ20ZkD}ӆ   ƮmR$$}\%3'D&BM`RM<q6]O1y}I!]6 G@֨nSj (ɲ,3ƎYM\*"u/JiJW>م\aJPiTZ#(meQύEin7tt(<[#ǉcBBvV_o3c"6#"1vm2KvsFp0SJA<ϵVC׾5y~zq9 $<ˌֻ7UYSw]{]?:k-yQfEQ$J"̴ލm?s(ʘ(ʳ{7D=PVɒ6:~C$DSTZicͳ(
7nAYlthc'cё1Νv1
#s	jD 6
bxM֍4B@>&'q#G@DW''AbhmA.ç26KU8@AQ"w`n7ʬiuObݾ}v|ًP    IDAT+y_??b; dnRggzioC!F`6PVb*}ݬ7w7nhm׻qp0|HlJF,rQ:˴͌V)ʤn"}3W?{v_}?OwMRW&Ic~ |V.b\r/I\wnw۷wwo}3?_o_ߎ}@
yY֋bqZ]\^<rYu=+f"T'e4- Jx4-"  S71 #`R>\D$ P&*Dz:=T,B H%#IA$Ɖ].zQƒR FD"H {t̉	/O05UQHoc..Of2ylcHHCgH'$v1xZ~ơWn{A  M?:c>QYeC?_5	NG<8ҩ0UWW/_~zs}+ʊ2ϲCdN"Z,UU0:0"\NYǮ̼o;:&<Ye"*eι`,lb $1YOTc"dy6~_:g:m,<?^vF!%C?FU\.r%xݠ)j\=<z6[W_t]{wo6t 8N"DeUύVeQ`J@Hֻ1sRy  bE?~8Ip5
) )e2#"XYbT$B0I'v$]},._勿n7o/뛪hNe& I4EH-"60E>R*x7MQ"F *FV*U=  (: vH19zu/UTQ8t?/8r ɀ~*;J1,=X8FI!NCN5(0]2Hw)g[XЅ)NV߿a C,ȱOD$,*C
J)rI;LXb_iMfo괪}R5)G!"ff?=YYk,_Gٌ>]$Rd!|V~6Bm48k.W.ƘrE.q-l1uX *)jc(,en!{7f L"cYG$uE 
@I/DnszkF+%YL/@)>a@` 뻮w]f"TJYkq栌q%5aR-N]U0f59yV*0ϷqW"Ϛێc@7}ۤX*</iEYyvafԖ)M@mF)u_K&,G>	8h
( LI;]l6+lC=1xc& ZD&#"!r."U_]}nONOONNa(Qa ($a/ !}6eYڦ~߼&l^䯿}s^O~2:_Wιr;v!aJ/Vˋg/~as!p 󪞯r&A`|neYUf7q8qt~!+ b!cJMZ)$@Vn}w,3Z^<O_f~΍C`1j"3Y,bftnMfZkYao߼nَ%B  j_|۷o֛./yYUӳꤞ糺ʪƦn9)%3ZRG#h(
H!;	%qJ H${@JNF#e.DQ?8L<AG2 A8|ROe2AxBuq~L	3wX҆D"mw cSdes2`)Glwg+?He#  T#)kvw&yn
CMޭY??v|,N?7ǂ4?4=ЏH~pTv8G?8>.	Shr`Fc<SJW- !& Ϭ	"ki\uD"K;} HuyfYf $%,.˲]D̈g|>YGB fP醐Q	#~4rlʧ
@k$GafhrJpwORO޼k[eAyDZuv!A5_(<1$Gon΍map&ϕ幠B"m5e(겘ռ޽R*ϋT RRc*Xfdi8:f0+R&ݿ"uc
D)o6AS$LrͩYA H&cI(؈ɳg痟W~_B@*Z!$IԄEX%\#rҸKB1%xNR<0P'#0a OʁSގD~6wB<Iq)"9ȃxƾ뻦kwm;8އ<O_fZ]p|	|q|Y  0daxBptp{sSy=/`NfNH%Tv6zgV}J2mlα+\ℚNʜ,lSS
D"d'A粹_ue1FE^8.JYkHEQhB~ߤ'/RHJ 37 1FHi|.P81/
43owzZJ'L+0xVw RΑ@M^e]VsMC!40&ɠpN|` 
G'1ZbCCkLUFowwzaBu0Xk1"2n! BdB"EhUe\+lonﶻƻc"26c1̨Y5CDM>ƈ ]pXe`L̲{Sh0 momO%B4Ji£0z%U/`NR*ZeYR8(D=s5 >P(UR7)2eRm""C*	V̈Qć?qJG E8ƣ|B"2JOpBC y aw#siv[y''RZ>UDP	wj"Bnl6TJ7~nWji[ BއY]E!&A)yU-ΟX_,&BX۬(E5{?nqz i{&Dinl777Y-8(~żͲTeYEQ*csѻn@|0>0LRY^eYEvz~yzzAdʋd싟,W<+Y]UQY^ZkG}ڏ:-'Cp<cӟ>aAR};'H2'``?" `J&ɍH` $>]cb1ʘjm=DT6`۲J=49eyq~vWW2moϪ,F'9x愨 @ !1ʬ*gٻAdtte?v<~Ç<>C2aLp3sJU"V$#"V˯Q@R%9EU~3"mh$5qc2k(H }yvZV6ă7'tABZ<
{DtB	t89&VpsnX(EYx|8jM1nEf4gBl6˲vе7Jg_Tթd8 w0:"0YY͊?ϟmma )*@pΏXyQ8#EEQ8C	"B ͓I.# 0#@OSk~}i}1?9q`5'X0I8G"YydYѧ[=$yJ'/?}"$FM93sȈ<8e5{_6sLT<2Q$qIIidB8ononnOΌdqCnqv5mmۦ뺱w!| ȉҶ	u?~zmӬwEY|,K(1 8Jc0~(D2\̢VDK3C
 '5rw<ID!}BfWd>6SEQVQR,Q@3QWz}s}-JQ~}w}uscRJ1(Ż[kJF A$ WPBQ\,+LJ}Z+P'O ˟w"ltҐ"cA*˪>D!ƨd~jlYA%$LP_R" XLBpVۻtBŏضs*+(wmMǄ%d)|1&͌ط 'E<euF'/^(kfw]8އv98YNۥI܏ncfAĤkqj<1T9(}$)C#E ha]A8Dя|@DP:ϬzcbzF!d},!.qP88J2TQ&4A#~63'<$ufyՏa	 7bUI]B#I  (LMQ!хF_/66]ufEYR.D"U5\vElVGm˲<
d :W?|>/̑4RFkktN[SEwnǡcc!r80 
iڹNt  H矜u}U׳Y	}~MJUUX,L Xлa~E17d9/LnMQuU&ze2|u'ʢ(O^4/J`Ѥ1

LaEy07yUB8>>Q&XoK?|zSS <F)KRw̜D˒ǏFD 
cק|%B|"WI}G}fc|z9ECqpھk50G?tLpP7~Mȱ~bH.΍"0P|>F#
OQ0z\q%<d}r
T@P.1shop(Bx%?9)mEDq1DŬut>FȠ1 X2D'_cM;6f/e]WҚ#0L,vx  <ʲiѳֆ$$"(LH*G  ԣ|?lUcy̭5+ݻwJȜ=ąxݛcbD8<₈FvnK,ͲpgYg_\x76mS iy}yvzvzm"O?^__^,Cя>8׵~*KmbL: PVspww`1sx KTQ''&_~Bn9ԢHCQkUVl)
I=^EDeE!"f/޿o\Қ9]"(c(")k6&EI6KMJ%gMҏD#"!Hspns[ՕևȾw΍>S=~ڶ~э;>yM~sdNXÃA:O˃6b}U
$ᙤt6wvT;7}:X[0	%""QJ*mJi$dܚbwۓժ*c3a1 pHLuҷ~/Mkf>tWUѴr9 ;oLU>yȲv'1&TPv<6]bTz #>b1'1D
"Yf	 |-?}]Wlv>@kۗ_<꺰,rT 9(BP+BNzN8FsS23Zj~H@B~aO'32F)Ȭ1fVWuU"R0(eiOJbbYyQt[ү>{o"?;Yjynbpd,"L]U'jX8m6;n{}svޮ7 gv1mYJ,1BvˈTJR	Pi ?/>{ zS.J hǇTq޳  E	H5&%Lހ۪(piG0Y&CYtn-p2@*JpL0L-	Q"y*  Ju[7ލ186ނ6Y?OWWzwDBQDhfJh1+<!rhJ7=,ˋjatCbY_[.N_|vj2Gd "bR	IIF711*9BWn>yi齻#˲̫o+ @3C\y1ӪȲyU3$mڬ0:m}$'aߴM{#U}Bի|@ DIauxJĦ@0UC_]$Lvv[}'ㇳ: $0=6GT
 קHDVvnRU'FHm@}(gD(Ȑ4!kgu\,˲ ݏu9Zpٲa`yUTMy1aK2ED"D	{43; C)TT >hz2eYVU=CBM|(I=M9RrD		ќ"w0d xyR8?~$|>|4g$1MBJBa̉\Hum7eN$>9Es*H(4gEEPu5N}6JBYH亮F0UF!Q(i.'+A%=[-ɚ~[^,W}^Q `p
*O?͵5]Bt]Y,n{җ_IRA)eVTYUlXo﷯{+fE'/nz H( ҷTiC8FWf,B˲<||xQ''뿹Yum@2L̏U7D"ʋAx'R&O8hMGeé,B2Gb,hos}ȳ	cdByLL)RQ2Z׹-)Kkmf&"J!<[ ,6 eEVaжv|!DN1K	rN
"#N냻:4ܨc.6"    IDAT2پR79"had]wmf-\8&ysV(@ я<O*	G%} " Ҋ RRJz6/"rI Ckm#'(q񸿿/|>EYq~/Bkm7ښveY&,뻻mѳ<3:Gv&|H-˟uYz7H{DY5-櫓S\q8;;]-~ͷoCge,7޼w!晡IXO :?e}9w[lVWU3e	.ZhقG#Â YeHNt[uY.}U]RPȊxދ=o1#}
>p)b?P׈B0Y9^ޏR10Cb V,\zEsAKU1s(%:uðk94Z[c\Y|>J	!yv?{9 Ѫr*ӓ[E=,J!a2{\.^>yvU1Uu\0),>W\͡;"yh5$ۈ)Q)@ܑMI	pIE#1G @kBDC'!B8$\)2 )JIcո[8ݮ'}LcSe$;
%EsSFwr?ԙ (bDe[>D!6kъ;7(1h몪s]׽x2/T%b𷷷]ܼxvtWun	 Q\M) T(ʲ>|pÓn1Zbxwe(
%uyeo),O{+/ 0#>}o[ծ%%`0뀒D9F g?@2Je:)R))$2SS>R zL<,bOMiYz&46 0rCJ%r1_hBpG!1{qidvkow'262b>c&N^ụ^ּ+|?n@I!DYZiFiX[T˫prRM&iQW) ~-8ʮ,BLSı[/$]8Tr?8 u  %ٛ8c1 {Me
˷PJEL9,/gOwxOk>i0_:Go&Ɣ(eÌQ>K(S!xO1ԭY{MJ9x8R+-L!*f^+BT#MUOv4$ȵ8sZgX1܀0[{MF( @# ($
~Ej&/9%!DtLg|CC}>\R(0z2y_?v0ں,rH5Vl>8;gϞmf2 R	@)\gwh%^Z%%sl6 Y# 5<|8Y.B q>=8ȻD<KQCRiH4*h{$!E	 %08R~PBHĐ1|@^EHjٲpMlQ_z&ꜙ$A 0Qkc9 /FyCDq)J!nv[\K102FJQ	JA0KQ!"^&iR⴬jkm"P!cJ"r)WbL>֨~vÐF
 YReZ+CL"l]Q]/Gc5vm;eZ}J(HR
!n7ۥLctY}AE1ch"l*v!z)FWt"nVڇQY,餮vGf>z2x_5{,)!C֡Re?&)~XWU{j:=4~^b
qPZ^z5}s@vBgV*aQ~Gr$n'2E&uQHeeiwBJ 9cL HJDJ+YWu.xY''}wmkU
෻&.M
kʲf1ELcHG?]^>{_|_?~v1xJcL1C1v],Bj9`p
q"$:Η2(Ti)QI012OL!,loo] 1k!mi(EiIQ8Cm;v۵mcccxi߬Dݍ|(S"SVеPmw[kͤeYBdzW'cfbrL*sݼg?>&J0mc0R|:L9"1!B HD~ȥe,*]599]ܟMcwAfPd#RL	r"!82@(??䧋f3|46&xjt1
4A	Yb:ӓ`Z m67W/^ڪy\vVfh9~)}'C}\. 9?Ĺ8^(Mo'2~+=r08~^+?h}N96r4  mmYUH Qax<
"
)'M^+$QRߖG%C{QD4*	re?npYS8()U(~> eտsJps_"yaXDܝWnʾ80C
g'B1Q۵o)0s`/Ro0vJ*]%}="*V+bmVSTLa`"dqZ6dm(lFY_oX3dmQ0D<O)<D,ڬP8߮Cai5Rt6K1Z77-:{}/>[n'SgDR勫'>>ޯ{q}ݵݻ]߹wɟ'"$MabJ{mכ]	+z2Ye6+sUCB!˲t9
v3C)<Ysk_ `ax9L)y_(AUq !hQI"b̀_xbs#J]|kYcjb
1sU>s\keUד)JvrTIkJ)E?KU)ɡؑ#& c]o׷uU5uNH}J)Rd-	 1G(@ǿ%>f2J(P,*&RvzV !B$J)"JDȬ0!F!&Ɉ %1vmQR
gQ"%kTa(0(-7+ʂ(bDiݕ'֨:hAD?|(Bu()@fzq5it2?9u()%$"wf)08&tm5|oo%&)n۶sJBF]qdx!JKчX[!\KDJeڶ]W?WWZ#uRs zn(	9R9S?1*m% lߒNiu㜓R=)ǌj:mBJadzyٳ/OȼD+%ΛSt:-Z(Pc99=wO>]7C-Ng3~ۮSJ }HE̊#NH)	wpN 1F}Ac^Yy ""HڦP0tÐ} z(Xj!Fvz9~2Ń.=+Zs'=vY_^xG_=zt^ޮ]"R(Bpvn+i`bH))ž}7pmK@(Wt! ed<$!qL(Ri|!\Km>-zZ*lJHBC_uf	2=]#U1]^>hN΋2ZoRcn| \1~WJ	b ď??K):窺<9x~vY[= cHRXkMt=S ԫpH7ςI(e6ͯn]n}nnq1n{j2?JCDa4hP	 TR%0	QV=<: ܙ= `ffk9R|Dxdc	80<jNGm7DbbBX;Vk *<Y4On׆$13z?M]Y~"Tz֘\3g[Wޓ 2o̼Y 81{_}mǚ`o뾗]y`N^Ld" c_"{KI-p\__?y~֑@9ˋ{oicbHmNgUY*)v;mVJ¹n
#yR""HJCJtw$ sdvR͔(1+ ^H?1\671fa5?9%:F֫G[Lj}vy_t~rz~QjR!z=ά1Cwm;4u׿tPJWXTifl:mnW?哧ϖzu{y?_,i+aZ]裟H_y_}ϧ[NNN,+1|icч}HV1%!vVZ5 	]H."+|viDRH"(
,`Ӫ: VSd:3&˷p)Fjܣ)͛|2)T)
g}(.Ō6L1ơ1ED>1ZkR(0k14u3_Nfv]
?`R RRbJG(!p$,	 @H0 @dzQ8WV-+-,T~zw򭬫9<L2Zs/>8Ĉ1l e`2ytZJP$c-84FA(th]g1l4vOZ;f QkcPJR
?/i4ʲ "B~OΦL>DMSU7Zr˾ EZڏ~8)li5Eb}ZEQ8:Y,NOO]v>EUmm=5Mۉ#>HmuRU|Jm_7VI@!! )c*,o6O>)*JDTJc# >biRBac "
zHK5
aII14hJZ\8W m;2Q:l(quE3*~O_?3S*Zi-1eQS*%(f	r["NNG1iIS:QYplbO_> 8#R$Gaq0CL3X}uAIB ^#ƶjm)Mk~.wڻ\첚io|ZדYQ֋~bvy/^<}ӧOnvk
 &	A"P9oN+Y )G!W"K9XUC10#ՙbSEY5u` @
iEHBt:Lg̙B9F7f9!B}ʗ>Ixd|PFLIԓI?tv ee%Bއ$rR1D%@]W*4?:׬u$@WVdqv~ڕd*@BK!
Z2ۄrDRdכq'478{dc<%XfPW@&戨(W;)8ks#˝#7B@QH 08 9g1H]RrQp+\|جVӳA9{UGEp`NWD@JJ[qj.oU vmnW@1^W9r Ħ+q׉9GbH!1d2A`d#R/1~h1o]a0Rjv%|C%Ǿ߭;9FCWt6WZ~(+B ~/VK":?;w,RL&ncaNkvZg+gO)zZk)*K!ECYMf]1]F䂫2PJYbB|νBQDgXQiBh%sW0ٳ,yEY1vJH)nUY1ٹ"?mQH`lH1Yݜ][^$Ͷ_Wpyy+kn/~Z.˪!Ntm{z*]-?}<b:ϛ|2LkO&3c+9_w
G
,77BJk1G;#*^{)`l	>Us(3
"@,8<PমfYLsn[15۴E3iټʺE霳ƌLbt `{k !PRxa!B sFº,Kc-[kOGf\WURx-BHDPRRI)BL&%b`Aw>bI *%]QP(ѪtR5|qO~ҶՋŢi&ZB)YXZwftݵS1)%1QJ1D@aJgɬi!BG>uy/;&$()\2 "Bc諯p~~V75S0xd:-kf9ibQ8%q2SUUTIlvin!cw^YW0`S>:ƤeI!CZN):g1Dp1%R(ѳ}@&ɐHM$*))ڡkeqkj}AA %%9QJ:@`lkjETUU9trJ).( Ąjv]?6ua1
b {0ƔΖΌ2B)GtJ#NȪÜI0BWLL Oc'3f.{D!&{ࣅS0J̑8n6[LzlS0%!x??MT"6Z)]Yd2͚I3gt:Nk[NȨ (}vέ)Hҥ+lQ_[׷vܾznC2YFkf!{\:Whc3#sDJv/ohD2K!(%b1<~$"QBPTYO!},.(2AB}>$.Jآ(3!B"F;bO<)0ۀQbI|'zY׵S+ݮBk5vXC/NZ)eU2\)A.
׶1FD!(ǢtƵȼx]7d>NZKL1@N䬝N& P7ӳˢHJyヂ{Gn!XGoyH @!>6 3C)o\/e`y$3q_=|zԬ=Na1@\2@ P"TQySm׷]zFGuV,    IDATvEֳiMD>v;/Fef!(Q2p9Of1޽ӦFD)";a_8\QnPg\)eqRD@	F\(%J!RLDc*1xx'UqH~0u&>zë@x95a{%($sB* 0:WR,JJ_'_/.~?L
j>߼]08)UaN*DDH$ZK)|uSOfe3u]>=J)10dL${@:J,!11`Hlfi-oˢ(O''=@h&{Gl"m7XJ]ZlNv6eN<Vb\  PJ	fy}lzɧ?xӟ]c"&:W;ic!ݬ?A`i~罋{|E_BDJ_%?vu}b$bbDLSaF

TR(9=JฅdsJ`sUUeeVUq R)mmYϚd~L&٬L]UsOYR"d@ V	!E	c!RL@)U"B'Ϟ]\.s֕ 4cH)BBFB $~i23DR= $" J=Q*Y82R*ctᬵs/^,o^U8=i&33Hnysu]JIJc"ǐZTJkI$)%M"Q1u) }&Bt Cd&)Q*%Ba*-h臶ĤiՊR8+B)aD?ӳtj[ݮ9==]V/s0:
khSR],˶m=}bLa6:'Zgȱub`)`8{b
G(GUkB"b]RcXqG1zy<()R#Q3s٬SJۮ Fe	!x֚VUH6~!REQcQHJ*kՋYNR'v0ZV;}o2GcBi)%0XbV0NF08Gl}qqID!7˫)xdE!RƮV+?ǈAI:;r!̘#M\  a,7ƺ`c^po@bih~<{TU׳b:?/N|q89OKkFhRC0b}ߵv]>x?6:[VlRVq{ J<yW_~O={gϣ(pDa k}u3J!!RR)Ac!ް1Q\̈(RJFIӼços.JshRK˲ZEeZJ1d`=WRZ|=NDp(tyQA1جi~?|IctR7@Wic%fY}'^,ֺ^,bC(xc]uCYr:g1F[cJ)eܤ.F!xW,]Qc'o=UuVkG? w>DTcQD5}s ^()>aT=+Ew#K"פ@B2@9_L_XR̜  Gv.Y{[7U|>S_{CF`\YcB8h`AZP1% (OD/pQaH@)B
 	1xHG:=xSV+t`ǓfN8xNa#u2VhAkY8_ġF?-QJ˟U!.NO_<}de!^#'g|&!vC+*T&1ԓٳg%
B(A!%pB b!w}%\HyEA |!0ݹMs)lOέW/3r6z91w]WbRW!Rb%[`HL)٢bfo7~Gُ?/ ߝ]ޓLQæ׫Ϟ"b4WϷNJg_:|ueaONŽ;k:2EJ &9SmՓV)2!AI}  @ h Tf>~2}?",J\F)![)u@De2*'uG;/Pjz6=.dZM&LYfR*A̚86tY! @Y}  I
e%iB(:|KjSVG!9H AoR^g/9%w
KAڲilQWru]6Ӣ!~𽳳?/>neU!) %NFN@)
)sU(RʸZLB| $@DR>
!~诮ʺZuaQQ'5BHt}}cҶM'UUHa2	)WMYdjs!UۮWa.|v}wz`ݽ^&"Xb8!u3Ͷ{,K%Zf<?iW>yDdr~~>
W8!CMSu$>hJbV'[`s\ryms% dRJJonM'J[F;0w0QIصl w}];!#{ApۅDZ ҇ok*f(rg<3{CRix"\YA )7`
PΧQJEyy~?C\g,N#IQ@ @){sO) /JA*%c>n]^?۬׫nǊFtQ6F[mCg(69Yd͋~v.+X{w" 
ke3mr6;OOgtzr_u""g_|쓏?']uQ̧Imw;
o}H<*{TBk2
JP HR0A1O>@z~AHv5U2)Cg&-%i!6(u"! )B
41*ORC("B Bg0?bXImZg͊bo6Bhc@3k%k=L{>8?}p|1RRiRk]8EF)m1@k#DZN槗O//ܸ"bo|c2:̇_NrR0^u8ƱSƷxMSx|Dטk逈B7)EV)Fd>_o:a3(r8=9B(bG&!g.YlK % qr v.pQFB_J)?b<(D	S"2vݵ?籬~9Æ  2N r>q8JN K}l '1U=UZm7W/gO<yTM1zv?G)%ln6MQgcFp3}BHJ(e2ZܩDBWu)e98k9@BJ1
WF,IR|kȌ}	Xf~n7_|`]iZ.WXv-VUL5!G`݋{%#̭ )DU_|Y뇿ϟ'ҏ~{uG_|!%/.*6Я7ۛR(;Ln?JDn4Ţ!bfbn[K-sqE.ȟZngO_޻B2kv  ՞ğ >"䤐Rߵ emRJ#!۬C?()lwT	TeTY=[NNt:f3494;COT1!EJꯔ9bwG10H]TT*yw?=9QH eSH)O_J1uS9њ{t\C!OBEֺt,ˢ(1)f_>xz'"F1|AJFQ@uUYZkVJ+3FqҤBpv&ai۷e=NvmDZ¹.]1 fFPwyl\}ncaf	 ﯗCٴ,
j~գl:tͮm{?n;jXSCC]PEF]'Y=q6t:-@1RTK˺XGHCbcsV
bV`Z댁RNPmno^n;66ݽQkeUMTXa6ud2i2+AH)j:Su
I H!zΘa@i\YUBnm7!&uo10B
@0Fg3 JVd1g+f:CHXwj"D)}CŐwkJu2:  ^.|iR6-䣯jn!!u1Lnjr S>m} J`in7Zk=CJvnivӵmu~2MJʸ]8W*+ʺ,R!R vu_X-o:R <ܷ-G:k]Q:SeU7u]u37M?÷.~~sZw]O?6t'ONO|`f*	Iq;QߐEIHd:8ga- :Rejo?<;;˯|JBhWep3HR2&^oژ@( 
 	R` @A^DZĈ(DORL鵍fM b~Q3*))жS@۴mS,yQ7(
RHLd3 `Jq8[.o6oݿ8J'RJ-TRicU()RtǑRLI[5fhUUvI2UpSLq̑.hƔ&cAe> [!Sxծ"#PJ9~4\gĉPC}w.e[,ꦩn&R!DĔxi`RR vmtRǿ͐6Z	!;&* glv~$0p)# G%B!!S#Ő5<a.bP+$"wUߵA|?lpǌZޝkwO̩/7ֳ^ЎWZ9+(R P{3IH:F4NN}]W7K]NvlV(uT2JR)^_O[҉q2no7ML{,.JMD!D @A	kt:nVQH6 +RLuFi7?䈘IA" 0(SfuBjmgz.C-J 14(>xe`i@. 6f׶~w~wTC_5M;_.oB$.T=D\mP*!p:e)2NskS~˛ۛDFlzeJL HYk_~(\Q*)gl:	){@:, "g 4()d=#9%N)%l*Ƙ""E!5}3"8ko7!ǸBJc]96t1Ogf6&3S:kV:w=3"H_?XBJ>2Mk#CQ=?(p~V>
dC}c{<2z/Jm7#nQXg*ʸuL٬i,+ʑ@}x^dWZk鎻|EKC%@/У^.z@/z4͐ͮ"EaYK;2O{oDnp{2Z\.f4]r7RB???_.}&cdGfXc<ύQbOI`	",A жm^!d:v#|<s}Iu(ޥ9c\-V!qeUy1zE*ϳ-~\
dTg)bZuvȮ7Ň|xr||$8TVuYՈຖhH>F$~"UTc"=_^~c̳,,%}	H3,bMJU8]ߒQ)Ap6ib{粲2Y@<xf
$7cWr&ٚmu->" N.bZ5鴃5y"Hٲ,k[Z,˜f0IcJgYeel6;:\_o۪*,K烋Uњybs})"e6PnDDC[  "ҵmAUeyzrrX],./YRJ"¯7ۦicĀ ,i0	 5!8BݴMi.]ղigEQմ.jUf6/M('cc2$c};_,W/ϯy5(a1&J""[Đ  ͊(ʲ'z2ITU7>__\_^^_^oeZ"kpL;׃1SZ:'@*2lv޽dryqa2Hq ؝t6(IhVJqIZX8x5pkm4!j4jJk4$hkj 1ί񳟾|l4#HwG1*fihRIl)XQY4ٮ GGuI 	"k4L$FTKB\Y>~<9:.BeT"~ed2[E vϴ7Mw(ARI&fW$z[Sc;+fab6j6boB@dQ+BFeb0b>
Vs?>܂@DȃsJ
?.q E(Z\"CP甅FE<m^<ݞ3ݎ>n%?@2{jB pPD,ǣ%jS齗/w>n;׵,|]$TeX,=}WكrU&laf D f16&)dFE 8M )OCYUUk6k!%T,COyBxJݞW=|!DF\ЉF!زjZ\G7eT͊1t)*X$a]tC,Oo]/?~իfXhu|mױ2zZ#B=5Mm$ϾOG6(SYfIwFDfm3c0YUU&9PCHTY^jm ;dS\;|׶9k&!r=Z14QOB\׫#)z4'l2r<-F$c1Z]MdH0 	wz WR*+*e!h ;92,aRQ֤nFafms}5
],11B'}ud    IDATD (,o9j'j+.uvDH *.:/+[xZOѸ.,,K+$֙}r3$J|a/m'dy^Fh͋</<'ٻOH؋$gŮ@z^.׋H +! Gkt]\ %Ƥ2ѨG!͍$.+QYmtv ژ{L'ǏxʣB`׵<M#bߵ18"y\oa$l/=}iZ+X2&f BE@:(I J#9
 (:HB"1yefI>PVfZD(&jEQv]\/( " Ĺ F:ϲm6DDX8ϲ<zƣQUUȋW^/ˏ?*4vGm,U%5/!4mvj6D3P<
!H !Uw^ދx<NƯ^~e=βL)]ף?dW/o6Ɣy&1}@V]B$"kuʴ9jemh\Reyyh4NOOcP Q Bnnn^}_<v1eLCŦJ3#,ܷjqs&ReYL'GT{O]m6/?}0ľAJdot| E}OiwBR5#A5?;;}%d61!TJ&tLq2bv/	;OA;e34Yf^ADQ-6 V'ַ<݇(X뺟}׿G Bp>,(BcDZ.Օvr4'Gcp1UlQiۯ2:Ihc-*%ly:$vC!2ȳ{ӳMfZ+QH'λ7FÛaSQX8 %I=8]YRH>OI! dg>TIb\@_D"Ѯݞ%`i=[8.
  8HAbwxF`Bߔ$쒦Kݔc 3A'Cin$#G$Hw~vh^ ܥќ3wwAo?gJ촖F3GO޻!!F;!!1mF|z<z9E>;:YmrDVDل(Sn<Zkq=+Ɉ}/o6k"df>)";@`@R6$RcDaTe91ՒHYgY:/`w޹bsbG.7Ǹ!RyBwvs͏_O)ubt<{f?#2#Rm=*UXt2Lι@ʦmwg"ns5j=u5p%zz$H@[cPD1R	GQHf  0
]ہ)(n:*˓iYJ˫Ϟ.V뛛fFmA^ƣl6MOz;].9O!xf""|"͐7&-䬭@
)ʲl4|ŋZ+E;*WC
yHo?REeUU-ʼUI^fXk3@\7uUNva1jMz 5%"RU(ϲoruU.˲Ӫ,Vbl{״MJ
FVw].!J)ͷO?f4ޓgϟ{yӴCw#$$\7a^91R6;%t5^|6E'6ˮV˕^>6ÇǏ?ɣO?X(&$@J1bfBƔW  QȂɵF&FN"h 1PQ6>Ʈ6˫fb4YNH)T"*)en9g,U]=!Vum&m^QŨ<E6ˁwiڶiR)L$3V%Pz٣'eof1_̦ccLz2ꪦ%Fnc= 8GUmyq޻Χp7xt۶|<;u;zbawCDEߧ:4}J)md@ĀG'OZN	y]דdTʲͨVjGEI3I`\=/e2@Bђ i=+8	rIfMY2-../__UEUE5	̎NdO?Ib^o#km* 21FTA1eQ 0
jVч#1ܿ/XcP=LyB̉vBh9t$H
Efؓ'h ww6ZC6'RJ9mdFfV1@B` @ޙE$X{qyomb.bzWu(dzzބx&cefQ50}uM{YPX%C#$m4Xbu}H颞>|˓2٠+x]"m`	2 Bg.AOoSSpYۯ#)%q'0MdY6JB(8ZT@HwrPA3dO;-""nWAE (̑9A'_d>@` V\E!JtiCeQ AcҘ<1J)f=;'RLދ o3	NZ/C7nGp
hw^JN j*&+D$J66$"Z6km88 0Ʀ2sm/_/KF#TJeYeg)58v]42Bfǧgh\8ЬBe@h9gw)#bPj~KifBH%EE\Uee'g<~ٮ֤Ѩm;@*:rDaαᜒe@kusu<:>>>>Y-gǳ㣣{	@\ӶYo=V_K@LXkDmӳ{Qv4eY\^^_g?'tYe8ߠB!f]ԣD0dB	 h$ʬEDOxGVo(Q]UuUydv|r\n]<ﻮ6ˋt6N'h:+'3@}#$a	I];?[ۮBN Ll: P((Ǐ ы/כA>z5DEdP9}"D	z,! !pܔo۪XcQ^yYgeuYuyfmMʢ1X ˲$NJ92X  i:%Z}T|qqw6&x:#1v\攁a%(Z,c\bt,/l:q}wu}Zmb*z;?`:C$Xxâ,fVVUYܴe4MUv90UuzzZ.W$M;;{lw]
+>p0'juuu֚AXI)TP0 
)A!b`}hmF+߷'Pz4v^/!BR1$0&L^XH
ܗIK 6IFVtu>Xc<#RTVɱ"!t!1z4]	"fMtvrr, _կv\ |CcE)UvTX`BRyQ! 7qrIפtQ}4͵wdTs(3x:βyڧ!F}X@D!yfdyKkM&~Fg6+˲ꪪʫz2UL^,( [ج6|\KD" 	$G{("	PUR4(u5xu0 *XA˰Z.MYz~i,/򲬫Ѥ<<99m6MwljݶMd>HR/(C $е1)9+ }O&cH+Bwl!H0	j>ԠZ"ޓ xHk7mRA)Gh!ipijgiIE'O~xTU \_ @^J(֫zTTr4E\1㸾Sڤimf/ofqPD@k=(HP;W]>lv㣇)jBl\dT$1	m_)a"w.!Q Jj,6 XU1)5?Lj,3+h 8F",zAﻃR8xam={{?0{H?=*v&1!e)i>D]&O3D(ߏ>h;c
}."Tj*WJ~^>I}gw{7Rb4bBߙ6t~#鍾B\ױi;-a"MJ3/$b)bA
C¼m8WD4
 ")m2fX,l=Ͷۭ"@aDY.m:mh,Ɠtv3nK" QJk)FB R.<FwaVDbbdB~Z=i"Gӳj4|׿U.X|4
*f/>K2@w"">rem۽~?fϾÇ/}R9ws}l+'l2pd(HOz;Dk}_}y@_O&:"2'aߓtfYVDؓP  2IimvOYch$z󈈈{7b^YQۢ"+''TSS=r1/h2Fh48sk|EH (l 8  إyII|8iXo\ݏE"b`JŇJe5/.ͫϷt<! cH:MKv. @a!Z eeuVyU̋*"OnJQelnnv &N	xdxs?EYN?l4i8z~'˞ΪQAwpd"6+vpdkd2Nִv};R".Y^ܷt6u	GMTWrڮv6sm|trzzr,Ͷ*cf߿lH4hRI9Uu=mӾzb^@eEB Qi!v,`!pX,˹Ƶ>B<*!hc>Dn /),
w1v<E]w}}2ˌpJu]v4mbLހJf^UkR
VeY痗\df4+6ۭ"2rL3!CqS9}W5J}M^JhwއιT&$cL]M׷l6}ڦi&GVRT)Jk1Hɾ聙Q)xQlQeUVdLeUU'j4V
m 9}W/R:3P<Qvy$#"4jk;Bܻ! L5Zk p7mn"/sExzr|rovr2Lhvt&$w\kmLis
1
^m"}1ă">ϲG}7.JY]H+zǻ~ER@$I# FaQk17uQ*mv4""k+qoE  Ե~7J̍&Ħm׫h<2Crhyugg(F>sРw]ye$2CMm,Wkw@lL#"·V#Ci|³omtxg!TÉÄ.aWI0|#NMoc;7YD8r5"
cATuZIO1rH#k23]q47UJ  "BdهSNm+r<lΖ}3'=3xB9 дVIg/F$LDwMH}|'
 *@$j)JшHa'r
}卿_@x+g{wG/-8;7x	7ߣ]4=e8(iNBZ  Isk<r\"%bJ)mz=_7+{@ej4)Jkb&̌VD9&0R:U3kgjZ-4DJ"M!174&&ﲈT
ķRs$918׵iǏwm*z.RJeEet@Dp#ẁcfH Zs^K¿O˲o~%>;;4?ť_~+q7M3OR4RB Nl|׿x{л~~_O,ϋC)+bn٬ H'}'ڴ1,-AB)C`TӿxG?/oobj]U]娰(jVB@GFFQb4ZU}RZ=+ 
5OIbUӿ?Kd/:/"D!B@J+C&<PL@7EYTQEQeyal (ϳ<ϫ<QChZ~?h:Fȉ'k<4e1`˿˾V~2=:ɋBkcp}ǻXA3bDH
!8Eִ/ŧ~t||\gכ`6xsʗ/]]^d2˗/??N]׫y}MFՁo$r>::"W7_}u=JM)qΧHQ11-ϲF?׆QFqAr=;N!*n P2  kLQEQ"rvn<Dׯ_WefJk5ӯzZyDuWhv#Q	]b̶]7&c2@ ynskR?xZwYcQh1΄&e_mYkݴƇXd%H/31R
2EE5}vfm;=_ee ځcD /rkʲ:)v`BL+c湝Φ';wz]J9eBDDk- H}<<?|~4^ QeZ(O}f(6$   Z+DJT'}h B7^ރ<:;Ot&f۹(!FkCp!x}QɊnƞN?|EkH@[D}Њ
,w "kI]? !zXD+MRA 9eRΏk`2KD@%&b  />'ϾG	r~uq Rf RuU., ޻\D
1	je5lsyh<6FtHk%CY-bq'GZ7eA    IDATD"yNhh33CZ$A'کzH@ ]k <@5jh gJaD#`5M{\vZ|.xh{^csFJ1I^iT1?@YH%,zq^bf"/8 7`/? ;0n~;:sN`	v^h|UE"ĝjmuaQ,CCrs[@Im0?{Vĝߴ.'p* ]rh(2F{ZD		,YQyfC*h )f뷎w	 fy15Z	/"5{#AH)@1NgxDAUbT}ߝIP!P9$I9ϲ<Scp]ϑ57&ھU^@wom[Cg}ٻadUJ&
*XGͯI_WEO/_>?mc~\hl	@w+ zE&ZW_4M,i>`mxvH 11aZSk*_	$R
1pQfD:u syO>Iv>F-B"40F+(('LD]1M@ju",9&9_{("X;c__ҟg!pʠm[(]WtFvwRbk+.)5CvEǔW0@Y^ee򼬪,|TeUۢT6OY L?!79"yVEy!4]%܈OCBQ'|eUmU,kf4;4ǈJ+M+9Fk)ܾYPacxh<O&=oh<(|҅x}}ѨnZ\]^qlNa^_6F?}*?
9 RD@͆cBٳ_EXYQd^
_:cw<LVNh1	@(L&˳r*(eh\mEHoCJHוּJ)Bۤ%XWejً릳YQV 裴vZz9WeQI#i^_#`mlA@iUyY6;Ͼw}}cw.	  &wl+ضI9E#7֘BL'XTʠ#jˬ)2H6	*Ƙ"V̚(i6)NUUE1L49Ɠ<lflnDulY/vvm)2ϜVy>w&V# 	0!"Iv;IeǽY&2J @ Mi^jW~y,|ʋ:<	"R &c2Q"ܷv/{ s{˓om۶)8Ɛs%.{{)
Q(Zc@I&R^ 7RZ>-e !F$P
-oW/jCۮ!R!*?1E."1p]~0gf;|dhWPc뚦mFb4|އ'guY&\R  !^)1&3h5)RZ:0/.<jx;P&C6Ž@ 5 @m	yG[$}^㉜?2C: ?W*1&1~;а~wn  @Gh{HȻO-8k^&}  >D}!K^m
()5v͕	<,SQ( h&_IT+HPSwxmy1ν_pR]v1	#)OD}H 1ƘyJȢB$c0F"LH!UA3BD;NG`v))>h4JT#͒n/CiItxw1樔fy!l P vVJ(sϫ*b4mI82))oNL	);җ hdFkt^=/Oώ]͗~ok_~1rZ]UdӸBi>RZk"(pqy^'B귿}~/8ݴ&y lJey"n0lv7$a`p߽a#qJJ>jnqwDPJEj<#KYX`UBDbl)}yqs89>JUQOt0@  9@l7r/'|)#$w]N=֐J$0g(J%2@	j)2/+eڬz\eQeQU!#""h468:uscl(56yxZk҉AONƓS߻v4띀0,C"cDM=!V$a9)FE^.˥~<!5&/$2i\aZ=}mb9M˲GE\h<ms9.l:N'(5L>x1"ڱbpi(</bF-f2Zd ֆ.D6CDb@zq$Q 7BR&ѸOm^6X,63*mz@E)MN E&~>QDUUeC!}l˥ReW е^m<],/
f^]Eue-ˢ}:skI9$C%{qaH;d㭵߾! IYYIkmlf5VYUUVEUU}||RE]''gdַy.:c]~l7ls"$c4"Q ʂ"$.H;M
۲ܿxPn;JQvZk^bh1l*9uv64	LV,7m1).d$ڐִ+@i]U^D֓?\m6/^kBDH1y "rR1 ,D,#HiuԩfHJH	B"0(g~/˒c\7} GҔR{Rޅ>x;u]6{k4p,jT5"sM۬v+YQLf'<|rtv*KurSL'6&[j  	(V:Ӡ*:8~ "s!i! J$]~*Je4 ]eW(U؅Oߡ"9=MqH|T;1ekiP-@m?5P"!Qym&wKI`892w2  ,#!)ihcUZ)eRJH
Τ	i;[طi3&w9C&!56" Չ DfEu,N3sZkWZҊ0FIH\0U@HHx:"e> e&(˺eyOv{DRJ THR Sⱷa <M]9@Hix҄9!"T__imz^=cL묖Bg޵}GBoCEṔC*C S7WwZo7VҪkMfE1D#3RU*A("#bJ$Q W77,dWQһ\I&+UdB#d%aO!{xH=2P
oO<wCkȌI{*W
vb]ۺYnlvQP!
(EW_>&[.ixYfQZk.i!Gn_</3Oɱ6űh4Nv
FTEDQZed<x
{Hڃcl`EE ʋfdyVY=΋,,EIZ"ABekBy!om	!B,zlmf	GT0I;v]6ۍHz1Vim2F@%z}PLiǰ=є'b8??߬h0hEAPD {z-ɖXC{8cL")زdAÐa?͆`C Â(/	5q9">UMR$vΝZ+ox,iL{w}-W/.g>Ѧic^={vyv%EGSբ],W,u{\ZOb`^[8E*i,,HGiLEaiZhߏ,JλX!Qv^WCU/]"QNckf7'k+
p,,̃#htJի<g:Vne.EJ6,UX!77DԶI@A*]%>\_MVQ@ ºnBUeр, R.EAǜe&7'uzSƳP
<Ѩ236諺UCDH|tiګ/?xvuzquvya<IK@vb~.9ͰaS)݈0x7&/ \!Jf-  (!M>o ?>DDav3cO*6#Gj=̜sv9KDucʈg
"
q"خO/͢Lsy~{].T	O!r,3Z39 ̋ a1M5Hqy6*w\@DaOw8US}?cN#,
ޓMl@FØѡȇ<tnN/vZ."~?E$wm ՋeLDʙ"s`O "3,=v[98^#`U1wQ<4Bo支fGUpC'R>&_-,9	񊍰WuaF {* `fNf)I̥i< ~9Ӈ?|v&eD33UCD:8jo} r9R/^8'7G쨅HӟMSO&{O߾8a%%TGCTuy@ dΊw.H>J?,˫nMQ@#)6A**0_]]{}]Dąs4bjˇ{RhykXf
6t U4EQP%w=".M9KiH,ZU՘߮v Uwv{E~K) "Ә&Gabq<&o__WϮCuvV9^g''o]p[\mR2S56}ʡGxxo;|
wWC`1* 2w	yh?9*=sl~UD>_B0܈~믯??;?!  YXȇ85vh~Y  ~CΣ!{GO3HR.5￻<?2:w۶/?۷oUUn&s)E #eYlt> 9:B;r\ֱi]Ī1*zGUڶ"t:q*{u]ws7@.4uSM4M3=ۏ}?dW`5]LUC{JN<P@yuBq^έ?;;!^__/眊xIPF ۛ[~txvug/iGn=lw?Y{vvZuSÒhE%~ݑWTdѶmۮ\JŶ")bpT1۷McAJEXdaVCnB"ՙqXX
[Ak aپ䛶ӛׯwgg
;\W:>78|8	,/?#)fPUC/^\W<bcBHPRN '222`G?T5Y3.M U]W1Fb$S-e@e˓gϮN.>LXv)(vs7wow~?
wpUuU1'W3V.C('vD LMPFH$YI0䒭cS :0r٨r"V{Tuպ>d.*\vws@n-TٜN_n3s<Hv䅱2E UX9`h捎EGQys yfv|tRhC^}׺nw{\p))%sn ;D`ajonލ}Ggw_|b#p!;HDnmгh.ggq
 p:X#
ι](RxH=s&I2Y>? v @gL=g>TUJ&  ||"Qס?&f9{Mۦ?<*$DxJl{.e)-d5pD
Pǯ<ӑD.͗'HkcʓA!BG|@J&r;Raa.125GT@4Io CGc[?&.4mNi%SzA%hWXjtww9bр
\LZD\1V9+M13ڒ YsR!UUU>I
@a1֭"v'*K݄[|RB *d"ݭcRʅȁi)bFo^/~e}MvZ->""!'
A^EflD)#_ON.uum_\T6~sm]Vw]u9纪ъֹj.̄H!:6w__?X:r<$ADs)qB p[w&)U8OY$1Z>L
E$2ȇAHmީ*|O^<MN, ޻P;Ȗ{<~Zc8B[EGdU!3n&I ldpqnb^]]_|w6~GfKYT	<VgЭfi(":g]>Īi
[WpFd! Q!VU91`Uub69s1"vwιNDJ΢D1δdTEJaFV@ l^n<$r(	u}"MS~R.\ gEERJ7!Ƌӳv[n^.wwwp۶/^xg8)S0y)O˾o޿}MUOh^EBfƱ,%#Yrps:ʢCGz5Ao	R:b21F#Q  !yv=@ť0n:Ӻ6.;sN w&
 hobVUaya/ ~w%n4޻n|8>~r    IDAThB
Y=dD 
0RR8\Th  a  TBEp>@ΩZ.bD Rgq]W1PNffѶbFaߕq}ǡKKN g*(+fE (:}ؒ!")#43K4034]c<ja,TeRO(sǃ<ᲹQ<lTzzv|CqJ sM@Q$cq@$$#X3F"HLD"A3.HN		fYD蛷޽{C~u0@s<f,xkbå<tw! o߼~^>~FBD@QBj}vxޜǦ5l10PRvD#R)}a⃠	uSG lcS*j@,L<  ?S@Շ.ӪaDB	:ml8}u DuCiwDPac=::=0 ]~Y'LX9@),VQ-5##c*CrJ*,fh&)][ha5sۏf 3@fiR7ǂy[8gme D;%Us%O2R0/izι<bFEjr1ɡI 35N]eUDՊȂcA{d!M8A	XHL,l4DŧvG[! (eZ.aٌcw,;RrDޕ,QaҺi߭' )SD8EO17.#EEU@AEB^%AqH!"Yݾ7!msC8=[6fHXW18LF8  :E9'!9nqL8ugEdwrGC<9 <sȁhiA>iS``qID~bKgNy,s ư9<¢*:B!ƁT$  	!*y T+SK\Y~7GEeѶyyuww{p{}}}}ww}}?wi؊ci;)	G
C!"=sV{|<MƉz|4/3\UǪYHS)CSKIivWUa*E|Ha @sqff3)&?Ҥm= 伷ΕLRUUjJ;\,c`RQ y }7ܞ_\vaXϟh6B
<^d{D!ͻ.|~vl"΀|M@ͅ~(p)ŅЦƶ]ucT ?1,|"(2сSQdjG.+"etΉƔmӔwMG@f\8"
̜&7R{S*/T!)DKt~ޚh)ϟ?3aH έ&8gXy̌c  $*9 980HUBb!֋naiM\\.Wb'gӳ:V^SSi(yan&gEY}C(.EѡZzCSRA9'NCD$:?+씆.TUbsQj*+,YQ2hfʅ3+È "ڍG=Íקl8UjU]UϞ]<w]WF4,Ghm]t9gtb؊N3"_EIIթ
Ii%"ՙ
*"R8Jw_ї}m	EPmX!Lx%ĺnSX7lųg:VQ D(Ʊn_DL'YlWyhU	lXU</N|fCS$OS}l  0eT)<?\>{7*Ou#7ÆɆ3<bR%֔S. 2qR*ERgKDpWYpe'f1l-	fR М+@C+|WE?\0V4T)yu?zޣ@@>8[[3_8Ǹws_lgM6'||+.# nvL-DQ
!nnbL! 7{J#f zuzr4͘@UT\0(,c 0Wa@C|ɹFY5xvNOD(Uar(}2bE8ֵ~1^xaqdB\B*;OP
7?Eh7g8_s$DEvd
eT 82S/)`l'"  g/˓3_],zG5j]]-CM(Ø*q]oC?vv"¬HNK<lBE+:'\潟zzbeM  3H IH@pCv!V˶ARFSC 7!-%XU5LU:=+DBq|ynbҧ/QU<`\(%%&tPJ)y5s`Ɣa~}~wo"*cT(b>  R..T liIȦRƔ1)}0uMTreqμBއP+Nċd[)EKN8aSa4V7R9rN=MD Z<ʹ=![* p7_޴Mee7w:uX۶v->av>-**9}ۛ諸~% dƾRaT%BZ~h.LRƾ۳NX,s45X:%W(8"UR
^2 * M0#Uh1
bwi9#Raw7"1֋Unq@YJ	QYD@NcIG"E,IDEΟ}-HY/C,c<;?!\Rb;$@2'!%bD)>:8Y"R,{xCu¨JLgg'Ӌ_~_\"=A  ߾~wuU<{3?eYNXh1BRb%y$8$8h
 <JisTD!D^\r)aa^ ''gW~6/FD@b[X*qv}gC5Ĥp3]?vj%,	2#bzS?iﷻNT=!6y[GS?':GbvDTFD (GIDyL8tSy~z̐YD*Bj]W59dfx^zjzJX=<<|''W./&d{T"2ۗRɓUS/r4uUutzÌlPn Gw	;bU%X+^yqoǧ0wʬR'~OU8'S&~GLA-J?oFCd<fIDt,\* @1~aӣ.0YǊΑA g HE $?|(tw!B'
N`cDDb>BDS.TGXt(XbǑ<*p2ӯx4C;hvTG#?ZLoymQZC)D.8E`)i/./FT/BOVo~2ː~,Ͽ)93ʪp6sg  )S.H!SΈDSCeUOz}rlBwƺABt ؕ4)5#:7	P~֫QpXHn[z`T9V"yV E-,X7iJ#?;?w5<27`aƣ# (U3 r-?|W/_Rwt8b肔sSWUZTAZ..5mkRmB|NrVffN9#OEhoml>o'g E8UEޫB!*,C?c:Ys֑ZtLhn
{D>Ly
оnCmr6QU.lN{	_7APJ JN;DX./KLw˿7fݱ(}# 4J(gsޘK<sJ\U2aBtFT- ShH@Rnj\kz&pF*%眆+9quCߏ}x 0+#оlw5XUι
}ΥZꃧ,)"8FE777ETAO_<;?߀0wՕ(HQ.7nqur}P"2CN]V"S9L8ua@Q_%NE3 sҪ$8dO*9Al# k+Y<x9{MHM.nH墔\QCd4TeᖥO3*x㘞_=/WWn_~׈ˈ9!ZEK zh(TI,Z]0LMXmSUUz6բU{Rv~K9ضibU7U]!~X8ݮmiq̹( QOq,6x4)l0
< |(ځ`( TU\M۴ge6m.W=qJS.0
Z7o.6hb.>9#; !F@
"ED9\roof}IQЪQ3%g\q,n7?ON3T N[Fj~!P]fFw9G:
Py (Dp  C-VJW65#wXw~vcU wrcp0:raUQnǺ|ݫr0777~}zzyqԕ._OrjJ}u}ߏYE|cu (މD>ś86K$%02s}D@>|,ʇeU)|ʝ ;L>v:6>a:˩aLsJidEPG,吰(@PSq%v.pj0<w7Qc(f,q!@,Sf8= 0): @e)	]ľ^cUPźiB݆8KDUHQ7)Ӎ'iӂ'~X@ SlG\D֣sޓ@xL{ש@䪺.X !	Cxs)10pyq'w7nnBO?3/+gcNi9gֆY5n_-mԳ.L]\9e҄'N+,$5]a``yͭ{qlE8SGddW!V\npwS7Puw}}vJc8ls>TuX7C'R'P&f9̛~..¯sJtlcQpugΐX
WWOPBinoIA`@MTXEvE.޿߿xrz\,K>A@4X?~۪J1iS,?8勧Y<&hjմ+Q4APA'uҔeƅ(МD"Z7Mmf=et8;?{Fv)5f4MʉӳND,\L෤TXR*!NToGfz&{)$o7=.k{L}̙Q4lMOPJqj89 8By*hJuĪB4DTh 1O_,E"a9J)B]7u.XݶQU~b96<eO>LR(XSe]RRr*~+9;GVȹvxF>(4qԹ5Yf_&UT$Pj, f2Ιx&Nrr^AK)i],WT&!nHug- {z~/. ޼z7}z]WQD|?YVv+'j@,ƶB0 'SUfliR;#=YNONOm.6G1NN.idج:b:9_,׋]"$U)}?}?]]ߍD=LJ:M8ǏƠ2G+Of$yC!#=	j9} daF*d^^%dR[Il"\bjM]mt
f|$lS*Rs>w~_!3RR	mUp>X<qr~wns<0Kk$0H޻`XCł(@.x=#y)bLLQE[ʈ,P͍aZC~Fvu@Wa&2sהSzx_W"x?b@  %00:__UU4U]G$UUHt2xw+;UPث9ZC*ǃ>z*| )!~B:u(|+tC|CJ8VRcJ{Fv4ZՎ@
Ġ\@YTGF
䠃)\Ve ?{:' Yi8bU>cTu\M~C EEGӾ'*@|%>{YY4)DdϬncÁcjZOU]7MVijۯlNDV_~)%4sh.9X9G0R<#9r)8~=sޅBECHu]d͕~tDAAab(H?`2u|!#B x , ZYN=UJip^mfZ;P9CsDxOg4m''Dt@
B\s ^}f|r
ggormڦF1܏Uo߾/ߍ#3ˋ8MX,ت/
 xfbDno7'_Ǫ0YZmUU1Fw~۝!f9Wx"<Չd>h^'Z,6 :,}w]Jd8|[!ֹPXY O
5?c=-%GZv9y4N<:m#@V%$4^~ҴKJzXUXLF`VIgd("rI)oQz*vBt=Ḻ"W!Un}P244朅94CI
dA$ "$>0Q4~jlFS1'fs{!FDd01.cj ˘=.DyE!DDI)vJfbWd٬]]w@@%curvvvlETEd4"*0 r}nZ+"O:aSw=!B!(_>   :m~㜪Х<vmb]7m_?߽{ov;9WŐR15MNu\m[
,bMUM],VsI    IDATe+B~otX0HeH㘊Pgb\,OWU D%1	Qg2<lfߏi q8<>6lhDhy(DqU#I@xE^\\~VgbBSEp$YEk1}gmx¹x_y>EQ=#
|}R_qv~w-41.%&HDb.ՒǮo߼ۦRcΑ`)hN4mɠ:&W@81lPUUJ]&2,)aDzXg "yppws~q4\J{fTDL
b	LBsu]]Ud8#GL]h\1@HɌd_3HМdVXIhZJVPud(LD$b@ g>*"r8,Sͽ#(}B~>Y,ѿcc=:VО圎2̩s24Us1YAFZ0	)@Pt`fPV$RPYYI*	Ai>\;є5;UU(%fv)9lZU-Clڕc@a΂$=i=ϡ$ |y:?f$	|\D)D'e~᦮*n ș s_}oUӟsNO.lHMNGN~(%ޑvhd$灼
#)inڪU 27܉(C.-0$VX_aڊ$8'"XXҘRꦪ Kޫ]rcU\X4}w>{6;]B vۭOǏ.?9IyrE|d9gBf˅y7_WO^~obb,mw_:W% UN矯_o_]]^.#sUݴmCD9Mo2+4t8e+%ynߝowD>V}?l7o_i[",K)"^dJǘΒui*~ps}lڦ!"b~dmS=S?J((s ap>SbVaO
J>pD(~wNҏL':	yBD1[YcU\^D,\9IOT%Ƀ@V`'G4t7m[Wwg''kr)q Gk99'9
 !:쭫0r.3bx3Pz 9U]97wI.fr6{=9˘wG[Urᇇ]2
J\%-uV%!0n)㘄n[	qyrvq~\.f+̒suG,طQuuTuM!zy .KQeVo rTVU2KN' |]UmUﶻ\h `L%gVU)EeٍXOb۔'?>+_?%GZ0@@Dȹb\D >Tj۪]ĶED)%ðo}퉐Ltz-}fn*s%"D)	}?<m۷ۇ~R.#tDuU92zxK> IU?Djj>y?-y}AN^)ԃO_,.PU04rnﻡ/fg*|kSuShwsa{pYЋY:ZƱ]ă ,cXb4A Ud)0_߼{vIXlX4Y&F"7ѓtf
 sdzFb  D:,
S?65=}WWd0G82(a.LsAA߽}^-:e]Uyiriv]dB;"iԜDE IN,c=X0CRQ\O9r$U`sMSZG0RS5MX\&AGR?.y\ 3lM9bҠ#+wHm9	-r(+: EάAJOH^GD0ŧjYi=MFc.('ะ˳wT7Mlj˿uO_ݿy6twsncz|t0kӿv;N8U>ez?&	|XhX]/"}1UTE m}gf0A^`.wa}\Q0 DtfqX5zœI;#MƆ47rh&7xd" |"*)3hUUCDXXbU8RB" 2 ,,,wqEuz&·7Cߛʴ"A`|C0Y$qG_UQq{߾_^]׫g$IwqUYWW_3!ݕ V A B !I.wg{ȈˎGFVޢ0ann}!NOOmQ%()(]Vr(w*?w//.Ί}-MӸ:{jG"TI}n6lXݶom|>/ɨJ6W_ˇNWjZeQ(hrbu<[q.ABW>6<
ICIBpG(2!R510%d!K0Ӄ2Ő5K?91r*X>i	lZݼ{J"6@IZWkUzʲxlҢ⪶eib}x@BPƕ2nwb߄lla]]UEQv}:`LrNRU!umg`Z;dSN$"()nWUv'6EYRhG""㌡,QWz}rr=M.}QLH8fce'cLQD(7>`qc²1><}GI5<(	hN=MBD5)9cbM!D6 1.32*q۶$` U=ck)ܺm۾k%BBdcuwݾ!B8??pyyvz~tZ]}}}JB'O<I)Uzj泪/uUʢ(0duk@uKX̹+uֲad)Wʂ~hvn6iΡOы$̈@~L>K|h~~NIrb_$18f) 0%rШR g}^1 Kglڡ|C!Į4|-(ñLި#=SYlN3" 	du,"ı=):We1+AcYYg6fݛ7̀@D;:b8#VǝH`\~PP,"*0NpISa.Ʋ-67F0L2<3re(*cv1Ʋ(9,%O)w!h
Cw]?$
=Y$àLbɣbwn{:)#FHb $L1uJIZͻ!c2uY_ISU ||f'ufy`1NIH]1f8CIbҘ>:DEeGpސcv	{)L1	熋<FYU%f%P)]~ 6קgMn6C׾~O~߼.<\%@~k	<y\TsTSlOv`.k{&y'dº$!CR<8)o߾?|\1~Kx$ðm%+!~95̢Cߵ}׺b	`c(f5FwHd* 	4M#:G&rZk.H֒5~>@XWے4QnU 1(IU1xUd
x $ԒCT᠒vw&iz1O<>xZ(,آ(!B_}?YFk"-f'''?/Msǣ*]Q՚noo隶gE=cwϟ|ǟNVjuzzzvvZyS>3*0&GS;g_,WpU׎CJx0aqle?,LT%N(%"@Qp8/V\eߵ
(*|l|qĮd*"1ONnYYuߏ*c-I#&?eҕ\]EY>}rr)1!D&qh{l0iv~_/N?
KCLF!:Tc;:MF=UͶq$ DuzP
m/qYU灈"!!"f.<|ćcD~odE"kc<wM \Qn1RYkpd+ˇY5CDkvB=W?#")5C!"qwfۆ}NowM41(.oo{@'ׯ߼x*V@kMn	!,ˋoן}|9+Y]udLc-r}ۧ!sŝj|qBC0]޴m׷ihc`̼O9\p_Ӥ!G1@$TU!2jȢn@
D|g?jB[&%42%bjvǘSMCl=̫*'Q79bV&͒Wل(2[`_saLQUC׶$!Fc-eЅx\ՋzV'ڕ$ids"&c8b3%)"fvW8ٱ34HD~&cb*Q$Ǽﺶg8m'6 >j;! h1{?89!s}?$4żJ3!DHQRd3}p@ T0$ "DVBX]VHis1$wOEu4IwI:ځ?z)^c'Ԥ!ܭ٭!ee|S0D$L)%r%0ŔB$j!u@TBBPL8ǭAsS^eËqd2zvbi0xCQٕ˙Q ~mi޾'ߧB䊛.^"7'|>1#
n%y>{wW3$4b,yc~5fV77׈vӶm'O.rڷ]C&v#cl)gu|kf5	I
v04[MEVL, ۫I  "ȧ5G-7A 
S*p@CQpΪJU୵zEiVeQ aUm]B6EUvs>CpWƥHR trMKInMc 
k]WӋ◻NOכۢ߽=$}X_KIfUY9?b1ibO}MU\EY"^nn޿k67U=z6Nbl6qh_z%lbV^<|jrĔqRG8$oI<Qnګ(!=zg
O#X ],jvm=_7WIUGqm5l!J"Q  AZy2Dm	h籬1i9h|u6[wYl\uCrfno7CH"	903uUeYZU*f1ה U~wdȖƕl8xTєrDYKgnnеyr12 m!j6Ʀ(lJ @Jc~(]zV#n=r1BI&ιˇO?d!nn6*zr  A< ZR[3ƚRR6:P1f3NB$
X?9?Yi,"?CbJ1Q89J h
} !GHX(Cc 	\,톪Cl-ՌY>Y-'_|muusoo099=-bZBL!n_}rhb?g=>9Yu0u[llNQpE:=",B^~ۼm7Mdư,vI)|ב"UMDdMYvEɒ\7 m4_]\>R720"~?2n Cpb p̡#%L \  J
К~$ ¨(~	DbĲ,ʲӓk7ۛ^_ZSZ%'Բ,}y=K~xeYDhYsmliGXKH`,ma=b-HAKgCzP5ve6 HJ12c!I4XFB b?=]ei8˹#b}ֿ4lYbJ18tU̜B@`m%#FJB	;&AI$ JT)@?B~}2Ԕ>黐2J>|Q/}<Y 頻0a
1ΏB&h} 2<mBQ|-#@Q>EX{4-%\L)84>R),QBg;GI O9 {IC1CvmθgO>{y?/:O >نk۶|=UH7uW\?BlqMᓤM<4M;&3&<y5NS?x
iᰨJ~lSV5nn>xkBoc~ߟU?49}5f>bNDpo޼A-#1=*UPZc	I"k`1]uo(	HE>>R]۩ꬮ55YAulLa$ꜫRb<Xk>{\vǏWk
V R%S} -dEci*v$aSXU&;I￻|Wz^Eq^fz6gefuY# ܶ/~._ps.W^]/PLPֽ&̈bJJr}R	e]m٢tebgCŲjd Ӌfd5Sg|xfsZ<~j/,@b<e>yBP}*x(``Dt0Y D!flR)%N":I=1b@ꆀ&SRh%L+:5]Aqn3LZΝl077d:8ʢZeQ8EQEYk0m%1osE\EedĎ    IDAT-UY	m9_jl˙8$g>R1 ($Y/bs$YvADv/)Kn Ms TL` XF@I`KI ٳ/ş?ִb1g5#j
1xT2Va&jA |dAYuU9 }קc|%|8W  <|ǜX 6ld7" #aL)CHI|L"b+jPվkԶ5(,C!ggS6w{?}t뛪*s}?@Cޟ}*O~Ϟ>gUUޭ$FRdf2f. *tft\ul~sl޷iދ@UeUfiR9\_ÎF1M5Dg1b>UUEUٲ6EI&˗_B28>|?-tHb  Ȇub2Lblwʹ)e9I?D0FA4=1HT?]Ϛ;[iڶmMS}5 ﺾmW?ۛϿ'	lSQc0 P	\Y,Ks׶n4qH!XkD늢拲ĥ1Ld$
BJqeQA?`#1$M)DB,!EcR M)䑖;:QxIBv$b>,%$Xg,ۘ9 02MQUJ	s`	DhA'<hA*FP5.br_eW*)56=Ό@*fS{sB_~_^9iq)'OƔ$!#")c"*[>4Dͩ8&͚+W!"`C8ID} 5KNO e˔eD2z9b~ds|FbpCmמ]~Wֺ8tUWo_}v0|fdR(5%hPBJcIcC*]Żԗo?7S~w}c`pMs@e=/g]lʲ$6zk惘SkÇ~诮⫟,
H)1FE߽{{{a6ggB!qPYMy?(Ԛ>4@ ~ 0~MB1Ɖ6<~-n%2>DZCmx?5`Y, L"1JQU,vmwv-L,qf2%"1IJjRL-
@Dye"f\]:'
"&o_~˷o6[E&㪙(ڶiڦrg}"yUURܗ_}^7}?<zl\n:U4Ɯ
n[V,ZvivۮkaDQ\EYJj~?~7wbX-b>SUUfmn7>٬6v(32AGUNN vSҘbtʪ*KGɍByی)2ڪG,,vkvt89Wl&LOx1}
@ƺ'8bkŲ/r>겞lVUsvBm8AU>&EaJ$&["DI6K%NRAK|'}߿{aQ'J9cIS)~!%E,24roF)O*A$MӔU]uEnZU!X yJgi@bc1)~gl>o6Wt>Yk+:I$e?
$T{0rU8?@tQ\Q}zb 1X,>ڳURBi'Lާ$@lqldI)˓A(ȘsdC߱qTX  16ư~lڪpEa^ozv	3QwHM%5RD'OU]V>g*v E.lmw&$ED@wpۮkھk麶a}>.:a'Xk$نiL|v.%$.\V-qUUUUʪ(z6/q=VH۶k)FkÇg_~|@2Sbnc$d@0xkZ(,)A퐹_IE);/axǏCM` uda09¹k~J
Cm}t}?D9pތp@c3Z`n>O>D^EղPDb$ż^,=y/ CQM)a`2!ڦ^U@:D("1&	UP2U*{OaUf&C;m]児Ihx$0p0"HDJbca#91sBf@2:@07heKBh)L	`ܛN5|'_6s*於nN !ar֗{z2W-!MBPYl,sPR~o!+'(0>J"Ib445ME F k2ن	A cҳioD LY	&Gn&DG7l%^:֎dT1KxG?~)ɣGON/h\jۿ{޼zCDc֫3\NS)$"uU^y?snZ,NG?Xps? qRޝs-PMe=/o߼NIsEHa99i~7ꫯJ1 *t}b\,21o'c5Uu۶ٹZ&UEE2c9N|p/3aKGua!|PE9u #sCvR! vC`UUΆR1YWbbgggۍa"*aƾ}2*JRɶ@Lg2I>/UV.m۽}w?zիW7h-rQX~kgRJl̴fe_.
K `C4َ}.&˘SCz^3sa-lb4]4"[TE]Ue]AHa}֧ggb\-+﫪\.9'|}T@}?U!Qfe
DxmeAdY`B,zH };	RkmQ͍qEYu5܇iu0;f}\6NDEжio6!WWճj>YVb׋eXf(c_qT}R6Uzv~{N"	,@Q^|SVkY$q$)EIGrPޅӨ=\r
 }߉*UuݵMu\lC!&$Vb%"I4b_o^|ӏ?NO,
$bއk&ƘerJS-zxu.xo%%=$c#*)ƔlEfeG4[sh2x<|MH4kcL
~X[z# )%˼\W޼z9_]#BbSJ|YQ1G>˳.j)IakW+TGc)Q $)BH\_ooݍJcfg\^' NNrq?/5 ZkmQU]U5WUQU+d{u5Q	i}rj6ů~>jE }aB̖m1؎e1!tI]UD3=J8=]"lF'O&B')UM ||JuQ*A뒴!}7D?~vU={䳢{|U@00! "j	Tsk._#tٗ_׿c1!)m6m׶7f}4."}?]1듃BY  arv~H(!N ,J!Aƈ
kb&vɡy$HSPD12J"Mh]2.&,ƈIp1	$2)D H =禳xck50)O<AlT449~?]B0n^r`{JcĕLi$ 0}@5	;F(Ĕ4A"!JXy'`#-O=	 }ADieG<N?I}>cѪ/?Eys}wݮiNDno|)1tQW} 2j8?&cfśׯN.	G>/w'yGVٻ+|TE^]t=KH)A]Y?h1m6cL)gg>O)o?闿s뛛1O<ֶm3/o_|yp~Ru.;ZvC)u(*'
&\Q0>\W
o7,</B)J~ꜫg!,Y9E*t CʁtZQCB
-ulq~,/͟nfʲI]7j6!((=G5nBLb$	^}ŏ_?~w^nn>z\̻?(jks9BOrꐓL8nCfc))vsU8ST5W1ƪd
x۾2bFĪYZc**ն~躶ݷo޾KTj>nTE%=}ϝ+ @%b@,1<꺨"bYزX{4)*Ct,FA䥱݌4ғ !&\gQ 6; Dbl?xQ5eYV|ZsDS/(!"HXd9;`HQcm7m;43٢tZ.Wz\U]Z'N֫!~9[crS$'~~w"ռ^<o޼y=XEY8"l+R@IکUxA.	H!=$pb2x}n}r6hU%d lDdK2N)嫿|_}SR!C7b^`|g_|\:Dl/Ռ0C$U b!!Hq))JJpvK V36ȄtOGNBf[Պ	@buE~s!FA:MZE5O/_ojY>%"1b̀ʟ}E
>|}6)`tvPӓ|(X`	4vv{}}uu}10!b* @G8cLJ$4@TcL澏~Xկ]]|gz6E`[ฏF)hC4u=c_}ٗ_zzQIDzgK[DѤ:yo" B6J>L eDdG$hʤGpA'{,((㟈	rA-Y3W\Q\\^oӫwWLJCB)	|Z7m %ׯ߶;#r=[ h}|HQ!o_t}}s~vzyZ.V@TRl޽y7ov7M$jb"?~[kyQeYO<0dNDXBLYT%뻾,,"1)OIUc`Zd-sD)E8c8%ND!CL@:)f@*GrQ3cg2Y1>>~r74]=|rpf4HDBLpR̕8)CH|wE5/[+9gELy$f"2xLNE0уǜ+eA<RJ)39y2)كǟvTć*l]U]w}ݖ"P	s  d|V6_BcNORA0䐒h#0ќ?'3 `4>\u3LŻ+{gz0"MxGdj^/w}LѢY.mۆHLICU/xX,fuH>9Yg+KI?rf]1_\>tE`WlV纺aԑ~llf|n#@	zR0EٶA2_E ZUlV-)28*(ŃGO1I=胋i}ꗿ.*ww߼ۛMt6Yàrs΍j"+ 4(r- 5\o^/=z/~xr9??;+CDCow|&H>h6	;>=Ψ?ѥ>T!aoEg*,KfƲ-n}?aw<YZ+ذ#rTjж]tm+_yC fd^-g)j0l3[)Yn/pdҤ|t/]s?2! f	X1F9!IcmlU]5NUs LBbcھzk`, sΕe5_,֧Y\Wz]WuU#t"D(}93͒iTDق2bYDVT-JUE0RB=[0t)&6	1lI	 E5 J"&8	?GdJB	ٓj;pn6[
HAf$6 *LQDMH,_nn]}00
3[cbX-3D>eEqv~~z~2S1ƬLwO1EBS)Pa#h}Pb7>Bps[N^UD8ka,w7EQ7Ǜۭe^/^~~+ b>UwM;VTqĹPSJUU=xp/(̯߼?]/Oͦ4(WeUY$]p
Cf7vuH{	YcLL4>wGJR   &[O@4L*X?;뜳EʲZEU.guQͬ->@U$IxE"ܐd[^|ﭵܴpE^ȪHC+grYV%".@PM	BJ	X1DADM`a<Q1kQdUOa|ȁc檚=|Xu/_ymw>bY[&yC7|o_1꺾|̪z1?v߱1xsyU77?0hggֵ~Oo6W<o淿1v>X!\K1㈈	QfFa߼HYS j0pYPcel 'Ԣ@)*$gn1V!cNbbPcZev("/4ĨMKdp(B02  ŉ`CYt߅FFX6_{f𖩔w+0|a*Sɜ}RLg9cgL*kj@Y_L .c5@GE"C1lȈ<N>69Ba[u{2PÄ'r=#$CL)$~Ǜ+bRCӥ+{Tɠn)|    IDAT3e$Õ+QEUؕ"e+PMO"ƔJ܉L=
9@B8b5	b?p~u
uPdoVEĢpgg;re}J)sb;+ҹa`6gg~mYUuUWU֓mOb>9H,H"$;k3ZT--Q>v[) #x$gs9R"đDfeYnT}}?Xc g[J/+.WzPVn|h_}__+2)+Gm!HJ1Y!Ƙdў7}Kwo_=z_{vZ={i!fAڶA:A{ࣀ	 μ@љ2Im UTP
cMYhl\Y(m6dw-+ú5HHlpXM]Iw﻾meYUYeYlȞ5lW<M[| sݟirɎh'0t!wh!b1ʢĬL6ddZm?\nnwdueY֋dqr<=]ղ^.gy\aHpC !r>㱶9N<UVR<"ƃ"GںvMu(3Ō:?ޫIJ;\2dՍ 3Cpv4m_hKOgl,4.:#GF	40;CT""=ܯ81C`r- ?)D<Pe EL&owQ(h(Dyyfթ@("]VFryt  }k7zl]4zl.pLdcsk3M|1 *3z`t\,o.u[]ۮ{9@}aG$a!]w;4%h0,jSxy"ιf;u}Gfi$RY\HC۝f޹p5:vTI5M'ӚD軶lv\׭n67iއ03F)YߖB9wd`(,",+gf:QiH'1p~	pVK$DBDz2==;{l)ňԶݫW痗UYite6K-oE
H9{Wzz϶m80-ga/*@(H$S9m4晱(c)j@P<4?dbHH'g>0$aeeyX@%N*bd$,ˢM~d幈_ΡȤ>zpopӺ*I""LTWpyy{wM^|qy޴a+<ɼ&*EJW:cRH1wbt!&Cb\1!!(H:YkRG`82QQ4OG~:PE8!+sR,(Ox~ƶ{c6jw92;*$΃["IatWZL@Tu~p>b}$-3E"CHtIT^ɐHFRF
D4Jq$0œ1]DQ
u@)2b"#hk2''ӓm=pTAXAo^)eM
x2{}x_1Bo2]o!8(%o"jysu}d6YVZ+_?~NM/_<Ero'?ɣ2k)j]'~:Nwʢ@ s]+1fYEp.˝D%dQ8X߆2V$.Y_"+EH ;=yF!
<b6]Y]w]zr"pO<,.d6-&se2av]Hڪ*wenտ~7{||g??{:kO||q}z {ۛ"Rz]orypt?/?{\9]>4oUъhRj;ٶaCVMʪr䙵YfmFm^2,o/)i`Ycm^M|Ck7s9n^)@Ϭ͋2Z"ϳ*< VmKO<6C" ,FvڶIa]Px"H۶MZ9xRh idEyS2)mwxu~U!&+.'ro7/Ӻʺά#wF&)ĐY %tEeɆ}yB
=an t:e9c-sDf%	<x]B JGM]
bx ﹃3]Jt2!}_uk{mskFADҙ55(u̐RI$yߴ B3,!4fӮ7߷]q}#ܚ*= Xf˃t	Ί<O&{Br3=I`I{PN$ss9 "1NX$jVYkQ<Y6ԯ<xYo..?qq~\mehY]e0qG3sm۸JZ,m|o1V߷g_^mק_d6Zk<{繋H/9SSahI ZŸ<Yf-b6j:5eEڼr W`(ON[itPTQec- YfF"kLb@׬ﻮm<DA(9+rkEiM,KmLd["j}? E5NjJEC֒Ɋ,+bZa=[k:2Eܿw6_'~_^HkUdYUeUi"|㏎_?|~rrҬ]۴MX[OIusx "gu]٬(K[LQƐU"ATL^[ݻ?OOkҩ|C< cM^"m51J(XY"Sn;a)O"D6@}w@18!z&K&1UMr0H}"IHI(h֋^ }c|#!{6L<I~G#ȈLw>2Áݗ#2uV  co p x[}Q""`jaJJIVz[FSC%
FBGr,y,'w<sW_?<{l}u޵]J{EQ 4VDʀB`沬4ѦiXDK a 0%䀩>=H;];`޾ӌ%%2N`Riz0FQ$'U۵*2եZ}b:[.2y4/=}Ͼ?8:g\ $ēׯ_|mv}[T$WdPI˗/e]cB Σ@2eJ|}H
NI7&>D "B{/AbaMXWe׶mf3u4*hڎEVYw/O6mO Gi^+?kEsp6gtϞ<xyp׳_WϿ7HCCJ'-PRi"R*H999}s2ԋpk7w< p{Am*ա6mbWDdn'3G߭7*YZimlXkOtMժȫzRMY0Ԛ@Ү!C#,+3315 	}6
2UhYV涬t:̊*@0)7BjTaI05MQV	U
SAkRz>1
`2^+鴬*@!h/E	qa</zޙ/.Ӣ(2clbD<\b`|`"ԥ|	{:ĺ3# XKRF)G 0#Ge!{#JD)~G1ĸ4&+ʪz>	Eؚ&!)ue=i^8@$r}pέ77zu4MCAC YRjKʘr1/sۮ]_^V*YN%m3/hE-<FRBp{eRTr?4!`b袪H l^1\_ysY&Xo|1Q]oZ	rYiRƕ'weV~s}rusuM)B+Ujk{Z:ub<t:am&˲dXd:+FiԞ`d0J" 1 AڐDRw`BkC1F`/3OL$^mm@!-=")J \$ԗTP\ Fv18H2c|icmo%3 cuYr(BD wƮ}Ǐϗ5f2ft2)
]	17ǯ^:9~˯^^z"ϳ<޿崺8<7'Jg"bRZ#xD$0	"Jwux\B,39F樵kA|\cV
/DSLZ%VJ!iV
Hm"_ QC"^fڀ  E{VDVI!D(ţ1^3 Il6"}҉}IX=ػ%C[tzecHD|7Hp ٳY nn")LB@@2mqwSXi4Q4!8Iq'  {@Z.*GBE8}ͳ~7ͦZN!$"W1A+]}wLfl( 6!	fXwo8"ʮ&/~{f?xwz*)S^oMEP|6h3FV77<ŢJh6).NNl6ͺڦmz2_EQ R2? e9LOΑHk꺎#kțG 9Ŝv(!&H>ͦADUfVV"ڶl63eIHXdoHBbi3! G@F{:|<;i6GOECາ%M!W &T^{G#"6*D^_z\.G/.={|X):2P%>4ޛiZMӶ-$;Fxa"}u)Ҫ2&RYFzt*zݬכ}ɂ2Eۓ%d ubM>E0VXV+ <MKkonz5L'd2)ҌdcKa02s<ԪgH EF܆4هQY"ǮCu=|*\>=u|B3:[,{|QN&eYe6Z'ҤdQ$\ĸ<VUQY>4>_vVpkc؍}X&d9EYhV1ҦLGdߍchE	oc} ]2X*I73R4&,R+^oί("V 0Glj%rL o118\@uUns~z5ͲG)e%Hn37+F!MZ98(W(BADQDk "D"1D!''sMD>&?̘yHHJ!bzr>"e<sΓ'O>z5i|!$CNDE;GrSo2mN_YYQڼȲZse2DPB,TkH (HaN̠!8TV!unV7f"(bm$Q;xHmSQ}>q^dLWD@wfI;Sr~i7uUTeYWu)oyYk|v~Zmy^WuUei3XdZ+P\\__={_~W_x
Q>;fӉ!ӿާ{xN
BrNHkʦ	>~gO
ǣ;Oyc$E	(̉xHyA'1ܑA3 0JZ'orЉ`"FJX"DADAXD1sDR:Ȝ.Ʋ $Dc֠Xy.9@ !}@)7$%	#-s?qE[fm CQL@86""b!UwhH F_$SVNozq%W	߮+"̀& F.3Me"4a>~o81&GNV`	1ٛF Iեܻ>Ncz>ҚrC(@\_H.6%fΌIET6Q4-`ؠҕٶuz;o'?/+ z:D]>,R֓՛t7-ݣ;{$8??O\6L&'D|.5R}__볢4B.,˘E 9H oCaA#sD"λ~:Ryu}QJEKTZiBX6Ӻ \޽{EQ>p߿8Cx߷m׶]s.oVC;TQxzDiAaIȒE$8cxDWwy///..uQw<&m4ֲ߻Gr̳ܬVMHLՎ*ŉZ"4!i1+JdUw!m7u׶YQf0k#S1R`LjfPcDJF 9r]v]}^ojZrXL'1vLGf ی82h`ItbT(ef$"%L{S)TaϭLBCnzu=uV2r`_dZU@uG7a
Q5_"F!֣nn:<JX̱luUEq[Et>Zkޝ7Rt,(s$°fѝt{gbR*@@fIYy{Pd>,<ߜ]yBk!)@H-"@Fd0Yj"Hid"czXJ7秙&˕<	Cdf![vzއCхdO.q6Ӗ:(NzODZhEFwCΥGq]z*y!t#}	#"95R̬2!Q]UYMj9}O=h#߿9~6+TRDS>}ȼtbۘa쪿h[,"81EQeYEQUUWr26uZphI
`QP,B* :"HRh)4 	"2I&    IDAT/&/ڬ./Oߜ_]_>/5}SZmRƤH 3  z+HSAeRON6˳</}i9;;/l6,t2Emg ;Sj) ҃L*'j2sO G?nޜ/>ϟ5Փ>N~_ѓ'U]:` 33҆"Tȡ֛o~ϟٝZ-B%JЂ<Q0(9ѐ~VZ6Fg֚Q_?&c''z @L"2qQbPS`hv(BQ@0caE *Nm1SP%m%^vWh%&l%7GyBi,!E"E$3,"33$k&B8}qpHwLOo n%hPV'(V IzE	5Qb(B$Mx4G+Cmqߑp|CDH1cTpJʲ|R޻^_߬VMlN	X$+#BD"ctge3*|  `:=~e[rmJe莒6hZ"3JkʦUnr~_| {@`ɧQvZĈ|ZU'ݗ?~;;żL1ژuνã"uM۬nnĻGw"֦ڳ_{DBTe]XVB2k<r1MD,\P}4JQHlR,\eEHw.vE{UMn17miH|6,E f&?y*K}49ag/O~ٯ^xǏʲEog?-)*ql2J)(9 @_;@lfޟ{tx7Ps&   @jy3l{aktUj ZRM7UfulU]Ap}j!(Z),(Ffc#:F)jLznlV[7zlۛUUDK'PP;w"IQs>ECx499`(kd"2ksD#m(ğ ?\=8>~_/&ޝl2k>JNI1#QJDуuUFf5И|5CRF1Ķ\\<?x"CFAQpDĲ{qyq f!FOM`c=uQ
C4:6HJJAb戰.zch6ME\b|٬OX=z2+,
cml}Q$0$hyy}x`?ϲӓՅklH	vw%kxwO+4dI.eP"	wʄBX+7yXMCH<I"z75sF#Dv7	H }O
Dȼe=W?H! ~Wɛ"ʲmA b$ݍIħhOSEQ4LHDd#@  @m ͪ[6.RwQ"#<ܾ7Ϩ$ADt?o_W]]]ȬU%m^EI^dZ	 HT%h8?  FpDb4IVJlV7{Ԧ餞b3f4u]eYim  K@!ɤZ}9')A2T*~%q;e<7'_<{vOャ#& yQ#泿O_9קϞ+@yp0" ,|{/[[jHU	Bh1cV	
-(1$IuZ1;Eo!٥ xgim+;r"m@UdpkސH}"2QD᫆SCɆZY@K?,*%K4m1 G@jgF1oAR>@Ai2)atnQxx=Y[BRĊn!"\Yϊu!$xp$]Mӂb6#a eyQ䙵!t}Q&Axkś__]kEdYQͦ=|Uvu%1ն_Ey8./bq;A<0:O,zz޽/Eh2:)ڴӗu^9UMkaXDVej {21ųN^!B׻<ƒґ9RcNu(*RIkV)utyQv]diU".̮wk6"jt:	#Ei{mroYzn6pi6M>*уֽCR
piъmW/WifM쪫Ȳ3"dx1)?ɝ'Ͳj27뵩}$:"XZGۖ70FDъb1L_9r1e<+D`K@zNBm?{"54n:S|ۗ&vmEQ4 )bdB׶B׶Mv<` D9DD3g pS̬If!|1jA$ M9QUlnմ{uꬬz2ˢ̬JɀANg?Ҋ6q蓎 $]6ډ;oU	Da	Vۊl5vRn"uÃ|گ֛iΣ"sU:2c2RZkMVw ^sduu?,	)+EkW7ͤ')ǈccsqN'=KO>N* "B(]ݬV,B Dy|0E bey+c\Ҏ&- J,rkڮ,bC۲&$YX,s'9Znnn y*mcd<E9*S1e5_Yb^1w9OaC;`H^PtB2-bj!w!1q0v(`ݤРSHҭ0(贉Ϧwݻ{nBeY?yri
}xvssS!~x7bdIYBuYQ{籈° UeQEYe]gEi\jJZM
YATfnHoMǌx}u_bܻ{RقwIl-u^75*CP<~~c!.fi]󲪫2%1VtOAi hBTZ)m! !eYbP.ĤUYj2͋7gMY,{r1Of,	i@DkroѵM"<'ԉҊBLKa?ynVONm{tv>Y (imT˗/yoƹ㏞L'l^oOޜfs "h5>Ӥ2meZI,EdJ)ĞIܴǍHl( Bah]*0$%ҷ3b
Gֈ$t!'~ZߦQdޥ/f8b2w1M 	1ɳ!JDW^mDz@~*o|i"hR"7AHm50x' (B)P)ap:H~)"I`,&d{@CVc[M1yee6)BD HHL iu~ѬW̜"4֪,KY֝Փ(A 1QF"4V&F~OܻgP'3cdeXdus}}f6N˔64/>'/dY8>	1Zcʲlus=/roѓn7|jtO֫^)Ni]"JJ	wyQd1C^iM0)mր@鄔]4&8b)Iie????~}<RB3jmE9vimsQ ^fu]>xd9b4 H4m)6F  (rkCyQfYNJeJgYWz:=}Dǟ|dyϞ7kczdoV(qrc@!^]|ރr8;=iv\,'mʪަ  L-r,Y O?Y6e2ƅ;)-\ wJ	jL(l>_u׶}5M׵ιzõXD o,d$1@VĢ("뺶;;f	>4,fz8P2PN|cnjKQ(	F_߃nmK	&$L%IBv];#3)]!w;!Io6(ޞT"圿8yy,}=$r[k`f\ᝲ@XRz]OjB@1@d'!2S>%eYXk RM)" 6/B1XkBkfH*:Q.rrw}vj/sA]u>YSN-nq}T*xEFBk&#' ['3'5'2T)  tD	1r7(;K{'6Ḻ$LZ<?8<8<ܟO"zrÏ>BۜWח'ϾzW*z<?N^"@<A?a,"/ȋ*2+
m-l6HLD[("$pR:8wy=[IY&~z6
SGasͦY7FT h6/=ο;gmӔ!hUug(+"Ԛ@YBT8SgSH$Hzm$dP)2J! 3Bp%"BC,6&6i@64Xt΀A<ϔBIUJr_c>0]ϖ{ggo޼^%,dRZi 04bu}uWǯߜAedzPsW}g]OfsU:8?EXvt`<^pl]I̠Ri֓T>ؑ?L 9fm?Q+8"H1a >}  #EGXe{y1ƭKڹbE8Ƹ9`5sa s[yLD/ODOPEZtN6ʇ><{KnDNQ*RHTʾ 2߶v
?qy+mjT[GbL(A<
,"{C cV)P;Y,
	kc3p\7mڰQ' "Fb@X.λx|4MsHactYV(C~{!%,+:.п0wx9~HQ*3k*{tͦ1XcӧO?n7ˋ˽D?scιdJ"	RYY|V/W1hځH9#Z)6?z(32a"t>ϦYffi֚靓fiMw\i}m۶Mu
scm]WUR"ڬnɲC] Lll4f2w!{!\O'ɲ~~/~9mu]>z~ ­gK,I,n1o_dXιYVe]W{aVcQ$mu,h3Y~?;=91,a5  o[
0p}zJ!# 'Mu޹ͦbPڶ5
pnt (6t68q4NyBp}lRӏEV77+Ue=*s1)Mj~( l{,v\9{aF\QdeG ;_2oin9ũA̦$FNiiAUYwEtr\TZ@U"d#HJio~V
R&R\Ŭc}j'OTj)EjB@Ca</B)A&B*xRU뛛jXV$,J"*XnR	"H1޹Ymmkz7,D9zLY~ptNEo7QU@:KmgRCiv黖;_~"1̑R*6iT(
"0h)vX$ɢ	/m 0"F+Ȩ3")XL9Z.Ugᓏс6(fz?ޡ;ۑĘ"HIeB( 6E)m&z>Mg,lQ)cu$fQ@
A@4y@(H(E4 BD$z]!bYOOW_닛fb6Ե֤TRkºTUUu5rJSZF$;gV+a{oG=<>~uQ}߷acdre:Y(5JkB$A%,	*#d-IHQ$nH{</K"7zY./,Mzoqݣ|y?8RjsX"EsOca\	Z;GGtg_f{wLDo7wϾY7L>zpo癋篎_)"yQO8 `PGFDBL7DapۏkR 9};a!  
){'˒>윓gUUwQ!Ef?>H !,vǶr]}{_UW,f5͛ys x' `9ҵ<HI9'/Wǐ<n MO?0AEpcGD YC =(P ;phWBaT Qʤ}(cfm
B~B瑱)D${$~` phRNt2͋{DmgE(TeYm樵̽|9k#Z ]!rg}WG_^_]hmf<P_Ţ4~dd:N'~_7!afqCX[|=~o!EFFɳv4mOO/I/տ̝'E7 XfIyJ__n7n^dgSK$Ew̔n"oWsEEAZu	 "1 )!=~ÛBȬm7ob2yo"iel哲X3_v]		+|>Nw76:ɲ|>_D`!8皶SmUEu·s"5"b_??{N/YVՋٶw RHꩈT `EYFWUVGt~_7̌ G'-8Rwt?pM5<o.,!Ly	[Qq#%&@D@A X    IDAT<sI5fu]v̀\s Q%ЂJ hFB66",r"2N&nI6z["?9yZgH"Έ?F:.,f%_(IY|"DṞo6oߞUu:ؤ 	]WRUYXcBd:R/I	> bҿL<9shu<_,<yZM-&t65
`:q(B,"KI@]v'IvUD`!A&k҆HA"R]}2zY'CɼȇF;TǍ%pJf([s~}]Ͼc,<|t||٬ofYTdu||셐>$z}u}mzS7}]#"#Ӡ=(W2	( 2&tA5Vx=?	TP+Ԋ9IptQd>/GGg/VKό5Y{7 P &ƈJQ+'wGf@+UEQNj^U2d9$;gpd|LNr * )$	]6k5]֮&H-̚w䩘gU1rXVqQZ<|+[V:$RbuwEp.l1pㆌ 9yj(Q++P0֦61#1xwy:{sMX3fkۺi9yUǫǏeyAJ'.w YkYs>}/igɲO?9;9z_}շ<7ƸyW/߼>(g6+ͬ.7/_|?{>[x̔4򗈓8՜PJtXDW7IQ5*|7A3 $O	|Ȑ $m$bDL @ 	@<#OB [asΐCf@vv0K0rH{&QC4F =,{^g  :yuI iE4 &@ RDIPXPX}|H(Џ3"#]`rMJDk[1[E(DZv6&<"GQ&2k<.rX>>~CB0 pw^|"
":::Z,L^xy5޾}m'Ϫ41 0D?%|gx?<6{a~h=Y-^o<ZMO~71?9]g͋"Uމ㘺Jgϻ֛uuEO6-:ˢȗn?<D!gs-'{J=I4E)1|bY7 ~:>~xo_	gv]]Yk&k[SdUY}YY^;<"$F,j:$zbDc(	!dy:!9'Ui*n߼yNEdXϝ7}46{.xA1цFw)E 013@׶W|q4Nw]4d:wfQJ%Ӏn <ޞW担1v@n U *O84k?5aft^U5Ͳs.s.Ǥ;"0+Hz )-̚;kѠ
06HIv`/DeyҙKsMׂ5sں(ʄh  4uYR$z}sru\6Q}/N#Ec<Oj"p ReGt^Vʲ*9*1wıgx)q furcL:P P`0wmYl6w֚T,Φ?~ni` ;6AT*BEzV7_"HF¸$I)E*"ĦyQ,O:1rUUf8
|È; &=fTdR2,'im\vmu_,?}d~ctr>LgS薊܈AA &cyCƪA%1ɤ$C @*Ly~L V02)Er%pD	1yy6TǫGN=}||~d>@c,G|__;gc,2j/!	6'<Z "yLK[L&y91,3kB 0x]6/DXS6Zr		,1MuIi]Ӵε% H}P!DB";G`sٽxdyZI'8
pj\<Qݐ	)t(mmhXՌGqQBI*SsP	TD	'
5]Tm[e!)>ޅM]"ɬ%Bm߷}Sv{\4G*1OY^7d &J!pl(eY̑Hio߾~~_sygD*z4M]ulU|2sYYG%,#2ݸQ8 p$r(Mte䉁A^g8-q-F$ M8 
0gB8 0dHUhm:F1<It/`Bf<&/"H(c!ˁ(xweoJ,R<ڳ$p`)|%I j@%t4*D"-,ZPH*@j@B~)7U<NAH"߿B#Dp!dEyw0/KE7 `PBA-BD8ڶ89!V *׫C_o6n[fw͎Co6yl6l^֊%8zQ>yjN
K~Cq  ݊<>7r.s  GE]7W7#N߆ও;:BӊJEfbkW7|A1u/ihuvf沪1|y:- Dά曯nkkWOმCeQrdFvt, PyVy^QJe66ۍejeoY9&=:j6 ,#E޹m"Pܹ>Y$c!p |1&̏RQߝeYVynj3z:u>O~p1z냏1Ȁ1K1X|wߞ=zTMgǫzo"
ݞ2Fgld,̬ݬo߾#."+o=ekra+)ˊrR<=\];R28)`OgY׵;dEɳRl|&-IH(1XIfAGcw!n\fY"JL	NˣD
 !FI}}I}wWEz2CMvG0$}k^_(Ut:f|t4(z6D֚>  s}ߵF+(`J[@ DH	Uߵm}cT)EE?߬|!Y y 11rX)-0S؂$Xe0%~f J(&EQFDhT?0st$#46 RY[}pƞ[Jd2!$	'si7ЧF,JTJ*Fb਄pZx8Tj$f:]	Z.đ LIIB Du^iur|'O>}K\__9֦^.GAqawAII)gȳ(ɤ.rZd %{wɉs}[7]sڢ̲s 9f|.z!mӵmr|h I3:+dj%" &M޿n7M|
s9*,7Y&"$]U1yy.r9/=[kɆ[HX-ɻIat;EHl5u4}}uY7vZkͬRMm%a޹m709~ARGl:-pՕ!2Ar}۷.vMozTQh&2$ŀHbK$IMw+)f!>`f 4	!(
G!/H{TObϩ7 rpP %R&1jCPZDh6Cq&p% }D/> Æz  |($< 6I D@2ZSZCoI) *
h蹿Y!/@J'=~0iCr>k_DPL 8;"Zss!)5ج3Q)B*ʬٷ{s)1MH(2ZkcW/|m릩nW-D5r2ɫYfJ)FLH;Wo_9^̖I*Y<ŋЇ#Bx2=8_zٴ<]-..._~=}!RFuJ76MUEQ&nc`yI]޼y^]?>^ˣz!,4a?T\"2sS}uv\~~MsXM<]zs' ӇyUeQEm?x ϳl@ݴWrב$V!tr
X.9tdYok]],.ZX,"q@>u3A.B(b0/?yɓ]1i@u\&,˳fYe:mi#{MJ(	jĩprCY  
r ODDFee!1wxjs<\o8)
k[YF  Be!#@#E	(Y[ |Mfaߺit6jTǟtvy3 ![!8'aaq"RYGGGmS5= 2?[g8=h9 I-d#0"пwT@18.RY__>:{_wzwfAR # ^ĻHXJ))8GZB1FtqR"ݭyhG?,jl3P{qD|]7m}vxyPټ}JP(v=i']>8皦;4mM%#h̢IIc<R9ᯒBLYad"f @!(4n҉:XSb1ɟɟ<|O?WV(Jl:y~?-cV"JasO0KXʲ˲L^9tVrB:Cm5 @oq}S7ח}3n}VGş=z߼_{XB,դ8:ZV'2/J0}o6ח_}.w}f(
QQHW#Z+mI[c(Hzw}|rzwqy<ˊ<[,lY&HaQDϬj=:ZD]_zիwޅ$4/]Wj؟>x{<pﾻ|L6Yafi5/݋/ @+mF{>("V5(bpZTZHe:̣e=ﱣ`dJQAn0 DHbRCib Iq Q( V"/-܇q" Qz11>HL K]A)g|{  8b) E_	gG1% Z(Mf	wGdNo"%At˚CS>W h>֏Obpϐ}tE1Y"Eeict^׻v$T2mftZ	>2Cd~?z2rr.g'Yb 8XXkRc]Own;hC &?$Q (PLf?O8M7rS{1*ݥ  J__]G @1O-|\r `6"1S)Y1QD$IZkrټ~_G)n\yg٣!0/̛t6sn<&E'e+h1/u]Dkk!@Vȁ`3Fҽ|\*EH#߇OϿxi'󲚈}̧bV:0̒B:Nh$@6''?{M`<!2 onNbie$h r
bA6ΔHI1pu+9ƥDTJFA|$!纮)*	L8@@)lL0ѨQeeYeFg&2k,,1ɍGB z	Guz}l=,XKDȁY| (twC'L閹TD<  2tJiYJw'4)םEYE	,0~_:HHJ1s>=F?=)urzW?vm6뛫w77z1BD@t5ȟHpĈ D|a@E `P"R XYar-@` %$Q<ub]UeD)o$ kI";(H>8o{׶]!IGB"(hr(yy:gDCOf"#
G_sK/I)E*j ¼<2XOgO~駫k"y{_tJD#Km7uMd5Κֺ*ȳj^Mfiʩ-gY^mQFkT*DM[7}Ӵm]9߶]4m SWGYEQY^*
nݬr<]\#T%0:y^r~4/f,7)fݮo֗ח7uSڮKJp< 1P7ނҠ-J	 .hfoDj:!b0*q6,b6N&dGcߓ1dp ~`hJ{&}'pRO-&r{]  q^ێ/=<=b:=S`v#"I @"HLʧϞKMo73; PRĦZey.'}qyEA1g	!$Y$Q4pyG7004Dx*zȈ)Cxސ> FY+90 ${Ĩȳ˜7Zi}8>B2\"1YY@^3 w8&l0nqa}AR:ȉ )EPiIAG-PE۩.3Fbb$H %L/#ƃ.έQ+ @JQ"O3 SN ]އmcUUeٻ#b,Rlt]- K\hG8ALQn Xk</2v5m?ytKml:T    IDAT	qi&3B   	#.$~fpqopWsEksݻWW7}k,zKL>~<XQ̖yq|rD,H̜繱,dffMg3wƚpA+5TP-ffn֓^oum9Ei]_UlBwJd2*˲ B$:lUtuqIiv0jZ0&@b!IADhR`!r޼~[;NN&Wa@s}dBR^__oۧOO6뻴	Npbĵ
!$]ChV|&˒;àx%?ckAb#'z$齏[DclĳGaRǴ
 LdqKE$D&R5j:La.="ɅAcB֔"e20,F+}4]Eߗe)2Ϭ1&	oPQ")c	bo;H
H!" zUit.&XKӶއlnmXܽf0ܡ@eYnADB@ᡴ9M1UY ˕u~\7z}uyyf}YoFa#$FRV9kc8RLVjpbPUlRJ)DEYMH{Ǩ~%a}GDl\VDk`D>(LKs!dl;9}1Bp/5ʽ HL̘t/f1$v7 MxHiSI`B"-&>O>O<<;9=ʂPޟ{hY$6
M6+,ʢ,2fEQU2\hvos]u;ozlvmS"s{ǂ6+,\&|aժiv޷]J5̠"IBTHfYY(ӿcs}[ߴm[7f}|w۶]V2V4i"DH/F%Tjc)2km@b*h1F; Hj2cf>KyfQJ!p.vM~۠?ĤV42ϲܾye]E ʋʇе;i0[fC0}jDgi>~gCE lU"Edt7ژNN<~,/*QxߺOnw?4|H$- 
$: !9xؑDD0E2䁔:{*>bx(|L-/a!w3c f1T,e%^kmDx5`1ȉ; <cN
 jĀQ`D`aE7zǃ  XA4FiV|'uzI;	d%2HTr/{@I "cr"1$=>\ӴDdL۬#G"$m(2/Je3m,bYBZE^vPc!rE**,Ť,6iIYn&MD,i/vWW5Hхێ@#h {`L
>>{R,RţG^ ,gf"A IO>Ygb6M&Ӧ$YDp>l! j1$!te$OOVyfO(q_7}W_>tϞ?,rU۶M禳ȓ\~;ڦ)'<ZygYYU̒lm3"18Ǘo6& u5$3^1OD4pBhTIwmMgşfUk&62,.c:A$8cwkۈU@(un'Ƀ3) t
 3kD >@!kWo޾), ,x%tBhuVKB0F'qy{zT2$ |߹k"@XP堪?вhLA'(3k8At
x	!&mOHӹΫxnlڶ{H)"Z,|>N&Y+B#gvX o6<#1屙y^4w(GE9|QUPHS6$ zD\3͝w!AF	5%/d2Tݣa\>޹m!6)|:)*Hn_}o~w;hp1E1w	#8c7yZŠ\=8U~VXmL`qLf&"ϳ("Ԃ s2$bUӪ\HzR%8()%(@cN~>Υ;#8a?M|cB~r`9tI%=VR`!*T:}j<Q)fRiʋh|ɟٿxك "P7/'eew A""c3kM1OrU̖eU ߚbga]u~Wovn}W׶]Υ:rD2>
ne&˳iUVǳlw.DHJ|>'i[m ]\//޽Z__nMۻh<<%5S HT:1hF,ϵؼ(MQ@J >Ƀ<$Ơt(>BQtD}ld:)dbqn㗖PCch:J ||ur>_ @u}qy%,F'kL3NfYI0KF4kMU;皦JVB RJ)2Z,GģgGǧhŐ&B>;,8(cc`B,J9>Rg  0@}Xű0JIN70m."3
&	8D0A"`dvC` G? (#q`T2R򆝋)(2@IVJRzx&[ 5TW	!w?H"D<X_!C\ )g OAG@ #YCT! $CG}w]?N(<'yeEW(;w[u	guwQ' yVEYUegYnƈHQUҏJ=i3;ۦ]oo^|mqu{&'w?4	LF
oBw Mn6;\1r\oMkz2CpD
hS*u]$E"DQH75iSTb0D50z:bn:,泦^zZ.rŋg3.Md<+٫ׯ%ZSQZ!N u,t"#fW7muJiH	 *`"H{]}ӾGD@
c6 H)bp}WȲG7чl	:˲(ke2ͼDtt9|)mEl>muۧPvEQ	@d
z@#H:ޝyzur ]
	_@}Ed|<NҲ.ds,a"${6{103EQ zTN&,?B/ۦ5/5~y16l1f|R eQ놮A @<>>7v}]w8jgL&S&cmPgYqr2s H'x $Z3HjLy9	C6NA̹申RGus׿_ͧHC&@hۨBIJe6Ϭ5, |k|:28&eYn1Z͓s7Dpr*$ID:+RAbF |H_׶·9!}>p

}|!r>,̬ DIX)FⱚVZBxҩ$"0&"yynY>Osͽ%izrO'S8W,I0ŬLdy4E5"UX6Ʈٮwui[s}4zlwu;& e-ȳ"ˌJ2VZއvvZyQcӽ߹2_Nl:L),w7on}w>I]U?<7o^o]\RQZZJ'ȭZ[k,	)LLZ3nDO<DD("ZiCd>}_7o׀Mvٜ_^/KMۅ2^CÓe@u'$//^lw[z://y␤<~g.ZeE@"nZOg|~tۦ4/˲G}gJ2+uV-slQS/1P&A{]@.EcB VPE!1F0i{!A׉t6 @wDuC DqH4
3HAiL08p^-/& |KF@&-c&K$_t;HR)HQB҈8xS'S	JC\n) BJ2 $Gd!#-.鑀Ib@YHR 
!(|[|..pqQi}1~$mlVeYVD%FZ)cL! NXyQy[k@g,iʐ" H`*{AqΝۛvӴQq(5&q
_Ѹ%QAK~ LDHj|x
xzlVB4#FDPqGzP-WUQ'	RMd	IX\<|*3y׫d2]v7W'ǫ>^oZgz^*=0HarQ7]MyUK/_mY0v>VaM$9;w{\yg `!grd"W& o2(V1h+8xO<2 g\mmHw!	 AE
[0s?7G:6v*gapEU%@4hUO{?$ZfTU5xz4|6;vD}}}=_1v#C{
w_Tfp"(3"bcXH)cƁDIV(TVX0L{˒AEsӛiD1'3F+BL!1I1A(7<~LbADx:m 0q(۶].˫8::4Vul}Ԑ\j$
BtLf3bpOz?1;Ƚ}XT"/	QcD" #kS霌Sk+iz\)dWOGO=_qu{-!feNL H"{g-Pb9ky늢4j4	.dز,`c2Jj-EDٗQm9c3Hi؁$c6	송?0>zC2Zg}8**acF*,*00RۂEDIucFCǊ$$2W8g]Y}駟|Gd:Vb|_~3t!fԼAXc˲tEŮEQVU4E=-++Ua0CnWכz޴znz\nݶ뻜qkǄD
SL$2Nuc;ez}}آ,˺iGd2UucEaݬnWo^z۳ju0x Nk9+)v}\~Z?/ B 423agYg)qU#D1}'ڢj1")ƈ@AT3Xfd>m۶۶ooi]OӉeYnZEqCTU6fO}EAⲬfy۵]ߣ31FWwdv
c*74qˍ*"rVR`r>g|駿ݟ>_m
&dcd"Ï~XOfͶ6e=(fS:ИrG$l~fܮKmDdܔaΖ=pgg#$FId   2YV܇
c`UAPBٯhkD r[1V4**"
|K{BUÞ:⽼/EQs|Ќw@fܨ Dư3&s5'ls&Ļ9psg鮮IBBu{/\^T4!( E5BiaJGЃ"	d;E]א$+0!eD*Ha,ip*+kk͘Lw B1a)_}/|1D(dv|ɓcc+1?X-F.NO=?ާf6еۺid%422CV~fNp6z̆qB Z]$Ift6|HEUf!ī,N?n7l!]cUZ)iSa~ &6\VUYfM1ZWj6ɔRJv{M,$F h@և %LUE4ᑵDؤˋl望M']ׯ6*{_"Ơ)V)R!HJ2dV>cCۛif2+Ivy+"﮹cw63@I8N-wW{l|x\Qb)+
sn@eeL\=}rWm*d (u
@Tuv("UU-oo1) I1>?xbwm~]YV9DJktYhO	 DLƔ
H( rRռ4_HXWU;ZU3BDq͇J1"H2:;uc6m~oO"#u>HQE|{
Ua֔(V5n!%y;hZ0l017e9O&fC:[6>cEQUUY9k5VwqjRB@J%tmQu}%H.Z>C?~Abއ1ǔ]<TfH.h1+1%D2]Q&  K)F? 1$g5s٧?'uW`8kLasEYifꪙ+˲bSJJ)]avnjZv۶}vr^ uUUi*g. *tTU4(UQ󆦈ĮpU]OGGG~usqsu}yWgo^9;Y1>+F n_x~p'!Eᓌn}F"b6c4\)M9Z:m;Dmڹ"3g("!iJ"0} Y_t((]zSmrZ֫գa>]f)XkqG@V4`jy8B7e,"oöV2%1rFݿ?ƻ/'P$ԌRӥQ U4#.| GGtnۿ%"Chgxk]Y|0"    IDAT߼|X)WI!!21TIUD{Z>ױ9,
 T0*]6Eëd:ĝR僑Pv4JQ1|stiG|FsMtjj91[D0l1Č&=aQ=?bex_3)wwSjw}uƊw}
 ʽA4@AEU+ _T M"@S}?aURU ^5GSLUI( H%1
:n
XcĦ,KW6iId1%f~{vvqqm7f:N&`88:p{ӤVy *Óhb/ǏNyp۶MΚ_onY.acͷxHȬ$  "^om<FUB\]Ƙ¦BƘRLy)@b6L'1նs7ruW/~z臟>?=|G~P^瓺ܬT7sv^U1bΆ[nur Ц48W9cƟEE);E  125uEџ_\u{noo	`>P5|Pb l--vMۍ
VdXz20Sv ݛM"Y&%T$w	$2sgX<jʮ>*pT~8O$15$& `{".1dUE%HDX}W;7p'S7妁*(w8MCT0,51}ߵ]۶]D	Y[SWTCRB6eQguO,Kau?^.@at߾x*!ˋsֳim<zxy#Ad`N(	"`v{6$bxnGH"ٶzػe6QDk?~Ul^vٌUYG{MQ Ð"uv#"2/5|tC{us{+WCn7ٲl2))D! ^jKA)w2TBB!Wu]uO|}m	Qx犑Xj2EfE~<~2e~EdjuwŘkJgJgR=?>f l$ZeqqU0]뻶ۛas]_]]]]]7eЇpQ[wu!4$d, 0a2d6֐8V+bUU/󣣓'CXޞ}/׿_|rņsnbuY
Z"Z&no,qEf28oY=WvGOe߀;mއ_m׫Q{ g=L=z}mɣ$9:>mo9(}w%فKz#uS_a,\ߠ8{cue=Oǵg<{@DUmY޺/ixd8$4<=}g򛯳ꁵEYUH4_,>W\^_aXg>:Dmެ"Wn67fV[QJ1!-v;4SÆn;C޹_DHԃuLBp>Ϫ@p/	vFt+"{ /+b4@MT$o^rYz %bG"sl!Nr:ǌD&Kd#٥y^c_+{pY,w`!A	  (joƤ@  C$]i!L|Rc]DADO?
Ƥjؚh2
4;!b6.ڔ+JkNfo0a0CIҽk5>䓘Rt88<:<:.2Cm!e *~ObWo#" -?My*	Tǟ۷777.
5(;yw+vI"tv`m~W˛aEX~>EJbtMSWYQMC\e5ַ͋/>Ǜz:9>|Y^=>~4]UU>v}_Ts,v,, ,oo%!R%!MXC )~M`(d2 c̮1S!IRY۶\L'7MمSD*ajIMSjLpU^nXUbA݆v=BFt0
BL=Fx}H{$~vJ`w{"djPL?$(ٶ[uteQB)zت٨$κvj:䯄HbȸSDd6T$)UzenR$bRfk]Y(lSP%6̙ﻮjfkq',INzWԑr9[$z$:/28sXo{WvU4
p6e.]1X$	ڡ1dbcaf±Q  8X"CbӉu:)usz?ds,a00"{+N<A]Տ?453H`[6eSWP;.B
C[tL )r:gl)r#Bۋ^ۛeLB7]\(Rբ6P PŘv=\X#ߕDf2L-sIEX&xvpXՕ3!ЋE>!DRby||ǟ}i\2uo/~&ⓓÓ|^7bKlBBC}m٬WflvZo~?}crœ9gs0%)ļPbD̦ c9 j:/IcUz:_n޼_}/^~zfG|yJuausX<yfEQAIMp!GF#:"qRCY:
v!V-K&>>|ry{l~KE(M{ss;J !AUS@ݵ>Ю!	$Vu/>C4nC?}R^]Ifb} z_ .J>8ԾOߢ)	ON~?|}O?'}qvz{~DEYӏ/aHٌ]IEUmY77/[^<g)$86 H2ʃ!$*@RT֌%;mBmsj kn2<hQjnH?TQ6  L$0Fd1a"WB
g9[^ݿ/;ЊjQKBp|YR@`{"&QEI*tcM*ݩ&QCРH,8$EԄHC?}m.!{cDvnt%"=j|1Nm]YP#%xteE6uv̲b!Sےhr{,x2qB*^2J~9v˳y`ɣR]dYw]nrZ]H(Jc-"Q "gꪞL&
c_~qy~6t۬l_f^o6O
skWT}渇v-WzUUW<LO&+Vk&d> Q t:L  xss{yy-^)*c|x'=|ofY;cqtS66tvy|vX|"2qAU:"ꇈ9aPզl[f*"/n}9k_|*uۭCUL(
^ep9{*H;\bQ@8# F!AanZ"JTE!Ġ)"!jwa8}Ռ!Q3LdtЦ̺_s~IDE4[f_22X@3ኙCD\bj639yXs(c-âJ;ۨ= ];`z7	*mWjͲ'+ڥ1BnF1S&.ԇ{rEUVU`SI2|zcA5VUe	c6*(%fl+Ol'Ș&.j1+T!Q%jmĄUǖur!%"xaI m!W"FCKmjDH5kyGD,|^M1@rYW\Db۶]\%ǏN~}O>8}VU%؂cnz٫6nvx88<<̏ԕ'})	еjZ׫jY^ެVvn7z۵}NcYFDcbZ,l>-k*Ƣ#|Elq:\YiQ,]vf\\_|_|g7mŔMN<^4l
gz:G<ybq4OP*[ $T 1LIaXXUe=dI=0r@0!î]34)|l/.nmۅsn6}RZV]DRJX&u=(9=6%ĆIuiJIUήmLB8{H*ZUvo[3]!RU$!{σ"
*	iy Gϟ?͟.7oaMg>zU^Jbq1u^^YWBUMqfZnKI)azԱ;|k#>/MTHP4 0H"ދh$ ʻ(`A?~t=qC	v=03 1Fd89bDӢʨ,}wWG;ߦ ]!b, Qs):9E%4 QTWP ԔD2ڲ!a}}HrXvRr֖ΑY($(Siu]WeQ9W8Wh.s 0:WubT+,rOu*d\QeAGN	!* hH$>{@|Mo5H)5M:bB*zxpƾ~{nhJqwcy')u}f٤,ۿՊ
;fI!f}}\o?`1CĔʢ	,zlv!ĘG'Gx{}ݶY2ƨZ[cڮߴ]Ji|H)XVu3ez\e& Dm}믂c{DF
C	*/sEn|Q]7GK6 3p1+sH uljM1dضmyxppxT5l:1Qa4ᮉcV6z0g6ҿ{ŹSE|}`t2b>"1灠IaJ)Q}~ Ps߻7wyDE"TѴHL)ow P4 @;;eNf`w9LD9Ii^^]	M^ggجXkq`cIb8QY}JU$a`6G\E@b 1ƶndjI`*¬9EXUQrg5J9 !&`2qhLp",*L
4󱌽0j+u&>)&O ĆA4=IDvbt$i?t,kʪ4Z#5bf.2jL
F!|l$K1 w,#"EY5p,D44#fdD۶o_y]~G?GeY$v8W/߾n<tZjOmfn7f]n6jܴv.$h
c(lQVUYN`>=<<9!x-\aT+@ 6yB1;R(벘E]:B>Wry{}sXޞ]\7_xfް)i(0;keY-tv|rgO>鳃O!RJRd܏>}MXPUdv۶pt0ƺbXj@ $,)M]_^]_,9-A餱ֶ]wry*2Z+:>=5aLc?Y;s!*˸nBY"1[df	)xՏv$yR#v"RRDB⤮~7~OOO!&VQ'}gsunZ./W/Y<zpt|_j\JΩHŐZF@dk.ݻJBferBb>SW ]>
I oLwYqX!0iۑr&RsnƖ8VBH#cn1:AffșeHw/+nn7?o'28>]2EMьfU<*xX{\|PAjLȨ@:DPjr)s}yS]!1R7DU&uƉblԍSE69U9LǇM]*p!jqhJ)N=QʖEzBy#*A=B\=@=Kv5<_ q矹_|hdS0M'5a1xI~r9L̕ ~ 'Yw~ԛ_gkMS9Fdm߼?zv DbJΑhd2I֫jn&l6?8<zu(sB~H1<vNUJdbq֒1ƺ/_.KDZXV# 
(0G%h	1LLy#E "e;U1|ZgӦi68_ds0f3	ҕ5z]7S.gm?,'l>G轪Lp1'JJf|~@D4ri6sCOQd!DSR)Es/b] F( AbV޷qWm*)0 (=!b$ )j=A	ǚQ  Qr-aBQ#*w Y9Bd6"
SLK˗7WDjP)ja6U9KOkVEa1̅1>?	RVCjVW	E5}/Wj=/>æa+2nm*'u9) CHcb~VTpTΰar&q=N|^nR֔{Md8
h3>{(	dSU(IQ5d\no9gD:`5GٽmT%QQ%Iib&Ha|1
EDp/	T*1Ʊ lX	2w)o6Fg"U$")6hNPCׯ^~w<9OzBH йb}{o~C6F>O&n/./o/onofl| d9WZ@Dd6_g sA;HLlW#P    IDATQQ$d-5\b:uΑDo߾iM]mwH;)km95Ǐ<~<}ǳZl)cDF]{iҮ'28 "~n$I֕%w@c9aO:k>8}v|8o^\\ߦZ4ô^cysՓyS7935
fFUl1y/_nۖ=}Wo֛M^Slqfؒ=Dw=Il  GlYψT!swǿM;?GOYWֺ>DP9;mjկϛ6l?7ѯw?Ͼ+dʲ&ӧXdՔ:h#d%tM 	!E AM̖r@ܘ{TWE  0B   @	ϟF7; /tt̿;z>=zrZ43[EQx2f+D`tz|tp7U-/vݪ!ΘH$1F%CRha$c^4DBS|/g]  {e}fH0v*$rOC>}H1vԕ1fv)I]{AH  ٕeLf۶]_~U8[WՓO4lz߇b1_zOc]""q^7OfW^~_콷?MqJ0|n܍N1%(݇rEDI$xxxTնvve[0Dj,'sNйgޚF%VD!Xf_/EQdl-WXRJi֚*ve6vb1.K >C\n$6,9ŋk- W7ŘdYW|"6+Xd$U!0!$^,c	Cbeg1C2cv>ͦg~>lCȫ[U{U%"WTوc.!cL)1vyCpEyus{_uÐ
&fP3"߼UEꝹp)]4")DDN%$elu̔K>a(+[fAm*I|oIEd&"$@ )7W TDSظIU!iNS{c5G#fz 0*/\oZ6|QUUWu=idRWuUŪbAǜpEU1Q ݉v¸EUMrأ@qW%vPSJ$) geY:I旿uUfNGG'ǏfBU$!GE2EUqe=a,zZT+ʢ,d,Wm[Mtw7l;FǇlNn;q4Hө)+	Z㊲~!ZCDLO/DYlS/u]/j۶w,Q$[ iRITUȚ}xD,CmCʪ{@JiWY$oSN~O>!ZDlmq}vvvݏNgYY1$Dm۫˫˫ˋ닷W77zC	 "زreA9۱rb:?z</.iXenH:<z=S]1Z[*b\vuk. I-u)">L"~{C0L9,b6m?}~zzG|4MUUUD'ֈQTu 7 ()p{"dR/ݙk__Fu]?y(o^~{v~u}b~6a)DI5*ZVuUߚoPQHf徤dRѳE۶U3LVз] n	۳[t.Hι%I,t)iwh5C;(V:>}pmRVt{?)﻾(|"II1!Vd:i۶7p\_]/ɿ||}{'A!3(  ^}$9#\M	QU	Fh(
%EƄqŷ.X%X;4xw	 f$:d
1` TƠ ~ l\\ͺf2&ryyqѭoʢpEg+mDYF;eܭ]gE~rݟ͟"" cDЈ*2JF*hI
؝ hL)$}w]>x:bIsx0g0zvmQ&('4N$Bj5!W 1w*j/hM1m~CEtL^侔Kp܃{yO6%CFT@q "꜍1t6LeQ uEUW[C^
SJ!}h꺩o/7֘I xb#1ys\<6DWeRLc:u}=m,|MQM_^ݔUsEii(⛳1&fL.c5tQ $PP$FwW:ڬ;[+9ޯHlfbølכ|:}W/^vH9QRu1BAR$kmr ~lQlLfE&ԱZ1֎ sL321<w0'9M\߹wk\(%Dwt5uʎCԤ	w!&G7cMG|NBoi2=,]tuOttRD ܁qDT~(>tMos@,% Jn_~&	Xgٰ5ƕeUUuL't:ͧISƕZcLK!agmE;1.w sbÐT HS;R]i]\+&7v̓I=L<yGOLgs62;;)HʶD- (+$ʢitQ7g1lU5k'z;%ei1qLJQV'?wNO? 6Hۏc? [۪,׫%BH k^IffӦ|O
df2&QIBJcx*a0 10[P4{tb>;ZcҨqRö^	xV7?~8Q4O7˳v=MONsJ1v7o.../6v35Ea5LD9&"RULãaU:bc)tZy54Fc{/Q8Fmz.з?uo%u9w1U  JjJt7v[v<o/Z^~`iYn%Q	  Y@Y9DdDᜳùU^mQ8AfaA,A5OHEC&+'5p2N;ܾswwwwGÑ+Jc90Y) cʾ0mZբ:,2l6u ^nސ[`0p3gggu]GX\k(󤑖Ή(G!:@jh.=	]AQݶϟcVM2˳gEOFk~=W_wb2N{PQ? w\ؾF@PS5-.=}aYƚ{_vE>!j> DԷM4e}v~1ղi w`"w}66܃\ų	*d   FU"!$d m$?  A.a{72imB º\PYˋ(!LUfV<}vy^Vt2j_*EF#$b~qz5κLB6M;e=hs}5]zB\͜ӻ H?uE$r˱H]IdAaETjWPLB"Hd>b|״M4MYZрV+%UXy`h`aQ"teYf<,AYN&Crl1o/驊j:u5MvHw;GǷqbiD(x¯7	;ַU  ''oy@`4Jt·}Y>VeYQEg|_6T8"m}GDEDH]13fqYe9GެLdrT(Ng+^4w@ @EBkMw"✫"/_~I~uW$	:k0l25HɪGY%F1]1FɂqhrXkoE{[U][TCj!4DAijɜaÃO^ZCˋz *S#bT"$mH(q BY˗rDc1(!xa[bTC>$EŘ7  w2HG-As(cP6J@ H('D unn9csN5ՆmoVu!	: ]<;yrrl>Em4e.dgж!zGgsISX4kf#޾!dQ1DڦkVh@"T|;UYm!nTg~\9<_ɳ"|_}?|7ztQ"R=GCg!,˲<3@BE-O:p!4+h7zW(\W4Qp4Y-/WK2e.se-=GQ)
XCU;wmYT1,	D{iR5јqCRf (-r9ۺ,w&w5jqy9+Ǉ~;߶Hк5?(ngwzέ:ON~~rl.p$F,ϝZ"ƪ
7 c[WF ȭqW? Dm,+	DtHihgfe@A<AAP`wg?=۶Y;ܾ  Ƿ;^}r86YdȐ1 '4 '6	.U'aջθm "rT?cfmi;YՒ-
8'̉U6̽U#U~]X$vn0G{۴eeqQ1WUy\A  cc U$c%Ɨ;7Фɩ yg4}WoWUi,8g8wY9HYDQ8HD	+_1[+,uӜ>{}8{zvyԵеё/<~ǒ7, J*Op$#d(Hf2W&8CICRkKRh~P)	0v !eV%j|Zg=yz4YuY73R_2N_~sޤWí]:s{Sڎ
RllJLBqHUP"	
F䄎5;K*حTt+M JYRDUDJʑ5Y.WuӪuZȆh{txl v~|,3!2IT;<5		 ,m׶Ye\ZK7h5>˺/MmXpx۷wڦI8c5w*v9[Iokl`29"sVU|}O_gك?姿xWYBZkuU5dBH2mVE
 X 60RJV aNsֹ6mZC6F"jiSC*[.DVUclYV;{Z (.:"dnwGcnݾu!8;y/ef",bggh F (lb9vwOOO>+ok߆s&S0QE"l+b4]SWpM0E@ؐ!KUnCUO^Ån`몚(DbvmB_fNL(F]	]2   :_9YGe.+wM޺"6YiA  $*#laon#1>2YI J[ʱއ<7.ЋL2Zhmѓii i&Iz>{~٧E9OnL;UbU6XCe9LU%ƾ!!Xc{{ (!d_We\`qf2ҺcևOw~WaIT垴f]-_'kIE|ywc>xB!f2ߩҕ#1Yñ1n1L("Z޼1يQY:"$$O8CdTՀз&R

ʠ ",`<!	 t1Q|[|`lsɣG|teEճ~|ϞMˀa^kˌ:!j )!D@Ty."eˌ=:Ӥ#(qk (Y].7+0rd:tt:u*}W]Z޹}o	 d<-A5e岂l0C>!{ I@STbÃݢȑHxe9Q/["Uy-e}'Ou͢.Ѻgo#"
m9*J2BS.5l^T	ժׂk4lQN&ӣ6Vl4Ld2rWeyAm1YÚuٿ.kp˟h4
"12 y[::y!ud@$fF5c90Gk]՝;|mry><ͦ;`x|>]\\f޷,~E  D
{ DNU*	YJ)V5񴉴9ԤFK	q-K  KʯZo9 Li]M.S26MSBX̘<3.C rY%R9Ys,qLx;" <J]뀉=bXg	(Ę BCJU77TaA	 19ED# }믿[7@8{O|g2w-KqŢ1t Ҙ%ȫb0O&;HT-}D$ĸlUӮ&viZƣp:NFUY<.=UUD
c}RP: %A~^Rap|No?ILO?O??DD?8<:ʇ׌& ^ץ-2VȺȠ=רKqeN͒3Rb%zY7Ccjl]v"*nC%,ˌ@eEYO<}t::b j!ĝݽCg'O糋Ţ< A[ǃј (!cV.a.Kt:|νW9Ʀ'{.CEDF"e1ʪ,˖ew5&|~"]Sd$%@a$"kd.ӬΕb`{M95M%*	A_KG+D  $۴uҰM5cmgڮVʊ!CgY)+H    IDATJ2H
=UIe$cqnS.bf1
Mկ}1-_Կ-	A1<{O[&$pk0s6Q6H׍Pq>5M}d<OwvwvpMdo:ku gJyv;f'+4DS8`)"ϋ@$髈Uw?oL Wٶ+cݹƈƠ 5q6+%UCcyaE^Zz"s.Uak0]-m
9}ƺDբLd׾t hwe_^	}aEY$3$q|I&IBH3QM7-FBg	6*#@#Ƥԉ
kg;~ݻ)EJ+LO>>_팉LׅGf?ϗu`!Y%3=cL	DIfB"̢s`(+Ee.+\c^6Qe 2^4o[P!k(C P0Gv(jPP𫌽W^	eZ2c-c"]lq3n_zt(O$d\,(/,7Ûi\_ISVa:M|Ū!TEX.WJj;;H$,e
WW;#0]v}$飯hZKYn۵iڶ˕sd<;mE>> S@w5
I]/[Ž;/現oA Z2!P!P5!Lt{;`Zj_^Ηz0vu9grمpMpHZVH "h6}7ӎ-jK&Ace۩@Z'rI֖}zMRdFw#ۆ2
Gc:]H1ղkV m!1T$Z֢1 1vMS,ˮ3>{J[V	>}sDz5	Esrd;((*_59@D  bYn·X7m۶!x?<?<udg*rvV/˦kRe	d1eh( șʲPQEHQ]|ַk;C$MXEVVEʲ*FS(uDI'U|u}c47H.#W
,s=8?7DUUe*sƤ~"EEbr
wo
j;dy/!"I^!rs1K\tޔ=:Lq -"ϲYoTiCI ki>,Ъ>z~qggg_~ho+ޥ
.AΑ0׫Up4O%w1aATm^(}c</21<sܶ*$qOW{ƄH
[m4	xhfvnFD#~l}Ww(zv!|u/!vT812IƸ̱+"ZCeݶmJ1uY#bb8dyt,3%"1h@jZ%R!"r"ʺ1P'!cEE\W?A0"3@}"LUzH\~C2HD3@͊<<GcIOf[wnߞN&yQXk-a1DZ29W9Y<i֙0Ga&TTA$1,UfH[ޤ)e|cߵ˹FIݾ<HUO>g?FG	dJ'%IɗoC`Y!X"rə{7KnEQƵtA#)|Kc&Y6d2"j*m9"!y4)>Ueb W dN7TE2,Bd
d6CQSݛ}W_c8ŜbѠe}ů/<=.$W7D?sOt޹g(9<Rm* թ0DaU!W]Ñ5:D)Db4}7n~e25 튙(0Iۆ$E&%  8g!5He	g4~nh*;Mdnt%)O7oj*"eq<w'˺Fh}WbH][gpg.ϐL\AĆ4Ă{3;n88cfig:6mp<,!ru޷mMf=;;sGn\bj)ț?]+^# 51u1ZC@0!ɣdwȤrFN !YDu 3FQRUps	/.Ο<=9yvq1 J''3}9oTE8%q ""#hN
IȐJiBƠEMݴ'^JƐ16y7a֠60,l  jz5TCz*w |dh[1B]A+D߅ HacMuՄMl)omʯMIyuDG,̚?QZ_6Pzا   5Ƥ']ۦiO`r8ٝܿwkJ뺶8?=;ygϞ=_,1GtggFEV3LVX,D4(Q׵ggB wmUӬmjjAyy^EUeYYk8V˕WΞOrV2}qɿ3k'H-xP4YcRQ;>'oޭW^en#I??mtm;,|AD"ʕ]_cl5L'y^6aIMt"9*h8fQJT1ldf=ŐHZSUG?)]ILֈp躴J+!5lR|?Nᣟ~4R|q~OGcP*b
K]۔U;Yg8=;˳CEPBEQ$Mdζ"uy,J81˦;]"E}qlC_\&V{EGl U9rP"E6?2Q8ɟcADE%<O ʜ3.Uf3)Ur׶]罗!鞿, 2F\:4E8sY1ir2&xbX |hnÄQJiSZ|<8:wpHctkjD.3g&<u`kzmzYe6ˍg=kz8=?{ɏw:w޾5BvU/%.!2EYAY$,}ST @ E株ƚ,8ƔfHbQIjut׬6s!rOhh2]|Ͼ+*1$ĺ=3$&jM|w!-H_`NhԫnVZf
_1jN5P{Ѹ$?  	doIU9
_ Md>Q @J8k#s8nu!x*ivYU<wx~z?M,3˓s&MZ~P!W	cTauν7ZX * ./@b@<cַN|}U@KAE6:杻Ñ*0RTEl"H솫$*	W,R;˷;7vm.esL1eC&u'U{Ɵ|TK;TdYvD5-ey58~:ٙGCP	ⵡ 6K?( 8k:hEz]v޹</ʪ,m ͫ6s#_x9Pꤽx%|Fc$0@dRTэlAQ@jXt,+27(d9 {oNӄ>엟,˷[|NNNyyXw6ֶD}RfFR1#"XkA@~̒&1V  Y!o!fQԃYc= 웦|!r:eY<kvZrd΂APSz)b_B/z4"Yěz謽w%	,D@Ĉ Bhv6旫%cFvpVfM'?ŲV[^{n$JAcv&)DV|Kx"ReQVNb1(6M,p8Gê,<dpM1KBGj7[IXД.BGmXLk^o$ah40r7T!%Db!$+8c"HU׶>iڶ8ȊRtSa'{[vcJdM-Uf4&J"h/_exUNw9g 4|.YRy`+ adNo}}I4lMDg}?~~qY3&#ZA`i`46mXl"%"/AjYUEQ @Z4*EPAbHzeUy]f/}%$ȋ[۶Kk-咤GȬWz1rwv# Tb>9 hUz1X犲0..sfD!.4K(DFr26Kۚ:tG/,XftXq"1U֐Wj~qV%)L,kNj 1CXfl6νǷnUe #rIHX2eι"syeEu.9k1WTnvu뛦՗_>|x0j DDb\7m7`fm5FAtP2yEMJl*IPz6Yrw~ˢ@cz%
]sqїʼȲ#s7-{8^՛4)\I߬J1tg0d!%$h"",+Ū.X&I_ႾI*\f!(۲̢a-A!$ayKa_SC{ D܎zhb|j@5n;Ȝ
>}<d5>.&D.b0F,=>KJTa2ܹ{wg2ʜE$2mƂX+<}tTױTϵC^Dp_!ƶm3g, l(!c9Lz  P$FB>IӭYt!J].gs2v<eYۦm2/
b݈بd6q>}#FimuO?ު
P `OHE9gBOy#o= tgl/uxc\]β</"l\VMah
7螛w-m
?
NZ/j1mMb_뛃(W_/~ÿ/^ZSp0;<:>>>}t7?+|4Ңݻ3>'ςxsqv:]grն-τ܋T4R k%EQwz2N+	OZKkR.ҿ!뱟]- b/n|5B%(c컺i[IX"A"sYdr1&_ .5*_wHuzA0Se7Jȸk*,Q ٭B	@ZD{4riև('t|{UUMɤ̜_<~'Ϟ7%dzۿS&&',+g(d565lX,Vżi/f!Ƙ+XcZ[y2eYUUκD@eԝ*:d`*Yl!$ǣ[gCLTCIUit=[_#	2!0 
Ǩ|?L@^Epߗ	r>&Xc5mӌF#p񢰕M!RVtgo:WU\fLko	Mq(" 17F I-11,ÇcJ'5̙^8QzZ= HQg_\=կŚzO~>ֽt""UNc/~sY=2g
L!Yyfv.󢬪jy9Wilx
9WI`=@ߘAq}?3&mNr+hLJdadE泋9 yM1}	&|Ud@N؈ȡYj¤YA؊*Hf\4ME륚g!Ʈ!B]/N/NC]0Ǯ`04b!fX[h!B&a\e.͙dK:C8k݅r>-˓bydgo4˲"!{`זYc{nh9dSZ36rǷG?Q?yZ erwjAt,d$HbOEA5JOm"r1&eȪ,K\U&CPgEQ/瑹(pSfZĕXRk#X!I| &<R{$AT)5
ZPDl
-i鳋ge5Jq\>=96jeE*)hv&,&UU?M8
NãcgK\BB16M
+JP]8\ᵈY@52!fYUV]]Bȝf+k2 &cǛ1 @(H/4_:	]֫ (^b_RU~ݿ5f8gB[?E1릾MKZY(p<]8>=]TM'_%ﲳ%p0fyE>iWMWTy"/D?#X#o7hS2|p4)c܋*5GO}]I2)1&p0?::{֛|oƛo{{{CYi}lQp8F|~yZ,ZCH A@ @@BdPUl

="$x_9AgA]+(m!St;1I+4mv|۴1FQ@417ʢc6uU*kAiyB3w{x1_6xW`/X8]5E#V*?(*|>ĸTr0;,[Ƿܽ{YsqvgW'i@wx|dmkU#D Q9tܬrq9]͖r1_,Q1yY>AYEQEl2bfMez^]{ѳf_U1__,@M*PdQoݾ{px1L}kV37]T]5)	,,z)zGJj8OQUVsfJL$A:0䕽Yeb\gdl~ZFNYF?YcPYEƘV wW>{>MO~C%|*HX4m:_ŝ;?CF msGhC" Θ"ϻaf$BGAе0#R^cu(/L˖fH&஋
 lf=
$r{9F9oB8Bgg;㢬<Ϝ3d aF    IDATi r}QQYTo9&BD! Hu>u]#rcEC];ﭵwG>|x~vf8yjCf~בk`#rYes\)CB@ӣ@YA.3&.c03eE~;[l_>eέG(<sDQ	
[E4H"".se=v`iZk|"G?O1t@|>}E.+dyՠ{oDaCDi7CyY4Enz8zE{~~X.Yv+餞Hˬ.GAA>ɺk"l	 Bq  1Q\J ϟE>> 7E/Zu>/>;9-<s&" 
s̱]"ȪD9:E6dڜ4#MNk8|5uF%^s @DL.|QCm	>PVV@ܞˢ+J_ygy˜]!ED$/!"W4d&l*/#3%x)mZuEYcd}4":EF~ڧ <>:m3[.u8].%pDS~/4M[0( mek\#S*7;ޯ6bǚ|B|EU&Mǯv҉nU*A1lVWOd$W">/rd2͋8
NNN<yӟ~W|G?燇Y}po7/+;Ѹ,x2_,NO_/ղ#3ALdF%U0F	D-٫/Zd@d	\5D-&0(}Ѕ1twѷM6]"w>ڶ1PH !d3zI\mUB@cM2Dd9+`E7e"fAC)ӧhC@LBJ/0HCםji_gժ^ECf7w;{_~ËGfoڻ~W,cs\g"jQšŢg_>񓧧gg2cXyYUU5`0`PVz1d),drUpImtQHLy	dRxZqTAUP/[?=qzڞww/?//ʪн{wRchfi"rU??9Y-	Ym[U-l38sT,`Y/נ,A^.ݵ5d䞍G~|ym<wCd%uߐEvtx("Mx/?Os 3hrippppPƗeSƙs}S px\M]wzrX\:k˲*s:@ 0d k
CAWOXKm)! sLR]wn3xގed!J &߶j ֠5oVwJ&2'JXھ""qi9"`M%&$lF)CcH 3rL^pՐE"s1ZkN<lFr14G2{-Y!%&ZĹP@)+4.ƘΗpEJ^Sc>xvrr~~q<Ot2Lh2`Vƚ9$t?̽׏miv'U9vHEHSD? @֟$@db{tߜ*×÷ϩ{"RN{a_I0x:MdW2nYsh@WmUpi5@SPQ$gyLNUf[[u=2Z⌯]"D )e3w'Ǉ!*s]纾;/B뺶ƬV˗/|X,;wwww_|1FoC0~ؾwZ!0KJ "Cj߂p@3(-$A tT,J[!b)bDJϗ̓O](B.PuQ>}{|9F5 ΈS0 "k-<7cbۚ%"Ĝ *(1R[	/,
HH1w]ږXWML9j?beLYeYMd1*Qt",xҢV.maRrAc}l[,s ׊N/qdMBF IuO&;G'ιU_e~֤xލEU}aBD8'[ë*n_ZNNzI_B1M,!ac	(̂0QDryr{0B '{oiށ1OѡVTZKZ+pH!7g?/oo]϶foλ{pIUY޼q.ywZh)
}	Y/1S$bWJRJ1b+ H:_qVkx9q1\1޻>A}`.xS.DJ!AiCж`EXOY˳,oCy
#t*qwkwvKj&dRV#ˢy(ϟ#3
s=؅M$[aKƠ"
dp&(˦Y-s1z<}۷q׮_3ZeUVŋ~|ӏ?}6_{o/_GuYUUUe 4)1OΚӳӳټkV]w}看"bٲ91,Rl.y7I 8Z+ۅ(&~}ԭ_0;S_['Vjdh|xͷٳO_7FYӴJ\P !.Ӧic)q۶!͕˗=zw 13
0sҊ*ޯ'f*ʤ Fܟ#̜F*:\'pseayo &"՚HIG80ZAQLO"ݾ}S|䗻6߸Uu.(]|ݻogll qkr~v4+ h9/.lZ)a:2E%mƐsDFe1-6a{yRTE^\ꪮ : H"\%#ȺL٩!۔RbMMFuYZ'|@i cJ:$c4)BR`l>GAk[ѤD `Ω(Q09"}309@KZ.O>}Q
EC̬Չό1e=RJ[(BcCR9瀺Qje2
B)_!+OvVQQ5**GrX5,j\(Q0JD{w𹅅RBXD&"cV
<c
AςMݾs;+O$ "'nնTt"	B9BL{0NZx]aQ 4wD /!0+1O|Z5/O֝[7wN!V11KbA3gx/p 	҅R8H#G9NfΪ)*@d"
)=?<\}]V>yO~pմ)Em3g Yk\P)Ovww X5'5ޓe3ē:N̯3dm,"S9!%AptH]Lwmma)*w}ɖږCvd@3pUEUj@D2Nq b_,R,εj7 $_U  -,6bQ!Dw{n:ٳmFxgQ_Hp|/gFzow׹༟L&}sC-CNW~y\mdEgʵl! f/QAM>'?+_Z3)@̲7_~?MꝏXaCfN;_~lTqUXLq4ª'ժQ"P M rg[p` D 	J$BrJȯgD $*	X"pnCN>y}朰(1 sUׅX1j:kvXVZ)RD|Pزr!6mc1 o+I!s/; d$c!G6!w9܈JTG/I]|eUm\?ͦӭݽK;֘gO?}jոK}+^vx:϶ml@@8)euc.|Z͗euM6]; M=((1&UGq!P,-	$
'1z5>9Bal	y,>9IC|~|P)5ke{[hcڶ1zkb\:wn,o޼tv6lhD({e@\|m 'D[~	3nC~kf%$_4mfe*kAN wT(qÇ/}SZ.?_f&|kv\o޽sr|}3*kVUY-cށƶ L ,K
h$M?uQuJBdN4υ7wsR@i"(lYddeNCg 5Sp)N6@w~okVZk&S}OgQ{Ǯ+r
9m$Tm,΄88RJ14?3?	HH$Žbq6Ӊ҆.i"2	],g"Q5KZ6ҹhYmpJsh;^4  $ETx5uEu2  JiT;q]Ua6U Bց^C@ibhQijvvv7|1[Uk{eyun#!0q}̔H?QUmzryrrrrzjhA) NzuNֶOONEvK]Ve1LfCPZ+A_ryxm|fmlUu/<9SQAH\&e"e-
M5%\XP*:1wmǨ	գG=zRi3JI#$ap1fwڵUQ 	OT&|B)yrȐfH"RJ6rs!Ÿз-iSXk-mUh%B7%8$IIq*۶!fӺȋe̞`r6ԑaBK0r pQ~ԥKj?[,UӮڶosG#g3I_*dZm8</_igkkjWM)3d#ԑbg1sL$0?a+cMaiYd4y>هI-z<f6x<wo|{ٟWO<=99]V1[=d9ʵk_ſnߺ=5,ӾY%ل8e2Ƙֶ}O#zy  )l IָDYGbA,ȉc[0d@DR!FyBpчއ{cBa0='RX)s)HQU
 |REU)8h4gR
RJmֻ:c$K[s9[Jm}'\CoY}wι,ʅ"_ABL"p$RVKKWݸ}n*صMϖ<ԅ8N/]vw\F#]c,"!]kflNdXmׇ-*d[EV;rq0JA	,Fơ!Wf/UX
.{2(G ^)u^{MN:> @mW	t$QD([͛f\)D9tZun[faFL0	!bFDJiffaa+É F(m?"ZRQ0R*!Ffh4*G?9 胟7]*J!1ß,t6+v!v]Z.OOOVd*!у{&O-9?(Jg	sRJMƣ*.'Z1()XEJ+ӺDNxu")sFHCJiBd	ަ.zD읻ع!z<  Q%(qkkZE	Jj#\j#GHژx;vz-t92B*4$wcY("]u1q="cO5}s#!dRpČ|U9xO O>!t6KfH;6dUV:Q(Yz	("Ȥ?	E-ٶ&SLo\w}dN	Sh{׷Ϟ=~H(흝K;;Vn	`1Zß}}o7׮E[:Adw~_UV9b-ʲ-F0FH	^9K$e,(NRb0.6FkS::>~Q߻mH;bhBa\-gx6)R1׮̦ZOڮ=<::ݭ9gOXhڕ7LHvLAD{+3b1I)VM$"s s2HJeUѶѲ_   ӏ?g.;{蔢s>Ub9Jd9rbm.쐄Av4~w^1L}*.FDϙژ SM"#*QE!EHIF""4Qkmm
!d+6Gb1*Ylv;[uE)eتB(<Th؀9EU^srww˲0YSCϏZ #Zl鞈,I[VA*ݻtԬ`}a&z)̶=}';k_)W_LK)f#{hTt]GDv_=[k7ͽ|.5gنgc̡mpr)rb2gGO~k۷UY`Fmwߺ?.Wዳ|\Vuزƣkׯ]ڤC)w-xyu((/O)˗S(vmyk޹mS8oS΄s} ER
Ebf!"TJcJQV@bр>	d:A!dAgFOޅτ;s}ޥ
kkג?PJkcbR:h@G( 15}wB?8x]$zyZ~ѷ,5eZQnd/JD$sJ Y3$]~p$yL>zѯvt1xt6rʛo};oq/eHӧ~ѽ~wI`    IDAT'ǧg"r;|W{wzn^8w]'ҵ]6s}L.$ d6Ngd\҆9qpu RRQ9Y0 J+e~a>]B]NSeV*kA=A_:<$	sIzRW}
P#k4 9瘑@qȘ7f]H1TRւ#N_W^ѶA gFkm+Wf@plP+B :@x]ݘyǤLƉyjڶ-HhR((ISdΝ@H+DE&U=N_<og92:S?;75_̅VZG.ƈq<y|| BN8eUvSBOu]GPG 
P]̚7HB읿qOEFkV
5_VJ{!NbbX^c!dEB ͨeͻPM`]zlZuܝBVb̮]s.FUUn>E\7W@{ӭ̼p?_vtbRJ[kcڗ EҦ! *uOjJ+6E@c}Y+%WB%֥ĉo]]1sc`f>|G/N'MmgbTJ˓Ǐ|~Hϟ<}p~׿/W!nޑ:=>ޣ"Q0?=99|,NJ}3rAP@DAaEJ4p
P)d$RZ 04jBkS15z\WkRˮۮ>uŲiVeY~k_tr RTUg~gw79y l{I\k'B HdSֈ!E!{% ")IH@n%O)xCBEQ&#ǴV@yS$m.1l'尚EkEl,*ٔZ$Ut\AȓH>HDe&RZ &hd-ɠ0V$CJ)r*%fIIb"9%/.xו#fp֘l(9QD"rd\UU!tb|"ljYՇ%*.sG#8bO$@ P	3^m
q8:Ue1:/blY[Z{rzRUōkOS蚕oCS"z.NMB8T~SV.Dk1q5*4H^W r0cAQ2]EB  cn#C!)tBZUUAH?9=;|G'۷oݺq+W3|CY Z>Y^#FDHjTUZR
	5jvyZ5-R)Դl\ b6ۮ5Bk^R(9	d,HYD^E$RA%M2)fLFa"d@d.# IRB]1\r19c`h{:ߙ)eYuc}  m+Z;^"C5*B&)()HeQeX,wkf|(i';T((r9,wy[^"p
iK&y !dtwijٶhwgҕk_zt6OFQ]*u?yۮQQoNf[ըj<'dM; 9$fi|]ֻھYӦY-|1_.޵ms	v2Gt2mmUUEfJDZCh A`R 11~A hb|a~sXlp|?$ lM;^_RL9DHf ")rB6~" ݛnx$k{bɏ=88N'ؔڀ"@ʻk"A dGb3f[[㓔UCDD1dqDTzfݫhT?~h%`><yx೯~07#"p9$*
WLd<LՋg"M@D :?=>Dર8D2C) Q&m({sҥ˿ϟ>=<<ޥ	 V|8$"kj  ^rZ)AJ)W%eB1l<sQ[EfR,˲,O@2$H&}F8`9|MׅR34Pڬ3+RJ]
`5GVI5eY'0!Xk0#8el-w}CTkS @r#\Zg>؟:+ Ų H DW  )mm}g9Hbp}-pzzzR;ټp=*=}?͢jWumV!Dm[߼~,Bpgۙ(r/,B롨	lQ b!%̞])mb蝋7ͪ:)C,J,˲j3seZڶGRWݸƛoh<ϢS֘QUޟ?99eN?ãߞfEÉĉ&Zۥ fVvIMtRTRtc 2}.%-t&$aB412yYM,)cق"Ũj55A!cJEw-sl	%HDښ40ZeYcREYXc4%+dH,Q[V
65^3$zR3xZoht:R1A)#8HJ H*D^N SJ!ƪ(2P$`fa )z!L1:7MeYp% 	!\>%%ryC{^uW9DtR_}R
u}rrb1],W}im˄$-3d˫ԋ}Cxǔ4.ִi" cFe	5d|U@^uȎ%Y@HQ00  y\B@0g;Jt!"Y۵O=;7oܸqƵ7]u]FdRuYTUYNƣ<ՃןmNN|v[(SĘcJ$|]Vs%Q)R8~03  VĔtJiDB@aJ L87c 0hy|޹]bN(10B!f}GYs}*3~eUP5]6,RYh6HPFt|:[5mDpdk@3#3אI sd1Mv]/8w&K^pKruxWMߵ],lYlg[ks%bSt;|vrr,Wy8[5ͪއ3UFqQe='h4Gu=+EC!  	g2]Wp.^wz}V$R)%bSพ"" )9wv1٬&9õO+]/>yw^쒈@tC9(GK[y9xɸLdãǏ޹sƍۻQp2F0:/ Qk~yLf<>>:ꂕX~FpB kѣ'eπ8;9~EA ynEU(/o}||?~g9*JB J~f  'G}L3DPMb@,D1gLwo?ɏ>Z9#|Qi"̶3-ߘ9\`u䞖G'{{Q}z6E1LʲC;		$KA2$@2!%iBUY(m5Y(G`kOAhR}
bUV.k;1%Y:f )Ue~\)cc"'f9
:&	%.J+<oQ"nF{4o}/JQiu*Tg`=pb>rd29jyvz|@5585>,q[[U>*}|(ofJN?vۦ(d J@b!͍rDJi)Cf1-z4Zẫ	J麮W/M4)xc뗿;;,v2}z/>s?>7._d(e  '&ѨV`@N I"J_ʩK1Ŕj\<)SHE"I`)0hƘbܣF$*z4yhb!$lս RƂH>Ƙ;c9sK9$*-t6Nq]UuYeaImÔ,k6s|5B2"  BD*׀6t"unR I"2ZiKPRLw.&1,uDEb1/BvnwgMG.PSPX8bPY7#@	H&	^M6{7NKz))}b!vwi.c!-ɳ'\2%a50>__u#:cvgB^k]yf&@LC r\Bb	 BI  @wcd#[hB.+9VM5ŋ}|,h4;tp˗_,;1w{X̟?{'-kTi%"N8*뭭ٸ4I@YS-	6t}΅ݽuLͬ~a`@ tҔbR!&dA$D%42r)rmwDhkJ[GUUWEizOb>oۖl 9僔2HW C)Z鼧!snj5dowUFb|䫗.}w}-"}rgwG++ژ	8^б唢D 0"]pS\6b\,VUۿy[޹sg6 @aϟ=ޏ~þk]w4E8@r ,{}Uߵ]ZMZ-Nӌ:^5MӴιFiSʺgtk;ŏ%{BHjS`SZC^1ޔcJއ>Oۋm 5JiD&mIDq  47rMǫLAL%pB!)׮mgk;DJ+(\[Rzoo/|x'q|˧'}꺮cn"4?=~ۿ7@|ߒ.r'Yr!ֶ,G39gm! Y(fyFTEH]r"jrß}ۿb4q Qȅ("$ޅM{_>''8nѹn\=;<ߙ٢Eyr:'RuYfp/PX	)F;[_xy޽O?yB
5Ea 6̂ĉS1DbLB2h
Ժ?Ctz5O daбP#'gg5&{@5 1[RoˑEdTJ$(}1ZNSL1ژ1!UX(lQSX^vժъʊIܿ@&!d _Ȱ%|,"37R sEi!K1
')|ogιTDHQUGǧ?G|L"⽫	֭[ӭ-"bfDAҍ7.'?BAWųO\mT~IDxhe51jLR!XÒLI 1[d-~~M3&_4 ].*|)"ݼu}w^<NIdd/ߛ{{{b<Uuv_5Fa Hn" S&	>Z"r1Fbqm')ùm:6ZWeUUmF9$1=))ě<+&N,EYr	R		Tteyx]VuiQα:b5|䐃{Sk	RQ6@DH2)UH0 賈vj 
"E2=Aby栬)U];u$N!އZoZ70FԊSI UUo4r%{;eYxH,})?
DဨɐDXxSR))Bp<
1UeD=~wM:|_-T5'ӫlΨ׿AL7k<`߼|!0 k$"Q6hO7I`) J?72!ESZWk4$6Z)mBDkZkVO?c(eYU]e5,iyY{b]BR΃SDwR߻mڮ\  |hb:mmmMEjeQ, Bbxh B`z F3BR>dAHP HBN CGs"\UUne9(Hiws'[sJ=pT9!"Ĕw.,b\-ыgEQNg*}RUQMݭd4v\Cnkkkk:%kz򰬪lS 
SLyb#}eSi|\{?L.]ny;w^zX[EQZr{-sEz5ξ]~s5H&2x@ 18vޮwmkrgE,ŪzG g;x2F$No>$2J+}ھooմTtA}r>C]6mjھM[U빮1SL\;J֤=?_Xs?@QxOl1QYׇe]\rv>!6Lu1 v]J"Jٞ5?;w7|͛_WO=??;< p}7Rg/H`s?l8eu5kEDi-r6An83kE\_dr1|+_J8ߴ'5(3l/w`Ǐ?y|~ڷm1" 2 	WK\ue&҉%@k|(Rf]&{{ݳ㇏xųgϖ]ۭ^%%Cڢ6F)*fgJ1F"%&!lP5uBed8ymA((Bbvgh" =;;AeF)`N@rI@2F"]ױ|̨]$AYYu][EQCR;K;D,h.L
1!XcB䍝LVj
`xh=പ}aPViuz|xvww/_jڌ0\6ADi?{e]LLi_/9ˋp"d u,5$;ЬG wҭ[.,;cMRm1|G]̦c̤*^}ɽ7Ŕ<Ɨ(	EY!!p$?A6    IDAT9HG1c4C>S\By~!c֚.xCeK{5[gbv^W ( Ñb4
NPRO*B3ћbn[]+39u!1>mI󙲚h`MF=qe*'d:fɤ(,˼s#0RDTahUSoPyVcF6qGHvﻍh0.U)E@k35s,)VV"}	X+h|9)\es>I
UlAz bL Kg&gگՐxr4P9nf[<˲s5T fP
&J= !-A߽F$ሣ*
d6njFͪ?f]]+sX/^۷<]8TE8ə=pc}ϹGEʛ;J0!	/8$3"+EI81CX XFP43-5`8):@#itaۣfqD ugj܊ 51`gQuι,*d7؇Pìʫ:d3	SEV &GNw@BPUf,%Z d,C@c_7AcTlQ`YXk|e am6mueahжƴ[uLbB,H֠bhLD*¡1;o餚[ye	$;)˲,3j9ꗿg.^>*aV݇9m^&.pQwwtrvrzz||<ZΗG'[z^^^7]Gރ'lLbN$X 2,öbvnvYm5uݴ]ף q*IUN&r:/IQY9!Ki#!mn4]]׻i۶F}n,<cCc2Q4g>tCOC	(!FKd(c$_UD\^U{đ﷖@Lt}@?}ߎ?$摴!̧qW7umvn10}69"LryD$1π&_ǿ/]	6DTu^pđDS7I5a饰Ѥ,W<nf%5cT%7HL;81#F7 tMfX,s~@%4㉲BZ;No/^~7O|syyYv}3̦*DVv<˼pDI}1 SզmSI{vv{Zo///=;oǯ^^5͎ChnZKde{e/JGh;bKlǫɃ.M a CI:i'RUMX  TEO޹60XT}ا1wlv]vtfM# DQ8j@	d1XVkl5-sWe:"Bw]mcļ0)۞o<oXQ}A.&^!Fέ 598E~1@`)%rbU8udZuAU!3":Cͺkk{::֠f_߽w>mJA^.gEYEK`RdLBz7GUU )
EU(Ei !F^7EWUa0ojRqb>/~hy7I84-YBDsM}v&UYUu{%e2??믾d^(B<Etٕ!&ĵPED8ABB`ISfQ➧~ӛ(H
`,ygtFc$ȱ&`928ˊh1_(tȢ䆡lחEM3Q BCd	XѱZ)
%(QFH-1!iBeY,n,iDbU42yQfE쨯㊤LFo=PcQEC3}ꈼ$h#J*"ny:+ʲ4{-hv eCUU@0#wzC3$%H`etQ7]TevUvQYRrn6?{VL,0kS-O0#VaҐ1G 8PU%C-!9h	ՑQcHG Yp2 "FRdc$8L$1U5s{K$Dd3UѠ!K䜳>s:묵emv=ͳLmmv	wmj[7)iUN;[en	 AcTd\\}£	όU0&(&BHƒC,!kl3r chzԛU}9}}"dwX	*)Wdpc,#Ϋx1{sv<ƀD2zksAbl(on%T18taTjz{Ï<x/3m6u>}|QoV^xl!'<xǷnUxz'75}?Mv[v{mݶmwfՑ9FDk]UdZMټLjRɖ9!0!®wvl7f6q0Ce=;;M&:@*,!CFIeYUeoףlZ~S9,'[ǧMd=Y4i |BoI!Lh;WgGYf|}ym(EC

Hٻo}/"AMl4yT8;>o~?}՗O}}D\E8	{ >Q
2֢("*E2dEl9MC q[uxi2~WDvo/ǡ_A74K#$}N^V$pƶnQnMY`_~7/_mCWPUo=} 'GٴZ  |=@G*]߷m dLg}oݳ_|ů~Փ'Ov۝5Y{(  :s4/v躰ax]WMz 		8$=`t*7jjZ]]ov}z,sm$:k1h-;0]ٙٳ'}4EBݶ "(+
` DS4,؆@Bd!3IOZg6Tm1&lX+dr>=zo@@?Z.Nn͏N6WdXRfc"}>=9=;*DQ]7eU{8k'U|W0M*cR*&Ƿ+?]\\\^_hf-v'z0m[d:6u}qqQMW?!x-F8"E(h7H3D4j94ǧQ47(4XT%0c]Yi h<>>::9ZM&kF6o^uzX,,2#[tYBT{08,{Oi	!er>[ouE}П 08gY,&I-(dۇ.-kOVh,y4m''G>Ƽ)Y#zը @SXF~ĀD`;-	ƹ0_VAYmMy}4b<ӳ ]'@sfx;c;ᆏ7
{v[CQoqHg8zqo ,kIQ$X4ZبLD	/ʑi7WD%[xAc{g}LRE9*ư\_j:s+0xCr8>:f]__C?\qU'IQUl뫫ūo9 ,eO)!Iaz `:Q9q޻Jv	qExkϼsL^C6}vm]7mݴCIIĮv^ǧ>w||G_?zQӘ!AbFZ;,f@?_1&Ae6NY}DW= 9M &H̚ˏ?*l6SbSvfZmvX,?O>ާϿ?o~펎~Ͽ[g>  k[24@cպ^/{}qZ(~:ry|t<ϋjRU8JDG%z뻮zU%C	eZЀ*lX1WCk@(ǣ {胔EqְKoUMh\1=z{}E!qϛ)~_ǟhx8U醽;b>w׻zնu@7u{[go  0/ǟ<9v\-]]]|W/_GˤLfow%=d ߠ` G'AQ@,"d/ I۾&p?{iZQo8oG!݀;D}54!DѣGe] <W) Ym.Nf'~[CW_/km?AѠ^pWEY̪(ghlf< EaG6eˣz=zW.DF$gnmbcL͢9ezkC8$2  o7Fon0@T~ *jYK|>;v״U<!Mۊp3r}߳^fIژNјAàDQx裏}E70Z<AGɈ5dl:_\mxCU4ccGP1*!Dp*3` fM/	at k\ VteY\VMm!D+r6.^@"z/=};dePDF a\55YT0!3#BQe9黶wwfCAѪ>?`FwշoBLA}cLqd66v}dۮ*_f%;= 6r&KsslŘ(I	B8##nzk0t)G"'((*e'Vf
DX'bRy^81"CjPv^]~$-{"E,<PPqgʓXtWH#Ð$@U2 9_ya}:s324nB֗4+*o!Mz,jLeC"IC!DBp62+@dAsGGomUe;cH& k£ p|Wae&r(Kʨ  ˊ*AeZ0L21L-8gwzTnZ¬拑LBTRY[:5H}!ː4i+0!
D]!$@X!j
=fk,fRQpnwlϜs.%6gϲ}yku(12"٬֛]8>+se.+H@7H&\mGt];+|6+|qbvuurp[
zue% a'P5ۺC,KO9ՁϜ1MS}7tm!ru]ۆMM_\7n>UUb2Cvv2DD@H#GQ$ʽb*z"C 6-1h߇&]d8A(KSf&7uSN?8⟞>}Zc(;w?|;ݪ&Te0>{GOmk;;ΦϊɴLDkygCnnhznwvn7zz!n~<;ΦlVMgeYfyq댱ΐ0v]~u}uuZ]\Vu61(:cLZ5GbyQe'O//^7`q9v.~pދd6/*C?  m[[U''gO,~:BHAR>3I(`Dks6˫<+"/0ɲ۳|W7s_eE1/w]lˣZ.NO>Ͼy00GU e:̐@5	RjF8Ldwψ¿"jgx }rQ0nF9qؘJޢ:jZ>;2ɱ7}s)P4ɩ[kH8煾+'S!ap\Ve##0n<2璆;}Ԓq多̖'>|}ˋϟnm[7uD!$1Bkwd7	^B:n17x^d/ٜ d2\CgYYi膰Mڶmv>1ZIy<"쌱LĻ4cIrRox8`9DjJj:^&VDփ\FaPR%UQ}͉=[(Z	d,)wYXcRvFP 9sX#I55{m֛2$xbQ%Q1Eɩ,UoΟ޹pu0)*QPETU(qu
zGMv!t];Mo狺iQ23;ύ*cbh3ЭWכ(2D3|x"7FC0!tJ!$;U_u7Oy|c'/UDck$/JctJʀLYM9uEAƚ0	QTEEG<OvY6!%C&^mz8bcE5ንIrd樘!7ŠId}gav}}VVI	M}d]Q%N]V,>Kc10$֥_I(uNĊHb|D']vN&EVI] (vD/CZou*|X޸/x;9Q|q4LU(oY鍯.q/g1U9rTr8Krj5N^U[sDFTuUT*Ync %L k( 2#HGMY)0烏~%y:4Ay8/K|:gZk;Ygs[eT50}`з}P:>˽sd$!k뼷N釦iaشBt>)gU^Tf]Y׫+f6 >s EX9Χl6Gi?yjT}B@[l{B 5¡CߵC}Y0$Ƅ0>!EYV%3v1;뜓lb	Q UޟO'#	!*GQBkQYb/`E5St:_U4y}p:UUX.{8tu}q]v6nm(QQރoݚ̦:v. Qr}!muvnfY6zlSF9t}h\6˪L&*[Fu#}ovZWjnmvCaXK R!]e# a対RnV[G{N,co1rdY    IDATeͲ b2S㯶M`QQgb2٤Try4_MfKK #[U?O=	|sR)&iFgeX̑w7m{vr<;wܺ{.ϐ[׶'|Ǐo~]f~prXnC Ce!
RU8'<@Jy|HZ0lXO!:{`A31oK	u_c12߶=y~WUl^(T$C~D0ˢݎ_?>;=}xnVN#huaLQM˪ʳ|@}diD9']?4] X[{ axՓO~=ylބ'&}C?VuY jƺ"w#@Do,7U>
D0FÉP:y_UrcvM=sXbLK)E$Zfc5YЪ8DU!8N'ɭ.׫U]3Jыp9y5-)u]kd# U	 aɣ*01 
°ς7UM#
&DևЈMR@(+Eݍ/d<<9oͨ,~Av9=^L!jED	Q  O|c:NRD4c*#D`Y%Ĭ g>Y*a@EE|Y3b>wwX Rgg,S fAEaUj.[0T0l!A,Rbk$½>$b7ig鴚L 0r(

"2f)JD$2k'|z֙w>matSױ_ח}[!|ԛFn-#~́(9FZ
 Y֒!@뼒]]_YU8]VRIY|6̗E!]5"K%s䵂,{rBp ɏ4sOʠL9#2SwF^hןQܷ%d(7Zjr3+PLXB]򡟤[Dv$gxKH/ME;cCx'3'SoJY!G CA Fا!lߜL#Ғ$93@=!AȎBd
 .I$ۅD c5۔Y`*֡1x81D*T(XkC73SVj25eECU%!4!lvb]]p4-NӣEzdZ!0tݰWK4+O߹Hd闯7]=>k  CZ Cá>}C~y䷿ua"rDD'Uv]*3 d({":kuaPжLlZ	]`|ֶm6=R|_|٬/ϟ?z֝O~|e~_ITUa!0ľwunmwznwdr<ZdRUisL1lH6ΛWϟ?uqqyynC PkroY30K1w}߷# DV E[+N&6*Cc+RX l8.>/Dgy[ox}WYռgtq||||ZT 0Q3@ط0?$pcMZ6  >_|oۻw~ᇿudu o*|f㣓I5釾ެ>=>;?=24mW͏ύ5Q)@fe RAQ!c˓[\_x}Tg&( #շ^F2 MEv_K{;;uΉ(cd4He:VUi	C߸$cTuBum  gm*ܾu7O<z'כo?6+{<. Pb:-Z怼!R!! $r<=я*ճg=_?bZYQV81Զ-ǘgYU٦Fj}|c'F fJCR?:::>9 Ǘu@*"2s4ZD^h8FTB]׋t}7mlWl6f#ClL*
 %2 (2l5ՑܒRA`Rb4uO(	<~RXk[S  〈r0DM* 轿xeU (2P)E@rNڶPdALJ/c"@B` HIyOʪAa蝡gPyݾX,^zE3g %rYer9ϳYUD2FUEI "8VRb>N&Ud	"`)2_3YYMʲ=@AB2ߧ  Xx6ϓ&)!!=N>UsNp[yqW:=	  ,\(rk (k62
!eY,ˬyYdffr1Lg^w5Xk	ķ{j"8kȁ!֛,͎R3𰼏A» dP{7D#'9)$֟.]LCEA|hvyy4v~GD1D IrM1~ @15B_<Uu1j}(s20FP (  {mo=ň@-`+1@6=`K%03&yTZg$dnF$/"7Q 0sYuůUYgoi<Eu<iMjZ&>ۺ:$*{uдծcx}}/@YUM7&at'	COC@9j D *M%ଵju9yE]C2uLceeUft["ဢgNQ~!yWj޽wС>~h[7պl:~ٟ=xɝ;v8JMBrz:lwvծ/vM[7ݮiiE|y4_,gYYM,Hж-5Zk]nwW/_zuG..Wժw`QY'n7۾m>21yʲL022pλ|\̜m9HWUQ	 X.+< $kׇݠ,wN߽<>2Ȉj;$~	/jo<
=I#-cU 3ogOyo+J|O?2 Y$q#/o&2EUa!\_]x~O?|1)jrv}SsD(Y덃rɬHUhzb^!4d~$cC$1Kdǈ`!PG#/"]4M/  BBђ"˺/?׿kڬd:,r0the޾Z;?~}&t2f,,`6MyR՘xQȁ #1gggOϟ~zu^Rwl2	5Z!r@$ M
" 
* nt܈|DȐZBA ;AbeU	v{VQAegC%$kYl6Cе{ݔoIF Dߌ?j+"p`!afN9FN4]08$ѹhbxtz\f3k뇃"&,$!uB"2q.^?o>QHvmS} !g1jADkm`,#(iON9ϋ<jBpJ[761]r5~x^?{MUCm km	K2AWAPHؤIE	0>10X39@DU` <ϳyn|VVӼAc(D
@8(*m@5L5a}W.^]]]m6cda2d
1J`F	1Y5ƑU5!iN8cR.5UFbPƢ"6ˋTeϫ,˜Ϭ *m]3sn1)Mg2nе4A"-Gm#ʪIYf/ʨ"[Rp*hom	no@AŇ bY(
gBDll:E½hmO#F3DAɋ9˨sx*¢Q ťA?DaaNȱCńLºD@ 
HjIt+l4ȬE z#Dg(>!gC#c!cMךЛéQGc! ]V,X_8U/-'yb7vWy4E$A+ƒ1ة<ŮE.[\D̕rdHCߩh͵fU92b4	.L|U/=qg٤NGd2)=N*k<	pC1@UUY_:(} [ONMl(rXb2ITmD$C:]߷]owvn]ջݦmm0Dt͖'EYNd2)&r2ɲ
#oI_f~uq @1svM$La|UV0_ϗGYM/[XԐl"g,A@"R2PYB}We1-ɤY:醩@RaE}Q}Iq}@%~>p=wY#ɐrxt:-"Ksuu۽|}#&zsT5hԘe3.`OON<x8N8vS$ouh7 !P
?f4N_} av9=>#1hD"`_gyp{ܹ<>9(@d1Xkf!zXכfu}W׻zYovj6lVLfg`uIٚ=!EoI$#&{I@줚-ֹ>hZ]^]<{ɓo?{Y6mӴ.<:OM5!SK1i!#	U10LdK
1}yGA"$JA4"(UQZ*GfM=,rkLYV!@Bu1ZJVX^bc<M<W6JS+AM`$<::ZMC Sj>o̤=G˻̗-7ߦif7=M=08ӭ@"%gapo uP$R.]!@XBZko6M5&N(Q@-HaRecb4gf2I9/ʢ*IQL{ P@UA@Q2X#'q΁:Hw`BE]ע`}9</}0kp6t,-0&tw²
	pT\sϼMc0;k3ﳢ,d2ʲ1y!j]N*'9!arȌEK{Zea+}ҽ
k{9$'R3!)	`ɠM؂!d`[2 B`(8"9+x	;n!M*wW9/S,Ew\Vn)aN>sɁVQ'eD[.<+<ʓRH9ǜz~q^{?x mr.e{=RSRHN&3;ĬL*DJ2!cS  ި y,Es&nYRDr8V0B|ʊ'nǱ癙-B6p
0LMVKCL {}Qr9"_5c?]?αCL }sȊ!1'[Hn9Ч!؄a"B֘`KnS1д c(s\VU"TrcWUb1szrhw:2(E(SgS)9}a]ɾl~O/|{}f6拣ӳ;ݻOj`h$E<(؇nmvufZvvu])%ɢH|,͛i9Y+juss}yqO~z~qBU"&3aBrC0AD$tLD!DDr`v
(]ׇD8QykEnT`~t;_|/|a#$Eɚ*(}Qw
?vI`8CjJşݿO$g7뫫Y]Ƙ-\W i<ú,+_1 Ey{?O~?mb>:>cĠBJr Uu]UX?c+2vi3E8X
6DeDMz.zRg}7A2N9|
>?ǏlٮWfv  8>>zw~//|wVAhXm 7j}G?O>}>2w޻wJTv}xUYUUEa0lIaƍa @Yw=xaf~{|m|W寜_\u]xODűC1f-IE 0r֜$LUX{J:6m茿r6"&y{, De@BRQfNYHTx߁& L?%uI4,?KR)+PL;%(&LDUcgOT4f;w5#b^\   JES!e \|ղ˲N"L#m׵mRH@4+1ƔqJU|	fA j|-qIu]#Q.iB_OώUY."@]Uܽs\_/v\ s Y(d4+oΊFn?΢@5|==br}>' 0iA *xBJr/YAcv}sG~)"Vu]+4efKզSr6ȶm0L>q8R?0ԧ2Xf/8r\ؑ+|QVeYy
EeSU'%νqQ%]H{[L!1Cwv☳HQQյ]qs=+T%} CUs|=ӫ$xlYbj_BY5?>== /FK:衯9őǋBcm[N@q	25<9L"u!fEbBU ;Q9g$[1	폚H    IDAT@I%{[<FL{`J*Gvg"v쉜u!5
	9LEq<!)d͓v9CvUQʕt~ S軌]L1&rޭrC"+XoVs۠]eDUFZ!&' Vv</!3]2rw옕}Y,.ʺ*49$KmF'rM)N%-4`J盺.3JN>t_׾_W>[,)0-3!H)j,w[u}\ozk3PYUGGǧwܽ{|6=!0)gș
r
'vb$榙5USHf	m:#NRVcuL168M)e	I ;.=@̀ǋEFYW~~g;_h5DxOPM522
?NI-5dªXW^7O_ggWaD2ŗl?;N|QT{v>9??>Y^<\WqrV"L	!QL10tݮ.<p|QU|Pa臮z-.cpDIsr9$&+J),
4EZOE, 6#̈hMSoom{|r\WHYS+*?o%X"Dھm;&Ī_x_׾ZonWX˲\zٙ;>5uz;vHlAKTD H]۵]?7x?󿔆]z6;J)*"% *f^IMcQ@^ƈ;yqb#
TFeRu4kpys|Qe]DD ɢ9v)ei.'$F4UI@0䨌 ma~$9Yg6,9:Q"PWfHλs CH''g039z&9ˌ3 }{oكO)	y&S%pv2{#䈃Hwhi#2@r΁ލ:3|>~Ӿ>xW^y҈@*o#vv=$տW{u*K"Zo6uU͚g
Dc1&y䱤g:9`kQ}9?󝳢c|>E(!%~0gQ$x(1,fLC/XzDvn٬˛&difOr]׆SBMۭכjݵ*qJ}CBc=ʑ4;͢wa7 #YiTC.Eዲ(|cx^4oU]ov(ؗGG:9t"]Yy=n7b69OF!ľo{UGSNy|(Ts$Qsy~z^)%~	Sz:5_YM)IU1Tm۵#Hx44s'<yXZ9K	~P0QVZFDǤo:`˗f(l!CTȨB,2:#}dvTbޱg,ά x˼ ?m''#=`bD22LtDrmNoȎyvL{`_0rUR\s4tΊLTEY'NUU-;?NٹZTuQeYzG}5g]P2:&ǎ\:"( .#Z0|q "O-2H\Wd IZbWWwz[_Koݻ||}g3#sh7ݵa{5C׶f]mjl]YG]=8>^5eUUTTăy s44wrǏ^]^]]_/z*sTEYV.oV.$,<3ŘSN&h)1#86xʺ1[$͂&@|oN~)e{뢃4.@Z?73~')	cnuʴGK)g(7_վ~_飇!B1 3onn=*wsnfׅsErusݷQ$B+CUQѻf]k]`iN}#!Nqj;apt#0#`Ϫ=tnwuuh4 B>ݲ,ڵv!&^U4<ko7{b*a\Ueu|ttݶ7jZvmS:XVE}T*iYY5UQ {tSd,:)'\v}Y!8Uۮ0Oz Isla3cݣ	16xLd]ѴK5+`V3,a~]J;LC߷* jT!U F%Gɘev	@ŚZE%k0 1#(̒fucG9;v0,泻wΎ'rCd4N[U49 >z{w9;+
VAon"ޫwHދL%.KݘZm9Gtw*;w}׿RH<?ݮ~97/~zHJV98VumBSD9ó34^ßr6uSVs @JFd]@D `J98zb7Y5Sr<s˺nfyYfۮnfހ1f'0˚D52BȊ
*Jd?[ߊ/UN]Ve=;:::7YSeUeQXHDTUe]MUubUuU'6ǍĻ\ڶ0dmjvEYUFvD~xp`I|7U$?rmQpKK3a.kl>qa6D  l\H"9(k)k	؃b7=`mU-;QQ!j&i96,AhLJ9+`yT
4)#Q1{D2!cg/ӧ$Q|9Os`Y'*"31Gܑ	s!;l0s3US!,HSA콯Y@`iA@vjUݔea`.b?7{Od%čH9eq3^2$I'3P%
E ɓK_׿{
![I9ojkw]]vzlڮa۶7\b?5u]fh67ͬnAʣ c!vfZ-on˫!vu}ٌ'xRJ~ݮ{O=pΤQnp iiqKLƤ;&DL<ǋ@<@ER1lv~(	ش	9xLynv2@Jp3$_=w'>*	
ՈDC>;_e32RU\QV3QE]vm)%1;g"RιH)/JD(bنcJO!]l8>o?Iwzucm#b]U777O=Z\[ccj;3S͎,|QT"1f^NQE*R
!,7^Nv77׫'媻Y4uSUNʺ{Cۋk.us6̒SUP^EErߞlA,)FId(ʠkPN JeS\fݩEYVUY:hȥ뺶ݙȹaTTɐXA3kNdʙSΘGr!8bN)Dv~X`fgv1eE 'bSiFS<CO9eyO7@۶o_{,lǔw-]L!(xusӇw{Q3ο)n9??*jV%GHm!e)GkĎh#a 9vH^_Gw{qqiދCBT&9`{~?=t||ryuMmb>߬nO)v~ )ũd1+m}fB$$@cYJ;; 8U]/TmqzJJfQFSllb=	PJ)g 9Ǭ"*	#ŜzXPfbNx##d\B\ھLG7Ɛ0f]ÐrC0b)$9eV)Mw^DOhfEYUl6;>:szz4ot-dg:9uUU9kf?Y]_-Nꪂ=EUb/fM9PR|}f)f2Y+ hn(2d,QP9_E򳺾/fWYsFr>2X28~!(»z̈́'GG!ƔI>Ŕh$O9P$9+`"9c6_LMѐ`)z4͢Yi6|<d ލ;pLHNtJ<2CBN%߶4%Q"ZsQ< yt~JI}؈Nz2שjZf#YY$rߛ3p{o1;RCvww䊺vT9 $䪺n3LXYb9_yǶL9hRΩbuޱCj!?R59`isSm~8!Goqqv"bJ1cf^mnsmmׯ֛fibRe糣ӳ;bXG윊4甓$9
*dS[/7O/.=z|yya8	FĲ,Ej07.	chrQI9En>8!L&t֦u9,*Hjm&YR]~/w2	Ё!$V;aݏQA'OVH
:dw/ӋgԗbxW˥HfѼ9n~/Ͻ2Ok!`b/weX"9%S0Hݠ4s 2!K  
 eO'ɗ0syo 9 <ĘS(<v "t5U;91OJ!H1jaUavO>yqQU4;yTu]6¹;<YB9ۢL{R3l  ۬6X$
0wSHtόRD~EYGsBpF#]E`OyT&N\Q*;*
I\dS J Y3) bRt9gS9S?FU/BМ21ϡKqc
};璙@aQi-`	_)ƄH?]/wG~X0fEYTw!+PXK0Q )fHY T%u]^o. :E2e!D,eQ,j8,n¨a,f?׿ﭖKtƔ{_zכn֌~IKۦvrUx"\5[W:b
!!Lf9N82,: ܆
*R8n-NOOmS#3Fd )*Be=ʫ's1ͷl1R1+gG'wh4g!iunYV딒e]KabaH^쪨
`ᙹ(|Q0G'G''ǧGǋzqtTWM]Q!zI^?yحo>|*ϟVKޫ@N	$
DuεyE*"1D^D{'Q)V~|siLU:Ex Kq^=sዮd2`19'3 1xE(i8lf1xY>Vt;+&Bbμ(H
EȀ8:V"!;;|U`h
kٙ zK[v0|Γ\9 ĞHzw/>Ǘ<Yy(Lm4B_:/F$f]Έ(@@\YU])Bl]Ywn8lr2w}Q6UU%dbgz`cj4k

"(J;qMAuQg;B@Ffn6X{>DD!@Yz)RE]Ui]?1aavy^ovmBC}\Vmu!gb7_l6EɬQ#L@.F]m6W?=:?_-7v׎lDǄ`hWW7BcZI(bkM	,GHKޱiñsSs<kj_Tb&$uU2:?o~p΅첂
M , B}H_[>4it$QqF~ۿtrxÏUUUU0䜝V0 ͏ON1!1xUM\ 	6M +$)8R"fTUĪeLz8IՃծnXK8࠯8ʪ~!2 Zflwu3/RADb숹NYsGY᝼\+e|֔eyomݶf׶0<z!(m]릙.
MMt1yD*SO~߾>{WONOTU{c*
"!*\*- 
::(뇂
>SDW$ɤp wFS-*xJhfPSb+'p 
<M0ŐcJQ	%SNĀ p!ĶgJ"	ÉmSvm?Ġ
9g|83Az+K} UUurr
!4[O~髳ѮTHn^욎e)$f#nnŌY^a^%ۮ$!%@ͨE+˲p_qC<HtUr\n"0QJ'ow|vd$IC4ђ-^T BPQ&v%+£__]=f(	?4<w{-T
0!BL(Q| UDC$&Rf9.h3?:9>9>9mfs=dG]SmPՔD@U$i:>>:>޶]?Q4!cqB!0vYl(K䙪l>b>;>>>9>y]5uUy±swY 
DӧME* {/̭ TA@w]*cqб|qH{Wۗ B9m<KNDۻr49XNdoeꝇϴ14NPQ몸N-"`b)$l!(HN0U
T1+լFgլHLq@2*y$X3W:oRfozrL& Crls.QQpQz4kxdDBU=Ld=Žl
0(p4UL4aL ,?@vdXfOд+j:UggRr[=:oقs&gw$R?|4G$U%'&BQ$ A8E,<UD0gj]?f*bMDX    IDAT	!ds"$Ml5G=ZF枩U]]oV˛~ڶݵnۭ/0\6|狦nʪ*kwӐ0o7zZ-W7zZoS)gkFytu1כoV*MwAHEq/F Yh:I,c|.Q(BQ%vE᫲,3!8+_~CԱ\ /7⏅Oav,+#g%x||;_hW~[/yMR`)cE]# @U	kA#LH]M1L8RNfqS,G-qHdlݔ
@tD<ɧZS>gcӈ+5g¶mCJ"!`bu--Ȩ?*b|fٕD87g-^7f]WC?d}umQUU᛺ů1tH
bI|U@fy?'ӳwS~aURE@c"&txYJ@bOТ_4}eb!)=\w9jc`SaX3!+V{J&\B"^ʨ7Ҡ&;R%CL
n9gEDdqa1EPU5GZjh_♪ܽWUѓ'Oo/W=E4Ld]vZ7Qԑ뻈(߬W+dW%»\ʵc*+X@UU_Ӹ9:lyp3ιrX@lcFv~Ͻ1y)4`w#3e+eySW咈<[L-lPG!ئh;>99;;7u)*9joe Q% 2;>J2e Rf竪ܹszz:͈Ȃ,B#Tx44$p
 :* {_4uvm;%qC0)ku]a1DsU]׳l6;wfMϏl^UU<{7jZbHr@edw	)ơo71FQ51vq3Đv]vYXQ*
o}=70 Ec[sAS[Y"w*!ç:fҐsLs
rsܶɢ`ARiEgoyTKl&s&  l $Ed+~;Pc#(/뢬;l޻(vSb+
HbE/mїG~cfGSJH,E oܵf<yxqE/f0 \r*1t =EQU%:SL1bg<W"9# fuJH 	r&GXgrLTRq])ְJK
ƜJ?2D,Z*3{_x_0_?^.Cm?mu}IDEQfl~tt4?yʢ:3IN9Z?a}۶vljjۮ~1%E ;!!!"8]e+[YNljNB(ƄD=e#E I#)X2ʙ*EQVt:_+?oŤ)NiZưw03{}y&x(eu|rW_~?N
(z'-=%g%"EFFT86\aH1JN2{b*"y=KB0qe}U!g[hml{sνTJ v*E/=y0$Z*(h10Q3_}dvxu}S!u"&Q`2@`{9ꫯ<po0c߇n\./ϟ^6m\<>Z5|48F&"?I[˖77qכj>I.V@b}Q%:dĘE1(@!+ fAtG2B)٧5T1Lt	@ +)a&)%f%%m $Ȟ#QGS)CHE$0Х3z@͚Yk*n@rJQؗ&@ˎVUB7)ݞ0̺"aYz}yulGm 2VtV bRe>ݽ_ֳ$]lUuZrR63#ilb;D|Q:oR`}vؔlwOί;-)g")_||Wכ2 Q'A)eru}uZ7c45f/ j<
@Lͬyݽc^aU1fV(Anћ`aGY)Cfǧw>y
1%FgޘH$BD0zJDi0n5!BbNv}?ĔNRdWWeUE=oٝYyͼ	39 Pd@N)ꫯQ~d@QsLqx7../ϟ>ڬ}ɶ0fA컮m|9&^<%i1kJ%ӭȓX1<̻MpфrJѬ,	4ݨj!
aJSzq1_35 G'y BroJ^f*z ̤
m$
:;>nC,J{cŬ(4bGT6fq\0'ΰE/4C~<j#(3v2eo^xL𜠰}z6TYڬ^FXZo7na슢1&Eq~oiBHndu=w/(
e?3j1u}inHD|QWUx\nJTYC#}]u3܃_?'?￷!BW޽g'˪ Wd\ A̙%AWŧ><Y~Fn cyqRHًvDuj40#茬j	e̛I -Ǥz,$+Z>ע/G*l:ψpXj_uᇘh+ʟz_|FHZM;儇I  I`vNO%i1"WaRl8~(_O>=|g$VZwcx~lqgWTMt8T%}&rk٧!ma0!Nu(y,7D4fq:}kB5xqX>:9*&2r).JO|5uڴ1eSV&Ϛ ޻|n_!rY %6erݽsV!떫նڮ??8WEQMS׳gټr(7qLIḩ??-"UUzpoV3?iQY	r̢9
 Hׁ8"#Dl]Vwx2M{EQ׵՘t$ ed 6>x|!(,	0CPheI10C!2HRLzD@rbTÌEYn/?g 1rmوX+iԏ?}xn=;9r<2xIэ!,%#ps}]sr%R()f|.כvEE>SyEZ]̥w٬jfRI  d#'j;8BN)^AAFzB̒?şzf#"<)K9߹vLi/{(2\"v{Y,Tu9.G_Wb]]]󳦱צGQ&:Ӄ$1.)>ګpDs@G^$1ּB%IlРBݳmʲr(BY5Rch2@]QEY5;g󪬫ʢޏJ~O© :ribCY@8;;჏.k{^2[,f
C1*[T ͺ'W,ыh|yΞm9f4v &OYr8q*8\I1d,| 	٣VBP_кB g+3=! r_PK¡eE_Ӫ3sn۾%"}Yn>"t9#=eQ8B䈐1M?:0"3)|u%ϳCiD 40]ǫNJ~/Oǅ,Xv&_9;m<Db?3cGEėeQVEYzؗ
f2#켥L:sc?Z 1öOm7fv}BbJJݭʢ*0CFD/7D?9\/,W];T,ݣ㓣f6(JFДҰ^!cf8z~qYV:8Tǳ*J&_PxyǳS1onsʬ_UKٱĘ d1k!ĔSL|̄#ώgg T39!VkkWiMw=-IsNr׼ڽ6c1¬+쒒!-@!s
>+/bZbv3d9G,1 }n2Y% &$R8o=8wݻ:9nꦏp29ٯjeuW?4'?O;w韧PnBBIƸ3KQ=~[³'O2L{TB³_n"jLsY(dsum."fN2e1;S%Bsc:T1UUa-Ve_iɒa<?TQc]\;g?~矫j1&ZESLغ6UY'\gy $ʊgeᛪfC]v~!7v,˲.*,w@֗jOt=Sܓ&щeDlbeߩ7_$B!Dպq4F(   B x]T3EffWjo,Y?7ST"Z5E@H Rdyɬ;]G/0&#{eKP(
"LffӫwJ2?yr(D0^%E뇡L%ƲEYՕ16nޛQO/?54x_MA
 `a5$ >}Y:1 1`Gn?Cｵ> Zv>@ĪGG4JȏhQX$vǏߩb*hS{ɔ H|>Ͳp5$;}h̬s$rRG24<8YH$[SBY`l؊pH1N1ڢ(9Z.iʲ(>ğq;e05ھr>&az9fUQ(r0u,t#Loڍ'D{@4(	Wof`!@Ȕe#|k  1G	$k8VDJ"")#Ĕk%O=NL.o;!k(IK4#B
H{^)F\ZuCzq|mrpXo..<}f{kr~\TusnCpրf#)j1B.CX_p9!c(*(8mzI.Tb,)EqRTLA΄ё;*2b\uY!%MkW ((XW=5wGUFZfchO#~d/JzB kl32+E̼eE腈hUfn.n麮mnCcJ XֳfX拺em	G$( a؅nUf]]]^^^^^]7ۮVb>}dXmfy$!!%ΣTELI	[K~̫Te!*`{xuuO>$Ą8r:uƐNcXtBtZgZUdyރw/h<Z.|4։jL0v|z ?'Po!bDϡ
QۍY ,K7֛ͮcQۿ}~~nqQbyrLpyVzVݛ&sdĉS` ]UkM(M;*:&叉@QE[@|PFDZkD:JBAs~󙵶,v[EUca}Uymm<@?ӵkl,'~6zj~]v+ʲlzVMS;uJvvWyv\>?]Ea8fT3:Q|qڈl޵ qT;ϣ'U;:\ڗ<o4&:eYֳ{?'Ĭw(
#aCt@,"*L DUIcJa:qVs:qLIs&̈H!h̚f%pU$Py9"}M3{w͔Qҁy-1a)qQZk**:/yc~h}e~1{_9&6C2!5$Q 8y;0͠#pƘ֛wVw^a*e)dCeΠ­G޹{ދx uUc&!ynD &TQB)1fԬ~Ou	{aK'Zp.8l,,cGq8,S&~gpn63>p9g].cp\S4IEEH7m?D&Y3;:uyapHjUTiv][| `*HPkiV܅Ӄ?13`s91jvg;knAvWC 5'W13TȀ(tIF`FoJ.JŁZk<!.7 PwI1=ujy3LRjquuy~/dL~U?xpk}Σmv]t41șɟ$;@e9	&Mo ´O[\r9ܬNrd)ܗ#x5W'feNIMbUeaM	)"h3&fEq{J9
'Dg/.wDllr,,5D$ɷ1y1{Bunk׻vuyAD (jfry\6N-'V4$2嫗g./.0DL2伟gݻsNKTeJv{v F&IL{ԛQiiƘ8?{\^_Z3c/-*ʨs.S31*?&lv[2;?|o߮
Ӫ7$3Aoފ fa7>|gn끯8\O2LU.3Gvo|}[Kq X!٫z6[܂)0DYaD1ZW5()ARB8A^8r5D|SRQT9#wH_qsꆌ	ȑĜ܆bjC_zyΝ˗asWd\̚ް_&}CT{wUS~ޜ]^^O=OapEQQ9_CȭZ(Z;/l_QƢqd>kU9lҗs#یݻ]f    IDATVewd
u@Dk(/ά"z
of4xhQ^cZs,XeL
bRբpEU@& la[qٺ82Gs3)-xuݿw>z'}M
(o@9sk"fZYSeߵ1ġWyzڇټ'Q#Ldp7FѲgƥ6z#$C׍:5GbV_\\^]|QGGؘRU3vn[T3< !(uq}	p1b>;/GBg0>$  :bHD;~蝢(~SXU-:_x}mvY_u]?tmZ @c٨P׍^US`"77Z
 33QR|˥|1D`LyDS
I%CDEh8LRv!~plfϞsgZ;w7+mיiDbP%ضua]q>c9ip3Ds#/c<e45s1yd*R)\" @jL7Xё^ rΈh5')) (5 /./zmŰ",w:n7?i2n? h,Q4 ι(A?/) @dD	X|v]cc1e!a>GDk* B.w~z8&Qg
1d/"Ac!,}Retc3_r|\uVEIYS%Dxv̩]nwf^]vۘ!9o"^Yg3笰0@y4uW?{'gg:mNrAƔY糦 {U1Κ:):_$Qh2b12}ʠjl6_vUסہw?::iw??\y+
_»/u֠u{_yo	'ԮΉӇ9!C!AL"" h-e8h5!PWWŃ ej~ah3~SGkSv7j!ht]H>|[O,,FA#`C4l^|ybXSU5Zf/*i0cD$XRl穒L~iÜt)s	/Iܜ2tUDLVrRBT@[0lwd˗ywȜb Igl"ŷK|UT/R@!rb>B!mWWBYH"dI8/	G@ 
chD:Q>&_[#EUD\ysvٶmcH)12flH8= &.|qx<:8$@,µ^!dPMaXER{#J0 HJ1D8_q Zc-c5X1A*zָ,l29bc**8o[D?^x@;٧N|ոǌM_!Ðbw4"KYBQw[狪>+K#/EU@5&SYx$̍24_ݻɓg%"Bfak!R	[^&T51[k1WW?|l8x'Nʪb$"}Ec|YԻo~v/_5fX1"1($w3D`T8D 'ܽ{!"Rxr:$),}D0DeQ6q8&c4VS4
IF9!e3a6_|.WXY3)BP%m7UqyNI,bμBK,IPQDRJfwhf>,vS{h8`xL d(bC~aaH1ڌbJǶ}<Я9y~N;*CP@XaS┒ɀQSd( FpR@kX}O{h^vi/#M?Y>*  $%	F)$N{zdBqo*h&N}!Ő$K r"I
dsݬ_6ǈ퇶kCbQ-ŰঞSPia{5}$ehP<'ޒ
e1*2~\C6-TPa"0`2\XiS~sC(wA9TCX3JwY"+miaa۶}?dxmTD<آ΢0iJg/{$sBeo^TSz}qql^ov3aY
ytΓ1mxp5HC"0;[Ed{$fἠRd ! y?|?n;o?*w=u;,:ٙ4U1 kg't4"-ܯ	b؍7ʔՌO=p׾M=_6
;xcos-17܃nv0'qg뎖G_k߿ZRDq
 *K)ziUȣ<>:_UUUU"}+D"#зm眭y?g"br++2S0W8Vs/3%ɒ]ۅNUضm31Zz!$C$*fQ767בl3=pot7͹W 0
U~VWc
1nvS:Zg''S&nפ|Xc5&L?G3 o'F/F].T(
_|9->!)1)9>^J],>z)kAO&t\9Tbј1)j1```匟TUx=\dG2/K%y_TE\B/k6CFd}GHu{|uf^[yEQޏ	zb ӾÆP8gDI#.!ȉe; fmwCW]N)bYAr|r_eFL	^{*x	KhnGե1&&e"p.q<;aPsBI0#[?=5٫g"rrz+ 0 lerne>w}OE23.  /VWzI}1 笗EX91L[mg/r\.o[.YSq^UYTFK%ˍP;ef۩qmY-SF()Dβ_2%!XDR}7,,ɀr^8b톮Sb` Fs]mʮ/$[K'0{	Xy[0Cra^U!h&9)qw΋QK	+Y@~7~4SPd7 f6d  f<]i {S 	Ero	
Hʲ}Gd~L b\4N11C2*q[P~k5@x}šK1rJ*❯*2;FTP%ADE+ulQ5p:*spDs`(kz׷ѣG\D	U8TFGʜ?{g#(yUFCun#VCu"*#b͝DV9kۛOQHc]/RCLIYg:k*w,tA	PR]۶n7WgggW!\SWykcXC "IEĶ.M=5ʜuzDč6d%Ku(")1hn?ww՟ٟO?{VfEQ|ʪ::>cϚD»g"K!PU}Qlvwޯ fn@Pv~w7ho_Q1_	@ـY"O$;**(tgrxpw~wvU/dvP楾k~;w˲ݿק":_(s<)匱vs񬩋a$OPP0cv۝U "K*LFˣBlc@fJX.`
g XD\o"0-6,TUSWP)`r2{Ì>ު d5!uG"Re&.
 1֎B;[BR[$ִ(A=skL4[n/2z>;?PEF$my53U3kxw * NRwsƑ@C3F%
$}8*= HTLUEUq7u4kq (|:w+`}&yg3@Ey8MEz˳p6_ulC"צeb f/
$xoܩCC5F
KI$<DdP BPM1AC8,{SJ6N?_ٟ1F9IAX "RTWe7!Ĳ)%Hc'9[>7٬!20mssmbt#T 5ABR>7~㛄Х O"/HTn>{/W)Dɪ[R9n.ۋ'}O+?||cPvPճۭ[''Oo'V-+RId@
YE4h֘" 2SseuЄMfsXŽGW6Ɓ[fִf8p@*)!mX<dν6>~?]Sb͆~ 42֠
L=!0ʨ:8 /Pф$UC˅]J\BJsuwp"q+D4:3r	sWIR*anM3E#M#K ({{;3I@kC4ŐRTgM=˲L)Y֯`>%A9!Q U Pb
!q:|@L"1@dy0	8k{`' "xzm[ ,Hٳ%q5?w|[TbaM7WgWM9ɘ}@ɘٺYCQ蜛5M]UUe	V8G$Wh۵WW=yիvnw)kufs/`ڶڬ/)%kmuO.ibmn6A#N}{].s?{J1q%x}??8sw?g_ܻ{Wg/_gEqbf=Oc%Ssr /_UnI:o1ľ|ۿE1A0@V={=wɯMAm#_d;g*8N-XX	1G?9JJ¯htI>?{nI&MK證ۢ"[f^Ur18kwӪe9D^#"NsSn :/!H2GbUrrr|uyn@+ˣ{dAU1
(ƈf^EqzaEx|YeeXlpmWOF09 LhoZq;{x>b<>:ʞT]l + 	@}ig;}z9 "ZkܺuX_]^|ʪ>::}rttt1ˋeBd'du,J~7WWWwoVa4X_x c;b9ﰰc}Q%!I`-TU93KD޹,l
4b̵ 3{]wSUY_7k[ ;7EUM$јs0xgUdV)핈\mwʪvĘRQAY#CU)v]wڲࣇɏ~зһ)?VV8Y]ʝ׶JvvG?;R?唘c}׮VkAPg-}eYY猱0[1jE>|~>O~^\\eEk6$Q$UKߔ~^A(:D>~u}3EeϾxK=fm{ Ȉe_֪1ȸqխ[p׶luuɉRm[+H	>[.|=X]n*%ZT:@D @682Ĩu pEQ#d,İ۵":ׅ#4q \Q::cJAj,8d @0!C޻(9zkIMNXS+W!XE80egy Y!0H9腪&qO&;J@ (=LFhs2~YB2}M#PwIՔ8L+ "GYBZ.OֆD9gǅM`Rءrn'1t]v]!kCߣp P(̯^Y?,bANVYUՔ(p݅x[Č  @A$$¤2A{0 V.(Vqṍtj 1c>Hd34 7 P1$ &	X DEUȜg*Ē1d5h-uΐSv
?뺪PbP! Xkr!'ϟ'O>;vyS/O:tzSUn7M"Tecgˣ_|Yowוq9ϟ<lw@Dͦ_ޕeQ56Cawݽ{yyhuKs:trRuUzWЯ/_>zfC<o8퇧*o!R!ؓ$CP.5nJ%8 }k_r0w۸w A # <3PYVUY^]q1%k̓?Wg^s E$SeUUNų|1_~TBk(3aHmmjEHY3_)<e0rdrb	+Vd M/UYL%՗f[,cCRD-"u<5]*b^¬OuacEQeSq5_kʽ;7ԛ:ecǏ]^gMRՃXCaU]Dwc$F6:~h)!1TUYbϞ=\],U=[]]^V)aYjafV Q	D3w>裮]]͚Gr:q5@"lE79kE#0{9ςk˭(󹦰ݬmY7MS;	!Đ˺)^z>e"Mlq~4gsދR]D˲4$YkȎ*N!]%%cJbۇ]>ƐG>O)כeQe$MX	\xeYШ60_GCY L,?~=ce,1}˗,Yan61a0GC*!(QDH/"ƔM[T<x'??$A`    IDATuUץfr.»Ӯ
@u<|?zJeQlw9@2w.w	%@U$/_U
0d(M~8'On;wp1@`!D
 
d*Cx"-Aͮ{bSqؚqjQaℌs$Hdތe5CS\xAM*|bcUU}ׅ؋(ެ]J1謡%H2[0tmxw#<1ךs0	TE=:cB{aA `ٶ>X_ǳ: JUYG$#fܒ
֐wno(M("ݠ)LDSdfTen7}SI2y8YbXXd!ŴZibJB4e4pfomS)AbjvCJL0CaY!4CI4T`s-ysӉ7T=E0O71Szj(GͬMkT 1G!@ٷ  S='lf
)%UJ#m#2 YPUDhQTi9h,p[cɢY'PDMA>?;OO7u۶}?dOlqUVU9r\^^mVhۮ)EQ\u|DaHfOX63f1(`U# c?YkbJ!X:Yg{pz@C6&9|U޹CvڮC/60۵fݬo''(;//:}$Oxc/ܬxtGHE~317qd@o($P';-?l￑EQEq"I?ӧO}3ͦ(sءCDgg۷q&!4MHd 	e~V 4rF~H +9g!PeQ2H9>^.f(|}-_~]Ub*f?n^3w37Mn(˓['BP,7ps%q_yx=?.!FSq(C /ժ  koyK14V'{3@ے@ q9ʑ2a&-5!m˫fc[om7B\鋢; x/)8k߼zQ 2Č)	N9"O)؅9WB$%2֘嬩g6۝Gku뇲,ʢ\.t+3}
NCTeUUeUUeM~L1%$7Ҩ]cbږ> )QksR_Dwn*2	 ڶș!ȤvI1&DJd?gvq9Bc}࣏XP*Ym>}kbQ1BAfb"c1ڄ1V$FOOOA۶MUZNiۅwYS3+"H[Q1䜓Q%ʲ'ܺ}zQ
CJQҁDCRO~<k{NOܵ!!'ffkuu"
!!~ծm?xz@AiJU܋gf622/ Yi£"!TX9&*3-%!**=p;u< HSySŦms6ӧ]Q[`dEEy-e&>dMcB~!)Ž?{ a43ѐ&I4
rrc̯k|R~myo8>;oq,>GBc3$AsND([e XKD|nr0LF4z&$䐘9Ő}Hbs{:WܹiT;iª`;@eYxad߬WjꦪbY% z^o6m= 0q臡B QaUUH2khM.lo
וXN,o^U>z2e9P5Y`H ;2N: D   'EDCƸM͝RTEy_x_*,Il~fdrcz0?O>*˲(L}YUUUzkˡ[v^V{(K6KEz%p1!0[c93+GR!!0mS ݨYm:b!Pݻw^7)E2ͬshyttW!	^]^lvz^Zo1,ͯ?~a1fSB>8}/lI</ *mP>+Gne9_U 3M
 бs;;Qs1S^kc]._篞şiU2)P:8BY٫gϿqr;1fc,a T2dC"H)Yʪ/򜨪b~* 2\4S1x~œćQ:cD=hu;"*Tt8+un1^v]Wr1+eaoX4s2g|>QuƘ?{ lѣ?^}ks8Ȭӷ]ߺeuo40\!VCl!!UۉѣG}߷z:?;ngeU͢t3/<+puy_\|Clpj!㌵Y5!& Hg'k+o)UinFcmQJ~J5;D@YV_G\^\=bEӻp%*X[;xY#
 f]ld]Y^UU@8~]!kLQ! h4fvе14Ƙ0}!wNrGU8tnZo++g0hm( U b65Mu&d>9/cjw?ڇWg/uJQAr!O|ֶ- "}Qݳ\pɈp5L)v|nUo}O?w"ºnmkY;Sn׷u!ex  ,,=z磯}ܶ:`,
||$Ǖ's"uj	 v7elÙwg6ksg(  ѢDVʈp}Y RDFx?7o߽{OWŋe!%ƸZ>oZp8;8{g?}7xC}` cMbvvv6vv{!Eٳkӏ^W\"* P6K.UEaav,]$HsVΖ(LlE4i҅D[ܣkZCi^Trm!lB-:.P>ٱqkSbd@ Hȁ'[ﻗ4
joZ|&mjTJ#i hm@iEf&:_~!&cs{GJۢ,z=;WxgY\+֊Bj{`>?u+b'ʽz'EQRiN_?Un9ws18$͋E$2J @Q`̾0T  MRr
!%&;[RqQ67y٪\2=DRjCk{i Bc&(!$/`;H%{k5&Ϭ6&RIi"5NtNj92FAyp8ώs8_,r]_9/5 U-jE,㉫p0r@Aj>wwwL)$"Se1._~Hs ,{>9zlxo?GORY(ϳM{;ߺuxp~v\kX
jUh7
׵:Kί(mg'俚tT l)6lذ:')+䆛^y5Zc"-_Gny?'?Y^_j(f֫/Fc 
./B[ͥPDj*իϰa'͟\Fg9lS1bZe9$b2pʕ?/4$گa6ƘZ%Mq]Ug(V5"Bk8M3цHy$._w=^ļbywwn}[>^*"%tQҁ"~]YĀآ@ע;7y"TD(BuSgtZ7)B-"H2KDYOqt\ZcBS!B ܹ}??K,Yasɬ	I2-tic֩2a"XUk%W
f
I(BDjd0^v{#QQyx)vk$:ORRAVlv^7aJriba@@vs>$|QWUpM9YŤڲ9kk&@#JGF rax`aNbqp_pokk7or.fPdS}(x\k\ |gggϞJ=>1l֖ԓO޹s}gZ<^,mb	^^|\FȬ	6L7oDEݺq7sT%a0 ?8_w<zxm0SQg=gz;Wƣãg{ZDl^,g_|>2klww!4Ūr.yK#%
 ! %EY E3}aAD8 ط0r6Y^M#c`XŨڍJ(*qSIu+F:˹	l)cBǴ_a#(;[VEtF]d!/&n]d(Jr s l!Ar:ʟV<˒9*v"N=!u󼷄D/A(^D8x\]Mjy~$3& 47/+)D[WR~Y`cTe]Jr]!@·/?i?wu]f2kRQcn6='$Tz8H:)t9F9<T丸D ʝ",C"  lvK9D{Ykc	Qc  f1*_:@˸A(BأD!$  JDZYfIRay OJi(DkN0p"%7F[ɉ1:,ˢjZMp8L9?~@8igg2G7@Ѡ3q؝咴ABݸ]Ѥm!?~AeZ^B4iC m	QMCD$b"^^wo_N$"~xW+hY;FfZ/
Hߝ  )Svws|5+A: _>j!yD]߃-Pͳ@.+%9@cTYuUswC>pX$ȄJ,hA+
MN~?kccB:r||1/Jc"Ys%],!,˝! V+?Fjv5^vmgwI$I8jXQ>;J;ˊBiӪuϘf&=8I1v%Mfr-pTnd߾rxm';UO=ao0Q:}D$DSqɭk+"չI泳t6U]U1mV&qDĦVpHDy!$sH1E,{{㇟;skۓN	ݐ5hLfd|	,XFc<3(BHm9xTčJ~24" ̄ Df  L,;ig03GfGOI| M,"\SJ *@	㚦Vsnvꊈwijmsc@	E]D@j]+<Ϯ߸9ٿ}pܼٙy}@D_<˳2iUDפH+
1A9(RJi$Zn1Lׯ_G>|jYEgY	`
eYVjX4	*	˲ݹsoooyyJ*<oӧ_|ڍ[W\QDMLw+u0:YC^J"DS	!xS{egfV{,prrٳd2A>
2!J08麟g{{Eew'C y]+al	`	|X[QJ@d,QQV#I.i[Cgr_AeNڹBP%NBE Q;Wյ:DbCrr֢]XXZ` l^C, ("Jl (̐38_	mՖ@hhB-)RJu&A_$DQgGkH̄%A"0ǤaX`0_zugo\K_CDyXW{\̃sr0$"ɭOY(r0#
b;%+<!LherM$8^Y(e:ZR2\i"NӴӿ(j1St3$S+("%'q{l_$e2[l9y!DS;UбwWCkA^"Үi- % IrOd4,p%"HLML/^nU^13Iu]!p00ؼH?UU]58̌FCiF $\j]O&jr0eZcلF45p(̈%rzsoVݿ]ѓUUk#1YSx4~; )ƖP[;?|ղ1we-e1e7 0./xal`[Іخ\B7JQtUI hˢ⹈k]ek2!$1IJ!D>㝝^`:HZ)>)aud/gk׮YkFm4ʖR RJvٹQ7uD8vUf  Dth\7	RJ1!&($clq8|i`1s9 lmnOZNMh[yL-rK9Kj]eYj^UuQkE܆tD"|#&-ٮ:/K.#{,12V-IQ`)^ftNs7u|BaaB|	iVjn\^h΋YөkcqMY>x|?~Qi qA*ӃR1u1"wn
Aj@$8n|ecl@6j^~F(Y^lZ~7Ϗ=^g@9@[` DH$wipJ+σ%jmdY,يdū"n`: <==+U$`5F{2F$ Jr	WG    IDAT윟-lV4[ĎޙJicD`&!\]=ۿww&тXn\]q,DdV7u==;Ƥ:DEfdo&I_~/ˤ/K"{]{xJϦ@n@L] bއwwv'Ǐ>}X̴1&<wvvQ?|߉7&?>>~7&ɲD	 bjgpM}6ɫl$!8I^֠&Ma
ctx[MʖGD\!kVڵ\UBh  	 PՍRS.)!L>pIe{DC(D6`WYt///@؂Q  BLHlT't!vQB)K/Ҋsl&_!>r5dw7nޙgg'zL:SU|>/r6;_/p 3Q>rrQ &dh-$h,YEf]fh<{ġiZ׮u2gQZ喀U&Q&mt!>E VlNBK6;πP_Q*PJk[
6H/icйޠ(d,p8,  I*@ DKV\ h0"  ! ]ҽARQ%_b()QIiwH0}-ӳ|>gfEQ
*pTh"놃znߞajtY+]u[N \:0AЛ/WZ)4XeJk"HG`ÃݫW|>G":JXWvܼCOO?#{;7o߹vd<6ZWU`&n8pp{k.\MɻJf;FxoE{P"3ϥU{rَk7Zax AWs܍H=\( 6?#>a&F	k~f~ qS!CIg_~yeW4#F}@iR("bd\
hg4GtozfI ֋&(iۘ0 i1o^;~ZBVId]֚BYY|XMaͪdJdU9ʲ=4z+z/ UO܍Mf|0E9琙u7n+]ҝC ]f 	̀hlkA,e5di|yLL^M٬֫efΦDj]?yO&ѽ{V)>=]C쓒lQf`=/V*"o\xvtgg]s3R7V
@ xE6JiE=fENX1	YD">y'}~bS8k  "[J!Zuj"pll>={ҊS9ƤQm 	M>7`WD,\7'5^zH"{Yl̥׉(	(zfdy\-}JRDIAH]BAᗄ\u@|fM\v6e[n?[-F!b@ʕo4/>GeJ^v>r^JdqуlzZ{CHn{w}n׋1 "%	Q_<tw5& E+݋t>;8LE2ςWvW{?yeNvv>ef}NHNgǧeYFC	2#>_b|d$Dș#[+ԑu#"sNT:t6)H!xr^: AmH[H`	Sc+ajHF:D$Ɛ̩-I 1@6EЀ06&BQnryhK.Mn EhT #DE.J<81fk\zJ   _d2Ͼ	mckb:d|p*ϗ]dޝl774lY AV(i ȼX.(tc u }SEUitHppb ?Ե/'`HV-%%";V7{!z=/ 9!k1 jx.~ീJbe
  Ai$BV(b 3ԟBtwU"D$X5n]UqιqM7HhX9jEQ&޹u5j.{{4b+6+k5AY$"޻ӳ{$-2p4(2_=  P^2D[k1n\U{wPH+ *;1ϞL{{J)e;;x|kWv#c34uj,ExwD-jYd]%M6{k~xWWnHRٮȥRG{K^rL	E~Svf@ӂ1q@) ib믾ǟ|壪6JQ2&D ώ2k{emf9lzS\i݊Ot	׫jۂ?fp (RC4{tHВcb?c6 @Bz[o\֍˲~cf|̬YWd֫1Zl|4b_ܹ{ރ׾xt]z-ݙ o$˛]󤍺7RMN6"{!دJn7n" "pyf'PW"cR;Q`({^¨. em}GQrUJYcN&q?=ƣzXƘ<ycQMBH <[Jgy\f-mINYHc֛F BT E:	1gL=Q q1%A$ Dpym~Zn[OppiCH-vK+(
("̒6ɰtZu6&q}i7RqUuێ @ Ag}Ei	*u|	MKt"g; Χv{';eYfz	|{nR?:>~fɋ\)OE9 RMAw>VuN I@J';w܉Iz*q!yO>CSWn&u0&v0rXVM^/zj1D4A`0cwww_~\,{ﾳ3aPuSGcD4Zɭwuo[i#'z$sʘSmt'TJKٝQ/&ht}d"  ԠǐXJ9h	}uPLar;!9f$  ;)0 " 
 SS/aB-t79|ᐞ&_d'Oxymј^_g?)"A" Rtm+JȚZ9558(8ʱ7OKESj&v1zUeo4~Hղk"$պ
!׫u(2XD"a$FAPZkۚ2H"(R{;A׳y."GGG<5^Jg+s̛9XBs"R &Tp[  DЭmuyV(/Jm, 1D>n .LSlj9o?#"5J"!HrIbM|kYi\4!0GD42#ѻf[W5L<RRйx~>;:::==|>wMs"az1/@+HUPWdyb(L1ʂtn-4b\""01Fn+	`w|yG,[(
<30;Ph|~Dj0E1<SZ't )[fa]Pg۷K"'	NF$.7ڿGme}em(^tů֭ۨ.`V&j5 &BH{{wG#" D,@œǏ{ZlW{aʓHk]$R5'ŕwn?}hzv&	T	N[hs"F/&k&+MՋBd|{ZDT"z\)1L,Z9*{O^~Ū:H"mONZ
8el}'v,_7t].|fd4ZMReYU)E8,gnsM9 t&hxzvnNeBIgMfo|v6=+``0;J[k</RC]
j+kͯ~LCDk$n<ĄvAbP­5/Z'		!l!"rWo0r\DR:,p۫.4[#"̂hƐ"m2I:Z;^,b>:<	޻O҉]ZU(e8Ց@&/
BW+ H? 4ιz="u|tiHŻ{w/>wE#@Z+ 3;1>-6yfx:&RL- fvdwӧ+lp!Z8:>>;=׫R*9+2x"ӳb	U.uc+@Pږa0@ej]}(2UAp\\I^7n=zUgumk>;ߛz)5$QC @.	TڈZ1ZwJQ"s18fQ5ok"R|Q)  5	WJ`FӇ\Ӕe{/@$JNDsW[hϴKnL6I""E (R$[ӭeJ٠-
(1ċWB`%}u{! c:a0z%ԕ0L\9!~\LOszi?;jD$ԖS:A =eFL+cUnM3f!jImT2/˼,Д\  }>DCN^b*/|^1sE=Iw铐i(ü7̊^6w}*q $jj !-%bq: N"(@\)݂LPT#t^$rLˠquܸT1cK'Mj:fu]d21Vi[) DbZ.ƣ#"i+#ny孿V (DZYfHYj*2;vvw_7yGHFtz7p0޸2kǃoJ
P91=\Lfgw`?$w #m/iJ&V?ӑ MG]}>pxn_iv6c:cԹjѽrW76FfQ$3J!dL
j[7oz=r!|TV  fCWx~}h&XD>o>w@JA1na\xHRY|YFkA.!ՊwVO/	粳Z.Ue8*ʲ@]7N^imsY>w_~׮}xOΦR%Ylm|CDZ+E=_2^<O:F7fNze*E\*I%gzJ</Jy]
y^4NuQ)3\rnf4Lح+l4˪AYk˲Y{K^w׷o׿^YdVIw	Aό>QcRz#T$G$8"*(
"" ED|IBB1R. @E$$X2ƨ$Ǌ({ojctbr:Sc1Zյ#V;iTҦ^OL$$|^,$R,V@QFʞtWo_s~ZuU/7n죔ew{ly|6jBQ^}~7ܻw/UBQ~>h 2fkEeYhkJOr;z
1c!!䙽{b-GǧdZku,o}tvOI?_k^VL*BPjUտyQ"2YHL:E "jT\XcI!%W#Ts"hchy'0Yv("N)3- 87EF}º7ChmFC!& KH*L'ˋVjZ]	 D2GjݠۜL"t'>wװZ!bA@D1f]1jFAbޥXiB5γNHZĢ:҅A͊7MaYd\4uϲlw<GO&mRz/Fp0*	$TOQAW>x߄Є\["ORK%1
2 ˺;iԗ3M2-`fDBdT}Wi
Z)!e4B,RA8l&5x[O? (@(W 0D *9p5V3x& HhIDZ#a]իuX,|>ciᡵsM]'?}ztz|^ׯ޻;>Gkv9_&+XN	   QER^|\ {Yitgˌ~Y$e35<ji:[ sfcyoM&J`P?ɏjrݹ@l6?Gc^S;U<SlbvM*
1EΝ;WhmBj!Z8[a]_]ox nࠉ1B/0}+xmK.IgKԘH@	.01!x3)!Pd|5_wya[^ `	HS?úiYBAHNZ(mZdYӣ'O 2+"$LhflBi*CD M:E Z-䵷_*|3˷yC  ̚,"Z1x&"ctYhhЏ1
ճG}w^:y%F6Fe^dVkk9QqηT [ƬiNTsG*B"5F)f1iI'iy+oMaǏ*޹~?ed3"4nVώOͪ2gW߽d<<˴6/ZBp9;=ٙ/ʃWӧGEJ /G	~bc TCz$̥H겿W2b bF  $kmFBT&e2c-$&b䤄u]#b^c>pdpp5M4ks!nSHT".$R1a@$U|a~YG;;{VDI.*	G\o܎{    IDATR"aa() cU7=m~?~Gw,raY+~ܹo>/gWA>P7fSFGw/,D1SZ,7<yZ ^H.Wgǫջ˲WW6ˉ?x:"p4qxg]̦t^͋ᵄ,>`82h4CY.Jݽ-5/B7kcL߼u{zz>y7Ϧ.*dB'''Fyɾ2-|ݺBڽC8D	R;h֚E@i!Fhw``M+1[&Uس4"HL!b` 
V=W 	k8vKg39 cGS,-3o6u# I SHHSDR؞ :-_~@DŅ  0Ép1!./I[歷DqjEfBi\$"޻$"ەT ˪f,3  IE"KM?޽vp/"rc"cMN,U^#_?آ=cRJ!fy!s&!اyH|!Hm# (3} fI׷BRMyy^ҀBtq1%,Dt D	<v?t>WNB-Q0_`8H@@w#5kEdv}5ޥrbQ</Rgy꺩Ս1KW^ufКnHVi\djE4^_+C
 CȭL@) B0{ș9d6DfDJV-a?7fl~91 0G@DҎ}!uxwbdB(n;|MSHlWUUUUƘl0?x;?-VwM_#{Ƀ7!"sQV7e	{쮽 ?l_sхz᯸pw-n	.giI'Z`frw}?riJx)# `lu)1L 	CE` Pɓ'^> p%:m:IhdQeYW@~!k,w&[w=yZ.$ lBcޕo};wݯk (FYeiw]%QyĻ9g|~z2[eYU4F[jSvy !i	1[ϟ-uTu8Z)m{efzeYeg9V/&&EV}	gԁ	~QD TJuaM9ۑʟkc(b&c,{̜2j]Ylպ
"f{WWB۽(`h,EǲHC*ihxӳt]x*Bd2j|4	b1*B  1"j89~}V  \{EQVIK[0UR@e!)"TZT1kB$;4kBLdfa;OY~{.B,]jGX (@f4 ArwfrwNkYU%RFd(w{<|Q3,;3*2'5M8\-)jѳ1HLHݰ"M&;N+-0-ۂSJ,~knY I 1Dx=eӧu]'W9k탇]\>|Cf\G~.//*9@p/ nܸYp4~.I}g)ӓ<(Ϟg5>|(Y^3kq0\..}U9ւ6<oVjI)=܊Yuutӓӳk*R	C{dLf3[d]qYF!iBAV$^X 1C
b'cw${V{6פ^QF!Hd 
#'$Q( ң[^ᜒWz	s5J
't=դtۄ`A"EI!+RJԦe~b3Im^4M-Sb. @D*RF)$e-zM3@0+"k"ʌ)2纮!&1R]$,2#Y4!f:oDd<hmZDa|=VIJ1p8k>0 clf0}lf- R㦳2C[eԾw[߁k_Er4TNA*iKR0HJ[6/0/&RCއr!*Ԋ4JJ庫ؤ)!"1(D@d9S-%ZE]Ņ&U{/ZMy9"QFh\n|ոx1NiEf R-!آO&׮]#"m3k@11F)AW*c"0JZ+4k, dy1̦B3bFI+ ks@#@Rn| pHDHJ[yΞ>}e6%Yi֤4&4"B\S몪M`I(j9}=^0r\g/nܼ&4}o:hwh"=?dw+nNߤnzZMč.:$1kH+y hRx֊p@E$jc~G%0#'>P ISW5Ii߉>ɾK+ANΧo{;{-//`Zb}5ǀH c1bra_)8Nq'Zki2}ϢMv^tz~=$ o<ϙb^u{hkx+F/wn܊F]߃ZDL;n͠Cx (B^/קG_?ώONgj!*'o\w;wRɃU8Щ߁1e;8nm9@e!i8uI+5)I&a#+HXLfɱ1f2&Eo U1uEj)2f,o.09jE׮ܨz:Ov>d1-BdCp@H:/"i#Kde
j;JƫH$C& J?QAZ`D$% Ƙ,˻g		xT'H|%s9BhQLZmJ6$܎HFJMvv<Ǎ7Vʹ vyQZ)MS?fz"@^p4&;DX6nɯ~rQ5P߿{^fl^.oU{fbdŇsޝϿz^Wo(,jOONfٷV6^<?yg	_.ƅcոrX,>Dg?r,2mњEwZ[S&2  H7ѸO>~[߲֮*Ƙg'gawb!m6Z~fFjpED 6QǷG> $+'_Rn<|TD᠑ۘ`n:lM@#}r`f@S{A$J]fTz)QfT ׊HQDm1?("\"M6.-n@$EUWHED6B4lpd Ee3kckemWY^!ƺ,,6ˊbc$<@B 1=TJk	D!xcX22cR`sZ!2j  ae;c1*:D"CpkEsuTUSCS'n(Dm-D2[%PP::%`Ny"ee//yo}x8C^|äȢB1aol'm=Ua[/Et2RJ*}^8(kSZ" 16Ar9_,\}xVgan]ĀFD,ڌcHZc-i"NĜղ({y;2u׳ưH*,QY!DDʛ7oEDZ#cJ5BO$Rz/ۆɴR'@{JV,WYBB*
hze1=[/gҘ+vaCbqE
^ES1ZϗqgԳ
/?u^b6_{8'ZCS#zP?cCaL+@qUIyn];<Fv6ݻI+T|SHڠk(`4!q_֕.ܧ|2^{k\fE0!&~ FԂ"rZ#eUYMZ#c7Gj;?;ٻ~;wϏ	hFS(5Y-F'HtQHN4YGD1Xd6DvEp3ϖEܢ7 17?{!ӳS -FFE4s!z엽c䨵2J}z]y,/z\.R_dU8X[Ѻ꣧G?K]Ht]SG`p뇷ojcRe#y[>$+5FTN%Kx-`& 1jt/IWʢt, i-)d C[n89!R	|>'ļ(,;Fh4ba!'R8QjN3_U}9OZQѠ7͚>;;ѓ㓓<zo1wܙ윞! *E^A0GFɉBԔef)x ǐeY Y	5V)m2꺽pջ֦13GXHFQF!Cw,1uؿb} Q"a/b"G<c<{pm晙y_.Iя~O?ӏ?j[0޿ɓc;qB8W;7e㯁w:gO!TQ8r4Z͗ ?lG}tzp{|-Uj2dԁD'guZiAկui]UjX
;q6yٻ}x4ѳ_?r0RUj\V>~7엪E EA+JzNDJ 	fo Ql<kc>x7nN&TJns,''_Y믵cƘ2ڹ|` @)yZU|Zb^a;aK$[YH'0pǎ Q=N(H:U%Ő\YHʫq+QˤZgTDRIt_F ТN{^Z%BMCWKJie7.B<emyR>WUUW<ϭ1±nGEHD-W$`=k ysΡ(CaCUUM"j+m~,61~>҄F<϶M)B(d7W%Zg'p1(<8/"8r\	vtDBXl͎h5022:+ޠNTh4}ꪵ%*m: jba,A@WB0SheY&R"*Z;%x&B̌{[Ӌr>.Ӻvs>FF,1HEP9Yv]EX6b1!$^UsjeYJ({}DWbI!I(VUQ?R>٥I
$yVTJ'oU"nG`'eQ*+N6MJ&BPN&[wT3`)(o2|/W՚"KIzE f|?~mMf-dS&AXw+~lZSqFʌ:⨠C]DA|~"u]y9^w_W{vS$VP D./zrck?H?|㓓_'xJ
tP. `iΖ1@uUut.so0[cG?͛ͯ~ZZhDSDJ+<PDUg RUNRB*MS7|M/YUjEtl4<yxۻq>D66T!26D_/yi8rHHTu݀pWjc^s}\.//k$J(J]V_|O<~y/Rmt5Mcr=L|[kHDq)j5#A73Jq'",$ n|3M@ m7mRQD|xjrqpEM&!x8
IJ)*DeJ:,^%{@ܪmHK+ݝɰ߿yF4b\5)wƣ`P%"2Ǧo\Lg/?>ΚJMv?sͲp*GRYXkcLn%#]lC%.@߁v=A 1nݹ13w\=6s.67H!J0$+BA@M$9
z9&;%0Sp 
pMy a͊</?˿D~yo]<|珿7l>/Qe>X뺮֨㯟ڼٙGOϦQi_.;fӓoݮ뺜LTjIQ >:p45)BX,g/?w̬t]c8==8;G7GIr:?=M/wp;Iia*aVms36 ݓqoں`(ZUώ,$5#ct^D|kh LVژwN|H5i	އ|3&/PI2a 
ȶJdZo@Z@v*٩-IZcB
U"HD46ֺ	mWί	dJ{;+Rc#G蛦v!@QHWbZҚD$,,IBD{;LElP!TIM6&z6s@PUiNXٵȃzivd%䊰Q"ˋ/L$}zX1\ țay6KrF-L޳ +{y `E& @Z%}LSL0peQZBvUUGQX$%vGHǰzZ?yde&$~j\jW7uβX\._eֈ!@KEy=$Jֺ'æ k1"Qkhlr	Kb( BD֚<ϵH[B2cVIXywH1t15Hr/!Z5M]Uj{[VZ	yZ_׿GW'g[wF;>n-Hy$# t,l-7	tW_*Qv𛇴_һ>'D pb; `^k6hD"ca:=}\޽w?gWE` D"ajJB>ǝj    IDAT<[,l<߾}{8xAh76_!r&Yd"6uәRZ+d9w>kd8]Φ%r2&ˋptƍo޾z\ i$E bhD5(\Ai$岪jǢ(zj9Wlvp9RBB>O?'պ
Q{ hHZ.g'''(/bb$+z;C`B`F VIK؂F6%Avsn.m&flKE2~igE)uP):z|Xf(F)YLއ *z=dYd]_}7o.esc9I"zP	>(EPJhL7o:㓓ri~y U;])feYYzZuO|q7Mw:fzw*=^v?O~zy2lHT1&Ko
pۨUz
	H%mUcĄn 6&e-G	UNCA*@;ieB)"(/sr?/͛7I/>ƅxZƣ(@ͷON~ Bv&8\LgUܹ~c0WճgG1H!'(nϞ=].~7~TrmMPd/Gz"ZG_b^-/y8M*wn#Y.''B {2ϳnThntj&TJQI<賏`ll|~|rx06JP21ιC[V@`O59&8 ;kSL<$/"ejBp;Q$4r*>10IɤdSkJkukWB+|^6so.As{EwҼo"fρ ZJm>nt?"9[R:CҋI2@RZRN!Rh8B@bj i{xBH:
 (zE~k^	 u#3y8DAw-;7Nzݺ!IU' KX׹5 sz퓳+l@iͰe]]IfAVɴ cc*ԙ7~Ѫ]U@baI6DgM2Vw^s)mC "P"\Cq몮ꪪ]4;J[1Zkm16l(rF" ;GQ|1ryjrvy[K#ESr7`X%rDIPZw.uUWU=vv&cSWj3eZMJ3޹&FbL ¤J6˳,W^?+{&/fZuEhRJg9!*TƓc"wwvs*C- j]nU*zƄ۽h:z]׍պ,[7ܻg|:;?ywX)8Ҙ[&b  Hu; lVܮ!ŻK`Q(dW{m;= h[)~Z~Bm[@')"Abdg'	Wn_|l:=>;?y7n~vt<`/]"*-ѿ1&E]Y$7ճ_'k7nyѣѐBZɱr%0ޓR"lmVd\2I
:cY|dV"&wo^N/V%o^;7|U̶/oBJjݤ5U&_̼0xCȲl0j5N]02'!RZgJ]\^~r|\l|0jD	s"hMRe"Ә[Jde!$%2F51FB]LZ:X (i{i8pʦC(v@JBTa3lZ}Nv^1/7n?~)Ȭ'ۿ>LWnߺ;	&W5Zj	c[kWSby@5H.Bۻsr!5f8m˥k1lV^Y5Q D	su["*EuG_ON^<2kmn2Q$0DA <94Zliw qwS(-fo#B*xoB @8F w̙.&̊0
Gm,~տ_X,~S@-Cgo=[}wO>˺G`8,?ŝ{vw&ɣG 1ߚάqudoO=;:>>!ysajUvSj ?J$u9pQM箩&{g'=/23c A/V0x<Y"*A f@DBZQB
ru~~1ȨT!/z2B",^ΣDmsJӣkВjQlNЇ>w.M8EXYT ba
{ W@g+٩c!z+	TJAk/^Q[ӋW ][j؁Crfy6.
*VZ2ZDH @VcVZimΒZW^"EOo9o=Bĺ˕A1!^+# tjD"H̱t,`-Bi!DH*0U]4s
X%
EAL "vEWnFw-V$TE/m9"r%H8*BLY1F+I3iC"1u 23bhBHDVTVyil^ //׫e]u݄cd'ºj1JOډ RJ)MJ%v2dE) MpE,svyhP8MYGj@d2}]N %Z-C$"Lܿ_9~olMkU]UߒGD,b0&ݽΠW,'cEo!R QiF޽o~Tkw-.}ڇvU.,sf6FyR4wUg'ܨ2z^trCT6{gBwjkˎ	DȦJRlC*^67:K9^El#ls7MHFWH [2(>)KLa3w@BZv@dl:>=bߠ  , n:R_tD
W]r9O&7zٳSGrTxY +T󢼜/Rbj<e6k$eJ 0kF2G!?P,#mj^HZ+[iy h1n2])y"Bڼ+r @f[>^V97eXDhWtX^U$BIPm"af$(,3k@F y^uՕƙ#-1gE/!9ϑZ3kQ)$JYu_&d:L"(
z'&f۴}Y noZ3]sR $
ښ	KSj?ؙ<[19n߹}5/>{{Jkį	28"WDyI!N `>Ruԍ.gi}  Ie6!4!ъ47ҠA#B91^Ow'UeA[cLkC%C,CJn]'qQ)m({Ad9qFtMv$@\#I7$IRt#6V@7ڟ BJE?ɿ7k?/}ｈ6oh2}գ/>=;yqhx9_|o7LΦg;`T%EQ_<W_~πsE6uu_}WO=ɻw}Of(Wtxz|ZDHi^+yy{?"ogϦ<p8!|; @az\ec5u\%*;Z d#_vm:~W{T>zu~zn'(Uc$RUX#yEA+#ђV.(j$<v=z!-biI5Ij`F@Q*k1It%驒$)lb*R"	&ԡRy#پE3֒6p]^qnұH+=&x'"֘"k)yϳL)`@"J	#+kܙ+qw%hߙ0#6&J)TzmUw0VsKimUJr?y_Ro᝻٫ `QTt bB̆Բ9e6iqN*SX2drY9ʾ-J-)M\!(D&3ڠJULGN }a.#Mu>-eQhmbztZUk<34U5!12 [*%h4cl6G35]JEQ奞K @W6򸩔֑#X^Q Q20a,햽^`
@ǜz^s1{e9\iE;RӍi\]i%T$1_;q?<7j  a7+)Ȩ
!FL
fv|5Z߿[5MUw I*5ίZYD)-)xwgk|pn<_@zzq^-%1 ӏF?qەԿEǫI`kv1a&Kl޽uGK0ԫ:t.\B7a)8F qT *2j6/7/~sWW&SOkOD	Di)QSLtP*l{;=|u.1&ZyH!xe)%!fEni1ژBnm鉙Y "1	  $LRHs9SuM&+eEc"AD D\#FU]UY6v^Tb1A^ж2!<hcER[$ 46 Q]&4eZľH!%ab82\@9A6cDETKv$LH!hiW5jӿ\J}[f 4!Hx4,b7~Ȳ5({5U7oHОK$"tO_n&cc Tg>5~AB$BAu+$2CblquDΰ@}ZV$5q{{{[7}^<{zrX'`*ҨJT+i1Z-,/zp SH	I!8zbb"QGjmmFXIg|Hӟ|ǁ?<_?yyYg_\O&㝝{ӧFvX'k7_
֋e]c
[o߾uhrj~wޫ׿Ǐo߹{ i,0k>=;Gh="&Dz<^b$}Y7o[ZeQ^ q[f6  ò,Su>#md"X_YӓpdDb\ԋ#(8F A+-uY)RJnk#]qV	}p'Pߤfk:}w{:}c4S}VHHʤ8Vʤ(JHPWWlnz+UZoxR!D6"!	m&FSLy,C#Zi,*pNw
]"LJժ캮Ɖoz0Ao0[c-,$EjgHjpNt>✟r6>>zvzvzvvvrz6엇n] IRXD5Ņ+HHM=%	:+Mˊ~^m6DpĀ JLkQ$`7Zc&u]ioVJYuX,ft_Uwp@"?u]cL"9	!A PZ yE"3RVkDc,z]UQgr<99QDMz^Jp@DUIi	!l6٣[L.^Q`0Ɠx2eK0Bع.m[C:@
3߸uG?F`.ʞaZU1}ιuUוsN%^(dw4癭b>EWu/2kEg`I+%ЁߢC_E^scW@Ks6x.go?hɤ˜:Ϟޜ	\9l%WkVP Dd-'H97n\,Eq{D 866LCP%Ѥ'|k޻sے8Y[+FSS7ZE8e"uŠCRyE"%<ITe1R5! WZir-Y$"j He7ZkydB؝]D:==_ΐp4y¹|{m=RQD쐯HZmTRJh:k9&Eb>^#hqЩhMHA|D ERcd/BZsuP_ȉeɊ
*fC-ATly۫kN])FXU޻ߟM/q8*cVܼu{7.Zc|yBo+_ "(+ rEǄݵY_I]X'),fyӑ#s!^_{oŋϞ<yrϟ]U4M2- DQA$ya3KZ'56(mHG`FgoK!8F bHjYv4æJ  6/gϋwv  "G:8_??~WvttDDYfnvv8M_EE望wݽ{o]˙_OO׫55M㜋Ry^|[ode|("?~?ݻdBBjwV :|Ca^-^9n)5O,sr>=;M/hMMZEN/.mlv2F  QI\$Y ,?z-W*R)lU&p3kTb1%ӿA  11-X6"ާ!QDbK_F9xDHq! &ݫ􊽑qڼ?	J#-!A+"rNEPU,[Ԓӱi*K5@P4aMyR[#u][Gfb\U `ֈpZ)hh6K~e) :j2ey!b1 df5Z)@:CHw")ְU    IDAT02{Uu9_xO:x8{D }R	,[BB<uRH)7wHeIZ)2ʬ罁Z6 S]tLY&S:5	3b!xԮic]15bٳO=.w ]{'K+?=_EhBPnl6*m>(V+	4"3$A a@wUwg]s~^Ui4^ʗ/3 Tk뒣 X#Qn wPt1R*1F4Ͳl<Ea 
Yk6cp8df}]׮mbQi4ۣPIBTXۦ|r1d"i!p]Uu];0QZ|"P<'ۻ{;VH)-4M Qvk#D G!޸u;۶mU]ឹu6*Zֹ]7 y:;;gO,3QU7jIDѹmj>'@^X2.~
P?1ĺiu!]*G(;L/ sBNȼ֝I.Zևh׶qOr@ `#iFkYסjѻO`lpۘHk-G_+{VY7Uֺۣp<a@|$i~mibZ7u3[ں~ZB
 LD IB+>u{ tmj5mmU{EBxd1;(: tkcK|zfۦ{Z.P/ &RjB jR~aݴ׋m;XlJ @{`@"^JTR%ri,WuPEmCV0Z%FGu<kHfGkf̰g-"p}ye{f"`G{׶mحɄQHｒ򢘌Gmł7NkcpE{u(Sq܉Ç	L@@2B2bODZI@01s`)mxkbHQ*cv;WbB$R
I rƤJ1pk󁉔1Q>S!\`#ac⑄@!r̳"2M7Z((pOo;{?ѿ?DrL/_x1;ܺsee{F?O>x@;;׮-[ovU8>><߿ώOw&mڦ#}U/._{7{g?ᣏbٻ2""tUMU),Ri F<v&ցH+um!*ˏ?$I̍Ӽ(WYZ"L$xM4m5ʒl$Fo`#³
	ZwG0Hi]rLPmI
6-uN&{t>tӒM CsQiQoE^7yޅED
!V&QBK 2-6/k@| ^2( ~U)P6p({ß V&8h4MJi&
:JVR*c6Ƙ^bEႽR*Mh(d{o>}TJݥ(Z)Q'%ŔA*We5;ylQ*d`uUY-f|;Kh% ԦQTK,{>'*%U49b?ܮkҤI1zCIRQ޻vmcfed&I1ZtScskߔu8k9B='//K-x3sm;ʨF'II&l+zŝ;wm./Isהjyr6=<wޟum_[7[Zu4mD@D!ϦU0V_WH"0U9Nmh%FeK{hܹ)B$@@$"2 ( w`ȎDRj몮Jkx%u,µF7wvFaȁ|z?fi4~U&I<MQ !/p)+_;SD᚞wli]}5sȗtY	vC ZkOm}fU޾sg`vv=)d	K{ߣyHɃ>ӛ7ݺu`(RLHT&^m"K1$JUUڶml&JPxB $ "<-G @H+^O* g|2I4FpPHI`IZ:~BH|G][f3h4O&r,u"8B@{1^4WsW@VR鍹00_GUYY;)b\$@P⎪8RO|`$b D4Ij3Hg-.{BT"3 F}Ҹ
y9.7/]M<被,SU-9gp)翿Tn^,,,h!bc9".+M$in@fh~զ:|IH"{昁&iv钙L&7o\ݓӳgϦ',bODBtWk&HO[YRyh%ET sNVdHW&ϧRKUw0 WӃx~_J(K罔G\,7o>9:zzlk<_,^G?۷/?~4׮]wbU>@ƷJME_z?~*˪,p7ݻ|<?R[od2?~gϚrmooGCX:OEQ ^_k sۘ6;,I,2e|6u{Y4#$Ɍ1Z,,M~lkZfec%3$b1 $b@A@";<:Z߾qnF[NVVe B*}
(IʫJIu¿kH!xmxA {o]Dև(c׉3qSR((H
6F'hm6J+	 (RRJզz6?!"
A!X9c_="5ug85 4 -;g۶i2X>I(HeiZBJ);@lE?C Tb7U9X/&RIP
PvUʶS=t$iXRvvv'{';RJE,4/\T`g.%+(p,"0IsM>PYBwK&-zI)m:6e6m꺮+r- +%N$Z3Ǐ5MLx){vQlʢRF! RR9/I4ͤRq'k$tΛJӳ,ֺVmSvkF OZ<9=;|vX+2!I%HĶg'uU:yxM K*ee#R
֦(32J(RR ?PX f)snzvs|\b(si}7oimOUesn\>{4-@,<%=!1X-= \)5Syy/^W6	;
_=GfqSn 8K^֡&obxt8aZߵ1MS0uM!Dg۷~qe˜xZn  uxqWc@,_FW=;<j'B$ΕGEHL%IUUI!.03s  $A" ( Y}N@@C+^v<[-F$3{=Ii Q4J%iFWU%Nϊ"v/-x J@DU"@L"X ᶮӳl:0Z}~[N1a&BJd "oq>>IW@d
(F!%^@2x;o21 ܵ6M~.CRggeY@4MVw/pw|^/&RJysJZm	1[K]
)Pyb1pew$J$I&իޙr>''gŢ*۶u.kwv13#1&~\iI5hTf$He	(,˳L8Y)Efo>/o{墪JBJv_+O+1+W;OO1I``x/Bbk2>>>Z,``8ݼ}ӧ.w^}V[p0N?G_iZHt{{?[kqm/Y.~OrQH(Y $&M˺*Pػ|)!2^'IcLfIb1ItMYyl[KW2j#<(3Qʕ+gӳn Rb,[74&B2 h$hXwH!"Nd~yh0ݠi]n>Q.&Y !@H(!D4fq]~.J)	ۨiCd!IDr9f(E8.Dƶtc"&qÚIm㜃ebR$Vdg`i(xA!y#EK|5FQvoٷ[k]]7U]U5NH! PF֕{Y+#~(̼(~bbbuL@uZ1
Iez$$GC29w66g6&ͳ9nO>xvM4uB@Ԙ,,V?|:u>hե(nr `,V  =5-:Nߴm vY4  8;=f\Uu6mDAkkz{w,K۶>;=}d>SPHRey٪,W˥@</h4l'[x44GB`qKBtQF pۺŊS0D̀J41Y1&	"rw_t*d"ϦY`ZgHH9._BlvrrӲ,[W\q˒:b6QO#ǝ+/0#{h^	έ/F+~@GQ`	<"T^XK-YsLd	פ0mq zbgiba\Օ+^?܎BtH Pwӑ}lG(N~'O&ko,W?NO-s`8oJjZdY"ӧh"g `	@ >*tV!G` U`dd2(
lrEZ.VifDҀR	{R/]Z4tO;[7Ïlk8E |:2V !Ef,rhx6[BkC+|zz/zVO\5?%%Ce1[{ Z)$ }ZsRRR)%@|[;%Vl*IR6}rs̾qnk̵f+FYЅb~J(oUoեݦ];J:;} ހi^&κnb^³qy  ##&fR*4fDܶmm	(wwo^"M]/Wlӣbԍm!GB$MJ$%YQ
QZ
Љ@_,+zB
tKiڶ~p<oMӬbAk  Q?glz~F{/'
\yoݺ/~՗^wwYgg<I`@_?x<KmݴoZ'y1m&w?N[ˇ'OH@ NƓ$[kһBj9w;`2ZIHJ94R4˲ޙ8<:n޸9
9+ Vr:ϒ@Ulz@)w.½'DXJ*ݽdJGRifE@d5y`N${iA';ZJu>mQPrt/@hF$[w') ,P8߂BiTh/D3 <q`P$&Ye6DDYOԷup(@H%Eߟ3(UMn瀈 3Axb7QB	afT*dwk;rG:3R)Rl2<ulsE<
B*յW05m9:"(p0ڦefmtUUk7._1ZEx|j e</#6ы"R"/nȇ6:z贗}1#k*=LB$"ϊ\pbjspMU5u֫zRiV$Y^di&$O꣏>ow6i%Ĩsh+!elɘ0k D_.eWRID; (q뼋Q jQGQ9fc]J1 D%$ ZkV@({w{7nlf1#)ҝIҼEUUUI FսFQf PWe<  
Rk"|*ilSD)<Ny{w_QHM,L Zz\z${ޕWÇGfgӪRkoãm۶M^8 ڤ95@C|8sDr B;gal:! t$t< m.?wAE^IDQ	. I_z'
T@iL]$h m\.eU{ޕ+7_{A!Ͳ4pQD9 :h~	!^4"OFë{wv<%T'DA)JU劉mX}׻~;>yy%#@CԝC,I4YvΝ^)~ (If	#6	s)r̽g)Q("K'[[;
)R  !   D	IBKn]pMJ*!w.'G:I"XLt0FÛw|/\,N(QHUv}|TEbml|UjS
伳G_ )eTj-Z@kB*mk쫒]D&s s?5:"/bN/~/
e?{w,E~+1~~̝Ǩ7 &I!uu^Ş(Z.TѠv/+%.U2귢@Hdd<zkmkWlzz6]-m@ %3H&%XI954Fym4=wUd4ڙ^6߿[^-'ǧәtt|rzvQbRaYϢ۷I꺚oK;VON,+7j:==ݽ|9MҺOeU    IDATgOaӓ^-' 0Ż;W"I_?}'M]d<#
(inB !<=<rtr6dtxyQ$&Y+D1O^0_",!yZ; C/ϲlrUU9%4Gu];gTZ;O?}v$އH oIEByiNQʗ@tYD(_-傣?b1 ` )ScBiP:ĎyH	im]K.IeR;Ըz!Osc4 w J 96mBňl)eLA㲼PDl?` @!
Qpmۦ	!dY("F`:w|z,[[[ۓ 4$9&?{BJiRFŚXJU"QFHEDj_sއq4McC2d I!\-WM޽kۻ:ɈuN w(|li! J2NPҀR*-t4謧QZcsv;6fLdEIlD8Rιj*mSk@Eg`0>w~ɩs6K"6>qO׹@Q?@c70dDnGL@@wZgJS
QuFJxOspLQR$mS='Gm)ˊ_λ߹}x/Mnv<N??99ι@h4,,bH^6yFIa(X[y$Zk!$ NOl9B,MӡT21sݺeU/?ᣯztGJ  @"gڦΦG_?q  Pc.]v7!:QOޚ sf$1ʹևX;4& F'~w]4uXr Nߟm^Dn"p]?wZ. 0 uב֟AH:~(
^8@VWv7#4HJΆ5,.m{n\J_^^ qqu>xo߸ykk2֛o~bmb>"":C(ITVͦ<ִQt`A@˄:T[JֹyZb(xk6INw`#!IdmdXEo m\;"()Q`4H$JpimA	^󀙃7Zˢ(ñIR
i߿ds:f];(Et@s?6^kD27| ψ9
:,Dkt#TJ	)@CjxܼU>0g]9!|x<4m٧&۷nB<_%.7y}xn P/;L#g'EohmD (`3@xk}n	\qcyƓ^XUZV.mVpP:R)6qJ %	K=ʸI&-mj5abmLyR"X"VJQr1@"DO?}.O4ׯ_Nv$r\UZVe|YIrp@o;UU~>x<}w?>99iV1Pk<B 0u	*\G"KI)u]I<Z1$aݒ"p.!,ȭJJ%Fg]lL!MX,LƘZkM{ӕTu]ǶfKuY,sVժjZ s],8f{VࠌB)B ZfYd#PHV(VR)!P.PNGDghkg;l+6(mw31&m <3zSs3s?DuJŌ+ls}?4M:yE5198P޻i2I]qѐRDjBmsrr\''<+^iScH4IV!2fDTRI~b7 A
dDI"JOu4)5j\  ROvp8I!B"9Jdx$BQQh$&K"
db#Gmr1IVY`s'۪lʶA4Y3R}W_<x՗E>t'pQE% 8vn1P,!{Ƙ!)E@Z4@TͦO=,U,$.]޺u^JQy|6}W''MS+!41Zim6&O<˲(^W4RGeaB!*UYVu[uݴι@ݬ1&RiZC1 {,ggOn޺eEJb Z.^땍!cd2O@Óg'Ųm[I`4A&MT~(@wwF\y<	|Emf~ 9+Zmd;f`4hk7W\8?:%~.V&1RizDjGrrm+]%8ċBz,Kۦ쓏>h<xj)S)ǐBF| H$ݹtjLIwFDfvU@jAB@M\zkۓɪt: Pu=Q'r!xT+҄BUj[ (z׮5UUd00NJ9pZd5B 0vv{ٞY~gUY
(Qh4QJҾQ2˲1SWJ􍓷~g4+(G"StFuT1gMH)V B4wևhDдm%FHhEyIcJ(T;5XǫgƟs$O#f%v:f3cL[|X,>G?(Zp^dJDkD1+#;kLد'R4m{xt4=;%FEJXif0 1b|KPB`B .z\Nri: _BD P"`Rě"t8vE1J{0sKۮ[[[Z̤Riۺh eUbyTYyokfA}+޺uJgFH&I޻b^W%JY.M bY"ˋd|juioo1:K MtA+=A"-WU`B2 7͈h8mzEfdYO׵RĠ&ŬB!"fujtf"A'  \Φg''+$q)bcj9D1wO<w҂g\B2B)NںhpAGecpM`kPPR,˔RG!(&rm뽏R҇L:QD1J>P]lk2ycC(h-m*[UR<1BJ D!<WJqi*ꜯZD*hh_xs$u՗nfXq{f!> W-4}!TbH,"4(:/s`|kmUK ;J'IR!)֮iIy^+^?0&kVJ3K!9 EzHGDFR+` 4""/{Wѩn\RIkU&"&Qt IΥ$ͥ.mN2J:I1Zj{lmD#IjQR26.zlƘ4/噖9r:o's&KHஐG{"=WD%Xw_ƎuEnA {Yi"8#
!4MSUj1M鴩*cFj{7n^rm9ppӓO?$"4MEpfPBpށQ+y[j5_.օ,MFh4:1RMILVRkNO~_'pXUQ{ h"b菷/pz6޵4iq7'Y"x8_ڻIL(]y<)$o;Ow[ ι3뛷$pC:o&jtQU͂5ϹDlEbNXl;w@b R6Z)C!p+r.$F_ۻqt>y@T  g0Fgln _{m>|8qMӄꦑBFF,41&Ӄ7of$0snR&e@]UU7_}bYf>=nմdBJEe{(I EJfm)a{{{Q_d! >)f"cw6u{wA4ibʪi<=qp6/zR)ֺWaZkJI1?~w߻}. u]V>#B x|#T%'I p@c&Td:޹N#c%?M |RI)׾Ds 5'/|27sʟLuXQHlՍ{LԖˏ?|W%?6_PXjⵜ\lCR=LbB@ JA*)XJ%úrP%JZ뺦yzk{UӬV*0
.PW=Â|sy?x,I4MvwvYWl6Mbf*b>g&!͋KFǏ=}bVJgB彽+וI`^IFѶ糙N?ܻrn]~d2ɛv2||~{->{;[W._Nm{IeF)=1GF|Nh%<99&>x̵NnU`"|Z5m?ʲԅTjU1[P
Li^PVtz,+p0@^:Lb*WGXLOʪvLiBD>ڭݽjTPRVgH &ΧnmlXwr>ߊټn: 

^Um-$&LEɍcA#PfsQZ zvVegOXۦZI)=EXwiiZ gxE  |( -uѡ7K)95EQܛRZ,Qx{;g)0䭵mY((g95)Mf$R A+E/t QK9,~?HQRcڶmm}T(VZRuX !Dd4.ZPJ_L%ABbm{n$j )ʽ4K>q^M8ꧦiڦ.]S *-;jŵQ
uFK|cmimj$IQtgiVp8?W''PR;cw^mƫvر|"eD;a]ҬH#p8>=8>>>;;[,jUWUkQth;oo3nZPeI"QU}g_<xH+%D%i.]ڽ|e4E[R>U-ITj43-ٳgG'gs|~o{{;/Q&b()Zvn$I~x55PZ!@`fJ.&;&+Y=q(FNҺ*N1ofU<$yԍ=[ѥS
`7~xRWM2vl`T/N]]_0츘7p(~æ_|H	k{]X\hnGcd/F
'31F\
D$`ݻw= x:/t_NAM*%Gу?ݸ}w<޼ysY yE@l!tXb;J"#d+IR= +D$FI)׮PR$R<;<.B*fvQbtul DTJMY5
<+Z=;OX'Bjt/K@"&q۷o߾(c<-DL'3RJ%ԩɊ~?(WŞLGb_g^v{Fh8=:sN #q $#z,˲36]wiWveۑCΐE5w	'	Ѓ	0F(7CvUuʬ̌wq-=s#"M0CfDs9g DY #6Oҋ 7(+]4vI oNdf΃}L#(.C(֕3`f/ᬵMNYfE^7?6HR0\I  *S0İc'jz;kMkdFr9i	Z8tF(3M'I:0ϲ4GCc]ۚm5+2vxBvg¸">xg"!\.A։5rYU,˲r4rx|>൒x}MN&*^}@hZ_y6;,=>>*TiK2rd6wyo0gt6\裏Zx}{csc+ gbf_#
[#8SJl{rz ?yqh<
myԗ~X8 QZ֚PYJH3{^rxg PI+ek[ZDA gr1s6X爐98[cj)e4mۺu1Rʍ$"dZ 2fA+_Tf%WĦ!H[;묉BJ;@BMB4Y6bryba5QD'1ɓG"!)}y&g[EѓRkB="B2Z,J]+ldf bѹBP
[+Oׁsp{gkZk3G\γAճyZoeBw઺>L[<^K%Ge\HHj@RR_@RXV "t<ZW5r2N=C?o
93y"t!CΌ¸佺iҝ=bI4+<adޱ$9m[-!8@'I:͋<ro}|>ODC?J+%IȈ>o"t޻`oF28~%YqQBSQQ7mݴB.7nʋeUMk}m"RxpxKw_xas{'Q2x|BDO.Ϗ<xpvvQV5.Mvwnommki	|Ƙ N0/|6 H(O,QZ) 	D\YEeO9TAx!¨ <Տ^<a\Ԓ$I[4*$ڶkHi
)	IkuҴ3'ޞM]f K_L> ҋ\f[޿l0޾/87⧟i=I `k$h<l;{Z$    IDATW&xV)!>{1cs/XJRxY8?{Q`u H!47iD|{{;~߶mi9c1tLw}0%Es*+aN/r1'iz֗4M1''uyQe8IAQ=! 	R4u-R8`Ӕ'ǣ(؈qF0r0gY&CDLݍ^~v狲n۶ii@+I9oږWI,:@@Meu溮/OOO<~ѝ^<88L"!90   n	 w?E2Dql@:K#$:ją5s0ݔV0D@*H Hqnu_+֔+5XX"FJDIA +z'GUU?3աp#j3p|D7>9Da65MS7RY{($30d^󭢴H	A|M:\9 wԫ90yfLkm!ivXLtOs9o;U:bYUȂ׋r~BƣဤB㧧kL;gF"/~@BcZ"m(([;|["'঩9|i ]6u"h9`{DD"Mfq]kc Y$"J"!@;<mh:`i!HGU0˲"BMSxXh$$c%Q
Sq4^/~ (!ƈh˔5Vj(),BFIIǜ b=,r4UIp$0xknZcD Ymԉ[65Ǒ fQ&)D+]
ʾ">\Vk_?^fluN1;:+C]G`1ijqŋHFp1
vvYMڶ)H yAH	c2`I)10Z'Iyz=TL9V[pĔ\wPץ``۶i,,##=so4z6sb!-)ѻVfY^x\ݽC<o{$Zbʊ!`}pƚ9J)U*iT*ݔӧ}ٻw||\׵V*i,H*	J
b,cuEAc.qnDPi]́Z[ŋ/K/mmo+zG?x
A+l_U
<_޹kon	 sr1|񓣓kizl{kcoww`{s(JKwqc,KB\UWM]ϫfQVM]{o4"ˋ"K$Bd -E{KB"Mn4غpJ{|7ѐikmHjmA(H2ikZQH\ ĶXVugyn޾민wE!56ٕ/$DvsY˼wFzGg߯4xћ0lI{w_[:q8[RJ=᠈$ xN;eǸ )08oo=䣳zi;z6r%QȦ5
!ɲ$A´h:yn=bVږ'~[>Z岪EA㋢( pFX@pǱN\7yիBlmmcO?Z,uU&Iֺ,G㍵F3)e QW_uV k+,fIE	G1γtRiro==={h{{gs}9}Q18D)3`$.ƚBI P:yXḿ:gC F!CG@Rd=:-wS  |.x!% " އ(0[D$ۧ{}9Xx>C9Q(^iCBP|Ϗ/ER uXf!@!a=b*QJ/ggeUNwwoߺuAu'vC;wi|tim[Ӷ&*4D*Jgl6	!vwv|2.拺Z
IH2I8O,'4=8<ol*	Bhssc+jc%0K.&Sk-II!̗dH`8\+;WUxi·Ǐ>Ώo76ֆEU!ٲ"~{g|մyb]"gIio+)[t2O}Y^VR
|'ba"
Mb^RR.Zǁ(ITW]M>1nBEEB^懷{E:?t1	Uu֫c- 0IX5^$tzzp=j&RTD$!$$BJ)$b$EPzYjBgۀٺBuktE%Rʲ$DiEJA;;?OD(}"&}38[~UsVֻW/!!3\3/ֺ6x@V[ 6-zk*UUbwK#3Mɲ8KPsqUU]4s:cJўS-)KN@,Mbp6zYV "u泋:Yn,M5H(|M9+]k^Aｵ87EnEB/M8kn]bZllH"/zy$QJ)AR$~|O>Q"y`VLBH!eQ4kj(˪1淽ҭED-Egd:+:*7" 8kTwynDk*RͯZ̀[__7kۦhɧ	<tO>xeclVBgK/}!xgZ%	B$Btvv~> ,~ D\ ).:IH*"sFt`ƈ] m͈_7mӪ+a;fd"ˋ/}+ۻM]Χ6J&I"TJTD2x׶MUղζ5e{;{i^3`UE>?ƿ/m@ yuc_U)jb0^~^x"ĖVk{t<Lб
-c"0ޤ@c;hhb,Q #1@$*<  $SIVֳl}|r/^.7N"xͧUy{-mS=x_^^?wyg8:Fs$ 	Av*ж6x7\KDr1A4$	!,omn.'BŲ \\^{Zc)Dݴ̌V:I_yN6w^~b19BL@[f>T##ιֺn*ͥΘ$ֺ#Zϡ @HYiwwo:m=>:9N:IӴ_kaeiU0JHPJblu}u=j$"ӓeYYih4B0Θh3"$D$u5WE{Bb+s7Rb$ J"QkBzλbuӴAu^_yD1C˟%
kD`.n&@1HHѻ/,ϝཿN./?z_LӴnf (<@H{u!K5@@gU
l4d$MNQsisڦ>??{'Oq[o98J'Qc CRh'!ܹ5MEZBh5-{O&ºɓӓQ`_ u$Y^錽o*s2pfR*5ӓl5\1F.ӎUӞ^Nr%bvssk>[ӶM] <OC RHNR2r>Y2E:`76uMB<?}z~try	!U[Q"Oe4M^fy/xw u||l}p=xss+xWWUQdmkxRUu]ےoۦ&D	J1H"
H(cy+JPNJH
ABhwo/V$5	t͒boٻ֘$cpOJb<# JARi-DDi߻ƽ{uUMr1[+,Q*InHwlW9u?#@MuЫb.IDDm^갔w6jXedYꦭk'Y֚eh;Rt:k]LMUuS7;( Ex̪ukgNq2Vxdv+z*u/l:MZzE^vzyKV@X^^b:Lֺ5fβ43L[UݰUbMHRwƶM`F%% RJI"Zz:OG>[,8X RHBTi꺭릮5 (zUwwwֆ㣣ǧELwobL$?Q]Vc@'!{i uN@r1w~ɧO:k1U8;޽K/:OFU90Dʲ̴50ITT摄:M$"II)P~sCմ''7Z =p`RιEYPQ&1O6z9^?{y/MR2x6MM44{栗7JxLsfE\pD+f܏R2_0\Qׇg:|Ey:߼n781 eYE!˪n6M!H[WL$K|<"~qӶxYUYIx+D0gH{G{[`M}!wI uI Q yÌH!pf!19W{ DR'$UeBǿƛ7f2Kӏ?}^m2tZɑHD`&b20G*ҦmR*}$T%i˯~{UYNghD9q?xi]W0ޗe9F>pyf )c7Zgk㚦e6GYzfd a`A}`$fpִsoD*D$8D0I! >D'nMRJ)ѓ}O>fMk|`%eE^h9,\CC/ӹM)+zw;h-	Rx7>c~	nI:4#,Kgl[فWr )JCi	98rLDJDR!+ƣq^9m[AoқuUlwwmm-j] $LӴ0BUx`2F5 @j%9'=L~ٓ'G٬+n?篼Ng8	qQ*!GQf!!5vOULlvy~Ǐͧ]nmnnlmַ-MӚ6ƴ)r׊"'U];vf۔UUU-'OXXWJ.+f ɴUX̥I:獱WMXgPi,LMZ5_,1gx}]L :?^bUYrRlR:	HU]?=>ml)# R	뛛ylp{{EU7CYUҘF J
!Z| adFݴ
Adku];YRiWR% )	AR*zY&LKJd6x=y|ND`ǐ&{ 	%"jRȳ|9Lfr1zRV,U'V0ee< Nݵv,/]̄ MS:"""9x`omL]Yc/[DH}Ν{ۿrV*Iɪ5m]NOLg(#9 #{=	b:I֚i
jxBh֙vY7uM[McsCH$˳^+D)ZV&|uVgcB̍1mka0y>􇃡P
 m]7yoC:B gLBHh'4&Iѧ*i[DPJj΅ľUu[m[kmc[|XM`$|4It2?::-:Tu~_׾>^.4.//nkƽD"!$!L&GO<dXXcn{yo[{{Y!Q) A& !a:-mMlkDkRR
%NHBF̑T*~FK(v,޺K/o$B:M|+JDJBX|XT[ü((b,Ck-V؋[s!4I,I*h@kEu5!1f ˈRy;a :>|}^>b s*ng"0!|neBdW%&Zž>0gPJӧ~Iaiy>B ÿ˿(~וtfZCD1rMaB@dfJIDUU`:ں.J' HXxKosi˪?y[/'fJ˥	0.V\	AB
!QM]Y4 vv.N:kw!Hvww{?}|nL[UܑeGEo!%IHy|٘iػqn2 pYa:! beIm1Ƙ|&It;YO-r]n"]BO_t!(ַwo:<<CD'.tZ@1[ǅxȫ`)BHcK"B)fuL9p8ZgV+460ZcZ+ \-_W5 h-0̄ c9^BJyA
t2}Wغn$!4^O=Ȳ"
P!f]}
>=W_R$mNg<xl6+W^<< 4Z	Ri #it *$	f|Z5N'gޙx4M,˺,iZ!b8CDҺ1MTlv~~qvv뛇͐mb3Ӌ$iZ	fgglmSdZC3g~u]benyW^|5$!̾56nr1oSOD($p]\[k^Q {Ba/666{F
>t:ҬiIYU!TKd۪[c3CH!AqH!"!pgB
u^
!)    IDATuã9pޙ6B߃Ȉ֚eY.i[|Tկ*BZy  qm۠' ʪZM]E2[`XeȼDփeO:r`k	ggW*t*+AB.9좓!jڶۦ-[[7MpV$R$MҼ(z{{[zŗ_^&MԕmkV &Z | b!*HJiD5m\
]jZ[M].geU֍RYb%uHAq!H"A(H$`^7C)\Y꟨vB4+667ֆ(
R:b웪<:zMNܽ{E Dt@TZK"$Bu,f'~|.EŽuEHID
-pƶmkikgLp!p`pj@Lt4dbD!<u7ɯyf6m'?Lf@;!e:oG#|ӴԕX\,>٧?ك@+hIDAW޸fsp!˕E>/.UpWJ)LTN(V%IDsyJDF:.ʪl$WvwRm!"땙RR\Φrm}S9ڦ6xhm9\I4N6ѸL_ +h\!(ezq|/s>JW!*j+V%u͌@`}ᇋٴ1FM̀JD*Y^eyq~_֥R> 8<r! mlmA$/_="Qր77lZ*"$Fke*[c!4~iIտgRr6Y ,D䃳J'<{B묔A*EZ7>X @DR͝l䅻/UZ|Wo]Ng=xӣǦm$.O2ZH4EdG:_3`C`390wu.`<+!4Aru%}3,k m㓓l pk{{op'Z!m6w]fgmTmWotRYg,ӓӧDwܽ}pgk;/+dTa$I)K Z(D.#3{BF:BI!"^=ոN݃;e}h1OkP!UBJc=;PAtI/۾oD (mq	AQw;xe *d].fnIfIY{ C(?|W~/KF[e飣OϿle8(!(ozEQ5woL"Ƥv|r7֏k_|OG_z+_}9T2s`bz&5[ʺW^'''''eqqEr>+eckZeǧyo}k[JJX[WU۶m]foˋe4;/smr)U&6l=s$"{ݟloT?J=t28?OZȒ'QU!<{{7}12}5/|񇍹˪,ǣq I&:"4q[bvkI$4/wF Ck̰ӵQۚˋxgYTմgBJ-PECv!c_B @^T>) KT+UH%p{1V08ҶET,*䘶W<o-c(%gjQpo5$ҕ}7IbVv717Ml"~`":~Bb'#1);>Xଵ ʪ.l~1]Zg%kí_yWk;iP;;}λ<}\̜IfY<MgJ<KuSi&:ϋ$ɤb^ӷ$-Wm۶vYUr\ΗeS-[}dghmm8ȓDi%Q 	TJZ%Z[=ҕ~ @ (憎7tS:Ukc(Rifyof88y|mB Ѱ; $D\+ P  ĸwϗK"i=DBUQXVƅ4`bl뜵yb$ǈ0Md`oy"w_x~ww'w?oN%ZR:}w`&gpoѓ?<9>k Ucwwok^*˶m	Q	:IR$mz2_3N\% H<s-PJD($EG6 c
G'w?
}YJ髽Yi|kvxx&y4DXKwnmnX5.'wm8bbTѢ/#&ʻ
5Q3?\s/UW2wׂ1Q8gsME~牂]	SǈBoA" L㣧ao2r8J)9xAJ   8D)XML4/zu]w7axjݠtgA
4I~GտC?nj>$ѹ&X~q!6{߶:K)Wo}׷6/.'UӬOO~?0*TRfyfM$i);>  MHCBJEBOBZukc!Xޏc >?=m6/
Z*DI'^ueYb,˪,ۺZ, IRTDH흱 `8ʲw6[g9Ҥz5u1xQ DB+%i[pmYG=|h=hz,XoO߱mSLq{$@HB]O>9==}o~GlhI16u];k1F[{{۽~?34xbYJ³d<jm*$"	6p`E8!(2־K'fp/UAayX
L	9 @~He!  BR7RAr  h1BUԶ{;?x뭟ܹ}wb~|t(E,\D]eg`oʽ^7u-	/Ç7??eHN+zAeB*{:AI֭[U]3[ZDI~4>=>??MӄTuSeY+bTiǏMS-{YH岬˦Z.tr͚zr:w!J?BoݞϦMk<Xm!Y^i%:M-T{?}9h	Zѓ۷oi BJ"B
wr1,f!EQTeY/uL#ՍsUR*A!p՚ONZ,I[Ƈ\;j@D[I ZXg#)+A^c5kX僩*nRY^cʒvj?9\^Z3-8R$)<j0V*\6uSgYgy:B _C"/]@dc̌(Xl]-M8| `A"oifXUݴ{d76n^Yn?xѣ'G'uUZgӼ^ll4IR$-xrJ*!lBek\Y.U&B~Z^gY&R+3gAEÄ荝M<.݄ Aܯ#YP6h8BkV R`[Smlr;
yaBFEgDUgg?=9;hR)!@R26DeJk+sZ!*&_cY3":I/|TBFS!!@cW7+I:~;_*)~9!	!^_wǣ֘= AXO?\"ri}W_ /Xd@$6ۢgeYa䈽>D'IU"vl#JS</VBI´;8X84D"KG!!mo4K<Odh!)v\W2 7+{
VE+_Rb9`uΟ}hm97Euv<(_V;P74;=IVReY,T$xlE33Ϧ${^X0~}ėtK$UUof~/&}*M{r|\.HtiH΢CȀ%;w__7MZǏ[?яfe!,&-zi'iLIhh-:X H 	 @DgZ!G,Rx@`γzeY4I_)K!2{k JAYg{Jwbׄx.}VfWU9$g AV IPfmئlwχOsˬ&7JE"2	=cMvͦ6jZ/Wfӵm[gJyu]YJs.OePǘ\	; 1@ Emm=9BJZZuնzfYeY))UAr?zGdeD}>B1罳H{즩6'e6*\ s6lgE)9F*|/iq=`)%IʩK{^νΓtzr6!b;c.υ=+)zjx|dI|% ]9lM b$$<WIu]ghﴖjcX ZSFb1/gfcmۮz8`$8>o5JG~ӟZ\s󳇏=x7oܾs7/QkMcΫrt6*$V;g9z=XPJt<F|eY׶Fk:̳l2Yi]BRLA#PBH4Z)$].1fuv^۶]W7ӝ:{|ȋWq[!8lgoszrZ.vv,;9t(N9'|EgZw>OW<˦IQ~ 1s2 ds.ɔs٬n8BȬPvn6xy!FvEʘR;<<TƣQ:c1Jg,r $>R	)%\ !V̹RJA9*(e$&轋mcƀ]מ֝" =Ro:\OON0t0xy&J\
6`RMUun2r^2B-LIs؉oN&H!]Sc ИP̴uFYUR$#R;E9O|X,vj<?;=|mQTXg}^g`4,v狝t&Ɋ0 @1Fg:ެzuv\-Wu4	1vQ(#,+B,iQRpB~! z0HT2Dw[  Lۯ:h:(AY0s9e,ˤ<iY/)g1RBsna\ɳ'OzB bcYDKnZk*Z̲ )B< xxt^op &b{ݛׯ[`?Gڋm1\;~oܺptm>⫇O8-ԍ7޼{wwq.Hc @Qԇ`*qUe))4eUP6l5&c)(O
$$I@|T5zڍn3B)Ƀ.P1ĸTG'UEgӉRd@I*/F^F.Ӏ&~]\HO_޾#cu   t v#(ߔ@lb^iFb
?˄#Z*ۗs0-:?OY4,K! R( `p/ͦ	[4b\-ϯeY&!8lwK &o%}{Wo@VӎH*ʅ0i͛o޽O>Tƀ3b  Jy.l)C |}]8z`aw?q9ZR"X		1!R3B *}jy1bLdmU$ErMg,%z޶O6 bbow7z\>yjR}ApeQ^VM]"Ds!!D "d\t)T ,!	`,,zTJiQI+ɈG_|yq2,B,uYkzuHry90Fimo(hpn<{g`2_v{n^,vr(U%r)!лn#_B͏lz-JRp+纋Cc`8{}h7ז>!r^-ӇBQ"ϔkF[m"ܤmd#B1)!D$0bSWl8vv|~6RB:cң[ogɓ'y^>zdggWfsŋ__qogoj]&*5MG'?><:OwC'?d2wo6օbp>B	ctNPF﹐I^Hwm2+g@)e=;;QJ:5E^&tum1
n;Wyu(!yCȋsn}~rr|R7q{'R	|qI53p͛ѝJeRJlW|#LNY}˟WkpPdY6"Ҟs1ip/x1h^R.
z^W+y"X$B(צmB	!.9ض59 ye)UFZS+)EQP=rJNzхcrt83i}|rR-b!$BƵ'jӵ- @Uet8DhYov]Wmu]G0E\HAds&ZNw^="	$$ZiD@L!{D0@)L۬W\*drWo~֝nB0oq6xw|O>^<Hصߺ;v\N&R3)!#CoMWzjg'/_+i @Yy),SJeRfRpJRB*y"dFs,1C0֎]&TrvFq BGBID`e&. V!`0|<e)mt;Bd
)eCRFtrɳ/^ԛMQ ʤ9kwR*!J</> }L	16ƘA`sJN    IDATel 秧O<k,޼wWpv|x{xtǟϔ 
(cg#MiNmk>ԺzROj,@XRcۦlڦYB,JIFyb|%)v軀T$6By(uW0q7R~
6p!MkeW&Ic])l~{wҷ/׊/QJqP p"=?{K/X$;_ _IWu1[,/W~d{PDB.޿  J^0FBX 4_n POUՆn͉Wf*Tg P)g1B4|qz" ѐX\%$ͽ1DO(
n" &.4͟]= BNo֭7>{_}vi;JH& h:߿wz۷wMռxGƘO?_oZ7R.=}h7k2T,QBB( hs8th}L$ hm_fL4 r>u [Q
"$$m윳ΧC3d<O'oM\UMTurȢRkBGLxo`쥜 ǈ$btnC~^_εMU4i]uӴ޷)ʂQF(%CYO!1 M_d֕& =2("~z<=죟y1{Wߺu+W'cJi:owEoC@=>Ɣn=R%}hg-cs^  B`0|ߛ/vNc!9"K I	iHKlҗ)% 4,N""D N ctcBl)H@Ov%2:Vs%eQCUgsFdtln*S51E#	k</ѳO??_eI	q^F!OͿϞ<_7YM+^󭷆Qtm9SR`/=knww l^rK"OE`4@٬)clwoOIg}Ki[9FPԴjq'B(c$QzƵdcBcp #>D㼵:/L,JB6kmpFAYdIeJJFiY_<{,8K&(;S)%D 1cƺHbx"/}VH#V[0Hc¼hfYm+r0Nb8\(gM#B2!D|!O&|8D`~ecyv]ct(5.cuyED ʂmGy#P .t[7ιd	ME'L]76yamut]	\.:12ƼscQu]km"s(ۘozEDD	@.b:	 yԇpd bg jiuaĲvw7޸w7_.RθBz~G_|>?[mȠ,?0$f"b,X$) $8VUZWrnY8ŧ.B)Yye)u
@! 1FOolҮx1B]zl JJ=  ̦ݝkWXVI[U\A^MRvrz޴Ƶ+D@uhY1(PJ* dT
Bh.bZWՋ'NϛC@%eT5&$),r%%`PJ%!c'^u#%)!8|:FϞ<99> L|V۲o߸Gֶ5YӟowiZ7޺!ȸ(l<я_r2%ƺ.[n~;#9ݵ@Y&E&i)#tSfctʤR\d2K+FD n*13D9w~~n޾v|kC }6%PF[#y4OOݿe:Jy:ʳ8q[ё]_+^^cm-i`eAB BOLե*ؑZZ=?|D Dey%[S> >U{//d}Ř·j^-	eH(WjӵEQRٳ3XgʸhGGqgMcp)%!9sObʘrB[kE[N)\cRjc~'?鷾nHqd:}wNNn>x((lg`|g9|S5r}GO?Ǎ!%9k1cDYι5K!8,K&bDm}T _x>(AY%GU;8/Gz?8T'"2J˲RGm^ӣ/=^+<@s9gBػbH\T "%ȶ<xgWZ)#&2_|(PBTY1YFI>Dt!Z5P1z'Qzҵ:27zRfĤ+1mۮãGFtggg2d2/Qpwy$7uvЂs{m%kS"ʮ߸'\@Wz;^2X?Rl]J" `n"= SUKS>Ϊ`d}e<8gQ!ΥjCP2ˋsuG(M(SN"Hy x4Ϧ=FưY/wǓIrϻNcy>x͛w};B/=	1Ǔd0b $FH8'o6iNի޹Nwe\2OiѓRg>TumqJnܺM)â,Tw	O._;\fYL#9q-WkD\h輫663]1ݹvOmc3f5ZVϦ#@d6ggg2m]y—1JT*RΏO|mEA)K	3VCv6U	Mikq1ٮxckgVWUuMa8"e1B5kt6/p8%'21.BHeEOgp(>PzSCsTcuFwsi;|!pAf:J!UFo6uMS'4)NReCj6ueY3<B$$ !\l0zZn2O{o9ǴD bW}$La7mSUrUE xX,;|1[,f|>O'rX=}h^u㭡;xs2p4M|!9FBAd#vj6MSWUY-몪몪FVu]ׄeY)bsF9*YJ%Rc@-\p l}TA!i)WLdH]dytYM BuSǣ[7ob3Lhb m<9EY惡!QJJoFJR
(!BVmwm4grٶM fY9kݥ 4s!8DJ^hۣn:B0A,gt2nzZM$dk޽1J0x%/~y4shiٙy}oP!1ZՃ}W_=1\ Bʢx|޵W8g6)Y(Fӳݽݲ(#47Mݴ>D!UJ*)$%5o bJRB+,ZwMoݾsڵh|aM
bD].+Gy\*ݻw훓,"O6_-w^T?k{t ew^*41^~˗(=4_nqG%*g i6:I]Wmڶ.$RFIB.ŹH$
Ƙ16bG0gk#l:eѴ-缮Ck4 p)e}4M $R .AL1PʄMSwضk?,/EQ,ȭmWUf41STVp4GqVitmMajG/~r\(ŅD<c1eC9u0ƅ B=c(K9\H&Rf1"SRݴ'`{t|RcmUW%-]	@Ly2)ftk;=25PUlWR[Dp[*,"DdtK	@اc
tj(eRBfk&8B4# $"b)2F3,^OPƀ'V'hge(|oX,ft6LBRRKD!I}-)\  S(QN9=$@ɔ,Z##%DЗ&`i`$<~o#\MZAH*)HUe+gqBY)MgX@!ӳ,ˋ\	(J!8y+Bf]Tӝ}W?d>;kq1n㣣?ѣG]޾u֭e{><|_jo۷߸_:}HԃiVs<b]Z.w 2+L65cq|2r.l69kB$XhD	&))22(JG[U%d<C59Ay.Dl^B7iP{mL1r% g뺮6 GQ
0RGj2ƒa]U6	ZVJ,HBiѰR1ƓaD Bcy3FuSˬH3h@#!FZck"96`*c1&y%JAO'r8#RQݴmӶh)>eje·1r!T	}D.<ϳdf].ϝ]ZLEzBUMKjfYo֔2X$E^dY1ea6ME2va{xQv#&5!. &gD>zk!<b@FWF|ok7n;:'M]WuCۓ/NOW1:w^qՃlM!Z6u\fZz1XFW LJ*RIQEYR>R2NRY	%ۃDw.l@ ̜':zM0$|c᧟}9uzHňAٶM4ƚd¸Re90RFHP*BqJF	w!vRFsniZg-ϔ!NFt1RLe"zc>kmw0J9Bp!t:NR'Oo6^HaiDoݿΝjS1JG?}*mp[]ZՕ!YXk=?_k1J	ex|{{jRPjSd6ӆ"c7ʆ8ϕ̤TRr)c j-dwB04D[\;mrxݼ(낔\DR3B0b4JFbNH$wCL!'s~_k7څ/!6.?\T22FH?E#$n۴ 1^}[>_	EЄ}	a$Mek 5*ڔYʸ$0ƹszQ,y΄ ykʕ+W6x૯<Z)vXGEާTBY󃯾O?_޾uS*4(r#cvQk۴Iqeh6!G?jSdj:>R&!x	RFc9)e1otL)TBuQ <f&_b:1,d6KBX {8EB0};ԁ؆1"8ǋoGk?_m6UK)U\Hs]茍Q@92F
H( (!#x $4ژ\[^{KyI2@)[Z 8Ѧg-']B \9cR.8Mom|׵hPt]}2wn޼~7n߾{n `6esBA  =w1PHTRJ!`k;Le.I^?[#>[9a!"r!	(%)D2)l8,ƘZ *(TG'g1b8'Ӊ\-(2uNJo엿4/ZYWO?֫{/?9>'z?}JhB !}p <ư^?y7oq놐Za!H ]m	bd!gHM&|a#"!J(.3c]@O(YN(K,kݶCQBh1Ycfө`Y# xiNeJ27H?Mw!eIMA!2
!!i.$cL
	 dyɄ_QȬ'guK־&xvZq,q^7]UUMS	)!׮x<ϳxMhcXdp!D SR(*r:.& Hg;뀐< zM۶mS{	!ǭ!"!b`ٛG;;;״O?\-Ͻ·"8B[{z~v^Eft]1:Xe,ˮ߻{굁R/e)(ր,I[a@dD*F8mIIٞѓhG!o/~G[UU4mۭ6A*pp{w޿杷)R'}ǟ~ŃGGǳڭ;wN @\tq#zTi;kuF thI9'dZCp'l2Υ%X}7^,!by@p}D !. d1Fڮ;>:_}ŗ/U^
! p<.ϗO>}J*٬wxE){.٬󼐃\d!eJ:::\oa8YuܻJ!t]״m|>(U@LZ# ~Y 8r_zzEuf̜u! λo`W_=??ϖ+@HB	əQ~*Jʅ`tow//eg*xW}iu<ϊr/>'/Xm4MYJ`2F o`iE?":" ė `֘juw8	9\J)xzxKJI\PюR-K n_:ʐ7?&GՏtM*m3߷	H٥Я^z|ESϊy4@hJH0
I	WR&w,s.-.f_j#b1 9 2&$'R
⨪=#ikpxg֫UY֝O?lMg7BDH.4HlK(y?q7ߺ{|8RB0a  0	2)<Sj4MϿ    IDAT}mڬ(q\fYY15q8!!0$v
>1N91F(w	eT+!b"Tpb̊1BdIfn_SIF{Kb	x歃??99}_>zz>^Qy^H)δY^X B))A)	H/v}1͐qޯ# wmLj]p8B1JʴXG9 JEI.8#!Ҧթ0N*/(!~ڜâ(wܸq͛l:q	@69s&AJ95KSNQ^0b~c$J6/EDnHhDB|OȥFW^˷!a#*r2(IٴDjrW""Pd(D2J:/9,Mag-O)>cjr^q=_..f=_٧<}ڕGxp񃓓MtmӶi{lZ-GП1$3CB?}Ӧ7'G/wEI^7(뺶9 Cĺ>B"G3Y^x} rT|=τEYMvz:[|ߓYf}iOH(q#xcĈBlz??_n\0ʊ\a)ʹ"ΦrʜQ04ś8^HCbbPx[Szϝ#gmOBl2wrF\֦Ym^-;ݵuCBtP PJ	%9c6FM m}Dh6MU]K0xy9Bbu
3jyuQJIʘ鮭&T%c|Zp@
C
gh<Zjb}|L)!8R</mRT
r %.Ƿ$BjhiۮnҢȯ\9ܿzc3/ˢȋ,UN<~󣓳ZqFwv7ݙg1cgS%.F着Ml'Z7n]:l1rJ2%p<)"us(O6#pRSIOkڻT|h;1:bBH"x'))Qi[o(7jc?}~rvnL4N&g^|#m}v{{{ɔ
"Oˊb:[(AΨw9$	β_iQ(/cJ|ĪWMMsNڅB*D̋"R˒11:$tċ0!\(5F٠(̦uy"8ݺsBwjg_|gϟ2B32εu{|bp!1ƢI9:ktwjrcy&Qk?y;zDͦkEۦ{{b;8] 1Dd41t}oM>#2q3>4/J.2#!
%$ͥ?sD 䰭9vQ%>&MEyMo>΋I"RPkoNYp! Ǔ5*i}"a;֘'UЧ9ѩb	!9:J)hH7{u۶EY,ںNbRy^e^5ӧŋO=9:NEQ2}G'>o1mjS<}]
1cB*B(|KLVЩte3"co/$qK)FpθBr!)eAp6p~zdGr8֮AYR|4%t;L qFq,mcp!"L;oܸwgO={vrbZ6mKJH2-boo42ao@i%,i<HMD@{Us_'i<JJ2{Wyn !D(yYfE)0J3i+r 3 qmtM}~~\o<~ɇ[tT Ĉmbk$V#:.x]2Ds遽hw۰ "TH2U)0,ڮ'c)8!RY{Gy%,m[J@HA('`0l.@)1X,svv3 U]\-ݻ߼=LPQh׿^-w<C`Pe	ggg chgbeoϞH.weeT{c [KtD:!FBi^z 0ΕR ZoyEQֺwPv= g.kD}B>@t֚PYN73B(-(#a<y'Qʜ֔@gE1HimzbDƄtyX	)9%R"᦮09s`zs~vc0rJTpn+s\1FjZca,d:L"޹} c:Ji*;Nw]Q
^d4N&(<;kWˈZ%p||٬ceYEA9y6͜Fkm1MUcˢ("XSY`CSmE1FioI#\NYјbvrIْk>_y/gppf %Sp݃GVU2+22?A)#K)gS@B 9ߪ	zhoc9k7Z;s't26w7w)tvz|txZ.uvQ6odyV՝+iEo)(Z(um6lY/b>_̺fUg S.D$IRYQy^dY&PSJ9|mG b.95!`p ɰj}=:qVSumggdəV:el4</"}6;:GpooZ5m%skmɴwFuZ%(nfES׉2I4e{om6i|@d	Z),cYfY*[kss{1	1: Jipkk fãcFh(%hƓ)){{_}E;En1RB<_>ǿf_\[o}#1eNN}y{G7n|w8F72RH!%Rr[y\wKC|=C=R(	[[Ɇ҇@  4I"2OX ;ߑI㹊y60??މ}*3_N/@/B ^j9u{\]i+!^._0	b P\ݽf0JK+f̿vR)F)A4#<ݩm:Y",JMB즅>\uu]1:E< 2p8Y)mcEQ؀oͭ$(@nNN),gg'''GǋٱQ*FpΜEc13J"/Y!g=z1hթ +@(m{=ƥ{ν2ɖJ]61B`G'R<l}WL쑞Arq>;Z:!+W{-WO>+uwtcyL)%	H|Rj-OwңE>Dmåu;HW}4s75>nM!(㝏X&$ǃ0KS.%%`(c~93E(F9$ Κv9٣~RJ9߿nzsoo<IJ(	@{y @yL;kJhuE"%\״߄EkS#	 4tx$̈to c<Ilr]H'4M^TY\@d#.T0NTQ\k5Fkcu$Ϊvk[ѣ_+{|7H	BQeǩo~'d)hgt\̝Aյ/xk!%4Iayy◟~?yaaQrnm}W0ZhVtshOBD	d0e!xB(c\J m6:I$I<2\j| B%Eiͷ=gS;lYޫloZ+B	e')%;T4˖YFʹjkD2>kFh9JsQi׸	v8|YQ1ƻ=9	y*gZ+eQm1]yre}H)J,TUHoAdmpZkT,J2ƍTH 	g<BEy:+mkL) /Ҵ뺶x\V,+
Pd2YkvXZ!e9F,/0`lZw- ʲIAD@BiUUغ^-ј1Kq"bt[40DqK6F)Rhwo[o~kr0hb݃gg'Geg;7nuڍ|q +(SfUw|v:f|>he$dBC!@h^pPUѨ,K$\͸G]_D, ldKPJCYscy}{eEDDu>xO.WY&Vqƅ"O`qwv@1ZJ/x>?ٳgFi c<ϧ1hbq>pB.a>=|wn4nfHB0,fgB+1ƨ>"KkeLȁ@	eK!\j0NdťN%IA
~7 Fwx~}ȝΝg3@RJ<xˣ<M%g;[})l%Y?>9싻1aXY1Y-5y^$I*G-#  3CptBUc'Nmnu1F9%,h\I" \Bo]"~c6E.[Sbs?>1Ŷ+`QKx2<!k@Z|=,RڑLS P&no;w|z
! B9B$I3ZII 4+;kL[=	ePb!B(ktp9WTUYVҌZ ,rs{'-*@pC]ˊ2ͲϞ `F(ݸZ.Jum׉Hl2_3*uiTκ|64){Kú  @)a"r1@I4a<hPR&PB ï}֖2Vi&3rh<%@H+K Y ".ACKFTacz7<կ~ãッ{_=|}+W!v~ւ;.8 2[@}5b.6F`:g5://iUU}Bh ѻzG#q = Q776N>vtx'?IQޕkdooswJkb"N{i8e\J$XM8%BDg!d_"bd=＂samqN/`~ ^M@)$ r9 x,>:>:99֪ޖRB1,8XytTI>%³c/=.˪eQڶ!˲,1!W?[[Q>'|;g/^?DxTH66u*IpT׫gO|5uM(BUwGYGC)eGl#wBc72  Rɤ)NOZQ@([K),޹u`@o[>c-gO8g! p=%cQvatdU !2uۮ
F=u݄	Suj1u<mvݩR|~pt|r꜕I `uB	yQ4(Ő{4$IRΞjCTQEQz릅"l,֊tJ-3Χ	"1.PsR@L3fjk2F[[[;!	^i팉3B-+c4 )"N77$iYiy6|puӭjaf"ͲOsW$Me4&8wdwxӟt\Ve%su_	F%g6JNgm4nݾu7n=<\vU?/~u/)2?70I`'H
QFMRDN|UebZ-V|޶]1F[ou!)p2G4x,'!:uSp܉SEufס#y o:q?y/!xdlvmlLuOjUDDO֘/6YUUup8[2um ,i$k׿W_}\ջ;W]H
gq(\.gR;!D]7 T
9gY",=$M,DpN919Ɗ<N(pvvK"އ@ׯydd<g !D
-|~*J|wso'ɠ,Nq.__nnLp1y$iyf//~,K{?Q   YsRVumS;k\D;Az :w&GcSVq'wtޥ˚4Mx8MDCdq.q^8/dg?ɩ^Xc/ z	u7e`?K*x((!8gW˹ 2UUUU=	 DB21
CܧIH	Rk@!xs9,C@;'9M0/(@cqQ hE8kWZj4M$MS,C H,jsqv-F)q!)Y9:Vz  DR6:K1y.qEUE,,MP)KmT@J. U3օ. @)q# !t8YwG/_>gӃgON6vvw&	sN(AtH58oxk~!ژFkz:ݵV+ѓ=\4?@B^!@a88%GJ	F;Y^Q4]2!V;;=yd<ۿ5B 38P;r 8eTmLQ:BF/&x~/{KZH|0zH	Ms;焔·o>|Xho]F)s'iFCB@9%Z[7-	Fic((Mi/GᕫW˲>c[o	htNt9?G4s<`=2DΙ5օ՗"֡m)냃׮߸vjl={îSgz ]{jC:    IDATpB(;C>q!d88v*&hp<kںض8yRJIe9SBNUX!# !xgϟ;kD$'RSB4K̜,+c;uh0Y],
nu]Ycs2IqDqxg1Һ<6^%x<VO_Ѷ9Md0Xs8kojLrN *8@ShmBy5L(`[/1j:q׶uRƵuh)`E5XmgB1x$h46Ɯj`YReVuMCY8Qe9cS4)'B&No\ſ{I녯tDQK:Ԫi)yQܸ~s5-h2a1?;:xvx|X4umU%lwgM6,t5ޱ3ZΨQ͢rj>:ESնֹs?La,yVDWw)RFa!1=wװsj.xg"Z@0v{m
 G]@)-ylv& Lp!X. `25M;_,ۦ:Ͽ߯rP{cLGtbek"t4$-"RΪ!D[$Mڶ}Vdc:ؘ,k2i&D$. R.Ap>Y|B76Jx+),瀯0 R`8Wl6uoݼq5MO>{KTtNG7oDJm  `uo_f>3FNmlLo߾;as!PJe_޽{ӳT{oXhb]j睔䂋
Fib{cVZk{FJ ''?ɳf5(&i B{NW=Z7|Fy/9{}|b\j8YIx;ǹ3^6_z95}}!mX}`gY6XT! Ff9"Q>&ƀ@@d,j0ƀ'ιQ1Nw yնpX* P,4Iص!4땋q!Bgg{YQ	#a;c3ӌH((ad8k"IgJCݰùWzѻ#JeH2a\x={Z,Wj2O24`w$k`EJ@<8ΗESi9]n9/<z㓓z:8xTWy^F,{Y>
5P@Xi9VFwR]5F+KoG^~R"$"*[BLQ!@@?7@9p*` { {cղmm  8RbrxIghdRix5 6	x
wqJ9c3Eϧz'c";ǓK..?X@YD*fyYVPJzUmnJiueE;纶%DXc>b_cSZ&E=^/}y3v֭)ʊ1?eEH4tݬ();1 Z-f\X._ gmg?<MMӸYku׶*ƣ->72XZTgVM\ <cꪪٝL7  <k)<<	4ML5Z릭sQI"O`X*˗(p0!e</luh:;;ӝY h4$ј@(I"@Ʌ8 :Ax&YUg\'g iYUtJ֪n1#8(1ؕBȨREwRcuSnl mvM<wRȼ(	U]"9Y*sNJeYaw5Z1J`CtZs2Bu BdH&k:c}:1޺9w0$(dggwoɸmr\.^tM;?=9=9VXf{W\c4J!A xcơ5]uMԋj1of9[u۶uӮĺ" rʸix2+,-</
%%y	R*ؔ;FLLC(&Aĸ@罵/gꬵr!1(cl٨ies΅@تm K<ۦj=~Rt24I	hU	48E 0($጑$KL$,mg;=;Kt4Ǔ4/
ƽ3|vuu)eBI"1X1&d¥]G	ɳ*DF>꽵ƊZ],RH/ZH ,OhT uć L'k׮mGO~''5	q?xo{kk>9i"R<?l!$,\vmqv2M^?}~{ңwΝR}82*ce.:U`Hi%q)9:<zyxZ.'GuۼkW*IH"ZCz){=EƤ6UdwA_Nְ8^OZ9}v<[?iJ ~8,\DqQsΫBH9BH'"@xB	eƍgiY)@$\HD$yq).DT#GB!дx2ҔQT;ll_ڊZ!x}x39!x2<}f%#R.zJ-`Bd3.mCV)5u$i'iF 1}.@aE@uEك2~6c9G8NvZNQv	x&3FrCĈGƲFyRh2l>O|gY_ƭ[7w	6MZ ŀ"m4Dm:ms*ou^k[յƅw6j{C{YR)dHaR
{wS j-buF " %$@@ 3bsRJ)5Zś!$sE$M[|[owu4
;eE5e}/e|Zk4B(cĪGy iF FRMhDdy^a%dck+ΫWnmn8><ּ]˕A5]`pRdc:\LSW_}1nN75,?wo~駟lnmޞ94lvf}[[Z)k}@\X,%,'OF/>֌Gîm%ů}tMC llLy?ۿgh<6Zy	\
5YM" :߯1҆%.ːB	Y5t>8cQj@;	h4eguF*dQbӱ(Zm:.$1&xqe9nnmoWee%2i&8xI  \u( 	h]G<+
[-d<s@dN;+g)[4M[׵<L9Tիy%YQRTAwE)6]srz:^E8({0M4M4JZl׵ӓrˊ%Y,8i荮W+	MlPdVg	.Xm@հ,2-Cg	7ZI*	Qk'HB`$mJ(z띦m!I166rvst{{gook7Gi_@~rw?zVއw>|;{W Xk{F0 "!QN7by:obQi;zU7]Yk! 0.jPY5EY$a\sy-9Pڦb>_,櫺iڶmM(|8	!d{c23؛DHiUm+ˊQ Q$0o@ij!L3b#j{l>_h4\?|t<\vu{s3͊1SʽU;;{u}q$=%aU׫UB,79:>·bcsc41Ν[=LYm&RX ID AYU*>d6W<{`WC2ƤEƓ4۶9880FkI[oM76eJBȧO旟""c4×Q3??O^&$9<:EYTd/^8~?6>hc1Cݪ|}a2Je(1@/ԕsh|)2Jm-+ A&Rkj&jpF/^xEu~p/e4&ԝGW0kCUF7K;Ы\pנdr^.^KP zgB9'hFbXkѿiB_/#%J/әaI>gYQVEs)(	~cQ cp H^5,/b|AX|8;=>W\/@ʈ@b4&:]M-d3IDsq|uE O5G	Όg?}EChnPmD?zNCBe:^GTu\#uiH,(-Fm6E;nll`6ݽ_-,˲(8gg1nZwv] IުcZZm6sZ[,J{k=Cܸ/\s-%	$XggUdvr5"4ZcwvC1igYvE.\<zlm_rͭ,c[8!0ǐQFwy\>KPE虄^	#Q!(%W]>Ox8'y!677,T'\Vi~5P.7naU/_$R[z_%78]S]&8;;;UJ))A5Z,lgwVu fytx͝<U2ZqΫA5lry9:	R ,Q"O~R)IE5b{Bu
SS`T^\L`LP TZk1<xO[C"!x1$1ZSJc3R$yYF41
I2O<A$Y@$(Vw`Ftmh}΅@ օȓ,*T=9g6VkeUbO<.y0ƴ 3>*3 t0ũJpsF<Ol<V|4+sk,˲,s7jۖSEmJ6{jZeH(0J([4u6ż^)!yqJl | ZerOQjx{:I)^)erx|oLB@""$匠77wH"x89}?ZF	Ml[{o\1<OҴÓG=ų'iudɟx<LJYeQF;wmgY\ͲۭT4MWM]u]1ZcxR$RLr0Fj0̲\&	"bڝuyJ	%8b1/r\5M5:c^fiQi& R}??ku.ruz6;8:	@j-e"8CVk'5sH:e*âuue'YIR 7uzzx8B$gL+W 5F3ƅY[>w9ݷut:G0X:6mQ]笎=DH@[y*9ӵE,)g4VtFH4AUzgٙayu%P)!d2=zN2Kt2ۛreY1o'<9ʼԍ[7?|ҍ?я8XMgkLt@qJӪM2\pF)!48p5VӶ]S/۶ZcNRʊ"m|bٶ$	1R&I׵jutxO?O۷nGAYTy&A=~Cs/^@^Fh迢uٻpoK9b&.wt_^b?	|_^?T/0J  c0J0s3&:Ϝ3J)`0·Uu:I)eI'IB YHo#aImH)n8룓Ӧd`z. @|>-{rOFityF@Fq.Zw;_ \1F[s(R)% ;B}<ց@\O?O67nXeJ$޳!^$QgxzzrrrJ"vifɤHʄYe5Ǔb{Rkr\Q2mz17Xg5/DZNέABy9bFFߧȅIsG8qmu
d"8:1Z|\WU)Ek~Xu,hp.hcU[7rf6>}`4't:*|EկK}&sSG)%=֚H y3& u%+W=k͍Fx4g]"+4ϋjPy)ch()eEY2)`*mӳr``;;;}	|k{{?MS:6&/gG'i$Ib
$R9P~||4vj<U(PJ9u!4Q)roOg?=:>.`\tcsgo{gQN(ጜygHRyUx*GY^Fx#)e,xoFղkkӵΚRRU1(>r=!
 @8W3Hl\}7⌧ڞ82Ry"uΡw}\^vmÝ`Dʲg2B	,zHhm,cyy^d/iB@F)`V]KBquD
mTR.	i!ҬHX|. u$ *Jz- pDVBB TӶ2sʅ1SZ)ÄL;WH\|}ǻNYZ!ʲBtRsLp| Qg$dT[[A9<ϮChPeTK)ҤȒ"ϲ<HtsF[iLFy=~ɧhGr0h4Gx٬VgQV0wL[[;㍭4Kky	!=v5vkT[M]/WrY7+ڶmu!ɠȊ4ˋ<)$C3JwmӴMS7j5_,rZusQ2Z#@)Smj18#Zo~v)ǜvJm7_\&"+L<"'1 Pʼ:BhNXGR!Y M6miySH    IDATD0y&AeZ7Mo1O<[[m=.rITUYU랿xqZѼ!Md2>޲.\۶mLrAN[ Dr0˲R@FbgJh< ް`gQβ,#rZ.1j5n:$M77t׿ӧB }6`PTAӴ=ǟx 7·w޾}ր8(U=x?C )ۣSk?"fY*"/ ֚MuKcZk(ֵmSΘmQZ{౻WZ!ZRZ췿-~f{iɼ| ܆\
ڿҿq	MwH}9_Rś䒱{D{[bxA!~}Z;~u+GsO	笲^ Uu|~sD{ " Fz]	S3 ya\@gB{C5R*˲׮ٟ_۽(a1 ͈  ޹5VS)m,c Ϲ59#);46=47wfRhIO)Ed=pqaxpNOvv,y-tsUl&b>&^>(=
1ڻ_|~={!x,3i ,$
"zo5F|ww+ju˗GgE[/3sN@\5'G|p2<ϝ vO9묉Yxeｚ$ɮ3sr*EeR@4Κ3omlVTpH  !FUwTʳ#20b	a!+UOl_I/yD*> ̳pqe p龓^NΫ:  Dfhd>t1%+B)#PT'Gώ=},+ׯ_zu>EEܴ,)0817*cG;va2qi։SR|IR	q0ĽAe9vںONOOrdYq9Ef\}cZ F#@d?;:9!PB]Yvrrw߻zZ$MSz-TI~u"WRw	dݣu]W훷)1ˋa2]k/F*U^|QI|prz2~U<L,MsC BHT *sF&1\&i>yRBʨujk=PH9SRŗ[(B 8$@qJѨo[(Da<μwTf\} ںmHp1T@ b9,{{JD)t: Vk-UC
 !R4H\\&YΣO9EiUժz2QIH{p!)
 cI<U{k6xMvR)k#:&ɭ;wɸ<z{|2iڦZ/FD)$-K<\)3&Q`Ӳ8<8)R%:88Dm/T5Z
^r\E@ {|)5޻\ B%9u_~r?/W_yk_+\G1''?G/Bd|{7nݺr*6<<cs4v\jYϻjژm]Ads!TFN9Cjpqy} sj<9::999=;V˪qdYڶ:*Uh4Ky1lNtV8c\2!Aȸ$:O\rN{8A.)1y<pȤ(j8_tmWY%)"22"ny|s9 cEQ]#\9*,GǏ=}x6 A;iX k#iNkHJ145]oi',&Ik !:E]x4m!Ic@4m=Iqn6_v-ϋ(mn'ǈF/&Ȓ4{?'G'R4M<oxNBp%*xǿ>4Iy߸~EkczY~49%ef!ru9W5M1ZfY"XDȌ:ִ!x"JTbN.).x9͑I"?o+o&v* &pܸA\
bC(d8qK13$k~pAn
0le`у1>pȐ  *BS;9!!\Jd"!z6m}~zt~roץT]^o{78OP!`"s\Ā`]%BX/ΛzQ9ńpMe
Q{GDLȔ1)u
Qi3YWss$JB
~f H~зx1zID@7<e<ĭ<R㜡w{9&h HJym޿ d2m b\$bCuM  {ŗ_~{ѯ?_~~:;&c !DPVu8/:AӴR!^youh`oRwm=TںEʸ\#z* CR1!z L  $i('W~Nώ<ɇ|H5[w^3Jm;|D64">!X-5
!xd7E8LѡiܙM_zeu]''G'Ϟ>RE1Oƣb4E
!q9'λk1}Owㆯlqpxo͑,2Beӧ>lw>=qU%jc)<rx޽}L泩3T"o|/z/FqQyAk~4UӶM3I!>{/~woN`sƮuc\u<_{?kcJ
cETC@@s8"\6A&Tx ^se9%>r&n\\, gY^I)g!usC9?Lps<3<Z]vCBJR@d\ $a+µԎǳ]"؛OuUBpQjdrz{kP&=	ukGpT#:BZ!OQ^sk6MԕEQk9>=5<('YkW<M'}#pw6sHlwg}Z# 2
ypZ^#d^%1+)5u !ORN4rO>>zrtH;;?|A9}DA/"ZUl.gmu7훶hiL
fh<Lgl2)2KSX\t%Eܡ5z\/GGGGzn^[Gjc|.ƜWMumvPh'oY-8JMS7mӛ<ҤT21Β$1v3rZ·@!VE]Cl"Ieހv:,j]M-HjJ>:_@bٺi>'ըO7^ky1E̸8}h^sQo׶].Q2Sm\e,K .m伵Fk|^d@Њ1فQe}߯׫n׋M׍&~uUqguwוuOeY^=>|8MRm_ݸyy8*b?|u7ʳ^dݻ')imB
|]WUY"
R05;ac]olq\5ua(OS)gtEg,M.!Upk\5qd =9>uky>̰8?( _:~go~=  A!/#9_xږ_.<bH1\]=$.WF' Dl}~z,"2̯.( (B&9 tȣ 
QktPb` x:ϧ1q|T\   Gc 2]#fGQH37m[DIrq)#6llp.R>|YQd	_p%\xW1X5EZgYVribDe66@D9!By%glbq~Sd<M:?JƢd\/}s>/_ h+d+V[oݽ}?::z?~|vzRUs.(- a`N9]!kCLTCfs=8G⴩
9ghi1oA<Z1!EwsD{q9O\GXFeVjݛ[/hn߿ig+{WWFE.D(X`ikyldFq҃% Ëva^FAB0᜗e$^۵uݴm1cO5"<U2$ͤRH!$u 0Δ]zwvvvGňsƺkU}|týd65;ϯ]VWkxz|ͦxݶ#Wp#{zK*RkZq im7{DpxJ؂1M""ggMm'(xmLӶ85mUɬ(i(I\zUo۶u$!L<r [bÅPiYeRi8ò$^ʠuo)>A#8>sӷkf8B'E`UMSURe"1[֌xBfo69_v$B&I⌎xq %.&n(8*.Ip$YV#D>hg짦Jgg}zRZz{j$a3<eY۶:@ΚEtRWoݸ^d)l@娘fyz&cs 0| mwF
c(	cLqQd"G>zɓӳjkeiQɴ/0(eB<]-Vu]e>׫i{VMn:v@qr<Ge$JT$iV!!*YE#V]UZ.źZZM11$QmZSFm`Ȅ(
)%l݈1%q	(x 
qDf_2J0pHq1& J8h\fE!` R$I<KU"`Z'IB:I)˒r\ɸY\98fg-!w9mluMX ArLZ"K}x4NZ4h*-w !blu^?2 !gCDDg'?W_yWz"`?bJF+ok7^KG/>GFSy"zZkq.8
]M$*ʴ\P0
H6ZKmML `c{ږ3c犘} Mo7*YC d\ Ș{e&D%RooŻݏG@h?pnJ_r3|c0G@aC pܪ(mA#!e2ĺ# Kbu>z0]DAH68@^<AQx&I45_Ybl	 R`m*'k&@4N(pJEeX\t8Q2Ήy?0[ *n g6"GE˹rmbc`> È?O|^}t2% ƹXSd\|:|H8mSyrPz p ||5?W81# %l6ݽy'GO<y'''zqvVו| @`<XL@\.0c@  Y55(Yt1޺K!WhH'&e|e1J\%FG?@d(U4#1$s]^IY^{
}_j:99V˦i.'Od\FIEզ%{*.~,/o_TDͶn0cgyE1kL۶U]Wu9W]RrieY͈K.PEeIY\3c}λBz={{{{Wx]Y-Gόs$sRy[@eggn"F9kcd;+ZMM @!8klpa*D ĸzh\>}vTW}hq&*y!RjT7|<3;>\ˬ>Z;aHs=J$IQ)XiQ&4MaL8tL| ]>:sKN7m&qd jήsrǇ2:\HƐrT(шb#}ϑs'y1gi"к{ZB 2=p>zc҇4ba|<RE@B'' pvvckL@!OT m.$ q!KGbh7۽۶m}p|:1ƴ1]s!6H9!u{[w3Lvu~jzm=<I'ӝݽ+n\~C)AZ6]mtXe\4EU7օӽ6kIʲ,ϋh4*Ũ,FE1 Pcǲ.WrUFdsk㽗#@s)R3.8WJq$d'sTxq"=@@<093Dd] #YrZB$iI"y"ȼs]$ QH8Grpeg>cR|'/
7] 1r{]c|Q}*}oI a1;qf#ׁn(0|̋"IBZmk%:?Mwwq}׫'?|$2I|[;;;!xkh2{ZsI[/"0k-R>{2MΝ;ok@֚OBpC;tnmTjD62 gōDLc@BAt"8`RtOR	)cن1$j}r||o }~|lkzP DMuc &ZAw[S`ԊxxB+T^P Zu_!gZ0`oM/2!Y@sޅ 1DalJ][[yx00rgo?ϋxrT>pqMc8}c` 1E6!\хޑuBHg3q>Γt붮ZwLH)R%Idq;B!BHsΙ<㜼Ks VB58L%B#2*>_j
n~mɹ/<`#v@(%k],UMӬWkp||ɓw{4(    IDATFtD\%!Fp6&$M޽7Uurrɣ>Wk 
!"/u 1{M4$,9uGQt;ii/ErD,x'ʊh2eqMQp!D"ZZ[DeE9o޾ jу>^ÃoݺuwȘ&&1|@Ƕ$s "	AJn7D4 g!*&	ᅾYW庮֕ZXhgOD C`! 'RAp=(yUӴM{nNdq'O9n\;4ƞpkjsT}٧1%3MSmK!og8EwM.  q \=pqzvtru/s_"CyR&+L4Q<T-r(EnnE=!,PB!c|@YT/Z*"ʋ<D]3<Ӻ'v9Ap 5HAHɹLNw9pDf\DvY 8s>uwvL+|:ݙQf<EZ) z;2v\.aTi2Ƣs$EQy.U@y[kY jٷyYN{@ZY7]Q[U.@TsKw'#zAeŨ|#׃'US󴐑eֹM/q3TYkѓ<x0L^s7޾+W"2y穐BlߴE8yZTuvg6166U KT>*'|>fx$M@l|pεZw]ߵM]Ӭ׫'O-W;o-!cc-"NǤֽ:"R"PpTi{'	AՀAIoyT 1dipfv(8p>_DICL2`DovH
8B骮 u(t2|:9 V ҐQUt6;^pRQ}MiTyM&Cn@j},@`CW$ʋBJZDt#QɄs>ʲ?|{=88xWO?&Ͳx}{'擒!Si/}6LIei6g(ڮD1뜓1'0֯e	 GΈ."ZMUU]]]kujjuufcU/}5򓱍(ݯӓ#e
s{&Rn3	~pm"Hp)# ƀdE #pPz^xC"19χ?m?mC/DΰҺn;ϹBvuۃH(19$B;uڶ̷U
Bxk2t:G͝Sr$pqE) 3A(xὓ0e5N"iY5u}߷BHvR)!V^FJ97:
1PNdCKk|G/zr!X]49mMq%@wJ  ZkB `*kAj6t Y#_Zm+p	E~w~W*r2Lӗ_ziO~?I0i<,;0r}2\D@}JJ`yoѽ꠱pqIbR0x*qAY D}TM'y6ʕJ.ݿuB&B(Q#8C@ĽHp2㻷om\U'''''?yY^v7wvvQZkD&>ll7/"(Ր`ѹ|lU^%2`ER8=sy0.drpurjAXG*I"rJvǧ7_/B%	 ><xw_{7/tz޽ݽ~7,_<~Z޶k׮9P";KN;g{B)y{Fe+ٍnV!:;| 22cUCu+V<yyυMyQZ ;i!w\JeI9k	ƃ;oMS
"F?Y".Qت+9kH2PS׌|>?<
`M!֘w)EQkkBd:N^zxxk]
wBTH)!1N	.@ѺnM$I|
(QL ZM}mc-cE!l2JXgOy,+ʲ|T$͋b>Nml  ,GY7:ij0Xet|m<-ω(J&,Ϲ("zk,+29BL =K*ONNR[_QR^/X J
%l[gzX/VUiko&sQI7Lh2 ddg]߷]۶m[uzy|zvvX-ϛB&:5E4K,ϋbRO6Řc"(\`¹\D \JqƣTą
4  323 iZstt_sޑ ,rƘs|7H0BAs΋4d$M"o85iD.F O\L9[UU^#ʲ4ϋNR)8 nc9g\UQ)4ɲ Υ/[gdDvh2u lwyw{vt}>*~?bߝWu}{W^H'?}(kmnZTIlӅ`黾Ѧm6}UZPZRT1E[.\>sd:_L8_qӇ~w_;|yw6 1Gx;<pNUSEI/ CQn&XCÞRV/4fx}!>{R! g`uk6Űq5m׵RI%.-"?M8eL2F1YB	qV"7CG{
>PEm`+&"pSzu;'̳BD)e$hE3f#Rz!Ѣ(JuODL699nM>XH)|ŻB%t:Q!N"$!uRQY. އ Q#[.B[Áͱ1|FAL4E冼HҼ(W^~gwn>y DD \/>hx1)hRd:BZu.9_$J
^T@Zk˲|zŨz999:~䘳!]DmoO0B"k>&1D6,&08L((&/ղr٧N|g?LQ1lA.
d3@Ir$7 7IIm'-hK-(R1#iR*ִUӴMw]ԋ3asF=A(9_ݽnf\t]ߺ+>zx=l6ۛL&y Ghn:3:gGE1ߙ'y^]%n}wq΋y^D8#C]HZdGS%h}Ȳ,GG<1xCM5	5
%Ise@H(8g)%|!!:縐>P]WN|_ α; kN
PYƑsֺ#8!biv}_kMLodI:ѨOM.#%&BS1  1X4FJ
zuvrRNGh>HCHJ0sڦmC4McZG [~\$ɲ#4}k	QkΐN~Z6m끥iRNfia&ɳ_#oP5m@<K"R",{i,K ),`ѳ_~_~퍃/ܺy|B(x	D]u]U[ZΗ1i!(˲(Fq1EgT)/M{u[ku4MTuU5m|]Mct3%,T2Jgx}׭Vw.Qђ(>0 iȡ8DP1"e Z` 0b`G9 :mz0XpKDD>P ir\=[-ir8C>8mΌ kL0/' z4h!^ڜm4#hDjuoLﭥmIY6*A		 !9cwҢiϨ"wQ*oJ''"٨(4u?c6KշƋw
!V<G?Y+Yïo}8O>ǟܻR ·^y^ۿr;\D!ƚ$ DC軮뺦mb]֫hH"0a~~p>"g[|Y'޽{ݟp!{jkt~|57?3( 1`5iã/_$@r)Ի/\p}	ۺap_\OtQ!Fؿ#1]+9`.Zk{o%t6D\ BԼ(gEQ.(>V¡..uBb[ y B8E 2QR1B21)J.z &׳6]dzy/~aX
90y%"7-!)R	w>Çs!:x/"wܱ%.>"@`qn}}x<~ŻӧGGGƴ;,Nb.DD"y"|1*,K9gضڶJɗ_yw΋n _ey-ktֹ@= EL`$+nSS l~0@>8 `IRd=>y>>k{R0:^3.6o"#
36T,1.%2 0lSeDyFEcZggs߆'Y9UU3.o}qwgz]UD{vMSgGu^9:N,@9;y'=gm$t:]/Y^(~^{Ν1@D~>'lqOMLd2*%GRQ a t!Pr|pE(R	(ximZ5DRs6I3.DkiBRJd_j+"MT%8cfqzZ.CxQ ,<6Ե6u e#@fg;@`\q3	!s:"b]|!LO,ͦ\Rȥu!`Qvw]n4@]ۦm&!:'(#c	 2ȌTJRPJ5 y1m!p\eY"Iߵ9mX%ˢPi	ɴXm\ ɲ,g\D+F)[zt~]7yo|[<yCN)@B@}TjX/Nώ}>`3#~IRy9*x\e9I8""S;3FM]׫^Zm׶n릭:`9I$G	8g|ni;'8K	pq)f8xcBp6/<M F!GO]E֥wXk1Ƅ,nH(CZG8??_#B
mZ4M!#@8CƘw=|vkB%H~]s\.Ѹ03*7Mb;nwR  .TR}h9WEyizl.睍~ƆVRڔcBʬq!t׶ueuEdHg:˹Ϧ\Jivѕ+Io|(˶އ>}r&R)e7xtcY^|'M<ua27n 8Q{3^Wuכ^붮ڮkr׉_H\qɾXoc<MݻwWsD̊g?ѣ?a$d4mY(B'pkBؖ xQB.[߈sϹMDG"eקBmb>m0(ցFo[)T2UODg}:\$  )9<g,\p
1>x>BqzxQ9qw6I$ͼB1Fmu-R$iZw#i8~=㬅!-!eS\|GmSU]y"0FKjuOҬ}
dKrU1 f0ږqt>ǓCO$vNN</!rwA,EV$Vm'UXW5CfqRok <aԏ\.ŉ"27;&y_I-FI@(yό4?RO#ΌH(R$Ak,s3;{ѐT8|쪬̻{η[V6Ibbur֚$;y"l7m) kk"RzDQ9*	bogfއ^i}e:5?}_}_Nã~[o;y{4"wZ<2	r?tYP:2ZKqez^9@ĸg3NvCv!>:LgoߗR~g>".///`29:qb_^͙[wuCv]H
,;'~tݶb<6B_g)Itlmy",R
m@J}^]VƘ{o=~T$ 7M	"g$ZKL6i]7$8x'F|	OLZ߾Ӈ_\^Jѓǣ[ѿ׿/rsxx4J)eiFj]˶m${T%v4B`VJ&F#Bl:TR:SPݦnR)	XJJI!,]g.WW&恞)[k41iJ(BpnSRk7oJ`648Ifb0`@u#$JINRjkrT%Y2O@e,CSdx`m|X4AkUmL6MYMzJLͲ=:>~߾d}]Z]ӕ'gzq1_.eӴz޻,qf4O0/Y+vFkZVjv[u,MvBDTK%Ei="Jdn6ʺȒۨF 3qU.  d_^rRV)4umG?S
<;۵Ui]'     IDATPt<M&ѠH 
kj^Y^<mLsuvZ[WUjJu^8TK.γGt!`>_u]'y~Փ!fsΑBzqy$^dY6Ц몊Ƥ4/9K-IBKY[n۷sa8tm#On?_\ݸq}	~?e铧O`:o֫O7MfiPoVJ^8@r!1lO6Bj~~^s(Pi7_"ڵ-^9%oBׯ߾u+-F󫯾J2ԫ(RI&&Eo;Wd~GO:(>~aה-Y)z!btp}7y ؓ{eZ|"vʲwu?B?`JTkE >ڠS & Bq"e+l/\ۨL%GRHHF<^lz	}BhY|Zr]gM5H$MM]VζJecR-UbLgv95"R*%IJ!$Moe;'GGG׮DdIHI"G?O7uInxbSsoYb'gJIf}RѨg2v30b_2)"oG1s;ٮJnV˶1"YvumhRMfm|Z̙B4]l3#TZpk@/k
xX
ū!#g#@D"N7fo{gZ֫Gb0qkx2Zʈ"bb>,)b! PDO5}-&$ay
A=[='df} ]Yï
63٧ι<?xA&]gus|t{9w~ye;<v3 
)x7 P	65?dCD(bXk.Bux6̲KUӃٺs>?/PgLB@m-Y-ȹ  4B`/f%D%0P~*I]imVknd:WHHM''Ox:%ZzkCץT@t5_F_e"j`:AD"Bj@ Q  ("Yzd:LFQZ+T(]k;
v\/O7eY NLJ&-"fiҴܬ$BAy@hk8K1y+Z뺘((xa]ZdXL,o @Z	\ێꪛ2o	NrKRɋgMgc MUmVWjlikYYWGJ9:8,b2qVi&`Tzbc
u]4u]UU.כfVe4궩ۮ!C-QXV.8ʲZCp.Rgb7h.{F?k),MTJ
my3 у t%yTHg*!#@EjR`$I6Jiry*XVz-guM B[zh2v8sm  $PquvD>}B`RI6F+
 ,ɳDkUخs]e]^)B\kT*ɲ(ڶY//!'@bi@adY>ͯ~ɦ&j?ެ׈8L6'~?e4M;ݻ{ J鉒$iJ= 3;u)K۵mެWuULt' ">om@QlжGy3hH0[=Y@A+k/0><x Ϥ_a>K?CL_ANKߖbbֹE)g]$mnT&_Xw}Q"nP+%G҇ dޑϘM{bEt݇4M"޹*>$mu˳<ƛJ;RDHJ:{0*@91^J%4QJ<H]h,5fуuUˋWWNn>99Z[x-3#2ͻwm٬|^ ՟M2@e-<,T!ƫ|;lJ}D)y8p(R&("A)Zܽ\\=}U޺@CE;&_8*)ȁfo0J)2""&ju9_^nrnp8h4`\1Q`q(p!2y$F-*%pO^-GٷDa ${rMKa2<>}v,d}uffw5J
>xG7қݴ)fp*)~t2T1Z\,..////rHi(gt:=::yrk4y~ppP[u뛺#3!$Q`pHLw"QCeUUqFGJDR  qR&Ii۶Y^HZKdd2JR)`PZB( Evm׍G5D󋦮./xruy6$٠(j&}BJ	2*#29u2x2L`6;'d:H]xفe u켬zN&q謫w(h;^K bQuN)UV|>>$FQ&q*)E쁐bE+w]!}QFi69`Um`8b2"h]h@E&7 YIڬ./.N4^ϫj*\/jٴ]׺`=G`2riyQG`X&-C>Z}۶MUUl6MY6>x۶:B   RRk%yv^yg?.Z<s3ZH Ii*B!1:0G<0m+X$$"*
)C;]lWZ(҇6Qs p<J	Yhl'"020:iauӪn߸sG
!(qxg	XN
 vݦY)Pzn@bPP=3	!^=MEbLeRn{+z+EQs;^^]z5Vi⭷'JL _|/?|a᭻oܿM1gιQbLֹrYVUUﺦ٬Wzumǉ^a!3%׭}1I}P&Y<i6b)z
n{/O`P_܉{͵wb&kbh9gRh  B xeY6M &Wݵ6ְ<11$(%
:. Rc/7Z$0S5DQPTvM\E\b0=p*-mO/a+#[xݷ	xqyQ/Jc6\E:*=Bo1&1MCAGN4ӧG<yܻw^Ռ3"21!giwGxttt͓<˲T3~g{D$3 2`F,Nqa7D~ n;Pd"].MmbF'T{BD! 	(Z{ǗZEMIBD;)d9eQzN@h[/I ^D-3E'Ƙ7Sm6ӳKg;fׯܽso7nysZ5rO7XrMD\g#Qi7fRZDKmg[Mض`oh	Z4߸~ͻo>͗?oL6?C@>>v6K!3'`^@+DC6ׯ^q#Yg#]<#"xq~g~嗛َ](i$I6Jggg?u߻qx4Z7-y-q
)+}@0${ @ P,CfJ! Jj IbFb\/cJLF%&x'L|1JL	TR'8,`:6y_}՗_W4Ul<b)h|@,@)NtA!$dEIkp<̦Ӄ׮_~ulזUv uUYmZgpD.,ڶ]:)Rm[4fU׵l@0C\bLs9AcB2w^
'S{ )&2)+(UyisjL&\uUV]gJkxDuMY-WͺuLDumZ<$7Ǔ`0L,ISD[] JDmj/bUV1w]zIY:kE4;J@I`}˪1X{\G1l[!ib Zk$&I(U0@D!b@0"G#PKhE#m#d6yۭW41T	hJ%Q(MA> Re83 9I庬'Oܺu]' 
={v
"2
nK4mY5mg<7I"$(&="*Tb1iҤ3 q߿Y5(gڝWQWϿLPn[O<i+_DŻ޸}k]n
 ug7U]7mQBJb4..b7zjJ*)|] =O(PU}i!fy>L JR!1=_ ۏ?~$pgư{!֯9_Aw<v[$XzMg뺲R45Z>*l:(gyRWϩlG!XGr5@Gi,JFBJ*/owd2SC5bRM36ιiw5>?Z! *C$H2zHnkBj3z1ovhD4M^k%_}~?ڿ*)o8~F} Ę|_Z7'$"Jzf&Sm*w.f+L/͢8koݖٟ:\>xg8z׀&pPǣj0'ڦZ8NDWP !$b7K~[X&&($"!2zO!xk~rZ.Ͽ׿''7'Y1L&I Q6BZ( @Gan XVRV=(9-BD"F	1FI1({w]bJu#:6-#J)$QlPܟ%R3pxZ ^~t|rp0PRJp;1~~BMp8(ƣq hڶ룣"2)ǟ'&ݼq /MJ:
ںnh8xz(m !Rxr~~u^1JI%0L|Mכb0X7dwџ|-|~ID:+Fx8:J"2'
HI) +m8zd	E09JJ)$J0J~B
.pӌBcY=}z%2!Ҽ&x,΅ʺE bhi(jSW%3|\i	eUe(Q,Ti} g;4tQ	hLӢ!y11,<u.8jD&iRƘ@G(͛jL	}6zuֺǓt6y^diYdt@Mgئ^][or^Ur6]vlyBҼRZsYڶnsZ	]"F``(?ᑟuµ1ڤ$Ϡ.qD*nA!׶sfIeaKޓHRj)V{'8lh8,MQ*&37{Dz 6vxMU~٧ܑ̘G^($Y*	A
oFKRJEq"sQ6PJkRஎn$rcglۼ|{O,Ybֶ JX}EfBQfjRiR>ux<go؈x2_G^yjRDDFPZ,U4m]-  DEg,D)}P &T׵ ńPBs7޸ (2RBHqo_MIǷJ@&}ϳ=.t	|ej:p'\vm9PhIbL;&;kQ
   (R @ !$C0I:O$Rm?~7M]!~w!ʋcq0$jJ"[Ֆ"0G0?}zrɭm<"{B!@RHT  -F{D$f(L޸y:_=}`w[dWWMjEDO48 9eJuBz{q	or\_} /85 DDb%!"zlEW],3Y///./ξ7Im,F׮F#t|yvVn7cf.xT1q-BJpk7bidRu]Wm]˒t:%rquy1Fp8,,Ml5<v@\$;o)ȍB֝׉yn>cq$3(%{]ODQgF˸N[-dZU1Tr<iBz٧}Gg;HJxTtBŠ(s!avx\o6yYֵy6޹ԘGGj-B!C`!u]Y1l:^"5dYf:?KD=샫Nn߹~tMkQʮm./>o9&u61F(m>8u^1	!VmY^$A&&j;(Qjmh,ILN&Ѡl6ĐI|4XDAV(W4MMGCeLA"cTR0D)1@|ԉ$8g\$ Z}vQ
RkQ|$JlQ!~D|2ib	i7D RFS\+ꦹZ,NB?it0'I2Fp8ʋB)-R"@ڦfSUUYnEY7MӴ]׶m6~c(D؉RJ1sڎZkC!*ߙcv@tQI%Ji RJL9ʡG*`$ú9K,MI$BP
#P|1D2QJj6J[8R[BmW^霋{Z|X^]^^IZ    IDAT;<JCd!YJ,"cۦ6MR	KqyC\j'<ϲ<G)r4u?
3QgݵǇBlQP!hmL|_~eUѠn!JasZi):7Nݿ7,nurUv	)ԞڔrZ5mq9h~.p8 QDR.Q8κ4n<uZ)d%=W9υ[_l'DwHjwW;GR?k^*>#yQpЫ >{WG%Z
m!g"jZ%Coۄ3rC8!|iaߺɋ`vh@O>ۿ/OA>W`0#fydYGs@DfBj9/ɝ7y6E"*5V16B`_gKnB(OtU%Yim"hc>]瞸ȳ[oK!iԒw瞩_```tUWgO,fӟk4M4E! 
o9S__^;`>(9Bʦ|//<Izv8ή,Mf̌UU9kyNۺZa(esda:o׆ؕKHهzʴ YwWq^M,Wb^.1x:,/R*b[?#p^_49)@nTs	\|weos`m~{wYvʽA*k%%m'<f>*ͣׯ%iZ-&1󳳟'|4sWJiZh4ʋJӬڤYi%jTJ u B,ϝs9Ȏ($@ ̂AAHȄݩsnbȳhG,B@"=i
!C6@JYrptgggO)zlF)&0 mq6vbP0Q^
l۬_ob0L1AJA*ɤ6B*`LH4MSJ`tDv]gm45H]U]7uJ P  Y*X)%vD-u1A8FQ4 12;0QZ1G9
xF)o	RJ!8{J*<D$
)%sMY^\]7u-4Ib$&R:x<GpeYTpzscͦE@ڦiX"0D"Du>1'Z	^Iy}Em{5R($ هV*zm y`#$"mN I)Rv\<~v D,)EbB(aB-cZk8ŉQIh%My>ì*mDvb_ĭl)Y"O  TRai RJH^	6mk͋,f} %1hkwygw޹κ.|V`nڂ(Vb`	oVvq36a:gD	c!Km<??Jso~!"vbgf'tRZH'''4M	GnfcR@Y.iDd
k몊"R ]$.{%%"{4b)Yu"8(q|`69GxXdZI >=%	dW#+v]zgo"ŮhY`	Br`'\]7HiL"gܵw=RL pga^
 fg}kǷI9</M8kBA/WQI oce"cT~vvp֛od=T8g.Sc"wnR*^2$b
֝<K?ɣW{@c+<ӏ@;u].>3r 6:?[,.}"ϳPRykYZ2 3WEF~ZD xȼ_RJy0E}UnV})D˾Ѹ(xhҼlA0J&`!\*t!ڭL35<LR<RFaAf @0Rݾ}2L_|o}{LGo<|7%Fp6G$I1bDƘ|
Q	TZkmԈ-7g(BIEծcGD"RC<6{[d?m۲A}0'\׍NpPF HAٴONu>}Lzt||0yA(p1R$ˢypɦכ9bT G	X#
K1rF{{-XTRIS\6G}KwmSnVy18Mݿ//>Pvn_ 6Yjdd< yPjZ-=r-efy8EUi$tS5<xPz'RP	WggFhFzbqy_}Utw Ɋbz0;ȲI^(M=ψB)3TZ(5:^؈DXkjcL<p8HTk$etnwƢd2t8H,9=lD\LlLJDIUՓ'OϯbFkDIFt<dy| ;
]՛r_jv#!nm;>RƘZ
D%(5ԹmۅE?@D޻UTԤ=Z;A!DM))V[aDչ%
mZXI/y'CZ鈤]W*d:ڶC``)BPZE>LfT'+ yAB*12MaQyf)ƳfiZIQ8Uqą

)gJ&ֶmDF))kdWQN@#mJG;VR o;gm`2&Axۄ#.:M`m_b Y|8Bz\-W䝖JmlEBG b00a6_}GO(ϒ_^;<|aa8^?/6UkXGGo۷EU z)Q(@|uUUMFGϚܓ&fb.Eq ٮk%uVKyݿI}zzV?wwnbЫ-"^Y?uW(0C^+*(Pׇo[zF[v߾s^ "jxK(*b /V13# @ jَ2QZډKzkAH!D d] f$;ήClv`>===;;C%"ж_@"b*PH$(bK%0`i kx1z Jj,L7wP24en|1{{!1q#)jIIL#ɭǏU4#]B\<xF!o>F1
~yǓp2޷^g[g%4VJ D$ 2KrڜݘGJK_D(Q_3~$@QU-?D@mуyYGLQ-lJ
BQZx!󁙈v֪SyxDk]/j}A"r|gDp}m}YgDh,$}t}'~UQG'nܺ}ܬf}9_\^IRh:AQ={7TZ`<lg;RjfB혉znploƟk"=B`
o"-IW5"^6y^
	 f-.Ξ,"k %&ȓ4MB ٠~tR5M(xpPJl\`PmX/q^^^*Pߚs 1f)ۮq0 0j#oMӴM}qqɀGUSBfh˪{V;wLr_/K)wNiXp<U%Ie2YQ-eӺzs5_z})"](mkDRqņ9!l:ffG04e)ۦ麮k;nc@l۶q]罷!D@!R H֚Ǝt2[G'Bybĺ<
PJ%ijLT2IZkH%fιֺp0eU$BH%fuaTUCDTR*Z8gLKKd7n$5XRJ'FgiŰȓ4S&B ypTWf\,z]rޔmmYGQY0TA5m v!;UE!Ry%FyfLLNQ+66 .|h)Pr ,=t$ՊChzXZ"v(82fnDRk#b0%h}<@mL&<h4U%iT@'гB;ebfsB(jZ@`m
cEj\܋}O!P@ bv^gcs()GQYlSeN!BJ)H;[u<OI^t"
<=;sf?n_\\0d2?>MYbb<j' 沬,MyODm.h4{$~0Il;K26ʏܫ!8T6뵷mf޻Uu}tSJ7M#u2]ϧ3GgAҪ-?
p/?| bY/_νu'hL7v=qBkrKGB {Y
!A*KX +PHt40j\.M!
>Lx23!.fo |I	QWjz<=^,m*u&sY&v{[#3H[tBL4HRTQaV.ή.7kkޛZr\ybĞV+,⢍j#xz```Ƙ?ذ1Lt-բH,徻	^U{	H}ee捌soAD.wqRRUIQ֭ӧܻwpx}_+X /_=1 8GΓ6fl\1aPB'r 	!T ,ro}|cttGnnǗ'+oЕaGiOcbE !8FF (M BpnHk9j1Ƃ	gΑ1&}=<gm׺w	!0>(~6HW>l"xF4J"HΚkM4AYM'y׵vfZmJy^UEYy^jc)nᜍ!H1Ę<E1'84Jv8Hz~ 2Ƙ`4S2ƅ\Vպ,6w.Hеڬ(vEYE^sEQ+e| )D5E}0x͉BJA|hFbyY"71c,s.lo9k'U)ı8)F@!Fz)eD&8RfiZsIΊLϪ`6?Gvu!Çj:?7N&d:eU`C-///z%9v]~)2\*EX@ȋBCƨhc(I :es.wqژ,ϋ</2P
>Jv:_-0pR%y
gB=-@J^o></_6LO/RpjZM,K}ZE"bɮtw M"p22RB).L)iɲ(ɸcpC}۴ۦ]mruy٬nzkX  @ֈkZ}ѥSL/Il3RW^
!ʴ4J)%A0cvȨ  E\fބ@,Dy̘2U1f%
Ⱥݍq4F,\812Ƿ?LI"㜡RJkm,'ӪeKm2&ub!b$b|ڌ!2{v	ٺi;>ޥ>RF,S1֍ux"/;Hƾ"1$ђ1BJi\2~SBpĝ;8`2H)m!UEq\޻GOQ(o|7n0.ͦȲG~'zZEƅ`q;EHCSמO^I~ھmnێ(̦l
g}ץq粟_;yqy~	zyFN?%"UB_^^n6Qf9Э[y8ͤTC߇Lj<%tWh#@|Um7L!xDL1W_2F?_1wqWBkq7!"QyJigQ'bYKS23d@BD 0"ȑEꖗ;I+`fiۆ3^đ&"`ږT0l֛j5-d6?NuO022 ۡwC<htֵ1Ƙu}pCQtqC:PBKo9'LY̧aMʢ,/?nݾsX@SbKW %? RVdoiK7ezv-:mL^>Pomxn[󣓓b|¸+pj؀p/xq_|/*8Ol!d* r!1Ǚ2\XZ8s@{4P&3%90>s{) -] 0}]kq!'A0	!]"Xr/K<M#	 D } nܸ9ʇ~'LV;7ЭWˋr\./ΤeUUդ,(L,ˌN6I&
92dE%L%u)0va_V$%R;/9B}F
qKy]LB#Ůka0@iֺZy!/|/,Sp!(f5,&4Ӻ*6RȍqUENGmoS7Ƙq(9Z)D!8b67*Q[YP
(vm{T!Gilk<@dEYJU!ye~7<Dsgfcv[޸{h6c	眔RHu|th6Jt) "r.B(BjdbRRJH7[ƅ3vt0?><8<8t;Î|@vXQ޺$`f<ˢ&U9,;v,a㧏//)xyrIA.gZ
"ptd_~u޻p66[!tÑkυ+ 4eUHbuCݶ]9;89ceTUR2LYAUcLH@!VEf}~~rm!x
!}\Ja˘w..M5m״vGuFL-"ϔ2Fgy%m\0 bv'@p  8 $ge#a[gg.3 @`1[,$/
]6Y22ٕRL'R21CX!R'leDBT#B*6&ϋl2;8&<ϕeD[`0>?G%}%v]    IDAT;w
-^ZLyp!m]89f`K}KT@ֵs^)T. P籎ɑ\'Qq3M;۴]`\BB3LNøڍeY2K2<gǿJ˫G?QHg{>+sG.?j"E]S}'F.ni.ʌy& <|LpfNAi&D!3duUQ}v;aT8fڮ\_,:vw(Jx!:+yvU7"Jvwu  ~z'JBϼ` "]m+7#4;Ӧ1I9k
M9a	H&qA*tZwQ;!9@ . 2`s 
)kFQ  ,P"-qQȕ:kۮ2AD=<2Ƚ_  l@vyvzƭ(ӧ $_L	J%DEƄ\)un4c:׵-0Fd>A?^4_v_eT  /"/+ ,.'޻Ih>MqjE({/~vx6˳>:[7ʼ!\\(E꜔x΅  Ql^kzbpоG>WK<UW;]ycm"UBq!G+a>2MfR)ƍ}(@>vaX-/I5ۚ@ s`E7tvh()$@I!\0h,a4tSiZ# #`@tpxhOG^y77w VӧOst6LeY1J,&SJ`+88Cy""Z筵+ɕHm$Jۣl|	x3d5/8ϴN'"&uD84ǉ"cy/ϟڮy;e1@!9CD
գ)t6ʹT69 {kP·MƘwQkDtIk%d2=O7naBD
Foz}X'4-E!$HeSTE9QJYk__.j21;j\)%lB
9"E6.lQVS4]l[o\?'+nu(J~pxw_眏(do]QV׺~h.3k:/+&xW9B+X,6\(G$?\;>>^U:0@n8X,NQj|̔eUMfe55y\:cZP"	LJ]dYap\]'OBD:2NbiѺ(
e҅mi?nu\I^eUUUUeJ
ڣ,rct(Su.=e\<x?z:F}AH\u!L5\pBĈӳn	)E	Jmg;l y;QM(!T_-_]\}O3Ɣ#]Iyxpp||t:ɲ_M*mmM3Ȳ,2	>^	8pJI:В踚/΄YE0ҟ(=Eu"a$ $B6"1!6].UJ/Ӣ38_7lxX/yb1&R`*SXd:*3C4zل@GƄ~IWL˓MJʻwngF[#P:2v?*޽w7L../sRJDH`Λ.^}o;;O]m+B1;t]u52^qYU}zKɣ`{ŧUN)1[WL/19%ڋluō0=C1J&ɍ'L!Fϯ8ly~Wo~AĴ۾%!b>$e*k
J 3`H^Ah{N˩?!wPT)O	Jj:)goEB&/)6c<1"rdN#'kK"c!Bu:"W|ՓRw1Dris|H]?-EWNDD?ˋkTdc'V,.(2)e%de9AkH7"LyuhszuݯH/쥔yQj)Ʈ?;;s?==NRZ2 Y`?a9pޟyǹ(^7n~53{蘜p}WQ}1|})n~u8<Xkw_~MZ{^vQ;TخE_@1q^HHJq)~ًyD9O\D q$<Av^o7]41#(e8N	]]R'<d ƀ\D c11FB80mxO(=1Ę=|JLdOz88GGǇy5vn6m۶O>>?ceYeY2)RJB$(G Z8cJ0~7}W=0 @4ƌ1NUvvLuIĜuYo+kQLf]ۜ٧Z	!e 7ќaUd]EBR m?x,r`GRJ]!-ϟN9vӳZ<_!Q^ c<+ʪ,bpnUU.PH0
!Uq>3Zg\ZEZY,(gD8?sΥB6ۯx/+)w^dsnػmL~Hf0c "C,+
eRzFGXf Qu<ӦpȀ]i.D@H&.RYVe R)MDbd1Y*3gOfuHI8_M\\\_}wZ_,u6um:gN{nuC%,2gm[2ٜ{9	yfʢBw`^&>xbb|ONOOu60Ql$l 192F!(Qbwv{g&b6 F!8Fr1ۤEr1: BΛqi޴m۶XqWJeYvp8X,鴚L,SWK}@{FkmtFG.x#arg,L=h3̨l~pp8拪T_;rp7rx/L Hr.E1k뭷.)&yy7}4>x8i8?S(yv]LJeYYd$X.˺aڄ`J%UDJ泓C!ctRֺz9J;w^{82zւXw_71Xc9mq!&zͶGƫdqp8?<Z./?yLTtEJ5đ=_;l;Dq$IHDcQw58*p?'ɉɲQs-ɵJkGH;4Xv̿_B}a˿:"pб<Wi)OSq<ˏ<O_'MSH~bm5?_"ŲϜR7!
JmtT>"" :ȑ%w@ c!¿,PĔΓ&Qd_R{;ɏi8YN37vloez"skm2+K1Hz 	`Dc08BMx Cɲ|qr`ԦJ!ˢT:\Hwal&!o}֭ۇYf^.>+3C;?'x%Jګ}7zg:_Hmo/D9դz_.gR;wO^{t\o?kYnFl)K+/-!  xsHQH	QJD;g}`	BHH12dEK6u$rηm4cCDnIl0@ q^c{_e`\!eqOܗJ/]`# Bi1zھ(>!DO?aQGorW^}ƍdnlv;krn2%,s3T2Lh>xJh%>JO]E>1 )%R7e´)s
Ak__^2x"r.2cCeQ`glV91lFJ9L<9'̲{_uӶFk)ڦ1FnX.WRjmXq;0&D^EU,EpSlA۔#K	R2fIgMdyu] ɦI%[ڶ	Ħi#D`,~좪X,gYwIݦ/G|2gB˳']"qγ,/.dLZ|xa"]Zob$9'wLʯ	jCH9xJ| O]LTU5N@Kf:Ŧm)6mݴˋj,_0MeBJm01`"Xm=`61(E̴Όf\|g(JJgHAd;F9p"Ęt9;?{ON/s\p )C%0aZM$<H<3{)dUI)F
܃"G)I1L,#P&{$ KF+|Çz皦mڶ,$Ƥ8bp8R+Qdf>-l6Nj9gﻦmHi5m1MEQ	)>$oC`'_|#G?,/Oȫ1sb/K8E@{pqt=MDI+D&eV
	"KfBmm#x2e.	xcU5E^p)njC
$$9wGcc[UU@=Rj/?蚆!o޾}d\Υz| ( _mM=| ;C\P@{j]?P,t:R>|mGѮ
ϴ^X-;)^x\H	>/}'" g(#lgo0ᠩEWӌA.6˥#ǿzk>W9쳟+~7ZQE6
.	D,/fd,=OM3͑`bON$a==g>SGU"GsH۾NStYu 
"!D`hg"6(a_(m1̓HDJm)Zݴ}oʐs& L*5<zdCuMz~{w~~<LL{?*?{|:n`/?O/~;Y"}ƹso9k?߼vrvXo_e
!k7`v}Zkm2B>8ǙЙ2.ǐ&9wN2ƘDċ.0H2BQ.llz;"|^NEYF j<$GlF ]?|{*1з}1fXlkRtw|7wtn<']8?88feYi̕	2Y	"vD4Ƥto06mbZ)%e28pHc+ŋr"@ b
F+jK!^9Cxѵkŷ!D6AJնMA0|w֦,+;L!,C.fLk2>}|~d[oyt|Bxwj+|>#z*<σ돎Ou{v)"=˕  p!,3E\2ǇG`F0FMDcA)øaجWOOOaoZvgڵCEeY~G.//N
#cls˥F	ڮ.?}fBaq	 w #@]9i*Ghby1br6
!wCz\vC! <Q)$}}1Ɛ˱T\p!yзz)k2G&TeQeTQy).x{B}?(-gU5*lLqegBI0Mv]W|>qip\'a^
iW@!Os6
!RFaVMѣͶDEf @kS0i	 p/t3gZ).up`~p4͋?_H!cRBɯ@Km"̴,eYMd"Ju}S 0\ZqmQJJy HB閽8.)VRZ߾so_$0׉ #ȀGc+R*9gRfY3$ߞL}`כmR؟6Oc)3^kפm>|hZ[kstʫxkǋ&%qt>\ 牰oGbXT凟;]B?Џ;"ǹI(YDw~n޼ ;  !V5csS}u+;xVIUqmVQ%1蒂ys-rxo	;1Q K-O_1Dh,3y>XE}cF9R텕tWK\M3ZDD|FktOꋔjOW" f R``c^T1<#5@=,,vmf҇΀ACι2_-&SbΐbL50/N.%$e}h
K!%b2BiHiSNm" އ	m!]MDv|B;{d1n]^],u|v,|e
 YQ4%Q,sq@|~ߵ|ۿ׮_w΍i*`ݻwD`)cfL??>?{?gٿ(iSoF5ۯ$( 6ukwW'ޤ$<V]C#}?TNѣERfYf2sctoCV&cgYVUy^En2P7\nVrB{;tft6r:GJ<JH/OrLާhO[z;	Q
fy}~?LW^v;o;u]//VӧOcEQLd:-,xw=CT^qǼ9g1FxMBr.J  ErQRH:q.ZI~O-pyִ.9پ٬g27i[yaj(Fd|2yQك>|487>:<48nM۝_'bqxrkf;TUngŴ{7*Z0Β#1ƄBʬ8g7unzE))$u/d[
(\./f[oV}D`mY5ܺ%ԝ6͛IuzvɯMֈw]$G ;ou׋hއ(>'t~~vQRU}J#e{n}oZk	1臾     IDATΣ		.QfBgR^, 1@ӾkQRe92YeK)R`-ch<wS 
.FBDwN.97Z%]Mm:$ǽ|)Ǐ?ynvr F [ڴ:K!љmY0M=.eR0D.$"vmJs>&=OMi5F%|TB$|f8yQ^Nɔy^G
8q2ZMWe9T٬*IntݬW+d21umT*(eI,'UVJ	 yQr믿qtrDvE/8" (@M@0 h"%ӳdR< @i~l/zEE*l6l6X{qlC?H%໊:Fd[yX޽qoͣEw1*D=g`ɲ;7oܹuC*Yw=Qi%eu۷oiv>(|=y_z[odRUъuݽ>l&?^NݒLQ )vC}>vl[`UUM۴˥:ӻR偐bB@(z'OTyޡ
ogR՟qE	2Hh3x/hXA)lc@|bp:e"b7H8OV	r1 Ci%9gO_P
ҥ t+$%UCx591 9ԵwNihK17R>ȄڡޮW禨h_AlYEqh)t6
O,(x!e^VdQm9]ڡbt!/rSjϸG0$&Ƙ ʢX.?? w*jbz=Lm7eVL!}3u0>h%_曑[7o}_ܿ˔L!_[%Cx7*1Ɏo*l7{vٮ2#
: vsuv`]?zI5@)2xt3mmMQ}?/jwJLH`=bg{5U"8È?D18>y9a$6zu+)?񵣓kGLyUֺZܶm9*11&LkmgB!$v3
!xb'3cl.smu]KDb$%*)<m-re)է~b63\^&R]oϗ|]q!q|YJk 8;;iwyOSɾH!ðR0Ʋ,yƣۍ,&Q?,MF ιNɉ`u)mr> mݔE0NOCku9oR(C0vnڹپRT$BI%,r糣Ã;( <~t&8cˋfEQyʅ&z"EDѣ'΀F#q'bTrCA `\vn\֛UDƳ<ˍ*+21 rB1FQr "y!9D	!T3)`3R(,"#"f.8K12!PZm YdcHJW7M]7uB$)R9+TJd $5X_Ml	.Bm#i D!xNXF7fiU8׮ܺuΝ;ۺ~/1*)Н\!SIuUU2ˋ̘ݵm^o~R+C?ؾ#3AuO]qH&Lp.BToݻoY֣Hc$`BHثe`iw ()%	WR@mOY
!>xkۦic:{y,2;k;ش]-{TfDXR`1Lc,3fz7nݸvƹRj^?~B+a6}s0; 1:kr]~[３sеm\T5mnZUj2<z}{ι>>#%^1C`+Ĵ%cOpBa1څ|]!o}ߢhf}ecv\]b$_`*q!FDB>j 0ƼwxyC֥	*x˲ZeFy=KG
i/+8@O輣XRN$wC"cݮWoZIu\J&oΪ;_R#Fv(T,J1YԑC;yĸj憡SZ3!!2ܕ4]lחԦ`8hA^*多LRN7-<mw]GfL3.cׯַsDp2)?_/`9^ZӴ"b׵~/!S8DÀ }%Mԫ]}wz'O?_}T7M};g1"g^fיPkKqA	sO~[[?].>~rts.ir""Kܼnଵ~FHq/"G;7Vm۶LȺ%8
`vq_%q4zzNCW"!y>Ī.@;Үd a>xƘ1[ݽ{@i;]]UݮlǑi27&ϲ,2)66֊U2d0 {a2zbEuyjY.~G&ZdB`OՇy=~r\z&>?~(HeQGJ
DpίR)!
!"֫ۍ1f69a93)x?z#,z4uݴBȢ(O?|lIsƲ,alF餤J1fOkgsݻCR糲nf)fT OTe^E!Yt:ܺ!@F)uv F_ɓ1µs%XݬO?J|q*92k;kaYVJHpW!Cu޻$|ϸJJd!G&Fۮ~oH!@jcpQV,˵$yvm D 8 2LrZ띄*'/)DG{cw`Q1$z$F!8CVY~v.l6f6bQ,˜sBdJ0&V:BܬW c&|Z`B*	(*H*?O?> {~[X3`;I(mJ,3iU1	)ba~R.f9k]}c$w}(1 gs%gXM}\@e@r/ 2l)E7mʮ>ÝߘsL T*IVtw؟-wD+RUE$9w:s_",*󅏉wϝ{"G95{뉺i'9V,ۦfZ|O8"w 4G;"Nڶ<;d=3K!"
!@< 2!dQd;;;{7_jƹ]?y{oV
 Dxz֭</⫯ZΆz*˲+|' 6ll36~&Hbqqvzv~sJ5ڃIQBo;B:OASH
)Eƹq]/g!nyR|64zHیq͔^%v=pU4fU4:ޮ h0x9y}`@tB6I	_KŐG!u,sF %yO,$RǫN`B Co+7uW~^V$-(z@'s_CvkKxgת1D(&"fBJwWݙ@'pZi3auUM'Q6jƽ>G0(N$_ΧElNb<!UUqk&k"1'֝/5Z×n ֆe㌝>O~  <"2=_6F?7?Zm:78Z_\N")776ÿ~~q_}\B<5$[pD2hAtNXoo㌿曈P7l6?==|i E̫\$".mPBAkYFDQMSWuUƶ#@d!D J *47/w\<y}:2w;@A8ꙿ] 8cC~rq1H7nnpp/Vțru9\^^Tȋ</z?Wq0}DLMm,'fYq'mǜtUPU1>W4J#L@"JEZ49ĩv[@F 0y[x~q>ϥ0NR)zڼ(wvZ&~0kcibR	?'{jV" "rDÝO$ȯx
mw=v?/lc8Irc4ٝ\^4U*V<Lrel*>8$NY
k9v]Ï>y[[[(rιux\(k/ϋ"0;k2^5~G1c]b[ :˲[eB Lrg"NLPD#lm///8{}!DDY^zEBRcTpZ:L*6\TBXkx$zW+3m16yH$fjݴJ[kCnu79k2M,RdYzxtr~9i6rű`i$yy2J)!xĽ<kZU.Ju硠NU gB묋$ܪ旿'ZdكEG?oFpP(8罬gJȂ3͗''rk{{411eU.k-P\^2@:!΅2o?(	\nп`;b!L0 Vڦi֩󜱵g-vFiӴZO)/k-2aZG͍M!l:N뺊☯j,!-`kj|n$6X
G裏NO9c˲{oItVWˇ{/NXUf0͍w{^ j*UM8rZ1Z..'U$`8G(N?@
	Dߐ:	+jftE\I\H6@HhS5c$ $8@R0HiWB:mg6ѿ+;ܷxLt.5v+tkVAړ4,%3--*kWkD;6*TM՘S"cR 9XGbXG$"<pr ևn.Q9J:?9ß?̋^08?;"MEP `K=<W73B|z眵 3FK:Kq@kbCBXjĮ:3}ћoߓ1ϧmOuu_(B^c cY4zsD)c+|N u=D l>;;?;;[_0$"g/?(8s IpFL.r%`?{Y&ǧgGGֆG]@cֹ/{JOC׷߼{}嗏OW19b"
!,XZY;gVƭ9k"(N⯟_zzNh=yYXbkwx4=/CeQ2r(ѯ?h0Gȳ|{kۏ7:l6f|e^?$Ns罵1(f\M(t[DB yi	[2!CZ,ZiDI43 B@Խ5eZ#8Ib)% 0$>h@IEE ,+W(,ϲ,IҺnդ\5<n_,ι`oC\Bq[e'/ϲTJ5)$q~?0[j!	rMv7iEgYGq|̈́|nN&m̗˪nnD68K$%c,RƑm}U$[M)E*QE/I1zggy&q\BH)"bn	gZ(8$J$Br&vX AqIRr g4 וּm֚V)sX#!::!֤.SDV(	W,TmBXNIMj
mICwִJ;	IuPw=ʺQ
{q"KXz碠✮mQb	}q^/`jZ+6@ĠǉsuFwJ
#ZeNr9<M)$3.(N("!#.@eU[^F|u+ukyrƸj ;kq@ y:Fbu7lO^o8þF	// #uؓ19#"uwwޅ*V8~6\PeGN#rˋ,5RFlW`XB(mLǯ~VX;
cGAsǑޝM'`LyzyYeiz~qy||<ns!wi*dTLs
DYYbYQ$p8B0Rӓ㓓UY%|nO"[n p(1oS	k:&1  v@i[pȯ_Gc.1dC⟠2 wWtwjJ	ZK{J-ꩼ Y3SZw=EZA<n@Vug Z}'kDP殪k~"eYOSwockjɳ0\u^.?/Q4dΓ)uZR/x2 u Q$2!2^GD\zvEtG{Wjk3]?cu&dfEݛL.Oõ ח2

c(/hʹִ'ＷbӶif6UYUUȶ2ĲnEZrµHCvq~G};(zb l5M3NK<Q^<{/Gt:Ţ3I{2Lvן3]^{7~[pQUs.2D!xnG}_\Nbe )L,smRFB
DATJ9֭Zj#)IB!Lد=	vg  Hnr]87$O&8E֦i꺪9,˲^qVkc]˪AqIʄjغ$mYĶ^8NcA oBFigy/mt5mx
    IDATV)OG{J9pʈEQdI)gڢzYe(RcVufG䥗^*zggZRFQ"F5v&$	i (7wˇ??8d@@ֹQ>j<+y񭃃bnɋު9-WrU*m8FS0I,۶mʲn֘^B.VmiF$$"rL\(<rU"9b6ѻ;Fd c~{c$wn[kC+ c<&[	!ةeiKXL-8 kN;Gd\ ׭Zk<ky@'0眭 c3FY ZFm_=hK)C.
c IJaLylֆ1VEE+D{|J9}us'eYuF#B$d'UUuiDܶ
mmnpqy1zE6 Y%q/MS$.cb)PFQpȬ1gٹQmgnt:2@ԭkJtp~RF୷[Z +3B,)]hQf'R<3h]$'6<o6#>2cGQyoygMPb"	k;=,qV? bX,s(Q|:cጅ}@˅{ۯfi1\BJYVU嬓IApx~vكG"DG(98k"WZ3.TU]7M,C[jU"p0IJHdBDBk4ĭŰ8`Á<<b]}ZxͅY%Ik.l`	46ma-TǪi4Q9d$cLZo?D8ؚ(H׏$ur"A<x":AAX蝿f,"ğ,$׊ϝa Z1:Jicd=% <eU|sOq\|J9Ϧ>ѫoŒDƘ1D_}ۻEqV9. 	CDtX_'Fs-Wjʭ˲:?9<T(`Fhzfk2qZqQ5&8W?yZiX)vReY5M()NsO?nZ| 4  ߄x5n6I#lZ5NOV3pݗ_s>9??󳺪C/.8ƚ	;Xӵ>y(K?x{o]gz?뺮1)[R/>/~O߿8S )[8RޅS̅*jFkۦY-oY|$RtBι+Ƙgq8+ "r&:`NԹPN(7/!A8,/PirUjjj:?;K^Qd^dE_F2s b18GdAHs{gwHr	[0F"Cl#wY8)z8˺fqΥDR,$5k[my s Ϲwv[V[.//Wu./~.O_},RztV%|kgo?_W,˪Z.j^7'EݴdEi4UU)E\,䊁9~O|uug9776l<F4NO:]-'R
 gڦ裏nz7.NVE50f˪,ۦq 	4q$ol7 @kI$FVݽ36ftqv*H
U-9  Ѱߗx6\/"Ayd,d$q!!z&՟##%gIc}SWW)Bh8SzWށz;ֿ11l\pjfl @4Z6mL0.^۶ĺnBάw`=&	!~خ9rUq<@D<"$YX]$Se(2)DnƸ .w?яLHHOo8\
`09υL'\2O_˳G{;ni6M]Wd>kZ{uB+q9dR#z<?dvDJ#gBp];;p1g6GWY5;/i$yDiaAr[5:Pzʪ]N΍{хnI:oNT0B0d&k;ƹx׶7|㵗_ZW ge?Rq.{￷%8Hu<><::<{9 )C`D3˪^UU
pt:D~8noo @Z|4 1 A'Jw>4"<QB׹GpY炙02&e4=|k0ua3&I" jsr.sl1N1g[[hD7 oaB[W~@ -4 2Ek<=qNu<|cΞ[ mXu(""+p$<q>֘2"CWGj_;{7˦5]׳|}1gFH~úH92='m8~C2X @8G"d.Ool^`p{g>')S2
20uUw;F٪*YÁ:( EZ?qsd|U/1W+Ġ\>?7[;n 7î7	c!VsΊ{
BVm}zvzt|EQ/^y^yѣ߿WdXJGDٺ1F?o^k'7#s,˲xOO}tz||>䓇>-W&ڝm1\FBFqKɭ0hif~/ҔGqZN{ɣ@vB"uֆK΀799gBFQ0	 \B~6N./g6NN,1T&p8E%qb}c8IV<$B)dIT+s6ZE2d<GZ#x4̲3^dd{Z)m z]pzk@[qgYB`ffkcuvzjrlRZ=MEQf˿~;hZ.1-_>I^X`ZXm,8_,MlNU|` P$1gq^gtv~CBp.1vrqvvvvqqo-drrvN [qZ˪:9zT+)^?EFXc@3)DGQ,eqb1 2)p8> +Ҩ&|0{`ss΀ОFDU]{ə"\%DĹL(eEqΙ<n*NmZJ4⑋4*$j5ȨHRH+F(SJ 9ORTUd:ΎsqqX%&xH)sDt;  zs}d2t\c(EZzUOOYhcEUݦqTd:>?(2 @di!yERkrigQ$|UJ3w_'+UE@QEqGsf!RMӬj9N&eY!olmEqb]l6LR@.}wJYνw{{Ȕ1  yL8P-vSA h{<y}eXk'bpuJ骪 - :o{h4Ԫ<?JNi{(:7oi$JLȘ1vw6ѼjNN/6Ѡ֫p$6IOG#<tkbY	Ѫ,&h)pNDl:kmY6Md	
kpi<9.0G]@ OsEi>;!$ z" ((jBk%зH`l]6ժ], ,}sw[I~ <Dj+믄'n}ԡ-i,ծWjW	 \d5OZ/ @
4!D΍uO-"z>`mcv37\md}[UCa.}9O"jZm `4-䜭qߘ =]8}j+Hd1r(j̈́y}- @7 Z'eeYn|ޔ+ZtG&;IQ[WFgc!JYZK	BD]^},	=imX $bc	WsB0Ɛ|Y*;9	eyVFލ_~NOO
rfʏvvw}?cm=ut >Ngq&ivvn߾o>~|tttrzzq~MV{g1AZHȹ\8kjk벬v[Ǯq ?AT欥'uB:UkMYk~cw .߈`|$I3(a,<8.D٦\gkϢ(ȳyY8¶m8\$N$QmkHi9,˲4M$Ji&0z" +@LMSkw (`_ł! fxyyYu${{'G~A$MS|gB!P]䈼CVgF<ښL&0M3jkUZHrHq·?&i8N_ʺyfYU?Q"׳5ub9Lrw'GUfcشMZ^?TIDi#IA5uȜ5"OTVJYz:tkk,RJ9󢯭PD@Aq߭!ZHǉ2䋜q8ʺGSH!R$,Kc%̛qH)5&$V)g8ƌ8c,"ZhQVDqWZM[UUeU˲-gim(
nsΐFL 2ƈˈ::صwP  \  Q$$v&'d:tqy3ں(~@*cއ=YLWpt_|;E_jk{5\U5nݺq'fsgm]UZuAqU.rZU%Eogvֹj5L&i:8+_V7׷6v%:*80<{/z^M3`adYQpDWZ;^WH8=t{A᫋59G> #Ykm"bOHW$M6;7M
î#vVxEWl;nYJ6@el6(8Cc,is[wnZ>{py9	0u."
ZsNi\E?TVt2D^14m/alə>giB2@9ulfy^4[,V֚$ q,ho{_J?c2dm4l?ƣf̙s_)&9*50Wپ @`w"c>puXw&kY=ZXZ}R˹}mT7Dx}1BD`&|^>kϋ>SguY.J
~'F-O;V 1䮒CdYZp9	O]dd @=#Z ,xd1ƅ,+4?\Ob6#,7vNOhF'!$r5NU۰*S84( 	`dq5kS&~r|4N666Rs6DۄZ 
s35l\c4YJu4B.4ܻypL.?OrIYu]Mc@t$~Bo{/njZ	_ʺzD	HkӶ:$EoÇ>xO~}yqZ' B[BFqGw-mFm,K[6u]%IWwHx*L-{z FkZk1Y #DE2	;g`	ɘ2QP΀3!K|eU3ڦA(Np{con rQ$`0v.-1$$͊<Z[=wiJTJ	F@ۦF^`& _\F,/d K1?OHH9"9ͽYmomyq$6m^^^CŽw޽}l>tssnJέVMk{ni5"R +xţǇy^lmnJ1dBpDf|+icfY pn޼9GQl^jct^y.ȳ4MUY.s <=~t(2Ƙ{4UU4Rd:<ːqe<PŜ 㝻,ֶ3419#"s*9Xk=%i'iq	!YdW<FkB6,Mb"t"! ɓoZU<NҮ!IBFs.   V:BpcUm0q(I)jkr-&3 #p(Q"e#Rig["v(ΟtC/RZIRxB<ֆ{4*$kf/zEHҦM<Q&	΋y|F뺪wol翸8;{ǣtyTXk[mV5UYu6Zk!7oeY^^^\\\,K<25/"bιyݗ^z{[;i	~Cs'ĮDa;[#"}ig0F&^]p_wqwp(Rǈx4Fb1L־왎q|[K/޽k7Jc x84=| }_}sz'pX`w՗"rUU8Vkp 1*˲m" {lXVx4<83ߏdXyԹ>xCvu}S"Uw}(~p΅JHdyŉ6&^\Ngq$٪,sRJg(`ppVYV:O~oj9mfS\٨?pc͛Z<MHr(s롗yѻ"^{߽dH/L_C'CDD	V)aî+~זx(Y-8  $L;7_,ѻg ϟ'_P* O;_&mu*zr(BDs1.dD\X$DjF*=1P#Fx,.Nݯxjr(hVeTDƂ(Kyk7m]!`%unXfs={GNNuXc1  OL[׶*R$v:ó^{cr.dFջJs$- "Lp 58]._<|xoowkk'?)C[x5xYy    IDATVA}617zޯG_g?NWus p 9?_ws;* 2A4U]|oo~v19:>OR $9w֪vFs!e39U[WU]M//h<ziQ,@BNL zq[0Y(c9mn[rvߎ*(-Q0JB
ց[D1
P:<1(p1ֶԭR09r.G'_>"v_F䝱nTe5F4q1a$eY2 
N@ޅ4X¾:J!6<Kn7o"ÿ??iU;{16b:QY^d^`	&y(c]4񧟌76nB0xwN/'UUTM֩VM9#Yx"x9immn  \L&9Uã_{oߓRZӚιO9O:fmFY8*b8N4=::QJmnnYըjU.WDg	5>:>N$MUUMr><+}Bq֭?@W)zsy~@Q67nM]Vb^uWB$wn)z>yBƢ8(%I'YE.PJ糐{^pdj(CiUZ|VgW$&d?~K,Ͳ(IGjQ͗d:[-  nܘ_.flͦٲ$p067#QIVGc!N~[|&3C&z8dڳS zX5Fj1"Oe][A0 lXMXpfMyf[o`kcZνs!^2^}^Ky]>~1UZ8ѭ2WܹsxA)/.=:<`X]^|\pFFq|ֿ"2FfomioGFbb9ۭʕ*"گ㠓G$ EΓ;mI BQcI"w7Emnnlo;g|1"p}{@ϕoidͷ|{A4\YV.~>T)5tE.#ZI-)vw_xYYqr~qunȹJ(Պ#h	@0vvzVUe;yϸ2&:).}yqz,hI u)؜sdj1Dt%JRF:rd6/X\ժLDFQ4rDRFy6ں{ލ{qYo8y[oӋ4p0GRLgSr37DdELW$Yw8mUDk[~na8z}	XDɚfUMD_'Dӧj(yJOjYp#x ֍rAkY7\VV$<4CD`&KCձstk77B~)sM]WuUhU(?Su5ݑ.{T;k6b#ʓd0Í͈fSW_<Fq{Bdu.j	
c,2 9@eH+6o
bW<ݳ`);t2N)w"0$|Pb@\X[U'rr+lzHͭ7n~/Uܹsgksl"$H>m۶mln[Wӓd6U׿u{w	ݖG""s,}޼<<|^`Bʅ{t.j^AY%i p&#!w,wLQ(ժimݶZ6IQ#3$/B`zڑ6ZD6NF29ruqqFD!G'hzóiE?41tFe9NEy1^Ze,#`y^,sDN7uo$u݉s\k]AII%#{gᘱ?ph㱤PP	htמUvfVW/ 		FUe{[wƴu1hqby/Vbt>[]%j>7dE9b1t:Pr
CUU㫫O>Dٻ}['ie Z7m׶ļ3M 'ߏ"ˋ[wO<8;ݕRYgsfR|zRHXW'I۶yPf3%E%J {{w۶:b	̄|[SVuYu]6.USt,>um\"L'ҽ^/|>*IveY
n3Ĩ^'''O&NWE CZEJ,,R.bVUUQt~%ꪜM'кUcut؋r1Msn) U=[,ʲpCX-3k}rI7hD<ϖe6ztyuvvDӓRUY5M[u?"(Dky l\ԥDL!$(	Lulz[3ϻBȳ4$J+UyHA!5Jڪ6M <MUV!$J"	.0uN!9$@RB(qs4Ykbowoo02@ˋ(fxb$" ID9(h;^ۚW0 !uC0'trr,)[sp-*0E.S1x43:g{?<ShҺK4Rl5m9S4ѻ{{~97WU؜VU=~޽<H9f'OMgs(r Q`]B|{rx$$MgWBJ &d ŲCJM3̲lkg7:"0	@TJU4ZI }^?hT{(0$	3#Vu601Ms,sv\JA/󇧟ommE1i[u]$䝻w#*+: JҔڶUR4e j95I<tNW$"oL5 7WE2( O~37 Mdr_`@U[sg]|!̟9\چ!pw=b=FZcL۶E*|{yQt]kPѣـ} :E|yjTF`Seۚ4n=Bn^6mȍgD49w6n#";{Y,lπ?o Ņ|:K%>K!c1&6^~_ʭ!qA[@|6!DS,;־ɱr Ny $`&!|O<>=;ݞRJ *zb::9MlkkKKF 3G|R+Ddv2\FWz5uEb/:ge`I߿ƛoѓg''x:eiq֑pR$IyiiZ.ieYfyJDK$" ABP8;`=5gMueuk֑udK,ˊB*c=϶> Zk6읫VtM< 	DDZkl5mb)F5mӶucP+5,&WW;;ylf'D$"J%	S+Xc=xՅ5q_fie) -mۻg?d:٪*wVi"ofZRJ`΋ZɓY;E^AFZ)d;;Ch{{;Ipol>;;;gYӶY[[gKAE1UUuj67MS;k#ʗ9IJ$uyM4qާi*6(AŲ,Kgm6<w,7iVH6-"XTu. t})s*0IP)J(&I&ZɦyS7iv^gi4|Kt|{<!z1reג,KnMGfu\m_UX2"ϥRnŪb6{4h#h:VU5O󢣵΋BpFV3{>D&}Z`t#ĨL `@NJQSeJi	:RHR,˕|( JBClfM!8djچH$ڶaf)8GI^owww8JAֺxXۛ\P5v_{v?z:1:/WO|G?ep0g?wޗJnLVB*  [sk]5qL}BŔw2"hlomDfՒJӚEi;<<|Na{KJF?{bAHYQJam!0'YʽW}[;,M?OZc:EA"L5ժآ֕j<I~I=BibB %"a`a@ p!B2uWe,n8D9kɲ4><4!"c"ViҊgyشAOIRR$I.U`4wwvvNvg _ϕ" JW3o+uƨ4aUVt}:_}3#*"A3z֔mXʪeTJɗ=H+l~OFZ)ݺiZu[_7HJ
!["TF&9  1 I޹rYUue7Zͦ%mRAcn	 H?եx,"9vnH$2ѓ//GB@jt1\5uE7pn!"\L@q`mjY @
AH@$08 tmDoX,\yuYei8D~Q_78꛿cBBhM~pW,3 JPUWF;ݳ[($$V&"&Z߹s7^GFK|b.욦oHUU.F_<?>䤪1D_I!R)+ej1Rj$Zj-Zk4)(	A klFspMMm[Z笵PyI0>?Ϭ4f	IAbfppdHX :rteFJ0{$LD6$DR*%|rU.mD*dÏ֭[A_*U֦\1EvC1277lK6P% TJgiҴWWMKBEO>9Xgl:  Wf|uvvv":kM[gr6y{=EhIޣ^L[0<˅(e1J;Z[Zb~vv*j `ghUVit2ʹ`/}>͌mWdEǹk1[{~u"u}yy9LyMJ\I):Rk$ܽ罫r6Nc"jU	RJcawwVUvwvvD77[V%YG%Y$mDHBG\(?_UU;wJbG{z?K,BiꦩuDA ]MӌWg	H*TV
w:NR`Rm#]EW^tB`t:;(IUȴmcSH6P ' $
tC5`+)sdRg'X;:;MJzӤYj} f\Y,/ta!gZ'Mkʺ@BzIY?j<VRzoE</...FWHB"φ탃,55i|~zz2G^yPA0Hb6B~5(''?ϋ˫?|Dt͜wR}qSY="Cf}Ic`Q9cmkVB1sI+ޚd|u9>]i<ya
"hJIg?!ADDyRr#ڝ;do[H1ӳD+5mbt*˪*[cAdl?JwBf`PRn=>e0E39FwkZKy$2`7i۶mZ7e->%^PMUU6M%>@kt2޿ڃt4m0{y@r2gUߏ+nҴS$ozk I4v{щiW~;yu FM)T?C>!x}\!2ਸ2=5!j#?X8F1IPڪڿ~U$qד2lj\FR!t|YUb,WK}*6Sr3ReEQm<w i] -^HRy<֭ DBxI~H$>1wm,Mor8LV苇IV"{'Y xuӒ!0sD$	M;#d97NGG{A{7,@`|uȌ|*`ɗ{-!Y() C48n) k( 5FΦgo` ?:ܤִjl>C$	`|/'8w/vĦ5"	{r>	)uYZ`c:+GxaoV[c$4n{zl~~q/>G?8=D;D4Q9Ｏe]Eq<+RR+MZ} a
蜱gѥ0/ dY4`cuͳ  ox}UW\6~Y@
 6,z8FYA6٪"!]+uZGi^;wQ=*mA
a 1QR+B*&gR`x|krtiYND[V:ɶ+!Nw@̧kd:p\u|g88mI"@`("MXݽ tT^>~E۱ƴu\b۷o;G/.-pX秧'4ъc;8:it[y>T>:z":awowj>ze}MNB( bݴ:BPRE|>C"!2nmm$!)*ܺ4dvv\+%e|>,RTYY^<K9:   H:"XXr^וr0v L B4+N7I3DM'U]@[SVL<MBnML,\y̝@YgYj
Y٪nZρTJ$"!AV"
.бH
 "i/ٙn]^*	bQNHT)n	sBvgoqXLE/?o  6Mu~_.;[{v::I4-,4IP-཯jla^_+-IK3"jsE?8|@    IDATw;jR{za,n?1:HZQJ_ͿWcS0hR!e-)@" >d>D
ѳ4I)ڽsXk"H{-up̓dX>t+~w߻'^8$;O>xBkq8T˭nX6.y%WK۶R{ȲtogK8ƊvWBhJX7-޾u)b 2xE.}%ذ1N`DZZVuOt1CM88ց~U;˥:<KH4~X%izp	{'痋ٴ\-ںTNqagyfipZNgǏ~{#",Ks|~xw7<o7;s;xXºQlw"o9'D'p2}\cA#d6VKV=E`ʵS強XܒJ%i:Mr18NM%HkkZEeYpzq_w޻PJ"
0ݼ*B$)NI"j\]Zcg!6>HUI `d״[RD$"6ꪜN~rǣkZ)ím1F"TM}9]Ud \C$(Hpbq5{䭵<Z~J/3Mnhnvs'o.m6]`ޮO
Q7ٹ1mn7NZ)5nLruv~1Nn4WNf6އj]^%ZeYF5u|AZ*AA*/iV[秧GGgg˪ڦ,U*TJEUf"A2JG[nX!R4dlJ,ϴ 63w"0$Rg3rl&<}6	3`с,A)fY$Jx!~65cNR-I$n!ܻ*".WUZ!~G; #鲰ޯD^/3$50m/><:z2Ndw:<ˬur\X~-:ݢ"rWeU%eY:?;==9;@ !İ?}n3U!&4I4+ zQtn;NWJ霭ʲ㓝ݭ흦ǣNY4umZcveUml[X,#Bu5v0Zno0,+! Zk%aU^mjcZ2\;cM>QhMQl:cHT帮IeiahTU]U!Zcc}w"tkk3&Zk V9X,'w^9|w"RZYgXS5F'":p.X$5MTMS56XP\8b|  !xp]PMxl I+֚! R7OuhAy4݀5aD#Db!QcxR7 ZcҼ8<<LҜ|tt嗏z|oklɓ[}!|gg%+ªc8z\^]l4ZvkzӁHP>7N70hkkJ!yӟO~?0m˛c)QbÓ'_}UIeL;yi8h}7k	1p_kAie2ozkR!D=lomm	!jWQYAzC+j8޻xO
a;h4}|ᜏ;("F"Kn"
1֤⣱MCLk?tRIcL@6ue p0yuRzAI)	$"@YT@gcyo94"N	 Bp!FbZ\vMZV0xZ.㣟2Er5M'c5,2fIC!*Vc[[|~ujt9$ϵ7y/ϑk x6lo?)^)v͟}#d+nV6IB^yzg\7m,]W)*0  .缳RJAJx2*boҭmv&rJ
4r6M=Y朋;z5*6ƦI	D b-دEQB"FV˺u=f6}3cZ!Ěٸ0!Bd5*2>,Cub)z	QJ	 eYU|~zM(Ҭ}^baXW.:=HW(ŚL! !>xOáu("ϥu&gry6:Cb	tb|_~"Du\FHPHJ
vEF,M4m7_ƚtD++<˜*)(X#^˂_1^$8XuF9!HIus>/~vz|\e]WM]y6Z)	Dbl.pp6)<	7VIps{#'$;dOi	2}Q(+skM*UYUBC:i(0he)"*%HާB̡7i)HH5owx^ӚGGӶZ))5/6zq-΀k]i4s-s!N'>⢮k?t:Z)rͦ ,Ke*JmbQUՠN>ΛoM_1|0r@\ISw~~6ܹ;zØQnǿ[[;[ƴUUmnwvv5BP$B!D$mڶwHUQtRZ'Ur%樵wŵQ
Zn7MŽػTuއ!{Ӟ'S{_Ujt|t\,tua[W,3-˲ۦ%1M[IEAE3/
S4C0c>O?TeR'ID:_TBU5r.!wu]e|Ѝ.gg uŐX @M$FqE,'q  έ>8a 
XqoV/8lDW^kc'X+{,c$I>??_,opp1\ln'ƴí`nw>n*Kkz!>0?X$1;^}7.[8%X VBH?j-2_\f@,>twwgoo+ZA@MS˺5*z k{<_[sQi6r>yCHBS+jMh_GxޫYZ-Jtw}W9%
$)"r[6F%!!2પ?}h*	"r>[tUc9!cuSNk+!	|:Eq+%$	$'6"	B{DI!<!J;"JV3δm	JJR׌*n[^Fޚ5Ht1ͦS!ζ6 Ʉmd Tngw?G4 v{}ަp|E~_Qfl⟆J/v8,O	Y)8\ZƈIF!HȡnlњV)33ZfFkꈒ-aw1MZg!k ZU UkcZ4M65= )u:RiH`=6=vRH"
m꺮:?Ogλ鑸^pX,i@ q HD
)Ed7Ihr5
e$͆ۻ{4Eo4AUWѓ_!%RD	!@]olsVJqhgg7Ѫlˋ_Iר5B %m6UE#j%eӶxoדwֺ"M[HHאψN3\Vq6m]E,huιo1Ra]K \ZӚE?v]7?z?8y|6'fI	:"\aT!`OQ!}MTBY'D`)e[ִfZm[UShaAwG,73Evk]B,/4URH)@D IY$ HBHHr:}[~;eUIl+uVHPcT&I4bss_<P'"M=Ly4;ƔeEefz݂&O'Y;_,R{{ۓ-/Eb-񠫦zHdESbY4INT44ɋX;MO꫏?9=;;|`YL+5y^UMS.Yk13_||ȳ@QgJikj>]{A_+fz `@$ BJ)sƴuUI}v~;*ne)!5btavzRßlwwwgo]ή^LƝ<I". By|[MS ),ݲj۪ni,cb<TKEMX¢2ƴ|UJjUVuCy6.2
%$umk :AIQP %0k P/}IVJYn*3
fxjafTHJ[s-&ٴmFuWM]K;}oepV'b>Y
(Z뛦ef!dDmQ8Rܺ5FCTw6!Qyn25w+.yUֿw~^(F _=4k?M&˃aBbmz{wZqkC8>>\^Z]^TɏMMLsB9zp;iDG6Ӊ="vâכǗ#CsCiy ^t|̂H+i/GJ
8 Fpft&.ur<x`CcpփknjCd<>9;WRz"|gd*zP}lr~ׯSEV)#p5B aD0`mvBhf=PJ I$J$I/GNg7i9v[ytBf^[.~ӟ|o 5^ўY3F|Vx=o$@?G:%rɛX6 t=)=Ӹb=UAG_#mhtny*9p2|˯3f"!^y%PIGolm2hB΋NTRiA<ZcmYޅ4
A"#NB"`'@2P`|I!@JE{fv>cڪN*}7=y(65ړp- D 	/$3+D8^Jw[^{=I3dpq1:==O=XH$˲"$QIzywvo߹{yq}_2l$@KLx[nO^Ąok 	RIVV_|^x2JEg<c@.68D:1FJyȋJw˨eI&Zk p__y[)5h]	7}z`yL̼xrtzzr|jtQUY3@kuX!A>>5VO^>жb>o6ͲwY	ĜCpnL61j{^.7~!RJ
 ιJ:K:l>p`Ro7FIR" JPH!`<'wu
 jVs =?]ɉղD/<RVe\._]~C]<tl6B(<ˋȓ$Z#bm]y8sVf|2/+)-[?h۲*JDap! 2jz&Z
;4l>???t@T7
)|yQ7?9WU`?8Hӌ4;!e?]FsWu]U9*w/RR	J* ZJ4Mq9yFn.ci"{Jkg[%`+vV)DTZ)6j.ǫ<x+`oW+4ǟ=.fr$m]^Fu]!wv:WIe8hlhm02IBJk$9X.5Z	t&mAKbj@|`oMV	"-HKR)BE,1Xݼ 'ι˲YHZ11o-sPJ%I%	RIhƲ"tNmX ,0өL'I<FD;c8DH>/~UrZdfs6mAܤ|p	@%[t[&Viɏ?OV<Z}ՈBl
(FAϖy]׉nYk:I;r{;[hfg#9o}m[nw:gSkMr{aCUYyv_{M)Yu~9!ZL$
V{mR]'_>9v)Al:88@U7ekTrUg˦{Z'!kTHdiN&SD*繬5;ZX^`X;Ę0 ]WDCx-ӊw7+H0@cLk fʪw~>BI)-l&Lwwg՟_wW_'qDHe:ykx1`"~͏CEC U9R^iuH}eUOOb жx<~Nsb6z_:K2
 ޙ%Lȴ( :kc!dO
"NR.zU'ZߺXc[cBb $:ݮ x@GHF/I@"X6mmL-eTZJ""#ln# 53q
Yg"!';q?Usvz|y~T7	T&yj9 @ ;E!<9:x_ofoW7?٠c~q(IH|kLt@rK RRJh7k#I:/ή.Ά[[_~Ye[?@$I"=R5ۉƓ5- dY*n# !},0w%捅 np=~dtB|q={B`n?}NkޘN&htq1f|69"MǛ*tQZ/!X猵,۶ƣsv}͛:PJHZ)sX
@ DEo0(:]"05:j!r (6p &Vd|urro: PK6Mkml2 oQQ)HBdY8pSWu]{F|Z-^6.1@t:JJ,˳,Cgrhij!e^nw{j>7MG_<?8x    IDAT?Lt޶ֲ,Ւ^F @!ΕnZ	DA?7ӼeZ缗BFݪ*<yAN7Qy皶q~.ZSŨ*ݝ۷8VUUUu,W#	cmYU~OJ4)elyE$Iz.TU]+wYM$BsmkL(-ȶuZ),R.s6n'{{;$Ͳ,g=$˲3szUԙUYU%4 `+ь4#f4	1͆6` dwWYU""#\>y>̪nrs7cpk͓'j8tmXc3]'qrUu}6)ۮ/˲rPdqZZ8)ݽ=yUB,8&DP9CG9Eb)'8*)H頝Cog@),9rDBO  mLݴMY' ArC(q!S*I%eq$IʅRqI%(RR!ӎd9s~:c˕.RE{ϐކ>2֖UyvvY<ۉ 5X on#{dgۿD0ы~ "`\zY]W?b>gHJ0zɆ=n t:ڑC/36䝱N9'@C m]i9pggGQuoHcY\=GȍY4\k>ocݺ};NbZ{~6C$\W<rΤ<+3GƦÇ<";o1ƃZ#9OMjcΦmS7bq޽8c1nMP ]օ%W?!=9AytD@pm5xOa
CYsRzוּ(NE+}vF$Yvƣ$nH#=/쭷,-[ڞOo wmVWhN{}:.`u>m-e5'DkO(l/&)Ѻm*DtvmKb>/|fe=WN	8OU] O \U7y^'rins&DBdŀ-GI[t6+ƘjDMPEl!އ"B{ C+2$X8RW  H  vàSu㧏],ӥAFEQEq	OƸ{g!GJ?9;=-Wѫw_WJQs)[UwN[[Vu$z-B@,$McH=9
mJE ."ehGǏ>W܉X+BG[5L"2ڊRqϧMpΣ(jvYػw&I6l>U<$ WbĭfV_^[ 6p0Fq|xtq$˲~vvO>?|fqւwJrO~>ioQ3/^c,|a}ah2(9DM׺BI?$K88"%q\~ƹsRd<Ɋa)	Cw!R
i"<|*ӟM&hp\Z>"t"2G.UIeյ1icB쟝M#HAZ2<k-tu]Wb	d2IX欝MgyY{zry,K;)ӫu~83!:+;ogR(D)BrWuU|,㘈ҴMrӶn4g7w&W8vicGrH֘ڮr\đ {dQev@6 6zYV٪BHeYEQHihc˅vPGrU.2͋pU(Nb 8Z9c_-'O8gGaL@lrfrjvwCG},VtRE.]JDf	 yQژ08"ƅRN$Su,c8@Ѻ:gfY
FJr!c2Ht2:)T6ꪮB&cR y0ƅ*Ryq1E)!xc|u֚ypqB
i=2@HHIkYYg1D7"7k]ݶ?~ٙ6  *xa{X81(uݾmݝ;v]佽T$?р[")8c:.+<O4m׵0;y'8:]V@R3{89g9AamO`&9Md,Mhą<?{VU%)@WB~bGDzo{}y_c(,qvmiyg6zkBdi}Qu|.4|߅5w{1gg?LJIDeU,;y .+R:Oo[umbKd!PQRr)EUCfA$qcK"O>}7RUEo6nJ[Hk]5RѕkWD|82y!>D}X8X׌B%0<0%Ml9vzKEíaCuҡíDt.R14e!>Kk; DDQ0R{!uj`rY.uUvmqs*.YktP ,r1{\,8#yϹ[4uASUU]Fq!sy$Zk1Ƅm׎Ɠ׿ͧ6J+bXdEG:r D>0B1_18kf6ٙ9n !eDdĜC	%i>9?y2WUγ+޽_tm+8tx _qVXK5Y\8	yQƣd2QJ!`Vvqd18I6q\*Xnǯ=N O<']x4/ÇYiQrnqqAdB<"]'o:{,/E_|Hy#FD\H:k*W`Y^oz4ξO>_Q]b'}al-%XKǉ[6u]I$&d9k^
dyD
よtx`0ލ<Lh$ƃԻ	pΝBq(;fi]çx8%`J(Or-z 2)<$IgMrD%YBE9`0,|:2%"zgֺ뺶ZkcA11E5N˲:Pc~T ql`@R00eXVvv&  XOXV~1͛X'KߖYe+%Ibt:}p7ɊdW;*W`Gq]W]R?0Ipkm]MGagt6#7^<8t6)|\<=>^d2κ\=;mڮm[ٳ`997X3~<y皦===yGGGOOʲ|>iڮjȝseU.Kuut>OvX8$gY)yjժ\	_RQd_C.33F ɡ@ޣ7XW1IF]~;a\xt@8Fx4G#%L*Mg=f{u- "ADDxo7IggJd|֝o4 yBNÇ7uDhc')8KE!pzw^_H8-	){ޏ~4V3ΕNΘP%{ =ֶ_[6M8+"L:kCVvw8ghݵ:y^si;gh$lZ﫣2!ŹykM zvwUH%>X.K>{-
"i:*,Rl#2DZTu.ؼ(^}hgsT{#ԍ6Bi?3XR|!_~ccoZB;RX|=Etxq Rd` JrgM VJk۶ՌH,#;kGa$ֹjp78RoQ̹3eYsοo_}?߿N.>ίUƯMmW7_zK_6C \o 8 :afNmMd \C7Okqk(ޖ"uѶOn ]۶x,*_&`Q6N9GrLOwBFp:=;8v1iH@5
LӔ#r{뼶|ZU1?⋌q}ƮWﻺw '$xgoτ. Hwf&c<#2<2>OT'=}JsRQymq)T FsOBEdrg'O>'D>|_<}5ѕ+NUםZOXrӳg'ںHEIi&h2;R hZb6=6QIxP(D֋=BhJ`@lciAAD$p$i]Zjά5ΓPZ+R,K'i]Z$IYso=5뵴IQPWKVȃ =2.\I6^{[u9'w҆o+*t  ,-7.['Z6mۤZs9u]ppwYYU,K8Fƭ5HcIb0=Q X<ۤCoJ,"gR*ӝAX!Dǂ(R$2EY	!Wjk,gL",lZU5gqFM/
)5ژ><3TQ{rXrOluU_x<:<'HW_DQ;EIzCf%%㜐yںᬭJYy.$OȰ"ݦiYYQ$7P*ZM=H<iKº۶,ϋ"#%9cXÇu^^Β$IӤ*Whk3"OxXXkguU.f}tpt%͔,/R$I,_-X,g8_,fl6/lȘ19{rr:Β$aO\b0!kT;Q=}h6:넊Vs"Mv$[hj@x@~y ',"dLI9L|Q$I)!N'J. Zz̤fVcY=J	8H4Ɋ$/b$IR;<\  vt.oJ<Rr44M ltk'O<}4ǰ5ZOiEζ<Az6wܹ꫓mmx4B<T__}geYeIdaݘR
8G8aJ7S 3@ZkjcFÍUִuey1(p8"uZ;獵>t9}׶Zk=g<M횶*!nl.i0hI֭[ѐ1ԝ&g$n_|ٽrGR	ѻ)
)D=0 cc4 g9c\*lqogo~CrFm˺aUYOeY^9:̲xS3.i>}YȞr .P ^dgÞW\Z	<	.3SQHi5J:(%uULgieU]97S=;% K競BB&׎%{;VٳwW"i׻j}[k0W+~ ed[6fl~=G'/V1>wE0Nwֿ
Ki?)%zً_9gi+Tԗ졇rJE*B"ro$XDa/V'.[rϙ8ZWvӳgO{G&T'iJڔU\,Y4v+:aȅ`O{
.xkz~^׵1F
A]uhV .go̻'B4M8cnNOO>~]
1!Dy+m˹J9t=y^howξ?rmc[oe  Wߘ]RJ R`^ϧά1;׶moݺrh<Q*F8ǣE;CLd4Š{. :9R*
	A { ַ1Γ4Kl4e)iۮ tXJ!<[ʽCf	vMvf{y8wL}+&/$
yZK=/*EQ\rw^wɓ! &zp//"	1B/Y?1k5TX}nzo]v=YX9mmq`ELL%Yo4{s@xO8;&B"Lݽ,;	HIER2&Izg=C*Z	 g''OfH0luDTUNAQ.8K$Iژժ*W|^3 g?{w:'8q|>D˲" ߶Qܾq=.^H9	 ژ4IF1|z~O=h4*AI!VJC`oy(ZrBE`'	.D^Y= HHCYYUyYh4-~EOcQUWR
)Dq+B|aU7QiK;IQ8&H-|h&K4M+kmvejmn\YUVjy|ꬔȒ,ϓ4{M#8K`81j!"I #ƥ&,HҌg`r)b($~J*mdB7:@O\Yc5a%9 *aArB*)e$i^\*<Zoplݘ`8@=ڒm/k7n]dGQZ1@Yں>;{ÓӲ,#@zuI<=A&%I_Ko]v sA.vp<==o<g O9WJVGkk.BNc@DEJ*[\wkM۰(ƴ5q 31,Mb;,Uw	\P(IuB(9y)}c Xc;W^!"^rv>NA'"#= <FyQp!QqۮDI(DΦUU1n8\vkuUzkZjck:#9/,,ϥRaY@D |iY!gL)(ZYd  #{3u@:N
	'vK}S@m@eyY]?y8wΗU@q+)8gmeֺgglo()eHH2171L׌ο޿~Rוbo_))n@`C	/^?T"N^n",J{&mC@t6UnHu%!.Z    IDATZz¡򅦄L3]|_<!_I8Iy.2kUY53&0<Uq`8Y1H<cTXIKO  [UY+{|,ڼI>q]|Q1&8[9#b BE-GoG97;UyO&@Z/"KHTGhӔ: '.ڮMϏ>>;=Zo_"
)4yIڦH@D.yǘL&Iwck׮޷g}$Y{^XB:d,I⣫7Ɠ錈13OʲL!BƴNO~~g?iy_?Ý|Fd nMSӻ{W^?v@D
 D9(}(#)a) F9WUZT\.=zvd<^V,MScxh9*N">?0p;PP_ -5 Y,WQIsp8ϻF!<C Wlm]vm]J!(zڭ[w{]WO{} o}qx'Fs]EQ8GadA ڃ"[,WmJkc{^)c9Onݸ#t&@?$Ǧfy* ?;~8V*GEQ hgr$$d/ȭ|>o;_=Ck?~|VX髷o몦Mb	8^}{Pd% VrM8Y=|Tew%sny^y@"rNf|d2|ͷ%Bx≚NT\''hPLNFQMݶ|ꫣHJ<J<OΧu|ͷ$߽b*˕5fow qFpDDƘٳ+W_qkoն&IbIH	ŀI譳OOOoz%sٕ+Gޓn1q^{wz񳳳β /ݣ+!(| \qII_~3,=Y=$8K`ovTZuD> @m8P*`
 9ӝ1Z jrY qgp3R  yC+9xMP{DrjiBZ[ k'ޓ 4kV  &r5LlxP!BЈȤ=yBVIutk|rj"SQrHY@#P"b=')\JvA"MYDŘi$[sIqEkv';R8,xk9$ьaDlԺRfzg,wnߺu3NZƲѧ|1II!cڄ7a/wl2$qMv|Gݽss<ٍy[ j[w^y	z-c *֚luR0Cєum>Xzِ/(_v#iO!w_pX>IvgRpdLBd$yo(:B&Tp UU#B)Q4+ӶZm y~xt?OO_7w^}7ۻ
2kǶh0/_U{0CO׹nE:///ո'oc+\FlG/2!`HD9"pz`q Ƅ災͛9owxu8EPs.O]u| !_<Bı:88rs$RyiKD˦:'g9q&8Ar!=^zoB$`qVVGWC<Kt{^2^*r.dUӳngBEIV|5U6TgS@V29q$Y._~`6E\Mۿ8?5Biˋ{AӜ \̏>^u$B
&'ؙ3u{ӳ~w'z\]q]wѕ䭝ڷ}4,+r#rr3Ƙy1Ϧ3%EŃm:k&YpBp '(rg8ZF _p8ΡЙN75: "!sQz_O%PDt{⌾G{@=b)^ YDWYuf=s駭"cLt*1T޻ݣÃ ]8G.^fI?_p'K3;9TR0!h;ceL#D` 8rIyѪ\UuI	ӎ$gJJ"8-8N=AUUCJHNI$5 ~c 9g'\r!8ch6˲6ID=޽_~_g;EqO#у <R3agzAE-
b~~3=2sd]V8NB4P*9ֶk8'iik')E$2ֶOUUэse<#yu
emKQ*iy˺Z%I2(%R]35QEdh{r>mi|^5D~wo*Q\zEH?쓏U4U8Vep0H8+HJP'h]z> H)	Se].4?})g1j:]G-QHouSjյ-d cg4tmv
g:$|0ʊaeq΅}'Rp^KPB`otZGZXgux(q}!d$`.˒!g֚(I89=5֝|Nю1ԣg@5a#Brݣ+{$q蜇@ v/y`?VZ獵Vp"z"r.Liۮᜣ'x4H,N֫,FguZ
!,DֹN8I ې'Go!yހ{mv;عҭzh83s΀NO>Gy%J).8C Bp"?:<R86;99Gwn#8YkR^d\. \8"ӵeO@){BQu?}Z7- pƜ266`Ľk8(`B-CGP
,o(P@	lQ`HE@ ܤB8Z* BeʭXH))eZfE4J<p>՟ٝW&/~w=Bn^>g*Wd?j4HXci l'{1y]`{EH:ԥ;7/}}(X;=X<Wy>3ւY"R#A~s<"IS\6mӐsaoIRR czl)q~\I',RxsgNh\neHyZ[K*C8pW ^qDY`\mGWoܺC
 0P_(u":fjdӓbathL)Qd s`ird\q"tb   2QιǏy厒r*ǓwzrjrƷEcxwƓN>` 뺲&4B
G|6mJpN?;=9yXw-y7nO7oqtջhtttExl׮\ɒD
S_h9"BI.H%iPcSJucs5{`ynMw.z-?B#@t6襘@D:,0΅Rl+7H3mu}ly6_DZ۶:ud(< "1voܺ}tG'.u|䈴]u!/@"nDwCU H^jUvrD`=&v Tuu9'<sk]uJJTDB"\'p<ޭh@sYx k6kۦZk3rh>޿wG;{{J
Mɘ16KAgI!BJƅs*2{ z>_$iaPm1286 .ݝ=|(ٽr>|8Ί<NGIq$20HSJi"9g5uYv]v]6Qy$#M\.wq,hw^{Ι6f6~ϛ̲,R֙mu׆k[ژbM۶$A)RQ<ª,嗏LϞYk=y&dEXV1KT/.uFwFwL!ΕRBJDZ5u:g1#Vo)9u4{^d.<Zkcm>ybHR4OEZFh2$Q9m>cB0d@;O]5M댱LJZ 9BEqGhyD&2˲`Gwڄ=H)`;ހG
1͛w7Ƅ֥-uY8׺~Gs6xQq3ƹE1d#q<O"6m;iN/,ˊPJsD: y0! 2Nޓ[3 򞘧N;zwb)P(wnP˺vh4X@.8>~5z4ȓ8RD=C5)NUiG#Ƙs.iYU*=,ϓ$=<ۮeȀ1k|UjR],ip6:Al66foBe8#"k[HЋ?{uSC{)!8Đu`΂B
$M؋iXp@0ƞ>;KX0<9}v6Fqw>[Y)i3ִ]\Y)SR ;WYB%8ŅDo~
]B~8{˿5³V[qM0$BC хM*y86VUM91/"Bz`|m:ZR)!UK(RrggrmƸ%0[  '16zY>iPsyw^}r1Ӛ
0lIyei֙Mށ;1Vf+Hy	pݽpJ֢#CDGP&oγggmBFxx.7$^>v1NӧY[e-R4+<R4MMLv$CY*Eb GJy747u駟ӯ}=M'O>z:)wK[k7wIZFJc4Mvݽ=!RRȈU*N3.R)u}aWo޺}jNϫK$~~ߓ:X,ȸ'K(UU=~`o1 I,c֭qH1ƥRBMgh%x':Ll;ήK fطAa*&s9"x
z97 炋9O襷bb}a}A1X._wm?8$@'RUr0][+W@@ɍ1}-o{7Y}NBS:% 
n ;8s=!#r*VRXߣ'\ۙeY󶩢8FGygu[8I3!RK})MDA ضꪮJk=7 ֹlӟ|[d6M׶Y]ڬV%g,"sH.$2촩MdLN[<G9mlgx8dmˌт 1j5~+W/OOǓm=9~*U *NC9*4MT讫\.WU9rx(0F3.ꦙ/N]qqɲ첈r:~ާ|482] QtY牺fY^Yi(	 IRO`eY'ٳsG1$]-xo*5m&;r==r.7a\TBxӜ ~kkTcMQrd]u5D ;%p8䃡 pAsmIPxGF;骮뺪r1/˪n:kM6h q릩*	E|\̓z%˲tΉoU5tGIl)R$ۄl/M0``',HKDEtw<՘t{t=}"ͪR5[Fqﻴuwwvv˲lx%FO49ｏh4g,,˯yGHDg4j@B#ݹ}>.9;>0Q(@TM

)48kkϵu(NNO#eQ֧Ⅽ^7@d
I|^\kρ`&fyD%4O( b+ϯ^.:4BNF~ V+KIP(jVwQ)ُ<`п|1s};W;+캶'CfȲV(x!ĴQ)ZEy'"l`}  E(mBV\>2<eBXkc[R
B`)`ZHb`އFyZ
"&iYJ
R(S!t͵\d*Ed/Ȳtwo`Ћ?3[fE<OY[YyƯ-W7o/y dc>ĩ9Ɠ:S\g2gP/Oa?_oGIw
 ~NF{)XOE{!.J^˧}qLg⊳1d~0h 4 ioɈ$!УG<<::RN;?:VAj[ $zx:/FihEwV.BfM+Lbʥ}]VuAue]nQY ! jNB cWg@P؄d|
Nyn(JWo_ޝ,V*u&qeD5
*hWhdLjٞ Bvsn<:ry6ywLcP'JjLD4Y^O~+W.onm$*|?GNe-- `#CW7k \dm%sat::mi+5HR5jZ2,Kc B9B>x_`4:z歗_~95ɼ,*$6pnpg|>oy#u-(8'PhVm.WG$I11Յ BN$тnT{R{Kfg>m.	BØ}R^BJ!H'Fq% b#*	\4>J |]CU14/4 V&76߹;oMg$IbsWU5/N:aHS$PT(`DL iVefzHnV*dGU=
YڄR 8[;sGҗ몲AS\?ߘϦ7_xյuXZ*}i{{tz
P )A#K3Oe]z7ֻ@Tj#L:^	P(Z`bB֬1Z)n{n    IDATzྔy)CiaCvr>MMtյpUkN[ŋVVJ*<غ}]~݅Y,} {UIΎOG YJk:<88=u;ջ1`p}mŕ5̓hjw6PJ%S-Q*m$M3"G3!y+[ZJT J p"EIX 0"FFA
Z#,FfY[;睍Q	14:j8Mw pAJѴ\(͊r`4>9ONw̌(d-UhjVuU9ͬfy]9|VGwwoXJi5l^uxs=1)cJ%iDc.>5DD=q˟r9!A%`f8S&ͷ~z1Bxvabd!(BW2Kc^i}efJѼ(&yv泺z~+MX &JCYU|战  y "
9osEQgkTJ٧\.^4I|aЦpw筷qεۭN&Z+%)S^JI!y"fDp޿0MS22]޺z2@J91Ǔh}s(`\X%e}O)5I7tlĺT|YGHT !ĖUICEQ1bmU>7(D`s
`(nw[kI&X]2\v'i;ω*KmLQ9`y>ϲk%f/|_}[oo_y@H\ˎgDٔ_q6.~|Lm I7E)e<W?|BqI\l}'KVG_jq( ܔYILτI'j4rN $jfӲ @cL`H"2b!s!5
b%/AJ)D/"hr.ri֚LryDC0`Q>tB!bD%TR( 3()PPKyS/٣aB0o/|2iTKFR
% )2&
b^[B*BYb%m|N#pRlpΡimꣃ;>ڼpy>y$K{/߾9Nc$ ^][ŗ>+kK!,gټ JIJe\-&di"g	`ĝx>X*04Ib]h
K[D	)^ߏ:ĄvS1@BXzYBȒḤN &սn#	,Y+dyu8B싃Āipp/3EX? Gh2G8paQ(г|QUJ
T9<zX̦٬$˺~?H}x%U Py\2IxHf!9/Q*@WsOJ(@"uY٢(V&IE$I=z/B;|Q㤦?;;<$&
ARn;_}QdRHRQ@Z-r>;X[[Y[9TUGJ#!Jk)Dkkinll<~`d4;WG3%U,Mp$++Ĥve:̧n+K{VNkB)D+XqcdLRݻʢ_+ܾutt|z:*k,IL&!R+&U&|iV&$g9@w;%12KBBUY;$O ^(T

}TEMD>0K!,WÕn$UZ!Ft%TJ&	 﫪N't2
[Yﭳ@LV5P\(V2HaZȻE1b*P LƧo~^/|T~ӯ͋j6T'VR)|suKGHY%
7>y*MuUYJ,dXz Bքw㚡㙉} &%e ¤$fkkc}}Si3Ɣ|6تJyQscp%53Kc>`OFf> DƠ,BTb&o.:HE  "kڪ㝽ã㬕ZY&Ƙ(5i8bkkk,ãZL)I%ix[`|6/*˲;{,˖wo#8:E!xR F*D8` P	%`vHۨѹHEmf-DEDǚMQ5`v_um뫽vk/kEnd6Og<'"\BHB]DRJ{@)iwP%/\dRk\~ČS8qǗ~އ|:8%YEIg˶gn!,aHly7.OShdb.J0ÝSOE)*( 
!feYU]B6J/ 20lꚄyfF!9,`(@L[cELJJ`e\\Kl
cal6 B)5r`
g9R.BU!Y0Sm_|s`tSE]Q7nDIFZ3ϦcF|kZ!%$˽Lub:|Z̈HLλ@y+gQ/?tյmW^KA]U ;._y_y3JV;'P0wn2xnb	ꈓV+B0ӂّ9wt7>7._zF+ q%E| &"wYDƴZkւw1AuA(qvۘ:7rIP=+7#yKl[CBl=Ohc}}}mM
bBɲ*/Y&⪶FI!#fӪ,v=|ĈN?vڭ^r&1KD֕50))#"EA"f!"lA,yB}uO "?Ķ(O䝫*C庮Fãc)Շz	G_x:_7`H! Ѡ{ *no/ϲuU I ])	H){餘ϫtr2HƓd2\-R:&n1y|Zt6;:YVv;o4˴j$r[ǇI"PֹHVj2qUŬqBҋiM't.4ɲR@TR:NH!y[r!YihØ˅r6MNW7" )
0H :鎂wY!$kۃAm};f\JX J!uUt2Ox2/kh%eʺ Q1Yfl*/"LiQJ9|$IT-^l:yw ZI2:/,@Zlb8Kv?Lի^WJ	FP;wGSx 1M@bF!tumן{ d7Mֶ{}mtUJ@wrsA,i2G+眭k[Uu[K#2\lkkYUDQ@,3hO<4" f
A+t>vvwfyH,gӓd@BLyY{`1L@J	̢QH~d:	E#`ea^B
J17I/.Vij*_A# eUJ(U"[ߤY"0vB0γĴ[`menn/p2EtF^vӨ\U3pml>v:Bx:8[[__}S~|}]b^3>o4>>j/|@1~xajHx/*C4(SeA "gOsò	y+fz+W|?`_@<(h$H ,+GDRB$`pnL"LYUUUE$4ZQ ZQ9@3D&)2SdXу	a8xDB[m>gRG \@"\U{j~/ Դi*{;D^	c3DFDNg)o;>J~+;KYYUuv?l6 6v0	s@)U[Wו(b:_fc\`]'מ/_w=N,ھh;4Ogy|i{K
	 (#;B3<y@
)L"9u] BT||rr2M^|v;<co\'y+)0ϋtޛChu"şh<ܽ?M,]͋;w߻ʕ#\FLs%ga>|v-6I?L[l:;'']>ԘumUڪb;ʢt}-Y^*)	4wP e;7`ao6U^6I_o^N'3 "@lK;
RP|h 8!4p8\__J;yY&[b^VʵʲyW_Ey|r|h<ڦΣ"p\U(Jy:~p{WVUeY\/D!kg?V;>e	3@7fBD
`ƭ;i+o|~eu~`%Fk%c"#Rj$I |HumMj@-PiQ:ѝ3J!HF< GVe\.w|km43cҬNgG߽^Un|}$"]g"mR]j$
 y=[ɪ.&^pN:s`N_,8/]iܺU5
FGt:eH4
1&,hkv^?9=Yw~+_p|:!fFR\&=Ng|1(jkWV{4IRGyY&;.iP6Oãwn}pcpNL!V+OLH.X睳1HDUUJX*1W遞LZK/s,¼wޝL&n'oeIhdq:!b,&*"ZN;ғ4I=ÇU,;9t=.Ee<I*j0"
q2ܸqZ<q@!Rɦ̍\fZ Rh")0{砡!VRBɉ{p2cVKԤ65Zkh5),e	J)Z͗?wacve0'h{>Bny J6Z?~ɲjBQᠯZ?g/}W_{-TY{mL'%k<|rk䛿_B  j7g}zj3.َ3 8k
qzЀ򩜻 Yts;
uڿk_}wwvwON՞"BQǅ1
bR(L| J&=ߟG٬%P)fK[$MzWNd`$B4E=  p`lșs6?KG(
!*Q<˲]ԋIR..XBJT*
,0@ Ĵ@(Jvj|U "<}L.A((ʴnRԨY]>zxoiQ*)ì(zWD
m *K&cUe$o|.T&:,[Zk1G'[07oo_xsoܻwk6:ݞ4ѝvuk=zi6Vxq%
Sq *R;aRT`ҥYL<Zof{do0|_Bd}8t~ϧ>tТùK)t4Ku4UCdKPzK&֜zfPjeh6/sփ2K"4`obDyQR,iya:۪bl>O\H@\*6,y筵$DU[SVR
e91ăKV7p9GG[6_ޝ۷n~_ZF/Ad9 '*k罏iQNnei)l,2ejLbt:/(n`ܰ ,kiCO{-hummuee:9efmcD!:N1/nݺ}7
.`6I$j<{竪<OOO(Ij ;6V'?d2#nojy+Ich3!myaLIZyʹ@kaKFʫn4fF>ںtMiKm2ʠKDs  *8[EGip`emmmks& b<Th&&?Lܾ}ټtToo_H$1C |RemR	)R(U #]b t{- v3޿W矿LPPNw~koC k[WUPB( n^WH"PQ$Ͽ⯼d{o/o޸ HRKL2\?b$x:S_x,)x)DYÃYRW(W=/$i	ĝǏyկ|9Ŧ2
4[hȀY|Z%@s cv-%BtzホeU[YTgg#օas T ̋VJQ4ar΍fyYˢvN1
\A
fGb&OJ)u&!UQZk·$1x Ǹ1PVMtTRYJιj[D)UUB-;8w;R+.8oND'\(OF~'___xc}:n]ip8`&`h~Vo)٬4Iʪ|?_S]ZYǆ?Kp.g񓌧2Wgrʞuh3oI/3KCŭ-^-Glb'rТ,T f"JV_rywl-Y&i&DNXEe?!Feރ{wwbnkLpFFkt8677MrqG/#XE(2L@`^Q䝝ϦC4pRgObޔ%r, p3    IDAT RIQGD " 6gr~h0`֚t}4N
9ēTir *myＹkVʪb7Db+!1uY<zp?wsR*e=nN-ccOjB񳗽wƧKPG:8>֚[y0 fci񳟽ocݾsյ^ʲHy܌ )I O$1:2e+b"QbL{[n~h(K{+Wܺ9ge ο@m@Eυn$	K˅慛I#Y/H)N;\M4ϳ-`
MO6(W5c]U*i =tA| x睕ZE&` !#K3@eUg3\wI:k)w9bT1farƲU OG'GJdp.1$ETFRBt|ˈJ`0RLYU(QJuu(ET@PH!G"v>ЂRhQGGE1/^;o#B^$1T#c;'J
[WY
A!L! @i+y;N;N>L93v󼕦ibRJ4}gw !fcJi9#
!%"tRELc(ɻIӘBt3Dmp68|ā򬿲uI!ve56_Jf(rgoh4:9=OdRi+R&Fk%ck "((Z
ِJ~_/jo@I	((`ZnMRȪ<xgm/Goo_<OPtv;( &QI%`}K/,w2Z;?|`k!(>:À_ u//\Fv" >&Np<ί/HA q&RΝ{a$isjcfN#7<O~ƘՋ.b,ãǏwb&p&6iBqe8hsN:{:Ra1 P}SH Nr4), J v"
Ge/4k9RY%zkmD!M#O/*׊d16g[Y9&yaRJs^+y!% 2`UUd<4Mֺv1e&sIDb+K{pu"^A	Gkdtz+!п!:MǇE'}?p[k8p:ݝճjK"0Q@Ov ȁ(>0>GƵ<<oX[NUYfif-%e>)44BΣ??Equ,"ZJż?CCoB02hJVhH$@<23 Wey|p0|K_~pt>/ @[<ysm9 J	Dh&LeQ1`hEs?I#Mw  "d,"mho$ILX5@*BP1h@@%ɏB9g9Z%Q-\/FJq+ֵ=88k_ؾpgWյv[1jtr}w4:veqs{&IÕW/\~,˄ Dl3FYhL"#]I2"{^?W֛g3<w/|˿k}D܆S"!yh{g	꺜sV#űTa.2H3§b$n7\#J$۲.SOl%޺(I8J@)&(fއ(Qڥ}13ۺA*/RD.,(4,>;h8??+o>p!p Bx<~իb,E*x46j#+y/9Bi:_~o?oΛQcR	mᝄ4I,T "}t9 0r&Nݺ,u4M<nFSJy>|FtHWClj4miVe1{h2zALj4K)_
ɾ9f	 @Qh8R`]фb7w!h!
 (&vl:N[$͙B$S6{ R,77/^I 4TH9ټ߿yN]UژpeeLY[D%ehe0bV$ibR@!9 jj2}"򵠸GO"c  L ~Zoe9'(t{7>)G4Q{ 2r@D`5f0ow/_zYG޹.lo))CQRy1߻p
W| ( @y<^{BPJ;W<Q!`0IYVh46Z+N'{޽~ZuY bbV$)y׵.{Rii<Da8_vtǄ^QA?21CÖxZY2eYAYVZHB dFl>Z|6ǃ$)Jht2?{!P8ZiYʤ!pQeYֺ1yd6Z"
])5 )$X!7wN ZkkuR!-j<N'v,WV5Q''i$˪BDpc$9jeƘf|>[[o|ugtj`$&r˲2~xTXi)B+-xyX~N>V:qVa<"+7:{ŃO8V	Ύ-XB)Եzl]!B,	D =XG"!e$~ߺqj?6a}skB~_(ɳˢy19	XV(TJ
e#c(v?&͕PZ+:Lzg@ܨ8!M4I|ھ mhg|}1>m
 ^!9%x$3Iꊙ'RZml޾ud!X˲  (Y[ޝ?7o5DYvId0+
3	Pν{/ʒv3Q{g{[nwƤBg wﾭ^xW_yzyUYMf3O,"k@G<! ?ESoRG7/+6.vIJEg,KQz	eYߟ8{_[kvzlS\G7U:Dm*Nb4v	A-$IY!iTF&L"fy+Jm2Pյ$iRi2:0H!$9O!ֳAG;&II.)xO1MJ3b y&SpbQ0M
rADDALyqWB~"?kP0s0speQL3<.HBR<4UUgSYVfgG'J,ѩ։$JGV&|6L&qY[iūu9?<85Zb?dm5QDNy::a4K!K+WUUx)uVWV+kV&Fi#rhG#%'^}Q)e!MI2ȵUb@)-$H%Bc֍d ٪*(ksHֶ/F)
Q+No~YQ%ںQy}QQ ($PJiT$  
I$i,~.5-4vowG?d2,f% U֛1i{|X(l:;A/??::̲4۞J%Cؐ +%t:׾vU Z4 bjo=jk9@\4lzN^߾pq|:
!(U}mUxtzK/h
RD6vDgo{as@Yi0ƬV3N$M>$ F_rҥK~* PUӕabF# pXPCwmkk^[]Zx4~wϫl%2L$m99*}px2̈́i"<-F+͛j8+NIIb^e $(%3!xRsH*B`(50Z
B@uRiEYUUpV!+eeV*ƓAIYw߿tBztj窺ffMej?.{77E[y}[o/?IC Zl9S_&SN`s|͢g).xbg> !EO,c=|̓4RQ[y1,ZĲvK)t?0I|'i]wr"+r (`G?;²(Ut;6S`Bfso!4%`\pqMl(]}T?>|Ȕ4)"$Ik}wx\1^lh_!2mteM~0>@eM$ˮ;s]kuUnuM(J$-cIFC `hD^HvkZrmw9p_DFVUe"⽻w~?ϾV[\c`b}$	)ǣ!{Qt +up;eQ~痖 H!  JF78~wݾ7Zm;QVgec!O""+=!{u4  B..<q(㏯]$H0PI;ݥA7'׮ml^ԥ˗+B\UZB o|n0Xzy)[og,\z8(&l:wo'V:*R݄MGh}]05wLݛE$	"NDQl<6Cz'Ps롨\xk}i!{VT!(mzN(MWqgi6岁50zizF 8! y
9TjeEV
IXcjT 2NHH dϦ,{SUZ"2-0Wv-((&"FÛ}_TyfY;:!TN(J#Bz$V##m)*[9"P$M;W9h<ex޳눣C )ʚRi (U%488fkHw}wy`7$`lJcjgJ|^V2{N)DEq6$N$I4IpԈZL 3
gHjسu`·rp9筵P*I"#y>:Dql4فwUUyVyel ϷK[kݥebs&(<޻(򤑶$Re)@D 
D=IdGBFű֑JJ܈ "2igw{o:͔|CF$ҽ^o޾usuuUHR)U9^}~w~эZd檪)x^}~ڲ7
*w8n@7~A"3{vY;O[i{ܞL!ZeuÃvE: khcm࠲:*nBQYSz 4mwKKKKKFxo}?0x,"fH d$32хu0!{RP#)}uA`Ph<9Cfn53/}ឤd89te<	IBѸp<Y(#s.uQj<s$$ȓR*41cK	.TJ#'HWӬn{?{mhmnn aYIEiJGY[[p4L._X
	2Ri_{?|w_yj%wo͏OO׿'q_A<(߄I< <]p6{13fq\(b2 8wl7GZWU9vHC(Rqh6=Celͦ1UUV!3P_0ٳ6ou~4AgN=C58M4[f9=cX?g5b	g1Ok! ]Cj7	9cAn2YZ(B4 MStO',_3[k=k{v8}P@:&4/wR̹4Ϧܹeg,-ϚȞ\~w޽fh2sqmƹfrR<uH`Ɔ|OzBt2M<MLC9޸iCUgm3ݥegt<F{nܸ~ʕ+W^zQEQui?2sѰ2R[?e`u%Ѝk?)|oXZx:پ̵1&Wy ϧQmln۝(49}~wt[xy>mp掀}AI 3s:WEZHGr$B"ϜuJkJM*c{"&uvHDosڠ}c5BH=RBZEQud+S"Ni״oz(gDy\UEDb`LQPzGwܚN&iژ(u2PZ}HLKJ	!<3 (%RVG$,svd)99DYk{#;%)Q'Q(UQ3iA 8˦{O>2{f"4mӴ$R"׳D u8qHkGQHGAZ$	U
	 ,GD!e'HPʡ5u5 KYג"-l2Hk!e[YYUujgEYN&ÇwFs>m4G-	˲*;G$أRHPSh
!F3m6(內c(B__ȳoNvZd"%EQw+:51$(IW_Z*yMcLY@Bqs4(_s>i]N3 i:V&MߝB~*źLj^NcWQ"vyQvn6"VUݪ,Tp+)*Cݕ奭,ϭ1JV&1Ӭ(JPZԵ,RRFQv:T|0 ι8RR))E`[	#V!    IDATǇ6	JǓ,L&STYVI,+)*gA LYVز,$ªÓòj;ʘNӴ&FZ
,c/ޅF6iDZbFU9 BJDR)0hQZH166!TUHe,|Wcc]$eYf#ͲlX`
(s3/ P,/2un4om;`fזxGlcd <(%@@x&+NIbVCz[|	it& gyfIn}Go?xB
U.9+ee11p&J)ցZ#iQzݽH4'ZJ-B- @IeT6[1<{!
&V2Ϲ}Fc 1O-z:R	QJc;:4Mjp|TRzb1:'m4$r2Ok60	B,=s:``F<!re=I4Dĳ%iC~|tp+ˁ2xw|'~.\l4蜛N&Ƙ8I_YZY ֺ@Pí*s *QJvF!٪J1ޟt&@wF*`{wn_}K^|ͭ2yYcq:q{Rzo?svSjP'.knNF#:OҶA%zX,T8w+?^~meug]ؘN'isܹ}+"E\ug5֚5^TUYdW:j78IF$Uֹ)pyXJ,C8Fؖ% LBQU15Eaa)l
 <$(Ze'`0J@ވt\14֕%3E3әICDY˻H,3Wē"Y [o;7;
d3Iʙxtn6c!:DMEYM4HBTh,u;rA .L%Eih4bKNDńlƍsukLG9s[ % [s"JJ)"E<gVq%iGR =&Ù"
	\  q&A H$(
sT,њPd.٪gi`*,2Sdl+$ZZY;wVF\(;;w>pLV	 UUU13$QB+)$OZPd3(wVT #O8қoµ7'C!: {{_y饗Q0"XǍW^SW޾wN'	1&I}~W^zv(TI,g*;XQ$k+${&,jSp<x.|񋯿ǇY6!2{]%Jʓd2?}RmY(4ct Y
`g}mgyueYkAi$$<`QJ핕Օ(!{[U@FHDhv6A*H310 "eZv2N[&fJ3T$ 8Bs~C:/4'ITV]v>8ι~Ϝ輛Nyumo[.IEk{0r\ILeYh ()BQ9gr\I*% tzyZ @$Y_^^z
C\9@URV&Y4x\Uee,GIjۻf˲fyfi:6^~/]y¤0QY]랇 ~v	AkޗY]9svY-G)x=8cgL"o=yY-
oF'nƆ(R@`o[Ƙw?7ތI$֚ͭx2N rZk:Dh2;[Yk敄`MD#╤}bݙN'FIm$gmyY,Yj#
!3Gܡ_^  $uSXgo5ʠu(u~:䓑wF*m02̈&di0wd+;fpf3xvf=6Vn6iι@1ej&:J>_޻sgڝ.2Lh}s^K#fhғ$
 *P8b˦[]{$-*@@}Yn?O'YhٻE_	^!	G;ښ<p:o|/3~SWx{jǑ>`<'3Ⴐl/~sq@H~WyD2ƎiW埓Rno_P:ʢ?\x_w}rk2"fyO~Z  5aR* e^*$Z+'{m
B׏Gx\l4[( GIo<<9&hPdS缊b>*!fSQI:>Qwn~{BI"gy`'[gJg4K[@gDYrkwӧ4"
F^ s:ُǣTZǡ!%r@fsUݓ ƣ87ƺyCkDwJɥnniw0N"0?g}ػFZi!"Uđ2o{~!BdcֹU*CI2(֒  8IJ*-LHA iқ%@,p:ѣ,f2%p4 hPmUeg1g.1  cCEM+Z[NųFkOܚNpv+:7)A$fI|H7$If;u6^OUBZϼ_!0Όn2Wxcu!l*~s/|'#vuΝ[[[䖞Y)"˄@YtI]8o'! ;+$> 
eM/g􏏪xrtp0>9tYe2~璴Q"(ΊpeR)M1"$`<pp*VV!T'J6Rlq  у;4m2Lq9r@]PFeY;{伻yz=[c}Z]]ʮ!d`Eh<ͦ P:B"X {z(<j9
h<vՑZ%V7zN+Te!JQGQd#)CZs)"D#-Ĝb-8. ܕN\FqOtOn|t~HHJi!q'mtZֳ֪neYy 3N8zη4/[w 	yFÅ|g4_wޞ ?ϼʛ;8D_:ՍOeo(jB;{`}/F->s>NdYG7nDQt||ϻoqB+5 W*i;kkkRE{sJB uXkʲ(iVU!'C]ܝƀ1SW.J)du|tZYdvwsk;.R'M_f	Dl!@irJ(9/LH(`T%qZ^؂CŽ`'<mH8y(?-9"Ԭ*O0kBOHzjD<Lvh(0{@iBatYLS# 6UUe6L'c HVUkieYi*kLiLu)L
3wM3]VL"Ͽ Σblk_NC"!kAuTE"IKe5OzAys/˛綥Xn+L'emam"ޏË/?}+s8&.` ':E7WV` :w?O|`7iZzPk3!Bt:R!DRq,3eQyU<˳lZ1%$"0<7&'Q?>:<؏huyCiRZG*<DcsnIl4V3c1_{S-0DaAy=z擓AYIADDF YGϡ@\Y2ycf `G21MF2@BTBđ92Y̅PZ+$qG۷n|O~޽O>{Z"TJ:ՍsnW+iP4!RE
! AB,V
v3'J$ױG@H؇Rh%J3X﫲N[F1	࣪*#]hg-Gxj%4 {6J+++6/[M# lkqwOBP`aRHW 'dJ !-ԉ@[ֱg(M"LmD<e_[&HEYZ͟}wܹCs:D>yO]Q<@B$p姮#Nn$RVEpVt(JF"h4z.]|4fAG:<,GpWuz3 4ok}nO =Qww[[[J,@J1B9	"ٰ(R,?qeQt[H)("Bfo#b#MZvv:2 8|)!a[k$OۢɺY 2Sqݕ岪PDgݽ(HPeL^[Y[Y#ĈXh<!ēt2i4	aFS2xI*$YeכN's1)/'ngdaE lV03Xvn6鐐J`0Nti繵(
)?	<B/̎])o@TWanTf<3Z(lmeEk̕9Bkʀڽ~+EY*ʪB.t&,4NF꽟L;$I$uBW_zG7~gNCŬSG{tk8]= <Ca䙗Fy9e<GܶP7겟  3D65闇;bRg=@B3})UhTU?XZ^7I
R\YYZ]]boo_j ιd&*S(5֘t2͌1hW}ĵ}LqH)[/l Ox0?K_SO]fY y`	>Py-D xDsZJ>i# l:0CNnW+)<{ݝC ;fEwX#><a8B{>fgū@ St6Qڈ,rkMg{3Z*|ttH$$$kmYVUeUuZP춹CRE^L'YQhpp*}ccʳgVBFqtڵ{?~FgL<=[2q݉F}YZZÝÝ;7%Q=l:fwܮ*O$"AXd~/4O< Pk3!"zeY' 	dΊRGxss{gwoo<4/rmhf^W3ARLBjU9MUL84!WRx8|8Lx<;Z!(7BY"k;
v8ϦHT6y6=SJdp0H8Nt׃BHcMY؃GtUh4Ó,bukf0]DS'L6<dSN0h8,R0  msY`-v|Z`]_u
ʢ %ϲPsIja 4G"x 0c$}>t{^_*(I ]:}4m @QTZ*Y> XQG 8Md
RA`,AS
ү9!RI#-tOê,QB* *(RRyq0n(sN DQ~¥ͭՙ2h|ogERBwEYԟB
IB*HASXrYku^
i1˳.P=`ΦY[oWU5~ 4DTҼֹ͍)EY-:ƣs׻ʔ)R3ACIvi*lO?sUH lj/"^?Ëw޵;[O666ʲf[H+zVgn&IYP=fCR^':+S[W/ܦ"㭍f%*chQU;,cEmBfvӴ14uR</mmnGJe<eOD UUEQph* 9|jaY)c' `r3;#,kڂ\CCOP`OrѰ֞nWZc.Q P>m=f ACSIZz`b&өT%{_i5qo}msLeK9k{0UiH1F%Qrr
!#qe^yqݻ{?kecy?OkIy[L|L`Pԫ:~\u ]Y,~G
! ch`5.Hßx&iF`3p00Uemg8d79#JKFZF!iQ5F _[Tv2͌qPB`kt@Ս/^tg^}HLJt]k̍~O>j 9#j]{kjRTHT7l< 6[\f48i4Rޚ:Y`E $.,--%ql1U8-׊IȟػZ1- (VA"Te.T,tH{!!bP8iD1[k,3ΑEdѥ(12dH)jRWJy~||s^gX
RO{kM+Aem#M	qowwvGȹ'MH㚄	VQqi4uygSw/ʯ~-0 J=ܽfxuifG}w~BJi k1:'EC"xΟBh`LNE(I@9ؽakҹ_}o>}?>*S^k%.rA3xyckK%B.(ixo*1ðdLYUw2V4>;}YSIRDlagY :ʢȳ4fϚ*8NVH  (R뼬8o#;dB$ju[4ॽ?3߈37'6""y뜒?,rgM $O5.g=y-	lsT aނ    IDATgAW2c׾ \+ ɝλNn'ϲF^>
dkcIS!QTg`uP)tcD1_@
"`_e]H#D
4O7"B(:mvv<dQو%AJGQEh8g-sǀ!3M(TXYYxa{VyDBj-$eqWU	̞FJj*k%#'jy&oκF;Jcy(KD8`KD!dQ4ϝo}˿c~&O̥qV֚۷n?_e~̤C@d8($ 1{pF*EHJ<>9.^tj1͜Ͼ^D_Vpx}%UY@6DB{eǯtZ*MU @{>pXV鍍_|(:REb)#N&ysW8q+,uom|OOvoonwg+cL^Uu16d:}A5SUޱWi+~BкxBU.|ve./>zQB*"OS۷iKaB~!ذg{UԥJ( p\泱'3
AXt:t颶.D&z>xἔX*xvJh p;*U{5.Ak,Z B)ke^xuWiʌc=GΚãdpr|y9;竼hUUOy֦rfO_Ƿn=}
	Bs/=ѿ_ƆV?g?Noّap<CBY:tzz9K05.#DFgEvA9"=YJ<Ͳ~i)e4M@$OEAD'^*AR9>:8_Y]Yj:Ͳ,MMdϰ/^y*HOz;>)i3'_W/?',BwB\]@$HJ sB
)R`?Φ(W<t叮}ݻ9gx` }ȺTBJDrޱU>ƣfG3;=12Z|dy1{b 	8ϲRl$eI@xf<H]޹I0`ʲmMY^nΔ;?><C bHKmn2<ɳ:B@"}GGGBH)s~	|Ww!I!{44I)׾/}$+Tiɧޑ[?M>sVk<y-yRk1{selH"Կ?<(2LӀj5>lhÝ;Ó, ) l3/fv:WlUYI)8L7|sƽ``aZfB	08ͮ챩*gf5 Çv_q++ hҴD= qe3X9),4{w?y7b
DB$
YM[YCfXkg" 	c1+åR3㉱.#,戏o?s6C!!R}{wfgsnǂK)17;PH\Ox>A85k/{J*d( 1g z΅1HHc DRMB,ʲ*4m$%tDqh	Rt#$1IdF!uX?|[%		URk)ߡPR  yR  n% ¥zkJy2dIDBx|	TU؄9m\Z[Upx|cgw?`8*R1d͛>GzMs!K!PAH*)X4G緷_}Փhv~]^+SfM+i̿ewhgg2VA
a٧./|_BӮ1F?ݹ}({g,	)޻wxTV6/ pfD1xsc]irA]tcm]X
*҇Mx.%"%~4^PVUOǣ<"o)7#R[4JB׿yw.^:'iQ(ǓIY?dE#MR!;1 {n4<zGUeΠgDO VR)gw~J=/Dx([k+Ik)._OwڭCIQVVJj1 ;畒uҒpXj[͍ե{v"4]YY}AUUVc{s]FZxxR6/`IgyQTlHW/uZIG#%V&yQdE9L8^v?G/2+Hzsخju
?1&E<9cqc8k}zL3ESbу_[7$G3`3M$1e0Ü	tK&`{=}j`Ry"N'J))綷ˢ'0#1&
Ã奮1&˲
gsG4I.?ukoB$% AM&~ 4+}g^|RZk'4f=Af X	Z<Wz$;?>[f97޹/1`" 135y 4ɳIQ|z7O9tf_}pO]-P4˲
&iCi!RF 2+X#eT6$-u3*(u&<T{;>1UB9ϵ2ƢYID!SdӢ,sD"z8|tﾭut  'xaQ1zPJ)u^4MN㏮Hl?n6R::$xgl:/ 	#8V<~_>sKKKa؂:"pZ89(qf0/hD(~Yn&q/l_T٠w{^h8,O|6Qg^h3˯~}Kdp8vw{hQUS4iA?g-\+p@
(kep:TqwK l6v`	#:γ <eѹ-)O=_UaA#nA Dg!HDZcMswc!>`fgM5d<UJ{s #/tE [?<G?QJҎZjw76KK<dLC)1@/\2lխ:PRxA8`s؀JǣI@HEQ9$A  %I٪ȋ<OPYJDBH%sb'	!4m6V]tV;J =\hʲ#-jJB  2!;ƚaٱ46s|w)De#7gfyYPMi`BE.]_h|c`]ɂ ޳B߸ŋ.^̧y`  PHDB`яeQͧ~2`o}իW.)g}A<Kҗttte27!+W+Ɔ&Hvprp!!Zk,w>}͍,g'0	M{Ȗegbkms\H﮿eL$IHO  I#2.@-ihnUݺwanak ndcfo}YiقPZEJKkq׬7^W0#
0& 8p8zq6sssIuOU3v!J^k;-+
7B QZY~t:]).
W_h㎈9ǤZuδRp.<?;w:ثJI+:'r.=1eSċgqjysvRd~'˕JVeYT*Zi^H)@zL0/2Y,J  85 `0dI)ZG a`RN߷ƶ6\ 1f4q.VFá&SR+I$N
dfH0XY^?я7^yUB@~^{tF&]a^ԅ$N(<.LA.m8ڜ_'  7ErV0Jm9"X-onIӞz֚x|Dƣ8B׫ՕIsl"3c4En1&3Hp6,.$"":7oܾ6ZJ/9m ('GiI2wBRx_Z"NK r
biەZ=4>ǏajU@. NHCV[k5: PYZ` ڙh"]i1X_ @
>ʲ, QƉcDt<" 2!΁7_h"|RE6r;Z)1쓏ؿoq֔kW	!?l(rZs磏>e:Iqy0c2x4D@s.LuN{R J(ʟئi#h/oln2.IȌ6i爾*s1(kD.Bq)&1=URHjWդZoԪWx7|7 CT<♬3/p
e)~wޓa4JsakHADtggΝ;=:SMR09=kFJaŨcuDDn\ZYJRm4IE90sȍ. (,W t~c,se `>I[BRh81hqDZ$[9g4 8gUpU!UcJK=&X2?m8
O?QWnuzüPqƛ sKJc\{g<K@LhM褔BrAt ցն,ED,cE/71l0FJ)0$a\0Vki:fdCɓ87ssF; @ ,MG';i2ƣĤ(dHə\2w.11 GP8@kc]ZGqQ})ͭs""[2{G֕ͫWրh4{?>|E0pZ">Y8ζ,)(Eͳgy pوP^f!2'\\\w,	OgQrQ7$YtyMcd1)ŵ͵Gu705ɑ3fp8Y`bk}kZ? 9 <kg8))脀XAg0DgG5`1ϲ<K=[pVV~I!sltpppzr)c,Ni:xf2<qB!+R'qfכsw?<<m[突 f󝷾a\ +v6~wv#GgO6!ʳ=S.öC!\pCɅ^Z.^;G|F}QZ68IZkׯ~{ܼy`J#PZY^(ߙ6$4+U2WWVIg8|^ISϒ#0%D=8RJW(=x=;[_]}Ko_}/׆ӝݫ[[ǧGY^7jz:0\]Yʲ?O>n>\X"IĿ_)MSv(eMQ4ܲK?wƼ4<?O L@^\.,. ԻŨϑF~.6 ww ʖEGyQ=w`UJ"s81lkF[V3Pzshӌ'|-s6J]q<>><<{B[p偏q@oXkI039Kq* j-?FHq!dq"dȜ(Qdje&N i'N~A?qmϷk	NF@!*"K"Dq!OޚD@43J9@4Fa0wYNDZk3XS&o'oBJrұ
EOkfew8ܧO ECZH[QϿ~7qyf֔w/ ]LBܤ!8?غ8 "}yQR?dYY;Yv ҐqbL[o.qz=Sy9o6z-+W߸qܿw퓓\ip5JwFAvo\vͷ]Z\Gh,sok>NONw<q:.1sOK>SZ|VP88A1Ε*:Z\xxՊVoT#P r"/   dY HR׷j̭	ΥspYk}8ɇQsV2]ʙƁ/ D *áEJi!%@߼^J)J6Kd%eM2IByZ޻{B$Z(q[׮^ȬVk)2$ vQ|: 9BPAP 82ǌ;9cb\daI΃04F+'u'q` BH!kT(8CDA eRgm}qBJ"Iz)0do
sRZ+uȲ4FnG~v}	(6X=~t'
J%u;d݋?<nfEZXv
$gpo)^{w^``Dd*mu2ƯK/@d)MA;_ч;~ Rzmc>7'¨9) ƒhZ/-}ݝ,Z׃8ɔYژIZ8gªRY r"pXnxq~V+c!:ț=(븐A  ;Es8I_Qo4<;99%JcmJпgE'	!<zx Y*duuy}c3Vx>I(V d >{3_DTU|`XceI+q Hrks_|	m&xViW*˿kV듏>rIYG1 @2=D:kFkԬW\jT+8Jhey9<9wtt` r~qZ_qm0U+ygYvesK6W8>miZ?AKy7Ff-)2m=z32㋵sqG٧IߤGSrr1^NI٘4+8z)ο0qV3Z !dѸk45|xJk؍=|Py$\XXF *$J</ȑ[9Ɯ$    IDATkmArΝ ZkGѰ-/O1I%+fޡ($[`nλj0@9Cybh;>w]Ef
HN@y}99YZ^~zJG>iT0b\H!mg}9k5Θ	N3/AaeޗWS5I%h;ܟ""By* Q"L4xZ*ٮ2^K<x"/gg\BQgɱ'g`y"FqRVȚȐäR@nmwώ^>.r[@ ]ф\  MX"hc  ;j}+_ӪNPV͌/K> 4toݾy4h-/TCrC4GD,u@26lEQ(UUiZdiUjZQՒJʍ7z㣃`!垽mʟv/ u.~֕^{}N*!"xw8I(7+kko:>:><<<>::8;=9zڔ@ٱd\.tsn-(U4ajݾ
e$󭅳GD
.py%URic(}VKMS	΅s#κzӆJE10]'tZ9C_)%Ly|yfsNL's/c64ٛ`N  s;۟i/-/ 5\TT4\{sg%a'8#,WHd@3{/Ni1#%lQLF1(*
  P-`ZpAX	Br 0C.CA,8#hzҾs?b82&p@8G(m6YQJ"ϲ,Mǣh0^)wzzM
# wOtP퓣7[KZi߽D4NWk;G7FO8lGO)"Xk0Ԫ/~oo?ZEAp㏭+aH} 96f5E+X_74 @ITq2Vk7|pOc֚0VVVg++Q7\ik-Gf!B:?|D#e::CX ^cOoη*`"$d\JyQtG^wFyQfsieya587	KLD΁AQz}yiYGC!80~pt|px4Pʬܸ~M
8,+qv{Ƙ8I,	g~RQ:z}o7\0_M;S5Ɠ3(DYERpey_I*Vk׮ؼ/h}m{f//GqTYm3 Jk."{^IN,KBիXn6QmnmhmQY0Z+UǱ#|}mZ[K`ueyf^YCaJi.AJѨחON|{"*U %]761nh`{&râDenL>._ϝ4(.rf94qJ4e8s X]\0Eq||2"3F#P>o<};EI1
2O@FdkdȘFkAq!hJeg}&(R%WskӴZ^ren~" A/ &%y"u$8ӉpD)ڥ!?iUmnm!{wFT(b"0LriUXRٌ9k19yyOMQĞu>0TI ȅVE(CFxȘO<EKj_khaGR,-âu;;GAj='".DF3uQV+<㹹y,,Rcn>"!EWjΙO*=?*+3,1XE<X[[[o͌+WJk;Nd2aꮗ;<vᛁ+1?,=M9rV[Nʠ8#Z0dq0d@hupp>=AjZh4Z^--/~htrtp'h4" ?^p!3kƵׯ\fun)e=N!R..-FGǏn{6t\d)L9y*"5c?Z?h<K]*lFQ p΃@ǔe1Q@D @1[7=`oB\&R|nZSR;,1Tk&%2QGGXgqBRZ6}\@:M[g ˨<^W7VWW8jի$ICWd\3Po]YX
M<J}s2	LR b(srJVOA3֙BQp!Am9rJ#8քj1!B h8⸒$,q"@.+}i^t:ӓn=r1)"%sL9kZFimT"l<G`4b:no?[WCc̀񈈐qya:-8I"IF}zWxs 8!cHdɍvEQHEIk4ׅr{q9ӻƘ|n\ڗhf
_s/jgF,..nmZeLnlZB@&Yvl9BƢ(^_[Z{^\BvK^.c,Ge8\yp\V:lOM(vѪh4^'eXQ C$  w>B+W,/-0,gNX#ܼU 〘Eq,B4R4 R8=myYE1]<K]O@*^ %9*eyjw?n4ܺ5l[_ɡ~ݝ,21CeӨ5K>eVBI	Z-,*XpnJu<σ@:`	`vRBT$/T0N8gBqcsH`b
8&bB-,Nyo1bEx{AΞi M\U.SPTbl6} Jae
ĩYW\uW7(Ֆ<=đu[*qAj[,gC `Usxt	b!"""er* 38Msgw~ ΒB4T3z 1\aio5s;luY{xxP_\Yی|ok-Ƙ#PYVkK#84q`&>a҂Κb8(h9r	LZKJ)AAADӧn8[RSV@zZq督MVBHB֢"w 0kjSƵ$d0N4O7&Dƹe*CF 4SvLy;;ytg:GBNOɉ=єab t;~%u:&ʘCf5JQ@Hasn\J9k?<ˢ(.Yu֌Q>=l$z^7_y+xtvr_Ǻ׹MVRoMJ_zWjz!'ռZBqB\rιpp}'w>PRp!e.`shM9;<Q ZZZprNp 4ENqLDܨŕ9D(
&\j</
ECZ/%Ra pP.LrHB(gQ s̋:[YC7͞كO!,VM	h(PJu:kjMJYdn'4:BG x~5c
V}"gR&qJ!kt6NqR(
0Ă:"H2f<>=s#Z8,OAkU"rxH@JOჍ3U;8<tҼyBB!x(/6+\vRJ)eJsmFJYeYeh0Gcw<wt8dΑR,}O~C!xQdę6Yj;H)aR}uӻa 3w97>iqIYo?O߯תzoj~GWnގUS6$0A/ C.82&pދLʰ h1Oꏟn?"G	sN(.&")TŅr	;"(,8IT):v?xxtVZq19Ǆl-._~Zei<ϓS ̌
8ZK\iEg?`8:GJzk~#"!v;E&q$F΁("`\IK=rAc/,a<S 2ΤR4L$k[2vG'Z,/llmܺ}?RCcL8J@FQhiT"iB.0+qAJh}jXc\v|Q(yjJ(eXMZȐ<{v^x;͊f'_~</=z:߬-ϯ,9GssMgv<{eRHjمXs,~w^h <QtI2pJ۬/Y7{|INAd-1j-S/HaesYq_?lm]#B6o]IU ^i g,+٫_\\0uY} %"dERi2Z1Dr6
7x`h8BA)I)?.AgBhW::7`6.LA}n7~Zc.¤ĕ2 gIA̕cZ猇:gaP<c˼xΚ0r!yQ,(
}"RM9gY8e˳{b)H޶QR HkB!rGȳ$<&ˋzc)"稵kUQi m>rNk{cKy>s*UAÇ x5i.$N0GR	;N7&1h8s8Tu#K֢C9D0!Ykm, CƉXHBOiժ<=mO|o]o!ciNGó(I5֘{]Gvv;cf^	 ,s1֚g:xWBqWo'Olooi'd賀Ӏ:'d DEFT*A\M[~ar.tX乱
@2n:>>K3LJ!e9W"$Hkk܍Ώ083Y	'L*FVM"X3)5xLNF&-{9"x$.D<j4676}"reb9G@|-I?DdE@`h>ZG,:BUakMQi*r.eQAt)D9@<8+k9 F
aqw1QV1^$͹!w炠C ~=;Z+D ,;w5Xe3(
VkcRJeYgYi<ʹ*h
 8u?>92!䥍8❝;}"&(/TV(cb6,UG_Mk\s@C[R2GΖ@XR{s@+,_iTysFP!/`@{1fkNpdad!ϳݝ=CP	eZcu\5:ϕڕ^yeuuu<1.D;8<<:<9=R"J!&qj/,..'GvR$fW珛\lͷ8yV8{CA
믿:77G g?8;:i; d1  "I2ϺD~֗+-/U}e}q1gCn	 5A?y2 `GVs2רﯭ.{A0VX4\pqzeq7ެAV	ga
c\7_֪9f}8c8OnmnjȘ(z>0΃ ^eSEt0K@|{|12Z,h<ÐI0<~FTL2`SRęz~GL.'Sy/ow'fLv?s9q`2SϏ0=ѧF'xPZxii(NTQNCn8_Z^="G3@$ga6Oȇ❄y0"BqC:kіHAEJ0FB%
 h6y^88R\6_Լ;	|1^baN{K)\
ur|W7FVm-.k5"A4FTJF+ct%kp&q BBN
CحĐ7{ۈHE6զ2#dpVn/׌,HǤ&ksky"T=rQ|EqE^xwEkaa)szTLtٺr!"2yw}ҏkVڸ3JU5gqIZ0 Jp0(-Io>ɦNAm752x*S4iy}9kXk ƹ	NNONKK0	XEB]{n(^X\rF{Ax
 R[X\^^\q՛ܸ;vFѴz-W_O*բP_ܐ;9rx3QRiZW^uýݳn{ۣXː9u1o8X+%aR}뙮`kDG4WnO!
!d.qciIqC|rl!	VZq$c"gcΖr0e=Q35M($MDXTQjRcG#8si',(	IMq3S)Jr>M!'Oaf8yi"d	N<Hw  0p+)%Y{~V<%pFqH)UR(wr.2/ iJJyyyYQjV@g^d3ΐum6I#dJ	ԳbN9Ӭ\$wFá:I%U/Wf@
qM0i^Ҟ	=Θ_6GD9GGGǝi:9,˅02߃+}n%I*޺HQ0/zv4KS)eǕJ^6f$u흝CЇ`{[rX0}FZ%I?ٻV*cR޾uZ*UFkIgg8xe+7\R~Ypa3 42؜..Ϗ4z=ژ'׮_]ۺo9]~OvV)gj@/:    IDAT
k6@T&Q5BXWnGqCd,s4I7qiAgH$O"Hr0M4ˤZ0I
x;)s?k8cadY@qܿwƛ_xа 0 <;ζg
.9kNyO.Y~&ĩ7.շs8qXhm8gs͹?mUda4yZ rΓm!DKFzb
Vyd9詎K%Y8O~ojy=wDFk)p9YHgG'"cB"2gABd\D :=>ʳlnvӅU!dVX_[]1ƜO} r}2y='	A	*C>vaܯΘK8a{ɜED4ZAsAq.=G3z`ȘߢJ6KF\)yh<:ږ9CQs!(
z<h$IitaRE$d~ŸPY6u1Ь'L"q F@$dxDAF3.Z)82LӬy+І1(YԕxciezgJ&;TٴRyBm3i>Mr94y1 B0mL5ٜe3쏇^yh0Δ*Zfk@*"/41F׋(8Nn~׍*N۝ݧw?ӏ?9)LkmdJcz/OWM*h,q\(9 \7nDzΣ>{xh":GآPZ`B~TcaOTP&믭^~VW5YB
(/TEVJ)UU7nzE
A	4$IP$Z%g0RJ)0/!c[FrW}r~R\DΨ^t{^Y^Y2L#ul"37:EO;wz1?Rqf%I-B)eY6i3e Q&`	Y/ @ 2>m%ffdB(e;犢F'p8ʋ1yWpe S%N%KGUB)"ϼr:,PZkU<7ZK`DB\{o,-VxDGeZ=gLTa ƍ^йDk3$:ힵ{7^{o{}ik/ɓC ~vH"uj,礗hb&!cX9=@<\^'Y̕Zgg$ G$ aܸqsHG  (Owv=xfXj%krZUZw{<Kɑnog^TJ@VqqN)%d>|0Bk&2̲TrfY'ie&<7@r.,Ys.q)aw >Ss"g c@rV(twln_jw>4?fka_?/1?w޽dHȂ0j5:'w0 ";JDV_s֨URO(z?8<m󼰎W8c?Yo-k4Xk!OwVA7EydY5jQt{g جWgllzؖRj1KF8>Ҝ	KzϜ40N
-E+xC^N ]4#+ZeTYY
Hu%dϸsgƖaWAq%&c]QŬ+";;=zh0h>|eYeK_7	'_yW__Z^A(9A|NAdc0&G/!mx4JF+Y:BEquq nݻq67"IAu8$02AzXjJyRnb_m|2scX2!BFlLY:5ь	9zTЪ1SO  W9k='c"DBJ!Cdܹ<ϳYF#TF}TJ  *5ƹVj4y	99}0BҙN/o-1g HSrps:qΘF	`?fs6([Z9v3l&U>qXc,γ3 9.H74kO{NtyyќCJ11E JiD\}uo_|[;!eFZgEaugAxE(n?̻=y`g{p70ܸz[ΗzDy6g	j|0 ԫG ͍7΃p8{8gfZY䬶8r|k' cmalkq/i3D 8aAP(ejD>W+xj׮
90^DKdnnxq΅0  R\! Y  I*QYA/>"G$w΍\y;ͷ߸-(qYs_8TzPrs4@qVi.nw0f'em r3ZCP'9KF5Yc	(IRo-̵()sD4t{p0\gEa(w8j %#d.XE_
hJhQEQ(e{_ˮNְ3tk`UER#%QvvwIv@#@7/v[@闸i[eeŪb,Vݺ/s*R#1	wZ{oާRJ89ag?|o|nYZH_shqʅTupV!FaP%",/xdbT$8 !bi8/A$q^DQtVE @ 9?ZÅ`yWUY׵6M 1e1 e^$
'GۃA?rY)kuZVV#}ʥ^/m4BÏ>^4j6^wunw(g,˭ᓉI=DիW(A>~LGliy^A`"@ܯw}4M+Ͽ@]~wQ,:0,|ZmQ
yK'Fk\rG/~?poot'`\8m8 /]OƚkW.e9O6spKK=)%cśQTip4Giu+KӬh4һ?Oҫj5LۭMޣGǏfi$ݴnj6ʛ+Wvvw>gAZ+sp@)z1Lx
R$gܳ|pyoN D6҂  AtT9Å;CDd+7sF + gIHeaM>LL)bU<qʵU[s:~]jѳ7nZ7_[_xiˑOHVI?13."Z"m, <0Y+׺qMZۻqN<N|w߽޻hŭK<W*ނΡ-aP' x""]% OOZUU2H%i]dh3Z'd|QpO|#cB e`ѠĽNʢȕcqڈDkͦ("<h_6O
FOu(`b;8X^]Hk&ɥCS_LmO$[kR9<!0Ew)}!r&8Zzшx1Gڌq<M`gzE:	&XmZյV8IFQ(777{ֳ>7GUY!W_l13T/x8Y6*p2\Y[oZ^|ᅝݽEwvw	14pʘ1&/1	"2ALXl:/ߟN3QZ@H	@Zi?o'#X^]pں	ƞ&&Ș..s$|Qra 41\IݎdVȑ'O?C`SLZ,,Zc&7n@!C `'(2AXx%qG=xޗWzCT4,'8gKKQI&Ǘ;׶>g=z_i,D2B&nt(fB09#UUUY^yUYUT];k)3ʪH;*RZim2(cҪ|.m*lUvu4P _B  mhy0} <H^AYrПLĝf3Z3:lrI)[V^Z 'zXտB)UV66$I)VR.⭭+Bod"dq{ͅtVe?<4֎Fݤt:V+d-Y"I\G0f3:GrXA6FQlQ_3B)*vwwvRvlVj6@leEUY63Ml8Gri[.)-Q(%c7EdJ 6֯?sMke@UG{G2`9J25ƍ?1O8ggE䬙ɑ?BD<rQX1fqbj^yNz̿({w~k_ES/_o3ן_GZ)+iq!PEZ=m!4-_gj]+O>slJJUu=>Ǔi^:kh8%qx|2J Z_XWy訪Viirxp2NҵՕ;wܹ{:axH?c2
im:'{g*<-OBp#$2\]]c"vr HpbTx5'k1 	;Gc|GsE( #
g\AX=p!o4hzK+++ݼJk_S;	.sa@`^|BDgh&%*v5Q8}wns 8Oz~ۃ=6/^ ISU</H+䞀@"G7}IYG}7;* QQ䌱s'"<1 ϋ匱0Fq~ryHB0
E
 |:ɦftƣQgZ<q# \tjFv>_k^DGI1f[d:2N֥IY|ʳgӣ3TRp鴨*RJoą:qbηtn~5Q=2+()r@su:nWţGvG @uTJj2J4<
fzY+g ,V
'Ks1}G8DA/\rsy=~}hlX+QIE1g`f[KJk߻!2^rkןI) `;rX?VJ45\m]gF''cXQoyENTcA FMĆК$ȅEQd)WęOɐU]Y$g,/޿{ŵE9C,iyBΖ=qb')<)cVʧigEmnu:Nw3RrT;*8)36h^@}1΅h;vđo5`UWEM٤|fVڨJkMDЧ`g*c1F׵wJY
sƘZ)Oa|9ΙxɃ^t~sc4м\ʺ*/%qTUvc}nI!⧁F%#RvFd@Y]WAumXkIK!gl;~@ 
d	;Zn>6[RU~8Xk>ɠjol|s̈́<6`wwg:qDD={'9rDv$avV
7f2ޞvyVGA @]`4.16/
Ef'*u'Q  J͍NQ</s.[]^><'Og@# !%bQ?.0`?gD5M+'i/vy^ueE<0Ϧc_}kW=Ҋ_;x~w~_~}w": TGBHe]%)E&I byyXey^8Y;]8vIY],g5,/EYE9fEQ^x!dRUeBL,&IQ	Fq2@'ow{scX9X?<Y)x%gg-s;<_~{h7CZs=R"6W;a GI(8cGb dO'1w~3cZOyQ1TuUř%μaƀ3Q]1ϿI^TYI))0
H\H99CpsiFpki9XxWe'$L[\i
 Vq#;;}&+Kݺ[W9 tZwWpjeNvYyVx2P'"k(XUװI/s+tQ:0m4vhM-?y|i \)9յ'nFȸj<te,뺞NFVk&OЄ|tCg˟!" Yk$+X ؕ
IN&y	e֥KR:i)gX[(ݟXkE! j99 A%iiv)@c+h<Ә8JUH!Lʰz8Tuve邘32XBX4 k]UeUuO'!øj5)g՟gC􂟲Vj4βɈ
!|{9YPgYGdg}Uma#gaQe(כskg hKδ~-ϲݝ$m!RE& (Uecg7o>w5n{aէ
@DFKκv6T
Q۝Nh[b 0NFZ[ZReא3Gvdi[8#2"+tUH\dƟoܵWU5JV޸b6> u䱂#[ؙ<dVWUx<dd¸]Zi;I @]deQ;!ra,j?vr<^ssW(83(z+(  C\gGeYhc2Ee87sǹDcLg*+hU]k9U-UJ9jkuxu !wr>#r߻^q`8+ Y	ވ(!^0gvpV<m>36:ū5^ZKUYcF' B&qE1ŭ5VpNHF@g2vvp&l    IDAT@d?<ں0WFpg-&8#O{wOiڰ1b|v+ 4ں$PUiTv13^,>ypowyJ%iQTu=GGjGlyBMSiO 8ƚV>ښUJk47G	GO[.wl'Qh0;X[[GOy(D rAo;G<X/8{6wD| ȼ$yY'S0k? zu;&D `qHy!3DYO]O}{6?/gFkwe|f]YW?GJ(tf?x\/܊X{U-;/,$Em]/{[?^zsaw?|ՕkmW{ (|o?{tnsSq4'd<" O׶l$d2}^x۩"cXd`!Yt\s	FOL>{cxf[yO+#;ZN솈rq]XjUf#kNHa 7cJx2LȚ@Zi 
4~uܢ!Lzl[DpkGLÚ'}jBɄ>apV[D!몚ty.
Ѵ֠Β2F"dRV%S2gm`m<cL"!#\sX.O 3@;`GYMx\ P8nd \$`a1hF4Mn&kwD>¹݂@(eDq9'"(`8Lx&-G$CDu^ٿ1O~sieRVW"tXX2fx0 92ƀ	l^a8eADQaEqĽ啵յU RZUjt4,0!9q^w޿֕vޮA[h:ySCGhRz[cR6*2]f(Fs!9g%G}D4}lt(h8<,ku:bf2f9k#gh4Gs/qĀ8F#N,\΅Vgy\ 9$XLsk+n=?}p."hscM95Z}[Ͽts'O`F=2FS+5ΒY]Yi;Q 8--[r?+ݱ1eZ[ ݾxBʼRopy=d JZ<{d!GBTKkZeQdx<LVjv	B8F2BJӟPKnV!g"*5Z@DVzK+n QHih:ғ|6v 	.9# ֖UUUjSu]+r:/9gV=:<̂-	.zH~fݻs?|+_sƒrv/]8u[Iۉt2s]◿DQUO*Q:1&d 9YkTy"hӦ*q6s\vj]7B޸yxx. 2LJ. 5Zi s@j鳔cqDjtXeUxtM'i7d@:!8믏Gco8z0q=!u=Ǔ	cqDaFCu*+,gS 9Htozꃍ V
xaaUu$	r1!:Wz$/ƒƃ{Vxj@瀬N^QkcJBZ) I'XmuSWJ$wxD.tfR,/*=HDiys$|?G?W_~g?wp8XZZ%IZJ[V(Krv:Dd;EYsXVVV?kWn<sE+j5?i^43׮kw{K+	?|h¹^;6V}Pn+˪v̓O>^algNfw?28"Hd7s~Mg!'4"GL$Moo?<fGdba( %1EqttT8g~u澆rW#'6\#8Z'9ev';]&͸sfsv"NVuhR"cADqD^HkZ Z#y%NsiGDn47gX> p<*^T=G8QID pqFkT$2o0tr<f  :n@huFS[23?<rG2eAǑңbCUU, 8Χ㺪F	)S5~>sSw̛ړ@*uPƼuHnyyiwv_(oz`w:1G9a>uEUey>=2Ƹ DNP<ϲhŅdsXZN{eye܅s6;NGeul4G2* |៽֛hQginK*U p&+8)DQ1ȁ{efQA0=woB=IC^RTø0)Sb1A aFk	.5dEAIV.0rsyx>L\kf/hmukc@bE@vg_omnBJ2>E51]4W0֖.:WJ)ku.saZsB6O2O>_bgC5eUjc<mͭ^k3 UVt煵F0 DEe)&k5Fk]EyyQ  HfnZqڐ"8Crje,IֹѪ*˪,T]cAi]Ziay6Vu6<T]1MQl)zi1 8!J"dj겮U]kOFievd^⼁> x 36g.D !(4mx2VVU׻y'}(%wJcݥKo}^[kAƌ9gy]J{QEi0B"lۼr{w*1=su;ݺ,z0)(6p~0_ۭ*a6ex4,ic.^[ |xRJR
O
+6t%G9.DƘR,2F6@TiSdd2&y{ImƘ)Zj8m!9B'~3uZ7n6:ã>~n5uB߸* +'\G>L'q/BBb@x<wwv i6\4N`AHb1\x:8{Qgxr'6Cv@#g7Sp6x__k^/?|۷w^4x{/uZժHHAR!{a 88
ZJ3h0X8Õ%52f(Be9rKh<QH!D P*+hjB9uFF+@~H8m<ia|≧xa+g>5oD'og&f@P8-p&6זaU+ԓ"VK1='xPdp8:<Wjc	PYUÇBD)lwƐe'92>Cy<ߚ 2 yL#tDO"'BHΘvz-"r1ϲd8O㼪0(.(sx<gY 	
ʙp@	DD!W)pnq{~Ć'@Is9Z;`A)=֟g9DƸ?8c^y6Uu^V+ﻅn-Ͳ/"p% r0RDaHs"2mL(I8]Z)! 3Dz*ijv;m<Q":Br8 ƬwwE~/p>  lq\ת68gBHϴ@0%q̀9紱/~^غ|#hr!M0EY/4Zmzp$yWE^t:] 2 2?t	X	rCR| fn \SqiQT V,F-tF=%?5waY>i["X8/+ezAX4Bk8p<Yv'~UJt11B^|+_͛ksqx葼G#.GdUJ)T>ͦps>ih~UpKhUbԛWUzMK]V9(Ɠh8ʢum $c!"r&WsTUd<kK&nu;)`!g kq.dڐY6uJs6ÊpЪ,|B[k#0I[Y[]Y1fU5vw˪朇Re=dy`9k{ \ shUyW9cRZkmAXxecj/d|K18BF\Jk˽җ_qiPR,ڭ{hq,ԗK_4uo;̱3v:4˵1RNghh2:]֑ܹZhTd|cc?sޒsKz0dY{{=[[@`8̒$Gf.ZT=Gt26GGGG~YQv݋.nnnUmϷ	=x;Α1VCEa 1Vk]]Nj4d qZ,YfJF7M9^`4::<GE]WؼlP !P!CBfĮ2X][qѵRq$_ᇂ@
rj}+ih0'out74!	+0. dR=;!0@ɜPf]kַxZIqبS++"c,
Cٝns?_x饕8^ⷿ[/G߸~n,`ŅAQĹyQqiQo\]=+|ݣt2;mtZp{j5_e^DfmwZãt+kmlLu @;+KˣǏ.^}&mL@j֋ߏo.|oϜs	@b̙k|½%kqeuCi8
p9 jhUW[+p2y9s ȹ0E܋".0 r9=OeYouZr @ˁJu0 G9!pa4TٙSdr:y'i$Au]UUQEa)Fi7ZA#X8mDȻ&q>Lp03_YB8Q4_yH"4x9c~%u)81$:Hs.p0ejUԵ4ӒydsÖ́AG>"8;U85a6l?\]YuYvyw>ߟ)~δ|.yta	 R_("VH!e 3ΕE98:_ҿeƹ֦^)ReQ5&MbD(o+/%#Ƙ]YN),sp^kLZmLA!Qx488<Eq6f#M$f	5 `ֹκdrqu}?;rdb(%c\+eF`Κfyx<\8hu̇FV\Xi̸ Q??x#ugM3ƅқ,2@	-xKW8oQU0n,-/h}mT|zi *Z0N'޿h3\ߺ|uoo͜k(Yc"SeQEY^ cP3Ue˺!2e O? G*muUʲ,uihw[FDQ(cqp Z!DE*qRMrdt2ΧȝQZ&DW7W7.<~d<T'Y6-ねXK{U*UY8g88ZhB)$fK0P-q\"yOe%ǻ[_}qG$f_s6ןfuUY/x*A[^yܽwpp"$n=_~K_sId\U(+k_4ڝNm2A΀5ե7z~?}5 oH)Rȏ1fѳÐs^&ϲt2*T];`84TsQ/)uƚ(~ǏǓ"/1BV|.I ^gssh*׌Az2Zk$. uhe>!_"/ֳqi@K Ȭs/\~=<眇R~｝;$NFuAU<
+c>~k'I$s$/J"5YRTzk&a0?켗VNi%!眗HcPf Y'@R
	)9)"h07q?w//M/W_~ϿFcy;pj5ۭp<MӼ(ϔeX[UZ<x(p\ul(s׮^&w>|K_xڕV4&yY+'O|?^rEi}igH1LwxVF\U%IÕqQUӼ:V4ʝn==GIu<o9<2<~_: GǾ>MpۜUUδ7Č-/qRe]W֚xpGQQ\w8O7&89:@0(3!P\GshUYVA$gOjfW:3b͂vgLb2hnGMeXc@UQlw{Gt,8:X,jv軛gGucƘ3;-;O 8tZ9[A
&5"0uU^xK/5\),Jf$<|H9PC gh8\Y2k֊Y<h{r\?vܽз:ND>9`&;o#U]?so%C `@rՕnuJNF"U]UAIswDD  #9<z?~ ._62@抌!s1"Qlr!s`O"6Ok90DJ|BWW֪Z"R
εV`<aaF3I 8Tr'U]w:(|x}Mk#    IDAT%舂 lw:2D]n9#j`\k-f
@Ts.Jۛ_2cd|')}L︪M4[/­_|삋f,s"$,!DkM{t:)Fs}ŭ9Hi|ANf٦꺪ZiY?[o$h8(ҦUYZյVR1;  Th ,96Ja-ڝLF40Bx6G3O1F H!Ӽ)%7q d"LUQF]꭬w{KIHJj`o4U#.,O^$s>+SL"T]'8us9t bE4.b:ݽs4RJļjG֘8fY;#d:@`eA |󇯿o`P`޻ﾇZNYXdy%Q`c,M02.5Ès{?{k	@W^9BbF*ˋ˲,JuMGAsgR9z͵U!aTO:gݎ#"tΩYkL;
(ז0~3ZZZ))DGR"WdƓxy]W45 E9ʧ^]Ӌf`HdCVWWr Ip{{Y֥K/ܺeau&ܻsu$?|:</4˔1UFtkc 9r[9\CO1DDJ[@Bq`3'"bQhJND'r嗿R?񕗿?O<x|Kx6riip<QYVeY6) v:%$('V[]^:F8Lx> ª:#(I݃djqs)eݪU-i"ٞL^piD/+Le;ylӾIƿaI |AZ<Nn^[G#1 :m4(Ru]V1cE >E霧{u͠ 5ꚜ#ts/K RK@9,բV4F"!r3Ǔir^I7a^lM@U4|Z8{/crfltA'BJhɑ,&XP(ӓ@rpFCATYcݗE!YU}^3pb!A\҉_,% \Aq2","oDYChSWZP(̑y]OC vڶc"r眱h(z7ωnoϽ*")R$EբvgLf0 `<2f ذmnK)XdUYYU|b9g>}YUEIvx:ލkt:]?{7㏧5FQ?	,Z,u34ve錑Bd65j(Q,uLMZG:vGF:Ͳ8IQ*yO)H+%}m鎈,PHFx w<f0xa/.-eYjcr#vn:GA`~iyv00?[t6;8v:Ņf?Oa{|x縷(P`P*H
$",k}S&Ii&&%I
k,#Ԧ8&ʫ}lLGGaB_X|ᥗ~׿fYZ)!1&6DaflfNyD eKW_,.MƣlZ)WWdYp8'E9*<_ 6GUv6߾u/:So=~H*26.5 ȞSg"f|<v,')UfNӋ4h))QH
n= ^@XʢjbRZ+GXSUYy1TUE:Zrb>v?ڒHII*3FY^U5{شoMeL\遁!clY,rcjaL{x#+%
#c'ICb#]zk{_KY̊R5"Bxڄ?`UBRJSW6'~p	vD<<<4IίJ!2_g:aP Rt?k>N&}Zg7WVV挀WLZSe>+ʲ*Sԓp?ܯZ版yyy^x 9LJi&n߹SUe+KuMgTRIĜZ@qnΞ]vRJyo$EUUht4ӦZ(VO'jdBDwÂ"C^|왵$'i$ykw>3)t_zKٔ||uUmlllnnZ-P 8L㱱YYqeiZJ 164hh :&KJbВ'>|jO49 YuMp^7&BI_w~훭VK/\woݼyw;?=u,	M~<&q]e]o>NӤ:6 z]TJ
D$OHY,{44cxWe9+nH
rVHJs8#jGq2˼(pȘPFQJvn`gkeuma^=7g՛8PI{mWWo1sn(t;
2ٳo|+UY\~'o[ ;La2{%8Ff
q䬟qk4EDeYզJpReN ϭ@N )VTIHb4[Y;(BJG㩔Rh:2b&T0 !sgwi7,:Q;iq\
c'@1P
9?S!){jc$I&Bdo뺘};}㭷h)@!I3X
):)Qjrt<N"i%@ U]*AO="[P=-/BHSt:v}3g8ɋ`powptx# (ӄR)v>گ|嫫gΆǈ8[DQ ,@tuWu=+,/nvZұRB&k$#5X!

!LP?QsQYU(,MsGt2)fq>MZ,L"? pw'˲[gif[Nj')-QByF8`]U 0*%F ppya'`.ryq7tϾe]OxyP%koٛ<r{$.[/Gw7~WQbM؁KgcSm+c>ONK;|h
Y3Lw0ݽTeBM[Sۺr@#  #;kBیij`t,U$VJi)P)J(%;+<cf+M|VUeCD`Wh<yNu)tuK/WV[K1 ܸ6L,wyO4PJk )$ J#GJGI+m	[GGqY@)DJK,ZR4'rLLc>+&ȃ7ЬoR)|Q~g{t
B!XW P 4#$q,O[weeiP$
#xB/D
ĽOyv+J$X/JX i-% mwƣ}v<y$:E;}a&gBgLwtpYtTզ;o\Uu`Ǜ}ųBkc&IUUJ+!$3b._YYFOyU9tz[{{Z+(',|KOAċV7=1[~N+3U/w7|ǻ{~E̳|/_ti3sJoܸ1LWWSHHHY&Ѩ(e^i[v+RzgɁ	E	tTU['!TXȲu̜1AVs
=QC01I3@EYI @8Ⱥ"ß_D;IY7O?#???_oݼuه/{gVWO?_pam//-~q3g[[۽NgueeiyG=sneϝ][Y^~zo|ʄVx+/*D˝4MwzIQ嵛d:efqZXX@ĺ6{?ΎFng{gkiܥ^'SgOQy_+N\W&[ύ"[y:3<I'~._y񭯽ƛoޏnݼ%A1(bk+mAv:O[A#x2E<9@輯JkG^$K9\f	{:B ySW8R8O<"
)n9o9j6tf[7$A~bhʂL	 WcZ*}RYk%k9  b's	HJ	L8iH|2co~4DJ	2m!鈈RS^B0C~NMvibBy_׵jܿHdSg!ɢ(2&(h$vZR7n,.ꗭ|oo쓟&8wLJPa%ť;N=ƹ~uUNF.R* p	4C h<Xk|(VW(zCl8@&3^|VWb( pZ: RFZ'b&?vO6dfBNK./
D@JɴXc惍xZ7LwҗڭV]J2{œDL4|BPV{tOb2'Y]<f!jZ[J|W~7Us:Z=o|kϟڲR㍙'	O^Y@~cbg/YQ]4'y`΄قu@jo+~::hwgWAlo3	hi,K9>P!?[ )$K!:J$vY	&r	;DR&GLRGJiikk+)(,.{NpJq{ww`*joohMm meJ$V'I$5߭CXB"BpBnGWUY:O bo,DDY/ZWՇ~W<J؜0 Of@j~Ç(eY=ORHD߸y뮟9SuYN>s$@HgQ$q6V{E7,
k{L"XK-dzx09y~n7`з9g8ǟ_~tt*k;pLf~,3{
UDIݽp2z&: ms3(  # q87nNǫkg^^뚉ZYfQ)z&;Ｓ4uHf?`2uڙV*ܥW
QQϾ[׆iGZvLgNaYhP'IAJ)$cSJ>mAc`8 F&e;[|w9 _YpkÍW̦;w/1G{%1|~"ieW^z׾un:Ϟ=B&<V,/->ھp1ۋKU(޷)yo^奅V/\"ѣG_a9<W,⨪$M9򶪪(uYey8l?^?c` ka$·À4_-_0>8q+x4FUٴgIZY@B~H(nݸJA+C@P΄|UU9_j0X1Rx4N@th,DR)=GJt>;)!*UUpp/?AL
穪جF tiM_+Q;gݞ;UeQWE5mrIoFDR4˲4 9q͹BfQcR tZZ)Wou"+8&'|]yF#|;3;SEop<yn@UUUeTAK1c(ОB@g%05_ss>
*Z-A&Kt[nw`/$:Y^o?84d+/s(Y꽧%|V9y l7:qDD$2{S{g;&R]t;^7 4x2'ڙ`)冋'!0p9ȻX)TR5n =10B
[ıJ	(#JD:vvvEJFGQn=l$P$f9FkXa{幦8jZeYEUژF#*KGĞYQݬ^Z}A'ťÃt2)Yvr/Օ%-l6B=yjsyU|>p8d b~~Il,sm)O<3Ǣ=pa~j2O&>:߸{gcȲjcqYD]B9 Uv"9dJ*tIevf2JQ`XD̢7$"䃇P`a	wHMUNGe,v8M[n_X4v'Tރ{[7,yE Pʠy%@(MU:wSWUqR(/8B<q9^f=yp(⩸H6l>~/-@3	BHitt~᭛7C>_xQ![c,{6]}DnlRs0_XX0/Kl"YkIvW.2uH3֭[8Ҫ%UYGY]㈢(`0n7JR!U6qLZcTZ;N7><<<*2giqxklB(|&7m@7/peQ;݋.]|),oݼ9:6Yu˗.ij4'o'84$/Ǒ7Y,ʒ$ fJkKds,av$)FO۟N ͊y?7Q	B :>:<;uƍ/;wҥW~ouĝvKf "N%Б	˺tD,KRvn+%AǡI%BgϝI^TP<x8Ɠs"BۮIS4JR8 y@	VJk'jcgh4iw:Tzs¼zՠ	)p    IDATN,_~QMz:w4DDb ^Fci1//.in=ުR 41 sQ
!{'9h:SM# X^Y><8#l2YuZF6l![(D!bHN/(Tmxi{U1ED%%u]UYAv{Z9T@g+SVUUeQ8g=qSkvJS0.1&NxOv5@Pts&-7`d[Q  00y"0d:]Y]Jj)]|_yȘZ
T*XX|V0:1"o[:C 蜭ژZJ`﬈#,O,OEt"> WC42YNKg?__^\`)wgwē;h-B,.Rτi4;WZSgK^HQ)Q"G	DADZ$5?WwK..-峩=UmʫiNgy?x1!{ Y*I(EI)(zn{gf(B)R	!És!2R:Ͳ|6gX)㼔B8NҽA{6Dd1 Ey_N(O@\Jy	+FD%U/{RJy:9ȥ1ǌ=&3e5=:PQjw^xuPU,5XJts1d:͋2_?t?ܓ:ܺ98M|>>x4ƆI/̼N'wd♌)J`X3՝;?ژA&'RRfi41X&NbJ`
'/</<vk@ı;:)r03yH,p A 0{KD] 3{9LUUu]W#roa7Xqk){wܸq}Ck l]9"1/a [iR Hژ*M]5 8R",a̞
C)ְ:֓峜a"h|wc坝WΦ3":ixHԜϯEjff)%ʍ@
$[;GǉR9&vgZ	"~ӟ^y*+8:
q Vzowggg_
q]2:b0Ea+.]z
L!UpcwVW:FѴ"qnw4IsRA5#@TJFZ͇)O"xbilV4QWe`D (l]/+/{pJJs|MVWV{!2Rrgo#IPpqRx48O,Th[Y"C
31K2BS3@WtZZGQ$:'D9G
dT
D
5h@!ywJ^z7?޿e}}}VVyYRj:@+'Utmֶŝ{[,;σ~wEi߫ ,cN;<8}o#ե+//wnݹ7}CugVnlkZ(K0{')Ǐ_z@1=1T<ʿWΗS<}uN<>ə_@4fCb)`0ȋjу}<n(`rpxi_}G[:햵B&Md=g*[^['UU1:<&Ild@笭KD4յQ#쟵EƤg
6Uo/9sK(X(l:r:kq/ϦvV)Yk[y]uHRY<)Q0 @ Rdf򲔒;묝).$8q@rD6 Xm%ȚZ[Z+k9gHD 蘿EY6@.lϟiƘ4GB(HL{wVA 
8ϼ.T'BS\	\d!D@L]3sǃG?{w@m)׿r<~_@" x?_z$I$1֕lweK%(I8I'"`HPk=ӉX"RJ7ߺﮔ]^`])d}frvDTR<ZXkCf,[ʲ<M=y,M[iq(!6
QfiPu^GQ(lvpx/_	<2'3g'7 gvO_և'6f4Gh2MƵ1)$ÝRvkaGQspvJnEYF:䣟Eh4y/i6ܸB8Iʠ8*}9{Ϗ3&AppD?٧&iK4$n$;x<ƀүZ)e[^^qRJM!B)|oONj&҈ @$\cuX#Kz猱EI>ynwNv/\jw8(N*<~On޸Sk=`lNXJы'L9cs][h('T^ O(݇TREaM@!{
A۷oݺko$L ܞ'IZ{w?dZ<7Cι\̱Ld29::R'qjUe9TB)e(pcx& z{gG.$Љ;zf<OS"v}.\Z{kqeippY^8*jhRT YHG8犲J4uqȖ#u]<zݜ-MPyHg $p^&	!<XX|זG#b߼qކM;K'yβ+/kzd߻wn>X^^FDfБ 5
C)tT,7"dzo-.;T%壘cZM3!TJz_ 4ϝ3LNZ_[u+KH	G9@y<Q"4F&emBI>G+Pw?~Gxx8xܛosgϬNLƣtBDU]|ﶲtg*/,gf{W\r,b-Fi?n;ƃi^:8;3*,ZqXPYie`4UJ;-L)-#(٣Ɲ/S:]{i>()[aX'Y Uh<<Oh!0cHd PPNպ4`'`eY8m2!18qCc!UmWߺ,)D /uܘk˫kn7dzc]VZkn_pZK{ӈ{A̶.gfBJ"<;RJ)@488$٘yiq2lΝ[;s6k$l68p<:,,ZkN>
1p$,s ǂ,>|"h1EQ[\\DDLO)[SE>ӕE&O+@,m]yg~`q:l(P( 4Th
] SuyoM]EYW;L(Yh4JL%Qg;OhOV y 轫l:ڧ._pb1Z@ڝ_ƽa=ի/KQjVY`(QjeN3dRC3͹"`Zݹycuu^3eL*:#l$7;@y$Ç3um H0{
PZJV:P.Ȼt:ΤZ(ґR(usX!f qGq&Ivzݞ{J`:i7j<%F1/s}Q|!ENI7SJzv:l*"TUUVi[n8
Oa xG;{y#uUEq(C6G[uٲa-ZOy,{ABwpw?|TVUZǞZ˲t΅(3:N'NR4"Θ*
焜 2{y#!P{E҂v!#8w[WU]Y1Ue I=X\<jw"UYGQ]wo~vwwvg+bLZ9btBbhNēE4tB4bhITƊ&7s<27P/\`IV[ݽsǘJ |,@){?:HS G$XO PkpFyQeK,k,NƭN'MӀpL^*UV彻w'		!192dNq˪޹s=Cmq(zճk̜iJJ=#"Kㄼ{'׮鴬jFa-k YB"jcQZ8nđV0F޹(|RBc9&%'| u	@4N@ .{ync祎y?&&ck/*g!P>lcQ\A̶)Vh<.R /~ֺ,R{V9 PJ	J(PJ	!qK!Mu @4ZEU$A}Y	LQp^NпRuD~ѹ|Wά,u;4ί|;z6*N	myJhkgg<,{}-vvxVzv+4գJY8a&\oZ`Y	LfyZ4#-:t)O';9gU"{l `{/|/H?s'Y-cjgѧ_J   ui{AD,]Ie!9f\Z\zWv7 ABuZ'.,,.q*9gmTZWeQ7wϬHD! c9(F4Tl1 Xk3@@p	!ήmvueg_R*uo<(wZ t wFGY-/fȺ6E>۵+@T*RQ=9kA
I@( xOZ^?kSמH(58{lnd&
 :KB?q<)  biO.4`cӯZ*LTUx"y|64N[8@D/27
)3vp<w871i ޹,B.t4˦￧r* 8g=K+/_|;Nha0Xpg֊<o:& AJ?*,1QJ8B>*h"FTJo^̙3+AX$ (I9JGkұAɺllu2LL`@ZH 5'뼵k%2բQRH-en dҲqk]K4~vX$Wa>#=1UeSJGZ;1:UVD2{kQEZKD765lsa^lvtkXk-Đt !s~kk(	AU{De⢔*`ÅLJ)kpÃǏʲZT+GH),\sJ8{oؐ s4B&B;:$TsYNDmklem!Nno<XX̲F^Ƈ_ΎsNSjD}4M䄁|iB8qn8G5vh)8KsÞ^3Z  đLƏ=z1!	!<777o޼Rsj4Qyq[զ>bcsi!yڂ˲|"Z pQz
/D`Ãk}~VjOPm5_!`[YZd:g ZJcvwwȻH+cP/Xr9!9T=74MpK(t*=:<JJ!ܽ ZOրco@xfGȺ@ǁ8%"sa2ut.^ҋ/TcAVwojgH̫+Kٳg˲$(ν{EY.,, R\L'UY PGDN6"2LSDq .$5HbUǑ:hf`"Qۙ3k("Cb8{>UUuUUPd,M>|G߽}kme3X|;|usÇ`VTum9Ibf&q4LZɺ6R
XHZg7(K&  ƺdr0<zvTς$
,"P+VHfWi7&'繩:N~]۵q	Kls(yOM㫆S~NxxǏ.GMg&xSLF64ΞqVYO=Jh:y YQ^ϯ	Pm+z2H(iw_Iv-fYYVl(y=^N<yg̬Ej28֡"dfl/!e E OttǛgi7X[?+pεi./;k	YGkgK?zzs¹sW/_;QOܛ)lj~>:pCIDSPQ>< vtdʔU
V'y Ge'~_GQ(yk-V2`pH xG{6ULIJ"UUf
Wc'űBd0lR2&;YF 1?蝭"ķBnuHz~o ҳνD>FZY )Pk噙AJ ܹ}'{LԞ
	x'J%P޻o~2fͯ~5I$Z~YY7f3RQ^,ǖJy߸uY@$kSnT*k6Tf:˧[TQY(3% ˲hK|fCZܼsZ
C'q?wa[#}2Cu[G3@؃kD>p<`gw9GQEQ0 ^JE̻tJDJ`U˪z|,ʋ/׾⽯:e\<Y8i AElsh4L&jڭ8\m,*
r"b$.Y_O@Hb0.5uUU%HA*;;GJJZJ'Fu'xW[[kȋ(%Izsv+#dXkهӣaU@XNN!O;C
줅C&A0r~0SQH	8Â2dstHm+'F<VX?^g~뻑VUY>iNg{ɴiAHJ 2    IDATx4 t'pl|]Q,%Q+MSR){r2:je)1KM]{<Z+xIyq_7{. 'DOU @T!a=3Yvޝ۷<>~{˳Kܛ6IvdWb^w[YUY+P+ح!9F$ӈáidҌd (Mn U׬bv_DFւn}ew~9"rRr:!aw;gc" @Wpa+_r@2gaGrzo]7,TQw'aG6Jwͳgq<)xO~2Ni6˔5֋P饐t#Ȓ8dKȋ(U5c]e&DJO0m4(Uea#"	,I[[ƚ(ʢ[u/#Rk^46F|[v
I)gyugտlS^_?Fv=`ߎ,Ael4y?{TnQUzYxN:?vv}֦9{vssȆa6*m|.	'ә2 (j6HCQ!RZ JOfsϜeYf*h>9wwfnKJ辄o4=çDWDt ~ioG" 's2V 0&ˬoEDY mww$,j?$yQt;ӧNnʧC>ku,|6gYHYAB:kf;Ox̺d2?nXETTZ_'سwֺ]&vIHH	zL 9IG$S-cQ;\ٝ[7ǓI#˼,}W~߾[[i<F7ymn:l2bT[ VA;(M8- WUMXQ`={<Σ]L6,h66[vwZq`<Z5TXk:Oq{JJkLYܘ[-tr;g
!$!Zs#v5Ws]N7	5*DRE}?%3UlƓjZ5|A1Y[Z-%d2я~UgiA-ņ;-dFlEq*x BLaor+)`p֭_~l8v֭k_|ů:yԷd4٧N\['q;vs<7@X\Rc2Rʵ^icfS)HJ)"G]lƘ8#k-Ke3<	f^-!.VCSfg]:b]*\$<ܺ}ɓ'ٴ~q[ׯ骒Jyfm,"		p4e)ZUB>~vk]Mwo]outEΚ WzqI)˗?(ֺht:HI>ZgjcBH5 4t['O$IR "Lbp̎AH2զd:ք*h-d^TJIEQ@p5Q[3ϋy8;q|}ccmm-KF1{;nܾy`6|>붛iy@bXUgF3@!^Ò+&DvZSun!3!$qsYz^ 
[B?on;B q0z)!߻}kv3KV[p @	w[cRn<R`8FB"")8E~l#g$$VUΒKE?~$	J{dh
F$fg;u+_{5"Xq^ #\#	H QLeesQ+`X(<q.RJ;^Zx<d͎~˗GaUA'O,/KRQ'n~lc3Mb6NZGZ뙳Fcxp0󑒀 X!Q"q=Mx|vUE$ B{(g㽗${x2?eﴔL2ID"B2]f΃g
%Dgmp8˿~WZOݟW/{կ5{{U1~w,C$z=c݇F@HgOߺsp0+2">xsᥗeUMGC1Gq<N97vZ4nU᪪:TYfVTZ8N1;")+UqlJuv>>Y_e-<"(EV:kS3";z~ܣWOoqQ"K]V.kqr %;_=#a#Q^//x7 1  Y}k)$EYnzߕI`OJDH( DB(.K]yQTenwUUzgv}ic?,/ P"wNH)TdhQ\V'gzY 7ӧtowlFl2y.|>PQ6Zf-UAQ!'>D~upbJ7;+s~nh<[H!*(rr%K_B2lV
	=kJ@$R
)#4M$J,H6X!5_|l8x*PH6A$$d9:"
bfcQLL*Iǣ/|l6^F
=$UؖbD@o(hAREf{O>|o:X׍fwki):Z쭳]0 +/v{<1{w&V"%TRZ8Εlb"$ Q xf	 YPpAD$Eg_U^:gS)ɓ^wO^ԇÏ:G˞[3+˂(L˼(倩̳b!Piky>fE1wܺ{hODqhIg4Mr UF<z9띝ͦ{}s\^ϲc1f73˗jG$|nteRB =KU4['666͖+E"3H)cn[t6N'ZCSEAF"<Z㍶nkvj46{Go?}IX)$5V	3;cd9wtQƕKr4,GusRޣ,Iy`vj	`+׶ `(Γ^X0<h8xh{4Qd /w q9p	I)$4ޑκsgMi[Zkl'B(iA%ɭm?<l<G#>(	Gv#HRjh$Ds-& 3Ա l.g!{hE-~Ǘf9׫C #!ʪR?ݎ3#D`?ǏY
1/o~hSq,wml")CmsXsVWi)d<R,j XIBT~9Ql&Ius"2i)*
fgVl x2k7N+K8XBHH)+`n92q4Qk\Ʊ~7^۾{_ٿ~}uI!Yj39&	D2I<ϒh0YFc6C jC`kmYVB@D$DFgOg2 T3[;0( ZGdkltCCXvu^}[gbu'Web=7N[jYR1a*c9Ouʻ_]_%(	k:So#+/>gfM{>! O2azֹ߼~;'tގg2z7|3Ϟ~`oWWb۬8Ҵl$| 0cc.\yeA[^9I	&iMT
Y,(# zv fUO?t{JE:현dt:wG2!KgBgi<?)@RBHk3&LpQt؉CzV$Z"uzbB$A1	!TD@H!Ls9/R=H<o{!W#0J2
+tG@¦ Ua6đjdYpֆλK)/J"CB*!eض{ cH
ADκ;o⽟Veh6FFD4Y;qlx'";kQ* @WյW~퓧:ޅ';w="IFl4N:BHxG[mz(,NojǑ"S5PsDXFA软1Z[SYSq(Ʊc`SZ5"]/[,2Xo{*4K7^
W,*21
A3kg`c\>>y|tYRWue_ Ƙd\;\$f|6Veűs_}xbkiQD _=x  ˲?~;ZA%qtkO8p1qM"D)Kh6kEYy﫲3$B"ӎdrCY4h{cOmt:f1{gt4<߽wk׮^s$HR$Jx>1s$f,
]U@.;R߱w<z[;j	
QR[clPnv0)=!$b@@qDZ7jcww޽uZ7Y430Gq=~`F=:{xI2S˂,Y9	)vI"fIBq[[qd< @Pj!I8R,@-ⳐQ	1NӓcR048Jw#:D}{ `g)p"xgm0""Qzɦ1ԱYml㕼60;o=uUQfh<|꧟}.#%iګ7çƑJxo޽{ (UiGʔ N d2Ƒ\^;&H
AkZiq~[7jv8$:nW:#괚I!pelɴܸ~</zv-bS^V	I:&D]Hck?O['67b._ٟi,qN69gOg0YOvQZF#d.I3NJx@,<BJ)ȁ/+P2</HJ#!Hk6#) ! <_`y=G"Cӽp_x^/حw/:ṏ{o 9 @&+aX>*=@[<)(kNk/K)1Sg*R
kmEǷNFqjuƃJ6Ջo|~2 
)_u=4UXH5L(JTCxLB 38O1{$Û-H H I! `5{R") h$)Iuuafga+e	hêւ a쭱|@a,E`Q<3Z;Tm^joWtf`pp٧?z$sTl
!8NH.wFWBdgp07  @(gKw缊#<r72]Zԍ EQ׈JFUeitiܐiCFZ뽋4NFa4d:$$H$^`p?ɣ%Y3I4,#"%qkkn/%gH_j=c笳Ot vV?wΓ+ıj]xh2΋ۭ,딒*wo=~hwYvܹ_8sijcYYD$ᡘHmHY&A^&)1:A7y^e&ADDB֘:[ϡfp|9]P
|P삒햔r:Mg$ɢ(Fe	<20,??<'Q{|5eYgljM#s򥻷K칪P@=!!Wq\'<8,tU:gy΀Y<y$Ib{Q0qGۏ*m=SgNn:{Y[R*$B R~"HDtMwI!I! @\? eY.+;וּ;睭8#j4[c'?Y$ʚ*I3;۷n^tׯò,;)c$b窪iZ(gIm62-ż(PG6"+mfV  2Bʸt q170!*"؉?޳e+.;{vt2M3ޮқ1@8J1B7:!`ABJFA8h^ZIVؙ/>yQ9-;GDRIɭo~NJ
:.Ja#	Dֳag
/JQBđ{ڱe! +K.k5tXJڧ\g͞Edh޺ӯ_|ߘGYFG͏~d:w[YE'5N>vcg698;$n62c4,!D)If:ˢ҂)о qϜz8jZks5gzuZiG( IY'Ij5o''\$q8""dN;/(>"{%{W/|oN_~[_eyljdRvt0{g8'9 >uW_)ƣјJh6Df =ttV.!8!vөj6, I򵯽2N˲Jt<DIB,KʲYEx6Ws:à;x{cF+	g٘s/y>ZJOW=9~As@DD\uV~Ij5F	@$-		?6#mnJIcsNt:햭fd6I^~vo8 ^(pb&I 8F!dz>GqG1,Ek`	YР j#2=[1^B5`A BJ 5`C$Iukc7@B
c z JG|#mh=ziG|iiP'x\;l  .hhB.'^{pc1^xBȩR}DOJIB()H4a>Ȣ}MG"l:y}_Jhֵf3k3H"tkЪ	XXpV(H{,fܯv2 RQ"{A2k4?x<}onl$c R(M4I(۽v}޽vs̹F;ciZmLR
S] .kwQuN??    IDATɸOn?ӴdsbclќL&W^0`fh?:}xnϲƹgNl\;Ci>4`1v{w2[SO :@\DFk FBuQyY-`Jl f<yπcؼ(%JK?  })9"`6FW.lZ,Ɠl:F}j-|+\Y` @锄~e`f[],t:i6OXkݡ9 J^s~[B ]psn9쭵끍%t H"HflH!]Fpc=9d$	Ȝi.0 !qa:Q$f[k;V3k4v#˒(ṛ۷=x`gww4ͦ`ruZ<W8BgF&ieY=?#p_:!LYg|#{"JuQiu]Dtu(&?Hyx\GM@̂ko
KЌ(޻B. pU XD>,><Zl;{vfQVyYN"24IZ4k:({ :O"1@`3JyuGמiIp@[)e$qqR\T/˯[JRR%0(0ưo~ۧN9 zJ^G}g<Kb<mny<ۍl8y)"_mFggw[Z `FJR G]~Μ:!	$VRٳOޛ}n25!d6󢨪$˪=UTz5(*mVx6 	$[<efDF׮߾ql{~ͫoo<y~ΜJ|9h&¢ԣ$/J y5[-"V34mZu@Hl6Q1 nODtbI,+@B~)13Pt[yQTZc@qKQE:èlyS_voqo_*ƀBF>{.sIy,Uu0ā*h<-o4K8 ˲~O~O>=缐eng69'؊XkH,$x`}I",5oteff)E*sӱ k'`F @%u ;kΘȝs@XBR2/<Ђ+|/ږED)DNOu^
Z.WjjuP!HTe9|D_x\ 3 J	!H({c@!v g`0hE5CniczNoۓHț @$ZЕ3^O8'D!buYXO4ce=3Q9gL[FKEJ(9h2n\Oܺin	֕1VI5ٌLTUY{5腞x4֍z9c甊 `ggן}ZV ! m,ry8ٽ7:yٳz4k&Ijz `$d46Dnŀ]:T[$BRٜ#Y;l7y ^Q^E
WY:޿ʕhĉs[ղMZ!gJ V*ʖUQeYUUeʲVy>WUa΋d02GDEI0[KZD$!x4^3ιF4b>N'N<,{ORHxgO||Cy<0`[	A)a]P+"R2{2,z@bB
(Mf[^HD)E>y{wܹ1JB
V7!{o/28Lpa%J+m2R+9ޢ#nYhdŕs"ʣ&ZҺ͏~g)ÇP(lFH(AE-vE\cIjkutEI7vZk!.=""7d>"עH(zQ<2()(rk}+ X>E:lhcvk9}:IҼȁAI%HO>޽B)^o}ܹ8I"Wq$|'fkfծ*aRݼq޽)HkCq@1kh]N&?DXVՃGWo9y|WEHE x:ҕֈ_'i:^h==q[V>߹鬬îXITZ͢Fϸ#Q$h2s_|oZoq͵c[['ʲl:;SMgyQV`C(`,"5V3LYAw!WWmg%e㘄ƀHdZhx1"I"N&$DQVr5^jxS\yʫ<\);?y&fr
Yάx<%?{r	;_n7WBe0Hj~g2N\ٸu?T!x4E}啗cBnꪊ*!e%F8H3	8c7hMY2wU霓DQ1In["3:>3 "*gnq!&!w$T$!1X\QJ*`8W+6z={gLkdohs002{1/9;XfF@!pVUw% BfY*WUӽu{q$YIkh]p4*D/1?0e m?Qq㯴b1B`Z'!ʉ\Ekn@eyc]G|ftι,˒$fvRf
8ST~ޝ۷.7|Iő|vƍ׊<Dq*c`0X[?h$%UGI*d,
ptx]t>3q
2`0xיs, =BπDYݾyˍfXq u"1|~}KͷN9'B PH!A(t, L8 x8NbU|x f/|{qQ:TuB3K!K$0M~qqV̽ i<zx; +`wgo`0Lg|v'wYS &;mw̼h5n	.Dp<@%,ֺHEB*롪Lm%FSQU|>x.Ι$#%Çdv_~-\Qfc';)),$T6y(9 !$0PfgQwrtR)%ZڱNIJ"n߸'W\98TFH4q>0J
_4fn5ng:ej4,~Q"7 #qz*$D :K0&$Mˠzl
έ3Dъ("	D`̣	KARR4_kwX@Ry`<p']{.?p؞Vó8n4fXy=3CK;kH"%c5û̌-reȈ8FU#J/S[K@gsXhTRIy쬥\*g kvz˓ aTEtϽt~> ,<Wߘf#uљ3Q$XjG[wܾuɟփP1z[ '`.,/sJ
AbBTB;HFf93K!"~~ ۿ;}<ϓ$TDDI_v'ӧFC*8ywwwss3ԥWϝ;{F+F~H6YWw^Qu#?d+_|7?|GQeYFd4MI>DZͦ6:/J]U0Vhd@JEQ٬v2;gTy^dYu6lF)̲,IX"<; @	Q"4eUE*1Z#pۙbINx}(;zR`GGy[U+GEbp3ʵ5IO]og.
o3\i܂

慾~+G. hfdvp W1Q5ݻ=iZy^xf%Uh)%XHZ2)T Jr@$"dCth6ZW,	*xr$-#1 |У`HBP9XK)AyBN7 @J")vv<A78Q YœǏVYFN%zkI%jug~a?wֶG:.x<ӭ/칪JmR)dM1%p]|m&Q?DRm@?d0# Mٔw"ϝ!^]Vv`_)x=x&0윊cZ|]lSq) 2	@B6@:(t<On߸h6VG*gl6Ag7汍(RK+jBL#W@ 71{;81?58TmY~R((O\E1	n/Qe*Bܹ}{gg_wܹ7|u,KNaêLHDC1 {h) xR8N^ϷǣQrf/_o~;ntUg\ IӺG⽻wu{(Y^̦ӿ_睇wGCPHÕv_|kW'㉵6`89""!edv<Q';t{Ҭ!^y9Yc/ kh6A'qtm(Jbgm3˪qGA$ӧ^pZk I2b(6>	%uqF몴49WbBFQe,~u3U1w4ike]q;veieiD1T)yxޝ/._AY̫iIA#"@UifnijFV+m4P|>N GsB֯esY~O=îX*'/]7U B,ƣ1FDKBcƁacVkpp WW_.gD,{<3+*Q z_\5̚pp/>F#xK/x7h 0?  7_lޞK8b3F$"!"H ! =?$ փ@0T5[z^9 {lzɒ7w6L}EI~_^u_ډχn2?`[ki/EfdiShc  2I</srQdQ䗮\Ǘ~;Ez8(Z'qiSn"ޠ5YN:aA4L Q = 4Mzwr\ճKٞ14yk=sj8We4UUJu4i\ LLH<tGqB;Ǔif(	1/ʛEb1ژf3kBIY&Y)lxbщ[qH)Mb]1Z#C+`dώMeB9"[I<w6!d;f	@`P={Jp_|{eux2~@ߗhQ'E$ lfyx,2ij-:R$%"#1{dB|Ủ;kBWe]Rb3 
%T}	~"vo_Bb[Rls!9/8~YɓO>/;.qwptGBGaQxÁ̦(WgMHbO`dE)ݮk!TA`CDI$	؁JkuFm63skYPXԑjSkN`{锤zĞEZ]dqϔa*9g!$"wyQ]AS>Ib>4,	) 7FWc]M'#!$"ca7/R
F#B`ظ`FD]{Oݿs`7/M/4'3 Oǣ`ZkǱ/W>*NJ:@Pk	{?N;;;ǷNn<s칵Zِ2rjk=RzPCA֐y An>|+?3L*1u<fd<Lw^}uf\LB&Þ}(#t?qFh(ưwW݅/~4M|Ad^aUU{ZE>h	TKla 2yc!	!],F	Yl:y3[:9}i*F6L2R|w}`82*):ٳ76=J7g"DR:1++FޕC{4[vegbkmwuϿ4/-HPr"d`7Ch&(B:EEX(P ywq-g@ /=}Y[WVeMWV:ʥ JiV;gEY:1jZNiZV;m6$(H)ƹ^pkksw{{ow{{ss<Yk8"22&Ӌ!"M9q$93	$haQBDCȐ`,D9!U`gX{,~3Y&(0paxmN-	v>(y8/˪?XkHr!S\B% ٧`)ڙ=Yz9?Ԟ.2Q΄Dd٢(6wv777`yeXSM8dBp%x;Y\3ӻWRF=Vs{C"2,3xΛ/_U	YM9>|/˲f{"gWy7ˢpFQu%u7R
8Ǡuxp0xgσ cxLQi3΋F5_$#?`IB^u1 g+YGjG7!Rp/w?Ov{KI{gN8**@PȅkW.vI)$qUUe!C`ଝvTjnq7Yca~ޣ'O/^8n._Xyť?yy\GȘj81#4pyPYUJ
)e" 2rƸیȌ$(,K #@(%G"_%"c@Sl$Xv8BH"Iz,Ja}8#A12Sos~0= `67]f 8zjQrő 897#q*Yωp}3? {9J!8tE\N͂qz;1mZA;    IDAT>c!UxfVWda ĝ" 8ǥ2<;YU!N!ԺCYJBU5Ȕ$ 1<" 2\wT `aB4Z믽v'
 5yyU|[iHNj,cCj`]5	) 5$ xFLiL~G2ko
,dw!Z`YKUew,%.  yz_U}'" x&iUUJ-E(!"y
޷bB>ݜêprmBD5&T0Ƭx\s)E
ys$#Z_԰uVVϵ;s0ʬ'Ga*HD]ݧo|>aR>@^^@*VH)g䥈r՗"Barai9mǏ>yҙ_q7D&Y8Hy!$|4g?y?4&!ϲnoA#ϯ]Yc+FRy^_HYy֘0ݬ1/ϕ.]\O8e7,^po8;idtudlƸ\.yq^p8{Νck@D W^ XGv]i펗sƒ$xqI&.]:2NI|O0a	GWuyl\s(J]h*v8R!mQil68|lmx飇^ R
%DD?!	 x%"C$$Jk0IF1uJfeu5Ec&ұJ5'-cr4<x<xCIQmm!rg'HJFϞ?~y!.KEp<Q@j:T;ب  k0?oy%ig؃R0i]ݝ^~7nuʢD!50D0w.(GZg1Ώ̉X#HJaďra*,GGƝ;oruUy R"c/^=zl4ǲT_[nݞ_83Kkkkј3a0HJ0>a37rX"{""' +mFMqg9}W{wni5sSor>_FQɥ@fHpEkvvvz`8j[hM a]mysj5,5ag*(0MR.onnu&hc<QQB*`\+A)U1q&@pk8I<QYSUZJJEQ@Ki`GJZks h1C>:)cYCqC :Qr<@⧋N0>apz6MMG{|唆	\c3G-'GK*	{v-W!ެC,օ3N߿G+%o,sJIzι5M*ʲe9ck'q̅rļs!	<h@$RiEѠ^c1h-cHͼ5T
 `% 3)S9;Y^,ڷ{-ȋY51fFz̓-k~X]Yɲloo8:7t
NhgcψtT 8H @>o}F>`4 /+@7
fgE,l-(i0.Ѻ,CL`2MN] v+`o7Fy+
#8
UvV	Y#|BFD\p%\iy[#nB\3lJCbJ&)g=8h4ʲ;m,ӦmI	pcacm}]]@	gj8f7dݒ/-̽{7|'ΚA0Jxiqy?|.\so]ҲҺ6iZn?ۿ{QQ䓢ٓGI3lm$/KhrƅTǿ@H,p8=Xl<<ln6Zl<u(Lϕ` |cBzo!Zoz{.\xQfk^<z8ʌ++.]4dYIG8?5H/\;yQ誌+OAI&l΃=Ⱥ,<gBy>lTV3+g%bjiǩP1 {^02d,...077i }+)#Ϟ<G/?i"yG=]cIvC܋(dɲ|8/5Y~4)pWSFє`!I-@#E1NY䥵GAX- &Y5 ,'"G(_/cΘu>/5D1ޫ(s|gR|	jq  'p޳ KPRh67>|󽽽8.][߻qv"< GCӴlEYz^{UDd8[YOʒ$j2\]3NӔEj\k` pt׿޹h42U	D%8E?zT,y <gi=GH,>}{?o-f_G3Bu?yc(YQ	)EQ: :yV#yU-.΋JE	ujvzVxco<xLE:˲8Ri7st{EQcl{n>+g/^~ji @iqg,aGv;2=8`jsD80^iGKKDW?'ύu\p[Ã((1R:"!ɨ3*K=*Ni+R[Q~GuΓ_XX(*Ihl=ee@TYJ$8h<fIM.x<֎$"2Vjn:ssPy
IUit$Nl[Zap4뿃ʉZ0'{c3	<_9o'l-g ۚSwsJ	߉	hZׯBb-+=S8"jZ6)/rcR Փ894Iufڛ[<{JU/y* W8	,]Pƽ,unܼ}w_^T5P$[pXPLwJxΛ}ah&ի/?*p Asg nTjvbͨO|3	zr!&C R*[;;kޓN[<!f~aҕo%h8xPvւ3d5'92Ƶ1u.HF)ʱ#XS=s _Aǝmv	&u!΅R((ϲ,3qڈ[Mu$9@YM̅){Ŕs;Hڲ*˲PRYȺ
'!GR0eUl>yp勩Wg'ң,BZ7M9@IHg?}?Xޜdg'*&"Ifhvg{{liqauu܅z8,)MbXQ[綶~923o8Ƙ/^~_KW,p[y+"/y?8n~} 㞎U쌲l0;`8Hy& qrYԱ'}}\(d&K}Q^֏A,vg/^ح7.]3zOFZՏ<l8!/\xa0!BXJdQj=l-;b9.,,ȳh<6Zw85qhIIFCSUsssV3ؙ_$I)8Zwp4,YjݤPm:2U<y৊N}=YEs4򼜾J&>R;#INudd?j5D(ˊ1/{og68Zw&l^s+WΛww8)Ƒq䜟_VE@H07/,+_	ޘw2Tq!U,%eY~c4l4*\r;w;ssV+Ibo@E*p/^o,[wn߽{guye<GJJ);3TfG?n$5c8y}5=C23n3Ro޾9@F5s/<{SJzԷoawJ?ů>ڻ]	QT( 677vnfs1Ιuvi	! ;)e*Km#"|JUƘKV9zj8\twzg[HJ&N)tpTe0xp_UqΓ$Ē jF 
V9Jpp|@QXjZMg涊b`lH$	r<GQhu:vrbQZZl5b598gUUYǑ813"**Tg㉬1IieQĩNYq nzR8i=ޥirseU;[?D)N3 GɌ绅gQ/&LQ;wgbu5gՙ?2zեۻ=ڬ(i5DU$._c*)UP	RRJ"qμsYkke z9iXθ&`Cfq.Ls 8N P<zd_]P⼷"sWV	!GqXHW% (^\X6 Xk9gKK+vٓǷoR*j6/_>zw#rUU9林~S{@45OY-Y,#
Ni.usxgv51..]z[.!(l;|Lq➄@#'m;w̭_^Yu2!^ǁ`z\J&f݇-[D伯\H)@*Jk28
k*'rAȊtꞈl4#
LUy{`ПF(NBSq-7(*B^IyE֘g^>=EIT֝BYmK3&J8m0ΥT6ϲ~vv6_honnywFimNd^~Ki<XHՍ`<?=z4Ziûxj6aUyea̬p۷}]lf}UUAYP/CЙ@ cUYv]pȓAR˗FQ2kkkIE8SUU<}']¹%dI{
}ΐq&8!"$sh,PѺh8gwc2ϋqDq,+q/,:sq _ytvê`.g%`gAaaLGD"0FeĉZk'qLD7ܚOV7^Rc\{c<%"O>;k]p a|8+Y+׮J)28uwZhhZzU!<wf('esx<eyeYZkRIfn;FC Z, ~u;^|=jcy8-...-, ѕbyi3~f 1TE1T'9kc=7wn//-I!1.tw7}OUEa^V/\x뭻wnr祐I76>~:t:޻qTWI{(,> cKy="x+{\4Ci+)u3Nk8AQUU4YX?p	pu?{ϯ?A!p]Ufko_uVTyQhc 0@ 6FW	lc{gei10+C,>t@@C $n4RE H9	8$iq66;s( 6F)wUZ#({Ƹ	>7D)&IYUDIB@ޓ;1J$U'ƅJc4ΤbqdDscrᑕ4Z;w6KhauftO`f#=XϚ+~Ԡ/XCsƁ1C\wƺ8n4y<n!F#xK*stUZ<0dgRQ rJ炈@M
 **扌Κ((Z X%isfRēE$qaie0>zpLdj9.lD{ۜ\e;Ua”,KdsȒ{pt,ß㡰r>92I v_tJ82kMic*cyIW   jPIB! >G<Y0y$$<_<Z   8"Z筧ńav"8%RfCI8eQEY&9d\)6,xu/%Z?n5y	BIsn4r<qU77v7tU՜7g!"HBFűTQY޹`g:{?p&e3sk1	v@DιR 4!Zp`&hg_T{DFk~si?y- xE yÕ}<s]$(1gl_pˍqƥth^ВADڄTęWn(@|9gևݞA %kׄ!afšH>~ᓤьfٸyH XGH0`@ G!] C!z4Ί,Ue%RJpG07h8VRzfp0#)#%9'AjӈEF =r6!h P6Ҥj#\h4REYUSPFc6rTa$b]鼬fO 'ATkSK¦3έ͍!̹;O33$mo!ak4k׮oWUiC=&qI\cE7Nl4q$L8[s8CkÇ>~YiX)!ںzRЊB[Yn5q.X%Fs2IDUr~Q0A[<M%6^o9e㼪BF?{ε[Bpcu_4?2U"?;{/\2mr&$;=_潓A' #2wq	) #IR./:OeaQ]OO/ѿc:WϷHa87)Rk32QçFcuy9De+"HSzO b4Ny6ڜ Ѩvzu6wvUGJY{x¢<gGxEJG4ﴉ(*%兝C#p<cVK^VsNJSc%%:R\
N!Zj    IDAT\F{kW:?eE)9 zapgf:=)j牉3>fᤄqrD#-WĘp`G:29؂;vseܹ/yyJDR0j%?7us/]uM["p.S]ݲ!BrZyƤY[92%ո0a8^ZYFRBls!K-b}.vB)rA1Rә[X&(f4ZǏ6w/ 9D(9G OĄ#o3U%񰻷uwOPvZ;wΊαY`L&:@NAh>>1pIz:i(B|ӯ{s*iʈ;g #$yGH3
sƐua<nm۝sz;i[3s!IAxks 80D%`&:D伆Yz2F#o
	!ʳl<Vί<NRP=h>C^3N| 1?xPj?r6sY^weYTe{E3(fHsn6>|~4প \ǞD/0PJ\"(".#dsN)PImm	ݻvg0p¯S)UG5"sCKDxy|$C7N!=eʪ7;݌g=Q$<Aѹ3RmΎNIYUzww/Όb:Jv0.sB(|aݱϵo|#</0d)#R
Mo/0gՕʪ,9';/KH7EwwzFxuc5a&8<< CFGpp'JџDD(_쒄<Axו<B$M1kOP9kF#-@lD ΐ3&%*aTXHzkWHXw\Xsyղ E~o}\TUOyOA<2Q9;{ϟwWqd	ȹ@r)Vey^+"R]:,+huQom޼q}02.έx^eA"DȓjNs~'Tѩ5a:a#o02)ŋko$#䜝_X,_:m!E^*~k)!ͦ'~'kW|߰:'"@n,1# x=ػ=])1
.,|M#!҂&h묪T<	Țn{Bx!pPGn]LΖeı1ZEs_[Y^vVđ<h6Ҫ,a0hwZO=xXIc",<:Eqyoq4E !dg3Dƅ((t\(:Gemlߗ	Μs[d*X)i98<ֶea'<vnuu<F]v\K,676;p$P@sQ kw U4#L1^Nc|AkFO|S uX+'-LޱqH|l6W"niE2<"7!IftǕF'
稪*"B6f3$P猼ڼv۷գh{gwogK#c,%"8zJIƘMX뜐2mRʗϞƑx6Zmg9!1xMTUe>x\W(}Ad
. kA$D@d'F0{G1NR^ὄ1<=[?rf EҢIý]	ib
ipD 9Q'1Σ(㇯ߺ'i{n*󙹌CVK8OTڔ	099CTRGQRf͐99N'>/cw"}RYUk0zq@|Ecilڝ$IW1bRO<a&yN9sAd3[I#DR0΋R_+;iim9=-c<'xJ_pRW  a^d`<٘Gqy_/hu.!9Q}f*tLnqI=Q«0 ֘A0LtuBndE'?yqܜ
d"Nb2"H䭵*5  8?'`,<w8ʲ,r]+E%L2$Eވ󺪬9CQ E}Đ= XK_ LtĤ6:tA>Gǔ|8`$g]qK%%y^(%$! ]U55+?MqTཇ@+%@\M4I:g!C5+`?yѣ{@HvyԀ&=^{Kڠtq޺{+Wa?XgDD2y+8ʋȑArɽO?:uJ.dex#m6w(ιJQu{:X	%82.8GRp4֖=<8\XL^`46Sz`\1q!C. O+w|&Xŵ׮/DRLX\a'J
!5F	~[-r3B74[\_X*1 O@).{;;کg&kuPUUVQ$Z A0$OϯFqrpسՕnY	.D#ug+ӈsY(CrƾWX;8̋*)Fp!qi:Ί<ZV^4\^\paf^ x"!e'
0 ;v:m6&Rs|4:8Vꪲ{XŲDH8u8rhC)Z8Q&lw֘sk.UF|s\Fr\JYXkn6ð){)c籹yxaVb&7şpܙ_|6֙@zv_(=~2A;;1o\tij-!h\ gu_ZV\)z^gY`'eQ8W [k6*f+Ÿ)/8OC'2%[\~-R}>l{kȄ3k@6J4M60Tw:ŅsYkF@}C8G`XYÃ{ۧ+O|ODH/6"Ge@H~Zl|\ 4MJf%T̅YFeqJ*Tso;C$!̬0(j6[ 0w6VV/,-loy(W&OYD``"Yk'QaBEI2Q;"p)lI2P\
@~vȂ&1*1oz~"pN{QUQH%QHlv6Ry(qҌ֛wwAx="Jg@&$NHK)PY^*%Oݿ믽fzD8
)ac1W4 Ed	|{{KpT,Ud1:6yW<˻3XxYDs =a];.'ءN4ƹ1f4v{4Ms0cj\B"ϳϞRRK."2O T9BJe(c!VݦP=z1UUE'qܛ Rut䰐VuO10D@o-hwӵQM:8>҈4"I&p8E܃nıvD#cuX`yE Hwڹ:MD{c-\	Atca9()=hwZSC# 1<(Ur7nѰeR\-w$YVɬ,N/ם53X?t8T|R݉XpÍ:wb4F^gm#M$:c9'%x#;fpccs4Z}ʕ/$UD"4Mq3#COvԣ?qLb9׮^[Y]-9ugc\Ji;{fC)Ikc\Z{wn{4Iww>ٽxmm@aCbxr<ƣ*kyf  C9=m!<zf+b0[@p^Wsf=7i׷zA^Y-.-YH
AD{CO~_yE)1&lU]~'φY6(RR 8㲪tU6Ҵՙ;wVWF5;6=g,Mb%e52ԝ	yJ8RUY*)(3Fy#rB]ȃǲzBF	Ȋāiȋ"/ugnn~a1ݽ`8?znMQ>*{1FH% s۞hHɝw	3ū0˓>Y{VÙoψ{+^%O_?_'0Ćό\&#pRr)xUzGƐ5Κ8oߺee<29LH!@9V+us s?y\?uB	 9笮1փ'KK4^(	
RjH༖ "DKZi7߾NW_گlpF*&RF1*2S5(ILZ9DZ^^^w_d#BEQ$*m#c j<?yWb?VػW`V*8ځ1#8	i<c
@~V۠:p|c!\(7TPȘT uΚ̋B=g4ME` < PD(B7t|x<B0"p\*5ej;w(P,Ct9G\i3wUhЫ1ƸH-@s%U1@vRczڥBr㼷<P[^wL@]5A0BF"p1uvH(Rs*J#	@3N1͖?.=rfVg`s!dI6aS=+'T*RBEVqYqdRE~Y_x!r~ø*_{F9K+P@/j839C7AZGgDW' 8:><}sb=(nusRǿ(N.]<Zx%,[m-q:ɈcoZS2y IMDɻDsʅOud=H3.,Ub-4wA>qʲ" !h8ƋK8{}"iWPzqO}C8g;iRz2&Ur!Tx,alqƼBTRdEѽ{NUP~erLY/}OOp@PqVsi4xg<| Q1}Y}s}4V3cOxwnݺuf0,[BE٨*
%jsanvTw2aɸ\v3VKvo	C,#I$i¥r0q<%SL"D2D4"VW׾,-/sƲ cFsݞ??{  .}k_7Uc' dv/?o,ͷ2S!IqA e͚J0w~w,@a+Tk몮^)HCDd7E/2h#QFmR{
@X̳Ed޼@upd6^Py3O'?Ͽ/xMVԼU ً"M %7m./.eԸRJigkE2?p8V58/ :EsɓrcB?6s?~ڝ{~Zd " "VzxtyY[[ztk{~ 1q_򐲫TEIYkwB1x8qYtZx4Bn&kkvZ&"DdǓs>K`=>1h@m&DE'id?:e׿zhR<@\w<ݽxի8kz|͟koV7oyGB~S9wR<[THgVg)ggyɗ
 _oA27vo/ĩuH.ϷAȳ fU(Hf 	:/tUyJVzbG> J.
;;gk[WHJ@UU"\[;WY:$ytfvD/=XnvKEQEYJ0Ǳt:YkQ1.1H*k(9?}yeD_78	xg+kVő9iBJyC	1vE-x4@R0ߋs+_TqA [!Ȱ@Opu霭9G&BRd#R)uUZ	JFL)rl~B2iO#l܏GR{ IC@  ,V 'Vfx8<:bMilLe)J0Va@P"ՀVHpB)"YL+"j[7*ι<LEQP9oe*bMY"'O0K|.(95VsyF봢4k[vvwܹG,K$JlTp xuʙc&Dq&I2<4Qtm]$r-_̕4%Xah/̌˼iz8{dnsk,K@KH^?]`[IZ]IiHյaa]]<Oy{JBP{nڬü!FfwZyI/>)fFyBjIٸqi12`)vt<j[IhZV<o%So{ğ"R& xk8q$;s9%HW>"_q;;?Ͽꭴiediթ"h(zf[Yǌ{o $@.zɓ;~ͭãx<x^l]֣ɸ?'EU?AU$ B/fՎ{nn;5Rx'Qֱ9W;ЬG&LY}beY\<n43aF^N+K 8YR*R|S;;?CA!TZƵW\y^k{PDwKG𣃽n+H?7oRZE΀YEJ◿;D{ީ%
IX%O?L&ϭn7uzѤJővsv'$(Þq]W
7oٝxRBG:$L(/J~vb]"BH2--ܼz'?C^{
P)UǈTU^Khxne\5u[>- DړΟֹk*    IDATkPEBqEVkks=b&XEUWhόκ̌DFGJE<s
AKm]굕Ef~dk++~ã|qԅM[ 4Mnvk n<}ΈY;rs0	4߲f!͑Ad70vbh5˪7t1Z6@c	X_.jE={%B!iGp'pZ<ґIaqaq1ISB@`۽|JOϝڴ:kuMX 'sNgh8*m"R3<nt"}W.]A{foEY\~GNq XUd<e藠E$,&gOE vad
0;<(Rr!!֗hd8[vu~܇a6^@&1cf&6mZ$$"ټkksuYX\lw9	,m׆_S&9m& 8P7JRF"w^q3ZeYy13ee
m8O(=UPyW3{ߤ_FE8I,uYa!(mҬUL&E1$i4((DAPlOB18g6h*sf^cxe-"9g+IREQ?(ҍ'Wou!W
"Ӹ1ڭd	BD ?eZڳg1Vx4䓏oZ@7(ʋ*D ""S:qskpֻiЧQU[u3QZڹՕݝ<	A^B!e1iDB10`e֏\
y]ӳo  nwgX9|azskkN(Kf0FcѱQcvUe쬵$Dl<_* 8/A3<]ܴ 
즯Kp&iccMQI=K	°4T{:xuM9%iVNj,e᪪!2-ͣ3/"w^pj+l@uj8뚃F?bxsz)ldLmY2V*?ݽVod|o,tVVV._;߸zjәI Y~#ǣG<x{I.λ?sn,(R1ŋ@+_5Vs> `pK^i4
6ŤwG jH9i8RDG&/~ctڗ/]~γgι(tڭ}YkML&B-g""2PWM/,.-/\nwLSLڝAO|ُ-HʪJ+ov0& `G?xR_?7;4!pgggowAί<>:	G-h	֊H~݈)?dgW.Ǔ\%q\k1J)
N  Lw_ *ۭ>e	PDP1$/Q=}y}UUlp(DL[>2" bcD䬫-2My,TֱwDE6I:bQME>2 @UhaKDHi}IQ*ReEk (Io\^Y;<~yʲR흝paaLDOp|shI/ ?ϼ?g矽aVosVl(6wx*ᔧ#E	mB(m<3*eXSjex/M$4Rjz{_|G;@c BZGqv¦s1a90,,,-]ؙsUYId^d2fWz8H5{_"Lֆ-{˕hZateݞ@sN0f[Sӝ0,f^!SoKl]Af(Ofm9bVP4@k>UjOֺ4ۺ;t6xO&i'/4#3UP)R&ֳg돎Q6j9{#)q4}a2kaqyfׄ/Z$m%񪘰(ZxxXyv# R
|cEKfW=L[Dʘ! <"lgNHN=y\4Z5 P)m"m ,wF 3!-)5HD
V!βpu #"{gUyO_E1ael	3$`K!Heq3$DQ=߻{x%YXpsq:7omm=~8{Ϗ6'),"LhCdտ`ooƟ=HS?4MrDZim(F*ۺ.KF<#"D 94჈fѦs Nh,Ft
z/~i<F$<e	YݜNx(
 HCڭV %7>0	NI:/@ؤ0)
ڈ7DV.M&c.c*lNN:U9Bhٽd_YZη߫?r֑Hi$yo;:ݪG#MЀR[H)$<:<9EG&KcL]۲Wzw۝RZyD F=&jhiYstp?!!4(2QDk*J)"hUg[[KBYL hqq|?hw~j<0H0ǂ4(  /DHkn|5MS}x؈.EcL>-:Fk@DʹwVWm]WUeIO?_֭[nSt pxyƍ(&ig&ۜVJixya&0e}ã㽃ê,[Y$8+H+CDhs{777$ X[qg;UbZ8˲:eY1?YpZWU53U8{2 x&a=WIǑ	nneUUHNR*J2JLDZi""
)R:2eA/._Oǣť?V?:oãßlm]X]w;vV Gw:Wo\x\;Q!@ۋPl%S$\+۔9˷ e}g33}`zz_$Ͽާ^|*2 \"SUD<f$m<<nnmU~|n~kFXݳ8pNDVw_W?$vLIJ_zͷ>x2ъTJȔc< tjul-en;@R>tiiPcfhZ{fYfJD!ǣȣ(q5JwM~>e,g ^wyy3;"޵i'{?ʺf4%5( YINs]{/^.*/Xl'I0;HD!1ɯ@"m7Vsxl^>D@xAADDZauSu$nwZ]1N3m"yTTV!3V#QJQh"E=	V;T'0Ab	J&fby (I[i($5D@&4_e׍KagDX=gH&N+Dֵbᣬ^Z\'cEuEiRUuYnT=)<o?~tcc+﻽j9x!B3zC	<?3uxRUII,~<<$ʮ_=u&2{v5ۺ+[B8e2")JiAxb6/K:<E\b:lsJ!Ȟ J)OD:A|(2<v*Ã^e!w:t5iE9k4B>sEDg@`jH(
!$h{_Uu$JQ-Zkٳ4l~.^X|rzK+W^֑6nז4V銫E] V'H~4nXk:޽{`_^Z>>:DHdY~`7'UUwۙڤsh&@qy#DFqidњ6'OVtQF뛯\>o>h{gƵWb㢲ރBL!XMA!&dT~7][^]˲0W80R׿?l<Xug;8vw~ͯ:ODhD]tiyeeO-P㱉b$?<<t:kkD&@DiMx j``;Knvshvvn\>YQ#&6J?eY* TUe~?~Qՠ4 VƑkWuYT'E	,ڹƢ!@Sa(DR'x4z-?3"&qCD<gɄZN.vʥ.]/t[wyѝ{RAEϞ8	yq"*|{{`Y;VV_η_˽O	quu+qF(L+լh!7|UAAz4&q$;̝O5pgZ
210Hed^ gv5츓rj7t9?MwDHʳ R * x:ksЄZ+$ýhl£q;q/--̦o{x4-܅_{߾~	C)v'I9[yݎqOdqiyai}3SNtvh{x4<,|<<DqE6,({EǱ"_+ rpºU%Ņrӵ^ggm]U{S)3漏gCNHc&ֻVҾ|`xxt2ghྥP:5:>ʲ𰮫NikGC[LsN08u|7KW._~kÃh4:=:<(8XÚv,={8iuD4qZffb=F̲EY[֥Y+$jJMk꤆4:uc$):42ŔF򀐒$*,"*tbiVeamVn"1f|2}aZyBc69Ͻ%$oCakk&I$q] 0{sK B  =x|Fʬn9qeYfEY@뢪gϞ[kw Bxr7nww6߅gDu{p &Vj&$SP-H,M#hSDmS`}14E*HyU"ϭJ3upˬu_~y7htZ$qr('yn$E 8V\U;<*	KjJqD]"1:c\m-x&h:Q;	Nݱ'57E/n,)%P@/U4[mpZdˎ Zƣqʴ	$$$IzŻ@>AH6)avyp3g@B, @@FGD4,]]c̱9G*"YYUC=1nAO?}7nzSH3\}啲,3eIjeI	NhQU_|9?ͯ>:UUFw;+\~[L)%̀A_-zkKH%co~?y7w. h5gD !I#@x#BS{B><8ںx"):{MG}IlPcgLH"LEo"]fqJBKr(\,,.M{ϿVTz7l'1ZeG|?:^k.*<{27|NZ#A[ۻ϶vVWWq¬"(%Ak&QYUGyYGQXb"(*MK^z_Z$N⨶6õ&,lns5Zyv,MʺuPYP)1DXuqldr8i²,'y9(#0'b2F+wӱBȾ󀊴Riq^֎%kɸ,K@ttFYznӻnn^~啵skZWb;;O<C׮-,,νJ/'O'?t:7oތn]xζo//-'}4WI)ƣE	l֘349r=T_]c>83@q_A(	[1?Otp/|o
yݔ@H^GG ¾cl] lI{
G@9BX=w5qq~׾v;!)-ti1sp 82:2
rwMW\ I$9-D?FhxXq^ZWVMs:ŉ	^F[_j P&(Ο,,hZk4790ej$դ'f-[20dfSRw վkY={Yi`@{TOTvg,'*g٣P f	t24 f\4k*|<lono>{Z;ò1aαpY֚>{z:[{S^0z1Z-cwjmjǒi$ZY)n9D4%g0M$I'aJ ! BZJDI4ӟں*l]HfV{w'Uk֤
N/J9g벰U%ؠ0
s4q&t6DGM/X.B6;"j]QT",Ϟll^pU$lNB@vhZsMWT@U&QY砕Z擪!{˫W-/Ɠ`XV[=y/T!;xx4<|`IZbp!xAT6ӿdjWfKRUYL&㲪$>Ӳ>ݻ|8Wݎ0	iG9u,9k-({%ggPO/07
R*4uR`lVBec(0B4w/<n,A2,Klx4ZmL$"R[#2$yࠩ19>>uF! 31JӃ?E BXd&1ΆusYUгR3 $操նU+HJ ;]UUyYz"m"~2vw6766>$[
*``r׾^9(<xǟ_Q 8~[i2u?(hAC+ ^ E*
B3w    IDAT<)bE`kkqfޫBy[UP&)$)k[,2Iv֖W~99(ccΝ_|qI.қ7_u~WL&BdF$pIo0x[ DլV5Ȼb~n-2O>/;w㺮 L@gmDV8޻~D iR"[]Y~wlԵ5Zq!CTdǻ{V6$59MN3Od)0VD\yRã,碲'+Q*<G!0&RUdvX!pU,nEeuZuYx$QzGJ$ȐAQdVkje'N+c΋tZiȞs!vD$JbA,dgqdű)$/wJhM(v5mdń)qf<	e<v
Lr΁]pe`sS ;<2NMy3Lø3ʻ1{-C݋:*js<|_8I\~`o{;{oJ)D
院ݼʍWm]FqH= `! {[6 Y9NҬ,$i*Mt H	ai<8X[B`qTm⦟33H.23&
 )|+Iյo*N#+-@dj;"ֳLQE(H)ښ{ʲ:$E0yOvj%FWeYTΠ[^^EY(wsS4
w{<CI	Rj'#BGHJq,p`{ﬠݝXx
[I(KcبgS3VU.J$qZ-u]ת0$m8U0|k"^Dq݉o CX)qN	gocaqn'Yڀ2 kWP!'T3iIw;0W s,0J{jRGϞ>y~
j8fRCU)$TQݹs7|u(*PGWoc>~ T fyk˲i}aTAR vR(V#)3ly%"h\evѠk>xDsa.J"WUF		[lAıxk5[QicZ56F^;%//&b!v"QdCe{Њ	~CD^ *.M!6~Jj `^w4Eu8,GQG&IbO70(Z4TJuYjel"$4%f"]+U[הE򢌢(~ _"ET[o|[#veYX;y4m @LU9tsO?}׿zh8튨yp4	ɘ3k_}?3k"eVʳs?$Js fvu=vůz?ѝ{qGQ^=R:yf("Z@$hizV+I2tZwhٓUg< Ċ4Ѩs ⸝W._E&/Xkx"0"&i~}?Atv(U-vc?㏑_{m}}]Y[ ; T$Ҩ}ҥNn3IWs*4R Oz6>C 䦵{_^:ifo0ƌ'`ͷoʪRH(>8	5ZH"Sg~qg9 F!!iѤhw:l","2DᡦbGa6_` ƻ㱑C%R:Nb=Oƣ>!ãcʄ4yw66͝˗/[6==>)޻ѣ7|7H#?Ҥw%7<?NW;~:o;x/H]r7^_}{}smLY[Ll)>_	+(ƒ,3c{qM @@gw
7yy8 ތw7զ{,^J+5N33f"QnvN{׮nomn<zDjiu%s/(R;);u<{AXk;faDc,ryyyuu- <kCTzyemyy9I(cs&R
*&.2y&,@!:ތBP  "y L&2&󾕦++/_H@Y,OO Ah2IӺ1 IL&㝝:"58[yPtynDHuK./[{ۛ
e ļ0這 <d2qU)ʀkM'{`qq2GǑ sVJI'Tr:kUYٺ~ ȪQg@TDJQăg+[81$b<4*"DdA_W1&IV`~6qxIh4eI4c@̋b8<ltUe'@â
|M !D(RBo98狲t$>" ;_xQ0(VٱBޭa,}SVIVVs~aaI1ɋ! h4:/"i;w|vCsai\x`_ӬސB˲xdcoo(K^$Rfe&$!0@D`V*(C/9W䓲ȉ|U+u|||޽ͧObyYwkkIc<
TEŤVhU-{uam<+I< #<w~-"jEyfiB$.F9BK^ q߷P!?G@P3oh.H!{AM U|+˲V+͠vu p488/[u>U,Y-.Xdeey4e|mv	Ql@Bt:T^l]GFwڭ`hDE`& ST' "Ƈ#$T(2a'>8Ee]o<mld2B^DJ(~_v_Y\/r<:[UvF촲bGIdPK>>&.'O޻'F:RJƔfh82&Fc̮  I,Kª*#tu4IVo0 :r+&4v;⥥ntVK	!EQy
{_`( `8<_?)h<|׾7iIa/>?Fiƍ7o`ua@PjjҶ*v|4MؼzEdey'I⦓M	tbJ"Go~S;KDIQ뵅W>e^KQxnoz<|'Yۭ</jgڂHemGƘ@p̕ux HdV%%qTTue6Ƴ%<P3 12*z#"#:BZZno38Nx8ƓVu|t<oѳxb=_8ok.\xϟ;tx/[zKGx\ի\\_lgﶺYjD*2*{ZxB,q	9ίMqO̵~45~g;UC/_4.5@!ep pz}iLunO0ޙsyyv,^~fk@q;B?` (njwW/^ʓǏvw&cZ[[[цJW PiMY}]qYX\luڶ.#7%ed*,3k*y (omOl]f#4sM<3"|3s""' Adt	HqB"mۭ4)o;Xpv0@Y$)"YvNcLYfNG+$U:4MH| .,dǛOYgqiIikL$APB8plhH)圫˼.R]Hӣ
߯͠2sV((Y9M(ISc'{,&xTKKlNaص1Y{xpPv)N|$VkxTdM"cBlJQ&I4˂xXV^5FN;4MLxR 9y1eYQeUUU5L%sEYB@lSk9
6PTzo:A#p,KV1Gx%)f$hvƆ7"'Mqd$⸨Ja1F+ɤ,j&,|<y{woܸZP̵7K.?~OFY]X_oNJ #JIeYAYա]6e8M\X+\s )9SƓf	@@a.(`%rooƆ{a w=3"L&90T:su]fE$pӟJ)TUd93  3:߬8MϹ0
(,<XE./=#=帮<sKWyxH$ۣލ؉ލw>tLnoǴѴ(	 w\w*ԃĞ@>29gĳH6?}҆`
`<Bʪ,18s", hƘa`-REY9ԣMM?A=Y KJ2%EJ HkJLϬ=4Ťp?xp'gH	uV[SK+ `)!M4tO?|L!cƺ8~nnl>xPcLJ!/*=\7xcqqAxsB-./YxUN3&d09HYD5 4	oZ]譵S!㱵SQI$Q%Ii$eبREB*ι#p
@&8Rp B@Inooݺ}wp"u:ܹ^qymĲFn}뽿~ʅPi{O$"҃AognH奃p{w{{l9"wS&F?yO΁sv{gwu{buX)k#>V⽷?o0!0ＵN
 ֙|o/rzd`HdѤ0ƌ3Z!(
c,yԣ{yj3Ġ+J !yrUUq!n^YY=>ډHI\;mDOťv孹snUIM jzuܿ`46ͷI766F˯F<܈+`eW^]N))֟l,BBȵ^հ+L?C1S0+ʵfQi?~I@}v75ͥOM1(}8{̳q+/|o? LX
@Had;ps˅ӧNy{}sG]RVeqx/`܋5)0jXI1@a7.,/<C,9C6vwWN<\C!"W3:CXg.ƃ	Ck7d2;7vgAh|{*AA 9Oleeeyy)R"QelYd28Ms'"a?'tZk*vT5u*$QR"i)#gh Zƣb%Ș󴸼lweQ8,mTTH>c9  Yka\c|?.$M."UA.Idth*4Dg-+3-x<wEYFQ7˪8gMkF,Jh]eՒRqh4E{§Cd֩-=XfIZN(ٙxTW%q&T`zis.a5FWe1`9t]=C@Ι`lW{N0\W8[bB	zw.KB>r\"L$j=faU$q{($RE:?իcuI'ouο;o;8봻kkk+K3[!DQ;;O6#(bB9Aʛ!@t511Tb\VUQ'Bbaoow87e@Fcee5 LTUŐ$ 2Y_C$UuH8<WXۂvb\"$!#"RHάuhA vjbsB&d"tlmoO0"1#c(2gZ2Rj{k+09kp3xw9
9~<8TjmuBpks  5x1'81u[U&MeʋߖR(67ܹ+YN&c@t<IXJuŧN:yAQJʐs!8g޹ŉ#)!^zLq}+y__<e@TZ#P$/\x?Xx4cqKD[~NFiVuBI)I\@3-xkL'IeViڍF#Lc節3UZS 18ȜιO'Z败@ONJw˗4Ƃc蜿֛o~WFmP38#&d4LhFx?|i54MrDa7@EPrwpxSR0!#(#~oٷ[缵62&Ƙ;m
{Y.</+,*TuYLL͈0kqX0RH8% HȀlxNrլK\EQyQj͍淋7nzu?޾x_	 ܽojfW];dדd0N{0ۏ4~~ӿ/sNxk؇>|8L^uue*?wf	U!eXg_XcX!1ʟ!g}Ͽo~VV!>ǗB8//|j4>0I|FD)2c-12h9^⬑N7pdS"r@*0;?`~sΝϾ7_铏~{/xcy T㡩ّv4
ڭf{{UU-xoBiP宙i\Iy+Xj~N""czVY]骲"9Cڟ!ru#!vG /!` =. RCTr	-j]i3yYyQ]yȄa: 3e>Ad'ϞGo92JCޓ8CKK    IDATm]tyaiVWTU?~Y.\:qJ"F,J2˲,KE5,r&. " 4;G:5:FW@.񠚀L0C5WNI  Q*ȬZ- p8:x8 t=	 @9 
fQLG{kIJR50&  #"<VZ皈WV=pZ2~-b:NDD& 0UGI*dޓ<xOR41{ܰw]X
'_:@uhB=0BpSȂ@^<wUQT=nvh%R .D5$6I <'9D䈐OPjcywH)ϝ9_|9[&0POD";9kt/fs&I@ևjsM "O/1Sz;©$2ƌUt$ Qo08^vΝ;ǹ@&<POFI`c:]@`͍4J2Ĳ4nd<@T;GO%ahLI.4x1ύpy$"뼯A0#X@c>6 {?04ٞ
DYD9Bi&XJ)h8qh4FΩӧ[u%dK
 uT%i<xycMsƜs:9c9RI,cmtUZ[8S
b[73˿~xh<z{|_|'dyii;4
!^{a_/v䬰杗Bp΃+'\p#?5v{֚1TjH;Waii,QKD.YcL 4Kou^qonm>^_hp2ɍ:ƙBH	ϗ=$bX4%B)hdf+qJ
Cbl  FCH
Bwx_'{oYjec⋯ba8VAxo~Cr1TR	
ٗ_eqw޺YcPmXvg8Rs.Jjww2GJUevxiTNw0oUsw8Ao8fZi3Ūh$8{r^/IS!eYicM+)(5GdRU5Wq)xYAM 7P Z[cX ' 1!dyrk	<1[()tvMR
!RεL19GW^qW_	)&ӵUd<nm;<Tpj0]1WK+ݸF޹h	OeQGqz4Ohb?*jpfccs_bQ\#zz 0\G g+ ^Zu}o=냹aZ
I,{bVS?9m~-Yq1ηXB%酋ݽѸ@r`@"
Xga7:{O7<~ON={k'N6[-o_xg~w1x͛Qeԕ˗><8l42d<楊N|K8WEY>e#pD r9gj|N!3W;<2	aws!$d9c֕sͥṄ̪!cR,mZVevAOu*,rkoq1yWF9sT 1uqq.xFOX\\::ܿ{h||aamoon)ɑ1gnU;F[stth^\Yvqkcy'Pq}`=DC( lZ;;߿W7Z^=iFFRB8*ƅJ:hS!d$1UEP|kx4,R[g%?3!?>8R͂$Y9g[toxpI.vutx r1B9Vs=z` >?DZxcs)uNJR" Ў_y*"/Tq2+EY1 sh3OBxb^4΀1`e$yDܲ@]T{ B4]v禚lom\tyomei#M8C|XL$Iȉ(2"*(+?ŝN`:xxGxГRG""_U6:=qx4Dd㲒4zk: ujzCSdÅ"PO0;B..-,
)-(\U]2XkwuIe$/!-Kyg3zY 
0֣n:4cit mM-	G@cw*Ԝ%>Xw_Pt *fq\p!sdLQUYk-yJT
ck+d/raq,kL%I`كV%ZuyMkǡtta-^W뼨x2Ǔf!8GR)# >SO?Fl<y{Q{+ϟ8qyBƼ?xp-c,bI.}{mmʥ_3?SU!yQ(RJ兖_U7^vjUUeY y=R;$VE'^qc8^o4N(At4xbtGJ6$ɲ,kdY8I4b))%R	!:LuZn
̚joowook{gkg˫Kj}/($ qΉ|0ov?}97qEG$?vȊ@I J\!IQ)(xFi-veY\4C FĈ:#MAjq?|9A%,BtZ͵[5̀J5創?	E"DGG=kTj=Y9Uc!TWwsD^r3jc$ƙBϴĐMp6@gTBzAHJ)8;<lv݅n{ݝFgeU}SR[$/>㭍'ox8oow. @a>:v*ܻsV9_ߺy?9<<Yh^q~$x$'9`к{|u8_?f:.?@{?hozΧv3ϟ?T
8H}<?r,K|&I^GLxb̋ϟ	ˇG}mx<|*EQh 眱 (n^y+g=7huϮ:Jc!$;?J@Dh8|pǿ16˚݅ׯ v>`ܿ[UU }',/7ZmDNsNo
sΓ$i 9) Y$19'22!gn.uS\ziZndY"!B<h]x< ^WOL.r@'{j5vw!Rh";c)3羹։Օn]XZZz3]{yp_ŉ3 4;}\{^knCd0U
}N5Zmg,3ca"̲8N  51T*9<<8wVSNHd,F}duhdH;eYfR8nޡΑsp_z>&2/'$
s&DREIz驨2i=^jgR1)kl)\{Aȁ^=No,z-9 p!O=2UEq3Vj54L&N-HI$IPp!d2.r*:砀7S/v8cDd!S0d2U>VJXk3aS'M5l`z|y&Ì (az'O4R%+'JKMUQwaque5M3:]qEQL#Ҍ88Zh{z֒sSاW5ӌ3	`P rGN+B8蝆w)fT..s3!N9)2bg2"uq.8p !"yuUU,5D@A<[i]i	(gmGn'K"iOJf|RV#P} OkR4E3y  2rTQH)m\{L3))o4x$Å,Ӛ__`0xSWR<~xscڵA5{?/\xS;;7CBG}E{md]^YO<9l X]Hq8|gA8^~DQC"d;KyEhZ-dO&h2'x2Z>	,D$RQiXʀB
)c)xgLdMj[ $x<v6wQk}buɓ+K1k|' U$.ԌWk+(Tich4I:VGUPri	1&P"8qx4RR PUѸh6[\8IVVVqiʘڸ8a cp4ѓ׮]5vTXseUEJ.v;PseUEqiR'/J,KñsncL[Ն*\
I[NSdef
:#
.n7D@Yc;DDB!,C%eY.#|eq!JkmcI0`E1v8QiG,-,,//UI''yDщemíFj6Vwvv<ҥ'N?,8RYR.#!L$_$ )r̫wy6{=s={4sVu3uf _癊09fMg>5?9Pbo8L*Q[.# k0Z</>o>յw{w=yBZ]qG$h$Ǐvsqݿwgye; OlW?>.Xe>_ƥWRx.@kO9y$9$)"/ʃ|<rI%*ȃ$cS`00HԏI6ZN;}ڐ3yoGG Xxx̍3Ƹ4)"dlcѥ+Wh'Ck-~֝w~Nwaey	yP*8k'!9hwWN=3f8ygKM
Ws ա~>]+ӧHQ
w<G'ɉgxR8(1	4IFQVxg_B qjA*$Rq8TIj!cs$5\[\pQ
fuU*B7O80/0dEIjms4FĔ(m0  S|YkܢO@sח3X;dl6o`Vvw4<WJJ:$j5(NaӖWE>OO[Uh, O>~g8steU'@p6|OΎ!Cn
ߕBloGܠ8c,R(iҕ&Ѓdv 	>CTC<"m4$!"<s֎FÃ啥(,kyn=nz<kxg2:u{?|"rx]xZ=ϐJ!" 
Yqm:2daX8XkdJm#DϹ1cΆYyF#Cdǉ{c`1\޷D92&eEIY9w祮ʲ(2 Nc)= 0	 Jl6@WTTQh8svZ[9cqH4>VqnT|gfyKO8Ec]Ui\HɍEwps!H	;x}Ɇ(o ƹ^qƢDG?y*Jmqyyo?ǿh8#7ƌǓ($t;[~˗//7x}qqi<EnCd9`ƃ @fSD	9kYs9oT `à% 	Lyr9W[D8x@a@TR
}M4z{=iu.dJ޿˯o  ƹ,JĉϝǀütVeE `ŅI	!0YEq1ƍuyY
FQ)phqVw;^Qg$g{6:%EQOI d Γ(JAE<Ymʲr>.LiczqQc[2D~SPy*"z
Eet\ń`L G d%ro;HڝxeI$B`?R^r(ʿ7\tg\ksϿ*˲Ft5k'ERɯ./+qlm<9{LYܫ`60{,8Βdcs:(k3s8۶_<~ :A=g}hJėՈ|rַ_|q o>Հ_~̖g3<ö7ߟ=EէO)gog^x%OykmTg<1dx|CFH蝞t>B8|7awnw~vkoʩYw{qQڼ,:݅Nou֚Ã"w˲w߽|ҝ;ݽ{wI0E&M1g$y9z2h'NIwhzEYy8˲,Bޮ68k>=f#K8J3PomF|O㪪z'X+%E/^D䌷)YIiy!9v3;E>]B)3)b\:F>H1.Cc:A."UG"FQX?y7\lkfT$y]OrFNp(JAoMFaЮRu)UlӬqՈUhw4+2N(&I^lzf6 $!!'S>(.W!u%?k,I^Fi# GC2Se]T/;? qgDiM8d,d#ֹN>ɋp4sDi8yrks Q$-JjqCDI> }l4~_icYXPW	 'D@ݝpBy#m& ihŹcK.`#?ޤAkB(JR0mUe#cdR'Ok42!1j @pjyo  c4+++*Nv6"|±]{	@EId$CssIEB*CMf"d܆NPB%99kZh{ P9긏Z;gc,N(C)LL|(.1[9+ ^S35I^%qbk4nq~B7^o@ژ4v
-Ԥ*NGSPKz~ *miʢOBdJq瑀UB    IDAT\p.JpD{g3&%'Ͽ~geQ艖RvoÏ^YV!v6U_z}ei!9w΍G(Z]o~Y cf{{Oڵw;s7^q͕%%xYU>q0"g% xOUYim0Z{sL)848OW{|gq!qYGPiO&G~ׯf+˯vceemyiHY8x]Up2#J3<|T3Vi9L(sȅ
j BBHr.ʪLF*HI%NQ'eUq<c1!aQVVkOھpRr8, wEQejӴR*FIGS6y^#ع
%s.Ny!LBQi*LrVqh5˅d\?BH%anvhօ6.q8+5q{4UnfJɢ(RIFȦi:=㬑ziJE?,G>|l5/9sԩkkOI#˸_y̩SyQ>x/^tfuxxxO?7Ο>ubeiAq5ΔJ6h!@\8]lp"eD|hTx"z)X?{=?.	oLSj>O)SNLziՄwʟ~W#@YO)\I8YCRpZN:'Ϟ[|7_|xaymί.v4#DLYXXJAY^o{glI!J{oQ0ʊW.mPJvΜ=TdeSFTYUO&cXRrEqnu$	"rŬ@DEJ,JWUsb
!("cJ	 cXX1A1eYzV(d0Ogw\g8(}@l6N'Jm}"@D9c}G5*osͦ*Qͅsd.48l6hӑ:DDrrh*]x4*J8m] @8MUZmZCEj{s<ˎS#C1Nfv[.d6pXJHywvg8gPD׮Og"Π"gLpF<uU5&|ښHA+ZyqAƅS-GcDtW^5uIȲ碪jvlw.^O#4JeSR"bQEY$Q뭍'~?AiARnX+
+}\fM_*Eɰ A@Rt:FS)h4U3B ,'U<ic'G.N:s6N]U^^'NQ	(8Cd1"
cw5>נr3
skq!B묵BX+6tm|#y+"n!JZ\pzOιaE%dZs>+?*?,8RJ,(V*=Ue!j6UY)%v霳Qf~<}aZyr<0kS%88+52'q2Q]gRO?oq!85&՟'|xxH3Bkg~  5fի"NƓ'~Е&\s.'OΟ;{,x Yfg5+Ox_CP+Yhr eF*JmUYx2{Fjuť4mđ
)1뛛O6l6R)Xt⥷~ɓFW@dcoR*RH)(Rp%JELp!$p2{goOF!pާI2G1qUiD<
sZh4ʪ,0@,9dki/ty^ NkSV9WVe<8q!ֻLƌaUi*cgmU2Ϧmē1$IAMMI]T!8X^]`xBTX$D  紵SK)4!dI	G$EƓ]믾>uT,+?9yLf?ĩ3#31F#IӪ*",..t'RӧOGqT9/RͅXX\Q5[4MuY#.$bL)d;3e0{$/#15x4tvj $wz)ok3I%?mNͿo^tjМ!ga2!8~#~K6xJWN:;>oۯXnҕk׮][9yjKv̙/\*d<zf9'"YE!nb&"c13ΘTǏ"J$m(y)rTD9Nm=gM1
)Fx_&+Rm1*K#2ijFqѮk:7CV|8EvgAh30ttGBpI)& g׈j$bE	kÁ:M@ΙwdVӋfꩵ|<`'WvR!w7+HkC	`0Oч_z C&єDT{+s!FSExط֞=wk/]>8<.  wԵ);;؎}&	p5*]UAb0坵FR@Z(~ZV!?v*
?Pfd Zm$ͤ(m4/\l5'*RR)YE<cvyFx|pCQ2.C/ce2"Θ`l<?|}HW%x[T*M! DΖkv˴J=-ZrTJHP!P(I8N XgC<"*JySӴ^zyiye2<A/T7 @2NbΙu!㈕'x)đւ3 |ړRʐ2CBsY:pn~6r2煵huetZ0	2[G sXހ9PɍF44x4rt:"pqιRR(B%]L&z#@dQ9gm:R
y6#"ּ4挅}j)>ka]D:|$d<{ÇϜ;X2fR/>z~N<ԏƺ⒊b5 p!Sh'v;[nݾ};gRrmy X{߻w˗^n9c/UkK8-jT}E SE[ɃLUjGh0LrkJSU!Dh"`.,,/t;FEQ̤>MeRyk6vue͛o޼iBIQœO?n!|5")R{}Yv߷I7VΝ"A%J^ZfybG#k,EI$H h4ՕӭN>Vu"AI3ZszUWp_4QQą>(
.% 
.yQD03F"S!:y*v++"c9 mts *XXOGqkmj+mژ4Mɩ'c6a*%x::9^\HLXi6:8`G])#Z煔R)a,q.E4lPlBAgd(8B0ΕRic0T$Y&l _]]ɣgE&vspt^<>9^y!z2=z}tt]<˲<<<JJqu wv6 $N~ip8	鶳,%$w2Ԥ@W8]mpi{i?%iHxeC3Qf.5 |$.f]A:Kd[/*J&0ƑKo'왁\L"U"VOPyƍ?Ky~weq2>OsiS\pND0L s|5p1$BB9!JF3uEId|Șf?FF	dY---w{}c͟O6ZL׺&`/0"H!C,3d2[iQ u.;owsF7qp}tY$ӵ'rZ 9,MT @#AI0?ǿN}~8u	t}S	v	T\46ֹj̸s5\1R $/Fέ/:aD\0!Zb2ˢӟw;Ե_y饗á6`CDmxX%H3~cy9BRr~pimJ{e4""k-96Z#kyrhDd\p.x@фJie!y9'I֎1G^z֭hTnDeY,Mgs^2'uRjY3!`%Bds~ahEUy]ԁ57"h<q3.wP`(RQ:EXh G8#ss/QbbaY
 DF *zvq0?<sLsKWݸuV""mܡޓ`1@`ar![̠EQ$ `	8Q$2tBwIng3dpeȀ`\
. pΐ&`tTk[պ*k_09BIYġ"$7uݠb$<Ɠs-}B_D0ȓ!saֺvn&i01Zq"+mFVFֵB81Yk1H)WVplwh9"罊T(wֆ"^.Sԧm@_hh7,Eޯ~67PYYṋ[nܸ}zr23ƝwTɓ{/ԟú($ h]d}csii͛|~h$#˒s sON_ܸvnW4B*u]ku.Ά6LEwXsq!8,z& S娜<zI^(K!D'~ۭ֭V3%qՒQL[c@YP @RHq<c"!2%B?я]+"TE1Zw?~Z<j`+UI)Bd3.c2:2l"ϋgl+Xp<t07?Eg<)$gQ${TUh4EGCƙ ?::YZe^T^jD)%C$ IaRʳ\o0Bi$<y	YVuнMb%:k#$\҄Ob'Z*,H;;=[ۺ2Z;wڭb~~aem_}'뫯#O?+K˟~׿~?7o]z5/ͭsͷ޼{|tDtEc짟~zzrk92D-.'b;4HMaճ ^(hYo`F<V٬w.~nLvge{I =O`_	 M:2d{=#I齷΅/DM0G Koxx10.&queO_택~|{0+׮ٟt~KP?a3TUx	$In]4aEiw$VYggwwUr֝U䘃"J;/m_z}F 1l h*{s!\"$rAAqkt;GƘrDg HļVU	Dk[WTy9y(VYkp|4u0tj26]~}(I|yiLdͦ/vxpɦO7>pn8	}:ȧ 4w y=p/AX.8[mptzrv8KXߺ7h'ݺZs.y]J]kw)'`:$GD{%G֕U]U)#k	Hc&?{xDNũ^&XkI1'Y:';O_NOzݮ,ˢ~>  _XWZ[²~4*:K8RJ)>T93h~W;;TUEZ/gLD( *==\J8$I4M4Mbb"!'_պ*ˢȇyQhmֆyfˁ<IQsν-Zv(ԕW6Kqv}-!qO6ud\UY8<J$m9Zee>I!BCc9yv+ya{f@s98#,W
)&%h&=:OcQ$8Tp`SYA 2Y@3cM]ZO^
I87A[tp#L5-F>Lh(Y'Nzƹ"K|2)<(yiTjcmio_05nS.󎀂Q8ւ8̤hokpJ
HޅV90UsRpܺy{yy)IRXW|cpz_Z@d?DNv||t_n|U\] ?g|! kq099?_Z\\__m;YfqP<a5pE	 sGе2꺪˪˺b2'ژx2sk]NJfA"v{^3TB0ΝsNbCa@&)Ңcw5:<֐<ǻ{W^H
9`hj){꺖B05U]: G*҃uR4}$(ˊ7Xh;L(J W%8SRJ!(lU*Ɠ#&qD)5T!!@!HEJJcc,c.5 e>ȧ4kb ڀZ)rD%q^֜(R2wvV+{W_{n 1>8??::>;;CQq;ʝ[|EQl]vv8??:47fo/x:eQr.8=(8β	>8ͧKs^BlH&/YJ8;쵗_{:fڳL_'	K?33秔_3{})Ds@@E`%j9DkQ/C$"&9gQ/,..--޸vm}s>˳K)Z\3)2FbX@9`4QS jIiWeUu]GHF΅(!rzeї_,.fYKꍛKK˫wwgg'Jqv15LCED DDk"
b;4    IDAThZ;ȃ	1=.(,1*VV9Xm(Wۏݿwzt^^\ܸruiy5keڒu˫kuU)ύZ"  pO 	<yqnZ]7+|r\2uYyݙ٧[.~Z	vٔ
J/ZAXNz'O"2Ijwˢ8=>ں9BfKx77ן$aT*OaUa@䬭2i޹(#9a Yk|[v OHsuٰovJ{MO	g"FARܻJ!N,˲y"v\˲,koEB."lTTZkk$ DDuUUpww;=I^U;B"B('G(ɲ4k%i+I8I$Hp^C>͵%m|8G|25=B-Xo{JX
N5#< E*@Vel9@2)' ଣ@R (g(NSk],M,M$$ڭ&y>!UDss0DeQ@. s?.$s:pJJ!B"%U佳輬3LʊiTM 0Dl,Uَ68.t\PZדI2"NB)d@uUU8:Mb)DPﴲ]OR^k=D[Z('! 8kY=c|Y
3Z՚WRp&Ox{/@NbssƵ+x+~UYpAZC$eڕ+qhk%snEDśquڭVUe2/P|:sN,//wzN+kgYӉHJa-\VkmZk4k]UeUeUky0L(4cjip"J)rANm
Z)WWWWʪD+Wko'U8O>ѣG|KkE(hDJE8cLYTl3SK%.o"Su]"V +Βc,{zqdk+KIimy18yuy(Γ|hBdi:=) ٦"2))}B8=CH)+ Y@ -sAgil4(9rPK ELm]B)j8i떖WAQs 4M4QQ	ѵkn;;ӕW7?= \[ᜃN%RQmGú,_RJ\I10#}cvk.NDF>_{<JFҳ.{1~0}Oiۃ< gƘpTVu;K{`;21pqȫ&;9ڄ"3oF_{?~7?1F_v]ZZJs,Jl{A@ { SJ
x R.-.8ki]ښUqy{wZXX|/[gg_luJLBrޛ[ͫGw?_(V0ux=8ȝVr2 qJ[Iv!Ct1GԺoz& t~ScEJwG]+^o;N講el\^T>EqSN!xNA6gB˂} 'DDmU:ŕ^c	53ePB.k= q=Gqo~`ɸ#T-\ySJYWUpyr24M>6!m'"iϋJg̳7nW ཫ<
;ksLXL][8
Mє`!9$]>F 1!!B(U5}km]UYnlleD:y@Gđ#PƉBdQuOv<t`oooox>,pPkۄ8O4K.t9B*)8~$M$mI*TԜZ̚BBMH!Ti''Q5L[ME!·#muzrpΓg]qcm}4+\[l0P@+k"JAm  1ӎ|̈́uލ$MU;vIUmq@JUU[EXoH{[ks= #gm`KsƄTJHbVtgƓ2ύ6Z뢪8kց,8UuZ͈/eaH9~#"#h\YL6q""%8>@UJQZ$Iڝ1"qdYYZM<Vrغфvt1L(J"QmqNp1Mg5⦧/#SR~Ž_{udqyڍַo~bMƞ$Iso>?h e.-./?/~mk]X"@K)Fݽ0?"(R|j\KC{'~:c/iȔQIQ8ZdLJ)9ևikmm5"Fs(Q(%Cr:[jR^v^5?X][~ҝ;JQ^L	{ĐYO>gdYSy0gCR/!%!#"E 0O 3Dj08֪h1guI(UU^c:%@Y9ɹl<ɽsW6׻q|8Bd㼌Gn;'Ve8MJ%c Jyg5 ۓ9C43`ü(6\ #XDPRDJR"@56^2e" z>X%!LJEqi?m77奅iz睷;;;ӿ[[[}핗WW~ݢW7~h<x_ןXuDs^?G]/-۝nm㝽,nݺ7q=ٽǏOh4B8\EiL8iBC\$~Axux	J1/q-QK':rD35Tvү.0sX dkh˪*j8!4ɒ8H)hsXGay
,
n1`He0_{}_~w޽uV;L9X<2C(\=CDJʹne<'y_ͫWB/GQڙO,K92VuPR\_ηw?hv8R$ox9qŸ
y~*8c,y]Y@Eȏ4V$9'{w?yo}~d>iSபk⛷_:;=9}\c!x "·VR眷9$O0N'D>/~A((@]Y]cSlSlDdqAL-u!|Myu)s`	ݓ}Ó㹹8mg
 [V݈<y1|6%	'zj 
r D]uU8g3\8	EzO6O$0?'{
ꝳ6IH)RvREYlm]}7·{ߓf#8gYoۙ[4Y]AF R
b֦(KoLY䃳d4O&Q^	f; H۝iZiIıPrƦΑ!!cZ4Z  ;䂁  Ƒ -;</"{q  ddl&v'OQ RDr{PRJǣѐBD$A{ d^_)I&I2N	ӛkBExp>3uQTYH)<3S<&Zks6x9o7DLZ=Eq$4NFy]k"B	z/Y]LfJ#=]^s6zS0ay	\XcƣqQ+ˌǧQj'yQV5 ӎ=zEQ&'XeURrTpR:b+X]V;պ{Ǧu<KSk?MzOl3D /,2tZ''lvEsgm|2neG~n]R*sZ$WTRItLȢby饯ng<<==()HEp; 
Ǡ3U
rΕYH)RR9gB*N, XTF)|M!'BD0Z7zw~oeyשּׂ[{ڵp) E(|XV%uN:g=:88c peUUN%R1S 80/'w^Qv k*k<XU//QPr&!ê61c*2>3BgcL@[e%PJUZ$<"5nyBƗ1URQ3.q JeQj<1ƤRp 23YNP>K{#c#GmMp<QYx,X۝wc|2ə~wK;ۏFU1u8Oh4UOc04 )ݻaueƭ[m?ݫvφpp'yGl0onldUQ*8IDYPЈe~_Q{2/q=,idO?gO_/-_\/=8C9gC@k]~OPTJ)H
ȓw8ǂ8`O+hVERD~l]~px?}ee͵ͭŅ$N<1mfkT 0Y:="@.dʸ"Vjyݞ|8=~x'GG^O)UuY7C(qo~!mo޼{u]U5 Aufsj5.1y<Jhqyena1ݑeUIe|{4M0gueiyy8yGڍ"4.ሚl
}Dd?К]7" w)|zOCLgw36զC;F۬s?PiYQ@0h;Rj4N$(R'nS>>y(s9?8I":UҴl*rm8g,ʺAc\OPBr h}fB`yc(hs{OY)%OON5+W\\^=?;i}qDM=`Sfk[/RץΚyˁ+o(xOƓx<2
8ksv
E #DpfZon.R))8gld{<:  ~p.(zOMOQ3%!45<\(|lyJι1(ljAa=se-`p![!x9bbmZB* :pp&6}D."P:49kj2D@p랚%$641O0C-V`yBZkSGsDdʅyTM(4)t$!OLU8DgR ,&#,1I"z</4B2hav㽳2΢(BN1ɤBĪ,}cPHI"*]}ivHHXs  ΁?4'!WXqoƹ`M+oO_Xkoܾ;a   8VVݽãӢ(Zu 1%B
$e&isi;]9	n' ;k! kb4;ɒhZ7_uvqFBV{/?Ï?`p&|w(0:s69NsFZ5gHk#H!\kZ 9a)ΝxhtPF(_;y]UH`(yRG,Emlm1.BX	G}E޹Zi:cW(
  r"!)#.KdS+.c8
yv_F.'X J6c!1hߟtg;R(>! {󭷣8:>;;<>98>]ZZqjlo'yU׷oߜm?^GFu* RRs...ܸ%|Ȑ]۟EጹvۆY\q<RÝB邋w?'pҗ<m z3	_,_߁0#>rQXs="d,8 MƁIOk/' *3&Tyuk݇_WW߸vrSq"SO)͖6#1D	8Jp4l+W,U
p#yk׮xowW_~u`pVĀB&wjC :zﵞYE7://wseYN|-;ݾ66|T]ڥNe9uvNGIXk|pOXvD]h:'u9K]D<)s-9k9ss+;8܁ yB:"DObqFaظtKV'lia^&LHIm/7ggqFB2ܭ`H9R;5)b<#c4Dگ.չQs
,Zk]@,
5o?"z"B dE>$f(2d	!BenK)N[YYY8Y[xͷ0dR<[HX]x7s]Y@5evTWhx~O(
5yg!e\LԄD8IWV[jckm[c]M@)71٬pD 4F BF$x Q`~ ƌ!-.u;mH	G3,C#c^3.UD(kTp,y?Pqybس(z$ITו6{GƬzJ)!{Or09眱F[sa3P(XQXUB4 
=pd{Oxf7nShJp)
DfVS>-Mg\1c]EeN''!M$t]3q6$	6%EY>͢0qq,DtƤYǑk,6]G2"AOvˀ|2c̆)V'?W6VHApw=9=?x甒2R"VKZeY+@|0`gã`0'uUg* qh\^CUCXwQ#fk	 JJ)ewYؘnq.O\*>Kڦ9ReU 
8Z;罷{o&8yRJ:Ÿ3pp$C4}ںH0x;K"%'E5΋v:O*5yQy:'qs:D&8^FX<Jy)P(wuYi    IDAT;ZSWeBq 2!8D@ȁM"#:bszGM??y`ΦFǈ#q*dpz:<?7$Kww~6ʫg~飇ޝ[olmmz˿Ko~ky_U0)x<MZꕭݽ>n޹nS%ƕj9R4|	_Hn
1.h{ӥg`ٷ_b >i<s2OK$_Y0ljzw >81QYU@WN~~c.֚3ضghQp.(y7x{<>/~?B+o7ε8v֌&%hX|3*%E)."]WeYU8|眒2RQ[WVVHJ.qvTꢬ  r/B|Ggy>a#@}'B=FeO 
_ppjtDQYs: _\B*'DpTJJ!$wy2?lecs6uzx Q; BcCcd2'ckLн`|/,"E 2&Hb5䁥RMyܳ~z75FO"4k%ixRte!A``q.AkBn>Aa&_^][Z^UY$g=9UDnqֆV@Ud@agƐ3& vϼFS;F[kHJeN[Z7^yYۓN+w?Γ)Yg 䨍o<9mYoɕ;Eփwy'ό%罻TσRQͰ$9猵8:CE(Gog<Ǆ ȑ @$5r9$&X %aK̲ïu߼Gƹ79@dB(kI@ 1v;  `<VFYrZ$* ʪ6Ǝ'V2lesnow9zDP%iJxR< 1QOByI!xi+
` sA)m63ޔEs=(RIǓtynK@,եd|RTJ*6v2Qbظ`AE8Iv(:;9hH )8ZcBʬ%ƣsgM  cq.MѽtsNyQÏ?n./ ht~|46UWJeӿ{_{7(/CV2)w}7ggvvvNNòf.=.|X}Ѽ/Qj~~7^{="0Z2!0><;yQkˈMyQ9k,w./IQHG'GqƖqz s&qeq-//[<au{}A^""ct$gXI\&/n7usRӳ3)wms)0|h JAh#"#eYp&ؼ(50S`͞"J2ƌ5`".-r a yMcۧt#;?;D&(k~sږt!{hggg^~ʪֵ5FWbOO$Y]YZ]o?{|w^~~gÏ>ֵeQkCW_#[w/,ܾ}{uu5M?YwTe%]=>:=fdO.3ӏ}dlH!s sRY]j)yF;/<; ʀr6>S9 "8q^;w|A+k7oY][SRVUS*s)Cdأ5_#F?ooog_l?|駟;z7UUq LmIUUwueaqQId~K# o兆yʪ w^ƫ'{_~y_n?
8gRE|>q*-s>=;;DWs2
ARrɓ֞GZ>ܿVH)A'v"0-{?{fI,=R^]UtUWwY1;
r@#>f0@@Ҁ`vwtk]]G{gaV捌p?=%9[\x4:|,5uسXe8_oȴppzV3LV+? $bKhqiKi]g$vU8^f]RK4.m	B˔5Lk^7ke|mU|繰TroZMϭA?H]GilWnH `y5R Hg@^tg/07d,mʲ767=[:u ༷&qߵίMİyisҟٟ]u>\
|Y'1]-މfa~ژ,mEFu<Q]{p*̧"pBb">8Ҁ ACs ./ @kJ<3=R	"3Wx+=xݒܖL38@Jk^?<8M'^_(^fZ +<K$mmekDkdcm]ƘN?NgK !,,P@zN" e+ P)EHgt	[NKK_|-CU{V-, "ǣg4Q>|LDQyUWk @:_E67*AH\Dֺ*4+W>Nٺ(+ D!H(K?"p'Q`ڷg?z{!` -۷?m|^VZkcLEv[+rU]Uh4wnܸ~֕
  R(A{Ut[+(eQAp_7`S80XJ"DѨ4 )FiJRZ⨕&I%iqDӄ"7Be*(2pƢ];ϢLDDyQ|i꯭pXuq=)j F[ QUa*"HTyeN[v66>FY(2!U˥I㨕<Mo+² ZiYL8Zf42uU9@d<5 a4EH#:J/\9aAa:7  J	bBG$ hA#γuqBZ%1AX/ǣO_rh?2j08>zt~x>p8NGi6ϋ7kWƓW_?<:zo+|^׮_K+oܼyU_?pξdvG$YɸRjƸ@-k(^+o£/1Df|Os-ЖVqd"c*%Hz !WL<n;߉3Uِ~@<'ģtl6Ws}օ/_~뻏{xo:?|pҥ.]zIcg@+,>::~Wo[^8ϙyI mtlԔBe /CM+L뭭lo;=;<89qBce 0$S&!sUYeya{Kk5b9R:Zkhq#s 2uw߿/~U8'1VKG|=i*x00HlnBL @/o,* XV'M'C^_3~)t9f)MB	I-ˇ"D&Ib4NzUEJKArABf	Q;(IV"lUv|6E!|Y<x0.` ey|x,cA?tƥJnLְ~	
?]" A |yڹI#(2DǏkQ0NݸyJ}Vy05ʓW^wwx2EI%*A>>>; l-"FǮK#Zڭ%uU[k	MJZ;R3F@Tg fmRD 0N@'I:={%N$yWeQ_
g$90"QvڭnuVoiZͭAB(˺N'/+}@ܘ(M$I *kƬdIv aaaXE)nP7eySkq"roz3"Y&G:.)/}&UWvKx>Z%In"RV+H"@ڝt;LsQ$A^H"Mbi2) _JYW'-@_	\ rҪi=}/uz6hPl}mOܿ_EEy^()8nZ,j2ݹg7^yeggY榩*Dtl׬j*[~g%EDhBWR5B$RE+RD<{kQx0ADay>HYVk~_U-|%Q8>lvn׹d7 B$b=Qž,hGDvZ;|V:w>uUl2QJ5ImZDyXYGh2u&DB5Ahq0
Z'I<͝gt{t6efBDȒx2A3*BYi.<Q	OD 0"Dal{39B)4!fMMJB W1{Ϝ ,֑޽U]|1ݻ_ݹ˗G>}g"Ct{}O8Xoe'ϼ7o^Kx2>|D˗G`Ε+W8>8<z6݋=E^z"q@/@KS^V^|9/\ϜGXJ'$
fMv3R5߬"9T8?~p`o_>w>/# TQ0 #^x9^kP^T wy.)${nd4xx~?xݟ?Koou+"0?jϞ<`&nJR:_VZ<MEG+A 3D\r֭W˺՝>?>x,ۭu*4qq_`0{f'}9shrU'l;esz"$Ivgfˀ \ .(>Fᨪk43UB #nHޅ}nWYq1㣏>xhM'Ӳ(	)qCj∳CDtx	~h @)!dDJ<ʲxC$J) gvA턢x86Q$M$Mgu]3gtjJvD$|٤yUUytxx<\vuC5^Nم*'`P$^"^aS/dORDEQ4M(=he[7o ιM;>wxd4nM,2qoEALzPE^gx]x4l{o_BRJjwM'M,iZ(si-9Ш"d ؉ Ņ˸mAmGɀ ľp&$7|{y.x4Aev:-cR@쀌4ld8JwzzZnG  x$Y_[ٙ::<*UI%qT%Sv]DY$B37Mh <3 R1
"[QjnᛪJif")"$=aOD3p>&n+5eWl^M@1N7泙wYiVK4Hj՜IQbd6 dH"
HY笵/C x R=EPq'{w/KnUD*#lm_{VΉںd:keit;qvão._lYD5g+繑QtENHRS㛷8=$2063蕩ChMHR^47
$7lvwoI^hoo<6mp .hq	
N)UeYU}|eUyge+پBp# M$scalGi"k,@I*Ch4<8Mf{J̌:XXn
*3Ш 5"ji]3 P<<tE݋3@ @Z0*k02ETW:v/ژv'׮_7sRJool>xvI\7Oֹ,ˌ1G|^[uY ˲VY;gnoc}=Vo-09[tiC;Y-Yyj}Quz/:噞=8[~-/ϓеWŠmAP5D|Tj["yiEg.wٺ'yQwV)\8w[7 t<,}
JxϢx7%[>dCDRXq6\|?'O?~ۿ_|mUENL)ta[L,_.ӂXl	JJ0PD+E7Yp2K][~՝z<V$_h0yejl\޹{Nz~`Ig]$]$l%Ki=~?3IT' Ɓ쓭l|V\jZ& .][G76wv$s<{ZifY[|7i>{kٹ`xfx?j67 rQTuY዁b;"bmF޹l:@kY9=Y3(:ѐMTL-\+yeܾlSDAh=Hp6`t+o"ֵ-@U0q^z	Jw7??l8+z7~VӽF"c=}~> w0s*˽Oﶻ8I@`|i("'C)" (Xm΅1 Rf	}ӽ;&JXe:疷y⨕G/\Z;7Χl6?{^_!,uk@<	*$vEq|5&03!_si+m9,r!TXYы>v"VD*xBXgƢ1ȃc+    IDAT/g
DJ
;(RZRD.AUp@P`JK~mY;DD|"5,WZk 
Hl];kSvsΎ{,ܘhm?<WZQ]UQdg7DT"<2z}}}XZ똹q0K6^H{MEY';ﶒ@}Q\QݷWE={I{6JU}|<8MuvnݺeFg?ه}tqw7noX窲9''FYĨ"	7
^ 9)S.H;|dI
"xn',kmr7f ,҅	Dcog[׮[ٳãY^0"ŋ-9+xʫs>`Lg3"쯭9p48,yB"K8;'Ơ 1V4QJ7JRy1qW֋p|I3{}'iqjc)E}<fv3;}̸555^ژHd"`fg0A`	lzaRK3ｷUDĞ8NAk7yZOkzΦ[韴Z'O'ܼ;_~1[UUyQp?J/eY}yf^h9&b:(4<eIF%n 2	.~oޚ43կ}toԬʋAyٌ0p_-=Kl "ڝzϿxC1U
P)<s60I}ƍ7_)2N(vfh4Ou]UU6rvOe9p3N9-!gBɫnʭW>~񣽧O|֥vϟX;Qt:tVrf疷ikI'Ytsn"yOҬuaw޸qs<8|ɳOgӉ2c%-DuND:v+M$k4M,tX7, 3=,ˮ\y||I!^|]ޕEZ~@N	U 0)`Ђ',ͮ߼v9g[UGYB@`E=ի^/|ihf1R4 xh>МyDQd ,˪~ 9ıL""iD]``u(&d:wxI%m'9u&eYLSܯ_JZ^ؓҋƩ! {hR(ƕhq1d1QlǓR,[;f,˧{zׯSZ}ͭ7z`Pd}sq΅t}Y,4kG{ Kn5#1 CYw8kE-ޛ(H)VJ8X~*D̞ q!92L"$Pc
!ʐZtBF'եh *Zt:ݞR䙃aŰVj-	K"CJ^⽠@9m[~ѡ6(j+,DD0V :e^D1q\fDQ
3c,c-+"ԤeEh(	f$Һ{qNkM H̍HqA9h j @ xS21UE (!ZjλP,Mг(9Q ueEYFQaR:#J,V
PHX:/㜃8Ì/Tw:N:Z+)G^UH$Nv7NYn4"$ԆػN Z窪v+IhRTգGf_ݽӬAI9k]̉/~A j5DePJ<QëE\Tm/\;ouEeQRPTEDĨM_j6߾}[EQel>IC!"a(zDV[[EY,0k)4VFDDIxUj%uWIL@tDSH0#*MS׸qdVngIYFr%X[#,/X`W%133J0k9aLx'X?2:'L˂Zk53[ڲ(6:0e8ÇOFG[۽^'M,t6_[wv/Ve+:6JiBtd3qJӧO_usks{ ij+PU% V휫j8Zp}neY_8/gaKS{\%Rqn.TCN8@V#i_oܶlKƋvh X4g~SY"}EŅX<1].	P Xgu/{r]fyGhuaw7/t^pN ˆ{g4}}wƹcN⸝eeUh<綮%B^%&/.49AJ_8I/_^rh4zO?w˃{p޵k._sWx/B/h
6W+g"H-ᆈF뭭vh8'|rgN)2a_UU{6av֭45Ziet3/*2Z,pbl6 eYp~A=B	gʽjbx&J}fq(?Ph{ޭoIʍVpfS"zU1}{iDJ6F&@)EHDK|}ZuUcANHhJHrłDQEZGDXp4rdb6ZW,WS!xfY/S~%.D!c0FR%1lXze"u$ژ"ϓ̲4kCL)H^g`arRn+׮k@eILOGEQ[^`[[ݹǏ泙6zAA |<كpH
yY|_[t:Dw]]^kRLD  `H"0	E|xeD@
 =;S:!jEAxx|<8:XȲVFVXTUYgx0e;~csKkaD$Lyι+׮3hv4-(k2mf*8t6-7Cch< (-KXXY6qc4Kv

Y>#""@^+3RZ03&'Kz?h"VP@"#Z2X@isUEQEeIw:@DĻ|fAq+Ȩ4	!pP_
Ѣxf@ưHYvY8FFrX	0u'W.q03	x:xⷋ<}z};GD4YgZk6zݎ2tgOܿw5EP"BsH+XE*+`RD¢ xRZn uI9QJA^7Mzv<Y("2s\U
;im^}c|:=/
DO	>p	7EQzg4) 1N2QsYeiWZ'T(EZi0G:IZ"(I"5$IqQNeU&S1:Th",7d"	=;|cju"a)=Y /uEQ$bvyDQZ~c?fFk׋٘mY(р4fb6lnniZn|x||tm²(1^j0FF#bmZ0Ϣ(h\_,pJ!lźq}YvյeQax~ϗN]79-<Vg@^8<7ƗʩvtN~^sA(Eu!OϩC(\R49@2޻z9»;+: X.]VdxW7JûD3\v=y:X  o׍"FlpPUU@ku:__v\cuN)JtwpPוQJBɓN;TC	iPDeoow?ֽ??z/Ze]Uy[=^RI@0CtvHg޲<l>~}ch$Q|ME8Ft:q*ªk(R	@uY&Qtngŋ,5̡P(L˘kٹp3>~=j)/溠R{0SWڣs6t]nn7 i70`M{ps;;ڋ
Z)c"փVRԛ;G ģw?ǯ IFx2fUYxfҚHI)m 9xΩ3pPe B,arZ}1[[+4e}uhDp85	jX@6iH^|Z5"4_on$YƫǓ)`8Fc%,M ^)km
 (O~{W9uFw	PFaEqp<zr$Q'cU:MڄFVB^(āhT( tL)C  j 4AՎY"Z p_$Qpiq(uUUMFxޭojm~}Y`t2ew~z-df9/K~>Ev"c$ p"@KedfgVAÓĄsZ/ "u%$mJDH I, @@EkǱ&;fB"$4M"X`{Ult b%cJx2Ѕ`sD48::Nh2wlmv; @=Oh:SD4meYYX"ETkMG* .˪1iE
zj-T~]Q7J`	-Kw}677_q	r?ٺ )X88H%I):Ͳ(׍~ у0Zܹsvϟ=UYӓpJpHˬY0]l%anWx AY} ap*ϧ߸zkDYfxx<:> i_}d<>wl>Lx2{@<c\T[^{a;eY,$IhLESudXJ`;>%2F]d'Hu89VD  ieb1;~<u]Wu`
R,iYy/* ib{y#f : B
ZtS.Rֶ֊xp{Ν?=c̍W^vU_~ٿWo޽{_}(k׮ܼZ/x*ٳKGwLwv:R;w?>xｻw,Vtnݺ;g'o*V<ߩvMeXbÀ_yߐyT0iUd٢鴒²RܲwP+/":U'&Y:i M!E?dyV͗Bj@0.4pؠ]o`-=u7x-]U*|6ǳZno|{y)Z\:< ^86`OFUU	`W'"_K	PsCEnˢPJ!\~s?~w|O~,vuƍ~f(vubeoa).CȾ Qh	7~@UW104 Tʢ8ٺpWw=z:UyNƘ@ ^ŖHu9鶮1Q!砱ƂEQӛi ^!jn.Z[[K-̤TUU͝t6!JEWo?a20"Y)mԩ%2s^5VR'&舕oM	C<G4MaYVVg6qN2MLg3W׶![ۊbZl\CϦtSJ'PDN<CJ+m>{oLK4#1:MS NtZ΋8`J^;Zn,&EJ!am>ID@"6/VǟɃ{_4#uA"H"`յHu>zo}c{l̀
ld  khzzFQ,: >41`(t y   iu) [[eYUe,HuUt<T)j>Hɼ]q8sgdU()W&H@|$7w|AFk ~]_{Pz)$6QAB`W{ǌ]U24V& Zkkgk{,;u%"^i&qH4L	D)55QQEYUuQv%H$Jb4*/J>LdtТpPx$6q9燃{uU>z(˲8Y' ;.{4޹4McUU-h"4unDC)sUc.4  EasukW(Pq^hpY5 )'[YtV`9,(I^|6'_*Ko}nE0hJ( IH$ I #u IR"H{_׵x|@1"JbC]`[]|եOg{'Yzn{+ ggƔa]>:l|<,4" )\qNFzEJ)uj#֊ KA4QZUUi8JR^:&m:
1ZiSՎ|R=8Em\`"+1EJ@\]3 yPTKU[Qf/읭,H$2轷m(*"ds?&Bavv/-Çu(Ǐƺٳ={jowN̦Nu}H_bGG}!\vus}w9wkT:MMyl B'2*ie"P	wj "ΆoH1q	\|۪b#(BpT%,g˥>7\|
?77"	*,"PƆaŻK'wT狈,,IVwXN}%)m(,kwz|2OVn+B7w1W}Oq~gKׯxd2rUYVӟ^ծYְpr_Ǝ+Ad(.,zkdBߗlzqQjcuz@ 5)fUǇq%ZR'6$Nfj6LS"a*۪v^iӔ;:$k)R{Ϯ_FBSfr    IDATkƄ5Xm*ILx<DH)yggK,,@@Du]ֵ(y!	<n		d1֖ہ(DAoesa("bP	w=oCӶu5͊"4˲v'P9<*%]Ocu44H|:v$,x
s1gAl=LWT$ƘxއmxTZR&qPM|$ۿ+mjoM96O:5 uM轟N'{~ݻeGqϕME{ҊDOKѲ杭|6׺vUt0h03"8*"F{	 dY5&s\m-;[h^a\AeYĊ((Z*!t2~ݻN~`Ի;38V3ԚSpu민Z;78:(9{&$YP/ZiE&CBz9ͧ&Вu7V֡b
#/HƠR 'B$Ble(Z{YLːYq\)N* hRcj"XI 9QjDMU[YǑ,{hu$<t,$Mča:PΑ(dSJUEUo
\%q#i޹l/2G_<XiYR"
W"wڭpg/o߾m)BysQ}7~XXk(RJRqc8ʲ,2{`$$Ze者t΍ǣd}2=!"(1 fyuU-H5kIxɡ\fCY^{K2
8<zٳG<z+;[lp08/^`ٻptppe7H?
 %ǜlᒠuQ+ɞHW&ʲlcGdL("oVnd2YqZˇ5B鹙>t!Q'@̬!<Q׵8̵d^ֵe@!d@O:kYYm91+8X#E^$iV:d:is|ڞ[;o㣣gO~J`4k}D0Z4˦<ϣj$9*eѳV^`% @<B30ʰ ΊӪtpu<"+gv/'VegEFF{	vM3L/t:.99j8Th<3EQ<F[e%˼X1tN`K	!~#vśMčGq  C LicV
Q""0,DKo>ŒDY%I:HڋV)ۄkJG)m]`'kMN"Scc\g%k""ZQmMƓȻ6i)TQYedT9ltlIR&t\gg'˕uvm_ $TC=@:VW>1Ւe?/?]_\\^=~>|w?j@ 56"mrux ofcDTa^JVAE|`xz"w_{k^VT˦V!Uz%oֶ],cLyVsQi{۶ En>;9mepTJ%v{6]וwX'緿2$8Rz4/˒v.,$Ãֺi7C{So	/#t'q>f
 (" !D|2ʼ5)ħ6U]7TY'd:
p,.6]cpu]% ڶ]1/Jr1S:C (Lcr["4 T^y@[Ddnr0Jb:l6O?p4~;{#!3K'	Ea~O'kmxtH[6)4yb޹,Jd͜|>d1_8fr`= lV,@B-J0 
ЦDfH1IXfEmB;Qi LzD}tu:R"mM1DH~?8<<s}DA7f_~#9އ?GzTsxX.Umx<.*F %cէWDfCYfYֆ]uS7mkw9e&X ƀ!p\eMfլ0A\3tfcVe^fY#ea@D|dDDJ|Rv*  Ds9"r2]e1*p8H9i[\pk8rUentd/ڶeyL̈ɱʲ  띵~st!*J"BLgϞٟٽWloM[QJ%:b1Gj0TTeaZ,ˋHH:8!9u̙ѹQ;2 D%b!խmUp>$S% Ducd#.J#H*BL{B&b}~wOSBDB"mbG~_~g?m|yӴtkkjum{yuuvq)`{DHnDOwmZb;eQi*b5UJEBJ%"2cBx<6btfdEe"%:QkuD">(mR{9I] ,>bi;iFaZB.΋,j1_.eh\(./v_y%}WwݹC OOiIFnB}~qYUj\ƓiWwb>{_歷*2{D\YUmludtk<,{=x k,L倰iNڿqXAuM4~_;>緟э$[)BDsh~i"ץJf;ScL2I/-@fu ̜ kO' s]+/OD C"]叙dTl]\_\ΐ0/1`!ض޵ujR*B\"Vh4LG7^yp>:;;;?}~yux ћb_$xWjļ,{?裿?uxxoGwUQ6Wm|}.FAt((57K{wE4ڔ@kPVZw}o;nzD1ZmB{D.3(c@sm>Eeٶe1J҆ ש׊|;(ucӭDO7Wg9<Gb0J̱e37a43RhgxV=F(e
&"15| ɽkY((*M&Xu[X EdyADZg BPr7ǭsFd{{g0zwĄT6!}b{єѤsg]ӴԵmVsq-	#aK9&1<cpJQgm\?<kV1("TU]??>?}x1a5(ץtY?Rd!R&r`mal9x<%i$ 	T$CȊ(PoN(9  ϑZ4u]cjc{Nxff(!B8Yn_拏~@zJBE`)Do$T.g7_|bmeY	*xRGYֶPH =pIU+j{Omӳic`82Đ:G)¢)b\.fPU(FR231&:V^<91ʔ=:h0FHXm}fd0_ժ{gljuzy16c6uӢ6Mz\  :(ʶ+v.HeQF+XlZ5.YVq8V1	$07|oݻ{trL\|6{^p4A"	ȳLiJiCGb1]^^yNDMkvU#޻Π*ۦV lS<{"wmZ)>QMkԃu^cVB,ĻΥL98Fh4|71QgGDy1WPΫ>J֎|?ycܞN&ʺp;"-$E!!s:?qERZkcnhchIP#&IpD ",gώC DQ]KU|,@˚ 0(mk@8:`- iFLytYmd'CL0*\`2J,B4y
%"yγs~^<]Oο_yW'??zܶtk7Z}7j8M9[~gUW$g1r0o(g'Ͽݻww/]E5Ȳr:{tʥpB&hwy &aoM{gzD-tjҿ  :vQYgwl|S9fIn}\)]7S RdY%{ ix]N9X{q5nGDiC1볊ҳwWI@D~KNQ$!7Rg9Șj<ՊdkjǯƇ?p<>?<:eǓ(g|>̦:R֦̂{quCg-'aw;8rǏ??䗿8<w7`2TA\z-8wۿ~vzRZQfMDT6x6&Nj 9].q}42s4"IOYHR4"x]k:Fc[a VJvR/7eH.!"6mV	Y;$7f\(eYԌs '[;ۻRd6fggG|H쥇)`K7JJX6ｷ.hC/!Dm[B`(޿wpHTUMSCǨP|V֒>Q #LKAzιyQEQƓr!0v"܀&Ҡ `ʌN*lp !	dYYeMM6mFj\.Ju8@P	r6m? A:͞'Ϗ/NZ(Dj=Emvu@'Lۍ<3yO{5yk!r`kLieYH*! eJ+&PZ12 su9g[6mlk1|.=cAJd@ Cv;R
OcJ0?(~Ud*R$Sim}ژx_׵YlU-" Z[EJ[	1IH_Q]?Ur=! ĸ\.x<,Bk ;h\NO*PUpXyhE8̣k_{(R)rp0mc3SQD̩&	ȳA+"Ef& M",23j}ycd¼ϭs1ƲdyެVEYsW"IE׭cɴ1#E,/|<SDӊIk3sN}dk
rpPOB^Hg?xPMg~\(^yGp8nm3RוvŘk]Ye ,Z!5t4Ikݶ~bv彏! ppm]7zQ!2G$,	{T;Nk]UUUUdb&EEE_753Wѩ!MFf<{c"2=:Dd"_ŝ;` HZf󳓓h0<w!\^\VKx:K"~c\"_`N-P0)MJ)
c40"˵R114QFhMocdcMdR(<%#jMDjZ"F"NƋR*ϴs9juC^갊YbE^UEbUr,ZLgO~;wy⫇ݿx4]gwÁ 2`y<h(Y^m\̿ݽ;Gc;+a6ZvHeQU$>ѝQ!"03?N弄PwS= r~Y$t}:|   ^+Hyoc&Tafi?%5RN$!KWR$e؃HƩ5J %R ,eRb$/Ƒ	>묻O!(Eںں`kN#EwkX$Qqj0nMVl\u휍1B{yBХ]OY僺E	@fLYV+o38}g8;xwt:J<cIƼ=fv[ƽN`	ZוRY兺yIcϏ1E39A.GyN۶ENI;CfYiiZɊ" ԶMaRy)TeCD85UT^9$AUAi 3!ptKJJ1PGwOONNR(˭mB礴*7Ogc "^:@TYgS)a]Z	syk1`4r0jPY^::|= eךHBII`6L3)I/Qȕ \i0zgs ]{ǽ
*U_{%sH<]	Q]y}̊"/bѶ6
MtQHv"̂$J,˯..Uݶ{ﾻtQn9_?yb>ʋ<a8w+7$O!p Ʌ0yy]  L 18lALLOwgW]`GDp	-v	,Ab>|4YogC;#5􋈳,+a5 HcZQO~eٝUU)Ci;
zpmdJFP"	+)!5Qe&S)=ɔ"DTTcMҮ"cӶ0=U)QQWZ]]^mk,r$+H4 	RMJsj.26&Bb13`&RcO"N49Gmjx/ʪ|}۶YQdYfLhAY
 ǐg,
HTD&u.imuP |n(j8nmgy]1zӏ?G?R- 8T?ϮO t*c>?Aw'''ggmCS.k>x@mOOO~VJkeRYf 	7pgggkkʤE!i
?%"And6ʘLF)em;HDy_~蛇u9*MUUy.|\,f-    IDAT!^]]oB{׸i<kǎH	Y;fDҗ`,ӝ EEjZ6ҊBf 3NOZu[Mi!n<:Pުs ;Y803,rk[&?ɴbZq1ضsG,Vr .CTnLSQ 3p8lWǲd!f3 
l,|MtQ)X0ضm!=TW޻gOzU5Qsv{<:<w&ۻ.)pa5Ino-A GP#p^rg|!!BHo`/g>e:T!kJ]voǥc	fyÌ!__H!B"{iYyvЎ@7${Xc87{^ٶBDLfq\U[g("E_I HeƶGw6z;s΋hۙLvv.gO<1"" v~cL\IQb@"f>t_QĸX#z0}?OV'_??쓏1^{Ϳ7[oK:kV˺i|yy!6كH)voLZEM'푅	H R@BWĒP	DE$u,omuSU]/U5Pls>\4`DB(/Y][	uEo7uTlBiwwsc8z̌9=}~r|ޮRjU71ƽã7g?ǋ(h<TqPZ' hsKZH0;kQDu.,KnQ"Y 5cxMXEfQ8FVh;1Vѽ6GO=:C/ge){)12`Zk' A?RD[[Yl.gW pptW<omkLFn܏.&@+m24-j8(,pvqwmvmcf4Txzum:p_G|o{{Wkfq|vï}ŦF'!!bZUQLq(˵9"aFt^2Rj4&軧.HVJ2!G .zwmosMb\vXt/֓Ýݽpֹbyrrb&9#
t6/r0<?ͯwwˋڥU֤(ɯ>/L˳9Ϯ! 奷6GjP>\pkH)Pd="EHJ]sxx8|ٓG|ͣȷ&tʑmQ^;=kx4PJK<7Y"he>
\J+,c3c6 |n0*(Q)Ϻ6XimZ.h28?^QcMJz۷m۶xXVeBLZEeiۆY8:	bĕ"E4*f[7nVK(ښN.ffw&}bd0j:///Ώvb21Y 'Z-=~׏d8 [g|D1@d&*z_},R׵DLm)@wP`QB@t71`fsw( sB6ĺig_}Ӻr4vS ϲdm5a4*2h4DDpXm܈"n
SB(Lu17Fx
&D+F# B҇DZ`00F2<c|#Z+LheYB\3)Tj;#dAGf,j\Y /CHkLAbmضV7Mh<*˒2ċSw#KY*ëz/|?x{ϏɯEdۚO?̘|Ӷt:X=z>:wy~vTQ(od<>Ϟ;.Dg&ؚ}ҦqQk}Yk& `ܼ=/L߾DzvKGv]NБ9a)l4"BDHP
qRQd:pO#vNַO wŰwpmͶ>3T.kl/yUaقIAQQ+thWhE(_?[.OϗWMV*2D"MC$]#4ÐEH	5`rJ6u6~GΟw~~/Ϫ8ߛLZ{gWu;bͬ6ZWwn!@Y"M!renV';A	ԉsEDq>Gݲ,S9<Ĥ!a]a}"&?sOcl>s}5H>+mT_|gݚj^y<ϲ{*˼DJѵ/Mn"At_XE!OLR+%ٵJ )NF{;d4F2}뫋G_F(1b]"s}"Q˾W'vBD̋<3 lw9po0h{I
UڐH*rQ&C2nt#1B ϋis{bVJ)C&犾-` ".yk>ɣt+4X.U]ڶU;K)V.EQW Zk*n<7Z$,AD			;4Nfw:]|vem˺' :fau9go]ku[om.(1Z&)De9T-j8F"SBgMS#*҉N#ˌ6y?n~뭷{%LDϏ?_",Z,"?<:z{	 8LR733jȐQU@I Jb.%Y/뷷&`hιr0|wvwwyT1n$LYU̬cMF,u
AdE\,#KfLZ+@h:ֶ.DcNӴ\+LmPbITkݺmuWozݴfwgY>z~|m| 2ϖ:vܺe{J_}h*Ux8XBʲi?!مL&(lfZ'??{@lVşeYo?v0@ ѵj\,0Vrܹ 	VD'zUVU>zT¢ˢȲ$&d@4L5QnY21, 3AlӜ]\G#b&H4Q@& uA*G;[hk铧3x bv^76fwwOg˫nRQX%#}A+"" hbɍJ/|!`I1t'8gB0eHMU9BJK@LƗ6EPDK"swu~B0⏉rCd@EQ<}qI6K,"kCB1\ckd:%Ed>sjZ"ʲy# ]dF2s6`P-ǏFiU^VX RtLo=||>ښխ;=='VW_{Fk
 7B-x٬^Fg(j8nsIҬL~9פ3&dq56o\#vyEO\ٷ
_|C[?|Wv*?tPK5LDC:%UZWz(t؛/"I!Kp I)w{eW0k[*/Ft<N{?{/??8<?8?UVA$MXM&c+
dYRGNS%|Pa\V++]. "֦OB1$|%Etwoo4WAbRfIBB!n0<yHՠ'w&[;eYv>_]^:k{d
im u/!ݽhއZ,Wx{JQQ D̴R
76_6=Y$ ,J܄zXxH0֮	ŉ]Y8
!e9,JkӴO8sgdkg<\;{g]VBվ$Ub
Z,MG]'l6yD<$B{D\RdyִmZF mR={mc"$:C!aP1*Ĉ 8Bm(nT꠵" -M~pfdYT۬l;	7d%DTikPW"hc1Z)mN!u?=Q[ks쭳68KsZN2ji1rJ=)u/p&B\^U6	 <v<Xib~tbS  ,`8Thև/s "zb"B(J) @Bɣۦ
p4γ"#B@yY=~\UgF+td	QLFHI!hY^d2Z)i11UրXEQ!zXmkQSTU1r\-Ҋ{T9(<wyQ@gE,hOdF+A";<_? 8kE" C X.怈1&Rgyݝztʇx1~z||'EYfyTZIom>0<wQRD#!<~mmQZk!#{s!r$b@hZKDW_djDH ²//.NNOUU FYS  ///,
 no3(/.Rj<hҶno܀mV
n+\_127)JU(1q;C)"ct:릩WɌRO-nZS!x,QHBIt=@T:E0I ߶D`#Q+,Z.UUey5[8煥/tvy`D?Ydb[(1"4'HΝCU]//..sx8BGTExuueۖY<\gFMh{k}7WWWh2pH1Z*Eƻﾷ_:Mqo}/h_?oyq=V-/GBDo:ID}F7o3LoRе7;>rsؗ/+_:6.E㉬u"7ɵ mO&{ہjvuqzz~vr1YSZr;AlY:%X  J?xw__|ӽ÷~W_aQݍZqmvho]1I*Pgv'I;U%fe5ys0FTG;gSCca;Vh{]u>=C&"P8J+!$4T^D[7FUt{x{G['mdyYN[eQHp6j<?9^-I''O%fɳl8@y=	tsךw{
B BD G!E(-nqέv R&H0K
RR\
g	3
UVdeeʁ6Ymjg((fRI^XAaÁ$M~Yu3hA*u9ӻOӦ{SDkexcdP<Fw;pI"I,
mdyum<b0Yr !x6;D4Y؈ UiIDE&ƄfM21!:ͅ(䜓kZYiOK^ H5,(Lz3cLdZ6Y[+Yh9z#&N^#{;f)v㐌RA	B	RhfVJFI-X 3_^^g!t\,秧Ǐ??ϞGN1=zR#=/˶mc̜ߵy?#ceHyVDHbpvd XՂ
P-tyo:8:HxzrRζdZzQ%)!Xu31Fm4iEMxS1t]He,˲1yYeӶZ(I"n+ch4RUYar
\V0:G!pI%>j1Z!EkmUȳZ,7HWU]`moo'W BE~2qN+OG_=!Z)tGAe믽<(y?OOOs4vZY)V9&ƛ"v>j:&>$ J &0y!b94I%hhD	,tS71dNtk2@HZU]Y6QrZKI}wpSH{F[(Ic3
W
PPBcT eɡa@2#FIk	AkRⴂdixC1Ms.H)eA JJWM^]beQ(D>pљB\7M51g]bi9{)`0bU3@QUYXڦ6YZvm={:[xtt?Gtk>g'{֮ִmY)|<M'o^]]={v1e5LFYA{{Aro9IX7E[SŊMŵCa+;1?
ڒX|	<eH_b  p"b=zݍYտ3zե-8/mwJ*ZL{\b]_ɵUQJi'z2ctrd{WOhbPDy}?gœO~_EU^{oml/.KwD @ı'B,V-Wvkk4d)L1iZ,  1Dr99zw?uh	BȊRi0Kt ~815+,&;{{ɴ(+ 	m|a{efsv<}6&4.ׂ
I0(DJH[O$fN+M>; cyRLf;򑛶]->jE#a5C@B +xʥQ"mPg}IIMlàw1xMH1U
z
wX!"6&e	ꪧO"j֘lsMZtPI&i$  LyTr1/&!M6{>KeakҔ}}쬛," B"ПHAA 
 .`fwz|w?^tל7^k$!?W<gDD"6&cc;H&IiyQu8@JG鞋@4(@EE"! /}Qk`84QE82e4 2GD"7x`$̊R]{#7DDZ)eV,6S	(bC"6Gq5 fJQ!tNL.ة`    IDATtV9z!UYW+VQb n/ "EѰ蛪26gIc<ί..N̻nUUuUˬGGw˫n~ýHQ:D8l["4!c77I	
q})Sb3 9#r>\^]zgwg2惲m,o_<K纃pHsJdҵsrp$2!=vwVe]UXTY^u!xxtuu\Uȳy1YFdFi<Ūb'yQ2wCu!dJJuM5QYf9^R p9׉Fm l&b*Z*Bc>n^!5	ddQDشdE1V¬wxu<Cz~'O<Oӓ]dE;w<zc2Y`WZ"zEżBwmԋcmhEw{Heim~Tdq>,  VZɧ"O?8/W'm)m,QkmRE9 cCRZk9M bm3P,oGFQJ'S !3
ZxUݫW_DF&u	PfcN	@)*
:;!sm4a}X6cQ{{@s`1:D4$oɭJ5cfMD UCH3V	 ,u &ATh8,p۶փ"7fժDd<(H;r~g>xtpx8.|eh-(K$u~9+Y%v;;Q^0rsYfzq|2ϋr8z?ᝣY)z˭3(XHd&v\g[ӶߔK!P4 $y7BzKI`l׀MX{Vލ5ge]̱+;e[6r#]Skn&~húʕēhenzpqujU-!*E)7&@R78{O~~ٗ_>==>O_޻O&;eY2su!ĔWr5FkծDcZ)B	).gݽ.#6oȱmrNwum,/ܻD	im' aɴi,F	!Z~/"&<ϊFpA	wm&1ȄR:$`D@nέ!_^
 ՙk]tS {bBQd]\Tj֭k692"[sIB ĠcQs>9 )1lؼvyKG5bkm^صyDL:)xurvyim?:<rwDHrmZk]r8dmڦmg6btjյ-"&h=[L#=FDJ9:0NQמ:oڹ1r*qABRQc-$OZ1̺cL[!"GbRFiCDtR{mZ"} 9s{1xﺄ',$ zJ@#&Rp"$R* eҌ[xmYbA>iO.NWkbu{}u@C|OcCmsmlWT #aHJ͍~"&0)$ bN|$
1.̋<7F!!3޹{_kSlp,Yiem8"d4V,h|Hjvhb<هDV+qηK%a1pt҅bGaOvin |!f r((
s= ɋϻ5wªj,Rm6JI*	vrrGs?}|vSn/#]@>LUU5M6YΚ,eQyFJbd$8aδ~ɱZnMtmu낂V H
}YHTbyUەy6Ga0sӶժϞ~.";!ei7#ߊHt1q `U8 (*	C7~?7S#u>"@ B,Դ@RiW0G!CHSEdp>G	cZYVH>AJMyA͆L1v\x"x_Eȝ 2trz61U%OF$  1ƺ^S$7&;:1?ιd#!5֚<RWW׋L~%!L+e%x:rt`t2zѠ,j?1'S
>,eV`oQ_l=ZC+e+j2MppzoHuO@	np_R|޼|׹!gqo[-'F~Yvs9`qk㈨.(d:gzXmӁ$kPwo6}*7j72m"ݿ};YQdL `ŋ;wi"^Xc͌cDX,y>VZr~f>O(dg,/cJSL1F,Pig
{QJ1yyQy^\8ts.	u"@3J>T:Y'S)kH@J-V[w:7^_t!8k*=;kۦ	HDIrXsc2/2ށ@A2s~bWRHicHib)	MuC@|ÒXiEV1/mBD(nG`#//z9fi J'& QȀ6Tu1$Uݵ]/eFff_WU]UdK^f "s+@+&:Z&Ƿ03l6*BDAEY(z`<e"6i&VksDa"9nkbj%|(hE~R( D:&rH>x)]GJ1J>\E @l6ҟ\#rR{* )]\.yb(b9UZ.	X7	!}N*#JtxE$$d4"N5 A)Ĩ7ƽ8zH"ϬUFcy>_TU")B HZkEfRDMIk96r :DD0`!EYR>ĺi'㡵GDnJ3Eԕs=3,=OVĀ4i-1:	 E@b:O9K)ZFCTW  "V+kq<Sy/?r0p]'"\eYy *UD6HbRn'mI6Dv!	1EJ	 -beUUU͍ʬw>8.//֑6mGB	CF)eA@1ƺY$+
@@r|- 7.rEBaCJ1v>rQ%=ސ):C)J'PttR|kS|X% "%>==#Hg|<RcW\۶,VE$B她sp8Z>z<*XQj2h궻8?Jݹsb>wsFݺj5yXt]DYHBh<fbt3-ʡG9U5ܽ~G?1vፀ^kG=Y5}:fb2Gxd@З}M뿔ފ'RYs5yk5LY^|ƝJ| 7M%`sfXHOmWuPV>o%E$1 @)utp9w}=;>~~vv683jĘQnĩ+P	!ռ[R*ϲ?5_>X$<zO? lO E$3fX|׿~ge/޻_5,Rg8m5ժVλrv8DY{vvvq~ς xrx&i PJ+ߺ轈e@OT2
56}R|)q!
a֨u__]&c<FLwN*ri\""Pqo~sq76H@G&	("RVuUJ6aIGI'HJ1Ƭ( %6u1x:]QY<xۯO2LVs~ xi!o
`^wvv1M]_^__VU)"wۯz{j:Mw9BLI#&Όe>k뺶^$YkX4MZ̪(A&ta-6,oMQl-%N^+[ke9,r ZKJoE8bL" ")E05@tR x"/lD@0nWJAYoB#b;1^q NQk͈HS7F-Vŏ!",@</,xP͆S1WWW׫fN~WgW# $E(BHE)^&!"M
QE"SO#nVu3wvvvF!xD*Ǐ_](RkSZ!p]- ͋< w>q4
sUWEG,PWAR;\7ykcm}2=_}uqqey*(>BQVUUUUmhK৮{ѷ\UD%1aVZ#3ae,Wm2Jnm9yk݉$@WW<R.F2"I%A/O]ۑM $Gi	^Z!0K ?~yS7Q$sCF$TLfy)"]F@&/l8*RWjtiO)r1 -VUڈs*$Ady!3Â]ZH)!"]u15x['/-}q6 F2/ KBf;@   C p܄TjGB" h*vsP()EedADce2]Gb溪.Sܖ;;`E9wqy}b>OA lYыpT:|շYݹw(KA5>ѣ;닳w'a]...{ν{]`<Lǣ|M۽޻MW_}l,FqU77'c+/TƘ|f<ߵոsPGo*t^ި҂D4yJ	Ms\a+bBP pj"o3-M^*fow]\Guo[?kqLoRͽ2
xoI"}eXnL!7ߴ V۴O&prqz~>UUc1$qfZu^jև/ m6"*'wW_>O{dwEo.ĸ\/NǣQǛ~&*l}@*tFYQs.F͗E+-]]^^~ߞxe~ãIu	Ϊp<M ݃enM6(c"0x6HZgXC @>3bV 0#DfvuQwa4
!6*ϭҚ9)qι2ق+iFk+̝s) pOz9%= H ժZ] Y^p2n
׬vLf29xۺm*ȵٹB"stGrжmZxRŧ'Kr3ĠpMZ緰7-w;1;~kWrB	Q^G㽽ˋJ$eB4LV5Pb>MjՕ^vk@fY^Qb18
26nō}P̬"D"P
cxWn+I&aImɬ1sĤߍ5O.EBHwDۏ`H""fWoQSڈp{f!RQ)ep]+adngn|CB+g	Җ&6!_~wϊ2*>xgyY}wB[#Zpppppuyeq[m1/Oc< TZEl$ct	HDJ3)<{Be&PD{tBRkF ^)h	MˋmF!)MJA{{J㓋O&cmweY޵Ift0HaÁ <Nǅ5upp2w]ij׶;;SRjbu0>b=<8PJ)ӓh/OeYpҷ(2r8v]'R$Uk	޻+2ˀuLx}.`\v>aaL#󯾾wZHbdFNF7;[l~<Ng9p T  $:^?ҨD8 0b}'|WuU5MCBF$DMmR66+DF % p>x%23&U,="օ"
ork2kS "k[9F#r0Ye&DH cD0@7R_ސi&
 m1&flUWއAYvm"^'@E 2)6eQm&Da]ݝ2:V{j1ynA"'wwh4$m[52
4_.WZ[B&WyW?p8\n|3_\WEwDZUƘݽA}iʲ'/EeY<<`rU]VEn-#g|?՗_~_߽{o2Eo?όU 햌P"-Şen$%eijp-ײNoµ9-(_l7_ۛ}G.vo;Ek3˦oi.o+x9-;So^nG@~k51Fimb~5իںmi$s'#y?EaeYy;N^|__?fgoh2Yӹs  !a4Ӳyfň@@kR!]DڶG(&{Gӝ,J"M>x{`+G;c_-{cF`WR]D`,!۶i׹B UU*SJ!c_8H]7g'ǋٌ̀'FH|KH)b>m^X;;beYƏJ2k&kjLڮ{u#'QO!$	FI-^$Jʤ	X< $    IDAT܃Ǐ|>_\_jV</"uPɄ9$9"ƘSBTHTV kђuiYHkeYY.D	"uG7n6׀ɛݯ]_V֥_?o	IcToD+RZ a~KY `3E$+fXC
t91&کOJ0æʙ}Nb!B`y=S!2( &ec{vz9"k0g {G>p׵1*E  ֊6FSBLLڑdr0JmBFT Q|A?BP(c\,WY)1D4]\\6M {!j@B	>rF:ݤ85Ѻi$\(>DCH*a!պVE!Q4ڶ*ϲ|P,V+,u+fe"0x25 qU*IGhevj	e=!.0!euyu=*sEuX6_}GG7>aᗹے,HMۜ|ןϞ/k 4"eF$:/E[	 RyveH1 XdXm;&VkUVuDmA
 Uh8<88MXy_u6.D,iM	{ιNZ ⽫0unz}oP #as>$:io`#V9#>ܲK9M&ڂ(Xxoogg29?N6	
1δ~M]3fQ"nZ+ڠ@7\;N,) ]\ϔR;ӱjX,IE]?zllB:|9_,؟_8㱤4
QGPJC\\v6ˆAfv2~w_BbϿ=!ں7+dX|Me&j*
zctŭ욹[x׷[^uܚgd"|Ry+.J9vַt{W7{K!Ve5e66އr'WT8mz>8=Z܇nkaDM .5Sd=.R0}=29<{77_>_ϟ>}9ᝇO}ɝEmh墋zu'ggӝig1B  D2SgG]St#"˺RCK ~dLk<;8spxu~uqvՕǰB ,/v߿_Fyqb1_^fٜcdw-, WΎҦGF$uJM3
:MH;BD@ig|}yqFJ1?n$BJ׭\G>H'&Sa6gO4ވPGwj޵m\Nɀժ*mWeA%e7a	(i# !:	u*`4.<Ϗ=1m{vn?y4McQXyiI,]u"jcn:xb "c	5Mr"[:i[yPw2RkT_K1ZJ&ҹO1x' CHaٚA+1iUʽT%|uI	)ALu!< (2oz<Q*ĘҀN|&W@`0:е*@1FhB8& W7f]gYic1:)ucQ 4 Gg):D\eUYer}uX"'ЬE%Sr`IHPR	  +Uf- ˕2# )"J%L`8!x8-WhƵ-HF4yMX׭ԶJB!͉ۺ.`bc\7"1{?9\Ud<ºإJz>>EWךv'!1ϳs_M=hEwaFBDj:99/~iZav>HM	6f<ϋȌDɠ8"!3sYg٬,ˢ,Dji["DcٵmۦZM"߸׈,
 w̜`JklV~$pl~ !D֊1u rZIGBdmҕR]GJ6rx- a׳릩IQH8/@ ;1ˋ|NJ,GCf&g%Mӷװ~d˄ض]S7uEadwoo:kN.ޞzU7'iWu]Gb0
,{έɲu^Hxgh<'!M+Y^pm
(s|^7qYA*2?yWɓwtVA.o96W/na( 漭sc}MWR/mmI=r,(VH7KmWlV@>5eÝ{ja@bߥzlIݪN7S Y\3֍[D6
֝.l0
hݹ訮ߜϗ63~Obgd1ᗰsjJk$|G?y._|_,-mV=;i׉u#>|tj98}}d"xgNnP5f23{˪\q}3(e%e. 1"wVutsZ.4Vw>'ӋkQ$7M;Oտo"x29hA*i*%u6 ffhZF*	]YWb>xτZƖuFC ̑EK:  :׵U[/cG>_!*JdS'"r0ܹf/r8)\]9WUp/PNNА=!2:
H=L:D칗uuZkml^|};$yʵsTCEk55g^̮ǣx-3:7Sr[k<]vk{"*actĐ
JJ!lec `hJQBbp" DB3;wD;hoDL.on Vy{_:iGn7];ZEf)R
]m]ۮV&)!$</qDa^2kR(cBhBi3[kE׶)bt:qMZZ#,c:VJk
k,&/j 4&A F~c@l^TQOONjwgZw_8QAYGAC`ܚ:a$KV4O&qB	 ML'ccrY|6s]t9+2}Uľ9/K)g<ϭ1mSkc1!_kY8-Vt2KclyvqLwl>GB4k$<[pDDf`"J%H{D rkgߞ/?~~^Z] 9\O?g/BJ@bP2Ʀ?0<sxpxjUKD+kr!gϿ9>9{ǰ7|	FA۶׳ιV  ZK4TMӴ&4js
ŐBg [ NX>9:MZa FL`
$ ܵ!c6  DVRq

}RU yX	H VF%/L9f@@|e)@Э"\UmHLZ!sݝڤr51\RZeY6b(jιIُ @VUv.%37mwޝ
~|]_(2t:%ew/}t{Oǃ촭4ug;;huyuYJ)52v2勓Ӫ;{p2,꺺|q|Rѷ?/翷E{eKj
[/R┴^j8n*$,qSC]WQo7^~4N_"KMd[/F`:Mtb&QL)֫nm޹9ʆ%&q[	&:?⒎14-!RGrvݵMJv .V:%qmHa\Fx޿o~7_BBE1c]CwdXu1Ut]\̛(cn$w}sMӄD0A8?||s6//.?'$S)ޓw._<{u:G~e{>8xqw:_^^m M9B1ZYf(j~-	aM"/}$4E=e"}Xn&0֖V{\SՋoFStߵ]{d4QJã;r\Vd D<<8xm5_.mڶNU(  ϣ޵\PXz- % Fއs1?1ÀzgѠhV^l=BQ")äC00R^WU02 RQVJ2RV#"~b5@'u֒nT"l
+qk!dqsS&R}8D+4l9Ȟ"%ir36%9Ϥ{s0"Zt\%1Cyb/rPi b}SUB׶úyf,@ 
s$3tj%Gߵm]mO;'!MӶ׳bP|1Ih(tR3Ktn.lr`IN HIMj}	֨R!Ħv&w>;96ƌc/.//9hih:,Ǔ&􈘌n@#2":߶qs3FwVZ-+@6u]Ue!17cp]˒ղ^-<ϵփ<S^{kLgKGPUbY{pｇ{97O:"裟_Η~E4Ft|rv}%YPQY}Dh~?ruzDBY'O=sx4ٝGA,uiry}}5Z-u],ccS,pw?8VIBvvv|>Crq~~~]:7ylC?|w! ̼AZ./ΛͬV1)BEfᵻF.kf n	93".DRTIW+H`y.sk3k5VMgB)= =8r
u5/ k5)"wma	Jx4TJmXd9!Nvf6``:>P&*̱kޫI%;;UUYZt^`bXϤiKpw	 (}UYY)B:|Ȩ;3 id<eGEp|_h)W6[[ۻLt:֩DeY/E[)'c} p}cc{st=,|s{{{k(Mb|>8~o6^>~ڰ/Ll퇚}a8 #". `[&O>\5n30_}su[5ϵ$ȝv,"WJtV֫;W$.^'f(\{Inϡw>+s-Zf=77vd3Ƥ^?Ip0\Mf"tYkWK(}`%h΅µnJÃ{Ͼ>=9l^dg_~{vQic<P*5ΦjGPRP{ ϐYgd2YﭭBnƣhc:eY5c+/LWq4~/*39όZ9 HΔ$sBdB\ ɻ9ΐtS^Z76Ӵ#rl?wo{w
mI'JRk]YU>˲k I_d'84eYÚ55#9\h PH@Z#2)UE&s說THo-cKw9t{gWJgq$z;iB2	(m42ʫ,l} !6ec\I"p`(8+0l9D "%kƹ"=Ho8҉h,G95]z]pkUUW6ZZ|@+t" CcsJEk󘈂9g5ιX6@c\8ɻ(Qߋ#eu>Zt/t{/W**[TEȲ(cj<O5,\]U#m|=!aH01!C;ow{kg5:N(U!YE\@[kkZ֖̓e9"9M`nr:	ƺ. TU]e-` y(8*) f9 )q!Q)=0C1~B\MsR
k]Y޹(RskZI8RǑv"b:RA7T1b){Qzz:;98wgm֋//A2D"ˈƺ( tv!`oEi35p!ʪʪk[g'E{[[(NEQygl2gL(N8r,"űNkc	˳`6
$pHLHQz69uY`XZk++cy'Z8^[[l2]v $`NDΘ"&,/8dTYDA6? CJ|X/߱Y5*@Yg<8"cH'0x,qR)mLxr@ƇYp)4IC*Ib1ϲkuE")I	Q鳧EQpΔRYu Zg9gMZ"$seYUEs!oc|ݽ-Of8EQXkzݴF(#y;RI2罐j}4J;UFQ$"]WUE$'smtLq?{fi)By	no7BHѭ^b(_{Nz~\ۓj-C)Z|sW5T\\*=-=`%_GKyafWVaw]3sulff{nu	'm\UVk    IDAT}ӟ?pޗeAJݽ<ϯ&g//WYQg1CŁ[:(
XpΓ8o}Yd>'_y~wMdSJN%phZ;,<bGqUueyYIB6L~Ǌ#ՀO|՗u]?|m!s9c  RovQg,Pu/gK~g0*%q\{Z
F{s`b<cR	񥀇䬵ig-y1`O9CDk4cxkmm}|ݻfYV/&,Rn֕/O/TJ)y:8z0OO_<ol^[JO^<sxk
D6psiysLlmFIɋE	8QuTI)3D]gN*pcev9x'iÅl6MT)Lˢ*K]kM5c1r$LHBHio cLx ܫx-ܺyZ!\N?zg+@Ƅ`7Y^Vu]
LtuaFy" Dyn[ͼ'Yg"T"sY(aCSJ{w'/yBc,g %Xۏ8ud6_EE [[~wk{ӓ󳓢(v{$+
oPp呱fP9>l;g5X[UUMYVqt.ISP g[RI䯯*JO~&q:w~quD0/HűK09G&dGAE*!(R (uMP
)CeN %gUU2D!e`"*P@0ϩ{k亮uv⼓F4z"kGw{t:Ng$/I;̊/?C"zw~Xdqmo.WU@II@y^t:)4F/gv(RZ<v$L4;DB//ד"ό:ceDU׺*m]g D <U˲`'iv.8ZwژW_~5r RRֳyD%S=)t0TI]Vkn3.b&ӹ&N+I#C!)liUȖpjr"p7ԯXs$B)%`uv8H0:%p#u>/G\J)@D뉐1	qA$Iu\sd:ˊJ[jR" "qrT*Tyx9cZן={ T#޹<.Y[U"ABm=[.鵳6x]Az>{yQ|z=rv7GWd2(Ib0c:ˊ(٫u鮧iEu]O<;<:B<Ϭ[[lzSR׷wv~l|qȊ݃COO%~G-%Y`_db|@ha^oEbbt^~GG|qy?-]BtQVdݕ}nAkwگЊ7E\7{mq][qei^h7ᛟo[ڸ$-j}8j<<ϳ9d7 8͛7]4la-,׫./$bwwgko?/x?_f=kMUU`ԇQ\X>6=p	=n RjcaQYgYB>xh4;_OZ?z͢5qx$(q0?&5yyVuQϞf9Zic"Nb]לs΅`VښPA#28SRP&8Cp x\a5cL0Tg`(I"3\6ىWނ6 dͬpo&[;^16m;z z0wxoOk뻇qM|:@RiG*lf˔=g=ERI$8NRRE42Su,SS >C<@(r+% #EAomoٵuCĪʲ"[˲x;톌b	;iGEj
ݖ<c\P1MCtRQU+3'A.VK,mU(3u$HMdFoz;-ə~ <$^hOsK%Ex0YkqF΄BI<&$  bNֻ;<E/(wte<@t=3_\^Oʊ*tG?*+ŗ_L.΂:hY֑AHqqg	B
)8QXM:2.+&unv^  W Wuz:SQgo}ҎkӋϟ|/^!@!pJv"&LƑ;o-(IΓ`Ed\SN'$K!q.XpѺRnq\x<ۛ#ƹ&|8{A>gks<?::|Ͼv;`xO__O:g'S- !a]]k!xӹgnǟ=wu Ib9"u">qr5OfJ83Ωb2ΓH1[]U6Һj8766 P
#u5Zw닋ˋK0RZѽ|f]#0G=h:KG3m-"p$s^W<˵1;g)˜ZQ)jP0d1dG&x[!db[yft	GXk]i- 5q^[O@a$8CYQsgmh<J)ʲ .kј"bm[=DR3LB=;;J	QF1Zl#)K/&ӋZE蠠8!B\)yQ n#$""8rmLyQG"PR dܘ=>E11~z~Y'R`Mkz6Qtatzz~xt$:cOX,g%"Cj6e՛{~="ϋ}?ч@g XZ-A+ު]`!,Z?t\wxqyWww|Ȥ!7V:}óy0XV۝-ڡU$aN
dKXa=m;_M.ڿj^awNxg7|Voj;-:IKXᦶ;W[nOsTh4fy˲2
r;w!"ys<G^hskr|WO>mmw4ɓR44 *[v[ ,NbyGkkCT pq~/;އ-jj 1~Ƹs@\J缓vwv|41Z:[3t];k!dΛ&gD|U|6E@X{L+|A@ Ɨbn (TCv!g]d7_nK)Y{u~Vx')
9KN]K=\B]]_q>wF8i"@&$RAsoM^@n>ͦד^ d@@QH I"Zs9uGud/0cZE6/s]Ww[feAD&8gܣ@d9/zӺC!_|ea;{.
΢8⨝DV7W$WR`(+RD1"к$N
$;OM!Bq4+P`"9gY,y BJ΅'r8RȔEYEI`?"GO|~zzȯ;sHuUOOדT<ܼ|UUnQ՗WB"6+xضBJ!)#c3%ujSWFׁ@[yOƝn%m=MqKϦ/꣏>oq_BJ9ٽ_^^^	!zٳeU3QXs!؃B(t54ayǰ/.?at5V^$pѵ2gtl(\x'@n4NbՕbkcp_'1g}a1Euߏ89׳@Xu]_WY|z6ݒ2L"*)bFIYֺ(+95Xc*1]EE9c]H=8IUD.b)xoLUe .,È(zsc,k`΅W3rR8h\@q&9~l	/'[$,	<Lx!x<,W]s.WA A+M-G   smpBz/L&4RB,Q*RR
Dmn@ xlIHkX͕6ÃH)m-yb8>>=%x/ nsnR*Z8AL{TH<</<v ,Ҵ{ﯭ1!K#L&iI_0IEYV!47R) 
:ɈXU9tSt@D֚(rǌ˴Rk?~>w$el\Caw`Gt-rB0KvClM q[q_NM?{Wĕ@K]כ뮴\PnW8ӢћBvUXgpWepeR0](푯E\;ln<Z=ɫퟍ _E퇶6$?L;o-U霳ֆbYͦu^hGa[VG0:UOJ7l]sƢ(;(/_ur峯wvIʥTJ@Z1.#ԾhYl;(1f5
L&㫭ݷyo޽o:猷D$(N4I,REqwaDEy B@BVB%=,,asd+WQ$ h޵D"d
-( rKL h#x}m-"dh+\׾,mSk#guUN'87PHr̳p}=IӰlqwxck,lf3dx
o[!c\dbϦdr=l{wom}#Uc;(9c@R^kmTw^
:ݞuY\UgEYgel nY#cZDDΚr8qUEɦyۧs8  c Q8aa1TRHXF-!@C/{Ao	x}5I)l.<ѡ׌!u\ )>@xkC
1 +.y pɓa(u~kd|kgr<:3\4;uH~1]xt>2`_;֘9eƖK!R*ɹ	^&O\F*LuU9Wsc=. h麹+'`x[onn/TIZ,_^ln˪&s&c9@ w!|%Or)"
a1kkJpdXK#v=+ˏ?Z`( 8zq!:I"z|=]8:xe?у#gmY}>'EQàFf%EGeUY礔R֞<GN=xry5)2#kIj!D1!e휩:cL],ςcIH[[Wں&E2""d\ cEIqՋ,+"/<cȢ(r
κh Q5[X"RK% -zX\0*ɅY]!
[Ȝo$@f|l0.׭1ɹܶ9.9oyhJ%"6&$1dr:!Φ| q.Z{RjЗBaYCA..ֺAv狅:<lkss׹VʎyOg秧'4F$kֵu6R"="[hch1U^uRqZ{#j[[GGӴ{z~_i'5V)1.NTsKc$!fiYV: J҄1^EehGr,/j{{+ISd"͟띝.61oF=x\AF 'iQћo
wa^y-~x}õ.rs%[v~X4KhJ+ΰef% V"7-Y=w-9oZXѶ5X-D\-l9,L_uX_v$,A gUY<R7lt諤$<Qtwt'g>|VֹVs!z֘[hUw{pmMY5 3QH99s(%yh<p0Hr,a?c{BWC{k5n'5Vr\"ڝ,rv=kͅ$S"NeDb6MλGDRu˲k5c{hN(s( {tryu5>y}劣u䢬jXH6㽃C@Azggg"*g6x^y.Θ"6!ZV`l_,fε뒛ZU Ā$ <ˎ-HҴo@ ER-n佮JV0BY&rqƚbk5|n(/E>r)h3{sg.;* zp>zxqw=`Ӻv!"yd|͒Xwpo~}},?w>om}l>?IS)!	s)BJ)Uĸq(0\06(%8ʲj*YkQ&rhZ 'p<X( ˟⟺i/ӧNy??H(VRk|E=/ hcu]-<(@	.ytnPNk1 4֥I4:xx6!/_NQU'''Z{{;74MkÐxk7[,..@E]q҄?Olu=}wW}|6_'3'E	Zguij2/ e5R[WUUgY y]M&pxttt||}=M;N%I'I,X`jbI:68\zX\\\,EYVU;iq1UgjaȹR;PgmQ_W1" qUU1/:"vʥ.2 /C7bm;Mȣ	kuE1KZk]k( rBD%uSQ7ZdyOA)    IDAT C0.y@'tHX֍΂iyԵt;;õ"ψ	"x2>=={;Zkc0\ֽ ,FV>{k}drm'C?`á`Ș׳o=9sqqɯ;cyV6"*N;H	X")U]WD{r[nW\%i'{;1 Ɔ6&+4G.r88Oٟ?%YD3ZG k	w@Άe2/YWWѿrb|A lEj	.2C&`<5tmyb0lIVka!ްڹoM6w~ohmm%²I[&VM,Ztj
h?";7Xoj6kgs;\[;ͧz652Vwzٕϲ,+Jw/?/>?}zуnр2x[R9G{?ã1<2d:!(+ze}qʲA$=xY2??=yy/pe䭑GJ۰u	*N: ,9.TgWh=oڇ!1/,J_2_AHaH;"!cT1g9ǸS1TfEI{[Cǖd{"wS̑}qvg_?|ojapF*_t&דtꝓRv"a-*ImiUYT,4doZ0B0@$J8 v_yCJLݥ{BFLJ8G}")U'Au070CPDB&xpǡ:TeB
)[vΙsn<oO+ě^[H{ WLnn1֤^ΌOPEq$`	 ! Nqv6sN :`Y":gzk9M=:/%m(2FO?(=x`{gWQk97])ds.\ιR!hĠ8o*Q1!H8sBLyYk/N.ӉY<x:(plIU`~8O?_}/?ÿp(B:1\'IλnpgqUApUJHFiXkKhoѽa?m։h4_ֺnk}_M|yxuټ&ӓK%e.KEd蝟Lֶ;?v;ٯ\Mɪ&m]$9O?G?CDά6 {%Qe9bc=|7c'gu]oná\0HA885Q9d U]ϴ)*$IfyQX>I^$11hY-'|6_]YQu]sz^yiPqt7GȰֶa<B ؊7fD'Um	`Α'CD3EB੪b	1$5Q'\ 4yDpKegN=A6R(8A#J|~~1gEI{w~1Fl,@|dXIj Y t{҃ E#cβ\밊P o~fbdTjwﱨb|v#,B𲪾ͭm.ϳ Ig^_Kưgg6,s!t6DG~)98[pxG*|6i᫛eh@
{`W7m+mn@{Э$	}9 %ͲЯmru~Ż󡝃w*ηV?N7[YW|>)-~EsuWvu'⭚;G[V{{w~oh/JEq:uGE6E[gds[44!Jp}m}8=8?y1>?L|Ӎ݃FӑI
yk,jW"_W_gdru`8viv&8kk'bi,^׳-	ҷ<2hs MSV4Jiq圇skN-KgI7Jy;ą7k("E_	Ua#Yk5gJ
!6={.Nj5&1:kd
1D)Mϡv98Cc[`@t]k}g(@E3)R2Tb^ֹ BYL(.DSMpy-!l(&W ;#5.W*&λ*(8O@lECkS
b(✳ogFkmBF,oL]U٬*K	9u2n  fes'x	VZ`RIE1 PcGFͭ~{rƭeeY2wv2OƗZNݽNӹw'OuUbH>"9cB0.8!DL4Yx=pVprɄE:Wy8:<^^??e+;<9?:~<///Pb)H g@7Μ9 #blcGF0F$HIi]dY]~ΤeɅpjd#sm6{qۉ"e-r9Es^rs|AXlo{i!FwRk^)e&"!]k_] DB(s,+:shc<WR{n#/!ks"rnIkcw.ho&IAm?Eq1B/ʢ(,/,˳,FkDGI+"R"c 䬩Z*s&uZ\Ka켳օ2M|(cq32̸֥icL$1"11.Qb=͋ckER"9gcA9kN*8@EϦӋKc(|>Zp)t8q_]]cHUum2FrdLج%ޓ[V0DDf.˪,KP"@ec+z{xhss6WW-uQV8%eb骪)WFr!Celmn2˲e(!8dMu]Uc6\[O;ݺ.2"Pq;xxR:G	2ܙtX#nןވ*U2esסߴL-3Á57KM&ߐ	i9~Y;C;6ژS~z~/T\EY;WMcRe%tpl=\"deCnیIh0c5-,UV{~׆jpv j|~~v9,;ϚEĻ {q%*(?|r1??~ӏ󟞼|œ'Hz["8OdĢ,?cc5˗Ivݢ(W{_;Wz<&AtoD'k	!O`wUĹPJlϲlѬTQTrV3]kc0Թ`.tDM)|{o1 FsmAdUU]Ӫ*F'M0A`?z=%ϟ~*2)E1v׫i/\Q *)%gA9g#Sh|{Cd/譝]T`08;yz>X8(/Dx Jf?-clx8ٌqs4~s"!8K%gϲٔe;Vx\(i&C90.ȓ.UZ88$\Z5go
=cu0^p^@<vk_c5+ OkjgssBHXPxHkmv66d	@ ` {}B0)FL|g\_]c$mlw$
# ~œc pۢ)[U g(8ezsC%0Q"/sڋŌA`DD`}! G^k/>xIӓo}{Ϟg8>9y?gn7 %"
XPr:"ou9`IYijI'"'gIno7G\(DyKcL9=y;677iVֵ>:᰿~rv\	Tu=wTK)?yG?яEؼѽ罒ż듳KkZBkP<B,#3ƄtEDQxEÇևCg8i"9`g8({/D$Iٔq6TRۍ8D{B& {5Iea+\HUtO.v 4|%F$@5
5`X,f0*U)CG7"*RTuO,q^;+r2G'R0VwۭIJ?=:f1"9)mtKc "B9#(U1ƬsRi	5)㏯qYg?c˲,9)A>s"̭Ckѳt6IKHjF䬭jɧ Eq(
HY)#4Ɔat䬪Jtsɧ$C"rEЁIx$9/Xi'00YYV8q!)gy7n?Ɠ۷=Lf"jw:M)h2EFi6Zi $qYikmYm;IrdgϞ=}{YQ\0!¤~WDq./ۋyWg^4\?+~㱰>ʇ^zkb+k>`N$x
nqpĕ h%papeYhe1]_z\@bK+p˝Do؅
B/g]}j"5siUwtG>ryP-[uy؆KWYVO.glssyq|vz||?=΋J}˺ƗZ ,ј3t:wuv?{A{7z׶vvr,lRV6@rL0
*~Bvn۳Yxy0v1C*|8xjϦkYo]YfUUv'ѣG8AJag3c VRZg(,94igHN-ƘX?ɰhܸu獷͢'Itx<	8_

h/$!0Z<M8Gs#%hFBz뜔9p֨2cuf5Z- B[]yҴf Gɬ(sU+7yED4^`9U=MawxtK9GqD<d+,߽yh]ུ7)2 !"(
W Ea0B\	bDVU;9xa,K1aQZ(LlJ00(*sB<sFPZ Z`"LUdQ$gZ-h]Ycg㇟}UR%ijonnu[k] &"cn޼Uk1ƸW9ÕԔ;m>1pđqZ(l ZMH 1rP>3	'7ެ՛ß??:8<>xv;vnj)1Bl:3"Q~2ʔuVk-dɲ!11k7]{x4ݾ}6uFt|r2e7vZdrrz:F4 u|_<|ǟ
)k86Q֡IhAIOǓfw?=>'Z8)rbZ@<GB&eE?8g+xtz遺[7ouJlg{+MSd1 ]
6KJ몪s5 looyY L\c"?YY)kclc鴛T *'cSVUMU @r&m2{"`\%#VE\ *"ARuƘ>gGˬEѸ3[2"0?	A#CkgTp0a Q !i5sm]VTU|? 0BHhԉR/m(*utt<Lnn%P2nTikͬ(?yѧ5B*ʊQd6v eY*mVBEscd4VJaqd{  u>FF<;=fz0"Im8pȈ 6ZqeR~/ZYͭzyrr:Lj&2^_vm'JjlU>(+NjJHMVͣ4TM毰<-pN?Z~r`!܏_v^Z^xI(K<PH~<%w}\=w Qmmn6p4$/+c-^_T.vXpEqG7=;yv0zڍv%qp~|4L2kc6+L\.?>svbeΠCgR2	qh΁6&zJkgA%YQUE^ReYtVkW;Dwޮ9}g	L!IHY=Fv{{g!8G?̦x#NkpIhsθ3#2s\8HY0JrFd_:Xg*{|Fy<#"g~-A0edeUUrq·A>5,Wybƈ=ʝ8g$|dy^i-DZٽ>|n'NaK1Σ8f\,h5mUUi$BhktDUU'coZA/2^6r1.'>g1gXkirk5 8JUYV;cCBp1 {{Ow6kq,z~*Eq\kNNj0Fw4
.:0kkp6Yedl.H+{՞\1@^*x8@Z.d`v8!NǑ!C-IwZ7|K2tܿOPU_?RQ( Ngtg}-xbimPjkJ)cdjZRR ;d<~vtiwZf}<4-b8M4ˢxt:Rcҕi^Bo(l5eUe1>,/0! KX8'920ȳ?4U%	踆    IDAToИڍ=pIi:ys`4?u(l;[Uߺyn1)p4B8a q_߼`YQ)e
0
8BP
d:l4Yei$i&IQi^+=Zk	9 "hdXchdD@'ɁQjy1
IeYMgցpm}]pȄ/z  @7_|2Y٤[y9χWdJsVӃjcsCBJBZ1^hkֹsp8q}gLk뜺uƝף0A8#91Y,sQTܯ֩J-i~ʪ*ʪ*H0P*`aT-<IqEders;@UeQ*81Ȉhckz`DYƄ8b2qd<	H2	v;vwwn\\td[ wߋR
.b|IYJ~ ^TE}" /t6." _ނ~uDY.\B.<Ӗ3^{վD/G\_M
e*_8D%[FAqjf`,˔OZ3_RqnZ2"ju7n꟝<y~qz|O?޹vnܮ>99<ȳL˅D"!x܊ڄeZGQ{NqFGgb`jmxI~j-i^U,K#cJJkO{n)s4|9
\Ĺus
""*Gl:7VZbvӧ~&IkǏ8DA tL 	ݜ5x/&Ҝ}Aw3D
z^ r|3"Fʲ,K.Dh$SS5~tcc<oc¸VcxpHgk#Ѻn~[&q;;eB"c3\~D2眏g0BDQDZ"2ޢ:RJP,''0Q|/+f!s]ϟ	ə9{y3Z+Vhk"Ixw1kZHXO?>x^aȈ	F.0Á¤֨as!{!Dgm-Zgѕ7/:VGbr fѪygb?	ǂ"S8 <Xk@;X*3z~b{{Gv B'?g?}w_EMy2e^w.+BkJY'IlgmŢ(9!xHDR\DpE]BϰaFɄ1&&$N*eJۧGYOYYyY=|0I00,RkeE`Le`1bAJ1|#(KګV# cp4y@k#%hZ`\#xojeTHtEQ `Br8F4@J`I^E?098a59B9yʀOͦh0OgӲ8QNݪ 9F`{A@Pԃo͉8C;>W:gzbR
6RAjXy]~΂`{>(Pl{ cmYU@^t1oA3!NOH<߸'HotրJdJDlۂI:X#⋢(Dg'7olouRYwѧ?ZbZ* 8g>
ZQJ EGEQbDR
YhR\d.q'{eYji eUhl5ͦS'&- `DA&IʥD$MUUq$eGz007oonݺqޝksm\^D0sn@;y0߃,Tp/\, ߆/xy}(_K0.%,Kl#!/^.r^~ݽ,\WCgW#,IYv̅Z˪{ jin܍wz|||tx|9"J))玣_""IYTlME~臟}/~S^}o;sT%5fq^)\veԁsWFX%3ە#ifBݝgOKU	Na(PfB>'WXcA2^鹏1Wވ4OYB
,ggoFq zYҴ]𽟿{;8`wg>$q9==UUp yg|rdZ@\73\9ɹo+LZ@gd 
!$Ugf#Y[:6Ak(˪J3.Z"DI^FBRE1Gkus뷈s+!"2rq2csk(S+B0UY8k X[t<~쯑2(pk7$Dfȸ3Zk[igE)|Y~WU1h<2ϖZ^[a<Ƙģ@$U*E%گydXZk2)9wMڠI;;vp2*Vg չ=JD,  8RnVfցAǋF8e_7m|v+fo?{?k?%i PVU`:f1s2!x^炏ٳHݺ]K4I֍4k1V`|޽\I7(äx<Al6sEQQUUUU9L4mZr!eQU?|<.k[ggY ;,O A
n58gHm "x2dGE34VVUYUkA   ~8ͺk-&Cd^#u?7|v,881 \Rp9lÓgl:UpfwӮ7AQZJʚTEYVEi8Fŏ:c4\rUXHK%9=cDjJas HY;l&I D-sb"9^AG9:h Xn5F4f})8tq4q!\
	1Nrf)xz|ptt"Wn!y_0$.G?Lf2Z7޺~zEyY-$xoO(B\UL+ݬ%fЍG#ڪ,bgd4
(pjH_@n߽ƛovy^<{aݮʒmXkUYfòdE[UkAacj67xL,i%Im{ks{gWo7ku0+lkp#/}7E09WRk@c|^Zrp+&
󹷾⪯%-]t~I;/N<4'?Я|p,SneާU9\Ht_N\EA0{$MʲTJbk{gm}io0NG~n'9/*>񗾆>Z3a:%F4<yzgOz'?w?޽~n U5U_ҥvFؖEke'QV%0&DUjU	9cUJ;4U07?29CsΫxͲ|8p)oݾʢt+eOw:<<~[o9uU"<|pwGbdF8 ,ZЁXг/<_!z2Vi?/gv3((
Bp"fZfg1!"pN	1_ w-84CX`v5ǘriC5t|z;mO=W<9eE m	Ԋgױ8{E;{!UUq<K)UEU2f&ByUY:]&[L1mgAFׇ$z]cs  H1p 7"%)Jã㲬Z]S;"QB\aH!߆pr srvR(9Ax4f>10owuZpA֔"7U?;(ُ"g5(m0o&WC_?>eYpJӍ$lVhcAtPJYoQՊPrO;nmonln&~'Y~2g{x/CDzd2+X#dJ,sEҵl:olAPdȈ ƣQ6Fi8KD)u|r0:Neݵ"!xѸw'~QgRFi97NDӧEh8ZMΘ5Jaq@l6!gd5G}5ݜq2REUUɬ?zdUJ!b[fQo44($ʲ0R°`8kQo(Fy@'2ĉ1)Lp+c樌D%i-k,/(
LkvYњŝ".K5	rs`61' JdREQo8O?zJb4͋Ș(
#)@R08 H3Xn7CSL,3&zgRTRWܸ~M0"z>N>G{^7Ll6g*Vl XUZ[*mApֹ(J!RH9ggrB7_{UY=Nf3d&Vk:ehqwk+" MkkZ9{<jI|ddnn4(F\ <@˞1\>KfpU+,Y/	5@XQj/`Q_|	\ͣeh B *Kʅ{[p,/w!|qv_"M}.KN.;by-
\ꯗ[!28ikv{4Lƣ<4/~9pNYk5iąH$iV{}}ý'G6&5D@<w.ecW!ȽbPfUW 2<#'e'IO5 x1Xg:QC=09Y[VTxrk <#FO<Afĉ3{ *s1bz杻>
@^YM&gV6:: Cy+7SBpj1\""ZQlw`"ˌ1\(>~&
*KC>7@ƺ
W@5j@/+#Ui4[_{}wwheuC/ˇΩ@mց1V928 o'4S!jZUV*9IOJUE᠞K%,v9g3m/oF$$7@|YRQߏ3)vo  ጃsl:􍪢f mF.~6_n8Pq&45p81 ū@FtaW{u(	"/b:Q$ -	~1[?kJV~{>wyg6>cg5 CD^}AcI4$4{Okq~cj4M,nqΊYge*'yjm-#ˋ" BF$PJ#a "*LxΪR`~%I,ZE'ngNy|zQXcC)_{ѣ'Y!R:gU@aLg</L`8%beUq5<b1FN{tik|(-  "fJ&Yd:N
)il}_D\H.X}<
UZEHɈ^qa.G@pV%鍹1dYe~ Zf:tPJ!p8#3^nXы#,k)yQUj۽~f~/<[:c,9'Bp!81 \& *[Z;uN~;{5&˴㼶}έ[7o$I⬙ew7G~9Hi h2]F% ")qZS#*͈oܼ-<=gya-MUYxfiΦ.AJqb+J cd2i׶k5Ft}kotkz=C"y܃%yAf<«nvƸAy׋#Z~x/FR_/_J>x9he/v^½ŝ⥜U WD+_r.Wr˓n/?de\8r׈F#Ikt:==~vrr0d+h϶^sJ)Ē{7ZO~ɇ|ؽW^uں[~E/|+x6^?6E&Er`.svr㙌K4:ǈ ՛@C|⇵F{~Z38:3_|nU/lֹ08p0{чluVJ(8HZݼ3>_|~ <_k6[ңiƸRU2²5hͼɬ0. O-Ep`p|/Ϳ+kuιl*ϲ08Bθk4_*~;[<X*Z!I5AhUzu/%߹ʝi:`.	V,TiDq^ߋX$dBR; g1#|WZTLZ2N+eaBh[1320247c3 xF[5	-6Z)HA"4_: ܾvDtF0id$D@KZEA z@oְ u,bEڎۭqs6NGâȍj>7̷=qj4Sq@YfSb˽zpN)Ybll8ڼvFYVDjݣǏ_;x[io6Fks4ZZc9ZlkۭF]T;ޙvkj6_{Yn7x!j1EUjf6ǽAQV,+OQ6!2ϲ(
(k0d4P
9uǱֆ߽ukE$8â@ٌ*82&֦Jk|VUt	ԺTFHZEI(2HĴˍwxD2fE~럜:QKN]V#"XeQ
gY>,xkZ!x^d> BƐqɵ#X1FUAa|L/BGRZa8LFc>}v;3b`{Tт	luBƫ-&c2T:q]p`Z \MHxjM"R1N5=    IDATx $鴷6iEުz=r[olQEUUgG<;z~wя(VQf޶bRi"D  *CPS>N^zTkou:oi:'SkmP$MP)9QgBJ$RU$Fgٳtn;5 Bkk[v+#Ni
F@	ZQ;xn"qEv,/wͯYŇ/
YV3ʗ_bxQz|Q9킵	?h[\py	ׅ<Y&cvAo|`%-9y)yѻ9{v0sR-#o}-=\HJe5uy
,:rn6׃y_Y Q޼uwgt:==><9=ɔ1\q4AaGkq`5˯QcYAqkۿ{>>O?^ooownyeccӇAfyy|cвW1T5[, sJ2s*J@#qm!t-" sxcTxsC4@W0a-Ւ{6mt8bEVEǌ΢3@l9?O8͒$nt?9(r"XPqF2cVy]0x'DGIgIZr08kJۯo1rȋI^k5ƺRKNV/;[YBL0
Cb΁11DD$kx8B煵Ab#̋90Z q㐑s% mE  XvFJs)J8J)]Vޠஊ-ZBFA _E[:EuA#VUkN޹ 8g2d"dk֙6D"b^ݽTY>9p5xZmom8RYgGe8
P#%cS>|w]0$,je!!℡׶vwvGq#gBcr/#OSq['ƅU%<b6ښ1r>wc^R%MG?Og?~+wo߽s"q) ({jdc}}ccm pY^tꌩ'fwjt6}v|~[7oluPY֬ך0gY>~T0$Zg~QR*Fĵhqh4	AU`<	spOo]\p@Rhc"f=-J[ר&Cl4׫Je݊C9d=<>Y_DQ2``M\Ƙ9(1f<	$1B0'gGǧaUUDڵZ;IkA8<7'l6v7ҏ>
eYK6N728@ Dq.AFReQ$qL9g}la~;w,Vcx2`KYo.w\i%DEY^޼q[z/sB0
,m' <A?O˪j޽G5Ƭu1
,N{'Fq7_5"0'OF{wnl&d,˲rrƹac,HNTUV9yzd
N^خ煈A;><5ۂstwvVoԣ 'gJ)Ews*,ϴRFZsj{Gãʸ۷n[zRPr`\+;BEÇ|e;Wu3!,q>ׇl+/_rF2/ZC:'Y~㷊Ӗ'p]I[^D#S27W.ڮYQ/rU	<i.z%\έ?W[XvWuU ^lտ	V๽`iZ{AR\k;d8Ll%rƉx̓(pZ˼X]Az+6w;GO<ַvf(eUQJ%MǪԛ<ō·nCUe鬥݂z 84ꪝh,	cDHPϏk>@CKNg#b'u|2u-dk*GVeRJ 9[[i$iY+9uZGxY,qƂW/[)g9x<˲d+K
"	~Nz2co|+k:"'3MsO$%"a(8
$8w!Zy굴,'$Jml߽w/I(^8`{>y3΢uF v8:ʀkλ(VJUYyV{:oO1Q1߾w!ril4a>
G6;´$G@ƙĹJ)5 x.YƐaD֓<i:28
oFiaHZV:CP";~vR?'@F_FWv`U.< 	ki,Nzh8N}ny
%f?_e/fޒEPU*f,)eĬ1^{!LTVŃ?'M{Χ|?͛GQlnu"RLgY2*^KlcMiUVUY6~!(:louO{{QG{O[F^\qWLkIgkkZe1 @JiNgAP7f7d,bR0FHp2͎z'Iadgy^VNgYGYQ6d\J,8
`:Gi݊gvdD\U8Ղ0T:pYq.]E:Gd4ʢ(l6iڨZ'IΆSfclt76( ¢ADck)߉N;fH08($"Ɖs0}ǵ3re5ͲZ Nki5iROfY9kZi*9{:W8`T1niu"zګ[[ys5R a1Z:QZWZk)jnlt	Ak{1#'}1ڭ7F]>ãZ;xWhc&X12&q1Mɴ*k `)ݤ¿_鬟mR^֭okת?8xvȚ:N't"0IVPE2Lj^WUZkøT{z!qi:VΈ!,  v`\:O~}}exU2վ_z,ӕ0K_V^n%r5RhyxU;%,Y>5pDq\]Y2"/.ז%0vɗv*P|_0GcqFqhy><Kp<fS31E%<)5"Zeo՛wwoܼsɓ'{gO>{vƭk׻nǜX\k^h@k:/E;]8.ΕEfrgj9;O{phqN[GԠZ@ 2>!P cΨ!7"uFF)VyѳvhcXc1ZOl6ѧg9kRBFjI6Zme
mZީYZ(Kl:9;>:dW(\,+9q{C$onlmޛ6I\Wb2r̬j4F;Gf#i/FId$he@@]][VVnŷlCGEFxϟ??{ê8HF Hhxfw+E  h	}y3`'ollt>%fxBAl0cB@(d) Z%j:ʢ+Y`ZAl8䃟dyfyc<<"=pfl=(TQUhezX @!MkkfZl 	ٙ('"dQI)l]iUy13Ϡb:=:xsȃ5~'IB4߷f5Pl$Yyj^oRG͉<EBVk$B(>֓8%Q{fK
˭ 2~vv?|?h[|;FY}}; #ι$C1ȪƣZh5r.ȧIV3{/Q(MEQDJuٳ=Gd2:Rƚ6v8V gthdYVe[R!CS5%0cqiQ8O{.cLk#DdƸTغ$I$MiQ9Al!ۜ3]QeUuV:q{=ڬuUUUULt0GEQZ8Ҵgkk+V#ϣ8	/,Vzu]ȸBpNR-Ɛ/h/	'ml(+O`{PR\ͼ
 "2֣iq3f7֮vڝf{tGu%qo?t&4EgP\my7^.'yD4B޼{f#G nuړͫ&H%ItkE3lnmmEqbuEDLPֹ~ײXYa0ƕ׷߻:vɴc,T)o-cLJ!յNfb@R)G*({3ƑQ@-׵Dy[ܹ{Oã鴈#(|uxvO+SUR[ߎVvJvܿsz'π	)	',xW~p?JT~[.^]k<[CH_-g]©^7eb
共ZX\Rn!j
m'EbI3\b6\D_x΋y:rveY5|Z;3n6s?>:9	oZI,I-~b[ء!V!8K'+[Ho>Z/>}胟<O?ҽ{ｷsj{ɴ:Yܜsƺʁ@еڿӛ9rvjz4n󤭋sDz 2G蝓g;._޳#L΄}̌t6`0<9kvG<XcRMHH%Y uP;>;QNDI7u3ŉ\]M]L|T*!ęs@8FxqybdvWyk;BEt0Z8uY2.T'QO·&Cn9y! 8e$.gvSG1kLŒιF][+EURɇI !q$MHރx#F.`|Qq%IBDhsV]N6ьkB$c5U8>kϿX[v]6ѕQH~9e$DEq8c:gjr8 Q	Bst11'DGPQp63Z7+[z9X?O{&8ga0i"##$OEtD{d|F8paAc<NO=yd< 3M)9 k"D,t:Iiڀ$M{-{7~?Ý;|ޛ?xpDDf(pXJMϞH8NƸ[ PW=G$o8RI.ۭ@[[7L*,{Y766yًã^9Ode-OXEѝ[7rC!pr_)0ue(kcT]-<y'Qp8-HiLDeu(%	צq+&qmT~pptrx?)jDdX_vy:4E d4::<4E.yqH,Vt¸ݕi]UV3q&UUzk͏ !CpW&BHRD8g*3YA
a'(8YۭvՔM'Yv֭/xcǸ=9*3퀈YJ{G2ƶu?Fq9#bzD
! ׷13΅trwo4p;FビW'n	jh5.e9LOxRk P3RITSn/	s!EQikoO?diy78I    Y[''''(NҝzpgݻwnޜoZu	;r0#CgZ_	lEsw_qgfM,`,>gyKWbAtCe-ta.n_iA~p*t&8"۹sy.C^/4f}`YL0	|Px Tbooz8RQ$!xQÓ怐t^oeԍ͍?>>~O?xE޼v7ngjcLйH#<1 "gW3aB@]ܲ	$sI;o׆/rlDi~mvo};7vwH\YYپq}8,Y".yȹ'31Du9tyr6lGhucS>l4x]]%;:Ib'`1R8AgC=r8c(¹n6g	Q*wm`|4WUn8
Fŉ{ͭׯEnE f&HR!ZHs !E){:c(veW_Vqg6AfpK% 8`ሸY!"g<6uQUQeb"1v8R=ftW${/.}YC(N8&E錹2tAy$	9__d|IeCe1PrRN'"!&h4$4MT
\7oDGգD׼YU#]WQJγgϞx>1oB L9 b2Tr΁G`$˛?ltwot0[[տ=GW''_<~]l[*{$?iov¯`4{o%jۭvkwzq$ir_|ϟYvkwZ36V㢪ysǏG]Jw:-!1f18,ʲd05-!wʸ(RQ0Kiʹ(FqMj5fQZU5 RN&ێ"IDVu].Ns{Bn	kK\G0_Nɴ1ݕw:V,Qں]A=GTINFzk'&dEޓR6hm˅P:+JEZ#ڪ<,gwFHbb>KclfvI	4,'qgYZif#}s1aғ!( 7xC>?ht~7^7ʢq;wmǓI]J)C!xЭu$;t:@kiy]$Z    IDAT0F*E]׮loomEJQQՌ1x;UUW1F;<8I8т.*EbpfkG[ۻ;{qQI)Ƶ{ϟZolBjkznyZۯ޽2R伣P~,:?=#$s\s岽/v%/q+ۅwb~
/,wX8^EGvogFou+TxP+t_ŇӸE/+STI_NiҼlr_qi'h('q&
d|<S%2ꕿ٨Q`(,Nf{noo|;zx\YXJB '"~VrweQ4g}_EQLrJN3ƽwˢ*˪jIDN;Ob*rWm:y|[3ݓ%q,Th{dP]UY![ {}I^h['rFQ\洝P%MSW%[+m1ΥBޓy.yo{y}q1~G2So޸0IfC ?}"o<.C`>TsĹK\H"t:mZŔҼʋȐERuS1Y CL	.8Bp4אַu8I뺪NeQUcvhLH
1T*N,sKr>_z("H\EyWUs-dQ,J!"y:ll@*e5a&  GJq.ȗRJTTM^*5>2ET2 PV@bi5<a5IWWVgi<}78=_1P[ r8' gӪNJw5fu< &ygg[[ ?o?'O~7_{׻`4f
GjyHpϿx*RDjvpx8c7#t2B6 pc]pi6,MI)%Ĵ, g(R1$H):`Xgla)Jɴ(iYUzXwN.kVRr!RFscsSR0Cq!8f,3;;kV#<ϚFوH	pV`E\1!<".uΕ,ˠ{v"916Cb$JJD "!$TJqƼB
9aː[lO~:5D1!j8><<zup`Hn=*"MsҘe[d1F
y݇M[s:`L
Q!Β8RR0c%DX_[m6Q@x|o|uuUpn	;"wڍvh4b1Z`u]P@LL.qvFEvTrBX猵y!˽pe6XD2ϲ Jdjmm4{֭ʊBVC 0K,u:Eϟ[BkU6_j~m8+L._-ghw%`_f^ E3H%Q+,`"O_yDo.N8e^/Y ɸ3&qj6Q!38kN}`!JyD;og>gǇϟ<Iڍ[hQ3}缶r$9[˲Fq#|}(q,'ppj
EQZ%jX<q<3r.VXDs.k7wRd1UʲRV0`
kmDU* YG@!Őp4<<xu(a@REq,KDh"lͭ%ccs5<<1Bf7vvꪬJEQ`AD)xÿOw`<vQpiI\H q[gyPC4_A.T&QՔJ1!T
)8cհ0ZoMU'0h\DR(84yj0\]UvT(j:Ӊ_h BFBd<8=㴻fuljֽ%fy&4ue|yEII[kLB0C yPpg`B*dy'Y7u]/c?=.$2.X]mJ1bqs{b "OKa78\>s4Zhm}I{ dBKg~	 XCp	!fYn-ic^ueZ#Y4_i݇ɓn\Zm̤(knYUշvqQӢQER~͍͍V UY9gǽkcL?M6VWqotb2Vei58NI{窲4Z{dBV3y+)1d,ϳ^,
;&E1u˪*.+'Nz<	!u]c\bRy!EdQ՞@DQ)&\RC a)TQ׻nwۍ6KmFIm0<:e +%Cu\
aI冓onn`B'	RN˲,;EQX˺Q,':+HVt:*K`=`ݾvmgի^E$Rh2,"Jld붷o7wwJ밅N5F0tY6B
Dt[H5y٪udEUGJ:(uWV1ȸPQ8asʪ
!ɘ'dDEyp'akwc.Xhl	
,nB|p0`kG'=몘H!4c8u{woܹAD֣U,"Ii@gMp-<ς?ŖJ]*[](˛ \2NX)/dL\P%_o3Y6cl/*-ò	!OY66Xm^8Uίnĸ͘5+1R)h>''YylvZ<K# Zkk!j.w_K'1@aF w䣟}w?g?tVvo~o^lι(k]] {sV$RYŅ,{'/?;1 3v8rZVńm;sp
#	g'b`!cIZ{`1cXXǭᾷ&/v'd1`BoXO$14I`ı3b2=wc䈼熈;JBJI9!1^;E}}l(B[伌O2i
|Ooz[y5f웉 b0"dyi{B1(,JR.(``J(I4M$SiYeQ9b2N'BW*&8CzjaPr;ouq{'W.4' 	cXh		\
H)<Vd\ojr8cp؂JB@4Z8ʲBOɨjD: ;B,ftPKWz'a=qqYr9P0&	/"pa3眿ƛyg~Ϲe!:C*g'g/r3	 A[x:(jL&ךrIޓ+՟Dq=}/?ٛo??z[ݽFc'ϦEO7m޽s7$ `4fΛl_gw?kgoId0	wn4[ϾxN*m^vgON훻QU}:s!,uY0 Pn5ֺ<II2!q`b<Yc!30:9PDa)%!3H
)3,ZV#}{w3ŃGEYוR*"&[7wXP:oD"b<3;5QӕyI!hxxpx<qhR͋';R6ZtʒgsrࣟwCZcݺxrpxiy{|'ąf++hƍ,(tU  gn;1Gt:\ȹ i;_wֹ(qiGRNNOvvvmm5kLCZ XC޺yRz H~^uI , =K^F bgN,Mo߹ηvt᜕RZM.h4u]7ݝ|ۯvwue2GlRz,ͫ`Rڃ! ̀sTႋ\fՖp^Bk.K\nx9)w,{Ʉ`6L-g|,YL;W~r9f87emyX`g[tp~\r!b_my Zs_%g"', 8`AlxvSO瑔4H) h^Rin5F$Q*se?:G.ճs>/96֣7n08zujŋgOfg5MZ	]3>޼S"]!ּxtmz^d2ea]ۼf흜<Y08QH%qA)t<Ð1Pp"LVJV8T=g7{g|BcG2*!Y,g`QE+Ӫi7+BEޚT
A)9w}{獇z퇞`:-FCAZ!>^e)8Zμ~?^]]kb0" O_r
JeG)%J8Ib)% \':C#AyOȥJ#BVt'd2.9NUUV^-Ͳܱ^t5EYw@<EQ%)jJf	#\_FQBu~0ly#J4u%O:ksMҔ 	ɸ+eĘdln}K5"X4ȑS*Op @+ˢi{ϟ=Vsp#@Fz
32yYh0iҍ4MY Fs dTL'_<yo}?_~߿Ӳ?8RhKYifY6WZgww7WWV:?G]ܸ~}xziu;y{lj*Uv d#!dٸ{C+knӲ>9ETY9Guu||dY'ׯciRۘ	zO3fP9ytqAq!::nhk<{@BuREWL׶6:,gHƹR*Ichv:m(R)"2dĂ}O]W`4ɴ*c,#'U$\@%F&!Vsu)Ƈr 8v+Jkkl[[yUU9?÷_jRʲ`41R2JaF7d:~w֪L&VQ3QxQh0NOGQQA!YHi84I8QUYI'im>{]]ͳ*!c8F BN ,܁q!D,׌ o;-ebL$eLܹ}{ͭ,IWn+O^{rtnũX ,'l1C2pg'Z0?EYί{WB/ ^%گ8h!Ҏ\@ '[.KT0^bi^F)WJ0&ml0޼{:ٖB]%8w|_y?_D!w9`(2綰W'#׮~`e9LX6uUV6 4R++Nl!`3H --_I|1&_vWhgw|铽G'G~pem1i}Y,6A`ct:)f8efx|rq;,1l&yF^3	UR!a<JRd}7L;kg20x#ChGଢ଼aA@3"eMyG)y
ls1!RpmTj61Gj]Wy5w$L q?6c|zONNNvo݉#5)
 'p#qιs ))8TefYEqep~(G0m!R2VyuZ;˵[VEUUhO>"oX={Ƅdq2Ɖ9Ylw,/r"qq(T9AaRB c Y4ugtpBpWm280WV8	w(gL p4$IA_μ=P0evY#8.VY,xdx_;+]QJic:a2e\̫xr`ȅ#ys9$mu94IZ3u`lRu榫ˍ_ΝWvwyG|rwZ
(Y*`omH)GIXژvG
!H",*Yʩe*MӪa3b%z'7Zf3tZ(hTen<χq1E鬭#3S%8\׺,4M|46VFLNCȌ>3
: V	+++I{gApyRp3ib ;<>)n/J\$#%g+)1FUMi  WJ]]8(uZWeUMb:'djj#eygwv0)1΁ gBŬg<f¬$J"C{O'ͭf1DkMkkGGGUYzܿ(V+^7|:+8"ca	 *8-㉋y_UjݿweYwY_UU9hcQ?Fd2H9Bh:B$qei3O8eUkG9wɣ'GΑ,eqc~qO@<atZ
U@kwDBF۝k[`pptNk}uEE5[~뵻w[nD!Q[f	|֛9c`u~&xFP?{pA_XyУ_l 9q
fM!G <ޟyfU'p,3"-%^K~kZ#߼k %:01f@N{f-:2OvL;B~Ձq>" d`"Laz|1gie9SgC|I]ʊ1&ٽ~~QUW{'~G}yf%`D84 x@OID#"O`< P)Q1x<O(FYBh4fCFuze%Q-" 	8yUwIXެ,j7}    IDAT.,Cs^k-<H8 cQ猐A]U",1d"Q1" 痒a(X|7R06 vjd19L]E90 Xo޾{uuOFf{c,gY.	(`PUbIHY> pe."Ͳ`+]q^?sD8RYU15h_Fd%2!JDJJOTLag8_W(9'.Bc,b`h07$tW5sYK9gY
!kdHaj۪ʲRqw8g<gg{G0{kFá*2Gښ#@Y"u U,䈈RJ r΃Z更hrlb_pCMYbw8ł". 2VBv׿[y@D!lYدqd3ɑ		뺶Ykg'{ w7KuՊD[gUvB Ço̻|G?oo}ɣIQDJ޻yc2-G'Dtέ=>2|z뵻7wv<{;=ǿǽ$<s^~i߻&񵭍8M`TuFijιݝpx;=zӓ^,i/ϒvgy$ʺtݕ(IGt2	 -Uk3g6B8SkB끀s|i A>ȍ1ZE4m4@fn;kf(x &Ien,#m`=YNNzѱ^pq%1N=yyPֵb'wRRI))T;mM0<<:upX,ܼ䍺y@&$Bp.#R*)2rC"&R)?-5 hcZwnx?ybJ\_CcM|1 BI\R
٦u_{jO{@>0苧}eU9[mZO&Sc'/8ϳ$f,˛6笪JRx!ȓL穬(9<1XIπ6S;GUڹyk{gg:M_y^68iv[7ݾ鴈Ҥ >^B}˿;!΁s@, -#3G3 ]Y+xǾ]_K=hy+Jۗes{Q&f`t@0yrj/n--@;seBf%ఄ/k-|HrM5-\A$ ThOE`Ii䗽a915clccW {cjkkLFw|zjp_|{&	#gUkOGBs!"lhL8A+N?{l8zf"r	.77 Yt<va;D6*No}7;??y<L@H$MZϘ& 8B`d1.6Eż^H(d\;N  ZGa	 
y3!B@> R#޹YL) xSfN@F Yvqon6;L&cluUpɄi9OIR*g3Ca61$Iy!iopzzX\='#r g%yRȅJ]|ݽ;RIaf8J8VEHd\X(+mv~uy[Xw`ps1a+,ĀTHqF1&_%KGdRYNzH {]h2q$) WfQE3Ɛ3蝐j)!Z+GIʅd  `qGd̈͓z|Tѵ뺮/GRƱ<ϲ8 `teF29=4u1jSPLDD. HUV[kyg6EYMF`ei[cs./!&|k?|7oO?{|}kvr:>8Uv3OիW~mk~z{޳<M{˿ӕvs?έvًTEJq́;<l"mo_Ghƃiިۛq4q@1ތhUUʳ,Ͳ_0.xOJ05#X,@	.xlp@] 'Y)N8<Ÿ A?,ϊeЉeQյ|mc'aGާYIHHJlE7@Tk}zz;Xk!7WNs6_FQYq(c($)
fc@y"P9c`4R:cf=|'OOzy{OolnVӱu3{f#aPlIv\`Nc(N}Fz|֦ꪪ(<$ L]^8R#dbuD.3O@G3)o6i8yPqCZʙCɹuRWe <_8g]yG(\鬬o^R*x4dumu͹R'ދ{/n @$!R$[~=7/
R[$R$@H7SêgpP5zڧNUV57w۝z9ɛ|+If1_5 (8*?A{-vZ-Yzs]Dk](fH-C,W@oE7ȸ}Kx)7v	\$E\g;Gsmlwo[%yxRo5n1 u'lezwkϸ7vD"*>0:'1DD߭-V1Bx)еPJ9wwvOO.fX-릩+7k%eQ*үuHk'y"Ԫ5rK/_"QPd8IG;EARx	FP
ιZ6)(jc -1mMwN^z;>z1F!); 4rB:fRƓ$Ib\>rQLW
!13wǌ D6v"eI.D6Ct F8y"F<Ϧ;;y0WeUM]6I&IC@R$q9PG/QZ"\k Vx>D!R
9PZԱU^ Ƹѱc
! I,MF311q$R[]8g]Fv*iĩ#lƘ80"46r6;?;,̄ڨk:XtDۺ\e/hT%6ZZM^5	0xt Ƙh,ur#Qن<˴6($ "@lFj{|u"ESWe*UY5u囪is`CT) %:M~?'pf@DVK?JH#q"Qwjb(PuaJD(!49gA0wއu>dyԙ>\*2$䓏'[?]ԩѯݻ[~g?/o>yǟ}m0˪w >?;EQΗ_J 9Ow=ڝN4}blOwGib޿xr
jck1޹Ę`EY"`@Lĝh{2%":K3%UfBI&FI11HysJ
l_BkD!0Xsi.D+DĀZ%H([Bk"VJ	WWD9(vlӔjUY"kQr{klLJaBUVj>_拢Xյ!Y:F2!.~_*k:1DLl82 Ss2ƺȐ%Ph/:.fQ_~~J=L28/
Bnt{|&:8ѓGON>g^<??,""c-N{R`ŲkF@i&<\-TRkZz|\J)F<MPʛJ`!2#Z+mZ!⑑/
' ;D)2I,{p<~,(t4v&Ab4mO[I8wMbtsfSۍvNag΁h3`wfU2WyNt7sޗ<]~Ruó]RJK1kM]7a7T|aas!u6u B#Mo6 +(q!ԵJ=l1sDF:x=y,h>꺬ꦩ)xBw߿[밃]'_}A?&GyylXFxh <d Nkp96u,#}ڼ䭝Osw
D=3K)53C@TtD,MQ)tg71V~1ÚHLW-Gl@ֱu]6Z
&DQ^khODFzUqrK:Z
YnORlM*ʢp*,4IZUU 00rDyQp6ppxwook-̈}Kb՛믾sr,1`()je&D(NUE]6]0\+kBuR<KӴ7	wT.MUX-<Edp8ݽ0@|lFUUyy/,V,_!Pkm9ԵN ;p2r**gm]WLc'-G,r_E7RXwvzQiX筧<<kow&9\|6-uY.7:{{&h<>88|kwz@$&&(G-gkIEV	dFI  q:kkty|v>GIUU5̂)b0>{_fQz<Ϟ?yś|z=γ4Os}O>YU7o>yB0|3#3cwÏ	oyD?Gi(^|g6	
><>i-$OFuTe*3yb(Q]F^/?=9M?F<rY TuL#j4A < 8F$>KhcC11V2$)
r<1N:Rb>)8`J4R&PHXZt6_TUmt`gwgg0k9u L(Ha(zR6a Ix3κQ*F`,&dEQf}%zf,=~|<.f|Z$u]3Ɠ?njnE49b;t8d<z<~x6/>=?Erט7R"C&)@fQ$A7B n;=}YڍVӭI-]<@5 VkCBQk̑vG*ux4O&x'Z"yWUrY6RޝN'DEfIs8@)wkh7y׎\o6D$SЙõ-&[ӆ_T|^O㰫!᫸osQbK.R**;1#*ཏ}sƫ:&ESiCw_e(!VUmVe7|WTW~ˍc_ŷ죚E.zb"AtNDך.\w'\V|豔r]~(C !J| ~;aDPWб.W+ff` 	 游25"%y?2<"ZO{ìA@FRewn:k!XZtNB)Gӽr BxO-$YbƓ`0RZb˽48
޹jU媨'@ <UZ|6D	GQa+t~wwwܙڦ,b\U Y[^ʲZkmR7˦i6ݻ_DKD8Sq33B92 `7Q)Px%5  !y!<6yx^ET%@!0!\51Yރׇ-d };fS틖2IRi(PsX6?x
pR5RJd{:ڞnmm*
op
N6eQ:(z&~/IB@>x_UuUO"&0{F_J^
v*%jٔ6:MZ5lJd0觉^53os^Vb4'N4R!xpB󑡾,r/g᝻oGPL$%3 8@Ρ[^-&\HA(R"P4'Fi-Iy\"hTYeʦi8P ٳ>{o$C!__}g2?ŧgiz`o7{ٙTUX>bz$C kObI]7O>{7&&U{|bXwtgph=l9#eh4TJe3&Mx  ISm$Ib=IWI46R YDILҤij!eD%e+!IZ@
Bd))p<sj0ކS@!m$IϦYL(닋/?yv~gi2z8˲z+"M`
 q>0J)K@
L?4b&(Vkt=3GNg$ $"NbX[oI)#[r/M~'~~_|*JpG?~{t/?(ic( RHIa9
·Gd8oG[YF'Z)i峣jEĽ<3Zcv  h[	  $F!#m\,DJi[=(R4't:lmmDtUUXbvql5\Kĉ4:ryߦV;RfVccop_xEZM^/+ "L]#*8?n^^H܆vfWaS/c/xl\u͂ߠ.ɣ
k:.*-oƈZ"ttΫa"p7qVc3R ĝԪ"FO2}o^Հ@Qpܺc.fn*)+s!hPj#T4qRI)X	q0Jkm -	6ؽ	+?lUM!hRB*XH.1JZuYp@: b+#+ P)sׂssG:;Ri	]`DdgD`UUj)?;ٞ$>Sf%    IDAT,ˤ6<@C} Hkdwwg5ICuUUV+[Rb0ȳY7oIZ4z?{SbM<z2Ht4m@fiZk17 5!t8P
`
MB(eTrL~
(yޛMSM:oҲˢp@Q"Itw'T*`9炳y?&XzD %P%C`
D!*.=kc`|E ILwvF"NL:! ,lm&[yh]]UjغJD.+gb&FR "~ZnOϝy4:".r{=HT|"׀@FŊv%BqQRDAe)WM<'o=|A4T
~#HRhGyPW
\&`ڸn\X
bidy
L$7|w_7}Go;oN'ӣyQg{;~/?g(M@t=)Q!F>|YOR
3GGIjuݐwBpZ...4BHʪ"" ̗+
B8?QXZ,M@A"'Z:kV4^e(MYD+gObJ(fkkrtrz~~(ߍ/R` Zh3*mo1"=ٹwxwjIfjX˳bQiI{^nD Ftm	pcΌA4uB&I LE%ZR1D
K)tMӤFĐ'rųXk|}3?|W}.,+˲v_ƺ&hhlXd|2?[ۧggaob6?99St"DT[B` !05E<KiynD	/V|^V+L<~5T
o:ˍdD@BFoܽGUYx  *$+eVZ4K<OL"tuqzVQ(*mR)0QH:IJrbrIankwKs*0o-:ȷg6v20%^g=wJ|n=<]:^xTdYO\4,8|GQ>mYki[n:7p^bCVa6J`c4[x._{nk 潠skvnyWpꎢkt뵞m׺רK
@ jO y5E[9noÛF& fM< f7M:TJ,[*c]f#(JJLQ]gr f@nutй+?`*PbD!p6Z!ULPȲXybI^-#(a_*
k3	bv
#p4(t*!zH-	8+0e*W˲(s;Y'f栔t :(`<`M)a kIA4lmO'QeD4MYE*VZHUzRgmlpPϾ{?糋í41ZJF-!fa8@[f|D[FJJFRrĺc,J֕{.<)P]Wy&FZhppx)'ژwM-GqHF'$pjlj7N^n)W7Ɠm@2Ji#p!p*('dd})E6_	q!0!EjhO* 
A)RQ+\.f!x%RTZ;^>Zk@lͭ!lY>#L2։ֆX}LzLAJZj<;=gg'o;y{@1  RDTzj"H4Ubl8x_U]eQ,˳뺪؇eUO{{?y٢-+v{kRb0ZK)suUI*"f-xJE?EY1~oڪ2R!,8x牵Z,B#df2Z94YsY+,}gy:I4I$1Ii=Otz~1_,שwcdQ`BJ)d #l°߫X0x<·eYVr/i1?Ǔp8LB->.Z7Dl :(qPZAFhJJ(%J<ϼx02"-KHS!I7?򌙭Yjy}.(VUZ<M:*ʠ|<Yf;>9"=CZ"X#iY~?~$#UU_bq6_\\,˺n@RJ+-Ʊ}xp`iL fW-+z9bFy]Sb-w`1-,r,IJ2sIJJ`R'MmmoLr|;7'_.qvƣڏ7e6|t/#MD^k-&W7tN+^+kgh?3c뫭E6DhZSnº$ ;l۵4&HoXZ^{Wdn.\;7.y87lp39̝? USBam"Klݟ{9Q7/x	7<`s lN 2X@uEtBw#!-z6]j
UԵF~7FÁRjmշqMym̬N!zD>Ų.Ujb,7U]rO,Iri9tYPJ2["b) d&+p׿DA)w\S. pdk&HM|%N[o,VE]MUep4ڞz!x)T*J)cuJs4VQQ: eGd4eQg\UuYբ\B!@a\GCeղ(ڦ{\Wыj[.Ͼr:,N0U$")dӝxj#RZ+ܡ77 Hƃy.pABɫdbp#J1mj=D;4M#V ӝݽ$I<*%ںϿWxxmmmeiZ$ 0.7p͛	n%&li<$@9;]dG6mBmp(3{g(^?ٚCF<11"JN68/H)4Ȗ7-)`80J:H))YgR0Rb^YƛI% 3YZˣg_~Z,ϕB'ZT+Tk,mSH㼳YRitZk//>oJmsfbh\#1 RJ| ιv($:l>?#ת.F@ዧ/?_7O';~~x Osy Wˣ㦱}<%bUur1_ܻ{~!&_~)SNRD` $Ͳ|ZJHE ;CrTmp<n꺪kR
sb8Fê*DICDᰪh8ZWg絵i4M1}Zq"]"`RJfA7u=&ZG@#2I$R" u¢O/>}zzzZ[+4Z=ܿs3'
o6k+`u(Ĉ.C(T,|RQR
9qygA*R2% p8˗O>HD
)w>g|᪨vEQW::>2[o媈e9)p0no+!<JFuUjP;H)9~B"*)Q'|?Yt:nG,M5BeY~g_JJ5vB>xz)ARqbF+ V<>9'{^oi,!ogMTe^H	BFݽh4F}slP*`JF')JMq;;2Pl.yoyo4y$2PD D\25(+vof}U/kWf[҅[@WOva7K7ƫ|EK~@ΉJ)ֈMiB'LEtbZ{g]n]OAN,wh֪Kh%eqomdt}_:f)eԪW<69N"Ɲ]Li s0	-R^x35RR.6M3͒,L 1Z!B9|fKnW}Uͅ@2i?bytt_0`f^5nGIQ)z?4ɓ7:88hft=z;O~6]$ifb-?BX+J1F;"z1EϊBЉkwZ
T(u8OLg}`Z[#"
ZVb$f$"Thiϲ4ٺ*V,t	!UUe9M]U%"`DJ
D,z6;_E<PJ^
`AޕR>HmAL 9H(ed!
 $IMf6D!
&"
|KdGiޯ/M>hh{0Og} Ba(eɡ )\AׇBR6Uuvc=z񔈹+=5J%BUmײBm``	UU5RL953'YelUeY٦r5Z%TBY@YgBMe.JT'Zx4-JƪW}O%gW_~y~z"kj)@Hٔg_~~|ttqvR,y"f6 Mc$I;w`Kyb%"j}UJSD9}:gmSEmmYjR:(*ߴU!0/?x<~gww?~ࣟG?z.Ocʺ限r4Oߟno{Bi3#I/sgS,Mh_ՠ׍=9=c$Ma/K+}jvvv} 묫+&҉XZ4F$	!L))Cuc^_H\.^/+ebAKTU5_,!_w'J<M\yn!4Rm|AKa{4k'a~> IY@$w;;``03EmKR":h&O |Mc<O+BjUJ)WϏ`<	U;i! 1^˯Jj)5,+B|~tۿ;?V@A*D9= : %"$RJ!zo?ώK!d=4MLƔJ)Fi/_|ytrrZ7s4AD%P+b'\Ήh]//m( xq|BiPRFwY!(=z;$P!<ϵrQ^TR,"BLl/|]vj=H1<m_ki(6=.>9ڳ]"oiz6҈QȢ6+O(~H])eԆ"Êuj*ow׺u˾')6URq,ۋW]67PyƸmOt<,XtWnnU%	k]&$*mnFcDz#qu.fg~}ܺ2W͝ Duh^XP`;>2Id"/Ko~!Cl1_-fxMZחF?prè-U	ļJdk%3 *l%{l6;?=].G//$IYz@Iy_i!x zŲmj_|OBp\VA䍷z_}y~vFF4ӚE};]:`,ʲ}y7OLbztg72 H	
uĩM+lSW%y+ Z2Nr ڼj1^o8G<ϒ,WFoVPzc]3sIL<tjjUe[xFfGYke=@#-_%^l8Q()bp*xuQiCTg{IAoUro+r+-B!Qi UQPU&I^ϘW
>   d p}A	K7(X|ڃ׷Ӫ*gJH;"YB+D	S n-"fYv.uq<B@)BH)P}' A*dZ$nڦ*M$eb4>wJXOEQ<윘,OĘDSыgrٺpJ"Fi-wAk(j!g'o&ijf:/3Lھ.V65Ę P$6peΕuZ`&-E7[CM
W=wlztOƓzv>eD6ݕR2`4g|D$˓qA(K@)qJ
BYJk%
Uc^XbPB(%Mpc#
4V)YB4d~X\hTID!tLhiQW1Z}RT1f*9r@ͪ F$k@W}',Y.DR
*j1fjUTUU[kR{pAgI RP d4\} }BkP҇`E`8h[r~/~ʲJt{{p$?I
yjN N:{@lIҤ|i4FkCGa!uu{\	ܞ<~t~z4ό1J
QRMS8;b9_,hPR5Đ}~{;kkG`	vƁż(VF (u<J<Mܿ'OޘnM4R
%IRVkJer6k{_ګ[{ro].7%EœbLBm}3KkixK/>FkZ׻̮_:}]}|B޸BvxC	z]`Z^ ]b&Pt[_|ͯ!m~6*p\&y[M*ґ+{i]ߢLcuG%]7  SүWv}B]ud7AO/M4+ƞPnEXa,d3xL{kD'Ѕ<QW墮*!ef1Js }vnz> y0l3|>?>::9zq~r\VEp%ż(n{824l΁h:=Y<y\_nmmns̰fh.߹7Mb2.6< Z>8U
G    IDATy\SZ'(4z}#z)HdDIM1n"(V)M)n=3EcBh4?^t .˪ubQvR*I3\h*v"(pLL4V6Ml	B>X} z e! 7! PDЎQ ">~p1#(BWr11AQy^"R \bU׵s.8WEUH)Tv9FF=@a#pkc0p}d;9zwp0ޚ헫kd@RJsGOIsr(lF. RJISgmc0u>±0 
%@D< ,6i [&y&ɍ1Th4ݞC7f3):===;=f$IӬ:Y.S炐$9}ӡJe~gYnjY,d½ʓ/.σoݻ|> KʎC8fH
UyU5MTU]4vZ4MҬ%RڦN`ŋg/E\.2#ǃo>^fqHmvvi6_EUViGMe)8==[eUBjitf9'd@!MPQZK-$m&Z):fsQ>$IDiԍVJ,n{-1R,MY9mc,BU~"qXKq!@T2GPղkLh=yQ0.7+fZgAĦiUaeY )uM]TW*]ĵ',If?~I,IBk=y."D\ɉVo
{VǏINONNi:>:B{R`-:Cng/,Vy)%95VyHZ#(x4eU/W|~|rv|rz1 P
ƖLRiݷ||L6!sN;5Lu6<3
JG`ppvo@p#JgOcn7V A![|_n[unj~iW\ꚿWbB+i\Qͅ]Zn^}mڕmamѵý+lv~:W@zm-O7G<ܨë7uZΉ%1:.FvM|W]k'>HL@<wQ&.NbMt͖S5kZHRJ|+
z?֛G  H 	=ڪ,# @dW̽wPxKV.eUzNu)Jǂk-EZ @q	)Yx(8Bw U @T?{oGϟ~_=əs<~7=@ĦEUYZY)O3Nxn.$>zɪ(YQQe )b5?8=Rixg{QB qim `@:Rt<qpvQԞq00K+$Ih4I$:\Sٺއ) 2?ܽW$Yv5>&"T52$Aoz8^>H>?RrÙ6e#☽p"-=FBVȈ昵ky?Lvv1ιGMQ7T"{r`\upDDP6	HX-<1 3lrDi/hb+_R4A,z}$HBjhRCZ9FttRjC;uH9eU/ Rzrs5;>99?}^< & HDJXd6_
Oq^>TৌcMۍ1VKcQ8)D16Fexv)(2(h>K
DBK֧Ň O	IEjfvFr~s5<?<?f"l6Z/jex4̻,TU\LV`];Wtg?w ĨDVEu8<#&4&7Y-AwYVUeKWnό.gfz~9Ң
>xϯ'yy|r(K;ǫf/=CѤ^93^O<3ݜ:Rne<sgf-\M yf61j|2D>A]W7\{h0*cU7"RdheXfbU.<3F+Сڻ$lortrQdÛWJA?>F2Tj2[>}~O[>p<婌ǸZ-cSNR"1|ue^'*loanV]]N@ZuDB
דgNVOhcpQBTBbʹϞx-TZ-j}oh5  bTkqun/0D
Y^*/.>}'gJDV5NH	kCZz{|{??wvr15+j>nx"K"wWWU]kOXk#+Kk5&^  4cBhkuZ	XuoWy-[߰l~ݿ9y i8-81	&aR9DICA`X+6Joxsn!ps7dA)[| ΰ- pM\dԑ1Oj%J7qf"]dR6،&@$	M	ғx`٨ bSq16}ྥ]du]Dy{5.'Ea	E} >
0FFX{P
<Idc  1Fu1(Ȁ@3o_$CǑL SDD!8jc<weI;_1ҼCNR_sp, ID|] v{~x|r}yuqvqf2ͯwNg MRC1rfwb663>1E`C['/]jEU/'zyMHLns 61d2'@ɴ=~LpIcRURFk]Y,7FE$\Y1p36l*ށ6DaYӄF(q9 `
ł+)DrQ89lD~$s{ R)yׅp
^$-Q*
?E3=_ݍ 4)Br\nWX>!	c C DRа0 لH>YUU0;ݢ۳E7$bVUn:[일_V+"%mp1ȑ}965N4W̊c
})Zct'`͋MӘgV۬Qhmb?9Ffh5S:Z{~v:MY[cFEQHM3kIkԶ?{{x .&7WgϞ>;}"R1&wtsk`sΧwR)em]/u{Hzjv/cx턥6Xk;E>~,UKkm綬b73u/<~rtX˲FY\={xm_|p/b>o|ZWסNTWeQ^o:kR8VQY9/JG^U *cFݮ1&itEUVge:zB\nW@+WWUUy6ugaZ+"t06;/_؊1NNI;-=|z~1-gk<~SV &Ww(c],/^LEcU"Ξ6˲I+2\Vsm3K!`z;( dru-pXְEAt?|a0pU*+kxg?dvs}t|g?1&Ts7&0,WUY)E1Y%Oktf2/:1֩gN{G{{(ˬz>F ~"|" s·`G[`f2"㓓pTt;9Pؼ*)@ce,]%A 4#coMMj/;/̓r,^?pKߜL2-e,l
[*ӷm\Wm~Y_9$P8M*rHm/_iQ6ڿ,zCWgTBsˋʯ\WqT{wt7}كuSe6Thi._#][Z-6~@D (q D--҃nwy{xx2iyFPwݽ3Z_ۓ 4BNjf&" kuA IeFܓ`C%MVI
p $LQXa"6*wRP3f1G	!B^wupH){ 
&yFx<;8:<7M'~ysuA8x<o)狥s;XIh79@ny-op5p@u;Ȭ):Kd3&ɈiN9&n[Ͳ1b\.zE~y<U[k[ϣAB(W}KmH"/H0 Ȫ?\XHm9%CBQ_I0#f܅507	`z3Ӂs:)@I+9&dtuhW$kŝ&Ո֓_j;{pSrH#HAͷ@Z5<:4v8E/ˬR
}]!pn.g7%Y4*!x0HhʃEzC$pR>yfR(Iè,SZ1F_kW1Jik@Cʲ|0#wmKH>F8,,[$e</:nsqv믦77)g+Jwvz=wlww=8㯿<??_.{U t5e"@Jr6ɽnD.V;^LiI.2+^-UYі66K]L>v;hxvv?;84|5FRjalX.W hu1Y"@@$j(p2hTr@TUt
fVywݢSm@"zo3Z@1ubQ-ykbF<,M*#DhքiGHZtDč޹qm;Jl͓_9`3B)x&R(jZsn28=r{@FhƂ\e
!k]	+!dL,cZm~:tݢ׋im5f}9!{֘B|{''y^O>xֆ6kP
"BdWbi`]r\d:Lnn٬bS M=|TDyx5l,/({V#)f ̨R,K[d'P)*k_UuQtҠgT",znkH^wV<v2-&nzo=k! g"1y6~0V^O^.M%(ԫ?/4TT"8ܰm Ƅ]<o4vYKG.UFY[m&Zp/^У"oz0ޤ6^ͱSŔKtӵA,%Zۯ^P0kzSNW{."VHY`Iֈpo>`rak&BR12  AZ  nYzxxmU`-oD֧:BpG/Y` Q96	pB jX[tz݇}gWruyy9{wO	tr{+Mm,v!c BZH#7w]]eʋ1mvq}}u3t^(xw PS{KFf:U䷠[ gF$c BMFL^%FN(`c0IT 7V%}@}YY%X4$FT*n Rх1*bN*Q"ܠ}듀҄j"jkNд*˪p5sH.J3k<N N!sW7{M?:nUF R;.)"hHiZ!3{9ek7elj6t@HZk"
ιvFDUfLc|RkY./UVotDTQEb>bU9_.@Vt1֘(q}ӟY-cj`8FG?x3mmm~?~ůo.ϕV!rUu<˻ReY;",ϊ<FU7fqWcpwXv5Z?eLj5h)mV+A@Z-<g/. R:ƸXNO`>?bUՈ8ӸTe]U~UU\,&j},ωTZR^/	 "H}p@4Iv`0|6ˊN{!FT1xB@ hx}u\"m(^WƶYj]/~pvqu?99>f6s!Ĳ,)BX(9XM77dUV'''["|YH<xS	1I9FWժDRQ"(sVJ(~ptt<mVh{G+%&]$1Tez铺.V78Umsr6ɬQJMfdMѶYǖ[Ds󳳳˫lQV5 $NiB:BfL^{tt?x{y! eZnXp[m, OQVUAjjQD1^{rtDF7C{.-sur<QlxKb[{ͽv[cd7\7lp aϷe|&ydɊ  jhc̛^	$w\ɷ@ ۚ9،	/1']9l%ZDZ=TUd%z&"/951F5WHkϲT]xS{$yZ6KQ oK6Jo%F 1lQQj! EB
PCv	SJIs"Qlӝѭ ,:	ȜGֈ62x@ҤҚ'P(z!ƈ$4^}e霷{|7y(/n<?_ՋO/mV8F3eʦk{!5sY'JDe1$X79VEżOOM>*_sa6Y }ɮqedEg0:"R9{pnr)It,"#(D\x{1r  J"H4\^    IDAT|!$eKdMM.10GT
HksuXW±1ªe6JDb1zLEi;[|k&W.v{~Y-\q 0rADInDrXKMwN;EZgYR"B06K9:=R:.UdSEW}(/WHmXRJR2UH*յyf)	Br PiT֯46 u?D˪|4(2t2ɳ^)OXV֘y]u]1|ٳ݃흝={_HU!ZPu:{Ip*Eb2K'b`{O)]x~q6Y1("wjV1H*-|];LVEg5G$]c<En|:! CZ,~y(PN[;DTU%R
"_\\tWUJ+ 1VίVe"cݕHEb0Q2F,:ݴbɬ嗿g'|r~qYeftbI811p3H!aI}$HkEEfT߉Hni!FzoghH{qQ
	؅XedQv|R @I" 0"zVK.o&r<nG꺮ʪN|+16dժ7Ygy&Utkؠ+We4i]emtG?gzX,cݝ]0
	AD8՝^oow׻?>hkP
9؊4F  [\0_fsd:˲ƚ< -V%z;}}{EQ(DxZNPH*S$
;Lo V姟bi8Hӳ鼪"Z>N[x+RMe5,Tx uy#VRmg?]7ߊ	_Ŝo?7io3Іi3WU|ֿ;6'A(-RjM<&MCQDuAR{6M}%kblMSfwUXmz^^!WSUwNv_S;ֿmPpr(o?$ ¤=!D␌ѐCJ$$ґ "Ĉ"b#'롡	$݌V;qhl mp#"Aш  "A0JjaZgm9c1m""
#Dm(PZ{/*֖
m,"pɽx{_>8;;{\-<~<v[{Zc[6E:Tǥ}Zs5e7! +W{(O?*DT_7"B62h>{%B"mNbwc㈜l:YnH˔iP`,
D@Kv_,W9cTt`a&6j ķ/ ƺv`1z  FJ;o]Ln ޓ2UU劀%xcɊ{xkr6_-޻ƖA,𶄀P`X3OI)$N{Bnmu{<ϬI_W)`ff8n1(IQ[DD!xv16\̅BZiJRDH<ϊ<ˬ̑# *8k!EXmz+I=#"~UVUY
5&Ɂ?/~X"4|`0v:p4?899/CE;;;7ïE"fZkS.Z$ 6f?ydŻ`8g?[ZJƌ*1DKIS{_fddr0F^ʛkLY^w*& r!"R"S^ b*uWD0 s	H6,t}rh0YuNw:Φ7{dUV?~YFpd_]^ȃ~\]E&"7±moofbC[E<+;ֵ^_	sVdBV!c$DղF!NHY/χAAo"7 K!(Ȁ
1AX`X,6:bib
_q I)uyqqzz6-Jimfjk  5L&R :]Ο韮V׏:"2L<'2R{VJ E.V5ZQU?٧e'[-8!r_6vtf_ · Z)p7Y[{at:<Ї*W	%IP3 `B)aYW7gW7T#FZ"4w A6z현i$mO㭦aZjzmYf]46g3_⥽55{M<iso	|cX#xšj@Mj?+frwkk[7fCBiOjԐdcaaC^>_x;N-nӶM/}̷xK5
 @C$@Z@Gah? 
 qd $0Hbc_H*	RDjQ@[`CI@5Q6]k2i19+6S<0,٤][_$(ܸaL9&,6̔b^
@ˋtVtXt,+iE߻ཋϞ|GǏm>p^rUiBKJRJ/S_nbuۄM B5(Ib
J@d_&ݻ Z$@0F{|bX- LP QSի6fER Ij5-c"QRBDfBdfDzD@UY5*}zX$yzR_蚸	D16wqI%(4y UEPu!hR>eZ講ey߿:{Q{D?`\-34BQ%@A{!Z ccLGy[k1JT穔LG]hXfy*	vj"ZT(;!`&2h!"<!Vh6+JTʬZ(8GH.MJ)Ji鞺_9XR,"/o^]R&Sg{wtŲ)ow77WA Cd2LMZ(s}՗_s#lMYw&""kB>v(! P.ݡFkI 89adtfGٱYC2Q`N`w-D1֚EVI3Ij6+!z !,ϭ1͔Ϧ1Nrѣm͋䦈SZo1󪪂PJimV*}!"yI:JM4ivˋDbE;Մ@)` @bLi)1t\mDF+E̱B0B ٳggi9x1cWT35w/O>IPU|6EJU"r7R9v8>}_~(W#Ci9&o=soHτp0,:jJAgy:<ؿrrpoww4u:UUF5)Cc%l5.'j{7Ѫ,/o^]+*xvݮ)AOw8>|=4`2zPtwR}~2M}I4]ؼT$߶=ŷm:2kۆ@Ѹ6c+%L!9tW]6gmi9lOҍn 61*"TBĵӇb,t(b)PQ[.lA|C	n{0+#ز8Ġ3 iaIBfMəӭ]k#r #7$34խ\
-.5!V >="E؈Eё
 reF_׫|UM'WQۣ4 UUյֺ|O?^G|W_x,`pｇyU+Z6;Qn~#̮&bu5	Erɣˏ/UfU$"eU[cO>xpzsG~uU DF*?t: \\\CcMZ̧@Y^tE]m,&ԕJ}jEQ""2x֊PbQQb$>&)|Û ׊©/DNi-"# 2Lyf\h(]_^L;b1A|gټ+"0)E`Y-/yZ:>Bd|0ww^6ˌJkVihm{p=|Zz)as!9s.}8 |h:߭_LbzdFccnֲ"RY!W[|]P\VU\ yVt7_}ݿUR4 G[lR%!v:E H_]wrGwv~~v| M ${ WOdӝ,a3 zmo` A"ZY/j.^!^ܤ0qъp6#Yry^ʇJCd1rf,+L)5_.{N,*L)ч/Y(NܿrtxGZz~'G'N,/Ū|O?zqz>/O<G"}0&s</Yuu}E%"P,ࣰ`f_//~'|DHR^+
sҊ4!8 soJ[KD$D.2HU~sx4`v>0.rf gr&u}"]^ݬ%g6.#Bdl^׵"JDAzO1U
7aa#i,08e>?=;Q  h4>G';X|YUQPilO	Dgd6/g?};"ϵ«'O__]gFi+:ַ,zE#lQ.Wp{pHQoӀڬR;߳%O㎾	~V+^=[Z#?r=Zrg9@f-ᷪ6[R)LT8%a7rm=IC_Zߡaȍ1C^[ ~lhѷݫ.Qm@Ek} $,1EwևbJ4otoEkbgdFatQH QXEY͈2*:A(F:]	I Mf	* @c0/ re0$-,%F$ PH@ġR,o;E\ID"*F4$	  !x0sqMݸ,qhN4 ""~C8!,/z0YYvvҺSTUs.yspt'ggOGg_=98[-fv'snfDEvlg_s_Dl61t+$ά".jUU
wų'Oꋋu]bZ,+,ϗ2z8ժ*UZUU+0֒R+WuUJV>Rbj3)PRzGI]#BH	+(?iIWՔTP)h 	) x1W.tMrUfYH*<˕"A"8_,;g7YQhG'?AZͦӯb6RRhlL#,T8 cdW9rr0"vh<yQeHM⚉HT4)"pw}KRIj'!SmwɌT,,"=FL=bem.brD2kR%J]ι1d6V'_І "yZ~&@<"jm>WO>L~>^ǟj$s 2-E7gMgf%I12sUU9>]D}]δɴ6`"NeQT `.:l'b6*CΕUg nZV
Icp 5j{km惏!"s\&vv<;"&I?8<<2Z_<~8Ogs`xqusuq;{J'O%oh~YeU/WK!䱡	!Vl..c"/j" #)m,)arbDEe=~w.&se1'/DA-i  @ب>eYO&?  I2ICd&Rt29;?*)W+cR(E/0׵Z#vۭ
6Pt:<ZggRFUU_LRZq\z,6K*(N/V?=Om $kբC_XHwj??<<:888F^ZKDDHNQ4dʶ5$&:O?ѣG~p4x?9lȌ<D;{o{{ۇ@o֡!DlE$xރwE0 5+u@7"|VF#YPޖ?Z9Mzi{%aۢ?ȃ~5Or'}S&P}iVТ]i+yX9U$R^9FݯSk͚CX 5LHpm@ i  $Eb1O@-Jf", t&+ۼ)~,ʚlY1-e1JMxK{,d>#	BLM5SRIʇ 'hː-QP@aDivh6/
@f J	\`$ Y̥!pk^%:iC$	1'
dڃ@J 1<hQ5*WeME$rĈI%_,Y7wvO?xofpv^t<I3|iE",B,|g{<?vե6vg݇$X"oS_ѦYnm8O{/dJ,N\/l*UIqާ<huf"R)ȹ\,NmZ[`' HDF7nqk| Jc#ພ_R1ŕ8uuZ@tr[,y"&(HUUL&Y<RIEl\.\]cn (,,p\cN}b#|8[Ea%9^F1icCDJDsXܮ6mR/>T9$ޘtuƦr!FPF֕TuA+$uKu" Ts#HfM"2cW_~#ncpZ(yVEVtmiQ)fkx8`_iNʪTZ?{5picl;$rOV"ף^>uTPdB7Zk缫}j]\.zjE-oeá    IDATUVUUGMgtVծ3UnxFp#H/sߛ/UXBYY#<#2!erNכLh<>><o.Hݽr7O ZkGfl&saMnMWgg
ЊGfCZ[Db䪪~g X"b<
 RdvSe.˕
@:9>LgnBT(SZŧ(U	 ^3)ZP!Ƈ\.d:UOiȑ}T"9ݝ>+i)``8Bllvvv\, 1Pe%H\ZD1DJiaFq}_ſ?8PZ34/1n?,R5hoۛ?q$bYU .V.3OOaˡ#ޟ^8lxCF3 H~zLP瞻d&ȹKUuuUe߷Xkp$4"hJ	FZՇPDDWw6ONϞ\DRU]GQtcgG}D_UqlܹswmcV}VNks_jv(\ԛ/?p.c">Wv iS1j~Y\sгHTge\ҀZ#Vyv,LeAu.`PU6( չ^jx{E^!.+5\[S,PfZvKH' ^{G$d	z{Ûv;%a& z"蝀fK0{0ףj-À΁C9  7(6 @qZeŲ]ֱ3-xB1XgrfD(yC啽]T0v@7s`!	hyoka_YX\UUHdt':J<I
 `{pTaݺ֝~X/?|zsk;
Y't)/BsCAYYH5B^Pkz7×{7޿;|P-KryDDT6$vo߽"{>y}Eq'i]y;[6&h-X	^XD8YQc! U &"l^D"JǞ\ADPQ>t:g}HKD^!v։(,"9 ~6wvnX_(<:"DeY@+O䜟LQc`*ǣp4
)k)H?7 UKSI_zIM4Ic(4I`8%Ii## tuY5cA #(:+	\T"uq0VQUU;RY	>7ثÅ9\sN)J(L'oy7Cs@i8L&Y։ѵP(6Nt=x|X`QT/1q»ּb>c~jf"D!huEYeUuQUeYWeW8Ѻ!	k(몪*EhB$Y(2R ye@)Mu8-(l^efYd>Cid6LgEQڲg (Lkn$Y>߻{cg'&l:5QtƎ(67BbT]eY"QLm-0%<=jcZ3Ph@fEeIhiaV-W8F1wȞ{{_,mq	cل熨
VU~Doaʥf?/O_E! IVk2D=y."^ %T(J/onm{@k{@g% lY,HUU5DQ@(lEOǣqX[qk]PX6ͭk`᭻ `l -Eh AR@w^Y_H{FRDbA⩝Bpx:)"ӽIdLbOO"c.=VKg}uhp|&m+^m}iP@[:}eͿf6^k_/y]ژUjnז9fxFG[Y`Y71)"₈gA"bep"j"R*إp^])_+7.qBԺdeĵ\kEx :5q{53{$Y߯C1Qh&BW{.6I0ΓTp7,P1/-ĎPD&,r	5Ƙx%ۋoE!"	P{ H=g漮|1MǓ)Z)u]^(:Y1y,HX "/
(w޾~rt_?7_=v~{N7[//Vo*/fo8IT mTnyNZonl(ƑQJOsl3#Vx"u> @DZ[;wރ?ۯfxX$jxZ@ǸыǤ!0֧ǳ1:1A@%s
AHܕybD
[,PiCBt{nͻ\d2FeYf$ܹ{(J[zc} 9܌Z%?;7wwsF?@ h6Ld"Tֺ:܌A5:%Yi@# M{Nnt{Um158$6K:gRHVZ)DF:bBhܚb{&PZYFeYdQ]I:E:2,%uDQu:n\E?鏷d#!Gq[goKgm]e>ϢC;z7~p&ڀt,|QeU-m9z.k=kmBk:vJBf%tZ,Mm't:5JEF[gI1Q[ `֪냷`4ud{r;>Zk;Y_[?$u||D_(ӣc'Ó_WN?yhڇ}x}'϶7ߺw9) 'SED zbeΕe(*k@l>_L'ce8M;~8ǑɒڪW 8*[F"iSu<tQL%!1\O9"Vj/t46"JR*MSTQG'_E,AZRXv:űF ̒x4<{`R"4oܸMh?_,sUUGƐEQ2:#a_9"Hv<EtmU ij9I#{F v~Xy 6$]t(^#{M!DEY1Mv<{b* JX!i8<ݬLyu]̜$G}G?vdtC{	u]ֺ3XҎ4kxMZ,0z2.B"5\yk8W!s<&eqyŸ[_ūN9r3~Uy3F`lKHU=񆶮=@p%<ۘYˍi`-` Y1_I\_LQi! E!
ٴ'p)5lޯi/Lmvq:7=,Pg  =9^Ay.%jA: M"譐fDz%iW4Ol3_-`c@deBQZ	 {	a+BNOil_QRp!,Ȏk bւQ	 {U"8^ H?Kfo/@'\UwI D* G@9,|Ej0Z2֍[YେǇ?:>xy|z:ꗏr}s[7nm ڵ,?:E/Ywy^p%li7zg0R$T0'
5"*w7n{e#I+{hiuSV$I
*K`ODP gd4L(ID "֋V1*jQքDvK7h^$kYuUO?XX4I:ڃ$IֽD<9xNmVilq|>NW+v t|Qe^AE=$A#Ү<q6X[ONFLfAmu|6X8ڍnݾ1ck0ܴ 4t~  $t92gvYIBA] iRx
I5!m1(H~!gI`}]U Z'q\W/>-Eܪ
6D18N;iI /EQ?ۯUE"$'?O_AR (Aύ\cg]]Ve@G(8g5[6deYUںuls;Y_XU~{ <eaA(81ZEqlMe1,sl ((o؎	*Dh46tE=}$MlAZ[WWwnߞZ7|{Vɢ-RˇoS%ܼ}nDeY ?x;DƓ$NNi"!8(T1
#x]Q䵵DJ@ө. e(M3qIӪ1hwUUr,tG߻{JξM	="P ^1sh:qP (	Ntzz:<9ƓE.T+e y%8Уu.,ID'r^NO>ia" 
Q>-dynz2+LκWR Bb1/RkhFosBai F * Sbɧ(N66e\Z3p2l3s7vwwwíMm;ILtTUu]eE$.hο(j9WC.ŋOƾZ5Y m˗_ad;0P:sڍ'4Qf3*(յF`89+X }:f]r"ZΧ^7@M90r2h<(A~]d ~=38jԅH,@&`b`upS],òWoCm[#(p7h=1VVE]B`y2>|D.bNX
Ȉ$ r!2 rD#=#2	gGzImX;z`ڵH Ĺ`CLN^NaL
ؗ$ԳVD)#QژD΢(ʼ*[ב16F*Iʼ*' [RZ)o|t2^=u[;b4),UV8*QO'_/NoG?HqjA5[ChGgǑH3wbms5<9ǋU`hpQ֥b1FR5C3@|1;)"R<l׃:
af[R<Qd  _˲R
A:焐$"D+ ~u.{]=NdA.|:'^	 ._EUuUںNcB4@dJw{Z3I( X|1M'd6YY,sw֝{^ϖ4_Ih!?&rAQ BRJaɠZYs	/oQU"8_.\l.!hR&4h佣
 it(NN9P-VjD$JM''O$!Z+h<.jxzvZ;e>U%t2>:YDQcUUUW)U]usں.PDtޖQsEiıu/])Z;h6DE(4$|UWeQZ[[,l)u\./^'ݽEN#5#]cd:{,
;1uYMƣlҸmܰν?X:K8
aq
 0u5ͤm"*mPGiQT%) bUY0:ggɱw5 iFB$t6jMG҄!UY.8  h4Y:?j:eV LHj6_|?|"1FD$] {,z>kZEꈖLUYںҊ۠ (]їRJVw[iB˜7+A[ x?Skm׻}ۏnnli
+&`m`2zڼw{ܹtbڬ`7q*lWެ\Y=a?^?fܒyU*zř0.6\S~aWFYv_Kn	+)m,ў%?r"њ}6kRE׿ XQ!Ν	 sJ7vs{  XEVEa.sj!ˇ#_̸{Mig'&=O"{	w4DV3+ HbFaK
 )g!aqZEs@(hI_[ 0ʬW"RD  c#TimQSbR 9W)(t:e>+i└2׆J]jNs:)+\V*M;zmk/??ϟƬon^'+e9kIkAc'_L'd[[AkX	^]FVDH>y82hm=;0'S غ{sp|޷9ik9c֭޽{t6/25/.8N]' XX	D-c)=/QMƈAhiӓlnskw;+[yUIӽ8quݷzO;=糺H\N_L_>NH 8M(:߆ Q$ͬ;H,#"ER&Yd|zr2<=OǮ%	7YL&ӺX {UU!a?HI%֨9%&` dY5wE:g%""HGqT纮
Q0 8={R.Aev6JYʲq.VcWUƝ	Br&8M3%@FH3iF	l'wNi=~򯿴uO?7[l"
m(H+u*ﭳj1ꭵNiWDjUQyYy"*}a}زD1+k-%Q+unԶvzH|1mlDQCbwen|IXotz]Wnir2ǣoyGnl;/X`"߉d/?Cԧ}_*[o==r4iI\g{q,Qߺysc}03"eF;vնff</n}})U!$6m !Dy;ڞfE>TYUVDT:d{ n(r    IDATKR1br4f"ZL* *</s7o:NY4jƘ`&UST(ZѪx<t2R@1.,ʪ.ʺRں*B}{ID;Na>\ hc1$T	]"^˶y}Jq|zz7{B\_$/۷yEӛՋ{I޼GDTVlq1"0_")EUU0:LkUa.> o6W걌,wMRq+.YM0~rlWz5\.l=^ĖD >QD6Np	 D0 ruf=a~s	@Qh0Qle)-b L}Q8 !YL;_2.֪٘_9;1J]KZp+W- 	zMV``` J0@>	 P "57)'aE7"m  2ӄ҈ ,"ގ $,("2$"$JҪ,|1:a1C¹EԊŻ&´|j[ ?p8||ٷ_Ϳ~}[oH}uJ$2.}{ϯ[:th"/H,(n1 ֵ rn;ϊDLWU~΍[:ɳuR^Hk $&HaeI9\8Fσ:rFEJ0;[#@Liۭt(|lh4Nwny$kSp%i׋9,?Iңd3OOP)^!hEJMm5L(L/^>ӵZ?Ib嵁6d,tzz|<ŢJ9oGiLdN(ܿ\XNQǉ22q!evj<0(DٓQ!fӝg˪j:RƐR(vhX;\]p).(ܻaqa3(Q&Afiu$B4Cd2fs50U$'OG?>*տʦibH9DseUgǣm$FnMsuy^繪k[[;3֥²Zyc(EP>P)m^l}c#˲/fD|w+kp֭82}l>_~|6={?X(+s"u- em./JB`4?G7O{{֭^WDEy޳ľ%냾_C+aIC
ʪ̕A_DNyZ6^Ɠhxbⴜ#$1|6$E3QdiZ9/Uz@ mBP"y^Tx6EagAaޞ<)SgVۉ8"D;!"0^_(*{6Q$,)	Q}G^/ˢRbf.fB p#	$UxxuկkN7[Gǧnƭ]qه0s^߿#EZkRjF 7_b>c'گhͥ]Qéx+ȯ +fUK.7,ը2r+DgSM9~yp ] Ъ;a>gJ"qe	.g|YW>خDE|.7[MSYn/?^ N!]-F%=/*Ko8YC+} "j0+%^W`qnHC\(V/-c*NYBWqBa<#D& ȍI" #V+.Z􌈡 EHxg-K7 +V	Bd?
f.m/F<UM} 3Ep&0hmv \WUQ:n_!%DPh=ZHj\6"AJ- -(_ؼyxtŋ~ı&$qqGFU9M9/eTrnI*(( Ea5$I"Ҍ
m,uk[nx|6˲(4=xgOo1QGnp'U1' hx4"a֔6IwK5iybH]],BjX)mB~NdNӬۋd:O'd\NEWeEQW+TXmm_}oT]\'~%YNL)2,5l2LF,r[ff]~tۻVl]]Up 	m3p_KX9],^c;q34{W{kE8H_qZȕr$"n&(gVeiDDJ8t,5QLJccZ3Qttxpr|ޑsOvzt^Q&=iMV*TYGHtN"UNqUU:^\	̥zkhK܄!=81Z'Ip2i$s"[^)(E/oZ'EYu8\p8ezV,gi6wtQ<ؽyZ&_k^8N;YVUytxbm'Yvl:EdV+4ˁ1/I&}]WHZw4M#.X[{zrNH,M$QEQE.1I;*&3s&ӖU=/fIֹ`7RH)q.MXؘ(NmLU ҵJQ1%=%ݹswk{٫8_<_~m0PD6B*:Z)@
zf; &xct'"iҮp%JE't80٦Ij(EYv"⽏(KS"b߼LooW6h`ẬG?X_[G^K+yaל(ӯDVNXn)/7x<Mj6wmm1 KW!O.lx:iC6	6E2mgt#ُgB`!xB`ev
]BD|U|o}+D,~V8Qn9I	5[U ҫ7琈6_هP0<ji_$Cc7 C*gHD΢ܼfY|'3Y#P,⽫^C)0#w@.6;RF|M(,jBK?@xa3Sı뺮]hm̓!MgLYP9A6
o녭	Q+ھqO|ヽϾwv{o=svծ7N׹FcuZEu53r !Zk˲4FiDn%cA"Y!q˽nܼ?x"~<µͭfY/B -[Exd|zI$̎}p\]kA5;A T;d(HH)2{R"_ VG=kus^[[7wO`.2] `IN%"ab1:N'lVץvp&!ctM,)|2BxezYQlH@;{_;fl6uV2x͇8IRlnՙ9X/,Gۯz|oi]ORDQf^?M@Q&|1:=ABzUU|'1?eS%GJ#چLк"pe={[[*Y	˪8 Gzb;(u:v拾^{NQseHTb 4GIYʲڽYV ܻ{9{rr:eu$6i}srR뻻GBHIO'K6U]8=?â,_x1~'}i}{diz||W"ٹuVQV9=l>6]]UZq̵EQum,˲^˲6qΎǓì3M8M$MMfI$1QfIqrswwx$ Q^UuQyQڪ,(,H42
*Q9IT[[[;=VU՘dRUgt
ܔd< BPʩ(ʐ;lUEQ5 0"/Dq*V<A *~B[U㡱 %7)"h<ɓÓS@Q#DĿ6'*$wn,"x<GQlh}m])'7u? r_[%74>tFY-u|\VgjF꣯l^l#<=3͖SJ*Cn3";aL
nJ O S0s?Ba4%ҸV'搼gHj6^Eֳ8PAIS*{ 9BYAIޒ"D5:qB-L"DFfՅw{KF@D[G!)Tk{!DT:| Yj:C)9ylhٺ)  Xw,\]$AǩpG ".&A "DhC]1^+%"̢U `Kmh:@E4샟|rݓOÃ_/6֣>I_/_F۠t/&j!4,xE1UuJ	WpYUuY"g`0X_uݹ{>{Ϫ]gϒуl6*cBQ4H<#hdݵ5Ɔ7Z V:k(M(EJbd!hJ)v{N~?4t;Iu Z  1dF<<>E$ɼw"ѤgH;nőA@\Wu/ÓhXk{E(N` y[k{[~t4vd5"峉uD3BABFTj[|^^+4 ҒA"j/e1#bnZpx)qژ$In?h	YH @)Q^Q9fFe"EʺԳߙ(6>LFbB@P;[anQՓE! ژ\x瘝9Ƌ!hq|Y둉rD r^Q&I7 {w
kd8ǳtks÷<40A7;>>9:<·Cź(|>~ {w{7_eo?^|o#ɲ{mLz`:x"X=y3lL'YәL(^c 
n(YX$7 Za.<^7v6Z'1{\EQhRJkm($4UQ2˽{Enں;

!޳gIicݺ {Ae(INw7͎EPrv0_!q4M3V1)"_c\fq9_9_UUP?9>>>:"y^ys͚8IY{/QiaψB*a=@Bq9!%E@:sDDV7CtW_;g8ZwvvnI ъ4}?{@ZȘż鬯mlzgw<onpְpk=m˃ MV.ϟpQ_I
3-L)$#k*8\rXm3xEdS|_aR 60bؑyY֦&!
>EyN<ƀ\m^[:R"|a
   rbepEl:g.fJ':x) +YΊA<"Mϣ#UHJlWSs LıXfVօOH@#;Γ BxXHB**dF`xոB(w  r\""$fE]-`Y"" yQJ&v$2b`:l`W /"} G ayB\v={6g/^\Ϳolnɟw-D޳08\8/ܾW$Mk`00&́ױ-+Č˿WƘ4	qgg{mm[HpYUn&ҨT:˲,|Q56'_#][غv*ET;ʹӍㄈ@XL*B)U6k`c+"R^zAAY,f"_DCh|zk9n:#	x2Yft>yj[` "Tfͭ`ݗਜ਼f_I٭;w{ݞ&{+WF+}]2&,E>U@RDGBBu$FȥpP<"zn?N _CDctN'KE!ȁ R3ϧ:"" $*xg:Ͳ?~ކNcEKq,V-EDC򂷎pR@/ RJX4; r.$;{ a`G㤓fYDx,Nü776^غN"s?Ǔx|=ɗ_7:1F)#yH`}d:> |wK(ۛι'~^b|:9d?omm#Tt4/7l8EC-.ĕs,"IFbXXA1
 s׳{z4cU0:nň(|(͘j;J(66{9YkEJA+ZHmT>*&7cP	8m%ɍ	{rR+EQ,S]=3ۿwwvΜgzY2Ǐp& ܻ0PduHO8&HDiFưssqdznY-W=Gh"ctdVzXgrt0lYT̗DaimEQTU%^ԔJVҲ(uQu9V8ϬijWJ UE6%굫نLYf(uۃ 2i%*̩OyDe. f.\-O2RͻzOЈʳ3B_?gIR\]z1cVkͭq9nR|]6sntk֨7&5<26xY|7jDHXXNOb♅O /;<ĺjEFѠDZ˅mފKv=<˖{i    IDAT|0ߨ2FWK."Qn8Hl9kڗK
	&]R- AGiü`	"t'3 x 뼌"e<>:p~bwo( AcCN
I+FQT\ҧAdMS/˪(raQ惨 tNy/EZb:B\/ ,)XkHlT Je-V(kwNwg/_-fG_|v$7onmg6s AURR3չ3лSk
sR*M3ubRZRhŞiJg,Zp6 ~	d*g8{Q ED+fYL7IQM1-JJkm,kՠ&3\0u=awt2MlY2sd|j[k:T@5WN^6D@ H3e9gq\TeWhZ+lTxDryyN GģR
(8gFU_4r xIZt:8zyO!!3kJghg{;NӍ@֋ɟb^!k`zDQdveqdVD&2J )!'1xG!1Sfo~qwɫbu*@ pcAa{>g54D 0FkA@|EQ+CV8I85w$qyѺEI)E̒6,KkmN;?ҫpj2IzxPƤI2_,le7Q}*ϷGYYqYUnuZ(ይ{wM-~7&"L,I,|2-IiCXyǠ(eUZi+MD"rEE,Mj{ J8N|YJ|{!faϮ&:2:L@iFlU! M0B*|06Q Cx))iZA6)E"Bw@D(lZVnaf_9WY[b>?8888<fV"RUejR&A aFN;zIEah>'h{m!A*w9/'/_Rj5_pt415skKq7l<dqClv<W޾q׮Wq+rZqw?6{_uaie|qw)/w73~oenk;NoelI6WYc=c	 jܦEaS$80IH9XPF.xdaSD4YY?>Z])ΚbKO;lxjzbEuHIàpό }rfXE=3õu"gXyhBAngПMz|"	Q(; B pޗD(bRB,zf*ϗwVĈ0nuw0i$I)BٕR!ظhLHl&<]EX1k{׊:9'?w޹ht޽;;(bkv `cM3(Rlt,cNߋ_MJ)Y3 @sj-eUY0Z.Tp g)_A}qA~"Vgpt:WUEUQv!tzu.Er|<[y>=QdQ(,/PɷW1DQ sGR[.b6
Z	TD(B$,3iJ $TJ@b?xl0+6G""셽|2"@%DN'2?>><Hvψ*kY#cp6޷	Px6>O7R*munjp[TG{/D2#;+Ft;բ]
:TimJ)勧|YwZK3, x:k(uBIK"d'f堃l}`'i$hfVb7sq'%qhe׏(:/lY|l6V{;;Q1*VjEQgM??i˯~'~/=ӟ&[ow4yytgkd{q?""; S(8;vLlYU)tfu;$*Yҳ,JTdkU/=Cq,	:xDI#cv{g4FV'Ϟ<bYHYU41#ҰgLjZv$*#W"c @Ċ	1AfRJ+e+)K狲Ǐy<LP	Cltvtq4vZ|G8:<q?ܬcOkx

ë z[k ӃhUeE;{n'2&}(`v4yM*%}7b!D"ə&|pW;O&өV49jL?M7ԕ&%|&	\7:7o+k<)3yE8; ̒C18R)huҺ'{jxc Z+ŕg	+w]ML zE sɾuQߛ\m)5_.w<лGhaDt¬2\v ~j3;}l
Qz?P',nתW`=&r^XDUu=6 D~&ļJ!-, ޲|1s2R(xdKoܼ+իQQ+2DZ)DpUxj F·3
x< Bw\-fW|/^?~7kw=kYW *c`èM\}<WUݎ{_TRPFje/ޡ:r)P ;Blmq\yQUvsg+f& UzkaB؝ژ$kY#$	#e|5TenwN$3~[3:	B"(RQ%lrTzZ9DuT䀟W!,tfTDQP$a_|:)[{D	j;Dڰw,Dɭ;wo BP4iJIUb=؟la.O5Y	ZNEY)
(BRE yfӉzk8L<9 bjLNO&@{na$Jt`Z >z㯿:|Dp{?-Jb:ٶիW&VDdZ-سu{Z-if{{{lzRDDfny/P6x9 ''Uis
!L! ĳwUJ" 4{JqΝۋ'D۶,~?nFpVipz٧|Z}/Xpwowg}GGE^޼qrW8괳nu4~|>KGO9^`{6Nv?d:-zxͽr5$IX5ȤPD^e+Kpڪʋ|, 1M%Kӭ~Š[Vy?Qo_|²$nZmmtQVǓra#M
6X'ƙfCwn-,"&;IΉl2]mqő6Zc1n(|TFrXZWUlU?g=v"޺BODJ+RfvdqeQܽ{wZ<z8J[nTI9 ;YYiXΠ:ID 0o&R+]rWV4I	lZfә^Hi㸺P(X@5P)̢ٿ/s!+ExﾗE::&>="-Dz+{Mt/^)=?f˕~,սs@!;_+Kvv5p9u7!wsG>lƝEnc` A_k.0P/!1gQ ‚7%z<0ib'BaQi<LpEi@xN=cJBՌR;_(em " tNctؼ'0Fu"WZD:EˍĞ

qxKO^0wɳy&py]9"0TJp9DJ	c	4Rqd R.usk* JUM{vfDWa˯w,*KEI$qlARn 6[3i<Kpv] @Lp8v/^/f/{po`<"RY$ @R|9tz,f3lEq^zĦ'y>W@Az<	|]_  c8F$E9⽗ :ACUO$[l;(RDKr>vQ(""뼂s6tz^y̤uw0/IZkXCk%Dg8HQDڠD6W*u*H)EZ)XI]RYb6E[ow$&ST(U\휵-+*$dN *@Qg=+(8kku*mHYHq$J	pJpZ{V%@ ֳt:Z"<[uݽk׷wvFQ?tL De劲\'zνюa12vm(P;<Ǡ{U\d|2rF Bf+!R5=t;"Xsi W ,xmUEPDV?c&	iqEYeU+Bn8^嫼(^sEt{vZYGi'v;<x3Bx<'/~ o^R/I_x} DI~=)ʲ,AE b6֊ T"Pl:ŝ|UdfMXkր weY`۽^I[7oO'Uw
AH|Yr9_,
)¢U!2!*"1l؈9CStO!تڝn ,0(҆	bGa$ hcvIWU5gW={:LEiMUe\c&7"KD׮u;[U?쳲(i_]%kC)T( 5:h`)vP$\֎vA0`Has*|lDWaj+SҩݵeͶVaVDx\bo~7HȰrvvvf?9_L͙mlo!ھ_p#yX\ޝrs2.ˆH.!!"FIOD7eZ ;y-9SU،[bQ2jB `ȼݜU7cP {hr6rU:n#^]W".xiɧ|yJ@@ʆlH\3OI;=/KױXe]FPL1 # G"RFB£Ѧ"_^p![>%%|\P&| :Ja&(D,#8^FR\9{-W*kwG;{q^u.yE8NttJCJjF얗jj>Eڌpϟ>ՋO<`8~۷8kC(x@fGVŋg<~<IUeNJ'i *N˜+n.(8qk4=F%Qk1em14 *f&R"Ds;+Db?_,VFHD6VNwg`?;yyTyF;;{{Klwo9?DĘQ \zJ"jcIXk</ 6]{J()ҊB" EN wv5ynYRHcbUq'IXJăx1H%UYvUʠ1QF txIֺ}~eVXphψg [[Ngʿn]ZZ,O^~)?-/]Uqu]u𰋢ЊGoW"P&Tj@   (PoHEDJZLAcցVct	%*dK		FI8@Qi| pD*/Gad|ߺq퍧O8z=wν;w>O7o:Ƙ =z'~qp/w_,7o޺{9~r6c|upp0om8A?Ei_]-Wa?$IjQUx/V D#W|8AA~em]3Jǯ</t:竼pRq.8T{"T46L^DF~ژVq,ι'U^ ցxUc".{=sKIY;͜s_-ϟ?{:_S]Y:kۙ9_N, Ƙՙ/_|d|jMf}jeaT  H Ej1;qy@H h1@Y&Q!Xk|hVieYX bpq8uUNޘx\:99qr֝w\ˬÅ zr;8ga~e	+_ҰFNh %߻:+	Cˬ+/q!KD]7;:9EBAK֛ @B#jy >,  8 aΆk=gvꢾK7?_Vrie(0ڑҹNiօ|@MCUDIsRgF6EE`X[UX쵫Ү(I[@JҺp-w%kBB,GDXG <τD H"@0nIdU)5Y5ݫk%Q</ @IG8hwU|afM5DvG7'O?Wuy֐"_="$Wōw,s[0՛/.Iv`A`}UwvU3 	P;aF{_EYFKoʮJk1ZWei7t:4NQ̜/QkWG/?ϒޖZje׮_+/>bڀ ATCHʭI;qW-*Ki&U&A"!@-${Z̗p8vL H	
6J8ΊӦRy26GTJ+5y "޹@ kg&0#&*\ wnܸ~^~?ٿÿ~RPSߔE_|PGrIѐNl>Qj(VUN{rJDH8ڨM("B TH&eVTS	}^T҃    IDAT8aܩEU1BT4H</o~v-v<xpW:~`kK^{rZ>}ރz=yG?g?G<"/kׯ۳b8H=x?YRD?_xxrnVdjXx1_jEVc^O&Ϭ2Qŉh͍!j6&Z^xݽrW|?/fӲșYiJDqU5*	 I _QC+	] jy~5,d|7Jk]*JuommmQQs:Z[9gϟ?{l2(
tQ4¬H%iuu?{知I,qX"60aj@gk4
 wZk"
I?i+IiZaVMf;o߸~j'ʘok䲍"W?Y溘$ɓ'eQܻ{Ao:{ATKxueg:|v&FxV#<K*1a#cjc^7On*#R;{*搆އo8ޤJu঒WJdf%v Iyf-,πVAq3..5 b˂"]E2.5ؿui0	5~'$m֙uOQ̌5Rnk4&$m*/n=T9]嵬Oz	O\	%*FDalEDG F,
27ś7RA$LAD*w	,~tP˃tK(Њa	u!2&Qޖ-W9N(r<z56.7 +B4I8HuN^
m@Z)ｵU%QO:w`t᳧xgw{Abv#Vx@*m!,al:{X)-888!'!8za	A<Z"뒆"({$9~[v<*JC*̥,+ZݾࢇE!:oݹLa6}qtpٓ'֝{oO,f(ր	Z  @N}UYӀYDPP!2@*(̷=n_i J6/9K)eLD:A 8τ*
[Y,m^rc#&jU/D\֪ΌVM"gIdu޵>o|_߸gmo+/ｿ5/[_|q(y;k2U/$I:Znj1v5:99aDP(,Ȟ, e1,RDʄ.RJ)M"^ `fcU%RA(`D,W"f,K3ibY+sPF={~8I*R,'I{4ϿzpZD;7Fϟ={H,W˥-O>كI<|C/?#m>N+~5{WFaeId~ӟVU{V%#{U )Dr>_,WV*ݻ}s4AÙ*gmǁ֑R^,WG|7ɤWR`~%qT8r@ n ]9L,)""T栔F),ޱ&Hi"nwukǉU VEQee"FXywxxZk<}
E!Iژ%̊$^ Vy>_S 6"
@("؇|( Piґ&P!p >Ujɇ"[[wΧ^[9?+ww,H_U]x~5FLDo.3ܢ(:::|U7x{k[5Nkk'J(t8||7 6ҿW:\eMix+fuf2MR"J*Ppxw u(?}lp	ڨ
.i,XD k	w/e	_a	:l",,u:Z-#. k'JǠq{M{9/|=op7.;rfsFROlaǹa<!r4?;ʹu VD;ACD0(f*`fKc`HBH@yN_geݳYR$˛ro;.MrUe$5qT[E	τ	6V5av]zYV}pa)&$	}جCB;kņxR|Eb6)eZLN^[7oHokZ,m5=yr%>o' psܐH0p )E3!'[k"/V"RSe2ZQU9oʺv?ڽ/Z420;Ϟ*bpQ)goE8$Ij~z'O&~hhRnߺ}9_V"15,J p[bDUP[[UUzĐ}DSkxƘvuAMڟ!bTT+z@LʀeцRNj~Z[942BQzec8럏NzݻoE4ík׮_fYϞVE~r8mYC"
!"0ow$]VY=x9uzh'N[JPa in|@ 0AU<iF)*2caZe4*`"+_)8[`@iVIp[ko޺_}IǝNwg4d:Z-8J	Wp4GQ'I}+W|6]lXyF"n<ϽRj8d:-Ml>_LfIigj`dH'rv+Hofi",UwŪ $fIb_z"5"*DM V;ODZRj~k_*Č$ 57qX1t{p+X,xXj##1Dsvvo߹'I: *mD"gY'KBRZPyϢ4!u'y! Q:IӬuYkA"T159PvD QF+JR A;LF)@lհfe  Z7"?_8:>f@|p$z⬉[*4|aLGGyzE&gΎpnk~75{i_z.jmng&NM+WO7&gadn̪y6wī$gv	4`;9q= "57B
pkqY<0;P A8 嚝6WVfhk^Vj(u֖AdʊAsz}uc9OG*5ʩgxa[k3\5>;]!ׇZm?9@䭐bI9f/$(ah;f)PMSD+o` P@7"K_M/Ů*TXw9$d"*JQ2q")=jfRy|Fֳ͋e^ @'M$DkM=&XnoyA tC&d/Εy*:JL"e8Nw/=!"wT.KB.r5a_ng  X7󠚬k	PP(ޕb6- $	+liTJgm}Ө  ([{7j5l6H%֮tZvW{5*ʢw;4ID$ycpZ{oݏ?OƯ,ۻK^ç
UF "*/"Je4D&
"eYU&vj" RZG5`ibȵdLE!"E
KS-fOX〽x/5k@+u6 IZ(pk3+x. -{>|oeYD;{[nl:?+e 5cp3q_=zt8F*tU 2&pD	*MnJE-VZfN7T´" (y{.*wSQ*~Y֯@re]U9ϬIH&iwV&2٬n߹s*cLy|jFAd̳g_ݼu+J\;o/_o7?o~ν{*2{dzxX:W}/>2o4|uܳxOb|c''NM*gRqIVv}W,ZG-Cd`/!ykr:E5Ң(BB	A<LZi[Ud	`wX)Qe#mڝ~f9k+d~x|(YGƬB Һ[[7o%uW/_ׯi޵/^N{_OHI`DĠs{M: PhE$I& ߋ	xEҊDāMiR(T4C (G,ZGO~ЄoZ4I1UxTsakgW9PߚP7r&M8oM]_3k4&lv}_kϐ_ui!3^Em)6e_{8bu(q b1) }6d~Dy w C@PuA/ PXR k9K]s{앰#%h
z1= _be7e`-tA^k`)qӦ&g%֣B+.r:fG[Y!Iۊ%$JJ{@b]I{"PeYrD9x3gDB%Rk7_Fï/6|Hx)m
Y7l(kO;k*l I)R:YaxB`)C"Dή;k[U^YW$DhM;E7ꬣ̇`)<R:2FGq*1nNo3>>?ON9=lgt6*~oYJ,@R
ո"V4R$X۲O2/󢪬V{U;ː;gH~M08p$\:[0ȆX|;k$wuZkUZkmE墴Qj1Apv9gIN:g*í/?󣇟>(^[o"0Rl&#h[Ȫ'U
h݁.:-\+_8.3{Cfz+M?PD4@UrZq$W 8XDB: z}DhC$59(hY%ϾxI]M' @)DUؽୃ?|ǿ'FGt;/=_(GۣQFg"%Vgز(HV uMA[eO'<[9*MJD4RIu8HTֱwPkm$If RUֱ8E^h4v}g[<2?{~G''_o][>{j||v[CRꫯ{ɟ2_mɝt?~U߻[o|X鿿;o\o;/=~Qk)pU\.|5wNr۽󃃭[
ZZdiβ$IZ-;WTLxqsւ1$\8bf,0@(:jccLN{4zUYDX6%VfG7o߹~ciY^|>j٪xN~\UVI5P-^
BBКL(VU*MN5:x3fg{EҕsO>#IХD,(pKboPHkΪM7^?[oL&ֺ~kE&"9ZiGϞ6_ʕUEJ=5L8g냛1<]b c(FnLA6;
b^ic|w[FFx|דZ0l48@GACX >X  k@i6 0sTXOۛ6q$YjfqGDxWٝmٙгu//#2]#]]*x 32.?Tu?GDfd$]=Ե(yfi6fj$]4oxRc#IlP,G i'^g^M+ђJu_qRך4JꣀV#gܔP3U0$,)
@ 0"2+E#TE̊C3-Ci-at"L&Ge<;Ueao*h2M +J0i@mz.iu{.M &jBYEo2FȈ
J-RJ.KESIDfQ-I"si
u"ћv)vdDsKS$V{$3mܿ=m6wg)y{vw6d9Tϵ#v4bTZe{k3s{A2T+IDpYŢ,ly}y~	H/hBG$T0ȩcDl
 ݷAᰘ]/VSdU@c Im&JD֝{yQ<Z-Dܹ;<J;XI+q<C"Px9T]ʽX;]	e+D!GDP`"oR ee$*!ZqEeOfqkjqVĺ4pPjx;P#&4x[^꤭Vn$M}Y|6wnhT1 ؕhWOwsӧO";lm$+J(y9DUc%DCV `[C ߨ ̬HkΥA j$i(ˈ"1j[,(ya%۷7NON~1{_L&~scW?QGoZ?#cȳ=|;C	1!L"(`0~憊i,	!	3v-gMg&<L.Tt6__L.&3xwg{kcXy1gg''o=V$c!TOfS8&t6tI:ChEXQj&@$c~LSXBOӴ3z,˲lXlf5#qWM2aJ7676 4կ/_eHJϞ={wn$VGbQE\Mb_!qTi :K6F?x7u`pz|rcw^[uEQ>m  Is}?!J"ĄE2K    IDAT
]i$ v"*`6SǏbU<1
}.W^]L٧`2bS_HMxRU
HvݘOdҀX.=*LuW:W~l	7ϯVøV"TB,1FѪ9U5 XrUr1}RTގĵdj@R׋?UDUXMU)Q51U^1,{uW~;@U0+?xJezbۊ}o_g(Ɵ@ШIUBPl.aQa2 *H@."#
#   lU%"F.E TU)p`	(VQVTj#pksj~O
իNh3(;;G2svI%ouI)hpU%*P*VZU+'aiP$Pu`KBg(M4MKbB|STPZD@V:[1T:k%pLITMn`~/Qj*I\1<Ѡ!Bkzhc1"I@(T,;?Oye/fཪ1
gͭsî,@dAvhk[W&cG.MY6>E1ZҗHd$I\+M+{7Dߜv:UUhgg@&8Ϣ}.≺I!4q_B`*
k@*ל4N\V!4ժ35f0H D4(G:aU9MIVbg (QMhwKQ7_T{"rsΘsKdmI8k0\eBEZ΍bg1_o흝V3Ʈ:q"|:IS$ĵ7{JCQJ$ N8*D1tidQNꚇTUH"j#D{LU	,Ť'[n4M6Q	ed2~?&>~d6@KXynNO&[g8::)r6߾us{{ۗW_}UddL~w}Ye0Q-l%l237lݸ1\bg"tá)p!l/<J'YZPy3DT!BB'~	/RLƘVpyQdE-lXy.,IPxWBZѷQK[ot;m'~R齂loo{=kŋnoQp0/_gYgeY9h``4eO>w~ 457nXcB`2%IպLuZ*U!j%QJL@AAM2!JrTFB,sia>2]/V3(~6_y/o\f .к>`)xmc]z[e0k W]}x\3C℗܈xqVu^%aW~}?QcCmO4GXOkxXգaԼ]H>Ua#R@S^̪-TbCl1Yu[ ??T1j+)Gsױ7e`;aO6 jmj{mSs\KY?SEm#E6%w<8KFAU+ʘ4Wq @"Ko+*3|,^!% +	H&^I*C"kcQ$pX.C֡ ]!!9ǻ/@[Zkcb6x!E5ŝVDQL)T",Z~/muC1΋fQ%X
mBAƨ	o=4|ONO|WOa}Ï|$!Y|9(B 5R2s[K͝{oy>MAB0.1dH`5
@^d6:/"hm. !IKK;7oo\,'x
	"6i]]x8IYuoU<ea&1d}(L[i]cH٘,;Ǉ/ƍ=LWιv_~>W_@E5L.W<vkIA8!Pd9 !]oe^%0(pU5beEEfQOb  !bA@b1
 @\6s4'U4U]Jj(^ c:gA@UWh4H(@  @B "vƍ29:<<izNwccnW畷FYV>Mb. Le	 TUaV4ٳpZNJ>c</?@ EYܻgW'~On[7A|>ɩ(<~?
!yvo6t^孻|x9~ݴlmmRt(YyXk/& z֖}Ç|_CZQ3$8/"[p:̂Owv{b:F2^lJ@,+(Ȩ ͍NY~r/ʢXdyX(ĥԢĘe`u{~f?ɓ/v*,Zx)VzϿxd&l6	wn>(}X,㳋l:/Pes	4JGOYęgyn\<տ˿FP( ˬW
V 
DrVii C	JFȈ# ~Z2^P1XYk!(_xi@4Gm1e|<'"}ۻ?i˼N:@PCANaЊx5i,T(?hH~GE{(N6噕]徹R(ۛ]&=X] 1t,oZkEDg3c"6*O  E 6*`	]@F"..WCZK.:T	ׅBc#1":f[	k\b.C)kX5U$$fvwUQk#(K5ԝXFEIEDq`2%/	IUSXa&}zK,F@KN#߽P#l% phSA&zUuU2V[C9yqx%k+["µ(*odԖpˏF%c+1JsԩƘt$z|<q)~RRMX@E (|A;~,
/^;MEvӟ=;=>>|o~ٳ^[nF !eQ%^W/QH9H-}<KSIi"#2֐%(<mu)zvv_ιeīEZWB-WLJ'pcݽ[@/NO_:|P6}>/.[n8SOON^z;46].ITybQ1TB*HH60B(bɎbB0V D3%@kWfV8 3,(b$T8Eb2rPUƞ0yM"އ0;66FZKW5f.\Y.GIdTzM,jVR2`&QVKfs@LVK82غ $I:kPAW#&c `cjUUԻI*AVs I >("d8mlѫWeQܹ{ݽY^任wmϟ?';egϞ}͍}ӓ>;{'O,sp]L&|ӧO77Fiy^ed_lomEyr6"?[o"__#"1 Vʲ֞gY1-FѝۃAqYäǏ>hxkVd j#Y3 EQNg^jԅP4pn"]!ưK+c4n:7_eY>W!B!i,˷wv}`k{>}u|ۭGUT"|,/{no}霳#}B\䥆R%Bl:K)ADf7jQOZ@PNxr˧Ϟu-\v;M$IOL1B¬H
+U&(Ku?u  REy/E6PÏܽ4)g UhAj,Ɖ WAPoyDo#sZ;YZΥM"<HZLD+︼^Gt2':.;LwT9ɕAFB/?VziwF- hC),eӊDTV+WHqWQ=jcBUb{*@n%6+ūpQ++P_Yۆ"D/?$n^<ƴzصJYY1g!aZ0&SeJ"[ aԈI9 T "&BPQD"*TJ	"@@a"UV1rRr"H:U8.`Z()*@"a,#J9cnT=aC@1۱|$RQ)}gYѭ:{ʩ
\3?׽ %&NWpei$9)8gVg{3ھqssgt|GGG;íѨ%I "|YU!DDky:
,<etb
+$z_!*3 cAYF[[ۻ7o(>aפhFDtt@Ad:(Vkꎴݷ_3xQ l/^8H9Q6^L/˷3dȥ-c]DE5+#m@WĴqa>
jHg-⋬k !Pܼh/K^BAYV*c]/*Z!"S,Qk eq~zvrr4 tscs`42D0fVaTAD眱Ɨ1I0t"2%/KK :d*Z
U*Y\lX|*$33F%m1bϔ( NۚKP@`=lVJ7h94dQ,t"} vv&lgVu־st6}yx$֖KnNl4q,Hd0^heᑪi2;¥έ۷/^~ѣ/s{7oܻ\	&I:g	4E~v~v|r:ϲNsol6F<h'Ϟ={7<w.ݽqcJ9aA1,ϲAa1ƌ<Ȑ3,K)}`fЊjWl51m8C}|>3l]{TZs%~_NS1D(*T
D糯2ϳФr"YtR99"da/xvzL9m4U=W$w$XTcK$MCVHGnhԩPjR'8 ]0?hU],b>Of"Ϙ66nyݽN}P1> D! q{Um>hQOuUVhsE-Exh\j%7ry+zOB\)mGc2m,ŘrEq$[zGkLZx粗IRC( 4zffIHbVju^Jhl|S{WU/=z4M`%hXrպFKz.dXV4w=؄(5
ClZL*fH%	&(@T LˣAU@{L,W$!*R@Tk%' ZD-x eM"%ٖÊYJ!>MTlS/)D9W)uc7nC!nQB A2}!cv bLY-'Tkp@"\%"jDm6s·s[5@P lE`UtAiw;"C 2di,| kV{[w,?9>zW_~~͗n[w$A2D01qL+XsQi2z&V;`0uhck6%AA Nݴ;(J XcݪQ?!VyJu};7 uZG/&ᆱFBK%o8EaFXĹgǯɍ[VTE}u1 *0Bf#bJq @W4nJA,</<C8YZQ~:2 ./ułEhc(wx~rj6g? T-"P4qd @DN֭=%p	$Ri8F#@L5l)hs|*f:ƴ;!c({Q @ZrW/,a+IQG` ,!f ;x|ްGE&{e}pk0Ny麤ё?7Ș[x2޹}k4Ǐ;}|8bkÇ>xp(CU8AͧgD߿|[{7ozG_776P:TVhAX~TiGC2{n(Ň,1H61&I3E^X4$:k)@P1^d?>p|vJeQ~WED4
bYd@4IR ͗O:^?Y5TRDI]R)E)!At776擋|6nBN.Ig(I"D1Ȥ*0  R3D1JQ	6ׂ,WfC|/tdUE 3x<ϔLbmu7o<+ jƱyhKUV]e WPU .<\z|` OXo$1V͟z|ZI ]seV%O:iǖbI5acըiN\7򯇃c5Տ9i^j?ERWUC1j_6f#"!zy)jzPV2צŀTe*zUrWU[	3W'APYeXmzJh"
3[s@0Niq)U	j^pdk7Ȣ$`@@[3dEB s42 z a@U]<ɏttD*KsZ=   kUW9 +("* \&Lv
ƚ!n*#x1z!Xe.pUc]V>NvRgߜs(s_z^sDb>_ܸveX{Rj Y,هsctࣟg_>~?u߿΃;o??hw:{ԵYbX zv    IDAT[ۭt7wzsc3ͅt[~EI"ЋFYc4vu90JhCeaD7zVuIcS;"w]̜ehuC2Y>Ϗ^Y&h	Z.<DA͑+X}(hP"ҥCl2m$i+@D$ eVf|V,feQxAc
F׉*S@Y%:DDEA{?}I>ᨤ.NݰEPYM= Ɵ} &Ib]PC1ՉWDh VZCJm߸yM^4эm|^^X^c~s}\%2cwH)-`kusO=$Mѿwng<8=;{vzɣ?'?x篾(ʟgN+r1w{t;-xwc_dYnoofY>^?y_\LNOO7FlVư d*|L߹{ շ޺=|xv>viNwn	!J}Y$WpGݝ7vvvUՋ[irQlu:QXkЖ1d.[CQxIZm0@k!CXYnF|X ūcШ2 a4qZkK]AEZk4ogg455X\7IZQ I\2/1ƹK+`l%2`v;D t:WUcLX&IbH*h	 )!0ME Dݝ$fju""6gE"N1;,(} UOIo{;ۛ;v r1\P\'=jn}LF)2Im%2t=F)?C*	d\XP	z} PAqjE"2juLץ#^wĠS4MUTf΍O|3 Z%g-S?ZF+kp+RnFZ/s7}F̼Ke^̺0J9l~C2  !ᰈj 6R=- H
f$U%ΧAUR
HƩ( #9edC(EPQd  & U	@
J,.1,!
ZG?և_|kOW,ZU/ֻjNFh[  !y(ƓQ"ɪn"!qŌtD L,8(DSXjdRz%ļl]V3rѥvvrtrٷ_:|9ں7z*"(h]*%-c$I*D/^"w[~zXAʝ0 8kĭ.	uꗉ/vѺEYBEPU($ޗeWe<x"֘^f{36iG&`uAa=F^&eE5!,-!Jۜ/tM|C+Qtэ̐m\$""Q~1EA]}8o<%d|z
C/Net$PPhIAWB+#"xB2D@$$5ޗUQ<i /EU[R@QĪWIUk>0uF
jPq9 hRep؇¢nd2ֽ;Eoӳ[{ |yrtټIpcc4<ŘF/f:ʲl1+hӽHv{ƍlVtrjL&gY=x]<Ni!"ͷyQ/&â,vE>ͳ,G + r uo?ݢ([3C9OYDd"m\$kl.I,gYHzo풁M~"$$}"j`sp~O} MEQ(Q!xQkI,QXfEc%Z"dQF<d{E̞(=}>!leYyލ{u!2$HE×h%㌵X[	@h3T:=hib`EVwԊiXmG.I;6miNm$Kk
W|Ⱥj_VX5$	2WpQ2N&e BIR긚jEs^nj~͟te\}4ൖk?mYoĥjvҥFJ`D ^@pE;!FdK*6ZcDïA{EϚG{ `kLsgY1kOnw]2E\.5F^-Z]g *6JU@F9*\AIX]G@$IbYJPWoG %jXXDB4 :eF"An F?*D[TL^R PĪIu;NR!At<]<yy]XWVӐfX	`n`(  D
Fs]4YT*crYCe4uC6	ȹ$q\LcJdMǯ,7F]PzD.767nN?oOO^>󛷶oov{}kQўYX,CjwTU]T9pؘi޻v^~,MZ̓sZ4P-1IzƑ`D2E. 2X1e9yu\WA5hv,!xT <!sPgf)&d|~1>޽!
"!ɮbpr1TBWq%G !ygpu6%a,Rt6N&ٴ,A9\4HQЅh*Tc9db6-\ V,*rz1>|b{{Da!DPE.p<pX:uX+YT 
F%,gNHBjhVFUSU^XD'DB	!:5k{*֒3cDA "Nxt:}w}":ʢxY67wwn읝_L޻ux|>;;b6ռN iloӳd2϶vvvK麟d2Zg7TdChۭnctًN+=u}Yyhjt˲$2oTCdyEuow(b</NN^:.2MSr.+
(L41.(Oe41gTYG'}gy(
ğTOQ).Ncm,X4/ˢ,Yq BEe
KFbcaAge)ދ*_/.&٢ܺ_f۷[!qV<:>^dy%Zk$M&2#*"zD@2A+ + D>A݄UTPVvPq61V+mw۝~vvY$E1-eVF(F25?+Iu:M՚u`kpzRΏ.YtW񯪗m:X
]_c]~\]z5?tE֮w+g
?~Ob~0{QZZ VDZ%E7`:7ɠjʑkTA6eP\V}Q}9Q%P3<H21`r #61"F0I( Fet9! *_Q%l[| bZ_TF@hc.%je_(x6iS e X;T94S`,A	!#RACzZTՓ͕MHP^`R i>"8V $A|VEHYYhG8@/,@ݛ7/_}/]U766y;o=޿CE.e	 E#@w0(*~(D*|ڻ{7܁	EY Ф/+vkccȨ*"0!kd, ɘ	dh6HY8C`hUK@T|9,fSEHˋC(% %sB7Eg6!
wED4dXQK?PQ}Y#Xy- Bt:>Oβԗއ2*^aʪUCb,T
ᵳ1XWx&K֐Q%J̩3ib(
f@Faeڌg>Dmhѐ
JɒM4q_E/%D~&5 oL}\+ح @`fa$gaU3C]R,*W6qLϿϲ޻s?㣣Ѱ!ܻ?J﻽KQ{e䫇;ý;uG=},I=W/~Y۳ }Uz[[[,r0xz1OȲ/^?><<|E[4M[NNŢ7u~SDВyQLbz|| @$n_\ ߷fBb6_LiebfҪT?'?ӟ|4 Wg  BL)PRIhOkq8X5-J68?1{³FgPLo4htE`eϊ(Eew<WǟFi@ s?>,U/јK䌨d@YXȠ%)(%Z  0u#2Hdh7H}$:_fE&P9wP94LR>3 ~["?y=X}ZmWb H+QP_Gq
m?T$?\`%*+m	(7xCso̽u9k+"я- HxєI@J'_wİj>L4RTY5~pU_VF&z#oxɗ=|}åDRm(S	%
b"6dXVEa5dI4	zj
!bdKDyցp*ȐQ){`Y%F*4.$ B.`3@<YP"	0 {PE"4bA #У6!c2Ç*sR7ԕ8xJ8r!w8pz"!ҥd(8l:[bȊ.J8T0qO@`-Y^ a?z{x~GG[wFIڒl&(7Em,XI+>W$4!R6n-teP#uƐ!/R߱Ft$Pe &y	o샀x) *!0g!x"$<ei?TUϪ䬵1g ѐ ("1M h#fqo$ɑ	W\wn48$C8+#y|p^ݸQ3+ϸTu32iκ@
~ۡǧߧ$u #L eU/R"f*jIrU.rUz烯'e :x]_ ҁ f|>ڲ&'r]lI!Hea1j6h?_FK.e,o^"ZgY*BL 
 Q@`QPB&
PՂɕ"ƪU@@&Rz#߇tXU :@ID6jp ق̨К$1
#}%.FUKN.D$>4gL7)WDǟ,MS	 nmoٹwNiJgo櫯?$y@'w;888;fa{:5ּ~l4onm=:N|s1`ŋѽ;~`޽{f!ca1V+QF('2+cbo}{DD4MPa+|4އݝmջw'UYKo飈<K㩏G>|p58}Ԛd{p8[DL),i>HhJkAr	LgBă`!Z	&v8L4QlU@ĎQX
!l_j8xWSA 
{uU;;nJ+eJ8ļDb3"J6pD db`QMT`шZ`E1`gyal"Up;g*ݷܻ	C
XBfiCFvhgN."BA+B'x}`oC@뜺΅oϡ%b8ǻd_kw}l-46HgKjޱŬF񸞐~-g
edClw]̻cud[waMSmrN
X2*l!bu+aQ LI <(E213XD-4 L0Y1y6*!C" X*fk\	-#s@! TCcv^A,B[x'  hj@e,'8Ĉ?*
pp	ᆆQdqukc;nkF+[Fb%ƀZjE֢wj(&FsgmzMЫu0N66o^9;=Y-?|xc:ݘn7cDJw?iںUhk衩RJ$#86w^ʕIl6׃ׂ8QJ	
+Ϭ"T%|bx$B"_{UUMb'"AWFk lM`FgaLr$M`P,F7֪U(u_^-*#h3:@= 6-CEqm6a`8uP4I ʲH?{c
Df1dYeYU;_;90fYI	s3(^hZ}ʪ9@L߶N"VϘbfX+Eq1"
V;W+ԑR1҆]\];W`6vX%nol鳽h}hZG,KWś7oŴܜUyq1`PeY_vggq䓏<CT,ϳݭTsg6zggqYY]gI&vscc87=a2,Tpowk9ggyEYYfe AmD;h@h}9[\^lb,M4`Qz4yIDkO۽XcA)ֽ݃ý흝,pU"A!x_iLƛi1_UU}v~Xb'0cOUՂJ%ps:IHFR2    IDATyŗ_}/kMRz{WFkFDPJ
KN,[iǰW\$0EIfyQ!4<WnRerZ)=A[臂bQ_**}zJ#3k ^>N]FȭZ+yN+k=욽{oޘ)z1e
vBq ZE-1RжsnfJ~qJ =]G^n֧[zv\T`&-C], 8-C?Q̠#;hJ^ H鄼` #uu{		JPİ08Pxh2"El@AH!)!@(Np& I9'.r+ih*<~o(՛o&3 *Fd<c]M:ETϭBoE6{|[$EQPXjeu*D{WWJae⢪kl;n_J(>8WXcv=xO_>_}gYщm)pD+FUP*D% 3:NJAۼ\ )ژ5k}}ދx#bMNVB.Qk HMU]r\,˪DDmL$0_vۋ"`h&1QLk @*A	!"@P*6CFP_¬4*D	^-|UZt|rq988_-LD*QEDs%fEw7[g` 
o^=zdӘY)=OML^ Ph#1+,-UU\UPVU\98ikb)V V#іʲʲn@ @k<~]nx"gƊJ%2J(< (* A&& zU3 DYGlCchQJ:*#*<d?,WJ?v߾~j<Z?}<]D5_, 1MSlQ_\\E5.|8ǣd4~x|L,zW12\tZXݨ7E@Lum"6K ϲl8xTEk=74	@򙵷J! JYtÏ?'?y]5뺪*
`00ac#*_/_>/eZy6 mbX*/˳3aJ)cRD8
:6&;ۇӭ|04*AbPFhDP @Ē ݻw>`w{$w# jU%ƒ k6f)(!d!J0Trj"Z"A&p0LMsm9308_w&#،&t*H{C0vr(Js1]Э?4	,ns~?sx(fuG#vk7?\???"/C[e& Z%q[D&b_=wҿ{~Hj~~W{LDM6P	ZYe+e<m-y $Rt ҁO /]PfLR	Y}X&с8hP8)̀	{- `jŗ,2V <`afu, q1pDS6*p@BCFRk9ԎZ5#/j_QFcDƹ觭:_6J72@bq~~1bvYVDf\1[Q,KDwpppg?^eRZ߆cU 'oF|8
E|tzr2W|0BD!¤AoB֯2@uA/J# \HtnF'
Ury9U{g{U%&&iC{ZY#un9Rt,j*WgAulu4+&fˋwr6o5 bzK?F+||lڂ֘|c?gO+spǊk<ޗU];uMMgb7ݞ=
hZ
"-rBQH0R\.[QZ5nߌhFn6w!}uU\]e#PF)#B
8:"hZ% KYUw͛ׯNN{x<?֌p4J=yw<5(U	";o/NB|Y ?~YU%gEQOV^7vwOOg"O b???ܜNr5Hah0kSk1XhFH
>#RJ@wh40Z">zx% x<1(]*x?H5,0QKVV2&l g'g?O>pogLQ_W2,EV@.^m,`/~+= MtkN)MX`-f&tk9'&I\R)xTLmc	?kD@o~w 0jx'_||fYk53K{*nM j	E$ 
vnFUz"F0ޕ17 u3-{܏ `' PZvU1xw^MXMǬ~)vP.c;p-.?MzYwkŏQG3MRԥZq?}n,- Vnj[ɦOZ*|j;JU]ۿm|ڛ}OM`s4[<o^kCdBTLTG I C@F#f1(0*x:[^[4Hz~mL0j  $pC*B*"@o 9p#LԱŵ4L  
D;f"toV*b {#%E1%$68:~ 0}L 4 EazZE-[,uۍSlPfRF)TEh4DDWs>J 3+\.	sC[O	u*& E)mptӓw'GoNxdss{{wtZB19@!y>]wϾr1}?OABP
@|wuU1F%U;-ƌD%6=%b V3J*%L0p*WJwjfN伫iVJk@ŠD( MwYj<68Ib[曑iA UU\-,hT.yec;0Q\\^^\8"mh4Nby *A%*ZiVӣ{;!b^݇ٽN߽xٙ Qvb &P)];WU%-oN:_Kh/M8E|uUV*I}`h2vφDR:bc8euֶihg b=1)DcPWe]9TCTq#m3e0hUYC	R o郇x<@mg/?d$g'''EQ@/߼yZ-w45
߼~u~v#ч W_c=~4*@'˲Bl6LҬmlΟ_%=
t ?&i1yj.In>DZHy[ΎZY(,]'"{p8,,I8ţR*r^, ,tE:YQX\	 Idrx޽=zpo1E()0DAf
jZ">`4OXU/NNNj粢Ӵ(b0kmb'nYy ,7ifEDf	rյ[u]UUVDD)R25D?ƣȫX6&G?8zf>#6IhH[>༏.AtfGWtK`lc֨tqI@L?hOZ/%yywĨl(] 1b.jvkFOBDUj36f4][.R4{}o0e`?f^IoiIws68{чFѪ#N[ڎ.-TDc5Aa7vۋz3E=_pp:"	>TQ8+NOP6*	g@aD hXrSr 4f[WQLs	s@Z@ zN sBAE1+-BJ$R QsSP#s-` X$n}C6aY

AҺ#i)tX%_d@b<m\;K>E"؍,Ȟ5xHCk 7gOn&jwDZIH6k~ͥyHGJ@0ZY+(\-s !q^ƠeY! 1gy!R؂<vW|8}?Q=$olN.O^|tk8$YaZfߒz1}͗G/~x<CT*a8A@|b>3Q
Jy(B&__52-!8|\BkcaUs>Uo+8D1ZK޶`!1Šȋ"].{=
GY-uu\k;BNlA|e-傃gh0ٜ#nvq*"(5@x** :=zar,/pgo~yny4f7JC`zژ`IpuZ@5Lw=;y* *\;u+EbMVrUN4ʹ<8 H\p h%ucfڀDB2ZKDu]9WGZBHJ \\$Jh@Srf*ZEQg<Z.ͩRTu]rTJEa~`;<ȋɻ_/.ƣs<ĬRj\WyURĂiF,.Ԛ:Ͳ< P {LpjXG2,^)[DD
a\_̔B1kwi,އ1yQJpPlnN{;>`wwk:yR)"-h9VǼ^nZjX3ܜnl:W7YjWVr9O6&`0,p4ZB
s˭"113]*+bi26 M4|x>1Ȁ(}9:~X,uHJ'bBZc(X1SGi"fQ>HvWzٵ5{vo=GD`0*k"\'We
%Ƌ4*5k%I-~{}"W^k;7Wk?l}o%}Ĕp+vMi[	勵@K"D27&HF5	xt*w=|JyȐk}:rڵ4y4oĺ%ebPDPB!B&d.@kmPmk`[!d ACA0tѰFAA+ m9=-Tb Q9(aHȯ09eqJY&-  $ Glk>7ͺڌ_Ue]w'UjP+e<"DQD6Numczʈ Q_zA8{@BP
I$R psbʤ&Bm~(b#\!D Dߕz}^Z];TJ
SVsiYFvuMuIjD(feYy9*,˭1,&٭q8@t zw'Ջ_ 4=b0`,sryy:/._xo<P%j
_l>g}sUUƸG#
^iM Ώ0FFQ "( C$_7oby_n0ݳYN'wdA`%5A2Pb2&|&6(l,rZ7%JcUV4
 j<U{IځC]Ng3_W@!x=?|~|tїza4([!
:NOO>(nZ>zh4~ťM+"2Gzt"j1wgYB[|7_PX 0DPyQ$0EY^稍CgՓ'#!ZmpI A"|gyf'
Sf$I@u]Ť.(vijyR>|ۣ#kގɻッO/^\\|/~:l<'o_=⵰FOSZ.Fd:R&ywLaXdyNbOkcgZ,ޝ0,I6V˅EtLlRնEU5Zki
˯ψ޻$6IL^\[,r0(,5X*
<<:>G`4S3x_|-VV V5Ԧ6i3WfqvM DyQ$ijUZNOx&I&Jێk"S)"!"!w
'XkVdp b`D="sj/6?x-6}S>F_|rr>yQxE\Sk6\;_Wes.`d8($Gm@E+#)RE%ow#ޏ9
4*J6qفHuŔ5xQnc	0i0nM!60<inrГ輾[gSRP21 9^DBƘn?Vя)谙X'&@+'"@G!O36ޚ3nmt믎9k M2.V$5hrNi¤t+P	
4] 9pPZ3B.2Kp2E1cD
YhVD	m 8fbA}L>$䕰,n$aE!( kmC&qBɔlVrU˸H+eƘ%S<P"
.!(c;j@󠴎eM,n; `mVm*Zѵh@&VMil,b&-bdNAEXB@#n <* ]͢sMܮyBtsL@E"@Ub-*r\NSPy꺉 
6c-6ArY4M,$	7\rD0D\eY)gW?ggo^__h{o?9YcmZ
18ꇧҼhKFf    IDAT<pwwݻrvZ- :][@\UZB &`.
>xwx?
M> jۢmUJ2¤5ZƖ3Vl6mg`0ETFT	U+ YUj1/Wdsg&I;hYˋ󣣣Q yG4=i|C!Rb˵9b{ y???&!DŦK	..gh{ w)F+4 NTJG|EȋړҼW)k|][A$	 I49($<,W/沬\x"ϲ9ًm&vsh8!Q
L"4QD<B rk,U]UD#~ lmI 八xB!t~>x|_}t:|Nto磏>'ӓO~o{ót6[|x4~g'g^lN/ϟxmd|eyZ+kb\6hLQd"067 @A	jDEt6x%z]veY*VMw''Y,xb,4V	Hr~p{{5~q`pyq 0k@#A4)$'oocWV}TE]ѯk$It6-h 	`ABmLf5yQb{EX$J=EQNJ}@D޻yΝzvwo_iEU*Lx<޼y{z~Ȳy!,-Ͳr,ʹzfNRk;"kE+MckA|7O3Fa,nEU	_܏8J psCnk@iSQG[l7	yk.bwp<:xDwXrJ];C'}]k?hwN`eeխ%߻b"m1@󔮟VO[7.oK~e|s<af^{&$=1 ,AD`d%!z V\p|qT0hDYEa
CD:#,,b33*d0"N,p&E h	!`Łe˒=h!`Q -mbJ{b"JD\,(zk0c,;'e`#k\
c{m߉8g` 
IЅj 0C3v3m8W#>HHh~0ץQS6N @JV(|+'q(Ů&i̻`:&Y"j
4)4YD)Fnͽ >wSnѹRj0 2+cLiZƛGo^._=vvv6llLӭ퍭<˭XUtck3 @ӓwUU4뮋(l0mnjXdcsEw1 RqK:ʠ:?{f6@\Ve]!E9l><[6h& FTLCpP&v~+յw.b8.K"Hs
Y^$hSx`seEt?<7٬,+;?deZ0{	bmn Z7-j 6)PfgwއٻW^D{x]cScVp4ʪ36?|f@Zw6C{7E~'Vk_jUEZ)jHZϪr%ĪJ@Oj,m<BvnUU"X$fqqV%$+D( ZEjvqNmoNJ,/jVewv4!&'i*"b2x@J'ݫ/5PƘUY6'Ib߾y0{nZ5@iXt9/om2s`vyYY>(dc8:8R14FJ&:MLMi&8̩_gvWU)fѨʲ,gY֚ڹG d<w>xp`Qh2NGÁB(])A)4q#һ2X48
f|=L/|DTNa "f QqSJ)^.bZUeYu%$H$d[>ZLoL5bL)juU%"ιxRVq鉓mS@Ƈl6x$I$Qih..}l*E{aBQQmAw2o]?wvrkI5ԣ-i&8zZ?
sDl?i.֖&F(XDwЃ0kXkjZh}Zo=|W۳[hBI;ƘuWw4˧D" sM)xhqfߚ%ݑK_o7Bt}oz;qHdQ	!ԾrD @R2@ &e4<B"a#\ۍlS
 0H $ƳD 'ķ1?9D"N- B #muJӴ꺪d(k)+B!:ǔ zU0(Q)҂כBI9IB)xqOk^R*܅DX0J	 Dt7}c-ô KgVڤXZ]̍<.+8"
Ԍn+=OҢH9wum2IѠUnn1S"ډ($[Go_x݋gOOyedkgCTa0=|Ϲ^1KYV
Q QA	"1ﵱƭAaAlwAr9މUU`ck{{wr+T
P
$
 ąZ#]dD_a36e?wʸמ1:ϳyAv 
hU9Éj4Še;;=9zz*QGt{{6Q@ ljS(k>0	bc1:9~p8LB,6IoQ)l+IRk#6rι󋝽8W>ܻ_Tk[EPE1%2ҭ݃`gW_vvyYzU9V֘EU"؛ xZ,˲h(% <B_*ALk^,U,J'ɋ% 2///d\9JE(GxWGohŅIYu]?yx4.{cy)*$zXxtsB]^c\X|Y|4*v<{wr:mZlll$͜'Ć Dx8/Xgv.vu]@PY^ԻjZ^^\֣A 1<9<<xOlo'IZ{tUĔYbmʡ$@e;==ۘGK^1x2甘\rXujG"&qy1FJ 
"C>DB !" MB@hmLF j~yndY@)n4pޅd2*KATD( ^=˯NΟ<dkZ1217
j}  ?4't]s[~EEq'϶; ѣًhe'bխOي6Wi}s}\?|[ۚ%_	ՆqUg_{|ܷ4ѺWw00H A#Ц'{/=%##^àFOGA-NawQ!3 $2[M ^錼G͈J R$Iu`avZT)F<)Ev7oWC@,/$NXp.mŌ}?8\-SDP30@( ĒYXKPLRf@`!F$PVB.S(A	0Sq\d( E4窪,W\ADhMUP.fXf6Ai}׾+VWUQWDES9xbQ48O	!9x @u>*B$tU#@kTM;M㠊 w!zvEF__on	LmUח1UUUY"iv(5T@`rX.آ&Q&J;1ҵ"ʾwo/NOo/?{?8w۷|eYo&%൱,J\oLܻyc2z FQZٻj~!sn\=ٟ9aBf(%8`cs4&lԦU5  TfW $YDw&SDFkG`?ů776}ufY$ɑ&fWyVf]=.9;}E/Bp߸ܡ.ɝFwWיwD|0wQv~ʅJjq58;?;-g~vx+6ы1"d8t4cp
Ba(h~dgɳM! E46$F')D\%0Ȓf~=8ˏF.'o~ˬ(./a`T7vOWo޼8;k&I__=:zZ\_]ob2X_@04Q\ <Fyv.46UI&*+Cn(dEژb0bfAzxdk280}Y_|r\Q6.WZ_?έm^|~O|?WJ?y8M<ϗ&wJAhm$kj{y58\/@'Il
e$PPMv(뽈$
η$H yPz0O&O4uSUY p8OybpcmYUfRi1X/}SgZ ex)
itw'ϲt4 "{Dkc2C4b/糫F1dh:,<%m ;gm:D!`cN!9ކn'DŹb]U̜Dy!Tџj} eI ZLU7#UU@Y%8x碹Wc*-Y)XCJ߫+ޱGܺuʽ-nb Lc;n-9]r M)  !յi.<C@@3H[(c^Og~O5.9.]vlI[/3hhk{n7 "7Fg'=@fi18$
F*u&5?EoϡEb̀{;000  +%̀(Eo,@OB""ޚ ERd1)"wp1u2
IeI! DGK~N(eCUgJA@39 mۨcȂS6Й!4˔Y^ڤº$Yw&*cVˬ4Uڄ(/IҸD!
oᘢ!dQ-=jvl$*72ƤiJDu+F$ϨP9ctUuغ$,A{i=")`庴5Fg^Nxݴ mGXa8G/./߾>??[<<zGJ&^A6I1ԕ6En/	3R[ zqYPiXc?:NAYA$
{cUYVU"&Y>TiM$8 ?	UI-b0OZ)q݊"$A@\`u2ށBW3_`4*BC;뗅؅QHB@$Ta O8 	hj8}^|Mz;q4KvR1:/j=xg7rTpG4]SKF)@M^0BG>:ϳ b~v;Ds "ea"Gc(Zvef;rsu6x_L$z~|PQ FĈ,{6/:`0WJi|uy3AJ<ךNϋFKc.VU3<8ߟL&~toW/?#ʲf&I<DtŹs="ɳh{wzXg$x&D1:I҈6biZ{D!ò9\z ʖ*DY`		PiiEc$b<Ā2v:Ȧ4IwNNyY;;D}i(X,bfuY/\\Wu>I_D lҬ"Ĳjm몮*[M|J>c$UIn͞(G]D4|>{Ee7|JR9]t	mR94`H[jF+{{זH@kw綠xb" Dd,*$
ŋhyGLVUQ :a	֦Cq:DB	!9k:7"xi܄Mp	Dmڇ(jA ָ덭SoN|p*w)dߧE"l$ܜ9ٸo+;Ki	˽t0oFZ"ȁRwYtȂ0"f>` @,B"[>C?\D3; @@q۠ 0Ǻ hf8@W  7P%UTQ/Z8zܹD)<VpX~r*Rb^iԕXEq8!R)흳u]IgTm	v./Ng  OY%"exRI{{eT ACjZ'I:OJ%YBYw:40m\H><j"vDWwHo ι
U$I$ЅDv,"==2k"1h='ӣO߿{suy5<]]Opwo<(i ؁MMw}7=h--7[Z.Y0M)Ǔ,ύ1i$YmP@سbIp<AB$;cL2ۿ:} 3Jt(1IE`]M*:Qb4iؖAdCAHTVfZ;DlSϮ.<;ghz1~GEX=JmbVD-~!x'f!Fv~yqG/>~^kl_JL^.QX(4M|VCag?o_~S1&8/{^bw 1I"h4Fk.N I    IDAT*E\Ͻw41-aY* Zd'IRhQ뷈s;l4̜Z.Z"ok 8 ,pz~Q׵*=Σ0puuޠ8X.ժ\<y ޻ׯ_,4=|h~<r>Fil*(2R9?OwwRa6-˦Ibƨ$)&s^eYeI}b\mxo"T2γl0h<R"06 I}`g^2	 *
;6]O!4E".N t)wd]i)IADVůo_}ە6٪iH4{@oʲ,˲.뺱;GDm){sރ)%W]@,HJidDH.x|v։Im&
Wɋ?UH7A&IXb=$6*C\ YX$0TWbpgz[\gFۭN0z5-4;P}jKPr+
!  ԭ~k&-+!b"v)k[os.M׻ك魟lZ^}[ELHB; ́9nyt3,~ؼC0Dx[|ҩ2 lMPİw sH1P e88RHEQN @ `!S'pw$ @@%0=KÒp 'YH!hge9,{!x$4 z{}~ Ao!io/ӛ.[PA1\^(%ZqpZ/5k&3E~ll9EZXsbhE^;cTD D J+!`*қYir0zeY]S8Fdo#fdȊp> P7vU׋ee`2$YFsT>D>}s㜳5!I<{4ٯ/ݫo^GG/>tbxcjZfBÃ1-4n>"  J,J %8<s>i>ĘhmD5ck3IpUuqvh3!9&Z_! h+:F"똬ӜT[YNI A!p(D`"[%jG߾y*8XͭQ@
IH$Y0h
:Ĺ6M@)t(_ϊZ/N55izo0f?ƲDB:Y'y:>W$"(./gWiX;׿oGGd
4U	Ȁ=Fڐz$MRy #!lfv5A(H`3$ɒ(IM}p3.mUYDLB泙m&T'3ʋ"ɆTޅoVU5ztAx<JUޱ`c`0|v~{}7_}~~~pp'ƣ$+NO^許,Lg㱙N&`o+ieWF2RA,'ivzqyYVJɳtg:=<g}pX6qҤ4b뽵;'izCX3o{ak&D$8TƤN_^^X*I !K,Zepȶ:;oo_<Ykt<. y MRW۷" ϓ$Jj\.^KpPh8խQyT,u^-Wz]uSU>jRJi&&K"tξc~ok=}SUUT<u|ި-%Jz>&yl8	=CY,@6(BqqEwpÌo;G(ܘ-n#m%$._d,*}6V ܴDA!qڨ`ƪ-nY.Em#նdٞ}o3 x1ʝH<!f"" xfWޖۦO{Gڄx+@|Sl"O(7D	 H~uº´k,
,"L4N ZebeHt＀^އ6QA>n1W4-T=
'MH	s+v Pk&10!خ,(o5@DB][Y[Av cQSK\pPShH(z0iG&IIHkR*>OB"^b|ЖD9c)\qMa>	AA)eҔz.'1*]Y:z190+p0@`[³7%&BM[ɺ@]M]ͯ.,(b0D}d} p4  /W,?]]zU1?y={幈8[߁81U$-i*)DU;6L=DYRp.Q&gWf5Is@RZQ]GO>7UVhݲmC!Dkk®37օ Zk"T( @Bb8ʋVN#16bVgFrã¤QE7">&LMjbKq޶!fZKm	*+ٷ8MoX˫zݥ}FQ	i9	1G}#1X4ᘛ5hc<φÁIrXY*(?w^~/L&sT%.?O/>@H  ua2#(zHD9F (IdG ŀY!fA\P7`,ˊWgD Ap0VL־|$yKliruU_ŅR*KSkWǣq4	y^Rz}xc~^]xݝzU.V]uOSd:=]Y]ia&p8/Ͽ~rvy)̴ǭܮ! ޹r?E1<{<y4MStNUsZ& DaawiZkmD# Njm9P ǽl<tgC 6yE]ů~/ۓkf<|q&uVoWD+xf҆ň ئfgjY1>~t'I۬+0\[[Vu^f˫j[v^Z_
ŋ?ͯYb~$#{=KiP7N1VJk(EJh0Кbhe;b# "F=nAd[gno_w74cqHNK %(_D1'P";bnUTGE	ʊp*hdX'q4B!Bv٠բM@[$nND}RCw_jSv$X0r]>ƇQPT=DU-o ֯ǣqܿ>iAGJ"Fݕ{ЇݿJ+D[
\>    9"f`E c)[w9ֆW*$DjCSn+*v Gj͢B)8u<k`ߏۥ{ >N(?7ݻ.z%V'[dG
`@iԯMlT=݀ǅq6Z+IuMVl0̊IsNRReՋ
>lfXM]ꠀ`\@=]:0vtA z_d
`$TUϲ>xg7DTMv;/"HHJ'i?ޞ, l/KD9nV"I"ޮ"-txw Dk'IZ'b><;y/&GiHp. ec2?2n0w cJxwA\\4ӓӓg(2 ;4

 F?Fͯ*5PRJxݖY-g`Vұրw.M$I$>"#ul$3욦Z;[ǚa=
R214KV >VX*K`AdecU3Sj'2uU52^&j'N7e+Y1Vfγ|2e].gyxZ}oy@߽?xx8kc@y^\ϯ..//..>Bk?p>bLDa|VVIhC~A R&ˋd1]	A:z[yuuԵehD府ϯ'x<F	EZDhl!6&IsEeY"0[;w(/rX,֫Uh
Eiˋ,M?zQgs.$tgKEͯ/..`pp_U>1f8y^.kaa}U951	r믽Π(,u1&ϳ,Kz;V<0DX
 JWڤyY30sIHpMݻw߼y{rݻN&ݝtg4MG8xQCDBeY^ϯNNNߟ&OF,Z)  MӬr~}=(d:ٙMF,MQhmX" 2	0'ied4Fx8^^ͪo=3k³?^/{Z)JkxT~ɊH`γl.O/V )e0z@JHGChmVJEZ4&{:}~޶i7Jr@Zz W/7>;6t';{!+dvhhݜ	bkHZ.(0?% Sꨧ}> nIxˆ{cu+BnB)z;t>]RbۦUn
<|gfcԕ{'#zPF0ED"Jo>{8>XP^P<߶NIvGNBl}]x$E(̈ @H  ȂDHX	h[H ˝	 mNm7x& ῖ'-ÌER}#8*X@ ;QH$}E@	 ­@uN;@I|q> n$.`t"")eъn553ޢ^ׯn:xR@~ql\#ɫ7<RՉG`EEZkY΋ZmD8ē#t	A$t#Tl捁nw覩"pAJimHhjH`b?bֵÖxq]ŷ_7gO~8?hॅ}JNJUD-eF$;)D4!1s$hErMY^,O޼	ގ'gϟ&:I_9ДI</7o.OʹX ".kD-*U}F6fމ0+Abkm17/W$7D@\uJ!("5)BQN&"AY[MUU>U\|Ӷ%4M<M6MԵsuބ74<\sZnR$僦\apE	iMGC1":k9G?׿_|G=2x<]]uk֕p`;q+1KY!Yq!!I2&`0,Cpm2u]uc cr^ZP	Dyx<L5vvuqqzOrb0meR3Oޯ+k$IQ^MfU0'ibU٦(
u`0 d<U(^,wqqQJ9v\&I;NYxUppHk!u9/lX4gpX,ˢSza{]4\h:i&NY8H,|! }um{A)RJR]..餩bPhu}uy~qqvq1<˯~Š(8::?88zt=$Vu+;[mfo߼~`8|'ϟ?+8^,WZy>Ȳȳ`8O&x8$!khD_ZVwٖ!f I6*88 H5py5[GGG@*Z)'I$&H˯:Ɋ I+P1Z,LwۋF|Q&=>ܽeozp]g4~o~p~݅dHշP!@,'pcSo#Q
+`HĶ1?/61[,?pM(]|{']F]ȺC-
R3sȵR0Ub(- 3w|:	"3S⡆jfo_lv,{ g5ʠJ8щB4J J3b\,霝CՀ Oa+a@X(o#T$Z` `<C[yTF<0EM͢ȰMۘ;٪Ʒ}d6!% !M<bQ$Ml$4W ͎ژwDwp{N?WERibLjwgq50UX	>Z6#akHGSR ·uU9T",SfnFuOs!*Iϟ*''_g~O?""Bc*@D"60ی^3#z,kWWW߿:;qM}tIra6Wie5|ßѻ޾oO߿RD"M+#gfG`D  KJ3RQ?5%h4NH_.˦s  7<08Ϙ*KL r^ܴFŭ*[moZ+of@&M%QLgΧY6LgOON>OE
e9|`<_}jq=_//RrWiMx,	J˓ 1VQ8f
@ ~'Mu"ߙ8#wFw"D\~]UYkgmxq}XQ! 1%z+`0:!h&jNJ'f_]Mhekڪ'â)ڪiYiŎY_Z5o?{z={,/MeB<9>Zy>ֺB',GYIxclSz]e]{Q$IQbBe'if&;}+>8Iҝ	ncV@d0(N~}Ris||tiβ^9;+!!?g}Y6ئ*Z, / sMurzzvzry~v5]_/rOH.׶Z+mj.7~jL{SE    IDATa)jCDZ,׳+ JSt4Ͳ{AtZ $D0И gY>yY,l~9_}6O=ofZugA,K1׍W_ZSiD P3cIn3>G *~ԪD"dlJѻjO~ m|oy.w&۬B[Ll4ud@'j,ES\HQ'& PH+AqO"?xא[oɭˆVbl} T]W=B#!(@W.ٽmPҵ< 9J-wnݖjV| dF(c>b#jّFAQFؕZ"4DAFFB   R;'( =	ǐE< ѣ0uObi@@BR1C $MQ6z7Qr(NZ<x"(u0cα"n]ZGR҆HDj)zdy&Ic iƺVO8S"^<sfR$ibtS6{*XgR  WBD͉|=nh`\F7fw]ژAe]W&ZkI110(r_u׸[(1 kfD/?.O߿˯|U1?yvޣ%D R-~w@yQډ:,n0*eHE"3TWj\.m]gy{Gb^
@bOZ_<sp{{{ǟ.'O*RUGQ_}Aq 52 aj(E+ p h./gWֺ6p7AXDc+mҚ4Iˁ8 Z+$"5~?'Ikik88C Y"ʋ5U}u~Q.p߯Zd24\ P 
{A"@o\N&	Z" qggN%uڦ:.45\\V+$QC@ Ǔd2IlxgzW02Z֤sp4"l8=~$ϒ|6;;/z28gΣ9pogj7\/^H4Moӳ,K'n6¤8IuUU+l>/&IDp M 2mZ
!1!g\pN&f8(yVd6YvZQO<MLrkADT?{t95Mc&K眵V#4 ۋ} '{y. wJDϯOOϔ*I`g2>}O<-LlfpP2XVիׯ/..gbQnnZ'ιϖ+\z9|teeL!$Dr~Z5u=Lv&㝝hnmgob*Hn+$l8>:<d˥Ak^.֫_~я'I]`DZ??g8SCmR>pMh[J_g~mM=ڃpE(@luJ1-ktcKis$֐Т$(:)BlBzw9?+&Vl_ַ$6H`Ǜ=q.zBxpK@- 
ڬaD"7lϜ[_I5?uKH0R%_hƳȝkGbH$LQpzJ;ƷVVN~2 2@hAⷔRs[|b// @Đ=1=VޭҎ&?-sAo?vl[IwZlT}D UP84u4(hI6Hܽ} ֣<v;(v`  1hXN+2iZeۅ-|Zs|$ҞsgKqHn= X"0w*KEif{,wLQ!V}3cٳuZ)p<M?_]]^\Wˋ󳃣x2($I#`ýnR"]y)١E4I4ˋb8(˝z,˲Z..^Tdu[0hmq6Lw<:::?<?[.UUGUiQ^d@hYF[ߵ1? NJ %NClkVE^NF #bqz拏 jָ	L+EibR$E9},;7>{y'o2gTub&骬#W/Q^ <y?'Sg]`8HL޺Mc* 
0D-HbXjY %%V{;;;;n`}E5_YQu]KkRA!"
! h4RZ[W8ISB]pS]<֫ef MuTu
| Y2Zy~)WJi:βRj8Yvu5/k1; Z1}cd:IT3L4:+mڦթi:@8SifEQdYDI&'Zk\G	GOά oZ^s0&h~~߼)(pgg``owoopooo2ъUj-eU-Wil>_^_UYrZ"W*rqvrZkm9MtY&I )8u1M hsHuU|lg,tF	xSܚ rVkI$1Y[p<6U^-OP'UU?:$Ī._~ۿ;??7-G?!}5"IP>;Π!^g v.>F}:u-/_ س5[a6c0bRqmr`Kl!p@_ƿOҾ&u"݅]1?cMK쬮~_nY=Ŀrc 6[u>P njyoNiUY>$]"}([wo0=6"BZB#$(RKāt*xH:h[H΢ JΛ 17mWMVMDښܳ0 ArZAZbL T$B%FYŀDAx{AnJ٬a?]A[Qb#\63;c{DElrZ3t4aPZ#ڂ.7.*ԁF[!Q$1(\WEfy^{H|&7s>6t0|pm`Pi8I4! {\	6:˲<M<ϲ<IRmtx{vjcD_&<'juoW__|o?}GI )0{pmP7 EsAKQ/~"*$I1ֺ\֋ٻׯt2=P&{ED(ǏzW߾}zn	l!R8ISoEov U4tz\88.!}px<LL0s]׳rq!]w|@)UIVX(4ֲ$U	 Nt_e9 7>#"rO߻:}훪\9kƺI(tHw)R"j.<b8PWE3zsas!4>4.Xkn5eyf痳,Y') (A\`Du||\%IR7'?yl(It&&ͫr]klX1ɗ_\V޻Y&{&I#MLU+ȣݸspCY"_+gee3 nUuqef|0ȫCPp7777K1 mdt:MX_bU'h|8:9?|&`}4RI,) GÝ= H4/i0Ƶmۺ,rZr*is FYk,Ͳ̦*!lǂ>>D	|,?>JliDet LB
)DZ-߽xwOy;D4ZYB	!8fF}O<yxU\VJAQV|>+6z<̶ŋeY
J4M[珎Bd<MFA ;@B ! yHP4":>=WiWUAQ	sm:/k5y[QYRyNĖ_~˥R4N߼y"Mޅ`<+-WCl}t5J+ʟP![,}F^+B}rccD@zF.fŭ "rbdRtu+~!FMy<Y瘯eb5UM@~|Jp79`.'Wk0&3R"cD*:'P |Bűzcڿ]aB\WQIC`5B@PXADB-۳.oytg==Ҳa7ܹÍDDRt-}ԩegxUtCJ  1+
@j2	ԠV^o,!i#1 `ja) 
=C$QE AD H` <(ЊH  :>3ױ|6G5"'P=kfRQ<Aa --욆Cmۚ$6&6\)ijkr9MͬTu7Õ%A~0K7c4m۶m wm')-|>'у,-l0Fm2[ۭqf/xW-!߻wo?7_={_~?]~Ƀ<W]B
ERiy\Ӻ 9WM&o<u2E4Ѥ~5:LW˸
D(~I\y^?6??mLDJD S#Ea}0/xMi&vkk{w^ZMX7|իhm r.̞)fb$Zd2MPk /}Z7ʐMM|& &yZ$=::Lp!@ŲmQAR>4uqb(}+J{YUD5F)RJvvg,۶eg;\:δnfY֫55>Wϟ;H+ PJ)x50(ϟ~ų USJ@iq.IA4M:uyn~}XVpggO?u>aggo}jUik]S+mrpoOks~v7XUbٙ
I_*\Sj\r\""(M6I4ք<r{!Yw %p_imhcg9d6!hW|7>{|Zq5mAYۛ}?>b˪kiXDD[	룣7^Uu<}Oqc=w?|X.|>۳d+JD2cuA3K>N¾릮94uBUS׋W/MVd:ijjjvvՋW1V !0*ŨYiTjI="&F	m̧?r8>|_\Vi1*ݴNk0n/ rT;L	Vԟ6j҉]w1y)>Tm̻ D)5zc.u#	8lN\C`.EXo8l67ȥkqz@G8҈qL",WtW96}.Ay#
su+n'6ۻv1c7u70xұ_q`9DiD	0@@ RAH@B1(R+^dVP ZV  "̱xZ0 IlHE޹,
@/}X6.uXzbf%p,C,"Q5SOiZ[Q=up`k:V)=%=zb}ڱn]AimMi9oq6u71=K)M]|2noc`a^i<CNCPc

Cӄi.JN|<gY$I M|ry!@( "Pdt1d8>x͛דd:ݛlϲb`
Xč#\.^$ ݸwu>tr5%
WknUO(ljc<?\M+1d{$ 9@c:({H]Whr̒,IS6II'ǋ<8ZiI)RY\] Q'4ζU_$#n舴6IwV4|Xdӣ4ߞ&T߼hS R:A! YZ~՗2vz,BPY^<xp8Ll4M4eՔ22c8?+WKB(ݚnͶb/b59>>ZVJ)ktL="!Ρ"f>I+U]/׶qek]Z(-.uUiE 2p|rZlzoo6NO˥A)#)Rzgwgoo2Yºuu6M[,lꪬi!x˰ZI<K$!9`4ښy^UW^xqxt4({=rM|  g9C]6IH$Dy?TbUΗ媬NOO/l\FE0hmfpg&@$I2c}ԭ;_,.ϗE4,tk+O4(	;(
nmm*Oñf0skXs]23RT	\ιP[ɵm]U<"Z)c-)Eo>={}(Hp{k+IRf.W|^VgI:XRHJ)ҊaFh<*p$'"FƘ]GO>~_m^+n  ּ0p}ZܓV u!^?E?7O_LkO閬sz?촗x/T㮸7G%V9]l}~,q:/h(qǑ$0v^q/BWt^W'	/&)ڭD]{A80u) 3!Unέ3ޙH1jNLz@بZR;.^l~ڕz_/z_ofw7M-$._$ybP0(a&(L Aj 2$B(SuȈ"@AEDc(S>ں/"VOJ$dc!rL|uŁ 1OxۨU7E"pE(XZ$s$HO&1j(c^_&๫6lZ"	 1xE	!Ͳ6眿RwʈS%8p5P93?!FY[v*#
(f	!PhK4jYWe`ݝGcel/A3̭sDm2    IDATܯVg}ųN_|O{'hl4Gq1"#Rڇիw 9@zy/˲hrڕv HU1'ӽ<zWG/N	sC"DJlTڇ A .f"εuU[gɔ{ʊ~OvzggL"X&ʘ6IJlxǝ6I5U)pey1Ȳfqqvxx5֊PRJ1V) k[栵FR6mG?.ݱ@VU %NEnAefޅ\gfUVeYm\OOA)BZaWrKix0zZmmo$)n4M@{} kć y[c릹8:<! .&Ha8r18?[Viد,5Y4εMTaqoo{mUUu[媌ΟAʸN("1YeijRC`$IGd:~^|=G#&|XʪijU#ŵӳ|\y!F1KSmIY^[۳{}phHu]UU+(*96(jX,mDx54zm|p!a!H*M6MA ޵M۶M:x$uutҕ!)d0h8bN'"?>={bH5m[Wkh4BDUH)EqwVBBE&: Y%iZy1888O?/"	{45u7zIzcsv.~Pa^zm'ݰ9㌷VKwtv	Йa"[b49Dr==8k&[k[us㦩,hl$7(MDZw9 D3k"ül-Ǉk_Իm-rh\݈X7vK:*(5rC!F $G#,RyΔfmYpT 9af-*H%xe.W(2p?~@J`[0-bZ%I@"E8C]p)Lxp=>o/wCJ-z^"rL"=A]k!"*0Eԍ #*L1o[߶
L&XUl?WPA,}^$m
1 M	tk4iRio<!jHQBup	0Q(J@|?W,+篟~9L=x{x4uk90acޘJ<?|ųo~?Zk>?g>xiꦮB N_|tۯ޿6WR:vi>xy'w$$cp.RDR~Z,|ͳo~컳7ZdE޿OJ$0hCQ\|ӓ$kirJ R}&"VM{}/_>^DuY9pG=v岪,./^88g]yڨʵGe\L&՗~<Ip61 B=kUS36IT([?&fyq*J"inooM'[Jtc%ir\P7rZEFDr~1i1jJdj={j\8l]+@&D\֚^~ &H>f_<::jzƇr<??o=;Ufd:l}wZ+k5VH9E~po4C6gԊZPJ+ڤG"&	)B|dy"h08>:?}ϓ4gϞkm_PHy?ϟK/U]UY.VUݴ~ @gYj]U5m.Wtᣇ?駟~O~2q˦䨮k!] Z&b<_u&;01zU7ιFԾi[>ݝ /Q<"(DXZ盺nU\Ӷ	m-,ѰQ-CPѸ&齽*k<k]7O{jYj|!b&Z 
X߸E A*DM!ֹi4E7!~vQ&yC4%|ӴDj:2ɰ=!R,18{Pn:ƺa-@7{ ǹ?^a""BA"@3ee>e;496zR<a;~`lwK4 "y>63=µ<a/^V6*}ŷCԷvFa}x0!Fٗ;̀3[a$hF"Aa1YC¡%M"FS!hB  `%'Gg;YZ.ʣ -)XU`	JQ'QZmDO*IBsdߜo8DzAf/ ABPwAW|61SdHZ)nhT vF[(ZY-w&I;t( )u/뙳M覮)#ѦvnztG>1gķ05GD + PuF`IDƦ!ϞGb5N)O#$TmۆYg;|_~ٷ_/wHy̌T>M[xJutЎ }Z=i}׸+š VeU5
~xooo_/ObtؘӸ	즥CP8DSpmjֺ3:˳tXdmx_?~v*i^ܻ0sm,r7oN$uI#Mӡ6f&sE\h^>GIUlfD9_!bFiM8$Iyݸ04DênacN&<|%FL$xnrZ6Mն5Ȓӳq2hQFkT:.SiN&tva:...a\nooEqXM(2ݝ/RĒ$qZ-cb~I>8N|Ȳ3A9DqjBڲbQѣx4bdK)sZ]b	NG`Nlp	 ,K PJi:&1)7/Z`PU0:V eU|׿s^ ;%a 4FkHuo41v<|O`wgk=M |zElDH~\~Z-n|h?BTZ{صJGfQp4cDlmՊHnj{:,˪i[}]3	Y'ij4Iljm$6Id2m%iI$I
 3[/?e7ZaUL ҄Z*$B4+" FV0ϐV$k@`MFo?~5OZ*nmV1"u;ػ $N"YHsnEUM'xr)p76T^ab3'"&p3cS` G=V%l uO	"%"4&#y#AN*[jw8 ˨PswAznɼ+~w_ݱ 7hH߽-A~7s7yzEcš&a`	D @C* hVד#jDH ]CWDc9c:I@4H "H "
ŪX+ytA$DR5	i@^/|W9˵H%{R뺺~<VE~CFkwz4JDu󶲮͎G`SZ[kcn'Rsn-v:ݸƿ{9nt~ NZRӐqf^Vb0dynъPw/"Sw5T4aa1wwv߼9:9>^\}gg'Gd:+F4+nM0m[mrF
TDk!ZQ,~{uz+wl1@$Mh<۝//N/NZw#H-t}>\珋A  ַM$HJ \1Hf=N'kG?zdH	&"`"̲(,4uXZ/iu DAϟ4Ͳ Z]|몖A%$YYkN%RZ1fXz{o^:J|#9	!>օnʲZbAZ|>wGjMZX֠ȝ,pzrhHDgsM)$PU"cWrqrr&7Źfh2MAy\8=9^-A15KӴm  :i2kIhoow8dY&)zd2HS# 1r-DhͲ(p3mo+cλsaDEI,gggkk3!J_O͛7h(DD pT h2̶;{<6&
mW$xX.˪rU5M2Dh(AQGqnf(V6q$$1Fs7Rm۶uۦmϱ\clc<6iVIFAQI&"EE{/"(#O~ꦱaFd2t>ԅ`!Mf{{sc"H(oztQZ+4FQxl̗X ?]~}.v>/wos/x:켹Op;:}{?#l,oWoQ!2л|9^uE "J8N{(vy 3էV'sL\3@_V֞;>;qͽy|gꟷ8ϛmD|{쀣:ѪbF $k#+atCe` ;&H	r-+%JuWzF""{ 6b`rcRP@I^h=@.T`]B]+G1𮂮=QAdٖέ5m>( 
`+yDdwX F@L	07;].@3PBX.:I`myr5Sy++KD\@f˭UK& J)m4Ydk26IAp>RUɿ1s]UUcG,Vϟ~WϾW<?tw^>,]fodh8@?(Z)dƙ Gw .D
AmL>OcGgoVei᷷Uw zgD[3iJHVK>_A%JkBXT)FU4ͻ8zHdL>8&Ő5Z=FTzV#@F?mk!D0,%E.Q )|^xqUBD6lmvFQ;s,"ҹΞ޹uUUU*r9nRE]UHڬhBg;{[[We?~ٓL&|5g/.V5rrrt:9<<<:<\,{$ZZ+6M]agE;:ybO,˲硟J jEgyup56&MAQ[~r_D$a4	4ax4f;p0m0kJ4IT oD"<~K1ƴ.H/g3v>(miRd㏟|O?zp`8"Ἤ۪cTB޷uX,˲RI:&p2M{stTV '	A"&p+AiɉwZ{oO ;Bf\u۴.xkMZ(2E1   b$+ECo6H."RHI`ч>~<Nϲ$tSQ@D@
FKgA㏆1"zB`ϫǏ?zq2uӨr%:3e Yǟܿ`FZO@"*],D\(YAH$_$U%U*WNԨ7fS6|hлqOA{1ͷHoR1-
cTYz?pvpyCG!( opbwgq=VW)n㍍7W;(.QW%[d;*{}5rC-H|=khsX>б\qR~˹fM`mϔMDFf  ] )ъlp̰* ZEcI"  А
: @͘(m8 {GZK A8@$UAb6-]<H00[H*ĠR$kWKMƘGu@$
X2(}uO0ե>B;GDH@DcO1	'@}z0QֵoMMiW2E#1ɲԚNqd>@xci[3a]Iti.z8R!-LITTJkc9wrtx~r\x2Ynu
 BH)$@tMfhzჇo}_}E;{޽ݫ/ZwKzV"TTJ]M5?8WUM|'֖ m35F7*[ƒs,oӭAQh֭ݼ>|d&rHjƏ(T
 ~VD$hbTf<$vëǇ9L[ۈ,+ b>0ֳf!@آȲ?~{`~?:|9F޻w=Te}s4jbX,+dt]g'&I&Fk	yow7ˊq֗_˯,?ŒHeӶ)[lO&|9sh@h3c 8\f;xÓcDHɓ9YI0wNc KӢɤvgh=N8>:hk2'~sxtt<BX]dtow;i'0` @HR:k-Zc$INNOnmY)zMh==~ӟ|$I8$-EZlεћ3@dd'F#2VDصuU9hZ-n<m,p0sAj@/Z% giibse#b[ۣ]"jʅ#RJք:>G?E=#}g12H4!T7[aMY^Ll=h4ՉxJ{;i1̊CnԜ0k9"P+a}]=r[ғpԼo    IDATB?ͻOt<Qt@/}m`WoME^i4ְ._;98H[2 j0斂RNBBR=p/qkzopS":h>VCB_"\q.R}aҚ|TؚH{{BrDߧ36*7s랼Ê\7v T*Jħm-x-D *hHE.$ZC0 j`K(PQBĂR6zn@ f@!$VBK"]	C4"PBI Z'*!P]'u.b:a ^bJ
5˷,^I)XB ŀ]yS ~ @ԁhk!RUoB^%ic4Iҵm6hko[CXgP{Ay~>Ee|WA >V$<˳,I|s+<BtfGzͫ=mvkkZ=GtkÇ6M}Á<$XBԽG'xCnANm&Pt3D"6Em$H/"TeY,ͳ|\M#"Q'sXFl>zXl1D Zk1lo/ǿWϾ?|_0N"hcBƘ`DM7_}铏?L&/ONN6  +"P+el2ÁkU*WrBaWUYW)e"Nkc2VixG<N'i00/Ç(nz:*B]uU-rU7͋//ϛ pí$IlY5&!EQ,""!&Sb#ϲ4vg$/:P;3J/ãYjh0`2'h4($I@k->m)k9E>`8/s_<կ~H1}6D0+,ˋ|6nmomf[Ѱ(1ڶ/uU^^,Wlʕ F}AVybb^bX3(i/.EDd6y4(2ƘoAR*t &d2ITRFGX{ƦŀK-n}@iO>z1 NjHE.
,Y4u-mFǵrwpo~[ MNd7SkP	<P:2co~]z)D(k+W @.zB+|rOk6c`Vջm|/K_9w4ޱݖi_y_)B~H" {VڍFNA 'coּGk7k<ꝳx9K]'kH} n}ԑ.SWTMDXXZebjR:I"|
ڄWH =@':@Gwݡ.T4@<=8}p ЭC^:(hbP4PDx>&dLO./WCBF)N*3_YLzV
GDv1ވk5  %O^U]'mÝS%_S!!v˧:vc)*"={-jcI5cH_ȎXڶm[@{6e?(Om/:# Ks'>Lvb)DA\C|Ei `iUjJEXklb6gя;rmV_=.gOϕdRkuSI"ܡnQR1?6EEk|/  a,R(cUd%ML @"sr$x>Sv-6W‛7Q坣p1"DZkD+m(ł?~UI$pNY5!M4j~o~=}e͛ߝ40DbRJeY4wm\[]ۺUY|~q1XԕT2(c6JZp;;YFw~].?/R"vM[r~QMU7uU!B̟*t 16M,+"MmMZBIӬi]ݺ*Dk$v,;i<O1&?x0ۚ<|0@]g6E>O>9?;5${[G6ˍ@H`A8ږ7 h4jֻҢȕVDW<M?/Q۶4GWiHY:&lgwNur:y1U4mUEy8Ax4E%(@]#05 nQk.m[UeZ!b$Y  H'SclR PQe #F5B|#zZf{kژ RXײՁ#xQd$	kM{n?4߫> fp2#c,pA `e9^or
:q\`+XGE7dRsY{ӗ8]p[q+c:o9B) $w/ MlW  g 0zkk*`Ff FG.õv,:GN# _}^H_x(]q7BEcWsZ|~26DT_h^z8h.65z@xP]kCqDDl
Dd׏[1f`8 @CH&v @ xD[RD** 2JRb#%   Q2Tup4 )Yc8QH9PԬ.Ǖ G9l "Z2>aa^+b#-Ke29庫@I/RC/! `FLlm2s-=s[A(=g̷`IaoHT=Z.`<@̦@K*!
(14p @%!BBp^BPȱKvi'liF%sE&Yfl D1=M-Sߜ&;`"jE {Y΢ Ab>&6_=t6 Q:Ф#﵁S
d	(	~\.sfp?I! 
[^s}eQib}٧_|w*~o~~Un4xOvۺ,_)f/|[`du^C.⣚!_
  F6dKpUb(1&aN(3}BGIX.ϧ|93&
m۷7T{T+6/{='ƀii?uuo~qqfA rQp4;80%˗//߾~\,|pggg{X3?hEU{W-x9,Ūgʇc$o^"66Imclk!:c٘ĲFw!D&#*w?~`ׯߜJ(b6C3JΟݽdw/4~዗/.`yytvZ3DEAfذ1ZkXTHN&Y
3I+D(">z%i!!bC@ &\kEkLbM媊|џٟ=,|ow'x7^$޿w_qvz"*<&a6f`gZ/2N!8@Y6lZo޾],3s|dLmx\?6_5dvwwg@=vZMήacQ86:u%!(vv?d4U0FC2L`JFUp4Z+S:ڿ]-?g?]LχIX+RC$&asw|xG~+j/kJ@h*&: M	nt"*4A
;I;q*iF떎ٖ__l}?_&YE`B@%h@ʪTA찢*4E16&Ni&@TEBmQ~K	&2a1؃Ԛxm-8]O5vl6$rfYZ
gL"Wbw/!"ڋQ15shy,Cl  *#()FxqʰASL0X X*R)И1+N *~ CR}@UoP Owj$H qP$@9	 6".PL*i?>1ō#f7	 )Bw.yoR5`B"$醍JBpUZTk_J<գ^'m *޻`kMM0h=I&rUTe>2SUEj/9R.Fgu
vUP o~(8`{jjܞ7mιE|4F$TՅ G5SS7G bs{?rœo}'ޜL~rtwt|o0 _}ḄOն՝ "5fiYwuԦM^Du9oxk#HIRT5xGlMX-Rk8ITշ.#K70 Jd3(ay@De mH~@J&4V	dr;~/Z̧o/m ,?{t\gb6늈Fr8<:L&gg/~6B-#0#[;My"һi˺^bUΦŪ(Ñb`&IIDU0ڑd,6' ˪^\?a惃|7߼~X&2G7dW&ɳp~b?	}oy&v<HhlAӲ,&üra\<}jy9_EcRW5橵L)1'
Rʲ*몂hv^P.W+_IdDs /g!1\.窒X]<?VU&t>6ÌZcLb٦RWd1q>h8LgcZuxfE9-dKxUHNO}loowwk"^!;㧷1Ӊ=1u˧Y+7~?/0lƇQ	$b"˲ÃýCTB1HUC@" ~W9;;4Mp4p0<:<<8:NCkh3=]h~R	ݗ-vMLp !MT~c:彨
!_DֺZ?[K!@Fo}w];baču|󽨮SJK"׈c,zDvKq4Q $cQFΠ<=槌k F.SAj?pKNs9pٗ;Ɛi7En/׿}37J=}x?\\7ލ-3lHCE1 %?tVlq1 1H ETA"c(0k $; #"h2H  0j "
*`M9jmVEԘP 88%Q  5~2(81AZoJXEC\t TU  A	!wA\[Dӵ7	sUUGPDE"`F߰Ytvt@tƪB󮮘[klP6\V94$Ieo딄-AOzo\)[o=5@/ǫ`DUl [MN}QyMŇP>eZ-U>ȓ$5@CAyW@c5T  IƓ_|yqq?lwp|o<I$)_GxEVQt}.oao7zcKCP%3
ј"	nwD0l -v$QhOq.Q j{#3}Hlba @D	@E>{/٫U9EQbU R*rZU|`A$>>鳧O߾queưZk`PuY >hJu]UeZӋEQlw޹Zij$I&Q-a6$1֋p8 
ggO`W/_-&8 hݤ!" 7s޹py(Fj^
_;gh%"kdgo`owg_L)VUe	 *"$QUD1Y
j)+˪(PU]UUrUeYod84MhCmIQ	U]ǴF$104pH5Yj6[j1_EY d2ɇ ϳ<K"(Z`R% *W+a]eZ >H:EٺJ 5LBZ
xFW᪻>ߦ}*˲oX.4b@Mޚ"<"H0{w<xhQWY[ZDGv',x<6Z$I:l(.w^|GY!4.Kc콨	fUZ\cot(x7eخz4Lg{+ٗۤœަ%=z N=*(@,Į;[w9~IQ4j&4?4Upt${Eghy/vpGfw!HW-ݫ׷rCplձw6]oWDl(M+Q/!d#M~ۘ76VG(!2KPlPjq&im1VADA$1VU9IPɪ#cJ[I4TdT۽( + $P BUH+
,DX
( yj!Z^[h1@tfEhrD19##!nXDD^/Pdں"!J@X)UUUU6I/1pFY26lkiEBW2I<6к*&i6Jnڰ?Z^Zr/׮w	e^PץGm7F@C$d"	~4ǣd8L`0U6עc9PVT@DI>|EQ|oz՗'o<8˲?OvÈsh;OMnPդplKn[i߲l5j"V	S -Ͷ]d11{Y5_vO~CnuԻ"E;=fFF^cܹ?jZ޿].s>"!Ud`0Bpst| L1-Qad;"Ue]W>E0cYeZ,'2$i\, )<K4I$)1#2$M	`iYרշ_׮vy󹪦i L MZh?F1iI"!Ll0f/&{{{xXԵssoĚ`pxttpxYQQNLϝ`aJe@/
4kq$ɳJ+j\VEYjWTb/Xs"stt0M&Q!bU)k@0Dv/h " 0$!x	! r:]UeOÃpDLއ9 `D@	 S(-WbI>㋳Ӳ*1V4*ME`8I"A"e߁5v,P}}@dI"    IDATJXf {1	=|࣏?'[ݥڈ*"wEB8!x`NFk-x;Ki3l}}"8U%z`NMU|\>[z-zϷޢGCYsV]kSc\cAyKhDR4 
e?Lm
NhDA/%PZ6@HUʍaͭYԷo(JE+@%BBҬ:,Y?0چsD6x.hnT>{>mL81#25{Fl4nqhq$RÍ)Z"H MQ8TC+814#E%hN$	$hdeA Ah	`qmkc41VTC[D0@&jy$uF,B0(03O\Y7\#QOxW;;kC@ T=d:sڄ_B]0(!W.VMhmnv&=@ou!]5Zsfk=jT/µqhT;Y`$?[E|~<d8ٟL jLliXh{͛7×/w}_|ν;{R9 0  zla*q:M9k)#@^7L m,C1KlTE/꣪ ϳ,˲<]
ǅsP轟@zp|<@"
;"㿪Ma"
(X|2r{Τ,V_2Fb>8<{AUWCU,\]gskgSk$yZ6Z%M!Awi)"U=8y7o,_VE*ZL m+К9tDU,ʇ@޹bUw9?=].Ĵ  9K`giX , !x6(boެÇ|烹5ZSjEY,WrX̧ogl*J|ʹHH;w&,IP8Tu}%4m)*.A5N`c4I&Ab6+|q6_TeX3=:;8L&y򪮃jD`C4
 Z *kwz~Q#={|{{57-	( -77KJ$=NaI#6-;fI?**hLEMIӽߘ:3"5QsA,E4R{R렕<y{A(UOh;`D#	HuW>
#y]ې.] a՘Z}l/L;OFaW1m*!\L2[NXbU	ZC(Aq8$J4H9c}`$	/%l"q6TZRj/0ꮃ ~Gg~1\}zN%r`/e?yRSwE7T %(BC" sug^^7FQc$j QP82<zcKPtH
ٰ IHPbTf2"K AbѳAI׾LE2[c|t DAL>A"27# $"uTEKEhVuUԋL!awA 'j @4YdLB5vJhoF!"w~ >oe΍9%d0'6v>%IlaZ\p$-&>t[1۵%#ch/E? Uf]qHt^Cu@VEY~X,/p0Ic'BW^kGDN6<;ׯ޼|qճ'ONN'{Gi> "l|z\:>;;_nѤ)sT4y1?lSdKb6+Wugx4Z.fo_}Z&{d8\+ FݛUx,dgg<$x@>׿|rv&I1dI33WUr6w"Ϟ?$dKH$>?:eQW"u]׵sޟ_LONN/i0|y$Ib9Icȴ%#I&Yfi"=;ysq~wsH*p\b=mw$b4$kA)+όI_D"6cD|thÝ@5Bx?_'ombǟ~Gݿ{VE|>t6_,媨j}|w`4IT6 [!(z,˲rEYWUUeU2&,Hff).h4(G^[<!eQeU9 ib!b AWu}~~>b:DڗDU@@#6Cc:sFRBZ|p\@PĦ jI'{Io8ݴ/ut k 6T	qawB_~GQ+ohj\Qnb^QMI#
zFr]Ymak
\R,wo+@F/h p%~eÈBKЀ_O8ؼs3%b"1@LNH T1FP	1-k՘B)4>K `Ba^QС.p-aű! Uzcɱ3AsEMxok9|ݲ;=ZAaUTӆh Ƥi&&UVQT51ܬ"1O hJjdZ6JXEUƘ6_"#wڶ !)]i1R$iQ1F_ɸ
$j	4ƅ(>Zu93G bs 5V(/ˠGއ,}lb 0ISk	25X-Cl@,)ݟ9?[[߷ůq[U@: ̺SF w,r*U*a޿Gk_1{GGr/?}Wߞyu~dcDLcemcj7mMU5`t7^J.A YeH#$͆Qf(`̞
|S4^|՗ϟ>Y,w={&Nlе4~y9jkr6u޹zg0a$;{{>,burއ$"BUΝO?,ϞͦYH62F>zYrUE(|tV;d2XgiMb8qc퐊\Iblbm&I~yrj[WeELL4,Ki9I3PQ"6IPB΁!(l"b U$EpeVqyt6/~K~YVu4c 믃鷯UQTUZ-#b;b!҃;wvvvfy!wDdDb6Egt6.hcl<ȇp4Ovyn4_õ^[%ڮ\hBj]]^S˦MdYkq^u]ij"v;	TEkPALȄ1dwmxRD6eY\Uؽ;GOVd<4k#, vIDc;֩bfOnPb|q}_kKۿ^kKH?iyg&{_bogoy{5v,kʎUuuWJї;}KoZ4p~u.}GM^W9@bfsJ殨&Q!A^e܎t?Dvį &7TGhmoBY.Npzt)Ctܾѯ>XZ0Pw 78$8tۈf׷0xR| 1!p`jl I; HɑZ"Z@2RG찡U T(0C".	A@#.cBG   ktMDd{( &1(@7R#h@th!k&oD4DT.&oD{|=Mz\5W"'U8{Ўu*DEc0"fk̬_?\-x;6	FWPց؄Jvbw!B_^vmtJU  sj'] 1GH+ -XSNb:3tkm6l:IFx<&i;h?Mu"S΁s?O?/勧Ͼ~_/>{Gi>TU'U%x3cG"6W6Ci7BqA!D"L^  t
GFbn$M?O??8.>?gwX(.=ف(.N=[*"Xks7;;;<gvDtG̜/5=;V+h<DdY.f;|{_|D<Fa>::dg*W٢,VqwZٳAyeY$M	XԄD[	Mk1t~zӓAj,*$O1S]5I1B@pY>a%`uu\cD" eaTyD!@IƳL嫿?7޽{0OѝcD:;OUUUu*J 4UZHݽ{hwgg4LvD Yk$].fo^|"ptp|hg3ᐈ|UU\ *"h,r:f$Mp QaVbLydhC] %FIAAA׵E
귥'Y;s0D9xg=~_|{vr2}bw^kgw싍 1pW(UZ/`O+QuQ.Z'<Qn H܄5X:}	Ѵo
%W~և\Ek"iؑ@+m%j
8DͲWR^
?0JD
Jdx i5ڌyLbD\DJVEClh/](`[nkFI@xn~K*n'c:UDDl<i١"6dVG
@DP6B ;R[*
٢j& ,*TV A& Uİe❈(dU0~  "Dk@D)㶥!zURJ 4JQPTDBJQ
M&A#I{"*k%4(j +$$p~*tb,1 spbKͽD&jzv698DN<9<.e1Wt&`6IZ.$^:r"؅@y	+ks/yLW3wEG{sEX%I$sk"6b}J𭍼:﫭 BBݻtOο}|yh88{'}7B]T L u&`6W
:W֤lrFd6@&ic#Ջ|;fCՑɛoO޼M? \ҹw0Q7锓=?=]LվX.{dLD!?ݓkAϿ{߿{XrJ$,WߜE>gyYI$e1d3ǤD&eϞ>y|q~rU ̼os}!6IӷobADD,˲4%Ժr"_Ll3;;(]YU޻	!(!`
B^)CHdXEAq1)۲Xvw&	I{uΧs @$M96*1#"xW k{>O>~d,4I4HMc"X.ߝWGGAZkb(,hӦsK1Szj-NG1!273Ffx<$xfB2&c:q4F&|w6"UU o/g*EN]<;:Gq6&W:KI;T Z"6(ntA=(=o*HQ쥐) 
ٸ^@-m ԵAp_aM1ةEa\$ڠU81vy)ZSHyBө`CXf PPYTD V	 J=jچ]eغ;\=nxm8}qV2FP\gK[Ы/1;]CKn؆ӷْ%"4ٕwu"	()DwP#,"QS?Ɣbz%T̨ʀ<i	 H @JcOD2A6)2"W,] }簕ƚ1(P\LqԮ$ 
S BeBQjG9=")&b;iV.F޼FI&-d1ANE9r66M|<qeP,UJ,rcSj۹غgKj,[ei4m% (@k[` ~qM絤IԿ[Es!eYY1pXۄ`"JR3=Ol#aNA޽޾y5^}dÃa$}Is4'AQ06UOs5vX{֟ق @BbQ<51|[cM0w U(ֱ8sΧO<>;9qu͑Kv&k
VtaD$wŪ,y\Hr|,U];5 4R;WW{|w_x,VIbI>|z1/|Q ٝ4yijk-Ėcu @d	t\<tz~*޹ʳڄN{<xg<"bA"5Qgιbh'd<ƣ4͌Ţ(P"*
b"6HEjM?"6IWרRWb1"0LjW/WE|b+61AQpK߹{w4Ae6ɂN_|X.1{&&K,hތ4f}P
7+E!7C"u(˲J`DDgqBǽ2ΦIjQ$5- g4Un  }ltwXגRg !FAa|q1eUec4l<A<lխ`ŭm4vh]GnF Ѝ׺n?6N.e@@ܔ}@	Ҷ^ަhǽ>~n_ m/tnl{D]@A;TkƖ4d6oM%pm['I6ERǺVj/Y.ߵyS;_(T^mxS|Xa6Dº{􅆮N륏 bm%}_-
ƌvPuVT	U @ Rc !<EUDeT8Q@"椕a_nKMNBqrm"D $a    IDAT	8
э$ h<J[
(*jD=D@CF$\״W./6Ʋ!(C䙂zc,YI!@6&{\Z,f|ʕ*43I1bM< @xmleRwI"
p)D^ U6ɭ)W\zu~B@ms罛I`8yNMEJHJۢZ!mctS\Y: &J{|uU^~/=oܽ!Ӓ<hGMw{1$ks3aeeᎊ!!్2- UY|ab3Hɳ߽wUQDuMQwJ^D4aYV,]UpHLD (>T!0!着>ϲ4׈dc~O><ggŢ,
jl$NƻAnMM$&F!FjbXp1!DF,7?}X,<6ac\@qAxkWeHl`8bēb2y3>x GrYWeRգށl"ZvSs> já%6MSB,jXhL%P:ZcMew޻wt0IFq|`6zoˇH/E#HčТ|դzǋqM)1,W˥wL
K ˭Q	{GmqZbϦ	cխ,T׸\aXV=OQugv?>C@t>|hKY3'^}6ܶNSt H#\xr	4ЌZi~NcQvh͑׺kd~'mj˭~r,hg}{6u>'S37Elmz]D	 1yTKC7OPUmB#Yc&ܘg@HɠZmlRhPYEU%HLW2y/@TcV>aPWUD1F
'E{K@M9m<(&yQ"u+D'vrh %6I$x1֢GȐM@F0;$h,
A4@I5Ză	1*Zu"I5K  *[  	(  (2uV÷t5QV٘ E5YHd,IR	,6ͼwց| "!8WUNǻ{rvuZŊ$YdDID7o(ݬ'+[! <Taq}rK߮ļ?JEDWc?DEc$!:;WWjHl4Nƃ<4kXZDʪ. yrޏ<b9_ݗ~_;{}wp4MAՕNDj] <\	RJPQG~癠1Ě*8"b֯H4K! <y͝{?r%	ֵTzy#ͯxNiUyX\\\WeJ;Ue]u]eYu];E"O_?C(O>???**7E\.\] ^l,\н}8,cj(ReڜH "w8H|'| 2A1[-˘oZ!99Gp&\'<(A
UC&OkO.MvwwkngTd4$y  PCĄ@*q
AѤI$~HTl{N-2 vv;~pݻ1˲vUSkwƣB
(ϟ<y|'y+5mbzǄ pKthLiV>tCȲ|4cnG ,m;Ͻ_L&;)!Z"D\1F-(23pX{Q܎Ź QgltSbXDiKAҏ	ڏߺ *C`uuJtF_eAW;ןDhӟM"a=mjnT	kwqoSunhTQֈ߮uA"mn^pk?Ji"	^Q})lTFIҚ4_5J`RH$zB7PfUӥ?-}צsVln)^\WT5\m6^ rL
Y]OP@`>͏DkE d@!`J}- QB!A%:[ 5F$Ǧ!uCxb `	N9n4(7^-P*Ph% ^, cTbj: H/m3lE49AJ@9$3Aą*Y  !*HJ"ZCDfŧ]cZl7nX/CjU\S62z89gWl\!N|`ԤY+	\ΪܦMsdsOҺvG5Ma.q/sԀ Wg瓆`}Pl6_m*r h]US"M<G	tӎw\o!E0={o߾}ͷ/^?{|9w;GI6Db"  Y%#]L@3AtCEA]O 4P-#ژN2AzOʪwqhU`pp"'bQVJ`BCDv8Iw-cOR%8~#$94'#"3KWK4Ap;G؞ٙv?.PhQ2Ew~xYYTEEx{x{__yfUrZm۴]K*WVLN0;#-THeQիח|^JӴ mc/O_2SQ gfU(pr|>L&Ǉ{\Q/țLUb\V1%"U dad?,`Fa"f	@C6d~PIe:&eZ>~ɣGỊEQ&jxo6-oiA&d⽗bvmtRr_&FS[ȴboΗ+RJ Lkb\X2d2	Ngvl@d4Fs{!mD>m0S !PaGDli`LG=<[u/VeUU6e !f#zȪO
v6wHUQJQep=Gw8zfݯPC<-=6\!%5>/E~_( $ Aܥnm:pm^տ_0E[E3=ucm|r¶ժU&~DT1o"z1:RP"jF4nF$dedr@@BvDfB~EfP=D40&$ $$V=z ``X<{H@s$Z@5RU a@VP4$H C̼H`ʪ]=4F;|<IO=CE)t)`*@-Q3/mٗU9R)6u1Ů?;!F6llM}wlP6h.RnK}sk}1B4zնM5E/O#F>i3恍È+GGO裏^=}wݛ'OLٖbQI#3,ͨEUj}Db1EwQE,@!;t;cqLfl~}M0%y* 1vY6Z9r|y5eN"((;Ǯ|;_TU= ѓg7ы&jJ]X,^y{uyՅSJ1r9oh@why\B_hM'\.YB1%&t!ĦU`bf wEYΦrWVUgRIDX+
$v
)Uu\fwښČk;K^䌄v!mlRyǡk-̧GǦHϿ㏞?>=fG{jR% BI4شm.xuyB4M[7Wחuh,1!3c"D `lm~z]bB&X8WE2Lej)L\ۯ2Zx*+
s
 V6QwtV{p"MU7vcj_5øֈ6zw3@`,'Tu;DlXid{Vك^F/?z|FVH7Ϣy,da;_{NAa7DH.Qe 꼭SZ{ʩt¼ogUUcWc^H{W)e gWsL7g;N
N5!&@ ES*H
 y @)@	 &@E=$j #<9	IDII # zB&	=J`"DM둵ef1*XE"EhC3޴	HRG@$`iRfDSRqZ/4'L. K֟m䋢(<sW]W+_Vz/!B1ňE5HJ]t]-bv:gy72@Ʒ.>E*_ۡIw"Mf@] )ժ^jb.r7;ߟLdD:"JJr ?W?w?ۿ|՟4N?/~N&S&FȄ)EALo{HH`:IjJMV5V.}1Ft"*FQޘQSUf.qRD'B]wuq~	ֱ[Hd9gw JE={gMw޼9?;[ͯW1F@r࢜!^y÷㓓GO?^[jL)^]^~_QE*O2ީY{ETX@4 "#]_ͦIEDg^]^1E ]ׅUSurZ.rWeYt6;<<::>>:WRmN(Wq {1={!Ʀ^sT@f'9"0ԫG'Ǐ=::>|_~'O{])İ?-Wztvb1\t1]!wo...e{{ӃYU]9G,6.!ҢQe#)bJTd1i.F&tLVp;܀Q.Ed:sY!oFU\ڙ%st*4^b4)m@-B=R{*>zxYKU9C%FKvϵ$hA[vLɑ~ _8ntg!c-}$:
:a^#v1Ntb6@S,Lk73]h,@$ {ΉJΛgȣf/9hwI݇>Z`C@qw;s""7B2k4¹ѻ!YăvHNEs-U} U5HɢH"UԑOĀbN@l܁k>3)kA5\XY$3$Bz)
 }$ Hwޥ`6ͤ=+M>)F$EʒI`y#CbNɴ*rUWuM#KfIZTfZ/md:l@> 
n}$	}Kg عz0';Qv+bɀm72=~FDǌ~`JJwwP$e}wN bgM꺶}W/NEY99.Uȹ@cnboq|r?=;;o/}MQ_|_l]Dx8I E;E$H5R>rk@ՄƬ1ƨ"pCKʢxtrwHI!QT<)14Om
>EDVu ?L=yB]]SJb9$b\_?b2ݛU!˳g~^~tyG]p @PaG D!v޾W~}6gޥju7N.yWUl:9}p(
IFa9$"UR*|1T?$|UYûϘ8a]6mQM~:kb~/U;s>&6" Eޔ|ϯ5Z] *'ãIYjXH%؅8LjrG0K:9^]_/:FM&(bBD5:;O̖kдbܟa!6)ge!p+XͷaIN;\R!ǧDҽk,Hm"K!tW5 #PNFg`p0n?!oS6[z"`FC?k8d3L޾)3ܪv3C^S
(޵!@n6>v.aW B"U;6Bd=c']ϘEŚnvC.ywl:d.m 
%K` 	\AT!N)Y( D@ASRffF%M˻Ke.%$I)cA"1	~Kq٥sq/h! pFe&/PEUd񠚉ˀ8% TɨLK9S鶐  1]4EYiuλqȴa=qY'7aͶrp3͹6ZK:k6`/kXJ%jm˼cp}xQTcm(ʪ(wL΃V}jzپ)-@}1;(gg^ӓG>LgfS^6.&MIfIWgo$1dl4OނF;X $H
PAc
[SSL}11> 1ŪIx[uRִ[&@?i nSXU♪\H]蠟*!$)un$IQ7gIUU(UOMv=-H8>?99>{v\T@iU7"ʄ1JQpYlvxx7f{{lVsls#RL!4M5w;Ie	 R۷oCkdGBH
_|s$L&lDl=%BWj oM<mz\e݊DFʢ؛Y(cYɤ(ok=oN&)3ŮM~DdLBXuӆժ(9OA!.>U>#  + T_*@<[A *QA\5KDy,N~tk(᪝b&g'd?@yL'vj$?s5U{gV*M`-|1}cx[vm3QjQ5'm G ) Aam(i\kaŷhn6{ܕ`FN&fҥ<C
I\@ɺfwO7fγgz@ޕ	NA|`an^bmg)FjN;S_)K8aj?% M@S 2!*)E`Xe%>k    IDAT,* ]DUL#HTQQ THQYUQU  ʒ %{ +IL:L#P P>0  P&$YȲ\8ԉf9$k8y4i#Kf>p^$.AU]1thvI3Jw,:Dc7k?l4ۏH6QL4wi߼}px1i̖Mj{ =V^m΍l7vn$E1LfӪ|QsCdLMt(!!."*g9???7_}͓g?O/Jf6~)Cs}3ާʢ?ǜI`'"*L攞*)fAHղ "(#(@)ɳG'ח)F_I4E)	҆>p[׵::nqvIqlnp2-QL뺮Yvyh׳Kgo]_]&IY9`# y{[t
hN6go8f\2Ol7?<<<==ߛN&dj)(l0t]6^+aRUږd\8o	@e C QU@3"ԵmTʲ:<<$҅v"DJEbJ].mX.|^׵Mgӽlo:L'IYIbJA	BWkfj뚦nB\YEYɓ/`+ppb{uLUC ƜF,pO/DA%X:p|t.Z~aG&lk}E"Y U߰92|v{vo|97遦i4H6ڹۿPC rt{NmОhv%J&I>P3 :4Pa.%s VᶸGK|Wk{V}샬G 2zL0n!1$"ހlHT2u%_zǡ$r` >v^Qէ.vsB䜁GN"IZ69$1  r2	$Lk"|j4ٖ4^!fI  荧T	;)H4E%%`
⪒F)"ע({Yͯj|4!rHܧI0F7MfޞN;a719{@,oBnWDΫ.X	`k8/N'G{IYCsƟ`iXNFd4mv3<g_]7:{W~IY/?/"Դm=7p[K.޾M
pɓv:TsmR@F$v2 
 4%\!TEau/&cOY^_NR$ 1Eq||#lg}8L'tDjEDwwW~_
?_7/뺩3Շ$	1_j!F7: EK l	Rf%¢^]\u!M+u-iO?yL]Lp=/KxtɓǏO{{#8/T5d]׶MjZL&8B@MG;gpIU~7?y[MJu )ff+{!ʼn	 6uBkn}iY8_t!Η7~xwq1_BNʲDauA!8w	SW㷿}몪NNNhؽTDyDlf飓 >yF Id}t3xf惽YmSO&@&.4=#QQCOXOmm(DDM\y/s0Xh/̆U0@I:`DRU5y~{вmÆFD#b<"	H$Hh7 DP,<UlDCi:-~T3&4>|P(D|B  θLcCBhG!s L+?ʱoC.3ی\Ukw*s9ڛrƽBU&Vt'%%bN@UMNLlw=:Ŕkbp'Rv$h$%Ɛ%bAbc>ȣw^5̀8$bp9  1A5qX-dS*0Z~)2DF[eؼɜ _WZSkYFxa6\kۛ5a`%EM	)(rswd$ۣ=,mM̄L~"	a BD ]햗~6ͪɔcv"d'ۑf~9̧h׶1Ʈ7_/޾?|gϳgO<"M@Af $zyώJTDMIBڀ90 Dhu~	D$U/1%JJǁD }/Wm&QTt<99p=;BDuُ᷿/=}}5G'UY4!t]ۦy	-JIZ6}H$PJRL"QH{ BJk֓l6xuԅw٬ΎNϞ}f9wPb׶M\.r\-u`U:9yN HH%¾GH/_%,d@R#a"m:Ř?EJ|>ojJ??xlV	'$I4LU,PaZ|rzٿo&Ui1|wvά	ժnbztxh?~%&F9=a*:ϱc3ʈEQzYVb[z!c3!72fS?kx0HeLdpRE?S}U1n',AxѾ%P=
MzgqRJ2:CVIhd(ՔݞP0itJ=ư 7Kւ@,`U݀w_ܼcȾނh`oS(M[Zn)Cwn>eair(6 XxHU	D-/!Eu JTP/B0kR%:"H~KW$Kg,泌X X*$"gIľc=,1
N0xHi_- DD\c4ʍ͏9BA#5@nםQq0="َbhCSHJ9)rcZ<?, VdϮf2m{ǎ
̒Wϱ!Lιѣ'O>y͛wW_ݛǏ>`D$j"D9iWˋwo%4IpOE)!ڊLcj,Vf̤=$CTYǊY6Eѓ/>WfdB#Ŕ&G!s=vvXFׇ"SPf{m:>}v]Ю`y>U1)-@8$(x@7|{FL)E )WeU˫CU{{{G''{iY<۟TeАR1Ս>Wr9_jUwm#ɴ,
b̎h+ETl
 x >(ڵŅzicϖ^4&a$f^­Dp!@jX #ڛN,А1D L]1c׵Y\_͛o/./}Gˏ_@FX<<B]ׅI{O6,`]qE".dZ ةVea5w{VUF& g2vK::?lG]V\K!% d 4isa*DQu5Hq~mnj! p[0ZnM
??oc6PyT.=hQ}&1!)꽴l)@;ci@G י*d羈ADIDTFֈ7 &!BBRBR؁U";lxMkIxd]=D6sԦI mO8  DIB Iz0irID0Ft;rOUI{X%ٖ11(0A_L@07ؗ&L`IR0y$:-0CDfH*8BZZD ]DQ$RDF!;FIm 6p$B{pVc]0dhϓb *18e~3N
@Ħķhmg-kyQdr7y_ p׾e0"Ji#"W_|?k?~o%Ͽ?GE!0#%]q{	|B$"5V
Оˠ BL#T.&4M=tߔDUgG|B_.Դ]Ӫ*QU"
!@1=vxi?\	ss_;nٻwdRTiQN.U1|g5$FAJH.$b%% V@v(BA)"8 HX޴~q>/DaZǧΦw,$R$!fZ-|XV1"l:)crL,& )*!8&lvrrmiDfA &@Q!J]/=ն))ryO?~/?}VVULn|%35S$FPMW׋ś7oW߆~_?SM1H|cMbf L1VrمX~2$KUْU(Ǩ"gg3lXPK[DȾ$W*&Hs
ѝwuq>nvivGޕ75޸3{_;prI> -ΰ]
"%h}P	?{H;|/	Vfd+`Xo0PP@-~_GQAküe*+Mn;w|<fxPPMKNzفS{N٩,11>/CU|S)rO{kuκ"lFI1'qLf,3;fUE @Aw[UJُI %(TϾe :WZ@Cle
aD".+ eN·b;Ą(5=@I9,PP$uEHD>FoxiB&f"v"kce*L3ìK$ق+KW};Ky4P=}qHס	'}_Q&τ kU%br !mt6w}{'0ջ]W#xO~_ӿoj2}O=B."f>&f_}(@> 9N	1blS;6`ST?
M`{<	ã/N޾ou}|r s97،h9WUeὪv!ʢ .9.mW+dvijQumr\EDRצVcITՂ8i.s@HX%R{EDvnReғ{q׵/ttt0-ѱqL*Iz_]__^^^\\^]]-拶뺮ڮ	AsY<yB<CAUGD;d'{{Ѕum$v"1 ֫:u-)"9ydZEv _~-n4*w1~'f\.۷/_:j1~g?ӧO@bL)*bv1rU/j t iK͊87TA֦@RJ:'U""12XV.I]dJ@/ RL @dNāblk K\hK4h57- #cmgX)zP	U$_λ2A%ft2Y3&K8,#[sݭ^J|uoxҟJґrl|	)@vr?ЖyMGg݆CC܆'*5weߧp"D+ƿGӨ;^[L		YA!XM0=	X9t<FL	2r,1`*(	0V !{D2,Yzsa9k}#J%q8]v'qfO?gF
頹gb,I(gW? RVD srఘEsqyS-bNT/m̤%&{DUi-na@jfn
`7Lw!fnfBD0[6wGg6^wuz)boqtmRƒˢZ7mae9LjZD%Z0>}lhJ&[޳=裳wgo^>}qp|\USv,5ł	&(RTpLkpupRaEڶIb1$)H	5,=}vsdk Q5GO<x1ɋO,h(Um6NE'YUeYWz~}5_|m%"!hY:HD/˲[,W˺]e{xQE!0sEYVդT~9/G	]A""c*^/.*&dZ%sޡw4v^}z>m.S$)gEʒ}a%hOmQ$MluI$nFMf@b"nQ2	OЬ/j
Q"&$)ݼmzXVrq}jڮ$E@|Gxqz|<N8lPR2:#",7-1ÆG09)q;)ERy=
0bd6eDP2gk[d3^	2rnGODdX^!bpo\Tu
:AAav; 䌲M@O;Ө
w&*IJݓl7/=fk߿@X8bd~ N>f{Ն:ŚW-a{|U=|lrzon:Or(9[w/OHÛ$@sb)ADCS"("f)mbM3>dmUc/?3JDn: Q2_ Z
$D4IdmUICĶBYAs2S
I5q`  ʈ쭱bavvk(_@0GGf "2;I1KA$M1AM׹ y3\$;g!ݜ/{q߅Ƿ`l,|;QD` K'AM-WuY餛N,m6փa.sv=ĶDeQ<~^}o<_^8;}dwCPUF>IرbITyj^.z߉    IDATӋ"Lt"y|Yef1_t`g"RE1iRvU)]]]___fIUs*6b8k3l;Kp*\Bes]̯kе6Qm~;>>/NOyD^-عLiUf{EU)# 5I*BӅeݴ;E'
#xBϔYSjV˯nVzz}>yspE|AD
jH$SJ1$MM]/kEQH"1WjFr0Ƙl{FTcCDc][M'Ѫ 1!hm.{!Őb@tztr|zzǏ?:9-mȸ9oWvжM]׫!¢(gn3x"9d!tmGbmVnٵy#y4&"6EA՜IǮ)9@fFX> ܽwm{t)[3]J4GJ΃T>{mݪ#pPV{vЏg?,ð@ &f~EǄG
b^wJvG7?`4tзvku젌Ehj` "9GCBĐNW/%aH)M}VVo@o1e눣$dSPX\$
9&11tCY9 HIX? w aIki? Š7"Rk趛Į4*el@gHƟ	ĽO$ٱi![	-|ĬѰHD	-x1eۖAC77b:%ŵ،	$B:@ΑT58^F΍sǨ!^R{$e۳$"윅[`hM2fAi$@ØD1쀹z3|Pzzvn^oLIx,c@5i*M-1T׫rQYM/wj多;]ǀܡcMS7 T{{◟7w?o+ً>GG,aS0bv\ﺕ'rجVﺦD @Ė  ./Tg?OvePh5f"a#|YoY-C[RbX^]./Cosʀ(1%vQ$!jX.m섍=@^Zx?O?$ضmnګˋ<Eʢ)SEI":JfBlջwm̞hfc|%TGESUz3w  "vQ:pSb(1mS/bCR]ŔbbmӐ+ @U2hH1"#3TRjft2%m|!|޽kãO?zɓO<=>9-
!Uί/7u_9wtt\81ɽ	P#6cozF|(Cݍc~GD 388,7AIm`!27Mzf'oſ	qʪAΰVAo.sC2x8~B az,lK9Ä/iEVKΏ5N@*=M0[ŭi]%(X4.:lG2x2hl02m/g߻cԷ.ĿYt.dBH<1D~:q#_/mvwm2;!}G^hg	":S%ҭCݛ>T#1x( P1%՘;g->;&]c@]I5=f{P
"   9yalM!b\#;"07 HbH<XH'*+dɘ@٬ת7^D>'[(|GE5Y$II\d)n!ef~H*qhVeMi8)Jf?$kntk$PRu2,Uw4RUS|x!wd$aG>J}1LtR 'N7،WƇd."]]ȁ~񧏞<ͿWۯ^__e;yT?z|r2N,b+I*^Ux2UU5*ƴwp@Lmd'URۦz>']wH7f,m]+)Ջ S"b5G$>pHw!~xLf1p8|"شsQ6Ķ]вF HR5bѴa29Wx#kURē$"S9r/Q=B+<I)vm׶)m/2sJ_zW($!MQ,.Хc!Bm-WMZ.A]c)EH"UbQƘT#]D"˳mۦʪ,˒uB`t?ʲbf$b1$T=S	$jZ.Kb>88(GM1O!-MH  b].Ff$ʴ6-xcVtP`f%z\RQ f_d|M*;GXĞ>d ^9i.'	Tv4M#ٟ}tlKr=h|2ju;udjf6M.~D_0$pz܏Pcܐ܊ 2t[; [y<7{5@ȶ"H!8!c6  W^28#j; Gհ;2Z%D('F&ڑoiutF"˯S o[r<UzEUICW$@F0n:Y?i┏><Sm43@SA"c22 DAH T^s? "Qj.SqC2r,5 H<`ĉ()MY%O%zLu&­F|dk0<fn[gr6݃vU%&URޱ~%Añ1KoNӭ Jf~Ctsu}MĔ]4jL٬(
<̖
gÃ5%Q??}rGxuZVGG'{{EY!R58	=Sq{vLZ.]&M"i\U
OzWzwc6kE$Q@Hl;cզY%.\*lChRI+$lL2^g8C[uUeY" ΚYMͬ8}MX`L)bu$B3i
ITD۵Uȱ3RCja\̠pTD1$)1@<{wݻn4F0M"rX	ɭ3āё}?]}w]51b68MS8vvmw.蘼sc
lbm%%;oIe  HqyzvDiq5)%绫n I%Y\
Igw,aچi;0M1N JRTJ91P%` {ͻa *!AūvSTVR4XBY
ga*ZP;ZcPw/Um~:?X:0] 0+6j̇J:0UL+qAi$7&֡hYkҚ-TH/9> xX7h<ԺJ"_ś?n߷۹46."EQzpy/Vtkxf֧k>6Y/'ZeuA=}>]ߢhk	Ps\|RNE%3iM&HFZlǽqi+9!"!3, w1^}+h6`jPf5j5&W4}	"Q4/ll_Ju)j9F@RSLj(U"cq^Rl0+4~PfTONUbŕKD]SRIaQS7YjAD4MmvfQ^N[zqhDq1""<VE@%B=T3/U%X=ɦ* l'^%yA붢f`f}X,Vj9c:`"ƘBͻſ{\՗__ۿ|/߽}_O^|ūa輻Z-S*d1ȮD}]Go5fJ:74~xC/!fRP6F;$v6?ۯ_ҕہ10|i.  V߼vsmQ""
"20,L̈4GŸ>)dD'Eqf 
H1בie[T̵yEWo"swb1XCbDBn1Nq
nݬ)Ɣ,w~zPu1bwb$jzKGD TD^7|^o݋0a~-DvS S*S]'kPUbvq;?r1 @cC+Dgkm}ò$<ĽdjBϪJ?ISΉ>TASXn1:-kk"U]>P8~>ŰJU) I
}jhծj^eTy!M#mhd8	N\ P@ȵ_ʠ9(j#C&3gGu8c5yApTk>j-Sbj*.Z84]}h/'$5|H&X'Pjfp"cl'9Os[~X6NSf ^ʜZ{Ab50\EƫBH3}XT-Q!etD_\:(;rN=/fHbf-#)ɬPJiH3-Nl.f+=KDYR2 'l
1#Bjf6mHZh̆ ED\1{w-7nkc@$Mca-3/n^	 DL 8U5b󟊅HSLpW;D" A b Bd"3ERBғ%)3ê%:>a8	&nׯ~xqs}}s\p	@bc'%a{w[aܽw}ɏ>ѧ7}??~Z{X]/˛a~Eu<; V+bG}/ s3⹻Ki|kI$&s$H,MøXFE9Yw1S%(?y|'NIjzywVWǇ$Qɂ̐1=<<}zvf9߭n~  EV [t]1sݬdiA뉝 D!FYuLrrvaKn2w~X.n_\_/:)H
SLAAinzm֛.dnnnoo 4כ/cLC21
xj"C w??裏^%()l7k$l%Ż/RUn|IT`1cr"RJvFu[,3I*y
 <`#  #"`Bhh
G>DDǘDPym$ !t͗H@IՆObFJ'N4.'9!9OvU%Chſ@B4WA
![Wr)?j&sѠ`RɃuŪ*m	LnGKI2&0fj?07AmRqgRPQ0k.M<JL'~M@<`2U/>pǺר*8?sm? jyB^"1љ{$$U+n7k3&UHII=D*ڂRs
ڃC
$Iw偝)59?WND\}/)ԗKL2*sHP&sRY''ky
1+?\i2 ȞKT$N;M!%G ;;1)n7CWW] $l{9K%d2jWP7pZC	dg%*Xk))vG_*&Xn%i~?TDPi޾{~q7o^ûvɖ;F$I]2c~5|5"q)TI?@ӎ![@\`;wo4ݼ6UPvI3oJBv~K)ə֦iK~7fR
2*g
aـ*3ܭWW7/^9d*ެz^OnɲȘ]!ĜU"*#dςgvH;XO~\\nVKyQQEBnf1Hݲ؝4 bX-͛ׯ|ͷ!;P\?eJJDvrF_77a較vD /߽կ뼈&
DaB*E h)	c1Bج7S)!̤\jt1e)\p$Pt3[~*h=31wZP\`	5sف{>;$̥.:eFfIBPx%eA2YsȜuwЧ|sa}DB)Bez6?H>ym{abX|~ Jl 
D$)s9$
&h_ gZoZr=z{ ]s^mAK>0l)5AF7{9HA:7V?uzmL{
3eaY")-@sz瞴N S/j9W${.$K{EQQ+nl6 &f݋>G>~%B1c9 +&aBs{Tl4  KR;앖6 +(̌&:9@6T&.l<X#~ rwW 7CX+9Ÿ]S*ZbRmMt^j" BAp69M!#QA 7=~npq~kHyz}_;U;Naf;l7}os*6"¤m*L"DV[Χ.BHѨ%IYX lCu%( 3G>ٲHPmLuUUPJފÖ:`E1*b2=bԾR@8ݛ$/^޽Ym7vv;@솾\D-
'!IgPL͎TB`B$"R	DǼ臫ՕX!)4'Cۦ;~y?t;TbBI;o	7ׯ_yn^#YCIv7~64LknRksI1\J8|5hPldq2T)%(ECL4Sج7!L!It b)B`g@]9D4,iY{6mǟ}X,@A]:{jvM9%He?ښO2rA	*b f}Mo&/Sn1oe6!>    IDATԾqcz``>9-4aWr{ln;XH\ڙ0CljM rmn{>mNUS2/[uyHY{9POl1}桞^.hAΕY~i;-TK`:aL4ExVυ>ĉ{l1>@)ԧ[RA@FlS3\0J!* cz銩\sc1)@{wZn v		R<<1CLM`)&!ƫ<W4G I haJٟg*"ZЛ HbAU4+$ :'1jJ*iW$r`UkƜJW~4O?"~|qܮW׷be*xOxR4b/~Ҕ52(%ΆZFH"B*>M~lSи/Cyتv؏Ԑa4}w1b~"beXܑJ!-S~X-
dܳyDAtPA*,"'[Dť6Y.~YU=U&ws$9f5݂i"49Bp22,Fw;lT!_~ι1LnNQrừg9*!C%i TuCyvč^.@c
2vw!x-r\xUu8¨Qt7f=<{fRJ?ooo~_f7	UbwﮖKb"8 yǔ!$x0,bT!4M8L8M)WP#RG~08~Z,{|zfb<DrEq~BD݋7":BO"CE5(bF /qlHd6?3CYd<U6RGh?WPc=<:QeWhZ 3R	-khUXT(BOr-lJ+n=aXq?̽t/c9yj"KPkrL*a[DrC(b_8O\7"nsҞՌ$WS0>x?w}f0Ü;mѱÀC!R{6܊=h?H.@D8(6ujO7Î:ǖ9JAűV]^
$""O N
{UIfj&$MRX	c(Z	u)JCI)[*3c TIȜ}Ye@B3ZF BTw(z*UNUq]X-:6#Ӗl-aE3/fQ'EG9t-ʎ(<`ImXB*ZW/;ECfLqt.6յ)0i]yER2fCj̅Sb4W
)bn\}0Ua"d$YkaТu+)X"P7"B	ҕiO)qa~ڢ2R"NE TRJ1*R?/^zEI4PLN:QXԕ'~y}}ww^Ʃ$8 V˻/_+dq0M!D:r\cДĘlN7z!$ftcع8~*I4)Pa	AkLȆ躾}Kӗ0\-Օ*1x~j@.cib)ES#&"{\T ";k}wtCn藝#XO?+/3	wwyW-2lKJ[3F 	
ėX=L}4i'?D, QPUM笐ڂۙ`id9"u%yJ-yЎs	!ss#:)dUљHj:{~qA0uOn1sϕ`d.Y^y8;RQ^0p2f؄-~lO/cAn2[{gH#?3FYED,2POi{'Ϯ}ʫ^:>=BQ̪~Ct2F)DD2+SX<*,t;L0==_(icgY&6Ubl͓Qb htjTu]Y]7քR[d&VUj\YhhSսυr}3K2qAj4vݰu޳.d
qbJcS<4Dshi$8_>^% O|WZ$${Rkqե'۞dkć74d@AZ%z}ߦ `Y	>hxͅ̥k
VL@	QR$<2}w}(jĔ1y]xy;,|HXX$ސ.W6"Z Ui'Zj >OnocvCP՘N	ǩ]R)Kbb_mwӔt[-ww/^YL- 0jcw*)1SMӴ7zv4" SOoo>dJd!G4mr[i)i
0t3*eCeOUNj"LjxEbkJ!Q$$yzCc1#9v33vzl1 @JX.7v{qs{\r1npy+YkU mpIX|LnAzoc6sHȁP<
EnO[4(mo
kҲB+w74B;M`yx=~ T7#׳KRmASZ~*PfUW=uk*CBU0EH>v!Z~80O=_SQҏ53YGI  z8G[
Ó`>_75z[HY[Mg%"5Bv !1:2{%Ix?m\OL/J'RSѤbb`vc9ªP3hݓxQY|`Tp)*dxsy[ɗvӲB̙]Ҙ)IefgbU,G@NVc$e)ҿg*`VUnYI{f4Ӹͺ|?83;gf!;G'6Ӛ:r۹q֠Y~"
`ےyfS=\3] zx`'mcdʐMJ=yWhpևX)D&V܄XoQ]QD<XbVVg;G'`rw~pYay3aWęPVکy|?c̎H2 Aqs[(KO"Zyu<xbG~O)5"h>␢}{s=Er9|vuu5sl}]q
Ӵ)$f}x\}X7nb%Bu9_h O>wswr!dHJVsˋcjxv7^^\_yvY\|2yljKUUi("S
r勗/cvh)$*J:D1%BuIٖsn\^]-Cwqzl]7櫯ôKEV201̱z3f 1>852\8"l_6\jv2(6&Mk K:ݵHeƞBwFD>L1ӿayZ[ ݼNbwq
륵}٦ЊsFtNHIr2UE/ ȠЦ(}~
s!1Qg*x|^i1IrpɆ('9w\}2ya}W QI>'?޴5! /Ԑ$☰<+F"D)F@	OVN1 ar/݁sԝN9Anj:I)G-Iizf "$
5<R3"Լ '@d(,02peڠwD?UQ_1bdSAt (K`rr&H.Vi^UUbX?Lkx auU	@:rʞlSd4NT1%`9TTS
@{~t
\/U${a_&ZH)х݃V(k"`t ¸w[?aRPYTP(!DLE3\ܵl{3u].%!Lg愲MFfC{f6\tY.?cƸ	`M*⡟=5 P{OtbEnT	Sb]kRnG Py­d*-<CkO'~-7ӸqLъH,8vI I!ܰ_ܬ9Zc)Iu777w7W/ocSL)n{Xo=_{ncDu93$!v0|y~_׿/~84 qy>@|PAȧ|tss3
"eS6Sr	 4hɠZDO}-?tnc*[
t+ahDFgB䉼s&HSyilaDwh_|	jJ8BJzNU;+/msb[XaF7;l'Ȭ+CTM3tsE+ G5H?Ui0^V#-Jit?O#q0۾LnUk\}DDb]cU^3ˢeZoK{@$ʞ[W}ô<N9v0k&V9X}ƕK0W{eKY2|=6Ȼ|a a/isWP݂Zt3',TL*3|3+!"USUbZ+Re'T %-l "/$Av޾>LLBNuT Z#`	S們 b 0LR$PlvS Umß(" 0mbݦ0g;f.ŦI䅦{o}:gYL1/֜dunwvh)fk<3A?:щy'=ת	P4O1L'{OnFHd/]ZN;2Ny@D]y纾%5ef{5zaϳVO8R16/aL^9';Jd  c@PL*vo8+b|!L
	7s@ TDCIb2cM
ɅSL7a9w}zqs}u}3tc4hJqwqv!i1Ee:B"R*LcDX./_޽|/no_ݭV}7<>\F DaRﻔ%_hɁD-D DdK|5HduPK;@ q86;U^+D(XW&39Be!3Xْ1h(K!	YѦ |R[f: œNTU@YNuVǰo:qja	I%WClM:VXu2[;aDkj<gc-CeAX/L.ImM֬MVF̵aI|fLl6m|yvYv΅
yv< |_rI߱<m) @qj+އC^^OՍȧ5CѵKJe<ai|Z t
Y2tNSL*Vflpޱrnb@E$hAL,4)dgI{99=$+ER+Y,2jL TnQB) RPuQ%6
\bF?dغ.L
#)| ^&AKRy$zHT-ϴn7}7\9߱n0SԚ솸TW5Gt`|3s`4Xn8N,Wqffо$Nf_%i¹Ҡʄvh>nOoElC!ʎ[RT{ZZp8?XE$ⱴ^$3_+ޫ64rlןfRJ16QX"7 *X	ei]`j0"RU̎HLdR4#{Ojhq=͈poԤt3@?I(Sa0tnۛ/n50mf7qכzۍ!JHHc)x< }Z.o^zG>yu~ŋABxlr8>7 蘉P |بazӪ%{GX65"@" U PT%LJLhix
$f"!")U6
!:MM[D@1㢪)iJiĔvMY4ģMiy}6/7k02q,
jV>хKSK;ΨzP s'W89OE;{I=!E0*`yzu?5/Us<IVz
K.љaQNA]	sK;x ƺ̠g[R5/_^m$^w_ U=kȍFu9,v('(sW2]$YTDp1#,Z8Xh^.RMpOc<J19 c7G`mL)-Ԝhg5E s_XMw#bTS4.q ;HPcN v @XL2Y,ًkIQKe22T""6 b;IDq9|a'%D$Ii]?,|IEJϳdf%MF 5[,H@i:?z88jM$$^$̧!3]S">ᬭ|-9e55Ol¸oS<(("OEkǤDL92HϑmX:oXGXxK 5c*7@>*bvXǰ1Oy.%xx̰!i2-	awTR!G#@ {"x
!@aaع 4?_կT!&EM1J
"1%	.&T	 J:GV˫asLj1O_x1ۍl6o6߽ywqL)wΒ 3aHi7йO>_ѫr4zUG9"~||/!K:<KXH"iJ :m4 `AvD	E!Bg<.0Litt.*PB6$ca20(LiX]"` yOsMJSդl
dS>;5?J.t,(y@LgEsG*mZ	%ÞA3tSspvg U}E*,j }!䞕jX0)ImuE6ƓFmfB "%ymZm	?63o{U0dim兡hi6}RioVnSf64f*f;K#+GVa    IDATdVι}ΰ[mv̱$%2]N^5`W;+"ˈV̡:MǙv&b@"}$"
E ";G )N 2;Yf)Kve"$,ʖ%p)3(L<K Epl  $% պ Hw%^8aD"Gj%ΦvnٹŲybώ%) @&Dx\Dh|9#348KƆ`J͛xgiܴ 0zdy#OFtLê*vÃ#_b@b5-A:i?%r5;^B-8+t
>G*\5GXeUܥn7#LukZ,VA7S^Z>{yyVD:hT5H01w~ۥC D9gf:Y1HDsȩ&5-qO?DSA(:
RDȄvu\]-7/noonoKqzYoq><>}wͻn;(ɤ7y?xfv1&I Z-?ɏ?я~v$J1><<8A &KPǮw Q84#H: FfjnQBFjcy\" $&1扮N+UMl04/@}lEʯԖ+4	ޫ$j%5 DH2):}AԺEN̲U݂0˗]SUϷZT
䧽szP5s<T	qab6i"jq(mʁIlg1B%|s^n	օdza][jk;j%+ %; ^3faED@[8h2gQ!xgB'֯5ee틀f~^<@9{UOw#.kLf$bfqȑgy ;ĚEERUB9NJ+,F-ws)08eMg<00&15|f}(6M	ZyeW XT"q1	xo9 !)i.dȚ@dעfLChƟWC$AGy`j0j7mȠ@6)IpT˻)^$NRq]7,TUFĜ gnJcpV7F̫QD̖|&^1u|Yg|F9I]eXm23^\?}oݮUy&g{;q>^RbEJ*$[<w;pE${޽a
>[MYbPU#`50K,{ JUPc2z;&3&URr!~Z
*K6;DDԔF
<S

Or\ !:&FC@-@$8iT\V0M_߿lv^qݬ7vkNND0|tzˏ_}ɏ>裛ղ{|T`iZO1BP9oT9\ Ft)
ʨthb}дئ@$ JX@oI	6OD='@!)sWdI+1%*DIG U4	ؠx,}!"3eEsmaU]y*<x 3D}&ސCo='*?WK9_T8xK-x;sBn-R-[r$R}*T7ڻiyr(v0;iѼSpL1ӷ[KdLWe@*4ŏ`MKl:83!mN`^#CUY7 #S2]v`mU:seU<x-|dOި3e|1;]a;˻oϙ*ʽZNvQ-bi-Vsj-e-1x+l
/߼~J!cW5g
\f?c>UXnaFrf`κ0S 3X/QUQ0x@ZxluN@0T>Ř1W4bPBDJwbcϦ1'0; WC0B&;;!|7|!Q% (:
e#(7xYJISh^4R~@I+8װPCVdG	0ho}m
6gn·1D.	JMdO{	@-vlÑ'W;ye|f_v
!u)[hM{8KaT5+f>,%`2A@ ))A$u"9*X:4s3/\*)WߥLݐr"]9v$Ew8Dc) I ;\.۷o7qm0Ř;k'}??ǟ^ӸێqڂOʫ*afsW'$	:W?O4k"56JeСŝ9̤J$*%O q#<WhPf%4P2(P3WBsIf97	N;lY
Pe,IvjBR2d_}Mz*Ԣ<OfꮝwY߷
8GCw>UtBƭ}2NU7߮ -:M9!;jBkG!qh)ƽ7Quv4fK;俀Zv	S _h/Y{Y	#Wd]eLB@sbڤWt51U D]Syt8Q	h`ɶP4ig9\&c7yyP3Wͣ2附xIȘ@&9Oivw&L EILIr~S %I㴮q[&Mab"DF=  ;g#j=RDO1s>ОD: H)$"b3?T#Jn()"7(٘`jYHu%QTK	U9PPRjGcĦ0c U$YB1B&ꗄd2{5+Q6ay`5\r  bA +kq/C(3H CcL>4!#mDg.#єSUoy_6ިbM3-t~{,jn`*n[b}0ӝ-|5"܉';zWWNUb!F ( p,)h|uOm41{=;GH1;o'\B`N"'WT"+f^oB1s;ǎ艀 w]	J 
j؍>zyNDR:n-0(1۾7mvzl6c)cH	w<z w_?O?!
L.i&Q %F.:p{$o6\_fN
I( -jx&$*O{A6IE<A $eIEc{5F d[S31  (H rc|:}Upn0gzT d:LW=SBۤA0xsLBI,ɟMH*@XOf"Z%\.5հ^R*@$@ p  YTpP=4PG]mo-*T3{-
|cճI*
ehjO BIssmϸHVP 3ʠJIN9Qc3U,.X*M|Fkob)  @y{˂@)xha/2׍  |lfY+]5 `Lɸ-ZL	!#ɘF0[Ý5:0"0;\ESJL,p¡`rh1z	<uy)LBsy8@UlCvܧBDlzYkPNHE`k	)sζYAM,$	FQN8.&qaf4|)<c#v3f~;V3%RHјm N1!"LĐ JQmg25/Y$or*eH8Jj;)<6!=h]ZE*Bېյ
hj
`NQj	g8< diS0gOh1o7RT4hy1fGLLj.w
<2:U 	iZu]7M4M1)]r, ,3)`ѻvjL]pL{疃b0W|ۍ<EIIkb~'>}y{\.CPK\N^-jy~P0fv۔3\))I
D f;GKS&xrIgCv:9bGp,ABH$O§B'J* w<iǆ<9
]sIMzaay!	^ŹPOP53JSoT°Tx"tSCymbq/SGht[Z>
jg-IcKc.T:{D5!l!if͡سW"z3ɖb. ,U,</|r¸^ɁXAN3Z,oQ{Ec3ѪrI6w-.
D`8~:)v)%sWq($*d T2Zl҃v4[=L=w{@hٗSE"-&e}e~5"^jW嘛}we(SHʈf֖,LK eK+YlRf
e(,/{Q{;謡	/*/S;*P5S*RJ!0Ӹw3$b}TTRUU#"p!HJq50!L*,*U
TvMUQ-كx2wpp `)^>v1Pjnq|0M}|{K; _ϧaw{ 6M^heg6rq-r\y`#@vp[Rs$)a)|Qolوy24%I""Re#m3NUۑIb	rg97MSQR
!9Ll]ߙV$ٗV<a"zfwu1!0qbLdђ$Z|uZ^]ܽxG>է~ܘ&SI
T5ĸ)B&I;u]}GqPraUh̶6rѫR%' @)5O49@.W,chB2gvIsl|O*CvZٿlRe,[lyڲjUVOJëiAbh~}?˰N+uQV<l~`{~0ʗXwtn=?ex0SLW>{ZHŲZł3)ZM۷vƆ	|fۻ؅FU2R @TpΥaBjcPq<*-xT^<>d"Uf.g?fWmb6=r$U&{xK\tUս>qfF3P%"HBts@L6	1lĕ14%,,2J3
fz9~0g
+~Nk۠&X PT䜉}ƅsjD*+"Y$k5?PӥfD'ϩs҈ c;\xs5Px(=& H1jEBCTC@sB8F8<J=!Xz^<LUAJ&
mj\!Iq zȚd)|v91  ʢ(]cVtZ2LPs9v,,'J D@bb\f,+ˎ]YUQ8W!lg1@a	 a0yh!U[@Ex4ftzZ&)~oI^n1۸spS/̭Pk%"gS]eh૝]ZA̎Y|thǈF%lh
.x#mPUUY*@D4}cPCɸ,3ZeA	D'@"2f.1wITl00uAV<<w~8Ǖ,YjZ]??o߲yӦfg;6`0X^Z<|JWn(+$vZ͛7pq't;ltz+++!k=x<m"H\rdaqCvM۝Z}Uy=;   RcZ`	wh(HfƠ$tM!
ɠ  i[OxP\5 0 @F"HB>2aGbA0U<%c@XmQIƸP/WKIp@d4g@4*JT4zmHp,@j4=,kYTښ61G4݇_K#ݳqww* @\.`jX,ul^e>ŇIp6`1()*"OOng	5!T*2?cBC#%d԰I^r,5D01ģyȞmۑ5n}:tQc5.76MhsEʬAD1H~;6ր@i @59N/rXt("JY~-j\D63Ci`U6C"f&!eZ\DM9% %HWoI<L\Dp4OZPAJ3|;eG2e]^鎣OâUYO\B⯢XP\]YwW<kv'kHD*@dW,9L!YvU}9'Q[_޲"RUՠyyjFiC:[\v"u2M {VNKP(/J`if;f$"#X5<rp?k&cJՍ|-/s Y`qw~5Uc?w|a!+fCԬ w0\,B_FKR/QB%pDʲtU媊iXٺR"DEEX]ĚfOX$s者*~Kd6[yʲ<ZDK
A Piא)*beY(ʲrcWUUUsYnLȲ,%LB=!$cUOepᅟ:|xaqU%6I7(ˢtӝ͛v;f1[nI VnK( <W3&o[p̽^~QTengg-2Z5,adJE}{lf$:nñXYEB2"8j4T!{*5eY3%8%#0Ÿ&(MtN$HDrNdv Yĕ`'GVR'K;#O 'qwXM)AIhB@o/,UU._G[j=0җ䧉&EsԵGugк!3FQb	-[7遧Z7)Oz8WWdŐMY`=D	'DJB|h[F4֣4,z \$T3a-U0Uh7<:"Q JJ7Ƴ1A˱ч'z\툨f
@8	pmd4, (hC'TSuG;!XH&PI@=:ʼqbH>@l~P    IDAT 5h8mk:Z+1v8%U3щԽ+`s'hB?tNtS1>]1QAjŏf0l*'3URW]DPdXQ8@Æv6Xxt1֊HsU#1JÂ,(UYHb7,k;v'kl"cXq#L];qN_LEOw!1%0VO.U$ \:UuX0jqˏwӹ=8.~?텧T3-<mɩ}cUN|jRoOc)'#FpOf!1^G'=Ul2HÇ./[JQ]0 Un ,}oa'v/_%@4Xjʲ,ʲ,JǮ,+XCYc>B141rdaqqiiiy+dffwoܸ[m;jm5wA*甡GAՎd!Ar"eY,+nU)"ƘVν?3b$xNғ> ʠVqh&0ą,QjLch0'3FGj2J5BC)N=,2J$4?p4K0yV+VF1[:a 	SjoWVOAM&DϷ=2Kԣ-gH2aեQBE.V%9$/ӊBnmeUBݩf&$1DsI΍xphѻuǄ"rEIځNMEdt~be|b=OHof	%($"5[vuA0L=~% $j*hۣ݉j%LkуaR`${^   
KSX~ǌqUNI!ƍ* [)y{c"1MC2*?@D	e r`ʒAuQwy1z}@j&KatۆQ@"Y(!tU ppհr@!aƈEY'k2k-cȨSe1uHxաUιUU H﮴:Svjgvd'	z`:WZaa.ќunkD\.E]4&\%?'lD tyvHyWy	VCӋgoDj1' hnh@aM-KY\yfc{׿~$O_uکZʹ}{}ӟG>."rկ:[VUU{'>?Ouy^쥇zp7GY7]	MP6MތoCǬR~̲VgP8i"c+M*"*$iyY 򀹪jn"!&B?qoiˡ#?9DQRemi۷u1;޼y\Q]tPRNJ`dPVK_,/-zG+rvkfig:Մ9O_@Y20{'K=oǉ\KP:ц@T,a-P6Y".x&d:zrPRK8uŘ%ѤjJDoS}={zZGTueCc7͉#-Yf<D`$	L)>NE1RpB~`JlA%/V`/c10́dJ;vasHa Bl>#TLfzHCXYWR!Kmv"<ycDγJHJ< FS*la`"]ҔgpHHMŎET\SKjzsIs&֐Z=WyP]d֖UF6TU&j"xUU}DHZR>*'GYʪhVe6ƈ&j	- \,`8U#aW9'I
I!!4Q;媒zW QGdv* `vI@4KHA4uj,zĮbf)7^~nS3S3,W:6ˌvrFf\tBDsN@\Uk U43B""ˮ١ pثҢ'?(f|9kI ݋%t0{{;hr443;?EAk׮s9{׿us6s1v淼4~8777.k7)7a]pvDĉ1>PH6-)buWʲ2Ƥe$Tŵ|,m۝v(~UYUK*1&$A
tBDyfNGς^oP%3m[:c?cq-GMOuЕ`0z= 5dL+v)8(<xhJ*驼Q qUeFzTCV85O7$X @5P]BP؍kMV1?:!6[)hph2 l7&f*!XvEu?=U2e  "M"bn-$a c*Jd8:ut}ǩj?U)DJuCq!""qӫ,V	wNmvRbp|}<9>9$8VA*ZsL8WF	TFMqXAA4 ^R ċ1ązD4E4xmtZ`SZ!$T {y KU:(aiV[ؐgV+AgV{t5A|F
(NXhw〆ƔkL54j9WBXc4_TD92>㌉J99Tjr`Z4_A4ƦI1nR5&i}S4`;|*<G!d8예Q9#Xfg28'twd{H95夻?%DrhqӜZ%hЊb-&.C!g$@%5EYzVnwv'LR?TakFlT*bI$P{KKIGlkS"YwMiOmD݅|{SM@Ugy@G'ou㖖>~cH}ywyϩx/{|_C__W]g{|9/뮻ܳg ^y_\~٥{>ƈ$?xj90D$< srPUʲ,3=E1(ֻտ!$V SSV?(ŻJZNnYֶ+ǃ. y>?;iӮ۷:-6ζc-BsP9'eYOMe֮GW<pCGVEPĞn"DJ&4Drl < /~Cd]'પ*X. Hƈ d-$r		"Z%,,Hfr2NkŢ8A h-i5ۢ S&IlֲLw"$@?E5HF1211?Bޔ@%ZGjEtKF{WY@ ;]jj38u;6aM9UNA],i6VZ<rЬb̸哦z	Fq.J-l"18BA!"?lB+Lfa #0A`[aup5S0O{ԡU=^/)B#.˸ۣcQ]IB|ʋSpQv-l*c*b@2JU$Br <P6Ɇ!ٹՔ(AAp(F"Ӄ	bx<ih&*JߺXL:_4hITQQ=ȍ!ʃaWQHɫUOD  $!4˨nE {6n-dvQlhؚLBMOBXpߓH,Q	HzG!kNQvUwUY{,[vnMMY<y@Q7705صK"'@,̽ɿ]Pmعgƣ{>ikQ8ooά^zN~3ހtII{^| k?0!ncݾmc;[og<}^/?}1G?zYg^g]OV/;vz?٣C|Qse=iO_+++֠\4Ƙ,7A{g"|*z	"P)'{0Vba
1M-B|αs#h'Lw:gfg7lزa~Mlٸyk"f*ݖ}i!rY<tdqTRZk:4ֲ׭_VA-JW9ayYc5j
'ߟ|u)Gn[8,2!W\?ފ H!QP'B FD}Ť'$YEML<mFb 54 	НjC(HH(ĿF𨏀*WϳR lOO"Ϟxq]^0<ё3y)V]W-}h#b#6ceZ5mv߅0V'@b(Zsb17T	>%mKƷM#$NU!jכȸQMjnN5QOh!apUxY@hT(N}0J8UYؠu4m	[݉aaKV7][;Ba[JbqȔclMvh[Ud=).7QUJᄁc`h`ibxs`1!"^pCD4IHHF*bm	M,9kwHU_>;KeH}16f(h*a>`S9,!@짼DBl$D$sqF@	q$\U \O!cD\5d8_R,<|C#*y&̊5Dm?Uz{
%0c9VV1Vޙnw[S3-j،s'bhI?#S=ʥ,Q*;}TS3YNrP{N/~p9og0<Ϳv1lNE/T%!  uO{Jv7*Cj: xcyA	!\QRO}{ۿ*5d/xΣ/z?ϝvکڻSto?i;w'=?=w..-WO?4km۽[׿]#9  {ꕏ}cDdqq={= %Rc"~k_{emٲw?zwŋ^t)jsg>s5,//Eo}[^Ws=?ڱ}\;/|	'hv_n7=YY}`\8>-Poc,:m=vڵeٙ,y_A CED# Z"#+C{pC<sٹvgPAc`{\\9vD
 dQz@}ȭigsX"2!kz;C !>uVwt7+q<Q1F H.1qYc,y\>Bt%T+¬ù6L"AX`*[уa+iX~Hw&Pg21Qet_0QED$(,y	}/:O5B=isSo:[;*wX*}tx	]/"Dj@ 	1dJ4aGkZ owE1BdL<3A	!Br:'0yfCƘ}N80"wMcɷLDqnjETer}w
   U9RCۆ1G:x4 Wɐ C>I[96kvZO2>K;;7Y!+Lo۩&4%M'R V K"HD{:Aq.I$E"(Ԗ<fNX4PƫH옌UpWhrsDP(\Q&BFCO1@ %U%dͺw3\W(1 ȶbK0fjO̶ڝT 0|QҡfƎmm5^uӛK`PʩO$
V~抍?|/o,<`w|" 6cJP*"*'|Rݾn`@ffV
ZZZʹJ_Ғ0w:O:I ^CeN>)~i7nڴi߾ʪܵsS.ݻַ]gؖ/x6v裏~ڹ󪫮Z^^o!""ܽ{?SO=ٵs뮻򖷼hKKKwu׆۷/=S򪕕ʶo 뮹m۶]tE[l9,gff:K.$7RGv:+U`[Mv捗?gu=C/y{Qz1glFWGV:rCݻbkvgvNTE*KXƴDwF1zP `\X`y/"yfMgL K 6Dsͬ2D$s%paan	DT躥҉0AcZY%$ĂdXG^}Z\d
S N"2%砠H5C@  Q* 4
txa>ȨcdeƸΚϻnU]?~	dh/1Ceo`Я<HW/}yX$Ǟ"s#U4TcGȂ ۱蹣E1f\FlD&E7ptDiyH~)ujPQJ$dALxhu?KWekq!σE0]DIE&JBЇjgYޡDDHjx!f!b(<#03f0 >+A	Q4:VL§::d"(&  $s:
AX'a! Xg]>v "H	ęL(B q$,kNo<aPqUV҄ue]ʠ^r	gC@ᦞPU,Ĝ?W.å5)r_&04dY(7|[V=bu-ZsRt[Nؼ!cCIB:vIz8bebJqWyԉ~
mOz?vRTj_[xzcFhMCkinMCg);Mx`3A;v JW]u'r~nS]333u32;O& 0???̆˲6?|5 s7G}_tUƦp/}/}_lO    IDAT>Uz5\_Cb2_SO=eii~c<wN8E/zu_|VuM75{o}K^/~k^؞|Moz|_|Yg[uӍ7C{=gy#yw!2[U<FDDJq<@t!zefYˠzAoqiqiGWznZDSbtFE0W"5J#oD"N YdU\_^-.uey  :@uDR6 Gh; P	6ZX@LjBʹvLBCB4D	7 FeT,*sbH:hkcLUA{6(԰)zE?QeIU-x1H1h#*fuT(Cǉ?/I&6ɚm|j˽ 1UޟP0]M֟$	DtH; 0Ѭ@d5/X=j]Շw`VꨟH^GR9VD2+8  	U0*:P'ŋtEA>D44S1}K$Q!`ΦrUK@6Ԥp5G2DD@֨1&cA 159uAja\OQP]~o`b7МUԯx(q l59LWC)]u{t@^C@A]#BكG/ uc!')E# )']揷xZ#!i<V>e	bbD_"3>3Ajw:3[yE* DB8)䭵
vJCe@%9!ob[]7tOmX9; c& J^" y& yݻ v|7_`~o^<KHtgm"ںu ?~}g>ǧݼ,pj g~Ygy%>74b|ܹsaaOCЇ>'=3<Ӌy{(/>Qor??ʯʶm۞䋞glذᮻz;jzG\~O|я,={o~	Ox1k?/|!V+.6l8m",ێs%Rq^DKA$Dp̭v# Z"}D~!
(`P,,wC=the몒۝v݆v8h!G :"FbכYʹ`_r+Dc.JW9JD:Dm`W1+q18jhzSIYh`"PE"fPGEPpqsYꁡ1:vn@tH36"XצjyJq A ŘV;|:#DFD	Dm^3ToAMb6>8jdю**?<Wzcw<d!FED1\}$:^]WZqac5&
M/Gp08UD$~vҧiwѶ!az/@9P1["		@X ID4SJFSva`Xx۵9.t4ZАqgS_F`_?Ы+JgO>:GDۤ!$YRj*  $y
 >ڑHLdDq1"U1&^(XcKb,5$ U+ELu}9pPK^GĲ,U#rh,(P!62&b	?UURjzEȵ橬_<*"pUR pUE߸*AԌAZ~HԎ#P7U
m뫣Y*""*ɡS1K#RqM}xCWk	`*"`rvPݙkOd/Q84&~ lơO*5e[a:[}QOȬK?׽82K(;Gx
i:yG{]w;~[u}~睿sW_}7޴/~.۲e˫_/_vY*_gnټx5+_xeƌz=_J7ܟO??dT N;Vu=ӗP/x t<sӦMno~3}k19S ;_#\gS͛7?vۿEQ?ʁ޽{;N%	MCS
$dX rnZc
ׇ^fͳuHw|²Ft}G1R*Y\'"#RL#BaN13*賫^)U*	dLjq/U!h<2CyJ&1:zTREDcŕ@رu_d(	)B63ԇ!pI]AQ:L)N"S9$b27v)S*Mؕ6kSPp8)BGDDozַ5XR||@Y}u8mMd?߼=S9<5|ӑ&=EBM3S EDlxQPh)~ U6kӐ=0D(x:
kX "}tł:DE@-X?qBCB&!>Uk<z!		zAQ>UbYM0vWbT比$0jq闫m L	q"0'w<DSGa>(bHL>Lpmj8)@a-񗱀FƬ!&`R9%aE_SjR߄Ơ\Fh8זcLHzDD%`D26S	Z
NBƕ1sZ=!)#$i'$Ϛ32&HY, $_Z4lP1c62J5mDFG	ue05===;7=3k[m֣o;'aI0	W0=)2dvdH.4
+?sϿ3`_bBfMPƨt_{__u'|E}~K___s9?{;w8p`aaaǎ p=_K^|Yg}ꓟwvsXXXܱc^eeeO߹e˖[ 6iF 8pJwV5zK ecݗƭرnEq=wAS\{wqqq֭[lOZZZBHbEYd0HG\0vx󐌈s͋d/CK?9CnoNmX};"ȠFEc1,|dq
R۫<,MMMͷڝ)cDb0
3@PCW9ǎ!Sb'?|R^SL&,bY	dAc'a Bn5C(  EA2 PUe	;W	NMuZ@Y:㘌B u S4AWz"ҷT
2C0*`PcK`jը8>e镈uH]qk֯kj&uI|6#26& 8|A, ]F&༧o"RTBb Du0	PБQ@|Q86<,[k9'TY)COBmj$[/|C0q.ϫhhjw*,3ҾpYuLr~]%9!1ƫG6zIgF%#уW!1Pś8.@Hl
!M!GQ=	S#ͧ;	*BQ
0Q4Bc L$<ߟ7\ ]xH@h9I4
54\[$rT "@@᠁%҉BA#1p#(Yv] "hn,Y7Ph)?#ſUɮ*Ajwv;oSfqIHaM	Mj8z_r%S{T+N}bG7Lk+5N}Sճ@Rj
`JZѭ?N?暽{/ٽݻwwݯ|ooc~`߾}W]N:i'O ʪvCbQ[6: )jnoSGuTܠ\5f  cc-:yAj<eֈʲ*rat!;2ѧ	$2"*R+zE+ʅť8pPDfg2k,4Vؐ \ %>RUAʲe1~FAx T6d8W!cq>D2EY٢ BhkBIX1
f-Wzn}NQKC2t󃥈}yB s 3wʹV%"6oYc$?" Ab
{Z"jzʌcP3<|x6 {H׶1*Yŷ3LKTTpa}NiVQYcSf=H7FGj$l;{ð4{a/SRB. xX2c@JC殆ʛ̃џB-*J8(yDDwkrQdC(i҉*;ʪᠩm֣ۀPTX\ioq"FNT$`tb+F@mlIT]'K؅K_ "&N*yOl^=J,H:`z# (Y'>"r+9F6%zO*Ţ~tXp'ӘtZ2 kMY90BH,"9E0sCD4֛r=kIt-DM @t #~:OT0t]ť  Wצ0_BE&&G6<t|P/pM*D96. $CeO@B4o1$"r1<c_o4j/%WZ^Z\YZlw:tUTj٬[AxT4q	5p?!PeE  }& Bՙ{y M?e4Vbls=daEYyIvˑ'"
ɥϺnWUo_O}ꓟTz.sYOHcdHq~O>y=CEQ7%(<ؾb/ptCQ $nZ:QTgWGWKR7o![NuZXVE2H<pEBF_M$@t^\*+UU
P^\\\ZZ2n8?7^{:e-[l:aTfmerBB#RT0yX`F՞ĵ CʫWE+ =*`L5.rj~Bkz "Z[$t<sUqb1e,e%65]Ɏs==JS"a;f~6B̍S`H/Bh7t.:2p6UV#_G	8MWݳ뜺1*xui veA?E5pEZBum$ӽDiGH4Q{6("MqMM!Ùx%e>No(vܶoV#Db+Ӫ0pՅ #f/{KI !6f=Y7imjͮm	~wM5h",OSS@dX!s	9Wĉ#2iC"_96D@kꛝE sc3CfMU5gy k=1cV*g3k( @Mv$2#7?VٍD]H&"1pYh% "9t D4"\UƘXZc$dIOhՍ!<I0Dm(oDҐ4gv3XQd6Fz+L Udc(V|~2353=33$	ͰOC S[fND0T\c.O-x~GĨ*={gٯyqYnvkMD}z*]w]p^xk6li%D[>{kh\ΣN/;ff}gdM+;_k|! V+<==5q$3~;O~w\U=ع9Rڭa(̌iZYfE3<SGzY3SSyˇV~J kfrU<1D teA5s y+^ XܨL
^Ou:7nh[.jOYy63s;Y^;?p=>@;蝧>XcDJ̠	ᙖyT 3U("1	 #ʠ@夂ĥp5F!`<4VM/f)CZ>XD=3eJv{ݕ6l0av P1!=۠JT1цmHO=bjEFDvΣZ@珩3Rp9*NԟF͘@5mFtcM4KL'hV؀i*M|ßCxBD	11Ufd}#c Tnh&UaJEIRy)D$#d]{5LR#-D7=sTۣ"  β(h&]<MbbQP!Wz`fʒv_֧B0`*f3PGEF"jƘƷCn-$ (V_ DAK>M c〠n s1BTOQxqD4C"Ҿ1dSjŚg0ipH "53(0k
삈
uW0QblF4@dЦٚH	ҵZJwdCF@Y~|p&3'%ML#*ܰaRP 4ba>@ogOJ5׀I~l"B!)jhcAX+T8EL*]b1Y lo<iKg'r99ypvH66#"V$eE*DQsj$]b5
X)zTt`1	Wq<iӣ̋λqm<_vS imeO rm=޴qEO~׾xͣ=wzzȑ#~; կ~_W]}͞}fzeo~[WWbaq{7ިMOO_pet:'<Ⴟ7{c,,|ߊc~IOpǎϾ뮻.vOoGy{[#G:;_wY}os=#}~{U'xEMMM=~P8ǂhGtsE*Wq_BEBrYXm{e-˂C#"10 Fvb}[k@+yn32B6( Pcv :!
Apo8ǃ    IDATsNu:S7nܴa:x@%,
b4yrn,#2 nP &q ȈA{b
 `YX jPb!cTst""Zkgg~seYf:VNZLh* 3'*$$))a׬WHc;-&b:܃8V!TjU$GkʢQ&p֏,Oa$i:RߐWJ$jG5ċѻH&d~LY%h%Am-2 j&T,f\ZM;!yP@ F'(ۄ4Ե{ƗE H$kMÜO\5Co(&+_c*';Oi
b%1uR1+j{yvd2kWYs`   ?$dǚ<G{b(1RT׀ "NJg4'D*L	YjgK| j-Gɻ7efpr$LTDD/kL]ZAA GK -̰Hp>MtJ#'Padߊ?[Q+T@/ŌhD$re,OQ*BP/D#71*;0{G׻1ՙݸm_^,,.:W{ݲ~jv0C	A`0fFbZ~wy]G?}-嶓aRΦvFܸsp` i项o|='vcpww?p o '<.;\ }]~٥/} o[=ꨣW%pzfygqȑ̵Zwܱu{*}82ċ䫮|? ?W<[ne8\Ku	'𲗽tﾽ߼v 38}K_]> xM7K/Yя~я~ ԧ>K1z7|}׮]{;o_s 7\,"7xoN'	2xR,(3e1[eTބ,d?˲4!cg)݋(b	kLr-kQX*ǎ1;ǄdD窪*4V}P\33۶mͭ[ypeyiLe(.iPִ3j<lPEtC 2gPMaQӥ@0%2T% q\͂^!dh"Yם*	1&˨ʪN\UL2U-A B}-dw%Z{9wyk$ER4GIWb$)LB8Rp01V%eP"UX@BUA edǃ<NV>v*[p}w{^253JWZhږQ+=z`&,BgĽ}!g4D
0|j_5Kvo;jGc6;,9
myUk54>$Hi(5^_XKB,d? Ыg$H
Tl]mF#E8:]1Nk1!K8);M5kBZlf۳;MU p?-`>]n@?iT	k:lTTU+V   by-**HHՍHD=oUeQT:P)%ՙ0uɂ@Lxֆ9{W!1i[`K2!jĳ0BᲳXEוGDJIM;?&fr2C F( H){N[FX""EP=SR:i Qf4Y{,Ax!=jos\m!fTLb˾X덪^q|[|+/ݹ::9=~zq#200 &@af"-V
HEhyzs#I+Eд<g?7oz޶}/~ϟy99WtM޻ȏ<s{ra~?7~o5ooo^qzٟ~9r7w[~3V~?P<]=߳=m я}'/=?sPSO//]__ߵ3w}zgYV?ϿMo_?O^~' g6It| $Rz}vnX,.eJf[
)[V,Ϭ:9/1%VQ"8I:OOn\2AR),3sefѮ]u]\X۔s^,:Jد.Nzob!wܹvzr"uM_-X$\$)P	#ZDΈHI=s⌄UaU
2,
\H9Qҋ:u"	0 hB	̳.[e'@2"u9VR=r&,qhڑBTKD RN9mC<a@Ĕ8YuL:̃d-i`ޛ*yzWb-v,]ChO9>f߀JU'caq,pvN]["^"N 
`1I[c4"E ;PAe@ aH/jՀԫLWg`ڄͣSfs0p~T-StOuZ2i 4#
'بW5HAQAmpjZJ^iZ/k7z(0(UB{wOax`%*FA%)A4(zbvN4PBOJ##"E+	-%?Eyp:",MR@&D̕4qyQBc&39$BFĚ m u]RJj* "NAED TSǩ0H(iRUFO)/4I~Pf"RI j0 4CbJbsU^#-No8I.
#j'J7\޻{"gǓREAʎ2*r&Va)iT`ڑf[y{47OkC/o>z>k+TEWG]_7 nݺ+ػ/~}׻SO=~C?/_w~Ƿ?O>z}g~~iBO替>KDn_~q(0_^K?ʯmK/OOm_^Ň?k?O3< w_|O7M=3xyݻw[%PڞI0犛yq"7fduv(vD KR0QJ- 24 &"%GGtu~Xu9MpX# 
=Hß(JLRu9u9q)ewsN瓢H&ݷoOaH@6CB"PBW$:/@4k"	r*+
*AʈUѳe )
* `nHj_MN%ru9!ݜ@p,
ҏ5҄v8H[xN6VٸRsր9=<*9Z<GUP6觃#HiM,hcM T4lQ[IHq5=iq*5n`[TgPc R@2HJsSD@-Jٹ4дZ 	nM6Cf-#Uk
5qP?ƻ6)ܗA)Dђ81wݳ>!~wrܰfU	X6:ܛ]*'lfj)_ƣ5cy!(!]Afo=W(XwnlwQq!!RdaQQ{l֑ѕRb![BΎY}cߧW@!LhïYN䱫l@XW8O,mqMc=#<h""TPM;΁T87L40xWtjC@ fa$mc!\7=c<OFՂSkOo.߿{_KV-"wny8Hɘ\5:m F>/>͝|ޗ{}.33s~?;?o|_?O_}xU5H9#ϸfk0jX5a!!|QH6w[# ?ÿNRTM窪\덈Prг&R~وHy\!b)eBTSN^ĵ.lߋNK)m^0~"VYgJdmW$w!S	- &ݽ|)峳kׯ+z%Ztˤ'b)j6G̽@_ݻru~qk뢟ԋo^;?;9=[Vr]7gl_?#[^;Y%;]^^&n a4'̐<HA L6"l$)l
o֛w7ϼry_˯B|kgt@g?9"zj`q-Ku)<o6o˯ܺ{I'EN"۫NA-	)D =J z@u7n<u3S"êNsrX,Vq@ѕ0''C+ d5Af?a;N60py`"}^N-'X9	`#SNhe@Wvbm}DPR-0t㮠zjÞ@ZU:rb<2==Z+7J1lam:]:	im]ݵPqʇXK.=ᐖ<VUD5Df`~QB2IiJ-OalϴH*5${ D%2P
Ϊǻf#J)Uc`eTIR=DIHDRCgNGGB*AKVEYnǡ[{A)Yԉ4v4DA;	P\$Bq.|QҺ_G>	eU)XпdKUgɨ>89D",Lpq0jGn5Jz,Zluv~~;|..Δ@-RH	U@ad ƪ#k#`٬OݯsӁ w~^+X?ͧ}'_>k1Y:bsήugaz5[}bǛ-ވκs||BG+=!@+`?e{TZ%NTӓӓ*QXxfnq$Q%)u*b'R!$rFB|,SqH*QZFKڒ*Z|Y/,ŘmJ%3 Ph@o!'BL,Z*!$."'"pA.u߃BsΝJEl4VNjZrRõ}(WϫWE>?ԯIwFWS!BLE(%l4}]&dz˼<[}5*nHmDh%8T-M@G[;OkqpS9t0[c-"LK3}/vϤ+P\Aج`J|wDVEKl=ՇI{ͬ
pLjGēf{79ZN rej¨؅1&.+6`$px?޲exJ[)CXm(Qb=EDAm-{pr2JBSr$G &˶jr2ۮ& >'YI{a6LH$%%2e 'GNt R")sJ.EJ
e7%c\fP %
-,˶¦B-̣#61PJ#sffsbDO6i06+S4'RbQo3  x+̂:8TsΦqq)Hv;DRRP)KȝDDD&ucYDWfm؛ UL]Jes{)/i9ePJHf]l"r~v:slgdy~ߨy9RZEo_x'<_y\|OΖ>KԊf:qvxj&լ@n`7 mÏ#Ky#֘vSG+k挃Y΍5)^@Ni  7*ӳr tSʳJ)wpGZ]̊	,SQ_Jiݞm1)[P)0x~>lR|`M/TU
	A,Jŝ
PԔ
`	rº3`bU+".rZ,9焊Ulօy͚ٔx}Yɉv0,DJSjDD~\8?=f:OVLM:VIx6Y[^A&پ;B'v iurI&ۈjp6v)"}%EJ$iD=P`	e♄r:$i;s \@`  QY0@8)GM  (0hqXh7ganLn(߆Fg>q}acfƄ&`LOn"{s( QeE/JD,4zrJ yD 
7nZaam[Ѷe@ $dqcmؠhi9WTsZ9#{dC(DY#
h̹rq)h:)'S}3
!"E{nl@h~#(V :)jؾh7^wZ|ґ#b\ͶڄF^L֬
K(X׋6he44X(}iI*x5 	$-leެ'I0.& go?PnQY`~;xy9}LFQoO?՟zrq Kz?x2m6#)ƃCCǍӮbW1b'NuJptà=JSM>qt7]x[؋ad邥jBr>9Yn@#	s	^ݸ$O%ZXZhCgCt۔ Ra⚓-*&p$D)(=8vEXGp( ^w5(,"u6>-D4`]s
̶ni B)ӳ󋓓fmʦ pO7]T "zrmU|21f*mK)J):.3i(jlFUՁPm~83:~S(    IDATϨ+iOq11V&~m6~&t.j>vU+Ve F^C#Ay <,r΃:=%
WiիdG\JQ7÷%nme:Pmח 7Xpa>YsdVkjq,c`Qd;E>N@8XR0W/ID3Rⴇ#ӶDhڱA!"?X%R҆gԂ<M/HUEQQ IdRUNDCV&ؽL3RU%U@aZ]fcmbBsֹjZ"ǩvr&oz:W騢+0 @9Ns/o.K7\Jٜ_@'}/V~!bOSȯp[͟z|w@ t'oS_{{huח_?^xHz`H: Ŷ75ALXݾ]D13ڮO<ْ`( hY߹s[UONNNOW''Jy#Xf":RLVA-=ib.5
wY<,7n:t7"<	붉m|-a3j4VAU9$ $!J1(2W xݣKV0-
auy:9]]&"e6dT}qM_X@]wћ.kVM[~\2lH=dVuPIpp>8?8-pf*x1x[Xhq̓071`eU]moswmuj1SEp;@︾:՘W6]d[a%hSfWgצˡN"* 	(|@M{FmiC+yjsUĩgcBƹݰ,h󂴩lqxVClxhh+`DL֯RCd19hYp!5%wzUEr@愅FXv.P2QH}FPP CysDQkma-)apӜ	RcDp8RZYHe#.R:	bf]	bYb]*BJJCt0%D"Ѣ{XD@rA(ڄp)y0HQ'(U]׈wqx*kӸ jى{AyhsEN0yLX̓lNbu\zޭ[[rP"i=rϾhaBőt@Я-?o/S7t^)g;/gzŮ]q`{ǳ}{~<:;"pJ4SҨ{!5M;45JQisxeWE{l<3RETyÛo6{
/^ 91ec#1B9#d,⭮&E+U!%/"bRýᅀׅsYE5̴o$8K6(dR Č@		͐RZ]囏<sZ^JfԁJA p*,ryKx7w]b#:;ڔƁZ%hGS640:c]Tm)9YMk~jCJ ;G=9?(7R̘ v:{#Nu0˫z¾<Bw|a]{F	t}  5haS"f!	Z{WjԐw\?. -Zx,R¦M{db!J"(/5YԸʰLL׀"'MTl}hceՊe?d'=Umxf4kO
&!1EK	~׆1XV`q,oՠ!XȴɃA,QTUBebT{?1
_JO)`TD^~PvWnoG-@MV0̷ʢ\aKJ)X@%hRҬDXE0V&ZC!4@hcDcTR2p!at&¶],Vzb!ҌmSz^{1)X"Oay&3TJg>w/>q/	 FZUClﴵ^3VE|ЇjJ=	9fNY?:2:V5޿H%g}TEe=M0ljZ-ONN6J߽1e(IG5)a)Xc.%l|abt)Q9.?_T@Ӌ
׿H2 @hQ5 :ɸr4B^tUG]2N	9K1]& H)#ѲJHY *BRxެ7>-Oϟ~#7SR=gIq)\NfZňZi̩	=MzzYXyq+cլnqRքinOބH<`H.{X 89͋!| BF)CM?ʔT8TSVeI@u#E1؍Ae4%(8kƠAʪeXHQ{ _jl
JRGrU3_纩P^*4@s:f< p("ZaCU'y'SUwfm<dCSarփ]a)(``"qSqC7!x-JPU 5ٻ#d(YF,qef[@݄[Ķ014|׉}xcjU->  PZ>Ta%c@5""$X]"%p&PE%GV+Lu&U?17T5x"Ar 
JPWaB/c," #PH4go<_zPaoB>y77j$hٛ|5܎+q\Ϝ`7f:nh;j`iTEōGn޹HQEBͤXDQ#Ŕ2VΦl(@q5DL$NU3$j1b!pjڻl-'rC`$PTM
ؖ$
(
#Wcjp" b*>/ٚdJyurBwס$~(%^T\udPjDZVg'7..ί]{kgˆ
H>f*dȯ"ۥB'@ufab{61Uւ{m5eϸ/U3>U4`=2LE%NW#m{.'?96؎mZ4FtnF 
g1՜1f{^  
 J;GiG2q5JSX)郪)M ;]9N1ހPbGk
X>K9fDl( @= *[[qPȣ04a}e@s"[!qۇ)uخkQd^P
%ʷG`bѭY\)]pٷ̲/[;OVkމA@5%Wȟ<q~=n:WuwVҤ"UEGG饔SI}[DT1+ofbx ̈ULLrRP@`FOmtcSU-5cDMǈy0]Ɓ2Ũ -imp["fLz(_Z;Y(]߬!C)D*;5j)%R}>?nnn52+|9f4jJevQ:((s6Q;^EpGc?-
} 'O)~!CCfUf$8o> A")D]B4C.'D޾wɈs%FKD#hK,
14_4lXܵckHiZB7	TE=OEw!${j6v MyB0Y&*KT tSmXNNNr
Q .A+V a鋔RNUGbu~~߸qCg&%M%īcAS/W "SSϋv\Ο+U$# SRf~g=|>*#56"ճ<sΪӓ:4ryK:8igf[	7<uShǸv<o˨4pZ{v ͦS+ "VaZGQN?] t F3ǫ.͟ɇ-pIj
0l|?ͩTDyp M$F#&ZUlq[&x[u%]nĨX.킔ĭZu:4*5Ih8V̧dߦYU,5Flא  r{+HUdB:&³C;ȑKI9SJ+v\6>2!s)җRD- SaGL]וE40bɛpT7GP#	xjG50KQDJ (re.20T/i3("  U?DO9O]MKnKO)َ&!5v7"S}PUUGr~wn-4h5Q\fqm70P86OSԑa#h $-:?G=n®Ey	k `yGx1 Lˌ2m \rZtݫzuKB<&(46f15U|lȉ?BYj.lCDdcQC(L>QpJZ._Ew/(S>n7~7uכÏ>͛<E;efm rvq#^V$Qʉb=^h8L
d?J:z( =/6>dUUjҠ~`P)YU/ŵE0"W-!<ơ'XC'<"l-Ouo1RMtm?"'`NQ}
 8Vy;Uh̜ݘ?	 Z ƕGT,w"=h/GepT`!%ĥs#c
ӟQAAs=YXVN=l_7`W`E5p`6HEip@6%cWy5jj*'  ,'`kVYN2ni
hf`~YPfBC1\9D^{aggMAJ]'"(%P20 QTϔ:\ 0RJna8GJC؁1
VMA'#5`ڏ`O>+haQM0ZHfP-_#Q7zCyy:%l=˭I!Wh) }ؚ[܊6~dUТWcqrX~1)>ƫ0)ݨƁ8w~~SDCU"d8)3ݺsnajĭ >.꯻6vxňTA ꛶MneI"O yW];	 TLBȻ?-LpZ}M񦜊NSTuP\
@SC"l./}#./]vڵbtY8-;閅ɔ4aڑ0<.M.m\DՙŃ_|>ok˷U6iMᏂ-x6hԭ#QsFǍeh0Ŷ6ko:﫜<FCEe5G|ͳϝ*~]f0P 㠮:"*(v I3hj*"g<x`2:~±CN!ݠm8FA$C)`SFRoo 2KG\;oG@d-׭юuMPq
FFm$$҇5#2B3<;~vixaȋTG>}e<c0v[D$B6Kޡԍ>`K(C8	@BHT<ƦSERW-yJ%⛋yz|*QUEW,c0#m?|PBUHUUEA0
ջ&f^S+P'"Z
sE/\mKo$L 鰽SE${OSCr @T@+"?jQA7ּ&v}3o4(`0x ^D$Y^6(@(	e'P=X.o\s¹R M9w9br^P}D7s@M<r"_.-W H,[0>~[B0
0ϒsrR*L^%bN1QbUH)ͦ/Dl1=wrj^p#.sNd o+Po`lqIh%FؼZp1q:o_^8ڧmUZCMT\tvlj%V	o1GGl[htk6Jz[T5Kc0<k92'ͼ "uC.jd=#YmkrkUқǌfھŪTn #,QVa-0}tr>e%ϸRTKG`*e
3(τ*#
RpbE;ǒ}q-:hֲt(zD9ȽtNJ^~*5$bJT0@42lR3URu11ݵVU"4NsK?Dʝ'ktݐ%o 3""ך!e+Ǜ5+xlQ!@_UȪ؊b23+Ei=66qA`B	  >*,bD3H1,ݔEhLV[URJ)Ѯʦe
8׺7/!M"wh':U֮/ǴcNTB#@&vs#06fPn;P@VտmDwD  ]_rv?jB^7woDKm'ݴؠ|5Q-cU'W#@-uap_J]
^c}!u	
 "DiRÉ ^|}Jpd(GOD{Xڡɂd*TAa $]NR]&b;8BQTEg^H2@o]-ׯ]{衇]\;;=ff.r)T:Qr \0~C("d	%ni(!-ǈ#7-'BQfILVqi"䚈}}m6mh®j{jPt칇NebN4ZQڦ]^PO8sU HDږN DfoB pcy-/ 86Xm3b+s2[*hO+9Q XYW?xfg#@>@54fk\#}W 59D$*,.@mK{P()DFdH$ʀ'm# u@$C$@Q`	}(BqHDBbWf9\KlDD"flĔGJ4DyΉDJV'764YN@GSAk\ƁH[ދ=_@7 rZrsR0skSv  ',Pa^_	    IDATdǩzhndBGy=H퉔Bn$in[ip@'G$I5SG(vzM=m%Ӷ<9}ٷ|w
ZAYq?G@cTYV;y)3ݫhf.j.e;iA*is F^cmֲ\rw|Y-o[o "3|MD;Tn
+fE,b-NʃqƘ4V'оq
%T"ythi_^AJ Q)eUafaaB5\N.B6 < V1e,N)wS*X ,H	3Q&$)B$$QK7ٛ7o^=ryPg3;le-KYf$J@hleNQXS% ۨ+z|1	3ًoXYFuߩ]1i>
^*1r\ `RL_DbdБD*Pش环>:<#a]Ny^xw]U
^39SA  *QUJ@MtD0A 	t86q8-u<6YC)3}j   eB1kw lY/hg]^ur98+7ԄGӌk"W5|ӱCc&  "az LBOzB	=hnX>+ވ PvLv&4ޗa봨*6MhPLb:fy5*@'Cw|6j&R^8SHpG)Q@*ɬW(d&u**I6EܨiIDֹ_;5y` r9+l;QW/TERkJ0rR"Cfo"'O魟zmӶQ5gZeKƻ[Fw=(jMSG<QA>gFSӆ]ﲏIC[59SoW12l*Zqv׮]{so_VƎHy\f
,*hh4tm1k45/)< ׈V B@UEC8_cbfWwpK#
_?(ܿY]a)s"r"Q0R6SY,|쑇>;=Aocc#JD-&:}336)Q~]8a;́Cl^`"/dP4Urb{A}T+y
W4^ 6:5zU	SW[]GH]ͮ
Vdp׳Sж9L'^Qp^SR,	I͸ퟒ#blK8%H051"!u2rlǩ[<gR 7#+- 4~870mgfAppjk}X@cxa}9IFoUC<0WI_yڀ>3n@Fk[߶r5'nTx("?|Q)ļ*ּD=<9!
36U-n{B	3GW7f"$%iF6竷>SJCdmXc8}@psՂ'jt &_l򐊈6D	KL0 fTAu6X< _U$JIEK)M^,pȁ1@؁	vêHLtEF5uZxװ* v3o}[4ֈp,jvA8ܶp+g>*5ZQ9J逻k>-~C="WbXD,)&>B:M_0BE'x޺ghH(uE)MHU&֭&\bn65n3XR>N8H?5BRRh,cFQ<$>04w#`2ܒUնju>==lJٔb,ԓ/xބ'c-,SO>yzzkTͲ!鎽BhSԑt̫p-_T;i,wFC[bQf>F4"jG\meXՅ9&DVͪ#M[Ź:KUt*::53$
]C٫<Ȧgĭ8FU7VhXA{:0 j=z(h"M(K{u@?b.9ǭuԸ2`AX , J>"/z>x]}_'`8H\UrXЪe\J10/,|yykVCL;74	(IA5f3{*"Kj)B	 Y7HXDY)EeNY%l5ܗb/jCĜs)B\
yRr.#]fr(!RܙVߏ&YQ-nYS5ņKDȻKpP\RJ	 J߫
 b9f$ jCA⑟RZ
F¥ 5[\ -]`| Z1
|` `ͨ 7{w1tx|a#~_dliYg ܩ
)6@8G|fuzg>%7ֱf䀆%N6:hO4Cn5aj/TXvEC0@,^FjLf蚏jF-S\
	]#sX_y͛7w  EJi}ye"LQDD	H*_ə 1%DB1qz'@@N*QX1H5-C[P!ϨhDLGkձ$vT
3#rug~Ǭ\J!ErJOėDkO?c7o^^cmHJ))9Biiul @yocs].47*,Vo&6/3:3[!1#wJu<([BkkW%!O@+\5UВT9g8|sz1m~˰xeF^EoS*G AU8Ym+&<Q#Bm]z	蠞OƱ* H&~&@bOSTRaUJmrFheĀբH*1+%
_5?1lQԦC"kz4ѯgZjf] ܎_RB%(]i櫋p1%27&$B`P]?BF :* CfCG)&Q[`pPflEBӢsg޹bD	;DP
6M(g`NM`Z,zaRM5ј3V
j
`c %[yFf"vA^
&!`Q"gDF)DPJ)4/VV-a?iVFOaf7,R5BDpYsI)sŲø2Rj%7.g^{3 Xw6ΝQ9jCkvS͑x%Lb ^P`<Z/Oh</.C B7$PJ8ZGyg8!v9STuF׺nJjSĤ*n,J9~L3filO `[%"B(zrUlhI1[ĨhZjh7j2vpܕkJ;J)w iX,kggjXi)0U@Djf A4taR a\DlⵌЮܟ'-"+)sz@Jtï	_TUnX?"ө/PZ&WT6)C7k&fTe$cO}	_GOz'x6'-AVުMjGApΏ?&?OѶi0
9ovee( [BL¬k?_ <3@M=ϖ!
{ V2eIcc>2TQú2s Z \]K4MhVdLMLhܰ">F^g7RfikTMuaa׌0sj
$(lb1L3(wX
UM)◎`DށӬ#_!'CDYX0S- ~ $Cn<!*[
bvn'T0JRS*7`:ocD\^h2˻ؕn: ys~){b"0彻)gJ;]TEOWh*IcO^W>wW*~%Udo\B087a(~H+Ƕ0*)iD-y8Epa] BK,0܌F} BO<O.-}9u қ݁EPgl0ZM#F3eK#b|̀ @G v2*Rga'c@'{;tp`_pHᢆH*Իhh<""_R ))& DbҎrXNO'''dX*f#rP@T&IeCkJ	Vת8q6;,I}EaRXDlXp+ssHayzoU wWyӁyrbɬV6bUHѽԶ3qt@!*ԏjxV͒ڨ/Ŧ^HKƋNޮ̿3F8E 2pIWNׇpTs~ CTBNYUTU9BIS64I9r`?)7YG	+KWo&BUHgj95U~3Ba$j`uCݳCNEoyA/6m}0ۑ)hѪa=B"(,歴=D3vlX9)%bs[D,|T 5AlIERE*CP	vk'&PUhB/x4lZ[e2|(}OMd_h:&aX`Lg3@U 8P}h؍Ղ<"eUPX+0̈̐,"1{傩*rR,P=_^rqc=wQܭN'a֧V@3{o>W_+n2	(;|a#8?k ukZ3َL5!XN(E cRAgKD0saa^.:-=p$"#|Go{LsB-qRBL*!Xys  %	t|~WH`I&nV0	E&}0*&	,0a4`]潁JJcC b=$VsVtiwlJ؞^$pYKf^_R1IA22эk=kƕ13xRUѝfGfWWf2Ցp8V[/ORjKjA-"Y`tt;<d<Ă⌀T4X%؞R';`"*"[\6I
7EWgZ<24#;[ȭDvQ
oE쁗')7hI*Q'm&[.)i=5ʠezP~	U!	萮jjCvr-J Di4Fm#A( N@bg<G>%9uY&+<ңeRRKOomkzoù[Vk6@TNFL`4Ҿ["Y@EG!qRzҿkfchczp]t./h
>8o"uSN݃H3Ą	lL?FTCG3dFiup`bn&67ck2
DUX« .DRb#zLb.F_E쾩Hvײdz1$U@#B^sOm}0B"qwUcϺ3z=S{ciC`K	Y7?V?}EX)VQSԫ!k=x\c5Hk]/OG="7dG8@c5|r|{]޼֑tja6qnrrQ]y7aywO?__*L=59wFhӕ31Q~,",abefeyzx|~~ӗIdVw^VT͊vUC#>`S2¤%r#z6C6~W&ܗpUm0?.MN&߁	m(ĺR -'1j*,˝LFyz<Pէ~۷pw?|?|ݧ!W1}]ĊFOyꮤUYfj6a`<"Ȱ+`yQdt..ˁޒ'(I3kiKA3sdE;խjb,̬vs\d&Oe'Rth29Z 2,%zJvd8uz~lk=[eL>w~.rY^!k$k	n:gKr Ifb5|$*XЏlyMi7N{Pi'1C{ۮG>xa683٢
! @)Mب"o܊BNBN^et*Edػ]mCMMƿ߶Xk"ڒ}'`hAFy'֬//
Of?KpSmu2?3H |KMmM]-YvZYT{)j~'*ω pxRĝvH)tls$a
'$&ցqdfjN&XF1EsP&7}<D4grZ	$zuy"XJ7368hoחOl9-IߒښK>"?`P4nRW3[uE׷#!M]=.Pk3Z=^kFe)ןRPe+$g%DSST V,K))Aq(`$QZ_뷗ӿ'?=>>RrX>>|zӣ{姟`e뺒,e)Ǉq1X)|}y_?/_kN<Y!D@"A|US5="MhBb[oXH~JHKPKros L/>rwoL!1"t>\mf#ouÃh3Go
ǧOCӼַ㱔𘧏{t;AF("jpeTOw6S5ݒ+B$Ry=܉bS9͘4_JGF vL wi*GBԱ$EWRZ5?4̾Moay1zh;''|:zb`w@ecJv 睯f|/:PyN/u"=h8Bv"YMNjfPTQch'~j}ku+VHFoR^,exEy)}n=1lƻ*=(_i5m3ञ%2n}mwk&Scֹ\ 7}|7ucN}A%U/9(    IDATlx9W6rHyoE2%}M勢bnL~h1v QDxbL&o\zܥd
QQeN+ILa|\=0쏢-D&~ ܀(%tVGh6Ot[@%mP}7qәiReJO9qmrfa>6gGɷח׷_qyxhfW$0:p2pbVN]QþVD7byőt)h\E/>D@LM.	RNZx>InS{|x_7 pP+9TYŴRvUS"rlV3_>=?gPB4brXhQٙ'NWk]kS`EC}+˼"rTvJSDPǁ봸Y.LK(iU%G:RT-FӑN]չ,DBEDumqXeYXh&PpM@2vA,ϋM%p"F24_?_aP0&lX66\aMe:%{M=9DlYmnє{b4yHcۈ]&6ݫVy[sTlc'9Dwj;L	U׏b6LF̴|DЫwVsn&t_PCc4O*2	dM,ĲsLt 4yΤNIz2F#$mT݃"XLec8B<#62IZr=p:߯C^o'UgH&M#Bsۑ1q+ySވG|IX,qrW(6s/Qa"kuS-k jkU'߫RHFJS(D,5S6ǥ0 b PO	iъ{e^FZ9 _=IDk9J=f2[&3xHwdʢ\s>"Ba4U˖S5IP_wCbMOP`VQ-{{[W%;ߵ@'K~
K#8=蝋57/\dYEw?姿|Ezxx0^ߊ<>};᱾H/oYj˿.+N@O8}(fz|qb&`8,nLwIi읨<,BPvP+mRYCUr5A"R̢[o["+ksa4baR kuTDp *(] H@HG,PY , Gjf :*˕o=$h3	c]0IPUUUdR.LѪT2[m>?Pg޲!nh6C'ڍ듘Ԥ@W/YDN,]YrjZD(V:φZȁ.[1_)JQ󚦥BA5[!j4xd/:BJ/gc]zZƺtE+=@ݩ؜Ifa|.5ox4
=9bbrhKy#~u6kHRי_&4`uU$ҁhuwO& gBgnWո
#LTDCDTK'{ l8AKfWPb\TD=#lY!"iPIfꞌ2/%Q--Nɠ\OSjWL~RZ(ّj|Y^w*#'KdG]B2'9ݴAA7М#BKaQ2#']@gn*L3=!c2ah;IKmSAg\9[XiۡlZ},ǧg+|`K3M9у
~NCmb;ADhR-irGX2Arw~Ƿ,px8eXߞ?A}n*fV&@4QeӿǷeY1'Aa2J=|;DJ]LS]N2~ONF^;)%)x08{(X:.,?|F6\8tU\$0LsrQfSHYFW8
x{X@	(M3ѓPKAF:7-dkcY#*Y{ Jo}I&I J))Q3`͓	j&nP;9٣˺my$]98-Y$Km!7Ƽ뎠Y;)c*ט~RTl6Ҵ)'JA[QlOl` Z#JC X!<<5m^3
:{'
wX!s@O+d	Mɩ	(ASvsI)3^M35@dP]
Ru*x^PUy-]>:<ORzږt VɄFKB2-H&۸ߑZSՂSK&/~55yq)O4}Cϻ;t<Ҭ3hډ] TYQ';thmǳ)2Sev.S'5l&CGg $ISZtgn%6/7l̗ڦD1[^Az=ޖ<>-e9@!<cKRH}<LhфKnvC  ER}u_+߮Rppxx~G/Y~|{{}y1-RJ),><B{7AN+"ಔ/_ O~yyq}z~z\QܣnITEZnDwSi\oحpt tZD!
)̬Yp5uoY?Z8P,H!m'<a&a)$/HQÒl\
suL4ӄTFx}A ?v %DBI6aPńyHe.:&3'Q1ɘMHe[P;אR0Ks
X+$+޹qj;qqXI5j>IR;Nx.ev?e;{)a(ّ>O'<15ע.51wO}ucwIG﵆1橰qI7#ءUې=C,.H?eV9{SVj5oU;JN`)HAJY}&?m,AZ)5['2PN4Uq$$bb6޽Zҗ\'EӨUבnlo{_ɵgoz}9 /*>bc'r6]xCb뢦PU#R.{ͬkHN`)UT4*"
# ls;8K${IN	oc&NvaX\7q[sۉ%u8RWUk]`26la/܇+Uё&,m
Pۊ)`441J]մK\bPL8W@xDߎVӧX$ EDa	*EE]k]CψPIF\rb0{',8W%ƴ]D`OOOO_חz|;X[LRoWQI K姟~_:?|w#L
@QCTI*,<ֵEBp&sٶݤm1L`:CQ2B4A*{bJhF*'*jo\$u$M" saK)-~ ZZ`$	/Dohs 6~xx+u=:	.n?}H)dZ3G #UMbaBUR6ɨ!fuG@<K3*H@PB(*P$Ir׀OIJd$1DegW7Y4 OAQլ	ymLglz.'v=ΐ9u5jOaaک/V5^]$H-꽩׽VMI>9E`&\l!yB)N'	DQMJK&-"P؈
}[D1sdm$_$6mP3zPUL]\()zS^p{'3O睦v{gڝ	´k?1}Ȇ۪J<4i,M#P0Qe̟eiLp:/"XaIdi ݩRLD<"<J,@WwS]4g{}uzw/Ҏ!*f_fGY$oRrY+IIdy@FVߘV/<& ݻv6UdPFUZb#jUۈLsiw{%$YHl&)jekj6}D"Wri3FT̤Qd˷//_?yE9#E!!Z	o頣:l0؉[ ҈U;C3u`d5K|ZU~%7
.`
rm0PV/?|۱|z<~`!GMofPa֏_>ݗ?׿}w?w?~@޳ (j"[M[I`	d'\w}`߉pΌ-S3sB.C@U,8%BmSE؆E3L*H_Wgg#<2d3'?pÝJT8=(J- VXvN	HUZ5phqdй P"4Uhn\TK}[QDXC4:B"e$<G$7%w]J,q~}{nG㻻H 0+i{*@A)'ƸX2+uӌ=='U]'r	fǹ#r+n&{cJ,w2IA[;4{LQ\z^ĻaEg\F	UJ=Ҋ@4))y{t$@V+!I3F8Z!IYH%6Sٻ<;D=Y/塚0͠+Ebl>N"\/
46O`D4c/B2FnqKoUcsD*'n=FBfY{%9{;ntB쉏ȇ<"mCWn95TU|J&_:*"b:\r@ݣqI:^!3ukB5}5OLՐj|ꐥk>L @xHم@TK&͋8$D]2B^W!C]>TFy)dJ#'eO3y]G?;{A [0dtsb[Xe"r895fPs.ij Bx<7k9@B!մtt'p{xP>y/|˷/}I oG $P8JSILP>?m_חOiwW3;^5R3:
-*kbA@0DlB N;ɦMFqw%H8GqQ
 A+B(>wE)/'u]ZhiCQ5jkUryQƫ9	84Sud@m1fD@t=.]+z`pBr ;Tg[@#3J|C!/o'=1q^Jhrlf	^MF@up?W~yaK#Q5ڡSt SK>*I]<Sʭ-<5|tW\Xeͥn"wgN\^֮^}C:)Qڗ*dz#Rrt2Eu`g8S>CFpsq/~yhUA>L^-Md5܁Նyܮg6m$q95I%|❳rnJsyxR
Qu{4Ԡ~u{_ s	DSN/;ύ__~/L%dF9];6]$}dNd6Rx|ڶȓlfl*d εhi7\EDX:ZN6DĈT$4)uy5/(<4	KEzN9Ѳ~4)i} H$Ӭ<e [z#2uXԟ~|{k],ihta6/cѺPfj֛+z풴zT^~QT@M}D)/RJK(q<rIb*u*0bvxzׯ/5ں
ʖnXKqyI:;	<90F	ޅْBʹZm!EJ3D;0TD0LM L$>z B2|71 A׵z=jpRZJy8zVm\KSӗ/O*_TizgPx48mQ@Y}9\NGա͂7	iC4bVbcpmd'v1>&>XSil;]ni?Z4@+x&d:	cɛly'˘V)Ppܵ-ѝ^?J4z:M ޿.Iy|;d}uo{.Ƕ&Mn]1%3voi %Y(fYƩ; 5*Q"+iu3ygD̻4h!p>H>4q!18&qK4yMljylI=L{ٓ'{Bdid7{K&k5ұDv	;McD߭-KT l*Eu`/1	6A~J1t}=_vLvFpOT"RJ:hbe) +vX#?dpPvnwZ9aYEĦ|{U\ rÕBL_TH=}ZK#j2ӧ4}_&`8ǨH״?XL{Mp4DP#<Iey|z~w8'tY	u?$OPLɗbL/TR?<@ۇox#J1.^2G!k:Iz% Ӳ3s@`HG)*f [he]}]n%UuL2[]ğ'C._󡯯U~#$A.'HYkVG2NGye$V}_Ǳk(`)`*~<&k$XXaNlY_bCMWx1XTRT3,4! kІڜQR@cB;1z \I.CJ1:!.mjmc38@i"{,o}=݂ƆJ)F%ASkIv.wW%{| N3KU%4pDj		B},NS>Gŵ:ߕrSg!
8F9ln#C1{}=-e M_1ڿFjeCwL?    IDAT5Aĭk&5CwM
m.ZpI4²7¯hi	`-H5HL#@nހ"rMFiƯH 1\	hâDu$؃ST)t۶=QHPDD1RB2	ƓYsKvk2T-7 L811;eF`Ŵ׉hT_3?&=zUU>čDJIkGX6dVd2v۶Y6Um,e2&L^^-*"z1 ^숻-vGd !\Ѳ#ָ2iQ?je0ѬHn >Sl`;ȡ=Mc#{IW._ooן$f"ꙍ@M&=BS·RأAN(oYk	].VIQ 5Ǝ/%U:TE^h˃r޽lKl|duGˢqqI~RD$/&s95mGG' v\	%7L,z@ W
ZI
G8RZWJwC9 /<>wKRƦk=c1Mɛ.p˗b*Bz5 R4rcJGu]<9JUz:!0աe-n	8+[j]kmng}$9R:[#%chWFS31]5{L>f:!T'%9टG΁܉Fh{_n@aZNҚ*5T
-ep`;~D?ɨ7jHXohQF3a6ژ]UHef݅;ȒVܷChP򝲊\1. 5(Qza'oW^?~4&HlÂq?)4\ޔ 4|GӲU%hMmJViڌamVt9U1x{pi&d+NLD=K6s;ƤMn{&V;,4WfVޤہ@H{_KoE(JKp[ʀ4yպj:2a"4253I+vdzIj%;t+|܂uW=etYIvЈPpڎo%HD@LSmn^DtH'oF@d%~fVǺz<_^OOq9r 
52/D^%w+lX&L0^=q$"b4XmslsNל$κ}_;d}G|T1i>th6T"%dz\)k~>Ib$?qN\K8^MUFPV	C%nO̥5oL1RtLpv~9QNPEz#`~9_[7f	@Lz[=Z5ܫ{	졔ӗo߾}R"ߎFJUU)+fEղXxxXmi /Q6:M##XP
=s^x_@m攨u
.HΜzXH?8K4M9<>~%SdiVAQiHcf1v=v;ov64jF-4TeKv(O,5]$"FQS;MSor;NQd@{m۟.%Ǐ[4Y뢮1{uC}ؿś4;F4C$}I
$rL$@"xO:Uhҗ4{.W ŉV0]͝=7N_Ji~ݷ+
!0n{[7Hw?$4@ShuڑU17kid4ZܬkU&%p9Ūrc;fD HU	6kYX&jn`*q=eXgkM!>T5@J*/듪F;1GH+RJu =imMFOC~OL#
$)辌a7ߢpsa=/;0hS`#Rnl3E @3nZd[;#muH
·R^>=<=[Y4_2@-<rC7橶?#B/y06koJ@Wa+7yW$E󴞽O 	  sN~d-;CvuZEzޭ|_+l/M%1,㌐Uf|@	Ag|)=.\wpugrM̌^L
Ob4%LtֵzN?p2*!T`Z2dkH)_/󷷵֌u@U
HאRl1y(Z%[#켍LN!AHx(+FL%РR f
kв"HD4V"2gZ`|*5-lz)sK%h47XFZ0BHxrOKOͰó>EgLV*ݭg61s7o̫+YMۺlα[`>b6T5H1ZsC|/XPbݤێ3r|EԀz cXy2ֽ['SWˋd-lqgj	DZn	$TCУ;2A'2ŝZ#Hx
eqOQÝ~""Qt} $njɢ
~Qt}]%Ө']S#g-_M~H2m_HDO3[,Pu"Z9pb&$3PPUMHU-C/KZLLKZT!"A%<aQŬz)=ZJ,Kq=Zd"jOodbfhO/%'=hzYb&00̠ʙNfhieGBh14(0(]u$*zm6oEB亮ׯӧχ'[$lU9wH,1J8%vf[/"wxU+l,tK-E)1#HzƖ
=p&r+M(jٲX=O2-3k`2Ĝ7/6?E&^kmal+7@2x|;ou:a p0qy"ݏ1?AFE@11GaZJIH{dLE&vt G#+Ŋ3@RR	'R,  m'U!p`hě0*@@UXm-+JPP{EuluUr9O8v=@z(ͺqy2	rsâV#S8"lqXs#uraS*4$Xe|h+
'ֺG{9iW|xA`ξ~vNz'╗:"!vO{ϩnZ`jI{ f.۹I{hV:sH=zPO#йj1c t2ddxZzڝKWעG!iS7vHN.6@(\IyM9n3zr(5+xۉc{(lUK]AlLeV{8Ms "إc%iDc^᠝p8z{Ψ'3zDjk^ )eWt)!L[8.|8ϧ;]	|3\]ydH<Ebe ')[afUmH30f컈h̰e%5hˌ"b=)dMRg	 tJzqD 0d"oǺחoǧχGس/K޹G0e j<ٯ@'oܥҖ!7IKa}rMyDmf+pPΌ_5s(2Y϶: L˃!]4/J/:GJM  f&lRpi9}h ?Ճ	RpEd-l
v ZZp{^kuwwW$ N$sN/jkgK"S:!0=cƖӤ&*`3 VG!R" m6).
]ZVb]$:uTVPn4lR	2礅SƥzR$# )=kPZr]x|9mj-"{t*~9]L&y_nh~5i߄e|M@Q䐱'җ@LS>YV9e{i6pW</l3Oa<ڊ<:MJ5ɁCK7/oi
n[`:0
Q=RN8}fS֎ijMGT9=*'%ڮU[o|X&}~N_}Z8\S_vNxx6m*[L$&o%:($brJ*mt'_#v@p8:+C/ZecZ/.TM=%dM\`hO[:#;;hġ#oXyvTؒ/3@Ќ\Hf'`n}=/<#^ZD?PIA?6tnZ4H~$o3# ZZu=|x|:<<rPcPܘSjZs9l~D9P!Ȕ$K"2!sBIHHˁngR`ۍ^Ļ(eȋ!g0ܩrv_,}9،D*6S긽IwO[]k|#F0c<@DM9WZDdR(}7K)_UL/ڐ=-HlQ\ҷlrv!$< P+.]TǾ@Pق548[3LѠR;FL噭~!ǇDVdମVL.1mB"ɵMK)
^ӬN^|g>Br?xbv"čr]g];gC01З_wKȄ2O?ѺhP/WNog,3K 픀H6}ูY
GN$=Z*h!'y#W\癗=>Y:D%&wit'\'E&<DDc?_u?Z6+NUTA.NAI:Ћiכx]\bn'DG7Í}ϿeyuJ&hXS+"'ޏ&M3w3}CYs՚<)]V"9p9"bŸ ';<Ֆ0¹4RӲp]Y`"X֕'nQ>af +=}GźpOD"ff3sR8MU5	oZ;aI`,4-DT?HLՁkۂjDx헯Oϟ>e94Yy9xQ`=jv%{O)şK	+r@
Kʹ(
TaR42B `[@hЏkeo?ԨB.V̭#@uΞޅRSAyvt'?(Rz<1
Z,'I}rvWtJڜ¡H%0u?=jɮS"(+5:a%D
Fi9	[p9k4dҢwF+^GcuYҖa"qAX/^"]u4|PVMUDBHVuL<QCxu}:U^+%ܘ+pSoL{լ$U{O?{7gO?ffF",II`nfxư&ir6}c8ßWܛ1هL>~^kș17/0tF7zNnTJ$+RaKn&6F0W&S&j[UNro=Yb
"~Rpm/Xy*("I]3f +m.#/zZvu< ѷdBػT/'{^͖9w6R:pwu䇔չ,mM7$mjznDJK0$ 3Da@*`q$`DO&Ɓ*;TpUXjF-[ERD-"=Hn3j8m7b}EdD5HO,b"JiU*.d""#ӊg-%5å,'1**AcЖA[L`SO.?j9<O29C5('ƐAG6	,K˽iL3QdRqxw0X:cu:\cy{*4$CPsWuhdcUmʏYD._~~/|WKu[&>͝D&}(@/PUۏc!Oy)OoS2d YHąlDjA/Eg6@^
cG\@;݋^lb"y' ʨ#(i)5 <JY׵fqVq=\Hn!Id)@DڎSPN#:,9;#md)ji,Ɗ~/VShY( R׊R!zX4 a+at%ր}khWRʡJБ77C5l!+KvEyC|a<Z2,=/(Du,CB`o=fX$qsn{dX".<醰vXD q].< g0[%)Q;V$k^CBD:JT2EN׿?I,HƯލ !Z+)0 U,@ڡ<ĐjR[5`]R= w -;5cN:l	bsH$b< sީ6
,h[ƘjcJ&& \2"d;9-R9M3YJ	@wLtFkd<M^O;_JUS9'^yS6/&ռlcDEbS3Gu}qm4*"	E$YFxˤj{dڥ$TD@gZ\ _}ٞ1?YWCT(wWTT:i;&XH<~sd I|ccn@ӵ-H
ʢ)UxTVȢ>ZMi<:}MhbӄH
4h1¥̘֮[6;nϫ3r=}u{{{}iyxGBf9)"2"LؐHt:ӓ\# ݢB̓3U;+̯)'TSDLke<R@DxUQ Koyڃpw*eX~mGp,N"﬛@RڃSBItg:DTN=Sڞ
ྺz1Ze@l[&܅N׌$ѢHs6k,#YK+Ą@8T	>QA9mB+DoLyP/dS
\P4ԃ=5zPVO=
84]$@۳P[&cQR4[!i:)D!Қ:.ydPj".MwHo~M܋{5҉R
rUs=)%жQ_PlnWw
Në˦So2VWz&r՝{2ivdbgiG    IDAT?v#9-7tUuO3sάTwe-)d[ثd)A2xec#dt_5$#dyU#Aa ध!'` ~6~BN?%%1z>O]n{%G{a6QXхT@oՌ?߀-:05\e>>77li^7fpj+8˞{wJw3w/O6QB  <݌#iV؄)s
 {Ofޯ>\݅x0<m^Tŧ*i{V#h<lhD2gXR>,3Re|*Jnp
A&-*3x0-Ea{Ax3iO )yڐBz-lKaZ{dL$eE"D협<^6:~&4ܩcjEltcp} 09XC-]r\/~9<S-(s@HIǖΨf\SӬ9GI V%1L 6xth̶`9E_-t*tZӱɋqEK4m:.sԗ!/A'C^w$]:m 8KwKdN<\ޞT&D#jZ˺],Z?b8lf4&NNS#$iV3% XL(6gx^P`0PP3q7iOeQ	Ã@,pZa&r
lM,NJbmy#}]p <Ev{_cۏ+n.DD8D+Ef\,Snj0$2%EX3)QD9"^,}]0uH^7cab</c[^~Hծok54gͶmN{˭1MTD[ʆHܨ7M*D/⠇=a@26g*(6uwp#!G`Ҁ1eWq䠐"TDlH<XH(żAcUon
{l09|dSk	$RD7e^m3Rve#-RyV	$;Qy[%@
 ^U!Ӳ%" (yx@Kk]-fX8l}@'חa԰5dq][BcN@U.#;__$cD&F^)\1Y*)_H,QR:x9zEb 10Zgn$Fz5P7e^Ni,-C@mܪ|Vၑ'FDXmuʶ-RָmГ ̽3 A2=~5a$22W%mk?~|x<ynVx).Wp	9kzwUܝ( Kњ|mhA+
Z2S*Z1@UP,7'"4[[
oķg{y>h)=G[D;WZV'ƃ%᫈
>{Ǔ"F#ۥ&Zj,+Eoȅ-=_}vkFkZgxXW"
 "+RR=W4#ҍǄ^\KAuHո <8 -Z@}1\O-KV. RZ RQ
j!*:^-5whOOJ8׺οw%2 yUc/$2|`0<U@ī4.<zh2"sgv`b2<?@l(͆u{%t"VG+sఓF^na<2\_mlS!!"WAN'u/f>1"ggsLӬ
]V<>rn<nLX1
C_υ&&*+W2(^Fy9Uh[*E72cb>M=?
}86;66##)Z8xSYi[]Jj$JQA1KgF#Hbu9/x\-;aEF}jt@)ĘԢvOM-M)K#wyGDlInH,au$|۬{e9&f\Ϫ( h>sv-O[7J man9 cc`M`~sHm9zj^|?>==헲Sny;S7/P%EΈYqx0yUT˃aW՛[+#Ӻ͇ H\_i
5uk1%v\ZCx\Mt.PKt:Zt>,pX؄<I{a*22f['Z_bPD:[i9`岮Rotݩ~|C9SX9GgW=_=e0XL*QI&CfQ4 V0ɴrAK	#!G *=w!aq`hHR5ÅoƻiY27}-="O&Oq
hF1"ך-E2=O,Mov̈7-b# N
^80.*&p/zrnAU5). +E1(%5qr	q0X\^2`")Wh	hn{L38.s-fiz_.F<i᜶v=^}?hmsಁґqhW[b/蜣a<<!' cK6wWe+W":5,WUu}Qƒ'3D:|:Bzˡkie ҢM-06rBR2cEI$W<)"ҨM&>҄{hs~!23ߥg$M].&'-TF=Dsq>8PhKMkjca9;6bْ9a?}E3y':#~mcx}w\j~ Qk]|-OߎOg E)@#7cm03G5bTs
W0fb~{4R[nf-f)~:/kC
r퇷H"HÔ?=.x8,GMVD&BF#L'~h_d9bB;r-oв!7~^/?Z/Z[6@=nS2uXYxH 'c#{5pRIRbƿi/lfL[
g-*i1HԀeu
<"SDK"N*#n*L26]H~lv)p/k,6q^;<xb;'^MM#lU3>A)eHg9{~p\6o_!'}gsvx(/n?_!PS6==<8߷O"C^$3.9HzƠ0,
&Be/qGADTA8@ð8x0r/"ucFin#:5s>ZxvGSt!hsH|)NswRwO䂧g/[&Ď_idp$1/}Dj׭]e~| <pH27D$ۛuߨ-cH}LΩf>|tQMDxR\#:TᦪtV	.me/$;p'GRbxDnNPjZTC-,Ee`8աƳvP(Ky{m»6YqϪmY99tU+1@hiJ 5C6DT);4{pFiۆ'"ܙ YFD^eIaiD5?ǧ_~/YjRY#pMNX;M'y]6lrߔjN;TlX+ܰn'ytZrtBdN׷SsUs7؊۔tإ~.Z957=||~y:.*gk)[ݩ3JN盰{vG&O%7ƾo_#ʑ_Η?~h)nuuWf.ɬ~'6[RGvq)r'oWZ[As;.;]|_ߗx {*&ud	#yWAN)*9P,eYsa&X)z\QT9dh+8¡ 8IV$%< Ӫ'(#GbsHjf(zskDfZ&amТqt%H*6dPGfĈ1#bD(jqw
@ q==OجֽrQ|no'8+wu-BL(ɶW3^P2dwT5cҷJI@Jc ]Aci᾵y+ԼjG[)ʕ)"DiIdbٛK+4xB44$Jg4#G6a56D#`U0ޘ$Bj_3.fu;3Ӧ99XC;1?@ bg-Imc6FU=P_*?n*IF40C_GUz҈u6, 	FdFn߁P;jaRz硸i_(=o[bJJC+0WtBCڴJ-Z%h 4ioVkDR=4Bh4g	 M_UcZCE`xloÈ։ڲl%EĆU#H=4ADXT픛 .tZﾜG:$q3zD㏿?痗91jAOjF4S7w&!QC/lpX暛U?S[ (wESOh]ETemr9N_x\b5V.S0+1gٹp#m2G!3)MWאOiB#4ȂI!lc:$;ܣl젻Rtv\y8Soڹpr`!Jiw$C`$-Ey"98h:QظC??%7Pt9g8CJD"r	, Gt]ݠLqO=VUTKG	 K)9RlߌF99-m, khuhVf3c+m["304.cL(Ae$.fvJYܶöf^Dmi ͪxNU5RtGV7.mS9O q=޹aF^9KM:sYn<vȶ6."	Xk Pp\BH2I&(BSP8xs9%|W_IӍyǭu.w^>L(w;ĹnΠgR>!1햓	LG e0uޭ>U.A3+	81S~)s;R~Q`{|Zc{hLSR} :lL0B&SHm1ﭝцnV܍0e]]0>P})< n.>-s0G"<;mНIuv*y&;0F Zh2?]p?mglACwj(ޥ6DPPGc: dy\3Ds{ATKF<$,wfs4p3ly@DHE4jDQvҮ2ޘw= )eIY ݥן^N?t9Zkn6̑$pFa"4xHp<Ztq4W
$	mMRQ?p8/G 鴞~No&<||yyQĥZvY/K]/|?t<,eN7	t[df7EL{L%b靡C n-O7mA9@3cK=@"\.%u$l$ﵳɛ%x
qÞq:jCl2Hk<5C1=MWTE,<w"*AX^ڻ>zTw/UA2JF1w/y+E(E}L"S#4̡@F"3wl7rjR	6g!8[r8\ (Mv	5on=䆚k}8.NrO1qܽqnoLhz[=;J;jS[6?$;ͭGwdq=߮(^*H }g86]O~(DnM߸NQl#tH BL	;<1Z.+),ֽGϦ-Lo( 6`7c@ ߶\@6ݲGbCW)OP?Kŏ! Fvw䱊[Ѽt1?hg9c0`&-V-$Wҕ.q+	*Zmtpi[T6snE2Zwd.gen;_O-)5Iv-cg-](#P~]
	ѱgHzў~Ϙ'V *@4f1m{oO6A'3ǭ clC.Vl07vZϧz9.緧ӷr8h)il8I-+ ;e
BRbS-@U:tt(xv8^^8oߞʲ\V{^~|ϟYǣ<-/TstNoi?_O//^eao2rwF݋ɶMJ le	0:w Pk]׵%hz_nU5QrL-=[g#u7Cs&cEHkPLpot7D@2Ú b{IF1AmDCF iOډ3pNAAk@%QZa]"<,V()F,Urw^;DJ'@K=P	Raf(ع9aiL~!@e}ޕs!b8)9=>8wf(YY~_LMzzy=P}UF9VaWԿ>>ޢ%b+U.<jt_IA=#%УTm@BaN${$HɱNr1鬤Y-< +B>=m6[0dF|*)d$0L(	N|sUCsvlH&Aᙐ#MHpaC˩iVmx-kRlK)GȻ!WlEF>_M0yZ`φ}Q֥-Fu^CHRTf;,KjLdu^@Hr-^E^nqIr_ x]F' ?j.LY-25; V%Q[_4܃胊dKwo,> "T$3|nGAR'K-%qUOO^_~9>=l#Pyբc?*h"] XQW(8<7`+Wnh),E<E\tYJ9l]///oǏ߿Z    IDATt(<oTzzǏ?w㗗_~yv8)e`+#%";՗L\["x	H%qXW
""*e4u^cD`8p+lZTa&T%;ꮩ}[c	,8`$KQsuQ|\0`&Gsqp)JQbu0.Xjض?x~f~ ZU#݅w:p,*܀l%W-%>q޹w֪N
}Zf>d	JnZĈ
	#$3ncclB d֑5'3gVOO:cK`7qgSe@FGtil"AΨ|ѨArMEk~kUR#[
͒&b:vuy'`H~і|o2<tiA Ԅ.ݽ)P\J_ٴh=/7	>>`o-Ӛ!	 {wls-"[^j|0
ղϴ?9B	if~rE9FmpiHpMA	J6nj+7s<(#δo}!i<̽xDx,E3l丩JcvpU5cdYNvegHD(I-@{CdWMڻT$eh!Xpu3߼mp(i%(R CS292[!U:x:g.}=ݞ zLK8Bxd"hb>ܣ[^.o?eQ-XEKYN[_jU#`uRm[HFy31:ˑYMܭOEq2^@AQLj]7
wo<1bݭhX* ~˿ۿT_ֵZkot4XJ믿|{z:?_ΗuߏOχRTˢeQ	fF_UXܦRʲ,B!mHx`fA`Z-=PO@j:[z`,$Ȑ	ZA$ٌ! JƋ @	L*
xoU)D!+;?r}RI^<宕X$P-9%V`,"!ET7D,̒fFR
}EHHv~"$ZëAaQ#Ԉx/CA"90><<MXap]71[3OëNZUgHG$}@k?RxgۆÉ杤?eʪb#"B:68mSw1"f+xw!%S8 qBvY	"dy3*R%bwWb\Hc#Ĕ1{-{8ysh&`4=qEUM QUZAj]͟І>(9y'Uɕ9'*uuP#˻6/G~ʧKUӉ0G(cn]6hSd6ynq!~n	6ik<jDw^mk4[JO,sf~Xjo1$"(qUoɝɡ^ߙCsN6djgȌԏLml+4NBџ.Z"YU gB .`302|l٥ϭ8m&1`nլ^g)RUEUTT[5+ey{'wg[z35̏ж>:FoHbTF*
KJu㧙]Η~mYJ"BC Kѷr>].e5PerCѢ"Bs`"m*ν;}0@"E
E$*67W@2v.0Z]j=gtA(伧͎xfWZn^QrS^*}/{RFtd>J*XBTQR`DbpA82#J	$K2w!3SF 0SY^32DZD#סgk<Vډ֪T\9"e JݰJ9J	<yP<\=;*? ^;Nn*sw^&zo'TwIxmlÆ!CzJ>[WV;xyM: n;)z~%ʄ6==Ik;A 2{S=~ӥ $k?`ϫ#EWG14REj}(WJzmLeͩ$z<iw3#1̕2V]@Ce$ӧP5	9О.`D
Ia>Ѯ{9'>1|k(/I9>B&"fs[E=b"!SVqUEᙁ 144*úLT7DXu
c	uŖIU25Ⱥ[2NNL+a.Н)Ĝ]>ykѵѶax(6Olgjc^lHh-hYr(eU-EtXwo#rgn|xMmr8n/h'E'\ŁU(#6|;raf#Y@4!S½~ֲ\eY=?_mfv|}=oor|z(R1x>>~|v<"K)H9,z<,SƴݘJ{:po{\ՠz8Y5e^#`ݭյK˺ֺvo0B#9b?W2qt;L0 6ꋏK\fLqTEd
3e=jh)S2Vf  /AIq1+{`a,LO)v)\k} x1_iOd6@$XE`hq(ŶwKwtr}[t8EKn5h6.ADBb%!jfyK`{Cȝ5/c7 D>TDҙ U-}5u6$S׏QոY#>fU&"'*i37n`߯|w(&8h&dJfe;ވxs+Ḩýd />. S"\4[M4|O E{KR-.X>qBr+ioD|<XZ/Ҡ=^"T#3xlC/|-Z'x_:@#_j٪!7! =^ _V-t/d5ﱲDW$p|=diQ}䥰a/*NtwH  .|w^~k5
VX K@}d>	t{ʗK' уla`&gqC%hd9̐f#hzu]
1}kYv*[;RNQ&
l,y2n7xN%XhS]ktbht)ϖQkQrnR"e9p<rGr95ZE,YuѲj΢<^"n]X6R
}غK+JHKzRXRRQ3HDZk"(_~2|9hѢ.rxZf=X
Vbu.H)w0sb3k0s_fVk5fP=JuR׋]zX~8NgJ-II2t!,nWPCM}E"-hVW[P!MЖ/x^,"I-%ɡ`|{<x
M* ̀3{HĚA+$S+X,lTR\%rXZsX`T_u4ȭ
̈C>LwZ}l~l|Jo!]_*Y$1K%wS26 /mRJ6!	q$2Ɍ9Eh5dbJ{m/ )+y@8O<OFK5(2`"E (`5,p xfb@U]$|pBߤû0?ҦK$bߧ]luL"W D0T{zeL,N.WD!_{bsA~_QjyMtA-4IOnLM}#<*f V.ȼJr6ζ0K^;>fL{]n
ysː=u fXC%u{n# &=9H(#9iB<#Ps$2Mz\!%U2ޕVu)U4zFD@o|Źl#UKtLG+dkv*ZHvl7cl)1aZ"^yI Q&a="khZp>XmQ{:Lߞ?V$HδjE7}L4WMQ	Zlr-Ĵ(}nh{n5̪ZdRN KmΕZ*|Q-eYᰬ窥,R@{ui6KtcnN1JQlgZ/zk53[W3&{Xms %ezu?~Vks5=lDHt8$pkas͖ډjA yCɜHoN|Y̔!T[ҡ@VEB&$/yGHf"G}hؒ! FBr(
@(X$QP=<-OjIXs>:u y\ȩ!4;z&7<|# ݃XE"caASPqgIΆYD-d7뻺fnGF QFzLM>&Rֻdp6$9oHpU57;
Q6OWbԈP>?Bs`r|bJKk9C>n@C">)\\%Q+jx,Ň74qId}\HѓԤ@3jTus
mF̬ؕޔyImkGB|+{	> <, |XV˞aV?E1Myq\=OĂw#-%YD@h0EUS?\܌yd6q|Hx4Ol e4c2qt1KBFUb	fXpύ@Nď)Zh=̽_!Dgϛ=C:$7Og|=)N5tՈ>+.Tax|4dS]]oZ~r>eѲD EWA`G3;	vLhBZhC(S7RHY'Aotu,cUJQ ΗZk%xxYXjZr<.'-ZpXKQU!E63"@5Fhc-</X1DLijVRkjt>j5a- J=afRkUaxrG=ۺ?NcVPm{ ;)np(ś`PюTCdBlI$HlT:7FH =)P&HmEFx@aJ[3''4H34a7I\
݈c*6C}};~$}rW$@xf'u1?FE/gl8  F,\3O"9cZS0Eum=-++l3Zڝo԰#D̪1z}qA;:O  qXgD̽=Cs`*l{	ˬR8Z~@tlw@vʶy4e s*fnAUhH
@ٿ Fg`Q Tx՘@On(Z7XK;BIdͅ&8lt]|e_&|mꖂxX+TvdS\F2PcШ3"ڨs&JRjLМXލ(:5sRZmQ͖aKjPz[rd)Z4\hݐbZMEDk-*Pb		֚b`DJ)(th0) OU+KRz]UVizuC
T
"M]#< <&6@Y9b0mt_́VJPWg`sufH1W$Fi^"Կ.4ؠۙrݽ^.Zn1O/KYGǧo%}T}gtW%B{mbChu,ztz<x:-BIbf?~|s]1QǧRYǧe9h)ByH01ehQ0t.ӥ^Փr>_.Z5rX(e͘;jn?@ҎZDTs@Fd
m_
	'ľee3t}lnndKQ gWe@I8#@n-6R$q)Z<b+ nT P}k"{ߠc)ALDK4aKtU"jͭZ%eYn.u%_ŮNK2U5shesWQ3wW»6pRbu){3ZJ1iɟin{5NtР`z+	]ZGUёl Fses^vE>(JV`x{i"/@W	ps^.U(A)VU[qr`5D<k @W\ϥYX@QeBܥNqn	һrwLC>;yf}w2k#4i?t'IjvW p"O3qmUH0ހ ?S>$Kw@?m+m3$'}'tOymN:߃1@rsiDy{N>xNAbysUWᄅ7jEJ`j-Ĝ>Xʖj[vtPQ"ª*Jj"h	ZWWJe9d)ˈܘ;iJEJ_/i+XϹ=sjj
HDO*5IoC[yS҇IU"+EJ`oG0ݔGIaLcG!MB~(Bx^W,o_p<~_^^p|LBJCEceczݻˈ	0j^/ӏ\APԕât5R!L$-T׳r:Ok}$̭EuFzuD\Nu=Op|㓪ZTK)"Z$3NhH @H8(h5-3үz9r:].SM:Z֌EOKE:ѭֺuNes8 "oqHf	\
c X@	w}QG-= {ea#^A&$GT~Y:.lϺ1X-r%cZTbRnd~wnwYj o|fy#2ǀKLYpNS["af    IDATT?Oǧ]R:wuʀܶ&@?$BwR]K[G(;Bf3HDf5}!?Eۗ[_zy?س}ξ"k`F38to#x%Q{v'.p"4pxN_!gKt뭜-̾&nZ/i]p4uƎ;zLL[zSi {9LWnYZE^c r;V1ݤwխ	*C*׏@K)ǝ~{磻} ?m*ϑMG=h:NΫ	)}ٖ*WuhMdprαU_)W?ޭnik odmUw[$y@E6vGlW]r0A;#MP@!C(' NN"1цGvwcن2$5_h65;= Vl;jjI6
:ܿ69]^GmyL4}o/0mHEp<ӷ_~=vOKk=_^w)h%;|AC:$gb#m+innדRTC'.&CBͬp$:(ZԢ?k8'=qzY(e9eYDHAvEj)*v02rYuu]z9/^.u]ZNpHMDUxLt썌Kf=pS{ʨ	B&f2o"~{PMDW^C*BuOCvAbS^n"Mn1&]=u4TKT0ZyBaw1hꞣ64Q)yL@q{$Z&Tegs=?x[5$*1
h}w 0B)L`cpR$FDnvlMh Zv
|8>Õ/=d4lϮԥnB;Vd:nz#ED4`.4v( 
@CD]oǳfضB i9:	nٸۉo imE$igEFW#woa)7f#EtՕocbFguy{_ N:&%m[s1^Aeo
̜}`C}}[钒iVW&ɼ?sZ[y!#[>kS ((Gκͧubr7E:Tk؜-]$)щ-՗v/pS힤smCE(HJ^~yeu2$F4'ԇ}'YJyj\/7hiRG :YH'c,CpۤlX&EU둰hyCkGe25tǴ]wMn?2) #J[h@P04	*0}	9@$=I|gHL%|:wre
~r8og
^u%
?"$/ݪWՌn_gvfZSD鼅+7_a T(RPkl^)}n[rT-p|ʸRPj(	e)z(J)-Y"nZϗr>k]#ty A28R6v3wn΄ShɤS78XszU8T;7>`"@ 22U@2=!C#3I!䇤vGN'z(XFstjaIlý	Rmy[i'L8h%.6`<L4}ksg~lEI6~ǉe@ѓ*KahYzu "Dnc0la/bOÇԍt7A%,nsSQl頢U צ{KfP\HYLeNܫ?Gגss6-A6i-;J y BkhAٓ=sR\=µ[HP=YOkݖ$u$0wY=sKJ2[NwUHRUٳҋl08L',o:qS_b{pƓ%<b*+OP0j`|pZ(Nj`N#kI߿T+h
QRQV╧&w_)B}<b~RVU^?|,+ոO}`u.Ѻ]9ӎH3n[dƗZaq&WBz3&Izzfu$[)0J]!
݈O$@lX)]ZKޕJ\u#ؼ||3"L3Ї
cܛ 5oѿ\ҼK>zJ].qE@$faԻ7}y='\CNmӼ7٥XLh 2V/
|Ս$N:̼Xj]6	.澘?irmǟ˿?ׯGOA0zSTQWDd#$(#+~]/a_gJq$-)s)3_ǻq^?>>ZkhweF.?.?ۥy3fn֚[CٯWu=ͬNKn%qc_Ad6>w\NHf <#7*fY$3&7hg<4[w| :j#f~y1 io+`Ҧ(uWwY13w｛Y3;zd1z$33	( "5e~/1:%ʎcq4ooc@&IEd5ZD}b'cTZD$r~L=5k<#$pӱٌ6ߊ9dԚuLtjeԯ2sKGfYON`8dF3lRKSRamY;]DU^fAokZی}mb/Zι	~dMP?o''˒56-soJ]5q+n
\.En#P(ȩzuP33oYcW~:p "hU/֨Yvk'j\{K8Os^ZଲL')ց|'bHMөT~8Okrw16¾1%yٌ&s;[_S
SHVgK)F!6#Mv~"mY'ԼjY.k諡<AH Ebl[],PP-&hmx0smT)-{~~`[释-a`ay TZ/2۟C '}q2lKҌ5iseĐU/	QHsͬ5tn? <@J		W">= R=qtoo?8ג1{ݽ\.>2gZDeƇ_{勥^F̐%UZ4Vh,T {+!,XwAP#0Q J3V.6Z-cNwz|RֶCoYF#ԢA1O;VOTUL	BS%"#Ҋ|>0uDKhv"TB[M!J	1Sawv9ŧ[63Ë$WݠT`F0
R`~,؃״xLΕy]E&QpٌBɲ<2/HQf0ȼmʝ$E,QMj"oŇ_s{_㘚G3	SRZX[y1Nv"
3WTN7%H:NA>@u'#W
\_\F'r&iW&I:!xvÆ\|ϕg#oePZMܽ[[+h(2)<t.9;$10:SX[nW8]a+҈7*5O7z?߭X9'w5c[*OzZgyƼ@(ҒJg][_ŻԼp0K=mMt8\[ vVt*ij$#Wg}O[l`wOôE `5$gQ༑P65̖˒o9h%kh @,dRXKCg׼V%dv_YW2)C<逕#cwbh;k^#Z4	>J:7"7bW6c`hԺ_ɯR"KZhpQ)C[*Ԛ<2323"**P)u᭵_uGsRR ͚1##V~V2mI{i[_?߯8?~hcYo,Zf*0=30sQi*iځnU嫍shS$
o]wɍx "~*@-XhEP;:XXY>
ʍ*<iei3a|vɎJs=/6֤=l
6yr1{1§/ght+g6n~.Z]y!@zye*8&M[c}OҼ2%96֧r^2`*O?wBf,P1TT7p
tCoڇ>@uG3dKSK_q<6''5@#Lai$XQˠ4r,+PC%lo<gq1"#?}aD'0/m|y&oz":7\&uz)Etȑ7r3;r[ْ_i\cr(E!{߁n:b;noAUؾVXM|`%B([Q7AO 
x5Cq_?k|`8݋LbS3"IT^-"f:EgsxY+&VR.+8]Z?z	r_Y͌7"u<<㤝4yl/Do͡I`ɿN-sd@aQ>רҜP!'O+ɢ-wQ~/WfvK,`O.e`pP?`x<ޢ'y/GS+dv11ea=C=3OooW0o-G.Jόoo?~@ޕx7_?W/x3D_FBr[ʌ̸%DIB'9K݃ܮ%%lB)M%SҔ(YkOv{c˓ԜeQy{
xDdeEO{c73Fw/9iU7K9^Y?vyEt3zw\-2Yv#hvȨiENnT"v1 viKyRڞs&rg2Lk&sد{fjU~n]I,( 2Ė^+dO|YxvflӛӦp}u@Nh5A)q2ÝJS?@HXx"'tp!E3X@A݉% $L{:=efuXW;w KE)zyLeiv߳i#J3t{dCa-OGsr|Re/tٮ/G["YXEHY9af nWr)3EfY.kk6w}[~ts=hV|`fuZc(t|V9qQC{Yyb=n|peY^F˽
LҭPkNH)z"k4oIz"uWM_vAʊ#H*jvim O#799,χ牶#@.L6y4hf|"m|(3kEQOF9ҌJ <&Mvv3TGs$Ũk1	H&hdr)sՀbmFi芏dǣח577hC$nbx Bϡ ]F{2E*=`W(;0«"3k!oןry$_}_??֚SA#{tk.ʃ"p=zdϿ~_Rwa?w'WTF$|^j=ce~^!gQ_7]zX-Wz# pch+f6ͫ=fL,zERyou63N<Ri0KTP%TK[Ϗ]ettkn4G3n=_4U^a
f+EJ}&dK@ŐD
4u#aFt5B̰<`,C`Ct!^(!^LItg_j$pf93sb*CLRc?<V|I\rQraP}p%+	ܗyfDǵafa6`@H*/NK)\+u=F,3iC(mʏ)Zȫ eیtR	_T^2Jajjo|VN|}ω^	&(k(t33gtb2ϾOKwVznʪ{'
ۨ~] ~$(
Nq8xD\{2Jv"@4g+m鷪@ܠ8R=>w쾔R%ǁON|R?nb|.amg>ha3L!](R\"~]qBHN$*TꕛTe=BfkaMsdvUorVgYvK,Qcf͟ˆР^]2;S5n 2;PBr	S*3uC_J:Zþ3ee7iB+@d7\YJGy@< ވrq69CČVΜ*ѹLi2 QTJ1).1s!x_8>}^}Zknww^]mz[ѳB~\qxTrց`ٷƓQ&KŶ?~MMOYD
ϴM7|ۮ,KQ#Lc+5nf&[1'`9IWKZ^ y][o+O4	4kg4x/6CZ{ޭ%xvOh40dTfIdj]P5/9sHAFRE#0DhT5%PO?OcR#)*9.e$\	:c05]N	QԹ0~a((d\rk#{pV)JRB\+Tp&V:@׆׼TA)@K#gmDzs<@WAB S0PTNjaϼ+7t+kV:%6fVhԋI0127tȍ|o$ZA	:/Kw+w=}x\K\2'hi*|#bKKZyynLòj}ٚLպ7;EFN}Cj[Z{'SK͠0%EA=ժl1_:=oNтK|7%&'uRњTk(mc-z.ab&AsXbu[H_sR DP    IDAT}%"ԓ3=T_=LPSH']G2"&"MR<@Y}4i2aTfoF$0pbr^ױw+ IQaR<{A"33#6_Wzq׏_?~R
+G75vu~G8q8f=nn޽#6*w	ZyP>fjICx?쐍lR#j@a}OQ!w233/oY]4ܽЕF3kOQ SeTu/?N`Ѫ]YUoR:C	离/8q ܊UYU9xVf+IA?U΄a+C6ILPb>ԛ9ܹ2iRzZ#a
 |Ι0Y̢[	b+370QKP4etJ0J( S, ndq/ q2̐odQq`1'j0֤m~SI242s*k'9JI[_i*C	P5%(9@>R(gHL%@2	˫Addh:F*SS	4nKiϴݚ!ɜɑ*hLj_~Iwd۶wDmp_!.gj[oIyzVpgd
t(V AK>)Dazߝe%UyAs$ꄾXmS|q%w Ob	ǥU䢯::է$m0+K;k h+=z!Zk(PaFF3<RtmykZmv:HvL|c3o-\<<!ޢL3cT;y0f^_)Z[8۷2Cѻë\uܛu:T0K	I伺nk$3349)CS\k"4dE85^֙vGR^||q͈8?篿~Ǳ$я.*#yJ7+vZD[}zz^?H4y<SGsf}`ez)aYsUBF8{ujNU=9q>Ͷivmu{ԗ%Qg8Gs)@ʓk=TS=gT:k>.̼~S.VM3'b[2WR@0*toT5*8iEYј0-@;*JoPByDt7uUѧ>@iMf53J{ve)䀃nbFA'^<oBJPaCV_ 	ߵx, @?b#/DW HvQ(_lmf7t\qqjz *]r[wK\~F1oU]@4m=HJ 0n͢rd-77gژm-o5r%\pSTm(DUͭ!%EDS䍘Ɩƿva-38gȿ[\Tr~[v(nMקu)a_Y՚#	_x:+:;c3O۰{/r4)#!ɨCUC[HyW;2NU6f̨*~#ȴp(m@j{=jcKˆ,\̳|<$᭕
<7͝`43G|_z+_U]2$x_~ufí'pied7-uw]2+E1 _s3Fpvs4g1RٌMl!Ed	Hg1R20^?2zk~D?qޣ_׏1ЈLL@E˔U|<Qz=*A qcyg!b/=\?ܾ	uEX8 '`iÄKϔj6ZD~C+o!N6)b|3WeepPN[NFPQtmcUα̕ 8TSlܕ2şk!933Sf6_gk\\ 9C/.jMl@TN.ΌeifH$!f;i^W)J12@=@
u0f'$RE/tF޺`ҍ۬4@ÊMo̘}*V|`ÙǎBސ2gQݒ)	&6\םnOU% F^6h8AtD)sWndȑ9	$\!Z;[SL6v$xM0)d$Z3By!ABCKhHka@巕*[+XH?Ԍ_({.kYl 1v5N$Z8`_#rY-Uۿ
5$l`i~P7{>y#'bil
v83Tښ jGۃͻOԧauָn3.uϬ2䄻d6nnuQCFn2s[y	8Y7]Vϒ)ݞ*Iu<(Inߍ ~	M HvCz8:㙛u(`iheȉ*}{ 2'}L,_ 	Ff	_% 9j$uV%&'2$ͽۥQ83~8zޣz~GOoI3>>h́7KI=Cz'lFuӲ7lNjǛ?5:UV?@r(#l[C	ԲmmM@Ѷa;8r`#/`i17c8tg.*Dt~X.u~q=>3ea{'/gf#6i(,30`R?`)@M*љiIrί4 PF;RX-@G`RI~(i|=b@P3J3|"9NmOƑ| >̨i8y+0a>ƙ kzlē1NXT>v;p)Ð|R'd꨼/{"Uj#M@|%c}# RfVkw=DU2e4?#a$EQ 6mPN^zy#De\qm<
x>)gtm>3AUcs_?I w~jGx:7-`$}DVom#Oqfr"*oZl{&u'%ylɺ/qd_<6w Nzo&*i";fIʴL~)qX-l=xo`!}}-)%x<fJgAad8m!A@C~2j.H6ڔQgʓ:ct?J}he%+ELj8-nuSVijrFcvLnZ%1zǌǏ?$#?~|#*jeTq\_׏㸖7r/{v
u0HLԖֲ$I*Z4O<<mo3܍wN;zwi>\zB(+f]D> #tH /CDr8 h\VKVuܱAЦ5omF<ڲ0:$9|ިVxk Qٰte)2ƤUP͋!]pZ>+*hp+ᾯ$H!)=¼	0|3%#ft~!y FR qT/UuxrZF7!4:بʁ72N"mC)8h+1B ߀<qD]f.}@3@JZ Y)e]ܳ̚E5Ǟhˆ
P5)(5&UILh́JʲDEҮ6
:DlP iH  u!Y+a돥"V-=M$_[BG^v2W婐p#D$k/=C9ZѱZU޽t/f~Fog$%^ qj([N=6b`_[~ d'KWoir\Յ80WKOqVɊ5ґC+
J%?;](STy<چ4PF^J&^mRJ}@h4K"#bР
X[:G*FfTζzrxs3s1L<XaS'dF<~O:xf͜o ~o64h}%H
h|<t\y.L?<ID9)=-:Lv.NG:Wr(Ώ>ן׏?.?.'OF?G=q=c8?ڏq=>sVLyur#ei&T,&+k3y}fs?ji4"xl}'IR^G7j1sZ)1	6gF#ڛ#84.X޿7x9ml $L旇/68#5hĘO|v߷.lS^׮}Nѻ53>Xn3sj˽)DҳJXO0&l2o%yvZ(H6 Q*RZ`xI*,Zo*-J2Ͳ73օfF;*#\3ΐh͢gfBLfiUeTL1y#M̬w@27D7ڥ0ȧZKtGiF6B6Iff/AoٟjUAE 3}|D77+ 4EoEvEaʋD(h5N']KYvB"	B+OBoALK(do E0@dŲ.<LDk޲]SA*j9r~ %c6h"J6z| 9J{0zVRL\a3l\r7,9ػxzjO3oka\9βvst=
k@n[y ֐{p)j=Oq&Jaanx	-*_c|N2F,{YsmexM+m>ss=L^Y{YA}6M4
#+tRAAK_R2OilN4`K߻W+b/&gc^w& ŊR_,<mm(3 k'qf(:tjVY1,NS%eJ(؎lK]
2q_T
DpT)'pqvV^ɨP쟔})M#?3q\~5
UQzяq~\z(-&kHu퐁uȞJ0
02"Vrmu@j$ߛIk$j/<PƑlFOV3c2%J̳vHR	;#hK	6}qUX F l$98lHq?  0hkx\mpA`tɴDz:5&KlII_6_IDwֲwYART.Н!BMv)EH9	-1XPʙH e^-(xY`-q-M(3	BAbf`9w DȦoV6R].N&=jG 8 $	D-[~]Pv[ySnũRH0ӈ9va$ݲ4/$ٓ7BE줛ԑA/nNo#sl+jyB[hMVW$ʙ̠`i@J`LIw5;:WmìU1E4kISJLJܵGD
?))qn#З_iØ÷ `{hɥKySYlhXWZV	0GFMr]VyZ? miX˸.Ɂ끟5sUKu7 W\j *_y4~=s 	H_N# ?O/{ǀT|0.]&rКPdbPX)uĊ$`pیE@w zMR;^E"Ywyۗ൩,yR6
)/)Qt&0ڴ	[a&Iwsgae(#u
WqqshKn6l$o1SYx%%0ut=#[{Ǐ?Ýy+#zDZ|=~G^޿[~sp[HOjUQg6DTDooQ_ʬnzԺyلSV>'.'NWk7O8V,R=p4q9WjsLb~^fVzELs36I@YYۧq?SD*S+3P&k9s5V1Fqv,?ͬyiiWԻvuhHYn8Z7!4pA鴦ղ;T`
-(RGpyѼ4fT0&Qb=@ÄZ,:Ԟ	^05 (r#V"<mN׎fxU5)!" 1:473݇	aQcpXcQ THhgy_-2ACHMʤLV|$	P¤LRǔIv;hL:.ݱ12jw^dBT&@\m1ͽ Ol.zD!5 {I̵GDYC[wIg%Re)ΘT04"7k`f!ׇ]#F7/٪qdA,@bK{ᄑ-Kys/R}~[$)gVPRF[i斯!'o[5Z&H*'pTͼgտCʭMA8%N"32[{￁N>G*^?z=
2,VSW"Z$BG`٪(I @>{ qhaD}\?
#*gL?Ϋ
wۑ]PE+8g
/[i48&J,7$Kl!<3-9@FogbPfkIyWD6ӿ_BzGʐ#~\OӹzYΨǰǎ{^ToG>gXr){2_Uz UsMj044?CZRnV 0'%fDp+q($!J]
'6!hHBI&&,6\V"O,
|ŏZh[,&r'a2/<#/Cjg)L
P*))ь?ӫڼQS[Mh֩K+Y1 #Q}D?\ިFAQ9D,>  IDAT)s^KG?h<ķ?( #ʌsoo;iRDe~ "ef^#Vqi"enJ0i&ĸOc[: f?hoWqmc:ׯ$Z%A§x#.ؾM*i]p?ZoHA^[QUA$х?GA'kOS)?OS)+R׺    IENDB`wxx   PNG

   IHDR  \  =   䉽   PLTEݿۭȶ )!-ͪݴűå%'3頬$%-&,.8=CO{JPZ/2<58B8<FpGMV!'*8/4B!$2̚~		=@Hk~xAFQ)*3  (8?Nw45=tOU^Zl{cuWgw|SYbӻLZjO^ngimɁ^qDJTCCIlpu=FWHUefy:BS17GScsruxVVZdeg􉓙*/>mmnEP`LLRAK\sqpqyyzPRX4;K̓GHNdlt_hpk{xusºku~^ciZ^d½ſ{}dqz\[]̤V^gszwð_`c<;@﫫}	YcmܒRPR205lhf1 zvN6*d`_LIK=&~Z?͵⩐ܞfMגu©sTv"ӄd՜K?~e;/¶s@:èr@    IDATxԜMK,K5F` <#ń}X~XHnwnT~'q<9_6:#nh<`n±v{c26Xvq*%mJuT|=ۇ{Ue+C>2>IncZvNa7gz7Ʃ	{ l89ő[
an=pɍ`
""ntߥRuh>D
bG-(],NՌ2=/3OLV	>orVgȌevFx}o"p kc2`!Xna^"f2]nq  ƅ[r67g<=KEo{gL4h[c;kI¿ϊ\-rdJt=`䱟!(b2Y"_L|#JbDN	gN;L0IZT/$_GEn2N.>	/>^ h]DB"HËɎe#ojy\rok>&Zߪh]bT^3_.Y%{Uyb/Eȉt͌!vR0t+I>MUM0,&@ #ݺ/3BbZV-f5$YM
ABB擢T5+H4qO~%52e%n"nj|IXhyx|9öuU_/V\(^k3⅀ur~vk\q2."\$ZOc ,nRAxqBF3e>YܜI̫BQ10
#4%yw=D0_'Pz॥WK/s뮃Y.Ŗ#ܸŖh(Sgk		-v2koΝhpp>*\&`&XmQ]!{@OQOJカ*~LD=I _g}<."{[NNVƂaW+98|^\(ZXxwxd/"]x/2tXnToQyؒ%@;K:BKڹ*+!+Kq8jJ&;4&	+J'_Z|g	=
V.elᾙ9R	w_sLn/ѵ! vj|"¤=zɆnle:)BPX><:RZeoVGV>uX3Fa~4P*s^a[@/b1
Z҃7(k*[]aGT$A4
H	i|kAxXn*^ `$\K/AIzų^u#<RD˕Ya=m*iNۄmMJbGoAUPi~}Z,%u}/|A&[/Ȗ)n׷4T'I'.N^
z1	_u8.N@^g}|0T%)1F Z2֒e+A
ZG.&`/ͪ|rLPn&Q۠bP86XB[LPo nD0H8 y!ze4
00[-12lzlɆ3'؇D@Amip8VH4msBY0SO*^|ƺAb+ٟ'
d)S)ArejdTR%;_12[VF87d ٸs4ob*5:(0$JyA;'%[K ,4pj7}Qh0`̓O#2a:OkYGHy\%mX
E}B6,×/ӚB^x4JK/T* /v98K
᥃f W
V9!Z:~𒓸5?8Oǈ(np	kT*׿һURM^V0PD,͔8z{<c_X}nJu8RY	&1_]`iږ_ ؉٢~tAuyFw(NY.h$)" YQuZsK f	N
YD*o@?j5ܝE_5gu]3Cx.}oiZ)h<WWSXNqڊE[z|FxVX,`|!C'7zb /6.pk6#CnR ^mx	appYy׍Z:e;8Ro@$DzkKSmzSYs{iQW;J9[ݱS%E6K1A<qvp`Z}|p;74u8 d"魬q2^kƫ0"k*_j"*~ڊ%&=1b1[3q=\{	^eeRw4
0u2h17Athj+MCcȂ=ЋsA--\XIVFH5|Kq=]V.'XKDlW5c~ V輧C}T{6qdHe0M`,`hHA,m~%E6=l+~c첨e\7]"+HD@ZXi)GIuiY#eYzQ0ưy*VYê^N_cqF2`.׈³Erltq*kSj͒r#
9ӯ0pFu~F/
3nT!k-k$p4xCV ZtVV QEY5XpHyK[_U)RDE`rK8TvI
vZ+/HWo/J^(ް#9iirC [rm4zcwH	Bc5zH5
Uw;XVb1oVt"H+\Xk}XS+G5/T4AL
pVRPUZ%RG0Zdqb{i\#W~zTN)ʛvA	LΟ]!>\0xWi#g^&B{2w]WN Kk^cV=tC!M$`Q!8D7W[^٠Go
Z+R2/*֜d]āX)
)r+S> uS0}&y5/!ʊsEYcBK*Ӗ%Mk.32wmg\;`Oȍ-m)$Q.2Ԭ䐸$4f(Nx%;AN!	Eb#'գ*e{o=iF^ۺK~{~<oNY<Q_X=*^6!V	}Qp	;+ƨzVI{JBfiuA	[J.U)aj@ϝXҲ\Mf 5#ՌL=Kl8,W4R)E,*e s<q8d^S_&ȁWR4ün}1"r:XEH
}-f$|I!`smMZU0ͱT^ˡl
+x/+~(0Ba@(GCH6ZA-DwVxWQgM1a4#vzv"Wy8pɕ7psJ\Ot1֍ݓ"Lf:ZuAUy	XZd(!^Ă|x&H<Ecc"}Bl`%_'}"㔬M[qŅ3I93XGpB*zn)an6zFʼ=}#^LV9B`,m
Xcg+;|^jm/!=5W@!i	9GQV$Ȣ1 n*r,љrI&I!8IHU,+1c8d[RoPMm˽`8DE6"B3IƃȃQ멲Φ|pK1s1[Gv0X)nAC0*J5J14S6ۦi	gLa-lUǹ e4F\7\Xt1Dc´tH.Nޅ)3.)ܨJP@2"DWRYa_yz$KLxQ*ƍ$6ǦY.gFIUЦ{؅2v%QR*VAbrhLcBLA$x4m.6VzJyRF jcAz:S2CǵIGwԙqhX
<T0c*Uyjq<{L'HHM$b`m
/-X}4L#ɵ5CUvӂ+6jrѨs`A}TQi`g}%3S^53EJblJN*~(;'b֨I.:̩gY=zHXGhJ]+婀(@#k3%n_wpӔԜŲۚ77b@ݻw+,O*CZ.CF_qGrleAsA(yדuxQe<vM[ha87Yws*QaݞgX
,
 .dAHJj#Gj5JB]7*x0_Sfij[42bX,PD*xIW[R41ԸTLQ`olO1QG{`cJagRLT``D$A,x]$( -˿gѧJ[i2p̦]eU%4,kXfmbc׏;v_H"10 2f9/"ژfږPiazUNRevp`QB9|d6P7p1[pִ vXr5܅9M?SR-)KjWذDN,|f2^4ҳ(?
\O&	 	:	}Y1c`vK>D ]~gK`9v`bׯz yA"JreƶT'vnQQ?"".B}D_&]7OC%2<-dfYB8pViW|i([3PajҳQ<(bJO <YL	2:\m	fX<r.a.8=0wכa_+K+%pQRXf)/	ÕsK˃WZhxn#<T{0lx:߲C24[3	arr*5DcQ^kIUjh/:Q@,H(lF
"ܘTZ__߼QZ1_`WMFl͛Ww@+t_:_N쪭-.}ur(;9j6//<tپϗL-
{!P՟H쇇|roZA>"
4aB3Z`u
{_5dcW+ Pi6zVdQm["Kwgc0\`i
$Z	%5lGՅKcckllȉw XiW%#n	v+i)fs~30߿ATȉa2{TgP7"UèV^>DhEzE#:*FRB0Z$(u»3T'Dj2Bg9'{軀3ё(+%l}kmr)vK/E5uaa˳x;wnll7tgljjj|ҝWBq|Ú!CyJ(OC՞02ղ~0WM,^VC_`ϏyxExD88-'W;V()DU\
<̫)n"`2 cr+jp|dKYaN _#?A,<7 L/ 鿶vqVgWSSSw.>\*ݺZIǲ|s&M@ฐxx7&E CGqmECJg_M,ys7TS{#=6?i=ڳ
3"PЦVZNT%$I;,63[J$j[	@0m:d1)Zϟ?Nk1N|oڿpp3g=z]SК]ͥܭk\+̣f[JG篟rd[	.{۷?ٱN^p"3STGeCeK	?㬝;4;,Aaۑ2mQYg^WCKI6%S_Ըձ gkzӧ@tYoLE]?ʼ s..|?A<t ` "5ubeinDSr~ :q;a_8{&#kUɰ2L
 R8<T7ɇy(ZwL(4'Όf:˄	#ʮU(ad>'=>_?i%eyI JƏVAֳg<Ͻ'0^(Q'x2_?Qw qtzq~]5_)zwA];33aL+iF8Ha\j*Rk\ixg6XBb0<nnP X}><N.rCcd"pkp!]iL(pta=VQzk>7YyT}\ځ4L9B.8YNGn~SDh8jҐgZ~nWk{W\φh ØC82ՙʥ4XU2AP-bjNf Mw v"8~|"0oOprBΎ;=q	J---ӿ$21~v&"2d4Նu~7~iUyWSzTP)_yA窰|mZKKكĶ;јA#k-Y,(]~7")vDj_ XH]}ҚwiDJ\
.x_),#J'vL-LM;|MKƐE@7#aT&&~1"^H$ z>/k.?9';l͹s[<}D08JhVﰐ`Y
낯mhhXC+65)<}MnWb'!4(RzO7y3vD[Y^pkqu2MF!т$+0Ī/V":A5{,2ђȶd
tѫPxĂ4%&\A"\w^ʹԫ٩م4i1YZJN1w&Tixzl~sh\j]^oWׯ}U|6oGϏvlurt5z"gZQ`]_bccS*^xw:nˎB!|R    IDATJpH;!_PHKbFO,:wk۶m#I27%8GX}(GWt0]$*5#PҰ`IRD%Nc&MICDb`Qo0'#?UEt%.-M|M.4+Y,6$h-kq&-ȵSB1bHOY[5۪=pz&l&+nuճn[廟5t;b/ki9EE~c"r8,$ZLx}a^42_(&_HSJ&L7<q!s
@GsՇyE7g'?J5(!Gs;
AO*.d[3]Wʹ4¨X	K"dG1t0)=>^,s~XdV5Z$Z |qF(YS3	\2"cAW{'͟V&b#nNԺf?>ino\kH|5x"R<EI~D&ڏԱh!X!
Twx@K:5oY
^At"u-h+e:S$J੽,_hpd%}|tR,fP;eZ50ZrsW,4P\>E aIjMBb;0- ls3_S^ZņX )T&f i
7Ҭf,JDb6{O/]kk|D?x{㟂#z{/uTK/y J&ͰPVòn%\Il^VӑխD:kURybäXFos6
y:R0',)CGig0jH>u!)W%N:~pdNbF	-R1DYgY1	ZG4#DkX&w%{AQ)e!O^	yQ7uqo7xt	Xmz۾+4ԐZjU1`r`X;9Jtrp\zj/V}Qε\Bђ^&B5kx1\w!-|ݷJmj-73;U\,HtF Y'POj[Vi	XķL Miɚwp|jvrr%o'=~(L%7c\gIl67Za[{g_h~⭪;;l-+Hcl]ٲ|1$*#pl_i>m1A,hIA,sx -DWi	|xmΟ:3HRT38PbRʕ%ÅR˙܊֧3uxnJ}[Xd&;z~~ХErW5ݙJx{narJ,BЮŅo0.ykXu{"ӘIJ-gH>GWtƪ}vۅg/Ϫs>o*8Idb*4#c|%p8{N\郟jOҥ/GnT@j8أJ*@,)-)+g66lU/5*eAQޅ61/KjH;9B|%D:(\q:K˒dgn2݅ET4AfhHJeY?^ioOGs0X6m_DܱD?]h]=yBދott|	2WtDs$cp<tHz^$][xϵڣ?x7ر@5V`
0`Lud|ŗ |mC2.dN=˴
1$=g	|w?@KIk;()M^?bp4;EVv֝Ti$HYHeKȖ˝LAd
Ȣ"יv ּY֘&,ZDnZn"톴I@c.		鯆M
?))R&u5[,Ew6fYDTd{KQ̼9y9 Z-cKՑh1OɎbwlfC3Fyfjs{YeS乒o._elf[8?}U6 2_~ߗG^P ^x`R0W!/:ʾ?SЕHKOW)՟ZYlt7
p#:DLX'B6詞~.$h?JP%c0LMLS5;O2Рe93?W1ҟT-v_R"	[klņ"Bxr%5?h@TmmˀۺjU"+C^ J%*-LIo2.MM-=- WƥkϚz5%0*<K8eNNXtD.7x0%@ӋΊc Pǲյu=MtYZmLC	s]Dp)<tϔu4s݃h!y=|Ĝ<+79HX)LU}!u<b)8|$eABv޼ahpwsidmlnP1T7oZ5΂0ՀB@0\Oyjāι}]~.P<utd2=mpp$*TQ^JqV!x˅*N^.]OQp,[`{)$c'Po,U;͓Fu<<lT!~Q yly8>rVA!+7$!VБ cP0/:mqrKL_q3+qPQF2BPBP@a!ø!$ψKV`[v7;\d">6tMc8u%*+JX'',xVG<J;Y)]qwZ= 3:gWZ=-v^o|Dz$ּ7dP)au75JU%BoFTL`-f$.tuV_5mξr%\߬6.Ql"yXC_HEDktbN@&'Bϑ;ߌ&'	eZG:`+R2ŏyu1
!>4$ULlmnlnqa`kwO~dCcmg\9sA bi?| 1ݨm1<0:'1{VLSxN\heZcqQ5t)mLonRA{MG@$,5|{ܻ=>QS $55ujӹ%9Z|;mbWEFPl6'	dhĥ$NN8z'd)b3]H+֧JiP'NS0Hzm3M{x`Lt?Q)Ԕ11͚-b)HLyΡ!c[ʪ_gElmLÊq ba_y~Q
zeOZ%ѝB1󽷮~Nn%Z]nHW+WW6 j]`mMrv|HMɦQܨj]rmI]T1
u,oZ8kw1ӐPSR/ ꈂwL|"=&(]og6˃`EUH֋Ϯ-ynȑF'ڕi}7D3ORbGB!g3oo5I\ObA0V_wbor'\d;$55Hk U#+Nxɿ04=Y tuwdjT_VkK率g]g^x F{A<=6Q^Χm0\󐹂fy EZ"F^Ch87/R111;-3 S>EPlgVV?~	hHp/Ydx+wW"i{TQޘV0p'&jZUN%M{zeuVAxڡ;#JS_z]6H\u<x#?*rESm޼$B˥D+~=pڄSV7 ]ezmlJ"s1!
b(GltUDWQxcaԬv-YN-DK"4 O?"rllgvSf]-Ң3%DC=	1l@5ޖTiUpoo=p;R bdY/p@{ٳk7M]cG7OjjkjK̣NsthpjZ>㹄b$|hMuBTTzev_$P^Hh mP
 `h\WAfx">qt=yxqo|`zwdjYvE]@WV}|^|ICD/{qS/,#٪!A^Jr+ 7עǣ](g"F4c-1%.v~׃ݶo
Ey_Pe!&C	bOD/0DB͏߾~eFٚl(jw78hho/<Oe||l|r83<gxGɆ4L?Ad%M(us%QU$ϱRa49U"*slʆ51ɤj@Lej#jaeMھ#?lHd,2BƏ Hwg>;L+gYHyoh]\˫a%;6.ڬ\93ؤZ4PE]t%a/*0/yLLѨɔP1ʖb~iq
rvnyKaw4kJf_~"izRҋ>S_z3,'n:Jo/gmأW폻*1(OdØrqjiMplZYŉL)鞮ΜfUi^Q@0qh}\XÀ7|"Jpb۩0Nwd8կ̿SC6uiQQ٬=z`tib{RA޾}8W0;t%aSk $a.*Q(<xOa|ragV܅'a_-z涜_-	H|.% lQl^&!eFeJ|:¹/*
_ʰrncOmyJdѪln{O*c$9iz֦LWY`J-0D:Q`bq';zH2n9d#gÉ,Y*T;2Eoy	)V;riR!79IwDD (:>m3( !wIOO$A69! QO!暈BЋͭ+pW.|?P\*WJK_օ{zS#~8877Y \E"e͍Vda~=1KS
8XxPxAlZt1KolJ+MT#ɴJ+nn*H'!dIzu̕4XgrL~d)$鮘+O||@EtQE|@1luͽyifV!koVۤF*CRLhD@wwp":Qn0ܸbp"0EB0s1nb^э[fpw;7%NZiYBZO-t'KWg<^0(WA Y88҅vԦUJ~U_&/qUCg`:]J}\^g]}ѱ!o2dk[z굉Wb+ي_kś16v8[Sb^RR+S}J,a)>풒S? /}ٝ+~ 	YwbX0ӵUp3xqoG{{; Lɛ'''ZhI$wQd2Z]!hxm_+7mύI\abXp0o6`A$P8yzY+2Gɗ3xILE<8Zu ρ3L81r ]	HԫDLzc%yÜRS(cQbؖHJcy]MYV'Z\X1W4IjŨV$QM~Ksϑ	VZ3-;RFdZ^[Kl=mΚ_XTpS%P'DKT(;.D
͙JZ&''FnJG߭sfH|ssHW)hq@{˹#ޓfoF<?l[k~VuOp0waQܸ9'?wPP|2x'\䥲@&j͋yUV;񡎌SK)&Դjuq䶍ڤFzŮ]ЗƜ͸\>x$[qZg6׷izqftrO4UoWWԥ'O{&}x1	&RWka_X8ЄMFD$h*a2'.UWd/weG`0]DCc:~0cw%}>SO4$wivzѡΛÂEA݆p knI<ǊX,
=QI	6C!*)n~kըGgö|@0Ypt

TUI;ĸweԋcK.mdծTWƌ{4麚J.֫[eJpV((;L`r3EG@HaGES<?$6QdV\d~Cccc_	3VJ/UhA#ZVS*ssv;h6\x"?1ju$Hh0=;89Mkc#SzN~9}o3v-ve}LVugp$/rߕP'E{%	w;,gZ̈́:Â<kG M;굄A,ce
a:t.3^}}zdRWIמhqZAF8f8FtfN81O<Ϋ/*Q/Q&4+ٱ"߲b炐J,j:zAVk,@/vT*=iK.];Oս[ߨT)Fyшl}[xCGrv1MwJK)гaʏDW&`.3LuvwKp+M{)uRxYikkEx[<'/]gr#*:wɾo+F!O|À7.@9A+ kŉ*813,8Wț}"fv0v5aB@5
Ĳ2"ؚpa%'\z-cZzV-.8C΍&7dʇb	W~t?)&nl:vG6Bڂ0u)JKw&6]a;    IDATq'Ceӛ3sՆt30~0D
W66ͪ$mzP'![("?z\Mq/X8{7+*N~\ 3ƹKYQ͇=QNN*, y[0ŗBv}zIjuɀ(KId屸,;j2Y,Ԡǻblg?%:"gPIܟ終
v[nC|Au:Ja\"
 a-Ed8`cd:e]C|ioo@]5
W"F^HONHzfC$)csݱk7aC
)Y42QqOȋK_rXR+uvKXa<a
=5_Ƀ ,T1W<S<^k50٫_q/Oy~Y]Z,$zrH|ruNif~EPGϩe42V#՝F*)g :
rC|e8HKm1a;@I=ѳ800ǆGeAzC+R=)d볁^q1 ^boR,S@K0ssV/fPjVqBH^dzut^oj*QE&V
jL8wAm-Nw1u:sRa+mHMܯ#Jl9$1 FKRq3_lIֵU|n+0AB8EH*9R I=ݔ&-"
ZJ*^b
FB@].z7چ:?+/+tuP(?߿?|*:hG[ky_ntԼ`!:Y&p+VJ+', jTij31G+Lw^eJefD=gvvX̠KEzV9@d9JKu8V:u7HE4XI茁 bRiF<ӈ^WØcҐmO<*J_evD=ܘ	^eļT9:VESznq0޴$93x2ņ$Į)eGWK_o͓C
o_d0@>xdEZO	kV_ s=}q}J力}z엗;t2|?s?3G}dUCYnhى4
Zj!ttXv}sԒgg[c\lX
y=K,>7hxWXSR#Pl7swt2 g	6_/p旚YT .JdD6qp6wsFR`'U]Kir1s4g5-HK /ԉH)RU1L10o\!y{n:#WRDB=SLƩǝ/Q&5V.ҫ	4<_ʈX)HJUY!暟IE]Gmu:|R0V1l-=}z)hسnCzce4 -2^VC55մ9u w)h)]zHhy
TL+Y19\|@8P[cZS95D2I*\zXSCC(%PsD@\wML0=խ@V`/ߕE_E}:GY-nHꋋBNi|-w`V$ZGcXtQ?MMe׮4`?)lw!|(z!DaªN~kN4DcK~5u2r)H$QSjFZoIp_}>V3*<sVT\WdlE%Osވ]4վw_sF7򢷴v46Z>zgVrw	ߨpIYa+E?]H̀ ,x=7!U辶5oK{B/kb^D(0;vϷ_{d;@`Mʫ( %Sp bZaf$_lφL}e\MWJTjkfa	w%ⴵm]lLgbN66&+~.(&!
gڪJg ~jEO0>lO/3daJV*3|R8U_K,R<u:٭o]4&Qv1My1ϩ!;G	àɘqrJN<.~l޸ Cfi2V::J堥@HiiZ@tM-*(<睹7}R#}|>y2ʃ>Gn@~|!'J;]>_Wg{+LZ,ʿvp`'(E|P-|nEBNp;
g]V)εCzn[rDD`| rH7:TSx]OBSS|^/Yz$R Elx+ˎ%a3`UƅbZ)&uH5zc:P == 2[)TرaxrHa~jEӵ.VZ<+([=Jli=+Wj;NӆR!<}~|4`)Y)Fv}OZ iA6O4x՝`@uޟл_^:{ҹs}}׃@0~sR(ItFX
+Յ/~) Dl_Jkd$e]kv|\+V#Ds
%2nkl()KkÅ\5{u$k'3Bc4Ьֱ۝b5VFN:D'O^<z)5FF:m%
Y#ܥ8:
mhlK͛mY&eH,kp zk&0t0ss(^yy6(pp[Z$U:V
ڋyH,Mk ˱v/GDGYOᨤBC
@x2b&\~i<_v\/?}2Wtm&uҟcvhsʕZFj=tf5)#8F	
kJm[ˢGvClX>Эz9;hvZM3vCS75۸k!o:}¸hTuLOOl1PQ>sƻ\o/a9#WƮaEV7%zd'y㝃5TB!7
W$jkTLXf! Hn7e)ٳsLz	_(-!p
~[-O0yZӇKHq(&geJH@OXOhU̘{.X{}ŏ]~}1floC~tLUչUW2Ri94:Jegg3ٙ{RNP:Q1 aY{8JHr .͒ź!I\#J]⁊ӼfVmmh\ҬvޕoT* Yc[K56(بV(Lru	ljZetOGvȬ fHg)|$\!w\&<QȺL	fȱ(ebiit6Abf]QسyFp|?@o{d+!ry^۴j1a93bR{0_D!uU!PC
6/]I2VxY?[+&(~Y2''+o/-ShӴT|б-tZvQlEڂ$2|=KgO[J>`4J
\FYM}Dن^Znnl@#Xݢ
1bsSs9kߐt. |Z-$3-p*fFÞ4f@1J%ʔ$=r69^M+L
nc[oBsNU_X]cp"3;/{n"7$P3	##/EbsJ.[_ژOW<)&Spo56Yz^R$Y͎W`lyM?<_'o	j>Ͳ}V>ˏ
iXC5=t6#
R-j{0jCFxaM
 5
آ)no23R]=S	uN1LmٝSerQf 0ӂ/THlFQqM/55Q80с~gN'_W봓 <KcZ@Ь! ^>ե05T,]|p1YEsL hXs7@[ˇyL Sopi#$:;~I?)јd_0XI;<ͳb^1#w?{M0+o-ЕB9cj>m"=)13 zt򃟰`|O||fEf3ˋΜgf;T[TJ/5(())0;?M/P"JngK Xz¤^dT/ ?iVvnV^}a^X5!&C6:n}< )nxV^p	 X9-Z
ePkY[/mvN;֙=#:Cx/ՓRL-)XNSѷ"QpVlOy0huwfM|ܒ loh#Pj}>gFZz< *[׹
2@>BkL/&!!q!2rb¨Z'MR+QtH\
ŀx[m Щ]x"6K
|lbyrh.)W uRl8x8-"_,ުpwzUNWKtxNOGcK^$)۷o߼k,dOI[{Cᧃ2F18&}-SV\LQhͲiVRٮ8CFu<T Eh-}3z%TpTݽG-_(DS҈V2RۀI|dK*mK[33wx"^zC./ܖ1'z=b6|YՄAPaWi"B>pA
 e+Uf0h3IjVyzGL	ISx8:CFrcNv	ok׾=C2ٿG{yʛencWRa'>*?~0;J{s):	G> 
["&@3jQCϛWYyB_c`Ahjf暖[\ܝ;C?.~@79
5*VAX!JP}MQMDf2	#}5>y[JЪ jؼ5$nΠ]___SCZ-n-*[{{98̪Ee1*KB	cA
A>*6 g	5t:2,zڌF[#XA i$/{,^UۏbK;٤t̓:KȨ	S>G33y M"]0jEp^x0o+BWR(\9P~vL0-g"TIݸio^mB#tB?tVs4K59֭յ73tX	U4jS8rqEi=AϘyX	 2.=Tp«@ъ'06ɨ6ch_#Heb_&D u -퓠}~=s$G	aq̤PGB#&e媼jBEP]fɮ aSn"ENI!4O:-,H|0Z.&Ð R:-aUh}#vlCڱ))(tEfX}}=y78!DFǭVGS"F	_u ""EŇ.:*a`n'Z/. L@"Cj>}#nh`ߏU]Fc1e780>VSkC2*S*A/2J!pFE]t.w4j&&#Q'5#A)s(:fn,p%]nӲV?>~|N߲gmjĮxf$KM>aufmx:HaQY p8#I&BGWѩ.K2
ί)7-s晀Vh5CdI	jDbXޑKK׉<M{ED9J7l;W.bGƱqK:J? 59e{0N'^
߾+-WE?J=Ec,ыo:@_$EYF>8u
JE&ᔳ$F{bc{{ISOKf!i*Ʃ7uhb3M׊+X5&gWZֳ38(-6*U搧XtgKےhxAX=QG828TccE)+ J@Zp}ӭ[Z2tKmdXڢGt1#F^ɛl&eФX#Z&S҉T@(w\p(ROXɨnM5oP@5e|c(kl)/v&&GMkԓ pG"#_/ej[M&_gqVQhx4~}>-ċ_efp]YDS}DHE>*fDte(Jyt,Ry&.0_,Y*݁w/dHM;/w,tƋDHlXY}V::7/kWP8Tڙf2cf;ۘ,iҺ;m؝Z~r7SFbHfӤdؐi&B^n0J  rQ;E p,;XS6nw}<51?<ar5m]3OA偧L2_kNyH!2-loMdrܧ,^kGP'sV!{sεoNL>qNfiHT!jiiV`ATk:Okr5,ĤT#07*}	by }zP4陛~ҩt҉@,]17tD!JɸkNC\*@6:K,*HP.QϨ|5-5_vubIle"ʢZawNl>.FFSy\0SjU/5Tԗ(JoehW`^҄:e'GRKn;FQsIhA|r'yˣ3[g7/_o\jkk\~onugbI=ՂaEd6+Ͷsꍝ}=o,UЊ"
_[!v
KPjWCCUh5    IDATqa[p]TdA2$5-B24ZQ(+Z󳳣.v[A`,_ ߿ȵɈ+ 
rG1]ʜihGak.pAȍ[}SUgu} q~9*(fmE63Դ|>)Hef5hrxpEag?fU(X0D"Z54oJ}h$uקC{M]^od)p}p|[Is`}| @`󨧇Lq.waw
x3_P?ւzlTG|L)۵[ʽ]U,vr{`8MN\$)ݾ}3ZziϛEQ2Lu}Bz.v`A¾!	5!Y\ιаu5ke?<aF5w,6JHk;w(!|ƻȁ%GQHJ ]J5'~NӦsV-L\lm*Wx).ūk>LI >-/9XJ޻W/I5(c-+dqUЫL䅢+9Qӳ4M5)hU\@~"yJLu׷}Xj q?7<::;v7sZ[ȹMdd7_MnO`
xV?}dV4,[aeZ]KVw]uUh]"qn3wWpGj+
a|]./T׷<Mb^Aq]$F,~3rl
1cildZ17hvFykk08}5x7]DvDLEHDr2pAE
`'lNԴCQ4AFsPo#pz.GbqF񀲾b*:ŷ1Ɩ虍O{ed),n}R"f2ҝZzVnWr6蜌Ζ%/2ի\e]C˜*V&Q *+3oxCޖ[a=-}MDJK(r`no'ymmml&C3ln+fk?S_mtum0yUyKfHixϥM]Du5Eش7?ِ˅qơtyB,-﵌_qEEYE.&zMD.뷶RB&diT\`0cKfy#hf	êwAVHBWd7aIdҘFѐ1E8dv:Vֹ[oaf'sCZR/'grW_^F_(6&_YO72L4mvink!+keZuZ	LbӪy)
 WvxT(L5YjOUQg=ߒ"ʕYz7b&15jQ71<##UO;gYNHV-YNsC3+F}TPxP' hUʶ~<K qVB8a$fXu?(I\.݌ۅCdRQu{o&[	qQ EF[@-b<gp\|n@dEw\?dvx|jU*|V0:%Q4
*0*3"+ZK2:@p<JC1;]gڜ*6>3en` "@,eKg՗᫯^a #^ziy{cpZ]wk49[a_n.3ִu$39P4#IMR_F_QoDҮWW`uXWs댽k}_xt71|>y8)`fGSYp7\Y{^
`Y2ܕj
"Y <̦U̬g*q,!R--|ڿ8ͥ˝ֺZ3-X چfc2itݻQís>x!Rrg.}3p:Av%	C&!,$}}>duW'k8(ώ(DӛpN,8˒[u(\If^dNQO^5-ܳB.O6%PǞ5faT4૑d*,)6%#FwvI,D#~i019#mv2!Z=L-p& .噣sr_54gQ=$9peI-[׍8(ebL{)0*!k{%塵+R;\uh]e**
%W9ta7X5u7E&r3
'YDlmƆo6œ-/{18Do|FrƸilJRcܹsmYsEbM	SqأWq2#+NԈy?t+GU`m*[^f/t٠l)wRsn&%GdF6!>eB|PI8FwQىN0}JC? R
|-4;а\-e296C~}%K2$Lԅkk ]F8(ba>KbENQćUۋ5^"Dƍa2B_0&k;FcM2~Z:%<L095&9yVbbPr"ґ޺B?4u(] 0Q()An["l}-I[a<.9Ɖk{M؟t6ukڻY>=RF]751醆FF;WdLZe=w'UCq853 +9Y!F<\yB<Ub}8gfe0BÞ)7D>CU5U͟;[ g!>.$R_-XX
ƺF͚ȎDCi=kxA?TymZ(s2"2d2%1T'cc)Zh!9 v&j(4#k`0.{Ŵ#t]q¢85 ~UQUq/S{ό:j#\mٚ-7'٦eK}
㻑9O/XmEwTG(>FN_zK,3z¯IE>WLv$-ikMWNooo{_jxrp*].Vr:uW.(ၑne!h k?l|:|vTÚx*eD6Y`Fӧ\vƕDWgYԑVуRn8ФA5 5BF:?!xsJ5hikmnR5>5=sx"dLCހ@ *أ|#VvԎX$hj>pԖďD6t2ڦ/L'Eh(H,S:6'.]nx"pɰއVdK/U^}"$:vl_~q\8YE^-&KSCC0M:OKe?
^~DxBU\r W_>_n3
q$bܼ=Y?|{<AH7u\mhܼh  K{;n> ͢ʺOMUEtPF8\b̻F&bN*uA!H
RX&u}ٟk9݃]#N`DQY0<@-cbB§-TVh=?*>jm15 RA޽XB0' >(x n3,r612SÈј0wD˅z/ɁS(p*+bqAB*[j)`ګ .]Uhr2EcQ
U$E6pWxeeJA VR¿_0Ar^
bzERa_(𑼢%__-t57͍Tl$HۛoJ֠uji Zf{s3_,[G<#iyUV_flp|RhSg<jxL?D!xf.wF.c=e-DpD]OyF_D0a[2E+ۻM3X8_Ʈ?⡢y	'(bq&%.έV"aP&9Ō5KћK1,^'핢}_[m)m-?lIO[(!ns~m-hh>>y>GY|T>aEMm7 mbi>lA@$~70 I+R+:u+61m.>1 Z	BW^Ea~QxhEW{քGWS(!u>-7\{ɯ=x2F?mQud^]VjjRJM4_$\`V )+Nv[Z)m)-@ѕU-7qQڠL"(?IvpcR-d,{㵚OrDUE8p7o9VS\TIǾq0 l]aq8T:JsP#NY;!udeԂ>aRE+h455	e_RF_42 -|F&*&:DϝM	 8^U7J5
Ʌ5ä(c(M=d$^ho/X.. mEU?.=X]]:@ň!	LL/~y=b{t,0 % y]',HL-íds>l{8p=J	Lfsz5'Y۶X/65P	rErt󲎣/~}(ec'4>hQgRE\$ݖ/B&Տ2]]s{\<PM/"L4a>V-vuٴƓM'OgrVK,u.9&i	4s`5>#c.lc3R]X<$m#܉4=p-oT,fTN^u#{MeK9*[U}Ż):'5Ս\Q'hNTl2jR2A^}  LNbu6}	/c~w)wXd2*B<Mn!_w͐0͗utCaUؙcIfR]W29bjM0m$ OmIM֞
;	$|Ыg^a\"qD`gQ6*z+>[>h85:z䫯Ef؎q4yqo_tpvV><TBOaZIiIśݪn0Rtv}FOՑ#!\.׶)}Ǡh!AO.J]M#*Thf؂yOf4U/Z5\gkH91
IK7-GFWInhsEʹ=c
-6=kNG-%'KA7ftJ!NKwżmNF0AA	Z50%v!?&NУ+eWlM|~dj҅6#cΝ,>wˆGe銊^L{#x*Ȓ0v
9ZA+5FZ)ӂ{z}V^Trſ*]a<qEx$ z4b[yTߒ!Z__:w/g볟}э}_gs]EMEW+K*+KknݽP)-?4oWv&c==*VRIgcce	r H&2QI0GS;nd5;^_/r;
TwdCe5sU(md,-^\(a^| Vx~sm)SݖifgZ>6{Ff3O:b?XYy	=Li8_%v'2	 PQIdKrtB1[	B3j(|4r!l[՟eeIcڠf9
;"GAaHQ6"m/eĚCዥ1-c㘌R8%ٰ8~md;"/&Y +mD/=D^i43"(b]VjE(/۟ۥRG΄tf:⵶[w_բKWOAU'@Hkz;ϫΜ%UT2	j]!%_  ErI}E-A7_Ur%Ao`LY%rs3	4#`&lup?m=Y(-ݢx!*hnGQ0MU-ئac.+idMX*Ҝ [땱ѥ/|+Su52٢s->2l!uAR!M7[rs*CHщ܀=P\33< ]U:.X_|^ 	;<kuucILGlOvےbjIÓaSiu_EpBB#L<4T7.
xCkq\/MĶ  v*D&~~kM7	~rtFfD˞R}^Hh7Nn{kIdJ9"|b:clRD+.]x~m΍yXLإz{e z?6
LNNL[v߃Ckkgw;NܯcMp[eWke9lnmb7'Jgǧx$`+ELSI]bVV6uE3||w&,qۧ= j@P) =YhF,ChGť 	M
&}Qz&1Z)"?nYFZOZopS";JCyEpmj2cPE(nXw\(W̤3Rj@QD(t	F.24ΛQ=5dHck~4,VJ|ቤݯ;)P.ngbpSGoO4d;`h: + 77/Co Zp0)Ix}?߾zw#mߏLN޻TyA]JVxGםֺVziu5YSYQsĪsXWY䍢QXl&sVB(ЬIO|Rbm
{Dbts@(7|j!ɫ
Do.]G
kYԂ.*uځ94{f^."pA]Z_Qo\Dt &Y8l0EA"k`ӆBiV 'U꣐QۅalqL+k	8\6ZuL ;nX^jo ]Fs2L!z(\D>Jܩ0qhYʩmG!52OfXBf+ZI=hgfabP]XHnK1    IDAT)C)(gׄ@c${`<ELh{U*'&&'_yct,	-jk)3Fu&[4Id*5gΏ̎wUӒ2ǱX:YӀ]NaO8,pG
F=
}k<^!9O6ñU-C -P2<ӣՎ|GR襔iG3X76L*:hS_c}Zwx`CkBzLO8HrEme]r#Kq|jv?D\׸s߉+ڭƀP@?̆t2- Iov>`hf:ij78yĸaFiMef.4⬴hObU&_RXJ~%7ĒXQr;.A~U>_h	'%~^L؛!h%g^}vw?샯6EC[&&&WT`_-)**)-|uSz|O6r5VA+aɤSr9[eJFa=`l'9$DҐ;5w}yt֖hy&\^^y$
ų#ӟLBt6ZI=Li{PgBBUbdpy߮|6 hT*^X^R被޲zڌG*-<<2\66Р%(`@VG0Oawɵs1/I _iU;Ϻ;L0IҬ>ХDfEgoЫҀ7D[0Q<a aIqg"87<A	c?anJp	ԉ{2?.Z.`,HS$܂ MqvEY[/NdqvأvGk?ݙ?O211dJάhW}K(Riu70q_6]ǠOs-f	y#lVƷz|]vFpdj␃YJf2Gc=lk0<(׆4lڑ6!/kjuQ$A.{ZrVD5{=k;Y}-B-nIa
7HQI[l:+u0Ax<YK;i _֦Vc1,'R	Y_GJ]euϺVsx:B9` [ϢSk>*V5x3Ϡן",82txVY:fA⽔+#m8tcU3itO+pJL']SQ玨`"^B퐡rr{y~Zn^/olő	x?a{P:I^DhŪv}X|W.u?,ӊ2̪/PtzE<l۩5L&혴ZtaN2Peu5qA2nԙM
&HPx(vEStE,r@2v
(Z,09x?]ʋ
!t4
઻]csw˭鑶q.F/UܺdgA{^,X8eu6hcҸܾzZ>VlB=iq(+]N΋+CׁIv(e]_}tjbk_:TNlDReBWVm$8?0Noslx4CF: iIi
mHyV [RSdpy5mI'?+vܟ	nNY,2ķÕKfEt558BToll@PaHEd5(_PuT~l)+OFÍ 8["cuRSɑDFoKT1Fx*2CUXQd=.x&[כx=&?Fzư◿~խ~K-ЪE.Wj;W[Zo}PUDQ4Rs͹ʛ}}E0XgSS%D0d9=(stנ: `VN(prSVX-kDRgg|*z15]Aun\tI'ZUaBӰ؍[>uvJ+@_dJݰӱH)ڵgl?Ǘ:=&І7?lKd&%ԛl~ )t8o
d`J>`ޖJ%cmmm:;SZ|%8;̹SW/mZ,Cip)^_ޒ&T'	$O<USIsiq(HP^kI$1>'֖RNbSAxЀ.3@+ieu`"kRWFx}{ۀ2O%Da|C+_G\ב!Z6i7lX}}ƗxV>lrɔ5󚲢,	jBV^I+{;دVZ),间*E|'O,]0y 683Ȥ8.hϳXi6d(0ZBtoE.sB޺[YݯFLGu|D#o誩zLԚڢAy:LnlDNPk??^(	hB7r\P怿 3fp ?ݣ`|T#VOV}tzG)7e%]J#QF:Dp|l@
[k2c]#:sJr6NWxn)񩄑|O>102
1[aſMOXӮ;> ⊊B"cs~BA~s~sÇw&>d@qMs	"F*/**,,%7}<2= 1T=ڥ~>Rw;:<O6䇝,߭y)+{kzt}ݸ$ՓE\i<k(r<*ኖmir{LzJoDY	Zã1 E)u6{BRaA2m]b@^ڕҾ#tu2 ٞ2/0Kdp¹ΌZ

%25B)W/"Uǜe|х1[58q\	c^|80R,J_I26ӧoGkDk"c[CKNVExie&rӞbTz,BEFt#xx_Q
uSѕD?:>/֠wq{[w.?xP\ڦ
U\fZ؜Uݯ"źb9&5t
a">qQΝ1P[r"97/1XW
tSS4:<=e[fgý^oόvp#/F(򦦆9Մj)ڱ5PAimL8iTp7@+LwWь;"<M 0l@b_ix:CQ3]!̶RNiH %z!(y,1q9==aʶ(@+UGuz=fTMqdxf9
"+O9l;aВ2AYQpAtBr.%tdbq,0qֱz0<9h`$6	ғKB8IJӇ(|AV_b l]#$|߹}ڗz[xduMdJ.RnaSCCC#vt鷷W:eӧ:osm;4;Z1Z&v^QH.KZ&"lK$b'X`AP~*E*9&殹xg`y^~>~qUFm3b2	x|(T:ա [Hj_*5<5-z~A/W̌E9'(þ[R	
躍SO|exXskt5^l&UljTp; x/&pf0U	ppvw;Az%ZVQ.R.=3#W<1bF93_[x҅ŝeCz2VҔH$b S@؜?R~lR+W;ƎY6>Jä~{?HYy1e@{RБq-7tɪJ
^H	GCrCUn6E*U!k9<gS:gk?h}wvuw''%#!ʣ_=nԐH57(Db`@˵kՄ5Gukk:6OzǱw22e "i/*㔚i|*c/=6i
tFf/uh:v;hT 皗&[|FNv~Ec!l|tܢQrO[-TM!]S*=G"	]3:7t@&'unW%V -=o2ŒhZefm+ŘV-T2'. VǢZ8F>
YYqy]nNy."^.cbi񢰰D|ma !0i`9HĔ!0{p]J;8|87|oћ]@2.^LF"vLhJHKNZ$m4~h6\!K*8J@}aPƹ/|Wهkmhjmvv&"HrZ+$CiC7\l<76b4YY6<%mR)K҄nu!plV9O/h Z}tY	`qsn|{7gE8V/XD#kIݰH, dЍav J{h.iIi}<8 h1A
ͰyEÇ#{!>Pn֚9M:nw}qYq,xjgٰU1 Z!cqBvO*eq&`OŉNEU.|g8sx+GI.6|%uX8>A`AuTR O$Iօ.6L֫t7*Yi/<շo޼~I`r![~Jݿ_ϯQZ''$kmuu
	[[ع`%j(N25ա	X
bncWzoS[W;NR8X,kRڂij[`k,(ڲ@|CgOȼmeDS3K xN^/ ]	lhi$RɌΣ{N$SksByv]j54ϳwqw!e?hO(-Ăa
C4UVLTd	K.Isr
T/dsX]٤1;}X`!U㞐{E'`5>V@
Kq]^hϓ;]# O',ŇV9)τ#յ1?HR
d 0]|*t?\dKgjKeZBXt%kkt[WXγ@&5 Ul
BVߟZd][կZFGG,en2[[^9Oؘ"+ta z>Ey2n0*\d@˼. Z-"ܯ=L'Ҟ;ء%ʊjRC<۟7Tvm2%ʗ]z3\R@p鳵/+F;T,sf3~yE-Ɣ˥us.c9']S،	6@2rrs\7WfbVN1E-,lƿ"F")=:wVX)>-\.ķ6b_:]~WѓN#QXxhJv<{hDst&21:hvJYs)F|\r2VnBe8}ؗ{}Q<LrM|STo|5	QkӣCɑxw]LЅtH&7!FW=RC&WTl,bzW[kȮWδ#C80+l463YqÅ%$d%u7B89*esӡ|]_ƗʗR''C*32sܝ{o }δkK/M<07{T|KR@/0z z~p48'je2<y7*&uxqqQlNYx -
&Eކav`/b}t@H˿}т4vXha02B<?LIC*[4dkdq6t'&~z%>_oGZ>ǓeYٓ
%c\x@][oK&O9ɃqH>A1f83`2 G;ZM.hr~]a6qHHg/_PQb,mƇD[?8h֥lSb*λ/cݨT֞=*Je/rO	~x+mKzFx2tA2FZ^^~	@]A.&em!b -=="e)Wm?xϤv=]}ّ94j}ՋNP8,Cn0b8)XυF

Jb#V(SLK,V($ PR^Lw?q;~sЅ]cb38SVd$455EX oN
 Çm@1l;	߶WCl=~LFa`_g=1qƠjkIWbUx-y1\ё`v(U+o--=b`S!̿b$iLj/]]4ڧj.P[{CXqfNl|ۥ\=+ ϊ%{yT]OCuhU*p߯<߿)8:׭y^9fS
uX]`={hٸ;Ӛ÷HI_.a0I
diFc40#[أQ?e?Y$iҦCl-bNV1dC+rtʸb7*#qMlFUP|o8'$5YINΌui`J/d>io1_/|lwh&Sb67o$GGv<>5NUX^ܶc1,[@.ڲ xm"QU27ZWA,BN:bwrBOB5/˺.-c
O@$E'|		5䋩le2jp3brjŒ\%MUxD
²ք­O?)+-^hpyEꂌ xZp?mh^P.+VR7oi4+Vn?כi4*Dl|C'-NWcor.A{4Kn|snhɃe׎FQV|Ϳ)B8t#`P BAo ZW*Ĺ
!ަP|p,n>Q"&hvyoKoCB    IDATXB'%1~z9L&rmDNIx7$3B>?.L'HxKPa!Kal>;ժ>']aN6qWB _ϿDd%_oU^(NbahJ*5[V횀 Zk\:` 66ФΡK	z2GY<--]xf+__TΊ*`nNJ[Ueo߯^ 
qVe@>k0[3u!a-VE9Ҟ0e4nk`haEk. bhinFvpfllUikAW7\ku.=M 2|R)/߽;;Ģɲ +`*5ᤪSMl2)jP(7a'Htl5<L$ᡐ{Mwy
^"I袋@`P:G:̭1/Zceө"BRAY"kKPɴmD%Q*gQ&N	p@.e޽68	1@&@Dr	Df [htԿ"phud dcpKL*ȖY]Z{]tX9[E/jCg9>;%%mhmE[eFR?X}^^ZT~lU_;f..xGuƥ~:}iU?2t*w/2l2?ouQ&YB"2
[^Z9꼽7	!)0A!B9#woC0WV<Ҭ6#lc\8n3KZ[OMnZ6Sr|I~PH<dK A
)<)xEA|	fѢceI>}? /9}&W"EAe%%(H!_ G@XCۜ-3-ֈlcHoR$rv2bw
u;AҗƵ2XY@zQDLe>+o7-\ggxj'pZ9ԏ{8&׆JL klE(jh5-/GmmmWF-4O?N"iu<Nro|-A䧴l,^Ja{\2؁tdaK/mdp\ҩе1fΜ7ʲNEw.X',uUpjʅ{Ei-Xx	չ5«{'T}<"BApy2xAezaEhҩΞNWhݍﱨVoF((	sv+$+s&n+1nsaazzXh~]
!] X/gR) [vT{D6Lur#QAˢaL0,?[fP@,l[ڄ㻅,*K0*g{YFMn6_OpAdեɦ)@,G8
c9DI{ѐAkmD%]SJZ]e]RxJTnL5+ M.EB x<-9b1:!ZԬSd)q_kVGx"g6|KI )yؔ,sΧEVɦJnW	s;r-&.Gpa Xxu!Ѫ#3c=@`aa-Z-4j}ŭׇ\޾9WFW\.wӎ_0u{ f?һO3{zFx#m8
(zs8FCc3X,u˯;}{털گ^unā&^WK!GѨVWQ[y]F^h.ȼzX	p8r4ݞ9 O\Eg|Fd55ĤU6|]->6Nĉ` SaiI<!\ KCr;n+
+I -Hu39wONAohX&	hUآ<F
@_Ax-Vkބވyl+)l_U@vQ< ó\iЮoٸ|Mr]FZw`Hx|E|UЕQ$YϵZ%+
WTʂ%oaV|/خIuF 2zਸ(oӐ=-ԮEK?	r7ͭGD*sb{Euj8co[p>y>k-?.v+b;}	ؘjkpA&zh>j%m jRА.H(rR*H\4lSwtjGѵ.3OdYFPw\Ϯ}MVFGX$I [g sK4$gf2%0UhGBiDz=ؾrB~H.ptEAR4ɣCHo&e!()[Al8#.BE b5%ԫ#߶ADT?ﵡ\U<V2@ԍDuLJ;85X{Xi	N+CW?=g0,|0Ac?h
(s-OCZʰUOUq?NJ?[{0}|ssֱ6{_u41VsQú2۳l6ޤ7Jn25f3c{ve7`0[Y9 .E2 /\%۠xEM&ATXB#cUoi*]^\v0q&aapPxRsbڮ~.2bх]StlCg	Kbp9&oƽ *̜
T#F''P4bUﰾ!\xl\NéF'(˃tJ-S)Bn /sys Ya*5l6URtj0/'7)X.D\!9'^ .T笢.^v-fP/b@$\N'[ŷV>"V}&uv1ii׌u2,jWmw1
ka)AlM6uۍp#	:6ԥ+Ǡ  Al .BEL!i^L3}_@I48?y<ih)SHAj?囗CRȃ-ԂBA-ò姮H+O?R6$	NMKFn^?|Bbw_E> 7@hdBMM]]]ee5BMiM#3HH*	I۷t]"A:.?=5La0:tj)bir\YFԁ/ttΆ\b1W05Tm-H!`0h;rn^Gz~6lOwHWlڿ[1t&	]I	dڤQ$RN&2g49d̩se sEkρB.m~K[ /JċNڞ[yHp."aOKu%Wy5ojks|q6^2<SYE .Kj"xO;?

S/+Ⱥ`|?ێqy5?a-OU"Ӈ!WJOÖHىaޒ0oIIɳ''gΞ9Xm%s'򘣭GGe]/hi~iDaQ|ZVT-z]AP+W&DTߥJjWo\Ez_@C3@Ngj*K٦&bG7)X!AoXv\P(`ـ
n}L44Ǻ|@XƵ|-:2uMpMuyz2OtyZxmCq8.=YjzDIU\-Z&fO-6=@5v%0LBjZ_oo<.SH}F<Fw~OO}y1i+nد5*8FGrdz /
.{hSSpk@1a|ZV;T-lTpB0K.H_VᡟVVb6
"߿m<+1u흚 \!S	;wo}TP0=h#=&<ژ ?f-;HypL'!<+{I,8uWTQȭ./?zt[hd5v0$\`4)fIمU[$҃Sz?E]FkJ~1ff\~/7ӺܴJ'/'/R{yC41ä> rsFp)eCqbP	Ro;,U5 \青$&m͖'N{1g;yQ϶F_Ps*
NcLe'":آPL@W]̖;-XgzBOFD߬كּlqZ.ע0xTb.p;
	ǫSToUmn
KaU0DL(c
cP#!_r>mڈ%]$\I
3ߕW
N>ڗAS+)	XfrkvT쁨|ɒle|Y&i&-[ق'[n1qtd>	./9gEϱO;YvkɴeF|yT%t]oe=K%5Xefw}w-p珃qNfit:ZGv@$zɻU׋Dr]tԞ龐)K	5dZ^ZY5/icW@bp'Njg"09i=1!tEBGG68I\RuAYRZ6Sr;">/F%7׫1R|Iz4'`Llu=W2rzZ^ <-o>L]Fĳ"35ϦX`B"M`*#"^SjmpE^	_PL QBgn֣̕`k@f5a].	 g{)a*cT.Ja?ف/<ty*^ٍ~V>	Wr[led72,8O5Ѝt=l`QaQv\`%έud˭oXatO,pHKH57gRU5c\{U^0g~;f1H|lS_,J]LiǝfnMfLfti7N 4&d/MInHla;hPd RPDA|C,U455؋VNqǛ7<?<<D
Gd
vAB$H	9o0&*n:@2.C2""uu&#ǣ4O*(R;(}O_Lؖ(yϦ~}ru`5m.50 >ӕ;+Բ4Ycw9]VUj3v*feV=D!lJ*rbQ0("s7'٬)cNʞr lT=۶uh7n4zW6o
&=
;C&\ΗlgoKjT5<|;lơN&ZVI<[8UC+,.^q]3OC(o^f2L~\ـUk/q/?䆧w .C|_npjYw=l[v/-i^OӋ\kꢳHCřX1bOKX=^#
뇭0+^uoNcWOϾwVAi6![Ӗ;܊j4b!*9p:s	`0$#\e[";0"Y+-V4>O;R W|*2dm*/fq&7M6CS,=NGӘ){z8UqhGCR0V%K1a ho(k(ƕD2d>#kB<H	e4e#m#Yᵰ1^h0ynL*`j}Î,A6kVV{'pK+?T<+߇c	ĚtzkAK	.b$^;]`}Ad}}9᫧\rUWuBZ\u25_U%ڮE_V5ߍgc2nO݄e;kq?Zg_ݹbH*a
{XRfBG"TsR;Q9$
I1۸
8
Y^W>ά3[@j-\&+-ᲨD6o89??HSΝSR城20]R9d2ht
٭| QԎ5>a|Pzb1.1rт7i:$Albh]oe+ Zop7"eMM$}VoGL$6PSnu}цr>a
IIS#Gu\(DzJWZ8R>*Uج!ݸ@38-#6T^-<]JsSH\m
pz/~i7ìoL'W%cIv;ZNrల<`,oh]ƚ`㠃zd\%rkC+c
\c;W-U?>$NRV*G:Cgvgsk;Ǘ]>&T[6'q?Rk?۶_/.l}cEa@J"h령(}܄.h
QStgҍa=1U8 Zm&Wծ@k.Jt@2xu10A1;Ì@$9
;&0?;E:QyDcax":O.ʡ)GX2ƪcJo\'tR{E5Ÿ/kEhq>"b%OTdZJBlV1r[`??.+^Dh*!@'= E@$M^KM5),+44?vhܶzzkRȞtЭPbX®Arg1Ɑؖ!\Iw`K4IkuJp횗:o%MK@`+YXK%9 M)GdGj"p[k<]y!a/pt\o^_7oj"6vOpձu..V+OF\^W_eqQDgKasLCt	AĐJĵjl~fLaaḰ.vA}8)7X@|kk+ƒ)Γy%Ygⱙ">'Q|G(0;vcG<P(kNG    IDAT4,jͿ"^WPdy"S?qjc\ϰ'8vҦg&=1.b*,Iڎ[7"Y.M	]%EZ)ƼZ0"*"|X|4FQDhLu!H뾯E	M"#!Ps:c^ 
;(Gg)B}O=()ҰݮLW(La]и"BynŭpjXTnt0'܇UI-	Yɚ֧ccQ;pL{_/pk@&Ȥj6r}+IEQcϕWٰXf-BxBwHUT!hОP(
z}h8mILwxW6gV&S
ӕ?+ly@\ӓRF g)ܐt6JpN`ZƧ'tO+	+Kni_:n/sYӁ=oL 0Jrl<d*%ѠnGo\4Z&YSrWZ盏
J+)ߓ_^p$l67lI1GZ'KLG8<%,?mIfK[|Hu,:s|#rqTmrml\ Qxm(B"*U3wg(ܾ.RXXD욽p!5kSctUTQBR0.ƛ~vkJfNsY$@P}]ҴH)_w%`#=tjrxٷI )8dgp<6.0$;\e\.|Nz5JeDH9DW _BŢ!ʼƵZfp
E}:>穂l(B*l0w}S;gNRA	D.p (#Ptx^7<>GY)CLK:TS9qZ)q?X]sџܙ0ʡlrK8$):Ma盙K#A.$=w/>wpwʕOj-5]XikWp¬YQg0MKbC(t\aJ3M":0tM$gjźP-W$U`$fTnYh9MuwGdAnztFN\Fp"WG"բLa=D^̺`z|ӱu</om"%BYn5YZ\8^F0ѿvtSih2uxJm[_
PIb}-Phۿh\1Gr W2V>֏-fpU* _AS+5" KTiq ]]GrߧX#~:Fik/Y}eݜi|oOw;*Hl2q{T	TX,|O`:$
+n$yP
^O䆕EURlW'gys(O~QVb[*/J&:ɒi?3_#V	`.' \<&IB"fF(B(JL2.WYJ~4  p/fLM&oa2bp1$ǣt^{DD(tޙ{ۂW<)Uy^1̥뉄A-,b{X6yc`?\/ej2)D*b	Q^Fa"fwjM+_ leǍNS(f3{uS64=ʍ<k
ABcV_XTJ#qB\<{ujh7oOYVbxi,
.ZSB:`xVc>W7
j
vԩ|s[	N/uoVkNi0"x/GIhdrM5h=*[(`T%n_}W1\TtҸq ",x(ERE1 ެ,E|e}|aqIuL[vdx3>OadHq"Νds[/I1\xf&( L

HW r0flWWyEr6pfٳD*87nԨ4
I@~Kdbmx@Vq8hUb1q*Ԏo$7Ӹ(RҊaaij\¤ZF;Lc"D',MuI;M!&A0}$;N7w7,CBL6K,D0Ak]T+ ?, W\:JUbZ7|\7獆|~<?j<z<Cnz_ٯgei+ۉ\`!bF9^59OP\E66v&6!jз#c6s;^li?5gJpРwbS>wéK afn#v 5~VZ4B@RGq5OOZbQy|)胹wSnuLAKL&ztr;^[m~0g'CbD59o7֨|k[@n"dE"Dz^wBΧZ4_U>+s϶DH.zKҋƕ2%L
m([Wnrꚴ=2L>$mlx6/	SSsN'p:iD,b
2 j5E[b C.sp/hwKsa#aP8CaO|TH4:}O2}p1"*3E4ޑ_|
x"Q,[\JP߮&ӫֱv\Fl22W@X3B .Q(\ovM.JO^03D7:,QФ#M4LW Z@w6>p7e9mJS[1w2uOޓ{=qRu+%|	(lu&H>RjImV;,u
1#dɖ2ȅ=#22+A$B.npy(R=UZ
ʇ:]@TjZigXCCs x]ꪉó".(_vHdD[ݻ~\AgO7)\[~AWUYgm}oQBbOG2R
([[~s[ ~*Ql<DQMS >//"hhT@q!PFIp1)W5ăvpytTe}Z;jW?s: HU;Jid")`~K6ć
EttP [l}cM{kN^y.Z
s Xkp[<]
U,p&v|)t02P$Pqbu臌k+D
нv|l<nz ]s0|ɚ{ҜLɾm/kv7V*NɚWtc ׷ޜ{&;<7ɰ-dh-OVN0'Z;wȄB
I( 9#vm
Ol`z˟M{ŬhʈEsLr:]Scn7V^M"/%:u/χ2YY/y޻7WG_|Ž.Gxt7p"SO݂M(5.l&fQL!oR)hVBC-6,"QW4/& ^!iO^ .!+Gh\.GQ
fuKo39)D$R贎<HA2LXg9L$-k}6Uڱ[MJA@KR.kįF0ʩCjy+3Ql)8ʖ2lEBhJd*|on
t׎JO[~>Pi3?ûnwfw9fLtu-.h]= Wg,Y.|>(]%;sh~$ovYcwgpJIp*}K&V.QXtvb*Xx_8:A3:;$FU,P1@Vfq72=[kEdN6 XwN5Oߔ^KiCQ\_]tY{^m3&d>45_?Bcؤ-F⹔0ph	ihS/j+ PRkFqO< 3 L9 _C-{Cc,(,taVQxb/;,<Ģ5W-)J%Kʢ(!bPΫn˕HKKG$a1@taWfیuqvYbV3WM\44E].@]B_kBlZ6H1b0
$
E~EQAi114M^l2&{Χgv?!$r̈́v@@*>![SJ 3j,h0ڷn~nb~;\^̖͕#mdE{
Ďq^zKa$yX=88p*_%%cº`Mo!uٵ|b_[ѡݺv-XdY1Tm/IZK&.;9^WncqMNAװoq_:CgPӉje)|\
@`tZ+F|+	+\ lS{$/n}y`BTc7⌃4~@{M^ly`9g4D
QVϒ'lR|Pt<":ԥ#:2/<]P7>iL;v3]}]p_ɸcѥD(cTpu6K,OA_Mrr@)dt Ɂl11 aCl f4Stz?h@QjD|qcF,KFTK! 6j" %(Fq3sc_6{wOUdRE:akށov/&^:VO}yeMDzhZz;qf=fƻa%uia(PZ|&1 K N'J^~z{cnQ+bĲ%~AБzY$׆VY0t1_	 ށ-ᒛcZEaazŠu9[M	ֆa
VZg@AZ?bJK?~cާ7)äm0bqֵ;uW7ZBo(ǣQZ쨗8I,lZWk`5:+gwrO;:ݾPk]DZ`pSCע|SX,/>74/:^!̌g)LA%лڻN6 4ߋϧ +> 4*M">%B+MaS,=1veLLE+HnpM9Fon'QTœ<a
9B-	iJ?R:x4>é;&]FlrL8D_
t\$JC;,l˛PkΛ6x<dҳd9n2]_ĈKlS /~ 0 A7yO[:.⩜)m7ɇi. [J;ᨯwSY_ypNgPOp²;rB(m`RiY֧;6싰d02bYȩC.'O3n;h6">cPl_of2fyD.\K]m%ΚY7VT-Dr@b9@d-H_esLKL~R:ۯϡNy]v|$aEu'>N@0x+-5qhMw$ij^nhV33JAgM1lpIJnEWj~?j~V	]1sQ"pLPRwz+ښj4g1gaI5?ZWNeaќA"0r8T&{y"B۷43|\ƀ73O PA<&B$BTO?LĜQ I]nviþ:2LɈؠV*|v7?=[P-Γv8x)aO8u:)W.ބ7V=:\\U/zH~[]-[DbeEr|/xlSMZ+U17n>GhtaS'k
@j9ib{-b4OODd34!Eq|xcCcpJkuW#"cYNʿ,
Sv^ ]e?>8PׯZR>?j?"/ѕKUUUc
o
uz	Eϖ5Mտ"ݤ] PE	
M/4/U }
 VQ|T 4ӅfNOB&<,C_pa@2A'.RzW+ZBSbK7Zo46ܹq%
r65nBl̶ϦV8)n')vU 7<2RpE Mf9@	8-ЀHԸwt [mX2DϦ7Z8"1Y#HD̀9\yM{uX*
I%׿/]WfFmJ1&vH
f_v3[J47d@"ZlMdLSZ]!nAp)A-(%
U0fLGM&@U1Cm<Dfl`ЮhXПw[z)>zcs"#1xpBeĤEL*qcee!#g5;F]~jƁe*+=2,1VAp	&t22Y1zYa-{ПiϠ2>hڲ-LBx5}k#Cr;d_dY$2:8&b'G$\(^//**.^Ua!ˉÜ"Uw\fNN
ss.M?k92>rJ_xS3:yZ0>~ ,]u"Z/ү'|&Pb4<Fon)^}h$IϺ鱧1ۇa۽kA(PVV'rTt'_>u֭o|p [4bo˭1)6Gbe 6W;Xs׽<ư%nNGi1߱3ht.0J J4kX)z}(ܥz64r]|giiq;dF6iE"XJ~* |]$bTju_2q(bDbr?e3	0 \l/M1-"1O46$:5]\=pxVZ#ZV>]/u /@SUS[ǧ߫6'PTΩ66
{buڪ_H8h
Y۶򂺺ªr׀Ϳm    IDAT^E(gu%ըOo强iӾش܊^TU\XASmE4_՝g)of2imELZ	!tydeX=W؝ysV81@s%Zk3 aj#0Od.ov߹ǖf@PHcFfdFLzR5o0܉AGbq,T:@
7H~^'{e`-&RAHpp4&?{oxlJF2Pqq? .A"	})3spb	f̫ިo%1<N$XJ*RbJ,${eX\{d&TO,|L'ƖzdsnV2Bht83iqTkrK  j@}д9=9Fc#XqVKL6ͪp ,d,T5)ػk,IyIW%7<=w(?TtӰೡ.^֧6iIsl3i}$ݛ9Ix,HE+G[rJ1Iu!~b줒ֳ:eȺ+(i!|׮cPj	.DZyԿܺ_ꎁ'QqQw.fd=AgtaJ:@;=$0멮't1BPs4n+~/1,<oS*nkW%D֫È֌2M'QfEmҔ12TBeҭ0kХX`*o[\"@Le7!m-Ebˮ\S*zQde.θwh;00V\RH)Z\Oތ19?;3ذUV,%_wvc.Wmau>w砍O "ޮf:Jf@cL;Vl<vMCDC>ybdlD՛Ngz{2¨+8:SxU.)gMrveyCa~u:.rmSgUu"Y5'/yZ|ugy.'R 08AL+נb;D}2
Ob
vQ	V6'2Ȧ7Ψ6ĜǭTR=P!!§?}nNX/~xAm@[;;;Yx<v5Ozfga;MO*	zOixe/O:
0|xPȡQT'lT lߪur'j%HrTɦU!3Ѝ{Q$&a|L[eIm62DT>d0vh<Խ]s*=`3m%jҨ[8g,UǓl(ƸR\X\GK/OƤfqk͚ͬ1ۚglL5f})_P2me3\ e-Z 2BKx_|R5FтLӯIey7	=?9gaUA^u2rg>+qj~J
'dpŲkcA&z/lJgpjzuwA[D?G3s .csi4)
UV;{uVEbȬbhwٍ7rC. .W$zzj*Q^8?u	_)oU.ǭ~RJx9lnU:w/ڮVR]I]<)	ςw%.e[o%(SPuie;]f_Lh_<dϟ(u<OܟWո!xAZdH(tyB{~}r^P4n
H<&yوEü~޲߰<cF. 0L䏊9ES9jpcstdy!HhLh2yɦj4rF 3mñ3hdZ%SF\ѽƕ,4od)۶)-;;Bi:H[1f,53˻)&އݾYDZUXNvֶW'ύFqJ1{])i
e6?D4,z/_&SA5W[16ZKpHTe .r7xNN6g?i_ ꫩU_]>pՔ/!'K	KYaQ:s}j]E{]3HkdU^mdkߑHwwt6:J\qae&	VGa}c
AX,hOsipu9vuvvۥJe*J'gpepޯZgݡ^NF#Vc\Dl1&V":,9"_^}Ƿ]R}/Wa 2@5	A$	y<Dxx0I}>\<~&s$.մ%)v FCv2̬Dgnzý=X-Ntʜ67[ &1;rףpi.k6voZye֩լl[./1۶C;KF)ICG"mVOm
o߆Im>8::x|Sn.j_e'bYf8 SEQ|_/>8O
p1K,X020ڧq(~ ?QN&ÝUwkB%Jѫ
꒯qe4v*7V:.˭Wܸ֘2V%[=%+n6ݺ#mLHNE9^&EWGCGG଻¤7qG˝N \e@K{ښrcjqh$e
E8S^I ALXnRZ唇x_ {WOB!B^A8tZ~fVe2`#rC֐*t!~ځ>Od]ղ[N8	N+:|DJd"e)5=teF@
Mǎ6''btѲXf,l֛~uyb[rΌB]ܙljro
~\Z"H2KvqZėAV0OE9ƩzBV0l|a'zⱛ] 5:P](b"Z,%PtQS߽?dIz%
END(Dl
細Ͽ7:;/lX;'|5_|6o{ոQ*IV[95+4;V$xL֙q/ǰ5p;0UϼKxuTA4Z	(2t}`r,dҀ.w@Rpe{jU5k)'bC-"ț3D`2A	v	{Ͽ |p9툫TVd-L@M"90j}:=?z9r>ALhP7Q-ecvqFHBdtq3{nQ[ FdyħqtO7*FZO].vydM_4,DVوtr=2=8?!Yr[=RhrqյXC7ҜZNErz?8._%Fqv^ti%k>Nvi"&b;HHإzV=eJٽs!C/a~TNI3¸.eSɺu)u	옰hx<H$@CbKHm"L6;@h[X@6AE_BVLؘ<@Ah/1w_9HN;NGAt-<oilTJ/Åʊ97hiJDa09x$5QkN6Fp]NIS"~ri2d[˥RjHa5U*d^*g#0W5ōNR&n5TMI%Yih9~{vکwb}>'Dc2*_Ldr|V{&7euBD!SH@^O?fzG,v)$-$آX{ݶA̳*]osuO85$XXpP@}$tP*,fAlѕsT~=K;V_X<w"-b/-[;k`<|np[75cerrҳ?kb~Q@m*f&еY]*et.rr97[AW>v{zKni\mfOG;j ^"YsxGܶ[ X:"rn<6La-8
1i6VGůl&5,?#Z%FK4ƬPz+/ק"2a.#"<=/uIݪhHxv)!<Ex/T֢D*>VaEE>ޠrCQz8&*P.ќ!'7E' U1Br4ƭ%h|+ęLxB5HNB,|PHu*pڏ/haZ	YԻ93ϕ:D,0>T?ՖDaՏɩK-W A:BX%"
-L/p\(p|i8j^"YGG{nz-U;~ȚŲ4m B|3C"[{<VMD\G/'lh8L"~	JyJF3v)+-ݚe.B?8zU} WH ;8>tb~y+uCXݎ `r\.{Xm,K8bqmZ@O<jbp.IMH( .aui0Xjࢤ^{<bco9ts"-Dcx3%^jA?ue)b`]ҬS-d,e+=.V)1ڵ|\Y~nPTՓ4:#&ڋB]I0zөipWRƕi;ws1£،	e90ٝ!dkXG!|^B,9BK*B,_ZMHZvP,9W ֩T=!t&RP_s`HK|exdYϨv^##6^Ըx^<ҴI]J<6w>փjp1݇>xxp{c+0|W0	ذMc鴜Kx ʿpwCQ.m^jwl僃c+ާjoZθjHښ~y^id\$9#	-s2.+u1`A`ŤċMIWꞙGeu$E.y%U4ՠftX7[hZhTz~<3eTF\~"mdU}3>	JN1eur6YYdϳd\×o__^-jMC44Y'^vEyQ׾Nl$f#Ք@ ټ/P﾿3j:\zýgL:,tiÎcl8^%Q%>[!2yBPb1ApB!5l.$)&HߘZO7sE2N	u8Q}G?
kMcf!`Qd%2^`6@myzKc2kPFnlLiW;Vz#EN>s+$vS:؋htŃwa{ `:&',:7Y8iFʺTUZP[-ʲ"b3`aֱMݼCe	xL׋6X.W[Y36ӏC?.X'Bt+Ԙ3$+v2lYa
HoJ	]XD3 0 \} 4L: Pf%c6aׂOm>x5kwo739aX>ܨ:gV5IT2٠\ [/tiWyW}	3*89X_~Çb^/"F:4Ll/3N;k݊-hf	Q{dl<0!YlAJjUTK[EE"[]ވM??EmMd{|>ړb
	9jw
d^ԦO.NOQx,w/뷽/J*tYy^QI,Iu3bQBERzb:]CRAHon߀OzEtm`raX# jUF?#*:jSe9C .yU288!8vf+>fj+.ޯjͶ>[<[mv%ڟI %H(x4p&p>O-6lnW$ebS>TJ>s~]lm%m1gA5F<po,EzvmVdiC>Vp})AlQU6Rr5.Wu
LIx#!~ҪVOm#ȕɃvD=crS~}}P6p]{sW׼]˧^Gk5s}2|0|BSI,$##'<}:r鵟\/MxO:g|wu.ġ$l:{nlyPWe   Ů.[Xg*CurS&)Ҫ,f$ɢ(RD+m&H[X*9bRPDZi0)Hen.baUovq	%<TIOH,PXU,fk>=.ߌR;lI WBzog6ַ	=-N9XvA"c*xZm7ж983sH3 (.|F!T_Wx1;e b
NԚ#&g/H_m*(anmFQ4|MLkZZɒJXE~?K5&x"JrŹEQzE<(]<<b@#RZsd}W4&4.s| ,}Bߘ3p/	RSv˞U*X|Jұch>(,?:<^^x/
ӂ7_򛬼@CmYt-a(Zt5 <xV1ɣXTBJգGAgQOds4#nmzU@#7!++!a1"xX+De\YnR,p~khwOUbV ;_GmWwWWώ0$/B(D@`ήP:,y~b^y?oV +68fG?Z4`&|<o3\loDI"+	z"z2g-h@I柱V4}¥6t闯2!J-K豕pNB[vv+r.mmA(n]-˜vFnsAf2v-
ϖm7 ZRjҝX(Ii#<Jy    IDAT*UK%p;<yxeVY@ep#/;pC,amNM7+=qo8D!bfeo)0+]%Qxej'DѕtR7cIrB[W>9)d?Oם;M೯pan	jV5633?$UX|Vmp?؍Q 
e$Q+Ir2dڮ髦ͷBT7yQa-V.KHDNfز6d3!"IlXL0x|am⃀=$jOUqU\fVn% U,!^HYDXLmp͌MY;'|khĊonKTZzԹԴV|-t)--Ɋv¥3l[lh1<# cZzrtb+Vr+PN@+zryݚ±$hF=8AY{q 5A|aFhK|<okfBڕ;GYI:Uţ2f,];M2]GCMЦkjS:5jV=.Mi"f+
Dz9ĴC˞̴<bz
2xeoP&=yu>UtyJi7}Bu^)._://b&t̬fb{+@tV@:pxn\WX`I	3;
5P-pTW]hVb*%!}pN+f}^bS*Dp4KQr
6XNHB"MeM_*+EJ8nwJ8N3dԩz[]k"euIENi!!2pQw- 0-ƈQ*e7yjE1M=E|i'	y<pougK$, ihWLcƃJcx3δN-}IJË_}WchյnxeAC3oND
Q[ϭoP{@ޘ kY]*7hE2w(SSnςL'Wr#\tR#Zjʂ6ʡQ.6P] ǋޙV&΋:YP}B҅0ѿ0L\(vv>e=*=P.&/H&@yZ|MSӛF$"Ά5Ȯի=oj
79Ʌ	kx}:2GuwdJY8{<{2@>Ϳzwxn'g4CyhGEkp2pTloMI;Gu#]HruT$6wCdeqYP,j.(eE\mc8Ԡ.'V[XRo[c	c\~=(E3M̰dFBdDp8|HC9N`TB>\),Q|IeuWUWWJfJf,ibIE]/91@1Žu8<7? ls#,*.kv
jj*ÓQveh *~Vq#q%.kģ,5b'c ZSpvկ	j[>BVyhǏG
?ji+Pw9гyqRa^HKc8iy |&u&zR/̢ s{ҰճDV>YFrzC?C!I׉Cp_'${}wӄdS?^_#;H "_ʕ+hJr0Fv:)33U;z؈gd6<
ܬ2/8Yu(ESF><*%JtxKzz	V+lЩ>*L[PgS>Sqp!(nn%6	 c
]<G\v.QVl(#=+"; ,gNblʧ슕evBq//y>R&kWgsKx 625;+`jC'ktp' Y/PcTJaՀ1.ӄTF)К8@rh_r{xV-4ȥRPu,!#uO""K18he!kHBfG%e*#xd]4o4&tx)W6Qy^Q<\t~
iZt$}\Zbd*5bGmqŪ~`jRJKh6ScNRn!Y#弉.:<|9'sǋRR\,֍jS~v&7@@~y+O*B1l?k_(/*lVwD[u!ONX,3tU
! 0vh<FhiQp+*+,B
<g|lX}>eZܜ0t^K~D!bV&F `1Tn$R.Fe㲆uebѳ"*#nSClKQ1&#сGe]Xho?3BkuVj-_:]ʹs_>3֘ب\Eۿ9<hpۀ>Sm3$V`_x+ꖶ;|=[U輿>1KYXZHuScϷf^ՑVUBKeĳdeL$
@hKz`10ϣYa.fW<xb4tm,p]qزcu7pl^QJd$\p\wM77o[AIkAXӫߵv#o"~qآ2z)|pNB9:&[rCa{בAΘ:eZ?\j77op]9xĳ/g٪NVȩYq[[[YeaatS2wdtVzʹshLT|&/'~_'"e\f0x-D$ 4KBZhMOO	I+úu3ҭŬ鶴va
n;77%4)	8NhGZЎڊnՂ(6A)cj16fϹI<y~
KNǮ H$P]
Yt.JbKUЦZҴHY`P , GVle. 
}>$:}O?C.@/?}Kpk<g_~j91&tqk||qrnM+$1+ije<p&2 RScǮs7өQj\B]0}wI4l6>oUn@p-iO{WAڀ,lr{L@7!]hjioAi"@vOJV.آxImUZpFwW  h	z2BDc~F]-j,bm6,(zO'Q҄b3:YNU;)؋w6WKpQU[@^_?|̑w	J¼rsuݺ5oNwF]y6P`ȕG(*Ic(UT5zicƒ-Vphl=;?b)3bBK81	ߔ !,2ձ8)cRթ"~?B0(J6nCM[z=U|[E%ҟ<d+BLil20'b\4G\s|^ȵ~e0Vd0tBc08d{vmٜx;Eš\ |*B	p8o
_~3suKz2Yg;*:u.8r R~S75ಈ"ޒ<NÈhV`(@6cS@7|qO*[J̷׎X8m8H"΁:*D@K!ʅBw8o~ћ&\쉿Zcl̔uh:}~=YqRxmavZ=xdgFvܵ/ڙָtz2=ǅ2_1Xm,Nuק9uu ݵ>LN]o:}]sЙ/R:'UшѨ4&xu2yb&YƃB![Dǹ[$%n@GÇKcr\׀`^{ˎ>fԊ5^K-jNF>AlYQQD5bvV1ΓPB(B<. -p0`YVLMOQ'؍z>PhOP(B9pJ.=|*` o"a˞֧o sC;`<DyV7bͻs[=a6b|MZې7w  w4	k4a .!7Þckah9:4,ϒMZ_X5::RM.7^{RY+rD$	ii\){@g;EkGFZz*a1;Sl@Sh	ELcEQؕ X .B` {y,rdZuQsR/a '- vc/'+yr;kpWN\T.3;6=]Zeú6 `&Ϟ\նGP ]/~Zuo\

ƋGxn&
Wܩ}x!<l3PeA1PJ78Zd+4I9u:>دuHNimh+N]}GWa2iL1H_ǂCmTJ g0A+\>*ă\Fc8\\Aj6ХPbOā}Cr
ܸG܀P$*n*Y@	DBM_b΍N,"z&@#~_A&v< 	~Y'MĵfmnѻuϨ0M,_sYZ7I0Y5Y3fG7$.]O  )Gj=z^PHKR ^{/A8 #pFP3XNX"M5C1b Qeaw"u4	wAL95n^0t^0!F=(5h:*&[^ˏ6/.ɻ3|_wtxEZwL6No;-<K\%e%0C, /і,0ef~nx*|ͭ5嫞NO]'e)lekB׼Z||]}Ly[O]~՜MMW]fsJIAۦ[vGGCL:	Ei`KhCD,B#'FnSߗ%l&q<<>|1m(H宭q5ds[lKSқzN뵃̿2ޥrnl#<HNIJW`Ъ{e!:"xF4Dۄm<!κ*itȰs(\:N*`bVffQ(ٕe"ICI(ġ36?;p4pdO?AlY;@opo7$,⾟Gpfn<,M*U6ꚍw祼+ '9Udv>	ý_SYML_;lmkblZݒeeu6V%DIU,8g.$H6'Qj.x"HQ1ـ. Ͷës[\аSgٺZEŔ"v EQƻz`}IZ UNf!c= ׂ ѵPE_yѵG.v[h}4Sx2;1C#|93~ы8ݼv]UWe͵;EY->/9UG/*ʋSp.N&kE!Wu83"(o4/:v zf*5+b+r%e6x	
G0n
joDk(7i_w?W[N,jU0AQpAuUkKϘwiE$)\c$ )C_YX	+ \ӶMj҉ONj?p-ɟ8qv!Ypvn'^Y)kFV_r4G:/~QfRV$\֌2.,
r*8v}<˷Shtj4Z#Z/󒐴U-jDQLƬA*CyQ)4)|c	E&\ Đǣ(:=Xjt@P*g"f"@g+a qᡰ#>%Fwģ78f?~GJY>[Ul#[^B33dHw=;)yfXGsԚL!݁-Z)<^/:w9m\YIeݽX', Ϳ_^)	,-uB`v;%VfAGa!1Pu?\[tFCDJ6oLl6ۛiJ2j~HQV&ЄGLf!"R(uuȢTIRِ].GlU  
;kL{dCXH&po3)-ʘ{~IG$'Ζ](us/j]4RV|17VV_-{wY}YيVd; `9k_AyyvMçSU廊'7/'o<Ց^y0#ht;Ԛg `t$x$-alt^	)&m}-!8jrNc0M	rnJ&Rr13-hxN0+íSXtHyj3fO\!P\oUZ3̢w"XPК2xE{=#pM^ծ2:$??ɦ˷
K? dqsKr8np]jjnTl+/*_gVؑɰs@.ܝ1xJnYC:,hJVOANM$tt&Rgdd ~'@UU(qA@"LӡBH;5cO,nJ<K$"dXj^Md2a	gZZ[ѫ*%hƞ{KH)\rJ(K1Ɨ<8BQ@ĥ%g-ΥK_8wozx}rt63yqENMZ_jNLTٮZ,^Y).+	+sb 偩ypm Vfz@D1kzLh z֋4x(**,kPȶʆ|l"E0    IDATù\g+ȧM0nBGT=0䢡hwt.N[UQZo0#']D^&:0Y{K=f`)jj l]kLSGf|5
?Xr"0Bzϕ1rK44XHZ d0@X +عĘS@PO(t}{}^{j7ZRkVo3Y0x	Wfop'.|K)~Qe]n$55;ip}tj[)_sۜzeJ6dzE	wzDaU]OdTzpeN[UP4ŗF!c1p0G?>\^jyvS.oTYF&gmNA}qRҫb='aX ]$=Zr[
QNZHH8E	S l6u]\i߶/=YQPb5;7o	s5O>}UBsy.kRFGM@M9m	t<m+MSr$o8jz#B֜4щ&fT#wЂ/=/$3Pxk]5/wk|RQ7."Np<`&w,v>/cB7t+/-m,SSHRuﱊKԍteziL&p5zO=ao>;56 a}}}4NKK]FP5_:ڴ6釆֭҉kv2]~ ?بߓ^$_Bee'^Jh;tiuQ^ҲzͶT;7l03&ea*RQ>`W>gYnw$;M uشgjD$ߟ?.,ISBt2,Jgc踬ƅ롢ȋHS*ebMeBxv&_,BwDEH|.C)I8/ϢX嬵lJJ䠤cQKfiqF]t'c?}Q%KHe%DE9Q<꬙|Wod="jV
諦텡Τ TLCf]wcЙ8YYk4~ז4لi6id~05\QІ幩ŋ娉5whNbb:Wj;Q\'E(u
aL%?つl';U*+]L-~A,gtzao/z@d.P>X7b4{}QAјv"P!l{>(U|m"t7kr|uk'=}@+v+K||m!39;#$t_~MLSQ)Qn],ʕ+3b9KV9N6"xppտNQb$!l:#anMsDDNPZ58޳$.N[g!A3R)Gz>.EVq|ϟ>Yh-z`7h%9BOy,7D҈J'prbq^/Nb^BSVXV`bsS5j`B}@re%bcіc׏`TdUn@6(J ׉]:KLtJTVajn94w07ًl ,71]
@`[
ZLIx1 fr^.zwP'Mqvx 'P&*pt	pdls.s_x=-E-	j{tTqٟ&("hosMj"Cνi].;'2=C֏oe#]齐+izg֊3T7>>qp_ԩAJCWA熜srG׮<+I|>2>BOΖ-|UmҷPbb"*"Vc"R.aILRB7jh&'MVÔ
Y؊ؔ[/?.//:YJs1VTc5>.8G3p@q GEȆOqp.rX%I{;F
x݈fT H8Y#)+\YtHzi!7@^CV9
[Z5/
+6*KDX@v@n7o۱cNfS[_'oi/-W/,}/_~Hahi,0>!pi"_hĚ
^*#Ye(Kd)`
ﯟF<ΩDi8'lmLSi}AaUDq:@ER{F$LZ!Kd.ANjZp%JAB\)//ZtB7eI>綼B99I=:Zʮ'QZ63H_8?H}15c%jXTQ*߽*]@pj*Bĥ`5_pn8fdHrKq]1}vL[k<[ϻtƄke3`S~'^MqQ#f_󛣦3lsu$U[?9+1lYv^?LSXQ\*\9(0mњM֑ڴJzJ$eChSr>Eٳٌ)̽MWt=!AJ .\YUy$;BqB"pSrVU!DPZp;V?٤R5)Vɻ"
Oa'P0'4ԴERćE&BLa S͔Htä(,drCls(eahx/y؂kZUJt۬m(٨SEԽߡCɺ㔝^!UH>9ћy\]oa2UulQB @o'x)uR<L\W罩%rt%DlUVf{*6?|MIoJZHgD)׃֦XEy|l(;:&5u-#v}TQ1kk	*؟h+?.wjsssQ$ĥHBlq	φ^ͶkP%eMp6m__rW
̙+<󼌓ӺyTͼ<Yi{a+7erms+"5>>^Wa]K2u]zΤllm׃Zߠ^n+loט5ʜ4b<񬳧QVDe{H<hIrz:59O7hvG8(dV$ALQlE`Y&b
`H(* #2d#	#qE3&K1
E	K$5 }?˗IfG˿}!RƁKx%>]f6ns"-W0jf,]ewVlyB?u}wqSRx΁`
zJ-EǋL>tkIlѴ;^ X#,
vժ_HA>w1X~PHV	DWcz: ryk/{eT^HXS@ ].|lT/`ҢAA̒$9/$xw\=ڊ>8ɄaUeS\<*3ݵOjk322ka >~lksdֈ٢]	wεunQ;Y|֛ NFnNegD'Gڱ'|cGr\;pBG+psa˺~=+"':#VwЂkIӢQ%yִ{ ٞđBUdK/+EcZq!xpZ]4(A8	 om/Wbq~,K$8LL*	W$!5)33bYLD`ag1nЋŗ&!Tcqlv\7""=v6>YЁhBKFkMM}~}{&Gv#>{v=9xRڀXQe@n
 ]mcXV(>E N]~8nOq$nE\wI;4*]IIB`K9Ro1(9Mԩ++B 0|b1Y&6Xinnll|еI@(v&\CLƃG3U8AzlhmY`后
sv1<*- r^F\tmL^5٪]9k־Ms&.A'_|Yb^=٣Ҙ#ivtHn,V?!O}}cޣE#
90E,t=fswEǵ~SgŢxuH<Aa (Ğ켥Jh*-%B:.V N
o6ۥ_QεqT	cA0.ICሔq)ʃkX		(R..B?da :P
\6MpΆ#_,Cd,vXnhsm8:455Zc{޽078	QIcQW lq&%NG#@˝3yRxsW WN8nNڔY*nhr5'"(xrws7hxEKDAA#3Gmvgg{,mqqdϏyq(kqӣZzər@J	E
E|כ8dI$dKLbqA|Q!OdV)I$Ǐj謢p-pbKbqF99;YNklQ]juڢҠP(K^V \Z׭#b2cA)?_{<45poO޽L^	 fPᚸ G4H[SQrHhs+` |jJV֕ٝRx=C_hUȅo}s_n_"R
]	9荞Jѕp9^\"p$Qd.MF,@Ԣs*P/wz~k'}\A/g Bq.D8nV_|BCB/wrÁeRaPβEIn:nX@ͬD)qFBpN풡W`RtVcR/43 \:捬7ؠPtv.7(Z:Pl~QWckyI7lvJ0ƠelVpvhW,AahjCm8xļJ:,bQL6{	x?^7uF HK.Ch[xV9*H"ү(ecS)uY QS \3}
L$Aӱ!Hhdҟ_RT*˂O%>f?\V,WqA)%  0
\ nWs^Z8*.`oWPiF_3			Donmi`fe̍8_?]=kҟkA0Ɵt)##ND3nIi2Q5| {Pn
s:GSm2Ps	SaTY5j~ck<`coq;pqIu_pokڪN`)@Kxx%y=N'?7uu -.h0!Oæp(MvHߵ|xWsY`]<ṫ+#NaFܵrAb`
;L-U<u*تSJ>v[)ŊtckC!Df`oiĲ1
2VJ`ѱ<G^I:/`x<ZnbABkLPM%Ȋa.2X&%bkƴE}/ѵ84Uدݢ=m)W?I ,':@
%pI0KRpk^?^  @W\֕Q51I]zJ}7pqqJ*qx'Sݵ;~gV)R[x;2o5ԤkC|qo?sh?\ŖҺn]Wv{
`7_H;%YlmFT||DEyW7|M`ַBmú?}>;Em0 1NRK'󳃻mqX垃 VBnq,X6-b_Ng3d2e8<
,ҥ<E	dvNm(pe&L5\翿ɿmmw[uf-rjea
ƨ\B YV [!ȋDR&^A3,AA[@4=	DZφ ^bIy__xH,MUٛ)yE?|9:=s9Q=pvէ"fQ/18-B/`X's*8FWƜVXEXVns~%qA{A]-,*k3 :lˤl6L00XV^_3.,%*+V)V9=V1͹.7,k0{Ckuq¿	V׍|W];4X#7|ά`.~O_=y3bitiщDxzs#BCQ	ZBGP Vqo__zO(1ݩiFf%{9sӧ[&?yX0aq=j0$T;Gھ>yx|MdItxNXND[y`p	Tke "$ %DixtI?_P2zdJjr(\ɉ'"Fd0Q(`N&q+FС2ܴ'ku#y/[gTqPFX݊ZT2feNRket7p+ͲH*!|\U"|Bˇ a@H0fެy-X]Obb"I;9?ޝg%\>藽}T,sh-S<8*݃1؍;	UՂ cfh(KNitVM`M$9LGOG2yDYx&#=Lzd	BKf294\6jb݆ŢRUuۛyp8Eשox@Wq!Q.euE6XHr{Ӯi=T8u91y*[
OW	\I>5)3p/\_Gz^ak}p@^oko'DE]8ʥqZmiMܝ[?>PC+r¡_!4뾆)om,/q*7')X!    IDAT`hǔ3cfrz} ݱ9;.I$4ԅ^l@1K5̵B
7>cfЄR,~EC\tKN=_ Pɦ"$)寎`>!+%'i'ύ&&z7gOu狸#	bEO \+C5/v{-*@P=Gkq9'+E=ݼyZg
BDȫ獛[qz
JeCbw:<
mT=aPq6#ojsU2dkfпt(N+SmL2
,X-'|P'Uˢ,*v÷Jbj^/O׼TU}[QQB3S[]f͆Q7eKd"9"~*Wj9='D#2Dwӱ'Bߟj|:))-#>vR]ˋϬyݰk}n{}Pb_yӓ? </׸BF91	1W3뚮*GM*5KB*rvWeńx<ЏE&`}Kw6v77\~*$S4h^!HPŗp,зEGDI2xB9zjgKVL(Hs@hB#Ѻh.HxjvV6	k.pܞ_Z6\ZզET^XUj} )#mؿȊ0"b8YG##C}횻>&>rBcZ
WPǃML#GxӠ]z;kΰeI2`dM/()T Qa5Y	*ya"-'RKѲ1TJTJNk[Xf]ueaFtU	2ɕbַk0̶ڢ]S	ѕWVpecn:y  {|B>GZ? )(}ݡ#.,Ƨk+0B{Wo[__h}O:r9.];ըΰ;dqQCn:1 w	~r4ʚ&{	9VY|[딎nlaÞB=ib3G^4yəEZRw16+IM'G2E<L"zz
I4AätѸ<Ex"H5)j㥳Y!FV\6#]@ݐ"*ex;sd'{M;6]||}}ސ,p,-ҎAtE,'˪w/&O^UO۶Zb0q'Hl[h{1D*墻:Ɵ9j!!rE\M{Y<`3GHZ،X~/ ov*D*Aԯ[2$^u5ͨEW*`C굥j{8e.ZM>H*r]ڕ<dK+5O}pۯVWa4]]:6VCpGjWuZu< q!224S&Z
[Y[p|6;;.r7̹ٵ|яw~;ωGJhBTuc8_G}}u>Ge\3ɧ^ckJFp\l3U=WAWonyrjrNNb@JTK}^	+E{-2Ktb>B6
Vqi"Hxii"ѹA"T$r!zOILQ3c)*Xk=G`,(Ӈ/9p`Ӣ	'z{/(4}qwưͭ0(J9'3+=<*gA&bݘ@zg<ФUֶZ_Y"
|*( ~Z|
;	&$z=_[XXO	_&տKԭL\'uq@y6_N:5h7t>Qryې2٠
RLiM8WT</>ctV^!^ YTW]IcB(UcNd dH f?YMQ-6J
#$pW('$jQ*!jQOIWUOo(E8(Bv\Mߖ0(vߝ0:;f{'cfؚŮwȿ72BRpmٰnNN~N~2|i//q8\j*hj
:p
<=UV췐kH@˝O|m;.d[{\*kH"ZH9^sWrҶ.FF@k3ɴcؽi)yBUxp/ZOk,vMHd,s?^\J+UPV>i'B~An!7/7Aæ1s?.Vuh1!JN-W&:v/><~ 1e!DyT>>P5' قvY*~ܷv|n<H-R}l{<6p3X$m>e	-|f^+&ExB,4zy*soX5𼖋A^)1Ժ2tsiLFQC "%udƘ"MQkLBP1v\wpW%IjVc9IiHըѨRKD!"㷵ɗ+u[\Gl̸ͪG.\þ7qw:yBf&'9}27]>=}gJP\ō&J>8KV1vsgt+^Fc
^)i1haLߺ~b$qI ]Cr;Iv$$-rjFxIj)i/4f氱\QٳYz,py~mQ]]:T,ΨgU
<.[bql\LAk%~Đ%bdURvsLRءG?~dʢ))Zl!%J@BVii WȝDJ_f/^)7JE:ĠK^=79&G'j^"<HAv&NXGKpgXC3.`HV匛W;<Z:kL.J*ĸ¤~hy=X^EF7:qsmx%JgQH.Ʌ5UlF10gW<%#
mK 	$yp=.|qI{&][׬xߊ]\U8ɧpYweb_m8+*d)P@WSx`8S>Oѥ^[gBP7lngD~W+k\ZE(VvX'l8(0LK@-;YYEn^Wv+'|7-)v\ҥ:+'pCbEdBBO$/r! ۲/S>C,cY1jr4
PnXNKrGUOptͅizL Ǐ|u2W3z:|ob>^ѠF8_7]ш{!a=%ܨbPha4sĥ3xj/uY?S(48x|4tPX:"_pv$˖ax睚P=V3nt[6$hɜ	=trIIᔴF]4bSyFz\NU3(3ߺ7&s/]xK'%%lR8,Fj!lЕ_w;^Utt59{vr@m?m<5X"6I[kk..coLt3ҰkcMk=vu#`(ς2Rj2L76UڻN\p{H?6fܩ݉?ԎP6LP	8DB)wc B6X/ܩ mT0ɖ3ó##;uY557ܬ:92ǥ^ͫ-]MJtL ŐV_E9E#b1BHEwQE(5,60;X& fJ}: ]y]t1*r!vS{N~x=3$@/ռ6TDŭMe2jZ$JwҳzޛFsi>8Y4ҦL9uc1f,v¤Qsd{dq1.f |/QED?`/<@ iHo}s17	uj,Yl9ZuX!k3|P-	=Mղ<)Em6hybLdx|Qo^%*W=4eu*;\@B(	O,&l(q/O<}&gs]"̴<Leŝ.6!pKU#dTjRVeU41\!\V#AM.#g[{tq;P_KRu`;Ndcii^{Җr Z_+S<82뒲,aEwU|?_=^U/N+;iʙ:%=au!|yش%n@jY(Wy/9k񤡵5uwe15#x,aAnQjLy%RTVk*s~ku_W,i Xbg
CaolqEf@2ĖK䒢 sUD\Q&])e28o$R	O $`''RVuV!O?$]r8afe֝;~h=7 |\:Ȣu%kq*Ǔ>3^1]{R_ɕGje;1&@,daKJ-6O5}n`RUq3(:k2iiQq(YG"b''z+-V#\=!4Zf7സ6Nt@O:^huѤ-HY~rk;v8m,}vץM#.u!(,S,j>5TR(g3K#pML6.HBrJ
w_sG~m¹Yw*3,̵Cs_ۯE/oinvްG/Up"Xæ'NZ[ѵ81^x`Vĳ-vdaTW(欷ŢU++♕M\W*X-Nj}o#F1QU*%IU\"ˊGq%>jOZdREXV62\,	xFP\J$͊{`
	(. #CNtmPLpX/˲<'e2nA)$yzHGMAmE󿺐E9j3gQ=?uCkGNJ1Ug2	5pŸ(*m<PA{Gj8nQhD?J
X@bi3Bn!b6IJ%BBYݺҌ~6f{=v>ey8w44>iHl{;;d\syаi1CP ?DF!dirty51I踇1 6 ê?l].<:6	~ѧB |Op˸+GK
pJ;qW4>o}>}c	{|0p/MXik|ta<jfx$BKiiBÎ-͖~alOPO jo&nK+ܮ`<@qM}賺C+ɤ3eˉALp%\!M"$ٲ]yF	DSeK _KA X]TAe_j(x<J*UM*)GjTm5#n39\2za^7N[f^GkxZGvsJG&Nazlow&ŭ>JÅ!+Dcx	Z8BYŹ->ϔ8oICR[%NR1D}sZt]
<K~J/s[[m';3ƋG5dѣ=s~,]icS'BPKH,<,cRr|ZſCY\jSsOy8u65p:;yH<(ŗ3L3R#U),d){p3<\5܅+;{ٌWz4|Z71;5h0|_,v{A۟ei߹.6/BҴonv6ڟG cR[)@!f&Lm~ţ,*Ӣg!!dqQT6pWnlOqëT[;uhG^;΄rpaO|J*snO"[Bc(\6|%,\}pKD<I%UjuOQq.ddzV2le pEl#YrNf:<35v^w酭mMwq ಴~]Sc͊Ժf; +p@	( 4Ue6:M@ݽ_oUw=|ddpx_kzs|X.A/ʽzdl aPZh4k:4+Wbg
l:G#IYl&r4GڪZP.FgաEXKo(lͭ9]Z
4̮ә&Xb ^x}T
BKR9,:-P
B&ډT͈Z
bU{(qF1ZYнBpZ'thyNClm`P/Gp/<oOç9x>u˙k#ΞaxqZP+r9,9WЃîpkvJ^Rk:-ș@|y>3,Y\?0t޽^z!__k
heTGKƚnd=FC#	/P$.ƷG+kܾ)p)7U:2.Ds栍U )Z2KC !LbM{PD2C` %$Fc(O-
ⅹ>VLIrhc^(S{7Q◣KO0X+kkX	*BÄHdCe9nd1tɮSyQE{	-"Bo~Ʀg64T$f§
H"|6L,i#q$n	%M0ggP^_/TI;m6q_+֮Wk+C0{/z";ʒS$NJ)r,nqbgj5D=W@F4s}CbT Ǥp+cv62)^1?g^Sice|ŗWz8TBIr}^~sye{\:3su`    IDATwّ@6jvK|Ni;g.͛ׯ.((t,Oorbkm`?;.U/M c	FGAAɶѣZ,# fҵ
c0#.[} I_xZ'
IlVH˃E`7T3sws$Jiuhd2	Ad9M&+Wzr	.|*X8z諏QߤӉ䡮:10]B>~
+6(#uBƺV(-MMG-\@7y>0LnKQ4[VX=Z򒋱d.4E8}>{>^Lf,,3"2Cݱ3$&rgjC+A^)Ic3͍C馉7Mo&@ar/."_S{("D^a`C}Z,NP좪_ht:n(,f#o7"1|
6ctp%a>~ѰksJ>rz36?yٿr/<|Iq1EϏ_CQW,^pQ6V3_x1Q~Kggsy-
zupmtU
gz*t3tZeUi@{혱ڑ[Wʋ"rmOuxԦG*S\+]i>lk̭x*@HdHLBWTBUD	FгE$8lU;H;Kda-W♈.
E*L%vȨEqxrhY-d,(p+]t±MQFFQM\˽{ütIfK; V@k|P*h &SƩB*!TM@xQ2˧HLB8X|I`IΡMg24HԨ*lrDZ&5>5̏'V'fnakmʫU,=kԉu.>@5aI$c_<%68Po Ftђs,WIDVUIa


++sֵSwq0Aq>% Z1ktm;c636ofӵ|91֋Ul\|ΫշGzڇ0˭UWp^sKߜ/1s(_^2	.UUT^u?ܿ|[=^|~TYr{49SKJx+eCZ-xӥQ32e_||JLsϾkjSSzO$%p%Ǚ;D&3Ydzo&\D3	Rf4uSAZCpcc	u뷾Id3TD2^BZPEAv%S?%qf^֩ܙM+1WjjZw׹_a3nH/Sd] t $BB *~-jMNcosTZG:ϗK*U[;o;5 Am*mmP4$ZdGNxgSu|ʧ"N:r6ЧX8fPxI,Ҋ==f3̄J.ÚQp(rQ*(JV8L1GW&
P^[j۔ZPTQ"=;	TIHw:#D|d=jB:<̏o0M-^ɥzPa*j60t+QpSF Ul}FwK\]zt[&mFWփB$[u.pgz炾7WTx],/K>Q
/]Aɡ[~?]t	};#e5SSfЙ_J{z$~ۛjD監Zg9܋yTڵ)w_sX..=RYR bxia\٨t0gjX".vr]U 3'Agg[ٟ\$[NCM%
*t6O9mMVŖt8	r䒯jpoRDgsHQ.Mz#1=AEg5~l{ȖjQsgN"X>y1S$1JHX3&0`R$L&^l?8DJJ%6ǊqS"YvӶLRM19)$l@i㾥7!ҬlXDteǄ10gKȮJyQt<V5ʬEY'kkitgM`%-I*+ L)EsÜ'\MېԨ錸N?qh+(nܿbÞv٩\={ѕr=)&D+'9[t曽[7" 89<<8-s9ׯvOקlDVտPH%p׺}(	7"쳘/;~)-/N1ښi|i_i>|)e%%%qHbHhC:Xfp4r8aqf&ߌufT"zz.#Pj%rgU&&PhfKmx`:+,m1&E#{iOIebFI:TsF`U+T09(a4δX0tNnF5xG*9qĸ7p\o0a6Z))hy؁yB;##Kb3uUFStG;uݞ2C'}[,3hjRP/a&nibPrgW U8!Ɠ_%tO-lpE
fH_>EOZZyTq%F-*rw5+hcٵ9|n	GZH&ڿ#[[]NWWJCA7|lUo;K(_yɟrl9rN?ߪ 5 ЅxBBQݗ}J%BoF!2ZB)QҪ`/sZƲݽgrIfݮDO7n3{x܁?xĵ<,,'2> W-sX栬% 
KdH:a7k4.:܃<-LXh\Y`v=&(6ow>Uy\V\.V͉-BN(Ĉ.rX.ǇPX}]߸E;$+#قF TIGrd~j%Ÿ@oћRͶ9Mb2qxNl0zz;22J@!dqya*&dh1 jBµ=|ĦKH}1cUrt4=Nu1jJarrlrMm94⭶ZZhn$~&Ld{:Ml)+l)DNџFo+zn`[o҆	{Z?\ԗ%a7a
736&Pr}NVuru!8b$'VN?wB}؝i):葟OC.x"#wJwdKޗ<F[vN5h!	vY^xBt5Р_WAhʼĸdw$ׂr_o foJ2`SRDe!2p֠A4/bcYl6IޒգP		cx+,&X9	F<xwUjaOmNH4\,HaV.D",Yj[d/?5ufq,⪫oT

DY.EQDHZP.8ۭ$ӫRAH70I	88<7@3{ v?<~dRC].zwQbhXmĄ)
snnR	f[sq2kkt%]bH*h!0pz$PzRoZJA]Iρ	qQjjdmcgkj
ۦ@jiinku?6j&lwD9&h_!]릷Es*m<<%9T&Sw߿IߡضZ4W&P#YBFV#bJZ l[.6]nWpkM][DWK[{z?hiǁtQ~j4>s,
HDy`t'~غ=~%KCLAŊ ;t—dmψAې<tUѾp	ڵm-HP޺zӻ]y*oFr+~8'DʆKdȑKGFO 6$DBn,/->RMb~ZT&wNQ|.WYsFP<>.6.5.b::]FGo~LtJ?(v2(Dvn"B^a'W^ꝭK$EqpXj`.FA$h~(IǄ3"½wʧ;q4+] W&`oRT/UzrQf/uJ॒
5U^#	4hYXl&3a˅S8㰔&@p ~ii	tCC.	#õxxtdVٶVbm,; شAId6M\k4	F^8]Ke`_}\kr/M.orp\IL]M,mɸbɍ+EvWN9^RTWWy]W~""ϟ,jp"W!T3oByih"fOk!./^qaCOI|W%!ns%x{'qd7G8[vm4JD"8KEQG0 $nʍ]dpoC	b:bKq9	t)ţ10Sc(Fס+l+zԦ҇cS+1Rx߈4^V:0d1ן{2UUtH6Y@56UKni.{ۃgK)uԥ5_YYMaXhZ-S:LNKǡDԺ@%zx]%c$7&,EPgO)9;@WT$Miݠq5liț{gDٕF"^W,^#ӓUCpNN"d-tPbk/GXu5]Rp57vymk׮A|w8+\ܗfkd\=ÆUyh,t߾};5
 ^|jdT.&QiUQÇ$>z=an{I蘘ޏ-+6ߘy>U폱D.K 꽀]ӟ,»[vsTD\)|,Nw3/H$VgiqBpqOx?m^<_c3ScbBV	Lq.e8{^<Zȍ)}#^̀uC՟ۻ\uא,wllʈU*2B$olŐGl1
B{	JAsl٫woZamٜ`pll9?fcʿʗ i8 .eXN#p%4-l$pv1r@u!IC/	^~
M`^+7/saMMW]:-iS/7pM-)jt:;:P5q˽K怀8T0':fs꭪JʭӥE))Ax@b_ki5޽r?ėbKp?ĵiI>MgG~ruϞaφ߾[rKQhPwB_l\E$:r4=9wU{Vpy2#	ߌ0YA3_$I379Y_}]5>LJ}s߻5_G!z~[y|sQloΞъΞxE8I˵3J_R7)x?u{ǋ{ /JlRR3;;;	q?nv	
WjZ4-6Aeew=*Omҡe2ؽqD6&UJe+<w(%d-ҰխZBZ	n`E\T+Vf)=LrԢVLRJԛ/YJ=	]l^[8/y<,j8js%5:輌tSUK
*Joeq-k^Y"	#E!HV\5&,Y%Ą@@!
H,8v ~<oa@y?=fUDThv,QhRǩؐϾW*:Mh%x\s[eE&jT-@ ʤ
v!GS&Ik!].t"UbJ23WovtLu?.8vǣtZi'rsMG~4ש3m#.RU\ﯞ<p˅惫m5B½OΚ?yzսVW)s:;sss]G6ۂlllXOLp>՜oҼg/\ݦc!*]c t1z٩[.xdiH@Z9YPp\XkŃp&8L<uג"=ĿyYyU.3z9*51%U_z+hfڀ,HԚ=upOb7G+2 MSX+WqJYEW~ $UcV#4)&AF!q MVfj(˩r.~-%TDzRpT˝mї,_%K*H&< ]# rRT ҥ+4xWCM֢e谯Uŗ>Qw+oJj"'hqT2+%\
|B֭԰j2m2M[W/m{^pވ83:vX5l%TwUwy9gΌ`z9$ڴwŒF|'~l6kwoݔkPp?L7Tw1wܴc	/ 7\SBЄk?7 nm͚k7/?lY*,.fVΚnܘ}-zi")2  \ě7+  ,h
+,<ݣ{i޴ 'B,NMfq,]v7OcrOwrqHDZeʦ|.ZDI26oP2(r*LSq٣oAbTꧦsC8мhqEQ&qr m	T_`̠Z@s!p..,P._gmSY(4)N4jTڤc/m`dY%oȐ4rps +Qa8j[W+%m@9]7|)2GŜZ<{|ߟÙ[<<~@")reղB2pTࢎW\iYc5Z5Z:Zvv{S 3Ĭ?DovH&2С,=(p1#:Ә r?ߞ)4gbX-U_]K?wvY8Duv`qPv%OH׳}$
$(0p7b|    IDATXg:`.`f~qiiqqŋo?LL0NT9#5,hm~fx`8+> )ۀaw$04mΐER7ɻ  V<z4@O4禶\Agp2xf0jJë6q*㛅ɖU>:w7 o6/̊/*rl)ЫfYNWa*2jQqAHג~c@:%JAQ*("mg]@I^ `F~!D%r+B%oer-oITT,̸RUhgcZ MU	t:H_1~bRoL"*4>m5$3̈ĬFfi{{C=?-?jȬ
)(gYFLH|fđG)\)Wghi.z@đ˥8!vr{Tͽ߂moJ CT-BX;kvSGahK7Eq?7[~fs&&rɽ )g ^d! '.IԣԙS)n 3ͅF3JԌpo@ruxj (?_{Pĺm2$9Xn.ȰgF/BDrڡNH&mlj]-:9 ;07 \xx/#[tQe5:;JK<hePL(XX'6Nf:U\Q_0J8_Gp̚/E#mQ_]gqJe.?Qeq1+.^'Wu8&/o=d1ܱVi(ܮslvo.@KUi"ǧVw(g&~\
pD \ƣ4P xӠ]XBq*>>tc(W gD:i2_qW#8cb},gr_k"rzj2ec{ȗ6읟7eFGʃ_YW՛Ѕ̻ZgxuOMYo;ufkD6.$ӮjdESHID,`,BY*dbD!hM0J B5#$!  G??s7009<|,IEFjzt"6_UYD
K]Q++mw"4a"Hth$Q܉!Hp6ܲn7
=Lho6CcC2-D_@f@|=jl7N"2`X 5LqI51"-hY[V`7&Ʃr@EUFNɝF>n\!a2"#S5&C.*/xutvhzqc%[˷̸I|͋W2qrH
!3beԎl5X_z
IxWenDlgW]̮?pYz
ҤYCeXhu3vA3;ڄZ`6;@x)aWJ赋k=(-w=i\iiIoA?*iCDWuZۈi!]炃Dq
E̙Ky24Jx!
cK%7 gg/ݿ}g{-|x}az76ђ{%:_p۞hk2񃌵}s/\H
όD&\<My?B%/Ș	OZjPX,>s=%a[27+TW!(+3Wnuݰh\484E0 ``f,>~V=xW1R
0c133ocL2<<NTQEy9%tk.jdX$\nl`XD+6YH.f]8\Qć'&K<ݪ~'gAn.3I9fsgظRCX焳}-/'6&x\G@uCX12Cڦ/'gK]#
3~(hgDm3Vkg!_qpe-Bpc!VOނːAnk+)ڻYqǞG~HIDpŜMp񰡔+"h=aezȩg=k.שǁ.\qsQi1FȺp}Պo@pST~. ]_w {Be~|*ew=-w1w0=aT/]{sG_LM$bN9X%2rFn"SPURDO։:Z՜cy',BFPi\2YvejFnhShݽC6Gjs{8Ck 1-(c Aޫ~c>Y@{l+LO1%Ժ"\
 .%gʦF)('ċȅBjm5FeBuq񿜆	OCBjawX+-,UaLrмB mP+5^|㫁ƍTL/t4tɲ9a0HZaZ&Ye%T']%
^mpy>yez2z3>.{G!J2VAdF#T7,!XBU]	DlmK}'\	wZe\?bqQ_Oǂ_m?}|!-n{/$_w}Miogo9w}!qqIJ>Qh&汫rd3sr#?1Ag阚Jʷ;vwKBk:yBq]A,\]w|CAoKcxj#mcal."xڠ4d@y"Z4xx=F#Kp:""|"|ez+'tA;N=uXؔ.*[*Z%JDdN!7U.ႢU;>ZlR5m҂vZ;p׾ytE._[]}p7Lҽ	*\vfн]52YCR&lAu>LU1pX9thv<xg[py/K<9XT/QtKgXp
:G54ozҮL@+6
):sغJ~gⴰ.<5F,.MjǇ2vDJ	-n%8zȇmdelDᕀ.\;)GL|g{dQ*dH**"w{95F{++]Hv>`/.LYX'èJS="HfD5FKx/펛?~4v^m?NX݃.+,>XV$&AH)WU΍g=uI$.u2MaU2IW*pwPh/v;[jFePbhz"oz2~Iiۻw5rH._:U(+D%lDd?4N&w]HuhAŁ.q2H
nv0KHl20Krk˥\
Pr/}Ob$B?=[^p9#2x.GR	T
c tEE%	4P[thf:̄Hn>MeL&ll8W87تXu5RyPËËX>q	[O_ Wո؜R=84<R:.aJ\o+fܨ^N~/AykB0i
K,x\g#KJu{$Zw|~Y{֟		{1!q^WIDCI%o{#gI>Et%GxX,$_


~~
QϟRiʬb=+6~}D:'-q>c+iv 
M]ʮ
	e"r<Oo\:΃?@79.U,ئvaB ̌OwiPh8-'J~I݃\>_6<<¦rr.g`uqfI5i5ˊm3cԮٙ6OTs8;D~p>(S	\epk@x\s0~ByLn RCHWVG
$:::"ijH̖TY26<֕=uAU/}Quv8j>49:̈Ao 	/j-\*	$8݇Vﯤ&	+,?f+0LpApY.l0V>k+<~ñO4x7Ȗs##|RR\"w˃6Vثz9c%OLX,|IWKEO4>gj
D\zT\U;'yo1$J:&p8iLۡq+rO`++v@v٠6hJxl# ǠCA_$[tg=*ݍu,/.6-@fMejN4vΐa\)+@13ذؠh(wɊöIcD?e];7MW>t@nr}	;pU6׹\F(E0=l6Wh(.hIB1Zs\^Npn1:Zl'#I8ׁp/r>quln_DeAAΰ<\a 5ǖt*x~JS܃pupB2"b
,~8{ɳ'+ac* V*>}廛KrńnVދ\ז\dT*μd:<naa&Le`kW$Yɱw$ӳРbFߎa!fcsWƌ*?yiU5i|U!MT!e2HH;Tw:$fDiL"Qy:@mKaÇd$$:t(40k
`>tn=At5>r	K1D*r}IĘee,^l;@P ܹev6,6lw\̶ͮUÌdRHj zm,[k"vM$\UrlXXȢP<īUF&}*]-7,vauU17[KQfV*rвQ,<"2Ws^ndP9__>.Mm/WB|&}(G*W[5}C?_sep3̔CcR0\/Rc꺓|Pրn-m;uk_EED']LGX;ޒK"@ڶIwTpQv?(㏞t6#|1i(*3͸*ZY_7AWy8_W[ʋ}ͤA?
0AE]ذVo#ZeW
,2M|jp(Φ""EX#&IYD+3EXVCDFI1\p/zz1YpӔаaY{:b)M.^eLcӦ-,,,tuh<ވRV	HDz2sEH33.+7[=bXgXSlӖnU8gp˯N΄fɊsPϸr	\{-npsL_.	'4G( )!ʦW[$\nx>¼>54۵k4d)ck\ [_$'gа[_1ၷ6<ɝT9pK2Yr(6t(plk@wY-YO<IBmtth( 6E4maVyo魸W-y`5ORbKE(,DpU7d.%]dxjC
xpUku?igg]떾fm掶GHڤYQW	`cD1lպ\
G+/pъRAŪѣH?w}1O!^5_!B#CYH>uJ{%ikvvE:zԳͨrMt{'ؘM66P#c}ٷ\Kqg:Z= DD2|F2f	dAf0Gț#0(92c3rzE)#D#kA6nAVAʅtń
vEK?>I(N_eM˽Ie(,(jm*ʪadRݏo[vm9]iGѕz Wn},5ӹQUVVI%&Uz
u\S`8$\uB|+s5rNX_">|Go|<n/1D2Y 'a՚E2ʮ(}3dc91YSQPj5fW>~9B/Sl`l?\>Ŭr0Xr|ILJAc;WxIpo׉mVXGhV!<eߚnІhJVőeZej.9~1xe mR &_lMٹnrtzM|B_ÏA֗.4L7_ |@E NId
!,Fe42$-U޹9D^ILP3l@v10_1	xQ.4$^}XBy_\'C9`WG33oQRn-cM-fvaڳwY.SÁ!Pk]9r#p5FGAzBCN}<>OPUMFY{F'yo|\u5z`'s6ʾco=|By!+.ҺI
z\]Hj'񎥚61KnP2zʦ-SWaZ'5vfqy)
W.Z;e]p0,JD)IeXÙB6%GHԆt7"BN%7d*Q_-EIlyHz.cj^so$(~Wvʹt5upr]>Apy/i2p[ .ӚZMmFRpQĢy<]Xȴt$ .qHZEoQp;aXstE .<GVԶ=p/ٍF'{}r*|}|2& .*hjFˍT6R^yzB}<%_\--w-;%k9~Aɳ3'Ο:uXKxWpFu!P/ˋ+V*/A\7|GW^\x0g˛W6%=Cj.@2}G͎CKg_;)HP;85lROӰFw4@ց#pE;QGZ)yh{9Efҽrak̃Ţ%tW6R|F"ÔGpBehqĂ~;a|FһD#	AO}    IDATߚtQoP/kA@ٚ\nUv:<YހCC]n^X[Y36Um
\((0e1d6+SQL&Gʣp))"iS
g@$1qWۺpkv`u1(D),\OcØ:#p=x|sɱ}*/zgCU:^efngfe·U-/.Br4rs%bFMqapAC#vuA>@_yMV~3g޽/'NyۡKgύEȮhC0_(}U6&D+E,gO4wXyq8?!DJL>@C\
=Cetu){4?628gǰcN D{MÚ^]
DImHoX=:^ܤX^AZА%ax6ԔEӡMIGlWCvN@pqa다ZXϙՓ~Hm߯<"sssDZ*ULS.X^&e1~[hvVa^Ȍ>`L:Z9#TB 
Q 0
%8B:A&⼉$ܜlѹ&IsZ N
GS([w ]PT& rO?3.<;<M\{39uvm[I*9B#a"(N1
[F"obJj@"6ITR>#Zy;rtQA}|﯈ݿ+][no?\-ߜ?V^^Rʈ|.]C\_rS3RT#4*Rd惔u~a\~]<ZԀ3EuŽmA.NpDUQ{+tʕ#:
{`
{vn24fKm)F=]TpK|#ܦ>74boS
]lM!52MOoal=0X~q~~ ~>{G?-jw{zr5 z5l8zU"y4L c#Ja;&mm%%TraUVOL݁LK3H9f5m8ތKgTjéaҢ	\Hj	HzmjE+FOhD![T>YFcZN7qÎ=奈ey<6j1?Af#3)ڑ[Z#uTNGC.zՄt;Gq\$WZ'7|E!$~<w
Z׶㿀p}~d'׮#.,t)Χp9%i-O 럞hɩdMV#ҮҸiF(]]58\ >c0[W%/8\1f↔K
Lʿysf?۽Gal<'8vU1<p/o,Ι7{SR<》'`"#
2Fo3xpΜ+oƔ뷶QĊ?ct!u>vIg=O4Gn}<\m!P٤y;j6Wyqr^
ollhP;rVW*-Ft+99Wd9jOɠgANgu'b3,2tZ&jʦqS9,vT\h 2Aի:=xF¥߿fkhōj_[<<4oZC [s
KhOJ$ud9_#ebڠ!jڠDEIDAx"O@&jAl"0I3F^$K>4pUE1.[{#kwg5pm!\õD|Ȏ/.7|=[\Q{\RsNHK9779YLᜊ)h9p ʅ%5*3xܐ-઻y W9VJ"ފn	 nZAA0;lM>ӱ/lGS({x~o3-wb)|` ܩțd3k)WȬѵpu0q{xP>1&=ERiA4) -Xx"x,V8GlODxz pWFwI]p!*=r+*_t;qꩄ^SC"eFb
Sc}QPE-5KPxrviVPkҘ{ŭ@5bl}m]Z^Ztkn5>㿉k#?kx-Fspc§j$ .D(OtHWWKl %RI@R5Cr MARY<0n\nɹ٭wfIKٵ%n}IMP>MpmWI">hR4{))'gdZl]hui4ҵPG%iH\XW.Xbsk-Хz@<B>V i2[daK}Bܸ0-;ۀ(ޣK*6y(Ż#)IMܽu=@׊IBv1
YDjxdD3+ii,aX,n <M_ܹA׻߾2S6>l2Y'p,;	 2	ж*4`=
|R/R\A`rGl#*/&Cfp9'McbΤI^ī	穫j$z>;PaZc"Fhպaw=X|1Ys,rxl޾yV<k5TֵsX~]M [jgOFDI/ V-
֢B$B燉U8îpAҫ YGRE	ID"ADQSt$l3?XYHtefEp?ێJ-哽#6d#>R>Z~8?r!ҵCa^LJ%(v@BѴnnS d~ClL ]XJLLLhdLI9kiiq|Oiǧl;m1NGLEjR	j^U#yUFq*C7+7_oR.v_&yAgļ1ssWH̪નχͻ{p5"%5.\]ҽg`zJ|^ ^0383\Ѻ)xlM6R*UUwڲo_iG%/ ]ϛ=b$$P)8<-8e5w۔}I<Gʉ#z}t"pXj`l)B$ر_î縳ˉS_@.FMlv87GWRdlEP6Vy=lrs3|ڸ)AhL&R䶼NxrA13>	9::0lT6fYX>oΣjwvFnqo4rK!\[ۯc~$zV|k?zxI!"jV8\	y.6ef)46ABLf EHQ!"Y)|RrPD#TZ!@ r &23r-i}:q0nkqfVʊG$*dx :OPB@TZ:Nn±qr?h<(IW>~ԥ.H8
aX= \V7ЪBW@MsP5%jYn#6
X})fp ;Y\Ql=~J@`>]gU\}YQQ~
htO+kgePL^qg@Sz8:OG
釈WF,c$S@'kơ	\9FtΏZѐq
mOer894BL{p`d_ܝ6&C'hNOS(D<FщLBa2Yp;e5q۷>bRY}Zzo"\wMZ?:ww1ߊun8l47eQsX
g_à5JfBXdAe טR BrTbAarR-F#bRZV0ήիW h0dC}7O?ʸ"u"]0Bjj_IԪҊ?NTdeZHr9:RH*,LWɟh:K d"BL'smDDyR`˃=foF|y"U-	,&^5qȹF*#eqWgjyBbe؅m4֫qwU_<?J\]ibڅUD.`J^zVｗ/F]/~.=672wb^@25 iB"!bIyX,+bBqƦz.ج/&GW{ϨPZ	U>cJy}<X|V3=Kˎ@Ws@
I+sy9Ps0&];|.
"԰>4d<>[wERq}:Cb^@;>׾P=t(aHFhqd]+s"
E($GQuښك+1% \$zDL㠥(.b#RtTp%]5H< X} +{hűߡ뽣8p!;'t%
&ɝRS32RvOrwAw=*oc>v֥Huu܊ZYu)VЀr唔L&BIyAPh|npq7'XGFg%JR+ \]XD*fuS8Ę`΋k_^ltn9ǟ9Q[(%mL} fH'R++U>27pjx Kt#0 _ssWu^0pTiHrY)c%
I@*V"X)&KF#-c{ϔr5ծiǴ~PxR>!&--:vo.uFT#@
(@,ϐSNVG4,ZټQ#<bll2cԚ|h$XViݲ1UEߺ^![Pvp{k{ipEJ-JPA*[vB4.>@#@rhhד)&
JY6ds'"xyEP9d+>2vaGߝHƌ:QO3=.2'S_lzZ2;̢S:[XVXl&iuMj*SRަ~iwgmZ[ZN^sX*tDTfֈᤉ6DЋGKEwct~>%ޣ88~?<ϛqL>̞,J~Ca6"WkVim3KtڋdnK\<0yU"!~x^DϹԟa?33ނvZyx~ƥs/'t#/oz4		Ib "c1o X&J|Y	"})6Bt=xn6aM$6\C#'@▚vpMј48\]_,lpl딧x~yG.amH/+%Jq|XV=^,ڍhjzOwKF#	BEC
@eו|2
\im\ 0wbr&fa;5!k7ǒ"M ((bj8+f(\uƍHclŒv)0jDtY\2Z-Q[o;ڱLr}\G~{x({"Pd\q676NVpAڍ~@W=Q⋯8(fa<!Y4y\U]]i3WfH3PqZ\B&* &=O6LA .~	_7CBtAn8v0"
g%G.^xdߋk֞!w= -]Υ
Q>6͈}2T_7zzգUW^O'a$\8(xAS
q㦊7	FWlX{"y奰f^$f J뗆߯r<^ba>Wвf[V2ʀpuk=6ADׅ;Hf >{iԢLvy	/3
zvAkzɲޣ7V{WZI*}-ܥ4ʈq::wTe>eRf{W~++ZNip1Ö(F0pݚt
[p$J~Z>%_9hj刀EbJ\zp9\.˛ܳDľqC		ՊZDp-Twm8r+\[3qn9ZYfWEU;q7ga"'\js?6291 TxJ=czX9=.dsf :^߁B 0E,dB!Ey@(|7*SD/>G:4ۻZᚚ>PXsC4ebTofq0ߎ聂t
 "lP(iLEx*K<
x<̭.pZrejͿNq܋9&Ed2[Ƈֲ!$ e^FJ
x'q937yW^t|\&7.t@+YxCn]xWx
Э bkZGDwnq
Voa	mi@+*eEߌˡB Tp
!ǸC~ŭ'".q˄fLA7_rEXw^=R/?
Gú.0@!W:]p^;nftm+ܳ-[[=GLg2	uϚwi"' 6%GB$99sE@ȹdr.	(!iP]|,I/-GHvi6<4uWt.QU(f .aN,W=?8ܟv{p00OtѰ]EZGhj/D|DL^H¾8ÿk._tgfڡk/)Ak@ESA#0oDI'~Ql&Sm~xG(*H-pWVp-16,ɆU*7y{w?^4򕀋+-RJ%DX"prR+pHUT(OsݗasxJ
^e?w[zvʩ` JUpqbrgNO( 6:|XoT3ߗyWZ[塞VeHz%fҰUG<+-lY⡆],4w DPHXrwZb9=2NˀpIUve@8hE]
fkcӡƦ0/ˡM
W-hȬ&&0}\w9<(W    IDAT\	T>jՉD泒ܔfqnYISonTgII+I|@Cˤql:wS/E%@?%qfJfRCd*Hpy/+{`TtlBJ$^_qV	Mtcgju48z}>rkIz_
5UUب49_ɗCb81~JQQb*-QH@7nZ҂f|2fjYո:3ysgZ&qzG%O
HH)^M[]/;<`яf&K8DZ+|kL" KY
OР{	AA\iuޜ.Xll(t# ]pxUz,꺉Hźb݈5XSƠva6Jjު|=6Gtk֭Y9N
FOys؟tCp,jюOߎ[F#7+]9%Ly+XlYC\ad$'2"+\KeU5[m49I^65\#AٲO8}#WWh\%𮎷^7՛MrahѿhޮW,nībBau#j%rU:%$kU*.kJNH%\æPezGKo/BU&D$1Q.:K饋-sqx,In-VU\rP%\@Nڞb^Q{3d/Vq&>0R>o՜j:.$~ΈWxd^*	/\.h%zw>Bk	|z#&k\PAŵ@*iYϽFpL<S	1j}$eE%?wi_C8HF>-ب4mƱ)ZtsZ&z,W\Lco9 9@,-=VF .3n63`d+Ha=CgYyZP^,V ]""x\+<Gm1zRl^dR,) \֓bak:kݮv++jG2o7?H|D?RH
&I[*U"*ciňxLB8NDR=;`SgR}ϤB)[EpաkM&`$B.gjUPiT#/Y%ʂ"8.9OWapƍq{.=_X_;_Lk o4ZfTVu^(Lz>ΪVWy^uIJ)Fudz=ך}
0֮AvRS)E+j @S6yqjeS=̏-,AB{ހffsfuRIdsArG~`< ss0;lm?5yĔ9\b6?t. ލ]6_u`fݭyj#0
]gu-duׯ}l;"0.%#9<\pF8jK坺T$z*FJ,Ȩ+樶3Y}Zjg|RٵftjڸdnW^vo3V-ks__SԼ2aj*/;HV#ͽ{.B0xaЊSa?^DAfC&$OoiӋLGJxhD"DXMLQ2_G_n퟾on.>=LDhe@WIFOB8)Ms/NdgLrB9
i;+>Qrŵ[H"N%ҵ+>*nݭX |]^?Oy-!u/,x	Io:-TqOP>p/#B}Ӛ1جTCE]HiWݸb/֭PWNY(]Fzv}вHQ55i˛3tEY#ZTZ6<qG:А}FpA{5tޙ~'$<= \YI;1z9HK:5"o
g++`=zV$'IGzS P]K|)\ϒ]Zt~kv}
7Fѵ'oVqf,!\1rsmMKS	DD0P/FHi@狫|>PW,ൄ#ZEBRŞ>?G$(h
.X/mf )$19[̕mEل;i?XQ5avLoip^p,=@j?~.}rN&tKjNyU]; M6UhyU}]Q;6o5?3vq֪]kVY8Ey1q.P*	ZI
-WK hxuP &XPp)A0LqϹ7"v2$3$=996aFl͆B99g{a-#|Jrq$l,\܁v6_JAJQ]\<tq5_ ]C<德m.x'(iX3[{-ƨP4Z`knfj֛wCC]׃<5)]󺱡:Rm}+g"kD6K-%%|[gj,p6^A=w㘘 W+:Bgĳm\%r=:<栲ԲPqjeT+:fAk!RԵ6Z{o#or%BV/o\hP1fsʖ.<ko sBs#3
'1|4&ouaV|$_l]Tˬ5WcZ}-T!/xE@yߖDJ<κtTОn㖍[m}?Qq_(ك"?uugĿ̸g^Zr5eXw©%%}V3ϒ[Z06ϓKx=Ï^l;"uS6J|x< M/>T:ժzUtΉxqnNVa
l&;kW.>aeHM-o^N9VhsRL!ҥ<Y- wAciYoz 3]"Dvt::mÕ;p-ȬVRē :Ox%%J` WrD\Q]axo+yf{F<k?-4
G1JrDwq|+;Ga~~|X#푮RU\˺oW55 rmZVp[>^o:ʍ'uEf%8Z
82&nzcKMc"4^#Z<ܱ`[5kB,ͺQ$,d [rEyJ_O۳gQx,%9t7៴W^dZ(ŽrJFADje

0*ו/d}|bv{w{[%:Y6!.KNk*'mCKVHȦKŊl`|vmԻnHޫwλ;pZ\g`Nq\TeI$޹=|Ku	VyMGN9$d>Qiɑ^a4lr5\:-XN<8Д;4<{?h[6(RɤsaaۉO{HJ%q0N]N	VR\rfq>ޖ,SmcPДl+N&UJRFbu\l:?CJp(
Juʵ2Bޑ0`WT[W

	Y.;>C#PrTnC_D&I@]F=qZ
cpEf9?Z~D&KI}?7ҕP$D!=+Ip

Bիmس!/s*Џ{q{DlG}#<TUvع7Ɉ/([Z4ZAǍStBF}<{~"k<umutaXtMpNGU2	1;x0AwŢHXO@E\Ij+L6KlsBaO7xx%$bN	2z#<mOvxlV.=s笢t׍]my3(})oO;/LLL,LuapKLnn٫י\:^;^K_oTέ9%wr߾"{ZCtV	eX۲ى؎6W:bU<FM-g.}iOM},( 5C34d֎5ߣ+`E!*U$/\Wza@٨ih߼@Nn>|G̜cF-1L$)ϏWL,Y"b6%DtuqԆk-HW7
h蠋.@Y7}6mwC_O>xpsd;7~l?
讣b((a2y)+l"S^@@d00Ձԯ.p:8]ikJ2Z37Xnf|!f1+0xy1cF8=ۿei)"z]1,4|/:#U8B."9'Et Ky
n+%|Yϡ0/8o`v:NW7]v16bԜXHKT3Kaa𚨙2ytTj¬SyǷjijۤ^zŐ zp*ezhyG%#B~Aņej uoGgpDy>_ziTQ"fmNK-BEM{x;lݸoN٪ʿ撳 ,gƣ1tP|1zA]..Sl\ͤK1	(B+=DDKDOE`ׅ]F
Qxm8Ov|fʵw{pdn2U!5qTTĸoP4~R!:~/wpQS&,K$:Z+(	t+)HL|*vLMuw?dY
[ޥ4,PpנUf-^(Ct[.JM~tw}`w7%gg'b޽r%qp>[T{i%<W. ӄִ_k:Mr~{,ڭP8#بqBvβ걱lIcpmab\!&͜YDu<x""BUVQ[o0{jA&DG4y1&jJh̄pו-NrMxDoRz]B]!
+J7o@وiDwgnяu^0IkF]s	b˼uhd֒%YZFzTJ}	J3 Ftl79fٷ4[ڭeo%7MOH䠚3$F( V:&X	s@E :5&/f&/%&|dk쎎ޞwDൡ-ܺNcMpU!	׾HQFk[VH=\Z?p|jrZ/ $\aZV咹j2IFոpx9mNTWWIna=_ȧf1
} L׏t[d>_Hʷ%w]v_|ˁRPUIEM&3;~{BAi)+D~t\:DvښMϵozdmE].+;5U%suZ.;)4
i+4$[a"
BHc1pc͍\5ytYDn@]Fg"_\2<I eZZqzXbOa%\Q	FA#輁DKT13up\D2t]ƞ|vhk&F	<PnlF"n#HF}>0itiPt|BPQ]@ZAFtAJ	A	Qfڨ*7vBӝm,`еA.ZZQkO|<#R~u˃sǋY,e2Gey$Z|qua*:u'Ӆ|zj@I>peVTM:;<)w3ӞtƟ.BDW| BW,-.7^'u'*IsǶP{d>C/1z^WFT+C{,6Iצs=\xX@AəhFƂr,Mʕݨzw-{]vh\
E\[S1<|_ϸ!jja[ax<|b0wr1*Ե3G,4U
'1;ŊrhHWƃXKIU`غ0Ҥv1Z$Bet40Q&Po% uuzJɡ\hd5yv_;^FG?*mRiPty 	U:$3AV:29g_ul/w%*AdB[=&&&	 ]@#`dt'!ހL2%`?{b++c{zVp
E3>(]wUuPWl͛7Loٰ{E%MZ^kf%%S{RY,b\Tb1yy@Bl1-ax#H_<p2WWE"<$`rQZKip4뿃>$>[]۾wto?ݘ߿꩹㗯+;ҐsExQ)J !~nhM! B`m}ZQNTrYIe2p5*F)Uh'\.ㅨ,fuoGތ >BtaA`
јNpxXnZnnڑa)e}-+G$u@HUk
%ʫ(&Q3b#9hFmcr}jr1py6!Noe;A؆vޒ0!Ө .^ٴZvɝyۍWNer~+1%C_g&Ʒ.-xA+E4"vd4WUCkCV\l}$ɟ{{~h=ei,.dT#u!bC/\,(;<̛s;.RwpV-5a7qT@ÅB#ْF*J )
]*iG xmr_DH	~}>_/m$X+/<UE-6(`s92!dK_xOc81VAAP%tUb¾mL%XoP<1ۗЫн7Ԯ^	>:wDfsg26A%ۛs8BL)va\x^LcxB=;gF02lF?@YǫX,dC=:zI҂lIM&A<}2l6ßؑHjDٕN>	w;;Qњަu3    IDATgfZdcamiqlzH=YZTVv\)dE\5ÊLg 	b0+0Jk๋s>қܾ
tBnr/q \sTq~<}PW[.iBshI|z)&tMAEʱV-S9׮e{rtF.pB'&<zTh-L+KPDusf~	/+/](j@qG>b"`,rg
tY3^nBf#+WqLcxm/yQ
P
(-jj^_:>PgCЄQuEϨt |c;C=M=e)/wG&FZj&!'[cm}dWCpͽ@MXZm#
C@,P .,AI$ q+j)>	=d%zlD\jm68*UPFX=6mV{`HW0].^__xX\;{`=Jkrh 
.$)B8Ci=NY9&F#\H}=C0
 p8Hc|M{}suߕxÓ}'q:)>-69O@e6Ðp?'fלng_Qh{ښAƶ*]swiTۄk{[tkG6[ق
ۏ^Nh-;>5<Ӓ4y@|+\]ŅR	4,C#zO:Y6[JJ_bm̨`_Ȭ+dBfpKą6'*<:鰰w{5_e''S'Cz@KU_^X5ƽ{QB|kΧ~1XIx;t$D$UH,2yB_:F5&&E$H2~NEĈ$M8}4"D|Q8!$-}aBŢ@PeggJRwcs9onk;d36TgCajmYwo.$dp 
89kJGhlϪߎm!	[ٯ:IYqNu67vx[yMer	m񴤥/ǻ3tx6^b%עV&ŋXvuJW`vT&ng\?ݍ=[u7$:ig'gyeu/tJIAk&kBa{S^Ed6e /?|Ȃ-ȷ10RXɖ8/J
(ҕV\,G mcJE&/< ٕS}/z=ԀhV"˯xH߫[KB;~Fzti7nx 1JQ+d/,)_^lqЩJ K^MG$ZFU<d+ocddD6* Pz/YH$zQqE>֭,";SR)&lZе57U>xd\~;tct??(Eqͻ:
::+¥m#RY5)dyU״mv{ϺsR92z
cKdvmιkM3|~\FB}#ˑ.J-t>(^34b@kFįUZZ;HuR۔k|kgu`3d{o:5x?zG.xeL@(W,Lk]cfV@҂"w;R6@s9~rn?Ie#(\rũű!ˋ%)2%+J®@_eB?"T\W)z`T`tDhkW>(H^9f=
ݫ+g/}<zZv%BZ[p!3h8uݏ?@҅}#8Z>w(M0w*RW$h@/t.) BJ(2[	ZP0-B) 4D,K$LᤣiFT	঍WM'2atLk^הS5mU0yNvXVսohR3Ka Ro4L,dt2Nui[fX"f]ii<ЎGJne8rJ,G! 9=-/4r>>}.r K{.M3MC 0ry:AF6X0p7:T5X~B&lqxW̭BN2WЩHyc#s+JdR1.:=a
pHŦFG#ٷ[&lk{˵'pm-ebjfO	Io2;^p*ÌXhasǜN鷹f$9cL,\(W*Qyu=9Gh#W|$;6b#HXy Uf62A୑7QPסw̅՛Jۙg@ցcۤrhA_T2͡NhDZ,c	Ѷb~S$Izwjk
]_#Y]&fHI캼.Bpeh-Fg9Z({w&\[#	xG	)driz=:zKcr'ՇFǳPJ:si.7h\m"+3A<PGu0ՊP
.WX\t"~_s;5KxqAE"a.F@&l/$u~Soa!g)ôW]u,P0a+\q5cpmnX}bo q@;J"&n,hf^<{GBKV[	e(<,BuJ7p	*U6sE؊%WŽ9"CDp+U^Ͷ1+Rg߻Wyo~yLeJe:h`+}uyQv˸e0Z(\ˢHR	hti܀Yrީ7gO~Kch]21NaaإS.ݱ9-uטP	'(d-LGRrNJV^oF.ÐNxT/zޑB]YhCc6lt1'4{2q4C1\&=Ei4W&VkFBKP(,-{l̶J,:pYEB!OȃEŞVl/DldNM$Q'nViQ1&6k-h䰇?s{t%l)+t%|0
Wح\24XbTD)PQ`ؠlK 8/VhUod|V$48G2AtqRn!P	㾄5۷yU1/>BV4jch)Ft88_]#ZMM}bIhq!vUQȽ%8x/N_9*pa*4,Pq%WJ!.DpK?	so@?zLIca.-
L-⥈q^JYnhp9%L%(gF" .9gPWVi)|X&̊_Ɩ	qSax)}DSO(Ҕ5t|Kkevg]孃	i-\G,b)\e򩕞%]@4ǰձ,~?f0pPF,\XTKp<nq~;F1CD~4HR`wSJ.܏B?7Lf!V!n*KcAW]S%I?׆Q2hg0
W*+)^ EǏێi+%*A\,]G^)J`D>'7Pئgm]2(şcJ_")ɔ8^btŒ*h!P.&\(^
r`UׯR硈67|w` x/O~iܛYC~gދN_Qx<5DN[٬kRyXnG59P,\>kibn;wyL-EÌRjww&5_r8íQXEINӫER'[:$\RONTlųĺ|@&3cbMM#3+~	ly=6O-.>qasF.{nĂ! .Dz-bs!]^#S{>MJ2N_''II)d`f+1ϝ+rJ jwlj-{`tH%\IN<HA?t} (
7nj[\؈D	GdPV$͎r1p}e:#qTeqi}&C.E#'O"\;jU|IV}ƑUċJSZF,]2v?iei5fݎ;i˴:^̾\AҢzUh]L`W/ȍ
wk߆2Aj_DT][[kPk4qϹTk;9=ϋ}UW5>ʂ&U Zd:ee&*O_id@?{-~nt'x'V]yhZhNǔ(=YEt6kvD
4\ݓ@ڶip|a#HCm-"yd/LC"kc}f<7GCA$$@*d<*%I8F<	Wgږlx464rD{6w3|>9Jv=Sfw,6w_n{
baRTX\k-0rm[M阭9Yb+R(yyG%E:mb]؊wZ^*O''BjQ"9Sa3|DQdq@fʕ(S:羼/s(O"s?BhWN/~\']p'2x\@PEv3\ ;X-h45j;"n+yq.a]Ţc⣷KygNM@i4EjZC;Vm
.LÄKW*0C᪳K>(Z̅;tt78}:w1- EB,. ^{NTU}z0UU*UR 0`G9s昧k:u&0,*	LI Q, \1D%(r<R(R$01Q]-"0qwpxlq0ol5[65»crWW+QQlo{+ nZẐmp@MyuX"Q7 /1AW"d$8,ihZF됨3@X!C8>q7m~
=fWBFff}rm(NE[wT^?~OV7Wλŋ?\ 0Εpzmɑ/.=E֢-=Q{P{U!WZ]x]wxy_Dn#*l*QW5ssB׽Y"^ŵ4taᛸ2 Jэkh]Soǳ{TƖKg&~~r"xj/\u?7Df_WsUqU
wD*~QُR4_^WF::ʂΌLux8@n8pj<ӯWM0sځj8l5pI1HCTF(	BpA`*Dy(JR*$Gj$:[ljy-]g,>ZXpҫARt=q7Ǽl/c~-;
E~4\PKKx<d\NG,!uZfcÜOMbaJ*:%4C6`{jkdj%1<KU aF":|L)K)e3Fw}kUwlrelRw>m뭺-h,CΕ©{=VX]V=8-2uQ	(!>Xպp
ZEnj^|?1O4Ȁ"izkVO_xܯ/	C}*/х&}*^vWhA:'1\ӿkqZ \7=v[guc3FqKeJXW!j{u^(]Ϸ퇋ps2cr˓w/^p> ́  [B)y
VUa,HI	J4aO*%ADAb"&k*EPQB fpJ<7;[p̯DY0N差('JۇQ-)] 9"W,K<|Ł$N<{oKngS -o<a')EXr ^^~mf1r9ማȏJIGYb~aTF_y>+fTJ&;1Nl:lTκ̍Ol,:pr1R;L,N
.+='J ]Ekz]\(5%<ZRaru] GF#d7bk@-o	y_TY5VVָdE3us?W_ήySZ.a*)dmii{sGs;_}qIccƂwe,MV^   w}l_W%|쉚-L4 ]}8l</9cvMcdM1neqH	Q\=Եɐ
Sk3ie"lmJ[!"UZ\+Bj#LH׼<*yǇuwu0f=say~^0?!*DHkBQ4  Xd3" Y@<e@^Jy28`$U%>]|\ss:rlYܓVu6Аd% fɓQӳ\X aa8JEC+O2nKvf!,ɰkQG[xX2aq<Kerkܒ.spITw:XG{J
%Ad*$c	["uıa"!bn#1?	pЛJ~70rOu[0Dtmg
uk{-˸9[tTՍM7*C:!&#PPX*?PSF,pyRi*R;>:__t\㍨K۪;7n\< \rphmgKs2GtxÁO>=kwjY]soZT>~<%t`o>?zu;zb\16`WR(n0@d
wyTbCۿgtzѹrz#reAW`21,'h*Z<䋎bB>;20	Vdl3e\:6b|f	 [&kaS2FFYTŴ	IOuK18jcrbV45ϸWU.9Ő,Ax"0xɮ,W൨PP@B' \J4]p$MIlp[@h)jq{e	H5Xp[F؂k><斥X^<    IDAToG-P/:56ukׁ&P$]ܦdOv}1)B5xi5Sz_gRrH$HM}gKBjJ6YpB)W?cE_(bR|{45J*W_#텲oŅZ`ɖr5\p[H._ߤО:	uL/|u˩뇆7wbu7xI{BU޸8X)CZF/y5uRiF\/^{vlo>pT(1wlnYA:M`Hk~	fqЮ{}i_$BIiB*k_̮ ֯`	Ҵ$GIn%'u:_g6,n)W+nHRZW>d~H)e6cn1t=@^fD0YqQv:0
*n1
%lGa(H:cb,?y&KRB$	H2qjn܌<4ClD-uub<qJ86aFoM [	BVW2Nv\mK{.M<Xtrh)OWYM_[$^w{ZY^ZkWA0F,)*R"{bNް51x_%E*jOUQ !㖘הpʍIL6dlxP#_>$ynAƵ?j-ZGq$R[mML<WoۃUm#^DB1<D
@\Dm=KPhidVd
].TKJY`de	c׀e$f`u"㈲ݨ$B%QC2>Aj}:7mv#k@So43NPH䎑X`qw.
zVm" 6uNQUܜnׂ\8dUD<*h疰PNDR.9iP
AyX11kY.*D G%5LP3BL-&{ͩ^Sō1[1D?r<˅ykskn﭅'e	Aoߟsm:Լ[0ܷ٢S.]WEJM#TqQq=7zR5EJ^ 8+`4WyZDQ"W_5h*5vU/+jX5PrqqYoWG(SnE,6WM.*uC˚|1Z-%ZK/s~sg[wmGD\wuYC }{~8֛)j~@H82;tyL$N\2Vypu4++$: F%"$IC)-"0LeLMrnyd|B~WfLO&c~1Ҝ2(c:\S?V#$p<J]ϣdhw `78RKn`v?iwwɥ1^ջH/fY^LK]+W8p3jheǹfYv|>)=>S/rÂZsښM-JLDz0:BQ+֋DU1 %]gHklTeK$KR9VyJSIC1f&Q!>ϗ< ׾CAߣ[[ ۩wVB''
tzzkh	imhƄDEp3и:NBPZ]pɛ06loíy;[r#*T3rծV@W+:MWNM"!;Z=>B--".:8n6gQrMZՁ/j%fiN -lZq]"}+QhL"J?J\՘L I+*4ba:HFaRa]ۭ)}5hw됣Yf<1){WM*h}f!(l[&rpْ$U*Ę)kS)TJاVo_P#EbH\x<!X#\ &8ǐMO W+5A q9-1)1L7U29kcIxܨHFFc*ݷyks5荵V+ZVv5?tÑBz5બs *IeزGCqՄpiw~쇪*H v<<:;[;`]S<?VUnډv&/=+q^ZZ<r.|_^x	+ދg~0j3	ޛm*m#3qe٬y~-8wWQQɾ[Zpcn,޸79W0,Ii11\`&!Eb14";{ҙ@tb$8	)݁)_:R-,'Ժ]>f)K!2x!Ɇ2zȨmaq1Đ9Վig\Ǒ٤I¤(ZH!M1>`	%VhY(IPT^.IpK 6 tBU֨ԜgUWYO+qMǅBTRaڱƒC!4#˔hھ$G3ɅE[;߀k\+E#w@PFe7;iS#[PyR^n;^l]a+(57<M?!*a;CؚkCcEmdeV.2?|492rgd9ȡ=:{Z/]跏zdxӧsh\;0dHO|hD@q{gpŋߜ$WN:7oLO_iXZ2rMG$&a\*O53Y}BB<L"q#dը?Rtx]g:|յg]4ZMIԓLrg`	A->4rЬMdAO4FX,T`<F]Z )$\9
㷐ZY	xe*|Aݾ(&ISFU+1'7׿qfx`LhNt4nI{<`vP.|HSϧYC>,\xpN͒Ƈoݳ?=J6.B'r Q0BGV:RUT6ԩy-dK[[3"RYDmANPӉSݗ..VިgT<\M97h7S0yɓex:'n]Y2cq{Z?(ų$nޝMsN}wgD:71VZK<ZQ{mz;x߮Dbǩ\jf0WVW1F p\՞gZGR-k/^k+4AAhH .8ql%)9a4|_F~3p}4{]%ф9xX67̾X7߼< [$tٌC6s!4FQ4w$lVXu{q,W4{"Dx%=F	lU2>BVş85DDaLJ(@1@K%RreCblh'C.<3tD"y<wohC'snٶaB;"_.,"CxEOT.k08咣-oZ]	8j/ĄuVqVѯ \RVV'QnpT˷ 0T7oV|E6U?a.uKn4!WY]V	PhĪ] ւ1xdO¤@DAGأh"pmfqmkxz~?DߕƔL?Y̳/qBhov~Iybv9|gWtdj`QE\1|&*wH*Hw\s2"O|#VHB,OB(_M%`mxD,TgT&Azߣ)]S<Q&u$UǧVG+85SS={$u;@\Idݗm +ĖJmNRȂ!JT*M.qw&}ޥ-
Ŗ@P.\Dr[LԕOaP:RRL,w2<NBLbGCkB_c*%3L!bTEQkSq<&R:xU$utrE;M^//|IPvm#$!}k疓C/*"C#>8*i܀|Hh.^uF
$Q6 \i+)W~U	:UV0[U9pǚ+yѵ5$dkX5oWjo?ÑShn#g|=^3i{vby'7E+ Yc2`˘rov^1H]w*qWOK|Qddޱ(fH+<ЇNnwwbٶXzB&B{}2 NۛMTǔf[e5*|>,K'T6U;puv.B]I*IԘ*5Jv%tD]]"RIA9?u u*=våej..(+̓QhBR`䊃x!B ]$F]W$ӗ͂ds8l8qP-:EB)lp1J(I!;uN!ÌNp:RmtJŢXfɶ.Ӆ;T	5{!;hۈ͘{%7|+H<4WeߔVA`eů?*
FV|+mCpՋziDPeߔ	y^ec#lAZ(F;7z[DԯVmM>uyh;5߶]Ā|z?NAMEgΜI!

FPp2A8ثAplC۱?౛L㭵SSZ+K14]}0h͡ūys`iu`lU/B\!oۺs&Z>H%£0I<v6e$ Za*\]i0}5M&}ll9
:^][^@v WDA3J2\.\9C{w/|҇%md/<,/1t\ezu*{A
lS8d!ӑ5$X(HFޞy-&eq13AK %EsKJۀ`%O9[$[sÃnЉ˱.:nPIu>Q댡7aڡOڄkdN	w+mflV[yhhy
DL(Q:_$Ba2)vZ]oi4x׎bx3eETaԖON.TGeʌU7'Z[Q=Dx[&\Xcfa5\#=6z-B=P!`xl/>۵܏P; xp~=Pemk3aqBlVSU(IBkKNNN,wk/^bn,*`͡L*vk<hІg]T}+QH!RVb>>ոwpU|XL.rMU͵Mv(gy!Ww;a%ĉl%q@4..f/EN{KS R0UN呹eu!\
m5gc]T
*A"H%h'N:{܃/y|GI:J!YyzruD]4:ӭwkS1IOZyu%'5xXE;WiW~~ƻJׁ:F*zI<CXf~X(˄i0?b4r1Pe4
/Z<Q[mt
ͮle..t~w<ZqK<@'cWpݣݧx>_ ͤF{kcGy(5K=s鑹UhLxВcdjpp}ʆ8V3QI ,* zbayyEQ;۟+gRdQLYl8cҾpKMbB,]:%D
,ǩw7na'.bc1I~$]@FkSZH@Fs~~DlѣHi9%Dp\Ēaii]"qpBl"d0Θj3Ӱ>JXPIܵ	GXRPy)H1VkRPgwSH(M(l t>pHV14ӡo!0?^7&dڹriZKGrةb^GTr9 jťWg{9r)zpRpqS-#v$yyƯ121 (^0);g ;t<Q3L2_/\ƿ?-	B^3ج	me[c,P49}Puu<3.7J{ggِxe	UT]҅93Ί֊'(.,hqFmm%elJt<}~v#k|/!f EU+߁hdП;Ϩ593rz_u^q-iv8|	tsƞ۷0MVvN;Ǘ;wcQI(L$b~u7]3l!\"(.duv5n[۩ !m\3Qh$Yw֔kxd40[č;)	["T0AMqw"PHх{ea|p|u|HZ֒4%&spYJ0x<l038f|W40ܨ+e-\GwwsQ:c4O,ƧݠI_&Ϥ/
_=6|ALvmf0l$50<r1@|h}'_?x
55M9{Q+U_.o4!<rzZ	&3'9+sߔ4_}"ki.VYQD//jjjk3y1mWk_'foޜ|wPΏ tGr9riB3xڕ:IO?=0p{;qy8K
ʰ^^/(ugvnCh!Fbh4iKv`q]b5`V[`ddֻ^Np|$\
Bfu(v"۵&$l&tZ"n%\} M^%Bu2 $]#$᳹\^w9pHT|*@b]x1JӠ&},_:DJBTY\NídqΕ[H-(aJ$ZFĉC7hP p[r
s8J00bJ#Ҡehw֔?I9eL`4?wB˵eO/_9,ܜfd{fϟh^_^̾60zzW7BrOWkgz<pr&|    IDATngkSu^L Hʊʤ'xJYҮ
5ڄW
fgMsf8@an.ƫ|u~;X,&|AP#_>Y|[grڶ;v컗u3gջt;YBu-A>w^.?~Ã흰!&T4~V,3藂ܝ9A]1#k[%2)K"ZL{qT}ApMO1jHzЮ Y1:$qX!QH%nSzZdE"Fw(أh43!^*thR(v4t!V/梑ĩSjRFvx`%.ŕҬbN["Dl!*r<,F-X802s(A=^"9Εr٦DA?/'"0AKHhDMLV>6aP@
_YxA^R4킟fzyl(6x2p\x'x
S-?	At"ͪ)B9EsAet:4\M'hT_I uR*WMJHfb'+j{ҢTkgdⓟ-^ݵϮ^J::@:'G2k{aaƎ]Z$KG^/?YYCp͹FwA{,1ê^osGXgl6*ZO<ưMLip~3[\.GEBG.xl_1CC1DDp}:7!-(n_;Qnae#"=panKF#$U#.;;۬׸EC7Udx[MR~"8(kNwiP7S*^APi9|=P
rJ0?`4s	&B<>y^O/(C{,S{B!dLDOx26 \ Sy|X`Q1a(H(!
CI:.o̍ZF㓛DpB#i`s$)paJՃ@Vg4nۇ0·)'I}qu 74vRkkyFXo]Pگ_jye^DO}N3!#٬Ֆ'Wsb@TRmʣ .Ǽ̄u[O7V},h[rႌK)fF[sW`Ark-\>~ "ϗ߿)ZϗG~JQс+}k+~_Pn2*jʯ}ϓ{ ^8zQH91Q]_KEGb'ȖĆY;HOܳ6Ro#x	`$|6:̹pk6xD&p EpNIl:hlFT+taWmz̡ܮjCrA'8m(6lZ>j|዗/^p<nN tb(\^Acsa&fpalbApC1nIu:Q;I9%WcԚQ.uQ̤
PTkRц$kM%z7sR-,ڶU\\Gw9G[Uox^k+ѴjKr08*Ȯ*)c	b
׿WvGg?'Q.(;29Q̟;C\rNfnD_d!:wZ/tڬiP<Z\1Ȩc~pg\77ۿ{~tXv9$KI9U-%;_(ܷp#%&D?Y_mJl'[B߶ǜYS3)N|_Og\j:3 PnC# ebMԥU 2N-t,8`6H X@ChB4t\J-Hp|̥&^pslA\A
IxN<vi#!`jz?S!DZImÕ:q :/br2Э?6" /p3X1¢*rxL9&Z_,LP.m)僪!_  j )$LrF8/\4YKϸpǻ[ʵ;\%oU*mEBIL7&bJ*uG*0RynEf\7J֟1ա0Z֨KDڪ3yuEUN":;-5BɩSM]k'ilFpE[Wa-\57{&UJ(Y)*9vbZ奊8R\Waeu7ྲྀ }KڟD=bDոz?IםofCCS|X"<_HI~ 铣(UPޛv#uIiNR=I>H1icTJ"%:#z$P<8!F4Oz^#9̓ژa[0$g&t:e7𚦦of6$H2qJFlG"魨zEB	3̖D,inP3oC7YV'lM҄ɹwbHXr9\ZO|FLP|_ΘF'xfTXҭW(Wvk[5hzgk\۫ۅlN#Zs==Dkes5L_pn:,ޱo?3@X	k:9D\U$hcK u">2<zk`rF+-On3;DSc[h-wx,ZV=^싯͔$Y>XΉ{K(U/n 'XU+aw\띚:bO<_WzJ\[0!BIq,mOYQ&`lZdY<Tk0^zD<gS	i2gդeG`Zwb8Nm@#P$!zehԐ2\$n^c "Q՚G
G?4N5j1"9Q,d3DFXl5ܰY 
7<P(lgtqYR*pSPtn=dO>U.i%P'J#*_m2.U
rvOIyۦkoblw삦v#Eu	'<LQs[1̈FlPE[;AбEJQ+O!?^7ѭ[1t2	v!YN[~n[㮨nMXˣ+%4yD=ɗ-HYV,\U0+#[NSj `q٭gEU\Ԃ⬬SMo[2SP\ŧ0qS"EuŔk29/"c(S+J(Tڳwį~WZZ}YZƷ'ٴ6_ww,~ߦ%$&i{of:uBRhOX] 1xevqXD`Bf!UA%R!˄sh<ڎh0vMݻ7^Y\O	jF* :!ɕ>
Y(70@lh(F]XY[f5uB.^wPe{{UuƹBl&Lf @aR	JBb`֑Tr!
ǾcX:D^^-xnvO [owrI[_14=ǎmom|ew#hƤ3QZ\oLЈO:!HD܁܉T!?#S(RM?]v0Y(s<ƞ([ 1gD2ጇRUTsjSe8AEKqSY* ˕9w2ĖY\!󌠱)&#5]pAU	P&gUBt5tヒK_؍Y[h%<pe"4 O۵A)xvN/\j}׍y9ǕSmITUnwם;^z
mJ,I%l.WSlDW&<e{At87Bhej+	{۫!0k}QG%»WCg^XpV- jx.mus.N<"MPaU`^0nAX2r\.33:.6[io78^鵋++! w˖H:	Af)Q@,;=a@ @%TT!e T1,
!m]O\uu3jww%p[wtmo8{ϫHo[,ܵ?c7b	k[%
Ŋekqߌ/U:=2+d<g
e4/lȲ$\vm-+xDp֖ԓ+V-t7*
22GZnJ[|\E;E	Bؙ#ıJs㉿ڿe1Tܝ(N`/)MDǶ40;։ǀTw>wh.%ߒF1215ڇH\OO](I
y*HNPC;#NeuHaE^jGeDg]_/,l|5Zo~ZEUn=7zT<uepV1%0)AUh*5lCkJBN;xl)gu&\:*!bPT&}AnAM-"0G1(,g@O4[tWp	BUjl׸gt*otTth~wԮN~ڪ=l!i-lwJ%_шMh'ad%E$,r"7Ep)>eBQ汌;؛4*2b@fRY˗k._Ͽ)KқrVRpsˋJd=N#`\9ўmsRst/,6Bjcyå3Of,g~ˣbڟ>[;Pa܅Ç=X^C>1Tbs
억g5gRD$%UXmjZ_Z|gv]?8Zڻ$RޖhUl]0]ȥ(|DȐw4#t9 e![hvo/J{Ƃ]lP;-0mQ7,HhJߴ@r,D`@r"RiBl%f,z*Fg`SH0[U`fâ`
.Wp5tF{6a\m3 \HeB,ںgGYIdl|{2sԵC:%ߗtۂka2ĄExK.:%zPeQF\!5=.3'Nd"2X5oV},T
O'MXZNtY~]\P..3ߥ.I
'ͻjI
{x-ZN>9WÓs~spi?{g޽8kO,Zqj-2vOMWwgwܭSjwwdZıڵm4f]H1"Ls1"%tMq8.yAo$KHD%$Iuxl(ʢw~aH|{ss+m@8ϧBνnqV0nCռ9d\ѐH.|1-Yd9L #_FٍјY&ߒٸ\z\\1!iEb݈fR{wB}ɩ&.;ڂ\Bh_GAۻGA%Pr{m²)R|.Ȅ$)kjj;}fz̰[il\T-g"(aYU@NCnW(d(67< tR$mzFFl5w<-C🻞CwuA55J&JwHIll),@%{^^ݽ@K|7=]Vr*#Nͺ-tU+ .TEXTͧP*	P[ JT#G4VkzWRu^(_(][&>/Ȱl9WN',;ҩ*-͡Nŗµ):rF&rG.qkrbCWWz,c/aK\J?5ztɠO[b@*,2ɗUdd	ŪK$I.^lG"b1W7.
oI$C4307 ϬđlC ֍RR|iP4K|(HhmPjY%^-xp)\"".!Ruʀ4Oppl	:cSl#	B`-B#!&-@^<r{&!'`Th&u@SA8LJ%I,7(^_ʅF=Z4ƍ2ml6'%mo57fx/YzbLa[j^f#~%`Ng%ẝSQM\]@Oc®	[NB0<HN|S-dOOd~s.;sZ9)褕ŪL:uVu!O͏XW:3__6ww[S~2Aхj];:1YĎNL>˕IfkhΝo->y2YSP獘;8"7DÝ,${*^5Dy-t18Em>KSEPe4!,cgź289%qfhͣk8lOhX8L
ڰ)fs<{$? nd˗+;jC}cʕ@198_
%`R6japRlΔ~ 1wC=2 :X3v4q0da`=FRr \j]FcXNx#69GNR_Y?A\Unyi
wQ\]AK8 KU隀
TIVhNT]#v
]U1oQ"2+.)k%+jVUIOy
UaFȱc̢203S\{>UTIRCUv2\T&ȸPR[~?]M{>w>_
b+eێ%B^o~ֹ}&qWm'U%w&[[ss,,ʉ{|PYdq>o$Ikk`kM(HK$^	Sߩ5B3jxM\zQBP[@,Ixh8L}}ft9\[3Uba:hC0]]b2zbxq9%
-i2ue5^'"SJHhBB0U<޹fã%D. ol):(gIq>3Ra@N8S?_8m7v^hk^҃̌)9nLT<,%aN@\Qm^תNצZ~[Tܻ%uldwDuC6õMps1Ν);77|7B&CRו+;5bdpt9Պ 
4iࣴ**ndY!XFVp**MSID+,]ӊ4q WVk@dAPݲ珗|WPqHLӴf??ъ/U6B	M    IDAT?<w+|s]n{IV}+t5xUyMbZnF{o~7zoqmd(6y|k&O5xW}#
^ H0CWkVO lO Hݩ7\GlavŔhGKaϑS\3&ffgWlŒd}!6wi;!2\9;ߧ+LIMltl^l1*QWmrFqn6Zm2!HB!FD!Bk!7>E4qqȝ{yfspK)P-{}gU 5U4N)!\.nTæ~buǉ1}AȣBQ	qRà0&L$
YmbBU.>Zp	Xtj8@/!DM
paQ˘VitxI-n7AξPQ$ۊn>͏͹^q?gd
ݼO|̝p=iIclW֟q631 !|>W-IR}bIn(,[]BiBDm}qAZR$7sX2qo]tee(C.Kr`fHW?1W~pϥ_oN҂ւk5Kn~A>{#?Z~TF5@gm@JFv]TQBЬiGu .%w2<{&SC1-X
iCjbsD5:27іz.FZfsUMUfZ8uWM봏,NMMu:zr%L&IV2\띢Ȃ:Z3K攩5Xܼ#W4u2Ν'Ig6h .dŸwjigNhч10ԃUaWQ-<;>\)xгa09C #¥3ZUƶ5)'%1hUcA \7k퍻ߧ\Y?,.gR4<[E	f66dGeLVQcrȶn&\Vظ_H.I=.kygMHI@BCxA\7
[@)la$׸&)l@l6gv]n'vIjq}c_OD83;=W.Uxjg{~wSHxtLHўgf~ff	P7k1;;*uq,0ۿ)b'uL_sm3xnXVP!jqgM8Q$*5'WW{@gSuݏ89Mᔅ QbF)	в-NQlMM&ADHN,ϧ`MSNOznu%1;]CcSH@C+1#`m=!ڦc#^d[@V.n CicnPrQtY:Ux8|qp[p1(j6h9jT,pb@=P,E"Tƕfusl3^0=?Kg8fg/98c__li;;\lwXM
++wy.'=YN~wYTo?p \O'|"KrKb00Į3g$"Ç/~$\eB .V%
jB㮤N@^UvNׁMۣcn#p=BK-ؿdg9-.MLCm8auNfZJDT^kVR)2
u]IGɦn=K (,]6'n]6\6tP3?YY'Fq>yt;u[\tXȚU66losbB77YRQ36ƪ,xHw'7o67yU(_L-,I'6RC ^mJgi1]	D~@p
c4zl[Xe.`("'^4|WV2
.ф pGAFZ8NJʾ>uTi~jvg\?T?mXr3V|-<,-4ܝn?OOKZ2Atϛ鰺>*!b|nXZ|Qj0Kn0M0ZjPR ւV`uEb1Gt5|R2]\pdheu]֊PpT
ku7v:/9.{
u\O!Y>n_8li'ʧ	5ZL#u#--=H枝:X{;}F名;6p\C[p	fAXBjk^R(C4__\UI-JLs!	Z|VW
6oPcWÊu}RWV;OaZ03SwDW-:AggVqa[ө8I3LZ[h*8f7ag CڴkmEBB:Ua|h
b@Z")\nn4']N׀D#/~s:G$c'2",FOMO[Mr[Rl@E!j@p{tO	rnE#}z6JB-pi46C`lOS 9֕R)-)M*%_ifek'\;{w8VG+v~nImG]=[&
Qpzt?$nQS~vOqLAkVF;!;[wBv1mάǻPR{6m2ݎ8;; ]g:Mۡ"\_ pCm=Ads	Kޏ?<xsbUTᓡA
QYtTdF˻?JVq/h=KuND=:ufrLgw;D=[wJD:Wm,m"'p5z&`r4
8 HnD@j2n-= \u5f!%2Ym',>dl;ZK˞MlyIq{QVoVu61fPsg.ΨK/-a.zJԷ+XɇF
	)^~lΠMnDKNؙ=nz(\<XpÅP8\"U	\
aZ4,czYy®Lp릶X׾{^hP3]ۚ+7[ѓo+熆b+d	3V2ŭ+&8v\Fx&Rۥh嘘.p>#njtu7BG}>8B:ⳗG^~122_@Rī,Iwyq't9k6- W>ާw\V}RJaZF2TUU`j=]o]=x0)˫wvߩVyѕU.)jly]xIׯ67*֡e$mS'mhj+MH4?5.o]Uz8ƵA/uDMGК{4<[O<$[3:.ˣǇaI$[Ob_PO$al;Z۔ҥ
\
@ɾ:X͠)#nQ-E#
hd I.lx~4'4DkXR)D"#"'0%!V3͜9قb%XXۻ
[o+/YU՞ŽL[(P6[)=6|݊"UG r3yǄi~QQD'& [
E=M%}C N4|^g+N_O,b; ]Хo sA+FŊ!:zA4ξvN`h o|(oz04$ڪeXtHdƵJw.+xd^P	w,S?GO2+J`θz҅ϳ3Dg]D#R(*dm(
Ԧ4*"HÉEp%q3l4z<:,5g˪Rh=}`\ 0tЇ{02PIS`ֵT9l5)C:%YjT0谯~u.҄4:Fv>Hz'Z
'S%z8eHo f3ђl:kT.zp65tYpaJwy-(\\?7UWvK	ZCr?_dp|0kߵ¹]'w*o! G?aq[HX_ŶG\qw>e[=Gp?hkw^{9tͥF섣dt':kK鬃pdh19϶l:t%{b	4;;>[*^^<U|o?GGe6j@lqqZвrb-Nz@]3O"Je2
HLr맬tF;=.oH;'yTسc65a=wـ+T$DH	xyְ1izt~Kc)?kpw'@Tzpah»< s,yHIY-lAD=}~Fck1ͺRMGR/R*>GB8Ӆ|:dmv'EJVPr}Jt <͆a!&p9LSj5DKmVO)4ԺIu$-[pZ	"bФ2[DRq`SJV(]>H(XQ4*J7h$#}/Z?t;W1F={WCsy~sHzzQ{0uXoug\{ߚ pLM۵JS'R:GJOkM99مr5_*~f~v4ekX;GafOm6g81)zi[MSL{뒢P+~ߚrT2q!+ ŎV7nxO]?Zl	Q'sQ,R_r9*}Q^a<nqjU<x4
fX6ה$Q33A_>oMV4ᅥmr8)VQc `\2FtMEP2)TDw3r"gWKyh3%'/V\KpBɳF\%.exM .u$A*PRa:֧.v(iybPU'- )PrIj~Q?F;iG#d8.n5B(ӄL(uAk&<0``%bcքn^悔6w:<x0/~OFƾU/ueẹǳJRgOF̙|x&4P3 SM_45E^Id9igu
\+	!́TMץ0G2kjZl-N#~g+a/6+تFc[v{u\ Y]5
2YMbtoGʩ%-W{.h);;V07Ty]g,]@' V4ZÚaQdy$Hd:KPQgbTMȕa/IK nulx@>FlΞM(SLڜ0=tpjT?+nV=~> sa嚇1tv,6)H:HivcPє"0яUݵ#ӮK-q$H}\\F\F@\b;Qhq*bYḄ Ea2W5U/	[m-f}HcU^)opf5-I[XpN
M9_.LuΖ\HilNz~YHf/5XiXKwFNB4翄nQnaj*9iBa&nTΰN҆o[
Gp޲W62z]֗a0i76s/o`ઁ2R_	Vyymp+-"MJOfd_,::C^a5Ѭji̝h`|A$oѪ;zPLk,F`~Tj{Mկ	X"D
D,4VԔwo8|ptƧa!Apz2=laN%ryzcpԪnA$:dSa_ZD$I¯KZ;Յڠ u"U.%Hn`mGBQ{7`uZk)jzQk2	&GY{p{bÏCe͒rrvsNa**,}9kvY~쉒.wfxfsr h/sskYW*2؆Ef$uC$Ѯ9dha6yݭjŦ&8_?~K|5)t_V[]-֊F׮\P0UL|^wFQ*ql(9P1,نW<&圩|Ayߑ*欚h<:6kVGnʌLm68c	o6ۨMLԉ!Wt$@cP{EGxldJ	GYȝnn7ooឪLՈ4([4?YkZ౲3B	ˢlDvZtt*2Vk#/0l2W.v~0S$=d2KΨ%aFa; .CBN)58iiHPTc^\:XU^E!L"n;!o0̘9U84oz'޵ʕU>o~:rn>[uEh`f}|hF,%?s|T<H$t@fegTS [h2@mze,:.4汁 /kaTU`O=C28-Jkׯ]FVT ߆I+ihAԊ%DaKÒ]*J>?',lkg?Llf
O$.֡B[LvD"xHBA+E7JJ LLMC{^KD	$|sK%e'	&z6:t=sKڤe&`mZ]b\gBFfoVXtB22o4 )
UWGC]T	YayUBv_3kqƏwƆN]adC^m$Jg>\ɒbҙ(cpQ||!Li@VaSNMQjn_Q8|.W+/R8.Q쓇Z&M#	DBb*iz6\>>^
*![
?V>ڛkd߸;Eoh]E_̛V'_H$ݲO?/+>>jV[;d=fyO_}*<p"aKe]20&BpaVw)Soj'j;N;$0pvVR㥦k_	<ڕS.y}skuH\ XC݉y-.(߭]yBE=    IDATG|vV&w;Uk*F{XDmTF1X=%ͺX$.Ҙ,re\펩mh7|ų+,aiiiꜘoHj `PH O/kyff*8-ԈznT.Bw֨j^'s~X[~ևA7S,4:Z2x^؉Cw|dmC&M0\:8B4:3058Cw%*v	Wn֓oh7ճ:cb3138U`:ŢX6I!ϔկ@nc`7SAߞFc/UݒH>[П8sك%%K˪mX:~R~R?=豌+(k,9\k0^nJp&OHjxaCƕۻ'5NpRcyet?u)G.T3iIDW.I*><F'G_{~vXI"Jh@Vˢb8B6"W/s\*UxKv?IF T]c~!x `$ {-,pRC >T6mxa,toc~ m,W -Ota)8uuB&nc]c/@\//a̈́OBxv9mN;5u)~wp X빇1:$0 IEigg	Fx$ڳ̚k-*,_X}*zǸӵ':!_XFv|a^Yp&prq:e2W<\_(>.xmUf:SPY+3t{ڱho?f@2
;.WdQoG7z;ag8o;Us_<Ku]8Թ&~nD&rID\(glkon_L|`Vv}F(Z XuL*gA/<^mxWX
$;{1I'%I`B`in܀ru Ș5yغOKWː<|%fMϨh$[ژFtE855g6j5T .fN6h:.daW@o[OY$[˗cp-XS	Khq-߉5
չKrջ
^EeOFg^8\n0`5隽g8[ )}mpanp'Y.C)lc(-y/=jt!ƊUGVWp2>g|$C#L(K"kx\xn}q_ [3˶6<@ejgK'4^kG)FB`j N1d7Fcn?D̵=x঱vsy+p	ed@W.e@U((kTa&sjŌŽ*]^I1b] Lf,4/Ob$'-KZP(- nbfY9"x~]Eel 0	c<sއ=jJgz9J<`j?/o~1.tvXo Z%"򅯄4mVPقQ^Ӳ;" \M
h4!xQvOIyrZˁ{m`vȰ ~A8r]ClKrG
rbE$
-Ӊd鏸&i6s/>3ȇ|>%O\{VzֲmZ,T`Bt50L9,f4Yw.\!4:TT07㑵\c=+ً^Fθf\Z<3zXbYF?.eS>-ޛ巏QΊMh0H	~ۯGLv'q댛![{|1Z' K41	RJFRiU>cWy=!.{/&Ŭl{{s'. 9bώlL~фdEs۳eb`uS"qL&ڂ.RFǭFIU\${,_Ц"ũڟ\%@X%V#[Zu*pqՕ+VJ kqpX[2QeƲ}ʐv$&8Fhuwյ%wqezƞecG@eKґ&K*$r&MFhJ5p--PKO]@uh)<ԙHM<O;n53q_DZ"e"\:vEۿnY:ƭj%]fp`]j%{aYw:Y3\ƍ7"TU7hr7kwvhmpM1>v:P-z^u9Эzz֎%á_ωo8+g{D2Vckx
%]s?6J65%R:]|>^iP̏Hu<T[p4qU7lFa5{>E.eɢENSx5.xs6ѣ9@q$+PNyG¥"*[,Al?:Uݣ:&F-N!ȶ:1_,Z_2lwja4[B@`$_f("w*n_Rkr+~6xE2*zlt wBelᮁ	Sb&}%|%$\p]L[<=:l;:/viʞҔ/6%cTUepq11/ ^%%<◶_-K{3K"%Z[aBHe78F>!Wҕ޷]evxZLvk[Fjk#ge.*:\pū->@ G<Y{~>iRDQ)||ؔ_ha5~(~{O&P٢2bl\|./$nJoJ/p+I<_cר@k4M@*5٦2MY}j]A{V3$kH]>Zɞ>&WMQ[(~^_{"`;&Sbf$&Cw	Wh%HNr$Q
Xrw
Xd2 V5AWXbKQu[J嘿cG5)ٲvg"q-;8Tn[%rƱ.--Z5ǖ!2
L,t
|BCД2&ˢ[$ZMeКȉyV0hYX$\4;L/z6EkŌpQ7_dɠq\?yR8R48GT(08,ޝTWFV*knP(|?\ެp;F1[biy`;? n@͇sx?^CyRD%ٛ?+lMA)>+9VGa>wgqF2F^YZZ%<Yxū8Y),T5iC5BML|/Րti`AΜ9ЮS+˼t/]:.^յg"(M.
e
E?OL1dpLude1N%e,@l/D:q_|ֽA|Wt̮[;^[JA5e[qERx\X!hX>ppwh2-ˏϗ@k矖H\$ۄitᰔJj5%Ve3FmZ Uw5t*pqw4=Lg*m2*]&Wh,H:-%W>yTYta>N-iMmz 
6q91S+ҮB^fd]|roBx[╕2_0jlLRת+ ¡N@r,8>Wqh)X~}ɉ2˻bx\9!`[O_>:<+իRT*E'cgVz4qmN
t\jqx(LZ/4M}YC֊t&jtQanQ욘iqG<^hAPg>{=9..[}ڧCjh؂⺎Keg2h]ק|m&#K'}//:8z4
&Sњ5&4ױU"t9]ΰ-<$JT&cAE_\ITBBKH*<)"z+4XHUQRiJx|Fp>_Z _EW;wH|6diD"	'*~ p9hphPͺj@h66ks t!a%|b΁79.xH+$MbT=8}}/ff?Ⱥ+<.bR 55Ls Gh<yY򷳶ٺhkWpGqCX:#Ne5Ok]VepCwWFLSz)빢'KN]#RAk)]$k0Իb!+4eRy@KvY]nm5i^uSj"cJ2F0_v^Gw5^V]\Wyy%~!X B_us|[wMO{ב!\Ώߢ
&S$X[@c)|GI  'I$2]IJ$%d28_Pa*|A|	L:CZUB!X|Vn|Z<=BD^U@"tqpI!ߺ44m@AIk
 v5NbvֳưpI	69k0-h"[BZn+dfsd*{6sþ%왂ه?hT 'dXl{ g[l1Ovbvmq2]vKב7.:[Ӝeu!9]Q,DVۦܤ Ҧ£$hI3	b:͸QPتFU:K,x%d,b	;*U,`z-)_$){"jZyMٓcR$
+-O%zuM{.^o=]VuťkeA'h@VFlѱGHPWWxN{ytQjbrрd0:ݚolLPCUtY+TA,";ŝ `	uZ:$GQLRK=1z|]|!HxR'΁NΙ1Im|t_5.>]S<a-^,.-zƵJ]`@.BgNiXZJ8?i)Ml.W;jnkwa\\[^Ax"qV͗7yKË}(Z̛++&W|~8?ρ)?g[%.UV tmKdJicȤ̵]5k":4"Yhqל>8bY/n׋X[[%"^˫13B`Fth(DGQaRϣ	U7eĦ"**Q.$])55{uj>:_SY\^<(a?]ji@P8z
޾?<ˠu˖"eP6Wcwj$06J@Qhwr&Y4B-嶸I\*.5&lpzq;1W0dۼL*N:]5G!jBcxCC,~f/-XXdޑX_FE*g.Q) fkz"WѶXqeJNm\R\7aBG	-l7WX6h"r!Y⯷ؘXfv4Ug>.ʢ&^9;zNO^M2wuz
?jc	0FXvrsw@Za5tBAfUUՍZP*(QUU$|Es7: q5U*D(ԂrJqnUM)z1MHzVPCFv#A1v+j*i^tUy"/WVh}lG'W~:[`#4eF5Ċ$iP6XrxL/;̒]+\EOMцs|*E+S}5X1n^cB#*h%vM:	:'T|}K/ +ĔsDN(xi%nJ9DBQqF`&nus,[M +_\SiKrb?69kKK/i7h lT>C׏KŴy^q<i%BhUjgzcZ!/V9/VH1.^C6qE18 cD ϔ"'&#		"y^GhPX,,nx~sswԋ퉶t&?2QQWk?T^4cIegņzd;~dD?0:20k",U~WxL)x^y.h)I{hOo~D-]ʭY謢ZҶG"*JZx)dW:U4{{g-AVřc^ ƽ'ybOÕeՖqշ_ɾ~=JlƆ]1װׁB3AK"Z<d(X]@FC6J'"l4&\g
-̹7SO<smym#f0-ਜ਼YX"c
1JvaUZojPi1il)JC }̀p5Nu`~Z&\	NN{Ӝ_ul>G⁕PQ44ba٢mc5-,-5.ix0׆l=Gfk7ᵦ\1ڄɇr/c+oW}appJЦw&;rmdyppMDccǺK#K/JTO>X)œP</iDiL+dRrI؛jNh%S4F"a]Q9iA,^ytPU/V|}pr0Rfzoס;b-@j	5ffG.}+[I RRjŧ8M$&0Z2"#1MT1!BAs~7p뮍,c}ǸO:n;||5%)e^X5u^)[/.s#4ϦZ ^E.аNosJ%.BF~NvfpI0E+?&yʃ1hD\@.ZCW[Hn!Eߕ?Zރ䵻O7 Y^fD.c[7ФسgMpGvܸٳyajmL6L16\N\M4'ƺτ(r@    IDATZIX+a3ŀ&Ns!IDd.iKL<(Z*UK*%dIX6^<znFUp51K	[
XYs5^b(DwWvl]·ѡm<Zlt9GF;}"@Jg@^^X%Ii2VI7vd:z˓TYjӷ&܃̓ג3{eN|\`CR/m_pZ6^kVj= EhQoV陯ПyѨ5|ڲV"ܸ8en̫9O`+wmZ4BY	G3+1P<`%prlQSsnN{0]0uX,]ZCToƾƎ]>c|['{^>oM|#5|5Y)32<0P/P1`J%x#JOZ/P+ⅬM="d<
r ^VApL`3ׂs"x(dӹH#`<}nr
K\"p4;U{7eԐK)WEJD׿z_x7xݻWL Hc#IC)MF0O")\ .@W/ǒI	-EښFnla5Y	(rÂ2P"UGl1W7?i_YY^',?sݎ9wQW+e2,ިdz.يO+JjRSr5AhqϚUJn!quYFx)aC.Q&hMUhKtIb^waJa<Fp9#37/gS!67m[߯l+:C׻X}tu6c[2/Oo#lmi}`[$6gY>[)mJZibAƠ9D<'YIEk>՟;oT¦PR
\g1
7Iƍ|j/00~xrqtx$]NKA1d.-BAKKu$BVFO|&-4N!6 QU/{}։_\JJ9Ɛig*GͩsJ8C%5t\nFE$ (vgaS%e1̠nJ+m4;;3SH`7}`&EL@?JS-A%uF83M`6i$$OEJ0CbTnqgC:ه}K5ܹ
w=9-m^Jm>\mQx`u=>*Kҥ
O"WmEy	P*K4}MXrӲ&1h9%wp7,(U&VYMdpv+؛!		@+A2\|cy)aWeqt2Aϋ	=^ĝ09JwՅ'HCJahha\x]ցJ׳wֳ+,6]Ye]o1]o)<)
S~Ԕ	\JBCxҪbz"j&:;*V}buiBA).)aW\ëy\|X\ĐJtV+n	mM@M$pǯ{Ng
=.w*p4p|p44O:N5Qj#B769TzȑO|ٱDquuaʵ;6q	ɚlm[2}&j7[(`(-dsoBe)xLvv4BThl5jSl!ZRjv 0.,G}I3NOm7wwe,VGE.msRV \iяJ:&,Lgp3_赗.S41.WU,D]"1[be\<566͖ȳsMk.8^rϨ]pfohr;VPiuR/
/B\罯پ+6yCJ3]͆m)ݑaA~j ߟp!\RI [, q"K]kٵg<x0}%kyHIYQ` ǻ5|GgUzD5${aA
u
=Þj	{Q<6YI8AmE/'Oɟ*r?+Rꕆ;p!#Gp 8A9sȚ1)k$YymСMU
2*.fJ;A<Pj03`4!ePl	T@[RkcKc2̚BdҼ~?.Wy;S) "WrZ-'pU~nViZH:XV76 .$1\9:7ِٚ'Cb<\fs-LPY
.bKLQ-OG808j6
gJ9;ʄ{9 YΛ0qfkr<_ݓwqPNv\XPyoW#ek	^*e#B,(\wB|cwgM."wroil?RR";S5<#^Qxutt4q6dɿ&C9LՎo|ʸ=l/x*<6-Ԥ8z­'=]ꯆA)O,+)K$Hixݸ8ǌ#c9gudRl7UQlU[d9B!
ҫ9s_0؎~Y_IUm-LKJ66BPre-\Y[JwO2s	x-\)ߴ?oY6jNcBP%RpBYpn9Hlh [#A-k~-0{ͳVa\|ԯQiSt|r:ګh LliE0bHf
gWz+0+++\9ٖ*K4k[^1;ک\^{~GJ͚-WT/Ut}8OuN\9:&fu?x.pl?9XVb&3lee2Y/M4TZ\N%
ZG/PZ<:=V"Zpg磟;OWҩT5Yr_9RE"qp2F`HO.Ƕv[=9OH	CaZXIH3*t&GULB&గnvt V)``sHj+ںl5>,/oذ@7_Z7W}QwLHl2hwpu]1U* w%-2-^#fp KW58tS:byS?$[Vz4f"jjS:8)|!(4K X, LP^A\z"BHSl'tMwޠW&2D۵oߛFzǋ ݉g)A![VwTM$Uܵʥ$͟<᯾o1IpBRI -]mT'?L|ya2=:eJJNd:k i(,,HQ @Df(;63R"RSK&NFL%K/W^ (؉DBW̉vbab1b.m4`Ҁ	H%"U{;ЄNF }>yA) ]@R2Y*E$Ʋ*>9_'S97VoPS~"wgUf] 6mX%X˗{o@OF2*pGÓ5#hpeٓdl##S+Lnd e&^$L+I.lQ!/B։B"F(׫)r\ڞj1Er7=KKMNsOzssNr+rc@|N#G{JX^N"cྚ"˭<Qa*qRDY!Ve"BY&C1>8$+y	Kxo$~TZFY&F}apA@܄vgD8.eOW@BROџ/(2v(/_EO/渶7i򋥮ѓ]]}_wg=^OW$SNI
+QpkO9~εn_H:jKpᏧWoGQ%i(׏u83Tl^J-Y3[ eNPBt7t A!VhC kX}O19h0%WO&ë2(np '3J̗A:bQ#Ak, L2NJ6A;
+ ő&EƹUxDYFQeP3x~noj߱8=~Zqng;vWՂHǕ%JszaKN2`a-[_.:ǆ٦ǼRA*DkJ5BBeJ' 1.,ic읙J,g-I(\8!bGeEGvDF*QKӜb
!^}x=qN5&0MyxuvUЮ]P9kgZP<~(W!.t<?2_C\_I7v~\KwN{?܈v~ZyB^!pl=p wީpu@l:`	s9d  tUgjfHCK1CO >ZpELJ%~^pQh\k; ]S	 *c'}qPUk(@h$ެ'k&iK
R=2	nMmϳj\`I?Xj.M3Nlx}#/\աMWƬܣk3e$2$kHYѺ*R"I3K{z";;l@d}֣p!k"ǢD*R+"[΍L26`TӮLa+D	I<I-C~!:KaT`,`^ xt$p~']9vt>!7|lULū{3O/ \EZ Wǩ6jW`kOs#kO>Lǃˍ)PYM`*3|xn>o}+7eV˂w݋Y8P/Wu7/ktdm
H>Z\,pjojUE5۝Ko1Y w4z ]Z[?&PX2P7<).;U HW*pÖ6{\K[ˢ̓8HV.0TP8t9g4ծĐmµ(isL:	.Ү-5JnƳn`l/k7pz|Eå^?MpRFNB,ح.TA{}	xEWm-"EE}\mD)iKks)50]sWSHxBB+;m-#RDQb hԒpp;Y((%XA%{<. 8=u-M.@Fv)dyFB9՗}pkA=_1,*y>+؛&!dIPYU )3A^;tc4Gi޻`[޻pFFoN`*l^h1e$+5a5%b	t_*WLpfk>Vnp35%yh}%p\rPzla52|Eg`&Ufa,jq9#j8k!)TFy
p)`
yCG%ڗ"]Ck5XF"fV-{h Xol \e8l[u%M wUF8-~mVJH
HxrRa5V٢r"T/@lr6rg 퀚hȋy>ϗ!c+,CڔF}Ǌ5L.JY7JoFcT|wށnK
%)h/O
Q,jJ^<=Xtk:6GT-ck"F\7Mc6\Po5ƴ)3eF#5<io-Cf#']\F.!ON'k8q8X8w_prׯÞw]B_Q@_S]Nϟ Y`F_8zMNfON$~m'5dM_v^\U_gs[X*p-6^
ȗqi<G#踮eI}((þ+`X݂ZKE y7T|!ExQ꽧lPz|7oZ\4婐n@b	48b`Ҝ)JW		a8ffi
dX?
 .XftO%H2`",nGG׬.JC4d๛jmv6WtDfjFa׺9Ԏ:c@SS/X0-
ʣ$JK~g*xCC3}W#_Cec8_e4@{$x9|@6ebmEg~+5SԲe|=<8i
V@,]xe+g9P
M6H}\#ҕ?;wx#^²%Eg2KR:]|m:]Nzh#(
1O{|xWD}B~~/{/UXc*o߾!$Wg]sl*:+DA ]+q-mjR,UKRW(Ncm}ھk@ۛ4|%)˪=}>O^pa@jP,ƌX҅.g?4#4q%6$bZ+I A9wB:ڀ2ʾ6툪/ApBe_ZKTigMCk/w!^
UoLNRe CHH
>`ǁ%ʁ,vyi7Zx55005F5<h_/(W@FqzYV!=eHYponV
xHc[,,(HҲeX'MuA4_G_L>]6Vg}\FH>{ܕKvru>8tQ_s> Qt+,ՙ32eclۧ왹~Oth4~i堬V-Xg}%w߻~P%O<0uvֆjD#&VuB V-G("0T8pD?)gT6TBw-u-.R~KB%DtyuXZL4 bDBʓX-K.1i !IHdcR)W/HJLk"IVѲN/	EXap    IDATbIftMG9Lɱ<aWvFwvvV؈ wx!F |U7* c55ZGc65<ߛ\_u%獧AzcQbZCC$UJtx9AH j]\ SYZX7GBbYi\s9VA(8?78&Oj܇ᵁ _H]9ʴ/<OK֡.ɷ_ᑋ>>Xax4:6$*G?MWު.]*s!
c=uQ%Gտt88Bq/y.xOJ7El+>(l)L.mVj$f'Y켢׀1f8:dg]B&B ]e՞PHRTۈNbUP2<amm@C]CS|%KRpWU]^%*UY9u%;}m10Ჸ.0DLrAcKH5O8㫯VV2opl	ҚL׬ip\,F冸߸쀛ގ\J	Sn|N,NYY	)]סVf 9\ mjhYC><ܺO儋N\>`IX<^.J#@hZMd']%mMlx3D# צK~(匛5EKwlsӗO6=h/_zqiv.]iLҜ61\{PBOP[U$H-`KuT#
~3"Ne 9P ~ϗѾWhen:A0xQpGڅΒW ]}x}w|!B+=wt?_m\խvYɻGNy_<=Um+.ҥVX(qcC~QBkog&
k-Ò[pb߾RIk^8fWh[/r*$+ K(%o$;U4Ƞ2[d<)sAfr!-}Mn[7nkТ>~T{_ DPM\NJhϞ}Kl1h 3PT:捵2Q*)^cŹ*D^H[
LF LS7ShKr-Q*U#j-uXnΧ8cݻ{o{ce0	AЂSv	4QC!IAql=v.-\_-/el@05kԊ208`
#8aȅ }=ۂrqurPdˇN43hqZ,_PDC963x7'|;^K^7v~4ڿWT?7{x=z~Jʿ),G^&	]ha8Dv(U'bX_+%%<z2']>oKKKnגFZ'Vj5.}]PHj B5!`0_Qd<ǃ$psqO<N5,6j8wzR!d0C
fjYp6sg'1=MC4oN+T.N%Kz3J2p~"ʎ3Ȗs9vnͺ(`u9!RPOGGXdYPnG&ԩEQ[vSd F71ukҺכbB0h	#@u:j!N<le\~r-G|8r?fǤ2!&e"Azj.yIzȠÕ"S W5lA.bOTswp8ч15$=
bg" Zoc+XϏ¨gbs)5	c-"M_w+wS>(7lI~|2pmmdrn}]OYBKءg?K8JVJ6I-uu~	V_)$ʦ
3ㅿdaG.?R AزtC5(N\[Pթ1U^^H(bj}
TkK|AO^DO [tګg[~2M&!ɀw%Sa+L&w٪2 *@Y,Me
T*5Qvl\`k79S
Rx</)$!<V"A쀄+˴]ew%lbKuDKgK2W2OB%@L;Ox(;,Oٽhdw'\b>}=¤B#*@ǋPnQ2ϕ8R5L	ea#(,Fl{{@]!tEڬL5N 9ӹۗ.F?sʕjᜡl'l~;?̋;^c[!hV}Gk;!\p{PG>vյ45
	{u?HJx[(?#C*/}+t"|.9 ҒǏBhX8IߏAΐ7KJo)аaK+?ݐ6O&L=xҩ-6ɰVhW[VTQ=,ORRc]Je\[|RMׅImxS7ZZNb4!MF?l0SRͷML:;l]roOt(!Q_QZ\E 5 `x`+#QGWdcnm%ikx6يn;\kGcX6fqRJ"L){52Eq7^_3~k
.בёi	]I7 Y"=ĬIT!C	8R:4AXT;
8'	$\+"W{ו
?l}̫(s_BHp[ZXОBԄ^7"n;.Ȑڼӵ5Wc{d8WH\uw.ܵb0F+ryYڥK](i\uLA
c5ey֒nCUAcG^f%49x:^@kktjK#e%DIi>x~6lʦMU[Z1ŧaEk4ggʹb4bt	 ab] %uQK?b1}~y>y?3n*bX.78xmW
fυ"tNR?:ݥlPëj]5k(dN	7iv
Ndd/=772MK^Y43+"Z7BhTCfE(/
Hp)ƫmFfSd/5*t`O=HcIS(e*#mo1|Q?#b\8dp9 W[.L)}ZcҙtC^gIj.FUfEٲ>OfiCdYcK)?>?'2R´h{
{q18j]̐/PQ.,@EvS.Rv45z=y
]_}ֵwsrLc']vݞ7C \^eВoȺouQG+qkktUz.^ts~''bP~p=z&Nx\I451>4[~[8EK޿:\Wfoa'=	ŋu9	K瓜x7x{J$5U 
̏?u+<:@L=gϝ+8r!7i&;h_EoioQPoΜΆs3^eGOOE#ձ0l6#me2KgBӍ&A#l	M8&Z@MEh2@ L1$U,St,-M-MG9l#682܂kj
[q@NGyiz?Iys	uRbw/o̵	Fp-r3]dvE[޼zV
5PX
{`m]E
Pkoݝtmǿ8ڻw=Cyߛrxr6kN킐ۄ☇|dðrNۧZ?LE,+yRU\(y&<>tSˎLVMVUlW,gZYkOSEQ6Xѭ2Ye-8\'y$/DrsOw4;qM}xO:&zcʢ&}z=KF5p
玧gsp	+h`.N,o<%X^Ob 7Zp4N	`4g@vU3VrFvg U(`hE+9H5UQ&Ҍ@+9%v/Mg9UR&z\A<<	hhMy}!;t:Jolv.>/V,L-¥ө~?/QHd)OALw?UW0*cWT֧iZKt{x_[M\E*F"Y=#ŸxC/ىד;_|16(ꅛVN=/j|<V)kARg	kak%|ߕsǀ+5~yUTWTֹFS#DjyWDa
:Gk. LyC3zPyyYYdY{kp歖xSs-| 
kĹEw)15i#L#aL&
Z vrt'``9FGDM:rP|dMY#)-r.EƲl :=O\cޑ0yljx>aFm>KPUDzYEvdsIEOJ#Bbu#KZP-[ST`P@$Iۗ.y_Hbt<1bpji)2Ҋs>9 Z̠l!e&p IBrC__=vr1*6|_ޥvw7ѺXaC:C6kdMj_k;"ҵus8]ikcbQ ;.pv6kݟgǏTx7U]W.īKp8NF0nyб}jF>'찀/Ⱦ{{{ra'XTX,|\5VD`3ri)Qߏ#Bl819 8sFD*I,\.'ɕ'g?H""ص<4FAHb=;H>Kzٲqw㕕`@f'bF3`V̊#*EPމt &QlI8⍅c\
/Ly2X4ayNʺ7jDi1m%q37׸ۆ^"c4Z 7ژԂy)buͦQ,	֙3^,y.88Ʋ99{l0\/B`Od,& ǀV~$ushhrVOJG\AZZ)W(cE3H1ZpBY/ WW@Q|x/3.,֫B.$|t!0$fP;MN`;
e64Bo<?զ&8uzNTh.o-+M9ܝ0[(ˉ9nȠVd;rA,5~/bʹv`h8t9s9ѡўXCYѕJ+T3S(BXz9#Z},Mq?|nH1;6rZhkx~^ˈUn/$}HJHV@2Q_0Y~~2*E}8P:(֡Z욼Nͱ"apN8
Z5R>N[] #8%p3#J[(~>4;89Q($˕p2&D{wx)|˷CC`CpMOO5_?w}I NDzr_~[3d|18E&Wcj{BGF+_B(\<!HCTD+Cjp9Z:EFKUv}Qt3fWK]vn\i㷨j^ٶȑi:5mZ+tZI Jչ/P響Ut0,7q}1RjzVu5%jyiZީ^33ja<rs*˨g<_l.s:A=s`NG!^ _GxTDlqfx)rJ$sPR̫#=y|l3=qKaxskk2:\~<(Wke#\ Ўgi!*}tzU),?(f,W(iIM%X)R@"hd	//BZVƪp}37ZT8IfA9jΞ?C@2K\* ࢚2RXY&	%
e3`DOcyBX</yόG`u \dc}$"u%xxAWL5W8Kfs_jfXO%w5d]p}mkks9z	o>wh_[SKp1HhWw:ޠWD2n4*}DuK[瀯Mo³;?f+%<3suїrAO=C Mj^L`fVNpw6 fT~=8?ߟX -pya\D)!X1TdE.&KbTFJX* oƸo<FNaۻUE|L<p8<ÐbHVW
fP8l/J
(1aH(,n	ZҊuz%\=7=}"hWwRq]uT!'$l9\2/s@o@`\=
$ZT_#\yR]$ݪ[a-I"҅t&^ji-e}?Gn[Ϲ^Ik[õw{~S=?pcEp#:y5[I_;jMkk{;nejCZaQu
ʈOs pk&̽[}m]-MMWo>|1le-x=?BŹ'm7ДKKHm|t2V]r3ph.	p]S]\Lh!v}i3݌ޮۅ52F@0xB).2~ƍF_xF-l9:\·0/!$LI翸X*\n鬌12Q,)\}sRZ$2=ZNA;|@N.Bl84{;w>P*qx`܃s..]0L\
!e)BU2DɩhyCD(\<
iluEK 7gԸ:݀Vvuup :ZCR`\8z>o#]{kpٽ{[ŅāV    IDATpx:5j61$g#
YX5ө&+<wSɘ ש+^p`~@_]M/}Z$ܷ-CB)	/XoRVzGadF1Ә|M>fo.qBtu\y&rفs	il_kSv?mdWVWRTv7h2h<mkKl,5ئ8kFq0ѺWpB"Aj|بDϹw&m;h~yιƟm*춁N'<vSsiEz<9RGZK#3OHSY*#t^dD4 4dX*CB;4}`6"-Y9apH$=N>leFaʴdʩD"^P{IJ3]GOnܾ8Cr6VǥJ	x	ɖl݈D,'X"sόM@0DEM!IݢU/w˜yp."p?wE/*tbڡk{{;S^~bOUkiuw~j3U/zW?܏`Uz"DVh\ϵ沭u|::v胏yua!wi=I+7F%˚Gc)0MN)Z-cnZ(U,Q4J["Du>[4z{lЎ-6	.Wڂl9xDY䄑IVb^If2Zd̓10b?Qu 56ȢSͤJ\d/f<]8]U%Y67vͱkQ=7`vTddr.:;\2|ݼ9kcl6ji՞m[jrqK.=x޶t;x}b>3-}t(W&1;nqkGnUu*W;mc*ch^1GR雽^Ojj~\Tk׾tT[k&;ɋ&\$jG6766̇&
Q
Oc=|;s}0"%ta?6sB2lYC)*<*OvXEdm'˜&$VviQlѽ-8)ـ.#mq!TLNG،bHg9Edny/Cw3&D="#*qaH
v%e
XjTd%ːlJtyYGAvLYcq[y	KL;遌ҕ|77-_?|5d(3aca-EƟYtHJ~Yb̕dD7_MMOp(\ijcf3:*
pSݢ0[ZԬ*KHdЀB
pTK6]_[ȡ#uvh
M[FpTWMeP￷5<x}OfROB)ghljF
n1Ƭ+D
灮zBqWWD»L䭶`Sȱh҃eT(ϐVpK\3$@ /9aF0+&{X*G"\fѧƁHޤ"(>,o_[fČR,b8]u;!{H1I.!Z1uYA-`8O~س(m9.@Oms3D[3cp=W8#^T+ZED:;)\-
W<>iΌe]ݏ 2)tE\!4A*
IRd!Yؤ$К0Jw]U]>5nނl|Ejvr=Pu:sޏ;Qu}M/ZN#ՙ5
b=L|z?(v^.Z~zw%e
ꎄJ$-P!g1Q &)c'}`r*J:

o97/N:nBExIR*r,U~]22 bcũ^حgi0;ڽܝ6e[JR)6@לDIEڮRA-El|peRp6=3C`
3U<]{I
)Tv$ݢ)lWB^5>2Û{˵w8EHew)eh,xpuՠ2~ߪ1:斖Ң6k(&-4<.؎z~*՚AuG:]] Ю=2\s}\;-BkvE]14K';ʹuv_&_){?,\oooNl)\k;^u]0ǅϞx\XqնЉW-# |ݼ[K\P6I^M$lJT<	-cݺS1b2ҥŢӛ_^7(
f#W7fV#3ne׬_KÓ$[(Y$[	o p$ږ!4#[Xc)fV# ep')xFtӓT^Ϭ,OR*pZ'gK\F70v?MYn6l&o\ۘw7"Sn.)jY[,[g4htVY`ԶE~,5d)Y(Ӑ)%ʼ D_< t1bIV|>=99xuUE@qܞ_x3߲,)paq!RlvtҢ!bl˹0rS⃕Jխf$|C%
[l]l#]M0
]_:Q ]hEtԁc5)ZʍBN㿂ܽ=Ͽmhn57\t6g]sc/_oWj!7=SxE1Wr˗wFno
\)::^S~lPxI8[nnA2QJo/0&>z#G?3)t^[m\򳭻Q1pds&x&>0:c)
`PiÛH됇%V's{aө~#a#/Qi-恍@j-)gv.ЂԘvvte$
ED'&.I'"$[Ϸ_Z~x>긥CXSD$q+w5T{<7,G
iVMi9 E3zGdjpȣ\䂤z=֢l+`Ɗ!TR"G"Pa$hXU@%gT%QQrԁK)7F>7b߇AΜE|jm%LO
 ?h6=W+s:nݺ57wwWK
\xPZR#w.X `.=7MyAr)lZ-6.ڍTRY)L13Ɗ6𯻹\!JJ.,jRb(- #I|WTBA<)Kmk&a  @ٲ([Vj;mpSpȖwk]٨ݡ܉賭ѭL&>^1:o=뛟Z[{kDNb(zN&/۵ʑ_IҥBld3a)+Duk:S(=UQjRLXZD@\/<S뛲vUծ'*>Pש+P5xGT~bJg[}>a~QqW]KKSgwOBa|"4d]K;.^5W}N+kEHAtn{Ƙ^uW-5α)gy)!agjqqϬ{S)%
-.4x$дyW|73x펇Ccuh-!KYD(i'HRf.i>Q$_y6	p!]		d,@C^l^ڳnҪC*eHz4Cgx}<x3u66%ITɅg߿zuv|L<j/P,e)Ss;-ԫ̙87A"]NF6`릝*
H{H=Rt	CXf)5FDKEK62,YO(]_ݫ8?.4y֑Wo'~r@*u]ɕXLع][p\~/tN+tBW)us6@:f/7ěcty?Cw[X{|0Jna-bn<.pbi ^0bEx^7W2v̻rY8ߒCAmE qXx, [,-DYM$"7gAf.Iɨdjc9-/r`	-r|0&҅`"a;-;b&Ǚ?>-b8FCKD2Vֿ pCT(sB ƚʟR	a6(RիWӣeuK^M{958V;V-..gхQICK	R٪ԡkeg9:rk,]_55yz49jk5׬HWm3hHVWd/;/ߟb>%0OBcȍ7iqt'WS;SVp |
μ'whILU2xSG/_XxVd`t,M AU++oLM*CH'*
ZAgb\g4hYIZwW,.'^2Xv8S-ŏ6t};)]2"-DV+~eqU,ƊY̺Veɾ[m?zrZHX\Z%pJ;	r10p@JH6k}` CY62VueFM*Ziu{5Yђ"¥@󽿗a1<qF<
wO|SGux	^8v~?mdWOPUU%T(KlH0ଢ଼a_yV۪4Ɩڎ!"®\PU8ZjbEAi C rD 4+KC$^V#zν3f)ސD"0{sn_?y u!\+QFjCV4] dJۯaUdXoWoׇ.\E,6ȉr&R2$*J$we՟s$
UATA"Gxc3tّ8l+WANߝNv7$ ]kzpx&o
NPD,B(^v;NVqOgv.F,pq$?1ǘpySluuk: ?z15[k.
Iޓ(LRQ"|59UkJNd;`hrF_NƩn]׬XrEiDu+iA5@H`]ah|QWruH~uv'w"O	AJoȠJW4
Bόdld]%ry$^o֚wlѫH,c_U㣽{;7_
&\\G(ap8L ΢-jnl%D,7qq$
2_
AM٬to' [GiDѤ"A!hG#9!Sw`bkc<݄}\y<B?؞Н/%rcyUCPun|ca"X59yxڠQvcobΓy`lae5?eƁp՘"#Y7էk\Z_Zh'a Oeot[ &V4xJVZz"o⽗u!K.ej4Pg]]PmH}H]gQBRUB{qK$<qK^j6U\tr/g	\I[*	Eb I9ޝCB搬 Xt lq4S֡ ZPEJVqI<n!EKÕwo~ȧ3%ai(=Js+YYI$W+XLK$%*(nIoJcnnQhhآ&qqXgd ssqp*[x'lrv/s>-xU(ϥz@#x{죷v Sw־Cx{F`X7v+^G3=l/xvJWcR472ZKHѺanREKGV@#-dk躢х!ɺZyruwթ\.h ť.}F8H "p޸/D6s\3YBz x񓅉1+$:D,vt9ApBR@ Z~S_-/Y-z	z.'`'*Ҩ$GfTH(>T-txaOd)n)""A Ȁ!	Xx'ۉyJfPBJTc5K [E`劼ȹg&GA([fRlnƢ0oW5fwĭoUb>K;S 
kml֋ékψp)\k0V7/M׏ޥ0.\UѪǳq3sϴBB+^3ßuh$+e;ZlQtpѬKojtd]\ֹ6.>]m|Yuu]K4
q`h<zie^\,ˡ*CCzV#dxErk.kﻕVM$I	cp +AtBZ%u,#ap=^V[^-1^HFLtLH: Gn"f2+ P1o<dV`AV +x,Ă|PqZƓ 6k
zը0Q qqvʍsN9ga̞а*GȖ'g [h̿- eCoE!$̦MOąW=ÅM1]7Qo!!45[Zm6YEVn`3-#8[euFzj#KC%[-(\D~IҮvj9OV:w><zu0}tO_EpophTUW&]CaK(8WވT*kMR{ c}\׮={}Hv_IL-~l
$"CbBQőq(8%#ˋKJPrH$AG	CaԶ@asP/7$!1dU6L5MB"թ.b: [@"PrEjjQ)%cxw:E+z{QuKQXdemIֳiX-6DU,Kd`6܂kZ{ϧ6V?}:eK*\l.╊Sn`B&fzA3J܌JJ	ϔ?c[g@#    IDAT(Z5#YSRӭS"G>#~ƕ+EB~s}t]|B\\.t=(tuQA?]4Bj zH*]kc);63¶Rat6ewZ.Nrz>,,($
GL2jTYQll	ȖaAR8&b雕
lB;K<0znv9?9߳CYn,̚ޣw1\rvi³gŔ!GMU4eg"Ȅt+4Gm	W>@	ܝ"EM"Q5DƎ"n$jUQpԝ*PF:|rCaO)X"oU-Fѕ*1w(Έpa+R~A;BY\3wf -D4\Wibx"<\r[u:ku:J͑Mp@ezq=Xf7\666>1A,6`PXެ;Ւc4&YVAp_xÏ"aKtcEO)T5]5W+]$EQ $|o?й0	~8WrO9M_Epʚ*!ƃ/_݁?wʹT,C@"ˢW?vV<pdp2N"KtxZ$`J y趾4l䘪
IeCjz؍WdRUnmdA7t`/1Z|LmS6rVa7?\ɹdDF^l\*q|1<Ū{3¹RP}X\US'SȧBEI>qS)jtLӛgH3.*{[nYpim}CfZ,	gFZd^lUVUЬZ֫ p_XެNm'?= XTsͅL 7mfuN^ ng]댟(~` H.
ğ<\P`1!&6#clgyrp?zQ0$*mpDX`BH_<#2c'	-H,^Q5Iu|?N+*zpdPgx&b3F8JS@W"YEM&ÿG>pP	lV/ƃ]h
fM	Zia*6&Slq
$[ބSc<GyBBdъtJ,h-I[u]cyF̢E'4ev	zց\EF?8?:VKFn#I	řH՝*T4.:[">t.H
[cͪFHӟUEk!Rh!jV3Zla:;_v]۟s}Z`xh*E`s-=]BVGzq__'3)g]7>y㽏{MbikHd4-d"`<x/@ɅfV-Q-YFMKsC5EKkBEIج,A Z>+?=./a.8/d*"2U}dBet4h"T@-p3dBvjH,:y0D!RKqDلQq1laYEq%9M,ώa7L2r5TaDWr[4Qx;xt6]8O52u	Y \HPE%2R?Yjٚ5sZ#&hՅ>u!oWt}(l4pi6:N&m)XDs}׮}po0ՋL@`ei z}}}7>;+\l$d,!:QK(8,ڒߟˇ{FUeM<8B<o.H4HN(	l۲x2?:زlo?}tcmhS<)	B$XU&`<^}<]@Yҏټ^pl$٘F9#	&">
;p!۟Y!Fo4D^%TVxѦ>ܐ(:yBt]ɹi2Zp-N]{QMzZhLŹo[.CYr
`))\Wnl1Nd[ZMd]҄dt[m]EBeO?u~WvD8׫W8faRJ9_ǃ}|q[Vln-׫[8@g/-w/G;y_ZYR:+ob>o|΅#!ץ#2fQxE9T0Jf+;~>`$qx`U ]`!\A}yݧr熅уG>XILMxaŉ7(b[dyE۹,akTEelZbDC&̼$R_ɑB;7<C+;#YAMNSS/y<EL]#dxdmzyu]p`C?fEp7e-׸e]ՆCIMPe˟j@6[VaDfGب[mz9.l.<Osǧ^mb-[/Dg?jaZo燝9@` )]gnZ3v/mycx{ ̓3f
WX-qS2;ILr!donWa[-uPb/"14?\hh<HE]!A;&17|bHWޟ;xi&*G<%;<4_}CpmGPKJed˴$+>x 2}s{vV'H0[Xf}r'*/Wxi՗[fغ`s4(l6[&W>}yfnbĠЂPu;lM7e(/8"'.;-οHV.A9[<*5k)[U!ťq:H-Y(L$_,\3pÓTqn9Q%9Q&gɆx]'P-Qb0[ɕצ&Z3hՂY[7P]'f:\]l=&
$y^djuSF{S/><4cƼPMjp¯떤->(G*Z0o
{-n#q)SJ%|8w`|0nMR(G/"LSXUPˑO,sxƽD"1U~PU	et.	@-H7m}8ػ$+(aBEX\J@x۷tdzo;0[r"q"BA4#t\οͼRÍSegxii)U*!bIx$~̂OvV6&,P,Uв\M68l6<4rLvV;,~lyԘ;؊UuѮ\G`uu.L~|~
ץ+NWf4X(Э}_>|pttވwn4+MBA
v#IB{x[)~ZTNW4BcM|ҫ+,P[exBƣ?ZsƬaV1^e,WO%YG+.-Wn7
nb[e'/6ۄT̊.UH4\p8d^;\}DxwȷEɩIlQ<.<O+4\Gesx
Hc,MH	B#A2$]~<L.S)!8ۛʂH.(1=\~^2<M
VGͅk6
$o6Z"X{DRj"hz\vvβ8ɺ.K]}9W=CCCGw|xt=7ck[֩U\绚KO&
f]v6+0`W\<J$BK0s"'$Qzx'%im2L4k
zuPWXVP:lfY^MOM-/A7ߗ^	tηl666G8p˩.Ҫv:Vw!M	l"J䨏_h˰G@m8|Ql<a`As=4XKh4"$[Z8KW$KKU]i\cЧ!-~%N7JS|epLm@C(t=mny5ń[27IZe5:1Zs1VNjg[|
WkTcnTuah4[(,\W0][;5󞘇_s,~ug[ñ\lV6׷\(g4EUYbcD{3Qʌ6\IJp@>DWTA "qZhI$Gr!oTy\zݏP6[`%z-enNũՐ.UySrJKul@Fzn뻧ݷV'Ɗ6k	OUSalnUpDy;mFbD{DIA>XO4Q!`(^`C %jKWϋ(a!HPh:T"g dk*`]!ydI!>($fz2bgߡZ'hEަBVl5U|uA귚yFt]d]jެqwCpPѝ?t4<طR4K枩XW;"貨D\hzGљ%\+*۫sBuZ(ݴTز2V恘d\eh@E
5b Ukfa=k]vʳn`9/hQop.w@8u{9?R%R{E F9=qȢ˪ZIFė \viP̲$[K@_`@څآ)0BY\%!(ÅK,>?Gp!
NMgзJkHIYKhy-98"7lzlpj#MZ-l}bDM-uKBJWL(;6+^,q	E%38"FR4GVH5
IVwh=X im](1ɅXb㽈-lm6]zѰDyѷ"?=<h
Wke?8ؑx^N'b4!P.\4}?_714qyjh$RB\.O#oT5Ӥpib1Mk KB?Z\*j~6[@uj]
?tEiQ)d2'eWeL=ϗFXHXz߿0hw[W\4+l\qj*$;I".
ޒύ`hw	VA$]Ip~N!4ccim?*"6|u 04tA|-c?4 0lꡳpBVfR2stl$\P+%j;Ѩ[Oݻ56V1Z WŽТlزBr \g5}12՝oty[Ѳd`=٧pqq_?Nao t.nRTEZHЄTW +k'&VcIP<6uZ`2şo~/G*<ڣ	.p*.煄+F1ƒ@!^4LL㍝%>D)a\8U B2~}h}~>ޖٝ2Kbԉ@7GMR5QS\ҲF`H-3_Ijc<ΰ 9	(]	Hm
w+{f6Vfҥ|RPC;|?t$/k=aVb+q#zdl}i]\5[uQᵎV¾ԫ;kLphJW(4p	ȧWL^eO(\DdG\W[{rՓrjw73{\>[z#twI_믊U&+ #{HOE9Q>Y2~WN wB"~%ѓsV
G߼z!\>̽UȪGփjȋ\G=bUjxXTebmwj}1L+[؅/ҋx*˕
`-zҊ7RKsv W|pm [{K|2`pD`ӡq͒])#5zvG.[ū?c?VnYQhm/m?NPNY$ٖq56Woz]#e&6ǼKI"㣀%<ylXZ-ҥ
҅n!kjtgYR+>\-!
@IVSMnOlʽ({dُY"(~aK}KEs;xSU99Kqp.Jl)I-@rI0$la\S<y[uTB+2I]<+
	*2ZcO<`bJ٪PIA<smEG1ZY"])ȧR5y`iål6
.;ϱN>㯛і92*G??XjL#-eePSgt׀ņﳐ}uWϼk*bhH1;|1l|A?ɰq>ou7F [;&S Wxt-7s8=Tkx9V
t͢鿠jcFVVb )UAT=;9gage3=xWe@*bX$6twެz|P	 $.	%Ydl.ZBlIOEKB@Ԩ-dA@85v5s.-0܋l6k(|Lz鲯z_bӫ.K\qrk(qvc}=]Mð/SOvAZOY~IВT>Zeq=i֗mg:ews{Uc<P[-"QUѭ\Z=(
rpYtuYū|+jϱҏ_exhmܿ?/{hrۉUl(]T\%DG<K[uuZW$BV]L 'cFABknŋ,l֧Z~VC:1BRbX|v.""Y֩w߬?~ޮkndBޘ{+G%B
]kLzacZRvR!,BG6-OhpŪ;pȐ8,#qHsT"VeK7|(JvTe=2&]AJ`xes&mʦ@ T@g9;`Md_d3-J]LBΎG	[_vxZcNϽyܭ|{H؀VTWGəfd_K~wKp#vFCQn-P_xCcNޟD    IDAT?9o//.\j ]~K2(E<yZ<ɑZ<r@
eKyǷenYAfaL0mL`$-Xd+u`XHZajDxq{g2NҴhҢUlW|mQֹqST8QH$W *ωyLz=!I=dៜ#'3jaJf"?饝_a]nrU֚ՖbղM9!fy);N!y9_q7*'`'OwceW,226WhF<9HrsvՓLp/1e15u.P)=ũWP^dɶNr 7}w+ EtUsވJhƄp}/㒟Yw?Tk}p
{QFux}9ܜl؝Y|ln͍UO'Ut%Sz9F_pZpz:"@IrA,!Lp
<eVj6 ~:d8	]?gIQ0ecA:5!J=vkE<W8Qi[!%3Rjx+Ai\KJǪM+ޥKةmq@(8~g&zB
J4M-Q!w:
꺖@<mZ7.JW>ƒT4jrµI/??ikWael:Hdȑ\lA?a@UMa:]cգZ}V?[A&\RS?[Owt}઼ia*r.J 62ҥTI&|mhʏc'"/bFsaml|,~U=^u"\S恬Vm"N}HDhZc&XjKu*-+		cdM-^ಸjnݢBkuV`5e3!Q#c'p埦^|,I!I^qZH=!^Xj:|]OS>vT[|=et5Q-ODQMĀ=F9.vvG˩盙\,TraAV>
ET^lS'ϒiy{ol@Z]>׽E}p>QYՌAB%x3U/Tv&]n#K#f0Wfla7L.D VF0P0g&(f]\n*[zCIE/A̰pN-\tjZCmkqܣ(Xhᐱ <!L-{PW< .kB̝HB
7=;>i99.cHVEF)^*gsz^Q$\m|eV*ҥ+˫nvEV\8)-(T OwAXe }* [6&

.[HŹX,M֨jP%Y*q<gsPum;0Gs[œO6qm_r9Q(ȈL:HC> bxp_̺3f[Jƅls6aL@kln
ׅIͨSFFAcPАEBK`]=u]HT7ʗ:JIÉ暶ѩUp!D:3p\LJWƌ+iQ:	X{NWj6jV*7&^WQ>뒲9-qB5˻w~P<bb$	|vޛ7z<
@+Z̭(JPVniI$L%3cVWZd3GkQC還/̤_F<ȼw?M 2]b)ŶL^%lX9(\2lS|Gy W-f6wڬVx#;O8N|~Oŝ#)YlxUӧx,lwG?[f eAMhTHZ/vtGG/w#ܬtzX/F~#-~i(8-4'oܹ OձRiYL6rC󆸨C%ŏM\^7 Q.\,F/ ,e~$
vpccʥDDÕ&"'ehr@)ݾ}kV.wTe$KZ"BAH9 z8zW+U\UXmB0Qȿ{.dJb;]pi)4g ZqSQf4,H|;m
iq:3;ir4I^x͈xM^I(Zq!>Lk:i`h ܗei粼Oq=ZlSËegE$[jѿ>H8 o z_&*lZ'$l+\=WrZ>=~QKC(wWfqĈ,f(i~ju雫oM_xg$.G~T9KRٹM ๞m6j.f@v{A]!: WS.%7Jdky7pA喛'GgX#gode>;p&\`b	0ImCb4E#%Ľ>h%|gJL50	psXul0
>+xWy[Y9^QUV9`8σϋ篚|3γIN>EaHi;jgd`<>pC+L&qepLwaՔhq<.Jag3QS(\
b$CCdopx >`p.BŽZbqtKS.Ë+q"|ȅ^!5lO?fT$3M+CkX&\=`K	xWr	W_5	eӬCnu@ȕ陭P˯?[8{cSuUoˢ.fZ \W+[meI%4x]ݶ,\3l6--"XA"Vy> Nz婩;w6[o}[|^Qtnp`wz|;L&VC7asC<Pf oStƝ4i`_ȇ~PނobX=Nexͪx)8U,ftoox>*
=a3,5{u5te
ZSB1F#`Փq[#d5BU!>	׍r3\(\c~׈W/m$ď/cw?O8YCY.gN3cE`nwU+i)l\!VAMa46HdٌFzY0,x\<(M@L8ni{vvʊՁͭ3?#lQN;ZNT-u+wAB|R(-d
V .EK'	;iZ\4Zz34eOY.@1ʲb=ढ़F ư@fzy(gcPuYOX>0EVqaOȕbtYӤ=RƲ+P,c`"ШIwF$did0[Dt#\zp_5(uy5ȃ>!k^vǫXoy`u-B[_,kX7tipau_$6j+
A,Gm#,kX.x-nӦiqv0{2t$NTSDhF`+V	ueU7/&rp<87Ɠv[~Ȗ.$yvQV\V`g7h([hUjEKMz"
im3fx*Nь	Ԍ=0ϒӂ
+H$Ȳ &	yҌ\O 5.(\%8o^tݪb%@I$\'f}A:ј/lbedsNQ-LC`ݽk:]]z¯iF^6m֧\!WïNox7xwXV Wĝ~?KSSo,`c|'>ɋ峙ξ.e!te04[,-Fs[y	ꪺ2"+y) X@)ɍ㎍^Gch6I30hTW,@rS.bkQ(fjƒ/T*^{6+ 6v@XH{mhkO~E);q)P!րˢ"2PzN!FW..R*L)֒ hmi}MVT+(YV"$Ⴅ0<6&¹ׂjQmGeK%썮[Q_^CKQ	?#,p4\+U^$!6ԄiUv!&'^NTwT.;i}||l7LS%ڳD J,A*$[Ȅ/;`L[ҥRʕۙL<eReĹ[iMn+֞:PRlV7)g?}َ#HRoiEAWTI^ByqnkX_|K-Gsow
`l ]L~0rC]]7QNg,X.M4E3hF0]%AQEHX)Ouz%=6bO;;5'g9,Z?SPa	NB@K+x7©os&vu&.Zw0Z}5
;Vpub)01[mr:+]cq[#ԋ !3m}U:IU$@Kׯ01c*yR8Q}~'uM-t]-p}HZ愖g2km>K~#3r9'e6nrb#}ZyUT,p\l"ə3Ot8=(Gahg1v?iins?lR9~&LҚ!vؑ]@i.-Et3+Ľ%A"5ŀ/Tb(XÈ4q<dw(f$ȋ<<0[՛CG^$o\Y@p /^B6ET&~TI
g32Kja42Y7]XA%	d
͢0+4t.A&>ќ?<aZ~	j(/dh	µ[4Ut?,?~tVVFUI,^	Dh[<[çl)\i`خiHq=͸~+\"N	;G6N-Dѡ1)w~XDhcc0Ь8ݗG@k1}w19/0\9K
Фk]-~/V"!Lei{edTBV؂Y.7n^yJߢ˪kp%tr5D ?gW%`­E>_wA[fO~ĖY-k6P_yŏ\2zhy;jo㲘/֣0ͤAS.OH7FmEH/\MBoò[TS`,0Y.].4)̧p	
JObkǷ>rm÷T;e5сZX?=?r%`KF$D!1X%Ą"jEpIU49.4ro*lIg\?i%?rI`xkՀ
`j11Zc
򎏢trr\Wۚ@=2xI/֏˿`M6D7ayܷJ_>W-XnL,#ae&dT	W5g7׿F#J>r$j6@pcͻL, IO{xJZ1dPIW9L;yzfQBa*iA%J9,+]jJF"`L-Lnx zb6$.-zDZVT!$cLf5
2	 L.-`3B:\.W[}5PBKĖ:HB:$CBfJOZGy\[be\-;]&(^:/:а#2SMQx&e.^h|c]|͝OzN]I9ILx2LWʩSOIc=׋(e9 q
[Wত ՠJՕ[iB-T(3{;s2+סCx_6k48v+_=ۨnjQ26>HB7PRz,Rx@֓'uu}.sEowr@-sR[(\\/;ZފՔ-HT*EfzK.'XzXXv)6 \)bM(X݆+&I!y_7\,G Wޗ4Kkr6[XUw
{ٺvK5IVgL!\|9CHjԜ`-հIf\(Jl`Y4&Ҡ$\}O@T6ZtzWk
,!INJNbX\PϘ1{ur2IL0:ʗ1N2PiH4ai;d'!Mfѡ_|ҥNeJs9_uvv5ƜL,A,x%.hrf|d!бW}u䋻\f*,}će\\i.;a0rR7b(Zr j0EM-(΁pz+z{0ьQZ+V"(qB)^sT9~UofM-/}HV=%mtk-nI5;}-qHxU!\K_YxO9|s]dILEJ7Y ׅ_#zsMyϽXqz4kC)kQqN0
ʼ":;5kG*
ITNFYIܺZ`"&XKPBZH᯾{>$vo?E@ॳY]ЩoMcJҝtR߬ȟ_Bǚz=6K?GG{\|cc'pm W**l2mV:rE3*9-3P	Q.¨$dY$\N|P2˜,7Sh$I.˙`FRL"Y\)/+9M:]h|po]ltK$tK!Nd&\rFׯ:*^\X.EE WKpF²_?Ċ5g2##F14~ҮQ@ӷ&=~ ȯ_ԔB_WOmZ2Ht)d&Jv5LtYPzz:Mvkx>I^??Ft=e0,g-h\Owy	/gjuޓ߱p=
р7^kSjƐt)IJ66RAY<7%cd6.کeihlMȧjܬ/gFkȺɥYoq_ BO-i\#LNo56hM]|    IDATZ{%TbZ+E!mNstrf410/yܡ.c#pµ6^ݠdN̤ς+^*E c{ctْRGWج[6efuXs׹fKx^AK)Kr^^?jf|V(īu{O*ա`CD«
ך , "'9ov.+Ÿ92L]@,6AEt>C1GcQ]KI>XUxyqd23ݎ1%g<?#VcAҋ9	ằ??lN(.=*h
zUK[j%=~o; o~>[X(&c+;wY}uqقZC֘vы+.s/90yOrCfwhrjٳ,[ϝ4O[Bd°!b9Cvб#Sr&ܠT6A!;^I-=ܝxnХԞP.p)BletKHx,~-<*!Uc,TU"pOrtKW(E$KSKBDCJ^R$Ot4即e]H.A(wtU^y|D\{6I,n;B<JbN,Gnc8WFo#_G &nw-γU=Ͼ3xѫ+0_P#U$dhUqw;߭=|jv6JRPQwnZz2M'
s WZcқ\nc`2zph8L	R
]go^Qg썸(>£!v-bݸ$-dlBd&&(ū-\BZRLa#[?5[t5*y'ldW
6ZFt{'%,kK¥SLo<u@JoUEÏ?ơ5^ET(q[Ou9}bY3@ZuxX6ap#@MBvycA'^Ǭ֘0t{C*L,'G?}z2?n5~8rJ34W`eBB!KB+]::JNc`;O~ndmZ}x6MN`DG tMi{NK¨w>1KȞa/P'cdKtBr;|xGqĖ b951+06BItВ.^%\V钋IeKVRzrdIV
W=!3U.(x5tLX[.NW'KSiW_rQա6kf@N"Ag$Mqj5$
m)P5+et&0Ykl1a{G4J1?W3룀EpA -~>*>'L_=X	6b!(VbRYD@Apkog+ 'fl ?f[+KTؚ,HpP
#mMr߮x-̤0C._Feg7P匘nq}>ar6B.BhChar"݇$<|`'ѲE<!#yaKm]T`[owj	P-'l-p!qpV<ݼ߄ԍU֔8E<wiI*J!V5t'[.ۅsժG&GLtrU$=K+D`|,KE>Jne4śג`(x˙`?ngMl\L(xyk|i(%vPH1<Ƃe\/4F-	3o>y2lvuMLq Z{EnA)wY]rzlq>6aasۉpa[@ڞpk4FڡwSaP9"l1]1.h.C{Tp[x*@*xZ2cfKfuI+TU3 -	e:6F櫩j.\YݪBYTuT5u4ndi<!ɏ^PbD&t
W.O	N^fpB~Lg?./Ɠ9&g猺|QWfʁ۬םT7K=e<::(ʧ]<pMM_YC!lB+`k}\5!jZ?vJnޝX⃮~?;\xa2\ ]ye8>Cڽl蝮'w{	M8 \z#p8|arra-<,Uh=Jz$w7B^<(Γ!\AfyLƥ:\|J颵9x-'l"Z`PHhcusuX'1뫄4%dW.6I%ޒm	Itʍ~\EYᦣP-X<\ɺ?}6.QjJBBAXSILa/3+pRhSQ/2Qxǹk	]n5ak";B^n<DC6q!Y6kӹ8:sip4rtk,.{,)7ZQJLu&vMNMVˮx'ΝB?sNiݻ($*E(V|B;W.XAs-_H1Z1ZxNNREªOF)sggv](&J~*H&[(r:?Ym ndN&v{LfrVK."+\v|&.n~f9nandBΎZ pc"k1n1*]1ָm

[Ć#jqN4қ½\a-<)1ȨE NKgMuamKAECCX[vٲԵ=Ss\$`/\v;i)=䅥^"%\(03zףԚ<1'(^[1oliH 7Q=IEv^/ln$!3XTcb*XZw=hrDu~H^"hӟ_GaGDr(dHB+;NpS3XOJ]ˮ5d#~I> KqFfMa`X98$
FO ѭ ՛7BY߉<ՇZNX:g?f~¥;٪/i	8>Eep{ۼåm72*q-4iKUPeʪ;{ll׾@
ϕrDXO\EpUXb$#nZq\W8.EW'U`Su#RXvVOL˩	D@cnvTP`eAP႙p)q=тG\4L<Avp%ZsϿ*BkyY4vdF'#m.ӕ#: [w4K\nVm%%Kam8+!Q'PpatII
]Q~2V~䲯oT]Wo.GZ 	n!KlA:O6pW஭ݧ𗄫
U~m+l>>xpOkrY4LZ"DOhiT5V*`~Y.ɸɟ.Od\E/.x<'H
C|k( pDQ&Wh:Ub)3wx&O
 v慥sX0]/;F l	*O^[
BWPrzq\ku];pljv=|К{%8/Q5ӛ7,N/޼֭S	`}R#Fr͘a \P 
 W(ڷV<C+dGe?J.cZp$lCqa8S2A*TWSvcT||?mR"kYFn7W.[Pw|KWod`k `w5RfZWXkU?*Шׇ%\*_%4;9jh5[F,f޸dWXL8"Z]e&P E)<҃`.QJySeAp(+Et|tzןZVYT^@	؀댷k&Q-'/MJB1_(ܫTgzܩӞ^wt[Lֳgۿ'HU/!"Dr+8XGWSā|*hPCp;w~)\~f(s\ \C wMv?"8
Dz4j9U	Bp!5]8oa{Vj뜾%.juv炀T7UB=Y>_4hN3ta bj6SS:ltsh՘Qsm{POh,؉T*{gnG_
HWBGdR)ӑa*/?sԌDCqFfIZ[E] ȵJ!V%.TbB犙x
IW+Woҭ.hmy)Ɓ#vb=ɡH~z,
QHf<#*i '\XBM=Έ T\ۑ-dz]BRfOM >t9`.o@t	ŔTUI8!Z֢[24*pկ5-<tJȖ>7VPWrpCpFZmppYf_m1/kFp֋\[-&`jG~~v;s܉*"o"|Cd NJu=VP(}CEt8+I`u4MJe03Uk1zN/,*<w(0 rɿǕN0LgFhE룣?x&4blsƷWWVW-;c V$B:'$HC~}Ҥ6qq<	0`%j#i'tوnƍtj
9MrTK
Gl]pG-?&TQt&JNI#=}w2 E yHPM%IiB؜qS<%#aRҺp1 \}{+d W>v&0vo&&}1GMdiUAKin	/E[콄JN9SɰzBp\5s7wM7B
Z {9-*UFrAvZPǺ[eGV]%C	s|R6 4),}g3<A!tt\,+ڔq9Mό0fe5S\_{[|el1֟$%Av%e熇pF|OO~~:xuB;O~t뗓+++IrAIyksC <Ep<[]C慝^WȃB(4ew85I|xx:ՄS2!HD-cG\<SWpUXFQ׀Ns.	U<帐zgϞm0|Y#QYpݩ냿j`2b-3[m*ht`<9Viɽ7 2)W|bȅP0*^Ѩy$gu05~鷝[:Tuq|*teb<~QhXNQХ'c=9	iWTD:̔j0*Y.j9S(|O镶Cձѱ
E8e)*wED
[?X{{V߉>t0ߵhMH{KG^E"_ynt٫j(Ǽnq4,SհZB?!
+p&2ZPFxV_Ũa&	y\q&\̪aoOpջm[;nzFUyfy^-%:ml94\۱Ȗa	5j(\d%wC[h*ά*&bNyl.Puu&xȪUC]m$]űҠp3qlw3a	^,{5wbsd:JD2BudU /R.=]?xc$ eR 'C':]sI?듓[;KGh}PDֿ0{&\<B[Pg\!n,ke	QAJѷ
/<0%Z}"8%	U=@<<ϩFRG~+kEƫ{hdTUYuclYa%4lhkmH/?V5ರe!W.@y9btKMuOx߄:Yi\S*Xv:}/qZC%nUG	O'STlr)'920VLZ(s\ñDeU[2i۪ـTvҥ]~P!쫞7[ggcvgٽ{ͅG/	wbvyQv͌nvCz@@1lDe>L Q_HHݸOypa(0dHV
[k
ô	iEJDFָQ/6̠Z&jqsGhG+-˨鞲-*[DEn	εAW|E,O&pU 3հ2;[b0e6V
Zni+-"- Z͢#I{>>\LMΏ_Ʀe>=ϐfB)Yy^(ctgZռ,Dx.PQf<~ʏ~q͎xßFj-,,7raeݍn\=	΋ii컍Ռ:(pyQ4*.\`uRJIAnWFa*\/ETIdEFU9FvTa&r٬Zږ֪5ѪVqq51Y֖z
pڟe|=ShX=-mC[s6QXGjsVYn;т#G++g 8J-%%ňaNOOoG3+$HlY9.LuT| }T9
sՌ:Wyuq~YDkLUegYl<x嫷]O:8dsVkgrDkΞ[_}0MѴv)i(c~mmxss-'mOnEkYH"^n'̋s~/LHtȃa5< \WG'U,ǳe5sKF3lZfMeln+h5⏛ԫTc-}η Deϩ4Al5:aiX*fyK+>̗v3ֽ8yTJK"lq`2IF(K*r\_ǽsïTEQKL8J YZ*cf|ڃfp񦽳yϪ[웅-wc;_pw]u$ޝ2<r/nUo	N 6R%j7DɆΒ+.q&(`zeIsC50$ҳyS"fNBB"-`۰׼    IDAT6'{|av	C?~<;rY^h*Z6B-(0}Ѩ7v+˅+lS'.vg붻-##ґVf7ɢ[1Zveldm"
)3j	\Ha?dZ䈫>z? \pS`˓Ν;)РI4)ё'`o0LHw\lʵ6:9=n[vM\$¹9Mru(ښè,Gx,I(Td.4#MC7\8~ŷڵXDNWy^gg>/?8k݅i낰ˠ
NC~;K{HGmfў*Kcp<h[}`4Z	pw#`
1;*g]n/)nu*&cx3:}N9,Z%D7صQ^
	kӭb!6a!\*ɨꍺ%\K!P2>/Tc b l>|'g1L4e[iQ[ɂExH!-8~ݞha
V/(]6]"#hK9ptȔ&H[H{M.NLX \-lR[pZ -k7.f2{tI*ԓi:ifc6zZf.uom!.Ӏc<\8AtYpҘ1l7#Hfu4Nj@Ee.m#d$&hVpP^ˏ%צ%W. uk3 ]d)pgP؁hV-޼,[3i]	:A>JIC&AAzdO4lC^\MM{7|vWɻȥXf\9`@ē40x,(=v缁O6nKŖOhm]Օ]O!^zbmxQf⮇<Z-HA:.1Aca324u#pue# D	CSפ~SpyӐ*VxtѧKm%h8GX:
![h/(8ZX%,Ck	fp	'*'	\J>Шʿ̅xRлQ3ek(NYJFUUֶu[_q60	Pp(96$DO.Ig	M&/ۂFQlyǹc\ ^>|.''0ʇhp=NC---
 ` -"zvuFt̽x165p"%tNЍrg/oP,pfF18IL#J,wy_:)DrOPPN@Zr`nES[}$C^ک+1+VQ(fK	.ߤ!ZS/BpQ|9^((∞MY.MJsU݋hy [;vԞUghe9g+ ~v7Qm_/\*
1ΥRl~S/zwc	^07톃^/Y٨%qhP<uN@ Yp'@kklTϸcdϡ[6v3-xf`k뱱旧`ˏ65Ohٲ+(3+ǩ_Lbp]6x`[.xaǁ.
trRZ IÀvYqs q#a0t:5:g)@-lDX]U?AdX-C${YWV䅅bzUu\oFْK*%2
.*ɒ Odե]"[h!jkn8hܷ'	au;l/:   C^.DW?bW`O:;|z-uV(E^Ydha&M~˟w׿%[٥'ON=Լskjj<s5+μ+thPM&v$ VP6:}} saV;$
SV 3UMx	$ ff &ab3xⴍ~`*^
`,2UBJ/bG8)|c%\2¤JZpW	,)]
A[T ag%
T
̷9UT<Z9aߑ{{h
'5犭&6IS`n˾?fGwahฉ7F$C7 (8:eN	C3߮[ԭ˵|Q]؂_u1ؚ;ՏϾWU?lЌ2Tv )\8][L	NOgvyRuրjƣa5]pxo,2rٕ.Av5A@[6JSڎ[㍬m3Xb ̦B@ ըdіJ@M`!fB2ɞsn_
{C<{[3`;ZlUZglØ?S'+/]C
d2'YJWlbh1lU'j`h8ǔ".Z{?}zČS1^	%0bhE:I֧lʺezWΐ,ZU~A2pMvہWms=bxUՈaHsiF,~$^yԍCw/T].mR&a}11d@+Nh2s	_(wylEԣo2xhx{s$*Vo3y͸>{2۬ɹjpxQNl 3eZ\:#Ij*IXQ= -֘Ga51jTlHYxj0 ,,h/5hξsUK-Vp0%.j+	}B,E!	WfbY,$Y|X~0A+&[!DU}V:`?OAUv֭Cx	I/pavrDQ--@ƧZ.	SХS*.?n)R N~w$eޗK>MH~\o[SC׃''R64Hhi4:_6v*;:#M+^xeT[AUG4R'5z.vlI%־(+X_a IȊhU-`Kb-v,0Sd){bg3#p'\Ic<ኡJ&,"0f+d'K_D -Y\rl7BF+
PU*=^c.$ Rtu]y݇".)aaTK5Ze_Bk./-MN Vb>4:g@'O=,O.O \2yBiܪ#B'Ә)9*;޶^xGnIM4jQoQjJz̘^@l1xɤLy jTxҪ_@$/phCXwqmgcIcla-t}>0<bK.vȕv+LJs`\~ J3EGZtq.-ZtlEUEt	gjYRno~C^g$X4n*.V5h!"<R8vBr!s&~uM>ɪJ>K>2v3^y9yslË7>^.eoF2gNTN[6eS檱{[`Ѫw:Fɠ+q)l:{ce_-5jhcc@<f@/$nY,Q)-5菦i=lX;[	.4ᾙ9;7lƷs\\L:A0ǓV%aF;!([YYY3jhad1wKK6}敕=j'F~M[v(fFFn 1Wr[![n$Znτ~3ʯ~BxGK|Gd&
zGiY -XϬÇo]RaBN YL}[AI0vW52-LO©E8dI{~wHE+R.5GZ*w@B~gUWp9A?+iA,5}nh86=|F(,M,[r恩VazP:Uⵅ]~I0tBz!?`Q#&~5ZU ujsnXMvhwñd+~_AAU bh`,xrD	i?Kyn;9B(9|4PS-7k@S[-`6K!+>fZSnTYY0֒JNg*uo6jf+[sap@dlV@f(ԙ78VX-&evnbydq[ZLU-c6Z\͢b+O,<(Sȃ+1)Bƕ+F/<e$?#x`M-(YDFT\1deE]#{s	8SNΛFv5se~z~"h4VPa'!T*9d}FOF#WG`iVvzt+z?runfpC&u!ocSРaY@"BD
Xb=,bZk1J.Ҡϊ5z* [RE-Q:}Њwb>Yocv7Ubtزan	=aK.hr<!bl10Uw'l~s//"8%{qŒYxEc*B[t*ゅQdsBD:hxI^;]-rM*U",>tCJ PL2- W^ΉgGne_Pk"pnT~pm}q՜ix0^jd.kD=Ee2$:'j-24XQ6Z W': U`ꨗc{"dfdqv?Myō^^=wHtS6mCk^ZqYi#G%n6zWKi%K	z@b`rgfNaRD&/yGo7-	b ~xBdDK-gr;<JVm2YPҨjpN-/gKfhd
57Ψs\]^aNKªiʨOZyƣ`S"lulњ%Ń\k/bi:A]Jǃ33Hn~9p&Ƨ5||[:e6dWߞWL"NTC/꽏\Ajח`}s8h'+.%8n2erm杧W/֕pb8EUߵD fwb/}\*J=~/4y?hk _&Gύcw#Yeg]h=vDTe9נĖZZ.<pSpQ=*.Jr	hb&>Q`(Պh)Ъ[[lZ*G(Ei"<}\қ,6gٵ"\}`ᮄ_o\덲i).
y|q'âZ՟Uo@@D~ ZK/_.M'O_X̆Ls֐ߙrqJ&z''I?tN	Q<x5M8{.^#!z.@bĜ? -Y3h{F!ZùZ"Zt`*KsԩòB\:q%jwq%YjS_
-ڋ觡g_ƽsYBEU>s8kf"8ĉt(DxRLl]ɷrɚ#ɿo>^Gҵ~\XBp!	䛅׿K#m\d~=9Bo`Jǆ:,tb)Sȉls9Pp~7]^XCm[82^c~AwGr!,IhIŲQ4f-ULXv z-%[C0_K5\E)o *%\Tnp|#h} 4-9$<*%[4ZYnY"\SHE"	Z6+$`&Eo!M	t;
8ÿbɓ0ZH^M}z}oqh-U~}}s3I\Jq\5dسv)ޱ]ZXSϡ3ЭBNpMb ]>V<ׁ.!pa{ې=oc7zs$sh!YhɪuІW:ͲZMcRlY5ulP#eK	UlieU>fTXsp/?pDƪEҽ>iRөq0h)2׋AQZ>QEˇ^"<ˈJÍ
=k!5ʰg`yGp0N92jiP 9,[|>6rj_X/-
{+9;D۟:q)dl.?FѶhl0
g#Npu^dz=xb|$5`0[<sQ^1EVl1@JcMdK֭3QFE?Uli
׉<@RVb`U#RAw#+-e*$<ehYi?\V×_8ѝ=4NEé1^Q4	D>ۉ,ZyA0ZWH#zRj%D???bxo{q#Nf9،#I{iĔ	.~t1]#c-)6C-"Za1;˃x0bKVGo̏C1D=Ef[gZjЍ`,y^dp}VE[J:R\:6Մ/
`>2'H&11j("lu-,lE3B89-N0{}}HԳ?bwoΝC!k ]6	F@/Zb(jb+OOV/[Y
[[\va;v\Ƅc1f1}F"e1[^v \3DpZc1ţH!}'ڃ'BK{STo-s݁J"drN&UkVGFVÊ-DZj)Ԯ5Q *Q'::
#|ȂF':]qѪ*=FMGʊju"m>@(b^)ʴ#m	Zٙp'gr2t1H]/7F[OU؜"h܍Lnzo1ڐ?'Qյo(BqQnyykd5=rqvv:L\P=W    IDAT!B|ttCf6
|zelzȨR5 KF$g* >-G4-(+s1%l}K*7Ќ8/H(di\*xU+Rl*ֱzASNjɖ,Ys^a? [߇	B0.ٽ3F34h~}D0Z]/|"K½~|ږ9c[Pkh_\#=̭nQ*uZWW}I\汒] XFfSzc2׆0[\`Su8Z-j]Ϲ?UQi$RҝP55Z9^
ʷ[l%q+@A(4 @1'A$NR4ys_Tm琠(tzuxhgCZTupwgtVlU]eJ'[A*:Gf;A[X-}EAKЊ~@IJP.-$IEIqfz	yyW7TZF.q
:3b3s"WZ-٫gʍsOh= dZ.[;fy3nAQ	ɉm6cОhD{l`$Mla2]t!c	B;Q2^Spl8|V8hU--5GVۢ)ڭQW?SBg1ڢ[2\FpQ}f[;l|w^QTU<.'u!U5>dFf-3ZzoG-j+.p( [)^]0cfA]$.x ];C=Ak/^+փi&WVljH񞶨$%T"Ica'l1`+U#أu)S+5b%/(e0ԛ!IsPv8~|QΗ,dĔ-J0PK0n2luf;euz05蹢m=,MO-BNl˰-+ ck)
DhzS'BMVP#X׆k䪌K
[0NRg][bZ߾8\gl"	ɃѾ\%ʍEu1>4KRl?9KXxb(
YfIM 
L函J ##y	l!EC70\l«T|pe` g<G9(mVOM94j8{eӳSzKHUjD1~qtN@W`	U2S{cYZ?fl
b'p$	]XJg5\6o:.7%n>TZǨx[#4OR]@ E>B"<a5Z*&Vx'lA+W_89;:>^/5\xIWhYr7)\--ͬ7.E֋WVB!("ޑF29gҩrD]kS|DlٹZ^Kip6ʫ2G.xB89-P8e2Ð 8CAW  FcΟ`[w	u.*YA!4A)Kajt	n2tCAK:Sx@g
-\rutRH*ކˆ绪:]cCc16]]GU+gY21mҭD)3p/P*yN<$^9'?Fsi=Vںww]8l!6['OZ++EXQu&hnbߔ(ٱr|>YM(kGyċ*\Y:$v1^id(7laWv͡+
%o2l,}Z%Vk>`o[Lp=4ei!#<a;lw,Cv }ҤSd7$o 4$A+%Li!A14KxLv#-%2կW
W9A@L(L4	3ۄ٩Qp/x~q9?^0\x.۾	\k}
Faa3HZ[[GpgZ-ة69	hn-N\Ocp`FC`Mw)0v#ιY>dgT2|X~qAf,05)x?XHX4e#4wL۩u`oo :nN튱j`aK[].֖6ߦ렡вIV.WvuzE"%!!-Gh}ϊ%T2KS8BO.WeHtlMOYiI{܉Ws6s+#];{C܏ظ	hޭKZ?lL [xnu]kVBNdA}\ӋLa%/Fٛީ8SJ%%6C$^u]3?J}!_jeo^-sE7]%bh	[&\@)	G\fHehΰp4\L-,]o]\]]DltK.
3=p
ݚboUh1۪%A4$@BI\-3R/	V^Fl]n^,e9y ,rG%`{S٪gb~0(˴]yQO8roݺZZh[󹂃`s4^DHޢ^oa.읡SHA+vVg#gqn@#x855Y.C@ʫ'	́t8ELo4ᝋFCd`DTt͹jE
D4,	jtTϺl|xNV#G*+3[*\TEd]#aN[{aJ-MtQ>c'IlzqClz[dPPReˀV-e16ze$|.3SGNWqRrwŪۏ6Ϟe(X/ew;=zxiI;63Mraw*LV4^ڲ vPظMExuYTm{V,	6i-d؋袷sfhlٓ$}p>7{FXsAAuQa|؈?N͏;|X-rsK4<EDwa͓spPw
#!ʻ2xZₐ@ߋF"\%vWLAn}sy{>iaݮu	/-
ʅo?eQ-S`S@tpfo`O=34봹<WGkQ-vf뎍--TD , 3h\N[E`kqT)
$pa;S|dھRAJߒk@ 0}-BOf[\g_>$h[vgЂoxų/=L+C pjJū3ZPonO*)1Y(:js^4MR/YM$B<
R"2)Ku-Z:[2'wotFOEǁ,Nκeo%խ?313ePLB9MF,Gs&2 ӛ>
L绛EE#j31]lu7_sOߎZ_Fo}}ɒn-$()eNq7[2/iVJtvl3>o1sc Ǉ:ZAA&ٖ |Xr!eZ.Ea2ť dn۫i|n\#ْ$f$WxP`O1ҿJJox<|تCH"ZV(_Icclxr*lCKDa/fƀ5(	I=nI)R-'{eS	sYA&p",cǰEd맺ll;[&X~d闤_-W.]^EN L
t!l}-Ďp+I$BGO[U
W;)9K|b);Tqbry:\
ǵ2Ċ{V(0!Aͼ\D
׍YȇkeZ,]]-[NuXږQ:fL~nTL,^!3mD$(4udOϡz\mV-T
ݡ+=$$hlA7GhH-ks-ڿ>wAp]Z[[۟FWΊ{{_l܇v(@|xT\3Ei_KkK>ztB>}<4}k	t _E3+%Αv&ȓBxǣL(^e<I)يbFyե*]JVm!"ļ($\[t,[f'E˔{%^GGʄpwϾ%"t@zf5:r.2VAdk4	{e2*fNrXQL"ᐙmOlaԎo޼iŐ5fy@AkerWvm}s|hrr&0_s?̥tﬠ܅⟖Fdk!ZpʍV!&cR<<*I{v/^L	q) \
a(*_<˧#<'#(Y2Gܤ]IkYbxmYϭܼ!}멍%.>k2ƖpP2.evg2x[Hв-H8q>o؟5iK]kHGdҭB5-ʖ-*eM\F$VPCu-D=ȡZoRᲲq![3]Je.nu:o|͗}T3m+QL/OR-'/V<1Z̞2?U<KEIVW0D@IW(kUp<bF\qt<'WT
K@b8U!0<tLm-F&.ղ;kEFFqc~CF'iYlB-Civ˶AWGnمsޜ{ڴ1,۩wHȰue+oIHEb .#1)BWs}3#.Db8Ç	̔a?ÿiQG%fRE>{fBU(cjFZw78]%襴8Swt1QaH+.ABXGx(
p)8ΩXF-|Ob@BҢ1Z_J-,62굞tf<zԭaQLj]bв3i/>CT\'A'8.+{'֐mg[F.)-+Zy3HEɺrlO ;HPTQ>ǰ5zTdrqgXɵ-ܷLvXL|ރL>iPq!o4`NזxHldB,^^.W(Kи0 +EAT`eW0U4OTtp((Z0^ ٠e	--zU4KYJ|gCBkDxRrr᭍OE7[|;[vp ([4c?ruh &cV\_cle3E^R0/^$dZDDի^zuEJpmFno[c*L(l&b8=蓭Ek	qF-`Wڨ{m<xɂIYB"LB3䇲ڴ"DT=:)!*\S:>4i\Sk!\(90WJ)kn?GΎ؉<#Niy>|3av|CV;fCT+tLӈMkVj
RYr=U!pOOR27rap(dL|X5~22[!Ɯ-5ɥR>1M="tmcѭ1&C/#TВtKk?S
s.Qĝ0l+,(
%È%++ad		c댜n1"zaɓ'R5E.`ڼ6ѢlRw]us+K[r>>_Y!rp5uudM3;E'?Gdaլ:pPD-Bn8<PŭoZ/8YpVbledX0rRΧ3y*lliҕIL 	^[C[?"~@,ٖ
xjnY{s\u
Eyhu҃˗q:#l$<?a\GzTT	2%aS8h;W$
'YH,EcBrr[9[#^޻r8X荵oI<hYES EBln,mpb޽s0]-߫éfܩO4~b? NQW;zl{I&/wJ@u-E:=3ib$5^9r-Y(3VcVyp5|3t<ӺW	,VZ-8t`K+wٖF,Ux2d9VF(bƂeLs(du+2.bpd8B'>M>'D'嘍򶬨\@h*"QA1nӭjH(uxxxF~o7_C6h]hY$l@|ݸ¥҅n=ߕiTqа䕽p>VK'Av|Q᠎n!ELWQpl\IuٌbH4s|tj!_p\6u0B/t9]<pz{
"U!ՠ2dKfC-iٱ!%T'ae3	5ݢn
Wxd(~fß=&aʅqu??!MTRQ
} xR+׭OEPxZ7)Xмcۭ`GmG~T.*]+w=X^ӨBtU.	h
R%Zﾃ2fwߩ7qX>@vEfH8)Ke}% WpF&VdsllY/[ռþS@Z(,*=$-޶,TdZ:Zlc 	]gu#S!NF0p)x%'\rfgUbȎ,=~A9L	"Z}ҦAWIu?VBBxغRȺv6fKFKΥz[swD`n˹SV{CDkrӛ|Ok5,TZDUWeO_$򽄍~Fr卲3r|u
¿_P؋Kf+(["ݪTH#
s2:'D83>Z4ीmuuO"GKh\xipҤ(pRDIcam訜`EV-![EҠ9%&cKFJGZhK.^vWVp	VhQz!j5ڑ.Sn7    IDAT.(nv	mcVUkafjVc]rytͣtdIe+0LT^Pl2E}|[kAf[Z!dKgrclX!.FNFV	HG+duZ<h9̈́]o\4$;zRUGx#}+['O	1[T+bBCK,LEϊl*]^lm-+AVV8^HPHZ
h]_f=oO5vvH x+]Jeky΀rU ʳȷ7θ2	!+W/tl+lZBȖ#OѢ֕^tCO0nc:Io<F5˖l4W8\)F#θ^VpIh|T,EΝ-R4R'CEHHآHj1h(ZZźZ.+!]4)]Tj3{Ehmii$]؊ݷ>MXpUYx0\-FŵuE	W&,Rn-u3dݒeK˶%Bd+ǎ5>l*^Ue<nwzPx9uΏY/WHn<./
q!0ZĉB:`"5RAɌc'bJ]U[*[jIhQ Ezx(f1[\Jjia^ jtt5=7Z~nv%PEHp֜߳;x# b/>5yb.7.-|Q5f2puGEҭ۷5n%TԊHVZjM["W~[523Rel.ngǟB׳BB2H$\qq Fs,	x0:6!ca'[" 2[0cuQ%܎xQ1_^K6~ݜ5"0ܜOPpiKrlz<b#A+kJ6fL''rj![ed	lu@PH,[NS6cy49oW26~5&[NyGH薆TK
)7_xe'#/b!!
=bl0OP<DJQMKO1V.[8/tK6
5H%%؂M[XrINX[vk$4WݥǃN??'q}ܴ9>ÿX;(,Ʉ`6,ɦƬ	N%44
"u2S]֝u_U	l^腑7!\ݸ\&4t׿fyΏ4}@fZb>}Ώ?LՓik5WWO{Zm6aNlZz@TA[l𯔭 ٠˅NgISe#GWEK
dˢuE-x73h-znb@?khC{}rA+]2anｧ؄nW7nݔ.Y!Ik@9!24'Owtն=yw٬Ao|7>7k'{rZ͚Y~FsL)+ZJ=pdc)[\([)ث :[K*G1Z&~R.E7q͌-R=H}T^͘OD}.]A",-f*WǊlt=	W.zeW߿p!]@t%N;{i2lt2wv^4dvuƄVw[g53sf|13ӦY׬74Z<d1*Dmɭ%eejEA#Њ[p.`w xgŬU34TӴZ 4wP-a뭢+EB[[9[Dv-3\$Z9Mt+_>{eN#Ϝ^Zjm`2IY?D4/w_nWMNyn.Y|Zstͮp-dA4K	!$2,"\ M`ă0p<5ʈ]`wPDQAo-p@YtzCee^d4U\Fo%kU!!MODPlBs.]^[+u,_kkފI/0;629h"2Ig_->3f:X[l&sU0B*@-d˘!"lkA}l].8ʀji3xSN
T;𢓟\ol=tP${uKڿĘ*Е+ __sF&[,VM>alnݵpQnIƇ⵼r^B*_):cV)AZi#ߒ.]}ؼp&ˏiN̬$Vxv*%x/[-^#pj< [wkE诌R'Ѻ$j2ˀ2BUc==PDɜnpBw J%jcqhzVpI<]xrtae\'Y](6L*6Wi6GBIϜz2;uҪ˺j|B7
mnl.Y"c&dEO!"hqm+%LhNxm-q>FCGY4$dhV\A,xysbNpO%Ub"tc![h˒81
nctQ}ICk0f~1`NxQ7o?z~9jהɹUVZ(YNʖHjcV~n)}_^oeВUOK?)@H9V
v{c&]m	͜#>Wâ%n	XXZ#˷Ͱux_vW\[^H˗^ `,HTѨgޭ>JV3-tX6nj'lm@[
NjEN-!NgfEs	Q_Q!a=5Ir)kȽW\>rpŬ
,nc`HyqOJ
Q[Tn#Oү\5W-roWl{5y<pѨMsuO<F'->+?Zw-ֈ[g6DF_ҭnmln)b(&\ M\lէ:W[^GW]BahM"^\hrX{]:bV
AK{{{4TZu)W7-4E
([-u[,^4hQ7*Jֆw	C-fV!UTzno[5,)-;"/Ͱ@"!tvY"6+$_B;Yk4ߗ-WZNyUFѢh$[ay*C)5֘	Ge˺J<ǖ|BfH*ba	tp~ƀ׮#lBp]h|3H4BC#^˼e%lQ%86/Xg|@WY&Qr<-6%㶂g֘eJ(\-Εj2&[!KW&lq/ccc#j:ïuT7,DfXw:.3pPO5=N eV[䉇O-yQNtA`!Ć0_	!/%2jzEqdZ4?,ftrZYub4h~'haA1T;Z)UVE-uKW+ӘO;[QbF&enş6^
1ra%W+A;l4IDu62HP{]H,]Qd(|/ /It	/դ>5>{+ҏ8%ڄ-$Z~7f-Y<R ?ml5jSeHL	cq([|2MuJ9ź.UkТ4xD%=xnyE
xݺ%."^++xA!JBWD%*^I?-b	(X0wߋWeu^Qղ&cw	>{nClZ>&f>|x]wE먉KҔ,
XYV<{4#R(=v7B@\K.|f..wEa+>
EC| `?$v":ߜ;w_I-u-++ij-l}lQ.Ƣnpүلq\|'\r'::'ѺGF}&jn ;G Ob:[2kTU<E	)V.[-8.R/#^/V[@1ۊz	 'bx'_S͙Xڜ({;EbkK8POQЊuר)k5J!ZN(zL,x[3ic ZJq5$4dјB,tY	u*:fKy	 5W.wϰH\% Ɔ،[dӆ/֔uu&S"uIS񅎖VB	=[cHcMriI02䬌ay8""!qW/Ϲkx**P*2pY::7a[#ܽV Q(
0xH!Q.B^C!/E/>`s3kMq屚i'34is֟(Z_Gy7]VZOΦ5li)B"[æ*TUB<6$A*V'*fP3gt9X]S}lp>zft*`mM_OclӓvVNH+&sݺ'0?~V+,o50%P	s6_J%lEēGg-\6',)?(xb͔8zs*HSk0Ζ1{%VU+F[vVvLQaϻuAA[ŕ.+$~M]f)KwE)<MZ&;',p0Ѣ dbY:	*}avE(^ _xQphwƜZa2DF*T+U|3h{%/'/'fOC6bqlm1Kv"Xs%m]?3	O;Ǳzצn1Z|B[/1WLF*(*C
_H-'J
g	KZ3'CB	pyt^P8^Xx%wG=-J\YTN)P,$K< s!{&RZc;p$:PC	nV!Z-d2k&% ^vN*醚
Q~be؂NO/x!!'z86`o($̓"Fjebu9R`E;_^~+P5I==p6PhoDήGqx5\[\,ǹx3R]Pn4cA]!L?%
LZgU<Wb_iBV`֊8	J)!	1Rt!^GXs~)/+Jw(K2`XҵVYm}80A[Q0dVb aM4MNݾjFmJ]NFZWF	]EPN#~0%iI\fH-`|%F>K/6q^ 0{'\y%˃2
a4OwgAaX#q%VlU<a&$<<^ߒ
YK6pI)\8;ofV3[ZaVb(cVV5[tJHl1Rtڥ+/V{%bzW1N]]5MEuYV$+Aem]D(cbhS+,%ּ<Ìcbf$Pյ,!0.c+{orZ-VBjp)Oork:CN/T%g2l(D2?ˍ
(1{X@V-UkN1~yQ3y;]ra	lyco
ɳ^FЭuc2CL춳pŢB໫.MY4"{_!*a3pu=flIka/V%K/|Eezk\P?iXՂʢ:[j=Rשq8haأ%"%y6XNWOa˄tk]in7h!ZLL肌2`"R+$1h9-W+g5zg8th%<ew(RԴ(TbIf!Zlʡ%Bx_Zyte>Dx4Aۑd+f<m!1%Gtk"Pi*W*WO`0^Ixg
	g[tRXyAa:1}K?{c+e@a.8X, zh[ZOGhKƷ_A]b!I.u:$Y«u7E7;d^o)}g+eHU2eQ[g@@/TudWپ\xAŲyN)8:U4%+&>cwa7hq{:VR^Zv⋬rI݄QGfr1vhfqg+޲fu\v#KJUе'$WIOf[Q/Z#QVc9ϗ,gkPFMs8EW*+IEr}2!1/f
`ɫW2'42!z¯$]FAQ\{ܑcO)*gҕB~\'\)lU~|>W(+[ր<9hE\9\8/02ػy788_z)$\eAI\[w3#-Tx\[
.N~,ýaDʪpBg(h+<fpd}o;F.WoA59!\
_5@КRCahJK5`5'KV2R%IR-2xxp5'Zkr̗WUZ~{'裚\WKUvmeLxhw++dXp8#/\n7b$E{Cmźaճ<@|q
jȲU^rk1)Bw[Z6XC	U<f;\{:!wrh5aRt`9?Ѳ*.!\ipFL!
W#vYG_8`VΪ;vF{8b$02eT*Kuy`-Ha,..<Fh<%#rܚs<^":.9o?y]4rUeXaF+٪Rcҡo]Ul~`2R.pڅxŧ,RsRGߍ#te#uE+%C67g9X1ߔ'ܲ'-]T 	)߄CV{J3WY ev;IezVWXV]'[N bO<e	KCy,Oc\|)
ſ(K%+NÍc=ZL;|a#]liߎIO-A!    IDAT[|| ]
)"0/[n9[	{,?聊	aadKW.\PoM'#T]mԌE]#]:uc?|&MǹŕD-CBDk-cZwY%[ec=ᜫm[.8	᎚x=6)|3tT^iץ([<!U5H(%q0+P*/\PaNsQ/|FrBedr5++ZR,ogz_R/<>yU>]2ZIcu|\M.>aEZMgjZ*دKɊhb$[L\vPRxXu!^'v!C9At/<;ԫhT?U]{der	_^3![ϔjcT`2B_o%<x*P	W!=իQT+MN¥1)pqW8댄̨Jz4۰_VT_Q@u~xN%jVk9CqzI3r#SPelܵ>&WπV\ծ[ըZГ_/^EDeepAe]'0
KeJP52 ق2JՊ;%!ǘ?h'wDl\e	~ )#hQdK\=ն_YH251\.do#4ʟ!}llXl)Jp%K5x)T^NrG<?ODE=n^W|S.CokZ%]`-B¯-|lk	wS*(*Jd%Χr2XN(׸w4/_rʵ+l70/^\UHܝv8U"˰\'zَlUΟ$ p-lN@6敏%4	,",M4+܉E44q#l-qUuzf0VHsb!1EeqF~!yst#`ޮoUVlկ
p@f}l}:n"[-3:xŜ;-8xã˚z3맣+*lQb]ojЅ/Jc [
0 N<Q1/_{;t~OB5JʃdѺh;SbI]DJ-_LˬhAҏ5v'n$eVYsPҽAɂaJAH嶠jɂвTūBeL+CSBJ)<+WPWy'>	C
sE^Z/ DTXEƸ>IU:K]OxuX+[;Ζ3.){\xkWꮏ2O7Z֠	zjJj쌦r[v(-IwF]y~e\\'_O(gz<e
`q1Bk./c,YDMjMBp%K#>tO^(O]Bj,|f둯qȮrFnvB(Ov{㲨[LM})
LEBvrTAK4g8s_3VrPvN
NB\X,E8:c=BTad-j]GUjBuo+@ɸES_4 B$vL'1]-V%{Bll5uYPϞL&W W؁WKpr5v"DB.^#x͈-?Wb+)cX}HR#N̜KV}*~q ewXf։zҘ֑cUB55.@%qNf}N|PnfTpYZP/pw5uCi[Yv-|Q(׊,djPcC &+c?|0ݥИR%oH$Z/8ҽs|NZ.Ցɀf>	{N&	a-+/5.ib+JǥH2iBְQU{`QLۡ%RKC+f28\*f
b.K>Mf^|5uˈ1
OGP~k;tZ+?1^fd!">Q;%^ئqE*Kɸv\[)D&JUpruURMkℿxWŲݞЕ~GjWKMh<cϰҵRXXf6"<YGi}T5E/|Z`9&Zry<֩^wزI9!I]bҹezM9THF\HB0l(|WZ W'alDRqE\
KM36א6ؼlӇ<
ڈ%zs>na2\Vl&f7>u({rX{eK[-4WpL.*r5whqؠnF3S5%eЗӀN˔C	Z.J6K(2sÝŲ$ۭqXھ@SX}gbǀ(EZɹxXe`-_\ԃ^5oQY>|4xKAxcket𸷿E
+p S-VZd~VY0P((!]x1AmŀYCP5CzT24Y;ecZ>Fׅchq@9[IA¢l9V }ׄ;#pǐ͸g><5Y]iÚ
6Uf7=Zngt-(q SKQʗC򪃼#SV*pEȂzNݖլ|߂ۆv['j瀎Gn˖MQ^:ޭ&4.gɖv_4hruCPۿ=Mj/T
(	;؁qDpmS]^5<``,a'Cp/E,J3#JPűbE:,BV-P-\FdGZ	/j8<*lmqy鲺"_`gLۛc.
fW誁'z], :%Dp5Oz./]öڵk4`B<S0Gg,+iHB/c@ڛ|-jcTXr^-TAR[;^FdS(j0rP[;	rlQjzЗ$%~N׋8OD9W"*_CP6F)T)XX1 -?3p[pZabȺ`4"["Z$2J'qN.،ˢ?.\!-|*CSOKE'6nQpxFԎ|xixoF8zJH8AYf
\Q"Zp׃n&뺭Mzd),B-v3[z*_6VYJ్h2 yْWLgtr-rwhBQ8_|KrbDlftOr?YD5R)Q=ݐҁIqO^)X5Ekr1`h
{D"y0$lOF*[EWKs𥽡V^ӤVL:VK;Qe yw	]^[-/2i	q.t^#$hюõf.x)M~OYlv`y(`J+&RViD1xsu `-cNaĐgcPb?yZ9:*d*g߂RIu+x╖@l٢+BvVOU,_d
قP<pŪuµ2HF١Hw!0ނ(W}^_g6b]U$ Zu^k3k-\j)K%?@S\*c+WyjkBlD4+2UH؅t[4WTK f~=pԢ<;TI203E_P>|yPc69yC8CR
` w,-ԃ{\Z(ZB--2v!](
&[ϥf&%v.KsO>'\>`]Ua2[XkuP0-\h\Ctp/ϖs-Atp%ŋEzChKLqsfqgǷ}ƹ:0	.%j[O[%k6tZ7ϣhP~BȢ)[$ocH3B.`3ihEJhכ.a(\uSUė 5İ1N!U,$'A]b׋%e!SZsԢ	2+űXA&7*ޏd-:vf.!:>c<el*sc	% sx7ҡvfRK]S0;.Yժ%lAEՄS.wל,pꥤ61`SJX~"Cc(GUBLE^prС`uZZdyX?*RNϥ{ien7YwʅBdZR#*ZR^zOӖe(	SZdą:pCL#jԆt!?-a&sCnFK|]RuQH!:B .kmgWHDn~B4	3Ȳ%Dp0ȑWMtɝ?ުq6h00
v8{N:E6Fʏ!Nn`Kε&YX4t -v,
E ͱQ
uQtkO(K+^V|?**#926 ؚ]>yc&W\|V}`yϺS*{,IVBk'z+%=2WZf3ZqaKi;<a.rx	jr~,Sdzjj=x-Œl>k%e4x\FraF\B<d|՛mޫvT%7`΢2_Qm*M|%lGՆ`5e}#Hh'Y6
)YwK&&c.r<YৠÙqJ<VtBN.YC5T
}gyrL5kJbAZ*ɲ]]{M]{)?/@p-ȴ[9_fa16P XCu`}rcS'N)׼U\U/MV#ֺ{T2{E
u8ք
Z}izq%KqY*9YY`
nrUЁX-z!eBg-
s.VNY4ߒU.FXf.S'#&W2gسBU7xAUhw.kceVJ\{_!VH&k]3Pl)=5BSy+@\Z̈r'Uc@dtl->B|Jbexh!*̙..
Ge%x͑13H,FU1XܽXɓsVcBUޘP	eF5.la!u,h" Zb%y/SuEMx,LPogRqU`VR5zԄWV
2<ւP*Ȧ:zU	WXXIDDWVoea>#Q5ӆ-gqAK1bU-jˎ[r4%J0=Ȁi=uf쐶vIHX86)U	Wye4Wh ;2clfK	C\
>A}cR(
%+bP["[.\l.MIB^Q/$"̊<tb%yj}6.M
*@&aXL/h5/dbe<iKViIS]T͐RᇟtjSIFYVx&֏8D^%W*qcǻ0cV?'d|52J5d+B2=y:][-'8ٻP9 c
CVÖ%-|AP~$&'B\6ќkE'm[s5scQC+"넖0?51:0#NsCa:hr&B͐	%ⰇJ]rD.
o後25"{z2nB Ѐ׆0^.oJܴKɞOV
WƕmW}a%-US^?/ѩ\[3%T9V")+(1VF(& ,o&\k\*Cժ*	"!TaU(Kp0zp`䏵_S! Wu(qqsZ0a?gJ`1ղQEEb`(ʎ<|25<'Q;
u6&?b+Q ]+|xٖSez4=Ԅ/~	""&'=&WE\`B\~M:(LbhW2pz-.P>MQJneK/.yee*Dh!Q*<%PE۹Z)iJ	1@h-O`K.fi;tckqs+[#[yIv잝=;Ac"1Yk.CMeɺQs1cTڂD
 efX#SJB	1׎\ФaKW9(lcGaS^dJ\1>sze_zQ?up_R(Zm'B60:5ڝkoJMcEwxo=&=8!O?[:a!q}VZKְNUثZba&\BXJ*hu@@-)\K˚60j&Lz7%%bV;2R7")VׁKY-6Y,?XK1\sY;}(VEw@Cwp"+F:S23ax5rkwX\
CT	}\he5rF=kh -6cFEy2b̓]j|FK,&d֥6	{Pj}|P ^q=@z)PEؔrmAWwNPLýI8^pv-PJd\L[ǁRetxiB3w|k+zc%Qv4 |0#uoE|%t]ZKakOܕORnI+9:+U"Aة/TY]!S-6bDhO#h$F~μ#hhk+B+6[$Jƃ^>q|<ZoΞ	!|\	s$LKTaz94\.s5c[*L5n+bkB:0W:0*2٢ƱR9(o<:^Y{AZ`\J/hO< +ZMCג],Vx{ZQݘ\OA	Ji+)?PɈ	3PϏeׁ\\V07^[a
.Zs]][5rM9=Cl+ýv[0R1tvd  BIDATSHB17]b`JyR [
/-VO9c%hie²nn,`#*`%uJ:0h@<k׏JF8n#iax,2^>_jwyJZŢ`0JD[Â7\8fP4?Ǻpl'tKׅB14Vj[eVv4rjSE~U,BVXkl9sT'}}"DRݯLǁe.1к#;m#W	`EhZ+GɬӁ΄
@YC'Kn3O!=5zƆ=   iTXtArtist     摄图网R;   tEXtCopyright http://699pic.com&_G    IENDB`K~xgL Lavc58.35.100  C $$""**+33>                          !A1Qaq2"BR#3brтҲ$ᒢsT4CSDtc5U       !1AQ2"a  "      ? z^||wԿ??u <O\.0OwxvzǚikhXCjq6?%ֺ$4Sm[ pmgkK?:M6Pժr	I3|^Z85Û"uc;\.cwET>@ptT~Ľ5]!$a6m};?4A2}1 
nkV I?-u˙;v)5q{q<Ă镜 KU-h];5KpsM1M'Һ|g<ߗ>D]n]Eȩ)tZ~:=>_TTĸGrkKsReҠT     24  +阎(Q,Ee;R$yaȔB6`sCxeVDNh3hG6́0 4 pl   p   ]ʗTGT lq0i#`yagG1B2Lls:KȁE<Fb1O<}lhrK-zfT0@
!C$^W9ΒXw׺99c558q^'N &gjGJߑ;>Q:'hR.o~qdG OȚuyG_)m<תY)ܡGs^qzUQYKd\m"kr 0(\l868bY#\)bG9Z&K=FtTgG&ǎx5FJ<q(;djDP%dx/ԗ$(g2d\c%X'K͍}KhJTO1Y姡 o !ZD,	]m-bYK~5z+x># j?Otr	yIMӨπauSCe5K'=%#)IdS멎u^.=}7[b"q?}WYL79mxsK:BuZ^*t鯲/`펊&*:2w-RzFƘ*%gjɁ#:yM˾'2O@Oul|4ۍxHv"[20:HBs_0}ҏ	xIMWNnU$÷|i=W#Vz7%9LҕqKp9m9?9[3#;{4ϳ8VųoV3ǵW+,ms5{׶}VzusqvGsMGyJOs鵐M.r^ @r%f_0J_ez:Vlc	z9eg?)ץT,TؗY/^mKSҵrv%^<r2Qp
~TFx3ݵv/;Yt(U\!+#ۗ>mG?sƪ ?ekG7%UvMgs rq&Zc F_Ju2Zz>?!nYΩ$ٿzd.kЗU:5nc8nvjzm_O>CM&#k!\QXљ<dGO#c<>j^vM:/Ts}-i4ZR풄(Zg\;<[j]uZ+kԻ/&|f?QuFNʾ7v<q15ER팖ϲoYtJK8mz|_N|j:V˨\ߓ(6?"ů=V+(2w6ݣ.V"S5k!</61~`SzjZK~0<Cwov׃ۖ4t 09 RO3Ug	IkY.+u*䟡4d)U~STܯF0)QniҚs/v9KSxzMu6 RL      ]DB]`vD3\9aȦӎBcnìmGoDi
n2z&8N.1K ƧG  bh0ч!aK$tJƝI1Y2,cr5cP#|k:<ސ<|gEs@=t/GLMq*;is?yZ<*!QďNm:_%X5[obYz	>YG_( Fq(*JFd"M1&Cl6RYb+\cӮ/O#v95npzlM4>G!wD,6M3jUrG\S}%=2xq]UOKZW .Gݪy㇃z]/%+-s|0;4T &pzL 62El$)cHʤnRw8rYT`B\\:dΏ^3K"/t/DOO	{Knj#QEr&_|5n2	%	~9:zM+ {YcFq9awsqY:B-8QD".~0,,::ȓqO WTj3?L	wNGV`1:gPiQ4MߊUYrMp<[ǰt
[4хRO
1~^xOv>JƶEms;as-qUyF3J/s8r:}-~]h:;K}),*.<Tps,kX'keV¹4~.s}DƽwWkpq*\^1>k\.>($-'Ek9g_dtͦ8DuMwKd6ZiqK z㧶5z5%;>yqg?Ӳcﱼzd5:j,siRlkihnN*;g66ƺt)nO	'.<r7axsӯ;#,g5z43UҏVw9(X;x Ŏ^CJU|;*O5GGl,Fn^\]qv_TSVcPx |8dz'fMA%k}LaQu
R!u6Rr[,So,ju;L4q;폼B4%Q	[
Mߙ5ZSK͓oǚ`K2~}Vos~"+1:i88;5u/usO{
Uk'YokQ:ĚZo,#KŴ,U%He3̥߳;/1ϝkݻw1yc  ٭5Z\-Y
MSkI*ꭩY\xnK>OUSjF+\xz@ :j
(^?psVQtT&	1jOsBO# 溆۲MǓk]CS_P6J1ڌbRsm]F<^|\sYFes~YZng85\>-eI8OZg$E%Pz}SxuӿSv[]pK3ǋƜ;wM_\=c 4y{WA+<_8Yp6 9It襫)vBtΗ//QnQkIKq~15nxz1;WiHϳ]zޛd[)^dɦW(G_gZς^gx+hçzHA!gYDo&~|` aP70QPh_97ąÑLF4 oi]kE @_s9V$1ftHn.C N[$MnKL0p
-DvFE`N݂D&'6=Yeg5"BR$FA'p6̚_)dPK9Dġ*ZCIWqB{ӸL+tx6
k0)zG[S\fg&&ìgKD7P.WC~X[c{N4*imͱ^ u?:?cjv<[;Nb{e'NчxD]`szXxbҖH,v*ԅ(HQFXI>FˉwEAw"Sj5[Wh=EZQQ\e"F_Z<c)&b;r+<wR|`
9xۘX{#m~atGLLfp!ۨvt6U5-o1OUL4lEZq `DRR
Q"MA!+f`ڥ
is")+䷼f#`_%w,F,!)tvdZ-$Fj$XCu,I哢ErŎgT6E!7EuC2p͋d0NOˋCI,UK2le"17>C@.)|er9uHyL
00Ԅ̑\$&F%E c}u
=)$osOP2*:sc5܋;#>;beOVX&G4]zޟU(ycrqq"[rZisCRZM.qX, AG\]OUD\= SɡgM^M),ɫ\ 7DMRPʩ|rR[w9vxr]]_h/Fl=f^}c8+I'ԭD!Vs'1slYW08Aa,&FU=kÌepD4n8λ]pKR=JޝmV-MIg}~]cBkǫ6۪W}^v֡;~Yo_FQϼrmGK꺝UJSUQ7g9<͗ܟ3F2FKpM4ZH〽$59i$F<Χ|rG#|sѦ:;BZGC^V9JZf/A$t0#	  P  
*yVQIdJhbBFp+]lɹ3SS!(=	KԇUFUK!YK	ZPk t:4V'i#̣xLbF4d4@4γG#Yg"bYA ;*!e7x˯,Q|vF;<S#,Zޛ4f>BM,<V4-vax>%K̆qN<H]ix2h/b)g8{^N"cV)R{ĈYc+6
FܜW8׌fz̈́}/)q=WKz=Qxx=
0zg	/lZ}G;e	 tyDjoxRx^wdQ]b$Do$Ę^UUަSa.BbYW1MKJ}"؃^m^5}Nrw}y3"חf&###L$D+zBͭ6.ȭ4iJfR!i#qfKnWqRpmbCoz^HH#dcuVՒ6IiŚ*s|(ꨫd8$4%fVɡ.sG!FyBOQyI&/m9yoTսEnʏnGW'#;m6N''FlҬ4\4ISh]
u-Ujh吥T4c(sێ\Nsl"T4,Dc/+qܛJpdU<e`:w7yVS$Fb2}S#t,*;F,#H3!>ySL2CpLS$j>dA--D_2L$٣xQL^
a[D$D8=LdCXmcYFyK0"q'W6j7&8&dqŌXj%Ky@YD"ܠ'kI]TLP(c4WqfFk<)'bOq̻x:{W!$/AQu1k*VK$>!C-r4Ә *xz@rF9*\q#8Rm H[թJqO3tK+ &t՛I(ޒoz#k)ðYv.R|"tsv|l>^UߎK$|$3֓TNS>/{N])[t"u:+^㹋<UqT^m3qkB?Yr8&.nx)5OVeS,mG$`0~#ƌh V +<Bmr`|+<ݱ;-ُa7"V7ܒ9Ы6o2liCy$'Z|[62)^,)}{GZ74R$T5!4XcN]B
113љj%Uic<1.{j4M]װVqIQrCM$Yx&TsW55ksoĶ]=EɐVOSwW+\G++WTgshY^(L&2f:%3j*eX86\*èhu"HNoYnyR#䩅u"6n 
t aU1i(l@s& _!0(yFygw$,<Cspo1Vc{J	JI56X	^9.hٓЈ$F̅Mo(40̆L	k)" p.Yl)xIfZ+YD'KFy'ŜBk(xF]4X'ΈDJxC'8wEL%LYtT jHYr`&1ҀӁ"%9w(J#nU     4 n.RǙ>cxrw}cxY:XI<䤎ꛦ9=2r7&sZDW/%";EHW.{]#Gt* s" p * Q&/Ԣ{Z/u) &^d)?2Kgj.(,b8&1/P&J,s|H%YL"ʒ\<;=M~ݎa)6z^yq2Vn^(I1a{OJ/ghʖwp{
۬qs3~!KlfHhّcz|63 `30=f	{LOh0z5HSqwO.:Sd}CNm9hj74Zsz2NcUs_ۥ$g'7Exwb#H!fG;rt2=|L`Q\uI<RcklQ\ maEoƍqLoaYAB9 SI dȻIq`Mޏ-A͞T%5Q+-r3;K>ڳ	x9ն{]U1ǁ'G\1
}H^Kg2;4DM
|f;?Q.(HVHq89zt󮒸)]Ba45jLC`a\:zqBV PJDv/@T0\Иo6~e'yH)
{CiV,$:_%;aLC./yc~Xctzg=QF9͘3y&'$8CtyOidgjbHt܅6ac hDز*@+Y%!2Ԉ9c&dR$#ЎM>c9tH"U#њB*;dYўq>UIr;)!δQ8fJ؅-7[NQ%a)7@-iluvG'GtuvG<%̅$ys+DLO&!z|#t0ĿOz~#8Se2ceLL~,$a  PCr=VԩǎOgm{p~g׋Œ:_
^I,caWPX&*\%[<[ 0E̔NI-Q).˹խHjKA_U%e:.(o7_uH=4Zk#OQ-X'OV>]9q;.Y7wu7x[bt2Je	R+Bd[rCu%^gщ:P1D9 e9Ɂᩱ2}d\l,^SdtYp?bO~&47M !j?!LzVn7Ytokb瘎v2JN~*~`#_2F4p8RW΋O	!seK^\S#J5WmO927gS"Fa9뚔3KJ>?Xַ̛_ihixJ2&zDZvah4ЦT&q5pԽJYi=Ty*aB9״j7$IteC-IӴr=Z> sO
M{;KUnéU5nOkx57i)}/욍
jQM^g Y\4D˨d;ְrYtU4Or~df9Ec9XgK3]E<*:2UAf7w eAD6Lv@oa<f30n Eu}2:^Xo:GQO$stO5ʸ`;&xls3"̴#Y`]:/đQ:$LF9`k7~DՉ*)AV"7&EAnVC (jr4Y\.̺=if:J_f{
:I.sh-"}؟QɛB둕G/ۑS.ƚ#/٤e=ѥ'`0?@r)r)쎼.fF]#ǹĈHBĬ=[L<~JG5AQLN2ґ*DL	)
  +{#j ޯtd\:ԅ`z&":gNSJJ9EADZV(?^Nom{cuybTեm9W<-bmɶGob}yEv)-~yuݸur9ག*%9EcY}r*\N--3J#8$RU2Ȏ>weZ؍ǱX@MR%dOq(Zje{vȼ|8(S02O#p[hq
 C{A8%8G^qɮ4=I4][$iӻx럙d_6^"d%.loӰ*	}N_3Z ޢ{ろIJ	ҏihx#ZdNxl8=3Y]GIнTۆ\#ӥ#D9]nd,Q=L»`\2EǌF%ӡ<yd5;Yq;.KsqRSyiWM{Zj^Ï2ݿ<R
/F'dEc45AEpI%9}īm!zQ"Mf^0G.'mֵQrKhlL0[[ ` dllfȮC-'C,4 ,zNGnL=	;Du &n7q&Nw&n7q&6rE[p6w$ќs pWi|4J/P6΢$gM:ct}6.>P-vgV+KO+i-Ȼ/A!0"aKpn 7x13q\bd]y"0bV5ٌ)S4N㜈%Ad9&#|3*952qRd{H6Z7W>}a9AIa,kYچP>PiKR<A=*)r#CY`֦&TuZv+B?Oͅn[ VŐj9fczW_^8L8Y'x]4*o1E]ߡeCv~sIp%˧:M$@*mQ%+׈ Ŏ,|&:4?v=VN3խlJY;r}M{zAfıtp:62O=ibIk~c_>oUOOu^l#^>MNB|"l6y O`"R>5}BBbBda>#19ZiiɎ&0\	@U11+qu0ܥ	'DmAeOo%Fd Y" AR *hP4 aka3`.%v.Uk>[$4FyP~IGqi2JVGy'luB{؞Gk⫃M޽`OKUgՌdatys@+8v1C;]ʵ z S}Jip!;t֪͑ooght:U\Skti 2k$/k5PQ''TJa#M.XZ\3rqCծ8/"[u6F1{7N+@>^Mo?iB߉S])?'7&42S
T++bE[;Y;Xha45˷ȀnuDMNڦ_$dӱFNKd9"s ?r1MnH-%dܑn@rGɹNM!$dl	B]H	Dn&dqSj(9+N"Y"ND@24#ʓt@eQ#5؎4rNONBaqa5vk1|P     0@m0lgd_%MQ&1$) \(䕘$CU8,f2KVr\n]䜋(&G.&SBWRVlSj`y"#<<CFJ_]	'	Gk/ir[yQrk/DfЗVg')*|Ș~k">c1V9fNE!*}Bci; s LFDO*+w'ǸRQgQN5ss5.ɧؗ"+(cTaz$qWpB|_b%<M	UkHu#R.G@"0r9SM2J P* `  t    * F	3 A7S50U"[|5$8ͬ6=:l$OSMIJ)tZi]
b%VY\flr:/aSU$cQcҹ#E顲a'96FM9+-Xe+	pE)4Ax}zϗ	e<s]K٪x9s[*@aX`E\
]D;t+/i1欝ۻR ap`tr/LrvbFM$dHRFMKd6y1L	7#9-ldܘdFrn@&k&nFrn@{!&䍐7R!_p7 Mɻ!"c@MR	HuH	&L)|(D:Td*;A9yўD9iUő8iw,㇕xKM+M g`] AC` b%0ɩEC-7spOUB"	ګc8WOJcbVD3ʛhd2N܈g6|<'We,%E/Q&"us48'&Ԭg'D 0yLFՀ)$U% X>|Jlm$HEB]Qsı%ς QӎEB͌(d0Y|_H,Q:=a-p8*h4sM<1g>V4qR43ķDT,RlٹgjDI5&LȦ*Tt(f[  n X    `]O5[⊨n       `84KMِp-CY`MuJ s|',ۿNo]dY?FvtqUMGOaRY8h6إzu6lڐ	WGK[Ylru;嫞r9f{c`X;(`W$(r5fj۰N$<{D)CU	h)`4Ao'71$5h6w!萘dDS料#@rGl2nH-$dH7!#&c&drd[$|LnFrFKdc%#&]0$:1rGɹJcL	Y7$|%&X||ds [6du1Q*PpoXRҡ(؋e䍺8ixcB<GރMwM3pRhzD6+/+%I&kiH	I>L5DT1'9	ZNzƣ@*]0D0Vr)k?O,rjbb:234偝چ])dɲsU MǣHJ|VR,ybIeNZ;g:usc(O#ҩU\|IQ&&5XfHPTG]5WQ}R튒"Edv:"0pfpf n0_*\b  (eY_ND,-H="l
9%cѧ(c@T  MK.	1AIX 1*6Z!-8K۞VF%Pd+(kʇȎ|ѹ]%q3e^Go:ӕt䤆r/[~_!78,$22^jduTtㆽ/c0oMv94QhY5vL";rY494 h@MM-d܍d2%
r1r@{!LH/ɹd6{%3?&@r1FG"`Jln@H.]2.KX`MHY.F,(>&HR+8nSY_iW`"H%n K琻6=;"y"ʄ	-7ZoCЍ-?Ct=M,,<v7+84=W$(CKX+k^Wx_x7)d&zdحDfKm9rT"]}<#ܝ{KHɒmH!nd ri)H:42@Mɤm^K$(d2HlDv4%ģ	 ?#R:<݈b4*i|X8DE MHQT=p~(mPvf6TQ%^#YB	=rr5I1N۰M2+=;e-ގuz#0[wğ'"Fbx3D3
`8\H d`=<&KCIf`G0+uW8~U%Qʲ47+r)-Xf$M(\*$WUE-Rmhj,VqC36&bK$8%#-N:ˬ9Dzs	k0  `  V`sL  l"ɣy7$d26idC!Lc%FܗLd@&k!ɹɹtL	97#97 ILddNKGt%!!=HuHҊ!HLR$FEBHuH!"X?qlļ#_ 7LƆlS04/#./Mnq&DqE /jCKvM0@{sh*C/	5HI{IGw*`ͥd͊<dge!3l`2Lf'LHT94:Bz˸$.ہċ`Fsx33 5p\@`i| r,x_ <8L6%2RE%Ƌ%V92<^\#dWq*ArFDȧ75@VBק8j2S{Ir)OM.lohmuԀ\Ʋ,95(>m2S"  R$aUXLkRNg}NUcqecFl67M1:/XpJ.ߋtuJ,x2곶2șiGSl8)2duvIS-M,味zPaƂ  @ h `  44,PЫT2Xl*i*h  Kdh@w!웑4il7 ?2]0t2\	-#8q26G2!$	CBr
JCBj
*E1bn""37$l s!2+o3lsɨ7཈m%`&"aUx#4No>$i
v>H00Jޱ'3a{CsC[B!JrhuI;/*9El⹀)E)Fr`(*D#ggԉ
Br)	ةK$DPL5!"dFpvx{i"NX#p[&H*$ w:[5&0K$V'lHhm25,}տ#m0S#2y"UwF	s"\HFXȍ+r>=(6vcU܈j0)I͍d2e\YS%`Ւqf@n߫"II
e˙:]6AÜW~db}sN[4&CtֈA.(0D\j&(L_/L  aX/QqY|ƴ/;4aݹ        ,   X ,i8   X `N*h  , |C@tqL@M]&p.Ko!|r]0%H/%&:1d4Ǔbe"8L`JLq2.G0ŉ97#9ÒℹRѨň2\M཈
jHIq䄫QR `G$Du"c!hĥ8HHu#<*m7i|.GJC.ã
>PLyi+bV	c2VSSTǔZ/h;dNMvNo /Y  鞂-q9)z8`uXrWj{cNNH<7;'CFIvBԐ^'cdCVi'UM:M2LTV(U{,jtJRi`%:.9i3llrx/@K2;1   hthL؍Ȁ!C 
(QU!*F2@6dfL@LSRdvɌf`CL2CJal)?SW[/dv+25c&:Ȕ&Ĕ:FYN~+[!>2],EoS  :ƷആpTkqK_Pq 5p: 2,    e@       0`*hUd2T4  TЧ@@q\.et|܍ 2dd6tɎ&S"8SL`JdTdDSd\Ɇ*VC$l9.0bUdg;Ԃ [Y[kY&P)
V&GP0(yArt#\L* Fbt)4 {h7gL!UOe^KtL+RKaZ:]1IcDTn[+eVNSŒx{DSsFI:m&Vtq9B:=#t^nu(Ak)LM^T[*e'8(et8Nt72?LZl⸞jȞc 'ۘ"VR!NaF`ܧdī$H3`  Uk)(8rȩddNLubH܀Ѩ	'"	K,hX:m❩<e5'.[!̎Mg)s{:jq P4CY9U_&k&)
ldR|{d"~Bnx"̓bY@+Y&Cz|Ҧ@w*ePモ\{ll} b    @ @ 0   #@ *  * F4@L  `\BNP,]@8]1ᣙ ɹɠ;r6ƍ.Bcɑ2:"8LanH7$fdHLRd	2Ul3]6-ix'dͫ([&5kY8﯋)(]2Ei$!	'LS`\ْu
d)B*`0=C&0R}hFuP{&(!lE=]ÓЭB/OZI$Jɶ%N IEIqB[GsK%*I 6PyY:+<Vi#5$srGf|~YPvrӑ^<N9m+uTGAAQ*R9ltC$j+pr00}D*VbM Ĭ67>fGkgG9/ȡWp<r*h2Peˢ)En^HrzO܌ܔ>3)ɐ%0;+0GGs]VɌ1ɹɹ#'rfF6gqB:|G"{\W~$VA	v`=f2a W'[M`d'5".͌ĥ`         *a`p    0 W  ,icJE\ҠE\B\҆beptp 
Kht]. B	tGC!(hCu!!*,LjF>!29xT1X0ęCL+k".m]-dkόsܭyydF2 
cl424R#0fp4`#$:GDY=:Mn/;@.+(    C:lcy"uu.Bc-*UxE`5+P}˱,EM~e|;%di2~fYM9*sOW5[O,:iQ9.^$/=i0l|>$
Ţ7J`Jh~lY#`	nxvd),wy*2bgA;q|)99awOT9!,;U橒d\6Er%eȠKtm9%Ջg5F)4nI?=-IЃ$WThԬOqAQgh:5Xhim  P[0*I 94   `      (a *hV VhU@` F,PU`.6XrQ`ƗJċ_P`s `lB25aȋd761ہ^IG+:/i XS2"L"$ʄO$MlcrCPaQjFX
!K(aERHbu"f%-R=+P8rCəə)E[v6tYv59WG(rRi<%:3U$	kcdfCO楞>g/QNMCÀ:QF`9u^;B|c˨֟ FĊY#d#2@@12DEs4[ttYWsdIȕdG fsPdճK.& :NDf5>d|NߧpQ.tܸ1	@p	G9g4C>gp5zӓ:$}Mfj-}y~FZVGW9ey=3jOALaI=u7z1fv϶t̒Ϡ:-{Hs! a ( qh `   
 iVP(    `@4@փK`0hX  , A S4q48p,xplp .Atb*]U5bCr#5pJE:8cLΒ:hkiòFґr/&D*Nf	чU3@";$HeM`64K`EdED={gyԞӢ= \S9L&Sx)+{qd +J,uz5ؙ4G!"\Gr1pZykҽ;axd,e,(Loiqs(@XL}2
d`Gm&#VIQ!rщأ[6pG@(;hӈ2=jt!;-+MJ 1d1a
1dY%0>1lCrԉHR%3>HBɂ~ cI5OFӥ,4yhz-xǮBnMwWYc8kak[@o9`l	M1杲C5URyi:ލ&俙!j3='֓kG_R9v캽Dlgu-X6=*֤$s^F;	yYDBN/{QcĬ&|_T~-errWZt?|FGOgha.}u#eȰz=/=I tq\    s h0s!Qp'ovŘJOЦvv7oɿ3vɿ 7f?ݢ? GLgHCh>UntGEGCE|Lk)0Ou= ,<ML֡́.́p?6D$F ET@<86LoX#!h?d,Xe^6#eȭY9=@#-*QXoqGW4nuG2.VPGIeB|~Ȑv:RDt0mC8GIGƉf|23"e d8U CE`zwNQ|;t;دԮSOm	&,'"&Nț
j=ė16 >z&|3w`y%jV{r:$7vK)&L>SL<
Qd"4ta.df<I#Ñ:0֬ļP rb:*."`09J!IBHa;F%Kiq":KЕ8bi+8-r+ L$FD48
q!LN* 3|U^8ȨutKvp6M$dKml.b]B;ĀiqYO$'SH<"URb}n$z 9^^椻:ޢ2rqN|;F|^sM,-o|[#P
rɧJY#HJ0;d1b>Q/3Gnjx aKt7H
`SuZW.J<OA^s+#bZ?CD*K9둆zY僫x
5\ztߓ|7ׁS\ tϓ;ϗ^>O~y>]x\ tϓ;ߖ^4;W>Yx ~zqoO5!W=Og^Y| !gzo˾C>C3={yz|A0~~G3=:ywʿzgzz_o6g&~C>Ca, զz'zn:_B\tj}Tt~:?BZzOn:?AJ?C(^hiv$QC<xB|bʇT#}oM`GMkg"^3=}RGOFJA<gӾPgOkOWYV7dǢW鬮JQM4wK֟2佁`1:ԉDiV.M!6`#N$xė4d#=/JZy%STOCs:m[s2"dvF\  8`>=.GV;ZqZN+kjɒ[gV,3&0662%yx4bo%_k&(JGh=w6Gegl*F*'.N{;Z#TЋőv@[zِ'vD}WwA8MM% *}(v cDL}0q#Ԭaw  °F-č:$T((T6VdA{x'ϸ DM{Ih؍L
dȉdw׹*'̊EF`q#-*4	NR1+ߘGn]*hfp\*:CM2<;^\Rnji>Nҥ܇="DdPȅ(8Ve@SJT
4 Gdc.@THkuDTGI*# CHdiܻ!nqK*$t*ףGg'?VrVʴWҬ
Н
"OH>c!Wt    `0h Shmx 6M.J " 凖K`^TycOL>L<ȟ6A Q$ e@s E@6`W@ʥ"P -?FU||^yR1$.8JD!RU2,f"'N/KM؏-|y#qh-o4ҏeufDJkcsY)dL_g:"aa02 QCL OOBLnj3*bep(y{ș.uJsqə6ʶq9vq:H56fXjT8oOlFqNO__3U^>"\b>:LVloqc<Rثq(J{܋WXp
_&_ۙ*ZNbS(+wɦl+F<T	dsyI<|&Hk6Y-zn`;sMwP7x%"7+rɌ6taF.=ɃY7#)r;*	uͱRG7B5y58X.HxQ""DdiU07zB2VB6Z?ܣE S'GP3P(F\mY%̕L D$	ҤdJ}Jru8m:!" sҮzu	83W$/;L GGbu`lp=RM)@BnO^w 1V#U̕Vn?^XOð	З!J	p
j.`0,       ,     4@                  h           0 0 0 +`h
~R3D!yRf/Ljp@qs[8Rg 듋ܤI2DyDf6X hP Jc(ZɊ2#+aX9a)Ox۰m2vx3\Xkȁt@k͒Ƽ>͹ۀ_Q湒%q .͏7`MhjӘL:+%LfsWOv$Wbmr˔tAy"]bC>yJe'bR5py/FnL|Eq^/r0!,d2u3!M#gZ7mXx88y\E;}D^B|KQBEz8cr!o7qKLpltsHڈmy">$Sh3_x5HyHܶ:AlM&'2;&69$4enfnDPJ8:琇da]YŸC"l5KurI["J<eD_"OHI馸ud_q
V6ti&K4-4!Z'z!p@MñQ%ӦjӇ4:BtRh&2C.Y0    , `    ,         h h   h  h       4      0@@@@@Ҫ   ILMckyLD؍ a16*X*XP$DAY=̑+*CD4JL?2Wa4"F &DZ+"ɘ7*a	FLHmΣuPƆ$YR46E
e(ׁ:(_#1|p:<%{\ޡH3-5$^V<2#)J24U"Ȋj\_s YO3%-io0ttZg	嗾š"6:t_#8Kz61a\H$O/{$CjCы@d3@ۆbBb35i![3w`{sgĚQ)SOS1"=NU0"!!ܐ`y b=N\F\HpNqq\F\sEIN#-  #07s$)@b:L4!O+r!)?qvձe>dIIw؟c6=jL1hCOB5V	[ƭuF-Ce\ 0 p ` 04 
,   `    ,       h    ih h  h       4                  
    jC3K18-Q̭DF1"bAV4cli1\BMBlY\³X=ȆSMnW x '` 6)mC[ OhfHQpu6Mqqha"YNlYy0oIf9;UI֎)!G
@4?*.-<c"'5-n]r3i}qRKJ"uZg>crySqHP86゘7䍸 QE2nxd%ґ`Fd<KЉQNk(DtY\H7Q>Did*$hTH@ ЮQ""ESi]80IhkQ!H}p3CxbgѲ+  }zIY`,eb	6TX}/#"\dwxcɆV.PE ` icL4`p       h h `* X
  4 L40Ҁ   M0,         A`            U U` kI"0<MOssVe1kdmVƛ562;fGlODtT7*߁XK*\Y@Pxgg>&4:4ao6^# 5(XFRk:k
*'7qQL324ȡ0m"M'uv '|V"N46й:P:/˫fkUIO/&olQxD	LSF+!Qm%VIl謡M	OƤODIAggm0Jb!lh裆6Pcrs	6@UX#a]P@ Sj7 Bu!P|`͢p09$1 2DF< 4ʎ"t ݁w#NAV?'Vra5>j=N
Rt5>w2Bgd[,;Du*9'rj1*h dh h            i  Q  i                          0  K]\<Zcdrȗ9`Ӽ5&0ٲdvMliFf64#ZLaWi$Z^1w@xc+ueIR%2v4
`?d`ê/ܩ68Cg#Jn#{ C!H^12(W!R $g?U$2>ewqc{Xk"}Jlqܪg"$'A2)քЧZJ)Ȣu56T%Wh:䊻+TncY*&1ıӓ` a  ,[ TY.H c`*5$Yo,Ra&8"+H g:h\DNhDI  +
*$Fx"o0`7jHSBnې
H{11CY%j!Lv78a|=*:ɐ'W}j=9uþV)էP7ӃL6dHu` 2.   `04 ,      `h      h i  `*i                 0  r}Nn5<s>լJ;yyȝ>٧dv;";
cll(eeE[3jԗ5H7G,];\VLY|pKفD2ɰ2Dzp1`9	&o?o 9]^8/	[(wM7c:Iw If6>eLM .w Ԡ1*Hr׺w~9La}Fl	X2ܫ)E^%YU"J;kGWS0G#r=\8sjv(EtRKlSC5!D$$TnQ#p0/&:&tNgSĻ (IPs	L%Y=0i4	F$Wy+Tv:4s`DKIq>W
}x!v- %ȉ!C&Hn٢(8(.#M0TP   wHM>M/2c#&d܅:ԈƁ><
O=@sN\R3d+թ{ZucO26hslUd~R̐AQH9XUX( ʑlX             @                A` @                 mecV;e9$@lvr ),a#kdv6UdvlKDy3!"c)Y\Zt_B*K8dbrf(2XNh0|AŶi58Eh	!*ǶI򈳎u4@	x.JI{_-틂Z^{)<U 0$pMx%'`%%Qol'>>"xI)a.ߣ_~O~U9ՙ'qǷ+V../ee\"v&n3N2<r'N~:C%{2%(5ـoUF轹;#I|K/zh^] J>1O(}+͕I u?e꥞+-ti)A	x#R:]`IQ"ĕ"I`Q"LQ#\CfZX)
)<Am:m5"5%";zsam<PT:ޯ[:^4.MvBBQpf/j:(_`	WBEeO_[[AQgsv;eSdI37aQѰ!$iDRk#R[	Da*1BFh02"_!K c'#28_$lL	&dL8&&nW+nG-k[.]cˣܝco˻ZTJZSW?J<JV9cWl9'#\['QǗA2TlDK!YL4,   h            h h X .                 `	<W[e=W¹y~2R6L)vli26J0vdv>$T3!asEsO.I8kchxn,$%'ie,To8P#I3Pݘe|VM5/nQ;rǢ74PrHٔWs%(WDTvkH3z g F{BZpl~MϚiwy<V;яFFrQm>k㍯`q`qZ?a{__Ω+טӅ-w,˻,X47EaUζB|p.:'^=z}'FdؼAkOtdF]W'⇩q%ā)aD5Qd@;7Nm5.%I5UY@7=$ld]vN2@An^'>ʷx`sN8:Wr.#k*xўˣ%|99YU!]lmeRP"Y]R0  HOhe#N$%n:$H	Y-6K&a1%tˡ:pS@GS#@M	yL	È!6%HoFSO	bbejZ☥^Yr9V4uN\Jxyo}-s\{wJi
2lH  ,                 @     h        ef#ԭq+|ܤg#Ʀ#6^L٧hܔlJ45` a[f"Tӕt}"v=F94ZЉr1uTyy?lh DK`= =$ӌE}r`o#Oy4~#ћK(m} Lo(bQK&Mc> FF)w&Ɍ)wٜ KK ?7+\ODk$hEq?vbi1k]xODCudɧG׃%$=oj9}_߂}񌱍}{<PdN)N*/sLvU2(EI:<[u zs["q۩V3/o2:Z,SIСEF]Xc9)dc.l_'*xX|p<[Rf7ג|/6
Ks۷y$8OǑ?{+_k?KQ8pcJiOkkǁvCf)]	Jqi.Z?5=(EI+%ۘĦPEOd`R;!-*XaR@
*   0, 8#N >	#˦0`=2[$l'&]2"eCLu0%dH%d2"MlS-:':2E&Fq
HMX             ``    4    ah     P  hż Ț}vyLŜ=#aC~CӴ4TPѶUf4ʖe@e*Des2pZ=I=Ex}*{^yb]r#XITKHCSR%d2Gc`C>Ƽsfx1FBs'O?:nhKjˈ Բ=$C=5ÆFTXܐh'2?xzxq*_q
oix=3ɧQkp q].IMEb\c*fPOo^ Dak&V,
UQkx|Iz4*(aw|<a{@5
cdrn|f3/\hR%^ڣfsdR'FO;:؉NJ[V\Vgw,KR]bUp%$0_D>̑^PʩN-?s柊de-5ȈE
)E4@,޸/}6VF y<jB}rݕٮ8fly_q	JY@R2Fi t{>+e8FNd̺\qRK16l ތ*m$FjH m]Ojg)i.I[mΆ qwSelbk8MF8S#zP57*sG'*lËOa
@ 
 
  
  #TyL	y.2@tɗtKLu2
c+%C`KRLS.ERS) aȹDX"PCHuǹti1zQR&!L4                      h `0,  i       V:ɵ*[% xX/'0*kfl>bXzd00á1aT*iP2@"ȗ"$6zwD2x_vO2;>?8~y6ף>tm,'ÉV4IT5RZ@jH 6Y,X^edd6#,_@x#	`7F2KkC@܇dr9V\@F#$E^{{cNuXOkM8.MsM62)GHܤ]/o,22ट\c4`9W!r>eOr|:g]0/]ױzY5qO`Gn<?l`ZșemȢT!0T&/)>K%ǹ1׻O8( ?2c LFn5Q0eZK9l
)f0OInM~ɮ	q*O$o5 Sɺ絯x&ę%4-FjvK6%	lk va<p}^߮8}ksD%&q!O)_Wp}!Y14.W)|K#9A-uNd#'Mc+DpH8jԬ<?A[ӡgW yi\(6ʥ	4K]Q p4 ``{n9-lt2Y0$82FM!%dlCb1 &n/^D-ԀP[qqmMYHyM;&䉽}%"ۀɎeEB) &Q i4*Ǉ @   4 4      P     a  ah cL4   0  "9n-ΚrcSTj95'=f.0`6f*K GDdV)w="^bo-{Qd\[4#YSs@IrziёyDDnC#y do %>UjDLd]vvCJW%$[	K,e} 50	{Ij$k!&ӏo}	urO`U{Y#e`=-d:e8?hP\Y&K
?LFkldcI oM='>謢RX*ǌ9
>%y&V"g(fm/3<^gߙ2#	_{v`  }a.2YO$jQɋ0_s\v:	<|S|KJ1
-:3-K{ ԗU2Eڡ&} Iq"P5>yAMq}&fԀ%*m'd8) [fI-{]+xˎ#<}p	]@.\W(އ(ѐ{Qtzzr"DjdVQDiq^9%Woi:X˩8 +nqZ,x֟]e/gmmA^t_P/{NqčʉCuE}^TJ9:`JEQ\bt󏎪2ǸEtiVS5	ݨM+Oqsy[K
 o Hoemt;u8ST;eelu9vI~Mimk赭^-3Ϡt#z=^vqyRs~?JΓ|kf?Y s;f|Fx_.sj.wGQ;.rzM]Sg+{ק=?:*Uw]9bJzuZx_Į?A2/C:Q,Lxno/=8p
8꩎*5қZ~ddCt{M><k^y}i}=?lwQk{yS&Ϡp=KGzik^*)I/3q}$F,uO6sq^6N,J2~zy6ra𬿾MJVm([R|~NiژEڦkǵ9/QRM6u
he7㹹<TI:T5Vn:_ŗRBO_l\cʖr?sa=V$zDt)MQn+-/dAK#iApLj/3qY26ͧkiw#S
d1 $ɹ#߃s C$t2M e Ȃ@ߐ`/$ |Z5?wa@  X        @   4  yO\=R`gyϹzCUca1ѦliP  2 H"Dz,)"KiǨ,Ub&GК&dsXJޜ,ɤ)""AYGs y"蛏= (5dwENҭ
>̉xpbmķvy,Y!,2&T@}34ǆgo&1(%9,Vk3hdғ]^ LdK+SN/oQ|@nI7	/_/Mˎ	܈,z]*M.R>~S(4c-J\3؞mW)W%clg|1qDI.1vN/s$7-IxU"-FiY/y$J>	D$
x
d)7&׵r~$|;$ROĉ8\e>͂c$y "d
tO &&l\6E+8r<WqˑXKtsRQ| fqr>+ėp۵"}ZГm|E|fQnW<`m8.%dӋkD:MtnJc>"nEy;>*>cb3:_NQWԹ"*]Y,U!iw:*,wCǈڸRGKtx<Oʅ(_zڨiLOV]9<ȱwv  w['*N+q~Xu}7ԣFO9q0kmtzje{yoa4N4ok/ =9p\Ժz\$%_F7FyJힱke=6;ڝ.Ҍ+wJ1XIpR|ԧXY>qiF]ˬv{Νe 69ZgO}Mmh[Tg^qӄ& Nn "kʶV .۷I /k:Ut	[֥<pj:1pM+ )LԴi)ٮ<`}r WW9{y[ q[7i}mX#;>\U=3uEJbJI{/%]lVeKlo8x _ ġ[M6-to:%}]6k}ǂ!ըt)[%,nݬйcǉ=e+nj~d{٨Õq1" {#-/QENc1O }Sxx9HB  VF=ZX7;cK5zk!|NK9y_WQF&?zF ˥6K!"05^공9 KDvIYʬTKk(fU:ڹ% [+BZ9UT[|Ύ8έ߮}1OIZX]
<֘yܽ}"G7-_6KY4ʰ=Q\8(<=?QL~
]?\R Ł©8,YCukYq~ G   yI$n~	  A     4    M04      i!'/a=byOŞg/a=F{W:G06UcL* @ dEXĽ\us|W4vbݾdAAKù`[K$POJ6G"@C?P\⤹,Z#hx 46_pږ뒒X.[ଃ"h0=UǊk'+d6-h\ψԿ4)An j9.wIo<.8O54(?3h} S%%v^Q~kr Y]Jcn;<zpR~
Y?g4P	rgsͮ-pPxQuqxsT!嘇1N\3!\#.8j4ܲd7$Eb26/ 1k(/M.+,ő뛋PwjV/	/\X`TX}'pHq&9!M5,UTr6CvVQo| )F{&?ZɯY bTa>SkĞ'f|Hܡ<cH/Pnc,	WUY#d4R6IȟM2LG&д:{{qۈvV)?x(9==Cp8u~#ִn׈tupTil[/n_LV}B.sS #:,+D e[ǝK~ә=:^]B_M5qcaV}:klF9_q_i~MM8Wt+~8i{8g^YNU>֢ˏї%ۑz(,KrYJ(ǋ}7>3٣I*bخ_W<|V8w9ϱSWfl~\eEOyzU YȓeVU-wOAz7NsݝЃpmqMc>iU"V8ECsܵa25IKm5Yk=SǼwFTG}KRQKH2ΌxmQz>:^뺺jMEK\椸>#+VUYQm?մ-/
|85yxx?k4CQmoO-#T[|:.>iݝd%q,+>}UȦ۶w	OnsO|yZN[Pn*)!MpO"uN*r|x(Y}in -O?vSq_>^zOYǜg+Qd4u=iJm>mnAu<IuiKmU?$<Vޞv6on^r'T Hzu{Zq|\W7EimV(ͯn-?--,go }OC?S _unxIc4c3̡ٶ8 >Hq,BE`?r,1!0gѯjk2Zk^7ɾOe-iCb<Cɿ܆ruM~Uq/E(~/2 #F>+o.~Y>k* DC&?K|Z?d,  `        @    4    4$XW#G'~,#caQ8Q6
lLL  d$G%HW:EѫPszG _DR\+cf(Vܸ| J9"m"K
ʂdnWgAM&d+8CpsMq/dc|QfYsG7C̃D=cHH\Ց_Chd0S!4! @ 2   0;52GOHLR?/k_!'|@H}y>,ϤPے5Xؾ@9S^?ܗ'6QbN/xx2N-X~PgI?KQp 4ؖG3ې[V_d]q ~'.<3AU%fE1	,1̏8~!(yx>w_uc&Igmr%S\h8d:9U2|,?ܐm)pRyRhCQ
!#NĎ܃*zR,1>rdm[(G2vըR5؞#	m|sfCF]BuL-s{vKt_qso]oUJQÂExGIߛ+)~)KE?|<i~/zE%lc(86߿4tiW/v_sM=|N#.Ff"7)tK:e['mP_׺:ki#/"O^KөRM6(tL#oM.zNb镒ĚinQ]IMKK^}S[;o+Bz#U=ON;%eR.Tzj k#hNwfw]K~Oh`^Hz*k	m;_TWm"%}'N9@Av*EE^]qRȓ9ny4kK{KL] q|19c>`ĬL0h)k4m +o$ܔ63 S۴ 4og{C4EW1y%\ ɼ䙒8._0Fc 4 4@      @     h  h      kI ^"nyg6%˹;pe!0ꩆXƘa@ PL F+"+'M$N'>:dP/y:clےwIFfCEv6`0m|^ Aff6hm%3iQiI{Chv/hӘc (p,f `      7#f C#YMC&#!w 5x)_/g%-u%/Pf[$]㜥>5U\ixve]Y^4\?/<SD5
nQx5Bx2R@kIs3	|8>"Gs38n(IL<+<gx}0đx>jq˸Ma;[2]hO|gD,=rz2>ge"-SAugW	ڝ<|q؀tsđ7Mn%2۬ȟ#tڥ,F_.' ajFZzCa6lښ[RK95s;4zzSS(ZUr7ejn+s{P]>X\Ism'
jRim,cǹօi(pUxUyoDtl~є%-6'6X8(ľowb/gl7FMpܓKU,C|׎诹CFBK=״屸m4tJ::Թ~%MJ͵.QXdt,}k q38BⳕY6򒓊0񏹚 ;dpTŸg8׺]FGk?=y fٍn2Km5G6ױ̯|#wfeʥs2v?4}6o^'6 9xc<&K4XK o2^9ep} WnX|<gk~x<?ܐ\珽I~wf9aݏ3s'aA'ͬ?~Ic˓, Qqc/ߏ!hgEq?Qx6 T   ` @@          4  04      !k$Bsa0+mo\9~g>t$2;00Y*i` iV*&H"}G7$pvyG ӝzь%J*TrT  `0`X  eB  .aCf 5``  10=  QF0&nL~?r.I?A\60,ϽX;ؗǊBi<._z?or!JRO#L\T|xVycq_LAKH $0Oa;4,ʅF[/&^z#|v XQ-?1DnI)iX5r'q9ϸdpguZOv]wvKe}tJ_ܠ߃TZǨ/|*a5|{KqÛA-SNU^?pQp-˄&A+I
;XKUUVIstMy.|'.p(*{2R{q{_ 嵚;|4q_O$tFǌM<~qɁl9|qR9QNY8z.z+'<uke.~LuC<)Nile6J_F[*lu{WgIRI/Y9^X)E}ðΫq sぽ	LyH?jɻ,s?E} v<ܟ (Eߐ  =!I  0 -͇תL \KPh        h        h aX      4  ڙLJY^ey:ߍC:*3X0#: 4  ebH"dr+йU^3J i*M,a&hMP4 R R4aapwɅrnJ 4 4
*@              ^e&| M  
/]X}YL։A=@C|H`zP82\F(JrQroK-
' P`wpIKER6>BM~a5hu{Umη8^d	ME6 D# __qRE[T	AI4 FaYТ'0_(+| M8J(4Tq>Po7Gl⮦TKl&]
z(k$ðԢkǱZ+kgZRLQP:.1[j:JYNۏ	gmTLO
f?W$.:_QP؜Ie̶0C1JS({etfׅɵ0$O[:ic-kl   i	1N՝|6E(n"K<S$Uu61zTXsn"ޥ`٦O	 Gb_Quӧ\]s~*S㤎w콺z=JW
c*c)rݿ928Ҿ/,+j?m=|bĈhKɾf}͞ r9M~b#mT{W}i I1ŭ=?S۩21B7EVtCq_>)PڎN9mIg<|ywtuk<rMZĿyС'GUy5^j@XIzwWWr>r(36#SSb<&<dFW (dܑnQ$ѕ!h  ir`  44ƕ .       h   i  ƣ a3z\Ja\U6R&'&.ƙE,ƛ0cl4l Ji` C2!ț"$CedN5=>{^l$ífܚd,`  *a
*m%dDԯ9Gx	f)DSjĖLa|\M#  
   @    0 *mү,+ٟxˏ2:u-%mNV5η3OgCOQTܚykӞY?,9\TZmF0v+sE2 mjӣ/SY[,%..[%ꚚzYa,,~/xvM3F2~.^S_Oipcʗ%t\45(t^R)WuҺ^PI S='iefԾqRX`O-/6lvS>Z(خe˂ hkڨ鱍q5SZNKVI~;J\z.^-f;JK;nIeeκWk4tV%$]sI 55]ZmjW7{}6IC%2s7UdrYdk݇?p4+Sn7%p9uz*Jnr~ISlV%bn~>!|gfNey~__^qX_i#,ꚩFn\)-޲ŕi(:uQ7
;q%22#VQR2XdpfUsKl^3+8ᕒwQCIGr{r:Qy6 gyZm2V̹E8\|y+mV7ͬλWhC|^'$zf=꒔uze+]cmMXrO;V/)͑rX޷j&/*J/f;c [mcuZ}Eڛ}_ xV0M<?5&5ſAWW_dbO<mBvGӞIF[crq lplc@!k4Ӓ]Z_IYs4xts&2 *NCVY;;RRNQK=sRe҅wj\IR㜆6^qn-sO8g;^2)ޙT˥vÜ\xSy OQm6NS~2mgqWGңm̔x1yxoEuCyj8sSe9|;do!;}IN.Ⱥ.L?QwiWߧ*IpY^UNs3ahOK	5)Eiij}N[R/ugm?Ɇ>80<cUn	h#%l&39x~K/B]
n5\aYF"~73@M}*dϙl6*<x>J=
ޭdL 97G9a]W@VzR]Uخ$f]@C\U{5zfE]ٍi\\[1otWKQM7e]y?I,ԭ4R78>]:e:>/.mMڄթ&W太"i'e|Ot7We*,n⻮2LmE+c=DTEa7U	觶_T{kA+GpmҔw4V?{OӨ^ڮSr\F8(z6dISx/YIE/nE==qN*)e^橉M<!2࣌ QL5:p7F=<_\xA2xFL ROYkHx0ПӎX2?WW' .hٙw!pϣV8ch	 3I4Ϥ H~~MKy$lq̔|~ݴ)O"``cJ     3L`":unƃr"ɎId΍cLfXfF624 0  68ʌ2c"LPPrCf+:SK'?u/{  橆,T
i` A?P(1dZO|TDdT,]SKk!gU[d"pAN-att9Cǳδ  @         `  i   IҴz]|UE88O/2t[Y>:GJۧJ;E{2=]3*Nmr\\vCUKOrK/!*mkv7rp3%RzL"*m]ܡ$o>Nx.X^/ @\<,qsoSoIGn6B>2K8Nȯqj??:JV饫ݕE7~r.b%lBvEf.<%K	_cQSkjn2K%zѪإc<[X{@-
[cx|fC:*v8rlt㿈
hQbi,^5eRG ` llqQ16eHdvV殗gvwEJOnd-?WQ|݉[l_sKt$ǃ;(juuҲulĿGgGuQqnO3 3XtFt]KEJyXg,4-htuy[kxcT؏/keQ[TeٔX26 .=,Rq#(,m7Z+_d|w~DM]([%L1|3+]NumQqY\=)ݤGQCUN/)C}N]гWߌ׭~G8y7(-Ot+: hB=[[%[(G}X!-;Q}mMXg'-{xg'MEա'|vks?NK<GCLקPW}{Ҋ׵2]iӼt$Κ&3)KIL,V#9gsݜꄏ0ΚNQ)xgOڹҩզAg1V  =%^[d#d SnqI/ty>^>^*ǯy7؅jz}n\3.9x&{o]誚Z^EsdNV+Z<R' A_յNf/EpOCҵ:߭IWJ㷎x:
eSĿ|'gc8]^FQb;}~c^2SBKėW=Zڥ	X',Hv꺅T_-O`\MMFTs%}53S}%-3eunsx|,u]wURuR5Gkt>b+64#/ǇQ]uC^ܤn}c=;떞/lx}. pj\yfRgP6XGFUlE6+52yf^{.k$Zl5O2_q5UXYXwgA[1j<K{hIS[}c[7 mN2Sy8;zw=\]^:#sYnc1̒xwȣ{UOi..%_ԽpNsdPcQ͞Pg>bXKe/cORtz{Sh@WG92rv9= DrWCQVp"\mXmY ^R5'{PeI{ g5>ϋɿ1ܰXsP5p>k~87Kذ P$KYo`X28# 4@ a ԇF[XrfO'륺;|&GTi#qk2,ƙ FL
 lqU#̒12	#s1	"?'"׉OӑH 
䩅`0T  lsJmx84wz v?T.\GP欃rGqq{dir6Em?SEnaᮔ 
  0        
     ug? &@RZ(%|eWsB^ۣǕ
d&j5Ϊ7<fJNu<IۤN^_;<K\V4[3Qrַ,rSS[^8\z
)Fܽ.nR.7.6A:]'Y9PC):8jK=?wN_t̤\޲1vqy:RW|9G;#wx>b )>U9C^4Mujʚ7m#ۯ[gWԦY=,\Uuإ)wnyX+A;jRbU%}6_\bK>Oʮ3	S'+ G *?HE맦g
irM7n<3e^KmIv(MbQ2bOBD姪Nqj1I緁`Pѹ:s%/^uƋ>VEV\`oS
4Z)')K<ܥÎ&ivr{x,.s,-
A5CsGNPN
[y,r&uU% D ,T .P4X*Ia["dJx:!ŉPNG

   IHDR      I   d   IDATx̝eUnwDt@AHT	MLE#8D :&ĬQHFrAUkt~oVϾߛ`i`ɧ-K/?}@x:|&C6}f"֚Pj9!k͘9ϘXᩤGggYڌC<	vM܌YSR ;S50}|YӞ`_vƬeglX0}ֲ7P+l&ev0}å`ܭo*W{ÙabAf·E8zfC@Z^Rv؀fn.bn{) Y$<	55墇:.5	ʄthj SIw@! @[rm,44A#UJR4T#
TYupUT=fESe:Z.9C@ĔGKW Wg7LYW!   ׅZKsL8tEoxO!\ؘM$ļ{SuA,51Xa!̝)t\yup VmKdy	9k)cb.ʡl[YήGX92*	I/G96TdIlիWR\N<t."0AJ|PZ虉+z@ibBREPl5ul\ A :8x"R";jPҥhzؑjFXEXGQa[	}|$d^"e 	)1Q?Csʫkc:a P TDQMBqŶxRr6WR2.I`Mv%'x9<g2&krD@*7Ps'175V̌mW_ՑL^}B0u4s4%'<EǸ;/pU^ sr,0&yzNA
3#a:T#$7N/JZXq(s*9*fy|~-x@2$9vU+4r7D̒$&̐FvN`gI=˚Y0@q:I9uqkIIYVIzۣ$׫hT:cBPND/H2?UY4*)&PP2Й7	b @N&#ٳDrGL<Lv&AaAg%JL7=bFLa?D	quHJK&MaڊFy)RR$\ܚK:2x
0;,˫bn&bFQaԍM I1$ˆC-.q66Lm˱h䓋UN=bʍȨKf5<oJ`̫)p%$EJǣ&fTXi*U	JA#+fե˫uƞT}'1y&$Uo٠I|DLJ7iC2vw 'p
M73t+L)͇{fmlMMCwk&Ap d͜O:1-[p/<]ؐ(܆+Mw.ݩ	b4Ss|0YuЇVhyB)@@ϓh]6͘dϺ#neslxXrU`5Tp?cS
Soi򸸌88	 :YKrSL+`T2bhQ
-ƽ]_1L^g'R8[l /+PUglBIDIgö5|h.nYv&D;jkVw(teaӨ$ٳb>zWاBDn$m&IKjxWLk,@(*	zޒV\Ե
Y9u]z`ń᚛l *Iz;7"}9Э/:pB'SzMgѕ轑e-\LYa2^t4sρҸ9:@աU+<kxeI87z
ԍw8Dpnfx҆[)c0"KVbͥQ<ChP*vpslnf9j#ԔA˫6=o˳&;O\3un1fKXC2|Y#&(r8zlZ4xMv>ey&e(Qx݌-@p2bjI
L)yIbf86yy7+}sg=F=q?rՄc.9cp}a颅Yt^W8j&aG M&xJaPyu
Pg1JKP*"1)"D$XbyZM+0GFגҌ*dRXQfB0G,C(	)N	))5@@.$%Ù@nAfFUxtRdۘ?hEq54y㒋XW9GKvIjh%˝JR{)ӲM @ 86<mb"k%өGkƝhQu؇x㤛 ;t-c8BfdV[IUن^5cnSSv+z
D !eg0xE"CN*LꃿY5CCQ50yo[rs3CDp/<]ؐcNpX`l!'1X$
CΠaj<x>=Il\U*&2D~/PUyCuOY=ZbX~hsruK0I0/\.*CpP:s39J@֫Tl<M"dqdƄNX:JXRjLǙ$9ή*ԑ !Uv)
ԃ?ա+/LlRQjBDc<8JẆ6WFQeerAkcz.1%'dx1(&AB:U8s&aO0}[MV5 .~ 0
)ED[X,g90( z[pݤ2[KM?қҼcA%"	YK䉄36Z6bC5౮?=`.6kϨt:cʉɸ^K73iN3eVyfoNA& _ՑѢYLQtquԪA\fJǯ\!9b"SX~hAtRH*4GF ah
H`'dlR`&!1Z4xx!.t/|ɺv6tKqs7+pa-^H#uEk~o0qS:3x$eei"hkd4. oDSP%04´,bn,F&sQ.X3˫{(nqml+aL;ֵ*Yr[ș
y3wiHsiH#C>.=9zlj%cJ|8Q<LǟRs74 "wYB"YA
Đ5S,&^bkQeL\cIhQT\S Fҹ4qaYjcnqBH/FI:r̆ęG5;+ɲ"2#YD@6Q9YS2<K[CE:%Dٕd/`61$ld	<aԱ8ϔ&HRQ0UGlaj3y%3ӻ:,BhlI&y%R 8;ϹR{Y# yč6^[IqP;!FT%n_ǡR`pB   IDAT&[kj3UZAr@ixΖgW<S+Yn`6uH0	֍ݢE %E>>>ﭮ^2LiR@`ݱX yrfzxm:.FPPU/HMIi2 y*_(JgZW捹58Q@	jTǤtIZC
#L;CzzU8^rKȵ"ΰ"4Ic[FRГk"DDTu!M1NOq$`,AH V]qv
bEڝdIâ16j'"`>F?xvOGJ*$VHQTЙ%k  d \utDE.+
P:E8.. 7&JjHIU78][ZI,AXdI3YҊ p)SoRUE# 4
d2Z8J3+XbcГk~p2L,7j"C 	AmGĸjbS.~xèHf1d"p#z42.G@@zoSQE9AF`.p3~rk=134v1a+\?Jk:uXN)Js9c%E̍r"zpRЭ&RL\
5I!I!
v J$<	55E9j.7Hwv $ܳ&YJܜV9$7#s$$LNaٙ1Ouqk8fh3wִ`o}Hf(:A2zǖh 04n.+fRl23+K=A>9dXݍshN,9ͬVt%:S&$wKn47&HG'j#|;QbyfY#|7 5DF+(bD=T0.e5w$d,gPɢ3)_ؘO k^f)7Zѵb]!rٙ>	#^8qQ)L_o#7Y H!vBTGIn:I芆zɑ-0Ò
L&aEc2b(dX+xDYH`*O]ZLCp/|2իX4WLDDk<JR?"l;ςp0f3vp7ZU8P7.QF¸ra :6(H$XIۙapqQ]pjA0C:tW}]Ⱥ]2W P6T^"hrMWnܢy0>ٰn@]17VnPZ*E[80y7H蔅h^XJ\\unHPql! : rTfn`+FThu,PL-gj(ս)Ac<X3c7MFK? 7ÚmKzEUϫB|[֩@5UBATK*B}o@^SחCH_8.rf,t#*UU]|
Ԑ= bdL:y' `yڸfm*:BTDBcLb!̈(DQ8Q:D:6=B<\Jˌ%H	-_?	H`%[9p$MWQF{ybh^
-p/|17A<t!QF\i](b.%x(i:Fu҈qq(HHDqa::"V\Hpq: DUtpEv)B@ϓLdke2P륫=ɭד`:.K\1W^wU@ELH~&TR<tjjy%o|n.)M<U 6	ˌliRBÓ6( A2@:N}ݱ	խaQbј,|oBC9uD3Sxܭp^B=w, i%'/ƛYTj\cYgErREq(\gqYnպ$9$AFc	X86N".Xܜ©؞BRN3qnsUR]2
!taJfq¢ŉӟԤ*%	!5ФrR5<(.
d;a3,ֹ<0J ͶaU@B(ل-e&aDM H-YqqC\j\|*yXuYLFcƠꔵSaJJ*\@9p*C+uWJM.F\k#IB^]u Ԕi)*ϛQ"b$7\֍*OnzK ZQ0dJbE,@̐q,d&sW2X)&0vF5QC	S$FH>ę-DL_\V]E$RȌA*Z Y9cb(PZyu8z^L0YN4 L?VnK3ZZ}YHfFd6F&$.CSrqoTi_mK
h@Yfl4"L,9б^ǂ.DtГKYІGƤZiE!pQ!MLy}Tp(`r+dÆ{6L#7d`i
NU:M9j =Lw\hss9,Ç^v9[Zd'-eڷwZVY@im逕c840t)%I	jfy$RLV
ph'.fF[m'2Kcce/p;-jȊBRjI.!&C78A8s3S75<S]ttxx
s~J,oiG>XbӧbN.9Gx>gC(,SsW\zKh7Q^KAoV.[qn1IzJmB'dd}%:o?0W4%,,%wǴ?yjNxMrjc6=W^"/C\t*˴\vXÇV
>
E<4U'G)lCv0w0SzXq{%ǩR\!x1ChiB
1&_4k쁒$	굢a=w}CRb~<Hh-uZLQ
4	ߗ;^$7!&ARl2Igqh\_#e3	gH%qp4#<94#'aRq[*Q"NYL݇.9o}or>{חO4qt<BcT){{p­4w/-5-K̪7ZaJET]-,Afn10SjkJ6:[ރG䆱n#2\"KTxNV`%Kf~Ȩ7IDne*ՙǨT]$'~x$@V3ү>y{޺[v}}mSϷ4<&6ZO
&lN`IpmxـslZ[:>xÅix*Sts3w6`M̓{ bZۦĬTY63/r8wa֑3
	j| 7:)>,?Iw픻Nҝu7xS;H&]x
gZ1FH ZP|i$ئT*V8$0.Wl/u$F"&BVPp1W0ڻph.8qE[@TZCgD *`b2AUOr.Ic!	8@Y3"g_YYiq2@L՛   IDATYM8'O_;m=e߶nqd'_p'q|-k-s=$0$+/pu97B>ѳe`6g[]EUDJ4Ym9^w]u<9昣({go1; é~>;g]~	`0ޜf6{zsѷog?>T)\<e1\pg[\s9ڠaRwA˼&%( ߸ٳ̏n?gE+v-&5(+mMr6-/?m
fnV[4Rfn{ݽIf(!7$fXj;$8Yph.:/YUn2dDW[u6h,NbM2eTuSkP,L]tM2I&k(x|,GԩYSjn67U -9ubM]q"x| ugXsV[CWrO">IkCNf`;nxdD?3/c'*<&`Pa轜1fƠoK,+^屼sZqbczɃh0d Aа{^k3EyڨAsdEl3GUe,z$Xao]{L{k-aT?_֊|ኇsxF'l̐$96$J9nHoa˶[/+¯GԩnFqL5~;pG~xAo>Oz~M7󩓎x>/;O}OS>o^|1=XPw)Gyߡo!$֦j^Qbva>5M7^#\c!7 ݦ~GpSUSxJƝsՑՇ bx0^<E1*Nh`b0vӡXm7W8d^wV_CowV&	Yi:n54A7F%r6ݿ=ďrwmfk3_bnW1o磏|{חm:s3'uWRc|[objV[swu{?|_yq:yy꘣񹧽eאzn۾}OɂOΛ7olE2cok#!|{|+g}kvsWxG}cM{'޴u|+G7Sa෾}}םu'{ORҨJ7'2)+UL\Ǆ:|}m???gՍV:1/ԳMp| z|lfwOIƻes9H2
\[(9ZuY/忿
uelәfnnSyګ?#z}sBSn펳__;+2Qo6[o}w˜{",|~3-?awL<y789<w|?]wc*f,mƓ&v;g^{G .^N쁟?_UW]KkPVރ;䕞\>V{~)n:z02>zʃkE5cƀi!,zމE)2F;>g
8oo77z
;H۠9Of^jc8%s7F,/Ͷ{-^}ҧNrʔW_s^{׿]vN=ڪ+i~/n<S#sR_]Cw͇uyj.sfnb
=y\z9ea6f\r=CQn<pukn}^
q mԩ۳7sW#Ǟ㏓Jҵv~K~NJm[??ޕf,g7΁۠,h|SOnZ.j44)Kǁ-G'<p]+b.,tdnX<ؑo:⶛>\k86κP	˛2T)f(*IsX`^'{¥.;u]Gqxt]{饗k^5}{p<<V]9Q<e/2p!W^}>8iD7[9h|/c׿G{?\B{s[lїo	wwi/;g4::/Y}Ŧɹk~B丯J+sw}O~
N;n9d_oz׌W=诔Rv\wt}8	t	rQAG˲Lahpv {h	8jeT!=a]-^st-7}_XRau#`x'Ȣc݌Wia7j=zoNfc/X{G}eerT3 |a7';ydݧN:2Xj%(]yx!GUE<:_G{έ7o}ǿovSŭ.(m^<o/?|]9'Oz'^\l"3Oǌԃ>|\Ĺ?mO9F]k:πVyGמCk?>$|2[Mn, ww%B kν)&xJa=lc&r	xf.Ҍϟ;=^(͜f}s?!3=sG႟jQϸV>ꈃwi-ȣ3'k||~Rk93̛7:g~[,B?z_f +ſ?/IItBs+C.n{԰I	1iAort`$̲~?`MO:6OQùݼ-+EݬY/]xxӟn?70yy&qs3}G#+O>fnM# e٪eͯM7xˎo7Pj\xm~[7 B͏)SN*O{}sK?om^Y0Lq?7W:鮻}ǁG"{w9/m?31	MQO\`P:uWk(a3`<ЋU'0aZ9a\/ZcU
_?=]&Ŕ0Mg^z-ގfv!冋; c)lFŦ6įM<byB=o1{tO6;!rynw~TvBSW3Q~{Ϙcw+4QKys{qG|ۍso#R̉M4|xSŮꝇ2S0PJ9K<FDLP@TΔ!i$Ʌ	`Vu<O\F̤bH@*A7$|iӖ1o~pv9C/dj0[ǹ9K?C{ޒ'?_}oܓT5cb'C1Z+p7O༯;_pI=SAKįe AFWy>wwl3NYcU|Wsϼ+~뮻_:N\yMһo[u?Y#\<LAQ:=qC"֧π#˻5V}3H  
oIDATjAH&"aaMz2@6ή(rɠc-uan_|r-t3Ko.3[y^v%_=?}qļy忿ŉ1Ji>*V>E%x]s{c~RtBc6Z2Qq?9?>$lr-݇C1%]c7ʏ<y2k5Cv/}嬣MWzW렣~?dոq6q	<'!>k6̤тݿ6lBhCIM#5{5S\;6Koj4/˯_I'f]Ӧ[z6ZcW;Ӟ{gvڗϜw>s.yſGQsz;2[M5\-;#_A7XiVZe'Y
؉ltwlL[qug<~_i[uݟoF`=>`Jם<j<+k{}n>̟3n;){!/Ug9)<g?{mwܗw~z9oߒh`eVhӭtQ>P.{-qa+4CÉYrB-xUǰөQ O(KHaP`;$X IZ~BPRWJo;C>sczLx!$%ڕ֎IۃTE4Mbȁ>/wJ.,+z+N?ܟ7*Q*21:@@d*a:T~..ťqO~:ΞRM~/~1eDaj`[ˮ
g.Z5Lq-2V{ET;m+A,L\$ZlB9b~\yZzХ8ܷ֎hJ@sHq4'=0Ә}SE'ƔaT(;$ef8 jizg4DSز/0q~L"z	$XMzFaݢy8+Ca|m?JFo!o?*)"/n`0ݤ)K#O'\Q9Ʌ<9OJԕ.u9 yWs"x3E! ƪAOxa_ՆnҌ4.<L!!
4)ub91Úa	X=("G̘#ҦD3cL=x7Gvsf2nI!XpNf4'.~jqAPĆ	dB\9v&8 5i	[THݻG{DEhqeE)y0!(#$	uX/ҐSPAkVwc]M_uZOYq8br
zbBBA	FQ7[
}bǲNľeШb$$l5%3:![5}ܩc!u0$p,b ]51|||.u&("^W>g4F5ɈV݋cI9
ZN8?P6!áUz%vXqĬJG-=бELt0/V8ɨ):%Cu!ƪ$5$ׅ 	2'!˫u8%!e?s8O\M#^ǭ6 q{
a_ғ{nfb;PQx}T<&O`D!O9`[$Z1y,)	%!TD:bf%gfHWݍ[k8f'yLd3N*Zg-{_C
qyS^xV+Jqs5숉C[k
7ZHe,OeJ;pRc,Dok(x[c713IfU..LlDUd(	w8'-~`R ).])D$Z+v㟛ZIn	IEHq36|ޓO,>-%&P7s({Ex9TWZ^}#3ֽwLABpM054
"S](`MX`tP&K	==sdD%D̰6AsCTAIUՈ!;Hc P.l"eJ Q6`8' wT\Iq>CdK^\5B8)$˭+NYm;:F͠Dzm*FF04\ZX+ҁRU)(R,@}A)AOL:9k1vْi?'jJDFaX>)Q'6N ڿ,^&yVhBHXL
i!)c/vv%kWbć~Bv2xj!.XseN7ƭo-mxL dX+@ il"84$BF(gizg4p-BdRQz c&$;bR-MqfU15)1^21;$A䦳0؀K433  7q   IDAT kF\15    IENDB`vvtxHPNG

   IHDR   &   '   \  IDATx[lVU:_((P2! &$d&q&j/!FEQFw|D}h	mSm)-*
mkN-^emusTWUWRXګ+U'TZjv|W,jWfDeHe;u:v}c{i꽽鿷48ZiD&$l&*jIi>A `mO%ٱOjβWN;v%f;CUu/PTzzguJ$@RGűH
3`kջ??0x[a3I-[Yź-6fd=ع7~]/ߵ3cxplI~@YD;yWůIֳi9gu_xIE_|z۹Bs$b#i62NxlJ_)zu]/=<£;rgǞyu|cMROGֱo$-]ees^]/=4bί^rV;.?XG#?yPD/ZZ?)*~\uqMy- эcO2k;;>77NӢ561]djaJwV~ r0.Z֭X>F=7ihřK*cu/{l"4H)#(E@`,^߻U=s?\u=nZyk|lLrKGNwJѧU)ܰO|Yٯ]]*P,ڿ!"jzs1Nj@@v6="r҇#myG=81x)&	a.b@6A5Vc5Kvʗk6t;J[TbP
F*< @]pU$ni3Zcxaɸ~3~%˻B<W[*ٖ̓<(Gĸ\n8DVp	.I	SKs EJ~3}36\0rFIEJK=a,.1iL3A'Kcb[!
\ty/,IXTlN<Ċ4C@.V󷽇AL=HUNJ_2;ނ#*$ cΞǜ 4ljplYYi,p8j h @,nLX	߭ݙ$d"-Fÿ8eַg$qNa)YRd-}dx,[/8NV#LHUQs)0"
((|;7 "P,k|xZ;x`^54IIUh&m#Ɓ>"aFq͙n˭~\pd&~=ٝ60rC2=n 3x>rXf/|H;*#QjVw,K#`DI2W"e-3G]Ӳa4ַ]n8Zec4:gfu4|r\g9p.,I!4!oKfADյPg'>;^2i{,>)2ѠS{ozJL  3   IDAT .Mm|    IENDB`~ix(\[
  {
    "image_name": "58a85f24f7cf_20260323024053.png",
    "image_path": "picture/58a85f24f7cf_20260323024053.png",
    "description": "设备名称：未知设备\n故障现象：未发现明显异常",
    "timestamp": "2026-03-23T02:40:53.157120"
  },
  {
    "image_name": "44b07d453030_20260323024633.png",
    "image_path": "picture/44b07d453030_20260323024633.png",
    "description": "设备名称：V型发动机（剖视图）\n故障现象：正常",
    "timestamp": "2026-03-23T02:46:33.821095"
  },
  {
    "image_name": "f38267265a8a_20260323032735.png",
    "image_path": "picture/f38267265a8a_20260323032735.png",
    "description": "设备名称：京东红途（Logo标识）\n故障现象：图片中未显示任何工业设备，仅包含“京东红途”的品牌Logo标识，无法进行设备故障诊断。",
    "timestamp": "2026-03-23T03:27:35.305548"
  },
  {
    "image_name": "f233ccc07264_20260323060328.png",
    "image_path": "picture/f233ccc07264_20260323060328.png",
    "description": "1. 设备识别：图中展示的是一个汽车发动机（内燃机）的3D渲染剖面图，具体型号或标签不可见。\n2. 状态评估：该图为静态结构展示，无仪表盘数值或指示灯，无法评估运行状态。\n3. 异常检测：图中无漏油、生锈、电缆破损、螺丝松动或烟雾等异常现象，部件表面光洁，结构完整。\n4. 环境风险：背景为纯色，无杂物堆放或安全隐患。",
    "timestamp": "2026-03-23T06:03:28.810875"
  },
  {
    "image_name": "bbeb197ac231_20260323060515.png",
    "image_path": "picture/bbeb197ac231_20260323060515.png",
    "description": "1. 设备识别：图中展示的是一个汽车发动机（内燃机）的3D渲染剖面图，具体型号或标签不可见。\n2. 状态评估：该图为静态结构展示，无仪表盘数值或指示灯，无法评估运行状态。\n3. 异常检测：图中无漏油、生锈、电缆破损、螺丝松动或烟雾等异常现象，部件表面光洁，结构完整。\n4. 环境风险：背景为纯色，无杂物堆放或安全隐患。",
    "timestamp": "2026-03-23T06:05:15.445638"
  },
  {
    "image_name": "334ee511347b_20260323061707.png",
    "image_path": "picture/334ee511347b_20260323061707.png",
    "description": "1. 设备识别：图中展示的是一个V型多缸内燃机（V-type Internal Combustion Engine）的3D剖面模型，非实物照片。由于是计算机生成的渲染图，无法识别具体型号，且无可见标签。\n2. 状态评估：该设备为静态模型，无仪表盘、数值或指示灯，无法进行状态评估。\n3. 异常检测：作为3D渲染图，设备表面呈现完美的金属质感，无漏油、生锈、电缆破损、螺丝松动或烟雾等物理缺陷。\n4. 环境风险：背景为纯色渐变，无杂物堆放或安全隐患。",
    "timestamp": "2026-03-23T06:17:07.234182"
  },
  {
    "image_name": "50da933dcb11_20260323062013.jpg",
    "image_path": "picture/50da933dcb11_20260323062013.jpg",
    "description": "1. **设备识别**：图中显示为一台笔记本电脑（品牌标识模糊，疑似HP），屏幕处于开启状态，键盘区域可见。左下角叠加有“马兆帅 警圣测试专用”字样及多组编号（如999997、440300999999等），表明该设备可能用于特定测试或监控用途。\n\n2. **状态评估**：右下角显示“Sto:20.7GB”（存储剩余）和“Pow:91%”（电量），数值均在正常区间；无仪表盘或指示灯可见，无法判断颜色状态。\n\n3. **异常检测**：未发现漏油、生锈、电缆破损、螺丝松动或烟雾等物理异常；画面存在手指遮挡与运动模糊，属拍摄干扰，非设备故障。\n\n4. **环境风险**：背景可见货架、包装盒等杂物，桌面略显杂乱，存在轻微安全隐患（如物品倾倒或绊倒风险），但无即时危险。\n\n结论：设备运行状态正常，环境需整理以消除潜在风险。",
    "timestamp": "2026-03-23T06:20:13.124244"
  },
  {
    "image_name": "e0bb42e29c58_20260323062055.jpg",
    "image_path": "picture/e0bb42e29c58_20260323062055.jpg",
    "description": "1. 设备识别：图中显示一台笔记本电脑（品牌标识模糊，疑似HP），屏幕处于开启状态，键盘区域可见。设备标签及序列号不可见。\n2. 状态评估：屏幕显示内容模糊，无法读取仪表盘数值；无明确指示灯颜色可辨。\n3. 异常检测：未发现漏油、生锈、电缆破损、螺丝松动或烟雾。\n4. 环境风险：画面左侧有手指遮挡镜头，背景杂乱，存在杂物堆放，可能影响操作安全。",
    "timestamp": "2026-03-23T06:20:55.600490"
  },
  {
    "image_name": "dcd6a33ef2b0_20260324071427.png",
    "image_path": "picture/dcd6a33ef2b0_20260324071427.png",
    "description": "1. 设备识别：图中为一辆汽车的发动机舱，引擎盖处于开启状态。由于拍摄角度和遮挡，具体的车辆型号及发动机标签不可见。\n2. 状态评估：仪表盘不可见，无法评估数值或指示灯状态。\n3. 异常检测：发动机舱内存在明显的白色烟雾（或蒸汽），主要集中在发动机左侧及中部区域，表明存在严重的过热或冷却液泄漏故障。\n4. 环境风险：背景中可见堆放的纸箱及杂物，地面有蓝色垫子，存在杂物堆放情况，可能影响维修作业安全。",
    "timestamp": "2026-03-24T07:14:27.522730"
  },
  {
    "image_name": "015ebb33d2a3_20260324072409.png",
    "image_path": "picture/015ebb33d2a3_20260324072409.png",
    "description": "1. 设备识别：图中设备为一辆汽车的发动机舱，引擎盖处于开启状态。由于拍摄角度和遮挡，具体的车辆型号及发动机标签不可见。\n2. 状态评估：仪表盘不可见，无法评估数值或指示灯状态。\n3. 异常检测：存在明显的白色烟雾（或蒸汽）从发动机舱内部升起，主要集中在发动机左侧及中部区域，表明存在过热或冷却液泄漏等故障。\n4. 环境风险：背景中可见堆放的纸箱及杂物，地面有蓝色垫子，属于维修车间环境，存在杂物堆放带来的潜在安全隐患。",
    "timestamp": "2026-03-24T07:24:09.812908"
  },
  {
    "image_name": "79493c5be2ac_20260324081251.png",
    "image_path": "picture/79493c5be2ac_20260324081251.png",
    "description": "1. 设备识别：图中为一辆白色汽车的发动机舱，引擎盖处于开启状态。具体车型或设备型号不可见。\n2. 状态评估：仪表盘不可见，无法评估数值或指示灯状态。\n3. 异常检测：发动机舱内存在明显的白色烟雾（或蒸汽），表明可能存在冷却液泄漏、过热或密封失效等故障。\n4. 环境风险：背景区域可见堆放的纸箱及杂物，存在一定程度的杂乱，可能影响维修作业安全。",
    "timestamp": "2026-03-24T08:12:51.902164"
  },
  {
    "image_name": "1ee23229170a_20260324082344.png",
    "image_path": "picture/1ee23229170a_20260324082344.png",
    "description": "1. 设备识别：图中设备为一辆汽车的发动机舱，引擎盖处于开启状态。由于拍摄角度和遮挡，具体的车辆型号或标签不可见。\n2. 状态评估：仪表盘不可见，无法评估数值或指示灯状态。\n3. 异常检测：存在明显的白色烟雾（或蒸汽）从发动机舱内部冒出，主要集中在左侧进气歧管区域，表明发动机存在过热或冷却系统泄漏等严重故障。\n4. 环境风险：背景中可见堆放的纸箱和杂物，且车辆处于非正常行驶状态，存在一定安全隐患。",
    "timestamp": "2026-03-24T08:23:44.780598"
  },
  {
    "image_name": "95f8928fb88c_20260324083528.png",
    "image_path": "picture/95f8928fb88c_20260324083528.png",
    "description": "1. 设备识别：图中为一辆汽车的发动机舱，引擎盖处于开启状态。由于拍摄角度和遮挡，无法识别具体的车辆型号或发动机标签。\n2. 状态评估：仪表盘不可见，无法评估数值或指示灯状态。\n3. 异常检测：发动机舱内存在明显的白色烟雾（或蒸汽），主要集中在发动机左侧区域，表明可能存在冷却液泄漏、高温或机械故障。\n4. 环境风险：背景中可见堆放的纸箱和杂物，地面有蓝色垫子，存在杂物堆放情况，可能影响维修作业安全。",
    "timestamp": "2026-03-24T08:35:28.036819"
  },
  {
    "image_name": "08f8efd6f1d4_20260324110619.png",
    "image_path": "picture/08f8efd6f1d4_20260324110619.png",
    "description": "1. 设备识别：图中是一辆汽车的发动机舱，引擎盖处于开启状态。由于拍摄角度和遮挡，具体的车辆型号或标签不可见。\n2. 状态评估：仪表盘不可见，无法评估数值或指示灯状态。\n3. 异常检测：发动机舱内存在明显的白色烟雾（或蒸汽），主要集中在发动机左侧区域，表明可能存在冷却液泄漏、过热或管路破裂等严重故障。\n4. 环境风险：背景中可见堆放的纸箱和杂物，地面有蓝色垫子，存在杂物堆放情况，可能影响维修操作或造成绊倒隐患。",
    "timestamp": "2026-03-24T11:06:19.237516"
  },
  {
    "image_name": "d345fbf33f95_20260325031818.png",
    "image_path": "picture/d345fbf33f95_20260325031818.png",
    "description": "1. 设备识别：图中为一辆白色轿车的发动机舱，引擎盖处于开启状态。由于拍摄角度和遮挡，具体的车辆型号及发动机标签不可见。\n2. 状态评估：仪表盘不可见，无法评估数值或指示灯状态。\n3. 异常检测：发动机舱内存在明显的白色烟雾（或蒸汽），主要集中在发动机左侧及中部区域，表明存在高温泄漏或冷却系统故障。\n4. 环境风险：背景中可见堆放的纸箱及杂物，地面有蓝色垫子，存在杂物堆放情况，可能影响维修作业安全。",
    "timestamp": "2026-03-25T03:18:18.243134"
  },
  {
    "image_name": "22f06245ed56_20260601022623.png",
    "image_path": "picture/22f06245ed56_20260601022623.png",
    "description": "Error: Error code: 400 - {'error': {'message': 'Qwen3-14B is not a multimodal model', 'type': 'BadRequestError', 'param': None, 'code': 400}}",
    "timestamp": "2026-06-01T02:26:23.900253"
  }
]6x	from openai import OpenAI
query_type_prompt = """
你是一个专业的装备维修领域用户查询判断助手，能够根据以下规则准确判断用户问题属于哪种类型。

### 判断规则
- **简单问答类型（simple）**：问题属于日常生活常识、通用知识、非技术性提问，**不涉及**装备、设备、机械、电子、维修、故障诊断、零部件、操作流程等专业领域内容。例如问候、自我介绍、天气、时间等。
- **复杂问答类型（complex）**：问题**涉及**装备、设备、机械系统（如发动机、液压系统）、电子装置、维修流程、故障排查、零部件组成、技术参数、操作规范等专业领域，即使只是询问定义、组成或功能，也视为 complex。

### 输出要求
- 仅输出 JSON 格式：{"query_type":"simple"} 或 {"query_type":"complex"}
- 不得包含任何其他文字、解释或格式。

### 示例
输入：今天心情怎么样  
输出：{"query_type":"simple"}

输入：请问你是谁  
输出：{"query_type":"simple"}

输入：发动机是什么  
输出：{"query_type":"complex"}

输入：缸盖组包含哪些组件  
输出：{"query_type":"complex"}

输入：手机屏幕碎了怎么办  
输出：{"query_type":"complex"}

输入：水的沸点是多少  
输出：{"query_type":"simple"}

输入：如何更换坦克履带  
输出：{"query_type":"complex"}

### 用户查询：
text
"""
def open_api_chat(query: str, model: str = None):
        """
        同步调用Chat API
        
        Args:
            query: 查询文本
            model: 模型名称（可选，默认使用环境变量OPENAI_MODEL）
        """
        if model is None:
            model = "Qwen3.5-35B-A3B"
        response = OpenAI(
            api_key = "none",
            base_url = "http://192.168.0.46:59800/v1"
        ).chat.completions.create(
            model=model,
            messages=[
                {"role": "user", "content": query},
            ],
            temperature=0.6,
            stream=False,
            response_format = {"type": "json_object"},

        )
        return response.choices[0].message.content
# querycontent = "发动机异响"
# query = query_type_prompt.replace("text",querycontent)

# res = open_api_chat(query=query)
# print(res)
]tx"""
提示词集中管理模块
将各工作流中的提示词统一提取到此处，方便调整和维护。
每个提示词都附有详细注释说明其用途和所属工作流节点。

模块结构：
- COMMON_PROMPTS: 多个工作流共享的提示词（格式规范、友好回复、无检索建议等）
- BAIKE_PROMPTS: 百科问答工作流专用提示词
- STATISTICS_PROMPTS: 统计工作流专用提示词
- FAULT_DIAGNOSIS_PROMPTS: 故障诊断工作流专用提示词（仅含与操作指导不同的部分）
- OPERATE_PROMPTS: 操作指导工作流专用提示词（仅含与故障诊断不同的部分）
"""


# ============================================================
# 一、共享提示词（多个工作流通用）
# ============================================================

COMMON_PROMPTS = {
    # ------------------------------------------------------------------
    # 格式规范系统提示词
    # 用于: workflow_baike.py (generate_answer)、workflow_utils.py (stream_format_and_postprocess)
    # ------------------------------------------------------------------
    "format_system": (
        "你是一个专业的格式规范助手，负责将给定的文本内容规范成美观、易读的格式。"
    ),

    # ------------------------------------------------------------------
    # 格式规范用户提示词（带图片示例，用于百科问答和通用格式化）
    # 输入变量: raw_content
    # 用于: workflow_baike.py (generate_answer)、workflow_utils.py (stream_format_and_postprocess 无content_label时)
    # ------------------------------------------------------------------
    "format_user_with_image_examples": (
        "请将以下内容规范成美观、易读的Markdown格式：\n"
        "\n"
        "【原始内容】\n"
        "{raw_content}\n"
        "\n"
        "【格式规范要求】\n"
        "1. 保持原始内容的完整性和准确性，**不要修改任何内容**，只调整格式\n"
        "2. 适当使用标题、段落分隔等Markdown格式，使内容更易读\n"
        "3. 确保图片链接在相关位置自然展示使用，并且只输出准确格式，`![图片](/api/v1/knowledge/files/images/xxx.jpg)` \n"
        "4. 如果参考资料中没有图片，**不要输出任何关于图片的说明**\n"
        "5. 确保LaTeX公式格式正确：$$...$$，并在 $$...$$ 前后加空格\n"
        "6. 如果有代码片段，使用适当的代码块格式\n"
        "7. 不要添加任何额外的解释或说明\n"
        "\n"
        "【图片输出示例】\n"
        "示例一:  原始内容：`![图片](images/xxx.jpg)`\n"
        "        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`\n"
        "示例二:  原始内容：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`\n"
        "        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`\n"
        "示例三:  原始内容：`images/xxx.jpg`\n"
        "        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`\n"
        "示例四:  原始内容：`xxx.jpg`\n"
        "        规范后输出：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`\n"
        "示例五:  原始内容：`![油污清理](/api/v1/knowledge/files/images/ce9650912c24fa0ed693228469322ec2a735f14d9ac729a1dc87427441bad0b.jpg)`\n"
        "        规范后输出：`![图片](/api/v1/knowledge/files/images/ce9650912c24fa0ed693228469322ec2a735f14d9ac729a1dc87427441bad0b.jpg)`\n"
        "示例六： 原始内容：`![部分断裂的螺栓及垫片](![图片](/api/v1/knowledge/files/images/e34eb1ddbe26730c84409e02365db416e74ce9e3bf2793a2605db5a085548415.jpg)`\n"
        "        规范后输出：`![图片](/api/v1/knowledge/files/images/e34eb1ddbe26730c84409e02365db416e74ce9e3bf2793a2605db5a085548415.jpg)`\n"
        "\n"
        "请直接输出规范后的内容："
    ),

    # ------------------------------------------------------------------
    # 格式规范用户提示词（简化版，用于方案重新格式化，图片链接保持原样）
    # 输入变量: content_label, raw_content
    # 用于: workflow_utils.py (stream_format_and_postprocess 有content_label时)
    # ------------------------------------------------------------------
    "format_user_simple": (
        "请将以下{content_label}内容规范成美观、易读的Markdown格式：\n"
        "\n"
        "【原始内容】\n"
        "{raw_content}\n"
        "\n"
        "【格式规范要求】\n"
        "1. 保持原始内容的完整性和准确性，**不要修改任何内容**，只调整格式\n"
        "2. 适当使用标题、列表、段落分隔等Markdown格式，使内容更易读\n"
        "3. 确保图片链接保持原样：`![图片](URL)`\n"
        "4. 确保LaTeX公式格式正确：$$...$$，并在 $$...$$ 前后加空格\n"
        "5. 如果有代码片段，使用适当的代码块格式\n"
        "6. 不要添加任何额外的解释或说明\n"
        "\n"
        "请直接输出规范后的内容："
    ),

    # ------------------------------------------------------------------
    # 意图分类用户提示词（故障诊断和操作指导共用）
    # 输入变量: combined_query
    # 用于: workflow_fault_diagnosis.py、workflow_operate.py 的 classify_intent 节点
    # ------------------------------------------------------------------
    "classify_intent_user": (
        "\n"
        "### 用户输入\n"
        "\"{combined_query}\"\n"
        "\n"
        "请根据上述标准进行意图分类："
    ),

    # ------------------------------------------------------------------
    # 信息提取用户提示词（故障诊断和操作指导共用）
    # 输入变量: existing_info_str, history_str, combined_query
    # 用于: workflow_fault_diagnosis.py、workflow_operate.py 的 extract_info 节点
    # ------------------------------------------------------------------
    "extract_info_user": (
        "请从以下内容中提取{biz_label}相关信息：\n"
        "\n"
        "【已提取的信息】\n"
        "{existing_info_str}\n"
        "\n"
        "【历史对话】\n"
        "{history_str}\n"
        "\n"
        "【当前用户输入】\n"
        "{combined_query}\n"
        "\n"
        "请提取信息（JSON格式）："
    ),

    # ------------------------------------------------------------------
    # 询问用户系统提示词（故障诊断和操作指导共用）
    # 用于: workflow_fault_diagnosis.py、workflow_operate.py 的 ask_user 节点
    # ------------------------------------------------------------------
    "ask_user_system": (
        "你是一个专业的{biz_label}助手，需要友好地引导用户提供缺失信息。\n"
        "\n"
        "要求：\n"
        "1. 语气友好、专业，不要生硬\n"
        "2. 说明为什么需要这些信息（更准确的{biz_label_short}）\n"
        "3. 鼓励用户提供更多细节"
    ),

    # ------------------------------------------------------------------
    # 询问用户提示词（故障诊断和操作指导共用）
    # 输入变量: info_completeness, existing_str, missing_str, combined_query
    # ------------------------------------------------------------------
    "ask_user_prompt": (
        "请生成一段友好的回复，引导用户补充缺失信息。\n"
        "\n"
        "【已获取的信息】（完整性评分: {info_completeness}）\n"
        "{existing_str}\n"
        "\n"
        "【缺失的信息】\n"
        "{missing_str}\n"
        "\n"
        "【用户当前输入】\n"
        "{combined_query}\n"
        "\n"
        "请生成回复："
    ),

    # ------------------------------------------------------------------
    # 无检索结果且无设备信息时的系统提示词（故障诊断和操作指导共用）
    # ------------------------------------------------------------------
    "generate_response_friendly_system": (
        "你是一个友好的{biz_label}助手。用户可能只是在打招呼或询问一般性问题。\n"
        "请友好地回复，并简要介绍你能提供的帮助。"
    ),

    # ------------------------------------------------------------------
    # 无检索结果且无设备信息时的用户提示词（故障诊断和操作指导共用）
    # 输入变量: combined_query
    # ------------------------------------------------------------------
    "generate_response_friendly_user": (
        "用户说：{combined_query}\n"
        "\n"
        "请友好回复："
    ),

    # ------------------------------------------------------------------
    # 无检索结果但有设备信息时的系统提示词（故障诊断和操作指导共用）
    # ------------------------------------------------------------------
    "generate_response_no_rag_system": (
        "你是一个专业的{biz_label}助手。\n"
        "虽然没有检索到相关资料，但可以根据用户提供的信息给出一般性建议。\n"
        "注意：明确告知用户这是基于一般经验的建议。"
    ),

    # ------------------------------------------------------------------
    # 无检索结果（简化版）系统提示词（故障诊断和操作指导共用）
    # ------------------------------------------------------------------
    "generate_response_no_rag_simple_system": (
        "你是一个专业的{biz_label}助手。\n"
        "虽然没有检索到相关资料，但可以根据用户提供的信息给出一般性建议。"
    ),

    # ------------------------------------------------------------------
    # 后续交互提示词（故障诊断和操作指导共用）
    # 输入变量: biz_label, ship_number, device_name, item_name, detail_info,
    #           rag_answer, combined_query, image_guidance
    # 用于: workflow_fault_diagnosis.py、workflow_operate.py 的 generate_response 节点
    # ------------------------------------------------------------------
    "generate_response_follow_up": (
        "你是一名资深工业设备{biz_label}工程师。用户正在与你进行后续交互。\n"
        "\n"
        "【设备信息】\n"
        "- 舷号：{ship_number}\n"
        "- 设备名称：{device_name}\n"
        "- {item_label}：{item_name}\n"
        "{detail_info}"
        "【参考资料】\n"
        "{rag_answer}\n"
        "\n"
        "【用户当前问题】\n"
        "{combined_query}\n"
        "\n"
        "【输出要求】\n"
        "1. {image_guidance}\n"
        "2. 如果参考资料包含表格，请转化成不用表格的形式输出内容\n"
        "3. 如果参考资料包含 LaTeX 公式，请转为 $$...$$ 公式格式输出，并在 $$...$$ 前后加空格\n"
        "4. 所有链接必须与参考资料保持一致，不得裁剪、转义或改写\n"
        "5. 不能虚构参考资料中未提及的图片、表格、零件号或步骤\n"
        "\n"
        "请给出回复："
    ),

    # ------------------------------------------------------------------
    # 正常生成方案提示词（故障诊断和操作指导共用）
    # 输入变量: biz_label, ship_number, device_name, item_name, item_label,
    #           detail_info, item_action, rag_answer
    # ------------------------------------------------------------------
    "generate_response_normal": (
        "你是一名资深工业设备{biz_label}工程师，请根据以下信息生成{biz_label}分析与{biz_label}方案。\n"
        "\n"
        "【设备信息】\n"
        "- 舷号：{ship_number}\n"
        "- 设备名称：{device_name}\n"
        "- {item_label}：{item_name}\n"
        "{detail_info}"
        "当前的{item_label}要以{item_name}为准，{item_action}。\n"
        "\n"
        "【参考资料】\n"
        "{rag_answer}\n"
        "\n"
        "【输出要求】\n"
        "1. **重要**：如果参考资料中包含图片链接（格式为 `![图片](URL)` 或 `images/xxx.jpg`），请务必在相关位置自然展示使用，如果参考资料中没有图片，**不要输出任何关于图片的说明**\n"
        "2. 如果参考资料包含 LaTeX 公式、连接等，请在对应位置正常使用，不得修改或删除\n"
        "3. 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性\n"
        "4. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式\n"
        "5. 如果参考资料包含表格，请不要输出表格，而要直接描述表格的内容\n"
        "\n"
        "请给出回复："
    ),

    # ------------------------------------------------------------------
    # 基于反馈重新生成方案提示词（故障诊断和操作指导共用）
    # 输入变量: biz_label, ship_number, device_name, item_name, item_label,
    #           detail_info, item_action, user_feedback_for_regenerate,
    #           rag_answer, image_guidance
    # ------------------------------------------------------------------
    "generate_response_regenerating": (
        "你是一名资深工业设备{biz_label}工程师。用户对之前的方案有反馈，请根据反馈重新生成{biz_label}分析与{biz_label}方案。\n"
        "\n"
        "【设备信息】\n"
        "- 舷号：{ship_number}\n"
        "- 设备名称：{device_name}\n"
        "- {item_label}：{item_name}\n"
        "{detail_info}"
        "【用户反馈】\n"
        "{user_feedback_for_regenerate}\n"
        "\n"
        "【参考资料】\n"
        "{rag_answer}\n"
        "\n"
        "【输出要求】\n"
        "1. 先用一句话判断{item_label}原因（包含舷号、设备、{item_label}，不超过40字）\n"
        "2. 然后给出{biz_label}方案，步骤清晰、可直接执行\n"
        "3. 根据用户的反馈调整方案\n"
        "4. 如果参考资料信息不足，明确指出缺少什么\n"
        "5. {image_guidance}，如果参考资料中没有图片，**不要输出任何关于图片的说明**\n"
        "6. 如果参考资料包含表格，请转化成不用表格的形式输出内容\n"
        "7. 如果参考资料包含 LaTeX 公式，请转为 $$...$$ 公式格式输出，并在 $$...$$ 前后加空格\n"
        "8. 所有链接必须与参考资料保持一致，不得裁剪、转义或改写\n"
        "9. 不能虚构参考资料中未提及的图片、表格、零件号或步骤\n"
        "\n"
        "请直接输出调整后的方案："
    ),

    # ------------------------------------------------------------------
    # 生成内容系统提示词（故障诊断和操作指导共用）
    # ------------------------------------------------------------------
    "generate_response_content_system": (
        "你是一名资深工业设备{biz_label}工程师，严格依据检索信息生成{biz_label}方案。请专注于内容的准确性、完整性和逻辑性，如果参考资料中包含图片，请务必在回答中展示出来。"
    ),

    # ------------------------------------------------------------------
    # 深度分析点选择系统提示词（故障诊断和操作指导共用）
    # ------------------------------------------------------------------
    "deep_rag_analysis_system": (
        "你是一名资深工业设备{biz_label}专家。用户反馈之前的方案没有解决问题，请分析：\n"
        "1. 之前方案可能存在的不足\n"
        "2. 用户当前问题的关键点\n"
        "3. 选择3-5个可以深入检索的分析点（如特定部件、原理、{biz_label}方法等）\n"
        "\n"
        "输出格式（JSON）：\n"
        "{\n"
        "    \"analysis_points\": [\"分析点1\", \"分析点2\", \"分析点3\"],\n"
        "    \"reason\": \"分析理由\"\n"
        "}"
    ),

    # ------------------------------------------------------------------
    # 深度分析点选择用户提示词（故障诊断和操作指导共用）
    # 输入变量: ship_number, device_name, item_name, item_label, detail_info,
    #           history_str, last_generated_scheme, combined_query
    # ------------------------------------------------------------------
    "deep_rag_analysis_user": (
        "【设备信息】\n"
        "- 舷号：{ship_number}\n"
        "- 设备名称：{device_name}\n"
        "- {item_label}：{item_name}\n"
        "{detail_info}"
        "\n"
        "【对话历史】\n"
        "{history_str}\n"
        "\n"
        "【之前的方案】\n"
        "{last_generated_scheme}\n"
        "\n"
        "【用户当前反馈】\n"
        "{combined_query}\n"
        "\n"
        "请分析并选择深度分析点（JSON格式）："
    ),

    # ------------------------------------------------------------------
    # 深度响应生成提示词（故障诊断和操作指导共用）
    # 输入变量: biz_label, ship_number, device_name, item_name, item_label,
    #           detail_info, combined_query, analysis_points_prompt,
    #           analysis_points_text, original_rag_text, graph_results
    # ------------------------------------------------------------------
    "generate_deep_response": (
        "你是一名资深工业设备{biz_label}专家。用户反馈之前的方案没有解决问题，请根据多维度深度检索的资料，进行深入的{item_label}原因分析和解决方案规划。\n"
        "\n"
        "【设备信息】\n"
        "- 舷号：{ship_number}\n"
        "- 设备名称：{device_name}\n"
        "- {item_label}：{item_name}\n"
        "{detail_info}"
        "【用户反馈】\n"
        "{combined_query}\n"
        "{analysis_points_prompt}"
        "【针对分析点的深度检索资料】\n"
        "{analysis_points_text}\n"
        "{original_rag_text}\n"
        "\n"
        "【图谱检索结果】\n"
        "{graph_results}\n"
        "\n"
        "【输出要求】\n"
        "1. 首先重新深入分析{item_label}原因，结合所有检索资料进行推理\n"
        "2. 给出更详细、更精准的{biz_label}方案，步骤清晰、可直接执行\n"
        "3. 重点关注用户反馈的问题，根据用户反馈和检索资料，进行{item_label}原因分析和解决方案规划。\n"
        "4. **重要**：如果参考资料中包含图片链接（格式为 `![图片](URL)` 或 `images/xxx.jpg`），请务必在相关位置自然展示使用，如果参考资料中没有图片，**不要输出任何关于图片的说明**\n"
        "5. 如果参考资料包含 LaTeX 公式、连接等，请在对应位置正常使用，不得修改或删除\n"
        "6. 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性\n"
        "7. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式\n"
        "8. 如果参考资料包含表格，请不要输出表格，而要直接描述表格的内容\n"
        "\n"
        "请直接输出深度分析和方案："
    ),

    # ------------------------------------------------------------------
    # 深度响应内容系统提示词（故障诊断和操作指导共用）
    # ------------------------------------------------------------------
    "generate_deep_response_content_system": (
        "你是一名资深工业设备{biz_label}专家，严格依据检索信息进行深度分析和方案生成。请专注于内容的准确性、完整性和逻辑性，如果参考资料中包含图片，请务必在回答中展示出来。"
    ),

    # ------------------------------------------------------------------
    # 基于反馈修改方案提示词（故障诊断和操作指导共用）
    # 输入变量: biz_label, ship_number, device_name, item_name, item_label,
    #           detail_info, item_action, last_scheme, user_feedback, image_guidance
    # ------------------------------------------------------------------
    "regenerate_scheme_from_feedback": (
        "你是一名资深工业设备{biz_label}专家。用户对之前的{biz_label}方案有反馈，请根据反馈直接修改方案。\n"
        "\n"
        "【设备信息】\n"
        "- 舷号：{ship_number}\n"
        "- 设备名称：{device_name}\n"
        "- {item_label}：{item_name}\n"
        "{detail_info}"
        "当前的{item_label}要以{item_name}为准，{item_action}。\n"
        "\n"
        "【之前的方案】\n"
        "{last_scheme}\n"
        "\n"
        "【用户反馈】\n"
        "{user_feedback}\n"
        "\n"
        "【输出要求】\n"
        "1. 首先根据用户反馈，分析之前方案的问题所在\n"
        "2. 然后基于之前的方案进行修改和优化，给出调整后的方案\n"
        "3. 重点解决用户反馈的问题\n"
        "4. {image_guidance}\n"
        "5. 如果之前方案包含表格，请转化成不用表格的形式输出内容\n"
        "6. 如果之前方案包含 LaTeX 公式，请转为 $$...$$ 公式格式输出，并在 $$...$$ 前后加空格\n"
        "7. 所有链接必须与原方案保持一致，不得裁剪、转义或改写\n"
        "8. 不能虚构原方案中未提及的图片、表格、零件号或步骤\n"
        "\n"
        "请直接输出修改后的完整方案："
    ),

    # ------------------------------------------------------------------
    # 基于反馈修改方案系统提示词（故障诊断和操作指导共用）
    # ------------------------------------------------------------------
    "regenerate_scheme_from_feedback_system": (
        "你是一名资深工业设备{biz_label}专家，根据用户反馈直接修改和优化{biz_label}方案。请专注于内容的准确性、完整性和逻辑性。"
    ),
}


# ============================================================
# 二、百科问答工作流 (workflow_baike.py) 专用提示词
# ============================================================

BAIKE_PROMPTS = {
    # ------------------------------------------------------------------
    # judge_need_retrieval 节点：判断用户问题是否需要检索知识库
    # 输入变量: history_messages, original_query
    # ------------------------------------------------------------------
    "judge_need_retrieval": (
        "你是一个专业的问题分析助手，请判断用户的问题是否需要检索知识库才能回答。\n"
        "\n"
        "【判断标准】\n"
        "需要检索的情况：\n"
        "- 询问特定设备、技术、规程、规范的具体内容\n"
        "- 需要专业知识或特定数据支持的问题\n"
        "- 询问故障诊断、维修方法等专业领域问题\n"
        "- 询问历史事件、法规条款、技术标准等需要查证的内容\n"
        "\n"
        "不需要检索的情况：\n"
        "- 简单的问候、寒暄\n"
        "- 常识性问题（如常识性知识、简单计算等）\n"
        "- 明确不需要专业知识的问题\n"
        "- 对之前对话的简单追问，上下文已足够回答\n"
        "\n"
        "【对话历史】\n"
        "{history_messages}\n"
        "\n"
        "【当前用户问题】\n"
        "{original_query}\n"
        "\n"
        "请仅输出 \"true\" 或 \"false\"（不带引号），true 表示需要检索，false 表示不需要检索。"
    ),

    # ------------------------------------------------------------------
    # rewrite_query_with_history 节点：使用历史上下文重写检索query
    # 输入变量: last_user_query, history_str, original_query
    # ------------------------------------------------------------------
    "rewrite_query_with_history": (
        "你是一个专业的检索query重写助手，负责根据对话历史和当前用户问题，生成**适合向量检索/RAG 的单条查询语句**。\n"
        "\n"
        "请严格遵守以下要求：\n"
        "1. 只融合与当前问题语义强相关的**最近几轮对话信息**，不要机械拼接全部历史。\n"
        "2. 消除指代和省略（例如：这个、刚才那个问题、上面说的故障等），补全成自洽、完整的描述。\n"
        "3. 不要加入与用户问题无关的背景信息，不要过度扩展检索范围。\n"
        "4. 输出必须是一句自然的中文问句或陈述句，便于检索；不要包含条目符号、编号或解释性文字。\n"
        "5. 只输出改写后的query本身：\n"
        "   - 不要输出说明文字\n"
        "   - 不要包含「改写结果：」「检索query：」等前缀\n"
        "   - 不要添加引号\n"
        "\n"
        "【特别提示】\n"
        "- 请优先参考**上一轮用户的问题**来重写本轮query。\n"
        "- 上一轮用户的问题是：{last_user_query}\n"
        "\n"
        "【对话历史（JSON 格式，已按时间排序）】\n"
        "{history_str}\n"
        "\n"
        "【当前用户问题】\n"
        "{original_query}\n"
        "\n"
        "请给出最终用于检索的单条中文query。"
    ),

    # ------------------------------------------------------------------
    # generate_suggested_replies_baike 函数：生成百科问答的建议回复问题
    # 输入变量: question, answer
    # ------------------------------------------------------------------
    "generate_suggested_replies": (
        "你是一个专业的工业设备问答助手。根据以下问答内容，生成两个用户可能关心的后续问题。\n"
        "\n"
        "【用户问题】\n"
        "{question}\n"
        "\n"
        "【回答内容】\n"
        "{answer}\n"
        "\n"
        "请生成两个简洁、实用的问题，这些问题应该：\n"
        "1. 不得出现需要归档和下载等操作相关的问题\n"
        "2. 与当前问答内容相关，能够帮助用户进一步了解相关信息\n"
        "3. 问题要具体、可操作\n"
        "4. 每个问题不超过20个字\n"
        "\n"
        "请以JSON格式输出，格式如下：\n"
        "[\n"
        "    {{\"title\": \"问题1的标题\", \"content\": \"问题1的完整内容\"}},\n"
        "    {{\"title\": \"问题2的标题\", \"content\": \"问题2的完整内容\"}}\n"
        "]\n"
        "\n"
        "只输出JSON，不要有其他文字说明。"
    ),

    # ------------------------------------------------------------------
    # generate_answer 节点 - 有检索结果时的系统提示词
    # 输入变量: domain_desc
    # ------------------------------------------------------------------
    "generate_answer_with_retrieval_system": (
        "我是一个专业的{domain_desc}知识问答助手，根据用户的问题，综合所有检索结果，提供准确、专业、完整的回答内容。"
    ),

    # ------------------------------------------------------------------
    # generate_answer 节点 - 有检索结果时的用户提示词
    # 输入变量: extracted_text, rag_count, all_source_text
    # ------------------------------------------------------------------
    "generate_answer_with_retrieval_user": (
        "{extracted_text}\n"
        "\n"
        "# 检索到的相关信息（共 {rag_count} 条）：\n"
        "\n"
        "{all_source_text}\n"
        "\n"
        "【输出要求】\n"
        "1. **重要**：如果参考资料中包含图片链接（格式为 `![图片](URL)` 或 `images/xxx.jpg`），请务必在相关位置自然展示使用，如果参考资料中没有图片，**不要输出任何关于图片的说明**\n"
        "2. 如果参考资料包含 LaTeX 公式、连接等，请在对应位置正常使用，不得修改或删除\n"
        "3. 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性\n"
        "4. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式\n"
        "5. 如果参考资料包含表格，请不要输出表格，而要直接描述表格的内容\n"
        "\n"
        "请给出回复："
    ),

    # ------------------------------------------------------------------
    # generate_answer 节点 - 无检索结果时的系统提示词
    # 输入变量: domain_desc
    # ------------------------------------------------------------------
    "generate_answer_without_retrieval_system": (
        "我是一个专业的{domain_desc}知识问答助手，根据用户的问题，结合我的专业知识，提供准确、专业、完整的回答内容。"
    ),

    # ------------------------------------------------------------------
    # generate_answer 节点 - 无检索结果时的用户提示词
    # 输入变量: extracted_text
    # ------------------------------------------------------------------
    "generate_answer_without_retrieval_user": (
        "{extracted_text}\n"
        "\n"
        "【输出要求】\n"
        "1. 请根据您的专业知识提供准确、完整的回答\n"
        "2. 可以适当使用简单的段落分隔，但不要使用复杂的Markdown格式\n"
        "3. 请专注于内容的准确性和专业性\n"
        "\n"
        "请给出回复："
    ),
}


# ============================================================
# 三、统计工作流 (workflow_statistics.py) 专用提示词
# ============================================================

STATISTICS_PROMPTS = {
    # ------------------------------------------------------------------
    # _extract_info_with_llm 函数 - 故障频次统计信息提取
    # 输入变量: text
    # ------------------------------------------------------------------
    "extract_fault_frequency_info": (
        "从以下文本中提取统计所需的信息，返回JSON格式。\n"
        "提取内容：\n"
        "- system: 系统名称（如：动力系统、电气系统等），如果没有则为空字符串\n"
        "- time: 时间描述（如：近一个月、上周等），如果没有则为空字符串\n"
        "\n"
        "文本：\n"
        "{text}\n"
        "\n"
        "输出格式示例：\n"
        "{{\"system\": \"动力系统\", \"time\": \"近一个月\"}}\n"
        "{{\"system\": \"\", \"time\": \"上周\"}}\n"
        "{{\"system\": \"电气系统\", \"time\": \"\"}}\n"
        "\n"
        "现在请提取："
    ),

    # ------------------------------------------------------------------
    # _extract_info_with_llm 函数 - 备件消耗统计信息提取
    # 输入变量: text
    # ------------------------------------------------------------------
    "extract_spare_parts_info": (
        "从以下文本中提取统计所需的信息，返回JSON格式。\n"
        "提取内容：\n"
        "- ship_number: 舷号数字（如：101、163等），如果没有则为空字符串\n"
        "- time: 时间描述（如：近一个月、上周等），如果没有则为空字符串\n"
        "\n"
        "文本：\n"
        "{text}\n"
        "\n"
        "输出格式示例：\n"
        "{{\"ship_number\": \"101\", \"time\": \"近一个月\"}}\n"
        "{{\"ship_number\": \"\", \"time\": \"上周\"}}\n"
        "{{\"ship_number\": \"163\", \"time\": \"\"}}\n"
        "\n"
        "现在请提取："
    ),

    # ------------------------------------------------------------------
    # _extract_info_with_llm 函数 - 维修反馈统计信息提取
    # 输入变量: text
    # ------------------------------------------------------------------
    "extract_repair_feedback_info": (
        "从以下文本中提取统计所需的信息，返回JSON格式。\n"
        "提取内容：\n"
        "- source: 反馈来源（如：好评、差评、反馈），如果没有则为空字符串\n"
        "\n"
        "文本：\n"
        "{text}\n"
        "\n"
        "输出格式示例：\n"
        "{{\"source\": \"差评\"}}\n"
        "{{\"source\": \"好评\"}}\n"
        "{{\"source\": \"\"}}\n"
        "\n"
        "现在请提取："
    ),

    # ------------------------------------------------------------------
    # extract_tool_parameters 节点：统计工具参数提取
    # 输入变量: current_date, tool_name, tool_description, params_desc_str,
    #           history_str, extracted_text, extra_instructions
    # ------------------------------------------------------------------
    "extract_tool_parameters": (
        "你是一个参数提取助手。请从用户问题中提取统计工具所需的参数。\n"
        "\n"
        "当前日期：{current_date}\n"
        "\n"
        "工具名称：{tool_name}\n"
        "工具描述：{tool_description}\n"
        "\n"
        "所需参数：\n"
        "{params_desc_str}\n"
        "\n"
        "对话历史：\n"
        "{history_str}\n"
        "\n"
        "用户问题：\n"
        "{extracted_text}\n"
        "\n"
        "请特别注意：\n"
        "1. 时间参数映射：\n"
        "   - \"最近一周\" -> 开始日期为当前日期前7天，结束日期为当前日期\n"
        "   - \"最近一个月\" -> 开始日期为当前日期前30天，结束日期为当前日期\n"
        "   - \"最近三个月\" -> 开始日期为当前日期前90天，结束日期为当前日期\n"
        "   - \"上个月\" -> 开始日期为上个月1号，结束日期为上个月最后一天\n"
        "   - \"今年\" -> 开始日期为今年1月1日，结束日期为当前日期\n"
        "   - 如果用户提到具体日期，请按原样提取\n"
        "{extra_instructions}\n"
        "3. top_n参数：\n"
        "   - 如果用户提到\"前N个\"、\"Top N\"等，提取N的值\n"
        "   - 否则使用默认值\n"
        "\n"
        "请输出JSON格式：\n"
        "{{\n"
        "    \"parameters\": {{\n"
        "        \"参数名\": \"参数值\"\n"
        "    }},\n"
        "    \"missing_required\": [\"缺少的必填参数列表\"],\n"
        "    \"confidence\": 0.0-1.0之间的置信度\n"
        "}}\n"
        "\n"
        "如果某个参数在用户问题中没有提到且不是必填，则不要包含在parameters中。\n"
        "只输出JSON，不要有其他文字。"
    ),
}


# ============================================================
# 三-B、受控 Text2SQL 工作流 (workflow_statistics.py) 专用提示词
# ============================================================

TEXT2SQL_PROMPTS = {
    # ------------------------------------------------------------------
    # router_node: 路由判断 - 判断用户问题是统计分析还是普通问答
    # 输入变量: question
    # ------------------------------------------------------------------
    "router": (
        "你是一个路由判断专家。请判断用户的问题是否需要查询数据库进行统计分析。\n"
        "\n"
        "判断标准：\n"
        "- 如果问题涉及统计、排名、频次、数量、趋势、对比、分布等，需要查询数据库 → 回答 \"statistics\"\n"
        "- 如果问题涉及维修反馈、好评、差评等，需要查询外部系统 → 回答 \"feedback\"\n"
        "- 如果是一般性知识问答、维修方法、操作指导等，不需要查询数据库 → 回答 \"normal\"\n"
        "\n"
        "用户问题：{question}\n"
        "\n"
        "请输出JSON格式：\n"
        "{{\"route\": \"statistics\" 或 \"feedback\" 或 \"normal\", \"reason\": \"判断理由\"}}\n"
        "只输出JSON，不要有其他文字。"
    ),

    # ------------------------------------------------------------------
    # SQL Generation: 根据用户问题生成SQL
    # 输入变量: schema, question, current_date
    # ------------------------------------------------------------------
    "sql_generation": (
        "你是舰船维修数据分析助手。请根据用户问题生成SQL查询。\n"
        "\n"
        "【数据库Schema】\n"
        "{schema}\n"
        "\n"
        "【当前日期】{current_date}\n"
        "\n"
        "【用户问题】\n"
        "{question}\n"
        "\n"
        "【其他有效信息】\n"
        "{extra_info}\n"
        "【生成规则】\n"
        "1. 只能生成 SELECT 语句，禁止 INSERT/UPDATE/DELETE\n"
        "2. 只能查询 fault_records 表\n"
        "3. 默认 LIMIT 100（如果未指定）\n"
        "4. 不允许使用 UNION、子查询嵌套超过2层\n"
        "5. 不允许使用任何危险SQL（如 pg_sleep、注释注入等）\n"
        "6. 时间条件使用 created_at 字段\n"
        "7. 备件统计需要使用 jsonb_array_elements_text(spare_parts) 展开JSONB数组\n"
        "8. 系统名称使用 system_name 字段，必须使用 LIKE 模糊匹配（如 system_name LIKE '%动力%'），不要用等号精确匹配\n"
        "9. 舷号使用 ship_number 字段\n"
        "\n"
        "【常见统计模式】\n"
        "- 故障频次排名：SELECT device_name || fault AS name, system_name, COUNT(*) AS count FROM fault_records [WHERE ...] GROUP BY name, system_name ORDER BY count DESC LIMIT N\n"
        "- 备件消耗排名：SELECT sp AS name, system_name, COUNT(*) AS count FROM fault_records, jsonb_array_elements_text(spare_parts) AS sp [WHERE ...] GROUP BY sp, system_name ORDER BY count DESC LIMIT N\n"
        "- 故障类型分布：SELECT system_name, COUNT(*) AS count FROM fault_records [WHERE ...] GROUP BY system_name ORDER BY count DESC\n"
        "- 按舷号统计：在WHERE中添加 ship_number = 'xxx'\n"
        "- 按系统筛选：在WHERE中添加 system_name LIKE '%动力%'\n"
        "- 按时间范围：在WHERE中添加 created_at >= 'xxx' AND created_at <= 'xxx'\n"
        "\n"
        "【时间映射规则】\n"
        "- \"最近一周\" → created_at >= 当前日期前7天\n"
        "- \"最近一个月\" → created_at >= 当前日期前30天\n"
        "- \"最近三个月\" → created_at >= 当前日期前90天\n"
        "- \"今年\" → created_at >= 当年1月1日\n"
        "\n"
        "请输出JSON格式：\n"
        "{{\"sql\": \"SELECT ...\", \"explanation\": \"SQL逻辑说明\"}}\n"
        "只输出JSON，不要有其他文字。"
    ),

    # ------------------------------------------------------------------
    # SQL Regeneration: 基于反馈重新生成SQL
    # 输入变量: schema, question, current_date, previous_sql, feedback
    # ------------------------------------------------------------------
    "sql_regeneration": (
        "你是舰船维修数据分析助手。之前的SQL存在问题，请根据反馈重新生成。\n"
        "\n"
        "【数据库Schema】\n"
        "{schema}\n"
        "\n"
        "【当前日期】{current_date}\n"
        "\n"
        "【用户问题】\n"
        "{question}\n"
        "\n"
        "【之前的SQL】\n"
        "{previous_sql}\n"
        "\n"
        "【问题反馈】\n"
        "{feedback}\n"
        "\n"
        "请根据反馈修正SQL，输出JSON格式：\n"
        "{{\"sql\": \"SELECT ...\", \"explanation\": \"修正说明\"}}\n"
        "只输出JSON，不要有其他文字。"
    ),

    # ------------------------------------------------------------------
    # SQL Review: 审查SQL是否正确回答了用户问题
    # 输入变量: schema, question, sql
    # ------------------------------------------------------------------
    "sql_review": (
        "你是SQL审查专家。请检查以下SQL是否真正回答了用户问题。\n"
        "\n"
        "【数据库Schema】\n"
        "{schema}\n"
        "\n"
        "【用户问题】\n"
        "{question}\n"
        "\n"
        "【待审查SQL】\n"
        "{sql}\n"
        "\n"
        "【审查要点】\n"
        "1. 时间条件是否正确（用户说\"近一个月\"，SQL是否有对应的时间范围？）\n"
        "2. 聚合逻辑是否正确（COUNT、GROUP BY是否与问题匹配？）\n"
        "3. 排序是否正确（排名类问题是否ORDER BY DESC？）\n"
        "4. 字段是否存在（所有字段都在Schema中？）\n"
        "5. 是否符合业务语义（故障频次应统计device_name+fault，备件应展开spare_parts）\n"
        "6. WHERE条件是否遗漏（用户指定了舷号/系统，SQL是否包含？）\n"
        "7. 备件统计是否正确使用了 jsonb_array_elements_text\n"
        "\n"
        "请输出JSON格式：\n"
        "{{\n"
        "  \"approved\": true 或 false,\n"
        "  \"issues\": [\"问题1\", \"问题2\"],\n"
        "  \"suggested_sql\": \"修正后的SQL（如果approved为false，提供修正版本）\",\n"
        "  \"review_comment\": \"审查意见\"\n"
        "}}\n"
        "只输出JSON，不要有其他文字。"
    ),

    # ------------------------------------------------------------------
    # Result Reflection: 检查查询结果是否合理
    # 输入变量: question, sql, row_count, sample_rows
    # ------------------------------------------------------------------
    "result_reflection": (
        "你是数据分析审查专家。请检查SQL查询结果是否合理地回答了用户问题。\n"
        "\n"
        "【用户问题】\n"
        "{question}\n"
        "\n"
        "【执行的SQL】\n"
        "{sql}\n"
        "\n"
        "【结果概况】\n"
        "- 返回行数：{row_count}\n"
        "- 前5行数据：\n"
        "{sample_rows}\n"
        "\n"
        "【判断标准】\n"
        "1. 如果结果为空（0行），可能SQL有问题 → 需要重试\n"
        "2. 如果结果数量异常少（如统计排名只有1条），可能条件过严 → 需要重试\n"
        "3. 如果结果明显不符合业务逻辑 → 需要重试\n"
        "4. 如果结果合理 → 通过\n"
        "\n"
        "请输出JSON格式：\n"
        "{{\n"
        "  \"reasonable\": true 或 false,\n"
        "  \"reason\": \"判断理由\",\n"
        "  \"suggestion\": \"如果不合理，给出改进建议\"\n"
        "}}\n"
        "只输出JSON，不要有其他文字。"
    ),

    # ------------------------------------------------------------------
    # Final Answer: 将SQL结果转为自然语言
    # 输入变量: question, sql, row_count, result_data
    # ------------------------------------------------------------------
    "final_answer": (
        "你是舰船维修数据分析助手。请将SQL查询结果转换为清晰的自然语言回答。\n"
        "\n"
        "【用户问题】\n"
        "{question}\n"
        "\n"
        "【执行的SQL】\n"
        "{sql}\n"
        "\n"
        "【查询结果】（共{row_count}条）\n"
        "{result_data}\n"
        "\n"
        "【回答要求】\n"
        "1. 用自然语言总结核心结论\n"
        "2. 如果是排名类结果，用Markdown表格展示（列名：排名、名称、次数/数量、系统等）\n"
        "3. 如果是分布类结果，说明各部分的占比\n"
        "4. 数字要准确，不要编造数据\n"
        "5. 语言简洁专业\n"
        "6. 如果结果为空，说明可能没有相关数据\n"
    ),
}


# ============================================================
# 四、故障诊断工作流 (workflow_fault_diagnosis.py) 专用提示词
# 仅包含与操作指导不同的部分，共享提示词使用 COMMON_PROMPTS
# ============================================================

FAULT_DIAGNOSIS_PROMPTS = {
    # ------------------------------------------------------------------
    # classify_intent 节点：故障诊断意图分类系统提示词
    # 用于判断用户意图是"维修"还是"百科"
    # ------------------------------------------------------------------
    "classify_intent_system": (
        "你是一个船舶设备维修诊断系统的意图识别专家。你的任务是精准识别用户的核心诉求，将其分类为\"维修\"或\"百科\"。\n"
        "\n"
        "### 📚 分类定义与判别标准\n"
        "\n"
        "#### 1. 维修\n"
        "- **核心特征**：用户描述了一个具体的**故障现象**、**异常状态**、**报警代码**，或者明确询问**解决方案**、**排查步骤**。\n"
        "- **关键判定规则**：\n"
        "    - **故障即维修**：只要用户陈述了一个设备故障现象（如\"主机排烟温度高\"），即使没有说\"怎么修\"，也默认归类为维修（隐含求助意图）。\n"
        "    - **排查导向**：涉及\"原因分析\"、\"处理措施\"、\"应急操作\"的内容。\n"
        "- **示例**：\n"
        "    - \"主机滑油压力低\"（隐含：怎么办？）\n"
        "    - \"发电机启动失败，有报警E05\"\n"
        "    - \"分油机震动大怎么处理\"\n"
        "    - \"锅炉点火失败的原因\"（针对具体故障的原因分析属于维修）\n"
        "\n"
        "#### 2. 百科\n"
        "- **核心特征**：用户询问**理论知识**、**设备原理**、**参数定义**、**结构组成**或**常规保养规范**，且不涉及当前的具体故障。\n"
        "- **关键判定规则**：\n"
        "    - **概念导向**：包含\"什么是\"、\"原理\"、\"作用\"、\"结构\"、\"定义\"等词汇。\n"
        "    - **通用性**：问题适用于所有同类设备，而非针对某一台坏掉的设备。\n"
        "- **示例**：\n"
        "    - \"柴油机的工作原理是什么\"\n"
        "    - \"滑油分油机的结构图\"\n"
        "    - \"什么是扫气箱着火\"（询问定义）\n"
        "    - \"主机日常保养项目有哪些\"\n"
        "\n"
        "### ⚠️ 冲突处理原则\n"
        "- 如果用户输入既像原理又像故障（例如\"涡轮增压器喘振\"），**优先归类为\"维修\"**，因为用户更可能是在遇到故障。\n"
        "- 如果用户明确使用了\"什么是\"、\"怎么定义\"，归类为\"百科\"。\n"
        "\n"
        "### 📤 输出格式\n"
        "请仅输出一个标准的 JSON 对象，不要包含 markdown 标记或其他文本：\n"
        "{\n"
        "    \"intent\": \"维修\" 或 \"百科\",\n"
        "    \"reason\": \"简短的判断理由，指出触发分类的关键特征词或逻辑\"\n"
        "}"
    ),

    # ------------------------------------------------------------------
    # extract_info 节点：故障诊断信息提取系统提示词
    # 用于从用户输入中提取维修相关信息（舷号、设备名称、故障现象等）
    # ------------------------------------------------------------------
    "extract_info_system": (
        "你是一个信息提取专家，负责从用户输入中提取维修相关信息。\n"
        "\n"
        "你需要提取以下信息：\n"
        "1. 舷号：船舰编号，如\"101\",\"111\",\"122\"等\n"
        "2. 设备名称：故障设备的名称\n"
        "3. 故障现象：故障的具体表现\n"
        "4. 故障码：报警代码或故障代码\n"
        "5. 故障时间：故障发生的时间\n"
        "6. 故障频率：故障发生的频率\n"
        "7. 已尝试措施：用户已经尝试过的维修方法\n"
        "8. 运行工况：设备运行时的参数\n"
        "9. 其他信息：其他补充说明\n"
        "\n"
        "提取规则：\n"
        "- 如果某项信息没有提及，返回空字符串\n"
        "- 优先使用当前输入中的信息\n"
        "- 注意保留已有的信息，不要丢失\n"
        "\n"
        "输出格式（JSON）：\n"
        "{\n"
        "    \"ship_number\": \"舷号\",\n"
        "    \"device_name\": \"设备名称\",\n"
        "    \"fault\": \"故障现象\",\n"
        "    \"fault_code\": \"故障码\",\n"
        "    \"fault_time\": \"故障时间\",\n"
        "    \"fault_frequency\": \"故障频率\",\n"
        "    \"tried_measures\": \"已尝试措施\",\n"
        "    \"running_condition\": \"运行工况\",\n"
        "    \"additional_info\": \"其他信息\"\n"
        "}"
    ),

    # ------------------------------------------------------------------
    # agent_think 节点（方案已生成时）：故障诊断后续意图分析系统提示词
    # 用于判断用户在方案已生成后的后续意图
    # ------------------------------------------------------------------
    "agent_think_intent_system": (
        "你是一个专业的意图分析专家，用于船舶故障诊断系统。\n"
        "\n"
        "根据对话历史和用户当前输入，判断用户的意图。\n"
        "\n"
        "【意图分类说明】\n"
        "1. generate_report: 用户明确要求生成、导出、下载、保存维修报告\n"
        "   - 示例：\"生成报告\"、\"写报告\"、\"导出报告\"、\"下载报告\"、\"保存报告\"\n"
        "\n"
        "2. modify_info: 用户需要修改或补充之前提供的故障信息（舷号、设备名称、故障现象等）\n"
        "   - 示例：\"其实是...\"、\"不对，应该是...\"、\"我补充一下...\"、\"修改设备名称是...\"、\"更正一下，故障是...\"\n"
        "\n"
        "3. has_error: 用户指出之前生成的维修方案有错误、需要修改或调整方案内容\n"
        "   - 示例：\"方案有误\"、\"这个步骤不对\"、\"需要修改方案\"、\"这个方案有问题\"\n"
        "\n"
        "4. not_solved: 用户反映按照之前的方案执行后，故障问题依然没有解决，需要更深入的分析\n"
        "   - 示例：\"没有解决\"、\"还是不行\"、\"问题依旧\"、\"还是没解决\"、\"按照方案做了但还是有问题\"、\"需要更深入的分析故障\"、\"需要详细的解决方案\"\n"
        "\n"
        "5. related_question: 用户询问与当前故障、设备、原理等相关的问题（非方案调整、非信息修改）\n"
        "   - 示例：\"为什么会出现这个故障？\"、\"这个设备的工作原理是什么？\"、\"这个部件怎么更换？\"、\"执行方案时遇到问题：...\"\n"
        "\n"
        "6. other: 其他无法归类到上述类别的意图\n"
        "   - 示例：打招呼、闲聊、与当前故障诊断无关的问题\n"
        "\n"
        "输出格式（JSON）：\n"
        "{\"intent\": \"意图类型\", \"reason\": \"判断理由\"}"
    ),

    # ------------------------------------------------------------------
    # agent_think 节点：故障诊断后续意图分析用户提示词
    # 输入变量: ship_number, device_name, fault, history_str, combined_query
    # ------------------------------------------------------------------
    "agent_think_intent_user": (
        "【当前故障诊断信息】\n"
        "- 舷号: {ship_number}\n"
        "- 设备名称: {device_name}\n"
        "- 故障现象: {fault}\n"
        "\n"
        "【对话历史】\n"
        "{history_str}\n"
        "\n"
        "【用户当前输入】\n"
        "{combined_query}\n"
        "\n"
        "请分析用户意图（JSON格式）："
    ),

    # ------------------------------------------------------------------
    # ask_user 节点：用户补充信息提取提示词
    # 输入变量: missing_str, user_query
    # ------------------------------------------------------------------
    "ask_user_extract": (
        "从用户输入中提取缺失的信息。\n"
        "\n"
        "缺失的信息类型: {missing_str}\n"
        "\n"
        "用户输入: {user_query}\n"
        "\n"
        "请提取用户补充的信息，输出JSON格式：\n"
        "{{\"ship_number\": \"舷号\", \"device_name\": \"设备名称\", \"fault\": \"故障现象\"}}\n"
        "如果某项信息没有提及，返回空字符串。"
    ),

    # ------------------------------------------------------------------
    # generate_response 节点 - 无检索结果但有设备信息时的用户提示词
    # 输入变量: ship_number, device_name, fault, fault_code, fault_time,
    #           fault_frequency, tried_measures, running_condition, additional_info
    # ------------------------------------------------------------------
    "generate_response_no_rag_user": (
        "用户描述：\n"
        "- 舷号: {ship_number}\n"
        "- 设备名称: {device_name}\n"
        "- 故障现象: {fault}\n"
        "- 故障码: {fault_code}\n"
        "- 故障时间: {fault_time}\n"
        "- 故障频率: {fault_frequency}\n"
        "- 已尝试措施: {tried_measures}\n"
        "- 运行工况: {running_condition}\n"
        "- 其他信息: {additional_info}\n"
        "\n"
        "请给出一般性的故障诊断建议："
    ),

    # ------------------------------------------------------------------
    # generate_response 节点 - 无检索结果（简化版）用户提示词
    # 输入变量: ship_number, device_name, fault
    # ------------------------------------------------------------------
    "generate_response_no_rag_simple_user": (
        "用户描述：\n"
        "- 舷号: {ship_number}\n"
        "- 设备名称: {device_name}\n"
        "- 故障现象: {fault}\n"
        "\n"
        "请给出一般性的故障诊断建议："
    ),
}


# ============================================================
# 五、操作指导工作流 (workflow_operate.py) 专用提示词
# 仅包含与故障诊断不同的部分，共享提示词使用 COMMON_PROMPTS
# ============================================================

OPERATE_PROMPTS = {
    # ------------------------------------------------------------------
    # classify_intent 节点：操作指导意图分类系统提示词
    # 用于判断用户意图是"操作"还是"百科"
    # ------------------------------------------------------------------
    "classify_intent_system": (
        "你是一个船舶设备操作指导系统的意图识别专家。你的任务是精准识别用户的核心诉求，将其分类为\"操作\"或\"百科\"。\n"
        "\n"
        "### 📚 分类定义与判别标准\n"
        "\n"
        "#### 1. 操作\n"
        "- **核心特征**：用户描述了一个具体的**操作需求**、**操作步骤**、**操作代码**，或者明确询问**操作方法**、**操作流程**。\n"
        "- **关键判定规则**：\n"
        "    - **操作即指导**：只要用户陈述了一个设备操作需求（如\"主机启动操作\"），即使没有说\"怎么操作\"，也默认归类为操作（隐含求助意图）。\n"
        "    - **流程导向**：涉及\"操作步骤\"、\"操作方法\"、\"操作规程\"的内容。\n"
        "- **示例**：\n"
        "    - \"主机启动操作步骤\"（隐含：怎么做？）\n"
        "    - \"发电机并车操作流程\"\n"
        "    - \"分油机操作方法\"\n"
        "    - \"锅炉点火操作规程\"\n"
        "\n"
        "#### 2. 百科\n"
        "- **核心特征**：用户询问**理论知识**、**设备原理**、**参数定义**、**结构组成**或**常规保养规范**，且不涉及当前的具体操作。\n"
        "- **关键判定规则**：\n"
        "    - **概念导向**：包含\"什么是\"、\"原理\"、\"作用\"、\"结构\"、\"定义\"等词汇。\n"
        "    - **通用性**：问题适用于所有同类设备，而非针对某一项具体操作。\n"
        "- **示例**：\n"
        "    - \"柴油机的工作原理是什么\"\n"
        "    - \"滑油分油机的结构图\"\n"
        "    - \"什么是扫气箱着火\"（询问定义）\n"
        "    - \"主机日常保养项目有哪些\"\n"
        "\n"
        "### ⚠️ 冲突处理原则\n"
        "- 如果用户输入既像原理又像操作（例如\"涡轮增压器操作\"），**优先归类为\"操作\"**，因为用户更可能是需要操作指导。\n"
        "- 如果用户明确使用了\"什么是\"、\"怎么定义\"，归类为\"百科\"。\n"
        "\n"
        "### 📤 输出格式\n"
        "请仅输出一个标准的 JSON 对象，不要包含 markdown 标记或其他文本：\n"
        "{\n"
        "    \"intent\": \"操作\" 或 \"百科\",\n"
        "    \"reason\": \"简短的判断理由，指出触发分类的关键特征词或逻辑\"\n"
        "}"
    ),

    # ------------------------------------------------------------------
    # extract_info 节点：操作指导信息提取系统提示词
    # 用于从用户输入中提取操作相关信息（舷号、设备名称、操作项目等）
    # ------------------------------------------------------------------
    "extract_info_system": (
        "你是一个信息提取专家，负责从用户输入中提取操作相关信息。\n"
        "\n"
        "你需要提取以下信息：\n"
        "1. 舷号：船舰编号，如\"101\",\"111\",\"122\"等\n"
        "2. 设备名称：操作设备的名称\n"
        "3. 操作项目：操作的具体内容\n"
        "4. 操作代码：报警代码或操作代码\n"
        "5. 操作时间：操作发生的时间\n"
        "6. 操作频率：操作发生的频率\n"
        "7. 已尝试措施：用户已经尝试过的操作方法\n"
        "8. 运行工况：设备运行时的参数\n"
        "9. 其他信息：其他补充说明\n"
        "\n"
        "提取规则：\n"
        "- 如果某项信息没有提及，返回空字符串\n"
        "- 优先使用当前输入中的信息\n"
        "- 注意保留已有的信息，不要丢失\n"
        "\n"
        "输出格式（JSON）：\n"
        "{\n"
        "    \"ship_number\": \"舷号\",\n"
        "    \"device_name\": \"设备名称\",\n"
        "    \"operation_item\": \"操作项目\",\n"
        "    \"operation_code\": \"操作代码\",\n"
        "    \"operation_time\": \"操作时间\",\n"
        "    \"operation_frequency\": \"操作频率\",\n"
        "    \"tried_measures\": \"已尝试措施\",\n"
        "    \"running_condition\": \"运行工况\",\n"
        "    \"additional_info\": \"其他信息\"\n"
        "}"
    ),

    # ------------------------------------------------------------------
    # agent_think 节点（方案已生成时）：操作指导后续意图分析系统提示词
    # 用于判断用户在方案已生成后的后续意图
    # ------------------------------------------------------------------
    "agent_think_intent_system": (
        "你是一个专业的意图分析专家，用于船舶操作指导系统。\n"
        "\n"
        "根据对话历史和用户当前输入，判断用户的意图。\n"
        "\n"
        "【意图分类说明】\n"
        "1. modify_info: 用户需要修改或补充之前提供的操作信息（舷号、设备名称、操作项目等）\n"
        "   - 示例：\"其实是...\"、\"不对，应该是...\"、\"我补充一下...\"、\"修改设备名称是...\"、\"更正一下，操作是...\"\n"
        "\n"
        "2. has_error: 用户指出之前生成的操作方案有错误、需要修改或调整方案内容\n"
        "   - 示例：\"方案有误\"、\"这个步骤不对\"、\"需要修改方案\"、\"这个方案有问题\"\n"
        "\n"
        "3. not_solved: 用户反映按照之前的方案执行后，操作问题依然没有解决，需要更深入的分析\n"
        "   - 示例：\"没有解决\"、\"还是不行\"、\"问题依旧\"、\"还是没解决\"、\"按照方案做了但还是有问题\"、\"需要更深入的分析\"、\"需要详细的解决方案\"\n"
        "\n"
        "4. related_question: 用户询问与当前操作、设备、原理等相关的问题（非方案调整、非信息修改）\n"
        "   - 示例：\"为什么会出现这个操作问题？\"、\"这个设备的工作原理是什么？\"、\"这个部件怎么更换？\"、\"执行方案时遇到问题：...\"\n"
        "\n"
        "5. other: 其他无法归类到上述类别的意图\n"
        "   - 示例：打招呼、闲聊、与当前操作指导无关的问题\n"
        "\n"
        "输出格式（JSON）：\n"
        "{\"intent\": \"意图类型\", \"reason\": \"判断理由\"}"
    ),

    # ------------------------------------------------------------------
    # agent_think 节点：操作指导后续意图分析用户提示词
    # 输入变量: ship_number, device_name, operation_item, history_str, combined_query
    # ------------------------------------------------------------------
    "agent_think_intent_user": (
        "【当前操作指导信息】\n"
        "- 舷号: {ship_number}\n"
        "- 设备名称: {device_name}\n"
        "- 操作项目: {operation_item}\n"
        "\n"
        "【对话历史】\n"
        "{history_str}\n"
        "\n"
        "【用户当前输入】\n"
        "{combined_query}\n"
        "\n"
        "请分析用户意图（JSON格式）："
    ),

    # ------------------------------------------------------------------
    # ask_user 节点：用户补充信息提取提示词
    # 输入变量: missing_str, user_query
    # ------------------------------------------------------------------
    "ask_user_extract": (
        "从用户输入中提取缺失的信息。\n"
        "\n"
        "缺失的信息类型: {missing_str}\n"
        "\n"
        "用户输入: {user_query}\n"
        "\n"
        "请提取用户补充的信息，输出JSON格式：\n"
        "{{\"ship_number\": \"舷号\", \"device_name\": \"设备名称\", \"operation_item\": \"操作项目\"}}\n"
        "如果某项信息没有提及，返回空字符串。"
    ),

    # ------------------------------------------------------------------
    # generate_response 节点 - 无检索结果但有设备信息时的用户提示词
    # 输入变量: ship_number, device_name, operation_item, operation_code,
    #           operation_time, operation_frequency, tried_measures,
    #           running_condition, additional_info
    # ------------------------------------------------------------------
    "generate_response_no_rag_user": (
        "用户描述：\n"
        "- 舷号: {ship_number}\n"
        "- 设备名称: {device_name}\n"
        "- 操作项目: {operation_item}\n"
        "- 操作代码: {operation_code}\n"
        "- 操作时间: {operation_time}\n"
        "- 操作频率: {operation_frequency}\n"
        "- 已尝试措施: {tried_measures}\n"
        "- 运行工况: {running_condition}\n"
        "- 其他信息: {additional_info}\n"
        "\n"
        "请给出一般性的操作指导建议："
    ),

    # ------------------------------------------------------------------
    # generate_response 节点 - 无检索结果（简化版）用户提示词
    # 输入变量: ship_number, device_name, operation_item
    # ------------------------------------------------------------------
    "generate_response_no_rag_simple_user": (
        "用户描述：\n"
        "- 舷号: {ship_number}\n"
        "- 设备名称: {device_name}\n"
        "- 操作项目: {operation_item}\n"
        "\n"
        "请给出一般性的操作指导建议："
    ),
}

xDx# Agent任务划分开发项目依赖

# LangChain相关
langchain
langchain-core
langchain-openai
langgraph
langgraph-checkpoint
langgraph-checkpoint-postgres

# HTTP客户端
httpx
requests

# 数据处理
pydantic
typing-extensions
numpy

# 其他工具
python-dotenv

# FastAPI 相关
fastapi
uvicorn[standard]

# Neo4j 图数据库
neo4j

# PostgreSQL 支持
psycopg[binary]
psycopg-pool

# OpenAI API
openai
tiktoken

# Word 文档生成
python-docx

# PDF 生成相关
matplotlib
Pillow

#M9xk
\documentclass[10pt]{article}
\usepackage[UTF8]{ctex}
\usepackage{geometry}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{array}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{setspace}
\usepackage{fancyhdr}
\usepackage{titlesec}
\usepackage{tabularx}
\usepackage{makecell}
\usepackage{adjustbox}
\usepackage{hyperref}
% 页面设置
\geometry{margin=2cm}
\setlength{\parskip}{1em}
\setlength{\parindent}{0em}

% 字体
\setCJKmainfont{Noto Serif CJK SC}

% 标题样式
\title{\Large \textbf{$title$}}
\author{}
\date{}

% 章节标题样式
\titleformat{\section}{\large\bfseries\raggedright}{\thesection}{1em}{}
\titleformat{\subsection}{\normalsize\bfseries\raggedright}{\thesubsection}{1em}{}


% ===== Pandoc compatibility =====
\usepackage{hyperref}
\providecommand{\tightlist}{%
  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}


\begin{document}

\maketitle

$body$

\end{document}
qxv"""
智能舷号映射 + RAG检索 完整测试脚本
直接调用 search_with_ship_number_strategy，展示真实检索结果
"""
import asyncio
import sys
import os

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from utils.ship_number_search import search_with_ship_number_strategy, smart_ship_number_mapping


async def interactive_test():
    """交互式完整测试"""
    print("=" * 60)
    print("智能舷号映射 + RAG检索 完整测试")
    print("=" * 60)
    print("输入 'exit' 或 'quit' 退出")
    print("输入 'help' 查看说明")
    print("=" * 60)
    
    while True:
        print("\n" + "-" * 60)
        ship_input = input("请输入舷号/型号/舰名: ").strip()
        
        if ship_input.lower() in ['exit', 'quit', 'q']:
            print("退出测试")
            break
        
        if ship_input.lower() == 'help':
            print("\n使用说明:")
            print("  先输入舷号/型号/舰名（如 163、南昌舰、055驱逐舰）")
            print("  再输入查询内容（如 主机排烟温度高）")
            print("  系统会执行完整的智能映射 + RAG三步检索")
            continue
        
        if not ship_input:
            print("请输入有效内容")
            continue
        
        query_input = input("请输入查询内容: ").strip()
        if not query_input:
            query_input = "主机排烟温度高的维修方案"
            print(f"使用默认查询: {query_input}")
        
        search_type = input("搜索类型 (fault/operate，回车默认fault): ").strip()
        if search_type not in ["fault", "operate"]:
            search_type = "fault"
        
        print("\n" + "=" * 60)
        print("第一步：智能映射")
        print("=" * 60)
        
        try:
            matched_ship_number, matched_model, all_numbers, match_type = await smart_ship_number_mapping(ship_input)
            print(f"输入: '{ship_input}'")
            print(f"匹配类型: {match_type}")
            print(f"匹配舷号: {matched_ship_number}")
            print(f"匹配型号: {matched_model}")
            print(f"该型号所有舷号: {all_numbers}")
            
            if match_type == "none":
                print("未匹配到，将使用原始输入进行检索")
        except Exception as e:
            print(f"映射失败: {str(e)}")
            matched_ship_number = None
            matched_model = None
            all_numbers = None
            match_type = "none"
        
        print("\n" + "=" * 60)
        print("第二步：RAG检索（三步策略）")
        print("=" * 60)
        
        try:
            rag_results, matched_kb_name, matched_kb_id = await search_with_ship_number_strategy(
                base_query=query_input,
                ship_number=ship_input,
                top_k=5,
                search_type=search_type
            )
            
            print(f"\n检索完成!")
            print(f"知识库: {matched_kb_name or '未匹配'}")
            print(f"知识库ID: {matched_kb_id or '未匹配'}")
            print(f"结果数量: {len(rag_results)}")
            
            if rag_results:
                print(f"\n{'=' * 60}")
                print("第三步：检索结果详情")
                print("=" * 60)
                for i, item in enumerate(rag_results, 1):
                    if isinstance(item, dict):
                        text = item.get("text", "")
                        kb_name = item.get("kb_name", "")
                        score = item.get("score", "")
                        source = item.get("source", "")
                        
                        print(f"\n--- 结果 {i} ---")
                        if kb_name:
                            print(f"知识库: {kb_name}")
                        if score:
                            print(f"相似度: {score}")
                        if source:
                            print(f"来源: {source}")
                        if text:
                            preview = text[:300] + "..." if len(text) > 300 else text
                            print(f"内容预览:\n{preview}")
                    elif isinstance(item, str):
                        preview = item[:300] + "..." if len(item) > 300 else item
                        print(f"\n--- 结果 {i} ---")
                        print(f"内容预览:\n{preview}")
            else:
                print("\n未检索到任何结果")
                
        except Exception as e:
            print(f"\n检索失败: {str(e)}")
            import traceback
            traceback.print_exc()


if __name__ == "__main__":
    asyncio.run(interactive_test())
QI#x7100644 __init__.py JŃF])40000 __pycache__ ڮlq$7H*"ܢk100644 agent_usage_statistics.py jA1^:H<ҭ;100644 fault_record_db.py a?sսl<PF!lֳ100644 fault_statistics.py [t7WF-3ig͝100644 function_tool.py I0!V󍻛#
100644 graph_tools.py asSЀ)vN/100644 pdf_generator.py S֮qF#"Ǵm100644 rag_tools.py ŹrU߳Ͳ100644 ship_model_db.py x ,G\y<"m100644 text2sql_tool.py ;AG_100644 texttosql_utils.py hi^&ӛ9/-I	R100644 vlm_tools.py BwWCJ}az?/沷9xh
"""
工具模块
包含RAG、GraphRAG、VLM、ASR、TTS等工具
"""
from .function_tool import (
    detect_input_type,
    graph_rag_search,
    fault_graph_rag_search,
    operation_graph_rag_search,
    rag_search_tool,
    vlm_image_to_text,
    asr_audio_to_text,
    extract_device_and_fault,
    image_rag_describe,
    file_to_text_tool,
    fault_type_statistics_tool,
    fault_frequency_statistics_tool,
    spare_parts_statistics_tool,
    ALL_TOOLS,
    TOOL_CATEGORIES
)

__all__ = [
    "detect_input_type",
    "graph_rag_search",
    "fault_graph_rag_search",
    "operation_graph_rag_search",
    "rag_search_tool",
    "vlm_image_to_text",
    "asr_audio_to_text",
    "extract_device_and_fault",
    "image_rag_describe",
    "file_to_text_tool",
    "fault_type_statistics_tool",
    "fault_frequency_statistics_tool",
    "spare_parts_statistics_tool",
    "ALL_TOOLS",
    "TOOL_CATEGORIES"
]

;.x100644 __init__.cpython-310.pyc sÀ?1LJ?100644 __init__.cpython-312.pyc 2!'Ԧ,U100644 agent_usage_statistics.cpython-312.pyc ^o9}L1NN100644 fault_record_db.cpython-312.pyc ^N{RV_pXgP100644 fault_statistics.cpython-312.pyc %8R\˦^XS100644 function_tool.cpython-310.pyc D޷cB>T۲N 100644 function_tool.cpython-312.pyc ݸρs'Vî100644 graph_tools.cpython-312.pyc (-꧘L.} 100644 rag_tools.cpython-312.pyc WBv@Lc$100644 ship_model_db.cpython-312.pyc ե066	O  A100644 text2sql_tool.cpython-312.pyc 'U5"'100644 texttosql_utils.cpython-312.pyc ؑGfLRq:kX}100644 vlm_tools.cpython-312.pyc ?SH z
TSޚĳx\o
    li                     @   s0   d Z ddlmZmZmZmZmZmZ g dZdS )u>   
工具模块
包含RAG、GraphRAG、VLM、ASR、TTS等工具
   )graph_rag_searchfault_graph_rag_searchfault_graph_reason_and_projectsvlm_image_to_text	ALL_TOOLSTOOL_CATEGORIESN)	__doc__function_toolr   r   r   r   r   r   __all__ r   r   /app/tools/__init__.py<module>   s    	@1x
    αMj                     T    d Z ddlmZmZmZmZmZmZmZm	Z	m
Z
mZmZmZmZmZmZ g dZy)u>   
工具模块
包含RAG、GraphRAG、VLM、ASR、TTS等工具
   )detect_input_typegraph_rag_searchfault_graph_rag_searchoperation_graph_rag_searchrag_search_toolvlm_image_to_textasr_audio_to_textextract_device_and_faultimage_rag_describefile_to_text_toolfault_type_statistics_toolfault_frequency_statistics_toolspare_parts_statistics_tool	ALL_TOOLSTOOL_CATEGORIESN)__doc__function_toolr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   __all__     @e:\ZKYNLP\Hjunproject\project0506\wx-agent\app\tools\__init__.py<module>r      s*       $r    x*d
    />j              	           d Z ddlmZ ddlmZmZ ddlmZ ddddZd	d
ddZddddZ	d Z
ddedededefdZdedefdZdeeef   fdZy)ud   
智能体使用统计工具
记录和统计智能体的调用次数（PostgreSQL数据库存储）
    )datetime)DictAny)POSTGRES_CONNECTION_STRING   问题排查   操作使用   百科问答)r   r   r	   	detectionrepairdocz#FFB800z#00C2FFz#9153FFc            	        K   	 ddl m}   | t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d       d{    |j                  d	       d{    |j                  d
       d{    t        d       ddd      d{    ddd      d{    ddd      d{    y# t        $ r t        d       Y yw xY w7 7 7 7 7 {7 d7 K# 1 d{  7  sw Y   [xY w7 R# 1 d{  7  sw Y   bxY w7 Y# 1 d{  7  sw Y   yxY ww)u+   
    初始化 agent_usage_records 表
    r   AsyncConnectionPooluD   [agent_usage_statistics] psycopg_pool 未安装，无法初始化表N
autocommitTkwargsa  
                    CREATE TABLE IF NOT EXISTS agent_usage_records (
                        id SERIAL PRIMARY KEY,
                        chat_id TEXT NOT NULL DEFAULT '',
                        route_flag TEXT NOT NULL DEFAULT '',
                        message_id TEXT NOT NULL DEFAULT '',
                        created_at TIMESTAMP NOT NULL DEFAULT NOW(),
                        UNIQUE(chat_id, route_flag)
                    )
                z
                    CREATE INDEX IF NOT EXISTS agent_usage_records_route_flag_idx ON agent_usage_records(route_flag)
                z
                    CREATE INDEX IF NOT EXISTS agent_usage_records_created_at_idx ON agent_usage_records(created_at)
                u?   [agent_usage_statistics] agent_usage_records 表初始化完成)psycopg_poolr   ImportErrorprintr   
connectioncursorexecute)r   poolconncurs       $/app/tools/agent_usage_statistics.pyinit_agent_usage_tabler      s8    4
 #"d#  
??$${{}}kk 	# 	 	 	 kk #    kk #    WX# %} %$	  	  TU %$	 %}}} %$$$	   s)  EC EC6ED2C8D2DC:
DD)C<
*DC>
DD 
D+D6D7D;D2DD2ED0EC30E2C33E8D2:D<D>D DDD
DDDD2D-	!D$"D-	)D20E2E8D;9E Echat_id
route_flag
message_idreturnc                   K   | r|sy	 ddl m} 	  |t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d	| ||xs d
t        j                         f       d{    ddd      d{    ddd      d{    ddd      d{    y# t        $ r t        d       Y yw xY w7 7 7 7 U7 G# 1 d{  7  sw Y   WxY w7 N# 1 d{  7  sw Y   ^xY w7 U# 1 d{  7  sw Y   yxY w# t        $ r}t        d|        Y d}~yd}~ww xY ww)u   
    记录智能体使用情况到数据库

    Args:
        chat_id: 会话ID
        route_flag: 路由标志（智能体类型）
        message_id: 消息ID

    Returns:
        是否记录成功
    Fr   r   u>   [agent_usage_statistics] psycopg_pool 未安装，无法记录r   Tr   Nar  
                        INSERT INTO agent_usage_records (chat_id, route_flag, message_id, created_at)
                        VALUES (%s, %s, %s, %s)
                        ON CONFLICT (chat_id, route_flag) DO UPDATE SET
                            message_id = EXCLUDED.message_id,
                            created_at = EXCLUDED.created_at
                         u6   [agent_usage_statistics] 记录智能体使用失败: )r   r   r   r   r   r   r   r   r   now	Exception)r   r   r    r   r   r   r   es           r   record_agent_usager'   A   s4     *4
&& $'
 
 ((D;;==C++ !*j.>BO	 	 	 )= )(	
 
  +  NO

 )(	 )=== )(((	
 
 
 
   FqcJKs<  EC  D' CD' DCDC;C
C;0C$
C 
C$C;C"C;D*C9+D/D' :D;D' ?E CECED' DC; C$"C;$C6*C-+C62C;9D;D	DD		DD' D$DD$ D' #E$D' '	E0E>EEEcountc                 &    | dk\  r	| dz  ddS | dS )Ni'  z.1fu   万, )r(   s    r   _format_countr,   m   s'    ~%-$C((    c                    K   	 ddl m}  g d}t	        j
                         }g }t        dd	d	      D ]Q  }|j                  }|j                  |z
  }|dk  r|d
z  }|dz  }|dk  r|j                  ||| d|d| dd       S 	  | t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }	i |D ]A  }
|	j                  d|
f       d{    |	j                          d{   }|r|d   nd|
<   C |D ci c]  }||D ci c]  }|d   d
 c} }}}|D ]  }
|D ]  }t	        |d   |d   d      }|d   d
k(  rt	        |d   dz   dd      }nt	        |d   |d   dz   d      }|	j                  d|
||f       d{    |	j                          d{   }|r|d   nd||
   |d   <     ddd      d{    ddd      d{    ddd      d{    t%        fd|D              }g }g }|D ]  }
j'                  |
d      }t(        j'                  |
|
      }t*        j'                  |
d      }t,        j'                  |
d      }|j                  |t/        |      ||d       g }|D ]"  }|j                  |d   |
   |d      d       $ |j                  |||d        dt/        |      |||D cg c]  }|d   	 c}d dS # t        $ r t        d       dddcY S w xY w7 7 j7 T7 57  c c}w c c}}w 7 7 {7 X# 1 d{  7  sw Y   ixY w7 a# 1 d{  7  sw Y   rxY w7 j# 1 d{  7  sw Y   {xY w# t        $ r1}t        d|        ddl}|j#                          dddcY d}~S d}~ww xY wc c}w w)!u   
    从数据库查询智能体使用统计

    统计逻辑：
    - 同一 chat_id + route_flag 只保留一条记录
    - 统计各类型的总使用次数
    - 统计近6个月的月度使用次数

    Returns:
        统计结果字典
    r   r   u>   [agent_usage_statistics] psycopg_pool 未安装，无法查询FN)successdata)r   r   r	            -02du   月)yearmonthkeylabelr   Tr   z
                            SELECT COUNT(*) FROM agent_usage_records
                            WHERE route_flag = %s
                            r9   r7   r8   z
                                SELECT COUNT(*) FROM agent_usage_records
                                WHERE route_flag = %s AND created_at >= %s AND created_at < %s
                                u3   [agent_usage_statistics] 查询统计数据失败: c              3   B   K   | ]  }j                  |d         yw)r   N)get).0routeroute_countss     r   	<genexpr>z-get_agent_usage_statistics.<locals>.<genexpr>   s     Hu  *s   infoz#8C8C8C)namer(   iconcolorr:   )r8   r(   )rB   rD   monthlyCounts)totaltypesmonthlyStatsmonths)r   r   r   r   r   r$   ranger7   r8   appendr   r   r   r   fetchoner%   	traceback	print_excsumr<   ROUTE_FLAG_DISPLAY_NAMESROUTE_FLAG_ICONSROUTE_FLAG_COLORSr,   )r   required_routesr$   last_6_monthsir7   r8   r   r   r   r   rowr>   mmonthly_countsmonth_start	month_endr&   rM   rF   
types_datamonthly_statsr(   display_namerC   rD   monthly_datar?   s                              @r   get_agent_usage_statisticsr_   t   s1    04
 GO
,,.CM1b"xx		AqjRKEAID qj 	V1U3K(wc]	
 	 -0&& $'
 
 ((D;;==C#%L&5
!kk  (M   %(LLN2=@3q6aZ0 '6 `o%o_nV[e=-Q=aahk=-Q&Q_nN%o&5
!.A*21V9aj!*LK zR/,4QvY]Aq,I	,4QvY'
QPQ,R	"%++!$ ",[) D#   ),"6CMP3q6VWN:6qx@ "/ '6# )= )(	
 
\ HHHEJM%
  Q//33J
K##J7!%%j)< "5)	
 	 A7'
3AeH=!   	 )
 	) &6 "5))+89=aqz=9	
 E  0NO $//0,
 )( 3 .R%o #7A )=== )(((	
 
 
 
P  0CA3GH $//	0T :s  OK< AO%!ON LN M04L5M08ML!
ML>/L$0L>L'L>
L/)L*6L/;A*L>%L5&L>=L8>L>M#L;$M(M03M4M08N M-N C!O)O5O<LOLON M0!M$L>'L>*L//L>8L>;M>MMMMM0M*	M M*	%M0-N 0N6M97N>N 	O &N;5O 6O;O  ON)r#   )__doc__r   typingr   r   configr   rP   rQ   rR   r   strboolr'   intr,   r_   r+   r-   r   <module>rf      s      - #""       YF)c )s ) )UY )X  x$sCx. xr-   Y$x2?
    ϱMj+                        d 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mZm	Z	 ddl
mZ d Zdede	e   fd	Zd
ededede	e   dedefdZdeeef   defdZ	 	 	 	 	 	 dd
ee   dee   dee   dee   dee   dede	eeef      fdZy)u   
故障记录数据库模块
用于在故障诊断智能体生成方案后自动记录故障信息到PostgreSQL数据库
记录内容：舷号、设备、故障、备件、系统
    N)datetime)DictAnyOptionalList)POSTGRES_CONNECTION_STRINGc            	         K   	 ddl m}   | t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d       d{    |j                  d	       d{    |j                  d
       d{    |j                  d       d{    |j                  d       d{    t        d       ddd      d{    ddd      d{    ddd      d{    y# t        $ r t        d       Y yw xY w7 
7 7 7 7 7 7 7 i7 P# 1 d{  7  sw Y   `xY w7 W# 1 d{  7  sw Y   gxY w7 ^# 1 d{  7  sw Y   yxY ww)u%   
    初始化 fault_records 表
    r   AsyncConnectionPoolu=   [fault_record_db] psycopg_pool 未安装，无法初始化表N
autocommitTkwargsa  
                    CREATE TABLE IF NOT EXISTS fault_records (
                        id SERIAL PRIMARY KEY,
                        ship_number TEXT NOT NULL DEFAULT '',
                        device_name TEXT NOT NULL DEFAULT '',
                        fault TEXT NOT NULL DEFAULT '',
                        spare_parts JSONB NOT NULL DEFAULT '[]',
                        system_name TEXT NOT NULL DEFAULT '',
                        created_at TIMESTAMP NOT NULL DEFAULT NOW()
                    )
                z|
                    CREATE INDEX IF NOT EXISTS fault_records_ship_number_idx ON fault_records(ship_number)
                z|
                    CREATE INDEX IF NOT EXISTS fault_records_device_name_idx ON fault_records(device_name)
                z|
                    CREATE INDEX IF NOT EXISTS fault_records_system_name_idx ON fault_records(system_name)
                zz
                    CREATE INDEX IF NOT EXISTS fault_records_created_at_idx ON fault_records(created_at)
                u2   [fault_record_db] fault_records 表初始化完成)psycopg_poolr   ImportErrorprintr   
connectioncursorexecute)r   poolconncurs       Ge:\ZKYNLP\Hjunproject\project0506\wx-agent\app\tools\fault_record_db.pyinit_fault_records_tabler      s~    4
 #"d#  
??$${{}}kk 
# 
 
 
 kk #    kk #    kk #    kk #    JK1 %} %$	  	  MN %$
+ %}}} %$$$	   sM  E>D E>D(E>E)D+E)ED-
ED;)D/
*D;D1
D;D3
D;4D5
5D;D7
D;E(D9)E-E)8E9E)=E>E'	E>D%"E>$D%%E>+E)-E/D;1D;3D;5D;7D;9E;EEE	EE)E$	EE$	 E)'E>)E;/E20E;7E>scheme_contentreturnc           	        K   | rt        | j                               dk  rg S d| dd  d}	 ddlm} |j	                  |d	       d{   }t        d
|       |j                         }t        j                  dd|t        j                        }t        j                  dd|      }t        j                  dd|      }	 t        j                  |      }t        |t               rd|v r@t        |d   t"              r-|d   D cg c]  }|st%        |      j                           c}S g }|j'                         D ]L  }t        |t"              s|j)                  |D cg c]  }|st%        |      j                           c}       N |S t        |t"              r*|D cg c]  }|st%        |      j                           c}S g S 7 # t        j                  $ rT t        j                  d|t        j                        }|r%t        j                  |j                  d            }ng cY S Y \w xY wc c}w c c}w c c}w # t*        $ r#}	t        dt%        |	              g cY d}	~	S d}	~	ww xY ww)u   
    从方案内容中用大模型抽取备件名称列表

    Args:
        scheme_content: 方案内容（Markdown格式）

    Returns:
        备件名称列表
    
   uZ   从以下维修方案内容中提取所有提到的备品备件名称。

方案内容：
Ni  u  

提取规则：
1. 找到"备品备件"、"备件"等相关章节，提取其中的项目名称
2. 只提取名称，不要提取型号、规格、数量、材质、用途等
3. 如果没有专门的章节，也从全文中识别备件名称

以JSON数组格式返回：
{
    "备品备件": [备件名称1, 备件名称2, ...]
}

如果没有提到备品备件，请返回空数组 []r   )	OpenaiAPIT)queryjson_outputu   抽取出来的备品备件z^```json\s* )flagsz^```\s*z```$z\{.*\}u   备品备件u/   [fault_record_db] 从方案提取备件失败: )lenstripmodelsAPI.model_apir   open_api_chat_without_thinkingr   resub
IGNORECASEjsonloadsJSONDecodeErrorsearchDOTALLgroup
isinstancedictliststrvaluesextend	Exception)
r   promptr   result_textparsed
json_matchpart	all_partsves
             r   extract_spare_parts_from_schemer?   :   s9     S!5!5!782=	   7:F"%1%DD E 
 
 	+[9!'')ff^RBMMRffZ[9ffWb+6	ZZ,F fd#'Jvn7Mt,T6<^6LU6LdPTD	)6LUUI]]_a&$$A%NADc$ioo&7A%NO % %28A&$DCIOO%&AA	?
 ## 	9k299EJJ$4$4Q$78	 	 V &O B  ?AxHI	s   *I3I 	G
A5I  G .I H5H5&I (I3)%I I H:
&H:

I I3I  H?(H?I I3I I3I A!H2,I -I3.I 1H22I 	I0I+%I0&I3+I00I3ship_numberdevice_namefaultspare_partssystem_namec                 z  K   | s|s|st        d       y	 ddlm} 	  |t        ddi      4 d	{   }|j                         4 d	{   }|j                         4 d	{   }|j                  d
| xs d|xs d|xs dt        j                  |d      |xs dt        j                         f       d	{    d	d	d	      d	{    d	d	d	      d	{    d	d	d	      d	{    t        d|  d| d| d| dt        |       
       y# t        $ r t        d       Y yw xY w7 7 7 7 x7 j# 1 d	{  7  sw Y   zxY w7 q# 1 d	{  7  sw Y   xY w7 x# 1 d	{  7  sw Y   xY w# t        $ r5}	t        dt        |	              dd	l}
|
j!                          Y d	}	~	yd	}	~	ww xY ww)u   
    保存故障记录到数据库

    Args:
        ship_number: 舷号
        device_name: 设备名称
        fault: 故障现象
        spare_parts: 备件列表
        system_name: 系统名称

    Returns:
        是否保存成功
    uB   [fault_record_db] 舷号、设备、故障均为空，跳过保存Fr   r
   u7   [fault_record_db] psycopg_pool 未安装，无法保存r   Tr   Nz
                        INSERT INTO fault_records (ship_number, device_name, fault, spare_parts, system_name, created_at)
                        VALUES (%s, %s, %s, %s, %s, %s)
                        r!   )ensure_asciiu0   [fault_record_db] 故障记录已保存: 舷号=u	   , 设备=u	   , 故障=u	   , 系统=u   , 备件数=u,   [fault_record_db] 保存故障记录失败: )r   r   r   r   r   r   r   r   r*   dumpsr   nowr#   r6   r3   	traceback	print_exc)r@   rA   rB   rC   rD   r   r   r   r   r>   rI   s              r   save_fault_recordrK      s    ( {5RS4
&& $'
 
 ((D;;==C++
 (-2'-2!KR JJ{G'-2$LLN   )= )(	
 
( 	@YWbVcclmrlss|  ~I  }J  JV  WZ  [f  Wg  Vh  i  	j5  GH

 )( )=== )(((	
 
 
 
,  <SVHEF	s3  F;D E: D-E: E%
D/E%E#D1
$E'AD7:D3
;D7?E
D5EE%EE%E: *E#+'E: F;D*'F;)D**F;-E: /E%1E3D75E7E	=E >E	EE%E 	EE 	E%#E: %E7+E.,E73E: :	F8+F3.F;3F88F;statec                   K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|s|st        d       y| j                  dd      xs | j                  dd      xs d}t        |       d	{   }d
}|rddlm}  ||       d	{   }t        |||||       d	{   S 7 67 7 w)u  
    从工作流状态中提取故障信息并记录到数据库
    在故障诊断智能体生成方案后调用

    流程：
    1. 从状态中获取舷号、设备、故障
    2. 从方案内容中用大模型抽取备件
    3. 通过设备名称反推系统
    4. 保存到数据库

    Args:
        state: 工作流状态字典

    Returns:
        是否记录成功
    r@   r!   rA   rB   u9   [fault_record_db] 设备和故障均为空，跳过记录Flast_generated_schemeresponseNu   其他r   )get_device_system_from_neo4j)r@   rA   rB   rC   rD   )getr   r?   tools.fault_statisticsrP   rK   )rL   r@   rA   rB   r   rC   rD   rP   s           r   record_fault_from_staterS      s     " ))M2.4"K))M2.4"KIIgr"(bEuIJYY6;^uyyUW?X^\^N7GGKKG8EE"   H
 Fs6   BC
CC
'C(C
?C C
C
C

start_dateend_datelimitc           
      6  K   	 ddl m} ddlm} g }g }	d}
| r"|j                  d       |	j                  |        |r"|j                  d       |	j                  |       |r"|j                  d       |	j                  |       |r9	 t	        j                  |d	      }|j                  d
       |	j                  |       |rM	 t	        j                  |d	       |d      z    |d      z
  }|j                  d       |	j                  |       |rdj                  |      nd}	  |t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }d| d}|	j                  |       |j                  ||	       d{    |j                          d{   }g d}g }|D ]  }t        t!        ||            }t#        |j%                  d      t&              r	 t)        j*                  |d         |d<   t#        |j%                  d      t              r|d   j/                         |d<   |j                  |        |cddd      d{    cddd      d{    cddd      d{    S # t        $ r t        d       g cY S w xY w# t        $ r Y w xY w# t        $ r Y w xY w7 7 ~7 h7 :7 %# t,        $ r g |d<   Y w xY w7 7 w7 h# 1 d{  7  sw Y   nxY wddd      d{  7   n# 1 d{  7  sw Y   nxY wddd      d{  7   y# 1 d{  7  sw Y   yxY w# t,        $ r7}t        dt'        |              ddl}|j3                          g cY d}~S d}~ww xY ww)ue  
    从数据库查询故障记录

    Args:
        ship_number: 舷号过滤
        device_name: 设备名称过滤
        system_name: 系统名称过滤
        start_date: 开始日期（格式：YYYY-MM-DD）
        end_date: 结束日期（格式：YYYY-MM-DD）
        limit: 返回记录数上限

    Returns:
        故障记录列表
    r   r
   u7   [fault_record_db] psycopg_pool 未安装，无法查询)	timedelta   zship_number = %szdevice_name = %szsystem_name = %sz%Y-%m-%dzcreated_at >= %s)days)secondszcreated_at <= %sz AND z1=1r   Tr   Nz
                        SELECT id, ship_number, device_name, fault, spare_parts, system_name, created_at
                        FROM fault_records
                        WHERE zg
                        ORDER BY created_at DESC
                        LIMIT %s
                    )idr@   rA   rB   rC   rD   
created_atrC   r]   u,   [fault_record_db] 查询故障记录失败: )r   r   r   r   r   rX   appendstrptime
ValueErrorjoinr   r   r   r   fetchallr1   zipr0   rQ   r3   r*   r+   r6   	isoformatrI   rJ   )r@   rA   rD   rT   rU   rV   r   rX   
conditionsparamsidxstart_dtend_dtwhere_clauser   r   r   sqlrowscolumnsresultsrowrecordr>   rI   s                            r   query_fault_recordsrq      sH    ,4
 #JF
C,.k",.k",.k"	((Z@H 02MM(# 	&&x<ya?PPS\efSggF 02MM&! 0:7<<
+uL"&& $'
 
 ((D;;==C  ,n -C MM%(++c6222!$/DwG G#!%c'3&7!8%fjj&?E;8<

6-CX8Y} 5 &fjj&>I39,3G3Q3Q3SF<0v.  $ #/ )== )((	
 
 
S  GH	6  		  		
 )( 3/ $- ;8:} 5;% ) )	

 )== )((((	
 
 
 
 
:  <SVHEF		s  NJ A:N8J* =N AJ: N"M 6K
7M :MKML(K
)L,-K3K
K31K
2AK36KA	K3L&K-
'L+M7K/8M<M K1	M NJ'$N&J''N*	J73N6J77N:	KNKN
M MLK3K3K*'K3)K**K3-L/M1M 3L9K<:LLMLML,	 L#!L,	(M/M :L=;M  NMM
MM NM 	N,NNNNN)NNNNNi  )__doc__r*   r'   asyncior   typingr   r   r   r   configr   r   r3   r?   boolrK   rS   intrq        r   <module>rz      s%  
  	   , , -'LVC# C$s) CL999 9 c	9
 9 
9x(c3h (D (X "&!%!% $"b#b#b #b 	b
 smb b 
$sCx.bry   ?$x[|
    ϱMjx                        d Z ddlZddlZddlZddlZddlmZmZ ddlmZm	Z	m
Z
mZ ddlmZ ddlZddlmZ ddlmZ ddlmZ i Zd/d	ed
ededefdZdedefdZdedee   fdZ	 	 	 	 	 d0de
e   de
e   de
e   d
e
e   dedeeee	f      fdZ	 d1de
e   deee	f   fdZe	 d1de
e   deee	f   fd       Z	 d2deeef   deeef   dede fdZ!	 	 	 	 	 	 d3dede
e   de
e   de
e   d ededeee	f   fd!Z"e	 	 	 	 d4de
e   de
e   de
e   de
e   deee	f   f
d"       Z#	 	 	 	 d5de
e   de
e   de
e   dedeee	f   f
d#Z$e	 	 	 	 d6de
e   de
e   de
e   de
e   deee	f   f
d$       Z%d%ede
e   fd&Z&d%edefd'Z'd(edeee	f   fd)Z(ddd*Z)de
e   fd+Z*	 	 	 	 d7d,e
e   de
e   de
e   dedeee	f   f
d-Z+e	 	 	 	 d7d,e
e   de
e   de
e   de
e   deee	f   f
d.       Z,y)8u   
故障类型统计工具模块
用于统计故障诊断智能体记录的故障信息
数据来源：PostgreSQL fault_records 表
    N)datetime	timedelta)DictAnyOptionalList)SequenceMatcher)tool)track_function_calls)REPAIR_FEEDBACK_CONFIG
user_inputsystem_name	thresholdreturnc                     | r|sy| j                         j                         } |j                         j                         }| |k(  ry| |v s|| v ryt        d | |      j                         }||k\  S )NFT)striplowerr	   ratio)r   r   r   
similaritys       He:\ZKYNLP\Hjunproject\project0506\wx-agent\app\tools\fault_statistics.pyfuzzy_match_systemr      sw    [!!#))+J##%++-K[ [ K:$= z;?EEGJ""    device_namec                 ^  K   | r| j                         sy| j                         j                         }|t        v r	t        |   S ddlm} |j                  d      }|j                  dd      }|j                  dd      }|j                  d	d
      }|j                  dd      }|sd}|t        |<   |S 	 | j                         |||d}	t        j                  |      4 d{   }
|
j                  ||	ddi       d{   }|j                  dk7  rd}|t        |<   |cddd      d{    S |j                         }|j                  dd      sd}|t        |<   |cddd      d{    S |j                  dg       }|rt        |t              sd}|t        |<   |cddd      d{    S |d   }t        |t              re|j                  d      xs$ |j                  d      xs |j                  d      }|r,|j                         }|t        |<   |cddd      d{    S d}|t        |<   |cddd      d{    S 7 j7 O7 &7 7 7 07 # 1 d{  7  sw Y   yxY w# t        $ r.}t        dt!        |              d}|t        |<   |cY d}~S d}~ww xY ww)ub   
    从 Neo4j 图谱中查询设备对应的系统（调用外部接口），带缓存机制
       其他r   )DEVICE_SYSTEM_CONFIGendpointtimeout      >@default_min_hops   default_max_hops   default_top_k
   )r   min_hopsmax_hopstop_kr   NContent-Typeapplication/json)jsonheaders   successFsystemsnameu   系统名称u   名称u   查询设备系统失败: )r   r   neo4j_cacheconfigr   gethttpxAsyncClientpoststatus_coder,   
isinstancelistdict	Exceptionprintstr)r   device_name_cleanr   r   r   r&   r'   r(   resultpayloadclientresponseresult_jsonr0   first_systemr   es                    r   get_device_system_from_neo4jrG   (   s     k//1#))+113K',--+#''
3H"&&y$7G#''(:A>H#''(:A>H $$_b9E)/%&1&,,.  	
 $$W55#[[');< )  H ##s*!17-. 655 #--/K??9e4!17-.# 655& "ooi4G*Wd";!17-./ 6552 #1:L,-*..v6x,:J:J>:Zx^j^n^now^x(..0F5;K 12!? 655B F-3K)*G 655 65555555J  *3q6(34)/%&	s-  B1J-4/I3 #I$I3 'III!I3 -I.I3 2J-3.I!I3 -I.I3 2J-30I#I3 /I0I3 4J-5A(II3 )I*I3 .J-/I;I3 II3 J-I3 II3 I3 I3 I3 I3 I0$I'%I0,I3 /J-0I3 3	J*<#J%J* J-%J**J-nc           	         g d}| t        |      k  r|d |  S |j                         }dd l}t        t        |      |       D ]  }|dz  dz  }d|dz  dz  z   }d|d	z  dz  z   }|j	                  |||      }d
j                  t        |d   dz        t        |d   dz        t        |d	   dz              }	|j                  |	        |S )N)z#00C2FFz#4E7CFEz#9153FFz#FFB800z#00D16Bz#FF6B6Bz#4ECDC4z#45B7D1z#FFA07Az#98D8C8z#F7DC6Fz#BB8FCEz#85C1E9z#F8B500z#00E676z#FF4081z#7C4DFFz#18FFFFz#69F0AEz#FFD740r   gQ/7?g      ?gffffff?   g?g?r!   z#{:02X}{:02X}{:02X}      )lencopycolorsysrange
hsv_to_rgbformatintappend)
rH   predefined_colorscolorsrO   ihue
saturationvaluergbcolors
             r   generate_color_paletter]   u   s     	C!"" !$$##%F3()1-$$+AES=(
q1um#!!#z59%,,AAA

 	e . Mr   ship_number
start_dateend_datelimitc                 D   K   ddl m}  || ||||       d{   S 7 w)u@   
    从数据库查询故障记录（内部共用方法）
    r   )query_fault_records)r^   r   r_   r`   ra   N)tools.fault_record_dbrc   )r^   r_   r`   r   ra   rc   s         r   _query_fault_records_from_dbre      s1      :$   s     ship_number_filterc                   K   	 t        |        d{   }|sdg dS i }d}|D ]3  }|j                  dd      }|sd}|dz  }||vrd||<   ||xx   dz  cc<   5 g }|dkD  rt        |j                               }t	        t        |            }t        ||      D 	
ci c]  \  }	}
|	|

 }}	}
|j                         D ]?  \  }}t        ||z  d	z        }|j                  |d
      }
|j                  ||d|
id       A |j                  d d       d|dS 7 c c}
}	w # t        $ r:}t        dt        |              ddl}|j                          dg dcY d}~S d}~ww xY ww)u   
    统计故障类型（从数据库读取），按系统分类计算百分比

    Args:
        ship_number_filter: 舷号过滤（可选）

    Returns:
        包含统计结果的字典
    )r^   NT)r/   faultTypeDatar   r   r   rL   d   z#6E7D91r\   )rZ   r1   	itemStylec                     | d   S )NrZ    xs    r   <lambda>z(statistics_fault_types.<locals>.<lambda>   s    1W:r   keyreverseu   [故障类型统计错误] F)re   r4   sortedkeysr]   rM   zipitemsroundrT   sortr<   r=   r>   	traceback	print_exc)rf   recordssystem_totalsvalid_countrecordr   fault_type_dataunique_systemsrV   systemr\   system_color_mapcount
percentagerF   ry   s                   r   statistics_fault_typesr      s    5
4ASTT!# 
 F **]H=K&1K-/-.k*+&!+&  ?#M$6$6$89N+C,?@FCF~W]C^_C^-&%C^_&3&9&9&;"U"EK$73#>?
(,,[)D&&''"(  '< 	!5tD ,
 	
Q U2  `(  
+CF845
 	
	
sb   E(D" D
D" E(A?D" D+A-D" E(D" D" "	E%+/E E%E( E%%E(c                 :   K   t        |        d{   }|S 7 w)u  
    故障类型统计工具（供工作流调用）
    统计故障类型，按系统分类并计算百分比

    Args:
        ship_number_filter: 舷号过滤（可选）

    Returns:
        统计结果，包含 success 和 faultTypeData 字段
    )rf   N)r   )rf   r@   s     r   fault_type_statistics_toolr      s!      *=OPPFM Qs   fault_counterfault_system_mapsimilarity_thresholdc                   K   | si i i fS t        | j                               }t        |      dk  r!| j                         |j                         i fS 	 ddlm} |j                  |       d{   }t        ||      D ci c]  \  }}||
 }}}i }	i }
i }t               }t        | j                         d d      }|D ]  \  }}||v r|j                  |       ||	|<   |j                  |d      |
|<   |D ]t  \  }}||v s||k(  r|j                  |      s"|j                  |      s4|j                  ||   ||         }||k\  sR|	|xx   |z  cc<   |j                  |       |||<   v  |	|
|fS 7 	c c}}w # t        $ rB}t        d	t!        |              | j                         |j                         i fcY d}~S d}~ww xY ww)
u.   
    使用embedding合并相似的故障
    rL   r   	OpenaiAPINc                     | d   S NrL   rl   rm   s    r   ro   z5merge_similar_faults_with_embedding.<locals>.<lambda>  s    AaDr   Trp   r   u,   Embedding合并失败，使用原始数据: )r:   rt   rM   rN   modelsAPI.model_apir   get_embeddings_batch_asyncru   setrs   rv   addr4   cosine_similarityr<   r=   r>   )r   r   r   
fault_keysr   
embeddingsrq   embfault_embedding_mapmerged_countermerged_system_mapmerge_mappingmerged_keyssorted_faults	fault_keyr   	other_keyother_countr   rF   s                       r   #merge_similar_faults_with_embeddingr      s      2rzm((*+J
:!!!#%5%:%:%<b@@)A1$??
KK
8;J
8ST8SHCsCx8STe}224.RVW -IuK'OOI&(-N9%+;+?+?	8+Ti(*7&	;+yI/E&**95:M:Q:QR[:\!*!<!<+I6+I6"J
 "%99&y1[@1#	23<i0 +8 !.. 0-??E LTD  A<SVHEF!!#%5%:%:%<b@@Asm   AGE? -E6.E? E9BE? E? ,E? 
+E? 5G6E? 9E? ?	G
7G?G
 GG

Gtop_nsystem_filteruse_embedding_mergec                 n  K   	 t        ||       d{   }|sdddg dS i }i }|D ]m  }	|	j                  dd      }
|	j                  dd      }|	j                  d	d
      }|
r|s>|rt        ||      sM|
 | }||vr
d||<   |||<   ||xx   dz  cc<   o |rAt        |      dkD  r3t	        |||       d{   \  }}}|rt        dt        |       d       t        |j                               }t        |      }t        |j                         d d      }|d|  }g }t        |d      D ]0  \  }\  }}|j                  |d
      }|j                  ||||d       2 d|||dS 7 V7 # t        $ r:}t        dt        |              ddl}|j                          dg dcY d}~S d}~ww xY ww)uY  
    统计故障发生次数（从数据库读取），按频率排序
    统计所有故障的数据，但只返回top N展示在表格中

    Args:
        top_n: 返回前 N 个高频故障（默认为 10）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        system_filter: 系统名称过滤（可选）
        use_embedding_merge: 是否使用embedding合并相似故障（默认True）
        similarity_threshold: 相似度阈值（默认0.85）

    Returns:
        包含统计结果的字典
    )r_   r`   NTr   )r/   
totalCount
totalTypeshighFreqFaultsr    faultr   r   rL   u
   合并了 u    个相似故障c                     | d   S r   rl   rm   s    r   ro   z,statistics_fault_frequency.<locals>.<lambda>  s    !r   rp   start)rankr1   r   r   u   [故障频率统计错误] F)r/   r   )re   r4   r   rM   r   r=   sumvaluesrs   rv   	enumeraterT   r<   r>   ry   rz   )r   r_   r`   r   r   r   r{   r   r   r~   r   r   r   r   r   total_counttotal_typessorted_faults_allr   high_freq_faultsr   r   rF   ry   s                           r   statistics_fault_frequencyr   9  s*    .Q
4!
 

 "$	  F **]B7KJJw+E **]H=Ke%7{%S&-w/I-+,i(.9 +)$)$# & 3}#5#9Cf $D >:M+] 
3}#5"66FGH -..01-( #=#6#6#8nVZ[ *&51(1-q(I$D$9e*..y(CK##!%	%  )J %%.	
 	
E
H>J  
+CF845 
 	
	
sb   F5E/ E*E/ F5BE/ 8E-9B0E/ )F5*E/ -E/ /	F28/F-'F2(F5-F22F5c                 H   K   t        | xs d|||       d{   }|S 7 w)u  
    故障发生次数统计工具（供工作流调用）
    统计故障发生次数，按频率排序

    Args:
        top_n: 返回前 N 个高频故障（默认为 6）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        system_filter: 系统名称过滤（可选）

    Returns:
        统计结果，包含 success 和 highFreqFaults 字段
    r%   )r   r_   r`   r   N)r   )r   r_   r`   r   r@   s        r   fault_frequency_statistics_toolr     s3     ( .kr#	 F M   " "c                 "  K   	 t        | ||       d{   }|sdddg g g ddS i }i }|D ]n  }|j                  dg       }|j                  dd	      }	|s*|D ]@  }
|
r|
j                         s|
j                         }||vr
d||<   |	||<   ||xx   d
z  cc<   B p t        |j	                               }t        |      }t        |j                         d d      }|d| }g }g }g }|D ]H  \  }}|j                  |       |j                  |j                  |d	             |j                  |       J d|||||ddS 7 -# t        $ r>}t        dt        |              ddl}|j                          dg g g ddcY d}~S d}~ww xY ww)u  
    统计备件消耗（从数据库读取）
    统计所有备件的数据，但只返回top N展示在表格中

    Args:
        ship_number_filter: 舷号过滤（可选）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        top_n: 表格中展示的前 N 个备件（默认为 5）

    Returns:
        包含统计结果的字典
    )r^   r_   r`   NTr   )
categoriesr   counter)r/   r   r   sparePartDataspare_partsr   r   rL   c                     | d   S r   rl   rm   s    r   ro   z(statistics_spare_parts.<locals>.<lambda>  s    AaDr   rp   u   [备件统计错误] F)r/   r   )re   r4   r   r   r   rM   rs   rv   rT   r<   r=   r>   ry   rz   )rf   r_   r`   r   r{   spare_part_counterspare_part_system_mapr~   r   r   partpart_keyr   r   sorted_parts_allsorted_partsr   r0   countersr   rF   ry   s                         r   statistics_spare_partsr     s    &R
4*!
 
 "$ !"		 	   "F **]B7K **]H=K#4::<::<#5534&x06A)(3"8,1, $ ( ,3356,- ""4":":"<.Z^_ (/
+OHeh'NN044XxHIOOE"  , %%(!#		
 		
w
L  
%c!fX./ 
 	
	
sO   FE EE FDE FE 	F3FFFFFc                 H   K   t        | |||xs d       d{   }|S 7 w)u  
    备件消耗统计工具（供工作流调用）
    统计备件消耗情况

    Args:
        ship_number: 舷号过滤（可选）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        top_n: 返回前 N 个备件（默认为 5）

    Returns:
        统计结果，包含 success 和 sparePartData 字段
       )rf   r_   r`   r   N)r   )r^   r_   r`   r   r@   s        r   spare_parts_statistics_toolr   *  s3     ( *&jq	 F Mr   textc                   K   | r| j                         syd|  d}	 ddlm} |j                  |d       d{   }|j                         }t	        j
                  dd	|t        j                  
      }t	        j
                  dd	|      }t	        j
                  dd	|      }t	        j                  d|t        j                        }|rUt        j                  |j                  d            }|j                  d      }|r|dk7  rt        |      j                         S y7 # t        $ r!}t        dt        |              Y d}~yd}~ww xY ww)u=   
    从文本中提取设备名称（使用大模型）
    Nu9   从以下文本中提取设备名称：

文本内容：
u(  

请识别文本中提到的具体设备名称，如：发动机、压缩机、水泵、发电机、空调机组、液压泵等。

请以JSON格式返回：
{"device": "设备名称"}

如果文本中没有提到任何设备，请返回 {"device": null}
只返回JSON，不要有其他内容。r   r   Tqueryjson_output^```json\s*r   flags^```\s*```$\{.*\}devicenullu#   大模型提取设备名称失败: )r   r   r   open_api_chat_without_thinkingresub
IGNORECASEsearchDOTALLr,   loadsgroupr4   r>   r<   r=   )r   promptr   result_text
json_matchr@   r   rF   s           r   extract_device_from_textr   H  s0     tzz|  ),F1%DD E 
 

 "'')ff^RBMMRffZ[9ffWb+6YYy+ryyA
ZZ
 0 0 34FZZ)F&F*6{((**#
&  3CF8<=s?   ED" D C$D" E D" "	E+EEEEc                 v  K   | r| j                         syd|  d}	 ddlm} |j                  |d       d{   }|j                         }t	        j
                  d	d
|t        j                        }t	        j
                  dd
|      }t	        j
                  dd
|      }t	        j                  d|t        j                        }|r?t        j                  |j                  d            }|j                  d      }g d}||v r|S y7 # t        $ r!}t        dt        |              Y d}~yd}~ww xY ww)u:   
    对反馈内容进行分类（使用大模型）
    r   u9   请对以下反馈内容进行分类。

反馈内容：
u  

分类类别（单选，选择最匹配的一个）：
1. 信息过时 - 反映文档或手册中的信息已经过时，不再适用
2. 步骤错误 - 反映操作步骤或流程存在错误
3. 步骤缺失 - 反映缺少必要的操作步骤或流程说明
4. 备件信息有误 - 反映备件型号、规格、数量等信息有误
5. 安全提示不足 - 反映缺少必要的安全警示或注意事项
6. 图示不清 - 反映图片、示意图不清晰或难以理解

请分析反馈内容，判断属于哪个类别，以JSON格式返回：
{"category": "类别名称"}

如果反馈内容不属于以上任何类别，请返回 {"category": "其他"}
只返回JSON，不要有其他内容。r   r   Tr   Nr   r   r   r   r   r   category)u   信息过时u   步骤错误u   步骤缺失u   备件信息有误u   安全提示不足u   图示不清r   u#   大模型分类反馈内容失败: )r   r   r   r   r   r   r   r   r   r,   r   r   r4   r<   r=   r>   )	r   r   r   r   r   r@   r   valid_categoriesrF   s	            r   classify_feedback_contentr   v  s*     tzz|  ),F&1%DD E 
 

 "'')ff^RBMMRffZ[9ffWb+6YYy+ryyA
ZZ
 0 0 34Fzz*-H  V++%
(  3CF8<=s?   D9D D
CD D9
D 	D6D1,D91D66D9feedback_textc                   K   | r| j                         sddddddS 	 t        |        d{   }d}|rt        |       d{   }t        |        d{   }d||dS 7 47 7 # t        $ r}dddt        |      dcY d}~S d}~ww xY ww)	u4   
    分析反馈内容并分类（主接口）
    FNr   u   反馈内容为空)r/   r   r   r   errorT)r/   r   r   )r/   r   r   r   )r   r   rG   r   r<   r>   )r   r   r   r   rF   s        r   analyze_feedback_and_classifyr     s       3 3 5 )
 	

/>>7??F2=AA  
 	
 ? @A  
 V	
 	

sh   BA' A!A' A#A' A%	A'  B!A' #A' %A' '	B
0B?B
 BB

B)token
expires_atc                  j  K   ddl } t        d   r#| j                         t        d   k  r	t        d   S t        d   }t        j                  dd      }t        j                  dd      }|r|st	        d	       y	 t        j                  d
      4 d{   }|j                  | d||d       d{   }|j                  dk7  r*t	        d|j                          	 ddd      d{    y|j                         j                  dd      }|st	        d       	 ddd      d{    y|t        d<   | j                         dz   t        d<   |cddd      d{    S 7 7 7 ~7 A7 # 1 d{  7  sw Y   yxY w# t        $ r!}t	        dt        |              Y d}~yd}~ww xY ww)uZ   
    获取维修反馈API的认证token（带缓存，避免每次请求都认证）
    r   Nr   r   urlemailr   passwordu0   [维修反馈认证错误] 未配置认证凭据r   r)   z/api/v1/auths/signin)r   r   )r,   r.   u5   [维修反馈认证错误] 登录失败，状态码: u2   [维修反馈认证错误] 响应中未找到tokeni  u   [维修反馈认证错误] )time_feedback_token_cacher   r4   r=   r5   r6   r7   r8   r,   r<   r>   )r   base_urlr   r   rB   signin_respr   rF   s           r   _get_feedback_api_tokenr     s     W%$))+8Ml8[*[$W--%e,H"&&w3E%))*b9H@A$$T22f &*01$(; !, ! K
 &&#-MkNeNeMfgh 322  $$&**7B7EJK 322 .3!'*26))+2D!,/% 322 322222(  +CF845s   A6F39F E'F E14E)5,E1!F ,E+-F 1F32.E1 F +E-,F 0F31$E1F !E/"F &F3'F )E1+F -F /F 1F7E:8F?F F3F 	F0F+&F3+F00F3sourcec           
      	  K   	 t                d{   }|sddg ddS t        d   }| d}i }| r#| j                         r| j                         |d<   t        j                  d	
      4 d{   }|j                  ||ddd| d       d{   }	|	j                  dk(  s|	j                  dk(  rIdt        d<   dt        d<   t                d{   }|r#|j                  ||ddd| d       d{   }	|	j                  dk7  r=t        d|	j                          ddg d|	j                   dcddd      d{    S |	j                         }
t        |
t              r|
}n5t        |
t              r#|
j                  d|
j                  dg             }ng }|sdddg i dcddd      d{    S d}d}|r	 t        j                  |d      }|r1	 t        j                  |d      t!        d      z   t!        d      z
  }|s|rqg }|D ]h  }t        |t              s|j                  dd      }|s)	 t        j"                  t%        |            }|r||k  rP|r||kD  rX|j'                  |       j |}t-        |      }g }t/        |d| d       D ]  \  }}t        |t              s|j                  d!d      }|j                  d"d      }|j                  d| xs d      }|j                  dd      }|j                  d#d      }d}|r0	 t%        |      }t        j"                  |      j1                  d$      }||rt3        |      nd|rt3        |      dd nd|rt3        |      nd%||rt3        |      ndd&}|j'                  |        i }|D ],  }|j                  dd%      }|j                  |d      dz   ||<   . d|t-        |      ||d'cddd      d{    S 7 7 7 d7 %7 7 7 K# t        $ r Y 7w xY w# t        $ r Y w xY w# t        t(        t*        f$ r Y 'w xY w# t        t(        t*        f$ r t3        |      }Y w xY w7 {# 1 d{  7  sw Y   yxY w# t4        $ rE}t        d(t3        |              ddl}|j9                          ddg t3        |      dcY d}~S d}~ww xY ww))u~  
    统计维修反馈数据（从外部API获取，带认证）

    Args:
        source: 来源筛选（好评/差评/反馈），可选
        start_date: 开始日期（格式：YYYY-MM-DD），可选
        end_date: 结束日期（格式：YYYY-MM-DD），可选
        top_n: 返回前 N 条记录（默认为 10）

    Returns:
        包含统计结果的字典
    NFr   u#   API认证失败，无法获取token)r/   r   feedbackDatar   r   z/api/v1/repair-feedbacks/r   r   r)   r+   zBearer )Acceptr*   Authorization)paramsr-   i  i  r   r   r.   u/   [维修反馈统计错误] API返回状态码: u   API请求失败，状态码: resultsdataT)r/   r   r   r   sourceDistributionz%Y-%m-%drL   )days)seconds
created_atr   r   titlecontent	user_namez%Y-%m-%d %H:%Mu   未知)r   r  r  r   r  r  )r/   r   r   r   r   u   [维修反馈统计错误] )r   r   r   r5   r6   r4   r8   r   r=   r,   r9   r:   r;   r   strptime
ValueErrorr   fromtimestamprS   rT   	TypeErrorOSErrorrM   r   strftimer>   r<   ry   rz   ) r   r_   r`   r   r   r   r   r   rB   rC   rD   feedback_liststart_dtend_dtfiltered_listitemraw_created_atitem_dtr   processed_dataidx	raw_titleraw_content
raw_sourceraw_user_namecreated_at_strtsprocessed_itemsource_countersrF   ry   s                                    r   statistics_repair_feedbacksr    s    $Z
-//  ">	  *%0Z89flln%||~F8$$T22f#ZZ0$6'.ug%6 (  H ##s*h.B.Bc.I15%g.67%l3577%+ZZ %&8,>/6ug->! &0 &  H ##s*GH\H\G]^_$"#$&<X=Q=Q<RS	; 322H #--/K+t, +K. +	;??6SU;V W " #"#"#$&*,] 322l HF'00ZHH %..xDyVWGXX[dmn[ooF 6 ")D%dD1 %)XXlB%?N) !"*"8"8^9L"M#((:$!g&6$%,,T2 * !.m,KN&}Ve'<AF	TdD) $" 5I"&((9b"9K!%(FLb!AJ%)XXlB%?N$(HH["$=M%'N%A!$^!4B-5-C-CB-G-P-PQa-bN
 !$3<Y"=H3{#3DS#9b5?#j/X&4;HS%7b&N #)).91 G4  N&HHXx0$2$6$6q!$<q$@q! '
  )!-0&4 .q 322! 0  3 8 # 32v " 
 " $ '	7; ! !( !+Iw? A-0-@NAM 3222@  	
+CF845V	
 	
		
s  SQ< O/Q< SAQ< .O2/Q< 2Q'O5AQ'O8$Q'8O;9>Q'7Q< O>Q< S	A!Q'*Q< 6P7Q< ;S<Q'PQ'0P1Q'>%P$#Q'$P$+Q',P$=7Q'5A"Q'/P?BQ'Q< )Q%*Q< .S/Q< 2Q< 5Q'8Q';Q'>Q< Q< 	PQ'PQ'	P!Q' P!!Q'$P<8Q';P<<Q'?Q"Q'!Q""Q'%Q< 'Q9-Q0.Q95Q< 8S9Q< <	S
:S?S
 SS

Sc                 H   K   t        | |||xs d       d{   }|S 7 w)u  
    维修反馈统计工具（供工作流调用）
    统计维修反馈情况，支持按来源和时间筛选

    Args:
        source: 来源筛选（可选），如：好评、差评、反馈
        start_date: 开始日期（格式：YYYY-MM-DD），可选
        end_date: 结束日期（格式：YYYY-MM-DD），可选
        top_n: 返回前 N 条记录（默认为 10）

    Returns:
        统计结果，包含 success 和 feedbackData 字段
    r%   )r   r_   r`   r   N)r  )r   r_   r`   r   r@   s        r   repair_feedback_statistics_toolr     s3     ( /kr	 F Mr   )g333333?)NNNNi  )N)333333?)r%   NNNTr!  )   NNN)NNNr"  )NNNr   )NNNr%   )-__doc__osr   r,   r5   r   r   typingr   r   r   r   difflibr	   asynciolangchain_core.toolsr
   utils.function_trackerr   r3   r   r2   r>   floatboolr   rG   rS   r]   re   r   r   tupler   r   r   r   r   r   r   r   r   r   r  r   rl   r   r   <module>r-     sY  
 
 	   ( , , #  % 7 )#3 #S #U #UY #$JC JC JZc d3i > "& $"!%# sm #	
  
$sCx.* )-A
 A
	#s(^A
H (, 	#s(^ ( #'9AS>9A38n9A  9A 	9Az  $"#' $"&h
h
h
 smh
 C=	h

 h
  h
 
#s(^h
V  $"#'	C= sm C=	
 
#s(^ < )- $"	e
 e
e
 sme
 	e

 
#s(^e
P !% $"	# sm C=	
 
#s(^ :+ +# +\2# 2# 2j"
s "
tCH~ "
J #'a8 (x} (X ! $"	l
SMl
l
 sml
 	l

 
#s(^l
^   $"	SM sm C=	
 
#s(^ r   x-Qo
    li                    @   sP  d Z ddl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
mZ ddlmZmZmZ ddlmZ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 ddlZddlZddlZddlmZmZ ddlmZ ddlZddlmZ ddlZddlmZ ddlm Z m!Z!m"Z"m#Z#m$Z$ ddl%m&Z& e  e d Z'e d Z(e")dZ*dZ+dZ,dZ-dZ.e&			dde/dee0 dee1 deee/ef  dee/ef f
dd Z2d!e/d"e/de1fd#d$Z3d%eee/ef  d&e/deee/ef  fd'd(Z4d)e/dee/ fd*d+Z5d,edee/ef fd-d.Z6d/ee/ef dee/ef fd0d1Z7d2eee/ef  d3eee/ef  d4eee/ef  d5eee/ef  de8f
d6d7Z9d2eee/ef  d3eee/ef  d4eee/ef  d8e/d9e/d:ee/ d5eee/ef  d;e/d<e/d=e/de/fd>d?Z:e&d;e/d<e/d=e/dee/ef fd@dAZ;dBdC Z<dDdE Z=dFdG Z>ed;e/d<e/d=e/de/fdHdIZ?e&d;e/d<e/dJe/dee/ef fdKdLZ@ed;e/d<e/dJe/de/fdMdNZAe&	O		dde/dee0 dPee0 dQee/ dee/ef f
dRdSZBedde/dTee/ de0de/fdUdVZCe			dde/dee0 dPee0 dQee/ deee/ef  f
dWdXZDedYee/ef dee/ef fdZd[ZEd\ZFd]e/de/fd^d_ZGd`e0dae0de0fdbdcZHd)e/de0fdddeZIe0e+e, e-e.fdfe/dge/dhe0die0dje0de/fdkdlZJ	m	nddfe/doe/dpe/dqe/dee/ef f
drdsZKe	dd]e/dtee/ de/fdudvZL		ddwe/dee/ dxee/ dee/ef fdydzZMe		ddwe/dee/ dxee/ de/fd{d|ZNe	}	}dd~e/de/de/dee/ef fddZOed]e/dee/ef fddZPede/dee/ef fddZQeEeCe?eAeDeLeNeOePeQg
ZReEgeCeDe?eAgeLgeNgeOgePgeQgdZSeTdkr&	 ddlZdd ZUeVeU  dS dS )uZ   
工具函数定义
包含RAG、GraphRAG、VLM、ASR、TTS等工具的function call封装
    N)Optional)Image)BytesIO)AsyncOpenAI)ListDictAny)r   AsyncGenerator)AsyncGraphDatabase)datetime)r   r   )load_dotenv)tool)	OpenaiAPI)
VLM_CONFIG
RAG_CONFIGGRAPH_SEARCH_CONFIGNEO4J_CONFIGSERVER_CONFIG)track_function_callsapi_basemodelsearch_endpointi   皙?   U   
          @querytop_kgraph_timeoutentry_nodesreturnc                    s  | r|   sdddS |   } | ||i d}|dur||d< ddd}d	}d
}d}d}	d}
t|d	 D ]}z.tjddd4 I dH }|jt||dI dH }W d  I dH  n1 I dH s^w   Y  W nC tjtjtjfy } z1|}	||k rt	d|d	  d t
|I dH  nddt| dW  Y d}~  S W Y d}~q4d}~ww |jdkrdd|j d  S | }|ddkr|dd}d|d  S |di pi }
g }t|
tr|
dg }nt|
tr|
D ]}t|tr||dg  q|s||k rt	d|d	  d t
|I dH  q4 zg }d}t|
trG|
dg |
dg |
ddd}t|}|| |
dd}nCt|
trg }|
D ]3}t|tr|dg |dg |dt|d}t|}|| |dr||d  qQd|}|D ]}|dg }|D ]	}|dd qqd|d W S  ty } zdt|dW  Y d}~S d}~ww )!   
    图谱检索工具
    F   查询文本不能为空successerror)r   r   r   r    Nr    application/json)acceptContent-Type           f@timeoutverifyjsonheadersu   图谱RAG请求超时，第 #    次重试，2秒后重新请求...   请求超时:    HTTP codemessage   未知错误datanodesu!   图谱RAG返回nodes为空，第  linksresultsr;   r=   r>   

propertiesTr%   
xxxx.graph)striprangehttpxAsyncClientpostGRAPH_SEARCH_ENDPOINTReadTimeoutConnectTimeoutRequestErrorprintasynciosleepstrstatus_coder1   get
isinstancedictlistextendapply_stylesappendjoinpop	Exception)r   r   r   r    payloadr2   max_retriesretry_delayresponselast_exceptionr:   attemptclienteresultmsgr;   item
graph_dataresults_text
graph_itempartsr=   link rl   /app/tools/function_tool.pygraph_search1   s   

($












rn   abc           	      C   s   | r|sdS t |   } t |  }| r|sdS | |kr"dS | |v s*|| v r,dS t| t|}}t||@ }t||B pBd}|| }tt| t| }tdd|tt| t|d  }d| d|  S )u   
    简单字符串相似度：综合长度差、包含关系和公共字符比例。
    0~1 之间，越大越相似。
                  ??r*         ?)rP   rD   lowersetlenabsmax)	ro   rp   set_aset_binterunionjaccardlen_difflen_penaltyrl   rl   rm   _string_similarity   s"   "r   
candidatestarget_namec                 C   s   | r|sdS d}d}| D ]2}| dpd }|s1| dpi }| dp0| dp0| dp0d}t||}||kr>|}|}q|d	krE|S dS )
u   
    在候选节点中，根据名称相似度选择最优节点。
    约定每个节点为：{id, labels, props, display_name}
    Nrq   display_namer<   propsname   名称u   设备名称333333?)rR   rD   r   )r   r   best
best_scorerf   r   r   scorerl   rl   rm   _pick_best_by_name   s   "
r   textc                 C   sL   | sg S t dt| }t }g }|D ]}||vr#|| || q|S )uV   
    从文本中抽取形如 MT007 的维修项目编号（MT + 3位数字）。
    z\bMT\d{3}\b)refindallrP   rv   addrX   )r   codesseenorderedcrl   rl   rm   _extract_mt_codes   s   

r   recordc                 C   s   t | dr
|  }n| pi }|d|dpg |dpi d|v r'|dndd}d|v r6|d|d< d	|v rA|d	|d	< d
|v rL|d
|d
< |S )u  
    将 Cypher 返回的 id/labels/props 结构统一为字典。
    约定 Cypher 中使用：
        RETURN id(n) AS id, labels(n) AS labels, properties(n) AS props, 
               <可选的 display_name>, <可选的 embedding>, <可选的 real_device_id, real_device_name>
    r:   idlabelsr   r   N)r   r   r   r   	embeddingreal_device_idreal_device_name)hasattrr:   rR   )r   r:   rd   rl   rl   rm   _node_record_to_dict   s"   


r   	node_dictc                 C   sh   |  d}|  dpi }|  dp| dp| dpt|}|  dp%g }|r,|d nd}|||d	S )
uO   将内部节点格式转为 graph_search 展示用节点：id、name、label。r   r   r   r   r   r   r   r<   )r   r   label)rR   rP   )r   nidr   r   r   r   rl   rl   rm   _to_graph_display_node  s   

r   	ship_nodedevice_nodefault_mode_noderepair_projectsc                    s   g g  t  dttttf  ffdd}ddtdtdtf fdd	}| r+||  |r=|| | r=|| d
 |d
 d |rO|| |rO||d
 |d
 d |pRg D ]}|| |re||d
 |d
 d qS fS )u   
    构建与 graph_search 一致的图谱展示结构：nodes 与 links。
    返回 (nodes: list, links: list)。
    关系：舰艇-包含->设备，设备-存在->故障模式，设备-维修时使用->维修项目。
    ndc                    s6   | r	|  dv rd S | d   t|  d S )Nr   )rR   r   rX   r   )r   )r;   seen_idsrl   rm   add_node6  s   z,_build_fault_graph_display.<locals>.add_noder<   	source_id	target_idrel_typec                    s     | ||d d S )N)sourcetargettype)rX   )r   r   r   )r=   rl   rm   add_link<  s   z,_build_fault_graph_display.<locals>.add_linkr   u   包含u   存在u   维修时使用N)r<   )rv   r   r   rP   r   )r   r   r   r   r   r   prl   )r=   r;   r   rm   _build_fault_graph_display'  s*    r   fault_reasonrepair_planmt_codesship_numberdevice_namefault_symptomc
                 C   s  d}
| r|  dp|  dpi  dpd }
d}|r.| dp+| dp&i  dp+d }d}|rE| dpB| dp=i  dpBd }d| d| d|	 dd	|
pTd
 d|pYd
 d|p^d
 dg}|rm|d|  |r|d|dd  t|dkrdnd  |r|dd| d |rg }|D ]&}| dp| dpi  dp| dpi  dpd }|r|| q|r|dd| d d|S )uK   生成与 graph_rag_search 类似的一段话，供展示与下游使用。r<   r   r   r   u   根据舷号「u   」、设备「u   」、故障现象「u   」进行图谱检索：u   定位到舰艇「u   未知u   」、设备节点「u   」、故障模式「u   」。u   故障原因：u   维修方案摘要：Ni  u   …u   涉及维修项目编号：u   、u   。   维修项目编号u   匹配到的维修项目：r@   )rR   rD   rX   rw   rY   )r   r   r   r   r   r   r   r   r   r   	ship_namedevice_name_d
fault_namerj   
proj_namesr   nmrl   rl   rm   _build_fault_graph_results_textQ  s8   &&&",:

r   c           @   
      s>  | r	t |  sdddS |rt | sdddS |r#t | s(dddS td}td}td}|r=|r=|sBdd	dS z>tj|||fd
4 I dH !}| 4 I dH }t |  }t | }	d}
|j|
|dI dH }dd |2 I dH }|sdddW  d  I dH  W  d  I dH  W S |d }|d }d}|j||dI dH }dd |2 I dH }tj	|	|dddddI dH \}}|sdd|dddW  d  I dH  W  d  I dH  W S |d }d}|j||dI dH }d d |2 I dH }|s!dd!dW  d  I dH  W  d  I dH  W S tj	||dddddI dH \}}|sSdd"|dddW  d  I dH  W  d  I dH  W S |d}|du rwdd#dW  d  I dH  W  d  I dH  W S |d$}|d%pi }|d&pd'}|d(pd'}t
|}d)} |j| |d*I dH }!d+d |!2 I dH }"g }#|r|"D ]P}$|$d%pi }%|%d,pd' r|v stfd-d.|D r|#|$ qsd/d0d |% D tfd1d.|D r|#|$ qn|"}#d2d |#D }&h d3 d4}'|j|'||||&p!d5gd6I dH }(g })|(2 zF3 dH W }*|* }+|+d},|,du rAq+|+d7pHg }-|+d8pRt |,}.|+d%pZi }% fd9d:|% D }/|)|,|.|-|/d; q+6 d<}0|j|0||||&pd5gd6I dH }1g }2|12 z23 dH W }*|* }+|+d=}3|+d>}4|3du s|4du rq|2|+d|+d?d'|3|4d@ q6 dAdB |)D fdCd|2D }2g }5|#D ]}6|6d%pi }% fdDd:|% D }7|7r|5|7 qg }8|rt | r|8t |  |5r"|5D ]}9|9dur t |9 }:|:r |8|: q|8r+dE|8};ndF};|;}<tj|<ddG}=|)|2|=dH}>t|>}>dI|>gdJW  d  I dH  W  d  I dH  W S 1 I dH sbw   Y  W d  I dH  W dS 1 I dH szw   Y  W dS  ty }? zddKt |? dW  Y d}?~?S d}?~?ww )Lr"   F   舷号不能为空r$      设备名称不能为空u   故障现象不能为空uriuserpasswordu.   Neo4j 配置不完整，请检查 NEO4J_CONFIG)authNud  
                MATCH (s:舰艇)
                WHERE s.舷号 IN [$ship_key]
                RETURN DISTINCT
                       id(s) AS id,
                       labels(s) AS labels,
                       properties(s) AS props,
                       coalesce(s.名称, s.name, s.舷号) AS display_name
                LIMIT 10
                )ship_keyc                        g | z
3 d H W }t |q6 S Nr   .0rrl   rl   rm   
<listcomp>      z3fault_graph_reason_and_projects.<locals>.<listcomp>u0   在图谱中未找到对应舷号的舰艇节点r   r   u  
                MATCH (ship:舰艇)
                WHERE id(ship) = $ship_id
                MATCH (ship)-[:包含*0..8]->(n:设备)
                WITH n, coalesce(n.名称, n.name, n.设备名称) AS nm
                WHERE nm IS NOT NULL
                RETURN DISTINCT
                       id(n) AS id,
                       labels(n) AS labels,
                       properties(n) AS props,
                       nm AS display_name,
                       n.embedding AS embedding
                LIMIT 100
                )ship_idc                    r   r   r   r   rl   rl   rm   r     r   r   r   r   ffffff?)
query_textr   name_keyembedding_keytext_weightsemantic_weightuD   在该舰艇范围内未找到匹配的设备节点（最高得分: z.3fu   ）u  
                MATCH (start_e:设备)
                WHERE id(start_e) = $device_id
                MATCH (start_e)-[:包含*0..3]-(real_e:设备)
                MATCH (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:包含故障]-(fm:故障模式)
                RETURN DISTINCT
                       id(fm) AS id,
                       labels(fm) AS labels,
                       properties(fm) AS props,
                       fm.名称 AS display_name,
                       fm.embedding AS embedding,
                       id(real_e) AS real_device_id,
                       real_e.名称 AS real_device_name
                )	device_idc                    r   r   r   r   rl   rl   rm   r     r   u0   在该设备节点下未找到故障模式节点uY   未能在故障模式节点中找到与故障现象足够匹配的节点（最高得分: u<   故障模式节点缺少 id，无法继续检索维修项目r   r   u   故障原因r<   u   维修方案uv  
                MATCH (fm:故障模式)
                WHERE id(fm) = $fault_mode_id
                OPTIONAL MATCH (fm)<-[:修理]-(p:维修项目)
                RETURN DISTINCT
                       id(p) AS id,
                       labels(p) AS labels,
                       properties(p) AS props,
                       p.名称 AS display_name
                )fault_mode_idc                    r   r   r   r   rl   rl   rm   r   
  r   r   c                 3       | ]}| v V  qd S r   rl   )r   r   )	proj_coderl   rm   	<genexpr>      z2fault_graph_reason_and_projects.<locals>.<genexpr> c                 S   s   g | ]
}|d urt |qS r   )rP   )r   vrl   rl   rm   r     s    c                 3   r   r   rl   )r   r7   )values_textrl   rm   r     r   c                 S   s$   g | ]}| d dur| d qS )r   NrR   )r   r   rl   rl   rm   r     s    >   fulltextr   
created_atlast_updatedknowledge_sourceu  
                MATCH (ship:舰艇)
                WHERE id(ship) = $ship_id
                MATCH (real_e:设备)
                WHERE id(real_e) = $real_device_id
                MATCH path0 = (ship)-[:包含*0..8]->(real_e)
                MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:包含故障]-(fm:故障模式)
                WHERE id(fm) = $fault_mode_id
                OPTIONAL MATCH (fm)<-[:修理]-(rp:维修项目)
                WHERE id(rp) IN $repair_ids
                WITH path0, path1, collect(DISTINCT rp) AS rps
                WITH nodes(path0) + nodes(path1) + rps AS ns
                UNWIND ns AS n
                WITH DISTINCT n
                WHERE n IS NOT NULL
                RETURN elementId(n) AS id,
                       labels(n) AS labels,
                       coalesce(n.名称, n.name) AS name,
                       properties(n) AS props
                )r   r   r   
repair_idsr   r   c                       i | ]\}}| vr||qS rl   rl   r   kr   exclude_keysrl   rm   
<dictcomp>R  s    z3fault_graph_reason_and_projects.<locals>.<dictcomp>)r   r   r   rA   u  
                MATCH (ship:舰艇)
                WHERE id(ship) = $ship_id
                MATCH (real_e:设备)
                WHERE id(real_e) = $real_device_id
                MATCH path0 = (ship)-[:包含*0..8]->(real_e)
                MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:包含故障]-(fm:故障模式)
                WHERE id(fm) = $fault_mode_id
                WITH relationships(path0) + relationships(path1) AS rs
                UNWIND rs AS r
                RETURN elementId(r) AS id,
                       type(r) AS label,
                       elementId(startNode(r)) AS source,
                       elementId(endNode(r)) AS target,
                       properties(r) AS props
                UNION
                MATCH (fm:故障模式)
                WHERE id(fm) = $fault_mode_id
                MATCH (fm)<-[r:修理]-(rp:维修项目)
                WHERE id(rp) IN $repair_ids
                RETURN elementId(r) AS id,
                       type(r) AS label,
                       elementId(startNode(r)) AS source,
                       elementId(endNode(r)) AS target,
                       properties(r) AS props
                r   r   r   )r   r   r   r   c                 S   s   h | ]}|d  qS r   rl   r   nrl   rl   rm   	<setcomp>  s    z2fault_graph_reason_and_projects.<locals>.<setcomp>c                    s,   g | ]}| d  v r| d v r|qS )r   r   r   )r   l)node_idsrl   rm   r     s
    c                    r   rl   rl   r   r   rl   rm   r     s    r@   u!   暂无故障信息或修复方案ensure_asciir?   TrB   u   Neo4j 查询失败: )rP   rD   r   rR   r
   driversessionrunr   hybrid_match_with_embeddingsr   anyrX   rY   valuesr:   itemsr1   dumpsrW   r[   )@r   r   r   r   r   r   r   r   r   
device_key
ship_queryship_recordsship_candidatesr   r   device_querydev_recordsdevice_candidatesr   device_scorer   fault_mode_query
fm_recordsfault_modesr   fault_scorer   r   fm_propsr   r   r   repair_project_query
rp_recordsall_projectsr   projr   r   graph_nodes_querynode_recordsnodes_gr   data_rr   r   r   props_filteredgraph_links_querylink_recordslinks_gsrctgtrepair_plans_datar   filteredrj   planplan_strcombined_textresults_objrh   ri   rc   rl   )r   r   r   r   rm   fault_graph_reason_and_projects~  s~  








6P
[

_
"













  4  7 r  c                 C   s   |  dg }|rt|dkr|d }nd}|dkr#d| d< d| d< | S |d	kr1d
| d< d| d< | S |dkr?d| d< d| d< | S |dkrMd| d< d| d< | S |dv r[d| d< d| d< | S d| d< d| d< | S )Nr   r   r<      舰艇z#F89A64colorV   size   系统z#C25C21	   子系统z#7D2D00   设备z#540802)
u   功能u   环境条件u   接口u   安全警告u   调试u   器材保障u   图册u   设计单位u   维修项目u   操作项目z#2261DF4   z#68C3FF5   rR   rw   )node	node_typerl   rl   rm   add_node_style  s6   
r)  c           	      C   s   |  d}|  d}d}d}|r(||v r(||  dg }|r(t|dkr(|d }|rB||v rB||  dg }|rBt|dkrB|d }g d}||v rT||v rTd| d< | S d	| d< | S )
Nr   r   r<   r   r   )r  r!  r"  r#  z#F59E0Br  z#FFFFFFr&  )	rk   
nodes_dictr   r   source_typetarget_typesource_labelstarget_labelshierarchy_typesrl   rl   rm   add_link_style  s$   

r0  c                 C   sP   |  dg }|  dg }dd |D }|D ]}t| q|D ]}t|| q| S )Nr;   r=   c                 S   s"   i | ]}| d r| d |qS r   r   r   rl   rl   rm   r   	  s   " z apply_styles.<locals>.<dictcomp>)rR   r)  r0  )rg   r;   r=   r*  r'  rk   rl   rl   rm   rW     s   
rW   c                    sp   t | ||dI dH }|dds|ddS |dpg }td|  |r6t|d	 tr6|d	 d
dS dS )u  
    故障诊断图谱检索工具（供工作流调用）：仅返回一段话摘要，与 graph_rag_search 一致。
    根据舷号、设备名称、故障现象在图谱中定位舰艇→设备→故障模式→维修项目，并生成文字摘要。
    工作流中用于与 RAG 结果一起作为上下文，不返回节点/关系（展示用 fault_graph_reason_and_projects）。
    r   r   r   Nr%   Fr&      检索失败rC   zRAG results: r   r>   r<   )r  rR   rM   rS   rT   )r   r   r   rd   
graph_listrl   rl   rm   fault_graph_rag_search  s   r4  operation_itemc              
      s.  | r	t |  sdddS |rt | sdddS |r#t | s(dddS td}td}|s9dddS t |  t | t | d	}zvtj|d
4 I dH ^}|j||ddidI dH }|  | }|ddsd|dddW  d  I dH  W S |dpg }	|	rt	|	D ]\}
}t
|trt||	|
< q|	|d< |W  d  I dH  W S 1 I dH sw   Y  W dS  tjy   ddd Y S  tjy   ddd Y S  tjy } zdd|jj dW  Y d}~S d}~w ty } zddt | dW  Y d}~S d}~ww )r"   Fr   r$   r   u   操作项目不能为空operation_search_endpointr   u'   操作图谱检索服务配置不完整r   r   r5  r.   Nr)   r'   r0   r%   r&   r2  rC   u   操作图谱检索服务超时u$   无法连接操作图谱检索服务u&   操作图谱检索服务返回错误: u   操作图谱检索失败: )rP   rD   r   rR   rF   rG   rH   raise_for_statusr1   	enumeraterS   rT   rW   rJ   ConnectErrorHTTPStatusErrorr_   rQ   r[   )r   r   r5  endpointr.   r\   rb   r_   rd   r3  iri   rc   rl   rl   rm   operation_graph_search_tool.  s^   	









4  r?  c                    sb   t | ||dI dH }|dds|ddS |dpg }|r/t|d tr/|d d	d
S d
S )uq  
    操作图谱检索工具（供工作流调用）：仅返回一段话摘要，与 graph_rag_search 一致。
    根据舷号、设备名称、操作项目在图谱中定位舰艇→设备→操作项目，并生成文字摘要。
    工作流中用于与 RAG 结果一起作为上下文，不返回节点/关系（展示用 operation_graph_search_tool）。
    r7  Nr%   Fr&   r2  rC   r   r>   r<   )r?  rR   rS   rT   )r   r   r5  rd   r3  rl   rl   rm   operation_graph_rag_searchi  s   r@     file_idkb_idc                    s  | r|   sdddS td }d|   i}|du r>td}|dur>zt|tr-t|n|}W n ttfy=   d}Y nw |du rUtd}|durU|durSt|nd}|dura|d	kra||d
< |durm|d	krm||d< td ttd  ttd  ttd  dtd td d}td|  d}	d}
d}d}t	|	d D ]u}z/t
jddd4 I dH }|j|||dI dH }W d  I dH  n1 I dH sw   Y  W  nD t
jt
jt
jfy } z1|}||	k rtd|d  d t|
I dH  nddt| dW  Y d}~  S W Y d}~qd}~ww z|jdkr)dd|j dW S | }|dg }dd |D }t|d d! d"d#d| }i }t|dd$D ]\}}t|ts[qO|d%}|d&}|rn|d'd	nd	}|p}|r||d(d)nd)}|d*g }|r|d+ d,d+nd+}||d-d	|d.d	|||d/d0||d
d	|r|d-d	nd	|r|d(d	nd	|d1}||vrg ||< || | qOd"|t|t|d2W S  ty } zdt|dW  Y d}~S d}~ww )3u]  
    知识库搜索工具
    调用知识库搜索API，检索与query相关的文档内容

    Args:
        query: 搜索关键词（必填）
        top_k: 返回结果数量（默认5）
        file_id: 文件ID（可选）
        kb_id: 知识库ID（可选）

    Returns:
        搜索结果，包含sourceCitation格式的数据
    Fr#   r$   r   r   Nzfile-idzkb-idr<   rB  rC  l   q{U	x-user-idzx-user-namex-roler'   )r(   rD  rE  zRAG params: r*   r+   r,   r-   )paramsr2   u   RAG请求超时，第 r3   r4   r5   r6   r>   c                 S   s    g | ]}| d ddkr|qS )r   rq   g?r   )r   rf   rl   rl   rm   r     s     zrag_search.<locals>.<listcomp>c                 S   s   |  ddS )Nr   rq   r   )xrl   rl   rm   <lambda>  s    zrag_search.<locals>.<lambda>T)keyreverse)startfilekbfilenamer   u   未分组文档	positionsr   page_idxr   contentr   rq   )indexr   r   resourcerN  r   rP  rB  rC  kb_namerO  )r%   sourceCitationtotaltotal_available)rD   r   rR   rS   rP   int
ValueError	TypeErrorrM   rE   rF   rG   rJ   rK   rL   rN   rO   rQ   r1   sortedr:  rT   rX   rw   r[   )r   r   rB  rC  
SEARCH_URLrF  config_file_idconfig_kb_idr2   r]   r^   r_   r`   ra   rb   rc   rd   r:   filtered_datasorted_datasource_citationidxrf   	file_infokb_inforN  rS  rO  rP  citation_itemrl   rl   rm   
rag_search  s   


($	






rf  entity_typec           	         s   t d|   t| |dI dH }|ddsdS |dg }|s#dS g }|D ]}t|tr;|dd}|r;|| q'|rCd	|nd}t|d
krS|dd
 d }|S )u  
    GraphRAG检索工具（异步版本）
    在知识图谱中检索与query相关的实体和关系

    Args:
        query: 检索查询
        entity_type: 实体类型过滤（如：设备、故障、维修项目）- 注意：此参数在当前实现中暂未使用
        top_k: 返回结果数量（保留参数以兼容接口）

    Returns:
        图谱检索结果文本字符串（旧格式，保持兼容）
    zgraph_rag_query+++++++++++)r   Nr%   Fr<   rC   r>   r@   i  z...)rM   rn   rR   rS   rT   rX   rY   rw   )	r   rg  r   rd   rg   results_partsri   r>   rh   rl   rl   rm   graph_rag_search6  s&   

ri  c              	      s   t | |||dI dH }|ddsg S |di }|sg S g }| D ]8\}}t|ts.q$|D ]+}	|	dd}
|
dkr=q0|	d	d
}|	dd
}|	dd
}|r[|||||
d q0q$|S )u  
    RAG检索工具（异步版本）
    在向量数据库中检索与query相关的文档片段

    Args:
        query: 检索查询
        top_k: 返回结果数量（可选，默认从配置读取）
        database_name: 数据库名称（可选，默认从配置读取）
        collection_name: 集合名称（可选，默认从配置读取）

    Returns:
        检索结果列表（旧格式，保持兼容）
    )r   rB  rC  Nr%   FrU  r   rq   g333333?r   r<   rT  rN  )r   rT  rN  r   )rf  rR   r   rS   rU   rX   )r   r   rB  rC  rd   ra  r:   resource_name	citationsr   r   r   rT  rN  rl   rl   rm   rag_search_toola  s8   
rl  	raw_inputc           	      C   s   t | tsdddddddS d}| d}|rd}d}| d}|r$d}d}| d}|r/d}d}| d	}t |trA| rAd}||||d
S )u   
    判断输入类型工具（异步版本）：严格对齐 MainAgentState 字段。
    识别：image, audio/asr, file, query (text)
    Funknownu   raw_input 必须是 dict)	has_image	has_audiohas_file	has_query
input_typer&   imageTaudio	file_textr   )ro  rp  rq  rr  )rS   rT   rR   rP   rD   )	rm  ro  img_vrp  aud_vrq  file_vrr  query_vrl   rl   rm   detect_input_type  s2   
	



r{  u  你是一个专业的工业设备巡检专家助手。
你的任务是协助工程师分析现场情况。

当你遇到以下情况时：
1. 用户提供了图片路径（如 .png, .jpg, /app/data/... 等）。
2. 用户询问有关设备外观、颜色、仪表读数或物理损坏的问题。

你应该：
- 调用 `vlm_image_to_text` 工具。
- 在 `prompt` 参数中，根据用户的具体意图（如：检查漏油、读仪表、看指示灯）量身定制分析指令。
- 获取 VLM 结果后，结合专业知识给出建议。

image_pathc                 C   sB   t | d}t| dW  d   S 1 sw   Y  dS )u&   将本地图片转换为 Base64 编码rbutf-8N)openbase64	b64encodereaddecode)r|  frl   rl   rm   encode_image  s   $r  widthheightc                 C   s0   t |d }t | d }|| d }|d S )u   
    根据 Qwen-VL 的图像分块策略估算视觉 tokens。
    公式来源：Qwen-VL 官方技术文档（Naive resizing + 192 tokens per unit）
    iP  r*      )mathceil)r  r  units_hunits_wtotal_unitsrl   rl   rm   estimate_qwen_vl_visual_tokens  s   r  c                 C   s   t d}t|| S )u;   使用 tiktoken 估算文本 token 数（兼容中英文）cl100k_base)tiktokenget_encodingrw   encode)r   encrl   rl   rm   count_text_tokens  s   
r  base64_imageprompt_textmax_input_tokensmin_sizejpeg_qualityc                 C   s  |  ds	tdz| dd\}}t|}tt|d}|j	\}	}
W n t
y: } ztd| d}~ww t|}t|	|
}|| }td|	 d	|
 d
| d| d| 
 ||kretd | S d}|}||kr|dkr|d9 }t|t|	| }t|t|
| }|t|| }||kr|dksqt|t|	| }t|t|
| }td| d	| d|  |||ftjj}t }|j|d|d t| d}d| S )ua   
    智能压缩 base64 图像，确保 (文本 tokens + 视觉 tokens) <= max_input_tokens
    
data:imagez:Invalid base64 image format. Must start with 'data:image'.,r*   RGBzFailed to decode base64 image: Nu   [VLM Preprocess] 原始尺寸: rG  u    | 文本 tokens: u    | 视觉 tokens: u    | 总计: u!   [VLM Preprocess] ✅ 无需压缩rr   g?r   u1   [VLM Preprocess] ⚠️ 需压缩 → 新尺寸: u    | 预估总 tokens: JPEG)formatqualityr~  zdata:image/jpeg;base64,)
startswithrY  splitr  	b64decoder   r  r   convertr   r[   r  r  rM   ry   rX  resize
ResamplingLANCZOSsaver  getvaluer  )r  r  r  r  r  headerb64_data
image_dataimgorig_worig_hrc   text_tokensvisual_tokenstotal_tokensscaletarget_tokensnew_wnew_hfinal_wfinal_hresized_imgbuffercompressed_b64rl   rl   rm   smart_resize_base64_image  sD   



&
r  image_inputimage_input/image_records.jsondescription
output_dirrecord_filec              
   C   s6  z|  dsdddW S | dd\}}d|v sd|v rd}nd	|v r&d	}nd
|v r-d
}n	d|v r4d}nd}tj|dd t jdd  dt 	d d| }tj
||}t|}	t|d}
|
|	 W d   n1 stw   Y  |||t  d}tjtj
|dd g }tj
|rz%t|ddd}
t|
}t|tsg }W d   n1 sw   Y  W n tjtfy   g }Y nw || t|ddd}
tj||
ddd W d   n1 sw   Y  td|  d||ddW S  ty } zdddt|dW  Y d}~S d}~ww )u  
    保存 base64 图片到指定目录，并记录图片名称和描述到 JSON 文件。
    
    Args:
        base64_image: base64 编码的图片数据（data:image/xxx;base64,... 格式）
        description: 图片的描述文本
        output_dir: 图片保存目录
        record_file: 记录 JSON 文件路径
    
    Returns:
        包含保存结果的字典：{"success": bool, "image_name": str, "image_path": str, "error": str}
    r  FzInvalid base64 image formatr$   r  r*   jpegjpgpnggifwebpT)exist_okN   _z%Y%m%d%H%M%S.wb)
image_namer|  r  	timestampr   r~  )encodingwr+   )r   indentu   [ImageSaved] 图片已保存: )r%   r  r|  r&   )r  r  osmakedirsuuiduuid4hexr   nowstrftimepathrY   r  r  r  write	isoformatdirnameexistsr1   loadrS   rU   JSONDecodeErrorIOErrorrX   dumprM   r[   rP   )r  r  r  r  r  r  extr  r|  r  r  record_entryexisting_recordsrc   rl   rl   rm   save_base64_image_and_record+  sr   
,




r  promptc              
      s  d}|r| d| n|}t | |ttt d}zFt|I dH }td|  t| |ddd}|d	 rTtd
|d   td  d|d  }| d| d}|W S td|d   |W S  t	y } zddl
}	dt| d|	  }
t|
 |
W  Y d}~S d}~ww )u   
    调用 Qwen3.5-35B 进行工业巡检分析。
    - 自动移除所有 <think>...</think> 包裹的内容（包括多行）
    - 仅返回最终结果文本
    - 支持 40K token 上下文，自动压缩大图
    ul  【重要指令】禁止输出任何形式的  <think>...<\/think>、<reasoning><\/reasoning> 或其他内部思考过程。仅输出最终的专业分析结果。

你是一位资深的工业巡检专家。请仔细观察这张图片并按以下结构报告：
1. 设备识别：图中是什么设备？型号或标签是否可见？
2. 状态评估：仪表盘数值是否在正常区间？指示灯颜色是什么？
3. 异常检测：是否存在漏油、生锈、电缆破损、螺丝松动或烟雾？
4. 环境风险：周围是否有杂物堆放或安全隐患？
请用专业、客观、简短的语言描述。u   
特别注意：)r  r  r  Nu   ✅ 最终输出:
picturezpicture/image_records.json)r  r  r  r  r%   u   📷 图片已保存: r  base_urlz	/picture/u   

![用户上传图片]()u   ⚠️ 图片保存失败: r&   r   u   VLM 调用失败: r@   )r  rX  MAX_MODEL_LENINPUT_TOKEN_SAFETY_RATIOr   open_api_vl_without_thinkingrM   r  r   r[   	tracebackrP   
format_exc)r|  r  default_promptfinal_prompt
safe_imagerd   save_result	image_urlrc   r  	error_msgrl   rl   rm   vlm_image_to_text  s@   
r  
audio_pathlanguagec              
      s  ddl m} tj| sdd|  ddS |d }|p|d }|p%|d	 }|d
 }| d}zt| d}	|	 }
W d   n1 sDw   Y  dtj| |
dfi}||d}tj	|d4 I dH I}|j
|||dI dH }|jdkr| }|dd}d|r|ndddW  d  I dH  W S dd|j d|j ddW  d  I dH  W S 1 I dH sw   Y  W dS  ty } zdt|ddW  Y d}~S d}~ww )u  
    ASR语音转文本工具（异步实现）
    将音频文件转换为文本内容

    Args:
        audio_path: 音频文件路径（如：audio/test.wav）
        model: ASR模型名称（可选，默认从配置读取，如"base"）
        language: 语言代码（可选，默认从配置读取，如"zh"表示中文）

    Returns:
        包含success和text字段的字典
    r   )
ASR_CONFIGFu   音频文件不存在: r<   )r%   r&   r   r   r   r  r.   z/audio/transcriptionsr}  NrL  z	audio/wav)r   r  r8  )filesr:   r5   r   T)r%   r   r&   r6   : )configr  r  r  r  r  r  basenamerF   rG   rH   rQ   r1   rR   r   r[   rP   )r  r   r  r  r   	asr_modelasr_languager.   api_endpointr  
audio_datar  r:   rb   r_   rd   r   rc   rl   rl   rm   asr_audio_to_text_async  s^   



4r  c                    sN   t | ||I dH }|dds|dd}d| S |dd}|r%|S d	S )
u  
    ASR语音转文本工具（异步版本）
    将音频文件转换为文本内容

    Args:
        audio_path: 音频文件路径（如：audio/test.wav）
        model: ASR模型名称（可选，默认从配置读取，如"base"）
        language: 语言代码（可选，默认从配置读取，如"zh"表示中文）

    Returns:
        识别出的文本内容
    Nr%   Fr&   r9   u   ASR 调用失败: r   r<   u   识别结果为空)r  rR   )r  r   r  rd   r&   r   rl   rl   rm   asr_audio_to_textj  s   
r   r<   
user_inputrag_textgraph_rag_textc              
      s  | r|   sdddddS t|trUg }|D ]7}t|trD|dd}|r+|| |dd}|dd}|rC|| d	|  qt|trN|| qd
|}n	t|ts^t|}t|trg }|D ]?}t|tr|dd}|dd}|di }	|r|| d	|  |	r|dtj	|	dd  qgt|tr|| qgd
|}n	t|tst|}d|  d|r|nd d|r|nd d}
zt
j|
dddI dH }|sdddddW S |  }tjdd|tjd}tdd|}td|tj}|std|tj}|r|d}n|}z0t|}|d}|d}|dks-|du r/d}|dks9|du r;d}||dddW W S  tjy } z`td|tjtjB }td |tjtjB }d}d}|r|d!}|r~| d"vr{|nd}nd}|r|d!}|r| d"vr|nd}nd}||dd#t| d$dW  Y d}~W S d}~ww  ty } zdddd%t| dW  Y d}~S d}~ww )&u  
    从用户输入、RAG结果和图谱RAG结果中识别设备和故障（异步版本）

    综合以下三部分信息：
    1. 用户原始问题
    2. 检索到的维修知识（RAG）
    3. 检索到的设备-故障图谱信息（Graph RAG）

    从中选择最符合用户当前描述的单一设备和单一故障现象。

    Args:
        user_input: 用户原始问题（必填）
        rag_text: RAG检索结果，可以是字符串或列表（可选，默认为空字符串）
        graph_rag_text: 图谱RAG检索结果，可以是字符串或列表（可选，默认为空字符串）

    Returns:
        包含以下字段的字典：
            - device: str, 识别出的设备名称（如"空调"），如果无法识别则为null
            - fault: str, 识别出的故障现象（如"不制冷"），如果无法识别则为null
            - success: bool, 是否成功识别
            - error: str, 错误信息（如果有）
    NFu   用户输入不能为空)devicefaultr%   r&   r   r<   entityrg  r  r@   rA   u   属性: r   u  你是一个专业的维修诊断助手。请综合以下三部分信息：
1. 用户原始问题（可能包含文本描述和图片描述）
2. 检索到的维修知识（RAG）
3. 检索到的设备-故障图谱信息（Graph RAG）

从中**选择最符合用户当前描述的单一设备和单一故障现象**。
必须满足：
- 只选一个设备（如"空调"），不要列表
- 只选一个故障（如"不制冷"），不要多个
- 如果信息不足或无法判断，对应字段用 null
- 输出必须是合法 JSON，且仅包含这两个字段
- 使用中文简体，保留原始关键词（如"打不开"而非"无法启动"）
- 注意：用户问题可能包含图片描述，要从图片描述中识别设备和故障现象

输入：
【用户问题】u   
【RAG结果】u   无u   
【图谱结果】u[   

请输出最相关的设备和故障（JSON格式）：
{"device": "...", "fault": "..."}T)r   json_outputu'   大模型API调用失败，返回为空z
```json\s*)flagsz```\s*z?\{[^{}]*(?:"device"[^{}]*"fault"|"fault"[^{}]*"device")[^{}]*\}z\{.*"device".*"fault".*\}r   r  r  nullz3"device"\s*:\s*"([^"]*)"|"device"\s*:\s*(null|None)z1"fault"\s*:\s*"([^"]*)"|"fault"\s*:\s*(null|None)r*   )r	  noner<   u   JSON解析警告: u   ，已尝试提取字段u   识别过程出错: )rD   rS   rU   rT   rR   rX   rP   rY   r1   r   r   open_api_chat_without_thinkingr   sub
IGNORECASEsearchDOTALLgrouploadsr  ru   r[   )r  r  r  rag_text_partsrf   r   r  rg  graph_text_partsrA   r  r_   
json_matchjson_strrd   r  r  rc   device_matchfault_matchdevice_valuefault_valuerl   rl   rm   extract_device_and_fault  s   




















'r  c              
      s   zOt | ddI dH   r drdddW S d}g d}t fd	d
|D r-d}g d}t fdd
|D r>d}t dk rKtd|d } |dW S  tyg } zdddW  Y d}~S d}~ww )u  
    图片RAG描述工具（包含准确度评估，异步版本）
    给定一个图片，返回图片的描述和识别准确度

    Args:
        image_path: 图片路径

    Returns:
        包含描述和准确度的字典：{"description": "...", "accuracy": 0.0-1.0}
    N)r|  r  u   VLM 调用失败r<   rq   )r  accuracyr   )	r#  u   主机u   泵u   电机u   仪表u   阀门u   管道u   冷却u   加热c                 3   r   r   rl   r   keywordr  rl   rm   r   n  r   z%image_rag_describe.<locals>.<genexpr>g333333?)u   故障u   异常u   报警u   损坏u   漏u   异响u   温度u   压力c                 3   r   r   rl   r  r  rl   rm   r   s  r   rs   2   rt   g?)r  ainvoker  r   rw   ry   r[   )r|  r  device_keywordsfault_keywordsrc   rl   r  rm   image_rag_describeO  s8   r#  	file_pathc                 C   s   dS )u   
    文件转文本
    Nrl   )r$  rl   rl   rm   file_to_text  s   r%  )input_detectionragvlmasr
extraction	image_ragfile_process__main__c                     sb   d} d}d}t d t| ||dI d H }t d| t d t| ||dI d H }t d| d S )	N163u   机座与机架组件u0   机座与机架组件润滑油消耗异常增加u0   ==== 测试 fault_graph_reason_and_projects ====r1  zfull_result:u=   
==== 测试 fault_graph_rag_search（仅文本摘要） ====ztext_result:)rM   r  r4  r   )r   r   r   full_resulttext_resultrl   rl   rm   _test_fault_graph  s&   

r1  )r   r   N)rA  NN)Nr   )NNN)r  r  r   )NN)r<   r<   )W__doc__r   r  typingr   PILr   ior   r  openair   r   r   r   r	   neo4jr
   r  r  r  r   rN   r1   rF   dotenvr   langchain_core.toolsr   r  modelsAPI.model_apir   r   r   r   r   r   utils.function_trackerr   VLM_API_BASEVLM_MODEL_NAMErR   rI   r  r  MIN_IMAGE_SIZEJPEG_QUALITYrP   rX  floatrn   r   r   r   r   r   tupler   r   r  r)  r0  rW   r4  r?  r@  rf  ri  rl  r{  SYSTEM_PROMPT_VLMr  r  r  r  r  r  r  r   r  r#  r%  	ALL_TOOLSTOOL_CATEGORIES__name__r1  r   rl   rl   rl   rm   <module>   s,   

 ."
*	

-
  Q
:-
 "*:$2

	
;

W 

Q
 G:

xi
    ϱMj                        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mZm	Z	m
Z
 ddlmZ ddlmZ ddlmZmZ ddlmZ ddlmZ  e        d	d
lmZmZmZ d	dlmZmZ d	dlmZmZ d	dl m!Z!m"Z"m#Z# edee$e	f   dee$e	f   fd       Z%	 	 dde$dee$   dee$   dee$e	f   fdZ&e	 	 dde$dee$   dee$   de$fd       Z'ede$dee$e	f   fd       Z(e%eeeeee'e(eee!e"e#gZ)e%geeeegege'ge(gegege!e"e#gdZ*y)uZ   
工具函数定义
包含RAG、GraphRAG、VLM、ASR、TTS等工具的function call封装
    N)OptionalDictAnyList)tool)load_dotenv)
RAG_CONFIG
ASR_CONFIG)	OpenaiAPI)track_function_calls   )graph_rag_searchfault_graph_rag_searchoperation_graph_rag_search)rag_search_toolfile_to_text_tool)vlm_image_to_textimage_rag_describe)fault_type_statistics_toolfault_frequency_statistics_toolspare_parts_statistics_tool	raw_inputreturnc                 6   t        | t              s	dddddddS d}| j                  d      }|rd}d}| j                  d      }|rd}d}| j                  d      }|rd}d}| j                  d	      }t        |t              r|j	                         rd}||||d
S )u   
    判断输入类型工具（异步版本）：严格对齐 MainAgentState 字段。
    识别：image, audio/asr, file, query (text)
    Funknownu   raw_input 必须是 dict)	has_image	has_audiohas_file	has_query
input_typeerrorimageTaudio	file_textquery)r   r   r   r   )
isinstancedictgetstrstrip)	r   r   img_vr   aud_vr   file_vr   query_vs	            Ee:\ZKYNLP\Hjunproject\project0506\wx-agent\app\tools\function_tool.pydetect_input_typer0   *   s     i&UTY#.H
 	

 IMM'"E	IMM'"E	H]];'FImmG$G'3GMMO	 	     
audio_pathmodellanguagec                 >  K   t         j                  j                  |       s	dd|  ddS t        d   }|xs	 t        d   }|xs	 t        d   }t        d   }| d	}	 t	        | d
      5 }|j                         }	ddd       dt         j                  j                  |       	dfi}
||d}t        j                  |      4 d{   }|j                  ||
|       d{   }ddd      d{    j                  dk(  r,|j                         }|j                  dd      }d|r|ndddS dd|j                   d|j                   ddS # 1 sw Y   xY w7 7 }7 o# 1 d{  7  sw Y   xY w# t        $ r}dt        |      ddcY d}~S d}~ww xY ww)u  
    ASR语音转文本工具（异步实现）
    将音频文件转换为文本内容

    Args:
        audio_path: 音频文件路径（如：audio/test.wav）
        model: ASR模型名称（可选，默认从配置读取，如"base"）
        language: 语言代码（可选，默认从配置读取，如"zh"表示中文）

    Returns:
        包含success和text字段的字典
    Fu   音频文件不存在:  )successr!   textapi_baser3   r4   timeoutz/audio/transcriptionsrbNfilez	audio/wav)r3   r4   )r:   )filesdata   r8   T)r7   r8   r!   zHTTP z: )ospathexistsr
   openreadbasenamehttpxAsyncClientpoststatus_codejsonr(   r8   	Exceptionr)   )r2   r3   r4   r9   	asr_modelasr_languager:   api_endpointf
audio_datar=   r>   clientresponseresultr8   es                    r/   asr_audio_to_text_asyncrU   S   s    " 77>>*%.zl;
 	
 *%H,G,I5z*5L#GZ45L#
*d#qJ $ RWW%%j1:{K
 $

 $$W55#[[U[NNH 65 3&]]_F::fb)D $"  ! !5!5 6bH / $# 6N 6555$  
V
 	

s   AFE8 )E:AE8 EE8 	E#!E"E#&E8 1E!2>E8 0F1E8 FEE8 E#!E8 #E5)E,*E51E8 8	FFFFFFc                    K   t        | ||       d{   }|j                  dd      sd|j                  dd       S |j                  dd      S 7 =w)	u  
    ASR语音转文本工具（异步版本）
    将音频文件转换为文本内容

    Args:
        audio_path: 音频文件路径（如：audio/test.wav）
        model: ASR模型名称（可选，默认从配置读取，如"base"）
        language: 语言代码（可选，默认从配置读取，如"zh"表示中文）

    Returns:
        识别出的文本内容
    Nr7   Fu   语音识别失败: r!   u   未知错误r8   r6   )rU   r(   )r2   r3   r4   rS   s       r/   asr_audio_to_textrW      sW     $ +:uhGGF::i'%fjj.&I%JKK::fb!! Hs   AA>Ar%   c                   K   | r| j                         sdddS d|  d}	 t        j                  |d       d{   }|j                         }t        j                  dd|t        j
                  	      }t        j                  d
d|      }t        j                  dd|      }t        j                  d|t        j                        }|rIt        j                  |j                  d            }|j                  dd      |j                  dd      dS dddS 7 # t        $ r&}t        dt        |              dddcY d}~S d}~ww xY ww)u   
    从用户查询中提取设备名称和故障现象（使用大模型）

    Args:
        query: 用户查询文本

    Returns:
        包含device和fault字段的字典
    r6   )devicefaultuF   从以下用户查询中提取设备名称和故障现象：
查询：u~   

请以JSON格式返回：
{"device": "设备名称", "fault": "故障现象"}

如果无法提取，请返回空字符串。T)r%   json_outputNz^```json\s*)flagsz^```\s*z```$z\{.*\}r   rY   rZ   u   提取设备和故障失败: )r*   r   open_api_chat_without_thinkingresub
IGNORECASEsearchDOTALLrJ   loadsgroupr(   rK   printr)   )r%   promptresult_text
json_matchrS   rT   s         r/   extract_device_and_faultri      s:     r**

 .1F+%DD
 

 "'')ff^RBMMRffZ[9ffWb+6YYy+ryyA
ZZ
 0 0 34F **Xr2GR0 
 r**%
(  +-c!fX67r**+sQ   ED DCD ED ED 	E%E EEEE)input_detectionragvlmasr
extraction	image_ragfile_process
statistics)NN)+__doc__r@   rJ   r^   rF   asynciotypingr   r   r   r   langchain_core.toolsr   dotenvr   configr	   r
   modelsAPI.model_apir   utils.function_trackerr   graph_toolsr   r   r   	rag_toolsr   r   	vlm_toolsr   r   fault_statisticsr   r   r   r)   r0   rU   rW   ri   	ALL_TOOLSTOOL_CATEGORIES r1   r/   <module>r      s  
 
  	   , , %  ) ) 7  

 w v %c3h %DcN % %T  "B
B
C=B
 smB
 
#s(^	B
J   """C=" sm" 		" "2 ,+# ,+$sCx. ,+ ,+b #	$ **o/EGab+,$%&'-/NPkl	r1   x_?
    ϱMj                     0   d Z ddlZddlZddlZddlZddlmZmZmZm	Z	 ddl
mZ ddlmZ ddlmZmZmZ ddlmZ ddlmZ  ej,                  d	      Ze	 	 	 	 	 	 dAd
edee   dee   dee   dee   dee   dee   deeef   fd       ZdededefdZde	eeef      dedeeeef      fdZdede	e   fdZdedeeef   fdZ deeef   deeef   fdZ!deeeef      d eeeef      d!eeeef      d"e	eeef      de"f
d#Z#deeeef      d eeeef      d!eeeef      d$ed%ed&e	e   d"e	eeef      d'ed(ed)edefd*Z$e	 	 	 dBd'ee   d(ed)edeeef   fd+       Z%d, Z&d- Z'd.e	eeef      fd/Z(d0 Z)e	 	 	 dBd'ee   d(ed)edefd1       Z*ed'ed(ed2edeeef   fd3       Z+ed'ed(ed2edefd4       Z,edCd
ed5ee   dedefd6       Z-	 	 dDd7e	e   ded8edeeef   fd9Z.d:eeef   defd;Z/	 	 	 	 dEd<e	eeef      d(ed2ed=ed>ede	e   fd?Z0dedefd@Z1y)Fu`   
图谱检索工具模块
包含图谱搜索、故障图谱检索、操作图谱检索等功能
    N)OptionalDictAnyList)AsyncGraphDatabase)tool)ATLAS_CONFIGGRAPH_SEARCH_CONFIGNEO4J_CONFIG)	OpenaiAPI)track_function_callssearch_endpointquerytop_k
use_rerankfulltext_top_krerank_top_khopsverbosereturnc           	        K   | r| j                         sdddS | j                         } | ||||||d}ddd}	 t        j                  dd      4 d	{   }	|	j                  t        ||
       d	{   }
d	d	d	      d	{    
j                  dk7  rdd|
j                   dS |
j                         }|j                  d      dk7  r|j                  dd      }d|dS |j                  di       xs i }	 g }d}t        |t              r|j                  dg       }t        |       |D ]  }t        |t              s|j                  di       xs |j                  di       }|j                  d|j                  dd            }|j                  dd	       |j                  dd	       |sd|i|d<    ||j                  dg       d}t!        |      }|j#                  |       |j                  dd      }nAt        |t$              r0g }|D ]  }t        |t              s|j                  dg       }t        |       |D ]  }t        |t              s|j                  di       xs |j                  di       }|j                  d|j                  dd            }|j                  dd	       |j                  dd	       |sd|i|d<    ||j                  dg       d}t!        |      }|j#                  |       |j                  d      s|j#                  |d           dj'                  |      }|D ]-  }|j                  dg       }|D ]  }|j                  dd	        / d||dS 7 %7 7 # 1 d	{  7  sw Y   xY w# t        j
                  t        j                  t        j                  f$ r}ddt        |       dcY d	}~S d	}~ww xY w# t(        $ r}dt        |      dcY d	}~S d	}~ww xY ww)   
    图谱检索工具
    Fu   查询文本不能为空successerror)r   r   r   r   r   r   r   application/jsonacceptContent-Typeg     f@)timeoutverifyNjsonheadersu   请求超时:    HTTP codemessageu   未知错误data nodes
propertiesprops   名称namelinksr+   r0   results
Tr   
xxxx.graphr2   )striphttpxAsyncClientpostGRAPH_SEARCH_ENDPOINTReadTimeoutConnectTimeoutRequestErrorstrstatus_coder#   get
isinstancedict_filter_searchable_labelspopapply_stylesappendlistjoin	Exception)r   r   r   r   r   r   r   payloadr$   clientresponseeresultmsgr)   
graph_dataresults_text	raw_nodesnoder-   
name_value
graph_itempartsitemr0   links                             Ce:\ZKYNLP\Hjunproject\project0506\wx-agent\app\tools\graph_tools.pygraph_searchrZ      s      +EFFKKME  ($G %*G
F$$U5AAV#[[)>WV][^^H BA
 s" U83G3G2H+IJJ]]_Fzz&S jjN3 3//::fb!'RD<3
dD!"-I%i0!dD) HH\26O$((7B:OE!&8UYYvr5J!KJHH\40HHWd+!.6
-C\* " #'2.J &j1Jj)88Ir2Ld#EdD) $" 5I-i8 )%dD1$(HH\2$>$W$((7TVBWE).8UYYvr=R)SJ HH\48 HHWd3)6>
5K\ 2 !* "+!%'2!6"J ".j!9J%%j1xx	*T)_5) *  99U+L$JNN7B/Et,  % $#
 	
I B^ BAAAu33U5G5GH F ^CF8+DEEFP  3 3q6223s   7PN M:N N5M=6N:N N N 
A2P=AO) A.O) 3A7O) +2O) A.O) AO) AO) 9P:N =N N N	N
NN 2O&O!O&P!O&&P)	P
2P?P
 PP

Pabc                    | r|syt        |       j                         j                         } t        |      j                         j                         }| r|sy| |k(  ry| |v s|| v ryt        |       t        |      }}t	        ||z        }t	        ||z        xs d}||z  }t        t	        |       t	        |      z
        }t        dd|t        t	        |       t	        |      d      z  z
        }d|z  d|z  z   S )u   
    简单字符串相似度：综合长度差、包含关系和公共字符比例。
    0~1 之间，越大越相似。
            g      ?g?   g      ?)r>   r6   lowersetlenabsmax)	r[   r\   set_aset_binterunionjaccardlen_difflen_penaltys	            rY   _string_similarityrl      s    
 AAAAAAAvAvaq63q65EE#!EemG3q6CF?#Hc3CAA,B!BBCK=3,,,    
candidatestarget_namec                 J   | r|syd}d}| D ]  }|j                  d      xs dj                         }|sP|j                  d      xs i }|j                  d      xs( |j                  d      xs |j                  d      xs d}t        ||      }||kD  s|}|} |d	k\  r|S dS )
u   
    在候选节点中，根据名称相似度选择最优节点。
    约定每个节点为：{id, labels, props, display_name}
    Nr^   display_namer*   r-   r/   r.   u   设备名称333333?)r@   r6   rl   )rn   ro   best
best_scorerW   r/   r-   scores           rY   _pick_best_by_namerv      s    
 [DJ(.B557HHW%+E99V$^		((;^uyy?X^\^D";5:JD  $4.$.rm   textc                     | sg S t        j                  dt        |             }t               }g }|D ])  }||vs|j	                  |       |j                  |       + |S )uV   
    从文本中抽取形如 MT007 的维修项目编号（MT + 3位数字）。
    z\bMT\d{3}\b)refindallr>   ra   addrF   )rw   codesseenorderedcs        rY   _extract_mt_codesr      s[     	JJ~s4y1E5DGD=HHQKNN1  Nrm   recordc                 ~   t        | d      r| j                         }n| xs i }|j                  d      |j                  d      xs g |j                  d      xs i d|v r|j                  d      ndd}d|v r|j                  d      |d<   d	|v r|j                  d	      |d	<   d
|v r|j                  d
      |d
<   |S )uG   
    将 Cypher 返回的 id/labels/props 结构统一为字典。
    r)   idlabelsr-   rq   N)r   r   r-   rq   	embeddingreal_device_idreal_device_name)hasattrr)   r@   )r   r)   rN   s      rY   _node_record_to_dictr      s     vv{{}|hhtn((8$*'"(bT! 0F d"hh{3{4#'88,<#= T!%)XX.@%A!"Mrm   	node_dictc                 N   | j                  d      }| j                  d      xs i }| j                  d      xs1 |j                  d      xs |j                  d      xs t        |      }| j                  d      xs g D cg c]
  }|dk7  s	| }}|r|d   nd	}|||d
S c c}w )uO   将内部节点格式转为 graph_search 展示用节点：id、name、label。r   r-   rq   r.   r/   r   
Searchabler   r*   )r   r/   label)r@   r>   )r   nidr-   r/   lr   r   s          rY   _to_graph_display_noder      s    
--
CMM'"(bEn% 	99X	99V	 s8	 	 $--17R7N7AA<Ma7FNF1IREte44 Os   
B"B"	ship_nodedevice_nodefault_mode_noderepair_projectsc                 p  	 g g t               	dt        t        t        t        f      f	fd}ddt        dt        dt        ffd}| r ||        |r ||       | r || d   |d   d       |r ||       |r ||d   |d   d	       |xs g D ]  } ||       |s ||d   |d   d
        fS )uQ   
    构建与 graph_search 一致的图谱展示结构：nodes 与 links。
    ndc                     | r| j                  d      v ry j                  | d          j                  t        |              y )Nr   )r@   r{   rF   r   )r   r+   seen_idss    rY   add_nodez,_build_fault_graph_display.<locals>.add_node   s:    RVVD\X-RX+B/0rm   	source_id	target_idrel_typec                 0    j                  | ||d       y )N)sourcetargettype)rF   )r   r   r   r0   s      rY   add_linkz,_build_fault_graph_display.<locals>.add_link  s    	YQRrm   r   u   包含u   存在u   维修时使用)r*   )ra   r   r   r>   r   )
r   r   r   r   r   r   pr0   r+   r   s
          @@@rY   _build_fault_graph_displayr      s     #%E"$EuH1Xd38n- 1SC SC S3 S Yt_k$&7B![&(=xH""[&$1BC #
 %<rm   fault_reasonrepair_planmt_codesship_numberdevice_namefault_symptomc
                 p   d}
| rI| j                  d      xs( | j                  d      xs i j                  d      xs dj                         }
d}|rI|j                  d      xs( |j                  d      xs i j                  d      xs dj                         }d}|rI|j                  d      xs( |j                  d      xs i j                  d      xs dj                         }d| d| d|	 dd	|
xs d
 d|xs d
 d|xs d
 dg}|r|j                  d|        |r)|j                  d|dd  t        |      dkD  rdnd        |r$|j                  ddj	                  |       d       |rg }|D ]  }|j                  d      xsN |j                  d      xs i j                  d      xs( |j                  d      xs i j                  d      xs dj                         }|su|j                  |        |r$|j                  ddj	                  |       d       dj	                  |      S )uK   生成与 graph_rag_search 类似的一段话，供展示与下游使用。r*   rq   r-   r.   u   根据舷号「u   」、设备「u   」、故障现象「u   」进行图谱检索：u   定位到舰艇「u   未知u   」、设备节点「u   」、故障模式「u   」。u   故障原因：u   维修方案摘要：Ni  u   …u   涉及维修项目编号：u   、u   。   维修项目编号u   匹配到的维修项目：r3   )r@   r6   rF   rb   rH   )r   r   r   r   r   r   r   r   r   r   	ship_namedevice_name_d
fault_namerV   
proj_namesr   nms                    rY   _build_fault_graph_results_textr     s    I]]>2hy}}W7M7SQS6X6XYa6bhfhooq	M$8p[__W=U=[Y[<`<`ai<jpnpwwyJ%)).9uo>Q>QRY>Z>`^`=e=efn=ousu||~
 +ok]BWXeWff~
Y2(33HIbZbHccx  zD  zP  HP  yQ  QW  	XE |n56,[#->,?[IY\_I_eg?hij25::h3G2HLM
 A%%'  JAEE'N,@b+E+Eh+O  JTUTYTYZaTbThfhSmSm  oC  TD  J  HJ  Q  Q  SB!!"% ! LL6uzz*7M6NcRS99Urm   c                   GHK   |rt        |      j                         sdddS |rt        |      j                         sdddS t        j                  d      }t        j                  d      }t        j                  d      }|r|r|sdddS 	 t	        j
                  |||f	      4 d
{   }|j                         4 d
{   }t        |      j                         }d
}	d
}
| rjt        |       j                         rQt        |       j                         }d}|j                  ||       d
{   }|2 cg c3 d
{   }t        |      |	d}|j                  ||	       d
{   }nd}|j                  |       d
{   }|2 cg c3 d
{   }t        |      7 7 7 y7 l6 nc c}w }}|sj|d   }
|
d   }	u7 Z7 @7 36 nc c}w }}|s)dddcd
d
d
      d
{  7   cd
d
d
      d
{  7   S t        j                  ||dddd       d
{  7  \  }}|s.dd|dddcd
d
d
      d
{  7   cd
d
d
      d
{  7   S |d   }d}|j                  ||       d
{  7  }|2 cg c3 d
{  7  }t        |      6 nc c}w }}|s)dddcd
d
d
      d
{  7   cd
d
d
      d
{  7   S t        j                  ||dddd       d
{  7  \  }}|s.dd|dddcd
d
d
      d
{  7   cd
d
d
      d
{  7   S |j                  d      }|)dddcd
d
d
      d
{  7   cd
d
d
      d
{  7   S |j                  d       }|j                  d!      xs i }|j                  d"      xs d#}|j                  d$      xs d#}t        |      } d%}!|j                  |!|&       d
{  7  }"|"2 cg c3 d
{  7  }t        |      6 nc c}w }#}g }$| r|#D ]  }%|%j                  d!      xs i }&|&j                  d'      xs d#j                         GGr*G| v st        Gfd(| D              r|$j                  |%       gGrjd)j                  |&j                         D 'cg c]  }'|'t        |'       nc c}'w c}'      Ht        Hfd*| D              s|$j                  |%        n|#}$|$D (cg c]%  }(|(j                  d      |(j                  d      ' nc c}(w })}(h d+}*|	'd,}+|j                  |+|	|||)xs d-g.       d
{  7  },n%d/}+|j                  |+|||)xs d-g0       d
{  7  },g }-|,2 3 d
{  7  }|j!                         }.|.j                  d      }/|/.|.j                  d1      xs g }0|0D 1cg c]
  }1|1d2k7  s	|1 nc c}1w }0}1|.j                  d3      xs t        |/      }2|.j                  d!      xs i }&|&j                  d4|&j                  d3d#            }3|3rd4|3ini }4|-j                  |/|2|0|4d5       6 |	'd6}5|j                  |5|	|||)xs d-g.       d
{  7  }6n%d7}5|j                  |5|||)xs d-g0       d
{  7  }6g }7|62 3 d
{  7  }|j!                         }.|.j                  d8      }8|.j                  d9      }9|8|9A|7j                  |.j                  d      |.j                  d:d#      |8|9d;       w6 |-D :ch c]  }:|:d   	 nc c}:w };}:|7D 1cg c]*  }1|1j                  d8      |;v r|1j                  d9      |;v r|1, nc c}1w }7}1g }<|$D ]Z  }(|(j                  d!      xs i }&|&j#                         D ='ci c]  \  }=}'|=|*vs|=|' nc c}'}=w }>}=}'|>sJ|<j                  |>       \ g }?|rAt        |      j                         r(|?j                  t        |      j                                |<r7|<D ]2  }@|@t        @      j                         }A|As"|?j                  A       4 |?rd<j                  |?      }Bnd=}BB}Ct%        j&                  |Cd>      }D|-|7d?}Et)        |E      }Ed@|Eg|DdAcd
d
d
      d
{  7   cd
d
d
      d
{  7   S # 1 d
{  7  sw Y   nxY wd
d
d
      d
{  7   y
# 1 d
{  7  sw Y   y
xY w# t*        $ r}FddBt        F       dcY d
}F~FS d
}F~Fww xY ww)Cr   F   设备名称不能为空r   u   故障现象不能为空uriuserpasswordu.   Neo4j 配置不完整，请检查 NEO4J_CONFIG)authNu  
                    MATCH (s:舰艇)
                    WHERE s.舷号 IN [$ship_key]
                    RETURN DISTINCT
                           id(s) AS id,
                           labels(s) AS labels,
                           properties(s) AS props,
                           coalesce(s.名称, s.name, s.舷号) AS display_name
                    LIMIT 10
                    )ship_keyr   r   uM  
                    MATCH (ship:舰艇)
                    WHERE id(ship) = $ship_id
                    MATCH (ship)-[:包含*0..8]->(n:设备)
                    WITH n, coalesce(n.名称, n.name, n.设备名称) AS nm
                    WHERE nm IS NOT NULL
                    RETURN DISTINCT
                           id(n) AS id,
                           labels(n) AS labels,
                           properties(n) AS props,
                           nm AS display_name,
                           n.embedding AS embedding
                    LIMIT 100
                    )ship_idu  
                    MATCH (n:设备)
                    WITH n, coalesce(n.名称, n.name, n.设备名称) AS nm
                    WHERE nm IS NOT NULL
                    RETURN DISTINCT
                           id(n) AS id,
                           labels(n) AS labels,
                           properties(n) AS props,
                           nm AS display_name,
                           n.embedding AS embedding
                    LIMIT 200
                    u   未找到匹配的设备节点rq   r   rr   gffffff?)
query_textrn   name_keyembedding_keytext_weightsemantic_weightu/   未找到匹配的设备节点（最高得分: z.3fu   ）u  
                MATCH (start_e:设备)
                WHERE id(start_e) = $device_id
                MATCH (start_e)-[:包含*0..3]-(real_e:设备)
                MATCH (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                RETURN DISTINCT
                       id(fm) AS id,
                       labels(fm) AS labels,
                       properties(fm) AS props,
                       fm.名称 AS display_name,
                       fm.embedding AS embedding,
                       id(real_e) AS real_device_id,
                       real_e.名称 AS real_device_name
                )	device_idu0   在该设备节点下未找到故障模式节点uY   未能在故障模式节点中找到与故障现象足够匹配的节点（最高得分: u<   故障模式节点缺少 id，无法继续检索维修项目r   r-   u   故障原因r*   u   维修方案uv  
                MATCH (fm:故障模式)
                WHERE id(fm) = $fault_mode_id
                OPTIONAL MATCH (fm)<-[:修理]-(p:维修项目)
                RETURN DISTINCT
                       id(p) AS id,
                       labels(p) AS labels,
                       properties(p) AS props,
                       p.名称 AS display_name
                )fault_mode_idr   c              3   &   K   | ]  }|v  
 y wN ).0r   	proj_codes     rY   	<genexpr>z2fault_graph_reason_and_projects.<locals>.<genexpr>  s     <^U]PQQ)^U]    c              3   &   K   | ]  }|v  
 y wr   r   )r   r'   values_texts     rY   r   z2fault_graph_reason_and_projects.<locals>.<genexpr>  s     "L844;#68r   >   fulltextr   
created_atlast_updatedknowledge_sourceu  
                    MATCH (ship:舰艇)
                    WHERE id(ship) = $ship_id
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path0 = (ship)-[:包含*0..8]->(real_e)
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    OPTIONAL MATCH (fm)<-[:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    WITH path0, path1, collect(DISTINCT rp) AS rps
                    WITH nodes(path0) + nodes(path1) + rps AS ns
                    UNWIND ns AS n
                    WITH DISTINCT n
                    WHERE n IS NOT NULL
                    RETURN elementId(n) AS id,
                           labels(n) AS labels,
                           coalesce(n.名称, n.name) AS name,
                           properties(n) AS props
                    )r   r   r   
repair_idsuD  
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    OPTIONAL MATCH (fm)<-[:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    WITH path1, collect(DISTINCT rp) AS rps
                    WITH nodes(path1) + rps AS ns
                    UNWIND ns AS n
                    WITH DISTINCT n
                    WHERE n IS NOT NULL
                    RETURN elementId(n) AS id,
                           labels(n) AS labels,
                           coalesce(n.名称, n.name) AS name,
                           properties(n) AS props
                    )r   r   r   r   r   r/   r.   )r   r/   r   r,   u  
                    MATCH (ship:舰艇)
                    WHERE id(ship) = $ship_id
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path0 = (ship)-[:包含*0..8]->(real_e)
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    WITH relationships(path0) + relationships(path1) AS rs
                    UNWIND rs AS r
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    UNION
                    MATCH (fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    MATCH (fm)<-[r:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    un  
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    WITH relationships(path1) AS rs
                    UNWIND rs AS r
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    UNION
                    MATCH (fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    MATCH (fm)<-[r:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    r   r   r   )r   r   r   r   r3   u!   暂无故障信息或修复方案)ensure_asciir1   Tr4   u   Neo4j 查询失败: )r>   r6   r   r@   r   driversessionrunr   r   hybrid_match_with_embeddingsr   anyrF   rH   valuesr)   itemsr#   dumpsrE   rI   )Ir   r   r   r   r   r   r   r   
device_keyr   r   r   
ship_queryship_recordsrship_candidatesdevice_querydev_recordsdevice_candidatesr   device_scorer   fault_mode_query
fm_recordsfault_modesr   fault_scorer   r   fm_propsr   r   r   repair_project_query
rp_recordsall_projectsr   projr-   vr   r   exclude_keysgraph_nodes_querynode_recordsnodes_gdata_rr   r   r   r/   rT   r,   graph_links_querylink_recordslinks_gsrctgtnnode_idsrepair_plans_datakfilteredrV   planplan_strcombined_textresults_objrQ   rU   rM   r   r   sI                                                                          @@rY   fault_graph_reason_and_projectsr   C  sp	     c+.446 +EFFM 2 8 8 : +EFF


5
!CF#D
+Hd( +[\\iL%,,Sh7GHHF~~''7 -335
 	 3{#3#9#9#;";/557H	"J *1Z()S#SLNZ&[&[';A'>
 &$L )0$g )4 ) #K
$L )0L(A"AKLW$X$Xq%9!%<y I'$ $T&[&[&[O&[&$3A$6	"+D/$#" #B$X$X$X!$X(',7WX{ ('' IHH@ 3<2X2X)0+"- #$'3 - -)\ #',9hiuvyhzz}7~Q ('' IHHT (-	$  $+;;/?9;#UUU
FPQQ3A6QQQ"',7ijy ('' IHH~ 6?5[5[,*+"- #$'6 0 0, '',  :S  T_  `c  Sd  dg  8h  iO ('' IHHT !0 3 3D 9 (',7uvW ('' IHH\ "1!4!45E!F*..w7=2'||N;Ar&ll>:@b,[9	($ $+;;( $/ $  
 HRRR! 4Q 7RRR8: , $ 1 7R%*YY/C%D%J$Q$Q$S	$ )X 5<^U]<^9^+2248!**-((16 QA1=Q Q+K  #"L8"LL / 6 6t < !- '3O *9)8AAEE$K<SAEE$K
   &)%( *1) ''5&3#-#5" *5 * $ $L)%" *1)'5&3#-#5"	 *5 * $ $L 13+  !VVXF **T*C{ #ZZ17RF)/EA13DaEFE!::f-9SD"JJw/52E!&8UYYvr5J!KJ;E(J!72JNN"%$(&,*4	  ,* &)%4 *1) ''5&3#-#5" *5 * $ $L)%. *1)'5&3#-#5"	 *5 * $ $L 13+  !VVXF **X.C **X.C{ck NN"(**T"2%+ZZ%<&)&)	  , .55WAdGW55 %$uuX(2quuX(7R $  ;=!(AEE'N0bE16XA!<BW1XHX)00:	 ) C$5$;$;$=LL\!2!8!8!:;$ 1+'*4y'8H' %X 6	 !2 $(IIe$4M$GM+#zz+EJ'.A
)*5
#'
|P\]I ('' IHH''' IHHHHN  L -A#a&+JKKLs  Bd c -F*.c 1cF,c
A*b4F.5b=F4?F2
F0F2
F4b.G	/b
GbGG
GG
G*c ,c.b0F2
2F43
b>
b	bbG
Gbc*G-+c0c <G?=c d b!H$"b5cIcc Ic d b7I:8	bJJ
J
J
Jb(c4J75c:c K	c d b+K.,b?cLcc L c #d $b;cM
cc Mc d  A3bO	bO7O5
#O&$O5
(O76A7b.bR!R! !bbT3T.b4T75%bU	b$X6(U+
)X6->b+
V;
6V;
:BbY%b?Z 	b	\ Z
\ A3b\b/]7b^^b"A!bb Ab8cbc
c bc d b/	#b&$b/	+c2c =c >c d c
ccc d c 	c="c82c=3d 8c==d c                 J   | j                  dg       }|D cg c]
  }|dk7  s	| }}|rt        |      dkD  r|d   }nd}|dk(  rd| d<   d| d	<   | S |d
k(  rd| d<   d| d	<   | S |dk(  rd| d<   d| d	<   | S |dk(  rd| d<   d| d	<   | S |dv rd| d<   d| d	<   | S d| d<   d| d	<   | S c c}w )Nr   r   r   r*      舰艇z#F89A64colorV   size   系统z#C25C21	   子系统z#7D2D00   设备z#540802)
u   功能u   环境条件u   接口u   安全警告u   调试u   器材保障u   图册u   设计单位u   维修项目u   操作项目z#2261DF4   z#68C3FF5   r@   rb   )rS   	node_typer   s      rY   add_node_styler    s   2&I%;Iql):II;S^a'aL		H!WV" K! 
h	!WV K 
k	!!WV K 
h	!WV K 
  _  
_!WV
 K "WVK3 <s
   
B B c                    | j                  d      }| j                  d      }d}d}|rA||v r=||   j                  dg       D cg c]
  }|dk7  s	| }}|rt        |      dkD  r|d   }|rA||v r=||   j                  dg       D cg c]
  }|dk7  s	| }}|rt        |      dkD  r|d   }g d}	||	v r||	v rd| d	<   | S d
| d	<   | S c c}w c c}w )Nr   r   r*   r   r   r   )r  r  r  r  z#F59E0Br  z#FFFFFFr  )
rX   
nodes_dictr   r   source_typetarget_typer   source_labelstarget_labelshierarchy_typess
             rY   add_link_styler    s   "I"IKKY*,$.y$9$=$=h$Ka$KqqT`O`$KaS/!3'*KY*,$.y$9$=$=h$Ka$KqqT`O`$KaS/!3'*KAOo%+*H!W K "WK b
 bs   
CC
CCr+   c                     | D ]4  }t        |t              sd|v s|d   D cg c]
  }|dk7  s	| c}|d<   6 y c c}w )Nr   r   )rA   rB   )r+   rS   r   s      rY   rC   rC     sC    dD!h$&6)-hMA1;LaMDN Ms   
;;c                    | j                  dg       }| j                  dg       }|D ci c]&  }|j                  d      s|j                  d      |( }}|D ]  }t        |        |D ]  }t        ||        | S c c}w )Nr+   r0   r   )r@   r  r  )rP   r+   r0   r   r  rS   rX   s          rY   rE   rE     s    NN7B'ENN7B'E*/?%Q155;!%%+q.%J?t  tZ(   @s   A= A=c                    K   t        | ||       d{   }|j                  dd      s|j                  dd      S |j                  dd      S 7 :w)	u  
    故障诊断图谱检索工具（供工作流调用）：仅返回一段话摘要，与 graph_rag_search 一致。
    根据设备名称、故障现象在图谱中定位设备→故障模式→维修项目，并生成文字摘要。舷号为可选参数，提供时可缩小搜索范围。
    工作流中用于与 RAG 结果一起作为上下文，不返回节点/关系（展示用 fault_graph_reason_and_projects）。
    )r   r   r   Nr   Fr      检索失败r2   r*   )r   r@   )r   r   r   rN   s       rY   fault_graph_rag_searchr    sW      3# F
 ::i'zz'>22::i$$   AA;Aoperation_itemc                   K   | rt        |       j                         sdddS |rt        |      j                         sdddS |rt        |      j                         sdddS t        j                  d      }t        j                  d      }|sdddS t        |       j                         t        |      j                         t        |      j                         d	}	 t	        j
                  |
      4 d{   }|j                  ||ddi       d{   }|j                          |j                         }|j                  dd      s&d|j                  dd      dcddd      d{    S |j                  d      xs g }	g }
|	rzt        |	      D ]g  \  }}t        |t              st        |j                  dg              d|v r$|j                  d      }|r|
j                  |       t        |      |	|<   i |	|d<   |
rdj!                  |
      |d<   n	d|vrd|d<   |cddd      d{    S 7 A7 &7 7 # 1 d{  7  sw Y   yxY w# t        j"                  $ r dddcY S t        j$                  $ r dddcY S t        j&                  $ r&}dd|j(                  j*                   dcY d}~S d}~wt,        $ r}ddt        |       dcY d}~S d}~ww xY ww)r   Fu   舷号不能为空r   r   u   操作项目不能为空operation_search_endpointgraph_timeoutu'   操作图谱检索服务配置不完整r   r   r  r    Nr   r   r"   r   r   r  r5   r+   r2   r3   r*   u   操作图谱检索服务超时u$   无法连接操作图谱检索服务u&   操作图谱检索服务返回错误: u   操作图谱检索失败: )r>   r6   r
   r@   r7   r8   r9   raise_for_statusr#   	enumeraterA   rB   rC   rD   rF   rE   rH   r;   ConnectErrorHTTPStatusErrorrL   r?   rI   )r   r   r  endpointr    rJ   rK   rL   rN   
graph_listresults_partsirU   r   rM   s                  rY   operation_graph_search_toolr*  &  s     c+.446 +?@@c+.446 +EFF^!4!:!:!< +EFF"&&'BCH!%%o6G +TUU ;'--/;'--/n-335G(R$$W55#[[');< )  H
 %%']]_F::i/#(6::g~3VW 655  L17RJM%.z%:MAz!*d31*.."2MN$
2 *y 9A  - 4 4Q 7(4Z(@
1 &; (2|$$(IIm$<y!&($&y!= 655 65555@  M +KLL S +QRR   n -STUT^T^TjTjSk+lmm R -GAx+PQQRs   CK* I :H;;I >IH>A
I#I /I0I 4K*5:I0A9I)I 5I6I :K*;I >II I IIII K*I K'2K*4K'K*K'K :K';K* K'K"K'K*"K''K*c                    K   t        | ||       d{   }|j                  dd      s|j                  dd      S |j                  dd      S 7 :w)	uq  
    操作图谱检索工具（供工作流调用）：仅返回一段话摘要，与 graph_rag_search 一致。
    根据舷号、设备名称、操作项目在图谱中定位舰艇→设备→操作项目，并生成文字摘要。
    工作流中用于与 RAG 结果一起作为上下文，不返回节点/关系（展示用 operation_graph_search_tool）。
    r   Nr   Fr   r  r2   r*   )r*  r@   )r   r   r  rN   s       rY   operation_graph_rag_searchr,  m  sW      /% F
 ::i'zz'>22::i$$r  entity_typec                    K   t        d|         t        |        d{   }|j                  dd      sy|j                  dd      }|syt        |      dkD  r|dd dz   }|S 7 Dw)	u  
    GraphRAG检索工具（异步版本）
    在知识图谱中检索与query相关的实体和关系

    Args:
        query: 检索查询
        entity_type: 实体类型过滤（如：设备、故障、维修项目）- 注意：此参数在当前实现中暂未使用
        top_k: 返回结果数量（保留参数以兼容接口）

    Returns:
        图谱检索结果文本字符串（旧格式，保持兼容）
    zgraph_rag_query+++++++++++Nr   Fr*   r2   i  z...)printrZ   r@   rb   )r   r-  r   rN   rQ   s        rY   graph_rag_searchr0    su      
&ug
./&&F::i'::i,L
<4#ET*U2 's   A&A$AA&
node_namesr    c                 N  K   t         d   }| sddi dS | |d}	 t        j                  |      4 d{   }|j                  ||ddd	
       d{   }ddd      d{    j                  dk(  rN|j                         }|j                  dd      rd|j                  di       ddS d|j                  dd      i dS dd|j                   d|j                   i dS 7 7 7 # 1 d{  7  sw Y   xY w# t        $ r}dt        |      i dcY d}~S d}~ww xY ww)u<  
    图册检索工具：从图谱中找到节点并关联图册PDF

    Args:
        node_names: 节点名称列表，如 ["主发动机", "压缩机"]
        top_k: 返回的结果数量
        timeout: 请求超时时间（秒）

    Returns:
        包含success和data字段的字典
        data格式示例：
        {
            "船舶主发动机": {
                "船舶主发动机的原理图": [
                    "http://192.168.0.46:59085/files/163-06A0015-B01001_船舶主发动机原理图.pdf"
                ]
            }
        }
    r&  Fu   node_names不能为空)r   r   r)   )r1  r   r!  Nr   r   r"   r%   r   Tr)   )r   r)   r   r(   u   API返回失败r&   z: )
r	   r7   r8   r9   r?   r#   r@   rw   rI   r>   )	r1  r   r    api_urlrJ   rK   rL   rN   rM   s	            rY   atlas_retrievalr4    sX    0 :&G-
 	
 !G
%
$$W55#[[0$6 )  H 65 3&]]_Fzz)U+#"JJvr2!   %#ZZ	3DE  ! !5!5 6bH 3 6 6555>  
V
 	

s   D%D  C%D  C+C'C+D  #C)$A
D  .D%/D  D%D  $D%%D  'C+)D  +C=1C42C=9D   	D"	DD"D%D""D%
atlas_datac           	      H   | syg }| j                         D ]v  \  }}t        |t              s|j                         D ]M  \  }}t        |t              s|s|j	                  d| d| d       |D ]  }|j	                  d| d        O x |rdj                  |      S dS )u   
    格式化图册检索结果为文本，便于在提示词中使用

    Args:
        atlas_data: atlas_retrieval返回的data字段

    Returns:
        格式化后的文本
    r*   u   
【z - u   】z- r3   )r   rA   rB   rG   rF   rH   )r5  rV   	node_name	node_datatitleurlsurls          rY   format_atlas_resultsr<    s     E * 0 0 2	9i&(0tdD)dLL53ugS!AB#r#b\2  $  1 !3  %499U,",rm   history_messagesfaultlast_generated_schemec           	        K   g }|r|j                  |       |r|j                  |       |r|j                  |       t        t        j                  |            }|s|r	 d|xs d d|xs d d|xs d d|xs d d	}t	        j
                  |dd	       d
{   }t        |      }t        |t              rC|j                  dg       }	|	r/|j                  |	       t        t        j                  |            }|D cg c]2  }|st        |j                               dk\  s#|j                         4 }}|d
d S 7 # t        $ r!}
t        dt        |
              Y d
}
~
id
}
~
ww xY wc c}w w)ue  
    从历史记录中抽取部件/设备/零部件名称

    Args:
        history_messages: 历史对话记录
        device_name: 设备名称
        operation_item: 操作项目名称
        fault: 故障现象
        last_generated_scheme: 最后一次生成的方案（用于重点抽取）

    Returns:
        抽取的实体名称列表
    u  从以下信息中抽取尽可能多的设备、部件、零部件、机构、系统名称（用于图册检索）。
注意：
- 请尽可能多抽取，宁多勿少，准不准没关系
- 包括所有提及的机械部件、电子设备、机构系统等
- 即使是重复提到的也可以保留，我们会去重
- 重点从【生成的方案】中抽取，这里信息最全面

【示例 - 输入】
船舶主发动机（舷号：101）故障分析与维修方案
1. 故障概况
设备名称：船舶主发动机
舷号：101
故障现象：主机运行中出现异响
2. 故障原因分析
主轴承或连杆大端轴承磨损：轴承间隙过大或磨损严重会导致金属撞击声。
曲轴主轴颈跳动超差：曲轴旋转不平衡或跳动量超出标准。
飞轮连接螺栓松动：飞轮与曲轴连接处的螺栓松动。
活塞头烧蚀或活塞环断裂：活塞环断裂或活塞头部损坏可能导致敲缸声。
排气阀密封面磨损或阀座烧蚀：气门间隙异常或密封失效。
涡轮增压器轴承损坏：增压器内部轴承损坏。
3. 维修方案
执行项目：MT003 检测曲轴组件（含飞轮紧固状态检查）。
执行项目：MTO03 检测曲轴主轴颈跳动量。

【示例 - 输出】
{
    "entity_names": ["船舶主发动机", "主轴承", "连杆大端轴承", "曲轴", "飞轮", "飞轮连接螺栓", "活塞头", "活塞环", "排气阀", "排气阀座", "涡轮增压器", "涡轮增压器轴承", "曲轴组件"]
}

【设备/操作】
- 设备名: u   无u   
- 操作项: u   
- 故障: u   

【生成的方案】
u   

请输出JSON格式，格式如下：
{
    "entity_names": ["名称1", "名称2", "名称3", "..."]
}

仅输出JSON，不要其他内容。Tu   你是一个专业的实体抽取助手，负责从文本中抽取尽可能多的设备、部件、零部件、机构、系统名称。请尽量多抽取，宁多勿少。重点从生成的维修方案中抽取。)r   json_outputsystem_promptNentity_namesu#   [图册检索] 实体抽取失败:       )rF   rG   rB   fromkeysr   open_api_chat_without_thinking_safe_json_extractrA   r@   extendrI   r/  r>   rb   r6   )r=  r   r  r>  r?  rC  extraction_promptrL   parsed	extractedrM   r/   s               rY   !extract_entity_names_from_historyrM    s    ( L K(N+E" l34L ,:	B%< "U# $%& '>E
  %   !&G*!)X 'EE'  v H (1F&$'"JJ~r:	 ''	2#'l(C#DL
 .:]\TTc$**,FW[\F\DJJL\L]#  	B7Ax@AA	B ^s[   AE4!:E E A"E >E4E/
E/'E/9E4 E 	E,E'"E4'E,,E4c                    	 t        j                  |       S # t         j                  $ r\ t        j                  d|       }|rA	 t        j                  |j                  d            cY S # t         j                  $ r Y Y yw xY wY yw xY w)u   安全地从文本中提取JSONz\{[\s\S]*\}r   N)r#   loadsJSONDecodeErrorry   searchgroup)rw   matchs     rY   rH  rH  k  sx    zz$ 		.$/zz%++a.11'' s3    +B#A)&B)B <B?B  BB)(   F   rU     F)Nr*   r*   )NrT  )
   rE  )r*   r*   r*   r*   )2__doc__ry   r#   asyncior7   typingr   r   r   r   neo4jr   langchain_core.toolsr   configr	   r
   r   modelsAPI.model_apir   utils.function_trackerr   r@   r:   r>   intboolrZ   floatrl   rv   r   r   r   tupler   r   r   r  r  rC   rE   r  r*  r,  r0  r4  r<  rM  rH  r   rm   rY   <module>rd     s   
    , , $ % B B ) 7 0+//0AB   !&$&"$#l3l3C=l3 l3 SM	l3
 3-l3 3-l3 d^l3 
#s(^l3 l3^-# -# -% -6/4S#X#7 /c /hW[\_ad\dWeNf /.C DI   c3h 25d38n 5c3h 5%S#X'%$sCx.)% d38n-% $sCx.)	%
 %P)S#X')$sCx.)) d38n-) 	)
 ) 3i) $sCx.)) ) ) ) 	)X %)}Lc]}L}L }L 
#s(^	}L }L@<4NT$sCx.%9 N !%%#%% % 		% %( CRCRCR CR 
#s(^	CR CRL %%% % 		% %( # HSM QT ^a  < K
S	K
K
 K
 
#s(^	K
\-T#s(^ - -8 !#a4S>*aa a 	a
 a 
#YaHS S rm   mxH*
    ϱMjs                         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mZm	Z	 ddl
mZ ddlmZ ddlmZ e	 	 	 ddedee   d	ee   d
ee   deee	f   f
d       Zeddedee   defd       Zededeee	f   fd       Zededefd       Zy)uE   
RAG搜索工具模块
包含知识库搜索、文件处理等功能
    N)OptionalDictAny)tool)
RAG_CONFIG)track_function_callsquerytop_kfile_idkb_idreturnc                 p  K   | r| j                         sdddS t        d   }d| j                         i}|5t        j                  d      }|	 t        |t              rt        |      n|}|&t        j                  d      }||t	        |      nd}|
|d	k7  r||d
<   |
|d	k7  r||d<   t        d       t        t        d          t        t        d          t        t        d          dt        d   t        d   d}t        d|        d}	d}
d}d}t        |	dz         D ]P  }	 t        j                  dd      4 d{   }|j                  |||       d{   }ddd      d{     n 	 |j"                  dk7  rdd|j"                   dS |j%                         }|j                  dg       }|D cg c]  }|j                  dd      d k\  s| }}t'        |d! d"#      d| }i }t)        |d$      D ]'  \  }}t        |t*              s|j                  d%      }|j                  d&      }|r|j                  d'd	      nd	}|xs |r|j                  d(d)      nd)}|j                  d*g       }|r|d+   j                  d,d+      nd+}||j                  d-d	      |j                  d.d	      |||j                  dd      ||j                  d
d	      |r|j                  d-d	      nd	|r|j                  d(d	      nd	|d/}||vrg ||<   ||   j-                  |       * d"|t/        |      t/        |      d0S # t        t        f$ r d}Y w xY w7 7 7 # 1 d{  7  sw Y   xY w# t        j                  t        j                  t        j                  f$ r[}|}||	k  r1t        d|dz    d       t        j                   |
       d{  7   nddt	        |       dcY d}~c S Y d}~d}~ww xY wc c}w # t0        $ r}dt	        |      dcY d}~S d}~ww xY ww)1u]  
    知识库搜索工具
    调用知识库搜索API，检索与query相关的文档内容

    Args:
        query: 搜索关键词（必填）
        top_k: 返回结果数量（默认5）
        file_id: 文件ID（可选）
        kb_id: 知识库ID（可选）

    Returns:
        搜索结果，包含sourceCitation格式的数据
    Fu   查询文本不能为空successerrorsearch_endpointr	   Nzfile-idzkb-id r   r   l   q{U	x-user-idzx-user-namex-rolezapplication/json)acceptr   r   zRAG params:       g     f@)timeoutverify)paramsheadersu   RAG请求超时，第 u#    次重试，2秒后重新请求...u   请求超时:    zHTTP resultsscore        g?c                 &    | j                  dd      S )Nr   r    )get)xs    Ae:\ZKYNLP\Hjunproject\project0506\wx-agent\app\tools\rag_tools.py<lambda>zrag_search.<locals>.<lambda>k   s    !%%-    T)keyreverse)startfilekbfilenamenameu   未分组文档	positionsr   page_idxidcontent)indexr0   textresourcer,   r   r/   r   r   kb_namer.   )r   sourceCitationtotaltotal_available)stripr   r"   
isinstancestrint
ValueError	TypeErrorprintrangehttpxAsyncClientReadTimeoutConnectTimeoutRequestErrorasynciosleepstatus_codejsonsorted	enumeratedictappendlen	Exception)r	   r
   r   r   
SEARCH_URLr   config_file_idconfig_kb_idr   max_retriesretry_delayresponselast_exceptionattemptclienteresultdataitemfiltered_datasorted_datasource_citationidx	file_infokb_infor,   r4   r.   r/   citation_items                                 r$   
rag_searchrd      sL    *  +EFF-.Ju{{}%F#	2%1;NC1P#n-Vd }!~~g.#)5)AC%tEw"}#yUb[w	
	*[
!"	*]
#$	*X
 %,X&G 
L
!"KKHNq)	N((uEE!'Jvw!WW FE	 *833&$x7K7K6L/MNNzz)R(*.P$$$((7C2HC2O$P-
 5	 ";a88ICdD)(IhhtnG8Ay}}Z4rHmgGKK8I$J[lHb1I:Cy|''
A6H hhtR(B/$$'3/$88Ir229T2.r6=7;;vr22&M .,.)H%,,];; 9@ -%"4y	
 	
} 	* D FW FEEE !!5#7#79K9KL 	NN$.wqyk9\]^mmK000#(^CF83LMM 1		N Q`  3 3q6223s  AP6M ,B<P6)M=MM=M' M!!M'%M=0M$1M=5P69 P P6&P  PPE&P P6MP6MP6M=!M'$M='M:	-M0.M:	5M==2P
/1P O#!P7P
8P6P

P6P 	P3P.(P3)P6.P33P6c                 |  K   t        | |       d{   }|j                  dd      sy|j                  di       }|syg }|j                         D ]8  \  }}|D ].  }|j                  dd      }|s|j                  d| d	|        0 : |rd
j	                  |      nd}	t        |	      dkD  r|	dd dz   }	|	S 7 w)u   
    RAG检索工具（供工作流调用）
    在知识库中检索与query相关的文档内容

    Args:
        query: 检索查询
        top_k: 返回结果数量

    Returns:
        检索结果文本
    )r
   Nr   Fr   r6   r3   u   【u   】z

i  z...)rd   r"   itemsrM   joinrN   )
r	   r
   rZ   r_   results_partsr4   rf   r\   r3   results_texts
             r$   rag_search_toolrj      s      e511F::i'jj!126OM*002%D88FB'D$$s8*Cv%>?  3 2?6;;}-BL
<4#ET*U2' 2s   B<B:AB<2A	B<	file_pathc                 v  K   | r| j                         sdddS | j                         } t        j                  j                  |       sdd|  dS 	 t        j                  j	                  |       d   j                         }|dk(  r,t        | dd	      5 }|j                         }d
d
d
       ddS |dk(  rcdd
l}|j                  |       }g }|D ]!  }|j                  |j                                # dj                  |      }|j                          d|dS |dv rRddlm}  ||       }g }|j                  D ]  }	|j                  |	j                           dj                  |      }d|dS |dv rzt        | d      5 }|j                         }
d
d
d
       t#        j$                  
      j'                  d      }d|dd
  d| }ddlm} |j-                  |d       d
{   }d|dS dd| dS # 1 sw Y   SxY w# 1 sw Y   sxY w7 *# t.        $ r}ddt1        |       dcY d
}~S d
}~ww xY ww)u   
    文件转文本工具
    支持多种文件格式：PDF、Word、TXT、图片等

    Args:
        file_path: 文件路径

    Returns:
        转换结果，包含文本内容
    Fu   文件路径不能为空r   u   文件不存在: r   z.txtrzutf-8)encodingNT)r   r3   z.pdfr   
)z.docxz.doc)Document)z.jpgz.jpegz.pngz.bmpz.gifrbzdata:image/z;base64,)	OpenaiAPIu   请描述这张图片的内容)
image_pathpromptu   不支持的文件格式:    文件处理失败: )r9   ospathexistssplitextloweropenreadfitzrM   get_textrg   closedocxrp   
paragraphsr3   base64	b64encodedecodemodelsAPI.model_apirr   vlm_chatrO   r;   )rk   file_extfr3   r}   doc
text_partspagerp   para
image_database64_image
base64_urlrr   rY   s                  r$   file_to_textr      s9     IOO- +EFF!I77>>)$ ->yk+JKK,L77##I.q1779viw71vvx 8#T22))I&CJ!!$--/2 99Z(DIIK#T22**%9%CJ!!$)), '99Z(D#T22BBi&!VVX
 '!++J7>>wGL&x|nH\NKJ5"++%7 ,  D  $T22  %1KH:/VWWK 870 '&  L -A#a&+JKKLs   AH9AH G7&H 2H93A'H H9AH 0H91H HAH %H&H .H9/H 6H97H<H H	H 	H6H1+H6,H91H66H9c                    K   t        |        d{   }|j                  dd      sd|j                  dd       S |j                  dd      S 7 =w)	u   
    文件转文本工具（供工作流调用）
    支持多种文件格式：PDF、Word、TXT、图片等

    Args:
        file_path: 文件路径

    Returns:
        文件文本内容
    Nr   Fru   r   u   未知错误r3   r   )r   r"   )rk   rZ   s     r$   file_to_text_toolr     sR       	**F::i'%fjj.&I%JKK::fb!! +s   AA>A)   NN)r   )__doc__rv   rI   r   rF   rA   typingr   r   r   langchain_core.toolsr   configr   utils.function_trackerr   r;   r<   rd   rj   r   r    r&   r$   <module>r      s   
     & & %  7  !	F3F3C=F3 c]F3 C=	F3
 
#s(^F3 F3R  Xc] 3  D ?L# ?L$sCx. ?L ?LD "s "s " "r&   ic6xT)
    j              	           d Z ddlZddlmZmZmZmZ ddlmZ d Z	deee
e
f      fdZ	 dde
d	e
d
e
defdZd	e
defdZy)u   
舷号-型号映射数据库模块
用于管理舰船型号、舷号、舰名的映射关系
数据存储在 PostgreSQL 的 ship_model_mapping 表中
每艘舰一条记录
    N)DictListAnyOptional)POSTGRES_CONNECTION_STRINGc            
        K   	 ddl m}   | t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d       d{    |j                  d	       d{    |j                  d
       d{    t        d       |j                  d       d{    |j                          d{   d   }|dk(  rDg d}|D ]#  \  }}}|j                  d|||f       d{    % t        dt        |       d       ddd      d{    ddd      d{    ddd      d{    y# t        $ r t        d       Y yw xY w7 U7 ?7 )7 7 7 7 7 7 }7 U# 1 d{  7  sw Y   exY w7 \# 1 d{  7  sw Y   lxY w7 c# 1 d{  7  sw Y   yxY ww)uz   
    初始化 ship_model_mapping 表并插入初始数据
    每艘舰一条记录，包含型号、舷号、舰名
    r   AsyncConnectionPoolu;   [ship_model_db] psycopg_pool 未安装，无法初始化表N
autocommitTkwargsaA  
                    CREATE TABLE IF NOT EXISTS ship_model_mapping (
                        id SERIAL PRIMARY KEY,
                        model_name TEXT NOT NULL,
                        hull_number TEXT NOT NULL UNIQUE,
                        ship_name TEXT NOT NULL DEFAULT ''
                    )
                z
                    CREATE INDEX IF NOT EXISTS ship_model_mapping_model_name_idx ON ship_model_mapping(model_name)
                z
                    CREATE INDEX IF NOT EXISTS ship_model_mapping_hull_number_idx ON ship_model_mapping(hull_number)
                u5   [ship_model_db] ship_model_mapping 表初始化完成z'SELECT COUNT(*) FROM ship_model_mapping))   055型驱逐舰102u	   拉萨舰)r   103u	   鞍山舰)r   104u	   无锡舰)r   105u	   大连舰)r   106u	   延安舰)r   107u	   遵义舰)r   108u	   咸阳舰)   052D型驱逐舰172u	   昆明舰)r   173u	   长沙舰)r   174u	   合肥舰)r   175u	   银川舰)r   163u	   南昌舰)   054A型护卫舰529u	   舟山舰)r   530u	   徐州舰)r   547u	   临沂舰)r   568u	   衡阳舰)r   570u	   黄山舰z
                            INSERT INTO ship_model_mapping (model_name, hull_number, ship_name)
                            VALUES (%s, %s, %s)
                            ON CONFLICT (hull_number) DO NOTHING
                            u   [ship_model_db] 已插入 u    条初始数据)
psycopg_poolr
   ImportErrorprintr   
connectioncursorexecutefetchonelen)	r
   poolconncurcountinitial_data
model_namehull_number	ship_names	            /app/tools/ship_model_db.pyinit_ship_model_mapping_tabler3      s    
4
 #"d#  
??$${{}}kk #    kk #    kk #    MNkk"KLLL"||~-q1A:$L& ?K:
K!kk 
 (i@   ?K 6s<7H6IIYZ[a %} %$	  	  KL %$
 M-,Q %}}} %$$$	   s_  GE GE3GF9E6F9F"E9
F"F)E<
*FE?
FF
#F?F
 FF
1F	F
F(F"3F	4F"8F9F F9GF7GE0-G/E00G6F99F"<F?FFFFF	F"FFFF" F9"F4	(F+)F4	0F97G9G?G GGreturnc            
      H  K   	 ddl m}  	  | t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d       d{    |j                          d{   }g }|D ]!  }|\  }}}	|j                  |||	xs d	d
       # |cddd      d{    cddd      d{    cddd      d{    S # t        $ r t        d       g cY S w xY w7 7 7 7 7 7 M7 >7 /# 1 d{  7  sw Y   nxY wddd      d{  7   n# 1 d{  7  sw Y   nxY wddd      d{  7   y# 1 d{  7  sw Y   yxY w# t        $ r#}
t        dt        |
              g cY d}
~
S d}
~
ww xY ww)u   
    从数据库加载全部舰船映射数据

    Returns:
        每艘舰一条记录的列表
        [
            {"model_name": "055型驱逐舰", "hull_number": "102", "ship_name": "拉萨舰"},
            ...
        ]
    r   r	   u8   [ship_model_db] psycopg_pool 未安装，返回空映射r   Tr   NzMSELECT model_name, hull_number, ship_name FROM ship_model_mapping ORDER BY id )r/   r0   r1   u*   [ship_model_db] 加载映射数据失败: )r"   r
   r#   r$   r   r%   r&   r'   fetchallappend	Exceptionstr)r
   r*   r+   r,   rowsresultrowr/   r0   r1   es              r2   load_ship_model_mappingr?   P   s    4
&& $'
 
 ((D;;==C++g   "%/DF#=@:
K*4+6)2b'   $ " )== )((	
 
 
  HI	

 )( 0	 ) )	

 )== )((((	
 
 
 
 
&  :3q6(CD	s}  F"C$ E3 D E3 EDED7D
D7D*D
+DD
-D0D7<D

=D7EDEE3 DE3 #F"$C=:F"<C==F" E3 ED7DD
D7EE3 D"DD"D7%E0D31E7E		=E >E		EE3 EE3 F"E0$E'%E0,E3 /F"0E3 3	F<FFF"FF"r/   r0   r1   c           	        K   	 ddl m} 	  |t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d	| ||f       d{    ddd      d{    ddd      d{    ddd      d{    t        d
| d| d       y# t        $ r t        d       Y yw xY w7 7 7 7 g7 Y# 1 d{  7  sw Y   ixY w7 `# 1 d{  7  sw Y   pxY w7 g# 1 d{  7  sw Y   wxY w# t        $ r!}t        dt        |              Y d}~yd}~ww xY ww)u   
    添加单艘舰船

    Args:
        model_name: 型号名称
        hull_number: 舷号
        ship_name: 舰名

    Returns:
        是否添加成功
    r   r	   u5   [ship_model_db] psycopg_pool 未安装，无法添加Fr   Tr   NaZ  
                        INSERT INTO ship_model_mapping (model_name, hull_number, ship_name)
                        VALUES (%s, %s, %s)
                        ON CONFLICT (hull_number) DO UPDATE SET
                            model_name = EXCLUDED.model_name,
                            ship_name = EXCLUDED.ship_name
                           [ship_model_db] 舰船 (u   ) 已保存u$   [ship_model_db] 添加舰船失败: 
r"   r
   r#   r$   r   r%   r&   r'   r9   r:   )r/   r0   r1   r
   r*   r+   r,   r>   s           r2   add_shiprD   z   s6     4
&& $'
 
 ((D;;==C++ $[)<	 	 	 )= )(	
 
  	'}Ai[LM-  EF

 )(	 )=== )(((	
 
 
 
$  4SVH=>s/  E
B6 D CD DCDC1C
C1C.C
/C3C1>C?C1DC/DD DD 5E
6C
E
CE
D DC1CC1C, C#!C,(C1/D1D	7C:8D	?DD DDDD 	E&E=E
EE
c           	        K   	 ddl m} 	  |t        ddi      4 d{   }|j                         4 d{   }|j                         4 d{   }|j                  d	| f       d{    ddd      d{    ddd      d{    ddd      d{    t        d
|  d       y# t        $ r t        d       Y yw xY w7 7 7 }7 d7 V# 1 d{  7  sw Y   fxY w7 ]# 1 d{  7  sw Y   mxY w7 d# 1 d{  7  sw Y   txY w# t        $ r!}t        dt        |              Y d}~yd}~ww xY ww)ul   
    删除单艘舰船

    Args:
        hull_number: 舷号

    Returns:
        是否删除成功
    r   r	   u5   [ship_model_db] psycopg_pool 未安装，无法删除Fr   Tr   Nz5DELETE FROM ship_model_mapping WHERE hull_number = %srA   u
    已删除u$   [ship_model_db] 删除舰船失败: rC   )r0   r
   r*   r+   r,   r>   s         r2   delete_shiprF      s'    4
&& $'
 
 ((D;;==C++O$   )= )(	
 
 	'}J?@!  EF

 )( )=== )(((	
 
 
 
  4SVH=>s/  EB1 D CD DCDC,C
C,C,C
-C1C,<C=C,DC*DD DD 0E1CECED DC,CC,C'CC'#C,*D,C>	2C53C>	:DD D	D
DD 	E!D=8E=EE)r6   )__doc__jsontypingr   r   r   r   configr   r3   r:   r?   boolrD   rF        r2   <module>rN      s|     , , -@\F'tDcN'; 'Z +++ + 
	+\3 4 rM   pɉxlo
    C;jg                     ,   U d 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mZm	Z	m
Z
 ddlmZ ddlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZ daee   ed<    ej4                         ZdefdZdddddddddg dddddg dddddg ddddddd dd!dg d"dd#d$dd%gdd&d'Z eed(   j?                               Z de!fd)Z"d*e!d+e!dee!ef   fd,Z#d*e!d-e!dee!ef   fd.Z$ G d/ d0e%      Z&d-e!de
e'e!e!f   fd1Z(d-e!dee!ef   fd2Z)d3Z*d@d*e!d+ee!   dee!ef   fd4Z+d*e!d+e!d5e!d6e	ee!ef      dee!ef   f
d7Z,g d8Z-d(e	e!   d*e!de'fd9Z.d(e	e!   dee!   fd:Z/d(e	e!   dee!   fd;Z0d(e	e!   dee!   fd<Z1	 dAd=e	ee!ef      d(e	e!   d*e!d>e2de	ee!ef      f
d?Z3y)Bu  
受控 ReAct Text2SQL 工具
核心思想：Agent负责推理，Tool负责SQL，Reviewer负责纠错

内部流程：
1. Schema Injection - 注入数据库表结构
2. SQL Generation - LLM生成SQL（使用 SQLAlchemy 连接池 + extra_info 辅助）
3. SQL Review - LLM审查SQL正确性
4. SQL Guard - 代码级安全校验（硬限制）
5. SQL Execute - 执行SQL并返回结果（使用 SQLAlchemy 连接池单例）
6. Merge - 相似结果合并（Embedding）
    N)datetime)DictAnyOptionalListTuple)text)SQLDatabase)POSTGRES_CONNECTION_STRINGPOSTGRES_SQLALCHEMY_URL	OpenaiAPITEXT2SQL_PROMPTS)get_extra_info_db_instancereturnc                    K   t         [t        4 d{    t         0t        j                  t        j
                  t               d{   a ddd      d{    t         S t         S 7 V7 "7 # 1 d{  7  sw Y   t         S xY ww)u9   懒加载并缓存数据库连接，避免重复初始化N)r   _db_lockasyncio	to_threadr
   from_urir        /app/tools/text2sql_tool.py_get_dbr   #   sn      8#%,%6%6((*A&   8
 <   888
 sV   B
A*B
2A0	A,
A0B
A.B
,A0.B
0B6A97B>B
fault_recordsuB   故障维修记录表，存储所有故障诊断和维修的记录SERIALu   自增主键F)typedescriptionusable_in_queryTEXTu9   舰船舷号，如'101'、'163'、'554'等，2-4位数字T)101163554602)r   r    r!   examplesuG   设备名称，如'主机'、'发电机'、'分油机'、'空压机'等)u   主机u	   发电机u	   分油机u	   空压机u   舵机u   锅炉uN   故障现象描述，如'滑油压力低'、'异常振动'、'启动失败'等)u   滑油压力低u   异常振动u   启动失败u   排烟温度高JSONBuG   消耗的备件列表，JSON数组格式，如'["密封圈", "滤芯"]'uF   使用 jsonb_array_elements_text(spare_parts) 展开备件进行统计)r   r    r!   json_query_hintuK   所属系统名称，如'动力系统'、'电气系统'、'导航系统'等)u   动力系统u   电气系统u   导航系统u   通信系统u   其他	TIMESTAMPu*   记录创建时间，默认为当前时间z2025-01-15 10:30:00)idship_numberdevice_namefaultspare_partssystem_name
created_at)
table_namer    columnsr3   c                     dt         d    g} | j                  dt         d           | j                  d       | j                  d       t         d   j                         D ]k  \  }}|j                  dd	      sd
| d|d    d|d    }d|v r|ddj	                  |d   dd        dz  }d|v r|d|d    z  }| j                  |       m dj	                  |       S )u&   生成 Schema 注入的提示词部分u   数据库表：r2   u	   说明：r     u   字段列表：r3   r!   Tz  - z (r   z): r'   u   （示例：z, N   u   ）r)   u   
    查询提示：
)FAULT_RECORDS_SCHEMAappenditemsgetjoin)linescol_namecol_infolines       r   get_schema_prompt_sectionrA   g   s   3LABCDE	LL91-@ABC	LL	LL"#29=CCE(||-t4hZr(6"2!33x7N6OP!l499Xj-A"1-E#F"GsKKD(+H5F,G+HIIDT F 99Ur   questioncurrent_datec                 p  K   t               }t        j                  t        |       t	                      d{   \  }}t
        d   j                  || ||xs d      }t        d       t        |       	 t        j                  |dd       d{   }t        j                  d|t        j                        }|rLt        j                  |j                  d	            }|j!                  d
d      j#                         }	|	r|	dddS t        j                  d|j#                         t        j$                  t        j                  z        }
|
r4|
j                  d      j#                         j'                  d      }	|	dddS ddddS 7 R7 # t(        $ r}dddt+        |       dcY d}~S d}~ww xY ww)u   
    使用 LLM 根据用户问题生成 SQL。
    并发预热数据库连接与获取 extra_info，提升整体响应速度。

    Returns:
        {"sql": "SELECT ...", "success": True/False, "error": "..."}
    Nsql_generationr5   )schemarB   rC   
extra_infou!   输出最终sql的提示词内容Tmodeljson_output\{.*\}r   sqlrL   successerror(SELECT\s+.+?;?)$   ;Fu   LLM未返回有效SQLu   SQL生成失败: )rA   r   gatherr   r   r   formatprintr   open_api_chat_without_thinkingresearchDOTALLjsonloadsgroupr;   strip
IGNORECASErstrip	Exceptionstr)rB   rC   schema_sectionrG   _promptresult
json_matchparsedrL   	sql_matches               r   generate_sqlrj      s     /0N "..x 	 MJ
 ./66!#	 7 F 

-.	&MT ??
 
 YYy&"))<
ZZ
 0 0 34F**UB'--/C"tbAA II2FLLNBMMTVT]T]D]^	//!$**,33C8C4"==e6MNNE
,  Te8I#a&6RSSTsk   5F6F	=F66F FA6F F6	A9F F6F F6F 	F3F.(F3)F6.F33F6rL   c                 z  K   ddl m} ddlm} t	               }|d   j                  || |      }	  |j                  |dd       d{   }t        j                  d	|t        j                        }|rt        j                  |j                  d            }|j                  d
d      }	|j                  dg       }
|j                  dd      j                         }|j                  dd      }|r|j                  d      }|	|
||dS dg dddS 7 # t         $ r}dg ddt#        |       dcY d}~S d}~ww xY ww)u'  
    使用 LLM 审查 SQL 是否真正回答了用户问题

    Returns:
        {
            "approved": True/False,
            "issues": ["问题1", "问题2"],
            "suggested_sql": "修正后的SQL（如果有问题）",
            "review_comment": "审查意见"
        }
    r   r   r   
sql_review)rF   rB   rL   NTrH   rK   approvedFissuessuggested_sqlr5   review_commentrR   )rm   rn   ro   rp   u'   审查结果解析失败，默认通过u#   审查过程异常，默认通过: )modelsAPI.model_apir   promptsr   rA   rT   rV   rW   rX   rY   rZ   r[   r\   r;   r]   r_   r`   ra   )rB   rL   r   r   rb   rd   re   rf   rg   rm   rn   ro   rp   ri   s                 r   
review_sqlrs      sV     .(.0Nl+22 3 F&
?y??
 
 YYy&"))<
ZZ
 0 0 34Fzz*e4HZZ"-F"JJ;AACM#ZZ(8"=N - 4 4S 9 % !."0	  G	
 	
1
>  
 CCF8L	
 	

sS   .D;D 	D
B>D D;	D D;D 	D8D3-D8.D;3D88D;c                       e Zd ZdZy)SQLGuardErroru   SQL Guard 校验失败异常N)__name__
__module____qualname____doc__r   r   r   ru   ru      s    &r   ru   c                    | r| j                         sy| j                         j                         }|j                  d      syd|v ry|j                  d      dz
  }|dkD  r	dd	d
| dfS g d}|D ]  }||v sdd	d| fc S  g d}|D ]  }||v sdd	d| fc S  d| v sd| v sd| v ryd| j	                  d      v ryt               }t        j                  d| t        j                        }|j                  d |D               t        j                  d| t        j                  t        j                  z        }	|	r|	j                  d      }
d|
vrt|
j                  d      D ]`  }|j                         }t        j                  d|      }|s,|j                  d      j                         }|dvsP|j                  |       b |D ]  }|t         vs|dk7  sdd	d| fc S  | j                         j	                  d      }d|vr| d }t        j                  d!| t        j                        }|r,|j                  d      j                         }|d"k7  rdd	d#| fS d$|d	fS )%ug   
    SQL 安全守卫 - 代码硬限制

    Returns:
        (passed, cleaned_sql, error_message)
    )Fr5   u	   SQL为空SELECT)Fr5   uB   只允许SELECT查询，禁止INSERT/UPDATE/DELETE/CREATE等操作UNION)Fr5   u   禁止使用UNION操作rQ      Fr5   u   子查询嵌套过深（u   层），最多允许2层)PG_SLEEPSLEEP	BENCHMARKWAITFORDELAYu   禁止使用危险函数: )PG_INFORMATION_SCHEMA
PG_CATALOGPG_CLASSu   禁止访问系统表: z--z/*z*/)Fr5   u   SQL中不允许包含注释rR   )Fr5   u   禁止多语句执行zfault_records\.(\w+)c              3   <   K   | ]  }|j                           y wNlower).0ms     r   	<genexpr>zguard_sql.<locals>.<genexpr>0  s     7;a	;s   zSELECT\s+(.*?)\s+FROM*,z(\w+)\s*(?:AS|as)?\s*$)countsumavgmaxminasdescascnulldistinctalljsonb_array_elements_textjsonb_array_elementscoalescecastdate	timestampr	   r+   u   使用了不允许的字段: LIMITz
 LIMIT 100zFROM\s+(\w+)r   u5   只允许查询 fault_records 表，不允许查询: T)r]   upper
startswithr   r_   setrW   findallr^   updaterX   rY   r\   splitr   addALLOWED_COLUMNS)rL   	sql_uppersubquery_countdangerous_functionsfuncsystem_tables	sys_tableused_columnsdot_matchesselect_matchselect_partpart	col_matchr>   colcleaned_sql
from_matchr2   s                     r   	guard_sqlr      s    ciik%		!!#I )^ )3 __X.2Nb4^4DD]^^^ Q#9" :4&AAA $
 LM"		!" 7	{CCC #
 s{dckTS[7 cjjo1 5L**4c2==IK7;77995sBMMBII<UVL"((+k!#))#.zz|II&?F	(q1779H (Y Y %((2 / o%#+" =cUCCC 
 ))+$$S)Ki$Z0 ?C?J%%a(..0
(" UV`Uabbbb  r   c           	          K   	 t                d{   dt        t        t        f   f fd}t	        j
                  |       d{   S 7 ;7 # t        $ r}g g dddt        |       dcY d}~S d}~ww xY ww)u   
    执行 SQL 并返回结果。
    使用模块级 SQLAlchemy 连接池单例，避免每次重复建立连接。

    Returns:
        {"rows": [...], "columns": [...], "row_count": int, "success": True/False, "error": ""}
    Nr   c                     	 
j                   j                         5 } | j                  t                    }t	        |j                               }g }|j                         D ]  }i }t        |      D ]  \  }}||   }t        |t              r|j                         }nct        |t        t        f      rt        j                  |d      }n5t        |t        t        t         t"        t%        d       f      st        |      }|||<    |j'                  |        | j)                          ||t+        |      dddcd d d        S # 1 sw Y   y xY w# t,        $ r}	g g dddt        |	       dcY d }	~	S d }	~	ww xY w)NF)ensure_asciiTr5   rowsr3   	row_countrN   rO   r   u   SQL执行失败: )_engineconnectexecuter	   listkeysfetchall	enumerate
isinstancer   	isoformatdictrZ   dumpsra   intfloatboolr   r9   commitlenr`   )connre   r3   result_rowsrowrow_dictir   valri   dbrL   s             r   _runzexecute_sql.<locals>._runc  sG    ZZ'')T!\\$s)4F"6;;=1G"$K%0#%&/&8FAs"%a&C)#x8&)mmo!+C$!>&*jj5&I%/c3tTRVZ5X%Y&)#h,/HSM '9 $**84  1 KKM +#*%(%5#'!## *))0  !!"$0Q9 s;   E DE<	E EE E 	E9E4.E94E9r   Fu   获取数据库连接失败: r   )r   r   ra   r   r   r   r`   )rL   r   ri   r   s   `  @r   execute_sqlr   X  s     /
9_!	d38n !	F &&t,,,K J - 
4SVH=
 	

sV   A=A A6A 
AA A=A A 	A:A5/A:0A=5A::A=r}   c                 T  K   |s#t        j                         j                  d      }g }d}t        t        dz         D ]  }|dk(  rt        | |       d{   }nt        | |||       d{   }|d   sddg g d|d   |d	c S |d
   }t        | |       d{   }|j                  |dz   ||d   |d   |d   d       |d   sN|d   r|d   }|j                  |dz   |dd       n+|t        k  rd|g g dddj                  |d          |d	c S t        |      \  }}}	|sJ|j                  |dz   |d|	d       |t        k  r|j                  dd|	 di       #d|g g dd|	 |d	c S |}|j                  |dz   |ddd       t        |       d{   }
|
d   s6|t        k  r|j                  |dz   ||
d   dd       d|g g d|
d   |d	c S t        |
d   |
d   |        d{   }d|||
d   t        |      |
d    d|d!c S  d|g g dd"|d	S 7 7 7 7 7 6w)#u  
    受控 Text2SQL 工具 - 内部形成闭环

    流程：question → SQL生成 → SQL审查 → SQL Guard → SQL执行 → 返回结果

    Args:
        question: 用户问题
        current_date: 当前日期（格式：YYYY-MM-DD），默认为今天

    Returns:
        {
            "success": True/False,
            "sql": "最终执行的SQL",
            "rows": [...],
            "columns": [...],
            "row_count": int,
            "error": "",
            "review_log": [...]  # 审查日志
        }
    z%Y-%m-%dr5   rQ   r   NrN   FrO   )rN   rL   r   r3   r   rO   
review_logrL   rm   rn   rp   )attemptrL   rm   rn   commentro   u   使用审查建议的修正SQL)r   rL   noteu   SQL审查不通过: ; )r   rL   guard_passedguard_errorr   u   Guard拒绝: u   ，将重新生成u   SQL安全校验失败: Tu   Guard通过)r   rL   r   r   u   执行失败，将重新生成)r   rL   
exec_errorr   r   r3   r   )rN   rL   r   r3   r   raw_row_countrO   r   u   超过最大重试次数)r   nowstrftimerange	MAX_RETRYrj   generate_sql_with_feedbackrs   r9   r<   r   r   merge_similar_rowsr   )rB   rC   r   current_sqlr   
gen_resultreview_resultpassedr   r   exec_resultmerged_rowss               r   text2sql_toolr     s-    * ||~..z:JKQ'a<+HlCCJ9,Z  J )$ #G,(  !' );??{%j1#H-$%56
 	 Z(_-+O<!!&{&<# 
 9$  %&!!"3DIImH>U4V3WX",  ,5[+A(["Q;" %*	  "!!6];-GY+Z"[\  %&!!"6{mD",  "{ !	
 	 (449%"!!&{&"-g"6<	#    %&!!"(1",  /Y!7
 

 "9-[)(5$	
 		
a (x +  q D$ @| 5.
s\   AH(HH(-H.,H(H!C>H(H$AH(/H&0,H(H(!H($H(&H(previous_sqlr   c                   K   ddl m} ddlm} t	               }g }|D ]h  }d|v r+|d   r&|j                  ddj                  |d                 d|v r|j                  d|d           d	|v sR|j                  d
|d	           j |rdj                  |      nd}	|d   j                  || |||	      }
	  |j                  |
dd       d{   }t        j                  d|t        j                        }|rLt        j                  |j                  d            }|j                  dd      j!                         }|r|dddS t        j                  d|j!                         t        j"                  t        j                  z        }|r4|j                  d      j!                         j%                  d      }|dddS ddddS 7 # t&        $ r}dddt)        |       dcY d}~S d}~ww xY ww)u,   
    基于审查反馈重新生成 SQL
    r   r   r   rn   u   问题: r   r   u   安全校验失败: r   u   执行失败: r7   u   无具体反馈sql_regeneration)rF   rB   rC   r   feedbackNTrH   rK   rL   r5   rM   rP   rQ   rR   Fu   重新生成SQL失败u   重新生成SQL异常: )rq   r   rr   r   rA   r9   r<   rT   rV   rW   rX   rY   rZ   r[   r\   r;   r]   r^   r_   r`   ra   )rB   rC   r   r   r   r   rb   feedback_parts	log_entryr   rd   re   rf   rg   rL   rh   ri   s                    r   r   r   :  s     .(.0NN	y Yx%8!!HTYYy7J-K,L"MNI%!!$8=9Q8R"ST9$!!N9\3J2K"LM   -;tyy(@QH0188!! 9 FZ?y??
 
 YYy&"))<
ZZ
 0 0 34F**UB'--/C"tbAAII2FLLNBMMTVT]T]D]^	//!$**,33C8C4"==e6MNN%
(  Ze8OPSTUPVx6XYYZsi   A,G1/AG17G	 GA6G	 G1A9G	  G1G	 G1G	 		G.G)#G.$G1)G..G1)   故障   频次   排名u   高频u   最多topu   发生次数c                     |j                         t        fdt        D              rL| D cg c]  }|j                          c}t        fddD              }t        fddD              }|xr |S yc c}w )u!   判断是否需要合并相似行c              3   &   K   | ]  }|v  
 y wr   r   )r   kwquestion_lowers     r   r   z _should_merge.<locals>.<genexpr>~  s     
9.B2.   c              3   &   K   | ]  }|v  
 y wr   r   r   n	col_namess     r   r   z _should_merge.<locals>.<genexpr>  s     Z/Y!qI~/Yr   )namer   r.   r-   c              3   &   K   | ]  }|v  
 y wr   r   r   s     r   r   z _should_merge.<locals>.<genexpr>  s     N0M1Y0Mr   )r      次数r   F)r   anyMERGE_KEYWORDS)r3   rB   chas_name	has_countr  r   s        @@r   _should_merger  {  sl    ^^%N

9.
99(/01QWWY0	Z/YZZN0MNN	%I%	 1s   A8c                     g d}| D ci c]  }|j                         | }}|D ]  }||v s||   c S  | D ]  }|j                         dvs|c S  yc c}w )u   找到名称列)r  u   故障名称r   r.   r-   u   备件spare)r   r  r   rankr   r0      系统Nr   r3   priorityr  col_lower_mapps        r   _find_name_columnr    sl    \H+237aQWWY\7M3 ##  779ddH   4s   Ac                 v    g d}| D ci c]  }|j                         | }}|D ]  }||v s||   c S  yc c}w )u   找到计数列)r   r  r   cntNr   r  s        r   _find_count_columnr    sL    3H+237aQWWY\7M3 ##  	 4   6c                 v    g d}| D ci c]  }|j                         | }}|D ]  }||v s||   c S  yc c}w )u   找到系统分类列)r0   r  u   系统分类systemNr   r  s        r   _find_system_columnr    sL    BH+237aQWWY\7M3 ##  	 4r  r   similarity_thresholdc           	      "  K   | rt        |       dk  r| S t        ||      s| S t        |      }t        |      t	        |      }|rs| S 	 ddlm} | D cg c]  }|j                  |      s||    }}t        |      dk  r| S  |j                  |       d{   }	t        ||	      D 
ci c]  \  }
}|
|
 }}
}t        | fdd      }g }t               }t        |      D ]  \  }}||v r|j                  |d      }|j                  |      }|s|j                  |       Ct        |      }t        |j                  d            }t               }|r%|j                  |      r|j!                  ||          t#        |dz   t        |            D ]  }||v r||   j                  |d      }|j                  |      }|s1 |j$                  ||      }||k\  sJ|t        ||   j                  d            z  }|r+||   j                  |      r|j!                  ||   |          |j!                  |        ||<   |r|rd	j'                  t        |            ||<   |j                  |       |j!                  |        |j)                  fd
d       d|v sd|v r#d|v rdnd}t        |      D ]  \  }}|dz   ||<    |S c c}w 7 <c c}}
w # t*        $ r#}t-        dt/        |              | cY d}~S d}~ww xY ww)u  
    使用 embedding 合并相似的故障/备件行

    例如：
    - "连杆大端轴承发生损坏异常" (7次, 其他) + "连杆大端轴承发生损坏异常" (6次, 汽车配件)
      → "连杆大端轴承发生损坏异常" (13次, 其他)
    - "发动机中空冷器管束芯体结垢或堵塞..." + "空冷器管束芯体结垢或堵塞..."
      → 合并为一条
    rQ   r   r   Nc                 :    t        | j                  d            S Nr   r   r;   r	count_cols    r   <lambda>z$merge_similar_rows.<locals>.<lambda>  s    QUU9a5H1Ir   T)keyreverser5   u   、c                 :    t        | j                  d            S r  r   r!  s    r   r$  z$merge_similar_rows.<locals>.<lambda>  s    s155A+>'?r   r  r   u,   Embedding合并失败，使用原始数据: )r   r  r  r  r  rq   r   r;   get_embeddings_batch_asynczipsortedr   r   r9   r   r   r   r   cosine_similarityr<   sortr`   rU   ra   )r   r3   rB   r  name_col
system_colr   r   names
embeddingsr  embname_emb_mapsorted_rowsr   merged_indicesr   name_iemb_i
merged_rowtotal_countsystemsjname_jemb_j
similarityrank_colidxri   r#  s                                @r   r   r     s     3t9>(+ )H"7+I$W-J9D1*.D$3#''(2CX$Du:?K?9??FF
36uj3IJ3IidCc	3IJT'ISWX,FAsN"WWXr*F $$V,E""3'cJcggi34KeGcggj1C
O,1q5#k"23&$Q++Hb9$((08Y88F
!553{1~'9'9)Q'G#HHK!k!n&8&8&DKN:$>?"&&q)! 4$ %0Jy!g).F7O)D
:&z*q!Q -T 	?NWG 3!'7!2vH%k2S #aH 3 { E GJt  <SVHEFs   AL
K  K-K4K  LK  KK  /K<D&K  #C.K  LK  K   	L)LLLLLr   )g333333?)4ry   rW   rZ   r   r   typingr   r   r   r   r   
sqlalchemyr	   langchain_community.utilitiesr
   configr   r   rq   r   rr   r   tools.texttosql_utilsr   r   __annotations__Lockr   r   r8   r   r   r   ra   rA   rj   rs   r`   ru   r   r   r   r   r   r   r  r  r  r  r  r   r   r   r   r   <module>rG     s   
    3 3  5 E ) $ 0 '+h{# *7<<>	{ 	" "W )$
 V#4	
 d#]	
 k#^	
 h#g	
 h#b	
  G#./	
I*. b *95::<=3 02T 2TC 2TDcN 2Tr<
s <
 <
c3h <
F	I 	
Q!3 Q!5sC0 Q!p7
3 7
4S> 7
| 	^# ^Xc] ^dSVX[S[n ^B7Z7Z7Z 7Z T#s(^$	7Z
 
#s(^7Z| [49   
tCy 
Xc] 
S	 hsm c x}  #'	`
tCH~
`#Y` `  	`
 
$sCx.`r   zQxh
    >;j                        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mZ d dlm	Z	 d dl
mZ d dlmZ d dlmZmZ d dlmZmZmZmZ ed   Zed	   ed
   fZed   Zed   Zed   Zed   Zed   Zed   ZeZdada d Z!d Z"de#fdZ$dedefdZ%d"de#de&dee   fdZ'dZ(dZ)d#de#de&de#fdZ*e+dk(  r) ejX                   e*d             Z- e.d!        e.e-       yy)$    N)ListDict)GraphDatabase)HybridCypherRetriever)Embedder)LocalBgeM3Embeddings	OpenaiAPI)MAP_INSNEO4J_CONFIGINDEX_CONFIGEMBEDDING_CONFIGuriuserpasswordNAME_PROPERTYFULLTEXT_PROPERTYEMBEDDING_PROPERTYSEARCH_LABELVECTOR_INDEX_NAMEFULLTEXT_INDEX_NAMEc                  X    t         t        j                  t        t              a t         S )N)auth)_driverr   driverURIAUTH     /app/tools/texttosql_utils.py
get_driverr       s    &&s6Nr   c                  P    t         t        t        d   t        d         a t         S )Nbase_urlapi_key)r"   r#   )	_embedderr   r   r   r   r   get_embedderr%   #   s*    (%j1$Y/
	 r   sc                 t   t        j                  d|       }t        j                  d|       }t        j                  d|       }|r|j                  d      nd}dg}|r%	 t        j                  |j                  d            }|rt        |j                  d            nd}|||fS # t
        t        f$ r Y 4w xY w)Nzname='([^']*)'zlabels=(\[[^\]]*\])zscore=([\d.]+)      未知名称   未知标签        )researchgroupastliteral_eval
ValueErrorSyntaxErrorfloat)r&   
name_matchlabels_matchscore_matchnamelabelsscores          r   parse_record_stringr:   .   s    99.Q7J993Q7L99.a8K$.Za NDF	%%l&8&8&;<F ,7E+##A&'CE K( 		s   $B% %B76B7embedderreturnc                 P    t        | t        t        |dt         dt         d      S )Nz*
            RETURN
                node.`z>` AS name,
                [lbl IN labels(node) WHERE lbl <> 'z,'] AS labels,
                score
        )r   vector_index_namefulltext_index_namer;   retrieval_query)r   r   r   r   r   )sync_driverr;   s     r   build_retrieverrB   ?   s:     +/$o &44@> B	 r   sentencetop_kc           	      "   t        t               t                     }|j                  | |      }g }|j                  D ]6  }|j
                  }d}dg}d}	t        |d      r7|j                  d|      }|j                  d|      }|j                  d|	      }	nt        |t              r}|j                  d	      rt        |      \  }}}	n\	 t        j                  |      }
t        |
t              r6|
j                  d|      }|
j                  d|      }|
j                  d|	      }	|	dk(  r4t        |d
      r(|j"                  r|j"                  j                  d|	      }	|j%                  |||	ddd       9 |S # t        t         f$ r |}Y hw xY w)N)
query_textrD   r)   r*   r+   keysr7   r8   r9   z<Recordmetadatahybrid )u   标签u   名称u   得分u   来源fulltext_snippet)rB   r    r%   r-   itemscontenthasattrget
isinstancestr
startswithr:   r/   r0   dictr1   r2   rH   append)rC   rD   	retrieverresults_rawhybrid_resultsitemrM   r7   r8   r9   parseds              r   _hybrid_search_syncrZ   O   s}   !*,?I""he"DK!#N!!,, !"7F#[[40D[[62F[[51E%!!),&9'&B#fe# --g6F!&$/!'Fd!;!'Hf!=!'Ge!< C<GD*5$--MM%%gu5E "
 	5 "D  #K0 #"D#s   
AE::FFu  
请根据给出的问题，以及问题相关的检索结果，以及实体类型和sql表字段映射表，筛选出与问题相关的信息并输出。
要求：
1. 请仔细分析问题和检索结果，确定问题中出现的实体类型和sql表字段。
2. 输出内容可以为充分分析后的一段文本，即你对这个问题中所用到的实体类型和sql表字段的描述。
3. 给出的信息尽量精简，不能省略任何重要信息。
实体类型和sql表字段映射表：
    {map_ins}
其中键表示实体类型，值表示sql表字段。

检索结果：
{results}

问题：{user_question}


案例1：
用户问题为：扫气箱内发现润滑油泄漏发生了多少次？
检索知识库为：   
   [ 1] score=1.0000 | 活塞杆填料函密封失效导致扫气箱内发现润滑油泄漏  标签=['故障模式']
   [ 2] score=0.9298 | 排除喷油器雾化不良故障  标签=['维修项目']
   [ 3] score=0.9115 | 执行发动机燃油泄漏应急封堵操作  标签=['操作项目']
   [ 4] score=0.9082 | 活塞环磨损或断裂导致机座与机架组件润滑油消耗异常增加  标签=['故障模式']
   [ 5] score=0.9058 | 检测气缸套内径磨损量  标签=['维修项目']
   [ 6] score=0.9049 | 拆检活塞头磨损情况  标签=['维修项目']
   [ 7] score=0.9048 | 检查排气阀杆密封面磨损  标签=['维修项目']
   [ 8] score=0.9015 | 润滑油压力骤降导致轴承组件紧急停机  标签=['故障模式']
   [ 9] score=0.8985 | 喷油器组件的维修工作  标签=['维修工作']
   [10] score=0.8979 | 发动机的安全警告  标签=['安全警告']
输出为：
问题中扫气箱内发现润滑油泄漏是一个故障现象，属于表中fault字段。
u   你是一个专业信息筛选助手，根据给出的问题和问题检索到的相关实体关系，筛选出与问题相关的信息。user_questionc                    K   t        j                  t        | |       d{   }t        j                  t
        t        j                  |t        |              d{   }|j                         S 7 Q7 w)u   
    参数:
        user_question: 用户问题
        top_k:         检索返回条数
    返回:
        LLM 筛选结果字符串
    N)resultsmap_insr[   )system_promptquery)
asyncio	to_threadrZ   r	   open_api_chat_without_thinkingSYSTEM_PROMPTPROMPT_TEMPLATEformatr^   strip)r[   rD   r]   ress       r   get_extra_infori      sj      %%&9=%PPG 88#$$WgTa$b C
 99; Qs!   A7A3<A7A5A75A7__main__u*   发动机这个月发生了多少次故障l   q{U)
   )   )/osr/   r,   ra   httpxtypingr   r   neo4jr   neo4j_graphrag.retrieversr   neo4j_graphrag.embeddings.baser   modelsAPI.model_apir   r	   configr
   r   r   r   r   r   r   r   r   r   r   r   r^   r   r$   r    r%   rQ   r:   rB   intrZ   re   rd   ri   __name__runanswerprintr   r   r   <module>rz      sF   	 
 	     ; 3 ? H H #5)#F+\*-EF"?3"#67 "#78 ">2"#67 "#89  	3 "8 8M  '# 'c '4: 'VB ] C  * zW[[(TUVF	
	&M r   #x3
    бMj (                        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ZddlmZ ddlm	Z	m
Z
mZ ddlmZ ddlmZ ddlZddlmZ ddlmZmZ dd	lmZ dd
lmZ ed   Zed   ZdZdZdZdZdZ de!de!fdZ"de#de#de#fdZ$de!de#fdZ% e#eez        eefde!de!de#de#de#de!fdZ&	 	 d)de!d e!d!e!d"e!de
e!ef   f
d#Z'e	 d*de!d$e	e!   de!fd%       Z(e	 d+de!d&e!d'e#de!fd(       Z)y),uW   
VLM图像处理工具模块
包含图像识别、图像压缩、图像保存等功能
    N)datetime)OptionalDictAny)Image)BytesIO)tool)
VLM_CONFIGSERVER_CONFIG)	OpenaiAPI)track_function_callsapi_basemodeli   皙?   U   u  你是一个专业的工业设备巡检专家助手。
你的任务是协助工程师分析现场情况。

当你遇到以下情况时：
1. 用户提供了图片路径（如 .png, .jpg, /app/data/... 等）。
2. 用户询问有关设备外观、颜色、仪表读数或物理损坏的问题。

你应该：
- 调用 `vlm_image_to_text` 工具。
- 在 `prompt` 参数中，根据用户的具体意图（如：检查漏油、读仪表、看指示灯）量身定制分析指令。
- 获取 VLM 结果后，结合专业知识给出建议。

image_pathreturnc                     t        | d      5 }t        j                  |j                               j	                  d      cddd       S # 1 sw Y   yxY w)u&   将本地图片转换为 Base64 编码rbutf-8N)openbase64	b64encodereaddecode)r   fs     Ae:\ZKYNLP\Hjunproject\project0506\wx-agent\app\tools\vlm_tools.pyencode_imager   ,   s9    	j$	1)009 
 		s   2A		Awidthheightc                 |    t        j                  |dz        }t        j                  | dz        }||z  dz   }|dz  S )u   
    根据 Qwen-VL 的图像分块策略估算视觉 tokens。
    公式来源：Qwen-VL 官方技术文档（Naive resizing + 192 tokens per unit）
    iP        )mathceil)r    r!   units_hunits_wtotal_unitss        r   estimate_qwen_vl_visual_tokensr*   2   sB    
 ii%Gii$GG#a'K    textc                 `    t        j                  d      }t        |j                  |             S )u;   使用 tiktoken 估算文本 token 数（兼容中英文）cl100k_base)tiktokenget_encodinglenencode)r,   encs     r   count_text_tokensr4   =   s&    



.Cszz$  r+   base64_imageprompt_textmax_input_tokensmin_sizejpeg_qualityc                    | j                  d      st        d      	 | j                  dd      \  }}t        j                  |      }t        j                  t        |            j                  d      }|j                  \  }	}
t        |      }t        |	|
      }||z   }t        d|	 d	|
 d
| d| d| 
       ||k  rt        d       | S d}|}||kD  rT|dkD  rO|dz  }t        |t        |	|z              }t        |t        |
|z              }|t        ||      z   }||kD  r|dkD  rOt        |t        |	|z              }t        |t        |
|z              }t        d| d	| d|        |j!                  ||ft
        j"                  j$                        }t               }|j'                  |d|       t        j(                  |j+                               j-                  d      }d| S # t        $ r}t        d|       d}~ww xY w)ua   
    智能压缩 base64 图像，确保 (文本 tokens + 视觉 tokens) <= max_input_tokens
    
data:imagez:Invalid base64 image format. Must start with 'data:image'.,r#   RGBzFailed to decode base64 image: Nu   [VLM Preprocess] 原始尺寸: xu    | 文本 tokens: u    | 视觉 tokens: u    | 总计: u!   [VLM Preprocess] ✅ 无需压缩g      ?g?r   u1   [VLM Preprocess] ⚠️ 需压缩 → 新尺寸: u    | 预估总 tokens: JPEG)formatqualityr   zdata:image/jpeg;base64,)
startswith
ValueErrorsplitr   	b64decoder   r   r   convertsize	Exceptionr4   r*   printmaxintresize
ResamplingLANCZOSsaver   getvaluer   )r5   r6   r7   r8   r9   headerb64_data
image_dataimgorig_worig_hetext_tokensvisual_tokenstotal_tokensscaletarget_tokensnew_wnew_hfinal_wfinal_hresized_imgbuffercompressed_b64s                           r   smart_resize_base64_imagerd   C   s?    ""<0UVV@'--c15%%h/
jj,-55e< $K0K266BM.L	+F81VH<N{m[mn{m|  }H  IU  HV  W  X''12E M
*
*us{Hc&5.12Hc&5.12#&DUE&RR	 *
*us{ (C/0G(C/0G	=gYayPefset
uv**gw/1A1A1I1IJKYFVFLA%%foo&78??HN$^$455=  @:1#>??@s   A&G. .	H
7HH
description
output_dirrecord_filec                    	 | j                  d      sdddS | j                  dd      \  }}d|v sd|v rd}nd	|v rd	}nd
|v rd
}n	d|v rd}nd}t        j                  |d       t	        j
                         j                  dd  dt        j                         j                  d       d| }t        j                  j                  ||      }t        j                  |      }	t        |d      5 }
|
j                  |	       ddd       |||t        j                         j!                         d}t        j                  t        j                  j#                  |      d       g }t        j                  j%                  |      r?	 t        |dd      5 }
t'        j(                  |
      }t+        |t,              sg }ddd       |j3                  |       t        |dd      5 }
t'        j4                  ||
dd       ddd       t7        d|        d||ddS # 1 sw Y   xY w# 1 sw Y   lxY w# t&        j.                  t0        f$ r g }Y w xY w# 1 sw Y   XxY w# t8        $ r}dddt;        |      dcY d}~S d}~ww xY w)u  
    保存 base64 图片到指定目录，并记录图片名称和描述到 JSON 文件。
    
    Args:
        base64_image: base64 编码的图片数据（data:image/xxx;base64,... 格式）
        description: 图片的描述文本
        output_dir: 图片保存目录
        record_file: 记录 JSON 文件路径
    
    Returns:
        包含保存结果的字典：{"success": bool, "image_name": str, "image_path": str, "error": str}
    r;   FzInvalid base64 image format)successerrorr<   r#   jpegjpgpnggifwebpT)exist_okN   _z%Y%m%d%H%M%S.wb)
image_namer   re   	timestamprr   )encodingw   )ensure_asciiindentu   [ImageSaved] 图片已保存: )ri   ru   r   rj   )rB   rD   osmakedirsuuiduuid4hexr   nowstrftimepathjoinr   rE   r   write	isoformatdirnameexistsjsonload
isinstancelistJSONDecodeErrorIOErrorappenddumprI   rH   str)r5   re   rf   rg   rQ   rR   extru   r   rS   r   record_entryexisting_recordsrW   s                 r   save_base64_image_and_recordr   v   sY   $A
&&|4$/LMM'--c15VuCf_Cf_CvCC
J.

(("-.a0G0G0W/XXYZ]Y^_
WW\\*j9
%%h/
*d#qGGJ $ %$&!113	
 	BGGOOK04@77>>+&&+sW='+yy|$%&6=+-( > 	-+sW5II&aH 6 	.zl;< $$	
 	
; $# >= (('2 &#% &
 65  
V	
 	

s   I" CI" 1HBI" H5 (H)>H5 I" %I?I" H&!I" )H2.H5 5II" II" II" "	J+J :J Jpromptc                   K   d}|r| d| n|}t        | |t        t        t        z              }	 t	        j
                  |       d{   }t        d|        t        | |dd      }|d	   r,t        d
|d           t        d    d|d    }| d| d}|S t        d|d           |S 7 e# t        $ r:}ddl
}	dt        |       d|	j                          }
t        |
       |
cY d}~S d}~ww xY ww)u   
    调用 Qwen3.5-35B 进行工业巡检分析。
    - 自动移除所有 <think...</think 包裹的内容（包括多行）
    - 仅返回最终结果文本
    - 支持 40K token 上下文，自动压缩大图
    ui  【重要指令】禁止输出任何形式的   <think...</think、<reasoning></reasoning> 或其他内部思考过程。仅输出最终的专业分析结果。

你是一位资深的工业巡检专家。请仔细观察这张图片并按以下结构报告：
1. 设备识别：图中是什么设备？型号或标签是否可见？
2. 状态评估：仪表盘数值是否在正常区间？指示灯颜色是什么？
3. 异常检测：是否存在漏油、生锈、电缆破损、螺丝松动或烟雾？
4. 环境风险：周围是否有杂物堆放或安全隐患？
请用专业、客观、简短的语言描述。u   
特别注意：)r5   r6   r7   Nu   ✅ 最终输出:
picturezpicture/image_records.json)r5   re   rf   rg   ri   u   📷 图片已保存: ru   base_urlz	/picture/u   

![用户上传图片]()u   ⚠️ 图片保存失败: rj   r   u   VLM 调用失败: 
)rd   rK   MAX_MODEL_LENINPUT_TOKEN_SAFETY_RATIOr   open_api_vl_without_thinkingrI   r   r   rH   	tracebackr   
format_exc)r   r   default_promptfinal_prompt
safe_imageresultsave_result	image_urlrW   r   	error_msgs              r   vlm_image_to_textr      sA    	;  DJn%%6vh?~L* ]-EEFJ ==jII#F8,-2# 4	
 y!*;|+D*EFG(45Y{<?X>YZIx9)AFF  /G0D/EFG# J&  (Q93G3G3I2JK	i	sS   0C9B3 B1AB3 C9B3 0C91B3 3	C6</C1+C6,C91C66C9querytop_kc           
        K   	 t        | |       d{   }ddlm}  || d| |       d{   }|j                  dd      rW|j                  d	i       }d
}|j	                         D ](  \  }}	|	D ]  }
|d| d|
j                  dd
       dz  }  * d| d| S |S 7 7 q# t
        $ r}dt        |       cY d}~S d}~ww xY ww)u   
    图像RAG描述工具
    先用VLM分析图像，然后用RAG检索相关知识

    Args:
        image_path: 图像路径（base64格式）
        query: 查询文本
        top_k: RAG检索数量

    Returns:
        分析结果文本
    )r   Nr#   )
rag_search )r   r   ri   FsourceCitation u   【u   】r,   z

u   图像分析结果：
u   

相关知识：
u   图像RAG分析失败: )r   	rag_toolsr   getitemsrH   r   )r   r   r   
vlm_resultr   
rag_resultsource_citationrag_textresourcer   itemrW   s               r   image_rag_describer     s     $2,ZFF
)%ugQzl,C5QQ
>>)U+(nn-=rBOH#2#8#8#:%!D#hZs488FB3G2H MMH " $; -ZL8MhZXX G R  2(Q112sa   C	B% B!B% B#A,B% C	B%  C	!B% #B% %	C.C;C<C	CC	)image_inputzimage_input/image_records.json)N)   )*__doc__r}   rer   r%   r   r   r   typingr   r   r   PILr   ior   r/   langchain_core.toolsr	   configr
   r   modelsAPI.model_apir   utils.function_trackerr   VLM_API_BASEVLM_MODEL_NAMEr   r   MIN_IMAGE_SIZEJPEG_QUALITYSYSTEM_PROMPT_VLMr   r   rK   r*   r4   rd   r   r   r    r+   r   <module>r      s   
 	      & &    % , ) 7 *%G$  :S :S :# s s !C !C !  0H HI"$060606 06 	06
 06 	06l $7	S
S
S
 S
 	S

 
#s(^S
l  !66SM6 	6 6r  #2#2#2 #2 		#2 #2r+   j+x"""
智能体使用统计工具
记录和统计智能体的调用次数（PostgreSQL数据库存储）
"""
from datetime import datetime
from typing import Dict, Any

from config import POSTGRES_CONNECTION_STRING


ROUTE_FLAG_DISPLAY_NAMES = {
    "问题排查": "问题排查",
    "操作使用": "操作使用",
    "百科问答": "百科问答"
}

ROUTE_FLAG_ICONS = {
    "问题排查": "detection",
    "操作使用": "repair",
    "百科问答": "doc"
}

ROUTE_FLAG_COLORS = {
    "问题排查": "#FFB800",
    "操作使用": "#00C2FF",
    "百科问答": "#9153FF"
}


async def init_agent_usage_table():
    """
    初始化 agent_usage_records 表
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[agent_usage_statistics] psycopg_pool 未安装，无法初始化表")
        return

    async with AsyncConnectionPool(
        POSTGRES_CONNECTION_STRING,
        kwargs={"autocommit": True}
    ) as pool:
        async with pool.connection() as conn:
            async with conn.cursor() as cur:
                await cur.execute("""
                    CREATE TABLE IF NOT EXISTS agent_usage_records (
                        id SERIAL PRIMARY KEY,
                        chat_id TEXT NOT NULL DEFAULT '',
                        route_flag TEXT NOT NULL DEFAULT '',
                        message_id TEXT NOT NULL DEFAULT '',
                        created_at TIMESTAMP NOT NULL DEFAULT NOW(),
                        UNIQUE(chat_id, route_flag)
                    )
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS agent_usage_records_route_flag_idx ON agent_usage_records(route_flag)
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS agent_usage_records_created_at_idx ON agent_usage_records(created_at)
                """)
                print("[agent_usage_statistics] agent_usage_records 表初始化完成")


async def record_agent_usage(chat_id: str, route_flag: str, message_id: str = "") -> bool:
    """
    记录智能体使用情况到数据库

    Args:
        chat_id: 会话ID
        route_flag: 路由标志（智能体类型）
        message_id: 消息ID

    Returns:
        是否记录成功
    """
    if not chat_id or not route_flag:
        return False

    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[agent_usage_statistics] psycopg_pool 未安装，无法记录")
        return False

    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    await cur.execute(
                        """
                        INSERT INTO agent_usage_records (chat_id, route_flag, message_id, created_at)
                        VALUES (%s, %s, %s, %s)
                        ON CONFLICT (chat_id, route_flag) DO UPDATE SET
                            message_id = EXCLUDED.message_id,
                            created_at = EXCLUDED.created_at
                        """,
                        (chat_id, route_flag, message_id or "", datetime.now())
                    )
        return True
    except Exception as e:
        print(f"[agent_usage_statistics] 记录智能体使用失败: {e}")
        return False


def _format_count(count: int) -> str:
    if count >= 10000:
        return f"{count / 10000:.1f}万"
    else:
        return f"{count:,}"


async def get_agent_usage_statistics() -> Dict[str, Any]:
    """
    从数据库查询智能体使用统计

    统计逻辑：
    - 同一 chat_id + route_flag 只保留一条记录
    - 统计各类型的总使用次数
    - 统计近6个月的月度使用次数

    Returns:
        统计结果字典
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[agent_usage_statistics] psycopg_pool 未安装，无法查询")
        return {"success": False, "data": None}

    required_routes = ["操作使用", "问题排查", "百科问答"]

    now = datetime.now()
    last_6_months = []
    for i in range(5, -1, -1):
        year = now.year
        month = now.month - i
        while month <= 0:
            month += 12
            year -= 1
        last_6_months.append({
            "year": year,
            "month": month,
            "key": f"{year}-{month:02d}",
            "label": f"{month}月"
        })

    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    # 查询各类型总使用次数
                    route_counts = {}
                    for route_flag in required_routes:
                        await cur.execute(
                            """
                            SELECT COUNT(*) FROM agent_usage_records
                            WHERE route_flag = %s
                            """,
                            (route_flag,)
                        )
                        row = await cur.fetchone()
                        route_counts[route_flag] = row[0] if row else 0

                    # 查询近6个月各类型月度使用次数
                    monthly_counts = {route: {m["key"]: 0 for m in last_6_months} for route in required_routes}

                    for route_flag in required_routes:
                        for m in last_6_months:
                            month_start = datetime(m["year"], m["month"], 1)
                            if m["month"] == 12:
                                month_end = datetime(m["year"] + 1, 1, 1)
                            else:
                                month_end = datetime(m["year"], m["month"] + 1, 1)

                            await cur.execute(
                                """
                                SELECT COUNT(*) FROM agent_usage_records
                                WHERE route_flag = %s AND created_at >= %s AND created_at < %s
                                """,
                                (route_flag, month_start, month_end)
                            )
                            row = await cur.fetchone()
                            monthly_counts[route_flag][m["key"]] = row[0] if row else 0

    except Exception as e:
        print(f"[agent_usage_statistics] 查询统计数据失败: {e}")
        import traceback
        traceback.print_exc()
        return {"success": False, "data": None}

    total = sum(route_counts.get(route, 0) for route in required_routes)

    types_data = []
    monthly_stats = []
    for route_flag in required_routes:
        count = route_counts.get(route_flag, 0)
        display_name = ROUTE_FLAG_DISPLAY_NAMES.get(route_flag, route_flag)
        icon = ROUTE_FLAG_ICONS.get(route_flag, "info")
        color = ROUTE_FLAG_COLORS.get(route_flag, "#8C8C8C")

        types_data.append({
            "name": display_name,
            "count": _format_count(count),
            "icon": icon,
            "color": color
        })

        monthly_data = []
        for m in last_6_months:
            monthly_data.append({
                "month": m["label"],
                "count": monthly_counts[route_flag][m["key"]]
            })

        monthly_stats.append({
            "name": display_name,
            "color": color,
            "monthlyCounts": monthly_data
        })

    return {
        "success": True,
        "data": {
            "total": _format_count(total),
            "types": types_data,
            "monthlyStats": monthly_stats,
            "months": [m["label"] for m in last_6_months]
        }
    }

x+%"""
故障记录数据库模块
用于在故障诊断智能体生成方案后自动记录故障信息到PostgreSQL数据库
记录内容：舷号、设备、故障、备件、系统
"""
import json
import re
import asyncio
from datetime import datetime
from typing import Dict, Any, Optional, List

from config import POSTGRES_CONNECTION_STRING


async def init_fault_records_table():
    """
    初始化 fault_records 表
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[fault_record_db] psycopg_pool 未安装，无法初始化表")
        return

    async with AsyncConnectionPool(
        POSTGRES_CONNECTION_STRING,
        kwargs={"autocommit": True}
    ) as pool:
        async with pool.connection() as conn:
            async with conn.cursor() as cur:
                await cur.execute("""
                    CREATE TABLE IF NOT EXISTS fault_records (
                        id SERIAL PRIMARY KEY,
                        ship_number TEXT NOT NULL DEFAULT '',
                        device_name TEXT NOT NULL DEFAULT '',
                        fault TEXT NOT NULL DEFAULT '',
                        spare_parts JSONB NOT NULL DEFAULT '[]',
                        system_name TEXT NOT NULL DEFAULT '',
                        created_at TIMESTAMP NOT NULL DEFAULT NOW()
                    )
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS fault_records_ship_number_idx ON fault_records(ship_number)
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS fault_records_device_name_idx ON fault_records(device_name)
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS fault_records_system_name_idx ON fault_records(system_name)
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS fault_records_created_at_idx ON fault_records(created_at)
                """)
                print("[fault_record_db] fault_records 表初始化完成")



async def extract_spare_parts_from_scheme(scheme_content: str) -> List[str]:
    """
    从方案内容中用大模型抽取备件名称列表

    Args:
        scheme_content: 方案内容（Markdown格式）

    Returns:
        备件名称列表
    """
    if not scheme_content or len(scheme_content.strip()) < 10:
        return []

    prompt = f"""从以下维修方案内容中提取所有提到的备品备件名称。

方案内容：
{scheme_content[:3000]}

提取规则：
1. 找到"备品备件"、"备件"等相关章节，提取其中的项目名称
2. 只提取名称，不要提取型号、规格、数量、材质、用途等
3. 如果没有专门的章节，也从全文中识别备件名称

以JSON数组格式返回：
{{
    "备品备件": [备件名称1, 备件名称2, ...]
}}

如果没有提到备品备件，请返回空数组 []"""

    try:
        from modelsAPI.model_api import OpenaiAPI
        result_text = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            json_output=True
        )
        print("抽取出来的备品备件", result_text)

        result_text = result_text.strip()
        result_text = re.sub(r'^```json\s*', '', result_text, flags=re.IGNORECASE)
        result_text = re.sub(r'^```\s*', '', result_text)
        result_text = re.sub(r'```$', '', result_text)

        try:
            parsed = json.loads(result_text)
        except json.JSONDecodeError:
            json_match = re.search(r'\{.*\}', result_text, re.DOTALL)
            if json_match:
                parsed = json.loads(json_match.group(0))
            else:
                return []

        if isinstance(parsed, dict):
            if "备品备件" in parsed and isinstance(parsed["备品备件"], list):
                return [str(part).strip() for part in parsed["备品备件"] if part]
            all_parts = []
            for v in parsed.values():
                if isinstance(v, list):
                    all_parts.extend([str(part).strip() for part in v if part])
            return all_parts
        elif isinstance(parsed, list):
            return [str(part).strip() for part in parsed if part]

        return []

    except Exception as e:
        print(f"[fault_record_db] 从方案提取备件失败: {str(e)}")
        return []


async def save_fault_record(
    ship_number: str,
    device_name: str,
    fault: str,
    spare_parts: List[str],
    system_name: str
) -> bool:
    """
    保存故障记录到数据库

    Args:
        ship_number: 舷号
        device_name: 设备名称
        fault: 故障现象
        spare_parts: 备件列表
        system_name: 系统名称

    Returns:
        是否保存成功
    """
    if not ship_number and not device_name and not fault:
        print("[fault_record_db] 舷号、设备、故障均为空，跳过保存")
        return False

    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[fault_record_db] psycopg_pool 未安装，无法保存")
        return False

    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    await cur.execute(
                        """
                        INSERT INTO fault_records (ship_number, device_name, fault, spare_parts, system_name, created_at)
                        VALUES (%s, %s, %s, %s, %s, %s)
                        """,
                        (
                            ship_number or "",
                            device_name or "",
                            fault or "",
                            json.dumps(spare_parts, ensure_ascii=False),
                            system_name or "",
                            datetime.now()
                        )
                    )
        print(f"[fault_record_db] 故障记录已保存: 舷号={ship_number}, 设备={device_name}, 故障={fault}, 系统={system_name}, 备件数={len(spare_parts)}")
        return True
    except Exception as e:
        print(f"[fault_record_db] 保存故障记录失败: {str(e)}")
        import traceback
        traceback.print_exc()
        return False


async def record_fault_from_state(state: Dict[str, Any]) -> bool:
    """
    从工作流状态中提取故障信息并记录到数据库
    在故障诊断智能体生成方案后调用

    流程：
    1. 从状态中获取舷号、设备、故障
    2. 从方案内容中用大模型抽取备件
    3. 通过设备名称反推系统
    4. 保存到数据库

    Args:
        state: 工作流状态字典

    Returns:
        是否记录成功
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""

    if not device_name and not fault:
        print("[fault_record_db] 设备和故障均为空，跳过记录")
        return False

    scheme_content = state.get("last_generated_scheme", "") or state.get("response", "") or ""

    spare_parts = await extract_spare_parts_from_scheme(scheme_content)

    system_name = "其他"
    if device_name:
        from tools.fault_statistics import get_device_system_from_neo4j
        system_name = await get_device_system_from_neo4j(device_name)

    return await save_fault_record(
        ship_number=ship_number,
        device_name=device_name,
        fault=fault,
        spare_parts=spare_parts,
        system_name=system_name
    )


async def query_fault_records(
    ship_number: Optional[str] = None,
    device_name: Optional[str] = None,
    system_name: Optional[str] = None,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    limit: int = 1000
) -> List[Dict[str, Any]]:
    """
    从数据库查询故障记录

    Args:
        ship_number: 舷号过滤
        device_name: 设备名称过滤
        system_name: 系统名称过滤
        start_date: 开始日期（格式：YYYY-MM-DD）
        end_date: 结束日期（格式：YYYY-MM-DD）
        limit: 返回记录数上限

    Returns:
        故障记录列表
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[fault_record_db] psycopg_pool 未安装，无法查询")
        return []

    from datetime import timedelta

    conditions = []
    params = []
    idx = 1

    if ship_number:
        conditions.append(f"ship_number = %s")
        params.append(ship_number)

    if device_name:
        conditions.append(f"device_name = %s")
        params.append(device_name)

    if system_name:
        conditions.append(f"system_name = %s")
        params.append(system_name)

    if start_date:
        try:
            start_dt = datetime.strptime(start_date, "%Y-%m-%d")
            conditions.append(f"created_at >= %s")
            params.append(start_dt)
        except ValueError:
            pass

    if end_date:
        try:
            end_dt = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1) - timedelta(seconds=1)
            conditions.append(f"created_at <= %s")
            params.append(end_dt)
        except ValueError:
            pass

    where_clause = " AND ".join(conditions) if conditions else "1=1"

    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    sql = f"""
                        SELECT id, ship_number, device_name, fault, spare_parts, system_name, created_at
                        FROM fault_records
                        WHERE {where_clause}
                        ORDER BY created_at DESC
                        LIMIT %s
                    """
                    params.append(limit)
                    await cur.execute(sql, params)
                    rows = await cur.fetchall()
                    columns = ["id", "ship_number", "device_name", "fault", "spare_parts", "system_name", "created_at"]
                    results = []
                    for row in rows:
                        record = dict(zip(columns, row))
                        if isinstance(record.get("spare_parts"), str):
                            try:
                                record["spare_parts"] = json.loads(record["spare_parts"])
                            except Exception:
                                record["spare_parts"] = []
                        if isinstance(record.get("created_at"), datetime):
                            record["created_at"] = record["created_at"].isoformat()
                        results.append(record)
                    return results
    except Exception as e:
        print(f"[fault_record_db] 查询故障记录失败: {str(e)}")
        import traceback
        traceback.print_exc()
        return []

췌xx8"""
故障类型统计工具模块
用于统计故障诊断智能体记录的故障信息
数据来源：PostgreSQL fault_records 表
"""
import os
import re
import json
import httpx
from datetime import datetime, timedelta
from typing import Dict, Any, Optional, List
from difflib import SequenceMatcher
import asyncio

from langchain_core.tools import tool
from utils.function_tracker import track_function_calls
from config import REPAIR_FEEDBACK_CONFIG

neo4j_cache = {}


def fuzzy_match_system(user_input: str, system_name: str, threshold: float = 0.6) -> bool:
    if not user_input or not system_name:
        return False

    user_input = user_input.strip().lower()
    system_name = system_name.strip().lower()

    if user_input == system_name:
        return True

    if user_input in system_name or system_name in user_input:
        return True

    similarity = SequenceMatcher(None, user_input, system_name).ratio()

    return similarity >= threshold


async def get_device_system_from_neo4j(device_name: str) -> str:
    """
    从 Neo4j 图谱中查询设备对应的系统（调用外部接口），带缓存机制
    """
    if not device_name or not device_name.strip():
        return "其他"

    device_name_clean = device_name.strip().lower()

    if device_name_clean in neo4j_cache:
        return neo4j_cache[device_name_clean]

    from config import DEVICE_SYSTEM_CONFIG

    endpoint = DEVICE_SYSTEM_CONFIG.get("endpoint")
    timeout = DEVICE_SYSTEM_CONFIG.get("timeout", 30.0)
    min_hops = DEVICE_SYSTEM_CONFIG.get("default_min_hops", 2)
    max_hops = DEVICE_SYSTEM_CONFIG.get("default_max_hops", 8)
    top_k = DEVICE_SYSTEM_CONFIG.get("default_top_k", 10)

    if not endpoint:
        result = "其他"
        neo4j_cache[device_name_clean] = result
        return result

    try:
        payload = {
            "device_name": device_name.strip(),
            "min_hops": min_hops,
            "max_hops": max_hops,
            "top_k": top_k
        }

        async with httpx.AsyncClient(timeout=timeout) as client:
            response = await client.post(
                endpoint,
                json=payload,
                headers={"Content-Type": "application/json"}
            )

            if response.status_code != 200:
                result = "其他"
                neo4j_cache[device_name_clean] = result
                return result

            result_json = response.json()

            if not result_json.get("success", False):
                result = "其他"
                neo4j_cache[device_name_clean] = result
                return result

            systems = result_json.get("systems", [])
            if not systems or not isinstance(systems, list):
                result = "其他"
                neo4j_cache[device_name_clean] = result
                return result

            first_system = systems[0]
            if isinstance(first_system, dict):
                system_name = first_system.get("name") or first_system.get("系统名称") or first_system.get("名称")
                if system_name:
                    result = system_name.strip()
                    neo4j_cache[device_name_clean] = result
                    return result

            result = "其他"
            neo4j_cache[device_name_clean] = result
            return result

    except Exception as e:
        print(f"查询设备系统失败: {str(e)}")
        result = "其他"
        neo4j_cache[device_name_clean] = result
        return result


def generate_color_palette(n: int) -> List[str]:
    predefined_colors = [
        "#00C2FF", "#4E7CFE", "#9153FF", "#FFB800", "#00D16B",
        "#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8",
        "#F7DC6F", "#BB8FCE", "#85C1E9", "#F8B500", "#00E676",
        "#FF4081", "#7C4DFF", "#18FFFF", "#69F0AE", "#FFD740"
    ]

    if n <= len(predefined_colors):
        return predefined_colors[:n]

    colors = predefined_colors.copy()

    import colorsys
    for i in range(len(predefined_colors), n):
        hue = (i * 0.618033988749895) % 1.0
        saturation = 0.7 + (i % 3) * 0.1
        value = 0.8 + (i % 2) * 0.1

        rgb = colorsys.hsv_to_rgb(hue, saturation, value)
        color = "#{:02X}{:02X}{:02X}".format(
            int(rgb[0] * 255),
            int(rgb[1] * 255),
            int(rgb[2] * 255)
        )
        colors.append(color)

    return colors


async def _query_fault_records_from_db(
    ship_number: Optional[str] = None,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    system_name: Optional[str] = None,
    limit: int = 5000
) -> List[Dict[str, Any]]:
    """
    从数据库查询故障记录（内部共用方法）
    """
    from tools.fault_record_db import query_fault_records
    return await query_fault_records(
        ship_number=ship_number,
        system_name=system_name,
        start_date=start_date,
        end_date=end_date,
        limit=limit
    )


async def statistics_fault_types(
    ship_number_filter: Optional[str] = None
) -> Dict[str, Any]:
    """
    统计故障类型（从数据库读取），按系统分类计算百分比

    Args:
        ship_number_filter: 舷号过滤（可选）

    Returns:
        包含统计结果的字典
    """
    try:
        records = await _query_fault_records_from_db(ship_number=ship_number_filter)

        if not records:
            return {
                "success": True,
                "faultTypeData": []
            }

        system_totals = {}
        valid_count = 0

        for record in records:
            system_name = record.get("system_name", "其他")
            if not system_name:
                system_name = "其他"
            valid_count += 1

            if system_name not in system_totals:
                system_totals[system_name] = 0
            system_totals[system_name] += 1

        fault_type_data = []
        if valid_count > 0:
            unique_systems = sorted(system_totals.keys())
            colors = generate_color_palette(len(unique_systems))
            system_color_map = {system: color for system, color in zip(unique_systems, colors)}

            for system_name, count in system_totals.items():
                percentage = round((count / valid_count) * 100)
                color = system_color_map.get(system_name, "#6E7D91")
                fault_type_data.append({
                    "value": percentage,
                    "name": system_name,
                    "itemStyle": {
                        "color": color
                    }
                })

        fault_type_data.sort(key=lambda x: x["value"], reverse=True)

        return {
            "success": True,
            "faultTypeData": fault_type_data
        }

    except Exception as e:
        print(f"[故障类型统计错误] {str(e)}")
        import traceback
        traceback.print_exc()
        return {
            "success": False,
            "faultTypeData": []
        }


@tool
async def fault_type_statistics_tool(
    ship_number_filter: Optional[str] = None
) -> Dict[str, Any]:
    """
    故障类型统计工具（供工作流调用）
    统计故障类型，按系统分类并计算百分比

    Args:
        ship_number_filter: 舷号过滤（可选）

    Returns:
        统计结果，包含 success 和 faultTypeData 字段
    """
    result = await statistics_fault_types(ship_number_filter=ship_number_filter)
    return result


async def merge_similar_faults_with_embedding(
    fault_counter: Dict[str, int],
    fault_system_map: Dict[str, str],
    similarity_threshold: float = 0.85
) -> tuple:
    """
    使用embedding合并相似的故障
    """
    if not fault_counter:
        return {}, {}, {}

    fault_keys = list(fault_counter.keys())

    if len(fault_keys) <= 1:
        return fault_counter.copy(), fault_system_map.copy(), {}

    try:
        from modelsAPI.model_api import OpenaiAPI

        embeddings = await OpenaiAPI.get_embeddings_batch_async(fault_keys)

        fault_embedding_map = {key: emb for key, emb in zip(fault_keys, embeddings)}

        merged_counter = {}
        merged_system_map = {}
        merge_mapping = {}
        merged_keys = set()

        sorted_faults = sorted(fault_counter.items(), key=lambda x: x[1], reverse=True)

        for fault_key, count in sorted_faults:
            if fault_key in merged_keys:
                continue

            merged_keys.add(fault_key)
            merged_counter[fault_key] = count
            merged_system_map[fault_key] = fault_system_map.get(fault_key, "其他")

            for other_key, other_count in sorted_faults:
                if other_key in merged_keys or other_key == fault_key:
                    continue

                if fault_embedding_map.get(fault_key) and fault_embedding_map.get(other_key):
                    similarity = OpenaiAPI.cosine_similarity(
                        fault_embedding_map[fault_key],
                        fault_embedding_map[other_key]
                    )

                    if similarity >= similarity_threshold:
                        merged_counter[fault_key] += other_count
                        merged_keys.add(other_key)
                        merge_mapping[other_key] = fault_key

        return merged_counter, merged_system_map, merge_mapping

    except Exception as e:
        print(f"Embedding合并失败，使用原始数据: {str(e)}")
        return fault_counter.copy(), fault_system_map.copy(), {}


async def statistics_fault_frequency(
    top_n: int = 10,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    system_filter: Optional[str] = None,
    use_embedding_merge: bool = True,
    similarity_threshold: float = 0.85
) -> Dict[str, Any]:
    """
    统计故障发生次数（从数据库读取），按频率排序
    统计所有故障的数据，但只返回top N展示在表格中

    Args:
        top_n: 返回前 N 个高频故障（默认为 10）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        system_filter: 系统名称过滤（可选）
        use_embedding_merge: 是否使用embedding合并相似故障（默认True）
        similarity_threshold: 相似度阈值（默认0.85）

    Returns:
        包含统计结果的字典
    """
    try:
        records = await _query_fault_records_from_db(
            start_date=start_date,
            end_date=end_date
        )

        if not records:
            return {
                "success": True,
                "totalCount": 0,
                "totalTypes": 0,
                "highFreqFaults": []
            }

        fault_counter = {}
        fault_system_map = {}

        for record in records:
            device_name = record.get("device_name", "")
            fault = record.get("fault", "")
            system_name = record.get("system_name", "其他")

            if not device_name or not fault:
                continue

            if system_filter and not fuzzy_match_system(system_filter, system_name):
                continue

            fault_key = f"{device_name}{fault}"

            if fault_key not in fault_counter:
                fault_counter[fault_key] = 0
                fault_system_map[fault_key] = system_name

            fault_counter[fault_key] += 1

        if use_embedding_merge and len(fault_counter) > 1:
            fault_counter, fault_system_map, merge_mapping = await merge_similar_faults_with_embedding(
                fault_counter,
                fault_system_map,
                similarity_threshold
            )

            if merge_mapping:
                print(f"合并了 {len(merge_mapping)} 个相似故障")

        # 先计算全部数据的统计量
        total_count = sum(fault_counter.values())
        total_types = len(fault_counter)
        
        # 对全部数据排序
        sorted_faults_all = sorted(fault_counter.items(), key=lambda x: x[1], reverse=True)
        
        # 只取top N用于展示表格
        sorted_faults = sorted_faults_all[:top_n]

        high_freq_faults = []
        for rank, (fault_key, count) in enumerate(sorted_faults, start=1):
            system_name = fault_system_map.get(fault_key, "其他")

            high_freq_faults.append({
                "rank": rank,
                "name": fault_key,
                "system": system_name,
                "count": count
            })

        return {
            "success": True,
            "totalCount": total_count,
            "totalTypes": total_types,
            "highFreqFaults": high_freq_faults
        }

    except Exception as e:
        print(f"[故障频率统计错误] {str(e)}")
        import traceback
        traceback.print_exc()
        return {
            "success": False,
            "highFreqFaults": []
        }


@tool
async def fault_frequency_statistics_tool(
    top_n: Optional[int] = 6,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    system_filter: Optional[str] = None
) -> Dict[str, Any]:
    """
    故障发生次数统计工具（供工作流调用）
    统计故障发生次数，按频率排序

    Args:
        top_n: 返回前 N 个高频故障（默认为 6）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        system_filter: 系统名称过滤（可选）

    Returns:
        统计结果，包含 success 和 highFreqFaults 字段
    """
    result = await statistics_fault_frequency(
        top_n=top_n or 10,
        start_date=start_date,
        end_date=end_date,
        system_filter=system_filter
    )

    return result


async def statistics_spare_parts(
    ship_number_filter: Optional[str] = None,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    top_n: int = 6
) -> Dict[str, Any]:
    """
    统计备件消耗（从数据库读取）
    统计所有备件的数据，但只返回top N展示在表格中

    Args:
        ship_number_filter: 舷号过滤（可选）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        top_n: 表格中展示的前 N 个备件（默认为 5）

    Returns:
        包含统计结果的字典
    """
    try:
        records = await _query_fault_records_from_db(
            ship_number=ship_number_filter,
            start_date=start_date,
            end_date=end_date
        )

        if not records:
            return {
                "success": True,
                "totalCount": 0,
                "totalTypes": 0,
                "sparePartData": {
                    "categories": [],
                    "system": [],
                    "counter": []
                }
            }

        spare_part_counter = {}
        spare_part_system_map = {}

        for record in records:
            spare_parts = record.get("spare_parts", [])
            system_name = record.get("system_name", "其他")

            if not spare_parts:
                continue

            for part in spare_parts:
                if not part or not part.strip():
                    continue

                part_key = part.strip()

                if part_key not in spare_part_counter:
                    spare_part_counter[part_key] = 0
                    spare_part_system_map[part_key] = system_name

                spare_part_counter[part_key] += 1

        # 先计算全部数据的统计量
        total_count = sum(spare_part_counter.values())
        total_types = len(spare_part_counter)
        
        # 对全部数据排序
        sorted_parts_all = sorted(spare_part_counter.items(), key=lambda x: x[1], reverse=True)
        
        # 只取top N用于展示表格
        sorted_parts = sorted_parts_all[:top_n]

        categories = []
        systems = []
        counters = []

        for part_key, count in sorted_parts:
            categories.append(part_key)
            systems.append(spare_part_system_map.get(part_key, "其他"))
            counters.append(count)

        return {
            "success": True,
            "totalCount": total_count,
            "totalTypes": total_types,
            "sparePartData": {
                "categories": categories,
                "system": systems,
                "counter": counters
            }
        }

    except Exception as e:
        print(f"[备件统计错误] {str(e)}")
        import traceback
        traceback.print_exc()
        return {
            "success": False,
            "sparePartData": {
                "categories": [],
                "system": [],
                "counter": []
            }
        }


@tool
async def spare_parts_statistics_tool(
    ship_number: Optional[str] = None,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    top_n: Optional[int] = 5
) -> Dict[str, Any]:
    """
    备件消耗统计工具（供工作流调用）
    统计备件消耗情况

    Args:
        ship_number: 舷号过滤（可选）
        start_date: 开始日期（格式：YYYY-MM-DD，可选）
        end_date: 结束日期（格式：YYYY-MM-DD，可选）
        top_n: 返回前 N 个备件（默认为 5）

    Returns:
        统计结果，包含 success 和 sparePartData 字段
    """
    result = await statistics_spare_parts(
        ship_number_filter=ship_number,
        start_date=start_date,
        end_date=end_date,
        top_n=top_n or 5
    )

    return result


async def extract_device_from_text(text: str) -> Optional[str]:
    """
    从文本中提取设备名称（使用大模型）
    """
    if not text or not text.strip():
        return None

    prompt = f"""从以下文本中提取设备名称：

文本内容：
{text}

请识别文本中提到的具体设备名称，如：发动机、压缩机、水泵、发电机、空调机组、液压泵等。

请以JSON格式返回：
{{"device": "设备名称"}}

如果文本中没有提到任何设备，请返回 {{"device": null}}
只返回JSON，不要有其他内容。"""

    try:
        from modelsAPI.model_api import OpenaiAPI
        result_text = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            json_output=True
        )

        result_text = result_text.strip()
        result_text = re.sub(r'^```json\s*', '', result_text, flags=re.IGNORECASE)
        result_text = re.sub(r'^```\s*', '', result_text)
        result_text = re.sub(r'```$', '', result_text)

        json_match = re.search(r'\{.*\}', result_text, re.DOTALL)
        if json_match:
            result = json.loads(json_match.group(0))
            device = result.get("device")
            if device and device != "null":
                return str(device).strip()

        return None

    except Exception as e:
        print(f"大模型提取设备名称失败: {str(e)}")
        return None


async def classify_feedback_content(text: str) -> str:
    """
    对反馈内容进行分类（使用大模型）
    """
    if not text or not text.strip():
        return "其他"

    prompt = f"""请对以下反馈内容进行分类。

反馈内容：
{text}

分类类别（单选，选择最匹配的一个）：
1. 信息过时 - 反映文档或手册中的信息已经过时，不再适用
2. 步骤错误 - 反映操作步骤或流程存在错误
3. 步骤缺失 - 反映缺少必要的操作步骤或流程说明
4. 备件信息有误 - 反映备件型号、规格、数量等信息有误
5. 安全提示不足 - 反映缺少必要的安全警示或注意事项
6. 图示不清 - 反映图片、示意图不清晰或难以理解

请分析反馈内容，判断属于哪个类别，以JSON格式返回：
{{"category": "类别名称"}}

如果反馈内容不属于以上任何类别，请返回 {{"category": "其他"}}
只返回JSON，不要有其他内容。"""

    try:
        from modelsAPI.model_api import OpenaiAPI
        result_text = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            json_output=True
        )

        result_text = result_text.strip()
        result_text = re.sub(r'^```json\s*', '', result_text, flags=re.IGNORECASE)
        result_text = re.sub(r'^```\s*', '', result_text)
        result_text = re.sub(r'```$', '', result_text)

        json_match = re.search(r'\{.*\}', result_text, re.DOTALL)
        if json_match:
            result = json.loads(json_match.group(0))
            category = result.get("category")
            valid_categories = ["信息过时", "步骤错误", "步骤缺失", "备件信息有误", "安全提示不足", "图示不清", "其他"]
            if category in valid_categories:
                return category

        return "其他"

    except Exception as e:
        print(f"大模型分类反馈内容失败: {str(e)}")
        return "其他"


async def analyze_feedback_and_classify(feedback_text: str) -> Dict[str, Any]:
    """
    分析反馈内容并分类（主接口）
    """
    if not feedback_text or not feedback_text.strip():
        return {
            "success": False,
            "device": None,
            "system": None,
            "category": "其他",
            "error": "反馈内容为空"
        }

    try:
        device = await extract_device_from_text(feedback_text)

        system = "其他"
        if device:
            system = await get_device_system_from_neo4j(device)

        category = await classify_feedback_content(feedback_text)

        return {
            "success": True,
            "system": system,
            "category": category
        }

    except Exception as e:
        return {
            "success": False,
            "system": None,
            "category": "其他",
            "error": str(e)
        }


_feedback_token_cache = {"token": None, "expires_at": 0}


async def _get_feedback_api_token() -> Optional[str]:
    """
    获取维修反馈API的认证token（带缓存，避免每次请求都认证）
    """
    import time

    if _feedback_token_cache["token"] and time.time() < _feedback_token_cache["expires_at"]:
        return _feedback_token_cache["token"]

    base_url = REPAIR_FEEDBACK_CONFIG["url"]
    email = REPAIR_FEEDBACK_CONFIG.get("email", "")
    password = REPAIR_FEEDBACK_CONFIG.get("password", "")

    if not email or not password:
        print("[维修反馈认证错误] 未配置认证凭据")
        return None

    try:
        async with httpx.AsyncClient(timeout=30.0) as client:
            signin_resp = await client.post(
                f"{base_url}/api/v1/auths/signin",
                json={"email": email, "password": password}
            )

            if signin_resp.status_code != 200:
                print(f"[维修反馈认证错误] 登录失败，状态码: {signin_resp.status_code}")
                return None

            token = signin_resp.json().get("token", "")
            if not token:
                print("[维修反馈认证错误] 响应中未找到token")
                return None

            _feedback_token_cache["token"] = token
            _feedback_token_cache["expires_at"] = time.time() + 3600

            return token

    except Exception as e:
        print(f"[维修反馈认证错误] {str(e)}")
        return None


async def statistics_repair_feedbacks(
    source: Optional[str] = None,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    top_n: int = 10
) -> Dict[str, Any]:
    """
    统计维修反馈数据（从外部API获取，带认证）

    Args:
        source: 来源筛选（好评/差评/反馈），可选
        start_date: 开始日期（格式：YYYY-MM-DD），可选
        end_date: 结束日期（格式：YYYY-MM-DD），可选
        top_n: 返回前 N 条记录（默认为 10）

    Returns:
        包含统计结果的字典
    """
    try:
        token = await _get_feedback_api_token()
        if not token:
            return {
                "success": False,
                "totalCount": 0,
                "feedbackData": [],
                "error": "API认证失败，无法获取token"
            }

        base_url = REPAIR_FEEDBACK_CONFIG["url"]
        endpoint = f"{base_url}/api/v1/repair-feedbacks/"

        params = {}
        if source and source.strip():
            params["source"] = source.strip()

        async with httpx.AsyncClient(timeout=30.0) as client:
            response = await client.get(
                endpoint,
                params=params,
                headers={
                    "Accept": "application/json",
                    "Content-Type": "application/json",
                    "Authorization": f"Bearer {token}"
                }
            )

            if response.status_code == 401 or response.status_code == 403:
                _feedback_token_cache["token"] = None
                _feedback_token_cache["expires_at"] = 0

                token = await _get_feedback_api_token()
                if token:
                    response = await client.get(
                        endpoint,
                        params=params,
                        headers={
                            "Accept": "application/json",
                            "Content-Type": "application/json",
                            "Authorization": f"Bearer {token}"
                        }
                    )

            if response.status_code != 200:
                print(f"[维修反馈统计错误] API返回状态码: {response.status_code}")
                return {
                    "success": False,
                    "totalCount": 0,
                    "feedbackData": [],
                    "error": f"API请求失败，状态码: {response.status_code}"
                }

            result_json = response.json()

            if isinstance(result_json, list):
                feedback_list = result_json
            elif isinstance(result_json, dict):
                feedback_list = result_json.get("results", result_json.get("data", []))
            else:
                feedback_list = []

            if not feedback_list:
                return {
                    "success": True,
                    "totalCount": 0,
                    "totalTypes": 0,
                    "feedbackData": [],
                    "sourceDistribution": {}
                }

            start_dt = None
            end_dt = None
            if start_date:
                try:
                    start_dt = datetime.strptime(start_date, "%Y-%m-%d")
                except ValueError:
                    pass
            if end_date:
                try:
                    end_dt = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1) - timedelta(seconds=1)
                except ValueError:
                    pass

            if start_dt or end_dt:
                filtered_list = []
                for item in feedback_list:
                    if not isinstance(item, dict):
                        continue
                    raw_created_at = item.get("created_at", "")
                    if not raw_created_at:
                        continue
                    try:
                        item_dt = datetime.fromtimestamp(int(raw_created_at))
                        if start_dt and item_dt < start_dt:
                            continue
                        if end_dt and item_dt > end_dt:
                            continue
                        filtered_list.append(item)
                    except (ValueError, TypeError, OSError):
                        continue
                feedback_list = filtered_list

            total_count = len(feedback_list)

            processed_data = []
            for idx, item in enumerate(feedback_list[:top_n], start=1):
                if isinstance(item, dict):
                    raw_title = item.get("title", "")
                    raw_content = item.get("content", "")
                    raw_source = item.get("source", source or "")
                    raw_created_at = item.get("created_at", "")
                    raw_user_name = item.get("user_name", "")

                    created_at_str = ""
                    if raw_created_at:
                        try:
                            ts = int(raw_created_at)
                            created_at_str = datetime.fromtimestamp(ts).strftime("%Y-%m-%d %H:%M")
                        except (ValueError, TypeError, OSError):
                            created_at_str = str(raw_created_at)

                    processed_item = {
                        "rank": idx,
                        "title": str(raw_title) if raw_title else "",
                        "content": str(raw_content)[:200] if raw_content else "",
                        "source": str(raw_source) if raw_source else "未知",
                        "created_at": created_at_str,
                        "user_name": str(raw_user_name) if raw_user_name else ""
                    }
                    processed_data.append(processed_item)

            source_counter = {}
            for item in processed_data:
                s = item.get("source", "未知")
                source_counter[s] = source_counter.get(s, 0) + 1

            return {
                "success": True,
                "totalCount": total_count,
                "totalTypes": len(feedback_list),
                "sourceDistribution": source_counter,
                "feedbackData": processed_data
            }

    except Exception as e:
        print(f"[维修反馈统计错误] {str(e)}")
        import traceback
        traceback.print_exc()
        return {
            "success": False,
            "totalCount": 0,
            "feedbackData": [],
            "error": str(e)
        }


@tool
async def repair_feedback_statistics_tool(
    source: Optional[str] = None,
    start_date: Optional[str] = None,
    end_date: Optional[str] = None,
    top_n: Optional[int] = 10
) -> Dict[str, Any]:
    """
    维修反馈统计工具（供工作流调用）
    统计维修反馈情况，支持按来源和时间筛选

    Args:
        source: 来源筛选（可选），如：好评、差评、反馈
        start_date: 开始日期（格式：YYYY-MM-DD），可选
        end_date: 结束日期（格式：YYYY-MM-DD），可选
        top_n: 返回前 N 条记录（默认为 10）

    Returns:
        统计结果，包含 success 和 feedbackData 字段
    """
    result = await statistics_repair_feedbacks(
        source=source,
        start_date=start_date,
        end_date=end_date,
        top_n=top_n or 10
    )

    return result

#'Rx"""
工具函数定义
包含RAG、GraphRAG、VLM、ASR、TTS等工具的function call封装
"""

import os
import json
import re
import httpx
import asyncio
from typing import Optional, Dict, Any, List
from langchain_core.tools import tool
from dotenv import load_dotenv

from config import RAG_CONFIG, ASR_CONFIG
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import track_function_calls


load_dotenv()


from .graph_tools import (
    graph_rag_search,
    fault_graph_rag_search,
    operation_graph_rag_search,
)

from .rag_tools import (
    rag_search_tool,
    file_to_text_tool,
)

from .vlm_tools import (
    vlm_image_to_text,
    image_rag_describe,
)

from .fault_statistics import fault_type_statistics_tool, fault_frequency_statistics_tool, spare_parts_statistics_tool


@tool
def detect_input_type(raw_input: Dict[str, Any]) -> Dict[str, Any]:
    """
    判断输入类型工具（异步版本）：严格对齐 MainAgentState 字段。
    识别：image, audio/asr, file, query (text)
    """

    if not isinstance(raw_input, dict):
        return {
            "has_image": False, "has_audio": False, "has_file": False, "has_query": False,
            "input_type": "unknown", "error": "raw_input 必须是 dict"
        }

    has_image = False
    img_v = raw_input.get("image")
    if img_v:
        has_image = True

    has_audio = False
    aud_v = raw_input.get("audio")
    if aud_v:
        has_audio = True

    has_file = False
    file_v = raw_input.get("file_text")
    if file_v:
        has_file = True

    has_query = False
    query_v = raw_input.get("query")
    if isinstance(query_v, str) and query_v.strip():
        has_query = True

    return {
        "has_image": has_image,
        "has_audio": has_audio,
        "has_file": has_file,
        "has_query": has_query,
    }


async def asr_audio_to_text_async(
    audio_path: str,
    model: Optional[str] = None,
    language: Optional[str] = None
) -> Dict[str, Any]:
    """
    ASR语音转文本工具（异步实现）
    将音频文件转换为文本内容

    Args:
        audio_path: 音频文件路径（如：audio/test.wav）
        model: ASR模型名称（可选，默认从配置读取，如"base"）
        language: 语言代码（可选，默认从配置读取，如"zh"表示中文）

    Returns:
        包含success和text字段的字典
    """
    if not os.path.exists(audio_path):
        return {
            "success": False,
            "error": f"音频文件不存在: {audio_path}",
            "text": ""
        }

    api_base = ASR_CONFIG["api_base"]
    asr_model = model or ASR_CONFIG["model"]
    asr_language = language or ASR_CONFIG["language"]
    timeout = ASR_CONFIG["timeout"]

    api_endpoint = f"{api_base}/audio/transcriptions"

    try:
        with open(audio_path, "rb") as f:
            audio_data = f.read()

        files = {
            "file": (os.path.basename(audio_path), audio_data, "audio/wav")
        }
        data = {
            "model": asr_model,
            "language": asr_language,
        }

        async with httpx.AsyncClient(timeout=timeout) as client:
            response = await client.post(api_endpoint, files=files, data=data)

        if response.status_code == 200:
            result = response.json()
            text = result.get("text", "")
            return {
                "success": True,
                "text": text if text else "",
                "error": None
            }
        else:
            return {
                "success": False,
                "error": f"HTTP {response.status_code}: {response.text}",
                "text": ""
            }

    except Exception as e:
        return {
            "success": False,
            "error": str(e),
            "text": ""
        }


@tool
async def asr_audio_to_text(
    audio_path: str,
    model: Optional[str] = None,
    language: Optional[str] = None
) -> str:
    """
    ASR语音转文本工具（异步版本）
    将音频文件转换为文本内容

    Args:
        audio_path: 音频文件路径（如：audio/test.wav）
        model: ASR模型名称（可选，默认从配置读取，如"base"）
        language: 语言代码（可选，默认从配置读取，如"zh"表示中文）

    Returns:
        识别出的文本内容
    """
    result = await asr_audio_to_text_async(audio_path, model, language)

    if not result.get("success", False):
        return f"语音识别失败: {result.get('error', '未知错误')}"

    return result.get("text", "")


@tool
async def extract_device_and_fault(query: str) -> Dict[str, Any]:
    """
    从用户查询中提取设备名称和故障现象（使用大模型）

    Args:
        query: 用户查询文本

    Returns:
        包含device和fault字段的字典
    """
    if not query or not query.strip():
        return {"device": "", "fault": ""}

    prompt = f"""从以下用户查询中提取设备名称和故障现象：
查询：{query}

请以JSON格式返回：
{{"device": "设备名称", "fault": "故障现象"}}

如果无法提取，请返回空字符串。"""

    try:
        result_text = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            json_output=True
        )

        result_text = result_text.strip()
        result_text = re.sub(r'^```json\s*', '', result_text, flags=re.IGNORECASE)
        result_text = re.sub(r'^```\s*', '', result_text)
        result_text = re.sub(r'```$', '', result_text)

        json_match = re.search(r'\{.*\}', result_text, re.DOTALL)
        if json_match:
            result = json.loads(json_match.group(0))
            return {
                "device": result.get("device", ""),
                "fault": result.get("fault", "")
            }

        return {"device": "", "fault": ""}

    except Exception as e:
        print(f"提取设备和故障失败: {str(e)}")
        return {"device": "", "fault": ""}


# 工具列表导出
ALL_TOOLS = [
    detect_input_type,
    graph_rag_search,
    fault_graph_rag_search,
    operation_graph_rag_search,
    rag_search_tool,
    vlm_image_to_text,
    asr_audio_to_text,
    extract_device_and_fault,
    image_rag_describe,
    file_to_text_tool,
    fault_type_statistics_tool,
    fault_frequency_statistics_tool,
    spare_parts_statistics_tool
]

# 按类别分组的工具
TOOL_CATEGORIES = {
    "input_detection": [detect_input_type],
    "rag": [graph_rag_search, rag_search_tool, fault_graph_rag_search, operation_graph_rag_search],
    "vlm": [vlm_image_to_text],
    "asr": [asr_audio_to_text],
    "extraction": [extract_device_and_fault],
    "image_rag": [image_rag_describe],
    "file_process": [file_to_text_tool],
    "statistics": [fault_type_statistics_tool, fault_frequency_statistics_tool, spare_parts_statistics_tool]
}
nH-xhV"""
图谱检索工具模块
包含图谱搜索、故障图谱检索、操作图谱检索等功能
"""
import re
import json
import asyncio
import httpx
from typing import Optional, Dict, Any, List
from neo4j import AsyncGraphDatabase
from langchain_core.tools import tool

from config import ATLAS_CONFIG, GRAPH_SEARCH_CONFIG, NEO4J_CONFIG
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import track_function_calls


GRAPH_SEARCH_ENDPOINT = GRAPH_SEARCH_CONFIG.get("search_endpoint")


@track_function_calls
async def graph_search(
    query: str,
    top_k: Optional[int] = 40,
    use_rerank: Optional[bool] = False,
    fulltext_top_k: Optional[int] = 15,
    rerank_top_k: Optional[int] = 15,
    hops: Optional[int] = 3,
    verbose: Optional[bool] = False
) -> Dict[str, Any]:
    """
    图谱检索工具
    """
    if not query or not query.strip():
        return {"success": False, "error": "查询文本不能为空"}

    query = query.strip()

    payload = {
        "query": query,
        "use_rerank": use_rerank,
        "top_k": top_k,
        "fulltext_top_k": fulltext_top_k,
        "rerank_top_k": rerank_top_k,
        "hops": hops,
        "verbose": verbose
    }

    headers = {
        "accept": "application/json",
        "Content-Type": "application/json"
    }

    try:
        async with httpx.AsyncClient(timeout=180.0, verify=False) as client:
            response = await client.post(GRAPH_SEARCH_ENDPOINT, json=payload, headers=headers)
    except (httpx.ReadTimeout, httpx.ConnectTimeout, httpx.RequestError) as e:
        return {"success": False, "error": f"请求超时: {str(e)}"}

    if response.status_code != 200:
        return {"success": False, "error": f"HTTP {response.status_code}"}

    result = response.json()
    if result.get("code") != 200:
        msg = result.get("message", "未知错误")
        return {"success": False, "error": msg}

    data = result.get("data", {}) or {}

    try:
        graph_data = []
        results_text = ""

        if isinstance(data, dict):
            raw_nodes = data.get("nodes", [])
            _filter_searchable_labels(raw_nodes)
            # 过滤 nodes 的 properties 字段，仅保留"名称"属性
            for node in raw_nodes:
                if isinstance(node, dict):
                    props = node.get("properties", {}) or node.get("props", {})
                    name_value = props.get("名称", props.get("name", ""))
                    node.pop("properties", None)
                    node.pop("props", None)
                    if name_value:
                        node["properties"] = {"名称": name_value}
            graph_item = {
                "nodes": raw_nodes,
                "links": data.get("links", []),
            }
            graph_item = apply_styles(graph_item)
            graph_data.append(graph_item)
            results_text = data.get("results", "")
        elif isinstance(data, list):
            parts = []
            for item in data:
                if isinstance(item, dict):
                    raw_nodes = item.get("nodes", [])
                    _filter_searchable_labels(raw_nodes)
                    # 过滤 nodes 的 properties 字段，仅保留"名称"属性
                    for node in raw_nodes:
                        if isinstance(node, dict):
                            props = node.get("properties", {}) or node.get("props", {})
                            name_value = props.get("名称", props.get("name", ""))
                            node.pop("properties", None)
                            node.pop("props", None)
                            if name_value:
                                node["properties"] = {"名称": name_value}
                    graph_item = {
                        "nodes": raw_nodes,
                        "links": item.get("links", []),
                    }
                    graph_item = apply_styles(graph_item)
                    graph_data.append(graph_item)
                    if item.get("results"):
                        parts.append(item["results"])
            results_text = "\n".join(parts)

        for graph_item in graph_data:
            links = graph_item.get("links", [])
            for link in links:
                link.pop("properties", None)

        return {
            "success": True,
            "xxxx.graph": graph_data,
            "results": results_text,
        }

    except Exception as e:
        return {"success": False, "error": str(e)}


def _string_similarity(a: str, b: str) -> float:
    """
    简单字符串相似度：综合长度差、包含关系和公共字符比例。
    0~1 之间，越大越相似。
    """
    if not a or not b:
        return 0.0
    a = str(a).strip().lower()
    b = str(b).strip().lower()
    if not a or not b:
        return 0.0
    if a == b:
        return 1.0
    if a in b or b in a:
        return 0.9

    set_a, set_b = set(a), set(b)
    inter = len(set_a & set_b)
    union = len(set_a | set_b) or 1
    jaccard = inter / union

    len_diff = abs(len(a) - len(b))
    len_penalty = max(0.0, 1.0 - len_diff / max(len(a), len(b), 1))

    return 0.5 * jaccard + 0.5 * len_penalty


def _pick_best_by_name(candidates: List[Dict[str, Any]], target_name: str) -> Optional[Dict[str, Any]]:
    """
    在候选节点中，根据名称相似度选择最优节点。
    约定每个节点为：{id, labels, props, display_name}
    """
    if not candidates or not target_name:
        return None

    best = None
    best_score = 0.0
    for item in candidates:
        name = (item.get("display_name") or "").strip()
        if not name:
            props = item.get("props") or {}
            name = props.get("name") or props.get("名称") or props.get("设备名称") or ""
        score = _string_similarity(target_name, name)
        if score > best_score:
            best_score = score
            best = item

    return best if best_score >= 0.3 else None


def _extract_mt_codes(text: str) -> List[str]:
    """
    从文本中抽取形如 MT007 的维修项目编号（MT + 3位数字）。
    """
    if not text:
        return []
    codes = re.findall(r"\bMT\d{3}\b", str(text))
    seen = set()
    ordered: List[str] = []
    for c in codes:
        if c not in seen:
            seen.add(c)
            ordered.append(c)
    return ordered


def _node_record_to_dict(record: Any) -> Dict[str, Any]:
    """
    将 Cypher 返回的 id/labels/props 结构统一为字典。
    """
    if hasattr(record, "data"):
        data = record.data()
    else:
        data = record or {}
    result = {
        "id": data.get("id"),
        "labels": data.get("labels") or [],
        "props": data.get("props") or {},
        "display_name": data.get("display_name")
        if "display_name" in data
        else None,
    }
    if "embedding" in data:
        result["embedding"] = data.get("embedding")
    if "real_device_id" in data:
        result["real_device_id"] = data.get("real_device_id")
    if "real_device_name" in data:
        result["real_device_name"] = data.get("real_device_name")
    return result


def _to_graph_display_node(node_dict: Dict[str, Any]) -> Dict[str, Any]:
    """将内部节点格式转为 graph_search 展示用节点：id、name、label。"""
    nid = node_dict.get("id")
    props = node_dict.get("props") or {}
    name = (
        node_dict.get("display_name")
        or props.get("名称")
        or props.get("name")
        or str(nid)
    )
    labels = [l for l in (node_dict.get("labels") or []) if l != "Searchable"]
    label = labels[0] if labels else ""
    return {"id": nid, "name": name, "label": label}


def _build_fault_graph_display(
    ship_node: Optional[Dict[str, Any]],
    device_node: Optional[Dict[str, Any]],
    fault_mode_node: Optional[Dict[str, Any]],
    repair_projects: List[Dict[str, Any]],
) -> tuple:
    """
    构建与 graph_search 一致的图谱展示结构：nodes 与 links。
    """
    nodes: List[Dict[str, Any]] = []
    links: List[Dict[str, Any]] = []
    seen_ids = set()

    def add_node(nd: Optional[Dict[str, Any]]):
        if not nd or nd.get("id") in seen_ids:
            return
        seen_ids.add(nd["id"])
        nodes.append(_to_graph_display_node(nd))

    def add_link(source_id: Any, target_id: Any, rel_type: str = ""):
        links.append({"source": source_id, "target": target_id, "type": rel_type})

    if ship_node:
        add_node(ship_node)
    if device_node:
        add_node(device_node)
        if ship_node:
            add_link(ship_node["id"], device_node["id"], "包含")
    if fault_mode_node:
        add_node(fault_mode_node)
        if device_node:
            add_link(device_node["id"], fault_mode_node["id"], "存在")
    for p in repair_projects or []:
        add_node(p)
        if device_node:
            add_link(device_node["id"], p["id"], "维修时使用")

    return nodes, links


def _build_fault_graph_results_text(
    ship_node: Optional[Dict[str, Any]],
    device_node: Optional[Dict[str, Any]],
    fault_mode_node: Optional[Dict[str, Any]],
    fault_reason: str,
    repair_plan: str,
    mt_codes: List[str],
    repair_projects: List[Dict[str, Any]],
    ship_number: str,
    device_name: str,
    fault_symptom: str,
) -> str:
    """生成与 graph_rag_search 类似的一段话，供展示与下游使用。"""
    ship_name = ""
    if ship_node:
        ship_name = (ship_node.get("display_name") or (ship_node.get("props") or {}).get("名称") or "").strip()
    device_name_d = ""
    if device_node:
        device_name_d = (device_node.get("display_name") or (device_node.get("props") or {}).get("名称") or "").strip()
    fault_name = ""
    if fault_mode_node:
        fault_name = (fault_mode_node.get("display_name") or (fault_mode_node.get("props") or {}).get("名称") or "").strip()

    parts = [
        f"根据舷号「{ship_number}」、设备「{device_name}」、故障现象「{fault_symptom}」进行图谱检索：",
        f"定位到舰艇「{ship_name or '未知'}」、设备节点「{device_name_d or '未知'}」、故障模式「{fault_name or '未知'}」。",
    ]
    if fault_reason:
        parts.append(f"故障原因：{fault_reason}")
    if repair_plan:
        parts.append(f"维修方案摘要：{repair_plan[:500]}{'…' if len(repair_plan) > 500 else ''}")
    if mt_codes:
        parts.append(f"涉及维修项目编号：{'、'.join(mt_codes)}。")
    if repair_projects:
        proj_names = []
        for p in repair_projects:
            nm = (p.get("display_name") or (p.get("props") or {}).get("名称") or (p.get("props") or {}).get("维修项目编号") or "").strip()
            if nm:
                proj_names.append(nm)
        if proj_names:
            parts.append(f"匹配到的维修项目：{'、'.join(proj_names)}。")
    return "\n".join(parts)


@track_function_calls
async def fault_graph_reason_and_projects(
        ship_number: Optional[str] = None,
        device_name: str = "",
        fault_symptom: str = "",
) -> Dict[str, Any]:
    """
    图谱检索工具
    """

    if not device_name or not str(device_name).strip():
        return {"success": False, "error": "设备名称不能为空"}
    if not fault_symptom or not str(fault_symptom).strip():
        return {"success": False, "error": "故障现象不能为空"}

    uri = NEO4J_CONFIG.get("uri")
    user = NEO4J_CONFIG.get("user")
    password = NEO4J_CONFIG.get("password")
    if not uri or not user or not password:
        return {"success": False, "error": "Neo4j 配置不完整，请检查 NEO4J_CONFIG"}

    try:
        async with AsyncGraphDatabase.driver(uri, auth=(user, password)) as driver:
            async with driver.session() as session:
                device_key = str(device_name).strip()
                ship_id = None
                ship_node = None

                # 有舷号时，先定位舰艇节点
                if ship_number and str(ship_number).strip():
                    ship_key = str(ship_number).strip()
                    ship_query = """
                    MATCH (s:舰艇)
                    WHERE s.舷号 IN [$ship_key]
                    RETURN DISTINCT
                           id(s) AS id,
                           labels(s) AS labels,
                           properties(s) AS props,
                           coalesce(s.名称, s.name, s.舷号) AS display_name
                    LIMIT 10
                    """
                    ship_records = await session.run(ship_query, ship_key=ship_key)
                    ship_candidates = [_node_record_to_dict(r) async for r in ship_records]
                    if ship_candidates:
                        ship_node = ship_candidates[0]
                        ship_id = ship_node["id"]

                if ship_id is not None:
                    # 有舰艇节点：在该舰艇范围内搜索设备
                    device_query = """
                    MATCH (ship:舰艇)
                    WHERE id(ship) = $ship_id
                    MATCH (ship)-[:包含*0..8]->(n:设备)
                    WITH n, coalesce(n.名称, n.name, n.设备名称) AS nm
                    WHERE nm IS NOT NULL
                    RETURN DISTINCT
                           id(n) AS id,
                           labels(n) AS labels,
                           properties(n) AS props,
                           nm AS display_name,
                           n.embedding AS embedding
                    LIMIT 100
                    """
                    dev_records = await session.run(
                        device_query, ship_id=ship_id
                    )
                else:
                    # 无舷号：全局搜索设备节点
                    device_query = """
                    MATCH (n:设备)
                    WITH n, coalesce(n.名称, n.name, n.设备名称) AS nm
                    WHERE nm IS NOT NULL
                    RETURN DISTINCT
                           id(n) AS id,
                           labels(n) AS labels,
                           properties(n) AS props,
                           nm AS display_name,
                           n.embedding AS embedding
                    LIMIT 200
                    """
                    dev_records = await session.run(device_query)

                device_candidates = [_node_record_to_dict(r) async for r in dev_records]
                if not device_candidates:
                    return {"success": False, "error": "未找到匹配的设备节点"}

                device_node, device_score = await OpenaiAPI.hybrid_match_with_embeddings(
                    query_text=device_key,
                    candidates=device_candidates,
                    name_key="display_name",
                    embedding_key="embedding",
                    text_weight=0.3,
                    semantic_weight=0.7
                )
                if not device_node:
                    return {"success": False, "error": f"未找到匹配的设备节点（最高得分: {device_score:.3f}）"}
                device_id = device_node["id"]

                fault_mode_query = """
                MATCH (start_e:设备)
                WHERE id(start_e) = $device_id
                MATCH (start_e)-[:包含*0..3]-(real_e:设备)
                MATCH (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                RETURN DISTINCT
                       id(fm) AS id,
                       labels(fm) AS labels,
                       properties(fm) AS props,
                       fm.名称 AS display_name,
                       fm.embedding AS embedding,
                       id(real_e) AS real_device_id,
                       real_e.名称 AS real_device_name
                """
                fm_records = await session.run(fault_mode_query, device_id=device_id)
                fault_modes = [_node_record_to_dict(r) async for r in fm_records]
                if not fault_modes:
                    return {"success": False, "error": "在该设备节点下未找到故障模式节点"}

                fault_mode_node, fault_score = await OpenaiAPI.hybrid_match_with_embeddings(
                    query_text=fault_symptom,
                    candidates=fault_modes,
                    name_key="display_name",
                    embedding_key="embedding",
                    text_weight=0.3,
                    semantic_weight=0.7
                )
                if not fault_mode_node:
                    return {"success": False, "error": f"未能在故障模式节点中找到与故障现象足够匹配的节点（最高得分: {fault_score:.3f}）"}

                fault_mode_id = fault_mode_node.get("id")
                if fault_mode_id is None:
                    return {"success": False, "error": "故障模式节点缺少 id，无法继续检索维修项目"}

                real_device_id = fault_mode_node.get("real_device_id")

                fm_props = fault_mode_node.get("props") or {}
                fault_reason = fm_props.get("故障原因") or ""
                repair_plan = fm_props.get("维修方案") or ""
                mt_codes = _extract_mt_codes(repair_plan)

                repair_project_query = """
                MATCH (fm:故障模式)
                WHERE id(fm) = $fault_mode_id
                OPTIONAL MATCH (fm)<-[:修理]-(p:维修项目)
                RETURN DISTINCT
                       id(p) AS id,
                       labels(p) AS labels,
                       properties(p) AS props,
                       p.名称 AS display_name
                """
                rp_records = await session.run(
                    repair_project_query, fault_mode_id=fault_mode_id
                )
                all_projects = [_node_record_to_dict(r) async for r in rp_records]

                repair_projects: List[Dict[str, Any]] = []
                if mt_codes:
                    for proj in all_projects:
                        props = proj.get("props") or {}
                        proj_code = (props.get("维修项目编号") or "").strip()
                        if proj_code and (
                                proj_code in mt_codes or any(c in proj_code for c in mt_codes)
                        ):
                            repair_projects.append(proj)
                        elif not proj_code:
                            values_text = " ".join(
                                [str(v) for v in props.values() if v is not None]
                            )
                            if any(code in values_text for code in mt_codes):
                                repair_projects.append(proj)
                else:
                    repair_projects = all_projects

                repair_ids = [
                    p.get("id") for p in repair_projects if p.get("id") is not None
                ]

                exclude_keys = {
                    "last_updated",
                    "created_at",
                    "knowledge_source",
                    "fulltext",
                    "embedding",
                }

                if ship_id is not None:
                    graph_nodes_query = """
                    MATCH (ship:舰艇)
                    WHERE id(ship) = $ship_id
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path0 = (ship)-[:包含*0..8]->(real_e)
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    OPTIONAL MATCH (fm)<-[:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    WITH path0, path1, collect(DISTINCT rp) AS rps
                    WITH nodes(path0) + nodes(path1) + rps AS ns
                    UNWIND ns AS n
                    WITH DISTINCT n
                    WHERE n IS NOT NULL
                    RETURN elementId(n) AS id,
                           labels(n) AS labels,
                           coalesce(n.名称, n.name) AS name,
                           properties(n) AS props
                    """
                    node_records = await session.run(
                        graph_nodes_query,
                        ship_id=ship_id,
                        real_device_id=real_device_id,
                        fault_mode_id=fault_mode_id,
                        repair_ids=repair_ids or [-1],
                    )
                else:
                    # 无舷号：不查舰艇路径，只查设备→故障模式→维修项目
                    graph_nodes_query = """
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    OPTIONAL MATCH (fm)<-[:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    WITH path1, collect(DISTINCT rp) AS rps
                    WITH nodes(path1) + rps AS ns
                    UNWIND ns AS n
                    WITH DISTINCT n
                    WHERE n IS NOT NULL
                    RETURN elementId(n) AS id,
                           labels(n) AS labels,
                           coalesce(n.名称, n.name) AS name,
                           properties(n) AS props
                    """
                    node_records = await session.run(
                        graph_nodes_query,
                        real_device_id=real_device_id,
                        fault_mode_id=fault_mode_id,
                        repair_ids=repair_ids or [-1],
                    )

                nodes_g: List[Dict[str, Any]] = []
                async for r in node_records:
                    data_r = r.data()
                    nid = data_r.get("id")
                    if nid is None:
                        continue
                    labels = data_r.get("labels") or []
                    labels = [l for l in labels if l != "Searchable"]
                    name = data_r.get("name") or str(nid)
                    props = data_r.get("props") or {}
                    # 仅保留"名称"属性
                    name_value = props.get("名称", props.get("name", ""))
                    properties = {"名称": name_value} if name_value else {}
                    nodes_g.append(
                        {
                            "id": nid,
                            "name": name,
                            "labels": labels,
                            "properties": properties,
                        }
                    )

                if ship_id is not None:
                    graph_links_query = """
                    MATCH (ship:舰艇)
                    WHERE id(ship) = $ship_id
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path0 = (ship)-[:包含*0..8]->(real_e)
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    WITH relationships(path0) + relationships(path1) AS rs
                    UNWIND rs AS r
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    UNION
                    MATCH (fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    MATCH (fm)<-[r:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    """
                    link_records = await session.run(
                        graph_links_query,
                        ship_id=ship_id,
                        real_device_id=real_device_id,
                        fault_mode_id=fault_mode_id,
                        repair_ids=repair_ids or [-1],
                    )
                else:
                    # 无舷号：只查设备→故障模式的边
                    graph_links_query = """
                    MATCH (real_e:设备)
                    WHERE id(real_e) = $real_device_id
                    MATCH path1 = (real_e)-[:发生故障使用维修工作]-(w:维修工作)-[:表征]-(fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    WITH relationships(path1) AS rs
                    UNWIND rs AS r
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    UNION
                    MATCH (fm:故障模式)
                    WHERE id(fm) = $fault_mode_id
                    MATCH (fm)<-[r:修理]-(rp:维修项目)
                    WHERE id(rp) IN $repair_ids
                    RETURN elementId(r) AS id,
                           type(r) AS label,
                           elementId(startNode(r)) AS source,
                           elementId(endNode(r)) AS target,
                           properties(r) AS props
                    """
                    link_records = await session.run(
                        graph_links_query,
                        real_device_id=real_device_id,
                        fault_mode_id=fault_mode_id,
                        repair_ids=repair_ids or [-1],
                    )

                links_g: List[Dict[str, Any]] = []
                async for r in link_records:
                    data_r = r.data()
                    src = data_r.get("source")
                    tgt = data_r.get("target")
                    if src is None or tgt is None:
                        continue
                    links_g.append(
                        {
                            "id": data_r.get("id"),
                            "label": data_r.get("label", ""),
                            "source": src,
                            "target": tgt,
                        }
                    )

                node_ids = {n["id"] for n in nodes_g}
                links_g = [
                    l
                    for l in links_g
                    if l.get("source") in node_ids and l.get("target") in node_ids
                ]

                repair_plans_data: List[Dict[str, Any]] = []
                for p in repair_projects:
                    props = p.get("props") or {}
                    filtered = {k: v for k, v in props.items() if k not in exclude_keys}
                    if filtered:
                        repair_plans_data.append(filtered)

                parts = []

                if fault_reason and str(fault_reason).strip():
                    parts.append(str(fault_reason).strip())

                if repair_plans_data:
                    for plan in repair_plans_data:
                        if plan is not None:
                            plan_str = str(plan).strip()
                            if plan_str:
                                parts.append(plan_str)

                if parts:
                    combined_text = "\n".join(parts)
                else:
                    combined_text = "暂无故障信息或修复方案"

                results_obj = combined_text

                results_text = json.dumps(results_obj, ensure_ascii=False)

                graph_item = {"nodes": nodes_g, "links": links_g}
                graph_item = apply_styles(graph_item)
                return {"success": True, "xxxx.graph": [graph_item], "results": results_text}

    except Exception as e:
        return {"success": False, "error": f"Neo4j 查询失败: {str(e)}"}


def add_node_style(node):
    node_type = node.get("labels", [])
    node_type = [l for l in node_type if l != "Searchable"]
    if node_type and len(node_type) > 0:
        node_type = node_type[0]
    else:
        node_type = ""
    
    if node_type == "舰艇":
        node["color"] = "#F89A64"
        node["size"] = 86
    elif node_type == "系统":
        node["color"] = "#C25C21"
        node["size"] = 86
    elif node_type == "子系统":
        node["color"] = "#7D2D00"
        node["size"] = 86
    elif node_type == "设备":
        node["color"] = "#540802"
        node["size"] = 86
    elif node_type in ["功能", "环境条件", "接口", "安全警告", "调试", "器材保障", "图册", "设计单位", "维修项目", "操作项目"]:
        node["color"] = "#2261DF"
        node["size"] = 52
    else:
        node["color"] = "#68C3FF"
        node["size"] = 53
    
    return node


def add_link_style(link, nodes_dict):
    source_id = link.get("source")
    target_id = link.get("target")
    
    source_type = ""
    target_type = ""
    
    if source_id and source_id in nodes_dict:
        source_labels = [l for l in nodes_dict[source_id].get("labels", []) if l != "Searchable"]
        if source_labels and len(source_labels) > 0:
            source_type = source_labels[0]
    
    if target_id and target_id in nodes_dict:
        target_labels = [l for l in nodes_dict[target_id].get("labels", []) if l != "Searchable"]
        if target_labels and len(target_labels) > 0:
            target_type = target_labels[0]
    
    hierarchy_types = ["舰艇", "系统", "子系统", "设备"]
    if source_type in hierarchy_types and target_type in hierarchy_types:
        link["color"] = "#F59E0B"
    else:
        link["color"] = "#FFFFFF"
    
    return link


def _filter_searchable_labels(nodes: List[Dict[str, Any]]):
    for node in nodes:
        if isinstance(node, dict) and "labels" in node:
            node["labels"] = [l for l in node["labels"] if l != "Searchable"]


def apply_styles(graph_data):
    nodes = graph_data.get("nodes", [])
    links = graph_data.get("links", [])
    
    nodes_dict = {n.get("id"): n for n in nodes if n.get("id")}
    
    for node in nodes:
        add_node_style(node)
    
    for link in links:
        add_link_style(link, nodes_dict)
    
    return graph_data


@tool
async def fault_graph_rag_search(
    ship_number: Optional[str] = None,
    device_name: str = "",
    fault_symptom: str = "",
) -> str:
    """
    故障诊断图谱检索工具（供工作流调用）：仅返回一段话摘要，与 graph_rag_search 一致。
    根据设备名称、故障现象在图谱中定位设备→故障模式→维修项目，并生成文字摘要。舷号为可选参数，提供时可缩小搜索范围。
    工作流中用于与 RAG 结果一起作为上下文，不返回节点/关系（展示用 fault_graph_reason_and_projects）。
    """
    result = await fault_graph_reason_and_projects(
        ship_number=ship_number,
        device_name=device_name,
        fault_symptom=fault_symptom,
    )
    if not result.get("success", False):
        return result.get("error", "检索失败")
    return result.get("results", "")


@track_function_calls
async def operation_graph_search_tool(
        ship_number: str,
        device_name: str,
        operation_item: str,
) -> Dict[str, Any]:
    """
    图谱检索工具
    """
    if not ship_number or not str(ship_number).strip():
        return {"success": False, "error": "舷号不能为空"}
    if not device_name or not str(device_name).strip():
        return {"success": False, "error": "设备名称不能为空"}
    if not operation_item or not str(operation_item).strip():
        return {"success": False, "error": "操作项目不能为空"}

    endpoint = GRAPH_SEARCH_CONFIG.get("operation_search_endpoint")
    timeout = GRAPH_SEARCH_CONFIG.get("graph_timeout")

    if not endpoint:
        return {"success": False, "error": "操作图谱检索服务配置不完整"}

    payload = {
        "ship_number": str(ship_number).strip(),
        "device_name": str(device_name).strip(),
        "operation_item": str(operation_item).strip(),
    }

    try:
        async with httpx.AsyncClient(timeout=timeout) as client:
            response = await client.post(
                endpoint,
                json=payload,
                headers={"Content-Type": "application/json"},
            )
            response.raise_for_status()
            result = response.json()

            if not result.get("success", False):
                return {"success": False, "error": result.get("error", "检索失败")}

            graph_list = result.get("xxxx.graph") or []
            results_parts = []
            if graph_list:
                for i, graph_item in enumerate(graph_list):
                    if isinstance(graph_item, dict):
                        _filter_searchable_labels(graph_item.get("nodes", []))
                        if "results" in graph_item:
                            r = graph_item.pop("results")
                            if r:
                                results_parts.append(r)
                        graph_list[i] = apply_styles(graph_item)
                result["xxxx.graph"] = graph_list

            if results_parts:
                result["results"] = "\n".join(results_parts)
            elif "results" not in result:
                result["results"] = ""

            return result

    except httpx.ReadTimeout:
        return {"success": False, "error": "操作图谱检索服务超时"}
    except httpx.ConnectError:
        return {"success": False, "error": "无法连接操作图谱检索服务"}
    except httpx.HTTPStatusError as e:
        return {"success": False, "error": f"操作图谱检索服务返回错误: {e.response.status_code}"}
    except Exception as e:
        return {"success": False, "error": f"操作图谱检索失败: {str(e)}"}


@tool
async def operation_graph_rag_search(
        ship_number: str,
        device_name: str,
        operation_item: str,
) -> str:
    """
    操作图谱检索工具（供工作流调用）：仅返回一段话摘要，与 graph_rag_search 一致。
    根据舷号、设备名称、操作项目在图谱中定位舰艇→设备→操作项目，并生成文字摘要。
    工作流中用于与 RAG 结果一起作为上下文，不返回节点/关系（展示用 operation_graph_search_tool）。
    """
    result = await operation_graph_search_tool(
        ship_number=ship_number,
        device_name=device_name,
        operation_item=operation_item,
    )
    if not result.get("success", False):
        return result.get("error", "检索失败")
    return result.get("results", "")


@tool
async def graph_rag_search(query: str, entity_type: Optional[str] = None, top_k: int = 40) -> str:
    """
    GraphRAG检索工具（异步版本）
    在知识图谱中检索与query相关的实体和关系

    Args:
        query: 检索查询
        entity_type: 实体类型过滤（如：设备、故障、维修项目）- 注意：此参数在当前实现中暂未使用
        top_k: 返回结果数量（保留参数以兼容接口）

    Returns:
        图谱检索结果文本字符串（旧格式，保持兼容）
    """
    print(f"graph_rag_query+++++++++++{query}")
    result = await graph_search(query)

    if not result.get("success", False):
        return ""

    results_text = result.get("results", "")
    if not results_text:
        return ""
    if len(results_text) > 1000:
        results_text = results_text[:1000] + "..."
    return results_text



async def atlas_retrieval(
    node_names: List[str],
    top_k: int = 10,
    timeout: int = 30
) -> Dict[str, Any]:
    """
    图册检索工具：从图谱中找到节点并关联图册PDF

    Args:
        node_names: 节点名称列表，如 ["主发动机", "压缩机"]
        top_k: 返回的结果数量
        timeout: 请求超时时间（秒）

    Returns:
        包含success和data字段的字典
        data格式示例：
        {
            "船舶主发动机": {
                "船舶主发动机的原理图": [
                    "http://192.168.0.46:59085/files/163-06A0015-B01001_船舶主发动机原理图.pdf"
                ]
            }
        }
    """
    api_url = ATLAS_CONFIG["endpoint"]

    if not node_names:
        return {
            "success": False,
            "error": "node_names不能为空",
            "data": {}
        }

    payload = {
        "node_names": node_names,
        "top_k": top_k
    }

    try:
        async with httpx.AsyncClient(timeout=timeout) as client:
            response = await client.post(
                api_url,
                json=payload,
                headers={
                    "accept": "application/json",
                    "Content-Type": "application/json"
                }
            )

        if response.status_code == 200:
            result = response.json()
            if result.get("success", False):
                return {
                    "success": True,
                    "data": result.get("data", {}),
                    "error": None
                }
            else:
                return {
                    "success": False,
                    "error": result.get("message", "API返回失败"),
                    "data": {}
                }
        else:
            return {
                "success": False,
                "error": f"HTTP {response.status_code}: {response.text}",
                "data": {}
            }

    except Exception as e:
        return {
            "success": False,
            "error": str(e),
            "data": {}
        }


def format_atlas_results(atlas_data: Dict[str, Any]) -> str:
    """
    格式化图册检索结果为文本，便于在提示词中使用

    Args:
        atlas_data: atlas_retrieval返回的data字段

    Returns:
        格式化后的文本
    """
    if not atlas_data:
        return ""

    parts = []
    for node_name, node_data in atlas_data.items():
        if isinstance(node_data, dict):
            for title, urls in node_data.items():
                if isinstance(urls, list) and urls:
                    parts.append(f"\n【{node_name} - {title}】")
                    for url in urls:
                        # 确保URL后面有明确的换行，避免和其他文字连在一起
                        parts.append(f"- {url}\n")

    return "\n".join(parts) if parts else ""


async def extract_entity_names_from_history(
    history_messages: List[Dict[str, Any]],
    device_name: str = "",
    operation_item: str = "",
    fault: str = "",
    last_generated_scheme: str = ""
) -> List[str]:
    """
    从历史记录中抽取部件/设备/零部件名称

    Args:
        history_messages: 历史对话记录
        device_name: 设备名称
        operation_item: 操作项目名称
        fault: 故障现象
        last_generated_scheme: 最后一次生成的方案（用于重点抽取）

    Returns:
        抽取的实体名称列表
    """
    entity_names = []

    # 添加明确提供的名称
    if device_name:
        entity_names.append(device_name)
    if operation_item:
        entity_names.append(operation_item)
    if fault:
        entity_names.append(fault)

    # 去重
    entity_names = list(dict.fromkeys(entity_names))
    
    # 调用大模型进一步抽取和补充
    if entity_names or last_generated_scheme:
        try:
            extraction_prompt = f"""从以下信息中抽取尽可能多的设备、部件、零部件、机构、系统名称（用于图册检索）。
注意：
- 请尽可能多抽取，宁多勿少，准不准没关系
- 包括所有提及的机械部件、电子设备、机构系统等
- 即使是重复提到的也可以保留，我们会去重
- 重点从【生成的方案】中抽取，这里信息最全面

【示例 - 输入】
船舶主发动机（舷号：101）故障分析与维修方案
1. 故障概况
设备名称：船舶主发动机
舷号：101
故障现象：主机运行中出现异响
2. 故障原因分析
主轴承或连杆大端轴承磨损：轴承间隙过大或磨损严重会导致金属撞击声。
曲轴主轴颈跳动超差：曲轴旋转不平衡或跳动量超出标准。
飞轮连接螺栓松动：飞轮与曲轴连接处的螺栓松动。
活塞头烧蚀或活塞环断裂：活塞环断裂或活塞头部损坏可能导致敲缸声。
排气阀密封面磨损或阀座烧蚀：气门间隙异常或密封失效。
涡轮增压器轴承损坏：增压器内部轴承损坏。
3. 维修方案
执行项目：MT003 检测曲轴组件（含飞轮紧固状态检查）。
执行项目：MTO03 检测曲轴主轴颈跳动量。

【示例 - 输出】
{{
    "entity_names": ["船舶主发动机", "主轴承", "连杆大端轴承", "曲轴", "飞轮", "飞轮连接螺栓", "活塞头", "活塞环", "排气阀", "排气阀座", "涡轮增压器", "涡轮增压器轴承", "曲轴组件"]
}}

【设备/操作】
- 设备名: {device_name or '无'}
- 操作项: {operation_item or '无'}
- 故障: {fault or '无'}

【生成的方案】
{last_generated_scheme or '无'}

请输出JSON格式，格式如下：
{{
    "entity_names": ["名称1", "名称2", "名称3", "..."]
}}

仅输出JSON，不要其他内容。"""

            response = await OpenaiAPI.open_api_chat_without_thinking(
                query=extraction_prompt,
                json_output=True,
                system_prompt="你是一个专业的实体抽取助手，负责从文本中抽取尽可能多的设备、部件、零部件、机构、系统名称。请尽量多抽取，宁多勿少。重点从生成的维修方案中抽取。"
            )

            parsed = _safe_json_extract(response)
            if isinstance(parsed, dict):
                extracted = parsed.get("entity_names", [])
                if extracted:
                    entity_names.extend(extracted)
                    entity_names = list(dict.fromkeys(entity_names))
        except Exception as e:
            print(f"[图册检索] 实体抽取失败: {str(e)}")

    # 过滤空值和太短的名称
    entity_names = [name.strip() for name in entity_names if name and len(name.strip()) >= 2]
    return entity_names[:30]  # 最多30个，尽量多找图册


def _safe_json_extract(text: str) -> Any:
    """安全地从文本中提取JSON"""
    try:
        # 尝试直接解析
        return json.loads(text)
    except json.JSONDecodeError:
        # 尝试用正则提取
        match = re.search(r'\{[\s\S]*\}', text)
        if match:
            try:
                return json.loads(match.group(0))
            except json.JSONDecodeError:
                pass
        return None


 \ximport os
import base64
import subprocess
import tempfile
from datetime import datetime


class PDFGenerator:
    """PDF 生成器类（Pandoc 版）"""

    def __init__(self, main_font: str = "Noto Serif CJK SC"):
        """
        初始化 PDF 生成器

        Args:
            main_font: Pandoc / XeLaTeX 使用的中文字体名
        """
        self.main_font = main_font

    def generate_pdf_from_text(
        self,
        text_content: str,
        output_path: str = None,
        title: str = "维修报告",
        return_base64: bool = True
    ) -> dict:
        """
        将 Markdown 文本内容生成 PDF 文件

        Args:
            text_content: Markdown 文本内容
            output_path: PDF 输出路径（可选）
            title: PDF 标题
            return_base64: 是否返回 base64 编码内容
        """
        try:
            # 输出路径
            if output_path is None:
                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
                output_path = f"temp_report_{timestamp}.pdf"

            # 生成临时 Markdown 文件
            with tempfile.NamedTemporaryFile(
                mode="w",
                suffix=".md",
                delete=False,
                encoding="utf-8"
            ) as md_file:
                md_path = md_file.name

                # 写入标题 + 内容
                if title:
                    md_file.write(f"# {title}\n\n")
                md_file.write(text_content.strip())

            # Pandoc 命令：使用自定义 LaTeX 模板解决排版问题
            cmd = [
                "pandoc",
                md_path,
                "--pdf-engine=xelatex",
                "-V", f"mainfont={self.main_font}",
                "-V", "geometry:margin=2cm",  # 增加页边距
                "-V", "fontsize=10pt",         # 字体大小
                "-V", "lineskip=1.5",          # 行距
                "--template=template.tex",     # 使用自定义模板
                "-o", output_path
            ]

            # 执行转换
            subprocess.run(
                cmd,
                check=True,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )

            result = {
                "success": True,
                "file_path": output_path
            }

            # 返回 base64
            if return_base64:
                with open(output_path, "rb") as f:
                    result["base64_content"] = base64.b64encode(
                        f.read()
                    ).decode("utf-8")

            return result

        except subprocess.CalledProcessError as e:
            return {
                "success": False,
                "error": e.stderr.decode("utf-8")
            }
        except Exception as e:
            return {
                "success": False,
                "error": str(e)
            }
        finally:
            # 清理临时 md 文件
            if "md_path" in locals() and os.path.exists(md_path):
                os.remove(md_path)


# 创建自定义 LaTeX 模板文件 template.tex
def create_latex_template():
    """创建一个用于中文排版的 LaTeX 模板（Pandoc 正确版）"""
    template = r"""
\documentclass[10pt]{article}
\usepackage[UTF8]{ctex}
\usepackage{geometry}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{array}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{setspace}
\usepackage{fancyhdr}
\usepackage{titlesec}
\usepackage{tabularx}
\usepackage{makecell}
\usepackage{adjustbox}
\usepackage{hyperref}
% 页面设置
\geometry{margin=2cm}
\setlength{\parskip}{1em}
\setlength{\parindent}{0em}

% 字体
\setCJKmainfont{Noto Serif CJK SC}

% 标题样式
\title{\Large \textbf{$title$}}
\author{}
\date{}

% 章节标题样式
\titleformat{\section}{\large\bfseries\raggedright}{\thesection}{1em}{}
\titleformat{\subsection}{\normalsize\bfseries\raggedright}{\thesubsection}{1em}{}


% ===== Pandoc compatibility =====
\usepackage{hyperref}
\providecommand{\tightlist}{%
  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}


\begin{document}

\maketitle

$body$

\end{document}
"""
    with open("template.tex", "w", encoding="utf-8") as f:
        f.write(template)












# 生成报告函数不变，但调用前先创建模板
def generate_report_pdf(
    report_content: str,
    device_name: str = "未知设备",
    output_dir: str = None
) -> dict:
    """
    生成维修报告 PDF
    """
    # 先创建模板文件
    create_latex_template()

    generator = PDFGenerator()

    # 文件名规则不变
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    safe_device_name = device_name.replace(" ", "_").replace("/", "_")
    file_name = f"{safe_device_name}_维修报告_{timestamp}.pdf"

    if output_dir:
        os.makedirs(output_dir, exist_ok=True)
        output_path = os.path.join(output_dir, file_name)
    else:
        output_path = file_name

    result = generator.generate_pdf_from_text(
        text_content=report_content,
        output_path=output_path,
        title="设备维修报告",
        return_base64=True
    )

    if result.get("success"):
        result["file_name"] = file_name

    return result


# 测试代码
if __name__ == "__main__":
    test_md = """
三、根本原因判断

根据设备当前状态、维修方案参考和知识库检索结果，最可能的根本原因如下：

**根本原因**：缸盖密封环老化或失效  
**次级原因**：启动阀卡滞或内部泄漏

---

四、原因分析说明

1. **缸盖密封环老化或失效**
   - 缸盖密封环是气缸密封的关键部件，其老化或损坏会导致气缸压缩气体泄漏，压缩压力下降。
   - 启动时，压缩压力不足会导致点火困难，主机启动延迟或失败。
   - 此类问题在长期运行或未定期保养的设备中较为常见。

2. **启动阀卡滞或内部泄漏**
   - 启动阀的功能是控制启动气进入气缸，若其卡滞或内部泄漏，将导致启动气供应不足或不及时，影响启动成功率。
   - 内部泄漏还会造成启动气浪费，进一步降低启动成功率。
   - 启动阀若未定期维护，容易因灰尘、杂质或润滑不良而卡滞。

3. **气缸套磨损**
   - 气缸套磨损会导致气缸密封性下降，压缩气体泄漏，压缩压力不足。
   - 该问题通常发生在长期运行、润滑不良或未及时更换气缸套的设备中。

4. **活塞环磨损或断裂**
   - 活塞环磨损或断裂会导致气缸密封性下降，压缩气体泄漏，从而影响压缩压力。
   - 该问题通常与长期运行、润滑不良或材料疲劳有关。

5. **调速系统响应异常**
   - 调速系统异常可能导致主机启动时转速控制不稳，但其对压缩压力的影响相对较小，通常不是导致压缩压力不足的主要原因。

---

五、预防建议

1. 定期更换缸盖密封环
   - 根据设备运行时间和使用情况，制定合理的密封环更换计划，避免因老化导致密封性能下降。
   - 建议每运行 5000 小时进行一次检查，必要时更换。

2. 加强启动阀维护
   - 定期清理启动阀内部积碳和杂质，保持润滑良好。
   - 每 1000 小时进行一次功能测试。

3. 监控气缸套和活塞环状态
   - 通过内窥镜或压力测试定期检测气缸套与活塞环磨损情况。
   - 发现异常及时更换。

4. 优化润滑系统
   - 使用符合标准的润滑油，确保润滑充分。
   - 定期更换滤芯，防止杂质进入关键部件。

5. 定期校准调速系统
   - 每季度进行一次调速系统校准，确保响应灵敏。
   - 记录历史数据，建立趋势分析模型。
"""

    result = generate_report_pdf(
        test_md,
        device_name="压缩机设备"
    )

    if result["success"]:
        print(f"✓ PDF 生成成功：{result['file_name']}")
        print(f"✓ 文件路径：{result['file_path']}")
        print(f"✓ Base64 长度：{len(result['base64_content'])}")
    else:
        print(f"✗ PDF 生成失败：{result['error']}")
L	x9?(U"""
PDF 生成工具模块
使用 Pandoc 将 Markdown 文本转换为 PDF 文件
"""
（方法名不变）（Pandoc 标准）g71（方法名不变）
    """
爱因斯坦质能方程：

$$E = mc^2$$

该公式揭示了质量与能量的等价性。在核反应中，微小的质量损 $\Delta m$ 会释放巨大能量：

$$\Delta E = \Delta m \cdot c^2$$

其中 $c = 3 \times 10^8 \, \text{m/s}$ 为真空光速。

## 实验数据对比

下表展示了不同材料在相同条件下的能量释放效率：

| 材料类型   | 质量亏损 (kg) | 释放能量 (J)       | 能量密度 (J/kg)     |
|------------|----------------|---------------------|----------------------|
| 铀-235     | $1.0 \times 10^{-3}$ | $9.0 \times 10^{13}$ | $9.0 \times 10^{16}$ |
| 氘氚聚变   | $3.1 \times 10^{-3}$ | $2.8 \times 10^{14}$ | $9.0 \times 10^{16}$ |
| 化学燃烧   | $1.0 \times 10^{-3}$ | $3.0 \times 10^{4}$  | $3.0 \times 10^{7}$  |


## 结论

- 核反应的能量密度远高于化学反应（约 $10^9$ 倍）。
- 公式 $a^2 + b^S2 = c^2$ 虽为几何关系，但在相对论四维时空中有深刻类比。
""" z((test_md,
    device_name="测试设备"
"yDoxs """
RAG搜索工具模块
包含知识库搜索、文件处理等功能
"""
import os
import json
import base64
import asyncio
import httpx
from typing import Optional, Dict, Any
from langchain_core.tools import tool

from config import RAG_CONFIG
from utils.function_tracker import track_function_calls


@track_function_calls
async def rag_search(
    query: str,
    top_k: Optional[int] = 5,
    file_id: Optional[int] = None,
    kb_id: Optional[str] = None
) -> Dict[str, Any]:
    """
    知识库搜索工具
    调用知识库搜索API，检索与query相关的文档内容

    Args:
        query: 搜索关键词（必填）
        top_k: 返回结果数量（默认5）
        file_id: 文件ID（可选）
        kb_id: 知识库ID（可选）

    Returns:
        搜索结果，包含sourceCitation格式的数据
    """

    if not query or not query.strip():
        return {"success": False, "error": "查询文本不能为空"}

    SEARCH_URL = RAG_CONFIG["search_endpoint"]

    params = {"query": query.strip()}

    if file_id is None:
        config_file_id = RAG_CONFIG.get("file-id")
        if config_file_id is not None:
            try:
                file_id = int(config_file_id) if isinstance(config_file_id, str) else config_file_id
            except (ValueError, TypeError):
                file_id = None

    if kb_id is None:
        config_kb_id = RAG_CONFIG.get("kb-id")
        if config_kb_id is not None:
            kb_id = str(config_kb_id) if config_kb_id is not None else None

    if file_id is not None and file_id != "":
        params["file_id"] = file_id
    if kb_id is not None and kb_id != "":
        params["kb_id"] = kb_id

    print(111111111111111111)
    print(RAG_CONFIG["x-user-id"])
    print(RAG_CONFIG["x-user-name"])
    print(RAG_CONFIG["x-role"])

    headers = {
        "accept": "application/json",
        "x-user-id": RAG_CONFIG["x-user-id"],
        "x-role": RAG_CONFIG["x-role"]
    }

    print(f"RAG params: {params}")

    max_retries = 1
    retry_delay = 2

    response = None
    last_exception = None

    for attempt in range(max_retries + 1):
        try:
            async with httpx.AsyncClient(timeout=180.0, verify=False) as client:
                response = await client.get(SEARCH_URL, params=params, headers=headers)
            break

        except (httpx.ReadTimeout, httpx.ConnectTimeout, httpx.RequestError) as e:
            last_exception = e
            if attempt < max_retries:
                print(f"RAG请求超时，第 {attempt+1} 次重试，2秒后重新请求...")
                await asyncio.sleep(retry_delay)
            else:
                return {"success": False, "error": f"请求超时: {str(e)}"}

    try:
        if response.status_code != 200:
            return {"success": False, "error": f"HTTP {response.status_code}"}

        result = response.json()
        data = result.get("results", [])

        filtered_data = [item for item in data if item.get("score", 0.0) >= 0.4]

        sorted_data = sorted(
            filtered_data,
            key=lambda x: x.get("score", 0.0),
            reverse=True
        )[:top_k]

        source_citation = {}

        for idx, item in enumerate(sorted_data, start=1):
            if not isinstance(item, dict):
                continue

            file_info = item.get("file")
            kb_info = item.get("kb")

            filename = file_info.get("filename", "") if file_info else ""
            resource = filename or (kb_info.get("name", "未分组文档") if kb_info else "未分组文档")

            positions = item.get("positions", [])
            page_idx = positions[0].get("page_idx", 0) if positions else 0

            citation_item = {
                "index": idx,
                "id": item.get("id", ""),
                "text": item.get("content", ""),
                "resource": resource,
                "filename": filename,
                "score": item.get("score", 0.0),
                "page_idx": page_idx,
                "file_id": item.get("file_id", ""),
                "kb_id": kb_info.get("id", "") if kb_info else "",
                "kb_name": kb_info.get("name", "") if kb_info else "",
                "positions": positions
            }

            if resource not in source_citation:
                source_citation[resource] = []
            source_citation[resource].append(citation_item)

        return {
            "success": True,
            "sourceCitation": source_citation,
            "total": len(sorted_data),
            "total_available": len(data)
        }

    except Exception as e:
        return {"success": False, "error": str(e)}


@tool
async def rag_search_tool(query: str, top_k: Optional[int] = 5) -> str:
    """
    RAG检索工具（供工作流调用）
    在知识库中检索与query相关的文档内容

    Args:
        query: 检索查询
        top_k: 返回结果数量

    Returns:
        检索结果文本
    """
    result = await rag_search(query, top_k=top_k)

    if not result.get("success", False):
        return ""

    source_citation = result.get("sourceCitation", {})
    if not source_citation:
        return ""

    results_parts = []
    for resource, items in source_citation.items():
        for item in items:
            text = item.get("text", "")
            if text:
                results_parts.append(f"【{resource}】{text}")

    results_text = "\n\n".join(results_parts) if results_parts else ""
    if len(results_text) > 2000:
        results_text = results_text[:2000] + "..."
    return results_text


@track_function_calls
async def file_to_text(file_path: str) -> Dict[str, Any]:
    """
    文件转文本工具
    支持多种文件格式：PDF、Word、TXT、图片等

    Args:
        file_path: 文件路径

    Returns:
        转换结果，包含文本内容
    """
    if not file_path or not file_path.strip():
        return {"success": False, "error": "文件路径不能为空"}

    file_path = file_path.strip()

    if not os.path.exists(file_path):
        return {"success": False, "error": f"文件不存在: {file_path}"}

    try:
        file_ext = os.path.splitext(file_path)[1].lower()

        if file_ext == ".txt":
            with open(file_path, "r", encoding="utf-8") as f:
                text = f.read()
            return {"success": True, "text": text}

        elif file_ext == ".pdf":
            import fitz
            doc = fitz.open(file_path)
            text_parts = []
            for page in doc:
                text_parts.append(page.get_text())
            text = "\n".join(text_parts)
            doc.close()
            return {"success": True, "text": text}

        elif file_ext in [".docx", ".doc"]:
            from docx import Document
            doc = Document(file_path)
            text_parts = []
            for para in doc.paragraphs:
                text_parts.append(para.text)
            text = "\n".join(text_parts)
            return {"success": True, "text": text}

        elif file_ext in [".jpg", ".jpeg", ".png", ".bmp", ".gif"]:
            with open(file_path, "rb") as f:
                image_data = f.read()
            base64_image = base64.b64encode(image_data).decode("utf-8")
            base64_url = f"data:image/{file_ext[1:]};base64,{base64_image}"
            
            from modelsAPI.model_api import OpenaiAPI
            text = await OpenaiAPI.vlm_chat(
                image_path=base64_url,
                prompt="请描述这张图片的内容"
            )
            return {"success": True, "text": text}

        else:
            return {"success": False, "error": f"不支持的文件格式: {file_ext}"}

    except Exception as e:
        return {"success": False, "error": f"文件处理失败: {str(e)}"}


@tool
async def file_to_text_tool(file_path: str) -> str:
    """
    文件转文本工具（供工作流调用）
    支持多种文件格式：PDF、Word、TXT、图片等

    Args:
        file_path: 文件路径

    Returns:
        文件文本内容
    """
    result = await file_to_text(file_path)

    if not result.get("success", False):
        return f"文件处理失败: {result.get('error', '未知错误')}"

    return result.get("text", "")
	Ǫx"""
舷号-型号映射数据库模块
用于管理舰船型号、舷号、舰名的映射关系
数据存储在 PostgreSQL 的 ship_model_mapping 表中
每艘舰一条记录
"""
import json
from typing import Dict, List, Any, Optional

from config import POSTGRES_CONNECTION_STRING


async def init_ship_model_mapping_table():
    """
    初始化 ship_model_mapping 表并插入初始数据
    每艘舰一条记录，包含型号、舷号、舰名
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[ship_model_db] psycopg_pool 未安装，无法初始化表")
        return

    async with AsyncConnectionPool(
        POSTGRES_CONNECTION_STRING,
        kwargs={"autocommit": True}
    ) as pool:
        async with pool.connection() as conn:
            async with conn.cursor() as cur:
                await cur.execute("""
                    CREATE TABLE IF NOT EXISTS ship_model_mapping (
                        id SERIAL PRIMARY KEY,
                        model_name TEXT NOT NULL,
                        hull_number TEXT NOT NULL UNIQUE,
                        ship_name TEXT NOT NULL DEFAULT ''
                    )
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS ship_model_mapping_model_name_idx ON ship_model_mapping(model_name)
                """)
                await cur.execute("""
                    CREATE INDEX IF NOT EXISTS ship_model_mapping_hull_number_idx ON ship_model_mapping(hull_number)
                """)
                print("[ship_model_db] ship_model_mapping 表初始化完成")

                await cur.execute("SELECT COUNT(*) FROM ship_model_mapping")
                count = (await cur.fetchone())[0]
                if count == 0:
                    initial_data = [
                        ("055型驱逐舰", "102", "拉萨舰"),
                        ("055型驱逐舰", "103", "鞍山舰"),
                        ("055型驱逐舰", "104", "无锡舰"),
                        ("055型驱逐舰", "105", "大连舰"),
                        ("055型驱逐舰", "106", "延安舰"),
                        ("055型驱逐舰", "107", "遵义舰"),
                        ("055型驱逐舰", "108", "咸阳舰"),
                        ("052D型驱逐舰", "172", "昆明舰"),
                        ("052D型驱逐舰", "173", "长沙舰"),
                        ("052D型驱逐舰", "174", "合肥舰"),
                        ("052D型驱逐舰", "175", "银川舰"),
                        ("052D型驱逐舰", "163", "南昌舰"),
                        ("054A型护卫舰", "529", "舟山舰"),
                        ("054A型护卫舰", "530", "徐州舰"),
                        ("054A型护卫舰", "547", "临沂舰"),
                        ("054A型护卫舰", "568", "衡阳舰"),
                        ("054A型护卫舰", "570", "黄山舰"),
                    ]
                    for model_name, hull_number, ship_name in initial_data:
                        await cur.execute(
                            """
                            INSERT INTO ship_model_mapping (model_name, hull_number, ship_name)
                            VALUES (%s, %s, %s)
                            ON CONFLICT (hull_number) DO NOTHING
                            """,
                            (model_name, hull_number, ship_name)
                        )
                    print(f"[ship_model_db] 已插入 {len(initial_data)} 条初始数据")


async def load_ship_model_mapping() -> List[Dict[str, str]]:
    """
    从数据库加载全部舰船映射数据

    Returns:
        每艘舰一条记录的列表
        [
            {"model_name": "055型驱逐舰", "hull_number": "102", "ship_name": "拉萨舰"},
            ...
        ]
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[ship_model_db] psycopg_pool 未安装，返回空映射")
        return []

    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    await cur.execute(
                        "SELECT model_name, hull_number, ship_name FROM ship_model_mapping ORDER BY id"
                    )
                    rows = await cur.fetchall()
                    result = []
                    for row in rows:
                        model_name, hull_number, ship_name = row
                        result.append({
                            "model_name": model_name,
                            "hull_number": hull_number,
                            "ship_name": ship_name or "",
                        })
                    return result
    except Exception as e:
        print(f"[ship_model_db] 加载映射数据失败: {str(e)}")
        return []


async def add_ship(
    model_name: str,
    hull_number: str,
    ship_name: str = ""
) -> bool:
    """
    添加单艘舰船

    Args:
        model_name: 型号名称
        hull_number: 舷号
        ship_name: 舰名

    Returns:
        是否添加成功
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[ship_model_db] psycopg_pool 未安装，无法添加")
        return False

    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    await cur.execute(
                        """
                        INSERT INTO ship_model_mapping (model_name, hull_number, ship_name)
                        VALUES (%s, %s, %s)
                        ON CONFLICT (hull_number) DO UPDATE SET
                            model_name = EXCLUDED.model_name,
                            ship_name = EXCLUDED.ship_name
                        """,
                        (model_name, hull_number, ship_name)
                    )
        print(f"[ship_model_db] 舰船 {hull_number}({ship_name}) 已保存")
        return True
    except Exception as e:
        print(f"[ship_model_db] 添加舰船失败: {str(e)}")
        return False


async def delete_ship(hull_number: str) -> bool:
    """
    删除单艘舰船

    Args:
        hull_number: 舷号

    Returns:
        是否删除成功
    """
    try:
        from psycopg_pool import AsyncConnectionPool
    except ImportError:
        print("[ship_model_db] psycopg_pool 未安装，无法删除")
        return False

    try:
        async with AsyncConnectionPool(
            POSTGRES_CONNECTION_STRING,
            kwargs={"autocommit": True}
        ) as pool:
            async with pool.connection() as conn:
                async with conn.cursor() as cur:
                    await cur.execute(
                        "DELETE FROM ship_model_mapping WHERE hull_number = %s",
                        (hull_number,)
                    )
        print(f"[ship_model_db] 舰船 {hull_number} 已删除")
        return True
    except Exception as e:
        print(f"[ship_model_db] 删除舰船失败: {str(e)}")
        return False

hxgQ"""
受控 ReAct Text2SQL 工具
核心思想：Agent负责推理，Tool负责SQL，Reviewer负责纠错

内部流程：
1. Schema Injection - 注入数据库表结构
2. SQL Generation - LLM生成SQL（使用 SQLAlchemy 连接池 + extra_info 辅助）
3. SQL Review - LLM审查SQL正确性
4. SQL Guard - 代码级安全校验（硬限制）
5. SQL Execute - 执行SQL并返回结果（使用 SQLAlchemy 连接池单例）
6. Merge - 相似结果合并（Embedding）
"""
import re
import json
import asyncio
from datetime import datetime
from typing import Dict, Any, Optional, List, Tuple

from sqlalchemy import text
from langchain_community.utilities import SQLDatabase

from config import POSTGRES_CONNECTION_STRING,POSTGRES_SQLALCHEMY_URL
from modelsAPI.model_api import OpenaiAPI
from prompts import TEXT2SQL_PROMPTS
from tools.texttosql_utils import get_extra_info

# ============================================================
# 数据库连接池单例（避免重复初始化）
# ============================================================

_db_instance: Optional[SQLDatabase] = None
_db_lock = asyncio.Lock()


async def _get_db() -> SQLDatabase:
    """懒加载并缓存数据库连接，避免重复初始化"""
    global _db_instance
    if _db_instance is None:
        async with _db_lock:
            if _db_instance is None:
                _db_instance = await asyncio.to_thread(
                    SQLDatabase.from_uri, POSTGRES_SQLALCHEMY_URL
                )
    return _db_instance


# ============================================================
# Step 1: Schema Injection
# ============================================================

FAULT_RECORDS_SCHEMA = {
    "table_name": "fault_records",
    "description": "故障维修记录表，存储所有故障诊断和维修的记录",
    "columns": {
        "id": {
            "type": "SERIAL",
            "description": "自增主键",
            "usable_in_query": False
        },
        "ship_number": {
            "type": "TEXT",
            "description": "舰船舷号，如'101'、'163'、'554'等，2-4位数字",
            "usable_in_query": True,
            "examples": ["101", "163", "554", "602"]
        },
        "device_name": {
            "type": "TEXT",
            "description": "设备名称，如'主机'、'发电机'、'分油机'、'空压机'等",
            "usable_in_query": True,
            "examples": ["主机", "发电机", "分油机", "空压机", "舵机", "锅炉"]
        },
        "fault": {
            "type": "TEXT",
            "description": "故障现象描述，如'滑油压力低'、'异常振动'、'启动失败'等",
            "usable_in_query": True,
            "examples": ["滑油压力低", "异常振动", "启动失败", "排烟温度高"]
        },
        "spare_parts": {
            "type": "JSONB",
            "description": "消耗的备件列表，JSON数组格式，如'[\"密封圈\", \"滤芯\"]'",
            "usable_in_query": True,
            "json_query_hint": "使用 jsonb_array_elements_text(spare_parts) 展开备件进行统计"
        },
        "system_name": {
            "type": "TEXT",
            "description": "所属系统名称，如'动力系统'、'电气系统'、'导航系统'等",
            "usable_in_query": True,
            "examples": ["动力系统", "电气系统", "导航系统", "通信系统", "其他"]
        },
        "created_at": {
            "type": "TIMESTAMP",
            "description": "记录创建时间，默认为当前时间",
            "usable_in_query": True,
            "examples": ["2025-01-15 10:30:00"]
        }
    }
}

# 字段白名单（SQL Guard 使用）
ALLOWED_COLUMNS = set(FAULT_RECORDS_SCHEMA["columns"].keys())


def get_schema_prompt_section() -> str:
    """生成 Schema 注入的提示词部分"""
    lines = [f"数据库表：{FAULT_RECORDS_SCHEMA['table_name']}"]
    lines.append(f"说明：{FAULT_RECORDS_SCHEMA['description']}")
    lines.append("")
    lines.append("字段列表：")

    for col_name, col_info in FAULT_RECORDS_SCHEMA["columns"].items():
        if not col_info.get("usable_in_query", True):
            continue
        line = f"  - {col_name} ({col_info['type']}): {col_info['description']}"
        if "examples" in col_info:
            line += f"（示例：{', '.join(col_info['examples'][:3])}）"
        if "json_query_hint" in col_info:
            line += f"\n    查询提示：{col_info['json_query_hint']}"
        lines.append(line)

    return "\n".join(lines)


# ============================================================
# Step 2: SQL Generation
# ============================================================

async def generate_sql(question: str, current_date: str) -> Dict[str, Any]:
    """
    使用 LLM 根据用户问题生成 SQL。
    并发预热数据库连接与获取 extra_info，提升整体响应速度。

    Returns:
        {"sql": "SELECT ...", "success": True/False, "error": "..."}
    """
    

    schema_section = get_schema_prompt_section()

    # 并发：获取辅助信息 + 预热DB连接
    extra_info, _ = await asyncio.gather(
        get_extra_info(question),
        _get_db(),
    )

    prompt = TEXT2SQL_PROMPTS["sql_generation"].format(
        schema=schema_section,
        question=question,
        current_date=current_date,
        extra_info=extra_info or ""
    )
    print("输出最终sql的提示词内容")
    print(prompt)
    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(
            prompt,
            model=None,
            json_output=True
        )

        # 提取 JSON
        json_match = re.search(r'\{.*\}', result, re.DOTALL)
        if json_match:
            parsed = json.loads(json_match.group(0))
            sql = parsed.get("sql", "").strip()
            if sql:
                return {"sql": sql, "success": True, "error": ""}

        # 兜底：直接提取 SELECT 语句
        sql_match = re.search(r'(SELECT\s+.+?;?)$', result.strip(), re.IGNORECASE | re.DOTALL)
        if sql_match:
            sql = sql_match.group(1).strip().rstrip(';')
            return {"sql": sql, "success": True, "error": ""}

        return {"sql": "", "success": False, "error": "LLM未返回有效SQL"}

    except Exception as e:
        return {"sql": "", "success": False, "error": f"SQL生成失败: {str(e)}"}


# ============================================================
# Step 3: SQL Review (LLM 审查)
# ============================================================

async def review_sql(question: str, sql: str) -> Dict[str, Any]:
    """
    使用 LLM 审查 SQL 是否真正回答了用户问题

    Returns:
        {
            "approved": True/False,
            "issues": ["问题1", "问题2"],
            "suggested_sql": "修正后的SQL（如果有问题）",
            "review_comment": "审查意见"
        }
    """
    from modelsAPI.model_api import OpenaiAPI
    from prompts import TEXT2SQL_PROMPTS

    schema_section = get_schema_prompt_section()
    prompt = TEXT2SQL_PROMPTS["sql_review"].format(
        schema=schema_section,
        question=question,
        sql=sql
    )

    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(
            prompt,
            model=None,
            json_output=True
        )

        json_match = re.search(r'\{.*\}', result, re.DOTALL)
        if json_match:
            parsed = json.loads(json_match.group(0))
            approved = parsed.get("approved", False)
            issues = parsed.get("issues", [])
            suggested_sql = parsed.get("suggested_sql", "").strip()
            review_comment = parsed.get("review_comment", "")

            if suggested_sql:
                suggested_sql = suggested_sql.rstrip(';')

            return {
                "approved": approved,
                "issues": issues,
                "suggested_sql": suggested_sql,
                "review_comment": review_comment
            }

        return {
            "approved": True,
            "issues": [],
            "suggested_sql": "",
            "review_comment": "审查结果解析失败，默认通过"
        }

    except Exception as e:
        return {
            "approved": True,
            "issues": [],
            "suggested_sql": "",
            "review_comment": f"审查过程异常，默认通过: {str(e)}"
        }


# ============================================================
# Step 4: SQL Guard (代码级安全校验)
# ============================================================

class SQLGuardError(Exception):
    """SQL Guard 校验失败异常"""
    pass


def guard_sql(sql: str) -> Tuple[bool, str, str]:
    """
    SQL 安全守卫 - 代码硬限制

    Returns:
        (passed, cleaned_sql, error_message)
    """
    if not sql or not sql.strip():
        return False, "", "SQL为空"

    sql_upper = sql.strip().upper()

    # 1. 只允许 SELECT
    if not sql_upper.startswith("SELECT"):
        return False, "", "只允许SELECT查询，禁止INSERT/UPDATE/DELETE/CREATE等操作"

    # 2. 禁止 UNION
    if "UNION" in sql_upper:
        return False, "", "禁止使用UNION操作"

    # 3. 禁止子查询嵌套过深（最多2层）
    subquery_count = sql_upper.count("SELECT") - 1
    if subquery_count > 2:
        return False, "", f"子查询嵌套过深（{subquery_count}层），最多允许2层"

    # 4. 禁止危险函数
    dangerous_functions = ["PG_SLEEP", "SLEEP", "BENCHMARK", "WAITFOR", "DELAY"]
    for func in dangerous_functions:
        if func in sql_upper:
            return False, "", f"禁止使用危险函数: {func}"

    # 5. 禁止系统表访问
    system_tables = ["PG_", "INFORMATION_SCHEMA", "PG_CATALOG", "PG_CLASS"]
    for sys_table in system_tables:
        if sys_table in sql_upper:
            return False, "", f"禁止访问系统表: {sys_table}"

    # 6. 禁止注释注入
    if "--" in sql or "/*" in sql or "*/" in sql:
        return False, "", "SQL中不允许包含注释"

    # 7. 禁止分号（防止多语句注入）
    if ";" in sql.rstrip(';'):
        return False, "", "禁止多语句执行"

    # 8. 检查字段白名单
    used_columns = set()
    dot_matches = re.findall(r'fault_records\.(\w+)', sql, re.IGNORECASE)
    used_columns.update(m.lower() for m in dot_matches)

    select_match = re.search(r'SELECT\s+(.*?)\s+FROM', sql, re.IGNORECASE | re.DOTALL)
    if select_match:
        select_part = select_match.group(1)
        if '*' not in select_part:
            for part in select_part.split(','):
                part = part.strip()
                col_match = re.search(r'(\w+)\s*(?:AS|as)?\s*$', part)
                if col_match:
                    col_name = col_match.group(1).lower()
                    if col_name not in ('count', 'sum', 'avg', 'max', 'min', 'as',
                                        'desc', 'asc', 'null', 'distinct', 'all',
                                        'jsonb_array_elements_text', 'jsonb_array_elements',
                                        'coalesce', 'cast', 'date', 'timestamp', 'text'):
                        used_columns.add(col_name)

    for col in used_columns:
        if col not in ALLOWED_COLUMNS and col != 'id':
            return False, "", f"使用了不允许的字段: {col}"

    # 9. 自动添加 LIMIT（如果没有）
    cleaned_sql = sql.strip().rstrip(';')
    if "LIMIT" not in sql_upper:
        cleaned_sql = f"{cleaned_sql} LIMIT 100"

    # 10. 强制只查 fault_records 表
    from_match = re.search(r'FROM\s+(\w+)', sql, re.IGNORECASE)
    if from_match:
        table_name = from_match.group(1).lower()
        if table_name != "fault_records":
            return False, "", f"只允许查询 fault_records 表，不允许查询: {table_name}"

    return True, cleaned_sql, ""


# ============================================================
# Step 5: SQL Execute
# ============================================================

async def execute_sql(sql: str) -> Dict[str, Any]:
    """
    执行 SQL 并返回结果。
    使用模块级 SQLAlchemy 连接池单例，避免每次重复建立连接。

    Returns:
        {"rows": [...], "columns": [...], "row_count": int, "success": True/False, "error": ""}
    """
    try:
        db = await _get_db()

        def _run() -> Dict[str, Any]:
            try:
                with db._engine.connect() as conn:
                    result = conn.execute(text(sql))
                    columns = list(result.keys())
                    result_rows = []
                    for row in result.fetchall():
                        row_dict = {}
                        for i, col in enumerate(columns):
                            val = row[i]
                            if isinstance(val, datetime):
                                val = val.isoformat()
                            elif isinstance(val, (list, dict)):
                                val = json.dumps(val, ensure_ascii=False)
                            elif not isinstance(val, (str, int, float, bool, type(None))):
                                val = str(val)
                            row_dict[col] = val
                        result_rows.append(row_dict)
                    conn.commit()
                    return {
                        "rows": result_rows,
                        "columns": columns,
                        "row_count": len(result_rows),
                        "success": True,
                        "error": ""
                    }
            except Exception as e:
                return {
                    "rows": [],
                    "columns": [],
                    "row_count": 0,
                    "success": False,
                    "error": f"SQL执行失败: {str(e)}"
                }

        return await asyncio.to_thread(_run)

    except Exception as e:
        return {
            "rows": [],
            "columns": [],
            "row_count": 0,
            "success": False,
            "error": f"获取数据库连接失败: {str(e)}"
        }


# ============================================================
# Text2SQL 主入口 - 内部闭环
# ============================================================

MAX_RETRY = 2  # 最大重试次数（生成→审查→修正）


async def text2sql_tool(question: str, current_date: Optional[str] = None) -> Dict[str, Any]:
    """
    受控 Text2SQL 工具 - 内部形成闭环

    流程：question → SQL生成 → SQL审查 → SQL Guard → SQL执行 → 返回结果

    Args:
        question: 用户问题
        current_date: 当前日期（格式：YYYY-MM-DD），默认为今天

    Returns:
        {
            "success": True/False,
            "sql": "最终执行的SQL",
            "rows": [...],
            "columns": [...],
            "row_count": int,
            "error": "",
            "review_log": [...]  # 审查日志
        }
    """
    if not current_date:
        current_date = datetime.now().strftime("%Y-%m-%d")

    review_log = []
    current_sql = ""

    for attempt in range(MAX_RETRY + 1):
        # Step 2: SQL Generation
        if attempt == 0:
            gen_result = await generate_sql(question, current_date)
        else:
            gen_result = await generate_sql_with_feedback(
                question, current_date, current_sql, review_log
            )

        if not gen_result["success"]:
            return {
                "success": False,
                "sql": "",
                "rows": [],
                "columns": [],
                "row_count": 0,
                "error": gen_result["error"],
                "review_log": review_log
            }

        current_sql = gen_result["sql"]

        # Step 3: SQL Review
        review_result = await review_sql(question, current_sql)
        review_log.append({
            "attempt": attempt + 1,
            "sql": current_sql,
            "approved": review_result["approved"],
            "issues": review_result["issues"],
            "comment": review_result["review_comment"]
        })

        if not review_result["approved"]:
            if review_result["suggested_sql"]:
                current_sql = review_result["suggested_sql"]
                review_log.append({
                    "attempt": attempt + 1,
                    "sql": current_sql,
                    "note": "使用审查建议的修正SQL"
                })
            elif attempt < MAX_RETRY:
                continue
            else:
                return {
                    "success": False,
                    "sql": current_sql,
                    "rows": [],
                    "columns": [],
                    "row_count": 0,
                    "error": f"SQL审查不通过: {'; '.join(review_result['issues'])}",
                    "review_log": review_log
                }

        # Step 4: SQL Guard
        passed, cleaned_sql, guard_error = guard_sql(current_sql)
        if not passed:
            review_log.append({
                "attempt": attempt + 1,
                "sql": current_sql,
                "guard_passed": False,
                "guard_error": guard_error
            })
            if attempt < MAX_RETRY:
                review_log.append({"note": f"Guard拒绝: {guard_error}，将重新生成"})
                continue
            else:
                return {
                    "success": False,
                    "sql": current_sql,
                    "rows": [],
                    "columns": [],
                    "row_count": 0,
                    "error": f"SQL安全校验失败: {guard_error}",
                    "review_log": review_log
                }

        current_sql = cleaned_sql
        review_log.append({
            "attempt": attempt + 1,
            "sql": current_sql,
            "guard_passed": True,
            "note": "Guard通过"
        })

        # Step 5: SQL Execute
        exec_result = await execute_sql(current_sql)

        if not exec_result["success"]:
            if attempt < MAX_RETRY:
                review_log.append({
                    "attempt": attempt + 1,
                    "sql": current_sql,
                    "exec_error": exec_result["error"],
                    "note": "执行失败，将重新生成"
                })
                continue
            else:
                return {
                    "success": False,
                    "sql": current_sql,
                    "rows": [],
                    "columns": [],
                    "row_count": 0,
                    "error": exec_result["error"],
                    "review_log": review_log
                }

        # Step 6: 相似结果合并
        merged_rows = await merge_similar_rows(
            exec_result["rows"], exec_result["columns"], question
        )

        return {
            "success": True,
            "sql": current_sql,
            "rows": merged_rows,
            "columns": exec_result["columns"],
            "row_count": len(merged_rows),
            "raw_row_count": exec_result["row_count"],
            "error": "",
            "review_log": review_log
        }

    return {
        "success": False,
        "sql": current_sql,
        "rows": [],
        "columns": [],
        "row_count": 0,
        "error": "超过最大重试次数",
        "review_log": review_log
    }


async def generate_sql_with_feedback(
    question: str,
    current_date: str,
    previous_sql: str,
    review_log: List[Dict[str, Any]]
) -> Dict[str, Any]:
    """
    基于审查反馈重新生成 SQL
    """
    from modelsAPI.model_api import OpenaiAPI
    from prompts import TEXT2SQL_PROMPTS

    schema_section = get_schema_prompt_section()

    feedback_parts = []
    for log_entry in review_log:
        if "issues" in log_entry and log_entry["issues"]:
            feedback_parts.append(f"问题: {'; '.join(log_entry['issues'])}")
        if "guard_error" in log_entry:
            feedback_parts.append(f"安全校验失败: {log_entry['guard_error']}")
        if "exec_error" in log_entry:
            feedback_parts.append(f"执行失败: {log_entry['exec_error']}")

    feedback = "\n".join(feedback_parts) if feedback_parts else "无具体反馈"

    prompt = TEXT2SQL_PROMPTS["sql_regeneration"].format(
        schema=schema_section,
        question=question,
        current_date=current_date,
        previous_sql=previous_sql,
        feedback=feedback
    )

    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(
            prompt,
            model=None,
            json_output=True
        )

        json_match = re.search(r'\{.*\}', result, re.DOTALL)
        if json_match:
            parsed = json.loads(json_match.group(0))
            sql = parsed.get("sql", "").strip()
            if sql:
                return {"sql": sql, "success": True, "error": ""}

        sql_match = re.search(r'(SELECT\s+.+?;?)$', result.strip(), re.IGNORECASE | re.DOTALL)
        if sql_match:
            sql = sql_match.group(1).strip().rstrip(';')
            return {"sql": sql, "success": True, "error": ""}

        return {"sql": "", "success": False, "error": "重新生成SQL失败"}

    except Exception as e:
        return {"sql": "", "success": False, "error": f"重新生成SQL异常: {str(e)}"}


# ============================================================
# Step 6: 相似结果合并（Embedding）
# ============================================================

MERGE_KEYWORDS = ["故障", "频次", "排名", "高频", "最多", "top", "发生次数"]


def _should_merge(columns: List[str], question: str) -> bool:
    """判断是否需要合并相似行"""
    question_lower = question.lower()
    if any(kw in question_lower for kw in MERGE_KEYWORDS):
        col_names = [c.lower() for c in columns]
        has_name = any(n in col_names for n in ["name", "故障", "fault", "device_name"])
        has_count = any(n in col_names for n in ["count", "次数", "频次"])
        return has_name and has_count
    return False


def _find_name_column(columns: List[str]) -> Optional[str]:
    """找到名称列"""
    priority = ["name", "故障名称", "故障", "fault", "device_name", "备件", "spare"]
    col_lower_map = {c.lower(): c for c in columns}
    for p in priority:
        if p in col_lower_map:
            return col_lower_map[p]
    for c in columns:
        if c.lower() not in ("count", "次数", "频次", "rank", "排名", "system_name", "系统"):
            return c
    return None


def _find_count_column(columns: List[str]) -> Optional[str]:
    """找到计数列"""
    priority = ["count", "次数", "频次", "cnt"]
    col_lower_map = {c.lower(): c for c in columns}
    for p in priority:
        if p in col_lower_map:
            return col_lower_map[p]
    return None


def _find_system_column(columns: List[str]) -> Optional[str]:
    """找到系统分类列"""
    priority = ["system_name", "系统", "系统分类", "system"]
    col_lower_map = {c.lower(): c for c in columns}
    for p in priority:
        if p in col_lower_map:
            return col_lower_map[p]
    return None


async def merge_similar_rows(
    rows: List[Dict[str, Any]],
    columns: List[str],
    question: str,
    similarity_threshold: float = 0.85
) -> List[Dict[str, Any]]:
    """
    使用 embedding 合并相似的故障/备件行

    例如：
    - "连杆大端轴承发生损坏异常" (7次, 其他) + "连杆大端轴承发生损坏异常" (6次, 汽车配件)
      → "连杆大端轴承发生损坏异常" (13次, 其他)
    - "发动机中空冷器管束芯体结垢或堵塞..." + "空冷器管束芯体结垢或堵塞..."
      → 合并为一条
    """
    if not rows or len(rows) <= 1:
        return rows

    if not _should_merge(columns, question):
        return rows

    name_col = _find_name_column(columns)
    count_col = _find_count_column(columns)
    system_col = _find_system_column(columns)

    if not name_col or not count_col:
        return rows

    try:
        from modelsAPI.model_api import OpenaiAPI

        names = [row[name_col] for row in rows if row.get(name_col)]
        if len(names) <= 1:
            return rows

        embeddings = await OpenaiAPI.get_embeddings_batch_async(names)
        name_emb_map = {name: emb for name, emb in zip(names, embeddings)}

        sorted_rows = sorted(rows, key=lambda r: int(r.get(count_col, 0)), reverse=True)

        merged_rows = []
        merged_indices = set()

        for i, row in enumerate(sorted_rows):
            if i in merged_indices:
                continue

            name_i = row.get(name_col, "")
            emb_i = name_emb_map.get(name_i)

            if not emb_i:
                merged_rows.append(row)
                continue

            merged_row = dict(row)
            total_count = int(row.get(count_col, 0))
            systems = set()
            if system_col and row.get(system_col):
                systems.add(row[system_col])

            for j in range(i + 1, len(sorted_rows)):
                if j in merged_indices:
                    continue

                name_j = sorted_rows[j].get(name_col, "")
                emb_j = name_emb_map.get(name_j)

                if not emb_j:
                    continue

                similarity = OpenaiAPI.cosine_similarity(emb_i, emb_j)

                if similarity >= similarity_threshold:
                    total_count += int(sorted_rows[j].get(count_col, 0))
                    if system_col and sorted_rows[j].get(system_col):
                        systems.add(sorted_rows[j][system_col])
                    merged_indices.add(j)

            merged_row[count_col] = total_count
            if system_col and systems:
                merged_row[system_col] = "、".join(sorted(systems))

            merged_rows.append(merged_row)
            merged_indices.add(i)

        merged_rows.sort(key=lambda r: int(r.get(count_col, 0)), reverse=True)

        if "rank" in columns or "排名" in columns:
            rank_col = "rank" if "rank" in columns else "排名"
            for idx, row in enumerate(merged_rows):
                row[rank_col] = idx + 1

        return merged_rows

    except Exception as e:
        print(f"Embedding合并失败，使用原始数据: {str(e)}")
        return rows


r5xiimport os
import ast
import re
import asyncio
import httpx
from typing import List, Dict

from neo4j import GraphDatabase
from neo4j_graphrag.retrievers import HybridCypherRetriever
from neo4j_graphrag.embeddings.base import Embedder
from modelsAPI.model_api import LocalBgeM3Embeddings, OpenaiAPI
from config import MAP_INS, NEO4J_CONFIG, INDEX_CONFIG, EMBEDDING_CONFIG

# ================== 配置 ==================
URI                 = NEO4J_CONFIG["uri"]
AUTH                = (NEO4J_CONFIG["user"], NEO4J_CONFIG["password"])
NAME_PROPERTY       = INDEX_CONFIG["NAME_PROPERTY"]
FULLTEXT_PROPERTY   = INDEX_CONFIG["FULLTEXT_PROPERTY"]
EMBEDDING_PROPERTY  = INDEX_CONFIG["EMBEDDING_PROPERTY"]
SEARCH_LABEL        = INDEX_CONFIG["SEARCH_LABEL"]
VECTOR_INDEX_NAME   = INDEX_CONFIG["VECTOR_INDEX_NAME"]
FULLTEXT_INDEX_NAME = INDEX_CONFIG["FULLTEXT_INDEX_NAME"]
map_ins             = MAP_INS

# ================== 全局复用：driver / embedder 只初始化一次 ==================
_driver   = None
_embedder = None

def get_driver():
    global _driver
    if _driver is None:
        _driver = GraphDatabase.driver(URI, auth=AUTH)
    return _driver

def get_embedder():
    global _embedder
    if _embedder is None:
        _embedder = LocalBgeM3Embeddings(
            base_url=EMBEDDING_CONFIG["base_url"],
            api_key=EMBEDDING_CONFIG["api_key"],
        )
    return _embedder


# ================== 辅助：解析 Record 字符串 ==================
def parse_record_string(s: str):
    name_match   = re.search(r"name='([^']*)'",      s)
    labels_match = re.search(r"labels=(\[[^\]]*\])", s)
    score_match  = re.search(r"score=([\d.]+)",       s)

    name   = name_match.group(1) if name_match else "未知名称"
    labels = ["未知标签"]
    if labels_match:
        try:
            labels = ast.literal_eval(labels_match.group(1))
        except (ValueError, SyntaxError):
            pass
    score = float(score_match.group(1)) if score_match else 0.0
    return name, labels, score


# ================== 构建 Retriever ==================
def build_retriever(sync_driver, embedder: Embedder) -> HybridCypherRetriever:
    return HybridCypherRetriever(
        driver=sync_driver,
        vector_index_name=VECTOR_INDEX_NAME,
        fulltext_index_name=FULLTEXT_INDEX_NAME,
        embedder=embedder,
        retrieval_query=f"""
            RETURN
                node.`{NAME_PROPERTY}` AS name,
                [lbl IN labels(node) WHERE lbl <> '{SEARCH_LABEL}'] AS labels,
                score
        """,
    )


# ================== 同步检索（在线程池中执行，不阻塞事件循环）==================
def _hybrid_search_sync(sentence: str, top_k: int = 10) -> List[Dict]:
    retriever   = build_retriever(get_driver(), get_embedder())
    results_raw = retriever.search(query_text=sentence, top_k=top_k)

    hybrid_results: List[Dict] = []
    for item in results_raw.items:
        content = item.content
        name    = "未知名称"
        labels  = ["未知标签"]
        score   = 0.0

        if hasattr(content, "keys"):
            name   = content.get("name",   name)
            labels = content.get("labels", labels)
            score  = content.get("score",  score)
        elif isinstance(content, str):
            if content.startswith("<Record"):
                name, labels, score = parse_record_string(content)
            else:
                try:
                    parsed = ast.literal_eval(content)
                    if isinstance(parsed, dict):
                        name   = parsed.get("name",   name)
                        labels = parsed.get("labels", labels)
                        score  = parsed.get("score",  score)
                except (ValueError, SyntaxError):
                    name = content

        if score == 0.0 and hasattr(item, "metadata") and item.metadata:
            score = item.metadata.get("score", score)

        hybrid_results.append({
            "标签": labels,
            "名称": name,
            "得分": score,
            "来源": "hybrid",
            "fulltext_snippet": "",
        })

    return hybrid_results


# ================== Prompt 模板 ==================
PROMPT_TEMPLATE = """
请根据给出的问题，以及问题相关的检索结果，以及实体类型和sql表字段映射表，筛选出与问题相关的信息并输出。
要求：
1. 请仔细分析问题和检索结果，确定问题中出现的实体类型和sql表字段。
2. 输出内容可以为充分分析后的一段文本，即你对这个问题中所用到的实体类型和sql表字段的描述。
3. 给出的信息尽量精简，不能省略任何重要信息。
实体类型和sql表字段映射表：
    {map_ins}
其中键表示实体类型，值表示sql表字段。

检索结果：
{results}

问题：{user_question}


案例1：
用户问题为：扫气箱内发现润滑油泄漏发生了多少次？
检索知识库为：   
   [ 1] score=1.0000 | 活塞杆填料函密封失效导致扫气箱内发现润滑油泄漏  标签=['故障模式']
   [ 2] score=0.9298 | 排除喷油器雾化不良故障  标签=['维修项目']
   [ 3] score=0.9115 | 执行发动机燃油泄漏应急封堵操作  标签=['操作项目']
   [ 4] score=0.9082 | 活塞环磨损或断裂导致机座与机架组件润滑油消耗异常增加  标签=['故障模式']
   [ 5] score=0.9058 | 检测气缸套内径磨损量  标签=['维修项目']
   [ 6] score=0.9049 | 拆检活塞头磨损情况  标签=['维修项目']
   [ 7] score=0.9048 | 检查排气阀杆密封面磨损  标签=['维修项目']
   [ 8] score=0.9015 | 润滑油压力骤降导致轴承组件紧急停机  标签=['故障模式']
   [ 9] score=0.8985 | 喷油器组件的维修工作  标签=['维修工作']
   [10] score=0.8979 | 发动机的安全警告  标签=['安全警告']
输出为：
问题中扫气箱内发现润滑油泄漏是一个故障现象，属于表中fault字段。
"""

SYSTEM_PROMPT = "你是一个专业信息筛选助手，根据给出的问题和问题检索到的相关实体关系，筛选出与问题相关的信息。"


# ================== 主函数（传参调用）==================
async def get_extra_info(user_question: str, top_k: int = 20) -> str:
    """
    参数:
        user_question: 用户问题
        top_k:         检索返回条数
    返回:
        LLM 筛选结果字符串
    """
    # 同步检索放入线程池，不阻塞事件循环
    results = await asyncio.to_thread(_hybrid_search_sync, user_question, top_k)

    # 构建 prompt 并异步调用 LLM
    res = await OpenaiAPI.open_api_chat_without_thinking(
        system_prompt=SYSTEM_PROMPT,
        query=PROMPT_TEMPLATE.format(results=results, map_ins=map_ins,user_question=user_question),
    )

    return res.strip()


# ================== 入口 ==================
if __name__ == "__main__":
    answer = asyncio.run(get_extra_info("发动机这个月发生了多少次故障"))
    print(111111111111111111)
    print(answer)

հx ("""
VLM图像处理工具模块
包含图像识别、图像压缩、图像保存等功能
"""
import os
import re
import json
import math
import base64
import uuid
from datetime import datetime
from typing import Optional, Dict, Any
from PIL import Image
from io import BytesIO
import tiktoken
from langchain_core.tools import tool

from config import VLM_CONFIG, SERVER_CONFIG
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import track_function_calls


VLM_API_BASE = VLM_CONFIG["api_base"]
VLM_MODEL_NAME = VLM_CONFIG["model"]
MAX_MODEL_LEN = 32768
INPUT_TOKEN_SAFETY_RATIO = 0.8
MIN_IMAGE_SIZE = 224
JPEG_QUALITY = 85

SYSTEM_PROMPT_VLM = """你是一个专业的工业设备巡检专家助手。
你的任务是协助工程师分析现场情况。

当你遇到以下情况时：
1. 用户提供了图片路径（如 .png, .jpg, /app/data/... 等）。
2. 用户询问有关设备外观、颜色、仪表读数或物理损坏的问题。

你应该：
- 调用 `vlm_image_to_text` 工具。
- 在 `prompt` 参数中，根据用户的具体意图（如：检查漏油、读仪表、看指示灯）量身定制分析指令。
- 获取 VLM 结果后，结合专业知识给出建议。
"""


def encode_image(image_path: str) -> str:
    """将本地图片转换为 Base64 编码"""
    with open(image_path, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")


def estimate_qwen_vl_visual_tokens(width: int, height: int) -> int:
    """
    根据 Qwen-VL 的图像分块策略估算视觉 tokens。
    公式来源：Qwen-VL 官方技术文档（Naive resizing + 192 tokens per unit）
    """
    units_h = math.ceil(height / 336)
    units_w = math.ceil(width / 336)
    total_units = units_h * units_w + 1
    return total_units * 192


def count_text_tokens(text: str) -> int:
    """使用 tiktoken 估算文本 token 数（兼容中英文）"""
    enc = tiktoken.get_encoding("cl100k_base")
    return len(enc.encode(text))


def smart_resize_base64_image(
    base64_image: str,
    prompt_text: str,
    max_input_tokens: int = int(MAX_MODEL_LEN * INPUT_TOKEN_SAFETY_RATIO),
    min_size: int = MIN_IMAGE_SIZE,
    jpeg_quality: int = JPEG_QUALITY
) -> str:
    """
    智能压缩 base64 图像，确保 (文本 tokens + 视觉 tokens) <= max_input_tokens
    """
    if not base64_image.startswith("data:image"):
        raise ValueError("Invalid base64 image format. Must start with 'data:image'.")

    try:
        header, b64_data = base64_image.split(",", 1)
        image_data = base64.b64decode(b64_data)
        img = Image.open(BytesIO(image_data)).convert("RGB")
        orig_w, orig_h = img.size
    except Exception as e:
        raise ValueError(f"Failed to decode base64 image: {e}")

    text_tokens = count_text_tokens(prompt_text)
    visual_tokens = estimate_qwen_vl_visual_tokens(orig_w, orig_h)
    total_tokens = text_tokens + visual_tokens

    print(f"[VLM Preprocess] 原始尺寸: {orig_w}x{orig_h} | 文本 tokens: {text_tokens} | 视觉 tokens: {visual_tokens} | 总计: {total_tokens}")

    if total_tokens <= max_input_tokens:
        print("[VLM Preprocess] ✅ 无需压缩")
        return base64_image

    scale = 1.0
    target_tokens = total_tokens
    while target_tokens > max_input_tokens and scale > 0.1:
        scale *= 0.8
        new_w = max(min_size, int(orig_w * scale))
        new_h = max(min_size, int(orig_h * scale))
        target_tokens = text_tokens + estimate_qwen_vl_visual_tokens(new_w, new_h)

    final_w = max(min_size, int(orig_w * scale))
    final_h = max(min_size, int(orig_h * scale))

    print(f"[VLM Preprocess] ⚠️ 需压缩 → 新尺寸: {final_w}x{final_h} | 预估总 tokens: {target_tokens}")

    resized_img = img.resize((final_w, final_h), Image.Resampling.LANCZOS)
    buffer = BytesIO()
    resized_img.save(buffer, format="JPEG", quality=jpeg_quality)
    compressed_b64 = base64.b64encode(buffer.getvalue()).decode("utf-8")
    return f"data:image/jpeg;base64,{compressed_b64}"


def save_base64_image_and_record(
    base64_image: str,
    description: str,
    output_dir: str = "image_input",
    record_file: str = "image_input/image_records.json"
) -> Dict[str, Any]:
    """
    保存 base64 图片到指定目录，并记录图片名称和描述到 JSON 文件。
    
    Args:
        base64_image: base64 编码的图片数据（data:image/xxx;base64,... 格式）
        description: 图片的描述文本
        output_dir: 图片保存目录
        record_file: 记录 JSON 文件路径
    
    Returns:
        包含保存结果的字典：{"success": bool, "image_name": str, "image_path": str, "error": str}
    """
    try:
        if not base64_image.startswith("data:image"):
            return {"success": False, "error": "Invalid base64 image format"}
        
        header, b64_data = base64_image.split(",", 1)
        
        if "jpeg" in header or "jpg" in header:
            ext = "jpg"
        elif "png" in header:
            ext = "png"
        elif "gif" in header:
            ext = "gif"
        elif "webp" in header:
            ext = "webp"
        else:
            ext = "jpg"
        
        os.makedirs(output_dir, exist_ok=True)
        
        image_name = f"{uuid.uuid4().hex[:12]}_{datetime.now().strftime('%Y%m%d%H%M%S')}.{ext}"
        image_path = os.path.join(output_dir, image_name)
        
        image_data = base64.b64decode(b64_data)
        with open(image_path, "wb") as f:
            f.write(image_data)
        
        record_entry = {
            "image_name": image_name,
            "image_path": image_path,
            "description": description,
            "timestamp": datetime.now().isoformat()
        }
        
        os.makedirs(os.path.dirname(record_file), exist_ok=True)
        
        existing_records = []
        if os.path.exists(record_file):
            try:
                with open(record_file, "r", encoding="utf-8") as f:
                    existing_records = json.load(f)
                    if not isinstance(existing_records, list):
                        existing_records = []
            except (json.JSONDecodeError, IOError):
                existing_records = []
        
        existing_records.append(record_entry)
        
        with open(record_file, "w", encoding="utf-8") as f:
            json.dump(existing_records, f, ensure_ascii=False, indent=2)
        
        print(f"[ImageSaved] 图片已保存: {image_path}")
        
        return {
            "success": True,
            "image_name": image_name,
            "image_path": image_path,
            "error": None
        }
        
    except Exception as e:
        return {
            "success": False,
            "image_name": None,
            "image_path": None,
            "error": str(e)
        }


@tool
async def vlm_image_to_text(
    image_path: str,
    prompt: Optional[str] = None
) -> str:
    """
    调用 Qwen3.5-35B 进行工业巡检分析。
    - 自动移除所有 <think...</think 包裹的内容（包括多行）
    - 仅返回最终结果文本
    - 支持 40K token 上下文，自动压缩大图
    """

    default_prompt = (
        "【重要指令】禁止输出任何形式的   <think...</think、<reasoning></reasoning> 或其他内部思考过程。"
        "仅输出最终的专业分析结果。\n\n"
        "你是一位资深的工业巡检专家。请仔细观察这张图片并按以下结构报告：\n"
        "1. 设备识别：图中是什么设备？型号或标签是否可见？\n"
        "2. 状态评估：仪表盘数值是否在正常区间？指示灯颜色是什么？\n"
        "3. 异常检测：是否存在漏油、生锈、电缆破损、螺丝松动或烟雾？\n"
        "4. 环境风险：周围是否有杂物堆放或安全隐患？\n"
        "请用专业、客观、简短的语言描述。"
    )

    final_prompt = f"{default_prompt}\n特别注意：{prompt}" if prompt else default_prompt

    safe_image = smart_resize_base64_image(
        base64_image=image_path,
        prompt_text=final_prompt,
        max_input_tokens=int(MAX_MODEL_LEN * INPUT_TOKEN_SAFETY_RATIO)
    )

    try:
        result = await OpenaiAPI.open_api_vl_without_thinking(safe_image)

        print(f"✅ 最终输出:\n{result}")
        
        save_result = save_base64_image_and_record(
            base64_image=image_path,
            description=result,
            output_dir="picture",
            record_file="picture/image_records.json"
        )
        if save_result["success"]:
            print(f"📷 图片已保存: {save_result['image_name']}")
            image_url = f"{SERVER_CONFIG['base_url']}/picture/{save_result['image_name']}"
            result = f"{result}\n\n![用户上传图片]({image_url})"
        else:
            print(f"⚠️ 图片保存失败: {save_result['error']}")
        
        return result

    except Exception as e:
        import traceback
        error_msg = f"VLM 调用失败: {str(e)}\n{traceback.format_exc()}"
        print(error_msg)
        return error_msg


@track_function_calls
async def image_rag_describe(
    image_path: str,
    query: str,
    top_k: int = 5
) -> str:
    """
    图像RAG描述工具
    先用VLM分析图像，然后用RAG检索相关知识

    Args:
        image_path: 图像路径（base64格式）
        query: 查询文本
        top_k: RAG检索数量

    Returns:
        分析结果文本
    """
    try:
        vlm_result = await vlm_image_to_text(image_path, prompt=query)
        
        from .rag_tools import rag_search
        rag_result = await rag_search(query=f"{query} {vlm_result}", top_k=top_k)
        
        if rag_result.get("success", False):
            source_citation = rag_result.get("sourceCitation", {})
            rag_text = ""
            for resource, items in source_citation.items():
                for item in items:
                    rag_text += f"【{resource}】{item.get('text', '')}\n\n"
            
            return f"图像分析结果：\n{vlm_result}\n\n相关知识：\n{rag_text}"
        else:
            return vlm_result
            
    except Exception as e:
        return f"图像RAG分析失败: {str(e)}"
'ѭxR100644 MML2OMML.XSL >x[fUtS:100644 __init__.py x*adŔ7&Age40000 __pycache__ YQBv-,?t
%J100644 function_tracker.py )&
49100644 image_utils.py u}G~̢100644 intent_matcher.py ~aCU](evҲP100644 pdf_generator.py ns8[5t=100644 ship_number_search.py ;؀z-100644 template.tex k'%mK(w[x*100644 word_generator.py â	|U>)#˽mTZ
\x   <?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:mml="http://www.w3.org/1998/Math/MathML"
	xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" exclude-result-prefixes="mml">
  <xsl:output method="xml" encoding="UTF-8" />


  <xsl:variable name="StrUCAlphabet">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>
  <xsl:variable name="StrLCAlphabet">abcdefghijklmnopqrstuvwxyz</xsl:variable>

  <!-- %%Template: match *

		The catch all template, just passes through 
	-->
  <xsl:template match="*">
    <xsl:apply-templates select="*" />
  </xsl:template>

  <!-- %%Template: match display="block" on math tag
       Add m:oMathPara and m:oMath for display="block"
  -->
  <xsl:template match="/mml:math[@display=&quot;block&quot;]">
    <m:oMathPara>
      <m:oMath>
        <xsl:apply-templates select="*" />
      </m:oMath>
    </m:oMathPara>
  </xsl:template>

  <!-- %%Template: match math tag without display="block"
       Add m:oMath when it isn't display="block"
  -->
  <xsl:template match="/mml:math[not(@display) or @display!=&quot;block&quot;]">
    <m:oMath>
      <xsl:apply-templates select="*" />
    </m:oMath>
  </xsl:template>

  <!-- %%Template: SReplace

		Replace all occurences of sOrig in sInput with sReplacement
		and return the resulting string. -->
  <xsl:template name="SReplace">
    <xsl:param name="sInput" />
    <xsl:param name="sOrig" />
    <xsl:param name="sReplacement" />

    <xsl:choose>
      <xsl:when test="not(contains($sInput, $sOrig))">
        <xsl:value-of select="$sInput" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="sBefore" select="substring-before($sInput, $sOrig)" />
        <xsl:variable name="sAfter" select="substring-after($sInput, $sOrig)" />
        <xsl:variable name="sAfterProcessed">
          <xsl:call-template name="SReplace">
            <xsl:with-param name="sInput" select="$sAfter" />
            <xsl:with-param name="sOrig" select="$sOrig" />
            <xsl:with-param name="sReplacement" select="$sReplacement" />
          </xsl:call-template>
        </xsl:variable>

        <xsl:value-of select="concat($sBefore, concat($sReplacement, $sAfterProcessed))" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: OutputText

		Post processing on the string given and otherwise do
		a xsl:value-of on it -->
  <xsl:template name="OutputText">
    <xsl:param name="sInput" />

    <!-- Add local variable as you add new post processing tasks -->

    <!-- 1. Remove any unwanted characters -->
    <xsl:variable name="sCharStrip">
      <xsl:value-of select="translate($sInput, '&#x2062;&#x200B;', '')" />
    </xsl:variable>

    <!-- 2. Replace any characters as needed -->
    <!--	Replace &#x2A75; <-> ==			 -->
    <xsl:variable name="sCharReplace">
      <xsl:call-template name="SReplace">
        <xsl:with-param name="sInput" select="$sCharStrip" />
        <xsl:with-param name="sOrig" select="'&#x2A75;'" />
        <xsl:with-param name="sReplacement" select="'=='" />
      </xsl:call-template>
    </xsl:variable>

    <!-- Preserve &#xa0; (non-breaking space) as-is so that it is not lost on import. -->
    <xsl:variable name="sCharReplaceFinal" select="$sCharReplace" />

    <!-- Finally, return the last value -->
    <xsl:value-of select="$sCharReplaceFinal" />
  </xsl:template>


  <!-- Template that determines whether or the given node 
	     ndCur is a token element that doesn't have an mglyph as 
			 a child.
	-->
  <xsl:template name="FNonGlyphToken">
    <xsl:param name="ndCur" select="." />
    <xsl:choose>
      <xsl:when test="$ndCur/self::mml:mi[not(child::mml:mglyph)] | 
	                     $ndCur/self::mml:mn[not(child::mml:mglyph)] | 
	                     $ndCur/self::mml:mo[not(child::mml:mglyph)] | 
	                     $ndCur/self::mml:ms[not(child::mml:mglyph)] |
                       $ndCur/self::mml:mtext[not(child::mml:mglyph)]">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: determines if the current token element (ndCur) is the beginning of a run.
       A token element is the beginning of if:

       the count of preceding elements is 0 or
       the directly preceding element is not a non-glyph token or fence open or separator element or
       it is an nary argument
	-->
  <xsl:template name="FStartOfRun">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fPrecSibNonGlyphToken">
      <xsl:call-template name="FNonGlyphToken">
        <xsl:with-param name="ndCur" select="$ndCur/preceding-sibling::*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fFencedParent">
      <xsl:call-template name="FFenced">
        <xsl:with-param name="ndCur" select="$ndCur/.." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fenceOpenChar">
      <xsl:call-template name="FenceOpenChar">
        <xsl:with-param name="ndCur" select="$ndCur/.." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fenceSeparatorChar">
      <xsl:call-template name="FenceSeparatorChar">
        <xsl:with-param name="ndCur" select="$ndCur/.." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fPrecSibFence">
      <xsl:choose>
        <xsl:when test="$fFencedParent=1 and
                        (($fenceOpenChar!='' and $ndCur/preceding-sibling::*[1][position()=1]) or
                          ($fenceSeparatorChar!='' and $ndCur/preceding-sibling::*[1][self::mml:mo]))">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="count($ndCur/preceding-sibling::*)=0 or
                      $fPrecSibNonGlyphToken=0 or
                      $fPrecSibFence=1 or
                      $fNaryArgument=1">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Template that determines if ndCur is the argument of an nary expression. 
			 
			 ndCur is the argument of an nary expression if:
			 
			 1.  The preceding sibling is one of the following:  munder, mover, msub, msup, munder, msubsup, munderover
			 and
			 2.  The preceding sibling's child is an nary char as specified by the template "isNary"
	-->
  <xsl:template name="FIsNaryArgument">
    <xsl:param name="ndCur" select="." />

    <xsl:variable name="fNary">
      <xsl:call-template name="isNary">
        <xsl:with-param name="ndCur" select="$ndCur/preceding-sibling::*[1][not(self::mml:mstyle[count(*) = 1])]/*[1] |
                                             $ndCur/preceding-sibling::*[1][self::mml:mstyle[count(*) = 1]]/*[1]/*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="preceding-sibling::*[1][self::mml:munder or self::mml:mover or self::mml:munderover or
                      self::mml:msub or self::mml:msup or self::mml:msubsup or
                      self::mml:mstyle[count(*) = 1 and (mml:munder or mml:mover or mml:munderover or
                      mml:msub or mml:msup or mml:msubsup)]] and
                      $fNary='true'">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: mml:mrow | mml:mstyle

		 if this row is the next sibling of an n-ary (i.e. any of 
         mover, munder, munderover, msupsub, msup, or msub with 
         the base being an n-ary operator) then ignore this. Otherwise
         pass through -->
  <xsl:template match="mml:mrow|mml:mstyle">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="."/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:variable name="fLinearFrac">
        <xsl:call-template name="FLinearFrac">
          <xsl:with-param name="ndCur" select="." />
        </xsl:call-template>
      </xsl:variable>
      <xsl:choose>
        <xsl:when test="$fLinearFrac=1">
          <xsl:call-template name="MakeLinearFraction">
            <xsl:with-param name="ndCur" select="." />
          </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="fFunc">
            <xsl:call-template name="FIsFunc">
              <xsl:with-param name="ndCur" select="." />
            </xsl:call-template>
          </xsl:variable>
          <xsl:choose>
            <xsl:when test="$fFunc=1">
              <xsl:call-template name="WriteFunc">
                <xsl:with-param name="ndCur" select="." />
              </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
              <xsl:variable name="fFencedWithScript">
                <xsl:call-template name="FFencedWithScript">
                  <xsl:with-param name="ndCur" select="." />
                </xsl:call-template>
              </xsl:variable>
              <xsl:variable name="fFenced">
                <xsl:call-template name="FFenced">
                  <xsl:with-param name="ndCur" select="." />
                </xsl:call-template>
              </xsl:variable>
              <xsl:choose>
                <xsl:when test="$fFencedWithScript=1">
                  <xsl:call-template name="WriteFencedWithScript">
                    <xsl:with-param name="ndCur" select="." />
                  </xsl:call-template>
                </xsl:when>
                <xsl:when test="$fFenced=1">
                  <xsl:call-template name="WriteFenced">
                    <xsl:with-param name="ndCur" select="." />
                  </xsl:call-template>
                </xsl:when>
                <xsl:otherwise>
                  <xsl:apply-templates select="*" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:if>
  </xsl:template>


  <!-- %%Template: match mi, mn, mo, ms and mtext elements that don't have an mglyph child
  -->
  <xsl:template match="mml:mi[not(child::mml:mglyph)] | 
                       mml:mn[not(child::mml:mglyph)] | 
                       mml:mo[not(child::mml:mglyph)] | 
                       mml:ms[not(child::mml:mglyph)] |
                       mml:mtext[not(child::mml:mglyph)]">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MNonGlyphToken">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MNonGlyphToken">
    <xsl:param name="ndCur" select="." />

    <!-- tokens with mglyphs as children are tranformed
			 in a different manner than "normal" token elements.  
			 Where normal token elements are token elements that
			 contain only text -->
    <xsl:variable name="fStartOfRun">
      <xsl:call-template name="FStartOfRun">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>

    <!--In MathML, successive characters that are all part of one string are sometimes listed as separate 
			tags based on their type (identifier (mi), name (mn), operator (mo), quoted (ms), literal text (mtext)), 
			where said tags act to link one another into one logical run.  In order to wrap the text of successive mi's, 
			mn's, and mo's into one m:t, we need to denote where a run begins.  The beginning of a run is the first mi, mn, 
			or mo whose immediately preceding sibling either doesn't exist or is something other than a "normal" mi, mn, mo, 
			ms, or mtext tag-->

    <!-- If this mi/mo/mn/ms . . . is part the numerator or denominator of a linear fraction, then don't collect. -->
    <xsl:variable name="fLinearFracParent">
      <xsl:call-template name="FLinearFrac">
        <xsl:with-param name="ndCur" select="$ndCur/parent::*" />
      </xsl:call-template>
    </xsl:variable>
    <!-- If this mi/mo/mn/ms . . . is part of the name of a function, then don't collect. -->
    <xsl:variable name="fFunctionName">
      <xsl:call-template name="FIsFunc">
        <xsl:with-param name="ndCur" select="$ndCur/parent::*" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fFenceOperator">
      <xsl:call-template name="FFenceOperator">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fShouldCollect"
      select="$fLinearFracParent=0 and $fFunctionName=0 and $fFenceOperator=0 and
              (parent::mml:mrow or parent::mml:mstyle or
                parent::mml:msqrt or parent::mml:menclose or
                parent::mml:math or parent::mml:mphantom or
                parent::mml:mtd or parent::mml:maction)" />

    <!--In MathML, the meaning of the different parts that make up mathematical structures, such as a fraction 
			having a numerator and a denominator, is determined by the relative order of those different parts.  
			For instance, In a fraction, the numerator is the first child and the denominator is the second child.  
			To allow for more complex structures, MathML allows one to link a group of mi, mn, and mo's together 
			using the mrow, or mstyle tags.  The mi, mn, and mo's found within any of the above tags are considered 
			one run.  Therefore, if the parent of any mi, mn, or mo is found to be an mrow or mstyle, then the contiguous 
			mi, mn, and mo's will be considered one run.-->
    <xsl:choose>
      <xsl:when test="$fShouldCollect">
        <xsl:choose>
          <xsl:when test="$fStartOfRun=1">
            <!--If this is the beginning of the run, pass all run attributes to CreateRunWithSameProp.-->
            <xsl:call-template name="CreateRunWithSameProp">
              <xsl:with-param name="mathbackground">
                <!-- Look for the unqualified mathml attribute mathbackground.
										 Fall back to the qualified mathml attribute if necessary.
										 This priority of unqualified over qualified will be 
										 followed throughout this xslt. -->
                <xsl:choose>
                  <xsl:when test="$ndCur/@mathbackground">
                    <xsl:value-of select="$ndCur/@mathbackground" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:mathbackground" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="mathcolor">
                <xsl:choose>
                  <xsl:when test="$ndCur/@mathcolor">
                    <xsl:value-of select="$ndCur/@mathcolor" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:mathcolor" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="mathvariant">
                <xsl:choose>
                  <xsl:when test="$ndCur/@mathvariant">
                    <xsl:value-of select="$ndCur/@mathvariant" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:mathvariant" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="color">
                <xsl:choose>
                  <xsl:when test="$ndCur/@color">
                    <xsl:value-of select="$ndCur/@color" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:color" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="font-family">
                <xsl:choose>
                  <xsl:when test="$ndCur/@font-family">
                    <xsl:value-of select="$ndCur/@font-family" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:font-family" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="fontsize">
                <xsl:choose>
                  <xsl:when test="$ndCur/@fontsize">
                    <xsl:value-of select="$ndCur/@fontsize" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:fontsize" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="fontstyle">
                <xsl:choose>
                  <xsl:when test="$ndCur/@fontstyle">
                    <xsl:value-of select="$ndCur/@fontstyle" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:fontstyle" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="fontweight">
                <xsl:choose>
                  <xsl:when test="$ndCur/@fontweight">
                    <xsl:value-of select="$ndCur/@fontweight" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:fontweight" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="mathsize">
                <xsl:choose>
                  <xsl:when test="$ndCur/@mathsize">
                    <xsl:value-of select="$ndCur/@mathsize" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$ndCur/@mml:mathsize" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:with-param>
              <xsl:with-param name="ndTokenFirst" select="$ndCur" />
            </xsl:call-template>
          </xsl:when>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <!--Only one element will be part of run-->
        <xsl:element name="m:r">
          <!--Create Run Properties based on current node's attributes-->
          <xsl:call-template name="CreateRunProp">
            <xsl:with-param name="mathvariant">
              <xsl:choose>
                <xsl:when test="$ndCur/@mathvariant">
                  <xsl:value-of select="$ndCur/@mathvariant" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$ndCur/@mml:mathvariant" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="fontstyle">
              <xsl:choose>
                <xsl:when test="$ndCur/@fontstyle">
                  <xsl:value-of select="$ndCur/@fontstyle" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$ndCur/@mml:fontstyle" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="fontweight">
              <xsl:choose>
                <xsl:when test="$ndCur/@fontweight">
                  <xsl:value-of select="$ndCur/@fontweight" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$ndCur/@mml:fontweight" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="mathcolor">
              <xsl:choose>
                <xsl:when test="$ndCur/@mathcolor">
                  <xsl:value-of select="$ndCur/@mathcolor" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$ndCur/@mml:mathcolor" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="mathsize">
              <xsl:choose>
                <xsl:when test="$ndCur/@mathsize">
                  <xsl:value-of select="$ndCur/@mathsize" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$ndCur/@mml:mathsize" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="color">
              <xsl:choose>
                <xsl:when test="$ndCur/@color">
                  <xsl:value-of select="$ndCur/@color" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$ndCur/@mml:color" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="fontsize">
              <xsl:choose>
                <xsl:when test="$ndCur/@fontsize">
                  <xsl:value-of select="$ndCur/@fontsize" />
                </xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$ndCur/@mml:fontsize" />
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="ndCur" select="$ndCur" />
            <xsl:with-param name="fNor">
              <xsl:call-template name="FNor">
                <xsl:with-param name="ndCur" select="$ndCur" />
              </xsl:call-template>
            </xsl:with-param>
          </xsl:call-template>
          <xsl:element name="m:t">
            <xsl:call-template name="OutputText">
              <xsl:with-param name="sInput" select="normalize-space($ndCur)" />
            </xsl:call-template>
          </xsl:element>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: CreateRunWithSameProp
	-->
  <xsl:template name="CreateRunWithSameProp">
    <xsl:param name="mathbackground" />
    <xsl:param name="mathcolor" />
    <xsl:param name="mathvariant" />
    <xsl:param name="color" />
    <xsl:param name="font-family" />
    <xsl:param name="fontsize" />
    <xsl:param name="fontstyle" />
    <xsl:param name="fontweight" />
    <xsl:param name="mathsize" />
    <xsl:param name="ndTokenFirst" />

    <!--Given mathcolor, color, mstyle's (ancestor) color, and precedence of 
			said attributes, determine the actual color of the current run-->
    <xsl:variable name="sColorPropCur">
      <xsl:choose>
        <xsl:when test="$mathcolor!=''">
          <xsl:value-of select="$mathcolor" />
        </xsl:when>
        <xsl:when test="$color!=''">
          <xsl:value-of select="$color" />
        </xsl:when>
        <xsl:when test="$ndTokenFirst/ancestor::mml:mstyle[@color][1]/@color!=''">
          <xsl:value-of select="$ndTokenFirst/ancestor::mml:mstyle[@color][1]/@color" />
        </xsl:when>
        <xsl:when test="$ndTokenFirst/ancestor::mml:mstyle[@mml:color][1]/@mml:color!=''">
          <xsl:value-of select="$ndTokenFirst/ancestor::mml:mstyle[@color][1]/@mml:color" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="''" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <!--Given mathsize, and fontsize and precedence of said attributes, 
			determine the actual font size of the current run-->
    <xsl:variable name="sSzCur">
      <xsl:choose>
        <xsl:when test="$mathsize!=''">
          <xsl:value-of select="$mathsize" />
        </xsl:when>
        <xsl:when test="$fontsize!=''">
          <xsl:value-of select="$fontsize" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="''" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <!--Given mathvariant, fontstyle, and fontweight, and precedence of 
			the attributes, determine the actual font of the current run-->
    <xsl:variable name="sFontCur">
      <xsl:call-template name="GetFontCur">
        <xsl:with-param name="mathvariant" select="$mathvariant" />
        <xsl:with-param name="fontstyle" select="$fontstyle" />
        <xsl:with-param name="fontweight" select="$fontweight" />
        <xsl:with-param name="ndCur" select="$ndTokenFirst" />
      </xsl:call-template>
    </xsl:variable>

    <!-- The omml equivalent structure for mml:mtext is an omml run with the run property m:nor (normal) set.
         Therefore, we can only collect mtexts with  other mtext elements.  Suppose the $ndTokenFirst is an 
         mml:mtext, then if any of its following siblings are to be grouped, they must also be mml:text elements.  
         The inverse is also true, suppose the $ndTokenFirst isn't an mml:mtext, then if any of its following siblings 
         are to be grouped with $ndTokenFirst, they can't be mml:mtext elements-->
    <xsl:variable name="fNdTokenFirstIsMText">
      <xsl:choose>
        <xsl:when test="$ndTokenFirst/self::mml:mtext">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <!--In order to determine the length of the run, we will find the number of nodes before the inital node in the run and
			the number of nodes before the first node that DOES NOT belong to the current run.  The number of nodes that will
			be printed is One Less than the difference between the latter and the former-->

    <!--Find index of current node-->
    <xsl:variable name="nndBeforeFirst" select="count($ndTokenFirst/preceding-sibling::*)" />

    <!--Find index of next change in run properties.
		
		    The basic idea is that we want to find the position of the last node in the longest 
				sequence of nodes, starting from ndTokenFirst, that can be grouped into a run.  For
				example, nodes A and B can be grouped together into the same run iff they have the same 
				props.
				
				To accomplish this grouping, we want to find the next sibling to ndTokenFirst that shouldn't be 
				included in the run of text.  We do this by counting the number of elements that precede the first
				such element that doesn't belong.  The xpath that accomplishes this is below.
				    
						Count the number of siblings the precede the first element after ndTokenFirst that shouldn't belong.
						count($ndTokenFirst/following-sibling::*[ . . . ][1]/preceding-sibling::*)
						
				Now, the hard part to this is what is represented by the '. . .' above.  This conditional expression is 
				defining what elements *don't* belong to the current run.  The conditions are as follows:
				
				The element is not a token element (mi, mn, mo, ms, or mtext)
				
				or
				
				The token element contains a glyph child (this is handled separately).
				
				or
				
				The token is an mtext and the run didn't start with an mtext, or the token isn't an mtext and the run started 
				with an mtext.  We do this check because mtext transforms into an omml m:nor property, and thus, these mtext
				token elements need to be grouped separately from other token elements.
				
				// We do an or not( . . . ), because it was easier to define what token elements match than how they don't match.
				// Thus, this inner '. . .' defines how token attributes equate to one another.  We add the 'not' outside of to accomplish
				// the goal of the outer '. . .', which is the find the next element that *doesn't* match.
				or not(
				   The background colors match.
					 
					 and
					 
							The current font (sFontCur) matches the mathvariant
					 
							or
							
							sFontCur is normal and matches the current font characteristics
							
							or 
							
							sFontCur is italic and matches the current font characteristics
							
							or 
							
							. . .
				
					 and
					 
					 The font family matches the current font family.
					 ) // end of not().-->
    <xsl:variable name="nndBeforeLim" select="count($ndTokenFirst/following-sibling::*
					[(not(self::mml:mi) and not(self::mml:mn) and not(self::mml:mo) and not(self::mml:ms) and not(self::mml:mtext))
					or
					(self::mml:mi[child::mml:mglyph] or self::mml:mn[child::mml:mglyph] or self::mml:mo[child::mml:mglyph] or self::mml:ms[child::mml:mglyph] or self::mml:mtext[child::mml:mglyph])
					or
					(($fNdTokenFirstIsMText=1 and not(self::mml:mtext)) or ($fNdTokenFirstIsMText=0 and self::mml:mtext))
					or  
					not(
						((($sFontCur=@mathvariant or $sFontCur=@mml:mathvariant)
							or
							($sFontCur='normal'
							 and ((@mathvariant='normal' or @mml:mathvariant='normal')
									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
											  and (
									           ((@fontstyle='normal' or @mml:fontstyle='normal') and (not(@fontweight='bold') and not(@mml:fontweight='bold')))
									           or (self::mml:mi and string-length(normalize-space(.)) &gt; 1)
									           or (self::mml:mn and string(number(self::mml:mn/text()))='NaN')
									          )
									     )
									 )
							)
							or
							($sFontCur='italic' 
							 and ((@mathvariant='italic' or @mml:mathvariant='italic')
									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
												and (
									           ((@fontstyle='italic' or @mml:fontstyle='italic') and (not(@fontweight='bold') and not(@mml:fontweight='bold')))
										         or  
															((self::mml:mn and string(number(self::mml:mn/text()))!='NaN')
															 or self::mml:mo
															 or (self::mml:mi and string-length(normalize-space(.)) &lt;= 1)
									            )
									          )
									     )
									 )
							) 
							or
							($sFontCur='bold'
							 and ((@mathvariant='bold' or @mml:mathvariant='bold')
									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
									      and (
									           ((@fontweight='bold' or @mml:fontweight='bold')
									           and ((@fontstyle='normal' or @mml:fontstyle='normal') or (self::mml:mi and string-length(normalize-space(.)) &lt;= 1))
									          )
									     )
									   )  
									 )
							)
						  or
							(($sFontCur='bi' or $sFontCur='bold-italic')
							 and (
									  (@mathvariant='bold-italic' or @mml:mathvariant='bold-italic')
									  or (((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
												and (
														 ((@fontweight='bold' or @mml:fontweight='bold') and (@fontstyle='italic' or @mml:fontstyle='italic'))
														 or ((@fontweight='bold' or @mml:fontweight='bold')
														  	 and (self::mml:mn 
																 		  or self::mml:mo 
																			or (self::mml:mi and string-length(normalize-space(.)) &lt;= 1)))
									          )
									     )
									 )
							)		     
							or
              (($sFontCur='' 
                 and (
                     ((not(@mathvariant) or @mathvariant='')
                        and (not(@mml:mathvariant) or @mml:mathvariant='')
                        and (not(@fontstyle) or @fontstyle='')
                        and (not(@mml:fontstyle) or @mml:fontstyle='')
                        and (not(@fontweight)or @fontweight='')
                        and (not(@mml:fontweight) or @mml:fontweight='')
		              ) 
                      or 
                        (@mathvariant='italic' or @mml:mathvariant='italic')  
                      or (
                           ((not(@mathvariant) or @mathvariant='') and (not(@mml:mathvariant) or @mml:mathvariant=''))
                               and (
	                                 (((@fontweight='normal' or @mml:fontweight='normal') 
		                                and (@fontstyle='italic' or @mml:fontstyle='italic'))
	                                 )
	                                 or
		                                ((not(@fontweight) or @fontweight='') and (not(@mml:fontweight) or @mml:fontweight=''))
			                                and (@fontstyle='italic' or @mml:fontstyle='italic')
	                                 or
		                                ((not(@fontweight) or @fontweight='') and (not(@mml:fontweight) or @mml:fontweight=''))
			                                and (not(@fontstyle) or @fontstyle='')
			                                and (not(@mml:fontstyle) or @mml:fontstyle=''))
                            )
		              )

              ))
							or
              ($sFontCur='normal' 
               and ((self::mml:mi 
                     and (not(@mathvariant) or @mathvariant='')
	                 and (not(@mml:mathvariant) or @mml:mathvariant)
	                 and (not(@fontstyle) or @fontstyle='') 
	                 and (not(@mml:fontstyle) or @mml:fontstyle='')
	                 and (not(@fontweight) or @fontweight='') 
	                 and (not(@mml:fontweight) or @mml:fontweight='')
	                 and (string-length(normalize-space(.)) &gt; 1)
	                 )
	                or ((self::mml:ms or self::mml:mtext) 
		                and (not(@mathvariant) or @mathvariant='')
		                and (not(@mml:mathvariant) or @mml:mathvariant)
		                and (not(@fontstyle) or @fontstyle)
		                and (not(@fontstyle) or @fontstyle='')
		                and (not(@fontweight) or @fontweight)
		                and (not(@mml:fontweight) or @mml:fontweight='')
		                )
	                )
              )			 
						)
						and
            (($font-family = @font-family or $font-family = @mml:font-family)
              or (($font-family='' or not($font-family))
	              and (not(@font-family) or @font-family='')
	              and (not(@mml:font-family) or @mml:font-family='')
	             ) 
            )
					))
					][1]/preceding-sibling::*)" />

    <xsl:variable name="cndRun" select="$nndBeforeLim - $nndBeforeFirst" />

    <!--Contiguous groups of like-property mi, mn, and mo's are separated by non- mi, mn, mo tags, or mi,mn, or mo
			tags with different properties.  nndBeforeLim is the number of nodes before the next tag which separates contiguous 
			groups of like-property mi, mn, and mo's.  Knowing this delimiting tag allows for the aggregation of the correct 
			number of mi, mn, and mo tags.-->
    <xsl:element name="m:r">

      <!--The beginning and ending of the current run has been established. Now we should open a run element-->
      <xsl:choose>

        <!--If cndRun > 0, then there is a following diffrent prop, or non- Token, 
						although there may or may not have been a preceding different prop, or non-
						Token-->
        <xsl:when test="$cndRun &gt; 0">
          <xsl:call-template name="CreateRunProp">
            <xsl:with-param name="mathvariant" select="$mathvariant" />
            <xsl:with-param name="fontstyle" select="$fontstyle" />
            <xsl:with-param name="fontweight" select="$fontweight" />
            <xsl:with-param name="mathcolor" select="$mathcolor" />
            <xsl:with-param name="mathsize" select="$mathsize" />
            <xsl:with-param name="color" select="$color" />
            <xsl:with-param name="fontsize" select="$fontsize" />
            <xsl:with-param name="ndCur" select="$ndTokenFirst" />
            <xsl:with-param name="fNor">
              <xsl:call-template name="FNor">
                <xsl:with-param name="ndCur" select="$ndTokenFirst" />
              </xsl:call-template>
            </xsl:with-param>
          </xsl:call-template>
          <xsl:element name="m:t">
            <xsl:call-template name="OutputText">
              <xsl:with-param name="sInput">
                <xsl:choose>
                  <xsl:when test="namespace-uri($ndTokenFirst) = 'http://www.w3.org/1998/Math/MathML' and local-name($ndTokenFirst) = 'ms'">
                    <xsl:call-template name="OutputMs">
                      <xsl:with-param name="msCur" select="$ndTokenFirst" />
                    </xsl:call-template>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="normalize-space($ndTokenFirst)" />
                  </xsl:otherwise>
                </xsl:choose>
                <xsl:for-each select="$ndTokenFirst/following-sibling::*[position() &lt; $cndRun]">
                  <xsl:choose>
                    <xsl:when test="namespace-uri(.) = 'http://www.w3.org/1998/Math/MathML' and 
													local-name(.) = 'ms'">
                      <xsl:call-template name="OutputMs">
                        <xsl:with-param name="msCur" select="." />
                      </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:value-of select="normalize-space(.)" />
                    </xsl:otherwise>
                  </xsl:choose>
                </xsl:for-each>
              </xsl:with-param>
            </xsl:call-template>
          </xsl:element>
        </xsl:when>
        <xsl:otherwise>

          <!--if cndRun lt;= 0, then iNextNonToken = 0, 
						and iPrecNonToken gt;= 0.  In either case, b/c there 
						is no next different property or non-Token 
						(which is implied by the nndBeforeLast being equal to 0) 
						you can put all the remaining mi, mn, and mo's into one 
						group.-->
          <xsl:call-template name="CreateRunProp">
            <xsl:with-param name="mathvariant" select="$mathvariant" />
            <xsl:with-param name="fontstyle" select="$fontstyle" />
            <xsl:with-param name="fontweight" select="$fontweight" />
            <xsl:with-param name="mathcolor" select="$mathcolor" />
            <xsl:with-param name="mathsize" select="$mathsize" />
            <xsl:with-param name="color" select="$color" />
            <xsl:with-param name="fontsize" select="$fontsize" />
            <xsl:with-param name="ndCur" select="$ndTokenFirst" />
            <xsl:with-param name="fNor">
              <xsl:call-template name="FNor">
                <xsl:with-param name="ndCur" select="$ndTokenFirst" />
              </xsl:call-template>
            </xsl:with-param>
          </xsl:call-template>
          <xsl:element name="m:t">

            <!--Create the Run, first output current, then in a 
							for-each, because all the following siblings are
							mn, mi, and mo's that conform to the run's properties,
							group them together-->
            <xsl:call-template name="OutputText">
              <xsl:with-param name="sInput">
                <xsl:choose>
                  <xsl:when test="namespace-uri($ndTokenFirst) = 'http://www.w3.org/1998/Math/MathML' and 
													local-name($ndTokenFirst) = 'ms'">
                    <xsl:call-template name="OutputMs">
                      <xsl:with-param name="msCur" select="$ndTokenFirst" />
                    </xsl:call-template>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="normalize-space($ndTokenFirst)" />
                  </xsl:otherwise>
                </xsl:choose>
                <xsl:for-each select="$ndTokenFirst/following-sibling::*[self::mml:mi or self::mml:mn or self::mml:mo or self::mml:ms or self::mml:mtext]">
                  <xsl:choose>
                    <xsl:when test="namespace-uri(.) = 'http://www.w3.org/1998/Math/MathML' and 
													local-name(.) = 'ms'">
                      <xsl:call-template name="OutputMs">
                        <xsl:with-param name="msCur" select="." />
                      </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:value-of select="normalize-space(.)" />
                    </xsl:otherwise>
                  </xsl:choose>
                </xsl:for-each>
              </xsl:with-param>
            </xsl:call-template>
          </xsl:element>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>

    <!--The run was terminated by an mi, mn, mo, ms, or mtext with different properties, 
				therefore, call-template CreateRunWithSameProp, using cndRun+1 node as new start node-->
    <xsl:if test="$nndBeforeLim!=0 
           and ($ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mi or 
					      $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mn or
					      $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mo or
					      $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:ms or
                $ndTokenFirst/following-sibling::*[$cndRun]/self::mml:mtext) 
            and (count($ndTokenFirst/following-sibling::*[$cndRun]/mml:mglyph) = 0)">
      <xsl:call-template name="CreateRunWithSameProp">
        <xsl:with-param name="mathbackground">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathbackground">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathbackground"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathbackground"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="mathcolor">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathcolor">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathcolor"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathcolor"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="mathvariant">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathvariant">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathvariant"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathvariant"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="color">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@color">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@color"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:color"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="font-family">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@font-family">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@font-family"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:font-family"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="fontsize">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@fontsize">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@fontsize"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:fontsize"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="fontstyle">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@fontstyle">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@fontstyle"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:fontstyle"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="fontweight">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@fontweight">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@fontweight"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:fontweight"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="mathsize">
          <xsl:choose>
            <xsl:when test="$ndTokenFirst/following-sibling::*[$cndRun]/@mathsize">
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mathsize"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndTokenFirst/following-sibling::*[$cndRun]/@mml:mathsize"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="ndTokenFirst" select="$ndTokenFirst/following-sibling::*[$cndRun]" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <!-- %%Template: FNor
				 Given the context of ndCur, determine if ndCur should be omml's normal style.
	-->
  <xsl:template name="FNor">
    <xsl:param name="ndCur" select="." />
    <xsl:choose>
      <!-- Is the current node an mml:mtext, or if this is an mglyph whose parent is
             an mml:mtext.
             Don't set m:nor for mtext elements whose content is only whitespace/&#xa0;
             because a normal-text run containing only whitespace triggers spurious tab
             insertion during paste in Word. -->
      <xsl:when test="$ndCur/self::mml:mtext and normalize-space(translate($ndCur, '&#xa0;', ' ')) = ''">0</xsl:when>
      <xsl:when test="$ndCur/self::mml:mtext or ($ndCur/self::mml:mglyph and parent::mml:mtext)">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: CreateRunProp
	-->
  <xsl:template name="CreateRunProp">
    <xsl:param name="mathbackground" />
    <xsl:param name="mathcolor" />
    <xsl:param name="mathvariant" />
    <xsl:param name="color" />
    <xsl:param name="font-family" />
    <xsl:param name="fontsize" />
    <xsl:param name="fontstyle" />
    <xsl:param name="fontweight" />
    <xsl:param name="mathsize" />
    <xsl:param name="ndCur" />
    <xsl:param name="fontfamily" />
    <xsl:param name="fNor" />
    <xsl:variable name="mstyleColor">
      <xsl:if test="not(not($ndCur))">
        <xsl:choose>
          <xsl:when test="$ndCur/ancestor::mml:mstyle[@color][1]/@color">
            <xsl:value-of select="$ndCur/ancestor::mml:mstyle[@color][1]/@color"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$ndCur/ancestor::mml:mstyle[@color][1]/@mml:color"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:if>
    </xsl:variable>
    <xsl:call-template name="CreateMathRPR">
      <xsl:with-param name="mathvariant" select="$mathvariant" />
      <xsl:with-param name="fontstyle" select="$fontstyle" />
      <xsl:with-param name="fontweight" select="$fontweight" />
      <xsl:with-param name="ndCur" select="$ndCur" />
      <xsl:with-param name="fNor" select="$fNor" />
    </xsl:call-template>
  </xsl:template>

  <!-- %%Template: CreateMathRPR
	-->
  <xsl:template name="CreateMathRPR">
    <xsl:param name="mathvariant" />
    <xsl:param name="fontstyle" />
    <xsl:param name="fontweight" />
    <xsl:param name="ndCur" />
    <xsl:param name="fNor" />
    <xsl:variable name="sFontCur">
      <xsl:call-template name="GetFontCur">
        <xsl:with-param name="mathvariant" select="$mathvariant" />
        <xsl:with-param name="fontstyle" select="$fontstyle" />
        <xsl:with-param name="fontweight" select="$fontweight" />
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNor=1 or ($sFontCur!='italic' and $sFontCur!='')">
      <xsl:element name="m:rPr">
        <xsl:if test="$fNor=1">
          <m:nor />
        </xsl:if>
        <xsl:call-template name="CreateMathScrStyProp">
          <xsl:with-param name="font" select="$sFontCur" />
          <xsl:with-param name="fNor" select="$fNor" />
        </xsl:call-template>
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <!-- %%Template: GetFontCur
	-->
  <xsl:template name="GetFontCur">
    <xsl:param name="ndCur" />
    <xsl:param name="mathvariant" />
    <xsl:param name="fontstyle" />
    <xsl:param name="fontweight" />
    <xsl:choose>
      <xsl:when test="$mathvariant!=''">
        <xsl:value-of select="$mathvariant" />
      </xsl:when>
      <xsl:when test="not($ndCur)">
        <xsl:value-of select="'italic'" />
      </xsl:when>
      <xsl:when test="$ndCur/self::mml:mi and (string-length(normalize-space($ndCur)) &lt;= 1)
								      or $ndCur/self::mml:mn and string(number($ndCur/text()))!='NaN'
								      or $ndCur/self::mml:mo">

        <!-- The default for the above three cases is fontstyle=italic fontweight=normal.-->
        <xsl:choose>
          <xsl:when test="$fontstyle='normal' and $fontweight='bold'">
            <!-- In omml, a sty of 'b' (which is what bold is translated into)
						     implies a normal fontstyle -->
            <xsl:value-of select="'bold'" />
          </xsl:when>
          <xsl:when test="$fontstyle='normal'">
            <xsl:value-of select="'normal'" />
          </xsl:when>
          <xsl:when test="$fontweight='bold'">
            <xsl:value-of select="'bi'" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="'italic'" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <!--Default is fontweight = 'normal' and fontstyle='normal'-->
        <xsl:choose>
          <xsl:when test="$fontstyle='italic' and $fontweight='bold'">
            <xsl:value-of select="'bi'" />
          </xsl:when>
          <xsl:when test="$fontstyle='italic'">
            <xsl:value-of select="'italic'" />
          </xsl:when>
          <xsl:when test="$fontweight='bold'">
            <xsl:value-of select="'bold'" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="'normal'" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: CreateMathScrStyProp
	-->
  <xsl:template name="CreateMathScrStyProp">
    <xsl:param name="font" />
    <xsl:param name="fNor" select="0"/>
    <xsl:choose>
      <xsl:when test="$font='normal' and $fNor=0">
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">p</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='bold'">
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">b</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='italic'">
      </xsl:when>
      <xsl:when test="$font='script'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">script</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='bold-script'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">script</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">b</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='double-struck'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">double-struck</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">p</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='fraktur'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">fraktur</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">p</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='bold-fraktur'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">fraktur</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">b</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='sans-serif'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">p</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='bold-sans-serif'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">b</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='sans-serif-italic'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='sans-serif-bold-italic'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">sans-serif</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">bi</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='monospace'">
        <xsl:element name="m:scr">
          <xsl:attribute name="m:val">monospace</xsl:attribute>
        </xsl:element>
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">p</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='bold'">
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">b</xsl:attribute>
        </xsl:element>
      </xsl:when>
      <xsl:when test="$font='bi' or $font='bold-italic'">
        <xsl:element name="m:sty">
          <xsl:attribute name="m:val">bi</xsl:attribute>
        </xsl:element>
      </xsl:when>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="FBar">
    <xsl:param name="sLineThickness" />
    <xsl:variable name="sLowerLineThickness" select="translate($sLineThickness, $StrUCAlphabet, $StrLCAlphabet)" />
    <xsl:choose>
      <xsl:when test="string-length($sLowerLineThickness)=0
                      or $sLowerLineThickness='thin' 
                      or $sLowerLineThickness='medium' 
                      or $sLowerLineThickness='thick'">1</xsl:when>
      <xsl:otherwise>
        <xsl:variable name="fStrContainsNonZeroDigit">
          <xsl:call-template name="FStrContainsNonZeroDigit">
            <xsl:with-param name="s" select="$sLowerLineThickness" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="$fStrContainsNonZeroDigit=1">1</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: match mfrac 
  -->
  <xsl:template match="mml:mfrac">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MFrac">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MFrac">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fBar">
      <xsl:call-template name="FBar">
        <xsl:with-param name="sLineThickness">
          <xsl:choose>
            <xsl:when test="$ndCur/@linethickness">
              <xsl:value-of select="normalize-space($ndCur/@linethickness)" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="normalize-space($ndCur/@mml:linethickness)" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:variable>

    <xsl:element name="m:f">
      <xsl:element name="m:fPr">
        <xsl:element name="m:type">
          <xsl:attribute name="m:val">
            <xsl:choose>
              <xsl:when test="$fBar=0">noBar</xsl:when>
              <xsl:when test="$ndCur/@bevelled='true' or $ndCur/@mml:bevelled='true'">skw</xsl:when>
              <xsl:otherwise>bar</xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
        </xsl:element>
      </xsl:element>
      <xsl:element name="m:num">
        <xsl:call-template name="CreateArgProp" />
        <xsl:apply-templates select="$ndCur/*[1]" />
      </xsl:element>
      <xsl:element name="m:den">
        <xsl:call-template name="CreateArgProp" />
        <xsl:apply-templates select="$ndCur/*[2]" />
      </xsl:element>
    </xsl:element>
  </xsl:template>


  <!-- %%Template: match menclose msqrt
	-->
  <xsl:template match="mml:menclose | mml:msqrt">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MEncloseMSqrt">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MEncloseMSqrt">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="sLowerCaseNotation">
      <xsl:choose>
        <xsl:when test="$ndCur/@notation">
          <xsl:value-of select="translate($ndCur/@notation, $StrUCAlphabet, $StrLCAlphabet)" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="translate($ndCur/@mml:notation, $StrUCAlphabet, $StrLCAlphabet)" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:choose>
      <!-- Take care of default -->
      <xsl:when test="$sLowerCaseNotation='radical' or
                      not($sLowerCaseNotation) or
                      $sLowerCaseNotation='' or
                      $ndCur/self::mml:msqrt">
        <xsl:element name="m:rad">
          <xsl:element name="m:radPr">
            <xsl:element name="m:degHide">
              <xsl:attribute name="m:val">on</xsl:attribute>
            </xsl:element>
          </xsl:element>
          <xsl:element name="m:deg">
            <xsl:call-template name="CreateArgProp" />
          </xsl:element>
          <xsl:element name="m:e">
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*" />
          </xsl:element>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="$sLowerCaseNotation='actuarial' or $sLowerCaseNotation='longdiv'" />
          <xsl:otherwise>
            <xsl:element name="m:borderBox">
              <!-- Dealing with more complex notation attribute -->
              <xsl:variable name="fBox">
                <xsl:choose>
                  <!-- Word doesn't have circle and roundedbox concepts, therefore, map both to a 
                       box. -->
                  <xsl:when test="contains($sLowerCaseNotation, 'box')
                                  or contains($sLowerCaseNotation, 'circle')
                                  or contains($sLowerCaseNotation, 'roundedbox')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fTop">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'top')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fBot">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'bottom')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fLeft">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'left')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fRight">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'right')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fStrikeH">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'horizontalstrike')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fStrikeV">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'verticalstrike')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fStrikeBLTR">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'updiagonalstrike')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>
              <xsl:variable name="fStrikeTLBR">
                <xsl:choose>
                  <xsl:when test="contains($sLowerCaseNotation, 'downdiagonalstrike')">1</xsl:when>
                  <xsl:otherwise>0</xsl:otherwise>
                </xsl:choose>
              </xsl:variable>

              <!-- Should we create borderBoxPr? 
                   We should if the enclosure isn't Word's default, which is
                   a plain box -->
              <xsl:if test="$fStrikeH=1 
                          or $fStrikeV=1
                          or $fStrikeBLTR=1 
                          or $fStrikeTLBR=1
                          or ($fBox=0
                              and not($fTop=1 
                                      and $fBot=1
                                      and $fLeft=1
                                      and $fRight=1)
                              )">
                <xsl:element name="m:borderBoxPr">
                  <xsl:if test="$fBox=0">
                    <xsl:if test="$fTop=0">
                      <xsl:element name="m:hideTop">
                        <xsl:attribute name="m:val">on</xsl:attribute>
                      </xsl:element>
                    </xsl:if>
                    <xsl:if test="$fBot=0">
                      <xsl:element name="m:hideBot">
                        <xsl:attribute name="m:val">on</xsl:attribute>
                      </xsl:element>
                    </xsl:if>
                    <xsl:if test="$fLeft=0">
                      <xsl:element name="m:hideLeft">
                        <xsl:attribute name="m:val">on</xsl:attribute>
                      </xsl:element>
                    </xsl:if>
                    <xsl:if test="$fRight=0">
                      <xsl:element name="m:hideRight">
                        <xsl:attribute name="m:val">on</xsl:attribute>
                      </xsl:element>
                    </xsl:if>
                  </xsl:if>
                  <xsl:if test="$fStrikeH=1">
                    <xsl:element name="m:strikeH">
                      <xsl:attribute name="m:val">on</xsl:attribute>
                    </xsl:element>
                  </xsl:if>
                  <xsl:if test="$fStrikeV=1">
                    <xsl:element name="m:strikeV">
                      <xsl:attribute name="m:val">on</xsl:attribute>
                    </xsl:element>
                  </xsl:if>
                  <xsl:if test="$fStrikeBLTR=1">
                    <xsl:element name="m:strikeBLTR">
                      <xsl:attribute name="m:val">on</xsl:attribute>
                    </xsl:element>
                  </xsl:if>
                  <xsl:if test="$fStrikeTLBR=1">
                    <xsl:element name="m:strikeTLBR">
                      <xsl:attribute name="m:val">on</xsl:attribute>
                    </xsl:element>
                  </xsl:if>
                </xsl:element>
              </xsl:if>
              <xsl:element name="m:e">
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*" />
              </xsl:element>
            </xsl:element>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: CreateArgProp
	-->
  <xsl:template name="CreateArgProp">
    <xsl:if test="not(count(ancestor-or-self::mml:mstyle[@scriptlevel='0' or @scriptlevel='1' or @scriptlevel='2'])=0)
                  or not(count(ancestor-or-self::mml:mstyle[@mml:scriptlevel='0' or @mml:scriptlevel='1' or @mml:scriptlevel='2'])=0)">
      <xsl:element name="m:argPr">
        <xsl:element name="m:scrLvl">
          <xsl:attribute name="m:val">
            <xsl:choose>
              <xsl:when test="ancestor-or-self::mml:mstyle[@scriptlevel][1]/@scriptlevel">
                   <xsl:value-of select="ancestor-or-self::mml:mstyle[@scriptlevel][1]/@scriptlevel"/>
              </xsl:when>
              <xsl:otherwise>
                <xsl:value-of select="ancestor-or-self::mml:mstyle[@scriptlevel][1]/@mml:scriptlevel"/>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
        </xsl:element>
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <!-- %%Template: match mroot
	-->
  <xsl:template match="mml:mroot">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MRoot">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MRoot">
    <xsl:param name="ndCur" select="." />
    <xsl:element name="m:rad">
      <xsl:element name="m:radPr">
        <xsl:element name="m:degHide">
          <xsl:attribute name="m:val">off</xsl:attribute>
        </xsl:element>
      </xsl:element>
      <xsl:element name="m:deg">
        <xsl:call-template name="CreateArgProp" />
        <xsl:apply-templates select="$ndCur/*[2]" />
      </xsl:element>
      <xsl:element name="m:e">
        <xsl:call-template name="CreateArgProp" />
        <xsl:apply-templates select="$ndCur/*[1]" />
      </xsl:element>
    </xsl:element>
  </xsl:template>

  <!-- MathML has no concept of a linear fraction.  When transforming a linear fraction
       from Omml to MathML, we create the following MathML:
       
       <mml:mrow>
         <mml:mrow>
            // numerator
         </mml:mrow>
         <mml:mo>/</mml:mo>
         <mml:mrow>
            // denominator
         </mml:mrow>
       </mml:mrow>
       
       This template looks for four things:
          1.  ndCur is an mml:mrow
          2.  ndCur has three children
          3.  The second child is an <mml:mo>
          4.  The second child's text is '/'
       
       -->
  <xsl:template name="FLinearFrac">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="sNdText">
      <xsl:value-of select="normalize-space($ndCur/*[2])"/>
    </xsl:variable>

    <xsl:choose>
      <!-- I spy a linear fraction -->
      <xsl:when test="$ndCur/self::mml:mrow
                      and count($ndCur/*)=3
                      and $ndCur/*[2][self::mml:mo]
                      and $sNdText='/'">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!--
    OpenChars

      (
      [
      {
      &lt;      Less Than
      &#x0230A; Left Floor
      &#x02308; Left Ceiling
      &#x027E6; Mathematical Left White Square Bracket
      ]
      |
      &#x02016; Double Vertical Line

    CloseChars

      )
      ]
      }
      &gt;      Greater Than
      &#x0230B; Right Floor
      &#x02309; Right Ceiling
      &#x027E7; Mathematical Right White Square Bracket
      [
      |
      &#x02016; Double Vertical Line
  -->

  <xsl:variable name="OpenChars">([{&lt;&#x0230A;&#x02308;&#x027E6;]|&#x02016;</xsl:variable>
  <xsl:variable name="CloseChars">)]}&gt;&#x0230B;&#x02309;&#x027E7;[|&#x02016;</xsl:variable>

  <!-- %%Template: determines if the text in the first child of ndCur is a fence open character
       and there is more than 1 child. Also checks if the first child is an mrow containing
       a single mo with a fence open character (as generated by MathJax and WikiMedia).
       This includes all characters used as an open bracket in the Brackets Gallery in Office.
  -->
  <xsl:template name="FenceOpenChar">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="sNdText">
      <xsl:choose>
        <xsl:when test="$ndCur/*[1][self::mml:mo]">
          <xsl:value-of select="normalize-space($ndCur/*[1])" />
        </xsl:when>
        <xsl:when test="$ndCur/*[1][self::mml:mrow[count(*)=1 and mml:mo]]">
          <xsl:value-of select="normalize-space($ndCur/*[1]/mml:mo)" />
        </xsl:when>
      </xsl:choose>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="count($ndCur/*) &gt; 1 and contains($OpenChars, $sNdText)">
        <xsl:value-of select="$sNdText" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="''" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: determines if the text in the last child of ndCur is a fence close character
       and there is more than 1 child. Also checks if the last child is an mrow containing
       a single mo with a fence close character (as generated by MathJax and WikiMedia).
       This includes all characters used as a close bracket in the Brackets Gallery in Office.
  -->
  <xsl:template name="FenceCloseChar">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="sNdText">
      <xsl:choose>
        <xsl:when test="$ndCur/*[last()][self::mml:mo]">
          <xsl:value-of select="normalize-space($ndCur/*[last()])" />
        </xsl:when>
        <xsl:when test="$ndCur/*[last()][self::mml:mrow[count(*)=1 and mml:mo]]">
          <xsl:value-of select="normalize-space($ndCur/*[last()]/mml:mo)" />
        </xsl:when>
      </xsl:choose>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="count($ndCur/*) &gt; 1 and contains($CloseChars, $sNdText)">
        <xsl:value-of select="$sNdText" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="''" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: determines whether the fenced set, ndCur, has a matching separator
       character for all mo child elements that aren't the fist or last child. If there
       is a matching character, return it, otherwise return an empty string.
  -->
  <xsl:template name="FenceSeparatorChar">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="chPotentialSeparator">
      <xsl:value-of select="normalize-space($ndCur/*[not(position()=1 or position()=last())][self::mml:mo][1])" />
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="count($ndCur/*[not(position()=1 or position()=last())][self::mml:mo]) > 0 and
                      count($ndCur/*[not(position()=1 or position()=last())][self::mml:mo])=
                      count($ndCur/*[not(position()=1 or position()=last())][self::mml:mo][normalize-space(self::mml:mo)=$chPotentialSeparator])">
        <xsl:value-of select="$chPotentialSeparator" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="''" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: determines whether ndCur fits the pattern of a fenced set.
       1.  It is an mrow
       2.  The first and last child are mo elements with a fence open and matching match close charater or
           The first child is an mo with a fence open character and the last child is not an mo with a fence close character
             and there are no mo elements with the matching close character or
           The last child is an mo with a fence close character and the first child is not an mo with a fence open character
             and there are no mo elements with the matching open character
       This covers all items in the Brackets Gallery in Office.
  -->
  <xsl:template name="FFenced">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fenceOpenChar">
      <xsl:call-template name="FenceOpenChar">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fenceCloseChar">
      <xsl:call-template name="FenceCloseChar">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="matchingCloseCharForOpenChar">
      <xsl:value-of select="translate($fenceOpenChar, $OpenChars, $CloseChars)" />
    </xsl:variable>
    <xsl:variable name="matchingOpenCharForCloseChar">
      <xsl:value-of select="translate($fenceCloseChar, $CloseChars, $OpenChars)" />
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$ndCur/self::mml:mrow and
                      (($fenceOpenChar!='' and $fenceCloseChar!='' and
                        $fenceCloseChar=$matchingCloseCharForOpenChar) or
                        ($fenceOpenChar!='' and $fenceCloseChar='' and
                        not($ndCur/mml:mo[normalize-space(.)=$matchingCloseCharForOpenChar])) or
                        ($fenceOpenChar='' and $fenceCloseChar!='' and
                        not($ndCur/mml:mo[normalize-space(.)=$matchingOpenCharForCloseChar])))">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: determines if ndCur is a fence operator element
  -->
  <xsl:template name="FFenceOperator">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fFencedParent">
      <xsl:call-template name="FFenced">
        <xsl:with-param name="ndCur" select="$ndCur/.." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fenceOpenChar">
      <xsl:call-template name="FenceOpenChar">
        <xsl:with-param name="ndCur" select="$ndCur/.." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fenceCloseChar">
      <xsl:call-template name="FenceCloseChar">
        <xsl:with-param name="ndCur" select="$ndCur/.." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="fenceSeparatorChar">
      <xsl:call-template name="FenceSeparatorChar">
        <xsl:with-param name="ndCur" select="$ndCur/.." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fFencedParent = 1 and
                      (($ndCur/parent::*/*[1] and $fenceOpenChar!='') or
                        ($ndCur/parent::*/*[last()] and $fenceCloseChar!='') or
                        (not($ndCur = $ndCur/parent::*/*[1]) and
                          not($ndCur = $ndCur/parent::*/*[last()]) and
                          $fenceSeparatorChar!=''))">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: determines whether ndCur fits the pattern of a fenced set where the closing
       fence character is the base (first child) of a script element (msup, msub, msubsup,
       munder, mover, munderover) that is the last child of the mrow.
       This pattern is generated by KaTeX for expressions like (x)^2, where the closing paren
       is placed inside the msup element as:
         <mrow><mo>(</mo><mi>x</mi><msup><mo>)</mo><mn>2</mn></msup></mrow>
  -->
  <xsl:template name="FFencedWithScript">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fenceOpenChar">
      <xsl:call-template name="FenceOpenChar">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:variable name="matchingCloseChar">
      <xsl:value-of select="translate($fenceOpenChar, $OpenChars, $CloseChars)" />
    </xsl:variable>
    <xsl:variable name="lastChildBaseText" select="normalize-space($ndCur/*[last()]/*[1][self::mml:mo])" />
    <xsl:choose>
      <xsl:when test="$ndCur/self::mml:mrow and
                      $fenceOpenChar != '' and
                      $ndCur/*[last()][self::mml:msup or self::mml:msub or self::mml:msubsup or
                                       self::mml:munder or self::mml:mover or self::mml:munderover] and
                      $lastChildBaseText != '' and
                      contains($CloseChars, $lastChildBaseText) and
                      $lastChildBaseText = $matchingCloseChar">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- Though presentation mathml can certainly typeset any generic function with the
       appropriate function operator spacing, presentation MathML has no concept of
       a function structure like omml does.  In order to preserve the omml <func>
       element, we must establish how an omml <func> element looks in mml.  This
       is shown below:
       
       <mml:mrow>
         <mml:mrow>
            // function name
         </mml:mrow>
         <mml:mo>&#x02061;</mml:mo>
         <mml:mrow>
            // function argument
         </mml:mrow>
       </mml:mrow>
       
       This template looks for four things to be true:
          1.  ndCur has three children
          2.  ndCur is an mml:mrow
          3.  The second child is an mml:mo
          4.  The second child's text is '&#x02061;'
       -->
  <xsl:template name="FIsFunc">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="sNdText">
      <xsl:value-of select="normalize-space($ndCur/*[2])" />
    </xsl:variable>
    <xsl:choose>
      <!-- Is this an omml function -->
      <xsl:when test="count($ndCur/*)=3 and
                      $ndCur/self::*[self::mml:mrow] and
                      $ndCur/*[2][self::mml:mo] and
                      $sNdText='&#x02061;'">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- Given the node of the linear fraction's parent mrow, 
       make a linear fraction -->
  <xsl:template name="MakeLinearFraction">
    <xsl:param name="ndCur" select="." />
    <xsl:element name="m:f">
      <xsl:element name="m:fPr">
        <xsl:element name="m:type">
          <xsl:attribute name="m:val">lin</xsl:attribute>
        </xsl:element>
      </xsl:element>
      <xsl:element name="m:num">
        <xsl:call-template name="CreateArgProp" />
        <xsl:apply-templates select="$ndCur/*[1]" />
      </xsl:element>
      <xsl:element name="m:den">
        <xsl:call-template name="CreateArgProp" />
        <xsl:apply-templates select="$ndCur/*[3]" />
      </xsl:element>
    </xsl:element>
  </xsl:template>


  <!-- Given the node of the function's parent mrow,
       make an omml function -->
  <xsl:template name="WriteFunc">
    <xsl:param name="ndCur" select="." />

    <xsl:element name="m:func">
      <xsl:element name="m:fName">
        <xsl:apply-templates select="$ndCur/child::*[1]" />
      </xsl:element>
      <xsl:element name="m:e">
        <xsl:apply-templates select="$ndCur/child::*[3]" />
      </xsl:element>
    </xsl:element>
  </xsl:template>


  <!-- MathML doesn't have the concept of nAry structures.  The best approximation
       to these is to have some under/over or sub/sup followed by an mrow or mstyle.
       
       In the case that we've come across some under/over or sub/sup that contains an
       nAry operator, this function handles the following sibling to the nAry structure.
       
       If the following sibling is:
       
          mml:mstyle, then apply templates to the children of this mml:mstyle
          
          mml:mrow, determine if this mrow is a linear fraction
          (see comments for FlinearFrac template).
              If so, make an Omml linear fraction.
              If not, apply templates as was done for mml:mstyle.
       
       -->
  <xsl:template name="NaryHandleMrowMstyle">
    <xsl:param name="ndCur" select="." />
    <!-- if the next sibling is an mrow, pull it in by
         doing whatever we would have done to its children.
         The mrow itself will be skipped, see template above. -->
    <xsl:choose>
      <xsl:when test="$ndCur[self::mml:mrow]">
        <!-- Check for linear fraction -->
        <xsl:variable name="fLinearFrac">
          <xsl:call-template name="FLinearFrac">
            <xsl:with-param name="ndCur" select="$ndCur" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="$fLinearFrac=1">
            <xsl:call-template name="MakeLinearFraction">
              <xsl:with-param name="ndCur" select="$ndCur" />
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
            <xsl:variable name="fFunc">
              <xsl:call-template name="FIsFunc">
                <xsl:with-param name="ndCur" select="$ndCur" />
              </xsl:call-template>
            </xsl:variable>
            <xsl:choose>
              <xsl:when test="$fFunc=1">
                <xsl:call-template name="WriteFunc">
                  <xsl:with-param name="ndCur" select="$ndCur" />
                </xsl:call-template>
              </xsl:when>
              <xsl:otherwise>
                <xsl:variable name="fFenced">
                  <xsl:call-template name="FFenced">
                    <xsl:with-param name="ndCur" select="$ndCur" />
                  </xsl:call-template>
                </xsl:variable>
                <xsl:choose>
                  <xsl:when test="$fFenced=1">
                    <xsl:call-template name="WriteFenced">
                      <xsl:with-param name="ndCur" select="$ndCur" />
                    </xsl:call-template>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:apply-templates select="$ndCur/*" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mstyle]">
        <xsl:apply-templates select="$ndCur/*" />
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mfrac]">
        <xsl:call-template name="MFrac">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:msub]">
        <xsl:call-template name="MSub">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:msup]">
        <xsl:call-template name="MSup">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:msubsup]">
        <xsl:call-template name="MSubSup">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mroot]">
        <xsl:call-template name="MRoot">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:menclose] | $ndCur[self::mml:msqrt]">
        <xsl:call-template name="MEncloseMSqrt">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mfenced]">
        <xsl:call-template name="MFenced">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mpadded]">
        <xsl:call-template name="MPadded">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mphantom]">
        <xsl:call-template name="MPhantom">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:munder]">
        <xsl:call-template name="MUnder">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mover]">
        <xsl:call-template name="MOver">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:munderover]">
        <xsl:call-template name="MUnderOver">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mmultiscripts]">
        <xsl:call-template name="MMultiscripts">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mtable]">
        <xsl:call-template name="MTable">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
      <xsl:when test="$ndCur[self::mml:mi][not(child::mml:mglyph)] |
                      $ndCur[self::mml:mn][not(child::mml:mglyph)] |
                      $ndCur[self::mml:mo][not(child::mml:mglyph)] |
                      $ndCur[self::mml:ms][not(child::mml:mglyph)] |
                      $ndCur[self::mml:mtext][not(child::mml:mglyph)]">
        <xsl:call-template name="MNonGlyphToken">
          <xsl:with-param name="ndCur" select="$ndCur" />
        </xsl:call-template>
      </xsl:when>
    </xsl:choose>
  </xsl:template>


  <!-- MathML munder/mover can represent several Omml constructs 
       (m:bar, m:limLow, m:limUpp, m:acc, m:groupChr, etc.).  The following 
       templates (FIsBar, FIsAcc, and FIsGroupChr) are used to determine 
			 which of these Omml constructs an munder/mover should be translated into. -->

  <!-- Note:  ndCur should only be an munder/mover MathML element.
  
       ndCur should be interpretted as an m:bar if
          1)  its respective accent attribute is not true
          2)  its second child is an mml:mo
          3)  the character of the mml:mo is the correct under/over bar. -->
  <xsl:template name="FIsBar">
    <xsl:param name="ndCur" />
    <xsl:variable name="fUnder">
      <xsl:choose>
        <xsl:when test="$ndCur[self::mml:munder]">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="sLowerCaseAccent">
      <xsl:choose>
        <xsl:when test="$fUnder=1">
          <xsl:choose>
            <xsl:when test="$ndCur/@accentunder">
              <xsl:value-of select="translate($ndCur/@accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/@mml:accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="$ndCur/@accent">
              <xsl:value-of select="translate($ndCur/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fAccent">
      <xsl:choose>
        <xsl:when test="$sLowerCaseAccent='true'">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <!-- The script is unaccented and the second child is an mo -->
      <xsl:when test="$fAccent = 0 
                      and $ndCur/child::*[2]/self::mml:mo">
        <xsl:variable name="sOperator">
          <xsl:value-of select="$ndCur/child::*[2]" />
        </xsl:variable>
        <xsl:choose>
          <!-- Should we write an underbar? -->
          <xsl:when test="$fUnder = 1">
            <xsl:choose>
              <xsl:when test="$sOperator = '&#x0332;' or $sOperator = '&#x005F;'">1</xsl:when>
              <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
          </xsl:when>
          <!-- Should we write an overbar? -->
          <xsl:otherwise>
            <xsl:choose>
              <xsl:when test="$sOperator = '&#x0305;' or $sOperator = '&#x00AF;'">1</xsl:when>
              <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Note:  ndCur should only be an mover MathML element.
  
       ndCur should be interpretted as an m:acc if
          1)  its accent attribute is true
          2)  its second child is an mml:mo
          3)  there is only zero or one character in the mml:mo -->
  <xsl:template name="FIsAcc">
    <xsl:param name="ndCur" select="." />

    <xsl:variable name="sLowerCaseAccent">
      <xsl:choose>
        <xsl:when test="$ndCur/@accent">
          <xsl:value-of select="translate($ndCur/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="translate($ndCur/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="sLowerCaseMoAccent">
      <xsl:choose>
        <xsl:when test="$ndCur/child::*[2] = mml:mo and $ndCur/child::*[2]/@accent">
          <xsl:value-of select="translate($ndCur/child::*[2]/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
        </xsl:when>
        <xsl:when test="$ndCur/child::*[2] = mml:mo and $ndCur/child::*[2]/@mml:accent">
          <xsl:value-of select="translate($ndCur/child::*[2]/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
        </xsl:when>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fAccent">
      <xsl:choose>
        <xsl:when test="$sLowerCaseMoAccent='true' or ($sLowerCaseMoAccent='' and $sLowerCaseAccent='true')">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <!-- The script is accented and the second child is an mo -->
      <xsl:when test="$fAccent = 1 
                      and $ndCur/child::*[2] = mml:mo">
        <xsl:variable name="sOperator">
          <xsl:value-of select="$ndCur/child::*[2]" />
        </xsl:variable>
        <xsl:choose>
          <!-- There is only one operator, this is a valid Omml accent! -->
          <xsl:when test="string-length($sOperator) &lt;= 1">1</xsl:when>
          <!-- More than one accented operator.  This isn't a valid
               omml accent -->
          <xsl:otherwise>0</xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <!-- Not accented, not an operator, or both, but in any case, this is
           not an Omml accent. -->
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- Is ndCur a groupChr? 
			 ndCur is a groupChr if:
			 
				 1.  The accent is false (note:  accent attribute 
						 for munder is accentunder). 
				 2.  ndCur is an munder or mover.
				 3.  ndCur has two children
				 4.  Of these two children, one is an mml:mo and the other is an mml:mrow
				 5.  The number of characters in the mml:mo is 1.
			 
			 If all of the above are true, then return 1, else return 0.
	-->
  <xsl:template name="FIsGroupChr">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fUnder">
      <xsl:choose>
        <xsl:when test="$ndCur[self::mml:munder]">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="sLowerCaseAccent">
      <xsl:choose>
        <xsl:when test="$fUnder=1">
          <xsl:choose>
            <xsl:when test="$ndCur/@accentunder">
              <xsl:value-of select="translate($ndCur/@accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/@mml:accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="$ndCur/@accent">
              <xsl:value-of select="translate($ndCur/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="fAccentFalse">
      <xsl:choose>
        <xsl:when test="$sLowerCaseAccent='false'">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$fAccentFalse=1
                      and $ndCur[self::mml:munder or self::mml:mover] 
                      and count($ndCur/child::*)=2 
                      and (($ndCur/child::*[1][self::mml:mrow] and $ndCur/child::*[2][self::mml:mo]) 
                            or ($ndCur/child::*[1][self::mml:mo] and $ndCur/child::*[2][self::mml:mrow]))">
        <xsl:variable name="sOperator">
          <xsl:value-of select="$ndCur/child::mml:mo" />
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="string-length($sOperator) &lt;= 1">1</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: match munder
  -->
  <xsl:template match="mml:munder">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MUnder">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MUnder">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fNary">
      <xsl:call-template name="isNary">
        <xsl:with-param name="ndCur" select="$ndCur/*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fNary='true'">
        <m:nary>
          <xsl:call-template name="CreateNaryProp">
            <xsl:with-param name="chr">
              <xsl:value-of select="normalize-space($ndCur/*[1])" />
            </xsl:with-param>
            <xsl:with-param name="sMathmlType" select="'munder'" />
          </xsl:call-template>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
          </m:sup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="NaryHandleMrowMstyle">
              <xsl:with-param name="ndCur" select="($ndCur[parent::*[count(*) &gt; 1]] |
                                                   $ndCur/parent::*[self::mml:mstyle[count(*)=1]])/following-sibling::*[1]" />
            </xsl:call-template>
          </m:e>
        </m:nary>
      </xsl:when>
      <xsl:otherwise>
        <!-- Should this munder be interpreted as an OMML m:bar? -->
        <xsl:variable name="fIsBar">
          <xsl:call-template name="FIsBar">
            <xsl:with-param name="ndCur" select="$ndCur" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="$fIsBar=1">
            <m:bar>
              <m:barPr>
                <m:pos m:val="bot" />
              </m:barPr>
              <m:e>
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*[1]" />
              </m:e>
            </m:bar>
          </xsl:when>
          <xsl:otherwise>
            <!-- It isn't an integral or underbar, is this a groupChr? -->
            <xsl:variable name="fGroupChr">
              <xsl:call-template name="FIsGroupChr">
                <xsl:with-param name="ndCur" select="$ndCur" />
              </xsl:call-template>
            </xsl:variable>
            <xsl:choose>
              <xsl:when test="$fGroupChr=1">
                <xsl:element name="m:groupChr">
                  <xsl:call-template name="CreateGroupChrPr">
                    <xsl:with-param name="chr">
                      <xsl:value-of select="$ndCur/mml:mo" />
                    </xsl:with-param>
                    <xsl:with-param name="pos">
                      <xsl:choose>
                        <xsl:when test="$ndCur/*[1][self::mml:mrow]">bot</xsl:when>
                        <xsl:otherwise>top</xsl:otherwise>
                      </xsl:choose>
                    </xsl:with-param>
                    <xsl:with-param name="vertJc">top</xsl:with-param>
                  </xsl:call-template>
                  <xsl:element name="m:e">
                    <xsl:apply-templates select="$ndCur/mml:mrow" />
                  </xsl:element>
                </xsl:element>
              </xsl:when>
              <xsl:otherwise>
                <!-- Generic munder -->
                <xsl:element name="m:limLow">
                  <xsl:element name="m:e">
                    <xsl:call-template name="CreateArgProp" />
                    <xsl:apply-templates select="$ndCur/*[1]" />
                  </xsl:element>
                  <xsl:element name="m:lim">
                    <xsl:call-template name="CreateArgProp" />
                    <xsl:apply-templates select="$ndCur/*[2]" />
                  </xsl:element>
                </xsl:element>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- Given the values for chr, pos, and vertJc, create an omml
	     groupChr's groupChrPr -->
  <xsl:template name="CreateGroupChrPr">
    <xsl:param name="chr">&#x23df;</xsl:param>
    <xsl:param name="pos" select="bot" />
    <xsl:param name="vertJc" select="top" />
    <xsl:element name="m:groupChrPr">
      <xsl:element name="m:chr">
        <xsl:attribute name="m:val">
          <xsl:value-of select="$chr"/>
        </xsl:attribute>
      </xsl:element>
      <xsl:element name="m:pos">
        <xsl:attribute name="m:val">
          <xsl:value-of select="$pos"/>
        </xsl:attribute>
      </xsl:element>
      <xsl:element name="m:vertJc">
        <xsl:attribute name="m:val">
          <xsl:value-of select="$vertJc"/>
        </xsl:attribute>
      </xsl:element>
    </xsl:element>
  </xsl:template>


  <!--
      Convert a non-combining character into its upper combining
      couterpart.
      
      { Non-combining, Upper-combining }
      {U+02D8, U+0306}, // BREVE
      {U+00B8, U+0312}, // CEDILLA
      {U+0060, U+0300}, // GRAVE ACCENT
      {U+002D, U+0305}, // HYPHEN-MINUS/OVERLINE
      {U+2212, U+0305}, // MINUS SIGN/OVERLINE
      {U+002E, U+0305}, // FULL STOP/DOT ABOVE
      {U+02D9, U+0307}, // DOT ABOVE
      {U+02DD, U+030B}, // DOUBLE ACUTE ACCENT
      {U+00B4, U+0301}, // ACUTE ACCENT
      {U+007E, U+0303}, // TILDE
      {U+02DC, U+0303}, // SMALL TILDE
      {U+00A8, U+0308}, // DIAERESIS
      {U+02C7, U+030C}, // CARON
      {U+005E, U+0302}, // CIRCUMFLEX ACCENT
      {U+00AF, U+0305}, // MACRON
      {U+005F, ::::::}, // LOW LINE
      {U+2192, U+20D7}, // RIGHTWARDS ARROW
      {U+27F6, U+20D7}, // LONG RIGHTWARDS ARROW
      {U+2190, U+20D6}, // LEFT ARROW
  -->
  <xsl:template name="ToUpperCombining">
    <xsl:param name="ch" />
    <xsl:choose>
      <!-- BREVE -->
      <xsl:when test="$ch='&#x02D8;'">&#x0306;</xsl:when>
      <!-- CEDILLA -->
      <xsl:when test="$ch='&#x00B8;'">&#x0312;</xsl:when>
      <!-- GRAVE ACCENT -->
      <xsl:when test="$ch='&#x0060;'">&#x0300;</xsl:when>
      <!-- HYPHEN-MINUS/OVERLINE -->
      <xsl:when test="$ch='&#x002D;'">&#x0305;</xsl:when>
      <!-- MINUS SIGN/OVERLINE -->
      <xsl:when test="$ch='&#x2212;'">&#x0305;</xsl:when>
      <!-- FULL STOP/DOT ABOVE -->
      <xsl:when test="$ch='&#x002E;'">&#x0307;</xsl:when>
      <!-- DOT ABOVE -->
      <xsl:when test="$ch='&#x02D9;'">&#x0307;</xsl:when>
      <!-- DOUBLE ACUTE ACCENT -->
      <xsl:when test="$ch='&#x02DD;'">&#x030B;</xsl:when>
      <!-- ACUTE ACCENT -->
      <xsl:when test="$ch='&#x00B4;'">&#x0301;</xsl:when>
      <!-- TILDE -->
      <xsl:when test="$ch='&#x007E;'">&#x0303;</xsl:when>
      <!-- SMALL TILDE -->
      <xsl:when test="$ch='&#x02DC;'">&#x0303;</xsl:when>
      <!-- DIAERESIS -->
      <xsl:when test="$ch='&#x00A8;'">&#x0308;</xsl:when>
      <!-- CARON -->
      <xsl:when test="$ch='&#x02C7;'">&#x030C;</xsl:when>
      <!-- CIRCUMFLEX ACCENT -->
      <xsl:when test="$ch='&#x005E;'">&#x0302;</xsl:when>
      <!-- MACRON -->
      <xsl:when test="$ch='&#x00AF;'">&#x0305;</xsl:when>
      
      <!-- LOW LINE -->
      
      <!-- RIGHTWARDS ARROW -->
      <xsl:when test="$ch='&#x2192;'">&#x20D7;</xsl:when>
      <!-- LONG RIGHTWARDS ARROW -->
      <xsl:when test="$ch='&#x27F6;'">&#x20D7;</xsl:when>
      <!-- LEFT ARROW -->
      <xsl:when test="$ch='&#x2190;'">&#x20D6;</xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$ch"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: match mover
  -->
  <xsl:template match="mml:mover">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MOver">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MOver">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fNary">
      <xsl:call-template name="isNary">
        <xsl:with-param name="ndCur" select="$ndCur/*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fNary='true'">
        <m:nary>
          <xsl:call-template name="CreateNaryProp">
            <xsl:with-param name="chr">
              <xsl:value-of select="normalize-space($ndCur/*[1])" />
            </xsl:with-param>
            <xsl:with-param name="sMathmlType" select="'mover'" />
          </xsl:call-template>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="NaryHandleMrowMstyle">
              <xsl:with-param name="ndCur" select="($ndCur[parent::*[count(*) > 1]] |
                                                   $ndCur/parent::*[self::mml:mstyle[count(*) = 1]])/following-sibling::*[1]" />
            </xsl:call-template>
          </m:e>
        </m:nary>
      </xsl:when>
      <xsl:otherwise>
        <!-- Should this munder be interpreted as an OMML m:bar or m:acc? -->

        <!-- Check to see if this is an m:bar -->
        <xsl:variable name="fIsBar">
          <xsl:call-template name="FIsBar">
            <xsl:with-param name="ndCur" select="$ndCur" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="$fIsBar = 1">
            <m:bar>
              <m:barPr>
                <m:pos m:val="top" />
              </m:barPr>
              <m:e>
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*[1]" />
              </m:e>
            </m:bar>
          </xsl:when>
          <xsl:otherwise>
            <!-- Not an m:bar, should it be an m:acc? -->
            <xsl:variable name="fIsAcc">
              <xsl:call-template name="FIsAcc">
                <xsl:with-param name="ndCur" select="$ndCur" />
              </xsl:call-template>
            </xsl:variable>
            <xsl:choose>
              <xsl:when test="$fIsAcc=1">
                <m:acc>
                  <m:accPr>
                    <m:chr>
                      <xsl:variable name="ch">
                        <xsl:value-of select="$ndCur/*[2]" />
                      </xsl:variable>
                      <xsl:variable name="chComb">
                        <xsl:call-template name="ToUpperCombining">
                          <xsl:with-param name="ch" select="$ch" />
                        </xsl:call-template>
                      </xsl:variable>
                      <xsl:attribute name="m:val">
                        <xsl:value-of select="$chComb" />
                      </xsl:attribute>
                    </m:chr>
                  </m:accPr>
                  <m:e>
                    <xsl:call-template name="CreateArgProp" />
                    <xsl:apply-templates select="$ndCur/*[1]" />
                  </m:e>
                </m:acc>
              </xsl:when>
              <xsl:otherwise>
                <!-- This isn't an integral, overbar or accent, 
								     could it be a groupChr? -->
                <xsl:variable name="fGroupChr">
                  <xsl:call-template name="FIsGroupChr">
                    <xsl:with-param name="ndCur" select="$ndCur" />
                  </xsl:call-template>
                </xsl:variable>
                <xsl:choose>
                  <xsl:when test="$fGroupChr=1">
                    <xsl:element name="m:groupChr">
                      <xsl:call-template name="CreateGroupChrPr">
                        <xsl:with-param name="chr">
                          <xsl:value-of select="$ndCur/mml:mo" />
                        </xsl:with-param>
                        <xsl:with-param name="pos">
                          <xsl:choose>
                            <xsl:when test="$ndCur/*[1][self::mml:mrow]">top</xsl:when>
                            <xsl:otherwise>bot</xsl:otherwise>
                          </xsl:choose>
                        </xsl:with-param>
                        <xsl:with-param name="vertJc">bot</xsl:with-param>
                      </xsl:call-template>
                      <xsl:element name="m:e">
                        <xsl:apply-templates select="$ndCur/mml:mrow" />
                      </xsl:element>
                    </xsl:element>
                  </xsl:when>
                  <xsl:otherwise>
                    <!-- Generic mover -->
                    <xsl:element name="m:limUpp">
                      <xsl:element name="m:e">
                        <xsl:call-template name="CreateArgProp" />
                        <xsl:apply-templates select="$ndCur/*[1]" />
                      </xsl:element>
                      <xsl:element name="m:lim">
                        <xsl:call-template name="CreateArgProp" />
                        <xsl:apply-templates select="$ndCur/*[2]" />
                      </xsl:element>
                    </xsl:element>
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: match munderover
  -->
  <xsl:template match="mml:munderover">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MUnderOver">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MUnderOver">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fNary">
      <xsl:call-template name="isNary">
        <xsl:with-param name="ndCur" select="$ndCur/*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fNary='true'">
        <m:nary>
          <xsl:call-template name="CreateNaryProp">
            <xsl:with-param name="chr">
              <xsl:value-of select="normalize-space($ndCur/*[1])" />
            </xsl:with-param>
            <xsl:with-param name="sMathmlType" select="'munderover'" />
          </xsl:call-template>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[3]" />
          </m:sup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="NaryHandleMrowMstyle">
              <xsl:with-param name="ndCur" select="($ndCur[parent::*[count(*) > 1]] |
                                                   $ndCur/parent::*[self::mml:mstyle[count(*) = 1]])/following-sibling::*[1]" />
            </xsl:call-template>
          </m:e>
        </m:nary>
      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="m:limUpp">
          <xsl:element name="m:e">
            <xsl:call-template name="CreateArgProp" />
            <xsl:element name="m:limLow">
              <xsl:element name="m:e">
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*[1]" />
              </xsl:element>
              <xsl:element name="m:lim">
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*[2]" />
              </xsl:element>
            </xsl:element>
          </xsl:element>
          <xsl:element name="m:lim">
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[3]" />
          </xsl:element>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: match mfenced
  -->
  <xsl:template match="mml:mfenced">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MFenced">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MFenced">
    <xsl:param name="ndCur" select="." />
    <m:d>
      <xsl:call-template name="CreateDelimProp">
        <xsl:with-param name="fChOpenValid">
          <xsl:choose>
            <xsl:when test="$ndCur/@open">
              <xsl:value-of select="1" />
            </xsl:when>
            <xsl:when test="$ndCur/@mml:open">
              <xsl:value-of select="1" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="0" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="chOpen">
          <xsl:choose>
            <xsl:when test="$ndCur/@open">
              <xsl:value-of select="$ndCur/@open" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndCur/@mml:open" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="fChSeparatorsValid">
          <xsl:choose>
            <xsl:when test="$ndCur/@separators">
              <xsl:value-of select="1" />
            </xsl:when>
            <xsl:when test="$ndCur/@mml:separators">
              <xsl:value-of select="1" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="0" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="chSeparators">
          <xsl:choose>
            <xsl:when test="$ndCur/@separators">
              <xsl:value-of select="$ndCur/@separators" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndCur/@mml:separators" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="fChCloseValid">
          <xsl:choose>
            <xsl:when test="$ndCur/@close">
              <xsl:value-of select="1" />
            </xsl:when>
            <xsl:when test="$ndCur/@mml:close">
              <xsl:value-of select="1" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="0" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
        <xsl:with-param name="chClose">
          <xsl:choose>
            <xsl:when test="$ndCur/@close">
              <xsl:value-of select="$ndCur/@close" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndCur/@mml:close" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:with-param>
      </xsl:call-template>
      <xsl:for-each select="$ndCur/*">
        <m:e>
          <xsl:call-template name="CreateArgProp" />
          <xsl:apply-templates select="." />
        </m:e>
      </xsl:for-each>
    </m:d>
  </xsl:template>


  <!-- %%Template: writes an m:d tag for fenced structure that is formed by an mrow with
       an mo with a fence open character as the first child and/or an mo with a fence close
       character as the last child. If the middle mo elements all use the same character,
       then that character will be used as the separator character.
  -->
  <xsl:template name="WriteFenced">
    <xsl:param name="ndCur" select="." />

    <xsl:variable name="chOpen">
      <xsl:choose>
        <xsl:when test="$ndCur/*[1][self::mml:mo]">
          <xsl:value-of select="normalize-space($ndCur/*[1])" />
        </xsl:when>
        <xsl:when test="$ndCur/*[1][self::mml:mrow[count(*)=1 and mml:mo]]">
          <xsl:value-of select="normalize-space($ndCur/*[1]/mml:mo)" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="''" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="chClose">
      <xsl:choose>
        <xsl:when test="$ndCur/*[last()][self::mml:mo]">
          <xsl:value-of select="normalize-space($ndCur/*[last()])" />
        </xsl:when>
        <xsl:when test="$ndCur/*[last()][self::mml:mrow[count(*)=1 and mml:mo]]">
          <xsl:value-of select="normalize-space($ndCur/*[last()]/mml:mo)" />
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="''" />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="fenceSeparatorChar">
      <xsl:call-template name="FenceSeparatorChar">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>
    <m:d>
      <xsl:call-template name="CreateDelimProp">
        <xsl:with-param name="fChOpenValid">
          <xsl:value-of select="1" />
        </xsl:with-param>
        <xsl:with-param name="chOpen">
          <xsl:value-of select="$chOpen" />
        </xsl:with-param>
        <xsl:with-param name="fChSeparatorsValid">
          <xsl:value-of select="1" />
        </xsl:with-param>
        <xsl:with-param name="chSeparators">
          <xsl:value-of select="$fenceSeparatorChar" />
        </xsl:with-param>
        <xsl:with-param name="fChCloseValid">
          <xsl:value-of select="1" />
        </xsl:with-param>
        <xsl:with-param name="chClose">
          <xsl:value-of select="$chClose" />
        </xsl:with-param>
      </xsl:call-template>

      <!-- Write an m:e element containing everything from the beginning
           until the first fence separator if there is one, excluding the
           fence open and fence close if there are any. -->
      <m:e>
        <xsl:call-template name="CreateArgProp" />
        <xsl:for-each select="$ndCur/*[1][not(self::mml:mo[normalize-space(.) = $chOpen])
                                         and not(self::mml:mrow[count(*)=1 and mml:mo[normalize-space(.) = $chOpen]])] |
          $ndCur/*[position() &gt; 1][
            not((. | preceding-sibling::*)
            [self::mml:mo
              [normalize-space(.) = $fenceSeparatorChar]
            ]) and
            not(position() = last() and (self::mml:mo[normalize-space(.) = $chClose]
              or self::mml:mrow[count(*)=1 and mml:mo[normalize-space(.) = $chClose]]))
          ]">
          <xsl:apply-templates select="." />
        </xsl:for-each>
      </m:e>

      <!-- Write additional m:e elements for each fence separator containing
           everything from that fence separator until the next fence separator
           if there is one or the fence close if there is one. -->
      <xsl:for-each select="$ndCur/*[position() &gt; 1 and position() &lt; last()][self::mml:mo][normalize-space(.)=$fenceSeparatorChar]">
        <xsl:variable name="separatorIndex">
          <xsl:value-of select="position()" />
        </xsl:variable>
        <m:e>
          <xsl:call-template name="CreateArgProp" />
          <xsl:for-each select="
            following-sibling::*[
              count((. | preceding-sibling::*)
              [self::mml:mo
                [normalize-space(.) = $fenceSeparatorChar]
              ]) = $separatorIndex
            ][not(position() = last() and normalize-space(.) = $chClose)]">
            <xsl:apply-templates select="." />
          </xsl:for-each>
        </m:e>
      </xsl:for-each>
    </m:d>
  </xsl:template>


  <!-- %%Template: Helper to write the fenced m:d element for WriteFencedWithScript.
       The content includes all children of ndCur between the first child (open fence)
       and the last child (script element containing the close fence as its base).
  -->
  <xsl:template name="WriteFencedContent">
    <xsl:param name="ndCur" select="." />
    <xsl:param name="chOpen" />
    <xsl:param name="chClose" />
    <m:d>
      <xsl:call-template name="CreateDelimProp">
        <xsl:with-param name="fChOpenValid" select="1" />
        <xsl:with-param name="chOpen" select="$chOpen" />
        <xsl:with-param name="fChSeparatorsValid" select="1" />
        <xsl:with-param name="chSeparators" select="''" />
        <xsl:with-param name="fChCloseValid" select="1" />
        <xsl:with-param name="chClose" select="$chClose" />
      </xsl:call-template>
      <m:e>
        <xsl:call-template name="CreateArgProp" />
        <xsl:apply-templates select="$ndCur/*[position() &gt; 1 and position() &lt; last()]" />
      </m:e>
    </m:d>
  </xsl:template>


  <!-- %%Template: writes the appropriate script structure (sSup, sSub, sSubSup, limLow,
       limUpp) with an m:d (fenced) expression as the base. This handles the case where
       MathML has a fenced expression where the closing fence character is inside a script
       element as its base.
       For example, KaTeX generates (x)^2 as:
         <mrow><mo>(</mo><mi>x</mi><msup><mo>)</mo><mn>2</mn></msup></mrow>
       This template produces:
         <m:sSup><m:e><m:d>...(x)...</m:d></m:e><m:sup>2</m:sup></m:sSup>
  -->
  <xsl:template name="WriteFencedWithScript">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="chOpen" select="normalize-space($ndCur/*[1])" />
    <xsl:variable name="chClose" select="normalize-space($ndCur/*[last()]/*[1])" />
    <xsl:variable name="ndScript" select="$ndCur/*[last()]" />

    <xsl:choose>
      <xsl:when test="$ndScript[self::mml:msup]">
        <m:sSup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="WriteFencedContent">
              <xsl:with-param name="ndCur" select="$ndCur" />
              <xsl:with-param name="chOpen" select="$chOpen" />
              <xsl:with-param name="chClose" select="$chClose" />
            </xsl:call-template>
          </m:e>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndScript/*[2]" />
          </m:sup>
        </m:sSup>
      </xsl:when>
      <xsl:when test="$ndScript[self::mml:msub]">
        <m:sSub>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="WriteFencedContent">
              <xsl:with-param name="ndCur" select="$ndCur" />
              <xsl:with-param name="chOpen" select="$chOpen" />
              <xsl:with-param name="chClose" select="$chClose" />
            </xsl:call-template>
          </m:e>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndScript/*[2]" />
          </m:sub>
        </m:sSub>
      </xsl:when>
      <xsl:when test="$ndScript[self::mml:msubsup]">
        <m:sSubSup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="WriteFencedContent">
              <xsl:with-param name="ndCur" select="$ndCur" />
              <xsl:with-param name="chOpen" select="$chOpen" />
              <xsl:with-param name="chClose" select="$chClose" />
            </xsl:call-template>
          </m:e>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndScript/*[2]" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndScript/*[3]" />
          </m:sup>
        </m:sSubSup>
      </xsl:when>
      <xsl:when test="$ndScript[self::mml:munder]">
        <m:limLow>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="WriteFencedContent">
              <xsl:with-param name="ndCur" select="$ndCur" />
              <xsl:with-param name="chOpen" select="$chOpen" />
              <xsl:with-param name="chClose" select="$chClose" />
            </xsl:call-template>
          </m:e>
          <m:lim>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndScript/*[2]" />
          </m:lim>
        </m:limLow>
      </xsl:when>
      <xsl:when test="$ndScript[self::mml:mover]">
        <m:limUpp>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="WriteFencedContent">
              <xsl:with-param name="ndCur" select="$ndCur" />
              <xsl:with-param name="chOpen" select="$chOpen" />
              <xsl:with-param name="chClose" select="$chClose" />
            </xsl:call-template>
          </m:e>
          <m:lim>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndScript/*[2]" />
          </m:lim>
        </m:limUpp>
      </xsl:when>
      <xsl:when test="$ndScript[self::mml:munderover]">
        <m:limUpp>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <m:limLow>
              <m:e>
                <xsl:call-template name="CreateArgProp" />
                <xsl:call-template name="WriteFencedContent">
                  <xsl:with-param name="ndCur" select="$ndCur" />
                  <xsl:with-param name="chOpen" select="$chOpen" />
                  <xsl:with-param name="chClose" select="$chClose" />
                </xsl:call-template>
              </m:e>
              <m:lim>
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndScript/*[2]" />
              </m:lim>
            </m:limLow>
          </m:e>
          <m:lim>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndScript/*[3]" />
          </m:lim>
        </m:limUpp>
      </xsl:when>
    </xsl:choose>
  </xsl:template>


  <!-- %%Template: CreateDelimProp
	
		Given the characters to use as open, close and separators for 
		the delim object, create the m:dPr (delim properties). 		
		
		MathML can have any number of separators in an mfenced object, but 
		OMML can only represent one separator for each d (delim) object.
		So, we pick the first separator specified. 		
	-->
  <xsl:template name="CreateDelimProp">
    <xsl:param name="fChOpenValid" />
    <xsl:param name="chOpen" />
    <xsl:param name="fChSeparatorsValid" />
    <xsl:param name="chSeparators" />
    <xsl:param name="fChCloseValid" />
    <xsl:param name="chClose" />
    <xsl:variable name="chSep" select="substring($chSeparators, 1, 1)" />

    <!-- do we need a dPr at all? If everything's at its default value, then 
			don't bother at all -->
    <xsl:if test="($fChOpenValid=1 and not($chOpen = '(')) or
						  ($fChCloseValid=1 and not($chClose = ')')) or 
						  not($chSep = '|')">
      <m:dPr>
        <!-- the default for MathML and OMML is '('. -->
        <xsl:if test="$fChOpenValid=1 and not($chOpen = '(')">
          <m:begChr>
            <xsl:attribute name="m:val">
              <xsl:value-of select="$chOpen" />
            </xsl:attribute>
          </m:begChr>
        </xsl:if>

        <!-- the default for MathML is ',' and for OMML is '|' -->

        <xsl:choose>
          <!-- matches OMML's default, don't bother to write anything out -->
          <xsl:when test="$chSep = '|'" />

          <!-- Not specified, use MathML's default. We test against 
					the existence of the actual attribute, not the substring -->
          <xsl:when test="$fChSeparatorsValid=0">
            <m:sepChr m:val=',' />
          </xsl:when>

          <xsl:otherwise>
            <m:sepChr>
              <xsl:attribute name="m:val">
                <xsl:value-of select="$chSep" />
              </xsl:attribute>
            </m:sepChr>
          </xsl:otherwise>
        </xsl:choose>

        <!-- the default for MathML and OMML is ')'. -->
        <xsl:if test="$fChCloseValid=1 and not($chClose = ')')">
          <m:endChr>
            <xsl:attribute name="m:val">
              <xsl:value-of select="$chClose" />
            </xsl:attribute>
          </m:endChr>
        </xsl:if>
      </m:dPr>
    </xsl:if>
  </xsl:template>

  <xsl:template name="LQuoteFromMs">
    <xsl:param name="msCur" select="." />
    <xsl:choose>
      <xsl:when test="(not($msCur/@lquote) or $msCur/@lquote='')
                      and (not($msCur/@mml:lquote) or $msCur/@mml:lquote='')">
        <xsl:text>"</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="$msCur/@lquote">
            <xsl:value-of select="$msCur/@lquote"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$msCur/@mml:lquote"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="RQuoteFromMs">
    <xsl:param name="msCur" select="." />
    <xsl:choose>
      <xsl:when test="(not($msCur/@rquote) or $msCur/@rquote='')
                       and (not($msCur/@mml:rquote) or $msCur/@mml:rquote='')">
        <xsl:text>"</xsl:text>
      </xsl:when>
      <xsl:otherwise>
        <xsl:choose>
          <xsl:when test="$msCur/@rquote">
            <xsl:value-of select="$msCur/@rquote"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$msCur/@mml:rquote"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: OutputMs
	-->
  <xsl:template name="OutputMs">
    <xsl:param name="msCur" />

    <xsl:variable name="chLquote">
      <xsl:call-template name="LQuoteFromMs">
        <xsl:with-param name="msCur" select="$msCur" />
      </xsl:call-template>
    </xsl:variable>

    <xsl:variable name="chRquote">
      <xsl:call-template name="RQuoteFromMs">
        <xsl:with-param name="msCur" select="$msCur" />
      </xsl:call-template>
    </xsl:variable>

    <xsl:value-of select="$chLquote"/>
    <xsl:value-of select="normalize-space($msCur)" />
    <xsl:value-of select="$chRquote"/>
  </xsl:template>

  <!-- %%Template: match msub
	-->
  <xsl:template match="mml:msub">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MSub">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MSub">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fNary">
      <xsl:call-template name="isNary">
        <xsl:with-param name="ndCur" select="$ndCur/*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fNary='true'">
        <m:nary>
          <xsl:call-template name="CreateNaryProp">
            <xsl:with-param name="chr">
              <xsl:value-of select="normalize-space($ndCur/*[1])" />
            </xsl:with-param>
            <xsl:with-param name="sMathmlType" select="'msub'" />
          </xsl:call-template>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
          </m:sup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="NaryHandleMrowMstyle">
              <xsl:with-param name="ndCur" select="($ndCur[parent::*[count(*) > 1]] |
                                                   $ndCur/parent::*[self::mml:mstyle[count(*) = 1]])/following-sibling::*[1]" />
            </xsl:call-template>
          </m:e>
        </m:nary>
      </xsl:when>
      <xsl:otherwise>
        <m:sSub>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[1]" />
          </m:e>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sub>
        </m:sSub>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: match msup
	-->
  <xsl:template match="mml:msup">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MSup">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MSup">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fNary">
      <xsl:call-template name="isNary">
        <xsl:with-param name="ndCur" select="$ndCur/*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fNary='true'">
        <m:nary>
          <xsl:call-template name="CreateNaryProp">
            <xsl:with-param name="chr">
              <xsl:value-of select="normalize-space($ndCur/*[1])" />
            </xsl:with-param>
            <xsl:with-param name="sMathmlType" select="'msup'" />
          </xsl:call-template>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="NaryHandleMrowMstyle">
              <xsl:with-param name="ndCur" select="($ndCur[parent::*[count(*) > 1]] |
                                                   $ndCur/parent::*[self::mml:mstyle[count(*) = 1]])/following-sibling::*[1]" />
            </xsl:call-template>
          </m:e>
        </m:nary>
      </xsl:when>
      <xsl:otherwise>
        <m:sSup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[1]" />
          </m:e>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sup>
        </m:sSup>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: match msubsup
	-->
  <xsl:template match="mml:msubsup">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MSubSup">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MSubSup">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fNary">
      <xsl:call-template name="isNary">
        <xsl:with-param name="ndCur" select="$ndCur/*[1]" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fNary='true'">
        <m:nary>
          <xsl:call-template name="CreateNaryProp">
            <xsl:with-param name="chr">
              <xsl:value-of select="normalize-space($ndCur/*[1])" />
            </xsl:with-param>
            <xsl:with-param name="sMathmlType" select="'msubsup'" />
          </xsl:call-template>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[3]" />
          </m:sup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:call-template name="NaryHandleMrowMstyle">
              <xsl:with-param name="ndCur" select="($ndCur[parent::*[count(*) > 1]] |
                                                   $ndCur/parent::*[self::mml:mstyle[count(*) = 1]])/following-sibling::*[1]" />
            </xsl:call-template>
          </m:e>
        </m:nary>
      </xsl:when>
      <xsl:otherwise>
        <m:sSubSup>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[1]" />
          </m:e>
          <m:sub>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[2]" />
          </m:sub>
          <m:sup>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[3]" />
          </m:sup>
        </m:sSubSup>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- %%Template: SplitScripts 
	
		Takes an collection of nodes, and splits them
		odd and even into sup and sub scripts. Used for dealing with
		mmultiscript.
		
		This template assumes you want to output both a sub and sup element.
		-->
  <xsl:template name="SplitScripts">
    <xsl:param name="ndScripts" />
    <m:sub>
      <xsl:call-template name="CreateArgProp" />
      <xsl:apply-templates select="$ndScripts[(position() mod 2) = 1]" />
    </m:sub>
    <m:sup>
      <xsl:call-template name="CreateArgProp" />
      <xsl:apply-templates select="$ndScripts[(position() mod 2) = 0]" />
    </m:sup>
  </xsl:template>

  <!-- %%Template: match mmultiscripts
	
		There is some subtlety with the mml:mprescripts element. Everything that comes before 
		that is considered a script (as opposed to a pre-script), but it need not be present.
	-->
  <xsl:template match="mml:mmultiscripts">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MMultiscripts">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MMultiscripts">
    <xsl:param name="ndCur" select="." />

    <!-- count the nodes. Everything that comes after a mml:mprescripts is considered a pre-script;
			Everything that does not have an mml:mprescript as a preceding-sibling (and is not itself 
			mml:mprescript) is a script, except for the first child which is always the base.
			The mml:none element is a place holder for a sub/sup element slot.
			
			mmultisript pattern:
			<mmultiscript>
				(base)
				(sub sup)* // Where <none/> can replace a sub/sup entry to preserve pattern.
				<mprescripts />
				(presub presup)*
			</mmultiscript>
			-->
    <!-- Count of presecript nodes that we'd print (this is essentially anything but the none placeholder. -->
    <xsl:variable name="cndPrescriptStrict" select="count($ndCur/mml:mprescripts[1]/following-sibling::*[not(self::mml:none)])" />
    <!-- Count of all super script excluding mml:none -->
    <xsl:variable name="cndSuperScript" select="count($ndCur/*[not(preceding-sibling::mml:mprescripts) and
                                                not(self::mml:mprescripts) and
                                                ((position() mod 2) = 1) and
                                                not(self::mml:none)]) - 1" />
    <!-- Count of all sup script excluding mml:none -->
    <xsl:variable name="cndSubScript" select="count($ndCur/*[not(preceding-sibling::mml:mprescripts) and
                                              not(self::mml:mprescripts) and
                                              ((position() mod 2) = 0) and
                                              not(self::mml:none)])" />
    <!-- Count of all scripts excluding mml:none -->
    <xsl:variable name="cndScriptStrict" select="$cndSuperScript + $cndSubScript" />
    <!-- Count of all scripts including mml:none.  This is essentially all nodes before the 
         first mml:mprescripts except the base. -->
    <xsl:variable name="cndScript" select="count($ndCur/*[not(preceding-sibling::mml:mprescripts) and not(self::mml:mprescripts)]) - 1" />

    <xsl:choose>
      <!-- The easy case first. No prescripts, and no script ... just a base -->
      <xsl:when test="$cndPrescriptStrict &lt;= 0 and $cndScriptStrict &lt;= 0">
        <xsl:apply-templates select="$ndCur/*[1]" />
      </xsl:when>

      <!-- Next, if there are no prescripts -->
      <xsl:when test="$cndPrescriptStrict &lt;= 0">
        <!-- we know we have some scripts or else we would have taken the earlier
             branch. -->
        <xsl:choose>
          <!-- We have both sub and super scripts-->
          <xsl:when test="$cndSuperScript &gt; 0 and $cndSubScript &gt; 0">
            <m:sSubSup>
              <m:e>
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*[1]" />
              </m:e>

              <!-- Every child except the first is a script.  Do the split -->
              <xsl:call-template name="SplitScripts">
                <xsl:with-param name="ndScripts" select="$ndCur/*[position() &gt; 1]" />
              </xsl:call-template>
            </m:sSubSup>
          </xsl:when>
          <!-- Just a sub script -->
          <xsl:when test="$cndSubScript &gt; 0">
            <m:sSub>
              <m:e>
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*[1]" />
              </m:e>

              <!-- No prescripts and no super scripts, therefore, it's a sub. -->
              <m:sub>
                <xsl:apply-templates select="$ndCur/*[position() &gt; 1]" />
              </m:sub>
            </m:sSub>
          </xsl:when>
          <!-- Just super script -->
          <xsl:otherwise>
            <m:sSup>
              <m:e>
                <xsl:call-template name="CreateArgProp" />
                <xsl:apply-templates select="$ndCur/*[1]" />
              </m:e>

              <!-- No prescripts and no sub scripts, therefore, it's a sup. -->
              <m:sup>
                <xsl:apply-templates select="$ndCur/*[position() &gt; 1]" />
              </m:sup>
            </m:sSup>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>

      <!-- Next, if there are no scripts -->
      <xsl:when test="$cndScriptStrict &lt;= 0">
        <!-- we know we have some prescripts or else we would have taken the earlier
					  branch. So, create an sPre and split the elements -->
        <m:sPre>
          <m:e>
            <xsl:call-template name="CreateArgProp" />
            <xsl:apply-templates select="$ndCur/*[1]" />
          </m:e>

          <!-- The prescripts come after the mml:mprescript and if we get here
							we know there exists some elements after the mml:mprescript element. 
							
							The prescript element has no sub/subsup variation, therefore, even if
							we're only writing sub, we need to write out both the sub and sup element.
							-->
          <xsl:call-template name="SplitScripts">
            <xsl:with-param name="ndScripts" select="$ndCur/mml:mprescripts[1]/following-sibling::*" />
          </xsl:call-template>
        </m:sPre>
      </xsl:when>

      <!-- Finally, the case with both prescripts and scripts. Create an sPre 
				element to house the prescripts, with a sub/sup/subsup element at its base. -->
      <xsl:otherwise>
        <m:sPre>
          <m:e>
            <xsl:choose>
              <!-- We have both sub and super scripts-->
              <xsl:when test="$cndSuperScript &gt; 0 and $cndSubScript &gt; 0">
                <m:sSubSup>
                  <m:e>
                    <xsl:call-template name="CreateArgProp" />
                    <xsl:apply-templates select="$ndCur/*[1]" />
                  </m:e>

                  <!-- scripts come before the mml:mprescript but after the first child, so their
								 positions will be 2, 3, ... ($nndScript + 1) -->
                  <xsl:call-template name="SplitScripts">
                    <xsl:with-param name="ndScripts" select="$ndCur/*[(position() &gt; 1) and (position() &lt;= ($cndScript + 1))]" />
                  </xsl:call-template>
                </m:sSubSup>
              </xsl:when>
              <!-- Just a sub script -->
              <xsl:when test="$cndSubScript &gt; 0">
                <m:sSub>
                  <m:e>
                    <xsl:call-template name="CreateArgProp" />
                    <xsl:apply-templates select="$ndCur/*[1]" />
                  </m:e>

                  <!-- We have prescripts but no super scripts, therefore, do a sub 
									and apply templates to all tokens counted by cndScript. -->
                  <m:sub>
                    <xsl:apply-templates select="$ndCur/*[position() &gt; 1 and (position() &lt;= ($cndScript + 1))]" />
                  </m:sub>
                </m:sSub>
              </xsl:when>
              <!-- Just super script -->
              <xsl:otherwise>
                <m:sSup>
                  <m:e>
                    <xsl:call-template name="CreateArgProp" />
                    <xsl:apply-templates select="$ndCur/*[1]" />
                  </m:e>

                  <!-- We have prescripts but no sub scripts, therefore, do a sub 
									and apply templates to all tokens counted by cndScript. -->
                  <m:sup>
                    <xsl:apply-templates select="$ndCur/*[position() &gt; 1 and (position() &lt;= ($cndScript + 1))]" />
                  </m:sup>
                </m:sSup>
              </xsl:otherwise>
            </xsl:choose>
          </m:e>

          <!-- The prescripts come after the mml:mprescript and if we get here
							we know there exists one such element -->
          <xsl:call-template name="SplitScripts">
            <xsl:with-param name="ndScripts" select="$ndCur/mml:mprescripts[1]/following-sibling::*" />
          </xsl:call-template>
        </m:sPre>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Template that determines if ndCur is an equation array.
				
			 ndCur is an equation array if:
			 
			 1.  There are are no frame lines
			 2.  There are no column lines
			 3.  There are no row lines
			 4.  There is no row with more than 1 column  
			 5.  There is no row with fewer than 1 column
			 6.  There are no labeled rows.
			 
	-->
  <xsl:template name="FIsEqArray">
    <xsl:param name="ndCur" select="." />

    <!-- There should be no frame, columnlines, or rowlines -->
    <xsl:choose>
      <xsl:when test="(not($ndCur/@frame) or $ndCur/@frame='' or $ndCur/@frame='none')
                      and (not($ndCur/@mml:frame) or $ndCur/@mml:frame='' or $ndCur/@mml:frame='none')
								      and (not($ndCur/@columnlines) or $ndCur/@columnlines='' or $ndCur/@columnlines='none')
                      and (not($ndCur/@mml:columnlines) or $ndCur/@mml:columnlines='' or $ndCur/@mml:columnlines='none')
								      and (not($ndCur/@rowlines) or $ndCur/@rowlines='' or $ndCur/@rowlines='none')
                      and (not($ndCur/@mml:rowlines) or $ndCur/@mml:rowlines='' or $ndCur/@mml:rowlines='none')
								      and not($ndCur/mml:mtr[count(mml:mtd) &gt; 1])
											and not($ndCur/mml:mtr[count(mml:mtd) &lt; 1])
								      and not($ndCur/mml:mlabeledtr)">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Template used to determine if we should ignore a collection when iterating through 
	     a mathml equation array row.
	
			 So far, the only thing that needs to be ignored is the argument of an nary.  We
			 can ignore this since it is output when we apply-templates to the munder[over]/msub[sup].
	-->
  <xsl:template name="FIgnoreCollection">
    <xsl:param name="ndCur" select="." />

    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>

    <xsl:choose>
      <xsl:when test="$fNaryArgument=1">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- Template used to determine if we've already encountered an maligngroup or malignmark.
	
			 This is needed because omml has an implicit spacing alignment (omml spacing alignment = 
			 mathml's maligngroup element) at the beginning of each equation array row.  Therefore, 
			 the first maligngroup (implied or explicit) we encounter does not need to be output.  
			 This template recursively searches up the xml tree and looks at previous siblings to see 
			 if they have a descendant that is an maligngroup or malignmark.  We look for the malignmark 
			 to find the implicit maligngroup.
	-->
  <xsl:template name="FFirstAlignAlreadyFound">
    <xsl:param name="ndCur" select="." />

    <xsl:choose>
      <xsl:when test="count($ndCur/preceding-sibling::*[descendant-or-self::mml:maligngroup
								                                        or descendant-or-self::mml:malignmark]) &gt; 0">1</xsl:when>
      <xsl:when test="not($ndCur/parent::mml:mtd)">
        <xsl:call-template name="FFirstAlignAlreadyFound">
          <xsl:with-param name="ndCur" select="$ndCur/parent::*" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- This template builds a string that is result of concatenating a given string several times. 
	
			 Given strToRepeat, create a string that has strToRepeat repeated iRepitions times. 
	-->
  <xsl:template name="ConcatStringRepeat">
    <xsl:param name="strToRepeat" select="''" />
    <xsl:param name="iRepetitions" select="0" />
    <xsl:param name="strBuilding" select="''" />

    <xsl:choose>
      <xsl:when test="$iRepetitions &lt;= 0">
        <xsl:value-of select="$strBuilding" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="ConcatStringRepeat">
          <xsl:with-param name="strToRepeat" select="$strToRepeat" />
          <xsl:with-param name="iRepetitions" select="$iRepetitions - 1" />
          <xsl:with-param name="strBuilding" select="concat($strBuilding, $strToRepeat)" />
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- This template determines if ndCur is a special collection.
			 By special collection, I mean is ndCur the outer element of some special grouping 
			 of mathml elements that actually represents some over all omml structure.
			 
			 For instance, is ndCur a linear fraction, or an omml function.
	-->
  <xsl:template name="FSpecialCollection">
    <xsl:param name="ndCur" select="." />
    <xsl:choose>
      <xsl:when test="$ndCur/self::mml:mrow">
        <xsl:variable name="fLinearFraction">
          <xsl:call-template name="FLinearFrac">
            <xsl:with-param name="ndCur" select="$ndCur"/>
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="fFunc">
          <xsl:call-template name="FIsFunc">
            <xsl:with-param name="ndCur" select="$ndCur" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="fFenced">
          <xsl:call-template name="FFenced">
            <xsl:with-param name="ndCur" select="$ndCur" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="$fLinearFraction=1 or $fFunc=1 or $fFenced=1">1</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <!-- This template iterates through the children of an equation array row (mtr) and outputs
	     the equation.
			 
			 This template does all the work to output ampersands and skip the right elements when needed.
	-->
  <xsl:template name="ProcessEqArrayRow">
    <xsl:param name="ndCur" select="." />

    <xsl:for-each select="$ndCur/*">
      <xsl:variable name="fSpecialCollection">
        <xsl:call-template name="FSpecialCollection">
          <xsl:with-param name="ndCur" select="." />
        </xsl:call-template>
      </xsl:variable>
      <xsl:variable name="fIgnoreCollection">
        <xsl:call-template name="FIgnoreCollection">
          <xsl:with-param name="ndCur" select="." />
        </xsl:call-template>
      </xsl:variable>
      <xsl:choose>
        <!-- If we have an alignment element output the ampersand. -->
        <xsl:when test="self::mml:maligngroup or self::mml:malignmark">
          <!-- Omml has an implied spacing alignment at the beginning of each equation.
					     Therefore, if this is the first ampersand to be output, don't actually output. -->
          <xsl:variable name="fFirstAlignAlreadyFound">
            <xsl:call-template name="FFirstAlignAlreadyFound">
              <xsl:with-param name="ndCur" select="." />
            </xsl:call-template>
          </xsl:variable>
          <!-- Don't output unless it is an malignmark or we have already previously found an alignment point. -->
          <xsl:if test="self::mml:malignmark or $fFirstAlignAlreadyFound=1">
            <m:r>
              <m:t>&amp;</m:t>
            </m:r>
          </xsl:if>
        </xsl:when>
        <!-- If this node is an non-special mrow or mstyle and we aren't supposed to ignore this collection, then
				     go ahead an apply templates to this node. -->
        <xsl:when test="$fIgnoreCollection=0 and ((self::mml:mrow and $fSpecialCollection=0) or self::mml:mstyle)">
          <xsl:call-template name="ProcessEqArrayRow">
            <xsl:with-param name="ndCur" select="." />
          </xsl:call-template>
        </xsl:when>
        <!-- At this point we have some mathml structure (fraction, nary, non-grouping element, etc.) -->
        <!-- If this mathml structure has alignment groups or marks as children, then extract those since
				     omml can't handle that. -->
        <xsl:when test="descendant::mml:maligngroup or descendant::mml:malignmark">
          <xsl:variable name="cMalignGroups">
            <xsl:value-of select="count(descendant::mml:maligngroup)" />
          </xsl:variable>
          <xsl:variable name="cMalignMarks">
            <xsl:value-of select="count(descendant::mml:malignmark)" />
          </xsl:variable>
          <!-- Output all maligngroups and malignmarks as '&' -->
          <xsl:if test="$cMalignGroups + $cMalignMarks &gt; 0">
            <xsl:variable name="str">
              <xsl:call-template name="ConcatStringRepeat">
                <xsl:with-param name="strToRepeat" select="'&amp;'" />
                <xsl:with-param name="iRepetitions" select="$cMalignGroups + $cMalignMarks" />
                <xsl:with-param name="strBuilding" select="''" />
              </xsl:call-template>
            </xsl:variable>
            <xsl:element name="m:r">
              <xsl:element name="m:t">
                <xsl:call-template name="OutputText">
                  <xsl:with-param name="sInput" select="$str" />
                </xsl:call-template>
              </xsl:element>
            </xsl:element>
          </xsl:if>
          <!-- Now that the '&' have been extracted, just apply-templates to this node.-->
          <xsl:apply-templates select="." />
        </xsl:when>
        <!-- If there are no alignment points as descendants, then go ahead and output this node. -->
        <xsl:otherwise>
          <xsl:apply-templates select="." />
        </xsl:otherwise>
      </xsl:choose>
    </xsl:for-each>
  </xsl:template>

  <!-- This template transforms mtable into its appropriate omml type.
	
			 There are two possible omml constructs that an mtable can become:  a matrix or 
			 an equation array.
			 
			 Because omml has no generic table construct, the omml matrix is the best approximate
			 for a mathml table.
			 
			 Our equation array transformation is very simple.  The main goal of this transform is to
			 allow roundtripping omml eq arrays through mathml.  The template ProcessEqArrayRow was never
			 intended to account for many of the alignment flexibilities that are present in mathml like 
			 using the alig attribute, using alignmark attribute in token elements, etc.
			 
			 The restrictions on this transform require <malignmark> and <maligngroup> elements to be outside of
			 any non-grouping mathml elements (that is, mrow and mstyle).  Moreover, these elements cannot be the children of
			 mrows that represent linear fractions or functions.  Also, <malignmark> cannot be a child
			 of token attributes.
			 
			 In the case that the above 
	
	-->
  <xsl:template match="mml:mtable">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MTable">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MTable">
    <xsl:param name="ndCur" select="." />
    <xsl:variable name="fEqArray">
      <xsl:call-template name="FIsEqArray">
        <xsl:with-param name="ndCur" select="$ndCur" />
      </xsl:call-template>
    </xsl:variable>
    <xsl:choose>
      <xsl:when test="$fEqArray=1">
        <xsl:element name="m:eqArr">
          <xsl:for-each select="$ndCur/mml:mtr">
            <xsl:element name="m:e">
              <xsl:call-template name="ProcessEqArrayRow">
                <xsl:with-param name="ndCur" select="mml:mtd" />
              </xsl:call-template>
            </xsl:element>
          </xsl:for-each>
        </xsl:element>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="cMaxElmtsInRow">
          <xsl:call-template name="CountMaxElmtsInRow">
            <xsl:with-param name="ndCur" select="$ndCur/*[1]" />
            <xsl:with-param name="cMaxElmtsInRow" select="0" />
          </xsl:call-template>
        </xsl:variable>
        <m:m>
          <m:mPr>
            <m:baseJc m:val="center" />
            <m:plcHide m:val="on" />
            <m:mcs>
              <m:mc>
                <m:mcPr>
                  <m:count>
                    <xsl:attribute name="m:val">
                      <xsl:value-of select="$cMaxElmtsInRow" />
                    </xsl:attribute>
                  </m:count>
                  <m:mcJc m:val="center" />
                </m:mcPr>
              </m:mc>
            </m:mcs>
          </m:mPr>
          <xsl:for-each select="$ndCur/*">
            <xsl:choose>
              <xsl:when test="self::mml:mtr or self::mml:mlabeledtr">
                <m:mr>
                  <xsl:choose>
                    <xsl:when test="self::mml:mtr">
                      <xsl:for-each select="*">
                        <m:e>
                          <xsl:apply-templates select="." />
                        </m:e>
                      </xsl:for-each>
                      <xsl:call-template name="CreateEmptyElmt">
                        <xsl:with-param name="cEmptyMtd" select="$cMaxElmtsInRow - count(*)" />
                      </xsl:call-template>
                    </xsl:when>
                    <xsl:otherwise>
                      <xsl:for-each select="*[position() &gt; 1]">
                        <m:e>
                          <xsl:apply-templates select="." />
                        </m:e>
                      </xsl:for-each>
                      <xsl:call-template name="CreateEmptyElmt">
                        <xsl:with-param name="cEmptyMtd" select="$cMaxElmtsInRow - (count(*) - 1)" />
                      </xsl:call-template>
                    </xsl:otherwise>
                  </xsl:choose>
                </m:mr>
              </xsl:when>
              <xsl:otherwise>
                <m:mr>
                  <m:e>
                    <xsl:apply-templates select="." />
                  </m:e>
                  <xsl:call-template name="CreateEmptyElmt">
                    <xsl:with-param name="cEmptyMtd" select="$cMaxElmtsInRow - 1" />
                  </xsl:call-template>
                </m:mr>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each>
        </m:m>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <xsl:template match="m:mtd">
    <xsl:apply-templates select="*" />
  </xsl:template>
  <xsl:template name="CreateEmptyElmt">
    <xsl:param name="cEmptyMtd" />
    <xsl:if test="$cEmptyMtd &gt; 0">
      <m:e></m:e>
      <xsl:call-template name="CreateEmptyElmt">
        <xsl:with-param name="cEmptyMtd" select="$cEmptyMtd - 1" />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>
  <xsl:template name="CountMaxElmtsInRow">
    <xsl:param name="ndCur" />
    <xsl:param name="cMaxElmtsInRow" select="0" />
    <xsl:choose>
      <xsl:when test="not($ndCur)">
        <xsl:value-of select="$cMaxElmtsInRow" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="CountMaxElmtsInRow">
          <xsl:with-param name="ndCur" select="$ndCur/following-sibling::*[1]" />
          <xsl:with-param name="cMaxElmtsInRow">
            <xsl:choose>
              <xsl:when test="local-name($ndCur) = 'mlabeledtr' and 
								            namespace-uri($ndCur) = 'http://www.w3.org/1998/Math/MathML'">
                <xsl:choose>
                  <xsl:when test="(count($ndCur/*) - 1) &gt; $cMaxElmtsInRow">
                    <xsl:value-of select="count($ndCur/*) - 1" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$cMaxElmtsInRow" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:when>
              <xsl:when test="local-name($ndCur) = 'mtr' and 
								            namespace-uri($ndCur) = 'http://www.w3.org/1998/Math/MathML'">
                <xsl:choose>
                  <xsl:when test="count($ndCur/*) &gt; $cMaxElmtsInRow">
                    <xsl:value-of select="count($ndCur/*)" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$cMaxElmtsInRow" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:when>
              <xsl:otherwise>
                <xsl:choose>
                  <xsl:when test="1 &gt; $cMaxElmtsInRow">
                    <xsl:value-of select="1" />
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:value-of select="$cMaxElmtsInRow" />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="GetMglyphAltText">
    <xsl:param name="ndCur" select="." />
    <xsl:choose>
      <xsl:when test="$ndCur/@alt">
        <xsl:value-of select="normalize-space($ndCur/@alt)"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="normalize-space($ndCur/@mml:alt)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="mml:mglyph">
    <xsl:element name="m:r">
      <xsl:element name="m:rPr">
        <xsl:element name="m:nor" />
      </xsl:element>
      <xsl:element name="m:t">
        <xsl:call-template name="OutputText">
          <xsl:with-param name="sInput">
            <xsl:call-template name="GetMglyphAltText">
              <xsl:with-param name="ndCur" select="." />
            </xsl:call-template>
          </xsl:with-param>
        </xsl:call-template>
      </xsl:element>
    </xsl:element>
  </xsl:template>

  <!-- Omml doesn't really support mglyph, so just output the alt text -->
  <xsl:template match="mml:mi[child::mml:mglyph] | 
	                     mml:mn[child::mml:mglyph] | 
	                     mml:mo[child::mml:mglyph] | 
	                     mml:ms[child::mml:mglyph] | 
	                     mml:mtext[child::mml:mglyph]">
    <xsl:variable name="mathvariant">
      <xsl:choose>
        <xsl:when test="@mathvariant">
          <xsl:value-of select="@mathvariant"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@mml:mathvariant"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fontstyle">
      <xsl:choose>
        <xsl:when test="@fontstyle">
          <xsl:value-of select="@fontstyle"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@mml:fontstyle"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fontweight">
      <xsl:choose>
        <xsl:when test="@fontweight">
          <xsl:value-of select="@fontweight"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@mml:fontweight"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="mathcolor">
      <xsl:choose>
        <xsl:when test="@mathcolor">
          <xsl:value-of select="@mathcolor"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@mml:mathcolor"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="mathsize">
      <xsl:choose>
        <xsl:when test="@mathsize">
          <xsl:value-of select="@mathsize"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@mml:mathsize"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="color">
      <xsl:choose>
        <xsl:when test="@color">
          <xsl:value-of select="@color"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@mml:color"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fontsize">
      <xsl:choose>
        <xsl:when test="@fontsize">
          <xsl:value-of select="@fontsize"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="@mml:fontsize"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>
    <xsl:variable name="fNor">
      <xsl:call-template name="FNor">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>

    <!-- Output MS Left Quote (if need be) -->
    <xsl:if test="self::mml:ms">
      <xsl:variable name="chLquote">
        <xsl:call-template name="LQuoteFromMs">
          <xsl:with-param name="curMs" select="." />
        </xsl:call-template>
      </xsl:variable>
      <xsl:element name="m:r">
        <xsl:call-template name="CreateRunProp">
          <xsl:with-param name="mathvariant" select="$mathvariant" />
          <xsl:with-param name="fontstyle" select="$fontstyle" />
          <xsl:with-param name="fontweight" select="$fontweight" />
          <xsl:with-param name="mathcolor" select="$mathcolor" />
          <xsl:with-param name="mathsize" select="$mathsize" />
          <xsl:with-param name="color" select="$color" />
          <xsl:with-param name="fontsize" select="$fontsize" />
          <xsl:with-param name="fNor" select="$fNor" />
          <xsl:with-param name="ndCur" select="." />
        </xsl:call-template>
        <xsl:element name="m:t">
          <xsl:call-template name="OutputText">
            <xsl:with-param name="sInput" select="$chLquote"/>
          </xsl:call-template>
        </xsl:element>
      </xsl:element>
    </xsl:if>
    <xsl:for-each select="mml:mglyph | text()">
      <xsl:variable name="fForceNor">
        <xsl:choose>
          <xsl:when test="self::mml:mglyph">1</xsl:when>
          <xsl:otherwise>0</xsl:otherwise>
        </xsl:choose>
      </xsl:variable>

      <xsl:variable name="str">
        <xsl:choose>
          <xsl:when test="self::mml:mglyph">
            <xsl:call-template name="GetMglyphAltText">
              <xsl:with-param name="ndCur" select="." />
            </xsl:call-template>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="normalize-space(.)"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <xsl:if test="string-length($str) &gt; 0">
        <xsl:element name="m:r">
          <xsl:call-template name="CreateRunProp">
            <xsl:with-param name="mathvariant" select="$mathvariant" />
            <xsl:with-param name="fontstyle" select="$fontstyle" />
            <xsl:with-param name="fontweight" select="$fontweight" />
            <xsl:with-param name="mathcolor" select="$mathcolor" />
            <xsl:with-param name="mathsize" select="$mathsize" />
            <xsl:with-param name="color" select="$color" />
            <xsl:with-param name="fontsize" select="$fontsize" />
            <xsl:with-param name="fNor">
              <xsl:choose>
                <xsl:when test="$fForceNor=1">1</xsl:when>
                <xsl:otherwise>
                  <xsl:value-of select="$fNor"/>
                </xsl:otherwise>
              </xsl:choose>
            </xsl:with-param>
            <xsl:with-param name="ndCur" select="." />
          </xsl:call-template>
          <xsl:element name="m:t">
            <xsl:call-template name="OutputText">
              <xsl:with-param name="sInput" select="$str"/>
            </xsl:call-template>
          </xsl:element>
        </xsl:element>
      </xsl:if>
    </xsl:for-each>

    <!-- Output MS Right Quote (if need be) -->
    <xsl:if test="self::mml:ms">
      <xsl:variable name="chRquote">
        <xsl:call-template name="RQuoteFromMs">
          <xsl:with-param name="curMs" select="." />
        </xsl:call-template>
      </xsl:variable>
      <xsl:element name="m:r">
        <xsl:call-template name="CreateRunProp">
          <xsl:with-param name="mathvariant" select="$mathvariant" />
          <xsl:with-param name="fontstyle" select="$fontstyle" />
          <xsl:with-param name="fontweight" select="$fontweight" />
          <xsl:with-param name="mathcolor" select="$mathcolor" />
          <xsl:with-param name="mathsize" select="$mathsize" />
          <xsl:with-param name="color" select="$color" />
          <xsl:with-param name="fontsize" select="$fontsize" />
          <xsl:with-param name="fNor" select="$fNor" />
          <xsl:with-param name="ndCur" select="." />
        </xsl:call-template>
        <xsl:element name="m:t">
          <xsl:call-template name="OutputText">
            <xsl:with-param name="sInput" select="$chRquote"/>
          </xsl:call-template>
        </xsl:element>
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <xsl:template name="FStrContainsNonZeroDigit">
    <xsl:param name="s" />

    <!-- Translate any nonzero digit into a 9 -->
    <xsl:variable name="sNonZeroDigitsToNineDigit" select="translate($s, '12345678', '99999999')" />
    <xsl:choose>
      <!-- Search for 9s -->
      <xsl:when test="contains($sNonZeroDigitsToNineDigit, '9')">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="FStrContainsDigits">
    <xsl:param name="s" />

    <!-- Translate any digit into a 0 -->
    <xsl:variable name="sDigitsToZeroDigit" select="translate($s, '123456789', '000000000')" />
    <xsl:choose>
      <!-- Search for 0s -->
      <xsl:when test="contains($sDigitsToZeroDigit, '0')">1</xsl:when>
      <xsl:otherwise>0</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- Used to determine if mpadded attribute {width, height, depth } 
       indicates to show everything. 
       
       Unlike mathml, whose mpadded structure has great flexibility in modifying the 
       bounding box's width, height, and depth, Word can only have zero or full width, height, and depth.
       Thus, if the width, height, or depth attributes indicate any kind of nonzero width, height, 
       or depth, we'll translate that into a show full width, height, or depth for OMML.  Only if the attribute
       indicates a zero width, height, or depth, will we report back FFull as false.
       
       Example:  s=0%    ->  FFull returns 0.
                 s=2%    ->  FFull returns 1.
                 s=0.1em ->  FFull returns 1.     
       
       -->
  <xsl:template name="FFull">
    <xsl:param name="s" />

    <xsl:variable name="fStrContainsNonZeroDigit">
      <xsl:call-template name="FStrContainsNonZeroDigit">
        <xsl:with-param name="s" select="$s" />
      </xsl:call-template>
    </xsl:variable>

    <xsl:variable name="fStrContainsDigits">
      <xsl:call-template name="FStrContainsDigits">
        <xsl:with-param name="s" select="$s" />
      </xsl:call-template>
    </xsl:variable>

    <xsl:choose>
      <!-- String contained non-zero digit -->
      <xsl:when test="$fStrContainsNonZeroDigit=1">1</xsl:when>
      <!-- String didn't contain a non-zero digit, but it did contain digits.
           This must mean that all digits in the string were 0s. -->
      <xsl:when test="$fStrContainsDigits=1">0</xsl:when>
      <!-- Else, no digits, therefore, return true.
           We return true in the otherwise condition to take account for the possibility
           in MathML to say something like width="height". -->
      <xsl:otherwise>1</xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <!-- Just outputs phant properties, doesn't do any fancy 
       thinking of its own, just obeys the defaults of 
       phants. -->
  <xsl:template name="CreatePhantPropertiesCore">
    <xsl:param name="fShow" select="1" />
    <xsl:param name="fFullWidth" select="1" />
    <xsl:param name="fFullHeight" select="1" />
    <xsl:param name="fFullDepth" select="1" />

    <xsl:if test="$fShow=0 
                    or $fFullWidth=0 
                    or $fFullHeight=0
                    or $fFullDepth=0">
      <xsl:element name="m:phantPr">
        <xsl:if test="$fShow=0">
          <xsl:element name="m:show">
            <xsl:attribute name="m:val">off</xsl:attribute>
          </xsl:element>
        </xsl:if>
        <xsl:if test="$fFullWidth=0">
          <xsl:element name="m:zeroWid">
            <xsl:attribute name="m:val">on</xsl:attribute>
          </xsl:element>
        </xsl:if>
        <xsl:if test="$fFullHeight=0">
          <xsl:element name="m:zeroAsc">
            <xsl:attribute name="m:val">on</xsl:attribute>
          </xsl:element>
        </xsl:if>
        <xsl:if test="$fFullDepth=0">
          <xsl:element name="m:zeroDesc">
            <xsl:attribute name="m:val">on</xsl:attribute>
          </xsl:element>
        </xsl:if>
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <!-- Figures out if we should factor in width, height, and depth attributes.  
  
       If so, then it 
       gets these attributes, does some processing to figure out what the attributes indicate, 
       then passes these indications to CreatePhantPropertiesCore.  
       
       If we aren't supposed to factor in width, height, or depth, then we'll just output the show
       attribute. -->
  <xsl:template name="CreatePhantProperties">
    <xsl:param name="ndCur" select="." />
    <xsl:param name="fShow" select="1"/>

    <xsl:choose>
      <!-- In the special case that we have an mphantom with one child which is an mpadded, then we should 
           subsume the mpadded attributes into the mphantom attributes.  The test statement below imples the 
           'one child which is an mpadded'.  The first part, that the parent of mpadded is an mphantom, is implied
           by being in this template, which is only called when we've encountered an mphantom.
           
           Word outputs its invisible phantoms with smashing as 

              <mml:mphantom>
                <mml:mpadded . . . >
                  
                </mml:mpadded>
              </mml:mphantom>

            This test is used to allow roundtripping smashed invisible phantoms. -->
      <xsl:when test="count($ndCur/child::*)=1 and count($ndCur/mml:mpadded)=1">
        <xsl:variable name="sLowerCaseWidth">
          <xsl:choose>
            <xsl:when test="$ndCur/mml:mpadded/@width">
              <xsl:value-of select="translate($ndCur/mml:mpadded/@width, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/mml:mpadded/@mml:width, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>
        <xsl:variable name="sLowerCaseHeight">
          <xsl:choose>
            <xsl:when test="$ndCur/mml:mpadded/@height">
              <xsl:value-of select="translate($ndCur/mml:mpadded/@height, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/mml:mpadded/@mml:height, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>
        <xsl:variable name="sLowerCaseDepth">
          <xsl:choose>
            <xsl:when test="$ndCur/mml:mpadded/@depth">
              <xsl:value-of select="translate($ndCur/mml:mpadded/@depth, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/mml:mpadded/@mml:depth, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>

        <xsl:variable name="fFullWidth">
          <xsl:call-template name="FFull">
            <xsl:with-param name="s" select="$sLowerCaseWidth" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="fFullHeight">
          <xsl:call-template name="FFull">
            <xsl:with-param name="s" select="$sLowerCaseHeight" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="fFullDepth">
          <xsl:call-template name="FFull">
            <xsl:with-param name="s" select="$sLowerCaseDepth" />
          </xsl:call-template>
        </xsl:variable>

        <xsl:call-template name="CreatePhantPropertiesCore">
          <xsl:with-param name="fShow" select="$fShow"/>
          <xsl:with-param name="fFullWidth" select="$fFullWidth" />
          <xsl:with-param name="fFullHeight" select="$fFullHeight" />
          <xsl:with-param name="fFullDepth" select="$fFullDepth" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="CreatePhantPropertiesCore">
          <xsl:with-param name="fShow" select="$fShow"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="mml:mpadded">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MPadded">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MPadded">
    <xsl:param name="ndCur" select="." />
    <xsl:choose>
      <xsl:when test="count($ndCur/parent::mml:mphantom)=1 and count($ndCur/preceding-sibling::*)=0 and count($ndCur/following-sibling::*)=0">
        <!-- This mpadded is inside an mphantom that has already setup phantom attributes, therefore, just apply templates -->
        <xsl:apply-templates select="$ndCur/*" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="sLowerCaseWidth">
          <xsl:choose>
            <xsl:when test="$ndCur/@width">
              <xsl:value-of select="$ndCur/@width" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndCur/@mml:width" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>
        <xsl:variable name="sLowerCaseHeight">
          <xsl:choose>
            <xsl:when test="$ndCur/@height">
              <xsl:value-of select="$ndCur/@height" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndCur/@mml:height" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>
        <xsl:variable name="sLowerCaseDepth">
          <xsl:choose>
            <xsl:when test="$ndCur/@depth">
              <xsl:value-of select="$ndCur/@depth" />
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="$ndCur/@mml:depth" />
            </xsl:otherwise>
          </xsl:choose>
        </xsl:variable>

        <xsl:variable name="fFullWidth">
          <xsl:call-template name="FFull">
            <xsl:with-param name="s" select="$sLowerCaseWidth" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="fFullHeight">
          <xsl:call-template name="FFull">
            <xsl:with-param name="s" select="$sLowerCaseHeight" />
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="fFullDepth">
          <xsl:call-template name="FFull">
            <xsl:with-param name="s" select="$sLowerCaseDepth" />
          </xsl:call-template>
        </xsl:variable>

        <xsl:element name="m:phant">
          <xsl:call-template name="CreatePhantPropertiesCore">
            <xsl:with-param name="fShow" select="1"/>
            <xsl:with-param name="fFullWidth" select="$fFullWidth" />
            <xsl:with-param name="fFullHeight" select="$fFullHeight" />
            <xsl:with-param name="fFullDepth" select="$fFullDepth" />
          </xsl:call-template>
          <m:e>
            <xsl:apply-templates select="$ndCur/*" />
          </m:e>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="mml:mphantom">
    <xsl:variable name="fNaryArgument">
      <xsl:call-template name="FIsNaryArgument">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:variable>
    <xsl:if test="$fNaryArgument=0">
      <xsl:call-template name="MPhantom">
        <xsl:with-param name="ndCur" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="MPhantom">
    <xsl:param name="ndCur" select="." />
    <xsl:element name="m:phant">
      <xsl:call-template name="CreatePhantProperties">
        <xsl:with-param name="ndCur" select="$ndCur" />
        <xsl:with-param name="fShow" select="0" />
      </xsl:call-template>
      <m:e>
        <xsl:apply-templates select="$ndCur/*" />
      </m:e>
    </xsl:element>
  </xsl:template>

  <xsl:template name="isNaryOper">
    <xsl:param name="sNdCur" />
    <xsl:value-of select="($sNdCur = '&#x222B;' 
                            or $sNdCur = '&#x222C;' 
                            or $sNdCur = '&#x222D;' 
                            or $sNdCur = '&#x222E;' 
                            or $sNdCur = '&#x222F;' 
                            or $sNdCur = '&#x2230;' 
                            or $sNdCur = '&#x2232;' 
                            or $sNdCur = '&#x2233;' 
                            or $sNdCur = '&#x2231;' 
                            or $sNdCur = '&#x2229;' 
                            or $sNdCur = '&#x222A;' 
                            or $sNdCur = '&#x220F;' 
                            or $sNdCur = '&#x2210;' 
                            or $sNdCur = '&#x2211;' 
                            or $sNdCur = '&#x22C0;' 
                            or $sNdCur = '&#x22C1;' 
                            or $sNdCur = '&#x22C2;' 
                            or $sNdCur = '&#x22C3;'
                            or $sNdCur = '&#x22C3;'
                            or $sNdCur = '&#x2140;'
                            or $sNdCur = '&#x2A0B;'
                            or $sNdCur = '&#x2A00;'
                            or $sNdCur = '&#x2A02;'
                            or $sNdCur = '&#x2A09;'
                            or $sNdCur = '&#x22CF;'
                            or $sNdCur = '&#x22CE;'
                            or $sNdCur = '&#x2A53;'
                            or $sNdCur = '&#x2A54;'
                            or $sNdCur = '&#x2A44;'
                            or $sNdCur = '&#x2A45;'
                            or $sNdCur = '&#x2A0C;'
                            or $sNdCur = '&#x2A0D;'
                            or $sNdCur = '&#x2A0E;'
                            or $sNdCur = '&#x2A0F;'
                            or $sNdCur = '&#x2A10;'
                            or $sNdCur = '&#x2A11;'
                            or $sNdCur = '&#x2A12;'
                            or $sNdCur = '&#x2A13;'
                            or $sNdCur = '&#x2A14;'
                            or $sNdCur = '&#x2A15;'
                            or $sNdCur = '&#x2A16;'
                            or $sNdCur = '&#x2A17;'
                            or $sNdCur = '&#x2A18;'
                            or $sNdCur = '&#x2A19;'
                            or $sNdCur = '&#x2A1A;'
                            or $sNdCur = '&#x2A1B;'
                            or $sNdCur = '&#x2A1C;'
                            )" />                            
  </xsl:template>


  <xsl:template name="isNary">
    <!-- ndCur is the element around the nAry operator -->
    <xsl:param name="ndCur" />
    <xsl:variable name="sNdCur">
      <xsl:value-of select="normalize-space($ndCur)" />
    </xsl:variable>

    <xsl:variable name="fNaryOper">
      <xsl:call-template name="isNaryOper">
        <xsl:with-param name="sNdCur" select="$sNdCur" />
      </xsl:call-template>
    </xsl:variable>

    <!-- Narys shouldn't be MathML accents.  -->
    <xsl:variable name="fUnder">
      <xsl:choose>
        <xsl:when test="$ndCur/parent::*[self::mml:munder]">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="sLowerCaseAccent">
      <xsl:choose>
        <xsl:when test="$fUnder=1">
          <xsl:choose>
            <xsl:when test="$ndCur/parent::*[self::mml:munder]/@accentunder">
              <xsl:value-of select="translate($ndCur/parent::*[self::mml:munder]/@accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/parent::*[self::mml:munder]/@mml:accentunder, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:when>
        <xsl:otherwise>
          <xsl:choose>
            <xsl:when test="$ndCur/parent::*/@accent">
              <xsl:value-of select="translate($ndCur/parent::*/@accent, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:when>
            <xsl:otherwise>
              <xsl:value-of select="translate($ndCur/parent::*/@mml:accent, $StrUCAlphabet, $StrLCAlphabet)"/>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:variable name="fAccent">
      <xsl:choose>
        <xsl:when test="$sLowerCaseAccent='true'">1</xsl:when>
        <xsl:otherwise>0</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <xsl:choose>
      <!-- This ndCur is in fact part of an nAry if
      
           1)  The last descendant of ndCur (which could be ndCur itself) is an operator.
           2)  Along that chain of descendants we only encounter mml:mo, mml:mstyle, and mml:mrow elements.
           3)  the operator in mml:mo is a valid nAry operator
           4)  The nAry is not accented.
           -->
      <xsl:when test="$fNaryOper = 'true'
                      and $fAccent=0
                      and $ndCur/descendant-or-self::*[last()]/self::mml:mo
                      and not($ndCur/descendant-or-self::*[not(self::mml:mo or 
			                                                     self::mml:mstyle or 
			                                                     self::mml:mrow)])">
        <xsl:value-of select="true()" />
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="false()" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template name="CreateNaryProp">
    <xsl:param name="chr" />
    <xsl:param name="sMathmlType" />
    <xsl:param name="sGrow">
      <xsl:choose>
        <xsl:when test="child::*[1]/@stretchy">
          <xsl:value-of select="translate(child::*[1]/@stretchy, $StrUCAlphabet, $StrLCAlphabet)"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="translate(child::*[1]/@mml:stretchy, $StrUCAlphabet, $StrLCAlphabet)"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:param>
    <m:naryPr>
      <m:chr>
        <xsl:attribute name="m:val">
          <xsl:value-of select="$chr" />
        </xsl:attribute>
      </m:chr>
      <m:limLoc>
        <xsl:attribute name="m:val">
          <xsl:choose>
            <xsl:when test="$sMathmlType='munder' or 
									$sMathmlType='mover' or 
									$sMathmlType='munderover'">
              <xsl:text>undOvr</xsl:text>
            </xsl:when>
            <xsl:when test="$sMathmlType='msub' or
					                $sMathmlType='msup' or
					                $sMathmlType='msubsup'">
              <xsl:text>subSup</xsl:text>
            </xsl:when>
          </xsl:choose>
        </xsl:attribute>
      </m:limLoc>
      <m:grow>
        <xsl:attribute name="m:val">
          <xsl:choose>
            <xsl:when test="$sGrow='true'">1</xsl:when>
            <xsl:when test="$sGrow='false'">0</xsl:when>
            <xsl:when test="$chr='&#x222B;' 
                            or $chr='&#x222E;' 
                            or $chr='&#x222F;' 
                            or $chr='&#x2232;' 
                            or $chr='&#x2233;'
                            or $chr='&#x2229;'
                            or $chr='&#x222A;' 
                            or $chr='&#x220F;' 
                            or $chr='&#x2211;' 
                            or $chr='&#x22C0;'
                            or $chr='&#x22C1;' 
                            or $chr='&#x22C2;'
                            or $chr='&#x22C3;'">1</xsl:when>
            <xsl:otherwise>0</xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
      </m:grow>
      <m:subHide>
        <xsl:attribute name="m:val">
          <xsl:choose>
            <xsl:when test="$sMathmlType='mover' or
						                $sMathmlType='msup'">
              <xsl:text>on</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:text>off</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
      </m:subHide>
      <m:supHide>
        <xsl:attribute name="m:val">
          <xsl:choose>
            <xsl:when test="$sMathmlType='munder' or
						                $sMathmlType='msub'">
              <xsl:text>on</xsl:text>
            </xsl:when>
            <xsl:otherwise>
              <xsl:text>off</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
        </xsl:attribute>
      </m:supHide>
    </m:naryPr>
  </xsl:template>
</xsl:stylesheet>Tx """
工具模块
"""

y	#x<100644 __init__.cpython-310.pyc >?fR100644 __init__.cpython-312.pyc >yU]Ap`ipO*2100644 function_tracker.cpython-310.pyc F	}Cv\(D100644 function_tracker.cpython-312.pyc lq-H|Q6([100644 image_utils.cpython-312.pyc ܸ/ֹÍ87tfT5100644 intent_matcher.cpython-312.pyc I߽#Ep47&.:(100644 pdf_generator.cpython-310.pyc ы2\:uRrM100644 ship_number_search.cpython-312.pyc ыԺY#5Mw]p100644 word_generator.cpython-310.pyc };Nѡ{RיL100644 word_generator.cpython-312.pyc X9hKRqrq,ZZ %/ +c۰	x oo
    li                      @   s   d Z dS )u   
工具模块
N)__doc__ r   r   /app/utils/__init__.py<module>   s    T"x <
    бMj                          d Z y)u   
工具模块
N)__doc__     @e:\ZKYNLP\Hjunproject\project0506\wx-agent\app\utils\__init__.py<module>r      s
   r   6x$o
    li}0                     @   sz  U d Z ddlZddl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 ejdddZeje
e  ed< ejd	ddZeje	e  ed
< deeeef gdf fddZdeeeef gdf fddZdd Zdd ZdedefddZdedefddZdedefddZdeeef fddZG d d! d!Zdeeejf fd"d#Zde	e fd$d%Zd&d' Z dS )(ui   
使用装饰器实现全栈函数调用追踪
解决LangGraph无法捕获子函数内部状态的问题
    N)CallableAnyDictOptionalList)datetime)dequeevent_callbacks)default_event_callbackscurrent_stream_handler_current_stream_handlercallbackc                 C   s,   t  }|du rg }t | ||  dS )uM   
    注册事件回调函数（使用 contextvars 实现请求隔离）
    N)r   getsetappendr   	callbacks r   /app/utils/function_tracker.pyregister_event_callback   s
   
r   c                 C   s*   t  }|r| |v r||  dS dS dS )uM   
    移除事件回调函数（使用 contextvars 实现请求隔离）
    N)r   r   remover   r   r   r   unregister_event_callback   s   r   c                  C   s   t  } | r|   dS dS )uM   
    清空所有事件回调（使用 contextvars 实现请求隔离）
    N)r   r   clearr   r   r   r   clear_event_callbacks(   s   r   c                  C   s   t  } | r
|  S g S )uV   
    获取所有注册的回调函数（使用 contextvars 实现请求隔离）
    )r   r   copyr   r   r   r   get_all_callbacks1   s   r   funcreturnc                 C   sB   | j r| j  }|dd  }t|dkr|dd S |S dS )uL   
    提取函数的描述（docstring的第一行或前100个字符）
    
r   d   N )__doc__stripsplitlen)r   doc
first_liner   r   r   extract_function_description9   s
   
r)   resultc                    s   d}| s|S t | trMdD ]}|| v r+| | dur+t| |  }|r+t| |   S q|  D ]\}}d| v rL|durLt| }|rLt|  S q0dtdtfdd dd
tdtdt	t f fdd| }|ro|S |S )u  
    从函数返回值中提取 details，顺序固定为：先 details 再中文。
    1) 先看返回的 dict 里是否有「details 类」字段（__details__、_details、details 或键名含 "details"），
       且其值为非空，则用该值；
    2) 若没有或为空，再走原本的中文兜底：从返回结构中找一段包含中文的内容作为 details。
    u   完成)__details___detailsdetailsNr-   textr   c                 S   s   | sdS t dd t| D S )NFc                 s   s(    | ]}d |  kodkn  V  qdS )u   一u   鿿Nr   ).0cr   r   r   	<genexpr>a   s   & zJ_extract_details_from_result.<locals>._contains_chinese.<locals>.<genexpr>)anystr)r.   r   r   r   _contains_chinese^   s   z7_extract_details_from_result.<locals>._contains_chinese   obj
max_lengthc                    s   t | tr | rt| |kr| d | d S  | r| S d S t | tr?|  D ]\}}d| v r3q(||}|r>|  S q(t | trT| D ]}||}|rS|  S qFd S )Nz...r-   )
isinstancer3   r&   dictitemslowerlist)r6   r7   keyvaluefounditemr4   _find_chineser   r   rB   c   s*   
$




z3_extract_details_from_result.<locals>._find_chinese)r5   )
r8   r9   r3   r$   r:   r;   boolr   intr   )r*   r
   r=   skvchineser   rA   r   _extract_details_from_resultE   s(   
"rI   c                    s>   t   fdd}t   fdd}t r|S |S )u|   
    装饰器：追踪函数调用过程，支持同步和异步函数
    
    Args:
        func: 被装饰的函数
    c                     s  t  }|j| i |}|   j} j}d }| r't| d tr'| d }nd|jv r2|j	d}t
 }dd |j D }zD | i |}	t|	}
d||
|	t  d}t	 p]g }|D ]!}z|| W q` ty } ztd|  W Y d }~q`d }~ww |	W S  ty } z;d|d	t| t  d
}t	 pg }|D ]!}z|| W q ty } ztd|  W Y d }~qd }~ww  d }~ww )Nr   statec                 S      i | ]\}}||qS r   r   r/   rF   rG   r   r   r   
<dictcomp>       z>track_function_calls.<locals>.sync_wrapper.<locals>.<dictcomp>function_executiontypetitler-   r*   	timestamp   回调执行出错: function_error   错误: rQ   rR   r-   rS   inspect	signaturebindapply_defaults__name__
__module__r8   r9   	argumentsr   r)   r:   rI   r   now	isoformatr   	Exceptionprintr3   argskwargssig
bound_args	func_namemodule_namerJ   func_descriptionparamsr*   r-   execution_eventr   r   eerror_eventexr   r   r   sync_wrapper   s^   



	
z*track_function_calls.<locals>.sync_wrapperc                     s  t  }|j| i |}|   j} j}d }| r(t| d tr(| d }nd|jv r3|j	d}t
 }dd |j D }zG | i |I d H }	t|	}
d||
|	t  d}t	 pag }|D ]!}z|| W qd ty } ztd|  W Y d }~qdd }~ww |	W S  ty } z;d|d	t| t  d
}t	 pg }|D ]!}z|| W q ty } ztd|  W Y d }~qd }~ww  d }~ww )Nr   rJ   c                 S   rK   r   r   rL   r   r   r   rM      rN   z?track_function_calls.<locals>.async_wrapper.<locals>.<dictcomp>rO   rP   rT   rU   rV   rW   rX   rd   rq   r   r   async_wrapper   s`   



	
z+track_function_calls.<locals>.async_wrapper)	functoolswrapsasyncioiscoroutinefunction)r   rr   rs   r   rq   r   track_function_callsy   s   A
Brx   eventc                 C   s   | d }|  dd}|  dd}|dkr(td|  |r&td|  d
S d
S |dkr>td	|  |r@td|  d
S d
S d
S )u"   
    控制台事件处理器
    rQ   rR   r"   r-   rO   u   ✅ 函数执行: u      详情: rU   u   ❌ 函数错误: N)r   rc   )ry   
event_typerR   r-   r   r   r   console_event_handler  s   r{   c                   @   sJ   e Zd ZdZdejfddZdeee	f fddZ
dd	ed
efddZdS )StreamEventHandleruU   
    流式事件处理器，将装饰器事件放入队列供流式输出使用
    queuec                 C   s
   || _ d S )N)r}   )selfr}   r   r   r   __init__$  s   
zStreamEventHandler.__init__ry   c              
   C   sV   zz
| j | W W dS  tjy   Y W dS w  ty* } zW Y d}~dS d}~ww )u   
        处理事件，将事件放入队列
        注意：这是同步方法，但队列是异步的，需要特殊处理
        N)r}   
put_nowaitrv   	QueueFullrb   )r~   ry   rn   r   r   r   __call__'  s   zStreamEventHandler.__call__r"   contentrR   c              
   C   sP   zd||t   d}| j| W dS  ty' } zW Y d}~dS d}~ww )u   
        发送流式内容事件
        
        Args:
            content: 流式内容片段
            title: 函数描述/标题（可选）
        stream_content)rQ   r   rR   rS   N)r   r`   ra   r}   r   rb   )r~   r   rR   ry   rn   r   r   r   send_stream_content8  s   
z&StreamEventHandler.send_stream_contentN)r"   )r]   r^   __qualname__r#   rv   Queuer   r   r3   r   r   r   r   r   r   r   r|      s
    r|   c                  C   s&   t jdd} t| }t| || fS )u   
    创建流式事件处理器和对应的队列（使用 contextvars 实现请求隔离）
    
    Returns:
        (handler, queue): 事件处理器和事件队列
    i  )maxsize)rv   r   r|   r   r   )r}   handlerr   r   r   create_stream_event_handlerM  s   
r   c                   C   s   t  S )u   
    获取当前活动的流式事件处理器（使用 contextvars 实现请求隔离）
    
    Returns:
        当前流式事件处理器，如果没有则返回 None
    )r   r   r   r   r   r   get_current_stream_handlerZ  s   r   c                   C   s   t d dS )u_   
    清除当前活动的流式事件处理器（使用 contextvars 实现请求隔离）
    N)r   r   r   r   r   r   clear_current_stream_handlerd  s   r   )!r#   rt   rY   rv   contextvarstypingr   r   r   r   r   r   collectionsr   
ContextVarr   __annotations__r   r3   r   r   r   r   r)   rI   rx   r{   r|   tupler   r   r   r   r   r   r   r   <module>   s2       		4 -
dxi7
    бMj}0                        U d Z ddlZddl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  ej                  dd      Zej                  e
e      ed<    ej                  d	d      Zej                  e	e      ed
<   deeeef   gdf   fdZdeeeef   gdf   fdZd Zd ZdedefdZdedefdZdedefdZdeeef   fdZ G d d      Zdeeej:                  f   fdZde	e   fdZd Z y)ui   
使用装饰器实现全栈函数调用追踪
解决LangGraph无法捕获子函数内部状态的问题
    N)CallableAnyDictOptionalList)datetime)dequeevent_callbacks)default_event_callbackscurrent_stream_handler_current_stream_handlercallbackc                     t         j                         }|g }t         j                  |       |j                  |        y)uM   
    注册事件回调函数（使用 contextvars 实现请求隔离）
    N)r   getsetappendr   	callbackss     He:\ZKYNLP\Hjunproject\project0506\wx-agent\app\utils\function_tracker.pyregister_event_callbackr      s9     !$$&I	Y'X    c                 ^    t         j                         }|r| |v r|j                  |        yyy)uM   
    移除事件回调函数（使用 contextvars 实现请求隔离）
    N)r   r   remover   s     r   unregister_event_callbackr      s1     !$$&IX*" +yr   c                  R    t         j                         } | r| j                          yy)uM   
    清空所有事件回调（使用 contextvars 实现请求隔离）
    N)r   r   clearr   s    r   clear_event_callbacksr   (   s$     !$$&I r   c                  R    t         j                         } | r| j                         S g S )uV   
    获取所有注册的回调函数（使用 contextvars 实现请求隔离）
    )r   r   copyr   s    r   get_all_callbacksr"   1   s&     !$$&I(9>>0b0r   funcreturnc                     | j                   rQ| j                   j                         }|j                  d      d   j                         }t        |      dkD  r|dd S |S y)uL   
    提取函数的描述（docstring的第一行或前100个字符）
    
r   d   N )__doc__stripsplitlen)r#   doc
first_lines      r   extract_function_descriptionr/   9   sX     ||ll  "YYt_Q'--/
#&z?S#8z$3HjHr   resultc                    d}| s|S t        | t              rdD ];  }|| v s| |   t        | |         j                         }|s-t        | |         c S  | j	                         D ]C  \  }}d|j                         v s|t        |      j                         }|s8t        |      c S  dt        dt        fdd
dt        dt        dt        t           ffd	 |       }|r|S |S )u  
    从函数返回值中提取 details，顺序固定为：先 details 再中文。
    1) 先看返回的 dict 里是否有「details 类」字段（__details__、_details、details 或键名含 "details"），
       且其值为非空，则用该值；
    2) 若没有或为空，再走原本的中文兜底：从返回结构中找一段包含中文的内容作为 details。
    u   完成)__details___detailsdetailsr4   textr$   c                 >    | syt        d t        |       D              S )NFc              3   <   K   | ]  }d |cxk  xr dk  nc   yw)u   一u   鿿N ).0cs     r   	<genexpr>zJ_extract_details_from_result.<locals>._contains_chinese.<locals>.<genexpr>a   s     @i8q,H,,is   )anystr)r5   s    r   _contains_chinesez7_extract_details_from_result.<locals>._contains_chinese^   s    @c$i@@@r   obj
max_lengthc                 Z   t        | t              r* |       rt        |       |kD  r| d | dz   S  |       r| S d S t        | t              r:| j	                         D ]'  \  }}d|j                         v r ||      }|s%|c S  t        | t              r| D ]  } ||      }|s|c S  y )Nz...r4   )
isinstancer=   r,   dictitemslowerlist)r?   r@   keyvaluefounditemr>   _find_chineses         r   rK   z3_extract_details_from_result.<locals>._find_chinesec   s    c31B31GCPSHWaLaC$u, 9(-9379c4 !iik
U		+%eZ8 L * c4 %dJ7 L  r   )   )
rB   rC   r=   r*   rD   rE   boolr   intr   )	r0   r   rG   skvchineser>   rK   s	          @@r   _extract_details_from_resultrS   E   s     G &$9Cf}!8s$**,vc{++	 :
 LLNDAqAGGI%!-FLLNq6M	 #A A A
3 C (3- $ F#G7*7*r   c                      t        j                          fd       }t        j                          fd       }t        j                         r|S |S )u|   
    装饰器：追踪函数调用过程，支持同步和异步函数
    
    Args:
        func: 被装饰的函数
    c                     t        j                        } |j                  | i |}|j                          j                  }j
                  }d }| rt        | d   t              r| d   }n)d|j                  v r|j                  j                  d      }t              }|j                  j                         D 	ci c]  \  }}	||	
 }
}}		  | i |}t        |      }d|||t        j                         j                         d}t         j                         xs g }|D ]  }	  ||        |S c c}	}w # t"        $ r}t%        d|        Y d }~2d }~ww xY w# t"        $ r}d|dt'        |       t        j                         j                         d}t         j                         xs g }|D ]/  }	  ||       # t"        $ r}t%        d|        Y d }~)d }~ww xY w  d }~ww xY w	Nr   statefunction_execution)typetitler4   r0   	timestampu   回调执行出错: function_erroru   错误: )rY   rZ   r4   r[   inspect	signaturebindapply_defaults__name__
__module__rB   rC   	argumentsr   r/   rD   rS   r   now	isoformatr   	Exceptionprintr=   argskwargssig
bound_args	func_namemodule_namerW   func_descriptionrP   rQ   paramsr0   r4   execution_eventr   r   eerror_eventexr#   s                      r   sync_wrapperz*track_function_calls.<locals>.sync_wrapper   s    %SXXt.v.
!!#MM	oo JtAw-GE
,,,((,,W5E7= $.#7#7#=#=#?@#?41a!Q$#?@*	4*6*F 36:G -)" %\\^557O ),,.4"I%6_- & M5 A. ! 604556
  	 ))%c!fX.%\\^557	K ),,.4"I%7[)  705667 & !	st   ?D5AE )D;1E ;	EEE EE 	G-(AG(9GG(	G#GG(G##G((G-c                    K   t        j                        } |j                  | i |}|j                          j                  }j
                  }d }| rt        | d   t              r| d   }n)d|j                  v r|j                  j                  d      }t              }|j                  j                         D 	ci c]  \  }}	||	
 }
}}		  | i | d {   }t        |      }d|||t        j                         j                         d}t         j                         xs g }|D ]  }	  ||        |S c c}	}w 7 g# t"        $ r}t%        d|        Y d }~4d }~ww xY w# t"        $ r}d|dt'        |       t        j                         j                         d}t         j                         xs g }|D ]/  }	  ||       # t"        $ r}t%        d|        Y d }~)d }~ww xY w  d }~ww xY wwrV   r]   ri   s                      r   async_wrapperz+track_function_calls.<locals>.async_wrapper   s
     %SXXt.v.
!!#MM	oo JtAw-GE
,,,((,,W5E7= $.#7#7#=#=#?@#?41a!Q$#?@*	000F 36:G -)" %\\^557O ),,.4"I%6_- & M5 A 1& ! 604556
  	 ))%c!fX.%\\^557	K ),,.4"I%7[)  705667 & !	s   B>G<D?G<E+ EAE+ 3E;E+ >G<E+ 	E(E#E+ #E((E+ +	G94AG4GG4	G/G*%G4*G//G44G99G<)	functoolswrapsasyncioiscoroutinefunction)r#   rv   rx   s   `  r   track_function_callsr}   y   s[     __T? ?B __T? ?D ""4(r   eventc                     | d   }| j                  dd      }| j                  dd      }|dk(  r t        d|        |rt        d|        y
y
|dk(  r t        d	|        |rt        d|        y
y
y
)u"   
    控制台事件处理器
    rY   rZ   r(   r4   rX   u   ✅ 函数执行: u      详情: r\   u   ❌ 函数错误: N)r   rh   )r~   
event_typerZ   r4   s       r   console_event_handlerr     s     vJIIgr"Eii	2&G))"5'*+Ky)*  
'	'"5'*+Ky)*  
(r   c                   X    e Zd ZdZdej
                  fdZdeee	f   fdZ
d
dedefdZy	)StreamEventHandleruU   
    流式事件处理器，将装饰器事件放入队列供流式输出使用
    queuec                     || _         y )N)r   )selfr   s     r   __init__zStreamEventHandler.__init__$  s	    
r   r~   c                     	 	 | j                   j                  |       y# t        j                  $ r Y yw xY w# t        $ r
}Y d}~yd}~ww xY w)u   
        处理事件，将事件放入队列
        注意：这是同步方法，但队列是异步的，需要特殊处理
        N)r   
put_nowaitr{   	QueueFullrg   )r   r~   rs   s      r   __call__zStreamEventHandler.__call__'  sJ    

	

%%e,$$   		s    58 58 	AAcontentrZ   c                     	 d||t        j                         j                         d}| j                  j	                  |       y# t
        $ r
}Y d}~yd}~ww xY w)u   
        发送流式内容事件
        
        Args:
            content: 流式内容片段
            title: 函数描述/标题（可选）
        stream_content)rY   r   rZ   r[   N)r   re   rf   r   r   rg   )r   r   rZ   r~   rs   s        r   send_stream_contentz&StreamEventHandler.send_stream_content8  sP    
	("%\\^557	E JJ!!%( 		s   AA 	AAN)r(   )rb   rc   __qualname__r)   r{   Queuer   r   r=   r   r   r   r8   r   r   r   r      s>    gmm d38n "3 s r   r   c                  v    t        j                  d      } t        |       }t        j	                  |       || fS )u   
    创建流式事件处理器和对应的队列（使用 contextvars 实现请求隔离）
    
    Returns:
        (handler, queue): 事件处理器和事件队列
    i  )maxsize)r{   r   r   r   r   )r   handlers     r   create_stream_event_handlerr   M  s4     MM$'E 'G(E>r   c                  *    t         j                         S )u   
    获取当前活动的流式事件处理器（使用 contextvars 实现请求隔离）
    
    Returns:
        当前流式事件处理器，如果没有则返回 None
    )r   r   r8   r   r   get_current_stream_handlerr   Z  s     #&&((r   c                  .    t         j                  d       y)u_   
    清除当前活动的流式事件处理器（使用 contextvars 实现请求隔离）
    N)r   r   r8   r   r   clear_current_stream_handlerr   d  s     %r   )!r)   ry   r^   r{   contextvarstypingr   r   r   r   r   r   collectionsr	   
ContextVarr   __annotations__r   r=   r   r   r   r"   r/   rS   r}   r   r   tupler   r   r   r   r8   r   r   <module>r      s_  
     6 6   <R;;Q;QRcmq;r +((h8 rAWAWAWXp`dBf //> fhS#X/?/E&F #$sCx.1A41G(H #1	x 	C 	1+ 1+ 1+hPx PH Ph+c3h +&* *Z
U+=w}}+L%M 
)H-?$@ )&r   sx{
    ѱMj              	           d Z ddlZddlmZ ddlmZ dedee   fdZded	ee   defd
Zddeded	ee   defdZ	dededefdZ
deded	ee   defdZdefdZy)u=  
图片处理工具模块 - 最终版 v4
核心思路（最简单直接）：
1. 找到所有 .jpg/.png 文件名及其周围的 ![图片]( 上下文
2. 不管周围格式如何，也不管文件名是否被模型改过
3. 统一提取文件名 -> 与 original_paths 模匹 -> 替换成正确的 ![图片](完整URL)
    N)List)SequenceMatchertextreturnc                 x    d}t        j                  || t         j                        }t        t	        |            S )u   从文本中提取图片路径z7images/[a-zA-Z0-9_\-./]+\.(?:jpg|jpeg|png|gif|bmp|webp))refindall
IGNORECASElistset)r   patternmatchess      Ce:\ZKYNLP\Hjunproject\project0506\wx-agent\app\utils\image_utils.pyextract_image_pathsr      s,    HGjj$6GG    generated_pathoriginal_pathsc                    |s| S | j                  d      d   j                         }d}d}|D ]I  }|j                  d      d   j                         }t        d||      j                         }||kD  sF|}|}K |r|dkD  r|S | S )u   
    找到与生成路径最接近的原始图片路径
    
    即使模型输出的是错误/近似/截断的文件名，也能匹配到正确的原始路径
    /Nr         ?)splitlowerr   ratio)r   r   generated_filename
best_match
best_score	orig_pathorig_filenamescores           r   find_closest_image_pathr!      s     '--c226<<>JJ#	!,R0668&8-HNNP:J"J $ j3&r   base_prefixc                 D    | r|| S t        | |      }t        |||      }|S )u.  
    规范化 Markdown 图片链接 - 两轮处理版
    
    算法：
    第一轮：检查和修改格式，确保是 ![图片](/api/v1/knowledge/files/images/xxx.jpg) 格式
    第二轮：只检查和替换最后文件名部分（xxx.jpg），与原始路径匹配，匹配度低的删除
    )_normalize_image_format_normalize_image_paths)r   r"   r   results       r   normalize_markdown_imagesr'   -   s4     >) %T;7F $FKHFMr   c                 n   | s| S d}d| d}| }t        t        j                  ||t        j                              }|s|S t	        |      D ]  }|j                  d      }|j                         }|j                         }	|}
|	}t        d|dz
        }||| }|j                  d      }|dk7  r||z   }||| }|j                  d      r|}
||	d }|j                  d      }|dk7  r|d	k  r|d| }d
|vrd|vr|	|z   dz   }|j                  d      d   }|j                  d      dz   |z   }d| d}|d|
 |z   ||d z   } d}t        j                  ||t        j                        rMt        j                  |d|t        j                        }t        j                  ||t        j                        rM|S )u   
    第一轮：规范化图片格式，确保所有图片都是正确的 ![图片](/api/v1/knowledge/files/images/xxx.jpg) 格式
    
    处理各种格式破损的情况，并确保有正确的URL前缀
    z(?:jpg|jpeg|png|gif|bmp|webp)z([a-zA-Z0-9_\-./]+)\.()r   d   
   ![图片](r   N   
   r   /images/uN   !\[图片\]\([^)]*!\[图片\]\(([^)]+\.(?:jpg|jpeg|png|gif|bmp|webp))\)[^)]*\)u   ![图片](\1))flags)r   r   finditerr
   reversedgroupstartendmaxrfind
startswithfindr   rstripsearchsub)r   r"   IMG_EXTENSIONSimg_patternr&   r   matchfilename_with_ext
file_startfile_end
mark_startmark_endlookback_limitbeforeopen_marker_posactual_open_poscheck_segmentafterclose_paren_posmiddlepure_filenamefull_urlstandard_formatnested_patterns                           r   r$   r$   A   s    5N+N+;1=KF2;;{FBMMBCG '"!KKN[[]
99;
 Q
S 01z2 ,,|4b ,>O"?:>M''5,
 xy!**S/b _r%9+O,F6!l&&@#o59 *//4R8 %%c*Z7-G&xj2$6	9JJE #J gN
))NFBMM
:(8&V ))NFBMM
: Mr   c                    | r|s| S d}t        t        j                  || t        j                              }|s| S | }t	        |      D ]  }|j                  d      }|j                  d      }|j                         }	|j                         }
|j                  d      d   }d}d}|j                         }|D ]I  }|j                  d      d   j                         }t        d||      j                         }||kD  sF|}|}K |rF|dkD  rA|j                  d      d   }|j                  d      dz   |z   }d	| d
}|d|	 |z   ||
d z   }|d|	 ||
d z   } |S )u  
    第二轮：只规范化最后文件名部分（xxx.jpg），与原始路径匹配，匹配度低的删除
    
    步骤：
    1. 找到所有 ![图片](URL) 格式的图片
    2. 对每个图片：
       a. 提取最后文件名部分（xxx.jpg）
       b. 只与 original_paths 中的最后文件名部分匹配
       c. 如果匹配度高（>0.5），替换为正确路径
       d. 如果匹配度低（<=0.5），删除整个图片
    u   !\[图片\]\(([^)]+)\)r   r.   r   r   Nr   r/   r+   r)   )r   r   r1   r
   r2   r3   r4   r5   r   r   r   r   r:   )r   r"   r   img_tag_patternr   r&   r?   full_tagurl	tag_starttag_endfilenamer   r   r   r   r   r    pure_orig_filenamerN   rO   s                        r   r%   r%      s    ~ 0O2;;bmmDEGF '";;q>kk!nKKM	))+ 99S>"% 

%^^-'I%OOC04::<M#D*<mLRRTEz!"
&
 ( *s* ",!1!1#!6r!:"))#.;>PPH *8*A6OJY'/9F78<LLF JY'&*::FA #D Mr   c                       y)u*   获取图片格式处理的提示词指导u?  【图片格式特别要求】
- 检索结果中的图片链接格式通常为：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`
- 输出时必须严格保留此格式，不得修改、省略或截断
- 图片的 alt 文本必须保持为「图片」
- 图片 URL 必须完整包含 `/api/v1/knowledge/files/images` 前缀
- 不要将图片链接转换为纯文本描述
- 如果有多个图片，在对应位置分别引用，保持原始顺序
- 严禁修改图片文件名或路径结构
- 如果需要展示图片，直接使用原始的 `![图片](URL)` 格式即可 rZ   r   r   get_image_prompt_guidancer[      s    Tr   )z/api/v1/knowledge/files/N)__doc__r   typingr   difflibr   strr   r!   r'   r$   r%   r[   rZ   r   r   <module>r`      s    
  #c d3i C c s 2C c hlmphq   ~A (<# <C <C <~; ;3 ;S	 ;VY ;|
T3 
Tr   }&xB
    ѱMjW                     p    U d Z ddlmZmZ g dZee   ed<   daeeee         ed<   ddZ	dd	ed
ede
fdZy)u  
意图匹配工具：基于关键词 + embedding 语义相似度的两层确认意图判断

策略：
  第一层：关键词子串匹配（零延迟，覆盖 90%+ 常见表达）
  第二层：embedding 语义相似度匹配（兜底，捕获罕见/创意表达）
    )ListOptional)u   确认u   是的u   对u   好的u	   没问题u   行u   可以OKu   足够u   够了u   齐了u   信息完整u   不用补充u   不需要补充u	   就这些u	   没有了u   信息够了u   不用再加了u   信息齐了u   开始诊断u   开始操作u	   开始吧u   继续u   开始u   确认并继续u   正确u   没错u   对的u   是的开始u	   就这样CONFIRM_PHRASESN_phrase_embeddingsreturnc                     K   t         yddlm}  | j                  t               d{   a t        dt        t               d       y7 !w)uV   确保确认短语的 embedding 已预计算（懒加载，仅首次调用时执行）Nr   	OpenaiAPIu>   [intent_matcher] 确认短语 embedding 预计算完成，共 u    条)r   modelsAPI.model_apir   get_embeddings_batch_asyncr   printlenr
   s    Fe:\ZKYNLP\Hjunproject\project0506\wx-agent\app\utils\intent_matcher.py_ensure_phrase_embeddingsr      sG      %-(CCOTT	J3K_J``d
ef Us   &AA
"A
user_query	thresholdc           	         K    r j                         syt         fdt        D              ryt                d{    ddlm} |j                          d{   }|j                  |t              }|rt        |      nd}||k\  r/t        |j                  |         }t        d|dd	| d
  d       yy7 }7 `w)u   
    判断用户输入是否为确认意图

    Args:
        user_query: 用户输入文本
        threshold: embedding 语义相似度阈值（默认 0.78）

    Returns:
        True 表示用户表达了确认/信息充足的意图
    Tc              3   &   K   | ]  }|v  
 y w)N ).0kwr   s     r   	<genexpr>z)is_confirmation_intent.<locals>.<genexpr>7   s     
6o2os   Nr   r
   g        u-   [intent_matcher] embedding 兜底命中: sim=z.3fz, matched='z
', query=''F)stripanyr   r   r   r   get_embeddings_asynccosine_similarity_batchr   maxindexr   )r   r   r   query_embeddingsimilaritiesmax_simmatched_phrases   `      r   is_confirmation_intentr%   (   s      Z--/ 
6o
66 $
%%%-%:::FFO44_FXYL#/c,SG)(););G)DE=gc] K()J<qB 	C & Gs"   :B?B;B?B=AB?=B?)r   N)g(\?)__doc__typingr   r   r   str__annotations__r   floatr   boolr%   r       r   <module>r-      s\    "

c 
 37 HT$u+./ 6g S  U  d  r,   syxko
    6vti                  	   @   s   d dl Z d dlZd dlZd dlZd dlmZ G dd dZdd Z		dded	ed
edefddZ	e
dkrkdZe	eddZed r`eded   eded   edeed   dS eded   dS dS )    N)datetimec                   @   sF   e Zd ZdZddefddZ			dd	ed
edededef
ddZdS )PDFGeneratoru    PDF 生成器类（Pandoc 版）Noto Serif CJK SC	main_fontc                 C   s
   || _ dS )uy   
        初始化 PDF 生成器

        Args:
            main_font: Pandoc / XeLaTeX 使用的中文字体名
        N)r   )selfr    r   /app/utils/pdf_generator.py__init__   s   
zPDFGenerator.__init__N   维修报告Ttext_contentoutput_pathtitlereturn_base64returnc                 C   s  zz|du rt  d}d| d}tjddddd	}|j}|r+|d
| d ||  W d   n1 s<w   Y  d|ddd| j dddddddd|g}t	j
|dt	jt	jd d|d}	|rt|d}
t|
 d|	d< W d   n1 sw   Y  |	W W dt v rtj|rt| S S S  t	jy } z"d|jddW  Y d}~W dt v rtj|rt| S S S d}~w ty } z dt|dW  Y d}~W dt v rtj|rt| S S S d}~ww dt v rtj|rt| w w w )u  
        将 Markdown 文本内容生成 PDF 文件

        Args:
            text_content: Markdown 文本内容
            output_path: PDF 输出路径（可选）
            title: PDF 标题
            return_base64: 是否返回 base64 编码内容
        N%Y%m%d_%H%M%Stemp_report_.pdfwz.mdFutf-8)modesuffixdeleteencodingz# z

pandocz--pdf-engine=xelatexz-Vz	mainfont=zgeometry:margin=2cmzfontsize=10ptzlineskip=1.5z--template=template.texz-oT)checkstdoutstderr)success	file_pathrbbase64_contentmd_path)r   error)r   nowstrftimetempfileNamedTemporaryFilenamewritestripr   
subprocessrunPIPEopenbase64	b64encodereaddecodelocalsospathexistsremoveCalledProcessErrorr   	Exceptionstr)r   r   r   r   r   	timestampmd_filer!   cmdresultfer   r   r   generate_pdf_from_text   s   
z#PDFGenerator.generate_pdf_from_text)r   )Nr
   T)	__name__
__module____qualname____doc__r9   r	   booldictr@   r   r   r   r   r      s"    r   c                  C   sB   d} t dddd}||  W d   dS 1 sw   Y  dS )uD   创建一个用于中文排版的 LaTeX 模板（Pandoc 正确版）u  
\documentclass[10pt]{article}
\usepackage[UTF8]{ctex}
\usepackage{geometry}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{array}
\usepackage{booktabs}
\usepackage{longtable}
\usepackage{setspace}
\usepackage{fancyhdr}
\usepackage{titlesec}
\usepackage{tabularx}
\usepackage{makecell}
\usepackage{adjustbox}
\usepackage{hyperref}
% 页面设置
\geometry{margin=2cm}
\setlength{\parskip}{1em}
\setlength{\parindent}{0em}

% 字体
\setCJKmainfont{Noto Serif CJK SC}

% 标题样式
\title{\Large \textbf{$title$}}
\author{}
\date{}

% 章节标题样式
\titleformat{\section}{\large\bfseries\raggedright}{\thesection}{1em}{}
\titleformat{\subsection}{\normalsize\bfseries\raggedright}{\thesubsection}{1em}{}


% ===== Pandoc compatibility =====
\usepackage{hyperref}
\providecommand{\tightlist}{%
  \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}


\begin{document}

\maketitle

$body$

\end{document}
ztemplate.texr   r   )r   N)r-   r(   )templater>   r   r   r   create_latex_templatel   s   0"rH      未知设备report_contentdevice_name
output_dirr   c           	      C   s   t   t }t d}|dddd}| d| d}|r0tj|dd tj	||}n|}|j
| |d	dd
}|drD||d< |S )u    
    生成维修报告 PDF
    r    _/u   _维修报告_r   T)exist_oku   设备维修报告)r   r   r   r   r   	file_name)rH   r   r   r#   r$   replacer3   makedirsr4   joinr@   get)	rJ   rK   rL   	generatorr:   safe_device_namerQ   r   r=   r   r   r   generate_report_pdf   s$   	
rX   __main__u	  
三、根本原因判断

根据设备当前状态、维修方案参考和知识库检索结果，最可能的根本原因如下：

**根本原因**：缸盖密封环老化或失效  
**次级原因**：启动阀卡滞或内部泄漏

---

四、原因分析说明

1. **缸盖密封环老化或失效**
   - 缸盖密封环是气缸密封的关键部件，其老化或损坏会导致气缸压缩气体泄漏，压缩压力下降。
   - 启动时，压缩压力不足会导致点火困难，主机启动延迟或失败。
   - 此类问题在长期运行或未定期保养的设备中较为常见。

2. **启动阀卡滞或内部泄漏**
   - 启动阀的功能是控制启动气进入气缸，若其卡滞或内部泄漏，将导致启动气供应不足或不及时，影响启动成功率。
   - 内部泄漏还会造成启动气浪费，进一步降低启动成功率。
   - 启动阀若未定期维护，容易因灰尘、杂质或润滑不良而卡滞。

3. **气缸套磨损**
   - 气缸套磨损会导致气缸密封性下降，压缩气体泄漏，压缩压力不足。
   - 该问题通常发生在长期运行、润滑不良或未及时更换气缸套的设备中。

4. **活塞环磨损或断裂**
   - 活塞环磨损或断裂会导致气缸密封性下降，压缩气体泄漏，从而影响压缩压力。
   - 该问题通常与长期运行、润滑不良或材料疲劳有关。

5. **调速系统响应异常**
   - 调速系统异常可能导致主机启动时转速控制不稳，但其对压缩压力的影响相对较小，通常不是导致压缩压力不足的主要原因。

---

五、预防建议

1. 定期更换缸盖密封环
   - 根据设备运行时间和使用情况，制定合理的密封环更换计划，避免因老化导致密封性能下降。
   - 建议每运行 5000 小时进行一次检查，必要时更换。

2. 加强启动阀维护
   - 定期清理启动阀内部积碳和杂质，保持润滑良好。
   - 每 1000 小时进行一次功能测试。

3. 监控气缸套和活塞环状态
   - 通过内窥镜或压力测试定期检测气缸套与活塞环磨损情况。
   - 发现异常及时更换。

4. 优化润滑系统
   - 使用符合标准的润滑油，确保润滑充分。
   - 定期更换滤芯，防止杂质进入关键部件。

5. 定期校准调速系统
   - 每季度进行一次调速系统校准，确保响应灵敏。
   - 记录历史数据，建立趋势分析模型。
u   压缩机设备)rK   r   u   ✓ PDF 生成成功：rQ   u   ✓ 文件路径：r   u   ✓ Base64 长度：r    u   ✗ PDF 生成失败：r"   )rI   N)r3   r.   r*   r%   r   r   rH   r9   rF   rX   rA   test_mdr=   printlenr   r   r   r   <module>   s<    dC
&:p!	xH
    Nj[D                        U d Z ddlmZmZmZmZmZ ddlZddlZddl	Z	ddl
mZ ddlmZ ddlmZ ddlmZ ddlmZ daeeeef      ed	<   d
eeef   fdZded
ee   fdZded
efdZd
eeeeef   f   fdZdad
eeeeef   f   fdZ	 ddeded
eee   ee   eee      ef   fdZdedefdZ d Z!	 	 ddedede"ded
eeeeef      eeef   f
dZ#y)u   
舷号搜索策略模块
提供三级搜索策略：
1. 指定舷号搜索
2. 同型号所有舷号搜索
3. 全局搜索

新增功能：
- 智能舷号映射：支持舷号、舰名的智能识别和映射
    )ListDictAnyOptionalTupleN)get_all_callbacks)load_ship_model_mapping)
rag_search)	OpenaiAPI)KB_TREE_CONFIG_kb_name_to_id_cachereturnc                  R  	K   t         t         S t        j                  dd      } | st        d       i S ddddd	}	 t	        j
                  d
d      4 d{   }|j                  | |       d{   }|j                  dk7  r+t        d|j                          i cddd      d{    S |j                         }t        |t              r|}n_t        |t              rM|j                  d      xs |j                  d      xs i }t        |t              r|j                  dg       ng }ng }i 		fd |       	a 	cddd      d{    S 7 7 7 7 # 1 d{  7  sw Y   yxY w# t        $ r#}t        dt        |              i cY d}~S d}~ww xY ww)u   
    从知识库树 API 加载所有知识库，返回 {名称: kb_id} 的映射
    递归遍历树结构，带缓存，只请求一次
    Nurl u1   [ship_number_search] KB_TREE_CONFIG.url 未配置zapplication/json1testuseradmin)acceptz	x-user-idzx-user-namezx-roleg      >@F)timeoutverify)headers   u9   [ship_number_search] 知识库树 API 请求失败: HTTP datalistchildrenc                     | D ]k  }|j                  d      xs d}|j                  d      t        |j                  dd            nd}|r|r||<   |j                  dg       }|sd |       m y )Nnamer   idr   )getstr)nodesnodekb_namekb_idr   _collect
name_to_ids         /app/utils/ship_number_search.pyr&   z_load_kb_tree.<locals>._collectA   so    !D"hhv.4"G7;xx~7QCr 23WYE5.3
7+#xx
B7H * "    u/   [ship_number_search] 加载知识库树失败: )r   r   r    printhttpxAsyncClientstatus_codejson
isinstancer   dict	Exceptionr!   )
r   r   clientresponseresult	top_nodeskb_dataer&   r'   s
           @@r(   _load_kb_treer8      s     '##


UB
'CAB	 %!	G#$$T%@@F#ZZWZ==H##s*QRZRfRfQghi	 A@@ ]]_F&$'"	FD) **V,H

60BHb;Egt;TGKK
B7Z\		J+ Y#- ? A@@= A@@@@@  ?AxHI	s   9F'E8 EE8 E#4E5,E#!E8 -E.E8 2F'3BE#E8 E!E8 F'E8 E#E8 !E8 #E5)E,*E51E8 4F'5E8 8	F$FF$F'F$$F'ship_numberc                    K   | syt                d{   }| |v r||    S |j                         D ]6  \  }}t        j                  dt        j                  |        d|      s4|c S  y7 Ww)uT  
    根据舷号从知识库树中查找对应的真实 kb_id

    匹配策略：在知识库名称中查找包含该舷号的条目
    例如 ship_number="163"，知识库名称为 "163舰资料"，则匹配成功

    Args:
        ship_number: 舷号（如 "163"）

    Returns:
        匹配到的 kb_id，未找到返回 None
    Nz(?<!\d)z(?!\d))r8   itemsresearchescape)r9   r'   r$   r%   s       r(   resolve_kb_idr?   T   sr      $&Jj +&&$**,99		+ 67v>HL -  's   A-A+AA-%A-c                    K   t        |       j                         } t                d{   }d}|D ]  }|d   | k(  s|d   } n |r|D cg c]  }|d   |k(  s|d    c}S | gS 7 =c c}w w)u   
    根据舷号获取同型号的所有舷号

    Args:
        ship_number: 舷号

    Returns:
        list: 同型号的所有舷号列表，如果未找到则返回只包含输入舷号的列表
    Nhull_number
model_name)r!   stripr	   )r9   shipstarget_modelshipss        r(   get_ship_numbers_by_modelrH   p   s      k"((*K)++EL+--L  */S%Q1\?l3R- %SS= , Ts,   'A.A'A.A.A)A)!A.)A.c                  T  K   i } t                d{   }i }|D ]'  }|d   }||vrg ||<   ||   j                  |d          ) |D ]Z  }|d   }|d   }|j                  dd      }|j                  |g       }||j                         d}d|d|| |<   |sQd	|d|| |<   \ | S 7 w)
ur   
    构建舷号映射候选词库
    从每艘舰的记录中构建候选词，支持舷号和舰名匹配
    NrB   rA   	ship_namer   )modelnumbersnumber)typer9   r   )r	   appendr    copy)	
candidatesrD   model_numbersrF   rK   rA   rJ   rL   mapping_infos	            r(   _build_ship_mapping_candidatesrT      s     
 J)++E*,M\"%#%M% e##D$78	  \"=)HH["-	##E2. ||~
 &#
 #

; *% %Jy!% 0 C ,s   B(B&BB(B(c                  J   K   t         t                d{   a t         S 7 
w)u7   
    获取舷号映射候选词库（带缓存）
    N)_SHIP_MAPPING_CANDIDATESrT    r)   r(   get_ship_mapping_candidatesrX      s&     
  ')G)I#I ## $Js   #!#
user_inputsimilarity_thresholdc                   K   | r| j                         sy| j                         } t                d{   }| |v r.||    }d|d    }|d   }|d   }|j                  d      }||||fS 	 t        |j	                               }t        j                  |        d{   }	t        j                  |       d{   }
d}d}t        |
      D ]%  \  }}t        j                  |	|      }||kD  s"|}|}' ||k\  rL|d	k\  rG||   }||   }|d   }|d   }|j                  d      }t        d
|  d| d|dd|d    d	       |||dfS y7 7 7 # t        $ r!}t        dt        |              Y d}~yd}~ww xY ww)u  
    智能舷号映射函数
    将用户输入的舷号/舰名映射到准确的舷号或型号

    Returns:
        Tuple: (matched_ship_number, matched_model, all_numbers, match_type)
        - matched_ship_number: 匹配到的具体舷号（舰名也会映射到对应舷号）
        - matched_model: 匹配到的型号名称
        - all_numbers: 该型号下的所有舷号列表
        - match_type: 匹配类型 ("exact_number", "exact_name", "embedding", "none")
    )NNNnoneNexact_rN   rK   rL   r9   r   u   [智能映射] 用户输入 'u   ' -> 匹配到 'u   ' (相似度: z.3fu
   , 类型: )	embeddingu'   [智能映射] Embedding 匹配失败: )rC   rX   r    r   keysr   get_embeddings_asyncget_embeddings_batch_async	enumeratecosine_similarityr*   r1   r!   )rY   rZ   rQ   info
match_typerK   rL   r9   candidate_textsquery_embeddingcandidate_embeddings
best_scorebest_idxidxembscorematched_textr7   s                     r(   smart_ship_number_mappingrq      s     Z--/'!!#J244JZ*%d6l^,
Wy/hh}-E7J66Bz01 ) > >z JJ%.%I%I/%ZZ
!"67HC//EEz!"
	 8 --(a-*84Ll+DME9oG((=1K1*=Ml^[ijtuxiy  zD  EI  JP  EQ  DR  RS  T  Uw;; $M 5 KZ*  B7Ax@AA#Bsd   1E;E6E;+1E E
E 9E:4E /AE E;
E E 	E8E3.E;3E88E;titledetailsc                     d|  d|  d|  g}dt        j                  |      |d}t               D ]  }	  ||        y# t        $ r Y w xY w)u   发送搜索状态事件u   🔍 u   🔎 u   📚 function_execution)rN   rr   rs   N)randomchoicer   r1   )rr   rs   title_optionsstart_eventcallbacks        r(   send_search_statusr{      si    UG_eWougGM$}-K
 &'	[! (  		s   A	AAc                     | r| j                  dd      sg S | j                  di       }g }|j                         D ]  \  }}|D ]  }|j                  |         |S )u6   将 rag_search 的返回结果转换为原来的格式successFsourceCitation)r    r;   rO   )
rag_resultsource_citationflat_resultsresourcer;   items         r(   convert_rag_resultr     sd    Z^^Iu=	 nn%5r:OL*002%D%  3 r)   
base_querytop_ksearch_typec                   K   g }d}d}d}d}d}	d}
|rg|j                         rWt        dd| d       t        |       d{   \  }}}	}
|
dk7  rt        d| d| d	| d
|	 d|
 
       nt        d| d       |
dv r|rt	        |       d{   }|rt        dd| d       |  }	 t        |||       d{   }t        |      }|rt        d| dt        |       d       |D ]s  }t        |t              s|j                  dd      }|j                  dd      }|r|st        |      j                         }|sX|r[t        |      j                         }u ||||xs dfS nt        d| d       |
dv r|	rt        dd| ddj                  |	       d       |	D ]  }|  }	 t	        |       d{   }|st        |||       d{   }t        |      }|r|j                  |       t        d| dt        |       d       |sx|D ]s  }t        |t              s|j                  dd      }|j                  dd      }|r|st        |      j                         }|sX|r[t        |      j                         }u  |r
||||xs dfS |r`|j                         rO|
dk(  rIt	        |       d{   }|rt        dd| d       |  }	 t        |||       d{   }t        |      }|rt        d| dt        |       d       |D ]s  }t        |t              s|j                  dd      }|j                  dd      }|r|st        |      j                         }|sX|r[t        |      j                         }u ||||xs dfS nt        d| d        t        |       d{   }t        |      d!kD  st        |      d!k(  r ||vrt        d"d#dj                  |       d       |D ]  }||k(  r	|  }	 t	        |       d{   }|s#t        |||       d{   }t        |      }|r|j                  |       t        d| dt        |       d       |sx|D ]s  }t        |t              s|j                  dd      }|j                  dd      }|r|st        |      j                         }|sX|r[t        |      j                         }u  |r
||||xs dfS t        d$d%       	 t        | |&       d{   }t        |      }|rt        d't        |       d       |D ]s  }t        |t              s|j                  dd      }|j                  dd      }|r|st        |      j                         }|sX|r[t        |      j                         }u ||||xs dfS 7 7 :7 # t        $ r%}t        d| dt        |              Y d}~~d}~ww xY w7 E7 /# t        $ r%}t        d| dt        |              Y d}~d}~ww xY w7 u7 L# t        $ r%}t        d| dt        |              Y d}~d}~ww xY w7 7 S7 =# t        $ r%}t        d| dt        |              Y d}~d}~ww xY w7 # t        $ r$}t        d(t        |              g }Y d}~d}~ww xY ww))u   
    使用舷号三级搜索策略进行RAG检索
    返回: (rag_results, matched_kb_name, matched_kb_id, matched_ship_number)
    matched_ship_number: 映射后的舷号，未映射到具体舷号时为空字符串
    r   Nr\   u   正在智能识别u   识别 'u!   ' 的含义（舷号/舰名）...u   [智能映射结果] 输入='u   ' -> 舷号=u	   , 型号=u   , 所有舷号=u   , 匹配类型=u5   ' -> 未找到匹配，将使用原始值进行检索)exact_number
exact_namer`   u   正在指定舷号检索u   使用舷号 u    进行检索...)r   r%   u   步骤1 - 舷号 u    检索完成，返回 u
    条结果r$   r%   u    检索失败: u.    无对应知识库，跳过指定舷号检索u   正在型号检索u   识别为型号 'u    '，使用该型号所有舷号 z, u   步骤2 - 舷号 u   正在指定舰名检索u   使用舰名 u.    无对应知识库，跳过指定舰名检索   u   正在同型号检索u   使用同型号舷号 u   正在全局检索u3   未找到舷号相关资料，进行全局检索...)r   u&   步骤3 - 全局检索完成，返回 u   步骤3 - 全局检索失败: )rC   r{   rq   r*   r?   r
   r   lenr/   r0   r    r!   r1   joinextendrH   )r   r9   r   r   rag_resultsmatched_kb_namematched_kb_idmatched_ship_numbermatched_modelmodel_all_numbersrg   
real_kb_id	rag_queryrag_result_rawr   found_kb_namefound_kb_idr7   numcurrent_resultsmodel_ship_numberss                        r(    search_with_ship_number_strategyr     s     KOMMJ{((* {m#DE	

 SllwRxLxI],=z1+lK^J__hivhw  xG  HY  GZ  Zi  jt  iu  v  w1+>stu@@EX()<==
* 344DE
 &,IX'1)5PZ'[![0@-.A-BBYZ]^iZjYkkuvw +%dD1,0HHY,CM*.((7B*?K,_25m2D2J2J2L*=03K0@0F0F0H !, 'H[Ha_aaa  %&9%::hij@@EV .NtyyYjOkNll|}	

 %C%,IH#0#55
!'1)5PZ'[!["4^"D"&&7-cU2I#oJ^I__ijk*$3D)$504B0G.2hhw.C#069-6H6N6N6PO#.}474D4J4J4LM %4 %4 @S@YWYYY{((*zV/C(55
*},<=
 &,IP'1)5PZ'[![0@-k]:QRUVaRbQccmno +%dD1,0HHY,CM*.((7B*?K,_25m2D2J2J2L*=03K0@0F0F0H !, 'H[Ha_aaa  %k]2`ab#<[#II!"Q&3/A+Ba+GK_qLq'(3E)F(GGWX
 *+%)l	L'4S'9!9J% +5iuT^+_%_N&8&HO&#**?; 1#6McRaNbMccmno.(7#-dD#948HHY4KM26((7B2GK'4_:=m:L:R:R:T'2=8;K8H8N8N8P )8% *: "O]DWD][]]]=
)*EBB(8:3{;K:LJWX#dD)$(HHY$;M"&((7B"7K$_*-m*<*B*B*D"=(+K(8(>(>(@ $ 8K8QrQQI My > "\  X)*=)>ocRSfXVWWX 6 "\   H)#oc!fXFGGH 6 "\  P)+oc!fXNOOP
 J ": &`  ! L-cU/#a&JKKL C  .s1vh78s	  ?[WA[W[)W :W;AW =AW W $W (A[,X:W?;X[XXAX)AX-X0X6[X6[X< -X9.AX< 0AX< 4X< 7$X< [:Y-;A[Y6Y0Y6$[%Y66Y37AY6AY6Y6Y6.[	Z* Z'>Z* AZ* Z*  Z* ;[[W 	W<W71[7W<<[?XX	X3X.([.X33[9X< <	Y*Y%[%Y**[0Y63Y66	Z$?Z[Z$$['Z* *	[3[[[[)g?)   fault)$__doc__typingr   r   r   r   r   rv   r<   r+   utils.function_trackerr   tools.ship_model_dbr	   tools.rag_toolsr
   modelsAPI.model_apir   configr   r   r!   __annotations__r8   r?   r   rH   rT   rV   rX   floatrq   r{   r   intr   rW   r)   r(   <module>r      s  	 4 3  	  4 7 & ) ! 26 htCH~. 58T#s(^ 8vS Xc] 8  ,(d3S#X3F.G (V   $4T#s(^0C+D $ #&9$9$9$ 8C=(3-$s))<cAB9$vc C 	 	~R~R~R ~R 	~R
 4S#Xc3./~Rr)   ynexdDo
    8Nia                  
   @   s  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 d dl	m
Z
 d dlmZmZmZ d dlmZ d dlmZ ejejddd	 eeZG d
d dZdddZedkrdZzeeZede  W dS  ey Z zede  W Y dZ[dS dZ[ww dS )    N)datetime)Document)PtRGBColorInches)WD_ALIGN_PARAGRAPH)qnz)%(asctime)s - %(levelname)s - %(message)sz%Y-%m-%d %H:%M:%S)levelformatdatefmtc                   @   s   e Zd Zdd Zd'ddZdd Zd	d
 Zd'ddZd(ddZdd Z	de
de
fddZd)de
defddZdd Zdd Zdd  Zd!d" Zd*d#d$Zd%d& ZdS )+MarkdownWordGeneratorc              
   C   sn   z!t  | _tjt d| _tj| jdd i | _	t
d W d S  ty6 } z	t
d|   d }~ww )Nlatex_formula_cacheT)exist_oku%   MarkdownWordGenerator 初始化成功u(   初始化 MarkdownWordGenerator 失败: )r   docospathjointempfile
gettempdir	cache_dirmakedirsformula_cacheloggerinfo	Exceptionerror)selfe r   /app/utils/word_generator.py__init__   s   zMarkdownWordGenerator.__init__   Fc              
   C   s   z<d|j _|j }|td}|du r$|jtdi }|d| |tdd t	||j _
|r6dnd|j _W dS  tyW } ztd|  W Y d}~dS d}~ww )	u7   设置字体，确保 rPr 和 rFonts 元素安全创建u   微软雅黑zw:rFontsNr   z
w:eastAsiaTFu   设置字体时出错: )fontname_elementget_or_add_rPrfindr   makeelementinsertsetr   sizeboldr   r   warning)r   runr*   r+   rPrrFontsr   r   r   r   set_font'   s   
zMarkdownWordGenerator.set_fontc              
   C   s|   z| j j|d}dddd}||d}| j|||dd W dS  ty= } ztd	| d
|  W Y d}~dS d}~ww )u2   添加标题，支持标题文本中的 **加粗**r	            )            T)default_sizedefault_boldu   添加标题失败 '': N)r   add_headingget_add_rich_textr   r   r   )r   textr	   psize_map	font_sizer   r   r   r   r<   :   s   $z!MarkdownWordGenerator.add_headingc              
   C   s   zF|  sW dS | j }d}|}|dr%|d7 }|dd }|ds|dkr2td|j_|}n|dkr>td|j_|}| || W dS  tya } zt	
d|  W Y d}~dS d}~ww )	uB   处理普通段落，支持 **加粗** 和全角空格首行缩进Nr      　r5   r6         ?      ?u   添加段落失败: )stripr   add_paragraph
startswithr   paragraph_formatfirst_line_indentr>   r   r   r   )r   r?   r@   indent_chars	temp_textr   r   r   r   rG   D   s*   


z#MarkdownWordGenerator.add_paragraphc                 C   s   |sdS d}d}t ||D ]?}| \}}	||kr/||| }
|
r/||
}| j|||d |d}|rK||}| j||dd td|  |	}q|t|k rk||d }|rm||}| j|||d dS dS dS )u   
        向段落中添加支持 **加粗** 的富文本。
        使用 re.finditer 逐段扫描，比 re.split 更可靠。
        Nz\*\*(.+?)\*\*r   )r*   r+   r5   Tu   渲染加粗文本: )	refinditerspanadd_runr0   groupr   debuglen)r   	paragraphr?   r9   r:   patternlast_endmatchstartendplainr-   bold_content	remainingr   r   r   r>   \   s0   



z$MarkdownWordGenerator._add_rich_textNc              
   C   s   zY|  }|s
W dS td|rtd|  W dS |rJ|durJ| j }td|j_	td|j_
|| d}| j|dd | || W dS | jjd	d
}| || W dS  tyt } ztd|  W Y d}~dS d}~ww )uw   
        处理列表项，支持 **加粗**。
        有序列表使用手动序号以确保编号正确。
        N^[-_*]{2,}$u   跳过无效列表项: r2   iz. Fr+   List Bulletstyleu   添加列表失败: )rF   rM   rW   r   rR   r   rG   r   rI   left_indentrJ   rP   r0   r>   r   r   )r   r?   numberednumberr@   num_runr   r   r   r   add_list   s(   
zMarkdownWordGenerator.add_listc              
   C   s   z;|  }|s
W dS td|rW dS z	| jjdd}W n ty2   | jjdd}td|j_Y nw | 	|| W dS  t
yV } ztd|  W Y d}~dS d}~ww )u;   处理子列表项（缩进的 - 项），支持 **加粗**Nr]   zList Bullet 2r`   r_   $   u   添加子列表失败: )rF   rM   rW   r   rG   KeyErrorr   rI   rb   r>   r   r   r   )r   r?   r@   r   r   r   r   add_sub_list   s"   z"MarkdownWordGenerator.add_sub_listurlreturnc                 C   sB   |sdS ddl m} ||j}|drd|tdd  S dS )u   
        将图片URL转换为容器内本地文件路径
        http://xxx:port/picture/xxx.png -> /app/picture/xxx.png
        Nr   )urlparsez	/picture/z/app/picture/)urllib.parserl   r   rH   rS   )r   rj   rl   r   r   r   r   _convert_url_to_local_path   s   

z0MarkdownWordGenerator._convert_url_to_local_path      @url_or_pathwidth_inchesc              
   C   s,  |sdS zddl }d}tj|r|}n|ds|dr| |}td| d|o0tj|  |r?tj|r?|}n\ddl}|j	|ddddd	}|
  |j	d
d}td| dt|j d |dstd| d|jdd   | d| d W dS ||j}ntd|  W dS ddlm}	 t|tr|	|}
n|	|}
| }|
|
jdv rdndj|dd |d | j }tj|_| }|j |t!|d td|  W dS  t"y } ztjd| d|d d! | d| d W Y d}~dS d}~ww )"u   
        向文档插入图片。
        - 本地路径：直接读取
        - HTTP URL：转换为容器本地路径 /app/picture/xxx.png 后读取
        图片嵌入 docx，生成后不再依赖任何路径或 URL。
        Nr   zhttp://zhttps://u   尝试本地路径: u
   , 存在: 
   )httphttps)timeoutproxieszContent-Type u!   HTTP 下载完成, Content-Type: 
   , 大小:  byteszimage/u   响应不是图片类型: u   , 内容前100字节: d   u   [图片加载失败: ]u   图片路径无效: )Image)RGBAPr}   RGBPNG)r
   )widthu   图片插入成功: u   插入图片失败 'r;   Texc_info)#ior   r   isfilerH   rn   r   r   requestsr=   raise_for_statusheadersrS   contentr   rG   BytesIOr,   PILr|   
isinstancestropenconvertmodesaveseekr   r   CENTER	alignmentrP   add_picturer   r   )r   rp   rq   r   image_stream
local_pathr   respcontent_typePilImagepil_img
png_streamr@   r-   r   r   r   r   	add_image   sR   
"
 

"

 zMarkdownWordGenerator.add_imagec              
   C   s   |sd S || j v r| j | S tj| jt  d}z0tjdd}|j	ddd| ddddd t
d	 |j|d
ddd t| || j |< |W S  tyn } ztd| d|  td W Y d }~d S d }~ww )Nz.png)   r5   )figsizerD   $r4   center)fontsizehavaoffi,  tightg?)dpibbox_inches
pad_inchesu   公式渲染失败 'r;   all)r   r   r   r   r   uuiduuid4pltfigurer?   axissavefigcloser   r   r   )r   latexfilenamefigr   r   r   r   latex_to_image   s&   





z$MarkdownWordGenerator.latex_to_imagec              
   C   sZ  zg }|D ]}| d}dd |dD }|| q|s!W d S |d }d}t|dkr:tdd |d D r:d}||d  }t|}| jjt|d |d	}	d
|	_t|D ]\}
}|
|k rh||	j	d j
|
 _qWt|D ]\}}t|D ]\}}||k r||	j	|d  j
| _quqmtd W d S  ty } ztd|  W Y d }~d S d }~ww )N|c                 S   s   g | ]}|  qS r   )rF   .0cr   r   r   
<listcomp>  s    z3MarkdownWordGenerator.add_table.<locals>.<listcomp>r   r5   c                 s   s"    | ]}| d p|dkV  qdS )-rw   N)rH   r   r   r   r   	<genexpr>  s     z2MarkdownWordGenerator.add_table.<locals>.<genexpr>r6   )rowscolsz
Table Gridu   表格添加成功u   添加表格失败: )rF   splitappendrS   r   r   	add_tablera   	enumerater   cellsr?   r   r   r   r   )r   linesr   liner   headerdata_start_indexdatamax_colstableicellrrowr   valr   r   r   r   r     s>   
"zMarkdownWordGenerator.add_tablec                 C   sp   | j  }|j }|jtdi }|jtdtddtddtddtd	d
i}|| || dS )u   添加水平分隔线zw:pBdrzw:bottomzw:valsinglezw:sz6zw:space1zw:colorCCCCCCN)r   rG   r$   get_or_add_pPrr'   r   r   )r   r@   pPrpBdrbottomr   r   r   _add_horizontal_rule2  s   


z*MarkdownWordGenerator._add_horizontal_rulec           %      C   s  | d}g }g }d}d}|t|k rh|| }| }| }	|	drL|s,d}g }nd}d| }
| |
}|rB| | n| 	d |d7 }q|rX|
| |d7 }q|	d	rl|	d	rl|
| |d7 }q|ru| | g }|s||d7 }qtd
|r|   |d7 }qtd|	}|rt|d}|d}| || |d7 }qtd|	}|rt|d}|d}| j|d|d |d7 }|t|k r|| }| }td|}|r|d}| | |d7 }n%|ds|dr| }|rtd|s| | |d7 }nnn|t|k sq|	d}|sZtd|}|sAtd|}|rA|d rA|}|rZ|d }|rU| j|dd |d7 }q|	drd }td|	}|r|d }|dr|dr|dd }ntd|	}|r|d }|r| | |d7 }q|	drtd|	}|r| j	 }||d}tddd|jj_d|j_|d7 }qtd|	}|rYt d |	}| j	 } d}!|}"|"d!r|!d7 }!|"dd  }"|"d!s|!dkr
td"| j_ n|!dkrtd#| j_ |D ]@}#|#sq|#d$rP|#d$rP|#dd }$| |$}|rD| | | j	 } q| d%}| !| q| "| |# qn| 	| |d7 }|t|k s|rr| | d S d S )&N
Fr   z$$Trw   u   [公式渲染失败]r5   r   z^\s*[-*_]{3,}\s*$z^(#{1,3})\s+(.*)r6   z^(\d+)\.\s*(.*))rc   rd   z^[\s\t]+[-*]\s*(.*)z   	z^\d+\.\sz**z^\s*[-*]\s+(.*)z^\s*-([^-].*)$)rc   z![z	\((.*?)\)`z!\[.*?\]`([^`]+)`[z\[(.*?)\]\((.*?)\)   z	\$(.*?)\$z	(\$.*?\$)rC   rD   rE   r   u   [公式错误])#r   rS   rstriplstriprH   r   rF   r   r   rG   r   endswithr   rM   rW   r   rQ   r<   intrf   ri   searchr   rP   r   r"   colorrgb	underlinefindallr   rI   rJ   r0   r>   )%r   markdownr   table_bufferblock_formulain_block_formular   r   line_strippedline_contentformulaimg_pathheading_matchr	   r?   list_match_orderedrd   	next_linenext_stripped	sub_matchsub_textsub_contentis_bold_linelist_match_unorderedmrj   rW   backtick_matchr@   r-   inline_matchessegments	current_prK   	temp_linesegmentlatex_contentr   r   r   parse@  s  























  /zMarkdownWordGenerator.parsec           
   
   C   s   zx|r t d|  | j }||}| |dd tj|_t d | 	| |r1| 
| |s@t d}d| d}t d|  | j| tj|ritj|}t d	| d
| d |W S t d|  td| d ty }	 zt jd|	 dd  d }	~	ww )Nu   添加文档标题:    Tu   开始解析 Markdown 内容z%Y%m%d_%H%M%Sreport_z.docxu   正在保存文件: u   文件保存成功: rx   ry   u   文件保存后未找到: zFile z was not created.u)   生成报告过程中发生严重错误: r   )r   r   r   rG   rP   r0   r   r   r   r  _append_images_sectionr   nowstrftimer   r   r   existsgetsizer   FileNotFoundErrorr   )
r   r   titleoutputimagesr@   r-   	timestamp	file_sizer   r   r   r   generate  s6   




zMarkdownWordGenerator.generatec           	   
   C   s  zp| j ddd t|dD ]U\}}t|tr#|dd}|dd}nt|}d}| j }|d| d	}| j	|d
d |rG| j
|dd |r]| j }|d| }| j	|dd | j  qtdt| d W dS  ty } ztd|  W Y d}~dS d}~ww )u   
        在文档末尾添加图片附件部分
        Args:
            images: 图片列表，每项为包含url和summary的字典
        u   附件图片r6   r1   r5   rj   rw   summaryu   图片u   ：Tr^   r   )rq   u	   说明：rr   )r*   u%   图片附件部分添加完成，共 
    张图片u    添加图片附件部分失败: N)r<   r   r   dictr=   r   r   rG   rP   r0   r   r   r   rS   r   r   )	r   r  idximgrj   r  r@   r-   r   r   r   r   r    s.   


z,MarkdownWordGenerator._append_images_section)r!   F)FN)ro   NNN)__name__
__module____qualname__r    r0   r<   rG   r>   rf   ri   r   rn   floatr   r   r   r   r  r  r  r   r   r   r   r      s"    



$:# 
9"r   c              
   C   s   t d z%t }|rt dt| d |j| |||d}t d| d |W S  ty? } z	t d|   d}~ww )	u   
    生成Word报告
    Args:
        markdown: Markdown格式的报告内容
        title: 报告标题
        output: 输出文件路径
        images: 图片列表，每项为包含url和summary的字典
    u   === 开始生成报告 ===u   准备插入 r  )r
  r  r  u   === 报告生成完成: z ===u   报告生成失败: N)r   r   r   rS   r  r   critical)r   r
  r  r  	generator	file_pathr   r   r   r   generate_report_word>  s   
	r  __main__u  
## **舷号163发动机油压低应急处置报告**

报告编号：UK-2026-03-27-0923
编制时间：2026-03-27 09:23

### **一、概述**

　　本报告旨在总结舷号163船舶发动机发生油压低故障时的应急处置流程、人员配置及具体操作方案。针对该特定舷号设备的发动机型号与管路布局，报告详细梳理了从故障确认到紧急停机的全过程，以确保在突发状况下能够迅速、准确地执行安全卸载与排查，保障船舶动力系统的运行安全。

### **二、主要内容**

　　应急处置工作首先严格遵循人员配置标准，由一名具备中级及以上资质的发动机应急运维专业人员负责负荷卸载、故障排查及紧急停机决策，同时配备一名初级及以上资质的应急监测辅助人员，负责实时监测油压数值、记录关键数据并协助现场操作。

　　在工具与设施准备方面，现场必须配备高精度机油压力表以核实油压数值，准备含同型号机油的应急补充套装，并配置荧光剂、紫外线灯及听诊器等泄漏检测工具，同时确保紧急停机按钮处于可用状态，并备有专用的应急处置记录表格。

　　操作方案的核心步骤始于故障确认，发现报警后需立即使用高精度机油压力表核对数值，并结合现场异响或泄漏痕迹综合判断故障真实性，随后迅速将发动机负荷卸载至空载怠速状态，严禁在油压低情况下强行作业。

　　在排查与临时处置阶段，利用检测工具对管路接口及油封等部位进行泄漏检查，若确认无泄漏且油位不足，则补充同型号专用机油并观察油压回升情况；若补充后油压仍持续偏低或出现金属异响，必须立即按下紧急停机按钮执行停机，并禁止频繁启动发动机等待专业检修。

### **三、结论**

　　本次应急处置方案针对舷号163船舶发动机油压低故障制定了标准化的操作流程，明确了人员职责分工与关键工具配置，确保了故障处理的规范性与安全性。通过严格执行负荷卸载、精准排查及果断停机决策，能够有效防止设备损坏扩大，为后续的专业维修与系统恢复奠定了坚实基础。
u   报告已生成，路径: u5   程序执行出错，请查看日志。错误信息: r  )r   rM   r   loggingr   r   matplotlib.pyplotpyplotr   docxr   docx.sharedr   r   r   docx.enum.textr   docx.oxml.nsr   basicConfigINFO	getLoggerr  r   r   r  mdresult_pathprintr   r   r   r   r   r   <module>   sB    
    
(
hxƟ9`
    ѱMj)v                        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 d dlm	Z	m
Z
mZ d dlmZ d dlmZ d dlmZ  ej$                  ej&                  dd	
        ej(                  e      Zdadad Z G d d      ZddZedk(  rdZ	  ee      Z ede        yy# e$ r*Z  ede         d dl!Z! e!jD                          Y dZ [ ydZ [ ww xY w)    N)datetime)Document)PtRGBColorInches)WD_ALIGN_PARAGRAPH)qn)etreez)%(asctime)s - %(levelname)s - %(message)sz%Y-%m-%d %H:%M:%S)levelformatdatefmtFc                     t         rt        S da t        j                  j	                  t        j                  j                  t                    } t        j                  j                  | d      ddddddg}t        j                  d	t        |       d
       |D ]x  }t        j                  j                  |      }t        j                  d| d|rdnd        |sD	 t        j                  |      at        j                  d|        t        c S  t        j!                  d       y # t        $ r%}t        j                  d| d|        Y d }~d }~ww xY w)NTzMML2OMML.XSLz<C:\Program Files\Microsoft Office\root\Office16\MML2OMML.XSLzBC:\Program Files (x86)\Microsoft Office\root\Office16\MML2OMML.XSLz7C:\Program Files\Microsoft Office\Office16\MML2OMML.XSLz=C:\Program Files (x86)\Microsoft Office\Office16\MML2OMML.XSLz /usr/share/mml2omml/MML2OMML.XSLz/app/utils/MML2OMML.XSLu)   [公式] 开始搜索 MML2OMML.XSL，共 u
    个路径u   [公式] 检查路径: z -> u   存在u	   不存在u(   [公式] ✓ MML2OMML.XSL 加载成功: u(   [公式] ✗ MML2OMML.XSL 加载失败: u
   , 错误: uY   [公式] ✗ 未找到 MML2OMML.XSL，公式将使用 matplotlib 图片回退方式渲染)_MML2OMML_LOADED_MML2OMML_XSLTospathdirnameabspath__file__joinloggerinfolenisfiler
   parse	Exceptionerrorwarning)	_this_dirsearch_pathsr   existses        Fe:\ZKYNLP\Hjunproject\project0506\wx-agent\app\utils\word_generator.py_load_mml2omml_xsltr$      s+    9:I
Y/GMBH*!L KK;C<M;NjYZ%-dV4FP[7\]^]!&T!2FtfMN%%  NNno	  ]GvZXYWZ[\\]s   2D++	E4EEc                       e Zd Zd ZddZd Zd ZddZede	de	fd       Z
d	 Zd
 ZddZddZddZddZd Zde	de	fdZede	defd       Zd de	defdZd Zd Zd Zd Zd!dZd Zy)"MarkdownWordGeneratorc                    	 t               | _        t        j                  j	                  t        j                         d      | _        t        j                  | j                  d       i | _	        t               d u| _        t        j                  d| j                          y # t        $ r}t        j                  d|         d }~ww xY w)Nlatex_formula_cacheT)exist_oku<   [公式] MarkdownWordGenerator 初始化完成, OMML可用: u(   初始化 MarkdownWordGenerator 失败: )r   docr   r   r   tempfile
gettempdir	cache_dirmakedirsformula_cacher$   _omml_availabler   r   r   r   )selfr"   s     r#   __init__zMarkdownWordGenerator.__init__;   s    		zDHWW\\(*=*=*?AVWDNKK6!#D#6#8#DD KKVW[WkWkVlmn 	LLCA3GH	s   B!B$ $	C-CCc                    	 d|j                   _        |j                  j                         }|j	                  t        d            }|7|j                  j                  t        d      i       }|j                  d|       |j                  t        d      d       t        |      |j                   _
        |rdnd|j                   _        y # t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nu   微软雅黑zw:rFontsr   z
w:eastAsiaTFu   设置字体时出错: )fontname_elementget_or_add_rPrfindr	   makeelementinsertsetr   sizeboldr   r   r   )r1   runr<   r=   rPrrFontsr"   s          r#   set_fontzMarkdownWordGenerator.set_fontG   s    	:*CHHM,,--/CXXbn-F~11"Z."E

1f%JJr,'8tHCHHM$(DeCHHM 	:NN4QC899	:s   CC 	C6C11C6c                     	 | j                   j                  |      }dddd}|j                  |d      }| j                  |||d       y # t        $ r%}t
        j                  d	| d
|        Y d }~y d }~ww xY w)Nr            )            Tdefault_sizedefault_boldu   添加标题失败 '': )r*   add_headingget_add_rich_textr   r   r   )r1   textr   psize_map	font_sizer"   s          r#   rO   z!MarkdownWordGenerator.add_headingU   s~    	>$$5$1A",H UB/I4idS 	>LL/vS<==	>s   A	A 	A:A55A:c                    	 |j                         sy | j                  j                         }d}|}|j                  d      r|dz  }|dd  }|j                  d      r|dk\  rt	        d      |j
                  _        |}n!|dk(  rt	        d      |j
                  _        |}| j                  ||       y # t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nr      　rG   rH         ?      ?u   添加段落失败: )stripr*   add_paragraph
startswithr   paragraph_formatfirst_line_indentrQ   r   r   r   )r1   rR   rS   indent_chars	temp_textr"   s         r#   r[   z#MarkdownWordGenerator.add_paragraph^   s    	5::<&&(ALI&&x0!%abM	 &&x0 q 7=c{""4 "7=d|""4 4( 	5LL/s344	5s$   B4 A
B4 AB4 4	C=CCc                    |sy d}d}t        j                  ||      D ]  }|j                         \  }}	||kD  r,||| }
|
r%|j                  |
      }| j	                  |||       |j                  d      }|r%|j                  |      }| j	                  ||d       |	} |t        |      k  r.||d  }|r&|j                  |      }| j	                  |||       y y y )Nz\*\*(.+?)\*\*r   )r<   r=   rG   T)refinditerspanadd_runrA   groupr   )r1   	paragraphrR   rL   rM   patternlast_endmatchstartendplainr>   bold_content	remainings                 r#   rQ   z$MarkdownWordGenerator._add_rich_textu   s    "[[$/EJE3xXe,#++E2CMM#L|ML ;;q>L''5c4@H 0 c$iXYI''	2c<H       latexreturnc                 6   dddddddddddd}|j                         D ]  \  }}| j                  ||      }  t        j                  d	d
 |       } t        j                  dd |       } t        j                  dd |       } t        j                  dd |       } | S )Nz\leqz\geqz\nleqz\ngeqz	\emptysetz\fracz\mathbf)z	\leqslantz	\geqslantz
\nleqslantz
\ngeqslantz\eqslantlessz\eqslantgtrz\varnothingz\dfracz\tfracz\boldsymbolz\bmz\\mathrm\s*\{([^}]*)\}c                 0    d| j                  d      z   dz   S Nz\mathrm{rG   }rf   ms    r#   <lambda>zBMarkdownWordGenerator._preprocess_latex_for_omml.<locals>.<lambda>       K!''RS*<TWZ<Zrp   z\\text\s*\{([^}]*)\}c                 0    d| j                  d      z   dz   S ru   rw   rx   s    r#   rz   zBMarkdownWordGenerator._preprocess_latex_for_omml.<locals>.<lambda>   s    +PQ
:RUX:Xrp   z\\textbf\s*\{([^}]*)\}c                 0    d| j                  d      z   dz   S )Nz\mathbf{rG   rv   rw   rx   s    r#   rz   zBMarkdownWordGenerator._preprocess_latex_for_omml.<locals>.<lambda>   r{   rp   z\\textit\s*\{([^}]*)\}c                 0    d| j                  d      z   dz   S )Nz\mathit{rG   rv   rw   rx   s    r#   rz   zBMarkdownWordGenerator._preprocess_latex_for_omml.<locals>.<lambda>   r{   rp   )itemsreplacerb   sub)rq   replacementsoldnews       r#   _preprocess_latex_for_ommlz0MarkdownWordGenerator._preprocess_latex_for_omml   s     "!##$#(&
 %**,HCMM#s+E - 02Z\ab.0XZ_`02Z\ab02Z\abrp   c                    t         j                  d| d       	 dd l}| j                  |      }t         j                  d| d       |j                  j                  |      }t         j                  dt        |              t        j                  |j                  d            }t               }|t         j                  d       y t        j                  |      } ||      }|j                         }	t         j                  d| d       |	S # t        $ r'}
t         j                  d	| d
|
 d       Y d }
~
y d }
~
ww xY w)Nu&   [公式] LaTeX->OMML 开始, 原始: ''r      [公式] LaTeX 预处理后: 'u&   [公式] MathML 生成成功, 长度: zutf-8u+   [公式] XSLT 不可用，OMML 转换跳过u!   [公式] ✓ OMML 转换成功: 'u'   [公式] ✗ LaTeX->OMML 转换失败 'rN   Texc_info)r   r   latex2mathml.converterr   	converterconvertr   r
   
fromstringencoder$   r   XSLTgetrootr   r   )r1   	latex_strlatex2mathml	processedmathmlmathml_treexslt	transform	omml_tree	omml_rootr"   s              r#   _latex_to_ommlz$MarkdownWordGenerator._latex_to_omml   s    <YKqIJ	)77	BIKK81EF!++33I>FKK@VNO**6==+ABK&(D|LM

4(I!+.I!))+IKK;I;aHI 	LLB9+SQRPST_cLd	s   B/D AD 	ED>>Ec                 b    | j                  |      }||j                  j                  |       yy)NTF)r   r6   append)r1   rg   r   ommls       r#   _add_omml_to_paragraphz,MarkdownWordGenerator._add_omml_to_paragraph   s2    ""9-%%d+rp   c                    t         j                  d| d       	 ddl}|j                  d       ddlm} | j                  |      }t         j                  d| d       || j                  v rH| j                  |   }t        j                  j                  |      rt         j                  d|        |S t        j                  j                  | j                  t        j                          d      }|sd	nd
}|sdnd}	|sdnd}
|j                  ||	f      }|j!                  ddd| d|
dd       |j#                  d       |j%                  |ddd       |j'                  |       || j                  |<   t         j                  d|        |S # t(        $ rI}t         j+                  d| d| d       	 j'                  d       n# t(        $ r Y nw xY wY d}~yd}~ww xY w)u7   matplotlib 回退方案：将公式渲染为 PNG 图片u(   [公式] LaTeX->图片 回退, 原始: 'r   r   NAggr   u   [公式] 使用缓存: z.png      g333333?g?   rE   )figsizerX   $center)fontsizehavaoffi,  tightg?)dpibbox_inches
pad_inchesu!   [公式] ✓ 图片渲染成功: u)   [公式] ✗ LaTeX->图片 渲染失败 'rN   Tr   all)r   r   
matplotlibusematplotlib.pyplotpyplotr   r/   r   r   r   r   r-   uuiduuid4figurerR   axissavefigcloser   r   )r1   r   inliner   pltr   cachedfilename	fig_width
fig_heightrU   figr"   s                r#   _latex_to_imagez%MarkdownWordGenerator._latex_to_image   s   >ykKL"	NN5!+77	BIKK81EFD...++I677>>&)KK"9& BC!Mww||DNNtzz|nD4IJH!'QI$*J"(bI**i%<*=CHHS#9+Q/)U]H^HHUOKKcw4KPIIcN,4Dy)KK;H:FGO 	LLDYKsSTRUVaeLf		%  	sC   BF 6CF 	G(G#=GG#	GG#GG##G(c                    | j                   r,| j                  ||      ryt        j                  d| d       | j	                  ||      }|r=	 |rt        d      n
t        d      }|j                         }|j                  ||       y|j                  d
| d
      }| j                  |d       t        j                  d| d       y# t        $ r"}t        j                  d|        Y d	}~hd	}~ww xY w)uA   统一公式插入方法：优先 OMML，回退 matplotlib 图片Tu+   [公式] OMML 失败，回退 matplotlib: 'r   r   gffffff?g      @widthu!   [公式] ✗ 图片插入失败: N 	   r<   u7   [公式] ✗ 所有方式失败，以纯文本插入: 'F)r0   r   r   r   r   r   re   add_picturer   r   rA   )r1   rg   r   r   img_pathr   r>   r"   s           r#   _insert_formulaz%MarkdownWordGenerator._insert_formula   s    **9i@NNHSTUV''	&'AF'-s6#;'')6 !I;a 01c"PQZP[[\]^  F@DEEFs   ;C 	C8C33C8c                    |sy t        t        j                  d|            }t        | j                  |            }|s|s| j	                  ||||       y |r| j                  |      }d}|D ]G  \  }	}
}|||	 }|r%|j                         r| j                  ||||       | j                  |d       |
}I ||d  }|r?|j                         r/| j                  j                         }| j                  ||||       y t        j                  d|      }|D ]r  }|s|j                  d      rG|j                  d      r6t        |      dkD  r(|d	d
 j                         }| j                  ||d       ^| j	                  ||||       t y )Nz
\$[^$]+?\$rK   r         @width_inchesz(\$[^$]+?\$)r   rH   rG   Tr   )boolrb   search_extract_image_urlsrQ   rZ   _add_rich_text_with_formulas	add_imager*   r[   splitr\   endswithr   r   )r1   rg   rR   rL   rM   has_formula	has_imageimg_urlsri   rk   rl   urlbefore_text
after_textrS   segmentssegmentlatex_contents                     r#   r   z2MarkdownWordGenerator._add_rich_text_with_formulas  s   299]D9:11$78	9	4lYef//5HH#+sC"8E2;#4#4#655i[g  wC5  Ds5 $, hiJj..0HH**,11!Zliu1v88OT2G!!#&7+;+;C+@S\TUEU '" 3 3 5$$Yd$K##Iw\`l#m  rp   Nc                 *   	 |j                         }|sy t        j                  d|      ry |r|| j                  j	                         }t        d      |j                  _        t        d      |j                  _        |j                  | d      }| j                  |d       | j                  ||       y | j                  j	                  d      }| j                  ||       y # t        $ r"}t        j                  d	|        Y d }~y d }~ww xY w)
N^[-_*]{2,}$rD   iz. Fr=   List Bulletstyleu   添加列表失败: )rZ   rb   rj   r*   r[   r   r]   left_indentr^   re   rA   r   r   r   r   )r1   rR   numberednumberrS   num_runr"   s          r#   add_listzMarkdownWordGenerator.add_list(  s    	5::<Dxx-F.HH**,13B"".79#w""4))vhbM2gE211!T:HH***?11!T: 	5LL/s344	5s(   C' C' BC' 8.C' '	D0DDc                    	 |j                         }|sy t        j                  d|      ry 	 | j                  j	                  d      }| j                  ||       y # t
        $ r9 | j                  j	                  d      }t        d      |j                  _        Y Tw xY w# t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nr   zList Bullet 2r   r   $   u   添加子列表失败: )rZ   rb   rj   r*   r[   KeyErrorr   r]   r   r   r   r   r   )r1   rR   rS   r"   s       r#   add_sub_listz"MarkdownWordGenerator.add_sub_list?  s    	8::<Dxx-8HH***A --a6  8HH***?13B"".8  	8LL21#677	8s?   B! B! A 	B! ?BB! BB! !	C*CCr   c                 :   |sy ddl m}  ||      j                  }|j                  d      rd|t	        d      d   }t
        j                  j                  |      r|S 	 t
        j                  j                  t
        j                  j                  t
        j                  j                  t                          }t
        j                  j                  |d|t	        d      d        }t
        j                  j                  |      r|S 	 y y # t        $ r Y y w xY w)Nr   )urlparsez	/picture/z/app/picture/picture)urllib.parser   r   r\   r   r   r   r   r   r   r   r   )r1   r   r   r   docker_pathproject_root
local_paths          r#   _convert_url_to_local_pathz0MarkdownWordGenerator._convert_url_to_local_pathP  s    )}!!??;')$s;/?/@*A)BCKww~~k*""!wwrwwrwwx?X/YZWW\\,	4KHXHYCZ[
77>>*-%% .   s    B*D 	DDc                    i }d| v rc	 ddl m} t        |j                  dd            |d<   t        |j                  dd            |d<   t        |j                  dd	            |d<   |S |S # t        $ r d|d<   d|d<   d	|d<   Y |S w xY w)
Nz/api/v1/knowledge/r   )
RAG_CONFIGz	x-user-id1zx-user-nametestuserzx-roleadmin)configr   strrP   r   )r   headersr   s      r#   _get_http_headersz'MarkdownWordGenerator._get_http_headersc  s    3&,-'*:>>+s+K'L$),Z^^M:-V)W&$'
x(I$J!
 w	  ,'*$)3&$+!	,s   A A, ,BBurl_or_pathr   c                    |sy 	 dd l }d }t        j                  j                  |      r|}nT|j	                  d      s|j	                  d      r| j                  |      }|r"t        j                  j                  |      r|}ndd l}| j                  |      }|j                  |d|d d d      }|j                          |j                  j                  dd      }	t        j                  d	|	 d
t        |j                         d       |	j	                  d      s.t        j                  d|	        | j!                  d| d       y |j#                  |j                        }nt        j%                  d|        y ddlm}
 t+        |t,              r|
j/                  |      }n|
j/                  |      }|j#                         }|j1                  |j2                  dv rdnd      j5                  |d       |j7                  d       | j8                  j!                         }t:        j<                  |_        |jA                         }|jC                  |tE        |             t        j                  d|        y # tF        $ r<}t        j                  d| d|d       | j!                  d| d       Y d }~y d }~ww xY w)Nr   zhttp://zhttps://   )httphttps)timeoutr   proxieszContent-Type u!   HTTP 下载完成, Content-Type: 
   , 大小:  byteszimage/u   响应不是图片类型: u   [图片加载失败: ]u   图片路径无效: )Image)RGBAPr  RGBPNG)r   r   u   图片插入成功: u   插入图片失败 'rN   Tr   )$ior   r   r   r\   r   requestsr  rP   raise_for_statusr   r   r   r   contentr   r[   BytesIOr   PILr  
isinstancer   openr   modesaveseekr*   r   CENTER	alignmentre   r   r   r   )r1   r  r   r  image_streamr   r  r   respcontent_typePilImagepil_img
png_streamrS   r>   r"   s                   r#   r   zMarkdownWordGenerator.add_imager  s[   +	GLww~~k**''	2k6L6LZ6X!<<[I
"''.."<#-L#"44[AG#<<RcgrvZw<xD))+#'<<#3#3NB#GLKK"CL>Q[\_`d`l`l\m[nnt uv'228<'A,%PQ**-B;-q+QR#%::dll#;L!5k]CD-,,"--5"--5JOOgllm&CFOTTU_hmTnOOA&&(A,33AK))+COOJf\.BOCKK.{m<= 	GLL/}CuEPTLU!6{m1EFF	Gs%   EJ 4J C?J 	K2KKc                 v   g }t        j                  d|      D ]x  j                  d      j                         }|j	                  d      r|j                  d      r|dd }|j                  j                         j                         |f       z t        j                  d|      D ]h  j                  d      j                         }t        fd|D              }|r9|j                  j                         j                         |f       j t        j                  d|t         j                        D ]h  j                  d      j                         }t        fd	|D              }|r9|j                  j                         j                         |f       j |j                  d
        |S )u   
        从一行文本中提取所有图片URL，支持多种格式：
        - ![alt](url)
        - ![alt]`url`
        - ! `url`
        返回 [(start, end, url), ...]
        z!\[([^\]]*)\]\(([^)]+)\)rH   `rG   r   z!\[([^\]]*)\]\s*`([^`]+)`c              3   v   K   | ]0  \  }}}|j                         k  xr |j                         k\   2 y wNrk   rl   .0sr"   _ry   s       r#   	<genexpr>z<MarkdownWordGenerator._extract_image_urls.<locals>.<genexpr>  4     QgaA!qwwy.9Q!%%'\9   69z,!\s*`([^`]+\.(?:jpg|jpeg|png|gif|bmp|webp))`c              3   v   K   | ]0  \  }}}|j                         k  xr |j                         k\   2 y wr(  r)  r*  s       r#   r.  z<MarkdownWordGenerator._extract_image_urls.<locals>.<genexpr>  r/  r0  c                     | d   S )Nr    )xs    r#   rz   z;MarkdownWordGenerator._extract_image_urls.<locals>.<lambda>  s    1Q4rp   )key)rb   rc   rf   rZ   r\   r   r   rk   rl   any
IGNORECASEsort)r1   line_contentresultsr   alreadyry   s        @r#   r   z)MarkdownWordGenerator._extract_image_urls  sZ     8,GA''!*""$C~~c"s||C'8!BiNNAGGIquuw45	 H 9<HA''!*""$CQQQG	1557C89	 I Ll\^\i\ijA''!*""$CQQQG	1557C89	 k 	(rp   c                 6   	 g }|D ]P  }|j                  d      }|j                  d      D cg c]  }|j                          }}|j                  |       R |sy |d   }d}t        |      dkD  rt	        d |d   D              rd}||d  }t        |      }	| j
                  j                  t        |      dz   |	      }
d|
_        t        |      D ],  \  }}||	k  s||
j                  d   j                  |   _        . t        |      D ]B  \  }}t        |      D ]/  \  }}||	k  s||
j                  |dz      j                  |   _        1 D t        j                  d       y c c}w # t        $ r"}t        j                  d	|        Y d }~y d }~ww xY w)
N|r   rG   c              3   L   K   | ]  }|j                  d       xs |dk(    yw)-r	  N)r\   )r+  cs     r#   r.  z2MarkdownWordGenerator.add_table.<locals>.<genexpr>  s&     $S7aQ\\#%6%A!r'%A7s   "$rH   )rowscolsz
Table Gridu   表格添加成功u   添加表格失败: )rZ   r   r   r   r   r*   	add_tabler   	enumeraterA  cellsrR   r   r   r   r   )r1   linesrA  liner@  rE  headerdata_start_indexdatamax_colstableicellrrowvalr"   s                    r#   rC  zMarkdownWordGenerator.add_table  s    	5Dzz#,0JJsO<OqO<E" 
 !WF 4y1}$S4PQ7$S!S#$ ()*D6{HHH&&CIM&IE&EK$V,4x<26EJJqM''*/ - $D/3'nFAs8|:=

1q5)//27 - *
 KK,-5 =6  	5LL/s344	5s<   +E- E(E- BE- A
E- *=E- (E- -	F6FFc                    | j                   j                         }|j                  j                         }|j                  j	                  t        d      i       }|j                  j	                  t        d      t        d      dt        d      dt        d      dt        d	      d
i      }|j                  |       |j                  |       y )Nzw:pBdrzw:bottomzw:valsinglezw:sz6zw:spacer   zw:colorCCCCCC)r*   r[   r6   get_or_add_pPrr9   r	   r   )r1   rS   pPrpBdrbottoms        r#   _add_horizontal_rulez*MarkdownWordGenerator._add_horizontal_rule  s    HH""$jj'')zz%%blB7'':wKvJyM3yM8	9
  	F

4rp   c                 >   |j                  d      }g }g }d}d}|t        |      k  r||   }|j                         }|j                         }	|	j	                  d      rp|s|	dd  }
|
j                  d      }|dk\  r|
d | j                         }|
|dz   d  j                         }| j                  j                         }t        j                  |_        | j                  ||d       |r| j                  |       nd}g }|
j                         r|j                  |
j                                n|	dd  }
d}dj                  |      j                         }| j                  j                         }t        j                  |_        | j                  ||d       |
j                         r| j                  |
j                                |d	z  }|r|j                  |       |d	z  }|	j	                  d
      r)|	j                  d
      r|j                  |       |d	z  }
|r| j!                  |       g }|s|d	z  }(t#        j$                  d|      r| j'                          |d	z  }Ut#        j$                  d|	      }|rDt        |j)                  d	            }|j)                  d      }| j+                  ||       |d	z  }t#        j$                  d|	      }|rt-        |j)                  d	            }|j)                  d      }| j/                  |d|       |d	z  }|t        |      k  r||   }|j                         }t#        j$                  d|      }|r(|j)                  d	      }| j1                  |       |d	z  }nc|j	                  d      s|j	                  d      r@|j                         }|r-t#        j$                  d|      s| j1                  |       |d	z  }nnn|t        |      k  rǐ|	j	                  d      }|st#        j$                  d|      }|s9t#        j$                  d|      }|r!|j)                  d	      j                         r|}|r;|j)                  d	      j                         }|r| j/                  |d       |d	z  }| j3                  |	      }|rt        |      d	k(  xr, |	j                         j	                  d      xr |d   d   dk(  }|r|d   \  }}}| j5                  |       n| j                  j                         }d} |D ]\  \  }!}"}|	| |! j                         }#|#r| j7                  ||#       | j5                  |d       | j                  j                         }|"} ^ |	| d  j                         }$|$r| j7                  ||$       |d	z  }|	j	                  d      rt#        j$                  d|	      }%|%rq| j                  j                         }|j9                  |%j)                  d	            }&t;        ddd      |&j<                  j>                  _         d|&j<                  _!        |d	z  }?| j                  j                         }d}'|}(|(j	                  d      r|'d	z  }'|(d	d  }(|(j	                  d      r|'dk\  rtE        d      |jF                  _$        n|'d	k(  rtE        d      |jF                  _$        | j7                  ||	       |d	z  }|t        |      k  r|r| j!                  |       y y ) N
Fr   z$$rH   r   Tr	  rG   r=  z^\s*[-*_]{3,}\s*$z^(#{1,3})\s+(.*)z^(\d+)\.\s*(.*))r   r   z^[\s\t]+[-*]\s*(.*)z   	z^\d+\.\sz**z^\s*[-*]\s+(.*)z^\s*-([^-].*)$)r   !r   r   [z\[(.*?)\]\((.*?)\)   rW   rX   rY   )%r   r   rstriplstripr\   r8   rZ   r*   r[   r   r  r  r   r   r   r   rC  rb   rj   rZ  rf   rO   intr   r   r   r   r   re   r   r4   colorrgb	underliner   r]   r^   ))r1   markdownrF  table_bufferblock_formulain_block_formularM  rG  line_strippedr9  ro   	close_idxformulaafter_formularS   heading_matchr   rR   list_match_orderedr   	next_linenext_stripped	sub_matchsub_textsub_contentis_bold_linelist_match_unorderedry   r   has_only_imgr-  r   ri   rk   rl   r   r   rj   r>   r_   	temp_lines)                                            r#   r   zMarkdownWordGenerator.parse  s   t$ #e*n8D KKMM(//1L &&t,' ,QR 0I )t 4I A~"+JY"7"="="?(1)a-.(A(G(G(I HH224&8&?&?,,Q,F( ..}=+/((*$??,)001BC ,QR 0I',$ ggm4::<G..0A"4";";AK((GE(B (**9??+<=Q$$T*Q &&s+0E0Ec0J##M2QNN<0#%L !Q xx,m<))+Q HH%8,GMM//23$**1-  u-Q "$*<l!K!/55a89)//2dT&AQ#e*n %aI$-$4$4$6M ")? OI #,??1#5))(3Q'2259]=U=UVZ=[&3&9&9&;&rxx[/Q --k:FA!! #e*n"  (2248L')xx0BM'R$+!2MBAQWWQZ--//0,'/55a8>>@DdU;FA //=H #H 2 !4 , 2 2 4 ? ? D!4 (A! 3    (IAq#NN3'..0A H+3sC&28E&B&H&H&J& ==aMs= HH224#& ,4 ".hi!8!>!>!@J!99!ZHQ &&s+!6E..0A))EKKN3C)1!Q)<CHHNN&)-CHH&Q &&(AL%I&&x0!%abM	 &&x0 q 7=c{""4"7=d|""4--a>FAO #e*nR NN<( rp   c                 j   	 |rkt         j                  d|        | j                  j                         }|j	                  |      }| j                  |dd       t        j                  |_        t         j                  d       | j                  |       |r| j                  |       |s)t        j                         j                  d      }d| d}t         j                  d|        | j                  j                  |       t        j                   j#                  |      r=t        j                   j%                  |      }t         j                  d	| d
| d       |S t         j'                  d|        t)        d| d      # t*        $ r }	t         j'                  d|	 d        d }	~	ww xY w)Nu   添加文档标题: r   Tu   开始解析 Markdown 内容z%Y%m%d_%H%M%Sreport_z.docxu   正在保存文件: u   文件保存成功: r
  r  u   文件保存后未找到: zFile z was not created.u)   生成报告过程中发生严重错误: r   )r   r   r*   r[   re   rA   r   r  r  r   _append_images_sectionr   nowstrftimer  r   r   r!   getsizer   FileNotFoundErrorr   )
r1   rg  titleoutputimagesrS   r>   	timestamp	file_sizer"   s
             r#   generatezMarkdownWordGenerator.generate  sh   	25':;HH**,ii&c2t,077KK67JJx ++F3$LLN33OD	"9+U3KK.vh78HHMM&!ww~~f%GGOOF3	26(*YKvVW9&BC'%x7H(IJJ 	LLDQCHSWLX	s   EF	 "'F	 		F2F--F2c                    	 | j                  dd       t        |d      D ]  \  }}t        |t              r%|j	                  dd      }|j	                  dd      }nt        |      }d}| j                  j                         }|j                  d| d	      }| j                  |d
       |r| j                  |d       |rA| j                  j                         }|j                  d|       }| j                  |d       | j                  j                           t        j                  dt        |       d       y # t        $ r"}t        j                  d|        Y d }~y d }~ww xY w)Nu   附件图片rH   rC   rG   r   r	  summaryu   图片u   ：Tr   r   r   u	   说明：
   r   u%   图片附件部分添加完成，共 
    张图片u    添加图片附件部分失败: )rO   rD  r  dictrP   r   r*   r[   re   rA   r   r   r   r   r   r   )	r1   r  idximgr   r  rS   r>   r"   s	            r#   r|  z,MarkdownWordGenerator._append_images_section  sC   	A^15%fa0Sc4(''%,C!ggi4Gc(C GHH**,ii&S 12c-NN3QN7..0A))iy$9:CMM#BM/&&() 1, KK?F}JWX 	ALL;A3?@@	As   D?E 	E-E((E-)   F)T)FN)g      @NNN)__name__
__module____qualname__r2   rA   rO   r[   rQ   staticmethodr   r   r   r   r   r   r   r   r   r   r  r  floatr   r   rC  rZ  r   r  r|  r3  rp   r#   r&   r&   9   s    
:>5.I8 # #  0,%N,"nH5.8"c c & s t  /GS /G /Gb D!5Fq)f DArp   r&   c                 >   t         j                  d       	 t               }|r"t         j                  dt        |       d       |j	                  | |||      }t         j                  d| d       |S # t
        $ r}t         j                  d|         d }~ww xY w)Nu   === 开始生成报告 ===u   准备插入 r  )r  r  r  u   === 报告生成完成: z ===u   报告生成失败: )r   r   r&   r   r  r   critical)rg  r  r  r  	generator	file_pathr"   s          r#   generate_report_wordr    s    
KK,-)+	KK-F}J?@&&xuVTZ&[	.yk>? .qc23s   AA5 5	B>BB__main__uB  
## **测试报告 - OMML公式和图片**

### **一、行内公式**

温度要求 $ \leqslant 40 ^ { \circ } \mathrm { C } $，不得超过。

公差范围 $ \geqslant 0.05 \ \mathrm { mm } $ 以内合格。

### **二、列表中的公式**

1. 温度 $ \leqslant 40 ^ { \circ } \mathrm { C } $ 要求
2. 间隙 $ \leqslant 0.05 \ \mathrm { mm } $ 标准

- 清洁轴颈 $ \geqslant 0.05 \ \mathrm { mm } $


### **四、图片测试**

![图片](http://192.168.0.46:11000/api/v1/knowledge/files/images/56b1c0a02ff03d9d202627e88603e6671d3f193511d98a9fab0daf8687e6a9fa.jpg)
u   报告已生成，路径: u   程序执行出错: r  )#r   rb   r   loggingr+   r   docxr   docx.sharedr   r   r   docx.enum.textr   docx.oxml.nsr	   lxmlr
   basicConfigINFO	getLoggerr  r   r   r   r$   r&   r  mdresult_pathprintr   r"   	traceback	print_excr3  rp   r#   <module>r     s    	 	      , , -     
,,6
 
		8	$ @m
A m
A`  z
B,*2.*;-893 4  $QC()	s   B   C% C

Cׯֵx/"""
使用装饰器实现全栈函数调用追踪
解决LangGraph无法捕获子函数内部状态的问题
"""

import functools
import inspect
import asyncio
import contextvars
from typing import Callable, Any, Dict, Optional, List
from datetime import datetime
from collections import deque

# 使用 contextvars 实现请求级别的隔离，避免多个并发请求互相干扰
_event_callbacks: contextvars.ContextVar[List[Callable]] = contextvars.ContextVar('event_callbacks', default=None)
_current_stream_handler: contextvars.ContextVar[Optional[Any]] = contextvars.ContextVar('current_stream_handler',
                                                                                        default=None)


def register_event_callback(callback: Callable[[Dict[str, Any]], None]):
    """
    注册事件回调函数（使用 contextvars 实现请求隔离）
    """
    callbacks = _event_callbacks.get()
    if callbacks is None:
        callbacks = []
        _event_callbacks.set(callbacks)
    callbacks.append(callback)


def unregister_event_callback(callback: Callable[[Dict[str, Any]], None]):
    """
    移除事件回调函数（使用 contextvars 实现请求隔离）
    """
    callbacks = _event_callbacks.get()
    if callbacks and callback in callbacks:
        callbacks.remove(callback)


def clear_event_callbacks():
    """
    清空所有事件回调（使用 contextvars 实现请求隔离）
    """
    callbacks = _event_callbacks.get()
    if callbacks:
        callbacks.clear()


def get_all_callbacks():
    """
    获取所有注册的回调函数（使用 contextvars 实现请求隔离）
    """
    callbacks = _event_callbacks.get()
    return callbacks.copy() if callbacks else []


def extract_function_description(func: Callable) -> str:
    """
    提取函数的描述（docstring的第一行或前100个字符）
    """
    if func.__doc__:
        doc = func.__doc__.strip()
        # 取第一行或前100个字符
        first_line = doc.split('\n')[0].strip()
        return first_line[:100] if len(first_line) > 100 else first_line
    return ""


def _extract_details_from_result(result: Any) -> str:
    """
    从函数返回值中提取 details，顺序固定为：先 details 再中文。
    1) 先看返回的 dict 里是否有「details 类」字段（__details__、_details、details 或键名含 "details"），
       且其值为非空，则用该值；
    2) 若没有或为空，再走原本的中文兜底：从返回结构中找一段包含中文的内容作为 details。
    """
    default = "完成"
    if not result:
        return default

    # 第一步：优先用 details 类字段（仅当有值且非空时采用）
    if isinstance(result, dict):
        for key in ("__details__", "_details", "details"):
            if key in result and result[key] is not None:
                s = str(result[key]).strip()
                if s:
                    return str(result[key])
        for k, v in result.items():
            if "details" in k.lower() and v is not None:
                s = str(v).strip()
                if s:
                    return str(v)

    # 第二步：保留原本的中文兜底
    def _contains_chinese(text: str) -> bool:
        if not text:
            return False
        return any("\u4e00" <= c <= "\u9fff" for c in str(text))

    def _find_chinese(obj: Any, max_length: int = 200) -> Optional[str]:
        if isinstance(obj, str):
            return (obj[:max_length] + "...") if _contains_chinese(obj) and len(obj) > max_length else (
                obj if _contains_chinese(obj) else None)
        if isinstance(obj, dict):
            for key, value in obj.items():
                if "details" in key.lower():
                    continue
                found = _find_chinese(value, max_length)
                if found:
                    return found
        if isinstance(obj, list):
            for item in obj:
                found = _find_chinese(item, max_length)
                if found:
                    return found
        return None

    chinese = _find_chinese(result)
    return chinese if chinese else default


def track_function_calls(func: Callable) -> Callable:
    """
    装饰器：追踪函数调用过程，支持同步和异步函数
    
    Args:
        func: 被装饰的函数
    """

    @functools.wraps(func)
    def sync_wrapper(*args, **kwargs):
        # 获取函数签名信息
        sig = inspect.signature(func)
        bound_args = sig.bind(*args, **kwargs)
        bound_args.apply_defaults()

        func_name = func.__name__
        module_name = func.__module__

        # 尝试从函数参数中获取 state
        state = None
        if args and isinstance(args[0], dict):
            state = args[0]
        elif 'state' in bound_args.arguments:
            state = bound_args.arguments.get('state')

        func_description = extract_function_description(func)

        # 准备函数参数信息
        params = {k: v for k, v in bound_args.arguments.items()}

        try:
            # 执行原函数
            result = func(*args, **kwargs)

            # 构建 details：优先用返回值中的 details 类字段（__details__、_details、details 或键名含 details）
            details = _extract_details_from_result(result)

            # 合并函数执行事件（只在执行完成后发送一次）
            execution_event = {
                "type": "function_execution",
                "title": func_description,
                "details": details,
                "result": result,  # 添加函数返回结果
                "timestamp": datetime.now().isoformat()
            }

            # 调用所有注册的回调（从上下文变量获取）
            callbacks = _event_callbacks.get() or []
            for callback in callbacks:
                try:
                    callback(execution_event)
                except Exception as e:
                    print(f"回调执行出错: {e}")

            return result

        except Exception as e:
            # 发送函数执行失败事件
            error_event = {
                "type": "function_error",
                "title": func_description,
                "details": f"错误: {str(e)}",
                "timestamp": datetime.now().isoformat()
            }

            callbacks = _event_callbacks.get() or []
            for callback in callbacks:
                try:
                    callback(error_event)
                except Exception as ex:
                    print(f"回调执行出错: {ex}")

            raise

    @functools.wraps(func)
    async def async_wrapper(*args, **kwargs):
        # 获取函数签名信息
        sig = inspect.signature(func)
        bound_args = sig.bind(*args, **kwargs)
        bound_args.apply_defaults()

        func_name = func.__name__
        module_name = func.__module__

        # 尝试从函数参数中获取 state
        state = None
        if args and isinstance(args[0], dict):
            state = args[0]
        elif 'state' in bound_args.arguments:
            state = bound_args.arguments.get('state')

        func_description = extract_function_description(func)

        # 准备函数参数信息
        params = {k: v for k, v in bound_args.arguments.items()}

        try:
            # 执行原函数
            result = await func(*args, **kwargs)

            # 构建 details：优先用返回值中的 details 类字段（__details__、_details、details 或键名含 details）
            details = _extract_details_from_result(result)

            # 合并函数执行事件（只在执行完成后发送一次）
            execution_event = {
                "type": "function_execution",
                "title": func_description,
                "details": details,
                "result": result,  # 添加函数返回结果
                "timestamp": datetime.now().isoformat()
            }

            # 调用所有注册的回调（从上下文变量获取）
            callbacks = _event_callbacks.get() or []
            for callback in callbacks:
                try:
                    callback(execution_event)
                except Exception as e:
                    print(f"回调执行出错: {e}")

            return result

        except Exception as e:
            # 发送函数执行失败事件
            error_event = {
                "type": "function_error",
                "title": func_description,
                "details": f"错误: {str(e)}",
                "timestamp": datetime.now().isoformat()
            }

            callbacks = _event_callbacks.get() or []
            for callback in callbacks:
                try:
                    callback(error_event)
                except Exception as ex:
                    print(f"回调执行出错: {ex}")

            raise
    
    # 根据函数是否为协程函数返回对应的装饰器
    if asyncio.iscoroutinefunction(func):
        return async_wrapper
    else:
        return sync_wrapper


# 事件处理器
def console_event_handler(event: Dict[str, Any]):
    """
    控制台事件处理器
    """
    event_type = event["type"]
    title = event.get("title", "")
    details = event.get("details", "")

    if event_type == "function_execution":
        print(f"✅ 函数执行: {title}")
        if details:
            print(f"   详情: {details}")

    elif event_type == "function_error":
        print(f"❌ 函数错误: {title}")
        if details:
            print(f"   详情: {details}")


class StreamEventHandler:
    """
    流式事件处理器，将装饰器事件放入队列供流式输出使用
    """
    def __init__(self, queue: asyncio.Queue):
        self.queue = queue
    
    def __call__(self, event: Dict[str, Any]):
        """
        处理事件，将事件放入队列
        注意：这是同步方法，但队列是异步的，需要特殊处理
        """
        try:
            # 使用线程安全的方式将事件放入队列
            # 如果队列已满，使用 put_nowait 并忽略错误
            try:
                self.queue.put_nowait(event)
            except asyncio.QueueFull:
                # 队列已满，跳过此事件（不应该发生，因为队列大小足够）
                pass
        except Exception as e:
            # 忽略错误，避免影响主流程
            pass
    
    def send_stream_content(self, content: str, title: str = ""):
        """
        发送流式内容事件
        
        Args:
            content: 流式内容片段
            title: 函数描述/标题（可选）
        """
        try:
            event = {
                "type": "stream_content",
                "content": content,
                "title": title,
                "timestamp": datetime.now().isoformat()
            }
            self.queue.put_nowait(event)
        except Exception as e:
            # 忽略错误，避免影响主流程
            pass


def create_stream_event_handler() -> tuple[StreamEventHandler, asyncio.Queue]:
    """
    创建流式事件处理器和对应的队列（使用 contextvars 实现请求隔离）
    
    Returns:
        (handler, queue): 事件处理器和事件队列
    """
    queue = asyncio.Queue(maxsize=1000)  # 设置足够大的队列大小
    handler = StreamEventHandler(queue)
    _current_stream_handler.set(handler)  # 保存到上下文变量
    return handler, queue


def get_current_stream_handler() -> Optional[StreamEventHandler]:
    """
    获取当前活动的流式事件处理器（使用 contextvars 实现请求隔离）
    
    Returns:
        当前流式事件处理器，如果没有则返回 None
    """
    return _current_stream_handler.get()


def clear_current_stream_handler():
    """
    清除当前活动的流式事件处理器（使用 contextvars 实现请求隔离）
    """
    _current_stream_handler.set(None)
Ux)"""
图片处理工具模块 - 最终版 v4
核心思路（最简单直接）：
1. 找到所有 .jpg/.png 文件名及其周围的 ![图片]( 上下文
2. 不管周围格式如何，也不管文件名是否被模型改过
3. 统一提取文件名 -> 与 original_paths 模匹 -> 替换成正确的 ![图片](完整URL)
"""
import re
from typing import List
from difflib import SequenceMatcher


def extract_image_paths(text: str) -> List[str]:
    """从文本中提取图片路径"""
    pattern = r'images/[a-zA-Z0-9_\-./]+\.(?:jpg|jpeg|png|gif|bmp|webp)'
    matches = re.findall(pattern, text, re.IGNORECASE)
    return list(set(matches))


def find_closest_image_path(generated_path: str, original_paths: List[str]) -> str:
    """
    找到与生成路径最接近的原始图片路径
    
    即使模型输出的是错误/近似/截断的文件名，也能匹配到正确的原始路径
    """
    if not original_paths:
        return generated_path

    generated_filename = generated_path.split('/')[-1].lower()
    best_match = None
    best_score = 0

    for orig_path in original_paths:
        orig_filename = orig_path.split('/')[-1].lower()
        score = SequenceMatcher(None, generated_filename, orig_filename).ratio()
        if score > best_score:
            best_score = score
            best_match = orig_path

    if best_match and best_score > 0.5:
        return best_match
    return generated_path


def normalize_markdown_images(text: str, base_prefix: str = "/api/v1/knowledge/files/", original_paths: List[str] = None) -> str:
    """
    规范化 Markdown 图片链接 - 两轮处理版
    
    算法：
    第一轮：检查和修改格式，确保是 ![图片](/api/v1/knowledge/files/images/xxx.jpg) 格式
    第二轮：只检查和替换最后文件名部分（xxx.jpg），与原始路径匹配，匹配度低的删除
    """
    if not text or original_paths is None:
        return text
    
    # ========== 第一轮：检查和修改格式（包括固定URL前缀） ==========
    result = _normalize_image_format(text, base_prefix)
    
    # ========== 第二轮：只检查和替换最后文件名部分 ==========
    result = _normalize_image_paths(result, base_prefix, original_paths)
    
    return result


def _normalize_image_format(text: str, base_prefix: str) -> str:
    """
    第一轮：规范化图片格式，确保所有图片都是正确的 ![图片](/api/v1/knowledge/files/images/xxx.jpg) 格式
    
    处理各种格式破损的情况，并确保有正确的URL前缀
    """
    if not text:
        return text
    
    IMG_EXTENSIONS = r'(?:jpg|jpeg|png|gif|bmp|webp)'
    img_pattern = rf'([a-zA-Z0-9_\-./]+)\.({IMG_EXTENSIONS})'
    
    result = text
    matches = list(re.finditer(img_pattern, result, re.IGNORECASE))
    
    if not matches:
        return result
    
    # 从后往前处理，避免位置偏移
    for match in reversed(matches):
        filename_with_ext = match.group(0)
        file_start = match.start()
        file_end = match.end()
        
        mark_start = file_start
        mark_end = file_end
        
        # 向前查找是否已经有 ![图片]( 标记
        lookback_limit = max(0, file_start - 100)
        before = result[lookback_limit:file_start]
        open_marker_pos = before.rfind('![图片](')
        
        if open_marker_pos != -1:
            actual_open_pos = lookback_limit + open_marker_pos
            check_segment = result[actual_open_pos:file_start]
            if check_segment.startswith('![图片]('):
                mark_start = actual_open_pos
        
        # 向后查找是否有 )
        after = result[file_end:]
        close_paren_pos = after.find(')')
        if close_paren_pos != -1 and close_paren_pos < 20:
            middle = after[:close_paren_pos]
            if '\n' not in middle and '![图片](' not in middle:
                mark_end = file_end + close_paren_pos + 1
        
        # 提取纯文件名（去掉可能的路径前缀）
        pure_filename = filename_with_ext.split('/')[-1]
        
        # 构建完整的标准格式（包括固定URL前缀）
        full_url = base_prefix.rstrip('/') + '/images/' + pure_filename
        standard_format = f'![图片]({full_url})'
        
        result = result[:mark_start] + standard_format + result[mark_end:]
    
    # 清理嵌套格式
    nested_pattern = r'!\[图片\]\([^)]*!\[图片\]\(([^)]+\.(?:jpg|jpeg|png|gif|bmp|webp))\)[^)]*\)'
    while re.search(nested_pattern, result, re.IGNORECASE):
        result = re.sub(nested_pattern, r'![图片](\1)', result, flags=re.IGNORECASE)
    
    return result


def _normalize_image_paths(text: str, base_prefix: str, original_paths: List[str]) -> str:
    """
    第二轮：只规范化最后文件名部分（xxx.jpg），与原始路径匹配，匹配度低的删除
    
    步骤：
    1. 找到所有 ![图片](URL) 格式的图片
    2. 对每个图片：
       a. 提取最后文件名部分（xxx.jpg）
       b. 只与 original_paths 中的最后文件名部分匹配
       c. 如果匹配度高（>0.5），替换为正确路径
       d. 如果匹配度低（<=0.5），删除整个图片
    """
    if not text or not original_paths:
        return text
    
    # 匹配所有 ![图片](...) 格式
    img_tag_pattern = r'!\[图片\]\(([^)]+)\)'
    matches = list(re.finditer(img_tag_pattern, text, re.IGNORECASE))
    
    if not matches:
        return text
    
    result = text
    
    # 从后往前处理，避免位置偏移
    for match in reversed(matches):
        full_tag = match.group(0)
        url = match.group(1)
        tag_start = match.start()
        tag_end = match.end()
        
        # 从 URL 中只提取最后的文件名部分（xxx.jpg）
        filename = url.split('/')[-1]
        
        # 尝试匹配 - 只匹配最后文件名部分
        best_match = None
        best_score = 0
        
        generated_filename = filename.lower()
        
        for orig_path in original_paths:
            orig_filename = orig_path.split('/')[-1].lower()
            score = SequenceMatcher(None, generated_filename, orig_filename).ratio()
            if score > best_score:
                best_score = score
                best_match = orig_path
        
        if best_match and best_score > 0.5:
            # 匹配成功，替换为正确路径（保持固定URL前缀）
            # 只替换最后文件名部分，保持前缀不变
            pure_orig_filename = best_match.split('/')[-1]
            full_url = base_prefix.rstrip('/') + '/images/' + pure_orig_filename
            
            standard_format = f'![图片]({full_url})'
            result = result[:tag_start] + standard_format + result[tag_end:]
        else:
            # 匹配度低，删除整个图片
            result = result[:tag_start] + result[tag_end:]
    
    return result


def get_image_prompt_guidance() -> str:
    """获取图片格式处理的提示词指导"""
    return """【图片格式特别要求】
- 检索结果中的图片链接格式通常为：`![图片](/api/v1/knowledge/files/images/xxx.jpg)`
- 输出时必须严格保留此格式，不得修改、省略或截断
- 图片的 alt 文本必须保持为「图片」
- 图片 URL 必须完整包含 `/api/v1/knowledge/files/images` 前缀
- 不要将图片链接转换为纯文本描述
- 如果有多个图片，在对应位置分别引用，保持原始顺序
- 严禁修改图片文件名或路径结构
- 如果需要展示图片，直接使用原始的 `![图片](URL)` 格式即可"""

kxW"""
意图匹配工具：基于关键词 + embedding 语义相似度的两层确认意图判断

策略：
  第一层：关键词子串匹配（零延迟，覆盖 90%+ 常见表达）
  第二层：embedding 语义相似度匹配（兜底，捕获罕见/创意表达）
"""

from typing import List, Optional

# ──────────────────────────────────────────────
# 确认意图短语表（信息充足 / 开始行动）
# ──────────────────────────────────────────────
CONFIRM_PHRASES: List[str] = [
    # 直接确认
    "确认", "是的", "对", "好的", "没问题", "行", "可以", "OK",
    # 信息充足
    "足够", "够了", "齐了", "信息完整", "不用补充", "不需要补充",
    "就这些", "没有了", "信息够了", "不用再加了", "信息齐了",
    # 开始行动
    "开始诊断", "开始操作", "开始吧", "继续", "开始",
    # 复合确认
    "确认并继续", "正确", "没错", "对的", "是的开始", "就这样",
]

# 预计算的短语 embedding 缓存
_phrase_embeddings: Optional[List[List[float]]] = None


async def _ensure_phrase_embeddings() -> None:
    """确保确认短语的 embedding 已预计算（懒加载，仅首次调用时执行）"""
    global _phrase_embeddings
    if _phrase_embeddings is not None:
        return
    from modelsAPI.model_api import OpenaiAPI
    _phrase_embeddings = await OpenaiAPI.get_embeddings_batch_async(CONFIRM_PHRASES)
    print(f"[intent_matcher] 确认短语 embedding 预计算完成，共 {len(CONFIRM_PHRASES)} 条")


async def is_confirmation_intent(user_query: str, threshold: float = 0.78) -> bool:
    """
    判断用户输入是否为确认意图

    Args:
        user_query: 用户输入文本
        threshold: embedding 语义相似度阈值（默认 0.78）

    Returns:
        True 表示用户表达了确认/信息充足的意图
    """
    if not user_query or not user_query.strip():
        return True

    # 第一层：关键词子串匹配（零延迟）
    if any(kw in user_query for kw in CONFIRM_PHRASES):
        return True

    # 第二层：embedding 语义相似度匹配（兜底）
    await _ensure_phrase_embeddings()
    from modelsAPI.model_api import OpenaiAPI

    query_embedding = await OpenaiAPI.get_embeddings_async(user_query)
    similarities = OpenaiAPI.cosine_similarity_batch(query_embedding, _phrase_embeddings)
    max_sim = max(similarities) if similarities else 0.0

    if max_sim >= threshold:
        matched_phrase = CONFIRM_PHRASES[similarities.index(max_sim)]
        print(f"[intent_matcher] embedding 兜底命中: sim={max_sim:.3f}, "
              f"matched='{matched_phrase}', query='{user_query}'")
        return True

    return False

%Yx[D"""
舷号搜索策略模块
提供三级搜索策略：
1. 指定舷号搜索
2. 同型号所有舷号搜索
3. 全局搜索

新增功能：
- 智能舷号映射：支持舷号、舰名的智能识别和映射
"""
from typing import List, Dict, Any, Optional, Tuple
import random
import re
import httpx
from utils.function_tracker import get_all_callbacks
from tools.ship_model_db import load_ship_model_mapping
from tools.rag_tools import rag_search
from modelsAPI.model_api import OpenaiAPI
from config import KB_TREE_CONFIG


_kb_name_to_id_cache: Optional[Dict[str, str]] = None


async def _load_kb_tree() -> Dict[str, str]:
    """
    从知识库树 API 加载所有知识库，返回 {名称: kb_id} 的映射
    递归遍历树结构，带缓存，只请求一次
    """
    global _kb_name_to_id_cache
    if _kb_name_to_id_cache is not None:
        return _kb_name_to_id_cache

    url = KB_TREE_CONFIG.get("url", "")
    if not url:
        print("[ship_number_search] KB_TREE_CONFIG.url 未配置")
        return {}

    headers = {
        "accept": "application/json",
        "x-user-id": "1",
        "x-user-name": "testuser",
        "x-role": "admin",
    }

    try:
        async with httpx.AsyncClient(timeout=30.0, verify=False) as client:
            response = await client.get(url, headers=headers)
            if response.status_code != 200:
                print(f"[ship_number_search] 知识库树 API 请求失败: HTTP {response.status_code}")
                return {}

            result = response.json()

            if isinstance(result, list):
                top_nodes = result
            elif isinstance(result, dict):
                kb_data = result.get("data") or result.get("list") or {}
                top_nodes = kb_data.get("children", []) if isinstance(kb_data, dict) else []
            else:
                top_nodes = []

            name_to_id = {}

            def _collect(nodes):
                for node in nodes:
                    kb_name = node.get("name") or ""
                    kb_id = str(node.get("id", "")) if node.get("id") is not None else ""
                    if kb_name and kb_id:
                        name_to_id[kb_name] = kb_id
                    children = node.get("children", [])
                    if children:
                        _collect(children)

            _collect(top_nodes)

            _kb_name_to_id_cache = name_to_id
            return name_to_id
    except Exception as e:
        print(f"[ship_number_search] 加载知识库树失败: {str(e)}")
        return {}


async def resolve_kb_id(ship_number: str) -> Optional[str]:
    """
    根据舷号从知识库树中查找对应的真实 kb_id

    匹配策略：在知识库名称中查找包含该舷号的条目
    例如 ship_number="163"，知识库名称为 "163舰资料"，则匹配成功

    Args:
        ship_number: 舷号（如 "163"）

    Returns:
        匹配到的 kb_id，未找到返回 None
    """
    if not ship_number:
        return None

    name_to_id = await _load_kb_tree()

    if ship_number in name_to_id:
        return name_to_id[ship_number]

    for kb_name, kb_id in name_to_id.items():
        if re.search(rf'(?<!\d){re.escape(ship_number)}(?!\d)', kb_name):
            return kb_id

    return None


async def get_ship_numbers_by_model(ship_number: str) -> list:
    """
    根据舷号获取同型号的所有舷号

    Args:
        ship_number: 舷号

    Returns:
        list: 同型号的所有舷号列表，如果未找到则返回只包含输入舷号的列表
    """
    ship_number = str(ship_number).strip()
    ships = await load_ship_model_mapping()
    target_model = None
    for ship in ships:
        if ship["hull_number"] == ship_number:
            target_model = ship["model_name"]
            break
    if target_model:
        return [s["hull_number"] for s in ships if s["model_name"] == target_model]
    return [ship_number]


async def _build_ship_mapping_candidates() -> Dict[str, Dict[str, Any]]:
    """
    构建舷号映射候选词库
    从每艘舰的记录中构建候选词，支持舷号和舰名匹配
    """
    candidates = {}

    ships = await load_ship_model_mapping()

    model_numbers: Dict[str, List[str]] = {}
    for ship in ships:
        model = ship["model_name"]
        if model not in model_numbers:
            model_numbers[model] = []
        model_numbers[model].append(ship["hull_number"])

    for ship in ships:
        model = ship["model_name"]
        hull_number = ship["hull_number"]
        ship_name = ship.get("ship_name", "")
        numbers = model_numbers.get(model, [])

        mapping_info = {
            "model": model,
            "numbers": numbers.copy()
        }

        candidates[hull_number] = {
            "type": "number",
            "ship_number": hull_number,
            **mapping_info
        }

        if ship_name:
            candidates[ship_name] = {
                "type": "name",
                "ship_number": hull_number,
                **mapping_info
            }

    return candidates


_SHIP_MAPPING_CANDIDATES = None

async def get_ship_mapping_candidates() -> Dict[str, Dict[str, Any]]:
    """
    获取舷号映射候选词库（带缓存）
    """
    global _SHIP_MAPPING_CANDIDATES
    if _SHIP_MAPPING_CANDIDATES is None:
        _SHIP_MAPPING_CANDIDATES = await _build_ship_mapping_candidates()
    return _SHIP_MAPPING_CANDIDATES

async def smart_ship_number_mapping(
    user_input: str,
    similarity_threshold: float = 0.8
) -> Tuple[Optional[str], Optional[str], Optional[List[str]], str]:
    """
    智能舷号映射函数
    将用户输入的舷号/舰名映射到准确的舷号或型号

    Returns:
        Tuple: (matched_ship_number, matched_model, all_numbers, match_type)
        - matched_ship_number: 匹配到的具体舷号（舰名也会映射到对应舷号）
        - matched_model: 匹配到的型号名称
        - all_numbers: 该型号下的所有舷号列表
        - match_type: 匹配类型 ("exact_number", "exact_name", "embedding", "none")
    """
    if not user_input or not user_input.strip():
        return None, None, None, "none"

    user_input = user_input.strip()
    candidates = await get_ship_mapping_candidates()

    if user_input in candidates:
        info = candidates[user_input]
        match_type = f"exact_{info['type']}"
        model = info["model"]
        numbers = info["numbers"]
        ship_number = info.get("ship_number")

        return ship_number, model, numbers, match_type

    try:
        candidate_texts = list(candidates.keys())
        query_embedding = await OpenaiAPI.get_embeddings_async(user_input)
        candidate_embeddings = await OpenaiAPI.get_embeddings_batch_async(candidate_texts)

        best_score = -1
        best_idx = -1

        for idx, emb in enumerate(candidate_embeddings):
            score = OpenaiAPI.cosine_similarity(query_embedding, emb)
            if score > best_score:
                best_score = score
                best_idx = idx

        if best_score >= similarity_threshold and best_idx >= 0:
            matched_text = candidate_texts[best_idx]
            info = candidates[matched_text]
            model = info["model"]
            numbers = info["numbers"]
            ship_number = info.get("ship_number")

            print(f"[智能映射] 用户输入 '{user_input}' -> 匹配到 '{matched_text}' (相似度: {best_score:.3f}, 类型: {info['type']})")

            return ship_number, model, numbers, "embedding"
    except Exception as e:
        print(f"[智能映射] Embedding 匹配失败: {str(e)}")

    return None, None, None, "none"

def send_search_status(title: str, details: str):
    """发送搜索状态事件"""
    title_options = [f"🔍 {title}", f"🔎 {title}", f"📚 {title}"]
    start_event = {
        "type": "function_execution",
        "title": random.choice(title_options),
        "details": details
    }
    for callback in get_all_callbacks():
        try:
            callback(start_event)
        except Exception:
            pass

def convert_rag_result(rag_result):
    """将 rag_search 的返回结果转换为原来的格式"""
    if not rag_result or not rag_result.get("success", False):
        return []
    source_citation = rag_result.get("sourceCitation", {})
    flat_results = []
    for resource, items in source_citation.items():
        for item in items:
            flat_results.append(item)
    return flat_results

async def search_with_ship_number_strategy(
    base_query: str,
    ship_number: str,
    top_k: int = 5,
    search_type: str = "fault"
) -> Tuple[List[Dict[str, Any]], str, str, str]:
    """
    使用舷号三级搜索策略进行RAG检索
    返回: (rag_results, matched_kb_name, matched_kb_id, matched_ship_number)
    matched_ship_number: 映射后的舷号，未映射到具体舷号时为空字符串
    """
    rag_results = []
    matched_kb_name = ""
    matched_kb_id = ""

    matched_ship_number = None
    matched_model = None
    model_all_numbers = None
    match_type = "none"

    if ship_number and ship_number.strip():
        send_search_status(
            "正在智能识别",
            f"识别 '{ship_number}' 的含义（舷号/舰名）..."
        )

        matched_ship_number, matched_model, model_all_numbers, match_type = await smart_ship_number_mapping(ship_number)

        if match_type != "none":
            print(f"[智能映射结果] 输入='{ship_number}' -> 舷号={matched_ship_number}, 型号={matched_model}, 所有舷号={model_all_numbers}, 匹配类型={match_type}")
        else:
            print(f"[智能映射结果] 输入='{ship_number}' -> 未找到匹配，将使用原始值进行检索")

    if match_type in ["exact_number", "exact_name", "embedding"] and matched_ship_number:
        real_kb_id = await resolve_kb_id(matched_ship_number)
        if real_kb_id:
            send_search_status(
                "正在指定舷号检索",
                f"使用舷号 {matched_ship_number} 进行检索..."
            )

            rag_query = f"{base_query}"

            try:
                rag_result_raw = await rag_search(rag_query, top_k=top_k, kb_id=real_kb_id)
                rag_results = convert_rag_result(rag_result_raw)

                if rag_results:
                    print(f"步骤1 - 舷号 {matched_ship_number} 检索完成，返回 {len(rag_results)} 条结果")
                    for item in rag_results:
                        if isinstance(item, dict):
                            found_kb_name = item.get("kb_name", "")
                            found_kb_id = item.get("kb_id", "")
                            if found_kb_name and not matched_kb_name:
                                matched_kb_name = str(found_kb_name).strip()
                            if found_kb_id and not matched_kb_id:
                                matched_kb_id = str(found_kb_id).strip()
                    return rag_results, matched_kb_name, matched_kb_id, matched_ship_number or ""
            except Exception as e:
                print(f"步骤1 - 舷号 {matched_ship_number} 检索失败: {str(e)}")
        else:
            print(f"步骤1 - 舷号 {matched_ship_number} 无对应知识库，跳过指定舷号检索")

    if match_type in ["exact_number", "exact_name", "embedding"] and model_all_numbers:
        send_search_status(
            "正在型号检索",
            f"识别为型号 '{matched_model}'，使用该型号所有舷号 {', '.join(model_all_numbers)} 进行检索..."
        )

        for num in model_all_numbers:
            rag_query = f"{base_query}"

            try:
                real_kb_id = await resolve_kb_id(num)
                if not real_kb_id:
                    continue
                rag_result_raw = await rag_search(rag_query, top_k=top_k, kb_id=real_kb_id)
                current_results = convert_rag_result(rag_result_raw)

                if current_results:
                    rag_results.extend(current_results)
                    print(f"步骤2 - 舷号 {num} 检索完成，返回 {len(current_results)} 条结果")

                    if not matched_kb_name:
                        for item in current_results:
                            if isinstance(item, dict):
                                found_kb_name = item.get("kb_name", "")
                                found_kb_id = item.get("kb_id", "")
                                if found_kb_name and not matched_kb_name:
                                    matched_kb_name = str(found_kb_name).strip()
                                if found_kb_id and not matched_kb_id:
                                    matched_kb_id = str(found_kb_id).strip()
            except Exception as e:
                print(f"步骤2 - 舷号 {num} 检索失败: {str(e)}")

        if rag_results:
            return rag_results, matched_kb_name, matched_kb_id, matched_ship_number or ""

    if ship_number and ship_number.strip() and match_type == "none":
        real_kb_id = await resolve_kb_id(ship_number)
        if real_kb_id:
            send_search_status(
                "正在指定舰名检索",
                f"使用舰名 {ship_number} 进行检索..."
            )

            rag_query = f"{base_query}"

            try:
                rag_result_raw = await rag_search(rag_query, top_k=top_k, kb_id=real_kb_id)
                rag_results = convert_rag_result(rag_result_raw)

                if rag_results:
                    print(f"步骤1 - 舷号 {ship_number} 检索完成，返回 {len(rag_results)} 条结果")
                    for item in rag_results:
                        if isinstance(item, dict):
                            found_kb_name = item.get("kb_name", "")
                            found_kb_id = item.get("kb_id", "")
                            if found_kb_name and not matched_kb_name:
                                matched_kb_name = str(found_kb_name).strip()
                            if found_kb_id and not matched_kb_id:
                                matched_kb_id = str(found_kb_id).strip()
                    return rag_results, matched_kb_name, matched_kb_id, matched_ship_number or ""
            except Exception as e:
                print(f"步骤1 - 舷号 {ship_number} 检索失败: {str(e)}")
        else:
            print(f"步骤1 - 舷号 {ship_number} 无对应知识库，跳过指定舰名检索")

        model_ship_numbers = await get_ship_numbers_by_model(ship_number)
        if len(model_ship_numbers) > 1 or (len(model_ship_numbers) == 1 and ship_number not in model_ship_numbers):
            send_search_status(
                "正在同型号检索",
                f"使用同型号舷号 {', '.join(model_ship_numbers)} 进行检索..."
            )

            for num in model_ship_numbers:
                if num == ship_number:
                    continue

                rag_query = f"{base_query}"

                try:
                    real_kb_id = await resolve_kb_id(num)
                    if not real_kb_id:
                        continue
                    rag_result_raw = await rag_search(rag_query, top_k=top_k, kb_id=real_kb_id)
                    current_results = convert_rag_result(rag_result_raw)

                    if current_results:
                        rag_results.extend(current_results)
                        print(f"步骤2 - 舷号 {num} 检索完成，返回 {len(current_results)} 条结果")

                        if not matched_kb_name:
                            for item in current_results:
                                if isinstance(item, dict):
                                    found_kb_name = item.get("kb_name", "")
                                    found_kb_id = item.get("kb_id", "")
                                    if found_kb_name and not matched_kb_name:
                                        matched_kb_name = str(found_kb_name).strip()
                                    if found_kb_id and not matched_kb_id:
                                        matched_kb_id = str(found_kb_id).strip()
                except Exception as e:
                    print(f"步骤2 - 舷号 {num} 检索失败: {str(e)}")

            if rag_results:
                return rag_results, matched_kb_name, matched_kb_id, matched_ship_number or ""

    send_search_status(
        "正在全局检索",
        "未找到舷号相关资料，进行全局检索..."
    )

    try:
        rag_result_raw = await rag_search(base_query, top_k=top_k)
        rag_results = convert_rag_result(rag_result_raw)

        if rag_results:
            print(f"步骤3 - 全局检索完成，返回 {len(rag_results)} 条结果")
            for item in rag_results:
                if isinstance(item, dict):
                    found_kb_name = item.get("kb_name", "")
                    found_kb_id = item.get("kb_id", "")
                    if found_kb_name and not matched_kb_name:
                        matched_kb_name = str(found_kb_name).strip()
                    if found_kb_id and not matched_kb_id:
                        matched_kb_id = str(found_kb_id).strip()
    except Exception as e:
        print(f"步骤3 - 全局检索失败: {str(e)}")
        rag_results = []

    return rag_results, matched_kb_name, matched_kb_id, matched_ship_number or ""

w<x)v։import os
import re
import uuid
import logging
import tempfile
from datetime import datetime

from docx import Document
from docx.shared import Pt, RGBColor, Inches
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from lxml import etree

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger(__name__)

_MML2OMML_XSLT = None
_MML2OMML_LOADED = False


def _load_mml2omml_xslt():
    global _MML2OMML_XSLT, _MML2OMML_LOADED
    if _MML2OMML_LOADED:
        return _MML2OMML_XSLT
    _MML2OMML_LOADED = True

    _this_dir = os.path.dirname(os.path.abspath(__file__))
    search_paths = [
        os.path.join(_this_dir, "MML2OMML.XSL"),
        r"C:\Program Files\Microsoft Office\root\Office16\MML2OMML.XSL",
        r"C:\Program Files (x86)\Microsoft Office\root\Office16\MML2OMML.XSL",
        r"C:\Program Files\Microsoft Office\Office16\MML2OMML.XSL",
        r"C:\Program Files (x86)\Microsoft Office\Office16\MML2OMML.XSL",
        "/usr/share/mml2omml/MML2OMML.XSL",
        "/app/utils/MML2OMML.XSL",
    ]
    logger.info(f"[公式] 开始搜索 MML2OMML.XSL，共 {len(search_paths)} 个路径")
    for path in search_paths:
        exists = os.path.isfile(path)
        logger.info(f"[公式] 检查路径: {path} -> {'存在' if exists else '不存在'}")
        if exists:
            try:
                _MML2OMML_XSLT = etree.parse(path)
                logger.info(f"[公式] ✓ MML2OMML.XSL 加载成功: {path}")
                return _MML2OMML_XSLT
            except Exception as e:
                logger.error(f"[公式] ✗ MML2OMML.XSL 加载失败: {path}, 错误: {e}")

    logger.warning("[公式] ✗ 未找到 MML2OMML.XSL，公式将使用 matplotlib 图片回退方式渲染")
    return None


class MarkdownWordGenerator:

    def __init__(self):
        try:
            self.doc = Document()
            self.cache_dir = os.path.join(tempfile.gettempdir(), "latex_formula_cache")
            os.makedirs(self.cache_dir, exist_ok=True)
            self.formula_cache = {}
            self._omml_available = _load_mml2omml_xslt() is not None
            logger.info(f"[公式] MarkdownWordGenerator 初始化完成, OMML可用: {self._omml_available}")
        except Exception as e:
            logger.error(f"初始化 MarkdownWordGenerator 失败: {e}")
            raise

    def set_font(self, run, size=11, bold=False):
        try:
            run.font.name = "微软雅黑"
            rPr = run._element.get_or_add_rPr()
            rFonts = rPr.find(qn('w:rFonts'))
            if rFonts is None:
                rFonts = run._element.makeelement(qn('w:rFonts'), {})
                rPr.insert(0, rFonts)
            rFonts.set(qn('w:eastAsia'), "微软雅黑")
            run.font.size = Pt(size)
            run.font.bold = True if bold else False
        except Exception as e:
            logger.warning(f"设置字体时出错: {e}")

    def add_heading(self, text, level):
        try:
            p = self.doc.add_heading(level=level)
            size_map = {1: 18, 2: 16, 3: 14}
            font_size = size_map.get(level, 12)
            self._add_rich_text(p, text, default_size=font_size, default_bold=True)
        except Exception as e:
            logger.error(f"添加标题失败 '{text}': {e}")

    def add_paragraph(self, text):
        try:
            if not text.strip():
                return
            p = self.doc.add_paragraph()

            indent_chars = 0
            temp_text = text
            while temp_text.startswith('\u3000'):
                indent_chars += 1
                temp_text = temp_text[1:]

            if indent_chars >= 2:
                p.paragraph_format.first_line_indent = Inches(0.5)
                text = temp_text
            elif indent_chars == 1:
                p.paragraph_format.first_line_indent = Inches(0.25)
                text = temp_text

            self._add_rich_text(p, text)
        except Exception as e:
            logger.error(f"添加段落失败: {e}")

    def _add_rich_text(self, paragraph, text, default_size=11, default_bold=False):
        if not text:
            return

        pattern = r'\*\*(.+?)\*\*'
        last_end = 0

        for match in re.finditer(pattern, text):
            start, end = match.span()
            if start > last_end:
                plain = text[last_end:start]
                if plain:
                    run = paragraph.add_run(plain)
                    self.set_font(run, size=default_size, bold=default_bold)

            bold_content = match.group(1)
            if bold_content:
                run = paragraph.add_run(bold_content)
                self.set_font(run, size=default_size, bold=True)

            last_end = end

        if last_end < len(text):
            remaining = text[last_end:]
            if remaining:
                run = paragraph.add_run(remaining)
                self.set_font(run, size=default_size, bold=default_bold)

    @staticmethod
    def _preprocess_latex_for_omml(latex: str) -> str:
        replacements = {
            r'\leqslant': r'\leq',
            r'\geqslant': r'\geq',
            r'\nleqslant': r'\nleq',
            r'\ngeqslant': r'\ngeq',
            r'\eqslantless': r'\leq',
            r'\eqslantgtr': r'\geq',
            r'\varnothing': r'\emptyset',
            r'\dfrac': r'\frac',
            r'\tfrac': r'\frac',
            r'\boldsymbol': r'\mathbf',
            r'\bm': r'\mathbf',
        }
        for old, new in replacements.items():
            latex = latex.replace(old, new)

        latex = re.sub(r'\\mathrm\s*\{([^}]*)\}', lambda m: r'\mathrm{' + m.group(1) + '}', latex)
        latex = re.sub(r'\\text\s*\{([^}]*)\}', lambda m: r'\mathrm{' + m.group(1) + '}', latex)
        latex = re.sub(r'\\textbf\s*\{([^}]*)\}', lambda m: r'\mathbf{' + m.group(1) + '}', latex)
        latex = re.sub(r'\\textit\s*\{([^}]*)\}', lambda m: r'\mathit{' + m.group(1) + '}', latex)

        return latex

    def _latex_to_omml(self, latex_str):
        logger.info(f"[公式] LaTeX->OMML 开始, 原始: '{latex_str}'")
        try:
            import latex2mathml.converter
            processed = self._preprocess_latex_for_omml(latex_str)
            logger.info(f"[公式] LaTeX 预处理后: '{processed}'")
            mathml = latex2mathml.converter.convert(processed)
            logger.info(f"[公式] MathML 生成成功, 长度: {len(mathml)}")
            mathml_tree = etree.fromstring(mathml.encode('utf-8'))
            xslt = _load_mml2omml_xslt()
            if xslt is None:
                logger.warning("[公式] XSLT 不可用，OMML 转换跳过")
                return None
            transform = etree.XSLT(xslt)
            omml_tree = transform(mathml_tree)
            omml_root = omml_tree.getroot()
            logger.info(f"[公式] ✓ OMML 转换成功: '{latex_str}'")
            return omml_root
        except Exception as e:
            logger.error(f"[公式] ✗ LaTeX->OMML 转换失败 '{latex_str}': {e}", exc_info=True)
            return None

    def _add_omml_to_paragraph(self, paragraph, latex_str):
        omml = self._latex_to_omml(latex_str)
        if omml is not None:
            paragraph._element.append(omml)
            return True
        return False

    def _latex_to_image(self, latex_str, inline=True):
        """matplotlib 回退方案：将公式渲染为 PNG 图片"""
        logger.info(f"[公式] LaTeX->图片 回退, 原始: '{latex_str}'")
        try:
            import matplotlib
            matplotlib.use('Agg')
            import matplotlib.pyplot as plt

            processed = self._preprocess_latex_for_omml(latex_str)
            logger.info(f"[公式] LaTeX 预处理后: '{processed}'")

            if latex_str in self.formula_cache:
                cached = self.formula_cache[latex_str]
                if os.path.isfile(cached):
                    logger.info(f"[公式] 使用缓存: {cached}")
                    return cached

            filename = os.path.join(self.cache_dir, f"{uuid.uuid4()}.png")
            fig_width = 6 if not inline else 4
            fig_height = 1.2 if not inline else 0.8
            font_size = 20 if not inline else 16

            fig = plt.figure(figsize=(fig_width, fig_height))
            fig.text(0.5, 0.5, f"${processed}$", fontsize=font_size, ha='center', va='center')
            plt.axis('off')
            fig.savefig(filename, dpi=300, bbox_inches="tight", pad_inches=0.05)
            plt.close(fig)

            self.formula_cache[latex_str] = filename
            logger.info(f"[公式] ✓ 图片渲染成功: {filename}")
            return filename
        except Exception as e:
            logger.error(f"[公式] ✗ LaTeX->图片 渲染失败 '{latex_str}': {e}", exc_info=True)
            try:
                plt.close('all')
            except Exception:
                pass
            return None

    def _insert_formula(self, paragraph, latex_str, inline=True):
        """统一公式插入方法：优先 OMML，回退 matplotlib 图片"""
        if self._omml_available:
            if self._add_omml_to_paragraph(paragraph, latex_str):
                return True
            logger.warning(f"[公式] OMML 失败，回退 matplotlib: '{latex_str}'")

        img_path = self._latex_to_image(latex_str, inline=inline)
        if img_path:
            try:
                width = Inches(0.7) if inline else Inches(2.5)
                run = paragraph.add_run()
                run.add_picture(img_path, width=width)
                return True
            except Exception as e:
                logger.error(f"[公式] ✗ 图片插入失败: {e}")

        run = paragraph.add_run(f" {latex_str} ")
        self.set_font(run, size=9)
        logger.warning(f"[公式] ✗ 所有方式失败，以纯文本插入: '{latex_str}'")
        return False

    def _add_rich_text_with_formulas(self, paragraph, text, default_size=11, default_bold=False):
        if not text:
            return

        has_formula = bool(re.search(r'\$[^$]+?\$', text))
        has_image = bool(self._extract_image_urls(text))

        if not has_formula and not has_image:
            self._add_rich_text(paragraph, text, default_size=default_size, default_bold=default_bold)
            return

        if has_image:
            img_urls = self._extract_image_urls(text)
            last_end = 0
            for start, end, url in img_urls:
                before_text = text[last_end:start]
                if before_text and before_text.strip():
                    self._add_rich_text_with_formulas(paragraph, before_text, default_size=default_size, default_bold=default_bold)
                self.add_image(url, width_inches=4.5)
                last_end = end
            after_text = text[last_end:]
            if after_text and after_text.strip():
                p = self.doc.add_paragraph()
                self._add_rich_text_with_formulas(p, after_text, default_size=default_size, default_bold=default_bold)
            return

        segments = re.split(r'(\$[^$]+?\$)', text)
        for segment in segments:
            if not segment:
                continue
            if segment.startswith('$') and segment.endswith('$') and len(segment) > 2:
                latex_content = segment[1:-1].strip()
                self._insert_formula(paragraph, latex_content, inline=True)
            else:
                self._add_rich_text(paragraph, segment, default_size=default_size, default_bold=default_bold)

    def add_list(self, text, numbered=False, number=None):
        try:
            text = text.strip()
            if not text:
                return

            if re.match(r'^[-_*]{2,}$', text):
                return

            if numbered and number is not None:
                p = self.doc.add_paragraph()
                p.paragraph_format.left_indent = Pt(18)
                p.paragraph_format.first_line_indent = Pt(-18)
                num_run = p.add_run(f"{number}. ")
                self.set_font(num_run, bold=False)
                self._add_rich_text_with_formulas(p, text)
            else:
                p = self.doc.add_paragraph(style="List Bullet")
                self._add_rich_text_with_formulas(p, text)

        except Exception as e:
            logger.error(f"添加列表失败: {e}")

    def add_sub_list(self, text):
        try:
            text = text.strip()
            if not text:
                return
            if re.match(r'^[-_*]{2,}$', text):
                return

            try:
                p = self.doc.add_paragraph(style="List Bullet 2")
            except KeyError:
                p = self.doc.add_paragraph(style="List Bullet")
                p.paragraph_format.left_indent = Pt(36)
            self._add_rich_text_with_formulas(p, text)
        except Exception as e:
            logger.error(f"添加子列表失败: {e}")

    def _convert_url_to_local_path(self, url: str) -> str:
        if not url:
            return None
        from urllib.parse import urlparse
        path = urlparse(url).path
        if path.startswith('/picture/'):
            docker_path = f"/app/picture/{path[len('/picture/'):]}"
            if os.path.isfile(docker_path):
                return docker_path
            try:
                project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
                local_path = os.path.join(project_root, "picture", path[len('/picture/'):])
                if os.path.isfile(local_path):
                    return local_path
            except Exception:
                pass
            return None
        return None

    @staticmethod
    def _get_http_headers(url: str) -> dict:
        headers = {}
        if "/api/v1/knowledge/" in url:
            try:
                from config import RAG_CONFIG
                headers["x-user-id"] = str(RAG_CONFIG.get("x-user-id", "1"))
                headers["x-user-name"] = str(RAG_CONFIG.get("x-user-name", "testuser"))
                headers["x-role"] = str(RAG_CONFIG.get("x-role", "admin"))
            except Exception:
                headers["x-user-id"] = "1"
                headers["x-user-name"] = "testuser"
                headers["x-role"] = "admin"
        return headers

    def add_image(self, url_or_path: str, width_inches: float = 5.5):
        if not url_or_path:
            return

        try:
            import io
            image_stream = None

            if os.path.isfile(url_or_path):
                image_stream = url_or_path
            elif url_or_path.startswith("http://") or url_or_path.startswith("https://"):
                local_path = self._convert_url_to_local_path(url_or_path)
                if local_path and os.path.isfile(local_path):
                    image_stream = local_path
                else:
                    import requests
                    headers = self._get_http_headers(url_or_path)
                    resp = requests.get(url_or_path, timeout=15, headers=headers, proxies={"http": None, "https": None})
                    resp.raise_for_status()
                    content_type = resp.headers.get("Content-Type", "")
                    logger.info(f"HTTP 下载完成, Content-Type: {content_type}, 大小: {len(resp.content)} bytes")
                    if not content_type.startswith("image/"):
                        logger.error(f"响应不是图片类型: {content_type}")
                        self.add_paragraph(f"[图片加载失败: {url_or_path}]")
                        return
                    image_stream = io.BytesIO(resp.content)
            else:
                logger.warning(f"图片路径无效: {url_or_path}")
                return

            from PIL import Image as PilImage
            if isinstance(image_stream, str):
                pil_img = PilImage.open(image_stream)
            else:
                pil_img = PilImage.open(image_stream)
            png_stream = io.BytesIO()
            pil_img.convert("RGBA" if pil_img.mode in ("RGBA", "P") else "RGB").save(png_stream, format="PNG")
            png_stream.seek(0)

            p = self.doc.add_paragraph()
            p.alignment = WD_ALIGN_PARAGRAPH.CENTER
            run = p.add_run()
            run.add_picture(png_stream, width=Inches(width_inches))
            logger.info(f"图片插入成功: {url_or_path}")

        except Exception as e:
            logger.error(f"插入图片失败 '{url_or_path}': {e!r}", exc_info=True)
            self.add_paragraph(f"[图片加载失败: {url_or_path}]")

    def _extract_image_urls(self, line_content):
        """
        从一行文本中提取所有图片URL，支持多种格式：
        - ![alt](url)
        - ![alt]`url`
        - ! `url`
        返回 [(start, end, url), ...]
        """
        results = []

        # 格式1: ![alt](url)
        for m in re.finditer(r'!\[([^\]]*)\]\(([^)]+)\)', line_content):
            url = m.group(2).strip()
            if url.startswith('`') and url.endswith('`'):
                url = url[1:-1]
            results.append((m.start(), m.end(), url))

        # 格式2: ![alt]`url`  (未被格式1匹配的)
        for m in re.finditer(r'!\[([^\]]*)\]\s*`([^`]+)`', line_content):
            url = m.group(2).strip()
            already = any(s <= m.start() and e >= m.end() for s, e, _ in results)
            if not already:
                results.append((m.start(), m.end(), url))

        # 格式3: ! `url`  (模型常见的破损格式)
        for m in re.finditer(r'!\s*`([^`]+\.(?:jpg|jpeg|png|gif|bmp|webp))`', line_content, re.IGNORECASE):
            url = m.group(1).strip()
            already = any(s <= m.start() and e >= m.end() for s, e, _ in results)
            if not already:
                results.append((m.start(), m.end(), url))

        results.sort(key=lambda x: x[0])
        return results

    def add_table(self, lines):
        try:
            rows = []
            for line in lines:
                line = line.strip("|")
                cells = [c.strip() for c in line.split("|")]
                rows.append(cells)

            if not rows:
                return

            header = rows[0]
            data_start_index = 1
            if len(rows) > 1 and all(c.startswith('-') or c == '' for c in rows[1]):
                data_start_index = 2

            data = rows[data_start_index:]
            max_cols = len(header)

            table = self.doc.add_table(rows=len(data) + 1, cols=max_cols)
            table.style = "Table Grid"

            for i, cell in enumerate(header):
                if i < max_cols:
                    table.rows[0].cells[i].text = cell

            for r, row in enumerate(data):
                for c, val in enumerate(row):
                    if c < max_cols:
                        table.rows[r + 1].cells[c].text = val

            logger.info("表格添加成功")
        except Exception as e:
            logger.error(f"添加表格失败: {e}")

    def _add_horizontal_rule(self):
        p = self.doc.add_paragraph()
        pPr = p._element.get_or_add_pPr()
        pBdr = p._element.makeelement(qn('w:pBdr'), {})
        bottom = p._element.makeelement(qn('w:bottom'), {
            qn('w:val'): 'single',
            qn('w:sz'): '6',
            qn('w:space'): '1',
            qn('w:color'): 'CCCCCC',
        })
        pBdr.append(bottom)
        pPr.append(pBdr)

    def parse(self, markdown):
        lines = markdown.split("\n")
        table_buffer = []
        block_formula = []
        in_block_formula = False

        i = 0
        while i < len(lines):
            line = lines[i]
            line_stripped = line.rstrip()
            line_content = line_stripped.lstrip()

            # 1. 处理块级公式
            if line_content.startswith("$$"):
                if not in_block_formula:
                    remaining = line_content[2:]
                    close_idx = remaining.find("$$")
                    if close_idx >= 0:
                        formula = remaining[:close_idx].strip()
                        after_formula = remaining[close_idx + 2:].strip()
                        p = self.doc.add_paragraph()
                        p.alignment = WD_ALIGN_PARAGRAPH.CENTER
                        self._insert_formula(p, formula, inline=False)
                        if after_formula:
                            self.add_paragraph(after_formula)
                    else:
                        in_block_formula = True
                        block_formula = []
                        if remaining.strip():
                            block_formula.append(remaining.strip())
                else:
                    remaining = line_content[2:]
                    in_block_formula = False
                    formula = "".join(block_formula).strip()
                    p = self.doc.add_paragraph()
                    p.alignment = WD_ALIGN_PARAGRAPH.CENTER
                    self._insert_formula(p, formula, inline=False)
                    if remaining.strip():
                        self.add_paragraph(remaining.strip())
                i += 1
                continue

            if in_block_formula:
                block_formula.append(line)
                i += 1
                continue

            # 2. 处理表格
            if line_content.startswith("|") and line_content.endswith("|"):
                table_buffer.append(line_stripped)
                i += 1
                continue
            else:
                if table_buffer:
                    self.add_table(table_buffer)
                    table_buffer = []

            # 空行跳过
            if not line_stripped:
                i += 1
                continue

            # 3. 水平分隔线
            if re.match(r'^\s*[-*_]{3,}\s*$', line_stripped):
                self._add_horizontal_rule()
                i += 1
                continue

            # 4. 标题
            heading_match = re.match(r'^(#{1,3})\s+(.*)', line_content)
            if heading_match:
                level = len(heading_match.group(1))
                text = heading_match.group(2)
                self.add_heading(text, level)
                i += 1
                continue

            # 5. 有序列表（带子列表支持）
            list_match_ordered = re.match(r'^(\d+)\.\s*(.*)', line_content)
            if list_match_ordered:
                number = int(list_match_ordered.group(1))
                text = list_match_ordered.group(2)
                self.add_list(text, numbered=True, number=number)

                i += 1
                while i < len(lines):
                    next_line = lines[i]
                    next_stripped = next_line.rstrip()
                    sub_match = re.match(r'^[\s\t]+[-*]\s*(.*)', next_stripped)
                    if sub_match:
                        sub_text = sub_match.group(1)
                        self.add_sub_list(sub_text)
                        i += 1
                    elif (next_stripped.startswith('   ') or next_stripped.startswith('\t')):
                        sub_content = next_stripped.strip()
                        if sub_content and not re.match(r'^\d+\.\s', sub_content):
                            self.add_sub_list(sub_content)
                            i += 1
                        else:
                            break
                    else:
                        break
                continue

            # 6. 无序列表
            is_bold_line = line_content.startswith('**')
            if not is_bold_line:
                list_match_unordered = re.match(r'^\s*[-*]\s+(.*)', line_stripped)
                if not list_match_unordered:
                    m = re.match(r'^\s*-([^-].*)$', line_stripped)
                    if m and m.group(1).strip():
                        list_match_unordered = m

                if list_match_unordered:
                    text = list_match_unordered.group(1).strip()
                    if text:
                        self.add_list(text, numbered=False)
                    i += 1
                    continue

            # 7. 图片链接 - 统一提取所有格式的图片URL
            img_urls = self._extract_image_urls(line_content)

            if img_urls:
                has_only_img = (len(img_urls) == 1 and
                                line_content.strip().startswith('!') and
                                img_urls[0][0] == 0)

                if has_only_img:
                    _, _, url = img_urls[0]
                    self.add_image(url)
                else:
                    p = self.doc.add_paragraph()
                    last_end = 0
                    for start, end, url in img_urls:
                        before_text = line_content[last_end:start].strip()
                        if before_text:
                            self._add_rich_text_with_formulas(p, before_text)
                        self.add_image(url, width_inches=4.5)
                        p = self.doc.add_paragraph()
                        last_end = end
                    after_text = line_content[last_end:].strip()
                    if after_text:
                        self._add_rich_text_with_formulas(p, after_text)
                i += 1
                continue

            # 8. 普通链接
            if line_content.startswith("["):
                match = re.match(r'\[(.*?)\]\((.*?)\)', line_content)
                if match:
                    p = self.doc.add_paragraph()
                    run = p.add_run(match.group(1))
                    run.font.color.rgb = RGBColor(0, 0, 255)
                    run.font.underline = True
                i += 1
                continue

            # 9. 普通段落
            p = self.doc.add_paragraph()

            indent_chars = 0
            temp_line = line_stripped
            while temp_line.startswith('\u3000'):
                indent_chars += 1
                temp_line = temp_line[1:]

            if indent_chars >= 2:
                p.paragraph_format.first_line_indent = Inches(0.5)
            elif indent_chars == 1:
                p.paragraph_format.first_line_indent = Inches(0.25)

            self._add_rich_text_with_formulas(p, line_content)

            i += 1

        if table_buffer:
            self.add_table(table_buffer)

    def generate(self, markdown, title=None, output=None, images=None):
        try:
            if title:
                logger.info(f"添加文档标题: {title}")
                p = self.doc.add_paragraph()
                run = p.add_run(title)
                self.set_font(run, 20, True)
                p.alignment = WD_ALIGN_PARAGRAPH.CENTER

            logger.info("开始解析 Markdown 内容")
            self.parse(markdown)

            if images:
                self._append_images_section(images)

            if not output:
                timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
                output = f"report_{timestamp}.docx"

            logger.info(f"正在保存文件: {output}")
            self.doc.save(output)

            if os.path.exists(output):
                file_size = os.path.getsize(output)
                logger.info(f"文件保存成功: {output}, 大小: {file_size} bytes")
                return output
            else:
                logger.error(f"文件保存后未找到: {output}")
                raise FileNotFoundError(f"File {output} was not created.")

        except Exception as e:
            logger.error(f"生成报告过程中发生严重错误: {e}", exc_info=True)
            raise

    def _append_images_section(self, images):
        try:
            self.add_heading("附件图片", level=2)

            for idx, img in enumerate(images, 1):
                if isinstance(img, dict):
                    url = img.get('url', '')
                    summary = img.get('summary', '')
                else:
                    url = str(img)
                    summary = ''

                p = self.doc.add_paragraph()
                run = p.add_run(f"图片{idx}：")
                self.set_font(run, bold=True)

                if url:
                    self.add_image(url, width_inches=4)

                if summary:
                    p = self.doc.add_paragraph()
                    run = p.add_run(f"说明：{summary}")
                    self.set_font(run, size=10)

                self.doc.add_paragraph()

            logger.info(f"图片附件部分添加完成，共 {len(images)} 张图片")
        except Exception as e:
            logger.error(f"添加图片附件部分失败: {e}")


def generate_report_word(markdown, title=None, output=None, images=None):
    logger.info("=== 开始生成报告 ===")
    try:
        generator = MarkdownWordGenerator()

        if images:
            logger.info(f"准备插入 {len(images)} 张图片")

        file_path = generator.generate(markdown, title=title, output=output, images=images)
        logger.info(f"=== 报告生成完成: {file_path} ===")
        return file_path
    except Exception as e:
        logger.critical(f"报告生成失败: {e}")
        raise


if __name__ == "__main__":
    md = r"""
## **测试报告 - OMML公式和图片**

### **一、行内公式**

温度要求 $ \leqslant 40 ^ { \circ } \mathrm { C } $，不得超过。

公差范围 $ \geqslant 0.05 \ \mathrm { mm } $ 以内合格。

### **二、列表中的公式**

1. 温度 $ \leqslant 40 ^ { \circ } \mathrm { C } $ 要求
2. 间隙 $ \leqslant 0.05 \ \mathrm { mm } $ 标准

- 清洁轴颈 $ \geqslant 0.05 \ \mathrm { mm } $


### **四、图片测试**

![图片](http://192.168.0.46:11000/api/v1/knowledge/files/images/56b1c0a02ff03d9d202627e88603e6671d3f193511d98a9fab0daf8687e6a9fa.jpg)
"""

    try:
        result_path = generate_report_word(md)
        print(f"报告已生成，路径: {result_path}")
    except Exception as e:
        print(f"程序执行出错: {e}")
        import traceback
        traceback.print_exc()
Yx!e"""
工作流注册表 - 主代理与 app 共用
主代理阶段四根据此配置路由到所有注册的子 agent；
app 据此执行对应工作流。
添加新工作流时，在此配置 WORKFLOW_CONFIG 与 ROUTE_DESCRIPTIONS。
"""
# ============================================================================
# =============== 工作流配置区域 - 添加新工作流时只需修改这里 ===============
# ============================================================================
# 格式：
#   "route_flag": {
#       "module": "workflows.workflow_xxx",
#       "function": "run_xxx_workflow",
#       "is_async": True/False,
#   }
# ============================================================================

WORKFLOW_CONFIG = {
    "fault_diagnosis": {
        "module": "workflows.workflow_fault_diagnosis",
        "function": "run_fault_diagnosis_workflow",
        "is_async": True,
    },
    "qa": {
        "module": "workflows.workflow_qa",
        "function": "run_qa_workflow",
        "is_async": True,
    },
    "问题排查": {
        "module": "workflows.workflow_fault_diagnosis",
        "function": "run_fault_diagnosis_workflow",
        "is_async": True,
    },
    "spare_parts_statistics": {
        "module": "workflows.workflow_spare_parts_statistics",
        "function": "run_spare_parts_statistics_workflow",
        "is_async": True,
    },
    "rules": {
        "module": "workflows.workflow_qa",
        "function": "run_qa_workflow",
        "is_async": True,
    },
    "other": {
        "module": "workflows.workflow_fault_diagnosis",
        "function": "run_fault_diagnosis_workflow",
        "is_async": True,
#
#        "module": "workflows.workflow_other",
#        "function": "run_other_workflow",
#        "is_async": True,
    },
    "report":{
#        "module": "workflows.workflow_qa_report",
#        "function": "run_qa_report_agent",
#        "is_async": True,
        "module": "workflows.workflow_fault_diagnosis",
        "function": "run_fault_diagnosis_workflow",
        "is_async": True,
    },
    "百科问答":{
        "module": "workflows.workflow_baike",
        "function": "run_baike_workflow",
        "is_async": True,
    },
    "操作使用":{
        "module": "workflows.workflow_operate",
        "function": "run_operate_workflow",
        "is_async": True,
    },
    "统计":{
        "module": "workflows.workflow_statistics",
        "function": "run_statistics_workflow",
        "is_async": True,
    }

}

# 路由标志 -> 任务分类描述（供主代理阶段四 LLM 使用）
ROUTE_DESCRIPTIONS = {
  "fault_diagnosis": """
   - 特征：用户描述**当前或近期发生的设备异常、报警、性能下降等具体故障现象**，需要分析原因或定位问题。
   - 关键词：报警、异常、异响、冒烟、过热、无法启动、突然停机、振动大、压力低、温度高、故障代码、不工作
   - 示例：
     • 主机滑油压力突然降到0.2MPa并报警  
     • 柴油机启动后冒黑烟且转速不稳  
     • 舵机发出异常噪音，疑似齿轮损坏  
   - 注意：若历史记录中包含“请补充”、“【需要更多信息】”，通常属于此类，因已聚焦具体故障场景。
     当用户问题中只有舷号、设备或故障现象时属于此类，舷号一般为连续的阿拉伯数字如“101”,"111","122","163"，"16","17","554","602","545","985","31","3261","799","905","781"等,或者数字后加舰，比如“101舰","199舰","18舰"等。
  """,

  "qa": """
   - 特征：询问定义、原理、结构、功能、分类、标准配置、常见类型、安全规范等**一般性知识**；也包括对专业术语、现象、部件作用的解释。  
     **即使问题表述模糊、不完整、缺少上下文，只要涉及船舶、机械、电气、动力等技术内容，均优先归为此类。**
   - 关键词：什么是、如何工作、为什么、请问、介绍、解释、有哪些、常见、典型、一般、作用、组成、是不是、叫什么
   - 示例：
     • 船舶主发动机有哪些常见故障类型？  
     • 涡轮增压器的工作原理是什么？  
     • 主机由哪些主要部件组成？  
     • 什么是MAN B&W柴油机？  
   - 注意：
     • **本类作为技术相关问题的默认兜底类别**——凡涉及设备、系统、部件、工况、参数等技术语境的问题，若无法明确归入 fault_diagnosis / repair / spare_parts_statistics / rules，则优先视为 qa。
  """,

  "repair": """
   - 特征：用户明确请求**维修方法、操作步骤、检修流程、更换方案或现场处理建议**，通常在已知故障或需预防性维护时提出。
   - 关键词：怎么修、如何维修、维修步骤、检修方法、更换、拆卸、安装、处理、修复、维护、保养、调整
   - 示例：
     • 主机喷油器漏油，怎么更换？  
     • 给出主机缸套磨损的维修方案  
     • 如何拆卸增压器进行检修？
  """,

  "spare_parts_statistics": """
   - 特征：用户需要对**备品备件的数量、使用记录、库存、消耗趋势、预测需求或成本分析**进行查询或统计。
   - 关键词：备件、备品、库存、数量、统计、预测、分析、消耗、需求、清单、台账、寿命、更换周期、用了多少、还剩多少
   - 示例：
     • 统计过去一年主机喷油嘴的使用数量  
     • 预测下季度所需空冷器备件数量  
     • 主机活塞环的平均更换周期是多少？
   - 注意：若仅问“某个部件是不是备件”或“这个备件叫什么名字”，属于知识问答（qa），而非本类。
  """,

  "rules": """
   - 特征：用户询问与船舶设备维修、检验、安全、环保、保密等相关的**国家法规、军用标准（如GJB）、行业规范、船级社要求或管理制度**。
   - 关键词：法规、标准、规范、规定、合规、条例、依据、要求、准则、制度、认证、资质、船级社、CCS、IMO、SOLAS、MARPOL、资格
   - 示例：
     • 船舶主机修理需遵循哪些GJB标准？  
     • IMO对主机排放有哪些强制要求？  
     • 舰船维修单位需要哪些资质？  
     • 保密资格申请流程是什么？
   - 注意：若问题提到“标准里有没有…”但未指明具体法规/标准名称，且无“法规”“标准”等关键词，可先归为 qa；一旦明确提及“法规”“标准”“规范”“SOLAS”等，则归为 rules。
  """,
  "other": """
  - 特征：**完全不涉及新的技术问题、故障诊断、维修请求、备件统计、法规查询或报告生成**，而是针对**已有对话内容、方案、步骤或文本的反馈、修正、补充、顺序调整或格式优化**。典型场景包括：
    • 指出之前提供的操作步骤有误（如“异物清理步骤有误”）
    • 要求调整操作顺序（如“这一步应当先怎样，然后再怎么操作，最后……”）
    • 对生成内容提出修改意见（如“步骤有误/有补充”“请重写第三点”）
    • 请求优化语言、格式或结构（如“请用更简洁的方式表达”）
    • 闲聊、非技术性确认或与当前技术任务无关的交互

  - 注意：
    • **只要用户意图是修正、补充或调整已有内容，而非提出新问题，即使涉及技术术语，也应归为 other**。
    • 不要将此类反馈误判为 repair 或 qa——它们不是在问“该怎么修”或“原理是什么”，而是在说“你刚才说的不对/不全”。
    • 此类通常出现在多轮对话中，是对前文输出的回应。
  """,
  "report": """
   - 特征：用户明确要求**生成、整理、导出或汇总**某种形式的文档、报表、清单或总结材料。通常涉及将分散的故障记录、维修历史、备件数据或问答内容整合成结构化文本（如日报、周报、故障分析报告、维修总结、备件消耗表等）。
   - 关键词：生成报告、写总结、导出表格、整理清单、汇总数据、形成文档、日报、周报、月报、分析报告、维修记录单、台账报表
   - 示例：
     • 请根据本周的故障记录生成一份主机系统运行分析报告
     • 总结这次对话
     • 导出过去一年的备件消耗统计报告
     • 帮我写一份关于此次主机停机事故的详细处理总结
  """
}

VALID_ROUTE_FLAGS = tuple(WORKFLOW_CONFIG.keys())
A8$xC100644 =0.2.0 ⛲CK)wZS100644 =2.0.0 "LV
%k!y>k100644 __init__.py .[d_e40000 __pycache__ yՈ
5?B100644 history_manager.py R=ùS@uAݟ8SK100644 workflow_baike.py OxH.f@Џ9100644 workflow_fault_diagnosis.py r\gfX	1(q+}100644 workflow_operate.py 'ܹ4v'_100644 workflow_other.py Ӟ	kzBV100644 workflow_other_report.py &AgU{100644 workflow_qa_report.py J  90F8fA100644 workflow_statistics.py Uj77VC100644 workflow_utils.py 8$:TI y뵺xRequirement already satisfied: langgraph in /usr/local/lib/python3.10/dist-packages (1.0.3)
Collecting langgraph
  Downloading langgraph-1.1.3-py3-none-any.whl (168 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 168.1/168.1 KB 685.8 kB/s eta 0:00:00
Requirement already satisfied: langgraph-checkpoint-postgres in /usr/local/lib/python3.10/dist-packages (3.0.5)
Requirement already satisfied: langchain-core>=0.1 in /usr/local/lib/python3.10/dist-packages (from langgraph) (1.1.0)
Collecting langgraph-sdk<0.4.0,>=0.3.0
  Downloading langgraph_sdk-0.3.12-py3-none-any.whl (95 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 95.8/95.8 KB 3.9 MB/s eta 0:00:00
Requirement already satisfied: xxhash>=3.5.0 in /usr/local/lib/python3.10/dist-packages (from langgraph) (3.6.0)
Requirement already satisfied: pydantic>=2.7.4 in /usr/local/lib/python3.10/dist-packages (from langgraph) (2.12.4)
Requirement already satisfied: langgraph-checkpoint<5.0.0,>=2.1.0 in /usr/local/lib/python3.10/dist-packages (from langgraph) (3.0.1)
Collecting langgraph-prebuilt<1.1.0,>=1.0.8
  Downloading langgraph_prebuilt-1.0.8-py3-none-any.whl (35 kB)
Requirement already satisfied: psycopg-pool>=3.2.0 in /usr/local/lib/python3.10/dist-packages (from langgraph-checkpoint-postgres) (3.3.0)
Requirement already satisfied: orjson>=3.11.5 in /usr/local/lib/python3.10/dist-packages (from langgraph-checkpoint-postgres) (3.11.7)
Requirement already satisfied: psycopg>=3.2.0 in /usr/local/lib/python3.10/dist-packages (from langgraph-checkpoint-postgres) (3.3.3)
Requirement already satisfied: jsonpatch<2.0.0,>=1.33.0 in /usr/local/lib/python3.10/dist-packages (from langchain-core>=0.1->langgraph) (1.33)
Requirement already satisfied: langsmith<1.0.0,>=0.3.45 in /usr/local/lib/python3.10/dist-packages (from langchain-core>=0.1->langgraph) (0.4.46)
Requirement already satisfied: packaging<26.0.0,>=23.2.0 in /usr/local/lib/python3.10/dist-packages (from langchain-core>=0.1->langgraph) (25.0)
Requirement already satisfied: pyyaml<7.0.0,>=5.3.0 in /usr/local/lib/python3.10/dist-packages (from langchain-core>=0.1->langgraph) (6.0.3)
Requirement already satisfied: tenacity!=8.4.0,<10.0.0,>=8.1.0 in /usr/local/lib/python3.10/dist-packages (from langchain-core>=0.1->langgraph) (9.1.2)
Requirement already satisfied: typing-extensions<5.0.0,>=4.7.0 in /usr/local/lib/python3.10/dist-packages (from langchain-core>=0.1->langgraph) (4.15.0)
Requirement already satisfied: ormsgpack>=1.12.0 in /usr/local/lib/python3.10/dist-packages (from langgraph-checkpoint<5.0.0,>=2.1.0->langgraph) (1.12.0)
Requirement already satisfied: httpx>=0.25.2 in /usr/local/lib/python3.10/dist-packages (from langgraph-sdk<0.4.0,>=0.3.0->langgraph) (0.28.1)
Requirement already satisfied: typing-inspection>=0.4.2 in /usr/local/lib/python3.10/dist-packages (from pydantic>=2.7.4->langgraph) (0.4.2)
Requirement already satisfied: annotated-types>=0.6.0 in /usr/local/lib/python3.10/dist-packages (from pydantic>=2.7.4->langgraph) (0.7.0)
Requirement already satisfied: pydantic-core==2.41.5 in /usr/local/lib/python3.10/dist-packages (from pydantic>=2.7.4->langgraph) (2.41.5)
Requirement already satisfied: httpcore==1.* in /usr/local/lib/python3.10/dist-packages (from httpx>=0.25.2->langgraph-sdk<0.4.0,>=0.3.0->langgraph) (1.0.9)
Requirement already satisfied: anyio in /usr/local/lib/python3.10/dist-packages (from httpx>=0.25.2->langgraph-sdk<0.4.0,>=0.3.0->langgraph) (4.11.0)
Requirement already satisfied: certifi in /usr/local/lib/python3.10/dist-packages (from httpx>=0.25.2->langgraph-sdk<0.4.0,>=0.3.0->langgraph) (2025.11.12)
Requirement already satisfied: idna in /usr/local/lib/python3.10/dist-packages (from httpx>=0.25.2->langgraph-sdk<0.4.0,>=0.3.0->langgraph) (3.11)
Requirement already satisfied: h11>=0.16 in /usr/local/lib/python3.10/dist-packages (from httpcore==1.*->httpx>=0.25.2->langgraph-sdk<0.4.0,>=0.3.0->langgraph) (0.16.0)
Requirement already satisfied: jsonpointer>=1.9 in /usr/local/lib/python3.10/dist-packages (from jsonpatch<2.0.0,>=1.33.0->langchain-core>=0.1->langgraph) (3.0.0)
Requirement already satisfied: requests>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from langsmith<1.0.0,>=0.3.45->langchain-core>=0.1->langgraph) (2.32.5)
Requirement already satisfied: zstandard>=0.23.0 in /usr/local/lib/python3.10/dist-packages (from langsmith<1.0.0,>=0.3.45->langchain-core>=0.1->langgraph) (0.25.0)
Requirement already satisfied: requests-toolbelt>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from langsmith<1.0.0,>=0.3.45->langchain-core>=0.1->langgraph) (1.0.0)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.0.0->langsmith<1.0.0,>=0.3.45->langchain-core>=0.1->langgraph) (2.5.0)
Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.0.0->langsmith<1.0.0,>=0.3.45->langchain-core>=0.1->langgraph) (3.4.4)
Requirement already satisfied: exceptiongroup>=1.0.2 in /usr/local/lib/python3.10/dist-packages (from anyio->httpx>=0.25.2->langgraph-sdk<0.4.0,>=0.3.0->langgraph) (1.3.1)
Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio->httpx>=0.25.2->langgraph-sdk<0.4.0,>=0.3.0->langgraph) (1.3.1)
Installing collected packages: langgraph-sdk, langgraph-prebuilt, langgraph
  Attempting uninstall: langgraph-sdk
    Found existing installation: langgraph-sdk 0.2.9
    Uninstalling langgraph-sdk-0.2.9:
      Successfully uninstalled langgraph-sdk-0.2.9
  Attempting uninstall: langgraph-prebuilt
    Found existing installation: langgraph-prebuilt 1.0.5
    Uninstalling langgraph-prebuilt-1.0.5:
      Successfully uninstalled langgraph-prebuilt-1.0.5
  Attempting uninstall: langgraph
    Found existing installation: langgraph 1.0.3
    Uninstalling langgraph-1.0.3:
      Successfully uninstalled langgraph-1.0.3
Successfully installed langgraph-1.1.3 langgraph-prebuilt-1.0.8 langgraph-sdk-0.3.12
Aݺ!x"""
工作流模块
包含所有工作流Agent
"""
from .workflow_fault_diagnosis import run_fault_diagnosis_workflow

# 其他工作流暂未实现，待后续添加
# from .workflow_repair import run_repair_workflow
# from .workflow_statistics import run_statistics_workflow
# from .workflow_qa import run_qa_workflow
# from .workflow_report import run_report_workflow

__all__ = [
    "run_fault_diagnosis_workflow",
    # "run_repair_workflow",
    # "run_statistics_workflow",
    # "run_qa_workflow",
    # "run_report_workflow"
]

)cx9100644 __init__.cpython-310.pyc yu=ƧozG100644 __init__.cpython-312.pyc xm?׏Dʑc100644 history_manager.cpython-312.pyc uug	6z='100644 workflow_baike.cpython-310.pyc \-LM pe͸V100644 workflow_baike.cpython-312.pyc P.eO )rqq100644 workflow_fault_common.cpython-310.pyc u%tG3߫100644 workflow_fault_define.cpython-310.pyc c3٭z70	Imyh2100644 workflow_fault_diagnosis.cpython-310.pyc ~!
E>}uy100644 workflow_fault_diagnosis.cpython-312.pyc >)iA^	l-q100644 workflow_operate.cpython-310.pyc =?Sg<E100644 workflow_operate.cpython-312.pyc ?#HIZ?Q100644 workflow_other.cpython-310.pyc DeZ%ҔW{4100644 workflow_other_report.cpython-310.pyc 3<Scn7fرr100644 workflow_other_report.cpython-312.pyc ^Z=ذw|5M100644 workflow_qa.cpython-310.pyc ]C).wjRP'_100644 workflow_qa.cpython-312.pyc )(>wݩFE100644 workflow_qa_report.cpython-310.pyc \UyϜ%lM_r~NH100644 workflow_rag_define.cpython-310.pyc jf,t#2Y100644 workflow_repair.cpython-310.pyc 䬯Ì+{j/KU100644 workflow_repair.cpython-312.pyc HqNk-=mA%}100644 workflow_repair_report.cpython-310.pyc =S~Kȏ2t=O/3100644 workflow_repair_report.cpython-312.pyc RkXⲾg100644 workflow_report.cpython-312.pyc %=yla^X5~pP100644 workflow_spare_parts_statistics.cpython-310.pyc ç7d#>100644 workflow_statistics.cpython-312.pyc 7WU;8wh߈100644 workflow_utils.cpython-312.pyc 48sHf%Zwxo
    li.                     @   s   d Z ddlmZ dgZdS )u,   
工作流模块
包含所有工作流Agent
   )run_fault_diagnosis_workflowr   N)__doc__workflow_fault_diagnosisr   __all__ r   r   /app/workflows/__init__.py<module>   s    	Y^x[
    ѱMj.                         d Z ddlmZ dgZy)u,   
工作流模块
包含所有工作流Agent
   )run_fault_diagnosis_workflowr   N)__doc__workflow_fault_diagnosisr   __all__     De:\ZKYNLP\Hjunproject\project0506\wx-agent\app\workflows\__init__.py<module>r
      s    C #r   ]{pFx^#
    ұMj              	           d Z ddlZddlmZmZmZmZ  G d d      Z e       Zdedeee	ef      fdZ
	 	 dd	eee	ef      d
edede	fdZdedefdZddedede	fdZdedee	ef   fdZy)u   
统一历史对话管理器
整合所有分散的 parse_history / _parse_history / build_history_str / filter_image_urls 逻辑
    N)AnyDictListOptionalc            
       6   e Zd ZdZ	 	 ddedefdZdedeee	ef      fdZ
dd	eee	ef      d
ee   deee	ef      fdZ	 	 dd	eee	ef      dee   dee   de	fdZd	eee	ef      deee	ef      fdZddedede	fdZdedee	ef   fdZededefd       Zy)HistoryManageruT   统一的历史对话管理器，提供解析、截断、格式化、过滤等功能max_messagesmax_assistant_charsc                      || _         || _        y)u   
        Args:
            max_messages: 保留的最近消息条数
            max_assistant_chars: assistant 角色内容截断字符数
        Nr	   r
   )selfr	   r
   s      Ke:\ZKYNLP\Hjunproject\project0506\wx-agent\app\workflows\history_manager.py__init__zHistoryManager.__init__   s     )#6     history_messagereturnc                     |sg S 	 t        |t              rt        j                  |      n|}t        |t              r|| j
                   d S g S # t        $ r g cY S w xY w)u   
        解析历史消息为列表，保留最近 max_messages 条。
        兼容字符串和列表输入，替代所有 parse_history / _parse_history。
        N)
isinstancestrjsonloadslistr	   	Exception)r   r   datas      r   parsezHistoryManager.parse   sd    
 I	2<_c2R4::o.XgD0:40F4***+,NBN 	I	s   AA A AANmessageskeep_recentc                 6    |sg S ||n| j                   }|| d S )u.   按数量截断，保留最近 keep_recent 条N)r	   )r   r   r   ns       r   truncatezHistoryManager.truncate+   s*    I&2K8I8I}r   recent_countassistant_truncatec                    |sy||n| j                   }||n| j                  }|| d }g }|D ]  }t        |t              s|j	                  dd      }	|j	                  d      xs dj                         }
|	dk(  r|j                  d|
        c|	dk(  si|j                  d|
d|          |rd	j                  |      S dS )
u   
        格式化为 "用户: xxx\n助手: xxx" 纯文本字符串，用于 prompt 注入。
        替代 build_history_str。
         Nrolecontentuseru   用户: 	assistantu   助手: 
)r	   r
   r   dictgetstripappendjoin)r   r   r!   r"   r   truncrecentpartsmr%   r&   s              r   to_prompt_strzHistoryManager.to_prompt_str4   s     (4L$:K:K&8&D"$JbJb1"#A!T"uuVR(55+1r88:6>LL8G9!56[(LL8GFUO+<!=>  $)tyy0b0r   c                     |sg S g }|D ]Q  }t        |t              s|j                  d      s&|j                  d      s8|j                  |d   |d   d       S |S )u   
        格式化为 OpenAI messages 列表，直接传入 LLM。
        用于百科问答等需要完整消息格式的场景。
        r%   r&   )r%   r&   )r   r*   r+   r-   )r   r   resultr2   s       r   to_openai_messagesz!HistoryManager.to_openai_messagesN   sZ    
 IA!T"quuV}y9IqyQy\JK  r   exclude_lastc                     |sy	 t        |t              rt        j                  |      n|}t        |t              sy|r|r|dd }t        j                  |d      S # t        j                  t
        f$ r Y yw xY w)u  
        处理前端传入的历史消息：解析、移除当前用户消息、序列化。
        对应 app.py 中 history_message 预处理逻辑。

        Args:
            history_message: 前端传入的历史消息，支持 str 或 list
            exclude_last: 是否移除最后一条（当前用户消息），默认 True

        Returns:
            处理后的 JSON 字符串
        r$   NFensure_ascii)r   r   r   r   JSONDecodeError	TypeErrorr   dumps)r   r   r7   r   s       r   preprocess_from_requestz&HistoryManager.preprocess_from_request]   sx     	2<_c2R4::o.XgD $%D9Dzz$U33 $$i0 		s   'A A98A9c                 d    | j                  |      }|rt        j                  |d      nd}||dS )un  
        一步完成历史消息解析，返回 history_message(str) + history_messages(list) 双字段。
        用于各工作流入口初始化 state，消除重复的 parse_history 调用。

        Args:
            history_message: 历史消息，支持 str 或 list

        Returns:
            {"history_message": str, "history_messages": list}
        Fr:   r$   )r   history_messages)r   r   r>   )r   r   parsedraws       r   init_historyzHistoryManager.init_historyw   s1     O,8>djje4B#&FCCr   c                    | s| S 	 t        | t              rt        j                  |       n| }t        |t              s|S g }|D ]  }t        |t              s|j                  |       &|j                         }|j                  d      }t        |t              rg }|D ]p  }t        |t              r<|j                  d      dk(  s(|j                  dd      }|s=|j                  |       Ot        |t              s`|j                  |       r |sdj                  |      |d<   |j                  |       |j                  |       
 |S # t        j                  t
        f$ r | cY S w xY w)u   
        过滤历史消息中的图片URL，将多模态内容转为纯文本。
        替代 main_agent.filter_image_urls。
        r&   typetextr$   )r   r   r   r   r<   r=   r   r*   r-   copyr+   r.   )	r   rA   filtered_messagesmsgnew_msgr&   
text_partscontent_item
text_values	            r   filter_image_urlsz HistoryManager.filter_image_urls   sU    ""	#>HZ]>^tzz/:ds *D1###Cc4(!((-hhjGggi(G'4(
$+L!,5'++F3v=)5)9)9&")EJ) * 1 1* =#L#6")),7 %, )+)<GI&%,,W5!((1/ $2 ! A $$i0 	#""	#s   'E E.-E.
   i,  )N)NNT)__name__
__module____qualname____doc__intr   r   r   r   r   r   r   r    r3   r6   boolr?   rD   staticmethodrO    r   r   r   r   
   sS   ^ #&77 !7S T$sCx.-A d38n!5 HSM ]abfgjlogobp]q  '+,0	1tCH~&1 sm1 %SM	1
 
144S#X+? DcSVhDX 4s 4$ 4Z] 44DC DDcN D" *!3 *!3 *! *!r   r   r   r   c                 ,    t         j                  |       S !   兼容旧调用的模块级函数)_default_managerr   r   s    r   parse_historyr`      s    !!/22r   rA   r!   r"   c                 D    t        ||      }|j                  | ||      S )r]   r   )r!   r"   )r   r3   )rA   r!   r"   mgrs       r   build_history_strrc      s+     lHZ
[C-L]oppr   c                 ,    t         j                  |       S r\   )r   rO   r_   s    r   rO   rO      s    ++O<<r   r7   c                 0    t         j                  | |      S )r]   )r7   )r^   r?   )r   r7   s     r   r?   r?      s    33OR^3__r   c                 ,    t         j                  |       S r\   )r^   rD   r_   s    r   rD   rD      s    ((99r   rP   rR   )rV   r   typingr   r   r   r   r   r^   r   r`   rW   rc   rO   rX   r?   rD   rZ   r   r   <module>rh      s   
  , ,i! i!^ "# 33 34S#X+? 3 !q4S>*qq q 		q=s =s =
`S ` `PS `
:# :$sCx. :r   "㰻xCOo
    ib                     @   s  d Z ddlmZmZmZmZmZ ddlmZm	Z	m
Z
 ddlmZ ddlmZmZ ddlmZ ddlmZmZmZ ddlZddlZddlZddlZG d	d
 d
eZdedeeef fddZdedeeef fddZededeeef fddZdededeeeef  fddZededeeef fddZ dd Z!		d'dededededeeef f
d d!Z"e#d"krddlZd#d$gZ$d%d& Z%e&e%  dS dS )(u  
工作流：普通问答Agent（使用LangGraph）
输入：文本（转化后和原文本query）、图片描述、语音文本
步骤：
1. 使用RAG和GraphRAG检索相关信息
2. 生成回答
使用 OpenaiAPI 方法调用大模型，尽可能使用异步
    )	TypedDictOptionalDictAnyList)
StateGraphSTARTEND)none_schema)rag_search_toolgraph_rag_search)	OpenaiAPI)track_function_callsget_current_stream_handlerget_all_callbacksNc                   @   s   e Zd ZU dZeed< eed< eed< eed< eed< eeeef  ed< e	eeeef   ed< e	e ed	< eed
< eeeef  ed< eeeef  ed< eed< dS )QAStateu   普通问答工作流状态extracted_textcombined_queryretrieval_query
route_flaghistory_messagehistory_messagesrag_search_resultgraph_search_resultresponseactionssuggestedReplieserror_messageN)
__name__
__module____qualname____doc__str__annotations__r   r   r   r    r$   r$   /app/workflows/workflow_qa.pyr      s   
 r   statereturnc              
   C   s   ddl }| ddpd}g }|rHz"t|tr||}n|}t|tr.|dd }W d|iS W d|iS  tyG } z	W Y d}~d|iS d}~ww d|iS )u,  
    知识问答步骤：获取问答类历史信息
    问答工作流只关注历史问答记录，用于提供上下文
    支持格式：[{'role': 'user', 'content': '...'}, {'role': 'assistant', 'content': '...'}]
    返回消息列表（history_message已经在app.py中过滤过了）
    r   Nr    ir   )jsonget
isinstancer"   loadslist	Exception)r&   r)   r   r   history_dataer$   r$   r%   get_qa_history_context0   s&   


r1   c              
      sz  ddl }| dp| dpd }| dg pg }|r#|dd ng }z	|j|dd	}W n ty;   t|}Y nw |sBd
|iS d}|r^t|D ]}|ddkr]|dd } nqJd|pbd d| d| d}|}	z#tj|ddI dH }
|
r|
 d}|rt	|dkrd|vr|}	W n ty } zt
d|  W Y d}~nd}~ww t
d| t
d||	  d
||	 iS )u   
    使用历史上下文对当前问题进行query重写，生成适合RAG/图谱检索的独立查询语句。
    只让大模型在有限的最近历史中挑选与当前问题语义相关的内容进行融合，避免简单拼接全量历史。
    r   Nr   r   r(   r   iF)ensure_asciir   roleusercontentu  
你是一个专业的检索query重写助手，负责根据对话历史和当前用户问题，生成**适合向量检索/RAG 的单条查询语句**。

请严格遵守以下要求：
1. 只融合与当前问题语义强相关的**最近几轮对话信息**，不要机械拼接全部历史。
2. 消除指代和省略（例如“这个”“刚才那个问题”“上面说的故障”等），补全成自洽、完整的描述。
3. 不要加入与用户问题无关的背景信息，不要过度扩展检索范围。
4. 输出必须是一句自然的中文问句或陈述句，便于检索；不要包含条目符号、编号或解释性文字。
5. 只输出改写后的query本身：
   - 不要输出说明文字
   - 不要包含「改写结果：」「检索query：」等前缀
   - 不要添加引号

【特别提示】
- 请优先参考**上一轮用户的问题**来重写本轮query。
- 上一轮用户的问题是：u	   （无）u;   

【对话历史（JSON 格式，已按时间排序）】
u   

【当前用户问题】
u5   

请给出最终用于检索的单条中文query。
)modelu   “”"'   
u   query 重写失败: u   原始检索query:u   重写后检索query:)r)   r*   stripdumpsr.   r"   reversedr   open_api_chat_without_thinkinglenprint)r&   r)   original_queryr   trimmed_historyhistory_strlast_user_querymsgpromptrewritten_queryresult	candidater0   r$   r$   r%   rewrite_query_with_historyM   sR   
rH   c              
      s2  d}|  ddkrd}|  dp|  dp|  dd}d	|v r(|d	d
d
 }td| |  dd}d	|v r?|d	d
d
 }z<|rOt||ddI dH }nt|ddI dH }t|ddI dH }t|trl|ng t|trw|dW S ddW S  t	y } zg ddt| dW  Y d}~S d}~ww )u7   
    进行文本知识检索和图谱知识检索
    Nr   rules3r   r   r   r(   u   用户问题：   u   Graph 检索query   )querykb_idtop_k)rM   rO   )r   r   u   检索失败: )r   r   r   )
r*   splitr>   r   ainvoker   r+   r-   r"   r.   )r&   rN   rM   r   rag_resultsgraph_resultsr0   r$   r$   r%   search_rag_and_graph   sL    
rT   answerquestionc           
   
      s"  d| d| dd  d}zft j|dddI dH }td|tj}|rj|d	}t|}t|t	rjt
|d
krjg }|dd
 D ]}t|tr`d|v r`d|v r`|t|d t|d d qAt
|d
krj|W S ddddddgW S  ty }	 zddddddgW  Y d}	~	S d}	~	ww )uc   
    生成针对问答结果的建议回复问题
    使用大模型生成两个相关问题
    u   
你是一个专业的工业设备问答助手。根据以下问答内容，生成两个用户可能关心的后续问题。

【用户问题】
u   

【回答内容】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与当前问答内容相关，能够帮助用户进一步了解相关信息
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
T)r6   json_outputz\[.*\]r      titler5   )rY   r5   u-   这个设备的具体工作原理是什么？u!   还有哪些相关的知识点？)r   r<   researchDOTALLgroupr)   r,   r+   r-   r=   dictappendr"   r.   )
rU   rV   rD   rF   
json_matchjson_strsuggested_repliesformatted_repliesreplyr0   r$   r$   r%   generate_suggested_replies_qa   s@   




re   c              
      s  |  dd}|  dg }|  dd}|  dg pg }td| zg }|dd D ]}t|trA| d	p7d }|rA|| q*td
| |rK|nd}|r[ddd t|D nd}	td| |dv rhd}td| d|rr|nd d|	 d| d}
d	tdt	t fdd}zt
jdddd|
dgdI dH }|d  }|d! }W n ty   |r|n|r|d" nd#}|rd$n|rd%nd&}Y nw ||}td'| |d$krd(}nd)}td*| d+| d,| d-| g}d.t|d/|dd0  d1 d2}t D ]}z|| W q ty   Y qw |}|  d3d4krd5}nd6}d7| d8}|d97 }g }|r2|| | d:|r:|nd; d<}|d|d t
jd||d=I dH }d"dljd>d|jd?}|rg| nd@}d	tdtffdAdB}||}dCtdDt	t dtfdEdF dPd	tdDt	t dtf fdHdI}|||dJ}tdK| t||I dH }|g dL|dMW S  ty } zdNt| g g dOW  Y d}~S d}~ww )Qu"   
    正在生成问答结果
    r   r(   r   r   r   zhistory_message(qa)N   text0000000000000000u   当前未明确描述问题r8   c                 S   s$   g | ]\}}d |d  d| qS )z  [rK   z] r$   ).0irg   r$   r$   r%   
<listcomp>  s   $ z#generate_answer.<locals>.<listcomp>u     (无RAG结果)123456u1    图谱检索完成，但未返回有效数据。654321u   # 任务
你是一个信息源选择器。请从以下两个来源中，选出**唯一一条**与用户问题最相关的原始字符串。

# 来源
## 1. 图谱结果
u   (无图谱结果)u   

## 2. RAG检索列表
u"   

# 用户问题
- 用户问题：u*  

# 选择规则
1. 优先选择与用户问题最匹配的结果
2. 图谱结果通常更精准，RAG结果通常更完整
3. 必须选择一条结果输出

# 输出要求（JSON格式）
{
    "type": "graph或rag或none",
    "answer": "选中的原始字符串，必须与原文完全一致"
}r'   c                 S   s(   dd l }d}||| |j}tt|S )Nr   z7images/[a-zA-Z0-9_\-./]+\.(?:jpg|jpeg|png|gif|bmp|webp))rZ   findall
IGNORECASEr-   set)rg   rZ   patternmatchesr$   r$   r%   extract_image_paths;  s   z,generate_answer.<locals>.extract_image_pathsTu   你是一个严格的"信息源选择器"。你的任务是从给定的候选集中，找出与用户问题**最相关、最直接**的一条字符串，并原样输出。r4   )r3   r5   )r6   rW   system_promptmessagesrU   typer   NO_RELEVANT_RESULTgraphragnoneu   提取到的原始图片路径:u   图谱u   文本u   选择的rag信息u!   ✨当前使用的检索类型为u   ✨本次检索策略为u   ✨当前索引查询类型为function_executionu	   内容为2   z...)rv   rY   detailsr   rI   uB   舰船修理相关的法规、规范、行业标准及技术文件uH   工业设备的结构原理、维护规程、故障诊断与维修操作u   我是一个专业的u3   知识问答助手，必须严格遵守以下规则u  1. **知识边界限制**
    - 所有回答**必须且仅能**基于用户提供的【RAG检索结果】和【图谱检索结果】；
    - **严禁使用外部知识、常识、经验类比或自行推理**。

2. **内容保真要求**
    - **图片必须原样保留**：若检索结果中包含图片链接（保证图片输出格式为`![图片](URL)`），且与问题相关，**必须在回答中按原始格式完整输出该图片**，不得省略、替换或用文字描述代替；
    - **表格与公式**：若检索结果含 HTML 表格或 LaTeX 公式，且对回答有帮助，必须在对应位置**原意转化为 Markdown 表格或 $$...$$ 公式**,并且在 $$...$$ 前后必须加空格；
    - **不得编造**任何未在检索结果中出现的图片链接、零件号、扭矩值、测试标准等。

3. **输出严谨性**
    - 不得遗漏输入中的关键信息（如故障现象、设备型号）；
    - 不得添加与问题无关的内容（如通用安全提示，除非检索结果包含）；
    - 若结合历史对话，请仅用于理解上下文，**不得将历史内容当作事实依据**；
    - **严禁重复输出已有内容，编造检索信息中不存在的内容**。
        u0   

        # 检索到的相关信息：
        u   无uP  

        # 输出要求：
        1. 如果检索信息中包含 URL，请务必在相关步骤中自然嵌入展示使用（保证图片输出格式为`![图片](URL)`）；
        2. 如果检索信息中包含 html 表格，必须将表格转为 Markdown 表格格式输出。如果检索信息中没有 html 表格，则不输出表格形式内容；
        3. 如果检索信息中包含 LaTeX 公式，必须将公式转为 $$...$$ 公式格式输出，并在 $$...$$ 前后加空格。
        # 重要约束：
        1. 所有 URL（包括图片连接）必须与检索信息保持一致；不得裁剪、转义或改写；
        2. 不能虚构知识库未提及的图片、表格、零件号或步骤；
        3. 若检索信息中包含多张图片，请在对应步骤中分别引用；
        4. 若信息不足无法导致无法生成完整方案，需明确指出确实项（如“缺少轴承安装间隙标准”）
        5. 不得生成检索信息中没有的相关内容，如：“维修工具”在检索信息中没有则不输出相关信息。
        - 表格必须以 markdown 格式输出，务必务必
        - 所有连接必须完整，务必务必
        - 不得生成'(注：)'或者其他无用的解释内容如: 没用检索到图片连接所以不展示图片
        - 不要生成重复的图片
        )r6   rt   ru   z<think>.*?</think>)flagsu   抱歉，无法生成回答。c                    sX   d}|  d|}  dd| }  dd| } |  |d}  dd| }  d	d
| } | S )Nz DOUBLE_DOLLAR z$$z	(?<!\s)\$z $z\$(?!\s)z$ z(?<!\s)\$\$z $$z
\$\$(?!\s)z$$ )replacesub)rg   placeholder)rZ   r$   r%   normalize_latex_spacing  s   z0generate_answer.<locals>.normalize_latex_spacinggenerated_pathoriginal_pathsc           	      S   s~   ddl m} |s
| S | dd  }d }d}|D ]}|dd  }|d || }||kr4|}|}q|r=|dkr=|S | S )Nr   )SequenceMatcher/g      ?)difflibr   rP   lowerratio)	r   r   r   generated_filename
best_match
best_score	orig_pathorig_filenamescorer$   r$   r%   find_closest_image_path  s    z0generate_answer.<locals>.find_closest_image_path/api/v1/knowledge/files/c                    s  |d u rg }g }d}t | }||k r| ||d  dkr|d }||k r8| | dkr8|d7 }||k r8| | dks*||k r|d |k r| |d  dkr|d }||k rf| | dkrf|d7 }||k rf| | dksX||k r| |d | }|ds ||}	|d	d	 |	d	 }nd
|v r|d
d }
 d
|
 |}	|d	d	 |	 }|d| d |d }q|| |  |d7 }||k sd|S )Nr   rX   z![]rK   ())zhttp://zhttps://r   r   zimages/r   u
   ![图片](r(   )r=   
startswithrstriplstriprP   r_   join)rg   base_prefixr   rF   rj   njkurlmatched_path	extracted)r   r$   r%   normalize_markdown_images  s@   $


z2generate_answer.<locals>.normalize_markdown_images)r   z
llm outputqar   r   
result_tagr   u   生成回答失败: )r   r   r   )r   N)r*   r>   r+   r^   r9   r_   r   	enumerater"   r   r   r<   r.   randomchoicer   extendrZ   r   r\   re   )r&   r   rR   rS   r   rag_ctx_partsitemrg   
query_descrag_list_str
rag_promptrs   rU   
rag_answerrag_typeoriginal_image_pathstitle_optionsstart_eventcallbackrag_textdomain_descrt   ru   user_contentr   r   rb   r0   r$   )r   rZ   r%   generate_answer  s   



 








  
r   c                  C   s|   t t} | dt | dt | dt | dt | td | dd | dd | dd | dt	 | 
 S )u   创建普通问答工作流r1   rH   rT   r   )r   r   add_noder1   rH   rT   r   add_edger   r	   compile)workflowr$   r$   r%   create_qa_workflow  s   r   r(   r   r   r   r   c                    s   t  }| |d||g dddg g dd}z.||I dH }|dr.d|d  g dg dW S |dd|d	g d|d
g dW S  ty_ } zdt| g dg dW  Y d}~S d}~ww )u   
    执行普通问答工作流（统一接口）

    Args:
        extracted_text: 文本描述（统一的输入参数）
        history_message: 历史消息（目前只接收，不做处理）

    Returns:
        工作流执行结果
    r(   N)r   r   r   r   r   r   r   r   r   r   r   r   r   u#   普通问答工作流执行失败: r   r   r   r   r   )r   rQ   r*   r.   r"   )r   r   r   r   appinitial_statefinal_stater0   r$   r$   r%   run_qa_workflow  sH   

	

r   __main__u   什么是主机？u   主机的作用是什么？c                     s   t tdD ]:\} }tdd  td|   td  t|dI d H }td td|dd	  td
 t|dd qd S )NrK   r8   z<============================================================u   测试用例 )r   u   
执行结果:u   成功: successFu   
响应内容:r   u	   无响应)r   
test_casesr>   r   r*   )rj   	test_textrF   r$   r$   r%   test_  s   
r   )r(   r(   )'r!   typingr   r   r   r   r   langgraph.graphr   r   r	   pydantic_core.core_schemar
   tools.function_toolr   r   modelsAPI.model_apir   utils.function_trackerr   r   r   asyncior)   rZ   r   r   r"   r1   rH   rT   re   r   r   r   r   r   r   runr$   r$   r$   r%   <module>   sT    I"2> u

D4]W>xEo
    3i{  d Z ddlZddlZejejejeje ddlm	Z	m
Z
mZmZmZ ddlmZmZmZ ddlmZ ddlmZmZ ddlmZ ddlmZmZmZ ddlZddlZddlZddl Z G d	d
 d
e	Z!de!dee"ef fddZ#de!dee"ef fddZ$ede!dee"ef fddZ%de"de"deee"ef  fddZ&ede!dee"ef fddZ'dd Z(		d&de"dUe"de"de"dee"ef f
d d!Z)e*d"krddlZd#gZ+d$d% Z,e-e,  dS dS )'Nʳ' /app/workflows/workflow_baike.pyr    get_baike_history_context6SyB!Dt| td |rWt||dddI dH }t|ddI dH }t|trt|ng t|tr|dW S ddW S  t	y } zg ddt| dW  Y d}~S d}~ww )4l	   UU*UXnBE	 '   sP    
 baikeѓZ   
      sVaFkg }g }|dd D ]/}t| td	 t|tr[| d
pAd }| dpJd }	|rT|| |	r[||	 q,d}
|rmddd t|D }
nd}
td| |dv rzd}td| d
tdt	t fdd}|r|d d| nd|}||}td| |r|nd}|
}d}td tdt
| dt
| ddg}dt|d t
| dd!}t D ]}z|| W q ty   Y qw |  d"d#krd$}nd%}d&| d'}|d(7 }g }|r|| | d)t
| d*| d+|r|nd, d-}|d.|d/ tjd||d0d1I dH }d2dljd3d|jd4}|rD| nd5}d
tdtffd6d7}||}d8td9t	t dtfd:d; dEd
td9t	t dtf fd=d>}|||d?}td@| t||I dH }|g dA|dBW S  ty } zdCt| g g dDW  Y d}~S d}~ww )FW)
   l   q8^*8}textfilenamez

D#u   【参考资料 rK   u   】
.   s    z#?8@    (无 RAG 检索X M".#=r8   ,%%vu   综合u5   选择的 rag 信息类型：综合所有检索结果u   RAG 结果数量:u   ✨已综合 u    条检索结]果u*   ✨本次检索策略为综合多源信息function_executionu
   综合了 )type&'\ s'w_；
    - **请综合所有检索结果**，提取关键信息，形成完整、连贯的回答' p(sc；
    - **如果不同检索结果有冲突，请明确指出并说明来源**。
        u#   

+共 u    条）：

u   

# 图谱检索结果：
u   (无图谱结果)u  

# 输出要求：
1. **综合所有检索结<**，提取关键信息，形成完整、连贯的回答
2-t,W `![图片](URL)`）
-	-?
4-~

# 重要约束：
D.g
.H
/K
4. 若信息不足/+失项（如"/"）
/<"维修工具"在Q-O0
6. **如果不同检索结果之间存在冲突或差异，请明确指出并说明各来源的观点**
7. 表格必须以 mar0
8. 所有连接必须完整
9.08
10.\111. 输出内容不仅仅要来源于给你的知识库，同时结合你自己所掌握的知识，综合输出
12. 严格禁输出注意事项，例如：*(注：检索结果中亦包含另一张同主题图片链接 `/api/v1/knowledge/files/images/0ba274885cf4885d44126c74e3afd322b5a37963f0da83769187d4504edda4ae.jpg`，但根据内容一致性，上述图片为检索结果Q明确标注的图 3.1 标准引用。)*
        r4   )r3   r5         ?)r6$.temperaturer   zynchroneg>.*?ost switching1J2(rw   )difflibr.4   r   rR4x4T   r   zimages/r47_777(7~u814   生成回答失败：)r   r   r   )r   N)8   	enumerater"   r   r=9-r.   extendr   r<   rZ   r}   r\   re   )S9)file_name_listitemrg   	file_namerag_list_strrs   all_source_textoriginal_image_paths
query_descrag_textrag_type9'domain_descrx   ry   user_contentrU   r   r   rb   r0   r$   )r   rZ   r%   generate_answer  s   







 



!;!C;<)=<<create_baike_workflow<<k   r   r   r   r   )r4?crun_baike_workflow?P=   __main__u*   船舰主发动机的安全警告是什么>@   t tdD ];j@0|d@,r   r   u   
执行结果:u	   成功：fA3   
test_casesr>   rA4\  s   
r   )r(   r(   ).r!   sysospathr_   dirnameabspath__file__typingr   r   -BB"   r   r   r   r   rÓ-C+\    $`C54  3 y

C(Vտ
xVp
    ӱMj/W                         d Z ddlZddlZej                  j	                  ej                  j                  ej                  j                  ej                  j                  e                         ddlm	Z	m
Z
mZmZmZ ddlmZmZmZ ddlmZ ddlmZ ddlmZ ddlmZ dd	lmZmZmZ dd
lmZm Z m!Z!m"Z" ddl#m$Z$m%Z% ddl&Z&ddl'Z'ddl(Z(ddl)Z) G d de	      Z*de*dee+ef   fdZ,de*dee+ef   fdZ-de*dee+ef   fdZ.ede*dee+ef   fd       Z/de+de+deee+ef      fdZ0ede*dee+ef   fd       Z1de*de+fdZ2d Z3	 	 d"de+de+de+de+dee+ef   f
dZ4e5dk(  r"ddl&Z&d gZ6d! Z7 e&jp                   e7              yy)#u  
工作流：普通问答Agent（使用LangGraph）
输入：文本（转化后和原文本query）、图片描述、语音文本
步骤：
1. 使用RAG和GraphRAG检索相关信息
2. 生成回答
使用 OpenaiAPI 方法调用大模型，尽可能使用异步
    N)	TypedDictOptionalDictAnyList)
StateGraphSTARTEND)init_history)graph_rag_search
rag_search)	OpenaiAPI)track_function_callsget_current_stream_handlerget_all_callbacks)extract_image_pathsfind_closest_image_pathnormalize_markdown_imagesget_image_prompt_guidance)BAIKE_PROMPTSCOMMON_PROMPTSc                       e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eeeef      ed<   e	e
   ed<   e	eeeef         ed	<   e	e   ed
<   eed<   eeeef      ed<   eeeef      ed<   eed<   y)QAStateu   普通问答工作流状态extracted_textcombined_queryretrieval_query
route_flaghistory_messagehistory_messagesneed_retrievalrag_search_resultgraph_search_resultresponseactionssuggestedReplieserror_messageN)__name__
__module____qualname____doc__str__annotations__r   r   r   r   bool     Je:\ZKYNLP\Hjunproject\project0506\wx-agent\app\workflows\workflow_baike.pyr   r   "   s    %O4S>**TN"  T#s(^ 455!#& M$sCx.!!4S>**r0   r   statereturnc                 D    | j                  dd      xs d}t        |      S )u   
    知识问答步骤：获取问答类历史信息
    问答工作流只关注历史问答记录，用于提供上下文
    r    )getr   )r2   r   s     r1   get_baike_history_contextr7   9   s%    
 ii 126<"O((r0   c                   K   | j                  d      xs | j                  d      xs dj                         }| j                  dg       xs g }t        d   j                  |r|nd|      }d}	 t	        j
                  |d	
       d	{   }|r%|j                         j                         }|dk(  rd}t        d|        d|iS 7 =# t        $ r}t        d|        d}Y d	}~2d	}~ww xY ww)u7   
    判断用户问题是否需要检索知识库
    r   r   r5   r    judge_need_retrievalu   无)r    original_queryTNmodelfalseFu    判断是否需要检索失败: u   是否需要检索: r!   )	r6   stripr   formatr   open_api_chat_without_thinkinglower	Exceptionprint)r2   r:   r    promptr!   resultes          r1   r9   r9   B   s     ii 01VUYY?O5PVTV]]_Nyy!3R8>B1299-=)5% : F
 N ??dSS\\^))+F !& 
  0
12n-- T
  045sB   A-C00C
 
C+C
 6C0C
 
	C-C(#C0(C--C0c                   K   ddl }| j                  d      xs | j                  d      xs dj                         }| j                  dg       xs g }|r|dd ng }	  |j                  |d	      }|sd
|iS d}|rFt        |      D ]8  }|j                  d      dk(  s|j                  dd      j                         } n t        d   j                  |xs d||      }|}		 t        j                  |d       d{   }
|
r5|
j                         j                  d      }|rt        |      dk  rd|vr|}	dg}dt        j                  |      dd}t               D ]  }	  ||        t        d|       t        d||	z          d
||	z   iS # t        $ r t        |      }Y 5w xY w7 # t        $ r}t        d|        Y d}~d}~ww xY w# t        $ r Y |w xY ww)u   
    使用历史上下文对当前问题进行query重写，生成适合RAG/图谱检索的独立查询语句。
    只让大模型在有限的最近历史中挑选与当前问题语义相关的内容进行融合，避免简单拼接全量历史。
    r   Nr   r   r5   r    iF)ensure_asciir   roleusercontentrewrite_query_with_historyu	   （无）)last_user_queryhistory_strr:   r;   u   “”"'   
u   query 重写失败: u!   ✨正在分析中，请稍等...function_executionu   正在调取百科数据...typetitledetailsu   原始检索query:u   重写后检索query:)jsonr6   r>   dumpsrB   r,   reversedr   r?   r   r@   lenrC   randomchoicer   )r2   rV   r:   r    trimmed_historyrN   rM   msgrD   rewritten_queryrE   	candidaterF   title_optionsstart_eventcallbacks                   r1   rL   rL   _   s    
  ii 01VUYY?O5PVTV]]_Nyy!3R8>B/?&rs+RO+ djjuE
 !>22OO,Cwwv&("%'')R"8">">"@ - 78??'6;% @ F %O* ??dSS,,[9IS^s2t97L"+
 9:M$}-0K
 &'	[! ( 

/	
!??#BCoo=>>_  +/*+, T  *$QC())*  		s   AGF 1,GAG#F, =F*>;F, 9)G#G+$GF'#G&F''G*F, ,	G5GGGG	GGGGc                   K   d| j                  d      dk(  rd| j                  d      xs% | j                  d      xs | j                  dd      d	v rj                  d	d
      d
   t        d       | j                  dd      d	v rj                  d	d
      d
   	 t               t        d       fd}fd}t        j                   |        |              d{   \  }}g }|j                  dd      r|j                  di       }|j                         D ]b  \  }}|D ]X  }	|j                  |	j                  dd      |	j                  dd      |	j                  dd      |	j                  dd      d       Z d t        |d d      dd }|t        |t              r|dS ddS 7 # t        $ r}
g ddt        |
       dcY d}
~
S d}
~
ww xY ww)u7   
    进行文本知识检索和图谱知识检索
    Nr   rules3r   r   r   r5   u   用户问题：   u   Graph 检索queryl	   UU*UXnBE	 c                  n   K   rt         d       d {   S t         d       d {   S 7 7 w)N   )querykb_idtop_kri   rk   r   )r   rj   s   r1   _do_rag_searchz,search_rag_and_graph.<locals>._do_rag_search   sJ     '(   ((  s   515355c                  P   K   t        j                   dd       d {   S 7 w)N   rl   )r   ainvoke)ri   s   r1   _do_graph_searchz.search_rag_and_graph.<locals>._do_graph_search   s/     )113    s   &$&successFsourceCitationtextfilenameresourcescoreg        )rt   ru   rv   rw   c                 >    t        | j                  d      xs d      S )Nsocrer   )floatr6   xs    r1   <lambda>z&search_rag_and_graph.<locals>.<lambda>   s    %gH[Z[B\r0   Tkeyreverse   )r"   r#   u   检索失败: )r"   r#   r'   )r6   splitrC   asynciogatheritemsappendsorted
isinstancer,   rB   )r2   rm   rq   
rag_resultgraph_resultsr"   source_citationrv   r   itemrF   r   rj   ri   s              @@@r1   search_rag_and_graphr      s    
 Eyy') II'(jEII6F,Gj599UegiKjEE!-q1!4	
u%YY/4NN*'--.?CAF7
e45		 +2..+
 %
!
M >>)U+(nn-=rBO#2#8#8#:%!D%,, $ 4$(HHZ$<$(HHZ$<!%'3!7	.  " $; ##49\fjklnmno "34>}c4R=
 	
XZ
 	
-%
4  
!##%-c!fX6
 	

sV   B!G#'AF; +F9,CF; 4G#5F; 8G#9F; ;	G GG G#G  G#answerquestionc                 z  K   t         d   j                  || dd       }	 t        j                  |dd       d{   }t	        j
                  d|t        j                        }|r|j                  d      }t        j                  |      }t        |t              rqt        |      d	k\  rcg }|dd	 D ]I  }t        |t              sd
|v sd|v s|j                  t        |d
         t        |d         d       K t        |      d	k(  r|S ddddddgS 7 # t         $ r}	ddddddgcY d}	~	S d}	~	ww xY ww)uc   
    生成针对问答结果的建议回复问题
    使用大模型生成两个相关问题
    generate_suggested_repliesNi  )r   r   T)r<   json_outputz\[.*\]r   rh   rT   rK   )rT   rK   u-   这个设备的具体工作原理是什么？u!   还有哪些相关的知识点？)r   r?   r   r@   researchDOTALLgrouprV   loadsr   listrY   dictr   r,   rB   )
r   r   rD   rE   
json_matchjson_strsuggested_repliesformatted_repliesreplyrF   s
             r1    generate_suggested_replies_baiker      su    
 78??ds| @ F
 ??d`dee YYy&"))<
!''*H $

8 4+T2s;L7MQR7R$&!.r2E!%.7e3C	UZHZ)00%(w%8'*5+;'<2  3 ()Q.,, F  SB  C9Fij
 	
+ f2  
 F  SB  C9Fij
 	

sc   D;D DB	D D D =D D;	D D;D 	D8$	D3-D8.D;3D88D;c                   K   | j                  dd      }| j                  dg       }| j                  dd      }| j                  dg       xs g }| j                  dd      }t        d|       t        d	|       	 g }g }d}g }	|r`t        |xs g d
 d      dd D ]  }
t        |
       t        d       t        |
t              s*|
j                  d      xs dj                         }|
j                  d      xs dj                         }|r|j                  |       |s|j                  |        t        d|       |rd|v rd}t        d|       |r|dz   dj                  |      z   }ndj                  |      }t        |      }	t        d|	       dt        |       ddg}dt        j                  |      dt        |       dd}t               D ]  }	  ||        |r|nd}| j                  d      dk(  rd}nd }|rN|j                         r>t        d!   j                  |"      }t        d#   j                  |t        |      |$      }n2t        d%   j                  |"      }t        d&   j                  |'      }g }|r|j!                  |       |j                  d(|d)       t#        j$                  d||d*+       d{   }t'        j(                  d,d|t&        j*                  -      }|r|j                         nd.}d/d0g}dt        j                  |      |dd1 d2z   d}t               D ]  }	  ||        t,        d3   }t,        d4   j                  |5      }t/               }d}d}t#        j0                  d|d(|d)gd6+      2 3 d{   }||z  }||z  }|s|j3                  |       (# t        $ r Y w xY w7 # t        $ r Y w xY w7 D6 |r|j                         n|}dt4        d7t4        fd8} ||      }|r|	rt7        ||	9      }t        d:|       t9        ||       d{  7  }|g d;|d<S # t        $ r}d=t5        |       g g d>cY d}~S d}~ww xY ww)?u"   
    正在生成问答结果
    r   r5   r"   r#   r    r!   Tzhistory_message(qa)u   是否使用检索结果:c                 b    t        | t              rt        | j                  d      xs d      S dS )Nrw   r   )r   r   rz   r6   r{   s    r1   r}   z!generate_answer.<locals>.<lambda>0  s,    ^hijko^paeeGnFYXY@Z@wvw@wr0   r~   Nr   l   q8^*8}rt   ru   123456u0   图谱检索完成，但未返回有效数据。654321rP   u   提取到的原始图片路径:u   ✨已综合 u    条检索结果u*   ✨本次检索策略为综合多源信息rQ   u
   综合了 rR   u   当前未明确描述问题r   rd   uB   舰船修理相关的法规、规范、行业标准及技术文件uH   工业设备的结构原理、维护规程、故障诊断与维修操作%generate_answer_with_retrieval_system)domain_desc#generate_answer_with_retrieval_user)r   	rag_countall_source_text(generate_answer_without_retrieval_system&generate_answer_without_retrieval_user)r   rJ   )rI   rK   g      ?)r<   system_promptmessagestemperaturezynchroneg>.*?ost switching>)flagsu   抱歉，无法生成回答。u   🤖 诊断分析中u   🤖 故障预检中   z...format_systemformat_user_with_image_examples)raw_contentg?r3   c                 
   d}| j                  d|      } t        j                  dd|       } t        j                  dd|       } | j                  |d      } t        j                  dd|       } t        j                  d	d
|       } | S )Nz DOUBLE_DOLLAR z$$z	(?<!\s)\$z $z\$(?!\s)z$ z(?<!\s)\$\$z $$z
\$\$(?!\s)z$$ )replacer   sub)rt   placeholders     r1   normalize_latex_spacingz0generate_answer.<locals>.normalize_latex_spacing  st    1K<<k2D66,t4D66+ud3D<<T2D66.&$7D66-6DKr0   )original_pathsz
llm outputqar$   r%   
result_tagr&   u   生成回答失败：)r$   r%   r&   )r6   rC   r   r   r   r>   r   joinr   rY   rZ   r[   r   rB   r   r?   extendr   r@   r   r   r   r   r   open_api_chat_streamsend_stream_contentr,   r   r   )r2   r   rag_resultsr   r    r!   rag_ctx_partsfile_name_listr   original_image_pathsr   rt   	file_namer`   ra   rb   
query_descr   content_system_promptcontent_user_contentcontent_messagesr   format_system_promptformat_user_contentstream_handlerr   accumulated_contentchunkr   r   rF   s                                  r1   generate_answerr     s    
 YY/4N))/4KII3R8Myy!3R8>BYY/6N	
!12	
%~6]
#%!{0b6w  BF  G  HJ  IJ  Kd12dD) HHV,299;D!%*!5!; B B DI%,,T2 &--i8 K (M*!SWd!d "(M* "/$"6=9Q"Q"&))M":#6#G 35IJ  -S-?,@@PQU  BM,}5'M(:';;KLK
 ./[) 0 (6^;X
 99\"g-^KdK o335$12Y$Z$a$any$a$z!#01V#W#^#^-m, / $_ $  %22\$]$d$dq|$d$}!#01Y#Z#a#aq#a  $A ##$45<P QR &DD/%	
 
 ff;RTVT]T]^-8k'')>^/1GH(]]=1"3B'%/

 *+H% ,  .o>,-NOVVcnVo 45  %99.%2EFG	
 
	H% eOF5(223FGY ! <
(   
	H 
 $*{	# 	# 	 )0 2.vFZ[FlF# #C6>"ZZZ  1	
 	
  
/Ax8 "
 	

s   A7Q,:A
Q AQ !B9Q N;#C(Q OA/Q <OAQ OOOQ )Q ;	OQ OQ 	OQ OQ OAQ 7P:8Q Q,	Q)Q$Q)Q,$Q))Q,c                 .    | j                  dd      }|ryy)uB   
    判断后的路由：根据need_retrieval决定下一步
    r!   TrL   r   )r6   )r2   r!   s     r1   route_after_judger     s     YY/6N+ r0   c                     t        t              } | j                  dt               | j                  dt               | j                  dt
               | j                  dt               | j                  dt               | j                  t        d       | j                  dd       | j                  dt        ddd       | j                  dd       | j                  dd       | j                  dt               | j                         S )u   创建普通问答工作流r7   r9   rL   r   r   )rL   r   )r   r   add_noder7   r9   rL   r   r   add_edger	   add_conditional_edgesr   r
   compile)workflows    r1   create_baike_workflowr     s    '"H 13LM,.BC24NO,.BC'9 e8913IJ""*F0	
 24JK,.?@'- r0   r   r   r   r   c                 r  K   t               }| |d||g ddddg g dd}	 |j                  |       d{   }|j                  d      rd|d    g dg dS |j                  dd      |j                  d	g       d|j                  d
g       dS 7 Y# t        $ r}dt	        |       g dg dcY d}~S d}~ww xY ww)u   
    执行普通问答工作流（统一接口）

    Args:
        extracted_text: 文本描述（统一的输入参数）
        history_message: 历史消息（目前只接收，不做处理）

    Returns:
        工作流执行结果
    r5   N)r   r   r   r   r   r    r!   r"   r#   r$   r%   r&   r'   r'   u#   普通问答工作流执行失败: r   r   r$   r%   r&   )r   rp   r6   rB   r,   )r   r   r   r   appinitial_statefinal_staterF   s           r1   run_baike_workflowr     s     "  
!C )( *!#M 
KK66 ???+A+oB^A_`"$&	  $
B7"y"5 +0BB G	
 	
 7&  
=c!fXF "	
 	

sP   B7B B!B B76B B7B 	B4B/)B4*B7/B44B7__main__u*   船舰主发动机的安全警告是什么c                  X  K   t        t        d      D ]  \  } }t        dd        t        d|         t        d        t        ||       d {   }t        d       t        d|j	                  dd	              t        d
       t        |j	                  dd              y 7 Vw)Nrf   rP   z<============================================================u   测试用例 )r   r   u   
执行结果:u	   成功：rr   Fu   
响应内容:r$   u	   无响应)	enumerate
test_casesrC   r   r6   )i	test_textrE   s      r1   testr   <  s     %j!4LAyBvh- M!%&VH .(( F
 O%IfjjE:;<=O%&**Z56 5s   AB*B(AB*)r5   r5   )9r+   sysospathr   dirnameabspath__file__typingr   r   r   r   r   langgraph.graphr   r	   r
   workflows.history_managerr   tools.function_toolr   tools.rag_toolsr   modelsAPI.model_apir   utils.function_trackerr   r   r   utils.image_utilsr   r   r   r   promptsr   r   r   rV   r   rZ   r   r,   r7   r9   rL   r   r   r   r   r   r   r(   r   r   runr/   r0   r1   <module>r      s    	 0I JK L 7 7 2 2 2 ' ) f f A  A 1   	 i .)W )c3h ).g .$sCx. .:??G ??S#X ??D I
g I
$sCx. I
 I
Z(
3 (
# (
$tTWY\T\~J^ (
V i
 i
T#s(^ i
 i
T!W ! !D 	?
?
?
 ?
 	?

 
#s(^?
H z 	5J7" GKK3 r0   C϶x0yo
    gi1=                  	   @   s`  d Z ddlmZmZmZmZ ddlZddlZddlZddl	m
Z
mZ ddlmZ ddlmZ dedeeeef  fd	d
ZdZdddddZdeeeef  deeeef  fddZdedefddZedeeef deeef fddZedeeef deeef fddZedeeef deeef fddZdededeeeef  fd d!ZdS )"u   
故障诊断共用逻辑：知识库检索、图谱检索、维修方案生成与建议回复。
供 workflow_fault_define、workflow_rag_define 使用，与 Agent 1（实体抽取）分离。
    )DictAnyListOptionalN)rag_search_toolgraph_rag_search)	OpenaiAPI)track_function_callshistory_messagereturnc                 C   sV   | sg S zt | trt| n| }t |tr|dd W S g W S  ty*   g  Y S w )u   解析历史消息为列表iN)
isinstancestrjsonloadslist	Exception)r
   data r   '/app/workflows/workflow_fault_common.pyparse_history   s   r   z>http://192.168.0.46:11000/api/v1/knowledge/knowledge_base/treezapplication/json1testuseradmin)acceptz	x-user-idzx-user-namezx-roleitemsc                 C   sJ   g }| D ]}t |tr"|| |dpg D ]
}|t|g qq|S )uF   将树形知识库列表展平（若有 children 则递归展开）。children)r   dictappendgetextend_flatten_kb_list)r   outitemchildr   r   r   r    %   s   

r    ship_numberc              
      sJ  | r	t |  sdS tdt | }t|dkr#d|dd } nt|dkr/d|} ndS g }ztjddd4 I dH }|jt	t
d	I dH }|jd
kr\	 W d  I dH  W dS | }t|trd|v r}|dd
kr}	 W d  I dH  W dS |dp|dpg }nt|tr|}n	 W d  I dH  W dS |s	 W d  I dH  W dS t|}|D ]2}|dpd}	| |	v r|d}
|
durt |
 r|t |
  td|  d|	 d|
  q|rd|ndW  d  I dH  W S 1 I dH sw   Y  W dS  ty$ } ztd|  W Y d}~dS d}~ww )u   
    根据 ship_number 从知识库树 API 获取匹配的知识库 id 列表。
    返回逗号分隔的 kb_id 字符串，供 rag_search_tool 使用；无匹配时返回空字符串。
     z\d   Nr   g      >@F)timeoutverify)headers   coder   r   nameidu   通过舷号 u    匹配到知识库: z, ID: ,u   获取知识库树失败: )r   striprefindalllenjoinhttpxAsyncClientr   KB_TREE_URLKB_TREE_HEADERSstatus_coder   r   r   r   r    r   printr   )r$   matchkb_idsclientresponseresultkb_list	flat_listkbkb_namekider   r   r   	get_kb_id0   sZ   



6rE   statec              
      s  |  ddpd}|  ddpd}|  ddpd}|  ddp d}d|v r3|ddd ddd	 }|r[d
| }|rE|d| d7 }n|d7 }| rU| d| dn| d}n| rd| dnd}t|I dH }d
| d| d}td| z5|dd}	|r||	d< t|	I dH }
t|ddI dH }t|
t	r|
ng t|t
r|dW S ddW S  ty } zg ddt
| dW  Y d}~S d}~ww )u<   查询知识库和知识图谱（按舷号匹配 kb_id）。extracted_textr%   r$   device_namefaultu   用户问题：   
r      设备u   出现u   故障u   出现故障u   ，表现为u!   ，请尝试给出维修方案。u   请尝试给出维修方案。N	   ，故障   的维修方案u   Graph/RAG 检索query   querytop_kkb_id)rag_search_resultgraph_search_result   检索失败: )rT   rU   error_message)r   splitr/   rE   r9   r   ainvoker   r   r   r   r   )rF   rG   r$   rH   rI   basegraph_queryrS   	rag_query
rag_paramsrag_resultsgraph_resultsrD   r   r   r   retrieve_graph_and_rag`   sF   
$

r`   c                    s.  |  drd| d  g d| d  dS |  ddp#|  ddp#d}|  d	dp+d}|  d
dp3d}|  ddp;d}|  ddpCd}|  dg pKg }t|trS|n|rZd|nd}g }|dd D ]}	t|	tr{|	 dpqd }
|
r{||
 qd|rd|nd}|r|n|r|nd}d|r|nd d| d| d|r|nd d| d| d|r|nd d| d| d| d | d!}z(tjdd"d#|d$gd%I dH }|pd }|sd&}t	||I dH }||d'dW S  t
y } z"d(t| g d)d)d*d+d+d*gt|d(t| d,W  Y d}~S d}~ww )-uE   故障原因分析 + 生成维修方案（单次大模型调用）。rW   rV   u   检索失败，跳过生成: )r=   suggestedReplies__details__rH   r%   device_modelu   未知设备r$   rI   combined_queryrU   rT   u   、N   textz

u   无u   当前未明确描述症状u  
    你是一名资深工业设备维修工程师，请严格依据用户提供的【输入信息】与【辅助线索】完成以下两项任务：

    1. **用一句话给出最可能的故障原因**；
    2. **生成一份详尽、可直接执行的维修方案**。

    > ⚠️ **重要原则**：
    > - 所有内容**必须且仅能**基于【图谱线索】和【文档线索】；
    > - **禁止使用外部知识、常识推断、经验类比或模糊猜测**；
    > - 若辅助线索未明确支持某项结论、参数、工具或备件，则视为“信息不足”，不得自行补充。

    ---

    ### 【输入信息】
    - 船号：u	   未提供u   
    - 设备名称：u   
    - 故障现象：ui   

    ### 【辅助线索】
    - **【图谱线索】**（含标准流程/部件因果关系）：
    ug   

    - **【文档线索】**（来自手册/工单/维修经验，已通过精准RAG检索）：
    uM   

    > 🔍 判断规则：仅当 【辅助线索】 中**明确出现**与 u6   相关的以下任一内容时，方可用于回答：
    > - 具体故障原因描述（如“润滑不足导致轴承过热”）
    > - 部件-现象因果链（如“联轴器不对中 → 振动超标”）
    > - 可执行的操作指令（含工具、扭矩、间隙、测试方法等）
    > - 图片、表格、零件号、物料编码等结构化数据
    > 否则，统一视为“线索不足”。

    ---

    ### 【输出要求】
    请**严格按以下结构与顺序输出**，不得增删或改写标题：
    
    #### 【船号】
    u!   
    #### 【设备名称】
    u!   
    #### 【故障现象】
    u  
    #### 【故障原因分析】
    初步判定原因：（**仅限一句话**）
    - 若辅助线索中有明确因果描述，直接归纳（如：“润滑不足导致主轴轴承过热”）；
    - **否则必须写**：“待根据图谱与文档线索现场进一步确认”。

    #### 【维修方案】
    1. **维修步骤**
       按照“安全准备 → 故障验证 → 拆解与处理 → 安装复位 → 功能测试 → 验收交付”六阶段展开。
       - 每步操作必须满足：**动作 + 对象 + 判断依据/测量标准**；
       - **所有图片链接（保证图片输出格式为`![图片](URL)`）必须原样嵌入对应步骤中**，不可省略、合并或转述；
       - 若某步骤在辅助线索中无依据，**不得编造**，应跳过或标注：“此环节无文档支持，需现场诊断”。

    2. **所需工具**
       - 仅列出辅助线索中**明确提及**的工具（含型号/规格）；
       - 若未提及，**必须写**：“需参照 u   标准维修规程配置通用工具包”，**不得列举具体工具名称**。

    3. **备件/耗材**
       - 仅当辅助线索提供**完整型号、规格或物料编码**时方可列出；
       - 否则**必须写**：“需现场确认”，并补充说明：“通过拆卸后比对旧件铭牌或测量关键尺寸确定”。

    4. **参考依据**
       - 每项结论或参数**必须标注来源**
       - 若无明确来源，**必须写**：“需查阅 u   对应技术手册相关章节确认”，**严禁编造章节、页码或工单号**。

    ---

    ### 【硬性防幻觉约束】（违反即视为无效输出）
    - 🚫 **严禁虚构**：零件号、工具型号、扭矩值、间隙标准、测试阈值、流程图、手册章节等；
    - 🔗 **URL 必须原样保留**：包括图片、PDF 链接等，不得转义、缩短或描述代替；
    - 🖼️ **多图必须逐个引用**：每张图片在对应操作步骤中单独嵌入；
    - ❗ **关键参数缺失必须显式声明**；
    - ✅ **所有输出内容必须可回溯至辅助线索中的原文或图谱节点**。
    uo   你是一名资深工业设备维修工程师，严格依据检索信息生成维修方案，不虚构内容。user)rolecontent)modelsystem_promptmessagesuv   （暂无法生成可用维修方案，请补充设备型号、运行工况、报警信息与现场照片/录音。）u-   正在生成故障原因分析与维修方案u   分析生成失败:    如何修复这个故障？titleri   $   需要准备哪些工具和备件？r=   actionsra   rW   rb   )r   r   r   r3   r   r/   r   r   open_api_chat_without_thinkinggenerate_suggested_replies_qar   )rF   devicer$   symptomsrG   
graph_textr^   symptom_textrag_ctx_partsr"   rf   rag_ctxsymptom_descpromptanswerr=   ra   rD   r   r   r   analyze_and_generate_repair   s   
 




&(*9AM
r~   c           
   
      s  |  ddpd}|  ddpd}d| d| d}z9t|ddI d	H }t| }t|tr1|ng |d
< d|d< t|I d	H }| dpFd }d}|| |d< |W S  ty }	 z"dt	|	 g ddddddgt	|	dt	|	 dW  Y d	}	~	S d	}	~	ww )u}   当按指定舰艇范围检索不到有效 RAG 结果时，用通用知识库再检索并生成方案（带兜底说明）。rH   r%   rI   rL   rM   rN   rO   rP   NrT   rW   r=   u   

（提示：由于在指定舰艇知识库范围内未检索到有效资料，本次方案基于通用知识库生成，可能与具体舰艇存在差异，请结合实际情况谨慎使用。）u   通用知识库检索失败: rm   rn   rp   rq   )
r   r   rY   r   r   r   r~   r/   r   r   )
rF   rH   rI   r\   r^   	new_stater>   	base_respnoticerD   r   r   r   $analyze_and_generate_repair_fallback  s2   r   r}   questionc           	         s  d| d| dd  d}zet j|ddI dH }td|tj}|ri|d}t|}t|t	rit
|d	krig }|dd	 D ]}t|tr_d
|v r_d|v r_|t|d
 t|d d q@t
|d	kri|W S ddddddgW S  ty   ddddddg Y S w )u3   根据问答内容生成两个建议后续问题。u   
你是一个专业的工业设备问答助手。根据以下问答内容，生成两个用户可能关心的后续问题。

【用户问题】
u   

【回答内容】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与当前问答内容相关，能够帮助用户进一步了解相关信息
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
)rj   z\[.*\]r      ro   ri   rn   rm   rp   )r   rs   r0   searchDOTALLgroupr   r   r   r   r2   r   r   r   r   )	r}   r   r|   r>   
json_matchjson_strsuggested_repliesformatted_repliesreplyr   r   r   rt   1  s<   


rt   )__doc__typingr   r   r   r   r   r0   r4   tools.function_toolr   r   modelsAPI.model_apir   utils.function_trackerr	   r   r   r6   r7   r    rE   r`   r~   r   rt   r   r   r   r   <module>   s2    *0$+$ $&x>o
    i                     @   s   d Z ddlmZmZmZ ddlmZmZ ddlm	Z	m
Z
 dedededed	eeef f
d
dZ		ddededededeeef f
ddZdS )u:  
故障诊断 Agent 2：判断是否能在限制的舷号内检索到内容。
- 若能：自动调用 workflow_rag_define 生成维修方案并返回。
- 若不能：返回提示 + 按钮「确认调用相关数据进行分析」，用户确认后由 app 路由到 workflow_rag_define（走通用知识库）。
    )DictAnyList)FaultDiagnosisStateparse_and_normalize_input)parse_historyretrieve_graph_and_ragextracted_textqueryhistory_message
route_flag	rag_statec                    s&   ddl m} || ||||dI dH S )u   延迟导入避免循环依赖r   )run_rag_define_workflow)r	   combined_queryr   r   r   N)workflows.workflow_rag_definer   )r	   r
   r   r   r   r    r   '/app/workflows/workflow_fault_define.py_call_rag_define   s   r    r   returnc                    s2  t |}|p
| p
d}| ||ddddddddg dd}t|I dH }i ||}|dr4dg dg dS |d	dp;d}|d
dpCd}	|ddpKd}
t|I dH }i ||}|dp_g }t|tojt|dk}|rxt| ||||I dH S d|p|d d|	pd d|
pd d}dddddg}||dg dS )u   
    执行故障定义工作流：在舷号限定下检索；有结果则调 rag_define 生成方案，无结果则返回确认按钮。
    r   FN)r	   r   history_messagesship_numberdevice_namedevice_modelfaultneed_user_inputrag_search_resultgraph_search_resultresponsesuggestedReplieserror_messager   u   当前无法从对话中识别到完整的船号、设备与故障信息，请先补充后再点击「确认无误，开始诊断」。fault_define)r   actions
result_tagr   r   r   r   r   r   u   在指定舷号（u	   未提供u3   ）对应的知识库范围内，未检索到与「u   设备u   」故障「u	   未描述u   」相关的有效资料。

是否使用**通用知识库**进行检索并生成维修方案？（方案可能与具体舰艇存在差异，请结合实际情况使用。）contentu$   确认调用相关数据进行分析
rag_define)typelabeltexticon)r   r   getr   
isinstancelistlenr   )r	   r   r   r   r   r
   statestep1_resultr   r   r   retrieve_resultrag_resultshas_ragmsgr"   r   r   r   run_fault_define_workflow   s^   	
"
r4   N)r   r   )__doc__typingr   r   r   "workflows.workflow_fault_diagnosisr   r   workflows.workflow_fault_commonr   r   strr   r4   r   r   r   r   <module>   s$    &
qJxKo
    i:                    @   sv  d Z ddlmZmZmZmZmZmZ ddlm	Z	m
Z
mZ ddlmZmZ ddlmZ ddlmZmZ ddlmZ ddlmZ dd	lmZm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%G dd deZ&de'dee fddZ(de'deee'ef  fddZ)e$d Z*dddddZ+deee'ef  deee'ef  fddZ,de'dee'ef fd d!Z-	"	"	"	"	"	"	"	"	"dXde'd#e'd$e'd%e'd&e'd'e'd(e'd)e'd*e'de.fd+d,Z/d-e&dee'ef fd.d/Z0d-e&dee'ef fd0d1Z1d-e&defd2d3Z2d-e&defd4d5Z3d-e&dee'ef fd6d7Z4d-e&defd8d9Z5d-e&defd:d;Z6d-e&dee'ef fd<d=Z7d-e&dee'ef fd>d?Z8d-e&dee'ef fd@dAZ9d-e&defdBdCZ:d-e&dee'ef fdDdEZ;d-e&de'fdFdGZ<d-e&de'fdHdIZ=dYdJdKZ>	"	"	"	"	"	
	
dZdLe'dMe'de'dNe'dOe'dPe'dQe'dRee'ef dee'ef fdSdTZ?e@dUkrdd
lZdVdW ZAeBeA  d
S d
S )[up  
故障诊断工作流（ReAct 风格 - 基于 Checkpointer 的状态持久化版本）

核心改进：
1. 使用 LangGraph Checkpointer 实现真正的状态持久化
2. 通过 interrupt 机制实现"暂停等待用户输入"
3. 支持 chat_id + message_id 恢复工作流状态
4. extract_info 仅首次执行，后续直接恢复状态

工作流架构：
START → [检查状态] → extract_info（仅首次）→ agent_think → [决策路由]
                                                          ↓
                        ┌─────────────────┼─────────────────┐
                        ↓                 ↓                 ↓
                   ask_user          call_tools       generate_response
                        ↓                 ↓                 ↓
                   [interrupt]     process_results        ↓
                        ↓                 ↓            check_supplement
                   END（等待）    generate_response        ↓
                                        ↓            [用户补充?]
                                       END                  ↓
                                                    generate_response
                                                           ↓
                                                          END
    )	TypedDictOptionalDictAnyList	Annotated)
StateGraphSTARTEND)	interruptCommand)MemorySaver)rag_search_toolfault_graph_rag_search)	OpenaiAPI)get_all_callbacks)get_thread_idcreate_checkpointerN)SequenceMatcher)
RAG_CONFIGKB_TREE_CONFIGc                   @   s  e Zd ZU dZeed< eed< eeeef  ed< eed< eed< eed< eed< eed	< eed
< eed< eed< eed< e	eeeef   ed< e	e ed< eed< eeeef  ed< eeeef  ed< eed< eed< eed< ee ed< ee ed< e
ed< eed< eed< eed< eed< eed< eed< eed< eed < eeef ed!< eed"< eed#< eed$< eed%< eed&< eeeef  ed'< eeef ed(< eed)< eed*< eed+< eed,< eed-< eed.< eed/< eed0< eed1< eed2< eed3< eed4< eed5< eed6< d7S )8FaultDiagnosisStateu   故障诊断工作流状态extracted_textcombined_queryhistory_messagesship_numberdevice_namefaultadditional_info
fault_code
fault_timefault_frequencytried_measuresrunning_conditionrag_search_resultgraph_search_resultresponsesuggestedRepliesactionserror_messageagent_decisionagent_reasoningtools_to_callmissing_infoinfo_completenesskb_match_typematched_kb_idmatched_kb_namesource_noticeiteration_countmax_iterationsscheme_generatedwaiting_for_supplementextracted_infohas_rag_resulthas_graph_resultis_execution_feedbackexecution_detailwaiting_similar_confirmsimilar_kb_listconfirmed_similar_kbsimilar_confirm_responseuser_confirmed_similaruser_rejected_similarneed_similar_confirm	ask_rounduser_confirmed_infoneed_model_confirmuser_confirmed_modelwaiting_feedbackuser_feedbackwaiting_report_confirmreport_confirmedinitializedcurrent_nodeN)__name__
__module____qualname____doc__str__annotations__r   r   r   r   floatintbool rV   rV   */app/workflows/workflow_fault_diagnosis.pyr   -   sn   
 r   textreturnc                 C   s   | sd S |   }tjdd|tjd}tdd|}td|}|r4z	t|dW S  ty3   Y nw td|}|rOz	t|dW S  tyN   Y nw zt|W S  ty_   Y d S w )Nz
```json\s* )flagsz```\s*z\[[\s\S]*\]r   z\{[\s\S]*\})	stripresub
IGNORECASEsearchjsonloadsgroup	Exception)rX   cleanedmrV   rV   rW   _safe_json_extractr   s0   rg   history_messagec                 C   sV   | sg S zt | trt| n| }t |tr|dd  W S g W S  ty*   g  Y S w )N)
isinstancerQ   ra   rb   listrd   )rh   datarV   rV   rW   _parse_history   s   rm   urlzapplication/json1testuseradmin)acceptz	x-user-idzx-user-namezx-roleitemsc                 C   sJ   g }| D ]}t |tr"|| |dpg D ]
}|t|g qq|S )Nchildren)rj   dictappendgetextend_flatten_kb_list)rs   outitemchildrV   rV   rW   ry      s   

ry   r   c              
      s  | r	t |  sdddg dS dtdt | }|s$dddg dS i }g }z$tjddd4 I d H 	}|jtt	dI d H }|j
d	krXdddg dW  d   I d H  W S | }t|trd
|v r~|d
d	kr~dddg dW  d   I d H  W S |dp|dpg }nt|tr|}ndddg dW  d   I d H  W S |sdddg dW  d   I d H  W S t|}|D ]?}	|	dpd}
|	d}|d u st | sqdtd|
}||kr|rt | |
d}q|t | |
|d q|r|d |d dg dW  d   I d H  W S |r-ddd|dW  d   I d H  W S dddg dW  d   I d H  W S 1 I d H sFw   Y  W d S  tyn } ztd|  dddg dW  Y d }~S d }~ww )NrZ   none)kb_idkb_name
match_typesimilar_list\dg      >@F)timeoutverify)headers   coderl   rk   nameid)r~   r   )r~   r   
kb_numbersr~   r   exactsimilarz[ERROR] get_kb_id_exact: )rQ   r\   joinr]   findallhttpxAsyncClientrw   KB_TREE_URLKB_TREE_HEADERSstatus_codera   rj   ru   rk   ry   rv   rd   print)r   input_numbersexact_matchr   clientr&   resultkb_list	flat_listkbr   kidr   erV   rV   rW   get_kb_id_exact   sl   






$'6(r   rZ   r   r   r   r    r!   r"   r#   r   c	              
   C   sx   d}	dddddddddd	}
| ||||||||d	}|
  D ]\}}||d	p)d	}|r6t| r6|	|7 }	qt|	d
S )N        g?      ?g{Gz?gQ?g?g{Gz?	r   r   r   r   r    r!   r"   r#   r   rZ      )rs   rw   rQ   r\   round)r   r   r   r   r    r!   r"   r#   r   scoreweightsvaluesfieldweightvaluerV   rV   rW   _calculate_info_completeness   s6   
r   statec           #   
      s  |  ddrtd ddiS |  ddpd}|  dg pg }d}|rf|d	d
 }g }|D ]/}t|tr\| dd}| dp@d }|dkrP|d|  q-|dkr\|d|  q-|rdd|nd}g }	|  ddpod}
|  ddpwd}|  ddpd}|  ddpd}|  ddpd}|  ddpd}|  ddpd}|  ddpd}|  ddpd}|
r|	d|
  |r|	d|  |r|	d|  |r|	d|  |r|	d|  |r|	d |  |r|	d!|  |r|	d"|  |r|	d#|  |	rd|	nd$}d%}d&| d'|p d( d)| d*}ztj|d
d+|g d,I d
H }t	|}t|tsAi }| ddpI|
}| ddpR|}| ddp[|}| ddpd|}| ddpm|}| ddpv|}| ddp|}| ddp|}| ddp|} ||||||||| d-	}!td.|!d  d/|!d  d0|!d   i |!|!d+dd1W S  t
y }" ztd2t|"  d+dd3W  Y d
}"~"S d
}"~"ww )4u   
    信息提取节点（仅首次执行）
    
    从用户输入中提取故障相关信息，并与已保存的状态合并
    rK   Fu$   [extract_info] 已初始化，跳过rL   agent_thinkr   rZ   r   ri   Nrolecontentuser   用户: 	assistant   助手: 
r   r   r   r   r    r!   r"   r#   r      舷号:    设备名称:    故障现象:    故障码: u   故障时间:    故障频率:    已尝试措施:    运行工况:    其他信息: u   （无已提取信息）u  你是一个信息提取专家，负责从用户输入中提取维修相关信息。

你需要提取以下信息：
1. 舷号：船舰编号，如"101","111","122"等
2. 设备名称：故障设备的名称
3. 故障现象：故障的具体表现
4. 故障码：报警代码或故障代码
5. 故障时间：故障发生的时间
6. 故障频率：故障发生的频率
7. 已尝试措施：用户已经尝试过的维修方法
8. 运行工况：设备运行时的参数
9. 其他信息：其他补充说明

提取规则：
- 如果某项信息没有提及，返回空字符串
- 优先使用当前输入中的信息
- 注意保留已有的信息，不要丢失

输出格式（JSON）：
{
    "ship_number": "舷号",
    "device_name": "设备名称",
    "fault": "故障现象",
    "fault_code": "故障码",
    "fault_time": "故障时间",
    "fault_frequency": "故障频率",
    "tried_measures": "已尝试措施",
    "running_condition": "运行工况",
    "additional_info": "其他信息"
}uK   请从以下内容中提取维修相关信息：

【已提取的信息】
   

【历史对话】
u   （无历史对话）u   

【当前用户输入】
u$   

请提取信息（JSON格式）：Tquerymodeljson_outputsystem_promptmessagesr   u   [信息提取] 舷号=	   , 设备=	   , 故障=)r7   rK   rL   u   信息提取失败: rK   rL   )rw   r   rj   ru   r\   rv   r   r   open_api_chat_without_thinkingrg   rd   rQ   )#r   r   r   history_strrecentpartsrf   r   r   existing_infoexisting_ship_numberexisting_device_nameexisting_faultexisting_fault_codeexisting_fault_timeexisting_fault_frequencyexisting_tried_measuresexisting_running_conditionexisting_additional_infoexisting_info_strr   promptresponse_textparsednew_ship_numbernew_device_name	new_faultnew_fault_codenew_fault_timenew_fault_frequencynew_tried_measuresnew_running_conditionnew_additional_infor7   r   rV   rV   rW   extract_info	  s   
	&
r   c           &         s  |  ddpd}|  ddpd}|  ddpd}|  ddp d}|  ddp(d}|  ddp0d}|  ddp8d}|  d	dp@d}|  d
dpHd}	|  ddpPd}
|  dd}|  dd}|  dd}|  d}|  d}|  dd}|  dd}|  dd}|  dd}|  di pi }|  dd}|  dd}t|o| }t|o| }t|o| }|durt|dkp|}|durt|dkp|}t||||||||	|
d	}d}g d}|  t fdd |D rd!}d"} td#| d$|   || ||d% |d&S |r:|r"d'}d(} td#| d$|   || ||d% |d&S d)}d*} td#| d$|   || ||d% |d&S |rq|rqd+}d,| d-d } d.g}!|r\|r\|r\|!d/ td#| d$|   || |!||d% |d0S |rd+}d1} d.g}!|r|r|r|!d/ td#| d$|   || |!||d% |d0S |r|s|sd2}d3} td#| d$|   || ||d% |d&S |r|r|sd4}g }"|s|"d5 |s|"d6 |s|"d7 d8d9	|" } td#| d$|   || |"||d% |d:S ||k rCd4}d;| d<| } g }"|s|"d= |s"|"d> |s*|"d? td#| d$|   || |"p;d@g||d% |d:S |sI|radA}dB} td#| d$|   || ||d% |d&S |s|dC}dD} td#| d$|   || ||d% |d&S d+}dE} d.g}!|r|r|r|!d/ td#| d$|   tdF| dG| dH|  g dI}#dJt
|#dK| dL| ddM  dNdO}$t D ]}%z|%|$ W q ty   Y qw || |!||d% |d0S )PuF   
    Agent 思考节点：基于当前状态决定下一步动作
    r   rZ   r   r   r   r   r    r!   r"   r#   r   r5   Fr8   r9   r$   r%   r3   r   r<   r@   rA   r>   rD   rG   Nd   r   r   )u   生成报告   生成维修报告u   生成故障报告u   导出报告u	   写报告c                 3   s    | ]}| v V  qd S NrV   ).0keywordcombined_query_lowerrV   rW   	<genexpr>  s    zagent_think.<locals>.<genexpr>generate_reportu   用户请求生成报告u   [Agent 决策] decision=z, reasoning=   )r*   r+   r.   r3   rL   handle_feedbacku3   用户对方案有反馈，进入反馈处理流程	follow_upu*   已生成方案，用户进行后续交互
call_toolsu#   用户确认使用相似知识库: r   
rag_searchgraph_rag_search)r*   r+   r,   r.   r3   rL   u0   用户拒绝相似知识库，使用通用检索similar_confirmu-   等待用户确认是否使用相似知识库ask_user   舷号   设备名称   故障现象u   缺少基本信息: , )r*   r+   r-   r.   r3   rL   u   信息完整性评分 u    低于最低要求 u	   故障码u   故障时间u   故障频率u   更多详细信息generate_responseu6   信息充足，已有检索结果，直接生成回复confirm_infou6   信息充足，需要用户确认后再检索知识库u6   信息充足，用户已确认，开始检索知识库u   [Agent 提取] 舷号=r   r   )u   🤖 Agent 思考中u   🤖 智能分析u   🤖 决策判断function_executionu   决策: u    | 理由: 2   ...typetitledetails)rw   rU   r\   lenr   loweranyr   rv   r   randomchoicer   rd   )&r   r   r   r   r   r   r    r!   r"   r#   r   r5   r8   r9   r$   r%   r3   r<   r@   rA   r>   rD   rG   has_ship
has_device	has_faulthas_rag	has_graphr.   MIN_COMPLETENESS_FOR_GENERATEreport_keywordsdecision	reasoningr,   r-   title_optionsstart_eventcallbackrV   r   rW   r     s~  


	
	



	



	

r   c           "   
      s  |  dg }|  ddpd}|  ddpd}|  ddpd}|  ddp&d}|  ddp.d}|  ddp6d}|  d	dp>d}|  d
dpFd}	|  ddpNd}
|  ddpVd}|  dd}|  dd}d}||krtd| d dg}|r|r|r|d t|d d|dddS g }|r|d|  |r|d|  |r|d|  |r|d|  |r|d|  |r|d|  |r|d|  |	r|d |	  |
r|d!|
  |rd"|nd#}|rd$|nd%}d&}d'| d(| d)| d*| d+	}d}ztj|d,|g d-I d,H }|r | nd}W n tyA } ztd.t	|  d}W Y d,}~nd,}~ww |sKd/| d0}|r`d1d2d3d4 |D  d5 }|| }g d6}d7t
|d8| d9| d:d;}t D ]}z|| W qw ty   Y qww g }d<|v r|d=d>d? d@|v r|dAdBd? dC|v r|dDdEd? t||dF|dG}| dHd}|dI|d dJ}|rMdK| dL| dM}zXtj|d,dNdOg dPI d,H } t| }!t|!tr/|! dr|!d |d< tdQ|!d   |! dr|!d |d< tdR|!d   |! dr/|!d |d< tdS|!d   W n tyL } ztdTt	|  W Y d,}~nd,}~ww t|dIdS )Uu~   
    询问用户节点：使用 interrupt 暂停等待用户输入
    最多询问4轮，超过后强制进入下一步
    r-   r   rZ   r   r   r   r    r!   r"   r#   r   r   r.   r   rC      u'   [ask_user] 已达到最大询问轮次 u   ，强制进入下一步r   r   r   r   )rC   rL   r,   updategotor   r   r   r      发生时间: r   r   r   r   u   ；   暂无u   、u   相关信息u   你是一个专业的故障诊断助手，需要友好地引导用户提供缺失信息。

要求：
1. 语气友好、专业，不要生硬
2. 说明为什么需要这些信息（更准确的诊断）
3. 鼓励用户提供更多细节up   请生成一段友好的回复，引导用户补充缺失信息。

【已获取的信息】（完整性评分: u   ）
u   

【缺失的信息】
u   

【用户当前输入】
u   

请生成回复：Nr   r   r   r   u   [ask_user] API调用失败: u*   **【需要更多信息】**

请补充：uD   

提供这些信息后，我可以更准确地为您诊断故障。u!   
**📋 已获取的信息：**

r   c                 s       | ]}d | V  qdS - NrV   r   partrV   rV   rW   r         zask_user.<locals>.<genexpr>z

---
)u   📝 需要更多信息u   📝 信息补充u   📝 请提供详情r   u   需要用户补充: u    (当前完整性: )r   r   u   补充舷号u	   舷号：r   r   r   u   补充设备名称u   设备名称：r   u   补充故障现象u   故障现象：
user_input)r&   r'   waiting_forr-   r   r   )r   rL   rC   uC   从用户输入中提取缺失的信息。

缺失的信息类型: u   

用户输入: u   

请提取用户补充的信息，输出JSON格式：
{"ship_number": "舷号", "device_name": "设备名称", "fault": "故障现象"}
如果某项信息没有提及，返回空字符串。Tu   你是信息提取专家。r   u   [ask_user] 提取到舷号: u"   [ask_user] 提取到设备名称: u"   [ask_user] 提取到故障现象: u   [ask_user] 信息提取失败: )rw   r   rv   r   r   r   r   r\   rd   rQ   r  r  r   r   rg   rj   ru   )"r   r-   r   r   r   r   r    r!   r"   r#   r   r   r.   rC   MAX_ASK_ROUNDSr,   existing_partsexisting_strmissing_strr   r   r&   r   existing_info_sectionr  r  r  suggested_repliesr   
user_queryupdate_dictextract_promptextract_response	extractedrV   rV   rW   r     s  
		




r   c              	      s  |  ddpd}|  ddpd}|  ddpd}|  ddp d}|  ddp(d}|  ddp0d}|  ddp8d}|  d	dp@d}|  d
dpHd}	|  dd}
g }|r[|d|  |re|d|  |ro|d|  |ry|d|  |r|d|  |r|d|  |r|d|  |r|d|  |	r|d|	  |rddd |D nd}d| d|
dd}g d}dt|d |
dd!d"}t D ]}z|| W q ty   Y qw d#d$d%d&d'd%g}t||d(d)}| d*d}d+|v sd,|v sd-|v r1td. d/g}|r&|r&|r&|d0 t	d1|d2|d3d2d4S td5|  t	d6|d7d8d7d4S )9uO   
    确认信息节点：在调用工具前让用户确认或补充信息
    r   rZ   r   r   r   r    r!   r"   r#   r   r.   r   r   r   r   r   r  r   r   r   r   r   c                 s   r  r  rV   r  rV   rV   rW   r   T  r  zconfirm_info.<locals>.<genexpr>r  u/   **📋 请确认以下信息是否正确：**

u   

**信息完整性评分：** z.0%u   

---

**💡 如果信息有误或需要补充，请直接告诉我。**
**💡 如果信息正确，请点击"确认并继续"开始检索知识库。**)u   ✅ 信息确认u   📋 请确认信息u   🔍 准备检索r   u%   等待用户确认信息 (完整性: r  r   u   确认并继续u   信息正确，请继续r     补充信息u   我需要补充：user_confirmr&   r'   r!  r   u   正确   确认u   继续u<   [confirm_info] 用户确认信息正确，准备调用工具r   r   Tr   )rD   r   rL   r,   r  u)   [confirm_info] 用户需要补充信息: Fr   )rD   r   rL   )
rw   rv   r   r  r  r   rd   r   r   r   )r   r   r   r   r   r    r!   r"   r#   r   r.   r#  r$  r&   r  r  r  r'  r   r(  r,   rV   rV   rW   r   1  s   



r   c           )         s  |  dg }|  ddpd}|  ddpd}|  ddpd}|  ddp&d}|  d}|  d}d	}d}	d}
d}|  d
d}|  di pFi }|rb|rbd}| dd}| dd}|rvt|I dH }| dd}
| dd}	|
sv|}
|}	d|v r|du rd| d| d}zt|ddI dH }td|rt|nd d W n ty } ztdt|  g }W Y d}~nd}~ww d|	 d}|}d|v r|du r|r|r|rzt|||dI dH }td|rt|nd  W n ty } ztd t|  d}W Y d}~nd}~ww g d!}d"t	
|d#|	 d$| d%}t D ]}z|| W q+ ty?   Y q+w t|trH|ng t|trQ|nd||
|	|ddt|t|d&d'S d|v r
|du r
t|I dH }| dd}| dd}| d(d)}| d*g }td+| d,|  d| d| d}|d	kr|rz8t|d|d-I dH }|}	|}
td.|rt|nd d |rt|dkrt|ddI dH }d/}W n ty } ztdt|  g }W Y d}~nd}~ww |d	ks|s
t|ddI dH }d}d}d0}t|tr\|r\|D ]:}t|trZ| d1d0}||krZ|}| dd}| dd} |rN| rN| }| rZ|  rZ|  }q!|ra|nd2}	|}
d/}td3|	 d4|  |r|rt|dkrdtd5|}!dtd5|	}"|!r|"r|!|"krtd6 g }#|dd D ]#}t|tr| d7d}$|$r|$ r|$|#vr|#|$  q|#rd8d9d: |#D nd;}%d<| d=|	 d>|% d?|	 d@	}&|dd/|
|	dA|r|ng dA|&t|dBdCS |r
dD| dE|	 dF}|}|d/kr"|	r"dtd5|	}"|"r"|"}d|v rp|du rp|rp|rp|rpzt|||dI dH }td|rKt|nd  W n tyo } ztd t|  d}W Y d}~nd}~ww g d!}d"t	
|dGdH| d%}t D ]}z|| W q ty   Y qw t|ot|dk}'t|ot|dIk}(|'s|(stdJ t|tr|ng t|tr|nd||
|	|dddddAdKdLS ||||
|	|dd|'|(dd&dLS )Mu   调用检索工具r,   r   rZ   r   r   r   r$   r%   r   r@   Fr>   similar_confirmedr   Nr~   r   u   设备u	   ，故障u   的维修方案   )r   top_ku;   RAG 检索完成（用户确认相似知识库），返回 r   u
    条结果u   RAG 检索失败: u+   ℹ️ 以下方案来源于您确认的「u   」知识库。r   )r   r   fault_symptomu#   图谱检索完成，结果长度: u   图谱检索失败: )u   🔍 正在检索知识库u   🔍 查找相关资料u   🔍 智能检索r   u    使用确认的相似知识库: u
   , 舷号: r   r   )r$   r%   r/   r0   r1   r2   r<   rB   r8   r9   rL   r   r}   r   u   [知识库匹配] 舷号=u   , 匹配类型=)r   r3  r~   u,   RAG 检索完成（精确匹配），返回 r   r   r   u   通用知识库u   最相关资料: u
   , 评分: r   uB   [相似匹配] 检索到其他舷号的资料，需要用户确认filenamer   c                 S   s   g | ]}d | qS )r  rV   )r   fnrV   rV   rW   
<listcomp>)  s    zcall_tools.<locals>.<listcomp>u   多个相关文档u,   【相似资料确认】

未找到舷号「u-   」的专属知识库资料，已为您在「u#   」中检索到最相关资料：

u5   

请问是否使用该资料进行诊断？

[KB_ID:]Tr   )r$   r%   r/   r0   r1   r<   r=   rB   r?   r8   rL   u   ⚠️ 未找到舷号「u0   」的专属知识库，以下方案来源于「u*   」，请结合实际情况参考使用。u   调用工具: r   r   uO   [call_tools] 未找到任何相关资料，需要用户确认使用模型能力model_confirm)r$   r%   r/   r0   r1   r2   r<   rB   r8   r9   rE   rL   )rw   r   r   ainvoker   r   rd   rQ   r   r  r  r   rj   rk   rU   ru   r\   r   r]   r   rv   ))r   r,   r   r   r   r   rag_resultsgraph_resultsr/   r1   r0   r2   r@   r>   confirmed_kb_namesimilar_ship_number	kb_result	rag_queryr   graph_ship_numberr  r  r  r~   r   r   best_kb_name
best_kb_id
best_scorer{   r   found_kb_namefound_kb_idr   r   filenames_listr6  filenames_strconfirm_responser  r	  rV   rV   rW   r     s  

 

 
r   c              	      s   |  ddpd}|  ddpd}|  ddpd}d|pd d|p"d d|p'd d	}g d
}dt|dd}t D ]}z|| W q; tyL   Y q;w ddddddg}t||dd}	|	 dd}
d|
v sqd|
v sqd|
v rtd td|
ddddS td|
  td|
d dd dS )!us   
    模型能力确认节点：当没有找到任何资料时，让用户确认是否使用模型本身能力
    r   rZ   r   r   up   **⚠️ 未找到相关资料**

抱歉，在知识库中未找到与以下信息相关的资料：
- 舷号：	   未提供   
- 设备名称：   
- 故障现象：u   

**💡 您可以选择：**
- 使用 AI 模型的知识库为您生成一般性建议
- 提供更详细的信息重新检索

请问是否使用 AI 模型为您生成建议？)u   🤖 AI 模型确认u   ⚠️ 资料未找到u   💡 使用模型能力r   u<   未找到相关资料，等待用户确认使用模型能力r   u   使用 AI 模型u%   确认，使用 AI 模型生成建议r  r-  u   我需要补充更多信息：r9  r/  r   r0  AIu   模型u.   [model_confirm] 用户确认使用模型能力Tr   )rF   r   rL   r  u*   [model_confirm] 用户选择补充信息: Fr   )rw   r  r  r   rd   r   r   r   )r   r   r   r   r&   r  r  r  r'  r   r(  rV   rV   rW   r9    s`   
	r9  c                    s   |  dd}|  dd}|  dg pg }|  ddpd}|  ddp$d}|  ddp,d}|s1d}d	d
ddddg}t||d|d}| dd}	|	ro|  dd|dtd|d}
td|  tdd|
ddddS td tddddddS )uH   
    相似资料确认节点：使用 interrupt 等待用户确认
    r?   rZ   r1   r=   r   r   r   ub   【相似资料确认】

未找到专属知识库，请确认是否使用相似知识库资料。u   确认使用u   确认使用该知识库r  u   取消u   取消，使用通用检索r   )r&   r'   r!  r1   	confirmedFr0   r   )r~   r   r   u5   [similar_confirm] 用户确认使用相似知识库: Tr   )r@   rA   r>   rL   r  u3   [similar_confirm] 用户取消，直接生成回复r   )r@   rA   rL   )rw   r   r   r]   r   r   r   )r   r?   r1   r=   r   r   r   r'  user_responseuser_confirmedr>   rV   rV   rW   r     sR   

r   c           -         s  |  ddpd}|  dg pg }|  ddpd}|  ddp d}|  ddp(d}|  ddp0d}|  ddp8d}|  d	dp@d}|  d
dpHd}	|  ddpPd}
|  ddpXd}|  dp_g }|  dpfd}|  dd}|  dd}|  dd}d}|r|dd }g }|D ]3}t|tr| dd}| dpd }|dkr|d|  q|dkr|d|dd   q|rd|nd}|ot|dk}|ot|dk}|s]|s]|s|s|sd}d | d!}n7d"}d#|pd$ d%|pd$ d&|pd$ d'|pd$ d(|pd$ d)|	p
d$ d*|
pd$ d+|pd$ d,|pd- d.}ztj|d|g d/I dH }|r4| nd0d1d2d3gd4d5W S  t	y\ } zd6t
| g d4d5W  Y d}~S d}~ww g }|dd7 D ]}t|tr| d8ptd }|r|| qe|rdd9d: t|D nd;} t|d<krd}d=| d>|  d?|pd$ d@|pd$ dA	}!ztjddBdCd|!dDgdEI dH }"|" dFdG}#|" dHdI}$W n$ t	y   |r|n|r|d ndG}#|rdJn|rdIndK}$Y nw |#dGkrHdL}d#|pd$ d%|pd$ d&|pd$ d.}ztj|d|g d/I dH }|r#| nd0g d4d5W S  t	yG } zd6t
| g d4d5W  Y d}~S d}~ww |$dJkrOdMndN}$dO|$ dP|$ g}%dQt|%dR|#dd<  dSdT}&t D ]}'z|'|& W qo t	y   Y qow d}(|r|(dU| d7 }(|r|(dV| d7 }(|	r|(dW|	 d7 }(|
r|(dX|
 d7 }(|r|(dY| d7 }(|r|(dZ| d7 }(|o|p|})|)rd[|pd$ d\|pd$ d@|pd$ d|( d]|# d^| d_}nd`|pd$ d\|pd$ d@|pd$ d|( d]|# da}zQtjddbd|dDgdcI dH }"|"r$|" ndd}"|r0| de|" }"df|$ dg}*|* dh|" }"|)sFdi}+|"|+7 }"djdkd3dldmd3dndod3g},|"g |,dB|) d4dpW S  t	y} } zdqt
| g g d4drW  Y d}~S d}~ww )su   生成最终回复r   rZ   r   r   r   r   r   r   r    r!   r"   r#   r$   r%   r5   Fr2   r1   Nr   r   r   r   r   r     r   r   r   u   你是一个友好的故障诊断助手。用户可能只是在打招呼或询问一般性问题。
请友好地回复，并简要介绍你能提供的帮助。u   用户说：u   

请友好回复：u   你是一个专业的故障诊断助手。
虽然没有检索到相关资料，但可以根据用户提供的信息给出一般性建议。
注意：明确告知用户这是基于一般经验的建议。u   用户描述：
- 舷号: rJ  u   
- 设备名称: u   
- 故障现象: u   
- 故障码: u   
- 故障时间: u   
- 故障频率: u   
- 已尝试措施: u   
- 运行工况: u   
- 其他信息:    无u,   

请给出一般性的故障诊断建议：r  u$   抱歉，未能找到相关资料。u   提供更详细信息u   我来提供更详细的信息r  end)r&   r'   rL   u&   抱歉，处理过程中出现错误:    rX   c                 S   s$   g | ]\}}d |d  d| qS )z  [r   z] rV   )r   irX   rV   rV   rW   r7  ]  s   $ z%generate_response.<locals>.<listcomp>u     (无RAG结果)r   u   # 任务
你是一个信息源筛选器。请从以下两个来源中，筛选出**最多两条**与用户问题最相关的原始字符串。

# 来源
## 1. 图谱结果
u   

## 2. RAG检索列表
u"   

# 用户问题
- 设备名称：rL  u   

# 筛选规则
1. 最多选择两条最相关的结果
2. 如果所有结果都完全不相关，输出"NO_RELEVANT_RESULT"

# 输出要求（JSON格式）
{
    "type": "graph或rag或both或none",
    "answer": "合并后的相关内容字符串"
}Tu'   你是一个严格的信息筛选器。)r   r   )r   r   r   r   answerNO_RELEVANT_RESULTr   raggraphr}   u   你是一个专业的故障诊断助手。
虽然没有检索到相关资料，但可以根据用户提供的信息给出一般性建议。u   图谱u   文本u!   ✨当前使用的检索类型为u   ✨本次检索策略为r   u	   内容为r   r   u   - 故障码/报警代码：u   - 故障发生时间：u   - 故障频率/持续时间：u   - 已尝试的维修措施：u   - 设备运行工况：u   - 其他相关信息：uw   你是一名资深工业设备维修工程师。用户正在与你进行后续交互。

【设备信息】
- 舷号：rK  u   
【参考资料】
   

【用户当前问题】
   

请给出回复：u   你是一名资深工业设备维修工程师，请根据以下信息生成故障分析与维修方案。

【设备信息】
- 舷号：u  

【输出要求】
1. 先用一句话判断故障原因（包含舷号、设备、故障现象，不超过40字）
2. 然后给出维修方案，步骤清晰、可直接执行
3. 如果参考资料信息不足，明确指出缺少什么

请直接输出方案：u]   你是一名资深工业设备维修工程师，严格依据检索信息生成维修方案。)r   r   r   u   抱歉，无法生成回答。z

---

u   本方案依据u   知识库生成。

u   

---

**💡 请您确认维修方案是否正确：**
- 如果方案有误或需要调整，请告诉我具体的错误之处
- 我会根据您的反馈重新生成更准确的方案

请问方案是否有需要修改的地方？u   方案有误u   方案有误，需要修改：   遇到问题   执行中遇到问题：r      请帮我生成维修报告)r&   r(   r'   r5   rG   rL   u   分析生成失败: r&   r(   r'   rL   )rw   rj   ru   r\   rv   r   r   r   r   rd   rQ   	enumerater  r  r   )-r   r   r   r   r   r   r   r   r    r!   r"   r#   r;  r<  r5   r2   r1   r   r   r   rf   r   r   r  r	  r   r   r&   r   rag_ctx_partsr{   rX   rag_list_str
rag_promptrW  
rag_answerrag_typer  r  r  detail_infois_follow_upscheme_sourcesupplement_promptr'  rV   rV   rW   r     s  
	
"




		r   c                    s  |  ddpd}|  dg pg }|  ddpd}|  ddp d}|  ddp(d}|  dp/g }|  dp6d}d}|r|d	d
 }	g }
|	D ]3}t|trx| dd}| dpXd }|dkrh|
d|  qE|dkrx|
d|d
d   qE|
rd|
nd}g }|d
d D ]}t|tr| dpd }|r|| qd}|rt|dkr|d
d }n|rd|d
d d
d }d}d|pd d|pd d|pd d|pd d | d!| d"}zTtj|d
|g d#I d
H }|r| nd$}d%d&d'd(d)d'g}g d*}d+t	
|d,|d
d-  d.d/}t D ]}z|| W q ty,   Y qw ||g d0d1d2W S  tyT } zd3t| g g d1d4W  Y d
}~S d
}~ww )5u   后续问答节点r   rZ   r   r   r   r   r$   r%   rQ  Nr   r   r   r   r   r   rR  r   r2  rX   r   i  r]     u   你是一名资深工业设备维修工程师，正在协助用户执行维修方案。
回复要求：
1. 理解用户当前的问题或反馈
2. 结合之前的维修方案和参考资料给出针对性建议
3. 回复简洁实用u   【设备信息】
- 舷号：rJ  rK  rL  u   

【参考资料】
rS  r   r[  r\  r  u$   抱歉，无法处理您的问题。r^  r_  r  r   r`  )u   💬 后续问答u   💬 执行指导u   💬 问题解答r   u   处理后续问题:    r   r   TrT  )r&   r'   r(   r5   rL   u#   处理您的问题时出现错误: )r&   r'   r(   rL   )rw   rj   ru   r\   rv   r   r   r   r   r  r  r   rd   rQ   )r   r   r   r   r   r   r;  r<  r   r   r   rf   r   r   rc  r{   rX   reference_materialr   r   r&   r'  r  r  r  r   rV   rV   rW   follow_up_qa  s   


	
ro  c           
   
      s   ddl m} | ddpd}| dg }| ddpd}| ddp$d}| ddp,d}|r6tj|d	d
nd}z ||||ddI dH }|dd|dg |dg dddW S  tyv }	 zdt|	 g g ddW  Y d}	~	S d}	~	ww )u   报告生成节点r   )run_other_report_workflowr   rZ   r   r   r   r   F)ensure_asciireport)r   r   rh   
route_flagNr&   r(   r'   TrT  )r&   r(   r'   r5   rL   u   报告生成失败: ra  )workflows.workflow_other_reportrp  rw   ra   dumpsrd   rQ   )
r   rp  r   rh   r   r   r   history_message_jsonreport_resultr   rV   rV   rW   r   }  s:   


r   c                    sb  |  ddpd}|  ddpd}|  ddpd}|  ddp d}d| d|p(d d	|p-d d
|p2d d|dd  t|dkrBdnd d}dd||||ddg}dddg}g d}dt|d|dd  dd}	t D ]}
z|
|	 W qq ty   Y qqw t|||dd}| dd}|dkrtd t|d d!d"d!d#S td$ t|d%d&d%d#S )'uZ   
    处理用户反馈节点：接收用户对方案的反馈，提供上报 actions
    r   rZ   r   r   r   u`   **📝 已收到您的反馈**

感谢您对维修方案的建议！您的反馈已记录：

> u1   

---

**📋 反馈信息摘要：**
- 舷号：rJ  rK  rL     
- 反馈内容：Nr   r   uv   

---

**💡 您可以选择：**
- 点击「上报」将反馈提交给相关部门
- 继续对话获取更多帮助rr  u   上报)r   r   r   feedback)r   r   rl   u   继续对话   我还有其他问题：r  )u   📝 反馈处理u   📋 方案反馈u   ✅ 反馈确认r   u   处理用户反馈: rm  r   feedback_confirm)r&   r(   r'   r!  actionu*   [handle_feedback] 用户选择上报反馈Tconfirm_report)rH   rI   rL   r  u$   [handle_feedback] 用户继续对话r   )rH   rL   )	rw   r   r  r  r   rd   r   r   r   )r   r   r   r   r   r&   r(   r'  r  r  r  r   user_actionrV   rV   rW   r     s~   	


	r   c           
   
      s   |  ddpd}|  ddpd}|  ddpd}|  ddp d}d|p%d d|p*d d	|p/d d
|dd  t|dkr?dnd d
}ddddddg}g d}dt|dd}t D ]}	z|	| W q^ tyo   Y q^w |g |ddddS )u@   
    上报确认节点：用户点击上报后确认完成
    r   rZ   r   r   rH   u_   **✅ 上报成功**

您的反馈已成功上报！

---

**📋 上报信息：**
- 舷号：rJ  rK  rL  rx  Nr   r   uC   

---

**💡 感谢您的反馈，相关部门将及时处理。**r   r`  r  u   继续咨询rz  )u   ✅ 上报成功u   📋 反馈已提交u   🎉 完成r   u   反馈上报成功r   TFrT  )r&   r(   r'   rJ   rI   rL   )rw   r   r  r  r   rd   )
r   r   r   r   rH   r&   r'  r  r  r  rV   rV   rW   r}    sJ   	



r}  c                 C   s4   |  dd}|  dd}|  dd}||krdS |S )u   Agent 思考后的路由r*   r   r3   r   r4   r2  r   rw   )r   r  r3   r4   rV   rV   rW   _route_after_think-  s   r  c                 C   s,   |  dd}|  dd}|rdS |rdS dS )u   检索工具调用后的路由rB   FrE   r   r9  r   r  )r   rB   rE   rV   rV   rW   _route_after_tools9  s   r  c                 C   s.  t t}|dt |dt |dt |dt |dt |dt |dt	 |dt
 |d	t |d
t |dt |dt |td |dd |dtddddddd
dd |dtdd	dd |dt |dt |d
t |dt |dt |j| dS )u  
    创建故障诊断工作流（基于 Checkpointer 的状态持久化版本）
    
    核心改进：
    1. ask_user 和 similar_confirm 使用 interrupt 实现暂停等待
    2. 用户输入后通过 Command 恢复执行
    3. 状态自动持久化，无需手动传递
    r   r   r   r   r   r   ro  r   r9  r   r   r}  )r   r   r   r   r   r   r   r   )r   r9  r   checkpointer)r   r   add_noder   r   r   r   r   r   ro  r   r9  r   r   r}  add_edger	   add_conditional_edgesr  r  r
   compile)r  workflowrV   rV   rW   create_fault_diagnosis_workflowD  sH   	
r  r   r   rs  previous_state_jsonchat_id
message_idrO  c	              
      sf  |r|nd}	|	rdd|	iini }
|du r"ddl m} | I dH }t|d}|	rkz||
I dH }|r|jr|j}td|d d	|d
 d|d  |jrntd |r]|nd|i}|	t
|d|
I dH }n|}|dr|d d| }i ||t|dd}|	||
I dH }ni d| d|dt|ddd
dddddddddddddddddddddd g d!g i d"dd#dd$dd%g d&g d'd(d)dd*dd+dd,dd-dd.d/d0dd1dd2i d3dd4di d5dd6dd7dd8g d9i d:dd;dd<dd=dd>dd?dd@ddAddBddCddDddEddddF}|	||
I dH }W n tyj } ztdG|  ddl}|  i }W Y d}~nd}~ww i d| d|dt|ddd
dddddddddddddddddddddd g d!g i d"dd#dd$dd%g d&g d'd(d)dd*dd+dd,dd-dd.d/d0dd1dd2i d3dd4di d5dd6dd7dd8g d9i d:dd;dd<dd=dd>dd?dd@ddAddBddCddDddEddddF}z|	||
I dH }W n0 tyL } z#tdHt|  ddl}|  dIt| g dJg dKW  Y d}~S d}~ww |du rTi }|dLg }|r|re|d jni }tdM|  |ddNg dJ|d g |dOddPS |d"rdI|d"  g dJg dKS |dQd}|sdJ}|dd|d!g ||d g |dRS )Su  
    执行故障诊断工作流

    Args:
        extracted_text: 文本描述
        combined_query: 组合查询
        history_message: 历史消息（JSON格式）
        route_flag: 路由标识
        previous_state_json: 兼容参数（已废弃）
        chat_id: 聊天会话 ID
        message_id: 消息 ID
        checkpointer: LangGraph checkpointer 实例
        user_response: 用户恢复执行的响应数据

    Returns:
        工作流执行结果
    Nconfigurable	thread_idr   )checkpointer_managerr  u2   [Checkpointer] 发现已保存状态: ship_number=r   z, device_name=r   z, fault=r   u0   [Checkpointer] 恢复执行，注入用户响应r   )resumer    F)r   r   rK   r   r   rZ   r   r   r    r!   r"   r#   r$   r%   r&   r'   r(   r)   r*   r+   r,   r-   r.   r   r/   r0   r1   r2   r3   r4   r2  r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   rA   rB   rC   rD   rE   rF   rG   rH   rI   rJ   r   u#   [Checkpointer] 状态恢复失败: u   [工作流执行失败] u#   故障诊断工作流执行失败: fault_diagnosis)r&   r(   
result_tagr'   __interrupt__u2   [Interrupt] 工作流中断，等待用户输入: u   请提供更多信息r!  )r&   r(   r  r'   r!  rs  )r&   r(   r  r'   rs  )checkpointer_configr  get_async_checkpointerr  
aget_stater   r   rw   tasksr:  r   rm   rd   	traceback	print_excrQ   r   )r   r   rh   rs  r  r  r  r  rO  r  configr  appcurrent_statesaved_stateresume_valuer   merged_queryinitial_stater   r  
interruptsinterrupt_datarV   rV   rW   run_fault_diagnosis_workflowv  sB  

,
	
 !"#$%&'()*+,-./012347	
 !"#$%&'()*+,-./012348






r  __main__c                     s2   t d tdddddI d H } t d|   d S )Nu4   测试故障诊断工作流（Checkpointer 版本）u   101舰主机发生异响	test_chat
test_msg_1)r   r   r  r  u   结果: )r   r  )r   rV   rV   rW   test^  s   r  )	rZ   rZ   rZ   rZ   rZ   rZ   rZ   rZ   rZ   r   )rZ   rZ   rZ   rZ   rZ   NN)CrP   typingr   r   r   r   r   r   langgraph.graphr   r	   r
   langgraph.typesr   r   langgraph.checkpoint.memoryr   tools.function_toolr   r   modelsAPI.model_apir   utils.function_trackerr   r  r   r   asynciora   r]   r   r  difflibr   r  r   r   operatorr   rQ   rg   rm   r   r   ry   r   rS   r   r   r   r   r   r   r9  r   r   ro  r   r   r}  r  r  r  r  rM   r  runrV   rV   rV   rW   <module>   s     E
*
:	

)  c ,c vD8  g$X4
5
	


 
f
,XNX'x   
    ӱMj_>                       d Z ddlmZmZmZmZmZ ddlmZm	Z	m
Z
 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 ddlmZ dd	lmZ dd
lmZmZ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)m*Z*m+Z+ ddl,m-Z- ddl.m/Z/ ddl0m1Z1m2Z2 ddl3m4Z4m5Z5 ddl6m7Z7 ddl8Z8ddl9Z9ddl:Z:ddl;Z;ddl<Z< G d de      Z=de>de>fdZ?dJde>de>de>de>deee>ef      f
dZ@ddddd d d d!d"d#	ZAdKde>de>de>d$e>d%e>d&e>d'e>d(e>d)e>deBfd*ZCd+e=dee>ef   fd,ZDd+e=de>fd-ZEd+e=dee>ef   fd.ZFd+e=dee>ef   fd/ZGd+e=defd0ZHd+e=defd1ZId+e=dee>ef   fd2ZJd+e=defd3ZKd+e=dee>ef   fd4ZLd+e=dee>ef   fd5ZMd+e=dee>ef   fd6ZNd+e=dee>ef   fd7ZOd+e=dee>ef   fd8ZPd+e=dee>ef   fd9ZQd+e=dee>ef   fd:ZRd+e=defd;ZSd+e=dee>ef   fd<ZTd+e=de>fd=ZUd+e=de>fd>ZVd+e=de>fd?ZWdLd@ZXdMdAe>dBe>dCe>dDe>dEe>dFe>dGe>dHee>ef   dee>ef   fdIZYy)Nu+   
故障诊断工作流 checkpointer 版本
    )	TypedDictOptionalDictAnyList)
StateGraphSTARTEND)	interruptCommand)graph_rag_search)
rag_search)atlas_retrievalformat_atlas_results!extract_entity_names_from_history)	OpenaiAPI)get_all_callbacks)extract_image_pathsnormalize_markdown_imagesget_image_prompt_guidance)run_baike_workflow)safe_json_extractparse_historynormalize_latex_spacingremove_duplicate_contentconvert_rag_resultcalculate_info_completenessemit_callback_eventbuild_history_strbuild_detail_infoappend_atlas_sectionstream_format_and_postprocess)generate_report_word)is_confirmation_intent)KB_TREE_CONFIGSERVER_CONFIG)FAULT_DIAGNOSIS_PROMPTSCOMMON_PROMPTS)record_fault_from_stateNc                      e Zd ZU dZeed<   eed<   eeeef      ed<   eed<   eed<   eed<   eed<   eed	<   eed
<   eed<   eed<   eed<   e	eeeef         ed<   e	e   ed<   e	eeef      ed<   eed<   eeeef      ed<   eeeef      ed<   eed<   eed<   eed<   ee   ed<   ee   ed<   e
ed<   eed<   eed<   eed<   eed<   eed<   eed<   eeef   ed <   eed!<   eed"<   eed#<   eed$<   eed%<   eed&<   eed'<   eed(<   eed)<   eed*<   eed+<   eed,<   eed-<   eed.<   eed/<   eed0<   eed1<   e	ee      ed2<   e	eeef      ed3<   eed4<   y5)6FaultDiagnosisStateu   故障诊断工作流状态extracted_textcombined_queryhistory_messagesship_numberdevice_namefaultadditional_info
fault_code
fault_timefault_frequencytried_measuresrunning_conditionrag_search_resultgraph_search_resultdeep_rag_resultsresponsesuggestedRepliesactionserror_messageagent_decisionagent_reasoningtools_to_callmissing_infoinfo_completenessmatched_kb_idmatched_kb_nameiteration_countmax_iterationsscheme_generatedwaiting_for_supplementextracted_infohas_rag_resulthas_graph_result	ask_rounduser_confirmed_infoneed_model_confirmuser_confirmed_modeluser_feedbackwaiting_report_confirmreport_confirmedinitializedcurrent_nodeuser_intentfollow_up_intentuser_feedback_for_regenerateis_regeneratinglast_generated_schemescheme_typedeep_analysis_pointsatlas_resultslast_combined_queryN)__name__
__module____qualname____doc__str__annotations__r   r   r   r   floatintbool     Te:\ZKYNLP\Hjunproject\project0506\wx-agent\app\workflows\workflow_fault_diagnosis.pyr+   r+      s   %4S>**JOOT#s(^ 455!#&tCH~..M4S>**$sCx.!!9s)  cN"N    "%%"49--DcN++ri   r+   contentreturnc                    | s| S t        j                  dd      j                  d      t        j                  dd      j                  d      }d|r)ddlm}  ||      }|j                   d|j                   rt        j                  dfd	|       } nrt        j                  dfd
|       } rt        j                  dfd|       } | S )u   
    预处理方案内容：将相对路径图片URL转为绝对URL
    图片格式解析和公式渲染由 word_generator.py 直接处理
    base_url /urlr   )urlparsez://z!(/api/v1/knowledge/files/[^)\s]+)c                     | j                  d      j                  d      s | j                  d       S | j                  d      S N   httpgroup
startswith)mkb_hosts    rj   <lambda>z-_preprocess_scheme_for_word.<locals>.<lambda>x   s@    aggaj6K6KF6S	!''!*.cYZY`Y`abYccri   c                     | j                  d      j                  d      s | j                  d       S | j                  d      S rt   rw   rz   rn   s    rj   r|   z-_preprocess_scheme_for_word.<locals>.<lambda>~   @    qwwqz7L7LV7T
1771:,/dZ[ZaZabcZddri   z(/picture/[^)\s]+)c                     | j                  d      j                  d      s | j                  d       S | j                  d      S rt   rw   r~   s    rj   r|   z-_preprocess_scheme_for_word.<locals>.<lambda>   r   ri   )
r&   getrstripr%   urllib.parserr   schemenetlocresub)rk   kb_base_urlrr   	kb_parsedrn   r{   s       @@rj   _preprocess_scheme_for_wordr   c   s    
   R077<H $$UB/66s;KG)[)	%%&c)*:*:);< &&0c

 
&&0d
 &&!d
 Nri   scheme_contentr/   r0   r1   c           	      >   	 d}|r| d| }|r| d| }t        |       }dj                  t        j                  dd            }t	        j
                  | d      }t	        j
                  d      }d	| d
| d| d| d	}	t        j                  j                  t        j                  j                  t                    }
t        j                  j                  |
      }t        j                  j                  |d      }t        j                  |d       t	        j
                  d      }t        j                  dd|      }| d| d}t        j                  j                  ||      }t        |	||      }g }|rdt        j                  j                  |      rEt!        j"                  dd      }| d| }|j%                  d| d|||	d       t'        d|        |S # t(        $ r.}t'        d|        ddl}|j-                          g cY d}~S d}~ww xY w)u9  
    从方案内容直接生成报告并返回下载按钮
    
    Args:
        scheme_content: 方案内容（Markdown 格式）
        ship_number: 舷号
        device_name: 设备名称
        fault: 故障现象
    
    Returns:
        actions 列表，包含下载按钮（如果生成成功）
    u   维修方案报告z - ro   ABCDEFGHIJKLMNOPQRSTUVWXYZ   )kz-%Y-%m-%d-%H%Mz%Y-%m-%d %H:%Mz## **u   **

报告编号：u   
编制时间：z

---


created_wordT)exist_okz%Y%m%d_%H%M%Sz[\\/:*?"<>|]_z.docx)markdowntitleoutputrn   z/api/download/download)typelabelrq   fileNamerk   u3   [_generate_report_from_scheme] 报告生成成功: u3   [_generate_report_from_scheme] 生成报告失败: r   N)r   joinrandomchoicestimestrftimeospathdirnameabspath__file__makedirsr   r   r#   existsr&   r   appendprint	Exception	traceback	print_exc)r   r/   r0   r1   report_titleprocessed_contentrandom_lettersreport_numbercompile_timereport_contentcurrent_dir
parent_dirword_dir	timestamp
safe_title	file_nameoutput_pathword_resultr=   rn   download_urler   s                          rj   _generate_report_from_schemer      s   9+)]#l^<L*^3{m<L 8G 0LPQ!RS(8&GH}}%56 #<. 1 ~     ggoobggooh&?@WW__[1
77<<
N;
Ht, MM/2	VVOS,?
!l!I;e4	ggll8Y7*N]hi 277>>+6$((R8H&Z~i[ALNNJ<.8NVbox  ES  T  UG}UV CA3GH		s   G"G% %	H.#HHHg?      ?g{Gz?gQ?g?g{Gz?	r/   r0   r1   r3   r4   r5   r6   r7   r2   r3   r4   r5   r6   r7   r2   c	           
      :    | ||||||||d	}	t        t        |	      S )Nr   )r   FAULT_INFO_WEIGHTS)
r/   r0   r1   r3   r4   r5   r6   r7   r2   valuess
             rj   _calculate_info_completenessr      sE    (udn  I  ^m  AO  fw  L[  \F&'96BBri   statec                   K   | j                  dd      xs d}| j                  di       xs i }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|s|s|s|rt        d       dd	d
S t        d   }t        d   j	                  |      }	 t        j                  |dd|g        d{   }t        |      }	d}
t        |	t              r|	j                  dd      }
t        d|
        |
dk(  r|
dd	dS |
dd
S 7 Q# t        $ r(}t        dt        |       d       ddd	dcY d}~S d}~ww xY ww)u   
    意图分类节点
    r-   ro   rJ   r/   r0   r1   u<   [classify_intent] 已在维修流程中，跳过意图分类   维修extract_info)rV   rU   classify_intent_systemclassify_intent_userr-   NTquerymodeljson_outputsystem_promptmessagesintentu   [意图分类] 用户意图: F)rV   rH   rU   follow_up_qau   [意图分类失败: u   ，默认按维修处理)r   r   r'   r(   formatr   open_api_chat_without_thinkingr   
isinstancedictr   rc   )r   r-   rJ   r/   r0   r1   r   promptresponse_textparsedr   r   s               rj   classify_intentr      s     YY/4:NYY/4:N))M2.4"K))M2.4"KIIgr"(bE LM'HH+,DEM23::.:YFc'FFVZ^ko  L  VX  Y  Y"=1fd#ZZ(3F-fX67X#)eTbdd#).JJ Y  c%c!fX-EFG'ER`bbcsU   B)E,D 	D
AD ED ED 	E&E	EE	EEc                 4    | j                  dd      }|dk(  ryy)u   意图分类后的路由rV   r   u   百科r   r   r   r   r   s     rj   _route_after_classifyr     s     YY}h/Fri   c           
      2  K   | j                  dd      rt        d       ddiS | j                  dd      xs d}| j                  dg       xs g }t        |d	
      }g }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}	| j                  dd      xs d}
| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |	r|j                  d|	        |
r|j                  d|
        |r|j                  d|        |r|j                  d|        |r|j                  d|        |rdj	                  |      nd}t
        d   }t        d    j                  d!||xs d"|#      }	 t        j                  |d$d%|g &       d${   }t        |      }t        |t              si }|j                  dd      xs |}|j                  dd      xs |}|j                  dd      xs |}|j                  dd      xs |}|j                  dd      xs |	}|j                  dd      xs |
}|j                  dd      xs |}|j                  dd      xs |}|j                  dd      xs |}|||||||||d'	}t        d(|d    d)|d    d*|d           i ||d%dd+S 7 # t        $ r&}t        d,t        |              d%dd-cY d$}~S d$}~ww xY ww).u   
    信息提取节点
    rT   Fu$   [extract_info] 已初始化，跳过rU   agent_thinkr-   ro   r.   
   )recent_countr/   r0   r1   r3   r4   r5   r6   r7   r2      舷号:    设备名称:    故障现象:    故障码: u   故障时间:    故障频率:    已尝试措施:    运行工况:    其他信息: r   u   （无已提取信息）extract_info_systemextract_info_userr      （无历史对话）)	biz_labelexisting_info_strhistory_strr-   NTr   r   u   [信息提取] 舷号=	   , 设备=	   , 故障=)rJ   rT   rU   u   信息提取失败: )rT   rU   )r   r   r   r   r   r'   r(   r   r   r   r   r   r   r   rc   )r   r-   r.   r   existing_infoexisting_ship_numberexisting_device_nameexisting_faultexisting_fault_codeexisting_fault_timeexisting_fault_frequencyexisting_tried_measuresexisting_running_conditionexisting_additional_infor   r   r   r   r   new_ship_numbernew_device_name	new_faultnew_fault_codenew_fault_timenew_fault_frequencynew_tried_measuresnew_running_conditionnew_additional_inforJ   r   s                                 rj   r   r     sQ     yy&45..YY/4:Nyy!3R8>B#$42FKM 99]B7=2 99]B7=2YYw+1rN))L"5;))L"5;$yy):B?E2#ii(8"=C!&+>!C!Ir$yy):B?E2x(<'=>?~.B-CDE~n-=>?{+>*?@A~.A-BCD~.F-GHI01H0IJK!~.H-IJK~.F-GHI4A		-0Ga+,ABM/077+:#:%	 8 FD'FFVZ^ko  L  VX  Y  Y"=1&$'F **]B7O;O **]B7O;OJJw+=~	L"5L9LL"5L9L$jj):B?[C[#ZZ(8"=XAX &

+> C aGa$jj):B?[C[)8aj  zH  We  yL  _q  G\  pC  E&~m'D&EY~^kOlNmmv  xF  GN  xO  wP  Q  	Ru.u>QUfsuu) Y,  D$SVH-.#MCCDsI   H'N*M% M"DM% !N"M% %	N.N	N
NNNc                   'K   | j                  dd      xs d'| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}| j                  d
d      xs d}| j                  dd      xs d}	| j                  dg       xs g }
| j                  dd      }| j                  dd      }| j                  dd      }| j                  d      }| j                  d      }| j                  dd      }| j                  dd      }| j                  dd      }t        |xr |j                               }t        |xr |j                               }t        |xr |j                               }|duxr t        |      dkD  xs |}|duxr t        |      dkD  xs |}t	        |||||||||		      }d}|rg d}t        'fd|D              }|rYt        d' d       dg}|r|r|j                  d        i ddddddd!dddddd"dd#dd$ddd%d&d%ddd'dd(d)d*|d+d)S t        |
d,d-.      }t        d/   }t        d0   j                  |xs d1|xs d1|xs d1|xs d2'3      }	 t        j                  |dd%|g 4       d{   } t        |       }!d5}"t        |!t              r|!j                  d6d5      }"t        d7|"        |"d8k(  r d8}#d9}$t        d:|# d;|$        |#|$||d<z   |#d=S |"d>k(  r9d?}#d@}$i d(|#dA|$ddddd!dddddddd"dd#dd$dddd&ddB|d|d<z   d+|#S |"dCk(  r dD}#dE}$t        d:|# d;|$        |#|$||d<z   |#d=S |"dFk(  rdG}#dH}$|#|$dF||d<z   |#dIS |"dJk(  rdG}#dH}$|#|$dJ||d<z   |#dIS dK}#dL}$t        d:|# d;|$        |#|$||d<z   |#d=S |r|s[dO}#g }&|s|&j                  dP       |s|&j                  dQ       dRdSj%                  |&       }$t        d:|# d;|$        |#|$|&||d<z   |#dTS ||k  rzdO}#dU| dV| }$g }&|s|&j                  dW       |s|&j                  dX       |s|&j                  dY       |s|&j                  dZ       t        d:|# d;|$        |#|$|&xs d[g||d<z   |#dTS |s|r d\}#d]}$t        d:|# d;|$        |#|$||d<z   |#d=S |s d?}#d^}$t        d:|# d;|$        |#|$||d<z   |#d=S d)}#d_}$dg}|r|r|j                  d        t        d:|# d;|$        t        d`| da| db|        t'        g dcdd|# de|$ddf  dg       |#|$|||d<z   |#dhS 7 # t         $ rB}%t        dMt#        |%              dG}#dH}$t        d:|# d;|$ dN       |#|$||d<z   |#d=cY d}%~%S d}%~%ww xY ww)iuF   
    Agent 思考节点：基于当前状态决定下一步动作
    r-   ro   r/   r0   r1   r3   r4   r5   r6   r7   r2   r.   rH   FrK   rL   r8   r9   rF   r   rN   waiting_feedbackNd   r   r   )   开始诊断u   信息已足够   信息已足够，开始诊断u   开始   诊断c              3   &   K   | ]  }|v  
 y wNrh   ).0kwr-   s     rj   	<genexpr>zagent_think.<locals>.<genexpr>  s     S=RrbN2=Rs   u-   [重新诊断] 检测到重新诊断意图: 'u.   '，重置状态直接调用工具生成方案r   r   r:   rY   rX   rW   TrT   rM   r?   
call_toolsrA   rU      ,  r   assistant_truncateagent_think_intent_systemagent_think_intent_user	   未提供   无)r/   r0   r1   r   r-   r   otherr   u#   [Agent 意图分析] 用户意图: generate_reportu   用户请求生成报告u   [Agent 决策] decision=z, reasoning=ru   )r?   r@   rC   rF   rU   modify_infoconfirm_infou!   用户需要修改或补充信息r@   rC   	has_errorhandle_feedbacku   用户反馈方案有错误
not_solvedanalyze_follow_up_intentu*   已生成方案，分析用户后续意图)r?   r@   rW   rC   rF   rU   related_questionr   u!   其他意图，直接调用 baikeu   [Agent 意图分析失败: u	    (降级)ask_user   设备名称   故障现象u   缺少基本信息: z, )r?   r@   rB   rC   rF   rU   u   信息完整性评分 u    低于最低要求 u   舷号（可选）u	   故障码u   故障时间u   故障频率u   更多详细信息generate_responseu6   信息充足，已有检索结果，直接生成回复u6   信息充足，需要用户确认后再检索知识库u6   信息充足，用户已确认，开始检索知识库u   [Agent 提取] 舷号=r   r   )u   🤖 Agent 思考中u   🤖 智能分析u   🤖 决策判断u   决策: u    | 理由: 2   ...)r?   r@   rA   rC   rF   rU   )r   rg   striplenr   anyr   r   r   r'   r   r   r   r   r   r   r   rc   r   r   )(r   r/   r0   r1   r3   r4   r5   r6   r7   r2   r.   rH   rK   rL   r8   r9   rF   rN   r  has_ship
has_device	has_faulthas_rag	has_graphrC   MIN_COMPLETENESS_FOR_GENERATE_re_diagnose_keywords_is_re_diagnoserA   r   intent_system_promptintent_promptintent_responseparsed_intentr   decision	reasoningr   rB   r-   s(                                          @rj   r   r   Y  s
     YY/4:N))M2.4"K))M2.4"KIIgr"(bE<,2J<,2Jii 126<"OYY/4:N		"5r:@bii 126<"Oyy!3R8>Byy!3U;YY/7Nyy!3U;		"56))$9:ii 115O))$95Ayy!3U;K7K$5$5$78Hk9k&7&7&9:JU,u{{}-I ,K5F1G!1K^P^G$D0SS9L5MPS5ShXhI4Ydkp  }G  S]  n}  M[  n  P_  `$(! yS=RSSA.AQQ  A  B)NMu$$%78 s&  s.A4  sH]_c  sdvx|  s  ~N  PU  s  Vh  jo  s  pA  CH  s  Ig  ik  s  l~  @B  s  CX  Z^  s  _l  nr  s  sD  FG  s  HS  UV  s  Wg  iu  s  vE  GT  s  Uc  eq  s  s'(8q]`a67RS/0IJQQ#2{#2{&;#,u) R 
5	u$-$L$L# 2% O .o>MF-.&**8W=7x@A **,6	0
,ykRS*2iev  KZ  ]^  K^  ow  y  y=()?	 Y((  Y3Di  YPcei  Yj  BF  Y  GY  [_  Y  `p  rw  Y  xJ  LQ  Y  Rd  fk  Y  l}  D  Y  Ec  eg  Y  hz  |~  Y  T  V[  Y  \i  kp  Y  qD  FW  Y  Xi  kz  }~  k~  Y  M  OW  Y  Y;&,9	0
,ykRS*2iev  KZ  ]^  K^  ow  y  y<'5H	*2idp  GX  l{  ~  l  PX  Z  Z--5H	*2idv  M^  rA  DE  rE  V^  `  ` *?	0
,ykRS*2iev  KZ  ]^  K^  ow  y  y Y//*499\+B*CD	(
,ykJK"*iXd  {L  `o  rs  `s  DL  N  	N88,->,??STqSrs	 45,//(
,ykJK"*iXdX~i}h~  Uf  zI  LM  zM  ^f  h  	h)&L	(
,ykJK"*i]n  CR  UV  CV  go  q  	q!L	(
,ykJK"*i]n  CR  UV  CV  go  q  	qHHI!NMi/0	$XJl9+
FG	";-yYug
VWZ^fgofpp{  }F  GJ  HJ  }K  |L  LO  ]P  Q&)Ub  yJ  ^m  pq  ^q  BJ  L  LO\  	u/Ax891HDI,XJl9+YWX&.)ar  GV  YZ  GZ  ks  u  u	us   KW'V 9V:A%V W' =V W'$V W'V W'V ,W'-V F
W'V 	W$"7WW$W'W$$W'c                 D	  K   | j                  dg       }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}| j                  d
d      xs d}	| j                  dd      xs d}
| j                  dd      xs d}| j                  dd      }| j                  dd      }d}||k\  r;t        d| d       dg}|r|r|j                  d       t        |dz   d|dd      S g }|r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |	r|j                  d |	        |
r|j                  d!|
        |rd"j	                  |      nd#}|rd$j	                  |      nd%}t
        d&   j                  d'd()      }t
        d*   j                  ||||+      }d}	 t        j                  |d,|g -       d,{   }|r|j                         nd}|sd/| d0}|r#d1d2j	                  d3 |D              z   d4z   }||z   }g }d5|v r|j                  d6d7d8       d9|v r|j                  d:d;d8       d<|v r|j                  d=d>d8       t        ||d?|d@      }|j                  dAd      }|dB|dz   dC}|rt        dD   j                  ||E      }	 t        j                  |d,dFdGg H       d,{   }t        |      }t        |t               r~|j                  d      r|d   |d<   t        dI|d           |j                  d      r|d   |d<   t        dJ|d           |j                  d      r|d   |d<   t        dK|d           t        |dB      S 7 # t        $ r$}t        d.t        |              d}Y d,}~d,}~ww xY w7 # t        $ r!}t        dLt        |              Y d,}~gd,}~ww xY ww)MuH   
    询问用户节点：使用 interrupt 暂停等待用户输入
    rB   r/   ro   r0   r1   r3   r4   r5   r6   r7   r2   r-   rC   r   rM      u'   [ask_user] 已达到最大询问轮次 u   ，强制进入下一步r   r   ru   r  )rM   rU   rA   updategotor   r   r   r      发生时间: r   r   r   r   u   ；   暂无u   、u   相关信息ask_user_system   故障诊断r
  )r   biz_label_shortask_user_prompt)rC   existing_strmissing_strr-   Nr   r   r   r   u   [ask_user] API调用失败: u*   **【需要更多信息】**

请补充：uD   

提供这些信息后，我可以更准确地为您诊断故障。u!   
**📋 已获取的信息：**

r   c              3   &   K   | ]	  }d |   yw- Nrh   r  parts     rj   r  zask_user.<locals>.<genexpr>G  s      T4$2DbKN   z

---
u   舷号u   补充舷号u	   舷号：r   rk   r#  u   补充设备名称u   设备名称：r$  u   补充故障现象u   故障现象：
user_input)r;   r<   waiting_forrB   r   r   )r-   rU   rM   ask_user_extract)rE  
user_queryTu   你是信息提取专家。r   u   [ask_user] 提取到舷号: u"   [ask_user] 提取到设备名称: u"   [ask_user] 提取到故障现象: u   [ask_user] 信息提取失败: )r   r   r   r   r   r(   r   r   r   r(  r   rc   r   r'   r   r   r   )r   rB   r/   r0   r1   r3   r4   r5   r6   r7   r2   r-   rC   rM   MAX_ASK_ROUNDSrA   existing_partsrD  rE  r   r   r;   r   existing_info_sectionsuggested_repliesrN  rQ  update_dictextract_promptextract_response	extracteds                                  rj   r"  r"    se     99^R0L))M2.4"K))M2.4"KIIgr"(bE<,2J<,2Jii 126<"OYY/4:N		"5r:@bii 126<"OYY/4:N		"5q9		+q)INN"77GG_`a%5  !34!*Q|]jl
 	

 N67{m<=ug67J<89zl;<.?@A 1.1ABC/@.ABC.?@A1?5::n-XL.:%**\*K"#45<<~go<pM-.55+!%	 6 F H"AAUYhu  @B  C  C'/8>>#R
 A+  OU  V"F$)) T4$2T4 K4 !46A!B(83<  >k!RS%  +?L]!^_%  +?L]!^_EVfr  DP  R  SJ,J%/[dgh[hjK01CDKK#! L 

	>%.%M%MTbimz~  Nk  uw  &x   x)*:;I)T*==/1:=1IK.8=9Q8RST==/1:=1IK.>y?W>XYZ==)+4W+=K(>y?Q>RST  e C ,SVH56B  x  	>3CF8<==	>s   I?R Q P>Q 7B>R 6Q3 Q1BQ3 1R >Q 	Q.
Q)#R )Q..R 1Q3 3	R<RR RR c                   K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}| j                  d
d      xs d}	| j                  dd      }
g }|r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |r|j                  d|        |	r|j                  d|	        |rdj                  d |D              nd}d}|sd}d| d|
dd| d}t        g dd|
dd        d!d"d#d$d%d#g}t	        ||d&d'      }|j                  d(d      }t        |       d){   r4t        d*       d+g}|r|r|j                  d,       t        d-d.|d/d.0      S t        d1|        t        d2|d2d3d4d30      S 7 Xw)5uI   
    确认信息节点：重点询问用户是否需要补充信息
    r/   ro   r0   r1   r3   r4   r5   r6   r7   r2   rC   r   r   r   r   r   r>  r   r   r   r   r   c              3   &   K   | ]	  }d |   ywrH  rh   rJ  s     rj   r  zconfirm_info.<locals>.<genexpr>  s     D^Tr$[^rL  r?  uh   

💡 **提示**：如果您知道舷号，请补充，这将有助于我们更准确地生成报告。u#   **📋 已收集到的信息：**

u   

**信息完整性评分：** z.0%u   

---

**💡 请问是否需要补充其他信息？**
- 如故障码、故障时间、故障频率、已尝试措施、运行工况等
- 如果信息已足够，请点击"开始诊断")u   ✅ 信息确认u   📋 请确认信息u   🔍 准备检索u.   等待用户确认或补充信息 (完整性: )r  r	  rM     补充信息u   我需要补充：user_confirmr;   r<   rO  r   Nu<   [confirm_info] 用户确认信息足够，准备调用工具r   r   Tr  )rN   rU   rA   r;  u)   [confirm_info] 用户需要补充信息: Fr   )rN   r-   rT   rU   )r   r   r   r   r   r$   r   r   )r   r/   r0   r1   r3   r4   r5   r6   r7   r2   rC   rS  rD  additional_promptr;   rU  rN  rQ  rA   s                      rj   r  r  t  s#     ))M2.4"K))M2.4"KIIgr"(bE<,2J<,2Jii 126<"OYY/4:N		"5r:@bii 126<"O		"5q9N67{m<=ug67J<89zl;<.?@A 1.1ABC/@.ABC.?@AHV499D^DD\dL I /4 52 3D1D EH Y  ^L  M^  _b  Lc  cd  \e  f#1>^_jx  FZ  a[  \EVftvwJ,J#J///LN%5  !34+/^km
 	

 	9*FG+0:]b  tB  D
 	
 0s   HI9I7AI9c                 2  K   | j                  dg       }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d      }| j                  d      }i }d}	d}
d}d	|v r;|9ddlm} | d| d} |||dd       d
{   \  }}	}
}|	sd}	t        d|	        |r||k7  rt        d| d| d       |}d|v rI|G|rE|rC	 | d| d}t	        j
                  d|i       d
{   }t        d|rt        |      nd        |rn	 t        d|        t        |gd       d
{   }|j                  dd      r7|j                  di       }t        d t        |j                                       t        |xr t        |      dkD        }t        |xr t        |      d"kD        }|s>|s<t        d#       t        |t              r|ng t        |t              r|nd||
|	|ddd$d%d&
S ||||
|	|||dd'd&
S 7 w7 # t        $ r$}t        dt        |              d}Y d
}~!d
}~ww xY w7 # t        $ r!}t        d!t        |              Y d
}~d
}~ww xY ww)(u   调用检索工具rA   r/   ro   r0   r1   r2   r8   r9   r   Nr   ) search_with_ship_number_strategyu   发生u   该如何解决   )
base_queryr/   top_ksearch_typeu   通用知识库u   RAG 检索来源: u   [call_tools] 舷号映射: 'z' -> 'u   '，更新工作流状态r   r   u#   图谱检索完成，结果长度: u   图谱检索失败: u#   [图册检索] 使用设备名称: r   
node_namesre  successFdatau#   [图册检索] 图册检索结果: u#   [图册检索] 图册检索失败: r  uO   [call_tools] 未找到任何相关资料，需要用户确认使用模型能力Tmodel_confirm)
r8   r9   r]   rD   rE   r/   rK   rL   rO   rU   r%  )r   utils.ship_number_searchrb  r   r   ainvoker)  r   rc   r   listkeysrg   r   )r   rA   r/   r0   r1   r2   rag_resultsgraph_resultsr]   rE   rD   mapped_ship_numberrb  rd  graph_queryr   atlas_resultr.  r/  s                      rj   r  r    sp    IIor2M))M2.4"K))M2.4"KIIgr"(bEii 126<"O))/0KII34MMOM}$)<M#}F5'A
Pp  }G  T_  fg  t{  Q|  K|G_m5G/O"?"3450K?,[M@R?SSlmn(]*}/D5#!,VE7/J&6&>&>?U&V V;R_C<Nef;ghi 	B7}EF!0[MQS!TTL	51 , 0 0 <;DASASAU<V;WXY ;73{#3a#78G]?s='9C'?@I9_a4>{D4Q[WY  CM  N[  ]`  Caq~  gi  {H  Zg  {J  Ze  x}  RW  nr  CR  T  	T!,Mcp  CP  ds  CN  ah  }F  ]b  sF  H  HO K| !W #,SVH56 "# U  	B7Ax@AA	Bs   B8J:H1;A J<"H7 H4H7 >JI*  I'!AI* .BJ4H7 7	I$ IJI$$J'I* *	J3J
JJJc                   K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}d|xs d d|xs d d|xs d d	}t        g d
d       ddddddg}t        ||dd      }|j                  dd      }d|v sd|v sd|v rt        d       t	        d|ddd      S t        d|        t	        d|ddd      S w)us   
    模型能力确认节点：当没有找到任何资料时，让用户确认是否使用模型本身能力
    r/   ro   r0   r1   up   **⚠️ 未找到相关资料**

抱歉，在知识库中未找到与以下信息相关的资料：
- 舷号：r     
- 设备名称：   
- 故障现象：u   

**💡 您可以选择：**
- 使用 AI 模型的知识库为您生成一般性建议
- 提供更详细的信息重新检索

请问是否使用 AI 模型为您生成建议？)u   🤖 AI 模型确认u   ⚠️ 资料未找到u   💡 使用模型能力u$   使用模型自身知识进行回复u   使用 AI 模型u%   确认，使用 AI 模型生成建议rM  r]  u   我需要补充更多信息：rk  r_  r   u   确认AIu   模型u.   [model_confirm] 用户确认使用模型能力Tr%  )rP   r-   rU   r;  u*   [model_confirm] 用户选择补充信息: Fr   )r   r   r   r   r   )r   r/   r0   r1   r;   rU  rN  rQ  s           rj   rk  rk     sK     ))M2.4"K))M2.4"KIIgr"(bE &;' (,- .&;' (25H e  hN  O#5Bij  vD  Qq  lr  tEVfuwxJ,J:!3x:7M>@,0:^qs$
 	

 	::,GH,1J_ln
 	
s   CCc                 :  K   t        d       | j                  dd      xs d}| j                  dg       xs g }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}| j                  d
d      xs d}| j                  dd      xs d}	| j                  dd      xs d}
| j                  dd      xs d}| j                  d      xs g }| j                  d      xs d}| j                  dd      }| j                  dd      }t        d|       t        |dd      }|xr t        |      dkD  }|xr t        |      dkD  }|s|s|s7|s5|s3t        d   j                  d      }t        d   j                  |      }n^t        d   j                  d      }t        d   j                  |xs d |xs d |xs d |xs d |xs d |	xs d |
xs d |xs d |xs d!"	      }	 t        j                  |d#|g $       d#{   }|r|j                         nd%d&d'd(gd)d*S g }t        |t              r"|j                         r|j                         g}nt        |t              rt        |xs g d, d-.      d#d/ D ]  }t        |t              r8|j                  d0      xs dj                         }|s9|j!                  |       Kt        |t              s\|j                         sm|j!                  |j                                 t        |      d1k  rd}|r|d2z   d2j#                  |      z   nd2j#                  |      }t%        |      }t        d3|       d}d4}|rt        |      d1kD  r|}d5}n|rd6j#                  |      }d7}|r|d8k(  rzt        d9   j                  d      }t        d:   j                  |xs d |xs d |xs d ;      }	 t        j                  |d#|g $       d#{   }|r|j                         nd%g d)d*S |d5k(  rd<nd=}t'        d>| d?| gd@|d#d1  dA       d}|r	|dB| d2z  }|r	|dC| d2z  }|	r	|dD|	 d2z  }|
r	|dE|
 d2z  }|r	|dF| d2z  }|r	|dG| d2z  }| j                  dHd      }| j                  dId      } |xr |xs |xr | }!t)               }"|r6| r4t        dJ   j                  dKdL|xs d dM|xs d |xs d |xs d || ||"N      }nf|!r3t        dO   j                  dKdL|xs d |xs d |xs d |xs d ||||"P
      }n1t        dQ   j                  dKdL|xs d dM|xs d |xs d |xs d ||R	      }	 t        dS   j                  dK      }#t        j                  d#|#dT|dUgV       d#{   }$|$r|$j                         ndW}$t'        dXdYg|$d#dZ dAz          t+        |$|d[\       d#{   }%|%}%| j                  d]i       }&t-        |%|&      }%|!sd^}'|%|'z  }%d_d`d(g}(t/        |%|||a      })|!s	 t1        ||||%db       d#{    |%|)|(d-|! |%ddd)|de	S 7 .# t        $ r}d+t        |       g d)d*cY d#}~S d#}~ww xY w7 m# t        $ r}d+t        |       g d)d*cY d#}~S d#}~ww xY w7 7 7 k# t        $ r}*t        dc|*        Y d#}*~*d#}*~*ww xY w# t        $ r}dft        |       g g d)dgcY d#}~S d#}~ww xY ww)hu   生成最终回复uB   ========================生成最终回复========================r-   ro   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   rH   FrE   rp     i  r  r   r  !generate_response_friendly_systemrA  r   generate_response_friendly_userr   generate_response_no_rag_systemgenerate_response_no_rag_userr  r  r   NrF  u$   抱歉，未能找到相关资料。u   提供更详细信息u   我来提供更详细的信息rM  end)r;   r<   rU   u&   抱歉，处理过程中出现错误: c                 b    t        | t              rt        | j                  d      xs d      S dS )Nscorer   )r   r   re   r   )xs    rj   r|   z#generate_response.<locals>.<lambda>_  s,    ZdefgkZlE!%%.BUTU<V<srs<sri   T)keyreverser:  textr&  r   u   提取到的原始图片路径:nonegraph

ragNO_RELEVANT_RESULT&generate_response_no_rag_simple_system$generate_response_no_rag_simple_user)r/   r0   r1   u   图谱u   文本u!   ✨当前使用的检索类型为u   ✨本次检索策略为u	   内容为r'     - 故障码/报警代码：   - 故障发生时间：   - 故障频率/持续时间：   - 已尝试的维修措施：   - 设备运行工况：   - 其他相关信息：rY   rX   generate_response_regeneratingr   r$  '   分析故障原因，给出维修方案)r   
item_label	item_nameitem_actionr/   r0   r1   detail_inforX   
rag_answerimage_guidancegenerate_response_follow_up)
r   r  r  r/   r0   r1   r  r  r-   r  generate_response_normal)	r   r  r  r  r/   r0   r1   r  r   generate_response_content_systemuserrolerk   r   r   r   u   抱歉，无法生成回答。   🤖 诊断分析中   🤖 故障预检中   333333?temperaturer]   u   

---

**💡 请您确认维修方案是否正确：**
- 如果方案有误或需要调整，请告诉我具体的错误之处
- 我会根据您的反馈重新生成更准确的方案

请问方案是否有需要修改的地方？   方案有误u   方案有误，需要修改：r   r/   r0   r1   r/   r0   r1   rZ   u.   [generate_response] 记录故障信息失败: normal)	r;   r=   r<   rH   r  rZ   r[   rU   r^   u   分析生成失败: r;   r=   r<   rU   )r   r   r   r)  r(   r   r'   r   r   r(  r   rc   r   rn  sortedr   r   r   r   r   r   r"   r!   r   r)   )+r   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   rp  rq  rH   rE   r   r.  r/  r   r   r;   r   rag_ctx_partsitemr  all_source_textoriginal_image_pathsr  rag_typer  rY   rX   is_follow_upr  content_system_promptraw_contentanswerr]   supplement_promptrU  r=   rec_errs+                                              rj   r%  r%  *  s>	    	
NOYY/4:Nyy!3R8>B))M2.4"K))M2.4"KIIgr"(bEii 126<"O<,2J<,2Jii 126<"OYY/4:N		"5r:@b))/06BKII34:Myy!3U;ii 126O	-%#$42Z]^K2c+.2G:#m"4s":I9;u*+NOVVaoVpM#$EFMM]kMlF*+LMTT_mTnM,-LMTT'6;'6;*{%4%4 / >;-<"3"B{ / 85 U 
F	A&EEFY]ly  DF  G  GH4< 0Bh  I`  mM  N  ~P  af  h  h  "M+s#(9(9(;$**,-	K	&;,"2s  ~B  C  DF  EF  GD$%(.B557!((.D#&4::<$$TZZ\2 G =RIVmd*TYY}-EE\`\e\efs\tO.?	
+-ABJH]+b0"
	[[/
';;&'OPWWbpWq()OPWW#2{#2{&; X 
	A&EEFY]ly  DF  G  GH4< 0Bh}  QV  X  X $w.xHH<XJGKcdlcmInos|  ~H  IL  JL  ~M  }N  NQ  rR  SK4ZLCC0B??77HKK6~6FbII01B0C2FF00ADDii 159O#(99-KR#P #V)=IVCVL.0N7 @AHH%*{A#2{#2{&;#)E!) I 
 
 =>EE%*{#2{#2{&;#!)) F 
   :;BB%*{A#2{#2{&;#! C 

.y ./Q R Y Ydl Y m%DD4^s  HN  [a  b  ~c  e  e-8k'')>^35KLkZ][]N^afNfg4[BVdghh  		/26%fm<!1 ''F'5Bbce /fQ\it  |A  BR-kYdns  NT  /V  W  W  W #gJ[pt  NZ  JZ  tz  JR  ch  @N  P  	Pw G 	A"HQ Qfhy~  A  A	AT G 	A"HQ Qfhy~  A  A	AL e i: W RFwiPQQR
  y23q6(;r^`qvxxys0  H%\(Y5 Y2Y5 $B\8"\\,C'\Z  0Z1Z  E\8[2 	[
=[2 [
A[2 [  [![ %[2 1\2Y5 5	Z>ZZ\Z\Z   	[)[ :[;\ [\[2 
[2 [ 	[/[*%[2 *[//[2 2	\;\\\\\c                 R   K   | j                  dd      }t        d|        d|iS w)u   
    分析用户后续意图节点：直接使用 agent_think 已经判断好的意图
    agent_think 已经用大模型判断并设置了 follow_up_intent
    rW   r  u)   [意图分析] 使用已判断的意图: )r   r   r   s     rj   r   r     s4      YY)73F	5fX
>?((s   %'c                 r  K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}| j                  d
d      xs d}	| j                  dd      xs d}
| j                  dg       xs g }| j                  dd      xs d}i }g }t        g dd       |s|
r	 t        |dd      }d}|r	|d| dz  }|r	|d| dz  }|r	|d| dz  }|r	|d| dz  }|	r	|d|	 dz  }|r	|d| dz  }t        d   j	                  d      }t        d   j	                  d|xs d|xs d|xs d|xs d||xs d |xs d!|
"	      }t        j                  |d#d$|g %       d#{   }t        d&|       t        |      }|}t        d'|        t        |      D ]n  \  }}	 t        |       |}|r||vr| d)| }|r||vr| d)| }t        |d*+       d#{   }|j                  d,d-      rt        |      |d.| <   ng |d.| <   p i }	 t        ||||1       d#{   }|rlt        d2|        t        |d34       d#{   }|j                  d,d-      r7|j                  d5i       }t        d6t!        |j#                                       |||d8d9S 7 7# t        $ r"}t        d(t        |              Y d#}~4d#}~ww xY w7 # t        $ r-}t        d/| d0t        |              g |d.| <   Y d#}~dd#}~ww xY w7 7 # t        $ r!}t        d7t        |              Y d#}~d#}~ww xY ww):u[   
    深层次RAG检索节点：分析之前方案并选择深度分析点进行检索
    r/   ro   r0   r1   r3   r2   r4   r5   r6   r7   r-   r.   rZ   )u   🔍 深度检索中u   🔍 多维度检索u   🔍 精细分析u$   分析问题并选择深度分析点r  r  r  r  r   r  r  r  r  r  deep_rag_analysis_systemr   r|  deep_rag_analysis_userr$  r  r   u   （无之前的方案）)	r  r  r/   r0   r1   r  r   rZ   r-   NTr   u   深度分析点u    [深度RAG] 选择的分析点: u   [深度RAG] 分析失败:     )re  ri  Fanalysis_point_u   [深度RAG] 分析点 u    检索失败: )r.   r0   r1   rZ   u    [深度RAG] 图册检索实体: r   rg  rj  u    [深度RAG] 图册检索结果: u    [深度RAG] 图册检索失败: generate_deep_response)r:   r\   r]   rU   )r   r   r   r(   r   r   r   r   r   r   rc   	enumerater   r   r   r   rn  ro  )r   r/   r0   r1   r3   r2   r4   r5   r6   r7   r-   r.   rZ   deep_resultsr\   r   r  analysis_system_promptanalysis_promptanalysis_responseparsed_analysisr   idxpointsearch_query
rag_resultr]   entity_namesrt  s                                rj   deep_rag_searchr    s     ))M2.4"K))M2.4"KIIgr"(bE<,2Jii 126<"O<,2Jii 126<"OYY/4:N		"5r:@bYY/4:Nyy!3R8>B!II&=rBHbL]  `F  G %	9+,<1adeKK!<ZLKK!8BGG!??PPRSS!>~>NbQQ !89J8K2NN!88ILL%34N%O%V%Vai%V%j",-EFMM).;'6;'6;*{''B+B&;&Y?Y- N 
O '0&N&NUdko  }A  Pf  pr  's  !s#%67/0ABO#2 45I4JKL
   45
U	7%L L{%7"-a~>l2".q8),a@@J~~i/8J:8Vse458:se45 6( M;>P`mx  @E  \q  r  r4\NCD!0LPR!SSL	51 , 0 0 <8m>P>P>R9S8TUV !-EYkx  Jb  d  dW !s
  	9.s1vh788	9 A
  	7*5'QIJ46L?3%01	7 r T  ;0Q9::;s   DN7"CL #L$+L N7!7MM0M	N7N
  N!$N
 NAN
 N7L 	M&M=N7MN7M	N"M>8N7>NN7N
 N
 
	N4N/*N7/N44N7c                 *  K   | j                  dd      xs d}| j                  dg       xs g }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}| j                  d
d      xs d}	| j                  dd      xs d}
| j                  dd      xs d}| j                  di       }| j                  dg       }| j                  di       }| j                  dd      xs d}| j                  dg       }d}|rt        |      D ]q  \  }}d| }|j                  |g       }|s |d| dz  }t        |dd d      D ]7  \  }}t        |t              s|j                  dd      }|s,|d| d| dz  }9 s d}|rKd}t        |dd d      D ]7  \  }}t        |t              s|j                  dd      }|s,|d| d| dz  }9 t	        |      }||z   |z   |z   }t        |      }d}|r	|d| dz  }|r	|d| dz  }|r	|d | dz  }|	r	|d!|	 dz  }|
r	|d"|
 dz  }|r	|d#| dz  }d}|r(d$dj                  |D cg c]  }d%| 	 c}      z   dz   }t        d&   j                  d'd(|xs d)|xs d)|xs d)|xs d)|||||t        |      d*kD  r|nd+,      } 	 t        d-   j                  d'.      }!t        j                  d|!d/| d0g1       d{   }"|"r|"j                         nd2}"t        d3d4g|"dd5 d6z          t        |"|d78       d{   }#t        |#|      }#d9d:d;g}$t!        |#|||<      }%	 t#        ||||#d=       d{    |#|%|$d?|#d@dA|dBS c c}w 7 7 P7 # t$        $ r}&t'        d>|&        Y d}&~&2d}&~&ww xY w# t$        $ r}'dCt)        |'       g g dAdDcY d}'~'S d}'~'ww xY ww)EuU   
    生成深度响应节点：基于深度RAG结果进行深度润色和推理
    r-   ro   r.   r/   r0   r1   r3   r4   r5   r6   r7   r2   r:   r\   r]   r9   r8   r  u   
【分析点：u   】
Nr   ru   r  [z] r   u   
【原始检索资料】
r  r  r  r  r  r  r  u    
【本次深度分析重点】
rI  r  r   r$  r  r&  u   (无))r   r  r  r/   r0   r1   r  r-   analysis_points_promptanalysis_points_textoriginal_rag_textrq  %generate_deep_response_content_systemr|  r  r  r  u$   抱歉，无法生成深度分析。r  r  r  r'  g?r  r     方案还是有问题：rM  r  r  u3   [generate_deep_response] 记录故障信息失败: Tdeepr  r;   r=   r<   rH   rZ   r[   rU   r^   u   深度分析生成失败: r  )r   r  r   r   r   r   r   r(   r   r)  r   r   r(  r   r"   r!   r   r)   r   r   rc   )(r   r-   r.   r/   r0   r1   r3   r4   r5   r6   r7   r2   r:   r\   r]   rq  original_rag_resultsr  r  r  r  resultsir  r  r  
atlas_textr  r  r  r  pr   r  r  r  rU  r=   r  r   s(                                           rj   r  r  f  ss     YY/4:Nyy!3R8>B))M2.4"K))M2.4"KIIgr"(bE<,2J<,2Jii 126<"OYY/4:N		"5r:@bii 126<"Oyy!3R8 99%;R@IIor2MII3R8>BM 99%8"= #$89JC#C5)C&**33G$*;E7%(HH$(!a8GAt!$-#xx30as"TF"4EE0	  9 : : !5bq!91=GAt$%xx+%1QCr$r)::%	 > &m4J +->>Km[O.?K4ZLCC0B??77HKK6~6FbII01B0C2FF00ADD  #EfzS{fzabVXYZX[T\fzS{I|!|  @D  "D45<<!&;.;.;"{%51+'*='9B'>mG = F ./V W ^ ^iq ^ r%DD4^s  HN  [a  b  ~c  e  e-8k'')>d35KLkZ][]N^afNfg4[BVdghh%fm<'5B\]_.fQ\it  |A  B	S)+U`jo  JP  +R  S  S  S #gJ[pt  OU  ek  |A  Yg  i  	iQ T|* e i S 	SGyQRR	S
  8QARdfw|~~s   E?P.P1P;PPBPN;
*AP;8O* 3O 4=O* 1O2%O* O +O,O 0
O* :P O* O* O 	O'O"O* "O''O* *	P3PPPPPc                   K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}| j                  d
d      xs d}	| j                  dd      xs d}
| j                  dd      xs d}| j                  dd      }|st        d       dddddddddgdS d}|r	|d| dz  }|r	|d| dz  }|r	|d| dz  }|r	|d| dz  }|	r	|d|	 dz  }|r	|d| dz  }t        g dd|
dd   d!       t               }t        d"   j                  d#d$|xs d%d&|xs d%|xs d%|xs d%|||
|'      }	 t        d(   j                  d#)      }|j                  d*d+      }t        j                  d|d,|d-g.       d{   }|r|j                         nd/}t        |      }t        ||d0d12       d{   }d3d4d5g}t        ||||6      }	 t        ||||d7       d{    |||d||d9t        d:S 7 w7 C7 # t        $ r}t        d8|        Y d}~1d}~ww xY w# t        $ r.}t        d;t!        |              dddddddddgdcY d}~S d}~ww xY ww)<um   
    基于用户反馈直接修改方案节点：使用之前保存的方案和用户反馈进行修改
    r/   ro   r0   r1   r2   r3   r4   r5   r6   r7   rX   rZ   r[   r  uO   [regenerate_scheme_from_feedback] 没有保存的方案，回退到重新检索TNFr  r   r   )rY   r8   r9   rK   rL   rH   rU   rA   r  r   r  r  r  r  r  )u   ✏️ 修改方案中u   🔧 调整方案u   📝 优化方案u   根据反馈修改方案: r  r'  regenerate_scheme_from_feedbackr   r$  r  r  )r   r  r  r  r/   r0   r1   r  last_schemerQ   r  &regenerate_scheme_from_feedback_systemr|  u   【输出要求】u   【输出要求】
- 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性
- 可以适当使用简单的段落分隔，但不要使用复杂的格式r  r  r  u*   抱歉，无法根据反馈修改方案。r  u   维修方案)r  content_labelr  r  rM  r  r  u<   [regenerate_scheme_from_feedback] 记录故障信息失败: r  r  u6   [regenerate_scheme_from_feedback] 修改方案失败: )r   r   r   r   r(   r   replacer   r   r(  r   r"   r   r)   r   r-   rc   )r   r/   r0   r1   r2   r3   r4   r5   r6   r7   rQ   r  r[   r  r  r   r  content_promptr  r  r  rU  r=   r  r   s                            rj   r  r    sa     ))M2.4"K))M2.4"KIIgr"(bEii 126<"O<,2J<,2Jii 126<"OYY/4:N		"5r:@bII<bAGRM))3R8>BK))M84K_`#'TY]pu  KP  ej  {G  Zf  hz  Y{  }  	}K4ZLCC0B??77HKK6~6FbII01B0C2FF00ADD\`z  |I  JM  KM  |N  {O  OR  _S  T.0N=>EE!&;=.;.;"{#% F F} ./W X _ _jr _ s  (<  ?z  {%DD4^s  HN  [i  j  ~k  m  m-8k'')>j2;?4[BVdg  xF  G  G'5B\]_.fQ\it  |A  B	\)+U`jo  JP  +R  S  S  S #gJ[pt  OU  ep  AF  ^l  n  	n! m
 G S 	\PQXPYZ[[	\
  }Fs1vhOP#'TY]pu  KP  ej  {G  Zf  hz  Y{  }  	}}s   F5K8A
J$ I:5J$ 8I<9J$ J  &I>'J  +J$ 9K:J$ <J$ >J   	J!	JJ$ J!!J$ $	K-#KKKKKc                   K   | j                  dd      xs d}| j                  dg       xs g }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|rt        j                  |d      nd}d}|s|s|rYg }|r|j                  d	|        |r|j                  d
|        |r|j                  d|        ddj	                  |       d}| d| }	t        g dd|dd  d       	 t        |	|	|d       d{   }
|
j                  dd      }|
j                  dg       }||g dddS 7 0# t        $ r}dt        |       g g ddcY d}~S d}~ww xY ww)uP   
    后续问答节点：调用 baike 智能体处理用户的后续问题
    r-   ro   r.   r/   r0   r1   Fensure_asciir   r   r   u"   【当前故障诊断上下文】
z; r  u   用户后续问题: )u   💬 后续问答u   💬 执行指导u   💬 问题解答u   调用 百科 智能体: Nr  r'  baiker,   r-   history_message
route_flagr;   r<   Tr  )r;   r<   r=   rH   rU   u#   处理您的问题时出现错误: )r;   r<   r=   rU   )	r   jsondumpsr   r   r   r   r   rc   )r   r-   r.   r/   r0   r1   history_message_jsoncontext_prefixcontext_partsenhanced_querybaike_resultr;   rU  r   s                 rj   r   r   .  s     YY/4:Nyy!3R8>B))M2.4"K))M2.4"KIIgr"(bEO_4::&6UKegNkU  8K=!9:  >+!?@  >%!9:>tyy?W>XX\]&'';N;KLNW[t  vD  EH  FH  vI  uJ  JM  ZN  O	H/~]k  }Q  ]d  e  e##J3(,,-?D$9JVXmq  CH  J  	J e  HA#a&J_amo  AF  H  	HHsH   DE8
E E/E E8E 	E5E0*E5+E80E55E8c                   K   ddl m} | j                  dd      xs d}| j                  dg       }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|rt        j                  |d	
      nd}	  ||||d       d{   }|j                  dd      |j                  dg       |j                  dg       dddS 7 <# t
        $ r}	dt        |	       g g ddcY d}	~	S d}	~	ww xY ww)u   报告生成节点r   )run_other_report_workflowr-   ro   r.   r/   r0   r1   Fr  reportr  Nr;   r=   r<   Tr  )r;   r=   r<   rH   rU   u   报告生成失败: r  )workflows.workflow_other_reportr  r   r  r  r   rc   )
r   r  r-   r  r/   r0   r1   r  report_resultr   s
             rj   r  r  T  sI    IYY/4:Nii 2B7O))M2.4"K))M2.4"KIIgr"(bEN]4::oEJcey7~es  EY  em  n  n)--j"=IZIZ[dfhIi  L  P  P  Qc  eg  h  }A  RW  Y  	Y n  y23q6(;r^`qvxxysH   BDC C;C DC 	D&C>8D9D>DDc                 r  K   | j                  dd      xs d}| j                  dd      xs d}| j     >Z             dd      xs d}| j                  dd      xs d}d| d|xs d d	|xs d d
|xs d d|dd  t        |      dkD  rdnd d}ddddddddg}g }t        g dd|dd  d       t        |||dd      }|j                  dd      xs d}	|	dk(  rt	        d       t        |ddd      S |	dk(  rt	        d       t        |dd d!d       S t	        d"|	        t        ||	d#d$d#      S w)%um   
    处理用户反馈节点：接收用户对方案的反馈，提供上报和重新生成方案按钮
    r-   ro   r/   r0   r1   u^   **📝 已收到您的反馈**

感谢您对维修方案的建议！您的反馈已记录：

u1   

---

**📋 反馈信息摘要：**
- 舷号：r  rv  rw     
- 反馈内容：Nr  r'  u   

---

**💡 您可以选择：**
- 点击「重新生成方案」根据您的反馈重新生成方案
- 点击「上报」将反馈提交给相关部门
- 继续对话获取更多帮助rk   u   重新生成方案)r   r   r  u   上报)u   📝 反馈处理u   📋 方案反馈u   ✅ 反馈确认u   处理用户反馈: r  feedback_confirm)r;   r=   r<   rO  r   u0   [handle_feedback] 用户选择重新生成方案r  )rX   rU   r;  u*   [handle_feedback] 用户选择上报反馈Tconfirm_report)rQ   rR   rU   u&   [handle_feedback] 用户继续对话: r   )rQ   r-   rU   )r   r)  r   r   r   r   )
r   r-   r/   r0   r1   r;   r=   rU  rN  	user_texts
             rj   r  r  g  s     YY/4:N))M2.4"K))M2.4"KIIgr"(bE   
 &;' (,- .&;' ( #&'^1Ds1JPR'S T!$H, $8AUVHX>G
 VZno}  B  @B  pC  oD  DG  YH  IGXi  zL  N  OJw+1rI((@B4BStv2
 	
 
h	:<%3dcsu!
 	

 	6ykBC%3i`mo
 	
s   D5D7c                 T  K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}d|xs d d|xs d d	|xs d d
|dd  t        |      dkD  rdnd d
}dddg}t        g dd       |g |ddddS w)u@   
    上报确认节点：用户点击上报后确认完成
    r/   ro   r0   r1   rQ   u_   **✅ 上报成功**

您的反馈已成功上报！

---

**📋 上报信息：**
- 舷号：r  rv  rw  r  Nr  r'  uC   

---

**💡 感谢您的反馈，相关部门将及时处理。**u   生成维修报告u   请帮我生成维修报告rM  )u   ✅ 上报成功u   📋 反馈已提交u   🎉 完成u   反馈上报成功TFr  )r;   r=   r<   rS   rR   rU   )r   r)  r   )r   r/   r0   r1   rQ   r;   rU  s          rj   r  r    s     ))M2.4"K))M2.4"KIIgr"(bEIIor28bM &;' (,- .&;' (%&M0BS0Hub&Q R=@H  $8DabdSUij BCTim  IN  _d  f  fs   B&B(c                 *    | j                  dd      }|S )u   Agent 思考后的路由r?   r"  r   )r   r7  s     rj   _route_after_thinkr    s    yy):6HOri   c                 X    | j                  dd      }|dk(  ry|dk(  ry|dk(  ry|d	k(  ry
y)u   意图分析后的路由rW   r  r  r  r!  r   r  r  r  r   r   r   s     rj   _route_after_intentr    sC    YY)73F 	%	%	;	 	=	 ri   c                 .    | j                  dd      }|ryy)u   检索工具调用后的路由rO   Frk  r%  r   )r   rO   s     rj   _route_after_toolsr    s    #7?ri   c                    t        t              }|j                  dt               |j                  dt               |j                  dt
               |j                  dt               |j                  dt               |j                  dt               |j                  dt               |j                  dt               |j                  d	t               |j                  d
t               |j                  dt               |j                  dt               |j                  dt               |j                  dt                |j                  dt"               |j                  dt$               |j'                  t(        d       |j+                  dt,        ddd       |j'                  dd       |j+                  dt.        ddddddd
dddd
       |j+                  dt0        d	dd       |j+                  dt2        ddddd       |j'                  dd       |j'                  dt4               |j'                  dt4               |j'                  dt4               |j'                  d
t4               |j'                  dt4               |j'                  dt4               |j'                  dt4               |j7                  |       S )uW   
    创建故障诊断工作流（基于 Checkpointer 的状态持久化版本）
    r   r   r   r"  r  r  r%  r   rk  r  r  r  r   r  r  r  )r   r   )
r"  r  r  r%  	follow_upr   r  r  r   r   )rk  r%  )r  r   r  r   checkpointer)r   r+   add_noder   r   r   r"  r  r  r%  r   rk  r  r  r  r   r  r  r  add_edger	   add_conditional_edgesr   r  r  r  r
   compile)r  workflows     rj   create_fault_diagnosis_workflowr    s    -.H'9nl3m[1j(+nl3lJ/)+<=nl3o}5'9'9&702JK'9.0FG79XYe./""#46K#NDFnm4""=2DNk~  M[  lz  N_  sD  Uc  @Z  \]""<1CWf  }P  FR  S""#=?Rhy  KY  m~  O]  U_  `')AB.4)3/nc*'-7='-&,66ri   r,   r-   r  r  previous_state_jsonchat_id
message_iduser_responsec	                 	  K   |r|nd}	|	rdd|	iini }
t        d|	 d|du        |ddlm} |j                          d{   }t	        |      }|	r>	 |j                  |
       d{   }t        d	|du d
|r|j                  dund d|rt        |j                        nd        |rG|j                  r:|j                  }t        d|j                  d       d|j                  d       d|j                  d              |j                  r9t        d       |r|nd|i}|j                  t        |      |
       d{   }nD|}t        |       d{   }|j                  d      xr$ |j                  d      xr |j                  d      }|xr |xr |j                  dd       }i ||t        |      ddd}|rt        d       d|d<   |j                  ||
       d{   }ni d| d|dt        |      ddddddddddd dd!dd"dd#dd$dd%dd&dd'g d(g i d)dd*dd+dd,g d-g d.d/d0dd1dd2dd3d4d5dd6dd7i d8dd9dd:dd;dddddddddddddd<}|j                  ||
       d{   }ni d| d|dt        |      ddddddddddd dd!dd"dd#dd$dd%dd&dd'g d(g i d)dd*dd+dd,g d-g d.d/d0dd1dd2dd3d4d5dd6dd7i d8dd9dd:dd;dddddddddddddd<}	 |j                  ||
       d{   }|i }|j                  dBg       }|ri|r|d   j$                  ni }t        dC|        |j                  d&dD      |j                  d(g       d@|j                  d'g       |j                  dEd      dFS |j                  d)      rd?|d)    g d@g dAS |j                  dGd      }|sd@}|j                  d&d      |j                  d(g       ||j                  d'g       |dHS 7 7 7 7 7 97 # t        $ r/}t        d=|        ddl}|j!                          i }Y d}~2d}~ww xY w7 ?# t        $ rH}t        d>t#        |              ddl}|j!                          d?t#        |       g d@g dAcY d}~S d}~ww xY ww)Iu  
    执行故障诊断工作流

    Args:
        extracted_text: 文本描述
        combined_query: 组合查询
        history_message: 历史消息（JSON格式）
        route_flag: 路由标识
        previous_state_json: 兼容参数（已废弃）
        chat_id: 聊天会话 ID
        message_id: 消息 ID
        checkpointer: LangGraph checkpointer 实例
        user_response: 用户恢复执行的响应数据

    Returns:
        工作流执行结果
    Nconfigurable	thread_idz0[DEBUG] run_fault_diagnosis_workflow: thread_id=z, checkpointer=r   )checkpointer_managerr  z[DEBUG] current_state exists: z, has values: Fz	, tasks: u2   [Checkpointer] 发现已保存状态: ship_number=r/   z, device_name=r0   z, fault=r1   u0   [Checkpointer] 恢复执行，注入用户响应r   )resumerN   ro   )r-   r.   rT   rV   uL   [Checkpointer] 检测到确认意图，自动设置 user_confirmed_info=TrueTr,   r-   r.   r2   r3   r4   r5   r6   r7   r8   r9   r;   r<   r=   r>   r?   r@   rA   rB   rC   g        rD   rE   rF   rG   rc  rH   rI   rJ   rK   rL   is_execution_feedbackexecution_detail)rM   rN   rO   rP   r  rQ   rR   rS   rT   rU   rV   r^   u#   [Checkpointer] 状态恢复失败: u   [工作流执行失败] u#   故障诊断工作流执行失败: fault_diagnosis)r;   r=   
result_tagr<   __interrupt__u2   [Interrupt] 工作流中断，等待用户输入: u   请提供更多信息rO  )r;   r=   r  r<   rO  r  )r;   r=   r  r<   r  )r   checkpointer_configr  get_async_checkpointerr  
aget_stater   r)  tasksr   rm  r   r$   r   r   r   r   rc   value)r,   r-   r  r  r  r  r  r  r  r  configr  appcurrent_statesaved_stateresume_valueresultmerged_query_is_confirm_has_full_info_override_confirmedinitial_stater   r   
interruptsinterrupt_datas                             rj   run_fault_diagnosis_workflowr,    s
    $ #I;Dn{I67"F	<YKWckoWoVp
qr<1HHJJ
)|
DC(	"%.."88M0d1J0K>  LZgZnZnvzZz  RW  ZX  Xa  ~K  be  fs  fy  fy  bz  QR  aS  TU !5!5+22HYfIgHhhv  xC  xG  xG  HU  xV  wW  W_  `k  `o  `o  pw  `x  _y  z{ !&&LN4A=Q_G`L#&;;wl/KV#TTF $2L )?~(N"NK&1oom&D  'EYfIg  'Elwl{l{  }D  mEN*5*~.*~Q\Q`Q`avx}Q~M~' %n{  %n\fs  uD  gE  UZ  jl  %nM* ln?C&;<#&;;}f#EEF!p!1> !pBRTb !pcu  xE  FU  xV !p  Wd  fh !p  iv  xz !p  {B  DF !p  GX  Z\ !p "!p%12!p6G!pL\^`!patvx!p zM  OS!p Ti  ko!p pz  |~!p&!p+4b!p9H"!pM]_a!pbsuw!p yH  JL!p M[  ]_!p `s  ux!p $R!p ):2!p ?PQR!p Tdef!p hz  |A!p BZ  \a!p br  tv!p %e	!p -?	!p G^_d	!p fxy{	!p JK  ch  D,1e]_z  UZ  jo  @B  RT  ln!p  #{{=&AAf)> f:JN f[mo|  ~M  pN f  O\  ^` f  an  pr f  sz  |~ f  P  RT f  Ua  ce f  fr  tv frf"2Bf7JBfObdhfi~  AEf FP  RTf Ug  ikf lu  wyf zI  KMf N^  `bf ct  vxf yH  JLfBf2Cf8GfL]_afbsuvf xH  JKf L^  `ef f~  @Ef FV  XZf [k  mrf sE  GLf $Uf ,>rf PQhm  EJ  ch  }B  TV  qv  KP  `e  vx  HJ  bdf
	V;;}f==F ~OR0J0:A,,B>BRST*..z;RS_m_q_qr{}  `A  Pa  vD  vH  vH  I[  ]_  v`  p~  pB  pB  CP  RT  pU  W  	Wzz/"A&BYAZ[gi  yJ  _a  c  	cL"-J&


:r2fjjTV>Wfp  FL  FP  FP  Qc  eg  Fh  wA  C  CY K 9 U #O F B 	7s;<!F		 > 	V,SVH56!"Ec!fX NZ\k|  RT  V  V		Vs   ?SPSP/ *P +CP/ P#P/ P&BP/ 0P)1BP/ P,P/ BSQ- +Q*,Q- 0C.S P/ #P/ &P/ )P/ ,P/ /	Q'8$Q"S"Q''S*Q- -	R>6=R93R>4S9R>>S)ro   ro   ro   )	ro   ro   ro   ro   ro   ro   ro   ro   ro   r  )ro   ro   ro   ro   ro   NN)Zrb   typingr   r   r   r   r   langgraph.graphr   r	   r
   langgraph.typesr   r   tools.function_toolr   tools.rag_toolsr   tools.graph_toolsr   r   r   modelsAPI.model_apir   utils.function_trackerr   utils.image_utilsr   r   r   workflows.workflow_baiker   workflows.workflow_utilsr   r   r   r   r   r   r   r   r    r!   r"   utils.word_generatorr#   utils.intent_matcherr$   r  r%   r&   promptsr'   r(   tools.fault_record_dbr)   r  r   r   r   r   r+   rc   r   r   r   re   r   r   r   r   r   r"  r  r  rk  r%  r   r  r  r  r   r  r  r  r  r  r  r  r,  rh   ri   rj   <module>r<     s{   8 7 2 2 . 0 & f f ) 4 g g 7    6 7 0 ; 9  	  	 B) BH' ' 'TF F3 FZ] Fkn Fx|  ~B  CF  HK  CK  ~L  yM FP &*$]aqu  KO  cg  ~B  W[  \ Cc CS CVY Clo C  CF C  ^a C  x{ C  UX C  ps C  }B C$c!4 $cc3h $cL!4  OD1 ODd38n ODbcL0 cLT#s(^ cLJt- t' tlL
1 L
g L
\<H/ <HDcN <H|(
2 (
w (
TJy#6 Jy4S> JyX
)*= 
)$sCx. 
)bd!4 bdc3h bdHq(; qS#X qfS}1D S}cSVh S}j$H1 $Hd38n $HLy!4 yc3h y&<
!4 <
 <
|f 3 fS#X f>1 c 2 s  1 c (7TfCs fC3 fC`c fCux fC  TW fC  fi fC  {~ fC  ei  jm  or  jr  es fC  C  DG  IL  DL  M fCri   DxBo
    @iI                    @   s  d Z ddlmZmZmZmZmZ ddlmZm	Z	m
Z
 ddlmZ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ZddlZddlmZ dd	lmZmZ G d
d deZdedee fddZdedeeeef  fddZdedede fddZ!ed Z"dddddZ#deeeef  deeeef  fddZ$d edeeef fd!d"Z%	#	#	#	#dOd ed$ed%ed&ede f
d'd(Z&d)edeeef fd*d+Z'd)edeeef fd,d-Z(d)edeeef fd.d/Z)d)edeeef fd0d1Z*d)edeeef fd2d3Z+d)edeeef fd4d5Z,d6ed7edeeeef  fd8d9Z-d)edeeef fd:d;Z.d)edefd<d=Z/d)edefd>d?Z0d)edeeef fd@dAZ1dBdC Z2	#	#	#dPdDedEededFedGedeeef fdHdIZ3e4dJkrddlZdKdLgZ5dMdN Z6e7e6  dS dS )Quo  
操作工作流（ReAct 风格 - 智能交互版 v2）

核心改进：
1. 更严格的信息收集：设置信息完整性阈值，引导用户提供详细信息。
2. 方案生成后可补充信息：用户可以继续补充信息优化方案
3. 历史检索结果复用：相似查询复用已有检索结果，避免重复调用

工作流：
START → agent_think → [决策路由]
                          ↓
        ┌─────────────────┼─────────────────┐
        ↓                 ↓                 ↓
   ask_user          call_tools       generate_response
        ↓                 ↓                 ↓
       END          process_results        ↓
                          ↓            check_supplement
                   generate_response        ↓
                          ↓            [用户补充?] → agent_think
                         END                  ↓
                                           generate_response
                                              ↓
                                             END
    )	TypedDictOptionalDictAnyList)
StateGraphSTARTEND)rag_search_tooloperation_graph_rag_search)	OpenaiAPI)get_all_callbacksNSequenceMatcher)
RAG_CONFIGKB_TREE_CONFIGc                   @   s  e Zd ZU dZeed< eed< eeeef  ed< eed< eed< eed< eed< e	eeeef   ed	< e	e ed
< eed< eeeef  ed< eeeef  ed< eed< eed< eed< ee ed< ee ed< e
ed< eed< eed< eed< eed< eed< eed< eed< eed< eeef ed< eed< eed< eed< eed < eeef ed!< eed"< eeeef  ed#< eeef ed$< eed%< eed&< eed'< eed(< eed)< eed*< eed+< eed,< eed-< d.S )/OperateGuideStateu   操作工作流状态extracted_textcombined_queryhistory_messagesship_numberdevice_nameoperation_itemadditional_inforag_search_resultgraph_search_resultresponsesuggestedRepliesactionserror_messageagent_decisionagent_reasoningtools_to_callmissing_infoinfo_completenesskb_match_typematched_kb_idmatched_kb_namesource_noticeiteration_countmax_iterationsscheme_generatedwaiting_for_supplementextracted_infohas_rag_resulthas_graph_resultis_execution_feedbackexecution_detailprevious_extracted_infowaiting_similar_confirmsimilar_kb_listconfirmed_similar_kbsimilar_confirm_responsehas_similar_confirm_msguser_confirmed_similaruser_rejected_similarsimilar_kb_name_in_historysimilar_kb_id_in_historysimilar_ship_number_in_historyuse_confirmed_similarneed_similar_confirmN)__name__
__module____qualname____doc__str__annotations__r   r   r   r   floatintbool rH   rH   "/app/workflows/workflow_operate.pyr   1   s\   
 r   textreturnc                 C   s   | sdS |   }tjdd|tjd}tdd|}td|}|r4z	t|dW S  ty3   Y nw td|}|rOz	t|dW S  tyN   Y nw zt|W S  ty_   Y dS w )	u    从文本中提取并解析 JSONNz
```json\s* flagsz```\s*z\[[\s\S]*\]r   z\{[\s\S]*\})	stripresub
IGNORECASEsearchjsonloadsgroup	Exception)rJ   cleanedmrH   rH   rI   _safe_json_extractj   s0   rZ   history_messagec                 C   sV   | sg S zt | trt| n| }t |tr|dd W S g W S  ty*   g  Y S w )u   解析历史消息为列表N)
isinstancerC   rT   rU   listrW   )r[   datarH   rH   rI   _parse_history   s   r`   abc                 C   s$   | r|sdS t d|  |  S )u   计算字符串相似度        N)r   lowerratio)ra   rb   rH   rH   rI   _similarity   s   rf   urlzapplication/json1testuseradmin)acceptz	x-user-idzx-user-namezx-roleitemsc                 C   sJ   g }| D ]}t |tr"|| |dpg D ]
}|t|g qq|S )u   将树形知识库列表展平children)r]   dictappendgetextend_flatten_kb_list)rl   outitemchildrH   rH   rI   rr      s   

rr   r   c                    st  | r	t |  sdddg dS dtdt | }|s$dddg dS i }g }tdt  d}d}d}td	|d	 D ]}ztd
| d| d tj	|dd4 I dH }|j
ttdI dH }	td|	j  |	jdkrtd ||k rt|I dH  	 W d  I dH  W q<dddg dW  d  I dH  W   S |	 }
tdt|
  t|
trd|
v r|

ddkr||k rt|I dH  	 W d  I dH  W q<dddg dW  d  I dH  W   S |

dp|

dpg }n5t|
tr|
}n-||k rt|I dH  	 W d  I dH  W q<dddg dW  d  I dH  W   S |s[||k rGt|I dH  	 W d  I dH  W q<dddg dW  d  I dH  W   S t|}|D ]^}|
dpjd}|
d}|du s|t | s~qadtd|}td| d| d|  ||kr|rt | |d}td| d|  qa|t | ||d  qa|r|d! |d" d#g dW  d  I dH  W   S |rtd$t|  ddd%|dW  d  I dH  W   S dddg dW  d  I dH  W   S 1 I dH sw   Y  W q< tjy^ } z4td&| d'|  ||k rKtd(| d) t|I dH  W Y d}~q<dddg dW  Y d}~  S d}~w tjy } z4td&| d*|  ||k rtd(| d) t|I dH  W Y d}~q<dddg dW  Y d}~  S d}~w tjy } z4td&| d+|  ||k rtd(| d) t|I dH  W Y d}~q<dddg dW  Y d}~  S d}~w ty2 } zFtd&| d,t|j  td-|  ||k rtd(| d) t|I dH  W Y d}~q<d.dl}|  dddg dW  Y d}~  S d}~ww dddg dS )/u   精确匹配知识库rL   none)kb_idkb_name
match_typesimilar_list\dz[DEBUG] KB_TREE_URL:    g      @g       @   u   [DEBUG] 第u   次请求, timeout=u   秒...F)timeoutverifyN)headersz[DEBUG] Response status:    u'   [DEBUG] Status not 200, 准备重试...z[DEBUG] JSON parsed, type: coder_   r^   nameidzinput_numbers:z, kb_numbers:z
, kb_name:)rw   rx   zexact_match: kb_name=z, id=)rw   rx   
kb_numbersrw   rx   exactzsimilar_list count: similaru   [ERROR] 第u   次 ConnectError: u   [DEBUG] 等待u   秒后重试...u   次 TimeoutException: u   次 HTTPError: u   次 Exception type: z[ERROR] Exception message: r   )rC   rO   joinrP   findallprintKB_TREE_URLrangehttpxAsyncClientrp   KB_TREE_HEADERSstatus_codeasynciosleeprT   typer]   rn   r^   rr   ro   lenConnectErrorTimeoutException	HTTPErrorrW   r?   	traceback	print_exc)r   input_numbersexact_matchrz   max_retriestimeout_secondsretry_intervalattemptclientr   resultkb_list	flat_listkbrx   kidr   er   rH   rH   rI   get_kb_id_exact   s   
	



!#

7;8=



r   rL   r   r   r   c           
      C   sd   d}ddddd}| |||d}|  D ]\}}||dpd}	|	r,t|	 r,||7 }qt|dS )u!   计算信息完整性评分 (0-1)rc   g      ?g333333?r   r   r   r   rL   r|   )rl   rp   rC   rO   round)
r   r   r   r   scoreweightsvaluesfieldweightvaluerH   rH   rI   _calculate_info_completeness+  s"   
r   statec           '         s  |  ddpd}|  dg pg }|  di }|r;t|tr;| dd}| dd}| dd}|r;|d	||d
|S d}|r|dd }g }	|D ]/}
t|
trx|
 dd}|
 dp\d }|dkrl|	d|  qI|dkrx|	d|  qI|	rd|	nd}d}g d}|dd D ]'}t|tr| ddkr| ddpd}|D ]
}||v rd	} nq|r nqd}d}g d}g d}|dd D ])}t|tr| ddpd}|D ]
}||v rd	} nq|D ]
}||v rd	} nqqd}d}d}d}d}|dd D ]V}t|trW| ddkrW| ddpd}d|v rWd	}d	}td|}|r2|d}td|}|rU|d}dt	d|}|rU|}t
d|   nqd}d |p`d! d"| d#}ztj|dd	|g d$I dH } t| }!t|!tsi }!|! d%dp|  d%d|! d&dp|  d&d|! d'dp|  d'd|! d(dp|  d(d|! d)d|! d*d|||d+	}"|! d,d}#|! d-d}$|#rd}t
d.|"d%  d/|"d&  d0|"d'   t
d1| d2| d3|  t
d4|"d)   t
d5| d6|# d7|$  d8|"i|"||#|$||||d9}%|#r2|r2|r2|||d:|%d;< t
d<|%d;   |%W S  ty` }& zt
d=t|&  |||d>||||dd||d?	W  Y d}&~&S d}&~&ww )@uB  
    信息提取节点：从历史对话和当前输入中提取所有相关信息

    提取内容：
    1. 操作相关信息（船体号、设备名称、操作项目等）
    2. 历史是否已生成方案
    3. 历史是否有RAG/图谱检索结果
    4. 检测【相似资料确认】和用户确认消息
    r   rL   r   r2   r+   Fr.   r/   T)r-   r+   r.   r/   iNrolecontentuser   用户: 	assistant   助手: 
)   本方案依据u   操作方案u   操作原因分析i)u   依据文本知识库u   文本检索u	   RAG检索)u   依据图谱知识库u   图谱检索u   知识图谱r\   u   【相似资料确认】u'   已为您在「([^」]+)」中检索到r}   z\[KB_ID:([^\]]+)\]r{   u%   [相似确认] 从KB_ID提取舷号: uB  你是一个信息提取专家，负责从历史对话和当前用户输入中提取操作相关信息。

你需要提取以下信息：
1. 舷号：船舰编号，舷号一般为连续的阿拉伯数字如"101","111","122","163"，"16","17","554","602","545","985","31","3261","799","905","781"等,或者数字后加舰，比如"101舰,"199舰,"18舰等。
2. 设备名称：设备的名称
3. 操作项目：操作的具体项目
4. 其他信息：其他补充说明

特别注意 - 相似资料确认检测：
- 检查历史对话中是否有助手发送的【相似资料确认】消息
- 如果有，判断用户最新的回复是否表示"确认使用"或"拒绝使用"
- 确认的关键词包括：确认、是的、对、可以、行、好的、没问题、同意、使用、是的确认等
- 拒绝的关键词包括：不是、不对、取消、不要、不行、换一个、重新、其他等

提取规则：
- 如果历史对话中已有该信息，优先使用历史信息
- 如果当前输入中有新信息，更新或补充历史信息
- 如果某项信息没有提及，返回空字符串
- 注意识别用户的执行反馈（如"执行了前两步"），这不是新的操作信息

输出格式（JSON）：
{
    "ship_number": "舷号",
    "device_name": "设备名称",
    "operation_item": "操作项目",
    "additional_info": "其他信息",
    "is_execution_feedback": false,
    "execution_detail": "如果用户在反馈执行情况，描述具体内容",
    "has_similar_confirm_msg": false,
    "user_confirmed_similar": false,
    "user_rejected_similar": false
}uu   请从以下对话中提取操作相关信息，并判断用户是否确认使用相似资料。

【历史对话】
u   （无历史对话）u   

【当前用户输入】
u$   

请提取信息（JSON格式）：querymodeljson_outputsystem_promptmessagesr   r   r   r   r0   r1   )	r   r   r   r   r0   r1   r+   r.   r/   r8   r9   u   [信息提取] 舷号=	   , 设备=   , 操作项目=u   [状态检测] 方案已生成=u	   , 有RAG=u   , 有图谱=u%   [执行反馈] is_execution_feedback=u   [相似确认] 有确认消息=u   , 用户确认=u   , 用户拒绝=r-   )r7   r8   r9   r:   r;   r<   r3   )rw   rx   r   r5   u2   [相似确认] 从历史恢复确认的知识库: u   信息提取失败: )r+   r.   r/   )	r-   r+   r.   r/   r7   r8   r9   r<   r3   )rp   r]   rn   rO   ro   r   rP   rS   rV   r   r   r   open_api_chat_without_thinkingrZ   rW   rC   )'r   r   r   previous_stateprev_schemeprev_has_ragprev_has_graphhistory_strrecentpartsrY   r   r   r+   scheme_keywordsmsgkeywordr.   r/   rag_indicatorsgraph_indicators	indicatorr7   r:   r;   r<   r3   kb_matchkb_id_matchr   r   promptresponse_textparsedr-   r8   r9   r   r   rH   rH   rI   extract_infoI  s6  





!


&
r   c           &         s@  |  ddpd}|  ddpd}|  ddpd}|  ddp d}|  ddp(d}|  dd}|  d	d}|  d
d}|  dd}	|  dd}
|  d}|  d}|  dd}|  dd}|  dd}|  dd}|  di ppi }|  dg pxg }t|o| }t|o| }t|o| }|durt|dkp|}|durt|dkp|}t||||d}d}g d}|  t fdd|D rd}d}td| d |  ||g g ||d! d"S |rIt| d#krIzAd$}d%| d&}tj	|dd'|g d(I dH }|r+| d)r+d}d*| d+d, }td| d |  ||g g ||d! d"W S W n t
yH }  ztd-t|   W Y d} ~ nd} ~ ww |rsd.}d/|	 }|
r^|d0|
 d17 }td| d |  ||g g ||d! d"S |	r|s||rd.}d2}td| d |  ||g g ||d! d"S |r|rd3}d4| d5d }d6g}!|r|r|r|!d7 td| d |  td8|  |||!g ||||||d! d'|d9S |rd3}d:}d6g}!|r|r|r|!d7 td| d |  |||!g ||||||d! dd;S |r-|s-|s-d<}d=}td| d |  ||g g ||d! d"S |r6|r6|sod>}g }"|sB|"d? |sJ|"d@ |sR|"dA dBdC|" }td| d |  ||g |"||d! d"S ||k rd>}dD| dE| }dFg}"td| d |  ||g |"||d! d"S |s|rdG}dH}td| d |  ||g g ||d! d"S d3}dI}d6g}!|r|r|r|!d7 td| d |  tdJ| dK| dL|  g dM}#dNt|#dO| dP|ddQ  dRdS}$t D ]}%z|%|$ W q t
y   Y qw |||!g ||||||d! dT
S )Uun  
    Agent 思考节点：基于提取的信息决定下一步动作

    决策类型：
    - ask_user: 需要用户提供更多信息（信息完整性不足）
    - call_tools: 调用检索工具
    - generate_response: 直接生成回复
    - follow_up: 后续问答（已生成方案后的交互）
    - similar_confirm: 等待用户确认相似资料
    r   rL   r   r   r   r   r+   Fr.   r/   r0   r1   r   r   r)   r   r3   r8   r9   r5   r4   Nd   r   gffffff?)u   生成报告   生成操作报告u   导出报告u	   写报告u   操作报告u   分析报告c                 3   s    | ]}| v V  qd S NrH   ).0r   combined_query_lowerrH   rI   	<genexpr>Q  s    zagent_think.<locals>.<genexpr>generate_reportu   用户请求生成报告u   [Agent 决策] decision=z, reasoning=r}   )r    r!   r"   r#   r$   r)   r|   u9  你是一个意图判断专家。需要判断用户的输入是否在请求生成某种报告。
            
判断标准：
- 用户要求生成操作报告、分析报告、总结报告等
- 用户要求导出、写入、整理成文档
- 用户要求总结本次对话或操作处理过程
- 用户说"帮我写个报告"、"生成个报告吧"等

如果用户只是在问问题、描述操作、请求操作方案，不要判定为生成报告。

请直接输出JSON格式的判断结果：
{
    "is_report_request": true或false,
    "reason": "判断理由"
}uP   请判断以下用户输入是否在请求生成操作报告：

用户输入：u   

判断：Tr   is_report_requestu   模型判断：reasonu   用户请求生成操作报告u'   [操作报告判断模型调用失败] 	follow_upuA   已生成操作方案，用户进行后续交互。执行反馈: z ()u3   用户反馈执行情况，基于操作结果回复
call_toolsu#   用户确认使用相似知识库: rx   
rag_searchgraph_rag_searchu2   [相似确认] 用户已确认，使用知识库: )r    r!   r"   r#   r$   r   r   r   r   r)   r=   r5   u0   用户拒绝相似知识库，使用通用检索)r    r!   r"   r#   r$   r   r   r   r   r)   r=   similar_confirmu-   等待用户确认是否使用相似知识库ask_user   舷号   设备名称   操作项目u   缺少基本信息: , u   信息完整性评分 u    低于最低要求 u   更多详细信息generate_responseu6   信息充足，已有检索结果，直接生成回复u$   信息充足，需要检索知识库u   [Agent 提取] 舷号=r   r   )u   🤖 Agent 思考中u   🤖 智能分析u   🤖 决策判断function_executionu   决策: u    | 理由: 2   ...r   titledetails)
r    r!   r"   r#   r$   r   r   r   r   r)   )rp   rG   rO   r   r   rd   anyr   r   r   rW   rC   ro   r   randomchoicer   )&r   r   r   r   r   r   r+   r.   r/   r0   r1   r   r   r)   r3   r8   r9   r5   r4   has_ship
has_devicehas_operationhas_rag	has_graphr$   MIN_COMPLETENESS_FOR_GENERATEreport_keywordsdecision	reasoningr   r   r   r   r"   r#   title_optionsstart_eventcallbackrH   r   rI   agent_think  s  

	
		

	



			

r  c              
      s,  |  dg }|  ddpd}|  ddpd}|  ddpd}|  ddp&d}|  ddp.d}|  dd	}d}d}	d
|v rhd|v rhtd|tj}
|
r[|
d }tdd| }td|}|rh|d}	g }|rt|d|  |r~|d|  |r|d|  |r|d|  |rd|nd}|rd|nd}d}d| d| d| d| d	}zt	j
|d|g dI dH }|r| nd}|r|	rd |	 d!| d"}|| }|rd#d"d$d% |D  d& }|| }g d'}d(t|d)| d*| d+d,}t D ]}z|| W q ty   Y qw g }d-|v r*|d.d/d0 d1|v r7|d2d3d0 d4|v rD|d5d6d0 ||d7d8W S  ty } z>g }|rf|	rf|d9|	 d!|  |rx|d:d"d;d% |D   |d<| d= d>|}|g d?W  Y d}~S d}~ww )@u   询问用户提供更多信息r#   r   rL   r   r   r   r   r$   r   u   图片描述：z</image>u   图片描述：(.*?)</image>r}   u*   !\[用户上传图片\]\(https?://[^\)]+\)u,   !\[用户上传图片\]\((https?://[^\)]+)\)u   舷号: u   设备名称: u   操作项目: u   其他信息: u   ；u   暂无u   、u   相关信息u   你是一个专业的操作助手，需要友好地引导用户提供缺失信息。

要求：
1. 语气友好、专业，不要生硬
2. 说明为什么需要这些信息（更准确的操作指导）
3. 鼓励用户提供更多细节up   请生成一段友好的回复，引导用户补充缺失信息。

【已获取的信息】（完整性评分: u   ）
u   

【缺失的信息】
u   

【用户当前输入】
u   

请生成回复：Nr   r   r   r   u8   

**📷 您上传的图片：**

![用户上传图片](u   )

**图片识别结果：**
r   u!   
**📋 已获取的信息：**

c                 s       | ]}d | V  qdS - NrH   r   partrH   rH   rI   r         zask_user.<locals>.<genexpr>z

---
)u   📝 需要更多信息u   📝 信息补充u   📝 请提供详情r   u   需要用户补充: u    (当前完整性: r   r   r   u   补充舷号u	   舷号：r   r   r   u   补充设备名称u   设备名称：r   u   补充操作项目u   操作项目：T)r   r   need_user_inputu6   **📷 您上传的图片：**

![用户上传图片](u    **📋 已获取的信息：**

c                 s   r  r  rH   r  rH   rH   rI   r     r  u*   **【需要更多信息】**

请补充：uJ   

提供这些信息后，我可以更准确地为您提供操作指导。

---

r   r   )rp   rP   rS   DOTALLrV   rO   rQ   ro   r   r   r   r   r   r   rW   )r   r#   r   r   r   r   r   r$   image_description	image_url
desc_match	img_matchexisting_partsexisting_strmissing_strr   r   r   image_sectionexisting_info_sectionr   r   r   suggested_repliesr   	msg_partsr   rH   rH   rI   r   4  s   
	




r   c           *         s,  |  dg }|  ddpd}|  ddpd}|  ddpd}|  ddp&d}|  ddp.d}|  d}|  d	}d
}	d}
d}d}|  dd}|  di pNi }|r|rd}	| dd}| dd}td| d|  |rtd| d t|I dH }| dd}| dd}
td| d|
  |s|}|}
td|
  nd}d}
|s|
rdtd|
}|r|}td|  d|v r|du rd| d| d}zt|dd I dH }td!|rt|nd" d# W n t	y
 } ztd$t
|  g }W Y d}~nd}~ww d%|
 d&}|}d'|v rd|du rd|rd|rd|rdzt|||d(I dH }td)| d*|r?t|nd"  W n t	yc } ztd+t
|  d}W Y d}~nd}~ww g d,}d-t|d.|
 d| d/}t D ]}z|| W qz t	y   Y qzw t|tr|ng t|t
r|nd|	||
|ddd0S d|v ro|du rot|I dH }| dd}| dd}| d1d2}	| d3g }td4| d5|	  d| d| d}|	d
krN|rNzAt|d|d6I dH }|}
|}td7|rt|nd" d# |rt|d"krtd8 ntd9 t|dd I dH }d:}	W n t	yM } ztd$t
|  g }W Y d}~nd}~ww |	d
ksV|sot|dd I dH }d}d}d}d;}t|tr|r|D ]L} t| tr|  d<d;}!|!|kr|!}|  dd}"|  dd}#|  d=d}$|"r|" r|" }|#r|# r|# }|$r|$ r|$ }qt|r|nd>}
|}d:}	td?|
 d@| dA|  |rc|rct|d"krcdtd|}%dtd|
}|%rc|rc|%|krctdB g }&|dd D ]#} t| tr1|  d=d}'|'r1|' r1|'|&vr1|&|'  q|&r@dCdDdE |&D ndF}(dG| dH|
 dI|( dJ|
 dK	})|dd:||
ddL|r]|ng dL|)dM
S |rodN| dO|
 dP}|}|	d:kr|
rdtd|
}|r|}tdQ| dR|
 dS d'|v r|du r|r|r|rzt|||d(I dH }tdT|rt|nd"  W n t	y } ztd+t
|  d}W Y d}~nd}~ww g d,}d-t|dUdV| d/}t D ]}z|| W q t	y
   Y qw |||	||
|ddd0S )Wu   调用检索工具r"   r   rL   r   r   r   r   r   r   r   r=   Fr5   similar_confirmedrx   u/   [相似确认] 用户确认的知识库名称: u
   , 舷号: u/   [相似确认] 使用确认的知识库名称 'u   ' 进行精确匹配...Nrw   u)   [相似确认] 精确匹配结果: kb_id=z
, kb_name=u9   [相似确认] 未找到精确ID，使用名称作为ID: r{   u5   [相似确认] 从相似知识库名称提取舷号: r   u   设备u   ，操作项目u   的操作方案   )r   top_ku;   RAG 检索完成（用户确认相似知识库），返回 r   u
    条结果u   RAG 检索失败: u+   ℹ️ 以下方案来源于您确认的「u   」知识库。r   )r   r   r   u(   图谱检索完成（使用相似舷号 u   ），结果长度: u   图谱检索失败: )u   🔍 正在检索知识库u   🔍 查找相关资料u   🔍 智能检索r   u    使用确认的相似知识库: r   )r   r   r%   r&   r'   r(   r3   r>   ry   rv   rz   u   [知识库匹配] 舷号=u   , 匹配类型=)r   r  rw   u,   RAG 检索完成（精确匹配），返回 u-   精确匹配知识库有结果，直接使用u3   精确匹配知识库无结果，尝试通用检索r   rc   r   filenameu   通用知识库u   最相关资料: u
   , 文件: u
   , 评分: uB   [相似匹配] 检索到其他舷号的资料，需要用户确认r   c                 S   s   g | ]}d | qS )r  rH   )r   fnrH   rH   rI   
<listcomp>T  s    zcall_tools.<locals>.<listcomp>u   多个相关文档u,   【相似资料确认】

未找到舷号「u-   」的专属知识库资料，已为您在「u#   」中检索到最相关资料：

u;   

请问是否使用该资料进行操作指导？

[KB_ID:]T)
r   r   r%   r&   r'   r(   r3   r4   r>   r6   u   ⚠️ 未找到舷号「u0   」的专属知识库，以下方案来源于「u*   」，请结合实际情况参考使用。u,   [图谱检索] 使用相似知识库舷号: u
    (来源: r   u#   图谱检索完成，结果长度: u   调用工具: r   )rp   r   r   r   rP   r   r
   ainvoker   rW   rC   r   r   r   r   r]   r^   rn   rO   ro   )*r   r"   r   r   r   r   r   rag_resultsgraph_resultsr%   r'   r&   r(   r=   r5   confirmed_kb_namesimilar_ship_number	kb_resultr   	rag_queryr   graph_ship_numberr   r   r   rw   rx   rz   best_kb_name
best_kb_idbest_filename
best_scorert   r   found_kb_namefound_kb_idfound_filenamer   filenames_listr  filenames_strconfirm_responserH   rH   rI   r     s  

 &


 
r   c                    s  |  ddpd}|  dg pg }|  ddpd}|  ddp d}|  ddp(d}|  dp/g }|  dp6d}d}|r|d	d
 }	g }
|	D ]3}t|trx| dd}| dpXd }|dkrh|
d|  qE|dkrx|
d|d
d   qE|
rd|
nd}g }|d
d D ]}t|tr| dpd }|r|| qd}|rt|dkr|d
d }n|rd|d
d d
d }d}d|pd d|pd d|pd d|pd d | d!| d"}zXtj|d
|g d#I d
H }|r| nd$}d%d&d'd(d)d'd*d+d'g}g d,}d-t	
|d.|d
d/  d0d1}t D ]}z|| W q ty0   Y qw ||g d2d3d4W S  tyW } zd5t| g g d6W  Y d
}~S d
}~ww )7u<   后续问答节点：处理已生成方案后的用户提问r   rL   r   r   r   r   r   r   Nr   r   r   r   r   r     r   r  rJ   r   i  

   u	  你是一名资深工业设备操作工程师，正在协助用户执行操作方案。
用户在执行过程中遇到了问题或需要进一步指导，请根据历史对话和参考资料给出专业、实用的回复。

回复要求：
1. 理解用户当前的问题或反馈
2. 结合之前的操作方案和参考资料给出针对性建议
3. 如果用户反馈执行情况，给予确认和下一步指导
4. 如果用户遇到新问题，基于参考资料解答
5. 回复简洁实用，直接解决用户问题u   【设备信息】
- 舷号：	   未提供   
- 设备名称：   
- 操作项目：u   

【参考资料】
   无u   

【历史对话】
u   

【用户当前问题】
u   

请给出回复：r  u$   抱歉，无法处理您的问题。u   继续下一步   请指导下一步操作r	  u   遇到问题u   执行中遇到问题：r      请帮我生成操作报告)u   💬 后续问答u   💬 执行指导u   💬 问题解答r   u   处理后续问题:    r   r   TF)r   r   r   r+   r,   u#   处理您的问题时出现错误: )r   r   r   )rp   r]   rn   rO   ro   r   r   r   r   r   r   r   rW   rC   )r   r   r   r   r   r   r!  r"  r   r   r   rY   r   r   rag_ctx_partsrt   rJ   reference_materialr   r   r   r  r   r   r   r   rH   rH   rI   follow_up_qa  s   



	
r?  c           7         s	  |  ddpd}|  dg pg }|  ddpd}|  ddp d}|  ddp(d}|  ddp0d}|  dp7g }|  d	p>d}|  d
d}	|  dd}
|  dd}|  dd}d}|r|dd }g }|D ]3}t|tr| dd}| dpxd }|dkr|d|  qe|dkr|d|dd   qe|rd|nd}|	dkrt| I dH S |ot|dk}|ot|dk}|s8|s8d}|rd| d}|s|s|sd}| d| d}nd }| d!|pd" d#|pd" d$|pd" d%|pd& d'
}z!tj	|d|g d(I dH }|r| nd)d*d+d,d-d.d,gd/W S  t
y7 } zd0t| g d/W  Y d}~S d}~ww g }g }g }t|dd1 D ]I\}}t|tr| d2pWd }| d3pad } | d4d5}!|r|d6|d7  d8|  ||d7 || |!d9 | r||  qF|rd|nd:}"t|d;krd}d<|pd" d=|pd" d>|pd& d?|" d@|r|ndA dB}#ztj	ddCdDd|#dEgdFI dH }$t|$trN|$ dGg }%|$ dHd}&|$ dId}'|%r:t|%dJkr:tdK|% dL|&  g }(|%ddJ D ]}|D ]}|dM |kr|(|  nqq|(r9dNdOdP |(D }'tdQdRdP |(D   n!|'dSkr@n|rK|d dTdndS}'n|rY|d dTdndS}'dU})W nD t
y } z7tdVt|  |r|d dTd}'t|d7kr|'dN|d7 dWd 7 }'n|r|ndS}'dU})W Y d}~nd}~ww d2tdXtt fdYdZ}*|'dSkr0d}|rd| d}|s|s|sd}| d| d}nd }| d!|pd" d#|pd" d$|pd" d%|pd& d'
}z!tj	|d|g d(I dH }|r| nd)d*d+d,d-d.d,gd/W S  t
y/ } zd0t| g d/W  Y d}~S d}~ww |*|'}+td[|+ |)d\krAd]})ndU})td^|' d_|) d`|) g},dat|,db|'dd;  dcdd}-t D ]}.z|.|- W qf t
yz   Y qfw d}/|rde| d}/d}|rd| d}|
o|p|}0|0rdf|pd" dg|pd" d=|pd" d|/ dh|' d| di| dj}ndk|pd" dg|pd" d=|pd" d|/ dh|' d| dl}ztj	ddmd|dEgdnI dH }1tjdod|1tjdp}1|1r|1 ndq}1d2tdXtfdrds}2|2|1}1dttdutt dXtfdvdw dd2tdutt dXtf fdydz}3|3|1|+d{}1td||1 |r>| d}|1 }1d~|) d}4|4 dN|1 }1|0sTd}5|1|57 }1t|1|I dH }6|0sm|6ddd,ddd,g n|6ddd,ddd,ddd,g g d},dat|,ddd}-t D ]}.z|.|- W q t
y   Y qw |1g |6dCdCdW S  t
y } zdt| g ddd,ddd,gdW  Y d}~S d}~ww )u   生成最终回复r   rL   r   r   r   r   r   r   r   r    r+   Fr(   r'   r2  Nr   r   r   r   r   r   r3  r   r   r   r   uA   
【历史对话】（请结合历史理解用户当前需求）
u   你是一个友好的操作助手。用户可能只是在打招呼或询问一般性问题。
请友好地回复，并简要介绍你能提供的帮助。如果历史对话中有相关信息，请结合历史回复。u   
用户说：u   

请友好回复：u>  你是一个专业的操作助手。
虽然没有检索到相关资料，但可以根据用户提供的信息给出一般性建议。
注意：明确告知用户这是基于一般经验的建议，建议提供更详细信息或查阅官方文档。
如果历史对话中有相关信息，请结合历史进行回复。u   
用户描述：
- 舷号: r6  u   
- 设备名称: u   
- 操作项目: u   
- 其他信息: r9  u&   

请给出一般性的操作建议：r  u$   抱歉，未能找到相关资料。u   提供更详细信息u   我来提供更详细的信息r	  u   换个方式描述u   换个方式描述问题r  u&   抱歉，处理过程中出现错误: 
   rJ   r  r   rc   [r}   z] )indexrJ   r  r   u   (无RAG结果)r   u   # 任务
你是一个信息相关性评估专家。请从以下RAG检索结果中，选取**最相关的两条**信息，用于生成操作方案。

# 用户操作需求
- 设备名称：r8  u   
- 其他信息：u   

# RAG检索结果列表
u)   

# 图谱检索结果（可选参考）
u   (无图谱结果)u  

# 选取规则
1. 必须从RAG结果中选取**两条**最相关的信息
2. 优先选择与"设备名称"和"操作项目"直接相关的内容
3. 如果有图谱结果，可以结合图谱信息判断相关性
4. 如果所有RAG结果都完全不相关，输出 "NO_RELEVANT_RESULT"
5. 选取的两条信息应该互补，避免内容重复

# 输出格式（JSON）
{
    "selected_indices": [序号1, 序号2],
    "reason": "简要说明选取理由",
    "combined_content": "两条信息的合并内容，用换行分隔"
}Tuo   你是一个严格的信息筛选专家。你的任务是从RAG检索结果中选取最相关的两条信息。)r   r   )r   r   r   r   selected_indicesr   combined_contentr|   u   [RAG筛选] 选取序号: u
   , 理由: rB  r4  c                 S      g | ]}|d  qS )rJ   rH   r   rt   rH   rH   rI   r        z%generate_response.<locals>.<listcomp>u   [RAG筛选] 选取的文件: c                 S   rE  )r  rH   rF  rH   rH   rI   r    rG  NO_RELEVANT_RESULTz[1] u   文本u   [RAG筛选] 筛选失败: z[2] rK   c                 S   s    d}t || t j}tt|S )Nz7images/[a-zA-Z0-9_\-./]+\.(?:jpg|jpeg|png|gif|bmp|webp))rP   r   rR   r^   set)rJ   patternmatchesrH   rH   rI   extract_image_paths  s   z.generate_response.<locals>.extract_image_pathsu   提取到的原始图片路径:graphu   图谱u   选择的rag信息u!   ✨当前使用的检索类型为u   ✨本次检索策略为r   u	   内容为r   r   u   - 其他相关信息：u   你是一名资深工业设备操作工程师。用户正在与你进行后续交互，请根据历史对话和当前问题给出回复。

【设备信息】
- 舷号：r7  u   
【参考资料】
u   
【用户当前问题】
u  

【输出要求】
1. 理解用户的当前意图（可能是确认执行情况、补充信息、提出新问题等）
2. 根据历史对话和参考资料，给出针对性的回复
3. 如果用户在反馈执行情况，请给予确认和下一步建议
4. 如果用户有新问题，请基于参考资料回答

【重要格式规则】
- 图片：如果参考资料中有 images/xxx.jpg，转为 ![图片](/api/v1/knowledge/files/images/xxx.jpg)，每个图片只用一次
- 表格：如果有HTML表格，转为Markdown表格格式
- 公式：如果有LaTeX公式，转为 $$ 公式 $$ 格式（前后加空格）
- 如果没有图片/表格/公式，不要生成

请直接输出回复，不要解释推理过程。u   你是一名资深工业设备操作工程师，请根据以下信息生成操作分析与方案。

【设备信息】
- 舷号：u  
【输出要求】
1. 先用一句话判断操作情况（包含舷号、设备、操作项目，不超过40字）
2. 然后给出操作方案，步骤清晰、可直接执行
3. 如果参考资料信息不足，明确指出缺少什么

【重要格式规则】
- 图片：如果参考资料中有 images/xxx.jpg，转为 ![图片](/api/v1/knowledge/files/images/xxx.jpg)，每个图片只用一次
- 表格：如果有HTML表格，转为Markdown表格格式
- 公式：如果有LaTeX公式，转为 $$ 公式 $$ 格式（前后加空格）
- 如果没有图片/表格/公式，不要生成

请直接输出方案，不要解释推理过程。uo   你是一名资深工业设备操作工程师，严格依据检索信息生成操作方案，不虚构内容。)r   r   r   u   熟虑.*?舒展rM   u   抱歉，无法生成回答。c                 S   sX   d}|  d|} tdd| } tdd| } |  |d} tdd| } td	d
| } | S )Nz DOUBLE_DOLLAR z$$z	(?<!\s)\$z $z\$(?!\s)z$ z(?<!\s)\$\$z $$z
\$\$(?!\s)z$$ )replacerP   rQ   )rJ   placeholderrH   rH   rI   normalize_latex_spacingR  s   z2generate_response.<locals>.normalize_latex_spacinggenerated_pathoriginal_pathsc           	      S   s~   ddl m} |s
| S | dd  }d }d}|D ]}|dd  }|d || }||kr4|}|}q|r=|dkr=|S | S )Nr   r   /g      ?)difflibr   splitrd   re   )	rQ  rR  r   generated_filename
best_matchr+  	orig_pathorig_filenamer   rH   rH   rI   find_closest_image_path^  s    z2generate_response.<locals>.find_closest_image_path/api/v1/knowledge/files/c                    s  |d u rg }g }d}t | }||k r| ||d  dkr|d }||k r8| | dkr8|d7 }||k r8| | dks*||k r|d |k r| |d  dkr|d }||k rf| | dkrf|d7 }||k rf| | dksX||k r| |d | }|ds ||}	|d	d	 |	d	 }nd
|v r|d
d }
 d
|
 |}	|d	d	 |	 }|d| d |d }q|| |  |d7 }||k sd|S )Nr   r|   z![r  r}   (r   )zhttp://zhttps://rS  rS  zimages/rT  u
   ![图片](rL   )r   
startswithrstriplstriprV  ro   r   )rJ   base_prefixrR  r   injkrg   matched_path	extractedr[  rH   rI   normalize_markdown_imagesr  s@   $


z4generate_response.<locals>.normalize_markdown_images)rR  z
llm outputr  r   u   知识库生成。u7   

---

**💡 如需生成操作报告，请告知。**u   补充其他信息u   其他补充信息：r   r;  u   继续执行下一步r:  u   遇到新问题u   执行过程中遇到问题：)u   🔧 生成操作方案u   🔧 智能增强方案u   🔧 分析操作情况u'   正在生成操作原因分析与方案)r   r   r   r+   r,   u   分析生成失败:    如何执行这个操作？$   需要准备哪些工具和材料？)r   r   r   )r\  N)rp   r]   rn   rO   ro   r   r   r   r   r   rW   rC   	enumerater   rN  r   r   r   r   rP   rQ   r  generate_suggested_replies_qarq   )7r   r   r   r   r   r   r   r!  r"  r    r+   r(   r'   r   r   r   rY   r   r   r   r   history_sectionr   r   r   r   r=  file_name_listrag_items_with_metaidxrt   rJ   	file_namer   rag_list_strrag_selection_promptselection_resultrC  selection_reason
rag_answerselected_itemsrag_typerL  original_image_pathsr   r   r   detail_infois_follow_upanswerrP  ri  scheme_sourcesupplement_promptr  rH   rh  rI   r     sR  

	
	





	



	
	

  

r   r}  questionc           
   
      s   d| d| dd  d}zet j|ddI dH }td|tj}|ri|d}t|}t|t	rit
|d	krig }|dd	 D ]}t|tr_d
|v r_d|v r_|t|d
 t|d d q@t
|d	kri|W S ddddddgW S  ty }	 zddddddgW  Y d}	~	S d}	~	ww )u   生成建议回复问题u   
你是一个专业的工业设备问答助手。根据以下问答内容，生成两个用户可能关心的后续问题。

【用户问题】
u   

【回答内容】
Nr3  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与当前问答内容相关，能够帮助用户进一步了解相关信息
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
)r   z\[.*\]r   r|   r   r   r	  rj  rk  )r   r   rP   rS   r  rV   rT   rU   r]   r^   r   rn   ro   rC   rW   )
r}  r  r   r   
json_matchjson_strr  formatted_repliesreplyr   rH   rH   rI   rm    s@   




rm  c              
      s  ddl m} ddlm} | ddpd}| dg }| ddp"d}| ddp*d}| d	dp2d}|r<tj|d
dnd}z%||||ddI dH }	td|	 |	dd|	dg |	dg dddW S  ty }
 zdt	|
 g g ddW  Y d}
~
S d}
~
ww )u0   报告生成节点：调用报告生成工作流r   )run_qa_report_agent)run_other_report_workflowr   rL   r   r   r   r   F)ensure_asciireport)r   r   r[   
route_flagNreport_resultr   r   r   T)r   r   r   r  r+   u   报告生成失败: )r   r   r   r+   )
workflows.workflow_qa_reportr  workflows.workflow_other_reportr  rp   rT   dumpsr   rW   rC   )r   r  r  r   r[   r   r   r   history_message_jsonr  r   rH   rH   rI   r     s>   




r   c                 C   sp   |  dd}|  dd}|  dd}||krdS |dkrd	S |dkr$dS |d
kr*d
S |dkr0dS |dkr6dS dS )u   Agent 思考后的路由r    r   r)   r   r*   r  r   r   r?  r   r   r   rp   )r   r   r)   r*   rH   rH   rI   _route_after_think1  s    r  c                 C   s   |  dd}|r
dS dS )u   检索工具调用后的路由r>   Fr   r   r  )r   r>   rH   rH   rI   _route_after_toolsH  s   r  c              	      s   |  dd}|  dg pg }|  dd}|sd}dddd	d
dg}g d}dt|d| d}t D ]}z|| W q6 tyG   Y q6w td ||d|ddS )u?   相似资料确认节点：生成确认回复等待用户确认r6   rL   r4   r'   ub   【相似资料确认】

未找到专属知识库，请确认是否使用相似知识库资料。u   确认使用u   确认使用该知识库r	  u   取消u   取消，使用通用检索)u   ❓ 需要确认u   ❓ 相似资料确认u   ❓ 请确认r   u#   等待用户确认相似知识库: r   u6   [相似确认] 返回确认消息，等待用户确认T)r   r   r3   r4   r
  )rp   r   r   r   rW   r   )r   r6   r4   r'   r  r   r   r   rH   rH   rI   r   P  s6   
r   c                  C   s   t t} | dt | dt | dt | dt | dt | dt | dt	 | dt
 | td | dd | dtddddddd	 | dt | dtdddd
 | dt | dt | dt | dt |  S )u   创建操作工作流r   r  r   r   r   r?  r   r   )r   r   r   r?  r   r   )r   r   r   )r   r   add_noder   r  r   r   r   r?  r   r   add_edger   add_conditional_edgesr  r	   r  compile)workflowrH   rH   rI   create_operation_workflowu  s<   r  r   r   r  previous_state_jsonc           
         s  t d t }i  |r*zt|trt|n| t d W n ty)   i  Y nw d@dtdtdtf fdd}i d	| d
|dt|d|ddd|ddd|ddd|ddd|ddd|dddddg dg ddddddd|dg d|dg i d|ddd|ddd|ddd|ddd dd!|d!d"d#d$d%|d%d&d'|d'd&d(|d(i d)|d)d&d*|d*d&d+|d+d&d,|d,dd-|d(i d.|d.d&d/|d/g |d0i |d1d|d2d&|d3d&|d4d&|d5d|d6d|d7d|d8d&|d9d&d:
}z;|	|I dH }|
dr0d;|d  g d<g d=W S |
d>d}|s;d<}|
dd|
dg ||
dg |d?W S  tyn }	 zd;t|	 g d<g d=W  Y d}	~	S d}	~	ww )Au&  
    执行操作工作流

    Args:
        extracted_text: 文本描述
        combined_query: 组合查询
        history_message: 历史消息（JSON格式）
        route_flag: 路由标识
        previous_state_json: 之前的工作流状态（JSON格式），用于恢复状态
    u9   执行操作工作流------------------------------------u-   [状态恢复] 从 previous_state_json 恢复rL   keydefaultrK   c                    s     | |S r   r  )r  r  r   rH   rI   	_get_prev  s   z-run_operate_guide_workflow.<locals>._get_prevr   r   r   r   r   r   r   r   Nr   r   r   r   r   r    r!   r"   r#   r$   rc   r%   r&   r'   r(   r)   r   r*   r  r+   Fr,   r-   r.   r/   r0   r1   r2   r3   r4   r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   )
r5   r6   r7   r8   r9   r:   r;   r<   r=   r>   u   操作工作流执行失败: 	operation)r   r   
result_tagr   r  )r   r   r  r   r  )rL   )r   r  r]   rC   rT   rU   rW   r   r`   r   rp   )
r   r   r[   r  r  appr  initial_statefinal_stater   rH   r  rI   run_operate_guide_workflow  s   





	















 
!
"#/


r  __main__u'   主机需要进行例行维护操作。u-   发电机运行正常，各项指标正常。c                     s   t tdD ];\} }tdd  td|   td  t||dI d H }td td|dd	  td
 t|dd qd S )Nr}   r   z<============================================================u   测试用例 )r   r   u   
执行结果:u   成功: successFu   
响应内容:r   u	   无响应)rl  
test_casesr   run_operation_workflowrp   )rb  	test_textr   rH   rH   rI   test  s   
r  )rL   rL   rL   rL   )rL   rL   rL   )8rB   typingr   r   r   r   r   langgraph.graphr   r   r	   tools.function_toolr
   r   modelsAPI.model_apir   utils.function_trackerr   r   rT   rP   r   r   rU  r   configr   r   r   rC   rZ   r`   rE   rf   r   r   rr   r   r   r   r  r   r   r?  r   rm  r   r  r  r   r  r  r?   r  r  runrH   rH   rH   rI   <module>   s    #9*x
 W  y pk   "K5-%(


nhF
@xUS
    Ljr!X' ddlmZ ddlm Z  ddl)m,Z, ddl-m.Z.m/Z/ ddl0Z0ddl1Z1ddl2Z2 G d de      Z3dddddddddd	Z4dBde5de5de5de5de5de5de5d e5d!e5d"e6fd#Z7d$e3d"ee5ef   fd%Z8d$e3d"e5fd&Z9d$e3d"ee5ef   fd'Z:d$e3d"ee5ef   fd(Z;d$e3d"efd)Z<d$e3d"efd*Z=d$e3d"ee5ef   fd+Z>d$e3d"efd,Z?d$e3d"ee5ef   fd-Z@d$e3d"ee5ef   fd.ZAd$e3d"ee5ef   fd/ZBd$e3d"efd0ZCd$e3d"ee5ef   fd1ZDd$e3d"ee5ef   fd2ZEd$e3d"ee5ef   fd3ZFd$e3d"ee5ef   fd4ZGd$e3d"e5fd5ZHd$e3d"e5fd6ZId$e3d"e5fd7ZJdCd8ZKdDd9e5d:e5d;e5d<e5d=e5d>e5d?e5d@ee5ef   d"ee5ef   fdAZLy)Eu+   
操作指导*extract_image_pathfis_confirmation_intent"OPERATE_PROMPTSCOMMON_PROMPTS)#OperateGuideStateu   操作指导

\Koperation_itemadditional_infooperation_codeoperation_timeoperation
G3"/app/workflows/workflow_operate.pyr&   r&      sH4\	d   r&   #9*   r+   r,O2   r-   r*   r+   r,O2   r-   return.$X/g   )r   OPERATE_INFO_WEIGHTS)
r*   r+   r,O2   r-$e$"cl   `   sJ    (Xf  {I  ]k  DW  ky  Pa  vE  FF&';VDDrd   state@%(    rE   r*   r+   r,k( 操作(#操作extract_info)rQ   rP(4()iQ   rC   rPz)<!操作处理)getprintr#   r$)G2	Exceptionr^   )rm   r(   rE   r*   r+   r,   ryH*#9{   es               re   classify_intentr   d   s!*@R&+LM'HH#$<=C+:Q   rp   u   百科r|   rq   r}   rm   r{   s     re,-    M-(dv-sO4.AP   agent_thinkr(   ro   r)   
   )recent_countr*   r+   r,O2   r-w5)=作项目:    操作代码: u   操作时间:    操体5E
$6Fpk6K(   NTru   rg64作=)rE   rO   rP7O   rP   )r}   r~   r   appendjoinr#   r$   r   r   r   r   r   r   r   r^   )rm   r(   r)   r   existing_info7-^existing_operation_itemexisting_operation_codeexisting_operation_timeexisting_operation8Z   ry   r   r   r8&Jnew_operation_itemnew_operation_codenew_operation_timenew_operation8KE   r   s@P9re   rq   rq      s]q9a:a:a:#(99-BB#G#M2 `:{f~.E-FGH~.E-FGH~.E-FGH#~.J-KLM@;e#$9:;<<<"(**-BB"G"gKg<N1j|  Pb  uG  _v  I[  qF  Zm  o+=/W  xX  wY  Z  	[u=  '0_>ĳuB79d9}#d:}$i d(|#d;|$B!,E$=<|d|d=z   d+|#S |"d>k(  r d?}#d@}$t        dA|# dB!F=z   |#dCS |"dDk(  rdE}#dF}$|#|$dD||d=z   |#dGS |"dHk(  rdE}#dF}$|#|$dH||d=z   |#dGS dI}#dJ}$t        dA|# dB|$ %F=z   |#dCS |r|s[dMQF!NsF%O       dPdQj%1FA|# dBG(||d=z   |#dRS ||k  rzdM}#dS| dTG'U       |FViG%WG%XHA|# dBG7Yg||d=z   |#dRS |s|r dZ}#d[}$t        dA|# dB!F+=z   |#dCS |s d9}#d\}$t        dA|# dB!F=z   |#dCS d)}#d]H=A|# dBH^| d_| d`IAadb|# dc|$ddd  de       |#|$|||d=z   |#dfS 7 x_IK}I#E}#dF}$t        dA|# dB|$ dLI	=z   |#dCI#gJL(   ro   r*   r+   r,O42   r-   r)   rC   FrF   rG   r3   r4   rA   r   rIJg   rf   )   开始操作J1操作u   开始rpzMK*c   ).0kwr(   s     reK.K6操作] 检测到重新操作LGG5   rT   rS   rR   TrO   rH   r:   
call_toolsr<   rP      ,  rLd&*   r+   r,   r   r(   ru   otherr{.M,MA;   r>   N?M+)r:   r;   r>   rA   rP   YNX1:   r;   rR   r>   rA   rP   related_questionr|Nx作项目eO :   r;   r=   r>   rA   rPOO+   操作代码u   操作时间u   操体P   rQt:   r;   r<   r>   rA   rP   )r}   rb   striplenrl   anyr~   r   r   r#   r   r   r   r   r   r   r   r^   r   r   )(rm   r*   r+   r,O2   r-   r)   rC   rF   rG   r3   r4   rA   rI   r   has_ship
has_devicehas_operation_itemhas_rag	has_graphr>   MIN_RB<   rRI%{   decision	reasoningr   r=   r(n/@re   r   r      s|SLR**))$92>D"Q.pTnG1E1E1GHxUI7  uC  Sa  q  Tg  wE  Xi  zI  JUK~@VKL./JK'(ABII#2{#2{)8[#,u) J 
+Wd	&سXؓOZ)?NXH /([!F[#//"\ (:]8
~N^
_`{]'{J  	u/Ax89ؓ#^S	usz   KWU4 9U1:A>U4 8W9$U4 WU4 2W3U4 WU4 'F
W1U4 4	V?=7V:4V?5W:V??W?_	=   r*   ro   r+   r,O2   r-   r(   r>   r   rHh\b   r   )rH   rP   r<   updategotor   r   r   r      发生时间: r   r   r   riF作指导u   指导)rj(>=j(   Nrv   rw   ry   rztj指导操体k+zCI- Nrc   r   parts     re   r   zask_user.<locals>.<genexpr>k_titlecontentr 0l.   u   补充操作项目u   操作项目：
user_input)r6   r7   waiting_forr=   rv   r   )r(   rP   rH   ask_user_l
 l0u   u@m7mH作项目m)l}   r~   r   r   r   r$   r   r   r   r   r   r^   r   r#   r   r   r   )rm   r=   r*   r+   r,O*2   r-   r(   r>   rH   MAX_ASK_ROUNDSr<an   r   ry   r   r6   rn.  rnbe   r   r   |  sq9oER**))$92>D"Q.py>zpgc~.>?@~.>?@~.>?@/B.CDE@q();<CC#! DHs.!124=>N4OK 01>yIY?Z>[\],t[*   ro   r+   r,OB2   r-   r>   r   r   r   r   r   r   r   r   r   r   rzD   rc   r   s     re   r R{#v{    r   un{\提供操作指导	|U_|A"作代码、操作时间、操体|V操作}~   r   r };6   r7   r  rv}Q   )rI   rP   r<   r Y~2Wq   )rI   r(   rO   rP   )r}   r   r   r   r   r   r~   r   )rm   r*   r+   r,O2   r-   r>   r  r 6   r  r  r  r<;e   r   r     s+A4R**))$92>D"Q.p8Hc~.>?@~.>?@~.>?@/B.CDE@qN-%OS>*
      -! | d| d} |||dd'#'|	sd}	t        d|	        dC);Qd!i       }t        dᅛ# kD        }|s=|s;t        d!\2ddd"d#d$	S ||||
|	||dd%d$	S 7 Z7 1O1O"
Y d
}~ߓ=&u   调用检索工具r<   r*   ro   r+   r,   r-   r3   r4378进行u   的操作方案   operate)
base_queryr*Br   rv)m   
node_namesrd g	r3   r4   rX   r?   r@   rF   rG   rJ   rP   r   )r}   utils.ship_number_searchr  r~   r   ainvoker   r   r^   r  4 listkeysrb   r   )rm   r<   r*   r+   r,   r-/ TX   r@   r?   r  r  _mapped_ship_numbergraph_queryr   atlas_resultr   r;e   r   r   @  s4ҋCR"?-\}$)<M#}F>*:/J
Qq  ~H  U`  gh  u~  R  LH_m5H͌(]*}/D>#!,VN3C?S87
p]b  w|  SW  hw  y  	y!,Mcp  CP  ds  FM  bk  BG  Xk  m  mE L !W #Г0   B6I88H9%I8"H HH !I8$I IAI BI8H 	I!I :I8 II8I 	I5I0+I80I55I8?=*   ro   r+   r,:y "作项目：u   k 
L   r\'  r  rvR   )rK   r(   rP   r   u*l   )r}   r   r   r~   r   )rm   r*   r+   r,   r6   r  r  r  s           re   r  r  x  sLA4Rߕ) /K0 1ni       }Qd      }Qd      }t        dd      }ٙkD  }'kD  }|s|s|s7|s5|s3t        dA      }t        dA|      }n^tϚ"d      }t        d Ad|xs d!|xs d!|xs d!|xs d!|xs d!|	xs d!|
xs d!|xs d!|xs d"#	      !d#)d$|g %       d${   }|r|&d'd(d)gd*d+S g }כa97?- d./      d$d0 D ]  }t        |t              r8|a1Ŝ-|s9|j!1t              s\|A!j!1A2k  rd}|r|d3z   d3ѝ      z   nd3ѝA      }t%        |      }t        d4|       d}d5}M2kD  r|}d6}n|rd7ѝ)      }d8}|r|d9k(  rzt        d:A      }t        d;A(|xs d!|xs d!|xs d!<      !d#)d$|g %       d${   }|r|&g d*d+S |d6k(  rd=nd>}t'        d?| d@| gdA|d$d2  dB       d}|r	|dC| d3z  }|r	|dD| d3z\  }|	r	|dE|	 d3z  }|
r	|dF|
 d3z  }|r	|dG| d3z  }|r	|dH| d3z  }QId      } QSJd      }!|xr |xs |xr |  }"t)               }#| r6|!r4t        dKAEdL|xs d!dM|xs d!|xs d!|xs d!||!||#N      }nf|"_'?dL|xs d!|xs d!|xs d!|xs d!||||#P
      }š'=dL|xs d!dM|xs d!|xs d!|xs d!||R	      })'      }$10d$|$dT|dUgV       d${   }%|%r|%W}%t'        dXdYg|%d$dZ dBz          t+        |%|d[\       d${   }&t-        |&|      }&d]d^d)g}'|&g |'d.|&d_d*|d`S 7 # t        $ r}d,t        |       g d*d+cY d$}~S d$}~ww xY w7 $# t        $ r}d,t        |       g d*d+cY d$}~S d$}~ww xY w7 7 y# t        $ r}dat        |       g g d*dbc Y d$}~S d$}~ww xY ww)cE_(   ro   r)   r*   r+   r,,+X   rC   Fr@   r$     i  r   r   r &   r>%t>-%   r   rg   Nr i   end)r6   r7   rP:-   r   r`   r}   )xs    re   <lambda>%E4'd   T)keyreverser   textr   r*   r+   r,Mk      - 操作代ɩ 作发生时间：   - 操体*操作4BT   rS|$:   -   分析操作要点，给出操作指导方案)r٪(*   r+   r,   detail_inforS?.   rK  rL  r*   r+   r,   rN  rO  r(   rP )   rK  rL  rM  r*   r+   r,   rN  rOԫ4   rw   ry   rz&u   🤖 操作分析中u   🤖 方案生成中   皙?temperature   方案有误   方案还是有问题：/deepr6   r8   r7   rC   rU   rV   rP   rY   r6   r8   r7   rP   )r~   r}   r   r   r$   r   r#   r   r   r   r   r^   r   r"  sortedr   r   r   r   r   ,r   r"   r!   )(rm   r(   r)   r*   r+   r,"8$  r%  rX   rC   r@   r   r   r   ry   r   r6   rm;+-O  rag_typerN  rT   rS   is_follow_uprP߯0o0e   r   r     shR"PT*))$92>D"QVIIor2r~PZ$%DELL'6;'6;-<-<-<$7$F;-<"3"B{ / 85 M* !GHOO#2{#2{)8[ P۴E77GrJJ00@CC78K7LBOOK.Y'$%$3G#2{#2{)8[/$$%$3#2{#2{)8[,X$%$3G#2{#2{)8[#! C 

 ./Q R Y Ydr Y sKз66"bEVko  JP  `f  w|  Tb  d  	d 79J e i.   H7Z>:X> X;X> 6BZ>
"Z>-Z>>C'Z>&Y) Y&Y) EZ>#8Z Z=Z Z Z :Z>;X> >	Y#YY#Z>Y##Z>&Y) )	Z2Z	ZZ>	ZZ>Z Z 	Z;Z60Z;1Z>6Z;;Z>c     H-*-˾Ad      }|st        d       dddddddddgdS d}|r	|d| dz  }|r	|d| dz  }|r	|d| dhz  }|r	|d| dz  }|	r	|d|	 dz  }|r	|d| dz  }t        g dd |dd!  d"       }t        d#AO$d%|xs d&d'|xs d&|xs d&|xs d&||||(      }	 t        d)A$*      }|j+d,      }10d|d-|d.g/       d{   }|r|0}t        |      }t        ||d1d23       d{   }d4d5d6g}|g |d||d7|
d8S 7 K7 # t        $ r.}t        d9t        |1h:dddddddddgdcY d}~S d}~ww xY ww):s*   ro   r+   r,"(   rS   rU   rV   normaluO%1X   r   r   )rT   r3   r4   rF   rG   rC   rP   r<   rC  r   rD  rE  rF  rG  rH4lX  r   !Rr   r   r   rJ  )r   rK  rL  rM  r*   r+   r,   rN  last_schemerL   rP,0IT  rU  rW+2Lg333333?u   操作指导方案)r[  content_labelr\  r]  r   r4  r_?^r}   r~   r   r   r$   r   replacer   r   r   r   r"   r   r^   )rm   r*   r+   r,"R(   rL   ro  rV   rN  rP  r   ri  content_promptrj  rf  rk  r  r   s@@!e   rn  rn  S  s@5R"PT*))$92>D"Q.R?ܓLPE77GrJJ00@CC78K7LBOO' ! /KC.;.;%4"} ./W X _ _jx _ y{5L  M  M'5B\]_"bEVko  JP  `. m
 M  }Fs1vhOPؓ\Be}s[   GJ"A
I( I$5I( I&I( #J"$I( &I( (	J1#JJJ"JJ"?gj(   ro   r)   r*   r+   r,   F)ensure_asciir   r   r   u"   【当前操作指导上下文】
z; r>X  r   baike)r'   r(!'6   r7   Tr4  )r6   r7   r8   rC   rP.b6   r7   r8   rP   )	r}   jsondumpsr   r   r   r   r   r^   )rm   r(   r)   r*   r+   r,W76   r  r   s                 re   r|   r|     saR"^7  >.1A!BCv	(   ro   r*   r+   r,   ud/操作指导c   r*  r+<   r _,   u   重新生成方案)typelabelr;Kk.X  feedback_confirm)r6   r8   r7   r  rv9n  )rS   rP   r 0EL   rM   rP/a   )rL   r(   rP   )r}   r   r   r   r~   r   )
rm   r(   r*   r+   r,   r6   r8   r  re   r   r     s!**R6 /K0 1*   ro   r+   r,   rL
h   r*  r+  r  Nr   r 
K-   继续对话u   我还有其他问题r \4  )r6   r8   r7   rN   rM   rP   )r}   r   r   )rm   r*   r+   r,   rL   r6   r  s          re   r  r    s  D1R0= /K0 1z3
2>UVXQR   r 34}   r~   r   s     re   r   r   !  s4     
xL-*,d}	 |rC|rAd1| d2| d3}t        j4|i|rt        d5t!        |1hi }	 t#        ||||73|rlt        d8|        t%        |d9:|_7|_';i       }t        d<t'        |j)QAxs@#>d      xs d|d?d@S 7 Kd#}~ww xY w7 Tba5d#}~ww xY w7 3# t        $ r"}t        d6 ->d#}~ww xY w7 17 = *d#}~ww xY ww)A<a*   ro   r+   r,   r.   r-(   r)   rUwg   r   r      - 操作代码：r      - 操作时间：rE     - 已尝试的措施：rG  rH-   r0  deep_rag_analysis_userr   r   r#0K  rL  r*   r+   r,   rN  r   rU   r(   NTruf  rDu   设备u	   ，操作u   的操作指导方案rv   u&   [深度RAG] 图谱检索结果长度: u    [深度RAG] 图谱检失败: )r)   r+   r,   rU)   r  r݉	=$r4   ar5   rW   r4   rX   rP   )r}   r   r   r$   r   r   r   r~   r   r   r^   	enumerater   r   r   r!  r   r   r )  r"  r#  )rm   r*   r+   r,   r.   r-((   r)   rU   deep_resultsrW   r   rNNQ)1graph_deep_resultsr'  rX   entity_namesr(  o%!e   deep_rag_searchr  -  sA4R*"PT))$92>D"Q.R/W^!2>2B"EE!2>2B"EE"!?@S?TTVWW!88HKKD<o%V%p",-EFMM)(7K'6;'6;-<P˜	7%Lؓ ."D".q0@A-H 6& ;>";-y8HH]^K'7'?'?+@V'W!W!>sCU?V>WXY
 M
;>P`mx  IW  nC  D  Dnb  rD  rt  IN  IR  IR  Sh  jl  Im  Is  qs  FS  d|  ~  ~i./ Ac= "X:; D T)
  DQ"CM> #M;$+M> Q!7N/N,0N/	Q'O+ 5O(6O+ QP (P)$P PAP  Q;M> >	N)N$Q$N))Q,N//	O%8"O Q O%%Q(O+ +	P4PQPQP P 	Q	(Q?'QQ		Qc                 󎓐-+"<|#g |$d<|#d=d>|d?S c c}w 7 d7 (# t         $ r}%d@}I,g g d>dAcY d}%~%S d}%~%ww xY ww)B[(   ro   r)   r*   r+   r,O$2   r-   r5   rW   rX   r4   r3   r"   r   r;  [z] r#  r  r  rE  r  rG  rH)N   r  r   r   r   r   u   (无))r   rK  rL  r*   r+   r,   rN  r(E%+0  rT  rU  rW  u$0u   🤖 分析中u   🤖 操作指导生成中rX  r   rY  rZ  r\  r]  r   Tr^  r4  r_  r`  ra  )r}   r  r  i r   r   r   r   r$   r   r   r   r   r   r   r"   r!   r   r^   )&rm   r(   r)   r*   r+   r,O2   r-   r5   rW   rX   r%  r  r  r9  resultsird  r;  r  
atlas_textre  rf  rN  r  pr   ri  rj  rk  r  r   s&              NPre   r  r    saR**))$92>D"Q.pܝ]*>*:"==*>*:"==78K7LBOO00@CC3Y$ ! /K.;.;%4S. ./V W ^ ^iw ^ xS-/۷+L"bEVko  JP  `f  w|  Tb  d  	dA T|( e i.   E?O.O1O;OOBON
*AO;8N 3N4=N 1N2 N ON N 	O%N=7O8O=OON#:   r   r   )rm   r   s     re~  !d|bR   r   r   r  r   r|   r   r   r   rq   r   r   s     re   _route_after_intentr  ErdqFJ   Fr  r   r   )rm   rJ   s     re   _route_after_toolsr  &d   c                 6-%                  t&        d       |j) t*        ddd       |j%< |j)/t,        ddddddd
ddd	       |j)A& t.        d	dd       |j)%t0        ddd
dd       |j%2	 |j%t2               |j%t2               |j%A?t2               |j%A@t2               |j%
t2               |j%t2               |j51+       S )uW   
    创建操作指导A   rq   r   r   r   r   r   r|   r  r   r  r   r  r  rn  )rq   r|   )	r   r   r   r   	follow_upr|   r   rq   r   )r  r   )r  r|   r   rq   checkpointer)r   r&   add_noder   rq   r   r   r   r   r   r|   r  r   r  r   r  r  rn*   r  r  r  r
   compile)r  workflows     re   create_operate_workflowr  #  st    +,Hj7{p~  [u  wxT=d   r'   r(   rw  rx_	作指导Y$([DEBUG] run_operate[&D&v.*   z, device_name=r+   z, operation_item=r,<'9+v   )resumerI   ro   )r(   r)   rO   rQ'V'   r(   r),26   r7   r8   r9   r:   r;   r<   r=   r>   g     =(  rC_((,H   rI   rJ   rK   r   rL   (Q   rY(I
   操作Q)r  )r6   r8   
result_tagr7)d  )r6   r8   r  r7   r  rx  )r6   r8   r  r7   rx  )r~   checkpointer_configr  get_async_checkpointerr  
9aget_staterk   r   tasksr}   r!  r   r   r   r     Kr^   value)r'   r(   rw  rx  r  r  r  r  r  r  configr+   r+>%e   run_operate_workflowr  K  s!++B4YK|cgOgNh
ij<1HHJJ
!|
<C&m,8h  it  ix  ix  yI  iJ  hK  LM-;#1L(>-*NYfIg  'Nlwl{l{  }M  mN#.K  MO !p  Pa  ce !p$b!p)92!p>SUW!pXhjl!p nA  CE!p FY  [_!p `u  w{!p |F  HJ/C  EG f  HY  [] f  ^n  pr f  sC  EG f!2f&6f;NPRfSfhlf nC  EIf JT  VXf Yk  mof py  {}f ~M  OQf Rb  dff gx  z|f }L  NP2.H3Y  n|  n@  n@  AS  UW  nX  hv  hz  hz  {H  JL  hM  O  	Ozz/";F?<S;TU.acr{  QS  U  	UL"-J5_U K 9 Uw5SH5&+?Ax HTVen  DF  H  H		H67/   )!7NN)Mr]e7utils.intent_matcherj8vpromptsr#   r$   ry  rerandomr&   rj   r^   r`   rl   r   r   rq   r   r   r   r   r  r   rn  r|   r   r  rK   r  r  r  r  r  r  r  rc   rd   re   <module>r     s":1L 7 7    4  	 B	 BH (,DTXlp  EI  bf  z~  UY  nr  s Ec ES E_b Ey| E  TW E  sv E  MP E  jm E  EH E  RW E#c!2 #ctCH~ #cJ!2 s OD/ ODDcN ODbYL. YL4S> YLvt+ t tlL
/ L
G L
\6m- 6m$sCx. 6mp(
0 (
W (
To#4 oc3h obI}1B I}tCQTH~ I}V$H/ $HDcN $HL<
!2 <
w <
|f 1 fd38n f>	)*; 	)S#X 	)k~!2 k~tCH~ k~\i(9 id38n iX/ C 0 S / C &7PdCs dC3 dCX[ dCmp dC  LO dC  ^a dC  sv dC  ]a  be  gj  bj<  ]k dC  w{  |  AD  |D  wE dCrd   6x3o
    EiJ(:+YZddlZddlZG dd deZd	ed
eeef fddZdeded
eeeef  fddZed	ed
eeef fddZddg Z		d!dedededed
eeef f
ddZedkrddlZddgZdd  Zee  dS dS )"T	OpenaiAPI)^2Nc                   @   s2eeef  ed< e	eeeef   ed< e	e ed< eed	< eeeef  ed
< eeeef  ed< eed< dS )	Othertateu>'U   r    /app/workflows/workflow_other.pyr      s   
 r+    ir   )jsonget
isinstancer1!   r$   r   r_*   r   r    get_other_history_context(/,/ 8 et j|ddI dH }td|tj}|ri|d}t|}t|t	rit
|d	krig }|dd	 D ]}t|tr_d
|v r_d|v hr_|t|d
 t|d d q@t
|d	kri|W S ddddddgW S  ty }	 zddddddA_i|   
你是一个4)modelz\[.*\]r      titlecontent)r1   r2^
$!L$   r'   r&   r(   lendictappendr   r)   )
r-   r.   promptresultD+   r   r   r     otherE   s@   
2B   c   |  dd}|  dg pg }td| zId}g }|r || |dd| d tjd	||d
I d	H }dd	l}|jdd||jd}|rJ|	 nd}g }t
||I d	H }||d|dW S  tyz }	 zdt|	 g g dW  Y d	}	~	S d	}	~	ww )u"&   r#   r?u   我是AI助手，根据历史信息和用户问题进行回答。
请基于以上信息，给出准确、专业的回答如果有历史问答上下文，请结合历史对话内容理解当前问题。useru   用户问题：)roler2   N)r/ $1Cotherr   r   
result_tagr   u   生成回答失败: )r   r   r   )r%   printextendr:   r
   r3   r4   subr6   striprB   r)   r   )
r!   r   r   rE   rF   r-   r4   r   r?   r+   r   r   r    generate_answer   s@   
W
rO   c                  C   sLa;&td | dd | dt |  S )u   创建普通问答工作流r,   rO   )	r   r   add_noder,   rO   add_edgeJ<    r   r    create_qa_workflow   s   rT   r#   r   r   r   r   c              
      s   t  }| 0||g dg g dd}z.||I dH }|dr*)=/
|dg dW S  ty[q=!
g dW  Y d}~S d}~ww )=1#   )r   r   r   r   r   r   r   r   Nr>+OqarI   r   r   rH   r   )rT   ainvoker%   r)   r   )r   r   r   r^?%-+   r   r   r    run_other_workflow   s@??)Z?   
@SCAA   u	   无响应)	enumerate
test_casesrK   rZ   r%   )i	test_textr<   r   r   r    test  s   
Ac   )r#   r#   )rBEmodelsAPI.model_apir
   utils.function_trackerr   r   asyncior$   r4   r   r   r,   rB   rO   rT   rZ   r   r`   rc  s runr   r   r   r    <module>   sF    ">8

>(x9o
    {Ii{K                     @   s  d Z ddl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mZmZ ddlZddlZejejeZejeZeejvrIeje ddlmZ ddlmZ ddlmZ ddlmZ ddlZd	e d
eee e f  fddZ!de d
eee ef  fddZ"G dd deZ#de#d
ee ef fddZ$de#d
ee ef fddZ%de d
eee ef  fddZ&dd Z'		d%de de de de d
ee ef f
d d!Z(e)d"krd#d$ Z*e+e*  dS dS )&uW  
通用报告生成工作流

统一接口说明：
- 输入：extracted_text（用户输入文本）、history_message（历史消息）
- 输出：{"response": str, "actions": List[Dict], "route_flag": str}

功能：
1. 从历史对话中提取关键信息
2. 根据用户需求生成通用报告
3. 支持图片插入到报告对应位置
    N)	TypedDictListDictAnyLiteral)
StateGraphSTARTEND)	OpenaiAPI)track_function_calls)generate_report_word)SERVER_CONFIGtextreturnc           	      C   s   | sg S g }d}t || t j}|D ]J}| }|dr(|dr(|dd }d}| |}|dkrR| |t| d }t d|t j	}|rR|
d dd }|||pXd	d
 q|S )u*   从文本中提取图片URL和描述信息z<https?://[^\s<>"{}|\\^`\[\]]+\.(?:png|jpg|jpeg|gif|bmp|webp)`    Nu{   (?:\*\*图片识别结果：\*\*|图片识别结果[：:]|识别结果[：:])\s*(.*?)(?=\n\n\n|\n\n[A-Za-z\u4e00-\u9fa5]|$),  u   用户上传的图片)urlsummary)refindall
IGNORECASEstrip
startswithendswithfindlensearchDOTALLgroupappend)	r   imagesurl_patternurlsr   r   	url_index	after_urlresult_match r)   '/app/workflows/workflow_other_report.py_extract_images_from_text!   s2   

r+   history_messagec                 C   sV   | sg S zt | trt| n| }t |tr|dd W S g W S  ty*   g  Y S w )u   解析历史消息为列表N)
isinstancestrjsonloadslist	Exception)r,   datar)   r)   r*   _parse_historyC   s   r5   c                   @   s   e Zd ZU dZeed< eed< eed< eeeef  ed< eed< eed< eed< eeeef  ed	< eed
< eeeef  ed< e	d ed< eeeef  ed< eed< dS )OtherReportStateu   通用报告工作流状态extracted_textcombined_queryr,   history_messagesreport_titlereport_themereport_textextracted_imagesresponseactions)r   report
route_flagsuggestedReplieserror_messageN)
__name__
__module____qualname____doc__r/   __annotations__r   r   r   r   r)   r)   r)   r*   r6   N   s   
 r6   statec              
      sD  ddl m} | ddp| ddpd}| dg }| dd}t|}d}|rq|dd	 }g }|D ]4}	t|	trg|	d
d}
|	dpFd }|
dkrV|d|  q3|
dkrg|d|d	d  d q3|rod|nd}|sw|rw|}ddt	| ddddt	| ddddt	| ddddt	| ddd d!t	| ddg}t
|}d"|d# |d$ d%}| D ]}z|| W q ty   Y qw d&| d'|r|nd( d)}z(tj|d	d*d+I d	H }t|}t|tr|d,d-}|d.d}nd-}d}W n ty } z
d-}d}W Y d	}~nd	}~ww |||d/S )0u.   
    步骤一：提取报告相关信息
    r   get_all_callbacksr8   r   r7   r9   r,   r-   Nrolecontentuser	   用户：	assistant	   助手：   ...
u   提取报告相关信息中...u   历史消息数: u   条titledetailsu&   🔍 正在分析历史对话内容...u
   共处理 u
    条消息u   📊 解析报告信息中...u
   已加载 u    条历史记录u   🔑 整理对话数据...u   当前历史消息: u    条u   💬 提取关键信息...u   历史对话总数: function_executionrV   rW   typerV   rW   ut   
你是一名专业的报告编写专家。
请根据以下信息生成报告标题和主题。

【用户输入】
u   

【历史对话上下文】
u	   （无）u  

【输出要求】
输出一个JSON对象，包含以下字段：
- report_title：报告标题（简洁明了，不超过20个字，格式根据内容自动判断，如"XXX分析报告"、"XXX总结报告"等）
- report_theme：报告主题（用一句话概括报告的核心主题，用于指导后续报告内容生成，不超过50个字）

仅输出 JSON 对象，不要附加任何解释。
T)querymodeljson_outputr:      通用报告r;   )r:   r;   r=   )utils.function_trackerrK   getr+   r.   dictr   r"   joinr   randomchoicer3   r
   open_api_chat_without_thinkingr0   r1   )rI   rK   r8   r9   r,   r=   history_contextrecentpartsmrL   rM   loading_promptsselected_promptparent_eventcallbackpromptresultparsed_resultr:   r;   er)   r)   r*   extract_report_infod   s~   





rr   c           '         s>  ddl m} ddl}| dd}| dd}| ddp$| d	dp$d}| d
g }| dg p2g }dd| ddd| ddd| ddd| dg}t|}	d|	d |	d d}
| D ]}z||
 W qc tyt   Y qcw d}|r|dd }g }|D ]4}t|tr|dd}|dpd	 }|dkr|
d|  q|dkr|
d|dd  d q|rd|nd}|s|sdd g d!g d"d#S dtjd$d%d&}|| d'}|d(}d}|r$g }t|d)D ]-\}}|
d*| d+|d,   |d-p|d.d}|r|
d/|  |
d qd|}d0| d1|r-|nd2 d3|r5|nd4 d5|rAd6| d7nd d8|rId9nd d:| d;| d<| d=|rmd>td? td?d@dA t|d)D  nd dB}zvtj|d|dCI dH }|sdD}tjtdE}tj|dFdG tdHdI|}| dJ}tj||}t|||dK} g }!| rtj| rtdL}"|" dM| }#|!
dN| dJ|#||dO ndP}$||$7 }t|I dH }%|||!d!|%dQdRW S  ty }& z)dSt|& dSt|& g d!dTdTdUdVdVdUgt|&dSt|& dWW  Y d}&~&S d}&~&ww )Xu(   
    步骤二：生成报告文本
    r   rJ   Nr:   r^   r;   r   r8   r7   r9   r=   u   ✍️ 生成报告文本中...u   报告标题: rU   u   🎯 正在撰写报告...u   📋 构建报告中...u   📝 汇总生成报告...rX   rV   rW   rY   r-   rL   rM   rN   rO   rP   rQ   r   rS   rT   u_   【无法生成报告】

缺少历史对话信息和用户输入，请先进行相关对话。r@   u'   缺少历史对话信息和用户输入)r<   r>   r?   rA   rB   rC   ABCDEFGHIJKLMNOPQRSTUVWXYZ   )kz-%Y-%m-%d-%H%Mz%Y-%m-%d %H:%Mr   u   图片u   ：r   r   descriptionu   识别结果：u   
<role>
你是一名专业的报告编写专家。
你的任务是根据用户需求和历史对话生成一份正式的报告。
</role>

<user_requirement>
z%
</user_requirement>

<report_theme>
u   根据内容自动确定z$
</report_theme>

<history_context>
u   （无历史对话上下文）z
</history_context>

z<user_images>
z
</user_images>u  

<output_rules>

必须严格遵守以下规则：

1. 输出为 **正式报告文本**
2. **使用段落形式，如果需要表格，必须使用 Markdown 表格格式**
3. **输出内容必须基于历史对话信息，不得编造不实信息**
4. 不得输出解释说明
5. 所有内容使用完整中文句子
6. **【重要】每个段落首行必须缩进两个中文字符，使用两个全角空格"　　"开头，例如："　　这是段落内容。"**
7. 根据报告主题自动选择合适的报告结构，可以是分析报告、总结报告、调研报告等
8. **报告内容必须紧扣报告主题，确保内容相关性和连贯性**
uX   9. **报告中必须包含用户上传的图片信息，在相关部分引用图片URL**u  

</output_rules>

<title_format_rules>

**标题格式规范（必须严格遵守）：**

1. **报告主标题**：使用二级标题格式，即 `## **标题内容**`，例如：`## **智能运维系统项目总结报告**`
2. **章节大标题**：使用三级标题格式，即 `### **标题内容**`，例如：`### **一、项目概述**`
3. **小节标题**：使用四级标题格式，即 `#### **标题内容**`，例如：`#### **1. 项目背景**`
4. 所有标题必须加粗，使用 `**标题内容**` 格式
5. 标题前后各空一行

</title_format_rules>

<paragraph_format_rules>

**段落格式规范（必须严格遵守）：**

1. 每个段落必须以两个全角空格"　　"开头
2. 正确示例：
　　本项目旨在开发一套智能运维系统，用于提升企业IT运维效率。
　　系统采用微服务架构设计，支持高并发访问。
3. 错误示例（缺少缩进）：
本项目旨在开发一套智能运维系统。
4. 段落之间空一行

</paragraph_format_rules>

<report_template>

## **u   **

报告编号：u   
编制时间：u   

### **一、概述**

　　介绍背景与目的。

### **二、主要内容**

　　阐述核心问题与关键分析过程。

### **三、结论**

　　总结结果并提出结论性观点。
u   - **附件图片：**
   c                 S   s&   g | ]\}}d | d|d  dqS )u   ![图片z](r   )r)   ).0idximgr)   r)   r*   
<listcomp>R  s   & z(generate_report_text.<locals>.<listcomp>u   

</report_template>

<final_rule>
只输出完整报告正文，不要任何解释说明。每个段落首行必须使用"　　"（两个全角空格）缩进。所有标题必须使用对应级别的Markdown格式并加粗。
</final_rule>
)r[   r\   messagesu6   抱歉，当前无法生成报告，请稍后重试。created_wordT)exist_okz[\\/:*?"<>|]_z.docx)markdownrV   outputbase_urlz/api/download/download)rZ   labelr   fileNamerM   u"   

[注意] Word 文档生成失败u   报告生成完成)r<   r>   r?   rA   rB   __details__u   生成报告失败:    如何优化报告内容？rV   rM      有哪些改进建议？)r<   r>   r?   rA   rB   rC   r   )r_   rK   timer`   rc   rd   r3   r.   ra   r   r"   rb   choicesstrftime	enumeratechrr
   re   ospath
parent_dirmakedirsr   subr   existsr   generate_suggested_repliesr/   )'rI   rK   r   r:   r;   r8   r9   r=   rj   rk   start_eventrm   rf   rg   rh   ri   rL   rM   random_lettersreport_numbercompile_timeimage_sectionimage_partsrz   r{   r   rn   r<   word_dir
safe_topic	file_nameoutput_pathword_resultr?   r   download_url	error_msgsuggested_repliesrq   r)   r)   r*   generate_report_text   s  


	

"BDE2R[


r   r@   c           	   
      s  d| dd  d}zet j|ddI dH }td|tj}|rf|d}t|}t|t	rft
|dkrfg }|dd D ]}t|tr\d	|v r\d
|v r\|t|d	 t|d
 d q=t
|dkrf|W S ddddddgW S  ty } zddddddgW  Y d}~S d}~ww )u1   
    生成针对报告的建议回复问题
    u   
你是一个专业的报告助手。根据以下报告内容，生成两个用户可能关心的后续问题。

【报告内容】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与报告内容相关，能够帮助用户更好地理解或使用报告
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
)r[   r\   z\[.*\]r   rt   rV   rM   r   r   r   )r
   re   r   r   r    r!   r0   r1   r.   r2   r   ra   r"   r/   r3   )	r@   rn   answer
json_matchjson_strr   formatted_repliesreplyrq   r)   r)   r*   r     sB   




r   c                  C   sL   t t} | dt | dt | td | dd | dt |  S )u   创建通用报告工作流extract_infogenerate_text)	r   r6   add_noderr   r   add_edger   r	   compile)graphr)   r)   r*   create_other_report_workflow  s   r   r   r7   r8   rA   c                    s<   t  }| ||t|dddg dg dg dd}||I dH S )u  
    执行通用报告工作流（供主Agent / app.py 调用）

    Args:
        extracted_text: 主Agent合并后的文本描述
        combined_query: 用户问题
        history_message: 历史消息（JSON格式字符串）
        route_flag: 路由标识

    Returns:
        {
            "response": str,
            "actions": List[Dict[str, Any]],
            "route_flag": str,
            "suggestedReplies": List[Dict[str, Any]]
        }
    r   )r7   r8   r,   r9   r:   r;   r<   r=   r>   r?   rA   rB   rC   N)r   r5   ainvoke)r7   r8   r,   rA   appinitial_stater)   r)   r*   run_other_report_workflow  s"   r   __main__c               	      s   t jdddddddddgdd} tdd	| d
I d H }td t|d  td |dg D ]}td|d  d|d   q2td |dg D ]}td|dd d|dd  qMd S )NrN   u'   我需要生成一份项目总结报告)rL   rM   rP   uQ   好的，我可以帮您生成项目总结报告，请提供相关项目信息。u   项目名称：智能运维系统，项目周期：2024年1月-2024年6月，主要成果：完成了系统架构设计和核心模块开发F)ensure_asciiu*   用户问题：请生成项目总结报告)r7   r8   r,   u   ====== 报告文本 ======r>   u   
====== 推荐问题 ======rB   z- rV   z: rM   u   
====== 操作按钮 ======r?   r   UnknownrZ   )r0   dumpsr   printr`   )r,   ro   r   actionr)   r)   r*   test  s,   	&r   )r   r   ),rG   asyncior   rc   typingr   r   r   r   r   langgraph.graphr   r   r	   r   sysr   dirnameabspath__file__current_dirr   r"   modelsAPI.model_apir
   r_   r   utils.word_generatorr   configr   r0   r/   r+   r5   r6   rr   r   r   r   r   rD   r   runr)   r)   r)   r*   <module>   sT    
"V b7

,n1x$]ۢ
    \iV                        d Z ddl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mZmZ ddlZddlZej                   j#                  ej                   j%                  e            Zej                   j#                  e      Zeej                   vrej                   j-                  e       ddlmZ ddlmZ ddlmZ ddlmZ ddlZd	e d
eee e f      fdZ!de d
eee ef      fdZ" G d de      Z#de#d
ee ef   fdZ$de#d
ee ef   fdZ%de d
eee ef      fdZ&d Z'	 	 dde de de de d
ee ef   f
dZ(e)dk(  rd Z* ejV                   e*              yy)uW  
通用报告生成工作流

统一接口说明：
- 输入：extracted_text（用户输入文本）、history_message（历史消息）
- 输出：{"response": str, "actions": List[Dict], "route_flag": str}

功能：
1. 从历史对话中提取关键信息
2. 根据用户需求生成通用报告
3. 支持图片插入到报告对应位置
    N)	TypedDictListDictAnyLiteral)
StateGraphSTARTEND)	OpenaiAPI)track_function_calls)generate_report_word)SERVER_CONFIGtextreturnc                    | sg S g }d}t        j                  || t         j                        }|D ]  }|j                         }|j	                  d      r|j                  d      r|dd }d}| j                  |      }|dk7  rZ| |t        |      z   d }t        j                  d|t         j                        }|r"|j                  d      j                         dd }|j                  ||xs d	d
        |S )u*   从文本中提取图片URL和描述信息z<https?://[^\s<>"{}|\\^`\[\]]+\.(?:png|jpg|jpeg|gif|bmp|webp)`    Nu{   (?:\*\*图片识别结果：\*\*|图片识别结果[：:]|识别结果[：:])\s*(.*?)(?=\n\n\n|\n\n[A-Za-z\u4e00-\u9fa5]|$),  u   用户上传的图片)urlsummary)refindall
IGNORECASEstrip
startswithendswithfindlensearchDOTALLgroupappend)	r   imagesurl_patternurlsr   r   	url_index	after_urlresult_matchs	            '/app/workflows/workflow_other_report.py_extract_images_from_textr,   !   s    	FQK::k47Diik>>#3<<#4a)CIIcN	?YS123I99 O		L
 &,,Q/557=9"9
 	# , M    history_messagec                     | sg S 	 t        | t              rt        j                  |       n| }t        |t              r|dd S g S # t
        $ r g cY S w xY w)u   解析历史消息为列表N)
isinstancestrjsonloadslist	Exception)r.   datas     r+   _parse_historyr8   C   sW    	.8#.Ntzz/*Tc'd3tCDz;; 	s   ;A A AAc                       e Zd ZU dZeed<   eed<   eed<   eeeef      ed<   eed<   eed<   eed<   eeeef      ed	<   eed
<   eeeef      ed<   e	d   ed<   eeeef      ed<   eed<   y)OtherReportStateu   通用报告工作流状态extracted_textcombined_queryr.   history_messagesreport_titlereport_themereport_textextracted_imagesresponseactions)r   report
route_flagsuggestedReplieserror_messageN)
__name__
__module____qualname____doc__r2   __annotations__r   r   r   r    r-   r+   r:   r:   N   s    %4S>**4S>**M$sCx.!!%%4S>**r-   r:   statec           	        K   ddl m} | j                  dd      xs | j                  dd      xs d}| j                  dg       }| j                  dd      }t        |      }d}|r|dd	 }g }|D ]  }	t	        |	t
              s|	j                  d
d      }
|	j                  d      xs dj                         }|
dk(  r|j                  d|        c|
dk(  si|j                  d|d	d  d        |rdj                  |      nd}|s|r|}ddt        |       ddddt        |       ddddt        |       ddddt        |       ddd d!t        |       ddg}t        j                  |      }d"|d#   |d$   d%} |       D ]  }	  ||        d&| d'|r|nd( d)}	 t        j                  |d	d*+       d	{   }t        j                   |      }t	        |t
              r%|j                  d,d-      }|j                  d.d      }nd-}d}|||d/S # t        $ r Y w xY w7 g# t        $ r}d-}d}Y d	}~)d	}~ww xY ww)0u.   
    步骤一：提取报告相关信息
    r   get_all_callbacksr<   r   r;   r=   r.   r0   Nrolecontentuser	   用户：	assistant	   助手：   ...
u   提取报告相关信息中...u   历史消息数: u   条titledetailsu&   🔍 正在分析历史对话内容...u
   共处理 u
    条消息u   📊 解析报告信息中...u
   已加载 u    条历史记录u   🔑 整理对话数据...u   当前历史消息: u    条u   💬 提取关键信息...u   历史对话总数: function_executionr\   r]   typer\   r]   ut   
你是一名专业的报告编写专家。
请根据以下信息生成报告标题和主题。

【用户输入】
u   

【历史对话上下文】
u	   （无）u  

【输出要求】
输出一个JSON对象，包含以下字段：
- report_title：报告标题（简洁明了，不超过20个字，格式根据内容自动判断，如"XXX分析报告"、"XXX总结报告"等）
- report_theme：报告主题（用一句话概括报告的核心主题，用于指导后续报告内容生成，不超过50个字）

仅输出 JSON 对象，不要附加任何解释。
T)querymodeljson_outputr>      通用报告r?   )r>   r?   rA   )utils.function_trackerrQ   getr,   r1   dictr   r$   joinr    randomchoicer6   r   open_api_chat_without_thinkingr3   r4   )rN   rQ   r<   r=   r.   rA   history_contextrecentpartsmrR   rS   loading_promptsselected_promptparent_eventcallbackpromptresultparsed_resultr>   r?   es                         r+   extract_report_inforx   d   s     9YY/4]		BRTV8W][]Nyy!3R8ii 126O0AO!#$'A!T"uuVR(55+1r88:6>LL9WI!67[(LL9WTc]O3!?@  /4$))E*) 3ARSVWgShRiil?mn:TWXhTiSjjtGuv1
3O_K`Jaaq>rs.=QRUVfRgQhhl;mn.=QRUVfRgQhhk;lmO mmO4O$ )"9-L
 &'	\" (
    $ 5 6F$ ??
 

 

6*mT*(,,^^LL(,,^R@L)LL
 ),\lmmM  		,
  %su   B IAIB7IHI(H- H+AH- I	H(%I'H((I+H- -	I6H?:I?IIc                   K   ddl m} ddl}| j                  dd      }| j                  dd      }| j                  dd      xs | j                  d	d      xs d}| j                  d
g       }| j                  dg       xs g }dd| ddd| ddd| ddd| dg}t	        j
                  |      }	d|	d   |	d   d}
 |       D ]  }	  ||
        d}|r|dd }g }|D ]  }t        |t              s|j                  dd      }|j                  d      xs dj                         }|dk(  r|j                  d|        c|dk(  si|j                  d|dd  d        |rdj                  |      nd}|s|s	dd g d!g d"d#S dj                  t	        j                  d$d%&            }|j                  | d'      }|j                  d(      }d}|rg }t        |d)      D ]k  \  }}|j                  d*| d+|d,           |j                  d-      xs |j                  d.d      }|r|j                  d/|        |j                  d       m dj                  |      }d0| d1|r|nd2 d3|r|nd4 d5|rd6| d7nd d8|rd9nd d:| d;| d<| d=|rPd>t        d?      z   t        d?      j                  t        |d)      D cg c]  \  }}d@| dA|d,    dB c}}      z   nd dC}	 t!        j"                  |d|D       d{   }|sdE}t$        j&                  j                  t(        dF      }t%        j*                  |dGH       ddl}|j                  dI      }t-        j.                  dJdK|      }| dK| dL}t$        j&                  j                  ||      } t1        ||| M      }!g }"|!rt$        j&                  j3                  |!      rt5        j                  dN      }#|# dO| }$|"j                  dP| dL|$||dQ       	 ddRlm}%m}&m}'  |&|       d{   }(t?        dStA        |(       dT|(        d})d}*d}+ |'|       d{   },|,rB|,j                  dU      r|,dU   })|,j                  dV      r|,dV   }*|,j                  dW      r|,dW   }+|)r|*r|+s|rtC        |      D ]  }-t        |-t              s|-j                  d      dk(  s)|-j                  dd      }|)s7t-        jD                  dX|      }.|.r|.jG                  d)      j                         })|*rwt-        jD                  dY|      }/|/s|/jG                  d)      j                         }* t?        dZ|) d[|* d\|+ d]|          |%| |(|)|*|+       nd_}2||2z  }tO        |       d{   }3|||"d!|3d`daS # t        $ r Y w xY wc c}}w 7 7 7 p# t        $ r5}0t?        d^tI        |0              ddl%}1|1jM                          Y d}0~0td}0~0ww xY w7 m# t        $ rI}0dbtI        |0       dbtI        |0       g d!dcdcdddededdgtI        |0      dbtI        |0       dfcY d}0~0S d}0~0ww xY ww)gu(   
    步骤二：生成报告文本
    r   rP   Nr>   rd   r?   r   r<   r;   r=   rA   u   ✍️ 生成报告文本中...u   报告标题: r[   u   🎯 正在撰写报告...u   📋 构建报告中...u   📝 汇总生成报告...r^   r\   r]   r_   r0   rR   rS   rT   rU   rV   rW   r   rY   rZ   u_   【无法生成报告】

缺少历史对话信息和用户输入，请先进行相关对话。rD   u'   缺少历史对话信息和用户输入)r@   rB   rC   rE   rF   rG   ABCDEFGHIJKLMNOPQRSTUVWXYZ   )kz-%Y-%m-%d-%H%Mz%Y-%m-%d %H:%Mr   u   图片u   ：r   r   descriptionu   识别结果：u   
<role>
你是一名专业的报告编写专家。
你的任务是根据用户需求和历史对话生成一份正式的报告。
</role>

<user_requirement>
z%
</user_requirement>

<report_theme>
u   根据内容自动确定z$
</report_theme>

<history_context>
u   （无历史对话上下文）z
</history_context>

z<user_images>
z
</user_images>u  

<output_rules>

必须严格遵守以下规则：

1. 输出为 **正式报告文本**
2. **使用段落形式，如果需要表格，必须使用 Markdown 表格格式**
3. **输出内容必须基于历史对话信息，不得编造不实信息**
4. 不得输出解释说明
5. 所有内容使用完整中文句子
6. **【重要】每个段落首行必须缩进两个中文字符，使用两个全角空格"　　"开头，例如："　　这是段落内容。"**
7. 根据报告主题自动选择合适的报告结构，可以是分析报告、总结报告、调研报告等
8. **报告内容必须紧扣报告主题，确保内容相关性和连贯性**
uX   9. **报告中必须包含用户上传的图片信息，在相关部分引用图片URL**u  

</output_rules>

<title_format_rules>

**标题格式规范（必须严格遵守）：**

1. **报告主标题**：使用二级标题格式，即 `## **标题内容**`，例如：`## **智能运维系统项目总结报告**`
2. **章节大标题**：使用三级标题格式，即 `### **标题内容**`，例如：`### **一、项目概述**`
3. **小节标题**：使用四级标题格式，即 `#### **标题内容**`，例如：`#### **1. 项目背景**`
4. 所有标题必须加粗，使用 `**标题内容**` 格式
5. 标题前后各空一行

</title_format_rules>

<paragraph_format_rules>

**段落格式规范（必须严格遵守）：**

1. 每个段落必须以两个全角空格"　　"开头
2. 正确示例：
　　本项目旨在开发一套智能运维系统，用于提升企业IT运维效率。
　　系统采用微服务架构设计，支持高并发访问。
3. 错误示例（缺少缩进）：
本项目旨在开发一套智能运维系统。
4. 段落之间空一行

</paragraph_format_rules>

<report_template>

## **u   **

报告编号：u   
编制时间：u  

### **一、概述**

　　介绍背景与目的。

### **二、主要内容**

　　阐述核心问题与关键分析过程。

### **三、备品备件**

　　列出本次维修或操作涉及的备品备件的名称（如有机油滤芯、密封圈、螺栓、传感器等），不要输出表格。如果没有涉及备件，请写"无"。

### **四、结论**

　　总结结果并提出结论性观点。
u   - **附件图片：**
   u   ![图片z]()u   

</report_template>

<final_rule>
只输出完整报告正文，不要任何解释说明。每个段落首行必须使用"　　"（两个全角空格）缩进。所有标题必须使用对应级别的Markdown格式并加粗。
</final_rule>
)ra   rb   messagesu6   抱歉，当前无法生成报告，请稍后重试。created_wordT)exist_okz%Y%m%d_%H%M%Sz[\\/:*?"<>|]_z.docx)markdownr\   outputbase_urlz/api/download/download)r`   labelr   fileNamerS   )save_spare_parts_metadataextract_spare_parts_from_textextract_info_from_filenameu   [备件提取] 提取到 u    个备件: deviceship_number
fault_nameu$   设备[名称]*[：:]\s*([^\n,，]+)u   舷号[：:]\s*(\d+)u   [备件保存] 设备: u
   , 舷号: u
   , 故障: u
   , 文件: u   [备件提取错误] u"   

[注意] Word 文档生成失败u   报告生成完成)r@   rB   rC   rE   rF   __details__u   生成报告失败:    如何优化报告内容？r\   rS      有哪些改进建议？)r@   rB   rC   rE   rF   rG   r   )(re   rQ   timerf   ri   rj   r6   r1   rg   r   r$   rh   choicesstrftime	enumeratechrr   rk   ospath
parent_dirmakedirsr   subr   existsr   tools.fault_statisticsr   r   r   printr    reversedr!   r#   r2   	traceback	print_excgenerate_suggested_replies)4rN   rQ   r   r>   r?   r<   r=   rA   rp   rq   start_eventrs   rl   rm   rn   ro   rR   rS   random_lettersreport_numbercompile_timeimage_sectionimage_partsidximgr   rt   r@   word_dir	timestamp
safe_topic	file_nameoutput_pathword_resultrC   r   download_urlr   r   r   spare_partsr   r   r   	file_infomsgdevice_match
ship_matchrw   r   	error_msgsuggested_repliess4                                                       r+   generate_report_textr      sw     999^^<L99^R0LYY/4]		BRTV8W][]Nyy!3R8yy!3R8>B 4.Q]P^@_`.^L>;Z[+.8WX.^L>;Z[	O mmO4O$ )"9-K
 &'	[! ( O!#$'A!T"uuVR(55+1r88:6>LL9WI!67[(LL9WTc]O3!?@  /4$))E*>{" "F
 	
 WWV^^,HANONMM^$4N"CDM==!12LM!"2A6HCuCE
|<=ggi(FCGGM2,FG""_WI#>?r" 7 		+.    #= > ? $)I J K
 & +-// `p[uw x  y@ ^  ~ " HX3r7"SW\\clm}  @A  dB  3C  dBW_WZ\_XcU"SZLPQ3R  dB  3C  &D  D  ^`  a am]F~i
%DD%
 

 RK77<<
N;
Ht,MM/2	VVOS,?
!l!I;e4	ggll8Y7* 
 )+277>>+6$((4H&Z~i[ALNN"(>/#%& (& H  H$A+$NN1#k2B1C<P[}]^  
"<Y"GG	 }}X.!*8!4 }}]3&/&> }}\2%.|%<
[
'#+,<#=C)#t4F9R*-'')R*@'-3599=dfm3nL'31=1C1CA1F1L1L1N'213;RT[1\J'16@6F6Fq6I6O6O6Q $> /xz+jYcXddnozn{|})+{FKYcd ?I9$K"<["II '#" 1/
 	
}  		@ 3C
P O H2  &-c!fX67 ##%%& J  
1#a&:.s1vh7"7Dab4A[\! !V1#a&:
 	

s   C
YV "Y8AYE7YV0.Y*X V6D X V? V9/V? V<A.V? <V? AV? V? 8AV? <X X X Y 	V-)Y,V--	Y6X 9V? <V? ?	W=+W83X 8W==X 	Y>Y	Y
YYYrD   c                 P  K   d| dd  d}	 t        j                  |d       d{   }t        j                  d|t        j                        }|r|j                  d      }t        j                  |      }t        |t              rqt        |      dk\  rcg }|dd D ]I  }t        |t              sd	|v sd
|v s|j                  t        |d	         t        |d
         d       K t        |      dk(  r|S ddddddgS 7 # t        $ r}ddddddgcY d}~S d}~ww xY ww)u1   
    生成针对报告的建议回复问题
    u   
你是一个专业的报告助手。根据以下报告内容，生成两个用户可能关心的后续问题。

【报告内容】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与报告内容相关，能够帮助用户更好地理解或使用报告
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
)ra   rb   z\[.*\]r   r{   r\   rS   r   r   r   )r   rk   r   r!   r"   r#   r3   r4   r1   r5   r    rg   r$   r2   r6   )	rD   rt   answer
json_matchjson_strr   formatted_repliesreplyrw   s	            r+   r   r     sY      	F(
 ??
 
 YYy&"))<
!''*H $

8 4+T2s;L7MQR7R$&!.r2E!%.7e3C	UZHZ)00%(w%8'*5+;'<2  3 ()Q.,, 4@]^0=WX
 	
'
.  
3@]^0=WX
 	

sc   
D&D DB	D 2D 7D <=D 9D&:	D D&D 	D#	DD#D&D##D&c                     t        t              } | j                  dt               | j                  dt               | j                  t        d       | j                  dd       | j                  dt               | j                         S )u   创建通用报告工作流extract_infogenerate_text)	r   r:   add_noderx   r   add_edger	   r
   compile)graphs    r+   create_other_report_workflowr     sa    '(E	NN>#67	NN?$89	NN5.)	NN>?3	NN?C(==?r-   r;   r<   rE   c                    K   t               }| ||t        |      dddg dg dg dd}|j                  |       d{   S 7 w)u  
    执行通用报告工作流（供主Agent / app.py 调用）

    Args:
        extracted_text: 主Agent合并后的文本描述
        combined_query: 用户问题
        history_message: 历史消息（JSON格式字符串）
        route_flag: 路由标识

    Returns:
        {
            "response": str,
            "actions": List[Dict[str, Any]],
            "route_flag": str,
            "suggestedReplies": List[Dict[str, Any]]
        }
    r   )r;   r<   r.   r=   r>   r?   r@   rA   rB   rC   rE   rF   rG   N)r   r8   ainvoke)r;   r<   r.   rE   appinitial_states         r+   run_other_report_workflowr     s\     . '
(C )(**?;'M  ]++++s   8A?A__main__c            
        K   t        j                  dddddddddgd      } t        dd	| 
       d {   }t        d       t        |d          t        d       |j	                  dg       D ]  }t        d|d    d|d            t        d       |j	                  dg       D ]3  }t        d|j	                  dd       d|j	                  dd              5 y 7 w)NrT   u'   我需要生成一份项目总结报告)rR   rS   rV   uQ   好的，我可以帮您生成项目总结报告，请提供相关项目信息。u   项目名称：智能运维系统，项目周期：2024年1月-2024年6月，主要成果：完成了系统架构设计和核心模块开发F)ensure_asciiu*   用户问题：请生成项目总结报告)r;   r<   r.   u   ====== 报告文本 ======rB   u   
====== 推荐问题 ======rF   z- r\   z: rS   u   
====== 操作按钮 ======rC   r   Unknownr`   )r3   dumpsr   r   rf   )r.   ru   r   actions       r+   testr   =  s	    **,UV$  2E  F kl 
 1 jG+
 
 	*+fZ !,-ZZ 2B7EBuW~&by)9(:;< 8,-jjB/FBvzz'956bFI9V8WXY 0
s   5C$C"B+C$)r   r   ),rK   asyncior   ri   typingr   r   r   r   r   langgraph.graphr   r	   r
   r   sysr   dirnameabspath__file__current_dirr   r$   modelsAPI.model_apir   re   r   utils.word_generatorr   configr   r3   r2   r,   r8   r:   rx   r   r   r   r   rH   r   runrM   r-   r+   <module>r      s    	  6 6 2 2 	 
ggoobggooh78WW__[)
SXXHHOOJ ) 7 5   C Dc3h,@ DC Dc3h,@ y ,Sn%5 Sn$sCx. SnlN
&6 N
4S> N
b4
S 4
T$sCx.5I 4
n"  "	),),), ), 	),
 
#s(^),X zZ6 GKK9 r-   	$賷xs3
    +yi5                        d Z ddlmZmZmZmZmZ ddlmZm	Z	m
Z
 ddlmZ ddlmZmZ ddlmZ ddlmZmZ ddlZddlZddlZ G d	 d
e      Zdedeeef   fdZededeeef   fd       Zdededeeeef      fdZededeeef   fd       Zd Z	 	 ddededededeeef   f
dZe dk(  r#ddlZddgZ!d Z" ejF                   e"              yy)u  
工作流：普通问答Agent（使用LangGraph）
输入：文本（转化后和原文本query）、图片描述、语音文本
步骤：
1. 使用RAG和GraphRAG检索相关信息
2. 生成回答
使用 OpenaiAPI 方法调用大模型，尽可能使用异步
    )	TypedDictOptionalDictAnyList)
StateGraphSTARTEND)none_schema)rag_search_toolgraph_rag_search)	OpenaiAPI)track_function_callsget_current_stream_handlerNc                       e Zd ZU dZeed<   eed<   eed<   eed<   eed<   eeeee	f         ed<   ee   ed<   eed	<   eeee	f      ed
<   eeee	f      ed<   eed<   y)QAStateu   普通问答工作流状态extracted_textcombined_query
route_flaghistory_messagehistory_contextrag_search_resultgraph_search_resultresponseactionssuggestedReplieserror_messageN)
__name__
__module____qualname____doc__str__annotations__r   r   r   r        E/storage01/home/cr/projects/wx_app_agent/app/workflows/workflow_qa.pyr   r      sy    %O  T#s(^ 455!#& M$sCx.!!4S>**r%   r   statereturnc                    ddl }| j                  dd      xs d}d}|r	  |j                  |      }t        |t              rt        |      dkD  rg }|D ]c  }t        |t              s|j                  dd      }g }|r|j                  |        |s?ddj                  |      z   }	|j                  |	       e |rdj                  |d	d       }d
|iS d
|iS # t        $ r}
Y d}
~
d
|iS d}
~
ww xY w)u   
    知识问答步骤：获取问答类历史信息
    问答工作流只关注历史问答记录，用于提供上下文
    r   Nr    contentu   [历史问答]

z

r   )
jsongetloads
isinstancelistlendictappendjoin	Exception)r'   r.   history_textr   history_datahistory_partshistory_itemr+   
text_partsentryes              r&   get_qa_history_contextr?   .   s   
 99.39rLO	%4::l3L,-#l2Ca2G "$0L!,5"."2"29b"A &(
"&--	;%$6:9N$NE)007 %1 !&,kk-2D&EO ////  	//	s   AC (*C =C 	C.)C.c                   K   d}| j                  d      dk(  rd}| j                  dd      }	 |r"t        j                  ||dd       d{   }n t        j                  |dd	       d{   }t        j                  |dd	       d{   }t	        |t
              r|ng t	        |t              r|d
S dd
S 7 p7 Q7 3# t        $ r}g ddt        |       dcY d}~S d}~ww xY ww)uI   
    进行文本知识检索和图谱知识检索（异步版本）
    Nr   rules   r   r*   
   )querykb_idtop_k)rD   rF   )r   r   u   检索失败: )r   r   r   )r/   r   ainvoker   r1   r2   r"   r7   )r'   rE   r   rag_resultsgraph_resultsr>   s         r&   search_rag_and_graphrJ   U   s    
 Eyy') YY/4N
 / 7 7'9 ! K !0 7 7'9 ! K
 /66#8
   1;;0MSU4>}c4R=
 	
XZ
 	
!
  
!##%-c!fX6
 	

sv   +C+C B= C -B?.C C*C 8C+9C <C+=C ?C C 	C(C#C(C+#C((C+answerquestionc                 V  K   d| d| dd  d}	 t        j                  |d       d{   }t        j                  d|t        j                        }|r|j                  d      }t        j                  |      }t        |t              rqt        |      d	k\  rcg }|dd	 D ]I  }t        |t              sd
|v sd|v s|j                  t        |d
         t        |d         d       K t        |      d	k(  r|S ddddddgS 7 # t        $ r}	ddddddgcY d}	~	S d}	~	ww xY ww)uc   
    生成针对问答结果的建议回复问题
    使用大模型生成两个相关问题
    u   
你是一个专业的工业设备问答助手。根据以下问答内容，生成两个用户可能关心的后续问题。

【用户问题】
u   

【回答内容】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与当前问答内容相关，能够帮助用户进一步了解相关信息
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
modelz\[.*\]r      titler+   )rQ   r+   u-   这个设备的具体工作原理是什么？u!   还有哪些相关的知识点？)r   open_api_chat_without_thinkingresearchDOTALLgroupr.   r0   r1   r2   r3   r4   r5   r"   r7   )
rK   rL   promptresult
json_matchjson_strsuggested_repliesformatted_repliesreplyr>   s
             r&   generate_suggested_replies_qar^      sr    
 

   F.
 ??dSS YYy&"))<
!''*H $

8 4+T2s;L7MQR7R$&!.r2E!%.7e3C	UZHZ)00%(w%8'*5+;'<2  3 ()Q.,, F  SB  C9Fij
 	
+ T2  
 F  SB  C9Fij
 	

sc   D)D	 DB	D	 5D	 :D	 ?=D	 <D)=	D	 D)D	 		D&	D!D&D)!D&&D)c           
        K   | j                  dd      }| j                  dg       }| j                  dd      }| j                  dd      xs d}	 d}|rTg }|dd D ]9  }t        |t              s|j                  dd      }|s)|j                  |       ; d	j	                  |      }| j                  d
      dk(  rd}	nd}	|	d| d|rd| dnd d|r|nd d|r|nd d	z   }
t        j                  |
d       d{   }ddl} |j                  dd||j                        }|r|j                         nd}ddddg}t        ||       d{   }||d|dS 7 ^7 # t        $ r}d t        |       g g d!cY d}~S d}~ww xY ww)"u"   
    正在生成问答结果
    r   r*   r   r   r   N   textr,   r   rA   uK   你是一个专业的舰船修理法规、行业标准知识问答助手。u6   你是一个专业的工业设备知识问答助手。ud  请根据以下信息回答用户的问题。
        必须严格遵守：
        1) 不要修改知识库文本中出现的 URL 字符串内容（不得改/不得截断），如需引用直接原样粘贴；
        2) 不得编造或猜测知识库中没有的 URL / 图片链接；
        3) 如果在文档内容中看到图片URL、表格或公式，请在回答中**自然引用或转述其关键信息**，但不强制要求特定展示格式；
        4) 输出内容不要脱离输入的核心内容，不要遗漏输入提供的关键信息，也不要加入无关内容。

        用户问题：z


        u!   历史问答上下文：
        z	
        uK   
        检索到的相关信息：
        【RAG检索结果】
        u   无u3   
        
        【图谱检索结果】
        u   

        请基于以上信息，给出准确、专业的回答。如果有历史问答上下文，请结合历史对话内容理解当前问题。如果信息不足，请说明需要更多信息。
        rN   r   z<think>.*?</think>)flagsu   抱歉，无法生成回答。
regenerateu   重新生成qa)typelabeliconr   r   
result_tagr   u   生成回答失败: )r   r   r   )r/   r1   r4   r5   r6   r   rR   rS   subrU   stripr^   r7   r"   )r'   r   rH   rI   r   rag_textrag_text_partsitemra   
pre_promptrW   rK   rS   r   r[   r>   s                   r&   generate_answerrp      s    
 YY/4N))/4KII3R8Mii 126<"OF
N#BQdD)88FB/D&--d3	 (
 yy0H 99\"g-fJQJ # '' (	 		 	
$&	((	 5) *	 (U3 4	# . !??dSS 	-r6K#)/O
 %'
 #@"WW  1	
 	
' T" X  
.s1vh7 "
 	

sh   AFE  /E  A9E  =E>AE  E
E  FE  E   	F)F :F;F FFc                  d   t        t              } | j                  dt               | j                  dt               | j                  dt
               | j                  t        d       | j                  dd       | j                  dd       | j                  dt               | j                         S )u   创建普通问答工作流r?   rJ   rp   )
r   r   add_noder?   rJ   rp   add_edger	   r
   compile)workflows    r&   create_qa_workflowrv     s    '"H .0FG,.BC'9 e56.0FG,.?@'- r%   r   r   r   r   c                 n  K   t               }| |||ddddg g dd}	 |j                  |       d{   }|j                  d      rd|d    g dg dS |j                  dd      |j                  d	g       d|j                  d
g       dS 7 Y# t        $ r}dt	        |       g dg dcY d}~S d}~ww xY ww)u   
    执行普通问答工作流（统一接口）

    Args:
        extracted_text: 文本描述（统一的输入参数）
        history_message: 历史消息（目前只接收，不做处理）

    Returns:
        工作流执行结果
    r*   N)r   r   r   r   r   r   r   r   r   r   r   r   u#   普通问答工作流执行失败: rd   rh   r   r   r   )rv   rG   r/   r7   r"   )r   r   r   r   appinitial_statefinal_stater>   s           r&   run_qa_workflowr{   (  s     " 
C )( *!#M
KK66 ???+A+oB^A_`"$&	  $
B7"y"5 +0BB G	
 	
 7&  
=c!fXF "	
 	

sP   B5B B
!B B56B 	B5
B 	B2B-'B2(B5-B22B5__main__u   什么是主机？u   主机的作用是什么？c                  V  K   t        t        d      D ]  \  } }t        dd        t        d|         t        d        t        |       d {   }t        d       t        d|j	                  dd	              t        d
       t        |j	                  dd              y 7 Vw)N   r,   z<============================================================u   测试用例 )r   u   
执行结果:u   成功: successFu   
响应内容:r   u	   无响应)	enumerate
test_casesprintr{   r/   )i	test_textrX   s      r&   testr   t  s     %j!4LAyBvh- M!%&VH*)DDFO%HVZZ	59:;<O%&**Z56 5
 Es   AB)B'AB))r*   r*   )$r!   typingr   r   r   r   r   langgraph.graphr   r	   r
   pydantic_core.core_schemar   tools.function_toolr   r   modelsAPI.model_apir   utils.function_trackerr   r   asyncior.   rS   r   r"   r?   rJ   r^   rp   rv   r{   r   r   r   runr$   r%   r&   <module>r      s_   8 7 2 2 1 * S   	i *$0' $0d38n $0N (
g (
$sCx. (
 (
X;
 ;
s ;
tDQTVYQYNG[ ;
| O
 O
T#s(^ O
 O
f. 	=
=
=
 =
 	=

 
#s(^=
F z 	%J
7 GKK- r%   k3lx0;o
    6ViOQ                     @   s  d dl 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
mZmZ d dlZd dlZejejeZejeZeejvrGeje d dlmZ d dlmZ d dlmZ d dlmZ d dlZded	eeeef  fd
dZ ded	eeeef  fddZ!G dd deZ"de"d	eeef fddZ#de"d	eeef fddZ$ded	eeeef  fddZ%dd Z&			d%dededededeeeef  d	eeef fd d!Z'e(d"krd dl Z d#d$ Z)e *e)  dS dS )&    N)	TypedDictListDictAnyLiteral)
StateGraphSTARTEND)	OpenaiAPI)track_function_calls)generate_report_word)SERVER_CONFIGhistory_messagereturnc                 C   sV   | sg S zt | trt| n| }t |tr|dd W S g W S  ty*   g  Y S w )u   解析历史消息为列表N)
isinstancestrjsonloadslist	Exception)r   data r   $/app/workflows/workflow_qa_report.py_parse_history   s   r   textc           	      C   s   | sg S g }d}t || t j}|D ]6}d}| |}|dkr>| |t| d }t d|t j}|r>|d dd }|	||pDdd	 q|S )
u*   从文本中提取图片URL和描述信息z<https?://[^\s<>"{}|\\^`\[\]]+\.(?:png|jpg|jpeg|gif|bmp|webp) Nu{   (?:\*\*图片识别结果：\*\*|图片识别结果[：:]|识别结果[：:])\s*(.*?)(?=\n\n\n|\n\n[A-Za-z\u4e00-\u9fa5]|$)   ,  u   用户上传的图片)urlsummary)
refindall
IGNORECASEfindlensearchDOTALLgroupstripappend)	r   imagesurl_patternurlsr    r!   	url_index	after_urlresult_matchr   r   r   _extract_images_from_text    s,   

r2   c                   @   s   e Zd ZU dZeed< eed< eed< eeeef  ed< eeeef  ed< eeeef  ed< eed< eed	< eed
< eeeef  ed< e	d ed< eeeef  ed< eed< dS )HistoryQAAnalysisStateu!   历史问答分析工作流状态extracted_textcombined_queryr   history_messagesextracted_itemsextracted_imagesreport_titlereport_textresponseactions)r   report
route_flagsuggestedReplieserror_messageN)
__name__
__module____qualname____doc__r   __annotations__r   r   r   r   r   r   r   r   r3   >   s   
 r3   statec              
      sx  ddl m} | ddp| ddpd}| dg }| dd}t|}d}|rq|dd  }g }|D ]4}	t|	trg|	d	d}
|	d
pFd }|
dkrV|d|  q3|
dkrg|d|d d  d q3|rod|nd}|sw|rw|}ddt	| ddddt	| ddddt	| ddddt	| dddd t	| ddg}t
|}d!|d" |d# d$}| D ]}z|| W q ty   Y qw d%| d&|r|nd' d(}z9tj|d d)d*I d H }t|}t|tr|d+g }|d,d-}|d.g }nt|tr|ng }d-}g }W n ty. } zg }d-}g }W Y d }~nd }~ww |r4|n|}|||d/S )0Nr   get_all_callbacksr5   r   r4   r6   r   r   rolecontentuser	   用户：	assistant	   助手：   ...
u$   提取相关历史问答数据中...u   历史消息数: u   条titledetailsu&   🔍 正在分析历史对话内容...u
   共处理 u
    条消息u#   📝 解析历史问答信息中...u
   已加载 u    条历史记录u    📊 整理历史对话数据...u   当前历史消息: u    条u    🔑 提取对话关键信息...u   历史对话总数: function_executionrS   rT   typerS   rT   u   
你是一名情报分析与知识管理专家。
请从以下【用户输入】中抽取用于统计分析的结构化信息。

【用户输入】
u   

【历史对话上下文】
u	   （无）u  


【抽取规则】
输出一个JSON对象，包含以下字段：
- report_title：报告标题（根据历史对话内容生成一个简洁的标题，格式为"XXX故障处理报告"，不超过20个字）
- items：抽取记录数组，每条记录包含：
  - topic：问题主题（如 设备、系统、管理、流程、保障、训练 等）
  - key_entity：关键对象或名词
  - conclusion：结论 / 判断 / 回答要点
  - action_suggestion：建议或行动（若无可为空）
  - date：时间（若无法判断可为空）
- images：图片信息数组（仅当有用户上传图片时提取，每条记录包含）：
  - url：图片URL（直接从【用户上传图片信息】中提取）
  - summary：图片内容摘要（根据图片识别结果提炼关键信息，如设备类型、故障现象、异常情况等，不超过100字）

【输出要求】
1. 仅输出 JSON 对象
2. 不要附加任何解释
3. 如果没有图片信息，images字段返回空数组
T)querymodeljson_outputitemsr9      历史问答分析报告r,   )r7   r9   r8   )utils.function_trackerrH   getr2   r   dictr*   r+   joinr&   randomchoicer   r
   open_api_chat_without_thinkingr   r   r   )rF   rH   r5   r6   r   pre_extracted_imageshistory_contextrecentpartsmrI   rJ   loading_promptsselected_promptparent_eventcallbackpromptresultparsed_resultr7   r9   model_imagesefinal_imagesr   r   r   extract_analysis_itemsX   s   




rs   c           *         sN  ddl m} dd l}| dg }| dd}| ddp$| ddp$d}| d	g }| d
g }| dd}dtfdd}	|	|}
d|
dd|
dd|
dd|
dd|
dg}t|}d|d |d d}| D ]}z|| W qj ty{   Y qjw d}|r|dd  }g }|D ]4}t|t	r|dd}|dpd
 }|dkr|d|  q|dkr|d|d d   d! q|rd"|nd}|s|r|}|s|sdd#g d$g d%d&S dtjd'd(d)}|| d*}|d+}d}|r1g }t|d,D ]-\}}|d-| d.|d/   |d0p|d1d}|r&|d2|  |d qd"|}d3| d4| d5|r=|nd6 d7|rId8| d9nd d:|rQd;nd d<| d=| d>| d?|rud@tdA tdAdBdC t|d,D  nd dD}zvtj|d |dEI d H }|sdF}tjtdG}tj|dHdI tdJdK|} |  dL}!tj||!}"t|||"dM}#g }$|#rtj|#rtdN}%|% dO|! }&|$dP| dL|&|!|dQ ndR}'||'7 }t|I d H }(|||$d$|(dSdTW S  ty& }) z)dUt|) dUt|) g d$dVdVdWdXdXdWgt|)dUt|) dYW  Y d })~)S d })~)ww )ZNr   rG   r7   r9   r\   r5   r   r4   r6   r8   r   r   c                 S   s   | sdS t | tr| g} t | tsdS t }t }| D ]$}t |ts#q|d}|d}|r6|t| |r?|t| q|rMdt|dd nd}|r\dt|dd nd}d	t|  d
| d| S )u6   将抽取结果转为中文描述，兼容 list / dictu   未提取到有效分析数据u   分析数据格式异常topic
key_entityu   、N   u	   未识别u   识别主题 u    条，涉及主题：u   ；关键对象：)	r   r_   r   setr^   addr   r`   r&   )r[   topicsentitiesitemrt   entity
topic_textentity_textr   r   r   summarize_extracted_items   s*   




z@generate_analysis_report_text.<locals>.summarize_extracted_itemsu   📄 生成分析报告文本rR   u   ✍️ 正在撰写分析报告u#   📋 生成历史问答分析报告u   📝 构建分析报告结构u)   🎯 汇总历史问答数据生成报告rU   rS   rT   rV   r   rI   rJ   rK   rL   rM   rN   r   rP   rQ   ue   【无法生成分析报告】

缺少历史对话信息和用户输入，请先进行相关问答。r=   u'   缺少历史对话信息和用户输入)r:   r;   r<   r>   r?   r@   ABCDEFGHIJKLMNOPQRSTUVWXYZ   )kz-%Y-%m-%d-%H%Mz%Y-%m-%d %H:%Mr   u   图片u   ：r    r!   descriptionu   识别结果：u   
<role>
你是一名设备运维与故障分析报告编写专家。
你的任务是根据用户需求、历史对话和抽取信息生成一份正式的故障处理报告。
</role>

<user_requirement>
z(
</user_requirement>

<extracted_items>
z'
</extracted_items>

<history_context>
u   （无历史对话上下文）z
</history_context>

z<user_images>
z
</user_images>ug  

<output_rules>

必须严格遵守以下规则：

1. 输出为 **正式技术报告文本**
2. **使用段落形式，如果有表格生成，生成表格必须arkdown表格，不要html形式**
3. **如果给定结果在历史对话信息中没有，可以进行删除**
4. **输出内容必须严格按照历史对话信息内容进行生成，不得编造不实信息和不相干信息**
5. 不得输出解释说明
6. 不要使用列表符号
7. 所有内容使用完整中文句子。
8. **每个段落首行必须缩进，使用两个全角空格（　　）实现首行缩进两个中文字符的效果**
u^   9. **报告中必须包含用户上传的图片信息，在故障信息部分引用图片URL**z&

</output_rules>

<report_template>

u   

报告编号： u   
编制时间： u2  
事件类型： 设备故障诊断与处置

一、事件概述
　　简要说明故障发生背景、报警情况、系统影响以及运维团队启动排查流程的情况。

二、故障信息
　　说明设备名称、型号、所属系统、报警时间、故障现象以及参与处置人员。
u   　　**附件图片：**
   c                 S   s&   g | ]\}}d | d|d  dqS )u   　　![图片z](r    )r   ).0idximgr   r   r   
<listcomp>e  s   & z1generate_analysis_report_text.<locals>.<listcomp>u  

三、故障排查过程
　　按照时间顺序描述排查步骤，包括：用户反馈 → 初步判断 → 数据分析 → 现场检查 → 故障确认。

四、维修措施
　　描述维修人员采取的具体维修步骤，包括设备停机、拆卸检查、更换部件、紧固连接、恢复运行和测试过程。

五、后续建议
　　提出预防类似故障的改进措施，例如：维护周期优化、知识库记录、巡检项目增加、技术培训等。

六、总结
　　总结本次故障原因、处理效果以及经验意义。

</report_template>

<final_rule>
只输出完整报告正文，不要任何解释说明。
</final_rule>
)rX   rY   messagesu<   抱歉，当前无法生成分析报告，请稍后重试。created_wordT)exist_okz[\\/:*?"<>|]_z.docx)markdownrS   outputbase_urlz/api/download/download)rW   labelr    fileNamerJ   u"   

[注意] Word 文档生成失败u   分析报告生成完成)r:   r;   r<   r>   r?   __details__u   生成分析报告失败:    如何优化问题分布？rS   rJ      有哪些改进建议？)r:   r;   r<   r>   r?   r@   r   )r]   rH   timer^   r   ra   rb   r   r   r_   r*   r+   r`   choicesstrftime	enumeratechrr
   rc   ospath
parent_dirmakedirsr"   subr   existsr   $generate_suggested_replies_qa_report)*rF   rH   r   r7   r9   r5   r6   r8   r   r   details_textri   rj   start_eventrl   re   rf   rg   rh   rI   rJ   random_lettersreport_numbercompile_timeimage_sectionimage_partsr   r   r!   rm   r:   word_dir
safe_topic	file_nameoutput_pathword_resultr<   r   download_url	error_msgsuggested_repliesrq   r   r   r   generate_analysis_report_text   s  "


	

"(*+23H


r   r=   c           	   
      s  d| dd  d}zet j|ddI dH }td|tj}|rf|d}t|}t|t	rft
|dkrfg }|dd D ]}t|tr\d	|v r\d
|v r\|t|d	 t|d
 d q=t
|dkrf|W S ddddddgW S  ty } zddddddgW  Y d}~S d}~ww )uo   
    生成针对历史问答分析报告的建议回复问题
    使用大模型生成两个相关问题
    u   
你是一个专业的数据分析助手。根据以下历史问答分析报告，生成两个用户可能关心的后续问题。

【分析报告】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与分析报告相关，能够帮助用户更好地理解或使用分析结果
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
)rX   rY   z\[.*\]r   r   rS   rJ   r   r   r   )r
   rc   r"   r'   r(   r)   r   r   r   r   r&   r_   r+   r   r   )	r=   rm   answer
json_matchjson_strr   formatted_repliesreplyrq   r   r   r   r     sB   




r   c                  C   sL   t t} | dt | dt | td | dd | dt |  S )Nextract_itemsgenerate_text)	r   r3   add_noders   r   add_edger   r	   compile)graphr   r   r   #create_history_qa_analysis_workflow  s   r   r   r4   r5   r>   r8   c                    s@   t  }| ||t|g |pg dddg dg dd}||I d H S )Nr   )r4   r5   r   r6   r7   r8   r9   r:   r;   r<   r>   r?   r@   )r   r   ainvoke)r4   r5   r   r>   r8   appinitial_stater   r   r   run_qa_report_agent  s"   r   __main__c               	      s   t jdddddddddgdd} tdd	| d
I d H }td t|d  td |dg D ]}td|d  d|d   q2td |dg D ]}td|dd d|dd  qMd S )NrK   u*   我需要分析最近的历史问答数据)rI   rJ   rM   uQ   好的，我可以帮您生成历史问答分析报告，请提供相关数据。u3   请重点关注设备故障和维护相关的内容F)ensure_asciiuB   用户问题：请重点关注设备故障和维护相关的内容)r4   r5   r   u,   ====== 历史问答分析报告文本 ======r;   u   
====== 推荐问题 ======r?   z- rS   z: rJ   u   
====== 操作按钮 ======r<   r   UnknownrW   )r   dumpsr   printr^   )r   rn   r   actionr   r   r   test8  s,   	&r   )r   r   N)+asyncior"   ra   typingr   r   r   r   r   langgraph.graphr   r   r	   r   sysr   dirnameabspath__file__current_dirr   r+   modelsAPI.model_apir
   r]   r   utils.word_generatorr   configr   r   r   r   r2   r3   rs   r   r   r   r   rA   r   runr   r   r   r   <module>   s\    
o  	9

OSx{o
    i                     @   s~   d Z ddlmZmZmZ ddlmZmZ ddlm	Z	m
Z
mZ 			ddeded	ed
edeeeef  deeef fddZdS )u?  
故障诊断 Agent 3：生成维修方案。
- 若传入 rag_state（由 fault_define 在舷号内检索到结果后传入）：直接基于已有检索结果生成方案。
- 若未传入（用户点击「确认调用相关数据进行分析」）：先按通用知识库检索，再生成方案并带兜底说明。
    )DictAnyOptional)FaultDiagnosisStateparse_and_normalize_input)parse_historyanalyze_and_generate_repair$analyze_and_generate_repair_fallback Nextracted_textcombined_queryhistory_message
route_flag	rag_statereturnc           
         s  t |}|p
| p
d}|rE|drt|dpg dks+|drE|dp(d rEt|I dH }|dd|dg d|d	g d
S | ||ddddddddg dd}t|I dH }	i ||	}|drndg dg d
S t|I dH }|dd|dg d|d	g d
S )u   
    执行 RAG 维修方案工作流。
    - rag_state 不为空且已有检索结果时：直接生成维修方案。
    - 否则：先抽取实体，再走通用知识库检索（fallback），生成方案并追加兜底提示。
    r
   rag_search_resultr   graph_search_resultNresponseactions
rag_definesuggestedReplies)r   r   
result_tagr   F)r   r   history_messagesship_numberdevice_namedevice_modelfaultneed_user_inputr   r   r   r   error_messager   uc   无法从对话中识别到完整的船号、设备与故障信息，请先补充信息后再试。)r   getlenstripr   r   r	   )
r   r   r   r   r   r   queryresultstatestep1_result r&   %/app/workflows/workflow_rag_define.pyrun_rag_define_workflow   sZ   


	



r(   )r
   r
   N)__doc__typingr   r   r   "workflows.workflow_fault_diagnosisr   r   workflows.workflow_fault_commonr   r   r	   strr(   r&   r&   r&   r'   <module>   s(    

dM*x8So
    xiZ                     @   s  d Z ddlZddlmZmZmZmZmZmZ ddl	m
Z
mZm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 ejejeZejeZeejvrWeje ddlmZmZmZ ddlm Z  dd	l!m"Z" G d
d deZ#G dd deZ$e"de#dee%ef fddZ&e"de#dee%ef fddZ'e"de#dee%ef fddZ(de#dee%ef fddZ)de%de%de%deee%ef  fddZ*de#dee%ef fddZ+dd  Z,d!e%d"e%d#e%dee%ef fd$d%Z-e.d&krd'd( Z/e0e/  dS dS ))u  work_repair.py
工作流二：维修Agent（使用LangGraph）

统一接口说明：
- 输入：`extracted_text`（主Agent整理后的文本，可能包含故障诊断结果）
- 输出：`{"response": str, "buttons": List[Dict], "route_flag": str, "report_data": Dict}`

功能：
1. 从故障诊断结果或文本中识别设备和故障
2. 检索维修相关知识（RAG + GraphRAG）
3. 生成维修方案
4. 为生成维修报告准备数据（设备名、故障名、维修方案、检索结果等）
    N)	TypedDictLiteralOptionalDictAnyList)
StateGraphSTARTEND)datetime)	BaseModel)rag_search_toolgraph_rag_searchextract_device_and_fault)	OpenaiAPI)track_function_callsc                   @   s   e Zd ZU dZeed< eed< eed< eed< eed< eeeef  ed< e	ed< ee
eeef   ed	< ee ed
< eed< eed< eed< eed< e
eeef  ed< ed ed< e
eeef  ed< eeef ed< eed< dS )RepairStateu2   维修工作流状态（与主Agent对接版本）extracted_textcombined_queryhistory_messagedevice_name
fault_namedevice_fault_resultneed_user_inputrag_search_resultgraph_search_resultrag_contextgraph_contextrepair_planresponseactions) repairreport
result_tagsuggestedRepliesreport_dataerror_messageN)__name__
__module____qualname____doc__str__annotations__r   r   r   boolr   r    r/   r/   !/app/workflows/workflow_repair.pyr   '   s(   
 r   c                   @   s&   e Zd ZU eed< dZee ed< dS )HistoryMessagecontentNr$   )r(   r)   r*   r,   r-   r$   r   r/   r/   r/   r0   r1   J   s   
 r1   statereturnc              
   C   sf  |  ddpd}|  ddpd}g }|rcz<t|}t|trOt|dkrO|dd }|D ]!}t|trN| dd}| dd}|rG|| |rN|| q-W n tyb }	 zW Y d}	~	nd}	~	ww |rjd		|nd}
d}d}d}zd
|
v s{d|
v r|

d	}|D ]/}| }|d
s|dr|
ddd  }q|ds|dr|
ddd  }q|r|rt|o| }t|o| }|o| }||d}||||dW S t|
r|d	 |
 n|dddpi }| dpd }| dpd }t|}t|}|o	| }||||dW S  ty2 }	 zdddddt|	 dW  Y d}	~	S d}	~	ww )u   
    维修方案阶段 一：从历史对话中识别设备与故障
    优先从历史记录中提取（如果文本中包含"设备："、"故障："等关键词），
    否则使用 extract_device_and_fault 工具进行识别
    r   r!   r   r   Nr2   
user_query
	   设备：u   故障u   设备名称：u   ：   u   故障类型：	   故障：)devicefault)r   r   r   r   )
user_inputrag_textgraph_rag_textr<   r=   Tu   识别设备和故障失败: )r   r   r   r   r'   )getjsonloads
isinstancelistlendictappend	Exceptionjoinsplitstrip
startswithr.   r   invoker,   )r3   r   history_texthistory_messageshistory_datarecent_historyhistory_itemr2   r6   ehistory_contextr   r   r   linesline
has_device	has_faultr   resultr/   r/   r0   identify_device_and_faultQ   s   





	r[   c              
      s  |  ddpd}|  ddpd}|  ddpd}|s|r.| d| d}d| d| }n| d}|}d	d
lm} dddt  d}| D ]}z|| W qI tyZ   Y qIw z`t|dd}	t	|dd}
t
|	|
I dH \}}d}g }t|tr|}g }|D ]}t|tr| dd}|r|d|  qd|}|t|tr|nd|t|tr|dW S ddW S  ty } zg ddddt| dW  Y d}~S d}~ww )u   
    维修方案阶段二：并进行文本知识检索和图谱知识检索
    - 若已识别出设备和故障，则以"设备 + 故障"为检索关键词
    - 否则退化为使用 extracted_text 作为检索关键词
    r   r!   r   r    u    维修方案及操作步骤u   设备:u	   , 故障:r   )get_all_callbacksfunction_executionu=   步骤 2：并行检索维修相关知识（RAG + GraphRAG）u   完成)typetitledetails	timestamp
   )querytop_kNtextz- r7   )r   r   r   r   u   检索失败: )r   r   r   r   r'   )rA   utils.function_trackerr]   r   now	isoformatrI   r   ainvoker   asynciogatherrD   rE   rG   rH   rJ   r,   )r3   r<   r=   r   rd   graph_queryr]   parent_eventcallbackrag_task
graph_taskrag_resultsgraph_resultsr?   r   partsitemrf   rT   r/   r/   r0   retrieve_repair_knowledge   sj   





rv   c           	         s   |  drdd| d  iS |  dd}|  ddpd}|  ddp$d	}|  d
dp,d}|  ddp4d}d| d| d| d| d| d}ztj|dd}|rU| nd}d|iW S  tyw } zddt| dW  Y d}~S d}~ww )u:   
    故障诊断阶段三：正在生成诊断结果
    r'   r   u$   跳过生成维修方案，原因：r   r!   r      未知设备r      未明确故障r   u   无r   u   
你是一个专业的工业设备维修专家，请根据以下信息为用户生成一份结构化、可执行的维修方案。
检查生成结果中必须为正常文本，不能是markdown或html。

【用户问题】
u   

【设备信息】
设备：u   

【故障现象】
u3   

【知识库检索结果（非结构化RAG）】
u/   

【维修知识图谱结果（GraphRAG）】
u  

【输出要求】
1. 先简要判断可能的故障原因（列出 2~4 条）。
2. 按照"安全检查 → 诊断步骤 → 维修步骤 → 复测与验收"的顺序给出详细步骤。
3. 对每一步指出：需要的工具 / 注意事项 / 风险提示。
4. 若信息不足以给出明确维修方案，请说明不足之处，并提示用户需要补充哪些信息。
5. 输出格式要清晰，使用标题和列表，便于阅读和执行。
6.**图文结合**：如果检索到的信息中包含图片链接（如 ![](/api/v1/...) 或 ![title](url)），请务必将其保留在回答的相应位置。
7.**链接完整性**：严禁修改或缩减图片链接地址，必须保持原样输出。必须保证图片链接来自与rag原文，不能进行捏造修改。
NmodeluZ   抱歉，当前无法生成可靠的维修方案，请稍后重试或补充更多信息。u$   抱歉，生成维修方案失败。u   生成维修方案失败: )r   r'   )rA   r   open_api_chatrL   rI   r,   )	r3   r   r<   r=   rag_ctx	graph_ctxpromptanswerrT   r/   r/   r0   generate_repair_plan   s<   

r   c           
      C   s   |  ddpd}|  ddpd}|  ddpd}|  dg }|  ddp%d}|  ddp-d}|  ddp5d}|  d	dp=d}|||||||||  d
d	}	d|	iS )uk   
    步骤 4：整理维修报告所需的数据
    为生成维修报告准备完整的数据结构
    r   r!   r   r   r   r   r   r   r   r   )	r   r   r   r   r   r   r   original_textr   r&   )rA   )
r3   r   r   r   r   r   r   r   r   r&   r/   r/   r0   prepare_report_data-  s&   r   r   r<   r=   c              
      s"  d| d| d|  d}zgt jtj|ddI dH }td|tj}|rj|d}t	|}t
|trjt|d	krjg }|dd	 D ]}	t
|	tr`d
|	v r`d|	v r`|t|	d
 t|	d d qAt|d	krj|W S ddddddgW S  ty }
 zddddddgW  Y d}
~
S d}
~
ww )uc   
    生成针对维修方案的建议回复问题
    使用大模型生成两个相关问题
    u   
你是一个专业的工业设备维修助手。根据以下维修方案，生成两个用户可能关心的后续问题。

【设备信息】
设备：u   

【故障信息】
故障：u   

【维修方案】
u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与维修方案相关，能够帮助用户更好地理解或执行维修
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
Nry   z\[.*\]r      r`   r2   )r`   r2   u0   维修过程中需要注意哪些安全事项？u$   需要准备哪些工具和备件？)rk   	to_threadr   r{   researchDOTALLgrouprB   rC   rD   rE   rF   rG   rH   r,   rI   )r   r<   r=   r~   r   
json_matchjson_strsuggested_repliesformatted_repliesreplyrT   r/   r/   r0   generate_suggested_repliesK  sD   




r   c              
      s  |  ddpd}|  ddpd}|  dd}|  ddpd	}|  d
g }|  di }g d}|o4||v}|s9|sYdddd|p@d d|pFd dddddg
}	d|	g dg dS dd| d| d|g}
|r|
d |
d t|dd dD ] \}}t|tr| d d}|r|
| d!|dd"  d# q{d$d%d&d'd(d)d*dd+d$d,d-d.d(g}t|||I dH }d|
|d|dS )/u   
    步骤 5：整理统一输出给主Agent / 上层API
    - 统一返回：response / actions / result_tag / suggestedReplies（与fault_diagnosis格式一致）
    r   r!   rw   r   rx   r   Fr   u$   当前没有可用的维修方案。r   r&   )r!   u   设备	   未识别rw   u   未知u-   【需要更多信息以制定维修方案】u?   目前无法从描述中完整识别出设备和故障信息：u   - 当前识别的设备：r   u   - 当前识别的故障：u?   为便于生成准确的维修方案，请补充以下信息：u$   1. 设备的完整名称或型号；uW   2. 具体的故障现象（例如：报警代码、异常声音、运行状态等）；uB   3. 若方便，可提供现场照片或更详细的文字说明。r7   r"   r   r    r$   r%   u   【维修方案】r8   r;   u   【参考信息】N   r9   rf   z.    z...r2   u   生成维修报告u3   根据当前维修方案，为我生成维修报告repair_report)r_   labelrf   icon
regenerateu   重新生成)r_   r   r   u   转到装备保障分析参谋u]   根据当前的维修方案中所需的备品备件，查看库存备品备件是否充足。spare_parts_statistics)rA   rJ   rH   	enumeraterD   rG   r   )r3   r<   r=   r   r   r   r&   invalid_device_namesis_valid_deviceresponse_lines
resp_partsiru   rf   r    r   r/   r/   r0   generate_response  s|   		


r   c                  C   s   t t} | dt | dt | dt | dt | dt | t	d | dd | dd | dd | dd | dt
 |  S )u5   创建维修工作流（与主Agent对接的版本）r[   retrieve_knowledgegenerate_planr   r   )r   r   add_noder[   rv   r   r   r   add_edger	   r
   compile)workflowr/   r/   r0   create_repair_workflow  s   r   r   r   r   c              
      s  t  }i d| d|d|ddddddd	d
dddddddddddddg dddi dg ddi}z.||I dH }|drXd|d  g dg dW S |dd|dg d|dg dW S  ty } zdt| g dg dW  Y d}~S d}~ww )u}  
    执行维修工作流（供主Agent / app.py 调用）

    Args:
        extracted_text: 主Agent合并后的文本描述（可能包含故障诊断结果）

    Returns:
        {
            "response": str,
            "buttons": List[Dict[str, Any]],
            "route_flag": str,
            "report_data": Dict[str, Any],  # 维修报告所需的数据
        }
    r   r   r   r   r!   r   r   Nr   Fr   r   r   r   r   r   buttons
route_flagr&   r%   r'   u   维修工作流执行失败: r"   r   r    )r   rj   rA   rI   r,   )r   r   r   appinitial_statefinal_staterT   r/   r/   r0   run_repair_workflow  sx   	


	

r   __main__c                     s   d} t d t| dI d H }t d|d t d|d t d|d	 t d
t|di   d}t d t|dI d H }t d|d t d|d t d|d	 t d
t|di   d S )Nur   设备：中央空调冷却泵
故障类型：电机漏电保护器频繁跳闸

请给出详细的维修步骤。u1   
=== 测试用例1：包含故障诊断结果 ===)r   z
response:
r   z

actions:
r    z
result_tag:r$   z
report_data keys:r&   u`   中央空调冷却泵出现电机漏电保护器频繁跳闸，请给出详细的维修步骤。u&   

=== 测试用例2：普通文本 ===)printr   rA   rE   keys)
demo_text1result1
demo_text2result2r/   r/   r0   _testE  s   r   )1r+   rk   typingr   r   r   r   r   r   langgraph.graphr   r	   r
   sysosrB   r   r   pydanticr   pathdirnameabspath__file__current_dir
parent_dirrH   tools.function_toolr   r   r   modelsAPI.model_apir   rg   r   r   r1   r,   r[   rv   r   r   r   r   r   r   r(   r   runr/   r/   r/   r0   <module>   sD     
#`C6&C\"CmWĻ	xkH
    Soi5I              	          d Z ddlZddlmZmZmZmZmZmZ ddl	m
Z
mZmZ ddlZddlZddlZddlmZ ddlmZ ej&                  j)                  ej&                  j+                  e            Zej&                  j)                  e      Zeej&                  vrej&                  j3                  e       ddlmZmZmZ ddlmZ dd	l m!Z!  G d
 de      Z" G d de      Z#e!de"dee$ef   fd       Z%de"dee$ef   fdZ&e!de"dee$ef   fd       Z'e!de"dee$ef   fd       Z(e!de"dee$ef   fd       Z)d Z*e!de$de$dee$ef   fd       Z+e,dk(  rd Z- ej\                   e-              yy)u  work_repair.py
工作流二：维修Agent（使用LangGraph）

统一接口说明：
- 输入：`extracted_text`（主Agent整理后的文本，可能包含故障诊断结果）
- 输出：`{"response": str, "buttons": List[Dict], "route_flag": str, "report_data": Dict}`

功能：
1. 从故障诊断结果或文本中识别设备和故障
2. 检索维修相关知识（RAG + GraphRAG）
3. 生成维修方案
4. 为生成维修报告准备数据（设备名、故障名、维修方案、检索结果等）
    N)	TypedDictLiteralOptionalDictAnyList)
StateGraphSTARTEND)datetime)	BaseModel)rag_search_toolgraph_rag_searchextract_device_and_fault)	OpenaiAPI)track_function_callsc                       e Zd ZU dZeed<   eed<   eed<   eed<   eeeef      ed<   e	ed<   ee
eeef         ed<   ee   ed	<   eed
<   eed<   eed<   eed<   e
eeef      ed<   ed   ed<   eeef   ed<   eed<   y)RepairStateu2   维修工作流状态（与主Agent对接版本）extracted_texthistory_messagedevice_name
fault_namedevice_fault_resultneed_user_inputrag_search_resultgraph_search_resultrag_contextgraph_contextrepair_planresponseactions) repairreport
result_tagreport_dataerror_messageN)__name__
__module____qualname____doc__str__annotations__r   r   r   boolr   r        E/storage01/home/cr/projects/wx_app_agent/workflows/workflow_repair.pyr   r   &   s    < O!$sCx.11  T#s(^ 455!#&  M$sCx.!!.// c3h r0   r   c                   ,    e Zd ZU eed<   dZee   ed<   y)HistoryMessagecontentNr%   )r(   r)   r*   r,   r-   r%   r   r/   r0   r1   r3   r3   G   s    L $J$r0   r3   statereturnc           	         | j                  dd      xs d}| j                  dd      xs d}|rTt        j                  |      }t        |       t        t	        |             t        |      D ]  }|d   dk(  s|d   } n nd}t               d}d}d}	 d|v sd	|v r|j                  d
      }|D ]  }	|	j                         }	|	j                  d      s|	j                  d      r$|	j                  dd      d   j                         }Y|	j                  d      s|	j                  d      s||	j                  dd      d   j                         } |rO|rMt        |xr |j                               }
t        |xr |j                               }|
xr | }||d}||||dS t        j                  ||z   ddd      xs i }|j                  d      xs dj                         }|j                  d      xs dj                         }t        |      }
t        |      }|
xr | }||||dS # t        $ r}dddddt        |       dcY d}~S d}~ww xY w)u   
    步骤 1：从统一文本中识别设备与故障
    优先从故障诊断结果中提取（如果文本中包含"设备："、"故障："等关键词），
    否则使用 extract_device_and_fault 工具进行识别
    r   r"   r   r%   fault_diagnosisr4   N	   设备：u   故障
u   设备名称：u   ：   u   故障类型：	   故障：)devicefault)r   r   r   r   )
user_inputrag_textgraph_rag_textr>   r?   Tu   识别设备和故障失败: )r   r   r   r   r'   )getjsonloadsprinttypereversedsplitstrip
startswithr.   r   invoke	Exceptionr,   )r5   r   history_texthistory_linefault_diagnosis_messager   r   r   linesline
has_device	has_faultr   resultes                  r1   identify_device_and_faultrW   N   s    YY/4:N99.39rLZZ-ld< !$\2LL),==(4Y(?' 3 !#	
!"KJ:
 11XAX5X+11$7Ezz|??;/4??CT3U"&**UA"6r":"@"@"BK__%674??;;W!%E1!5b!9!?!?!AJ  :kAk.?.?.ABJZ>J,<,<,>?I#-#;)<O &##  +(':#2	  *00(+BB 2
   	 	 zz(+1r88:jj)/R668
+&
$	)7i8 '$#).	
 	
  
#'#<SVHE
 	

s-   BH. .A5H. $B	H. .	I7I
IIc           	        K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|s|r| d| d}d| d| }n| d}|}d	d
lm} dddt        j                         j                         d} |       D ]  }	  ||        	 t        j                  |dd      }	t        j                  |dd      }
t        j                  |	|
       d{   \  }}d}g }t        |t              rV|}g }|D ]<  }t        |t              s|j                  dd      }|s)|j                  d|        > dj!                  |      }|t        |t"              r|nd|t        |t"              r|dS ddS # t        $ r Y w xY w7 # t        $ r}g ddddt#        |       dcY d}~S d}~ww xY ww)u   
    步骤 2：并行检索维修相关知识（RAG + GraphRAG）
    - 若已识别出设备和故障，则以"设备 + 故障"为检索关键词
    - 否则退化为使用 extracted_text 作为检索关键词
    r   r"   r   r    u    维修方案及操作步骤u   设备:u	   , 故障:r   )get_all_callbacksfunction_executionu=   步骤 2：并行检索维修相关知识（RAG + GraphRAG）u   完成)rG   titledetails	timestamp
   )querytop_kNtextz- r:   )r   r   r   r   u   检索失败: )r   r   r   r   r'   )rC   utils.function_trackerrZ   r   now	isoformatrM   r   ainvoker   asynciogather
isinstancelistdictappendjoinr,   )r5   r>   r?   r   r`   graph_queryrZ   parent_eventcallbackrag_task
graph_taskrag_resultsgraph_resultsrA   r   partsitemrb   rV   s                      r1   retrieve_repair_knowledgerw      s     YY}b)/RFIIlB'-2EYY/4:N(!E7">?xy8!"">?$ 9$P\\^--/	L &'	\" (!
"**UR+HI%--b.QR
+2>>(J+O%O"] k4( +!E#dD)88FB/Dr$[1	 $
 yy'H "34>}c4R=XZ#.8.L]	
 	
 SU	
 	
/  		 &P*  
!##%-c!fX6
 	

s   BGF!G$A	F -F.4F #F 8AF GF G	FGFGF 	G'G :G;G GGc           	        K   | j                  d      r
dd| d    iS | j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d
}| j                  dd      xs d
}d| d| d| d| d	}	 t        j                  |d      }|r|j                         nd}d|iS # t        $ r}ddt        |       dcY d}~S d}~ww xY ww)u?   
    步骤 3：调用大模型，生成维修方案文本
    r'   r   u$   跳过生成维修方案，原因：r   r"      未知设备r      未明确故障r   u   无r   u   
你是一个专业的工业设备维修专家，请根据以下信息为用户生成一份结构化、可执行的维修方案。

【设备信息】
设备：u   

【故障现象】
u3   

【知识库检索结果（非结构化RAG）】
u/   

【维修知识图谱结果（GraphRAG）】
u  

【输出要求】
1. 先简要判断可能的故障原因（列出 2~4 条）。
2. 按照"安全检查 → 诊断步骤 → 维修步骤 → 复测与验收"的顺序给出详细步骤。
3. 对每一步指出：需要的工具 / 注意事项 / 风险提示。
4. 若信息不足以给出明确维修方案，请说明不足之处，并提示用户需要补充哪些信息。
5. 输出格式要清晰，使用标题和列表，便于阅读和执行。
N)modeluZ   抱歉，当前无法生成可靠的维修方案，请稍后重试或补充更多信息。u$   抱歉，生成维修方案失败。u   生成维修方案失败: )r   r'   )rC   r   open_api_chatrJ   rM   r,   )r5   r>   r?   rag_ctx	graph_ctxpromptanswerrV   s           r1   generate_repair_planr      s#    
 yy!A%BXAYZ
 	
 YY}b);^FIIlB'<+<Eiir*3eG		/2.7%I
     		 
  F,
((t<#)  0Lv&& 
A9#a&B
 	

s6   BC.B5 4C5	C>CCCCCc                    | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dg       }| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  d	d      xs d}||||||||| j                  d
      d	}	d|	iS )uk   
    步骤 4：整理维修报告所需的数据
    为生成维修报告准备完整的数据结构
    r   r"   r   r   r   r   r   r   r   r   )	r   r   r   r   r   r   r   original_textr   r&   )rC   )
r5   r   r   r   r   r   r   r   r   r&   s
             r1   prepare_report_datar     s     ))M2.4"K<,2J))M2.4"K		"5r:))$92>D"))M2.4"KIIor28bMYY/4:N # ".2"&'$yy)>?
K ;''r0   c           
         | j                  dd      xs d}| j                  dd      xs d}| j                  dd      }| j                  dd      xs d	}| j                  d
g       }| j                  di       }g d}|xr ||v}|s|s/dddd|xs d d|xs d dddddg
}	dj                  |	      g ddS dd| d| d|g}
|ry|
j                  d       |
j                  d       t        |dd d      D ]E  \  }}t	        |t
              s|j                  d d      }|s,|
j                  | d!|dd"  d#       G d$d%d&d'd(d)d*dd+g}dj                  |
      |ddS ),u   
    步骤 5：整理统一输出给主Agent / 上层API
    - 统一返回：response / actions / result_tag / report_data（与fault_diagnosis格式一致）
    r   r"   ry   r   rz   r   Fr   u$   当前没有可用的维修方案。r   r&   )r"   u   设备	   未识别ry   u   未知u-   【需要更多信息以制定维修方案】u?   目前无法从描述中完整识别出设备和故障信息：u   - 当前识别的设备：r   u   - 当前识别的故障：u?   为便于生成准确的维修方案，请补充以下信息：u$   1. 设备的完整名称或型号；uW   2. 具体的故障现象（例如：报警代码、异常声音、运行状态等）；uB   3. 若方便，可提供现场照片或更详细的文字说明。r:   r#   r    r!   r%   u   【维修方案】r9   r=   u   【参考信息】N   r;   rb   z.    z...r4   u   生成维修报告u3   根据当前维修方案，为我生成维修报告repair_report)rG   labelrb   icon
regenerateu   重新生成)rG   r   r   )rC   rm   rl   	enumerateri   rk   )r5   r>   r?   r   r   r   r&   invalid_device_namesis_valid_deviceresponse_lines
resp_partsirv   rb   r!   s                  r1   generate_responser   9  s    YY}b);^FIIlB'<+<Eii 159O))M2.X2XK		"5r:))M2.K QC/C!CO o;M()>;(?@()=+(>?M2eP
 		.1"
 	
 	
F8
E7
J "./ !22A!6:GAt$%xx+%%2d4Cj\&=>	 ; )I#		
 !#	
%G IIj) r0   c                     t        t              } | j                  dt               | j                  dt               | j                  dt
               | j                  dt               | j                  dt               | j                  t        d       | j                  dd       | j                  dd       | j                  dd       | j                  dd       | j                  dt               | j                         S )u5   创建维修工作流（与主Agent对接的版本）rW   retrieve_knowledgegenerate_planr   r   )r	   r   add_noderW   rw   r   r   r   add_edger
   r   compile)workflows    r1   create_repair_workflowr     s    +&H13LM*,EFo';<+-@A)+<=e8913GH*O<o'<=+-@A)3/r0   r   r   c                   K   t               }i d| d|dddddddd	d
ddddddddddddg dddi dd}	 |j                  |       d{   }|j                  d      rd|d    g ddS |j                  dd      |j                  dg       ddS 7 G# t        $ r}dt	        |       g ddcY d}~S d}~ww xY ww)u}  
    执行维修工作流（供主Agent / app.py 调用）

    Args:
        extracted_text: 主Agent合并后的文本描述（可能包含故障诊断结果）

    Returns:
        {
            "response": str,
            "buttons": List[Dict[str, Any]],
            "route_flag": str,
            "report_data": Dict[str, Any],  # 维修报告所需的数据
        }
    r   r   r   r"   r   r   Nr   Fr   r   r   r   r   r    buttons
route_flagr&   r'   u   维修工作流执行失败: r#   r   r!   )r   rf   rC   rM   r,   )r   r   appinitial_statefinal_staterV   s         r1   run_repair_workflowr     st      !
"C"."/" 	r" 	b	"
 	t" 	5" 	T" 	t" 	r" 	" 	r" 	B" 	2" 	b" 	r"  	!"M$
KK66???+;K<X;YZ&  $
B7"y"5"
 	
 7   
7Ax@"
 	

sS   =C B B B 5C6%B CB 	C'B>8C9C>CC__main__c            	        K   d} t        d       t        |        d {   }t        d|j                  d             t        d|j                  d             t        d|j                  d	             t        d
t        |j                  di       j	                                      d}t        d       t        |       d {   }t        d|j                  d             t        d|j                  d             t        d|j                  d	             t        d
t        |j                  di       j	                                      y 7 /7 w)Nur   设备：中央空调冷却泵
故障类型：电机漏电保护器频繁跳闸

请给出详细的维修步骤。u1   
=== 测试用例1：包含故障诊断结果 ===)r   z
response:
r    z

actions:
r!   z
result_tag:r%   z
report_data keys:r&   u`   中央空调冷却泵出现电机漏电保护器频繁跳闸，请给出详细的维修步骤。u&   

=== 测试用例2：普通文本 ===)rF   r   rC   rj   keys)
demo_text1result1
demo_text2result2s       r1   _testr     s
    %

 	BC+:FFmW[[45ngkk)45ow{{<89#T'++mR*H*M*M*O%PQ x
89+:FFmW[[45ngkk)45ow{{<89#T'++mR*H*M*M*O%PQ G Gs#   EEB$EEB
EE)/r+   rg   typingr   r   r   r   r   r   langgraph.graphr	   r
   r   sysosrD   r   pydanticr   pathdirnameabspath__file__current_dir
parent_dirrl   tools.function_toolr   r   r   modelsAPI.model_apir   rc   r   r   r3   r,   rW   rw   r   r   r   r   r   r(   r   runr/   r0   r1   <module>r      s    @ @ 2 2 
 	   ggoobggooh78WW__[)
SXXHHOOJ 
 * 7) B%Y % T
[ T
T#s(^ T
 T
p@
; @
4S> @
F ,
k ,
d38n ,
 ,
^ ({ (tCH~ ( (< L[ LT#s(^ L Lb, 9
c 9
3 9
4PSUXPX> 9
 9
| zR0 GKK3 r0   ៹xA&o
    s5wih                     @   s  d Z ddlZddlZddlZddlmZmZmZmZm	Z	m
Z
 ddlmZmZmZ ddlZddlZejejeZejeZeejvrKeje ddlmZ ddlmZ ddlmZ ddlmZm Z m!Z! dd	l"m#Z# G d
d deZ$de$dee%e	f fddZ&ede$dee%e	f fddZ'ede$dee%e	f fddZ(ede$dee%e	f fddZ)ede$dee%e	f fddZ*de%de%de%de
ee%e	f  fddZ+de$dee%e	f fddZ,dd  Z-d!e%d"e%dee%e	f fd#d$Z.d%d& Z/e0d'kre1e/  dS dS )(u  
工作流五：维修报告Agent

统一接口说明：
- 输入：`extracted_text`（主Agent整理后的文本，可能包含维修工作流的report_data JSON）
- 输出：`{"response": str, "actions": List[Dict], "result_tag": str}`

功能：
1. 从extracted_text中解析report_data（如果包含JSON格式的维修数据）
2. 提取设备、故障、维修方案等信息
3. 生成完整的维修报告（包括故障原因分析、维修步骤、备品备件、注意事项等）
4. 返回格式化的报告文本
    N)	TypedDictLiteralOptionalDictAnyList)
StateGraphSTARTEND)	OpenaiAPI)track_function_calls)generate_report_pdf)rag_search_toolgraph_rag_searchextract_device_and_fault)SERVER_CONFIGc                   @   s   e Zd ZU dZeed< eed< eeeef  ed< eed< eed< eed< eed< eed	< eed
< eed< eed< eed< e	eeef  ed< e
d ed< e	eeef  ed< eed< dS )ReportStateu   维修报告工作流状态extracted_texthistory_messagereport_datadevice_name
fault_namerepair_planrag_contextgraph_contextfault_reason_analysisspare_parts_listfinal_reportresponseactions) repairreport
result_tagsuggestedReplieserror_messageN)__name__
__module____qualname____doc__str__annotations__r   r   r   r   r    r,   r,   (/app/workflows/workflow_repair_report.pyr   '   s$   
 r   statereturnc                    s  |  ddpd}|  ddpd}d}d}d}d}g }z>|rWt|}t|trWt|dkrW|dd }	|	D ]!}
t|
trV|
 dd}|
 dd}|rO|| |rV|| q5W n	 tya   Y nw |rid		|nd}|r|
d	D ]%}| }|d
r|
ddd  }qr|dr|
ddd  }qr|rg d}|D ] t fdd|D r  } nq|s|sz!t|r|n|dddpi }|p| dd}|p| dd}W n	 ty   Y nw ||||dS )u   
    步骤 1：解析extracted_text，提取report_data
    支持两种格式：
    1. JSON格式的report_data（从维修工作流传递过来）
    2. 普通文本（尝试从中提取信息）
    r   r    r   Nr   icontent
user_query
)u	   设备：   设备名称：u   ：   )u	   故障：u   故障类型：u   故障名称：)u   维修方案u   维修步骤u   维修u   修复c                 3   s    | ]}| v V  qd S )Nr,   ).0keywordmsgr,   r-   	<genexpr>   s    z$parse_report_data.<locals>.<genexpr>)
user_inputrag_textgraph_rag_textdevicefault)r   r   r   r   )getjsonloads
isinstancelistlendictappend	Exceptionjoinsplitstrip
startswithanyr   invoke)r.   r   history_textr   r   r   r   history_messageshistory_datarecent_historyhistory_itemr0   r1   history_contextlinerepair_keywordsresultr,   r8   r-   parse_report_dataE   sv   






rX   c                    s  |  ddpd}|  ddpd}|  ddpd}|  ddp d}|s%|r6| d| d}d| d	| }n| d
}|}ddlm} dddd}| D ]}	z|	| W qL ty]   Y qLw z`t|dd}
t|dd}t|
|I dH \}}d}g }t	|t
r|}g }|D ]}t	|tr| dd}|r|d|  qd|}|t	|tr|nd|t	|tr|nd|||dW S  ty } zg ddd|||dt| dW  Y d}~S d}~ww )u#  
    报告生成阶段一：进行文本知识检索和图谱知识检索
    步骤 2：并行检索维修相关知识（RAG + GraphRAG）
    - 若已识别出设备和故障，则以"设备 + 故障"为检索关键词
    - 否则退化为使用 extracted_text 作为检索关键词
    r   r    r   r   r   u   发生ue    故障现象及其原因,可能原因包括部件老化、操作负载异常或环境因素影响。u   设备:u	   , 故障:u    维修方案及操作步骤r   )get_all_callbacksfunction_executionu=   步骤 2：并行检索维修相关知识（RAG + GraphRAG）u   完成)typetitledetails
   )querytop_kNtextz- r2   )rag_search_resultgraph_search_resultr   r   r   r   r   u   检索失败: )rb   rc   r   r   r   r   r   r%   )r@   utils.function_trackerrY   rH   r   ainvoker   asynciogatherrC   rD   rF   rG   rI   r*   )r.   r>   r?   r   r   r_   graph_queryrY   parent_eventcallbackrag_task
graph_taskrag_resultsgraph_resultsr<   rb   partsitemra   er,   r,   r-   retrieve_repair_knowledge   sr   




	rr   c           	         s,  |  ddpd}|  ddpd}|  ddpd}|  ddp d}|  ddp(d}|r5|d	v s5|r5|d
v r<d|||dS d| d| d|rG|nd d|rN|nd d|rU|nd d}ztj|dd}|rh| nd}||||dW S  ty } zdt| dt| |||dW  Y d}~S d}~ww )u   
    报告生成阶段二：生成故障原因分析
    基于设备、故障、维修方案等信息，生成深度的故障原因分析
    r   r       未知设备r      未明确故障r   r   r   rs   	   未识别r    )rt   rv   r    ul   无法生成故障原因分析：缺少设备或故障信息。请先执行故障诊断和维修工作流。)r   r   r   r   u   
你是一个专业的设备故障分析专家。请根据以下信息，生成一份详细的故障原因分析报告。

【设备信息】
设备名称：   

【故障现象】
u   

【维修方案参考】
   无u1   

【知识库参考信息】
RAG检索结果：
u   

GraphRAG检索结果：
u  

【⚠️ 图片处理核心要求】
1. **必须引用图片**：在“原因分析说明”或“故障现象描述”中，如果 RAG 检索结果包含相关的结构图（如燃油系统布置图等），请务必在正文合适位置引用该图片。
2. **链接绝对不变**：严禁对图片 Markdown 链接（例如 ![](/api/v1/...)）进行任何修改，必须原样保留。
3. **图文解释**：引用图片时，应结合图片展示的结构（如管路、阀门位置）来增强文字分析的说服力。

【报告输出结构】
请生成一份结构化的故障原因分析报告：
1. **故障现象描述**：详细描述故障的具体表现。
2. **可能原因分析**：列出 3-5 个可能的故障原因，按可能性从高到低排序。
3. **根本原因判断**：基于维修方案和知识库信息，判断最可能的根本原因。
4. **原因分析说明（重点引用图片）**：对根本原因进行深入分析，说明其演变逻辑。在此部分**插入知识库中的相关图片链接**，并结合图片进行说明。
5. **预防建议**：基于原因分析，提出针对性的预防建议。

请使用清晰的标题和列表格式，确保报告专业、逻辑严密、图文并茂。
Nmodelu!   无法生成故障原因分析。u    生成故障原因分析失败: )r   r%   r   r   r   r@   r   open_api_chatrK   rH   r*   )	r.   r   r   r   r   r   promptanalysisrq   r,   r,   r-   generate_fault_reason_analysis   sP   



'r   c           	         s   |  ddpd}|  ddpd}|  ddpd}|  ddp d}|  ddp(d}|r/|d	v r6d
|||dS d| d| d|rA|nd d|rH|nd d|rO|nd d}ztj|dd}|rb| nd}||||dW S  ty } zdt| dt| |||dW  Y d}~S d}~ww )u   
    报告生成阶段三：生成备品备件清单
    基于维修方案和故障信息，生成所需的备品备件清单
    r   r    rs   r   rt   r   r   r   ru   u6   无法生成备品备件清单：缺少设备信息。)r   r   r   r   u   
你是一个专业的设备维修备件管理专家。请根据以下信息，生成一份详细的备品备件清单。

【设备信息】
设备名称：rw   u   

【维修方案】
rx   u   

【参考知识】
u   
GraphRAG检索结果：
u  


【输出要求】
请生成一份结构化的备品备件清单，包括：
1. **必需备件**：维修过程中必须更换或使用的备件（列出名称、规格、数量、用途）
2. **建议备件**：建议准备但可能不需要的备件（列出名称、规格、数量、用途）
3. **工具清单**：维修过程中需要的工具和设备
4. **材料清单**：维修过程中需要的辅助材料（如密封胶、润滑油等）

请使用表格或列表格式，确保清单清晰、完整、易于采购和使用。
Nry   u!   无法生成备品备件清单。u    生成备品备件清单失败: )r   r%   r   r   r   r{   )	r.   r   r   r   r   r   r}   
parts_listrq   r,   r,   r-   generate_spare_parts_list8  sP   



r   c                    s  |  ddpd}|  ddpd}|  ddpd}|  ddp d}|  ddp(d}|r/|d	v r6d
|||dS g }|d |d |d|  |d|  |d |ri|d || |d n|d |d |d |r|d || |d n|d |d |d |r|d || |d n|d |d |d |d |d |d |d |d |d d|}||||dS )uo   
    报告生成阶段四：生成最终维修报告
    整合所有信息，生成完整的维修报告
    r   r    rs   r   rt   r   r   r   ru   u   无法生成维修报告：缺少必要的设备或故障信息。请先执行故障诊断和维修工作流，获取完整的维修数据。)r   r   r   r   u   一、基本信息r3   u   故障现象：u   二、故障原因分析u!   （未生成故障原因分析）u   三、维修方案u   （未提供维修方案）u   四、备品备件清单u!   （未生成备品备件清单）u   五、注意事项uH   1. 维修前请确保设备已断电、断气、断水，确保安全。u?   2. 严格按照维修方案执行，注意安全防护措施。u6   3. 维修完成后，请进行功能测试和验收。u6   4. 如有疑问，请及时联系专业维修人员。r2   )r@   rG   rI   )r.   r   r   r   r   r   report_partsr   r,   r,   r-   generate_final_reportz  sf   
























r   r"   r>   r?   c              
      s*  d| d| d| dd  d}zgt jtj|ddI dH }td|tj}|rn|d	}t	|}t
|trnt|d
krng }|dd
 D ]}	t
|	trdd|	v rdd|	v rd|t|	d t|	d d qEt|d
krn|W S ddddddgW S  ty }
 zddddddgW  Y d}
~
S d}
~
ww )uc   
    生成针对维修报告的建议回复问题
    使用大模型生成两个相关问题
    u   
你是一个专业的工业设备维修报告助手。根据以下维修报告，生成两个用户可能关心的后续问题。

【设备信息】
设备：u   

【故障信息】
故障：u   

【维修报告】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与维修报告相关，能够帮助用户更好地理解或执行维修
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
ry   z\[.*\]r      r\   r0   )r\   r0   u   如何执行维修步骤？u   维修后如何验收？)rf   	to_threadr   r|   researchDOTALLgrouprA   rB   rC   rD   rE   rF   rG   r*   rH   )r"   r>   r?   r}   answer
json_matchjson_strsuggested_repliesformatted_repliesreplyrq   r,   r,   r-   !generate_suggested_replies_report  sD   





r   c                    sJ  |  ddpd}|  ddpd}|  ddpd}|o|dv}|sBd}|d7 }|d7 }|d	7 }|d
7 }|d7 }|d7 }|g dg dS tjtd}tj|dd t|||d}g }| dr| dd}	t d}
|
 d|	 }|d| d||	|d nd| dd }||7 }|dddd  t	|||I d!H }||d|dS )"us   
    步骤 5：整理统一输出给主Agent / 上层API
    - 统一返回：response / actions / result_tag
    r   r    r   r   ru   u    【无法生成维修报告】

u)   缺少必要的设备或故障信息。

u   请先执行以下步骤：
u7   1. 执行故障诊断工作流，识别设备和故障
u.   2. 执行维修工作流，生成维修方案
u5   3. 然后再次点击「生成维修报告」按钮

uK   或者，您可以直接提供包含设备和故障信息的文本描述。r"   r   r   r#   r$   created_pdfT)exist_ok)report_contentr   
output_dirsuccess	file_nameu   维修报告.pdfbase_urlz/api/download/downloadu   _维修报告.pdf)r[   labelurlfileNamer0   u   

[注意] PDF 生成失败：erroru   未知错误
regenerateu   重新生成)r[   r   iconN)
r@   ospathrI   
parent_dirmakedirsr   r   rG   r   )r.   r   r   r   has_valid_infor   pdf_dir
pdf_resultr   r   r   download_url	error_msgr   r,   r,   r-   generate_response  sd   	


	r   c                  C   s   t t} | dt | dt | dt | dt | dt | dt | 	t
d | 	dd | 	dd | 	dd | 	dd | 	dd | 	dt |  S )u;   创建维修报告工作流（与主Agent对接的版本）rX   retrieve_knowledgegenerate_fault_reasongenerate_spare_partsr   r   )r   r   add_noderX   rr   r   r   r   r   add_edger	   r
   compile)workflowr,   r,   r-   create_report_workflow]  s   r   r   r   c                    s   t  }| |ddddddddddg ddd}z.||I dH }|dr1d|d  g dg dW S |dd|d	g d|d
g dW S  tyb } zdt| g dg dW  Y d}~S d}~ww )uv  
    执行维修报告工作流（供主Agent / app.py 调用）

    Args:
        extracted_text: 主Agent合并后的文本描述（可能包含report_data JSON）
        history_message: 历史消息（JSON格式字符串）

    Returns:
        {
            "response": str,
            "actions": List[Dict[str, Any]],
            "result_tag": str,
        }
    Nr    r   r   r   r   r   r   r   r   r   r   r   r   r   r#   r%   r%   u#   维修报告工作流执行失败: r"   r   r   r   r$   )r   re   r@   rH   r*   )r   r   appinitial_statefinal_staterq   r,   r,   r-   run_repair_report_workflowv  sN   



r   c                     sb   t  } dtddddddgd dddddddddg ddd}| |I d H }t|d	  d S )
Nu   主机发生异常振动fault_diagnosisuC   设备名称：发动机
故障类型：运行异常，振动加剧)r#   r0   r   u'   建议检查轴承并更换磨损部件r    r   r   )r   rA   dumpsre   print)graphr   rW   r,   r,   r-   test  s.   r   __main__)2r)   rf   rA   r   typingr   r   r   r   r   r   langgraph.graphr   r	   r
   sysr   r   dirnameabspath__file__current_dirr   rG   modelsAPI.model_apir   rd   r   utils.pdf_generatorr   tools.function_toolr   r   r   configr   r   r*   rX   rr   r   r   r   r   r   r   r   r   r&   runr,   r,   r,   r-   <module>   sF     
XLMA&PBP@
kο
xUP
    (pimX              	          d Z ddlZddlZddlZddlmZmZmZmZm	Z	m
Z
 ddlmZmZmZ ddlZddlZej"                  j%                  ej"                  j'                  e            Zej"                  j%                  e      Zeej"                  vrej"                  j/                  e       ddlmZ ddlmZ ddlmZ ddlmZm Z m!Z! dd	l"m#Z#  G d
 de      Z$ede$dee%e	f   fd       Z&de$dee%e	f   fdZ'ede$dee%e	f   fd       Z(ede$dee%e	f   fd       Z)ede$dee%e	f   fd       Z*ede$dee%e	f   fd       Z+d Z,ede%de%dee%e	f   fd       Z-d Z.e/dk(  r ej`                   e.              yy)u  
工作流五：维修报告Agent

统一接口说明：
- 输入：`extracted_text`（主Agent整理后的文本，可能包含维修工作流的report_data JSON）
- 输出：`{"response": str, "actions": List[Dict], "result_tag": str}`

功能：
1. 从extracted_text中解析report_data（如果包含JSON格式的维修数据）
2. 提取设备、故障、维修方案等信息
3. 生成完整的维修报告（包括故障原因分析、维修步骤、备品备件、注意事项等）
4. 返回格式化的报告文本
    N)	TypedDictLiteralOptionalDictAnyList)
StateGraphSTARTEND)	OpenaiAPI)track_function_calls)generate_report_pdf)rag_search_toolgraph_rag_searchextract_device_and_fault)SERVER_CONFIGc                       e Zd ZU dZeed<   eed<   eeeef      ed<   eed<   eed<   eed<   eed<   eed	<   eed
<   eed<   eed<   eed<   e	eeef      ed<   e
d   ed<   eed<   y)ReportStateu   维修报告工作流状态extracted_texthistory_messagereport_datadevice_name
fault_namerepair_planrag_contextgraph_contextfault_reason_analysisspare_parts_listfinal_reportresponseactions) repairreport
result_tagerror_messageN)__name__
__module____qualname____doc__str__annotations__r   r   r   r   r        L/storage01/home/cr/projects/wx_app_agent/workflows/workflow_repair_report.pyr   r   '   s    %$sCx.))O  M$sCx.!!.// r.   r   statereturnc                 T   | j                  dd      xs d}| j                  dd      xs d}d}d}d}d}d}d}	 |rVt        j                  |      }	t        |	      D ]3  }
|
j                  d      }|
j                  dd      }|dk(  r|}|dv s2|}5 |r|j                  d	      D ]|  }|j                         }|j                  d
      r$|j                  dd      d   j                         }H|j                  d      sZ|j                  dd      d   j                         }~ |r|j                         }|sL|sJ	 t        j                  |ddd      xs i }|xs |j                  dd      }|xs |j                  dd      }||||dS # t        $ r Y w xY w# t        $ r Y "w xY w)u   
    步骤 1：解析extracted_text，提取report_data
    支持两种格式：
    1. JSON格式的report_data（从维修工作流传递过来）
    2. 普通文本（尝试从中提取信息）
    r   r"   r   Nr%   contentfault_diagnosis)r#   r   
)u	   设备：   设备名称：u   ：   )u	   故障：u   故障类型：u   故障名称：)
user_inputrag_textgraph_rag_textdevicefault)r   r   r   r   )
getjsonloadsreversed	Exceptionsplitstrip
startswithr   invoke)r0   r   history_textr   r   r   r   fault_diagnosis_messagerepair_messagehistoryitemtagr3   lineresults                  r/   parse_report_datarO   D   s    YY/4:N99.39rLKJKK
 !Njj.G )hh|,((9b1++.5+33%,N * +11$7D::<D?@"jj226<<>!TU!ZZq1"5;;=
 8 $**, :
	-445"$6   	  &AHb)AK#>vzz'2'>J #" "	 M  D  		s+   AF F ;A	F 	FF	F'&F'c                   K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|s|r| d| d}d| d	| }n| d
}|}ddlm} dddd} |       D ]  }		  |	|        	 t	        j
                  |dd      }
t        j
                  |dd      }t        j                  |
|       d{   \  }}d}g }t        |t              rV|}g }|D ]<  }t        |t              s|j                  dd      }|s)|j                  d|        > dj                  |      }|t        |t              r|nd|t        |t              r|nd|||dS # t        $ r Y w xY w7 # t        $ r!}g ddd|||dt        |       dcY d}~S d}~ww xY ww)u   
    步骤 2：并行检索维修相关知识（RAG + GraphRAG）
    - 若已识别出设备和故障，则以"设备 + 故障"为检索关键词
    - 否则退化为使用 extracted_text 作为检索关键词
    r   r"   r   r   r   u   发生ue    故障现象及其原因,可能原因包括部件老化、操作负载异常或环境因素影响。u   设备:u	   , 故障:u    维修方案及操作步骤r   )get_all_callbacksfunction_executionu=   步骤 2：并行检索维修相关知识（RAG + GraphRAG）u   完成)typetitledetails
   )querytop_kNtextz- r5   )rag_search_resultgraph_search_resultr   r   r   r   r   u   检索失败: )rZ   r[   r   r   r   r   r   r&   )r>   utils.function_trackerrQ   rB   r   ainvoker   asynciogather
isinstancelistdictappendjoinr+   )r0   r<   r=   r   r   rW   graph_queryrQ   parent_eventcallbackrag_task
graph_taskrag_resultsgraph_resultsr:   rZ   partsrK   rY   es                       r/   retrieve_repair_knowledgern      s     YY}b)/RFIIlB'-2EYY/4:N))M2.4"K(&  (M  Nxy8!"">?$ 9$PL
 &'	\" ('
"**UR+HI%--b.QR
+2>>(J+O%O"] k4( +!E#dD)88FB/Dr$[1	 $
 yy'H "34>}c4R=XZ#.8.L]RT!&
 	
/  		 &P0  

!##%!&-c!fX6	
 		


sz   BGFGA	F "F#4F F -AF G	FGFGF 	F>F93F>4G9F>>Gc                   K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|r
|d	v s|r|d
v rd|||dS d| d| d|r|nd d|r|nd d|r|nd d}	 t        j                  |d      }|r|j                         nd}||||dS # t        $ r*}dt        |       dt        |       |||dcY d}~S d}~ww xY ww)u   
    步骤 3：生成故障原因分析
    基于设备、故障、维修方案等信息，生成深度的故障原因分析
    r   r"      未知设备r      未明确故障r   r   r   rp   	   未识别r"   )rq   rs   r"   ul   无法生成故障原因分析：缺少设备或故障信息。请先执行故障诊断和维修工作流。)r   r   r   r   u   
你是一个专业的设备故障分析专家。请根据以下信息，生成一份详细的故障原因分析报告。

【设备信息】
设备名称：   

【故障现象】
u   

【维修方案参考】
   无u1   

【知识库参考信息】
RAG检索结果：
u   

GraphRAG检索结果：
u\  

【输出要求】
请生成一份结构化的故障原因分析报告，包括：
1. **故障现象描述**：详细描述故障的具体表现
2. **可能原因分析**：列出3-5个可能的故障原因，按可能性从高到低排序
3. **根本原因判断**：基于维修方案和知识库信息，判断最可能的根本原因
4. **原因分析说明**：对根本原因进行深入分析，说明为什么会导致该故障
5. **预防建议**：基于原因分析，提出预防类似故障的建议

请使用清晰的标题和列表格式，确保报告专业、详细、易于理解。
Nmodelu!   无法生成故障原因分析。u    生成故障原因分析失败: )r   r&   r   r   r   r>   r   open_api_chatrD   rB   r+   )	r0   r   r   r   r   r   promptanalysisrm   s	            r/   generate_fault_reason_analysisr|      s     ))M2.@.K<,A0AJ))M2.4"K))M2.4"KIIor28bM+)JJR\`j  oS  aS &T&$&	
 	
 }     ' (  ' (  U + ,#F<
**6>'/8>>#5X%-&$&	
 	
  
'GAx%P?AxH&$&
 	

s6   B D#1C D	DD=D>DDDc                   K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|r|d	v rd
|||dS d| d| d|r|nd d|r|nd d|r|nd d}	 t        j                  |d      }|r|j                         nd}||||dS # t        $ r*}dt        |       dt        |       |||dcY d}~S d}~ww xY ww)uw   
    步骤 4：生成备品备件清单
    基于维修方案和故障信息，生成所需的备品备件清单
    r   r"   rp   r   rq   r   r   r   rr   u6   无法生成备品备件清单：缺少设备信息。)r   r   r   r   u   
你是一个专业的设备维修备件管理专家。请根据以下信息，生成一份详细的备品备件清单。

【设备信息】
设备名称：rt   u   

【维修方案】
ru   u   

【参考知识】
u   
GraphRAG检索结果：
u  


【输出要求】
请生成一份结构化的备品备件清单，包括：
1. **必需备件**：维修过程中必须更换或使用的备件（列出名称、规格、数量、用途）
2. **建议备件**：建议准备但可能不需要的备件（列出名称、规格、数量、用途）
3. **工具清单**：维修过程中需要的工具和设备
4. **材料清单**：维修过程中需要的辅助材料（如密封胶、润滑油等）

请使用表格或列表格式，确保清单清晰、完整、易于采购和使用。
Nrv   u!   无法生成备品备件清单。u    生成备品备件清单失败: )r   r&   r   r   r   rx   )	r0   r   r   r   r   r   rz   
parts_listrm   s	            r/   generate_spare_parts_listr   &  sh     ))M2.@.K<,A0AJ))M2.4"K))M2.4"KIIor28bM+)JJ X&$&	
 	
 }     ' (  ' (U + ,F8
,,V4@
+5Z%%';^
 *&$&	
 	
  
"B3q6( K?AxH&$&
 	

s6   BD1C D	DC=7D8D=DDc                 ^  K   | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|r|d	v rd
|||dS g }|j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  d|        |j                  d|        |j                  d       |r4|j                  d       |j                  |       |j                  d       n3|j                  d       |j                  d       |j                  d       |r4|j                  d       |j                  |       |j                  d       n3|j                  d       |j                  d       |j                  d       |r4|j                  d       |j                  |       |j                  d       n3|j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  d       |j                  dt        d      j                  j	                         j                  d      z          |j                  d       dj                  |      }||||dS w) ub   
    步骤 5：生成最终维修报告
    整合所有信息，生成完整的维修报告
    r   r"   rp   r   rq   r   r   r   rr   u   无法生成维修报告：缺少必要的设备或故障信息。请先执行故障诊断和维修工作流，获取完整的维修数据。)r   r   r   r   z<============================================================u   设备维修报告u   【一、基本信息】r6   u   故障现象：u   【二、故障原因分析】u!   （未生成故障原因分析）u   【三、维修方案】u   （未提供维修方案）u   【四、备品备件清单】u!   （未生成备品备件清单）u   【五、注意事项】uH   1. 维修前请确保设备已断电、断气、断水，确保安全。u?   2. 严格按照维修方案执行，注意安全防护措施。u6   3. 维修完成后，请进行功能测试和验收。u6   4. 如有疑问，请及时联系专业维修人员。u   报告生成时间：datetimez%Y-%m-%d %H:%M:%Sr5   )r>   rc   
__import__r   nowstrftimerd   )r0   r   r   r   r   r   report_partsr   s           r/   generate_final_reportr   i  s     ))M2.@.K<,A0AJ))M2.4"K!II&=rBHbyy!3R8>B +)JJ l&$&	
 	
 L!,-! 23/+78/*67 <=12B<=?@B 67K(B679:B <=,-B<=?@B 23bcYZPQPQ!/*Z2H2Q2Q2U2U2W2`2`at2uuv!99\*L %" "	 s   L+L-c                    | j                  dd      xs d}| j                  dd      xs d}| j                  dd      xs d}|xr |dv}|s&d}|dz  }|dz  }|d	z  }|d
z  }|dz  }|dz  }|g ddS t        j                  j                  t        d      }t        j
                  |d       t        |||      }g }|j                  d      rI|j                  dd      }	t        j                   d      }
|
 d|	 }|j                  d| d||	|d       nd|j                  dd       }||z  }|j                  dddd        ||ddS )!us   
    步骤 5：整理统一输出给主Agent / 上层API
    - 统一返回：response / actions / result_tag
    r   r"   r   r   rr   u    【无法生成维修报告】

u)   缺少必要的设备或故障信息。

u   请先执行以下步骤：
u7   1. 执行故障诊断工作流，识别设备和故障
u.   2. 执行维修工作流，生成维修方案
u5   3. 然后再次点击「生成维修报告」按钮

uK   或者，您可以直接提供包含设备和故障信息的文本描述。r$   r    r!   r%   created_pdfT)exist_ok)report_contentr   
output_dirsuccess	file_nameu   维修报告.pdfbase_urlz/api/download/downloadu   _维修报告.pdf)rS   labelurlfileNamer3   u   

[注意] PDF 生成失败：erroru   未知错误
regenerateu   重新生成)rS   r   icon)	r>   ospathrd   
parent_dirmakedirsr   r   rc   )r0   r   r   r   has_valid_infor    pdf_dir
pdf_resultr!   r   r   download_url	error_msgs                r/   generate_responser     s    99^R06BL))M2.4"K<,2J !Y[8Y%YN7AA33NNEEMMaa !"
 	
 ggll:}5GKK$'$#J %'G ~~i NN;0BC	 $$Z0">)=#}$56!#
 	 7z~~g~7^6_`		! NN  ! r.   c                  T   t        t              } | j                  dt               | j                  dt               | j                  dt
               | j                  dt               | j                  dt               | j                  dt               | j                  t        d       | j                  dd       | j                  dd       | j                  dd       | j                  dd       | j                  dd       | j                  dt               | j                         S )u;   创建维修报告工作流（与主Agent对接的版本）rO   retrieve_knowledgegenerate_fault_reasongenerate_spare_partsr   r   )r	   r   add_noderO   rn   r|   r   r   r   add_edger
   r   compile)workflows    r/   create_report_workflowr     s   +&H)+<=*,EF-/MN,.GH-/DE)+<=e01)+?@*,CD-/EF,.EF-/BC)3/r.   r   r   c                 P  K   t               }| |ddddddddddg ddd}	 |j                  |       d{   }|j                  d      rd|d    g ddS |j                  dd      |j                  d	g       ddS 7 G# t        $ r}dt	        |       g ddcY d}~S d}~ww xY ww)
uv  
    执行维修报告工作流（供主Agent / app.py 调用）

    Args:
        extracted_text: 主Agent合并后的文本描述（可能包含report_data JSON）
        history_message: 历史消息（JSON格式字符串）

    Returns:
        {
            "response": str,
            "actions": List[Dict[str, Any]],
            "result_tag": str,
        }
    Nr"   r   r   r   r   r   r   r   r   r   r   r   r    r!   r%   r&   r&   u#   维修报告工作流执行失败: r$   r   r    r!   )r   r]   r>   rB   r+   )r   r   appinitial_statefinal_staterm   s         r/   run_repair_report_workflowr   $  s       !
"C )*!#"M$
KK66???+A+oB^A_`&  $
B7"y"5"
 	
 7  
=c!fXF"
 	

sP   B&A> A< A> B&%A> ;B&<A> >	B#BB#B&B##B&c                     K   t               } dt        j                  ddddddg      d dddddddddg ddd}| j                  |       d {   }t	        |d	          y 7 w)
Nu   主机发生异常振动r4   uC   设备名称：发动机
故障类型：运行异常，振动加剧)r%   r3   r   u'   建议检查轴承并更换磨损部件r"   r   r    )r   r?   dumpsr]   print)graphr   rN   s      r/   testr   b  s     "$E 5::,9  A(5^_'
  !#%"M* ==//F	&
 0s   AA$A"A$__main__)1r*   r^   r?   retypingr   r   r   r   r   r   langgraph.graphr	   r
   r   sysr   r   dirnameabspath__file__current_dirr   rc   modelsAPI.model_apir   r\   r   utils.pdf_generatorr   tools.function_toolr   r   r   configr   r   r+   rO   rn   r|   r   r   r   r   r   r   r'   runr-   r.   r/   <module>r      s      	 @ @ 2 2 
 	 ggoobggooh78WW__[)
SXXHHOOJ ) 7 3 
 !) : M[ MT#s(^ M MbF
; F
4S> F
V A
 A
S#X A
 A
H ?
; ?
4S> ?
 ?
D R{ RtCH~ R Rj F[ FT#s(^ F FV2 7
S 7
3 7
SWX[]`X`Sa 7
 7
z6 zGKK r.   j=*x$
    -MgiH              	          d Z ddlZddl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mZmZ ddlmZ ej"                  j%                  ej"                  j'                  ej"                  j'                  ej"                  j)                  e                         ddlmZ  G d de      Zd	efd
Zd	efdZd	efdZd	efdZd Zd Zedk(  r ej@                   e              yy)u  
工作流五  报告类agent
输入：图片、图片加文本、图片+ASR、文本
1. 设备（获取相关vdr数据、图谱检索、rag）
2. 按步骤生成（故障、原因、解决方案、所需备品备件等信息）
3. 关键步骤信息交互
    N)	TypedDictDictAnyListLiteral)
StateGraphSTARTEND)MemorySaver)	OpenaiAPIc                   j    e Zd ZU eeef   ed<   eed<   eed<   ee   ed<   e	d   ed<   eed<   eed<   y	)
ReportState	raw_inputreason_analysisreason_approvedsolution_steps)yesnoback_to_reasonplan_approveduser_feedbackfinal_reportN)
__name__
__module____qualname__r   strr   __annotations__boolr   r        E/storage01/home/cr/projects/wx_app_agent/workflows/workflow_report.pyr   r      s>    CH~I899r    r   statec                 P  K   t        d       | j                  d      rd| j                  d       nd}d| d    d| d}t        j                  |d	
      }t	        j
                  ||j                  d      |j                  d      dz          }|j                  d      dddS w)u$   节点：生成或修改故障原因u-   
[Node] 执行：故障原因生成/重修...r      
用户反馈： u$   分析设备故障原因。输入：r    u)   。请返回JSON格式: {"reason": "..."}Nmodel{}   reasonF)r   r   r   printgetr   open_api_chatjsonloadsfindrfindr"   feedbackpromptresponsecontents        r!   generate_reason_noder:   %   s     	
:;CH99_C]"599_#=">?ceH3E+4F3Gq
  SB  CF&&vT:Hjj(--"4X^^C5H5JKLG  '{{84r^cdd   B$B&c                 P  K   t        d       | j                  d      rd| j                  d       nd}d| d    d| d}t        j                  |d	
      }t	        j
                  ||j                  d      |j                  d      dz          }|j                  d      dddS w)u$   节点：生成或修改维修方案u-   
[Node] 执行：维修方案生成/重修...r   r$   r%   u   基于故障原因 r   u    提供维修步骤。u,   。返回JSON: {"steps": ["步骤1", "..."]}Nr'   r)   r*   r+   stepsr   )r   r   r   r-   r5   s        r!   generate_plan_noder>   1   s     	
:;CH99_C]"599_#=">?ceH"5):#;"<<RS[R\  ]Q  RF&&vT:Hjj(--"4X^^C5H5JKLG%kk'2RZ^__r;   c                 (    | j                  d      ryy)u   原因生成后的跳转逻辑r   
go_to_planstay_at_reason)r/   )r"   s    r!   route_after_reasonrB   >   s    yy"#r    c                 T    | j                  d      }|dk(  ry|dk(  rt        d       yy)u-   方案生成后的跳转逻辑（含回溯）r   r   finishr   u8   --- 检测到回溯请求：返回原因分析阶段 ---stay_at_plan)r/   r.   )r"   decisions     r!   route_after_planrG   D   s3    yy)H5	%	%HIr    c                  T   t        t              } | j                  dt               | j                  dt               | j                  t        d       | j                  dt        ddd       | j                  dt        ddt        d       t               }| j                  |ddg      S )N
reason_genplan_gen)rA   r@   )rE   r   rD   )checkpointerinterrupt_after)r   r   add_noder:   r>   add_edger	   add_conditional_edgesrB   rG   r
   r   compile)workflowmemorys     r!    create_full_interactive_workflowrS   Q   s    +&H l$89j"45 e\* ""*$	
 ""&*	
 ]F,PZA[\\r    c                    K   dd l } t               }t        | j                               }dddii}t	        d       |j                  dddii|      2 3 d {   }
7 6 	 |j                  |      }|j                  sZt	        d
       t	        d|j                  j                  d              t	        d|j                  j                  d              y |j                  d   }|dk(  rtt	        d|j                  j                  d              t        d      }|j                         dk(  r|j                  |dd	id       n|j                  ||ddd       n|dk(  rt	        d|j                  j                  d              t	        d|j                  j                  d              t	        d       t        d      }|j                         dk(  r|j                  |ddid       nN|j                         dk(  r$t        d      }|j                  |d |dd!d       n|j                  ||d"d#d       |j                  d |      2 3 d {  7  }6  w)$Nr   configurable	thread_idrepair_loop_007u#   --- 启动全流程维修 Agent ---r   textu   电机冒烟并伴有焦味Tu=   
==================== 报告最终确定 ====================u   最终原因：r   u   最终方案：r   rI   u   
[待审核原因]: u$   原因满意吗？(y/反馈内容): yr   )as_nodeF)r   r   rJ   u   
[已确定的原因]: u   [待审核方案]: uX   选项: [y]满意 | [r]原因错了，回溯到原因分析 | [反馈内容]修改方案u   请选择: r   r   ru&   请说明为什么原因分析有误: r   )r   r   r   r   )r   r   )uuidrS   r   uuid4r.   astream	get_statenextvaluesr/   inputlowerupdate_state)	r\   apprV   config_snapshotcurrent_node
user_inputr6   s	            r!   mainrk   u   s_    
*
,CDJJL!I{,=>?F	
/0 ;;f6S-TUW]^dad^
==(}}ABOHOO$7$78I$J#KLMOHOO$7$78H$I#JKL}}Q' <')(//*=*=>O*P)QRSEFJ!S(  *;T)BL Y  :Z_)`jv w Z',X__-@-@AR-S,TUV'(;(;<L(M'NOPlm}-J!S(  /5)A: V!!#s* !IJ  %5%-',* &	 ! '   :X\)]gq r {{4066!0Q sC   AIAAAIAG4IIIII__main__)!__doc__asynciosysosr1   typingr   r   r   r   r   langgraph.graphr   r	   r
   langgraph.checkpoint.memoryr   pathappenddirnameabspath__file__modelsAPI.model_apir   r   r:   r>   rB   rG   rS   rk   r   runr   r    r!   <module>r{      s     
 	  6 6 2 2 3 0I JK L )	) 	
ek 
e	`K 	`k 	K 	 ]H37j zGKK r    qju	xH@o
    i                  	   @   s  d Z ddlZddlZejejeZejeZeejvr%ej	e ddl
mZmZmZmZmZ ddlmZmZmZ ddlmZmZ ddlmZ ddlmZmZ ddlZddlZddlZG dd	 d	eZd
edee ef fddZ!ed
edee ef fddZ"d
edee ef fddZ#ed
edee ef fddZ$d
edee ef fddZ%de de deee ef  fddZ&dd Z'			d%de dee  de d e fd!d"Z(e)d#kre*d$ dS dS )&u  
工作流：备件统计与预测Agent（使用LangGraph）
输入：文本（转化后和原文本query）
步骤：
1. 解析历史信息，用户意图识别，如果历史信息和用户问题中，没有设备或者备品备件信息，则直接返回"请先提供需要统计的设备或者备品备件信息"
2. 简化GraphRAG查询（将复杂统计问题简化为"备品备件有哪些"）
3. 使用RAG和GraphRAG检索所有相关的备品备件，检索不到相关设备信息和备品备件信息则返回“抱歉，经检索，知识库中没有相关的设备信息和备品备件信息，无法直接统计。请上传相关文件后重新查询。”
4. 结合用户意图和使用RAG和GraphRAG检索所有相关的备品备件使用大模型生成echarts要json数据。echarts柱状图格式```echarts
{
  "title": {
    "text": "每周销量统计"
  },
  "tooltip": {},
  "legend": {
    "data": ["销量"]
  },
  "xAxis": {
    "data": ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
  },
  "yAxis": {},
  "series": [
    {
      "name": "销量",
      "type": "bar",
      "data": [120, 200, 150, 80, 70, 110, 130],
      "itemStyle": {
        "color": "#5470C6"
      }
    }
  ]
}
```"还可能生成echarts结构的饼图或者折线图。
5. 根据原始问题和查询出的所有备件信息，使用思维链提示词生成统计结果结合4生成echarts数据进行返回。
使用 OpenaiAPI 方法调用大模型，尽可能使用异步
    N)	TypedDictOptionalDictAnyList)
StateGraphSTARTEND)rag_search_toolgraph_rag_search)	OpenaiAPI)track_function_callsget_current_stream_handlerc                   @   s   e Zd ZU dZeed< eed< eeeef  ed< eed< eed< eed< e	eeeef   ed< e	e ed	< e	eeef  ed
< eed< eeeef  ed< eeeef  ed< eed< dS )SparePartsStatisticsStateu$   备件统计与预测工作流状态extracted_texthistory_messagehistory_messagescombined_queryquerysimplified_queryrag_search_resultgraph_search_resultecharts_dataresponseactionssuggestedReplieserror_messageN)
__name__
__module____qualname____doc__str__annotations__r   r   r   r    r#   r#   1/app/workflows/workflow_spare_parts_statistics.pyr   :   s   
 r   statereturnc              
   C   s   ddl }| ddpd}g }|r=zt|tr||}n|}t|tr)|dd }W n ty< } zW Y d}~nd}~ww tdt| d|iS )u,  
    备件统计第一步：获取所有历史信息
    备件统计工作流关注所有历史信息，用于辅助统计
    支持格式：[{'role': 'user', 'content': '...'}, {'role': 'assistant', 'content': '...'}]
    返回消息列表（history_message已经在app.py中过滤过了）
    r   Nr    iu   历史记录消息数：r   )	jsonget
isinstancer!   loadslist	Exceptionprintlen)r%   r(   r   r   history_dataer#   r#   r$   get_history_contextX   s"   

r2   c           	   
      s   |  dd}d|v r|ddd ddd }|}|}z2t|dd}t|dd}t||I d	H \}}t|tr@|ng t|t	rK|d
W S dd
W S  t
yl } zg ddt	| dW  Y d	}~S d	}~ww )u   
    备件统计阶段一：进行知识库检索，查找相关备品备件数据
    使用原始问题进行RAG检索，使用简化后的查询进行GraphRAG检索
    r   r'      用户问题：   u   
图片r      )r   top_kN)r   r   u   检索失败: )r   r   r   )r)   splitr
   ainvoker   asynciogatherr*   r,   r!   r-   )	r%   r   	rag_querygraph_queryrag_task
graph_taskrag_resultsgraph_resultsr1   r#   r#   r$   search_rag_and_graph   s8   rA   c                 C   s   |  dg }|  dd}d}|r9t|tr9t|dkr9|D ]}t|tr8| dd}|r8t| dkr8d} nqd}|rLt|trLt| d	krLd}|s_|s_d
g ddddddgddS i S )Nr   r   r'   Fr   text
   T   u   抱歉，经检索，知识库中没有相关的设备信息和备品备件信息，无法直接统计。请上传相关文件后重新查询。u!   请上传本地需要统计数据titlecontentu$   缺失关键信息，请补充完整u6   未检索到相关的设备信息和备品备件信息)r   r   r   r   )r)   r*   r,   r/   dictstripr!   )r%   r?   r@   has_rag_resultsitemrB   has_graph_resultsr#   r#   r$   check_search_results1  s.   
rM   c              
      s  |  dd}|  dg }|  dd}|  ddpd}d}|rDg }|dd D ]}t|tr>| dd}|r>|d	|  q'd
|}d| d
}	|rT|	d| d
7 }	|	d|rZ|nd d|ra|nd d7 }	zJt|	dkrt|	dd }	tj|	ddI dH }
d|
 v rdi iW S t	
d|
}|r|d}t|}t|trt|dkrdd|iiW S di iW S  ty } zi dt| dW  Y d}~S d}~ww )u   
    备件统计阶段二：生成相关图表数据
    根据用户意图和检索到的备件信息，智能生成多个合适的ECharts图表
    如果数据不足，返回空
    r   r'   r   r   history_contextNrC   rB   - 
u'  
你是一个专业的ECharts图表数据生成助手。根据用户的统计问题和检索到的备件信息，智能生成多个合适的ECharts图表。

=== 任务要求 ===
1. 仔细分析用户的统计问题和检索结果
2. 判断数据是否支持生成图表：
   - 如果数据不足、没有具体数字或统计信息，返回"NO_CHART"
   - 如果数据充足，可以生成1-3个图表
3. 根据数据特点选择合适的图表类型：
   - 柱状图：适合比较不同类别的数据（如：各备件的使用数量、各设备的故障次数）,data中数据必须是精准的数字,data中数据必须是精准的数字，如果data中数据相同则不生成柱状图。
   - 饼图：适合展示部分占整体的比例（如：各备件占比、各故障类型占比），如果数据各个部分占比相同，则不需要饼图展示。
   - 折线图：适合展示数据随时间的变化趋势（如：月度备件消耗趋势、季度维修次数变化）,data中数据必须是精准的数字
   - 混合图表：可以组合多种图表类型展示不同维度的数据
4. 每个图表都要有清晰的标题和完整配置
5. 确保JSON格式正确，可直接用于ECharts图表渲染
6. 当data中数据值相等时不要输出柱状图ECharts图表
=== 用户原始问题 ===
u&   

=== 历史记录（供参考） ===
u?   

=== 检索到的备件相关信息 ===
【RAG检索结果】
   无相关RAG检索结果   

【图谱检索结果】
   无相关图谱检索结果uE  

=== 输出格式 ===
如果数据不足，只输出：NO_CHART

如果数据充足，输出一个JSON数组，包含1-3个图表配置，格式如下：
```json
[
  {
    "title": {
      "text": "备件使用统计"
    },
    "tooltip": {},
    "legend": {
      "data": ["数量"]
    },
    "xAxis": {
      "data": ["轴承", "齿轮", "密封圈", "传感器"]
    },
    "yAxis": {},
    "series": [
      {
        "name": "数量",
        "type": "bar",
        "data": [120, 200, 150, 80],
        "itemStyle": {
          "color": "#5470C6"
        }
      }
    ]
  },
{
    "title": {
      "text": "备件使用统计"
    },
    "tooltip": {},
    "legend": {
      "data": ["数量"]
    },
    "xAxis": {
      "type": "category",
      "data": ["轴承", "齿轮", "密封圈", "传感器"]
    },
    "yAxis": {
      "type": "value"
    },
    "series": [
      {
        "name": "数量",
        "type": "bar",
        "data": [120, 200, 150, 80]
      }
    ]
  },
 {
  title: {
    text: '周销售趋势',
    subtext: '单位：件',
  },
  legend: {
    data: ['销量'],
    orient: 'vertical',  
    right: 60,           
    top: 20              
  },

  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  yAxis: {
    type: 'value'
  },
  series: [
    {
      name: '销量',       
      data: [150, 230, 224, 218, 135, 147, 260],
      type: 'line'
    }
  ]
]]
}
```

注意事项：
1. 每个图表都要有独特的标题
2. 图表颜色区分度高。
3. 图表数据要基于检索结果中的实际信息。
4. 如果只能生成一个图表，就只输出一个。
5. 不要输出任何文字说明，只输出JSON数组或NO_CHART。
6.输出必须是严格 JSON（RFC 8259），所有 key 和字符串必须使用双引号，不允许使用 JavaScript 对象语法。
i   i  modelNO_CHARTr   z\[[\s\S]*\]r   chartsu   生成ECharts数据失败: )r   r   )r)   r*   rH   appendjoinr/   r   open_api_chat_without_thinkingupperresearchgroupr(   r+   r,   r-   r!   )r%   r   r?   r@   rN   rag_textrag_text_partsrK   rB   echarts_promptecharts_json_str
json_matchjson_strecharts_data_listr1   r#   r#   r$   generate_echarts_data\  s\   





d



rf   c              
      s(  |  dd}|  dg }|  dd}|  di }|  dg p g }zd}|rKg }|dd D ]}t|trE| d	d}	|	rE|d
|	  q.d|}t|trV| dg ng }
d}|
rt|
dkrd}t|
dD ]\}}tj|ddd}|d| d7 }qind}d}g }|r|	| d| d|r|nd d|r|nd d| d	}|
rt|
dkr|d7 }n|d7 }|d7 }|d |d! t
jd||d"I dH }tjd#d|tjd$}|r| nd%}g }t||I dH }||||d&W S  ty } zd't| g g i d't| d(W  Y d}~S d}~ww ))u   
    备件统计阶段三: 生成统计结果
    根据原始问题和查询出的所有备件信息，生成统计、推理、预测结果，并结合ECharts数据返回
    r   r'   r   r   r   r   NrC   rB   rO   rP   rW   r   u   
=== ECharts图表数据 ===
以下是根据检索结果生成的ECharts图表数据，请在输出时将其嵌入到对应的统计结果中：

r4   F   )ensure_asciiindentz```echarts
z
```

uN   
=== ECharts图表数据 ===
当前检索到的数据不足以生成图表。
u   你是一个专业的备件统计与预测分析专家。请严格按照下面要求逐步分析并回答用户的统计问题。

必须严格遵守：
1) 不要修改知识库文本中出现的 URL 字符串内容（不得改/不得截断），如需引用直接原样粘贴；
2) 不得编造或猜测知识库中没有的 URL / 图片链接；
3) 如果在文档内容中看到图片URL、表格或公式，请在回答中**自然引用或转述其关键信息**，但不强制要求特定展示格式；
4) 输出内容不要脱离输入的核心内容，不要遗漏输入提供的关键信息，也不要加入无关内容。
5) 如果有历史问答上下文，请结合历史对话内容理解当前问题。如果信息不足，请说明需要更多信息。r3   u:   

检索到的备件相关信息：
【RAG检索结果】
rQ   rR   rS   u  
判断检索结果和用户问题是否相关，如果相关严格按照检索内容进行回答

输出格式：
备件统计与预测分析结果

步骤1：提取备件信息
- 从检索结果中提取所有相关的备品备件信息
- 整理备件的名称、规格、用途、数量等关键信息

步骤2：数据整理与分析
- 对提取的备件信息进行分类整理
- 识别备件之间的关系和规律
- 进行必要的统计计算（如数量统计、分类统计等）

步骤3：推理与预测
- 根据历史记录和当前信息进行推理
- 如果需要预测，基于现有数据给出合理的预测结果
- 分析可能的影响因素和趋势
uI  
步骤4：备品备件图表分析
- 在统计结果中合适的位置，使用 ```echarts``` 代码块嵌入上面的ECharts数据
- 图表应该放在对应的统计描述之后，方便前端渲染
- 确保图表数据与文字描述相匹配
- 为每个图表生成一段文字描述，例如："数据表明：备件A的使用数量为100个，备件B的使用数量为200个。备件A在1月份消耗比较多，而备件B在2月份消耗比较多等。"
- 如果有多个图表，请为每个图表分别生成描述，并将图表放在对应的描述之后

步骤5：结论
u   
步骤4：结论
u  
- 综合以上分析，给出清晰的统计结果
- 提供具体的数字、图表描述或预测结论
- 如有必要，给出建议或注意事项

输出要求：
1. 请进行完整分析，但只输出分析结论和必要的解释，不要展示中间推理过程。
2. 最终给出清晰的统计结果、推理结论或预测结果
3. 如果有图表，在统计结果中使用 ```echarts``` 代码块嵌入ECharts数据，确保格式正确
4. 如果有多个图表，请为每个图表分别生成描述，并将图表放在对应的描述之后
5. 如果信息不足，请明确指出需要哪些额外信息
6. 使用专业但易懂的语言，避免过于技术化的术语
7. 确保所有数字和统计结果准确无误
8. 图表应该放在相关的统计描述之后，例如："根据统计结果，各备件的使用情况如下：
```echarts
{...}
```"
9. 检索内容中包含图片链接切勿省略回答中的图片链接也不要输出和展示知识库中没有的链接图片。
10. 如果没有图表信息，则跳过图表分析步骤，直接进入结论步骤。
请严格按照检索内容进行回答。
请开始你的分析：user)rolerG   )rU   system_promptmessagesz</think>.*?</think>)flagsu$   抱歉，无法生成统计结果。)r   r   r   r   u   生成统计结果失败: )r   r   r   r   r   )r)   r*   rH   rX   rY   r/   	enumerater(   dumpsextendr   rZ   r\   subDOTALLrI   %generate_suggested_replies_statisticsr-   r!   )r%   r   r?   r@   r   r   r_   r`   rK   rB   rW   echarts_data_sectionidxchart
chart_jsonrl   rm   user_contentstatistics_resultr   suggested_repliesr1   r#   r#   r$   generate_statistics_result  s   






r|   resultquestionc           
   
      s   d| d| dd  d}zet j|ddI dH }td|tj}|ri|d}t|}t|t	rit
|d	krig }|dd	 D ]}t|tr_d
|v r_d|v r_|t|d
 t|d d q@t
|d	kri|W S ddddddgW S  ty }	 zddddddgW  Y d}	~	S d}	~	ww )uc   
    生成针对统计结果的建议回复问题
    使用大模型生成两个相关问题
    u   
你是一个专业的备件统计与预测分析助手。根据以下统计结果，生成两个用户可能关心的后续问题。

【用户问题】
u   

【统计结果】
Ni  u  

请生成两个简洁、实用的问题，这些问题应该：
1. 与当前统计结果相关，能够帮助用户进一步了解相关信息
2. 问题要具体、可操作
3. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {"title": "问题1的标题", "content": "问题1的完整内容"},
    {"title": "问题2的标题", "content": "问题2的完整内容"}
]

只输出JSON，不要有其他文字说明。
rT   z\[.*\]r   rg   rF   rG   rE   u$   这些备件的使用频率如何？u!   需要提前准备哪些备件？)r   rZ   r\   r]   rs   r^   r(   r+   r*   r,   r/   rH   rX   r!   r-   )
r}   r~   promptresult_textrc   rd   r{   formatted_repliesreplyr1   r#   r#   r$   rt     s@   




rt   c                  C   s   t t} | dt | dt | dt | dt | dt dtdtfdd	}dtdtfd
d}| 	t
d | 	dd | 	dd | d|dtd | 	dd | 	dt |  S )u$   创建备件统计与预测工作流r2   rA   rM   rf   r|   r%   r&   c                 S      |  drdS dS )u*   判断是否在意图检查后继续执行r   endcontinuer)   r%   r#   r#   r$   "should_continue_after_intent_check     
zRcreate_spare_parts_statistics_workflow.<locals>.should_continue_after_intent_checkc                 S   r   )u*   判断是否在检索检查后继续执行r   r   r   r   r   r#   r#   r$   "should_continue_after_search_check  r   zRcreate_spare_parts_statistics_workflow.<locals>.should_continue_after_search_check)r   r   )r   r   add_noder2   rA   rM   rf   r|   r!   add_edger   add_conditional_edgesr	   compile)workflowr   r   r#   r#   r$   &create_spare_parts_statistics_workflow  s*   	
r   r'   r   r   r   
route_flagc                    s   |s| }	 t  }| |g |dd d d dg g dd}z!||I d H }|dd|dg |dg |di ddW S  tyX } zd	t| g g i ddW  Y d }~S d }~ww )
Nr'   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   
statistics)r   r   r   r   
result_tagu   工作流执行失败: )r   r8   r)   r-   r!   )r   r   r   r   appinitial_statefinal_stater1   r#   r#   r$   #run_spare_parts_statistics_workflow;  sF   



r   __main__u.   开始执行备件统计工作流测试案例
)Nr'   r'   )+r    sysospathdirnameabspath__file__current_dir
parent_dirrX   typingr   r   r   r   r   langgraph.graphr   r   r	   tools.function_toolr
   r   modelsAPI.model_apir   utils.function_trackerr   r   r9   r(   r\   r   r!   r2   rA   rM   rf   r|   rt   r   r   r   r.   r#   r#   r#   r$   <module>   sX    #
 &3+ ; ">N
 nZxxGp
    jy@                     
   d 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m	Z	m
Z
mZ ej                  j                  ej                  j                  ej                  j                  ej                  j                  e                         ddlmZmZmZ ddlmZ ddlmZ ddlmZ dd	lmZ  G d
 de      Zdede	ee
f   fdZdede	ee
f   fdZ dede	ee
f   fdZ!dede	ee
f   fdZ"dede	ee
f   fdZ#dedede	ee
f   fdZ$dedede	ee
f   fdZ%dee	ee
f      de&defdZ'dedee	ee
f      fdZ(dedefdZ)d Z*	 	 d$dedededede	ee
f   f
d Z+e,d!k(  r#ddl-Z-g d"Z.d# Z/ e-j`                   e/              yy)%u  
工作流：受控 ReAct Text2SQL 统计智能体

架构（简洁直接，无多轮交互）：
  用户问题
    ↓
  Router Node（判断：统计分析 / 维修反馈 / 普通问答）
    ├── 普通问答 → final_answer → END
    ├── 维修反馈 → repair_feedback → final_answer → END
    └── 统计分析 → text2sql_tool（内部闭环）→ final_answer → END

text2sql_tool 内部闭环：SQL生成 → SQL审查 → SQL Guard → SQL执行
    N)datetime)	TypedDictOptionalDictAnyList)
StateGraphSTARTEND)	OpenaiAPI)TEXT2SQL_PROMPTS)text2sql_tool)repair_feedback_statistics_toolc                      e Zd ZU eed<   eed<   eed<   eed<   eeeef      ed<   ee   ed<   ee   ed<   eeeef      ed<   eeeef      ed	<   eeeef      ed
<   eed<   eeeef      ed<   eeeef      ed<   eed<   y)StatisticsStateextracted_textcombined_query
route_flaghistory_messagehistory_messagesroute_resultsql
sql_resultfeedback_resultfeedback_paramsresponseactionssuggestedReplieserror_messageN)	__name__
__module____qualname__str__annotations__r   r   r   r        %/app/workflows/workflow_statistics.pyr   r   "   s    O4S>** 3- 
#c3h(( d38n--d38n-- M$sCx.!!4S>**r&   r   statereturnc                 6  K   | j                  d      xs | j                  dd      }t        d   j                  |      }	 t        j                  |dd       d{   }t        j                  d	|t
        j                        }|rZt        j                  |j                  d
            }|j                  dd      j                         j                         }|dv rd|iS ddiS 7 # t        $ r$}t        dt        |              Y d}~ddiS d}~ww xY ww)uC   
    路由判断：统计分析 / 维修反馈 / 普通问答
    r   r    routerquestionNTmodeljson_output\{.*\}r   route
statisticsr4   feedbacknormalr   u   路由判断失败: )getr   formatr   open_api_chat_without_thinkingresearchDOTALLjsonloadsgroupstriplower	Exceptionprintr#   )r(   r.   promptresult
json_matchparsedr3   es           r'   router_noderJ   @   s     yy)*Meii8H".MHh'...AF/ ??$D
 
 YYy&"))<
ZZ
 0 0 34FJJw5;;=CCEE<<&..
 L))
  /$SVH-..L))/sB   ?DC) C'BC) "D'C) )	D2D	DDDc                    K   | j                  d      xs | j                  dd      }t        j                         j                  d      }t	        ||       d{   }|j                  dd      |dS 7 w)	u|   
    调用受控 Text2SQL 工具
    内部闭环：SQL生成 → SQL审查 → SQL Guard → SQL执行（含重试）
    r   r   r+   %Y-%m-%d)r.   current_dateNr   )r   r   )r8   r   nowstrftimer   )r(   r.   rM   rF   s       r'   text2sql_noderP   ^   sp     
 yy)*Meii8H".MH<<>**:6L (NNF zz%$  Os   AA7A5A7c                   K   | j                  d      xs | j                  dd      }t        |       d{   }	 t        j                  |       d{   }||dS 7 '7 # t        $ r}dt        |      d|dcY d}~S d}~ww xY ww)u7   
    处理维修反馈类问题（走外部API）
    r   r   r+   N)r   r   F)successerror)r8   _extract_feedback_paramsr   ainvokerC   r#   )r(   r.   paramsrF   rI   s        r'   repair_feedback_noderW   r   s      yy)*Meii8H".MH+H55Fc6>>vFF#)fEE	 6 G c/4s1v#F[abbcsP   4B	AB	A" A A" B	 A" "	B+B;B<B	BB	r.   c                   K   t        j                         j                  d      }d| d|  d}	 t        j                  |dd       d{   }t        j                  d|t
        j                        }|rst        j                  |j                  d	            }i }|j                  d
      r|d
   |d
<   |j                  d      r|d   |d<   |j                  d      r|d   |d<   |S 	 i S 7 # t        $ r Y i S w xY ww)u*   从用户问题中提取维修反馈参数rL   uW   从以下问题中提取维修反馈统计参数，返回JSON格式。

当前日期：u   

用户问题：u  

需要提取的参数：
- source: 来源筛选（好评/差评/反馈），如果没有则为空字符串
- start_date: 开始日期（格式：YYYY-MM-DD），如果没有则为空字符串
- end_date: 结束日期（格式：YYYY-MM-DD），如果没有则为空字符串

时间映射：
- "近一个月" → start_date = 当前日期前30天
- "近一周" → start_date = 当前日期前7天
- "近三个月" → start_date = 当前日期前90天

输出格式：
{"source": "", "start_date": "", "end_date": ""}
只输出JSON。NTr/   r2   r   source
start_dateend_date)r   rN   rO   r   r:   r;   r<   r=   r>   r?   r@   r8   rC   )r.   rM   rE   rF   rG   rH   rV   s          r'   rT   rT      s    <<>**:6L~ z 	F( ??$D
 
 YYy&"))<
ZZ
 0 0 34FFzz(##)(#3x zz,''-l';|$zz*%%+J%7z"M  I#
  IsA   -C?C/ C-BC/ )C?+C?-C/ /	C<8C?;C<<C?c                   K   | j                  dd      }| j                  d      xs | j                  dd      }|dk(  rt        | |       d{   S |dk(  rd	g d
ddddddddgdS t        | |       d{   S 7 /7 w)u1   
    将查询结果转为自然语言回答
    r   r4   r   r   r+   r6   Nr7   u   您的问题似乎不属于统计分析类问题，请尝试更具体的统计查询，例如："最近一个月哪个故障最多"、"101舰备件消耗情况"等。   故障频次统计!   最近一个月哪个故障最多titlecontent   备件消耗统计u   101舰近一个月备件消耗u   维修反馈u   近一个月维修差评情况r   r   r   )r8   _format_feedback_answer_format_statistics_answer)r(   r   r.   s      r'   final_answer_noderf      s      99^\:Lyy)*Meii8H".MHz!,UH===		! E.;^_.;[\(5UV!
 	
 /uh??? > @s$   ABA>*B9B :B Bc                 *  K   | j                  di       }|j                  dd      s#|j                  dd      }d| g ddd	d
dd	gdS |j                  dg       }|j                  dd      }|j                  dd      }t        j                  |dd dd      }t        d   j	                  ||||      }	 t        j                  |d       d{   }	|	j                         }
|
g t        |      dS 7 ## t        $ r t        ||      }
Y (w xY ww)u   格式化统计分析结果r   rR   FrS   u   未知错误u   统计分析执行失败：r]   r^   r_   rb      近一个月备件消耗排名rc   rowsr   r+   	row_countr   N      )ensure_asciiindentfinal_answer)r.   r   rj   result_data)r0   )r8   r>   dumpsr   r9   r   r:   rA   rC   _simple_format_result_generate_suggested_replies)r(   r.   r   rS   ri   r   rj   rp   rE   answerr   s              r'   re   re      s3    <,J>>)U+w75eW=.;^_.;[\!
 	
 >>&"%D
..
#C{A.I **T#2YU1EKn-44	 5 F: ??dSS<<>
 7A  T :(y9:s<   B5D8C8 C6C8 'D6C8 8DDDDc                   K   | j                  di       }| j                  di       }|j                  dd      sdg g dS |j                  dg       }|j                  dd	      }|j                  d
i       }|j                  dd      }|j                  dd      }|j                  dd      }	|s.|rd| dnd}
|r|	r	d| d|	 dnd}d|
 d| dg ddddddgdS g }|rd| dnd}
|r|	r	d| d|	 dnd}|j                  d|
 d| d       |rPdj                  |j                         D cg c]  \  }}| d | d! c}}      }|j                  d"| d#| d$       |j                  d%       |j                  d&       |D ]  }|j                  d'd	      }t	        |j                  d(d            d)d* }t	        |j                  dd+            }t	        |j                  d,d-            }t	        |j                  d.d-            d)d/ }|j                  | d0| d0| d0| d0| 	        d1j                  |      g ddddddd2d3dgdS c c}}w w)4u   格式化维修反馈结果r   r   rR   Fu-   维修反馈统计失败，请稍后重试。rc   feedbackData
totalCountr   sourceDistributionrY   r+   rZ   r[   u   【u   】u   （u    至 u   ）u	   未找到u   维修反馈统计数据u   。u   查看差评u$   统计近一个月维修差评情况r_   u   查看好评u$   统计近一个月维修好评情况u   为您统计u   的维修反馈数据u   。
u   、 u    条u%   核心结论：共收到维修反馈 u    条（u   ）。
u-   排名 | 标题 | 来源 | 反馈人 | 时间z--- | --- | --- | --- | ---rankr`   N   u   未知	user_name-
created_at
    | 
u   查看近一周反馈u!   统计近一周维修反馈情况)r8   appendjoinitemsr#   )r(   r.   r   r   feedback_datatotal_countsource_distributionrY   rZ   r[   source_desc	time_descresponse_partskvdist_stritemrz   r`   item_sourcer|   r~   s                         r'   rd   rd      s    ii 126Oii 126Oy%0G "
 	
 $'';M!%%lA6K)--.BBG  2.F $$\26J"":r2H+1F83'r<F8c*U8*C8Y[	#K=0HSVW(5[\(5[\!
 	
 N'-Cxs#2K8Bx#j\xj4UWIL5J9+UZ[\:::M:S:S:UV:U$!Q!AaS~:UVW Ek]RYZbYccklmIJ78xx"DHHWb)*3B/$((8X67c23	,45cr:
c%K=I;cR\Q]^_  IIn-$1WX$1WX-:]^
  Ws   D,I.I
 DIri   rj   c           
         | syt        | d   j                               }d| dg}|j                  dj                  |             |j                  dj                  dgt	        |      z               | dd D ]M  }|D cg c]   }t        |j                  |d	            dd
 " }}|j                  dj                  |             O |dkD  r|j                  d|dz
   d       dj                  |      S c c}w )u<   简单格式化查询结果（LLM生成失败时的兜底）u   未查询到相关数据。r   u   共查询到 u    条记录。
r   z---Nr   r+   r{   u   
... 还有 u
    条记录r   )listkeysr   r   lenr#   r8   )ri   rj   columnspartsrowcolvaluess          r'   rr   rr   0  s    ,47<<>"GYK78E	LLG$%	LLUGc'l234CRy8?@#cggc2&',@UZZ'(  2~}Y^$4J?@99U As    %C7c                 &    ddddddddddd	dgS )
u   根据问题生成建议回复r]   r^   r_   rb   rh   u   按系统统计u$   动力系统近一个月故障统计u   按舷号统计u   101舰近一个月故障统计r%   r-   s    r'   rs   rs   D  s2     '3VW&3ST#0VW#0PQ	 r&   c                 @    | j                  dd      }|dk(  ry|dk(  ryy)u   Router 之后的路由r   r4   r6   r7   )r8   )r(   r3   s     r'   route_after_routerr   R  s+    IInl3E
	(	r&   c                     t        t              } | j                  dt               | j                  dt               | j                  dt
               | j                  dt               | j                  t        d       | j                  dt        dddd       | j                  dd       | j                  dd       | j                  dt               | j                         S )uY  
    创建受控 Text2SQL 统计工作流

    架构（简洁直线型，无多轮交互）：
    START
      ↓
    router_node
      ├── normal → final_answer_node → END
      ├── feedback → repair_feedback_node → final_answer_node → END
      └── statistics → text2sql_node → final_answer_node → END
    rJ   rP   rW   rf   r5   )r	   r   add_noderJ   rP   rW   rf   add_edger
   add_conditional_edgesr   r   compile)workflows    r'   create_statistics_workflowr   a  s     /*H m[1o}5,.BC)+<= e]+ "").)	
 o':;,.AB)3/r&   r   r   r   r   c                 t  K   t               }| |||g ddddddg g dd}	 |j                  |       d{   }|j                  d      rd|d    g dg dS |j                  dd      |j                  d	g       d|j                  d
g       dS 7 Y# t        $ r}dt	        |       g dg dcY d}~S d}~ww xY ww)u1   
    执行统计工作流（统一接口）
    Nr+   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   u   统计工作流执行失败: r4   )r   r   
result_tagr   r   r   r   )r   rU   r8   rC   r#   )r   r   r   r   appinitial_statefinal_staterI   s           r'   run_statistics_workflowr     s      %
&C )( *M"
KK66???+;K<X;YZ*$&	  $
B7"y"5& +0BB G	
 	
 7"  
7Ax@& "	
 	

sP   B8B B!B B86B B8B 	B5B0*B5+B80B55B8__main__)r^   u!   统计101舰的备件消耗情况u*   近三个月动力系统故障频次排名u   统计维修反馈差评情况u   连杆异常磨损怎么修c                    K   t        t        d      D ]k  \  } }t        dd        t        d|  d|        t        d        t        ||       d {   }t        d       t        |j	                  dd	             m y 7 -w)
N   r   z<============================================================u   测试用例 z: )r   r   u   
响应:r   u	   无响应)	enumerate
test_casesrD   r   r8   )i	test_textrF   s      r'   testr     s     %j!4LAyBvh- M!Byk23VH2(( F
 I&**Z56 5
s   ABB.B)r+   r+   )1__doc__sysosr>   r;   r   typingr   r   r   r   r   pathr   dirnameabspath__file__langgraph.graphr	   r
   r   modelsAPI.model_apir   promptsr   tools.text2sql_toolr   tools.fault_statisticsr   r   r#   rJ   rP   rW   rT   rf   re   rd   intrr   rs   r   r   r   r    asyncior   r   runr%   r&   r'   <module>r      s$    	  	  7 7 0I JK L 2 2 ) $ - Bi <*_ *c3h *< 4S> (co c$sCx. c*S *T#s(^ *b@? @tCH~ @.'? 'c 'dSVX[S[n 'T; ;C ;DQTVYQYN ;|T#s(^ 4   (# $tCH~2F o # 'b 	4
4
4
 4
 	4

 
#s(^4
v zJ7 GKK3 r&   >Ojx
    ԱMj                     f   d Z ddlmZmZmZmZmZ ddlmZ ddl	m
Z
 ddlmZmZ ddlmZmZ ddlZddlZddlZded	ee   fd
ZddlmZmZmZmZ ded	efdZded	efdZd Zdeeef   deeef   d	efdZdee   defdZ deeef   d	efdZ!dedeeef   d	efdZ"	 	 ddedee   deded	ef
dZ#y) uk   
工作流公共工具函数
提取自 workflow_fault_diagnosis.py 和 workflow_operate.py 的共享代码
    )	TypedDictOptionalDictAnyList)COMMON_PROMPTS)	OpenaiAPI)get_all_callbacksget_current_stream_handler)extract_image_pathsnormalize_markdown_imagesNtextreturnc                    | sy | j                         }t        j                  dd|t        j                        }t        j                  dd|      }t        j                  d|      }|r%	 t        j                  |j                  d            S t        j                  d|      }|r%	 t        j                  |j                  d            S 	 t        j                  |      S # t        $ r Y ^w xY w# t        $ r Y 0w xY w# t        $ r Y y w xY w)Nz
```json\s* )flagsz```\s*z\[[\s\S]*\]r   z\{[\s\S]*\})	stripresub
IGNORECASEsearchjsonloadsgroup	Exception)r   cleanedms      Je:\ZKYNLP\Hjunproject\project0506\wx-agent\app\workflows\workflow_utils.pysafe_json_extractr      s    jjlGff]Br}}EGffYG,G
		.'*A	::aggaj)) 			.'*A	::aggaj))zz'""  		  		  s6   +#C" (#C1 D  "	C.-C.1	C=<C= 	DD)parse_historybuild_history_strfilter_image_urlsinit_historyc                 
   d}| j                  d|      } t        j                  dd|       } t        j                  dd|       } | j                  |d      } t        j                  dd|       } t        j                  d	d
|       } | S )Nz DOUBLE_DOLLAR z$$z	(?<!\s)\$z $z\$(?!\s)z$ z(?<!\s)\$\$z $$z
\$\$(?!\s)z$$ )replacer   r   )r   placeholders     r   normalize_latex_spacingr'   +   st    )K<<k*D66,t,D66+ud+D<<T*D66.&$/D66-.DK    c                 f   | rt        |       dk  r| S | j                  d      }g }t               }|D ]k  }|j                         }|s|j	                  |       '|j                         j                         }||v rJ|j                  |       |j	                  |       m dj                  |      }|S )N
   
)	lensplitsetrstripappendr   loweraddjoin)r   linesresultseen_segmentslinenormalized_linecleaned_texts          r   remove_duplicate_contentr:   6   s    3t9r>JJtEFEM{{}MM$**,,,.m+/*d  99V$Lr(   c                     | r| j                  dd      sg S | j                  di       }g }|j                         D ]  \  }}|D ]  }|j                  |         |S )NsuccessFsourceCitation)getitemsr0   )
rag_resultsource_citationflat_resultsresourcer?   items         r   convert_rag_resultrE   O   sd    Z^^Iu=	 nn%5r:OL*002%D%  3 r(   weightsvaluesc                     d}| j                         D ]=  \  }}|j                  |d      xs d}|st        |      j                         s9||z  }? t	        |d      S )Ng        r      )r?   r>   strr   round)rF   rG   scorefieldweightvalues         r   calculate_info_completenessrP   Z   sY    E v

5"%+SZ%%'VOE ) ?r(   title_optionsdetailsc                     dt        j                  |       |d}t               D ]  }	  ||        y # t        $ r Y w xY w)Nfunction_execution)typetitlerR   )randomchoicer
   r   )rQ   rR   start_eventcallbacks       r   emit_callback_eventr[   c   sF    /&--:VcjkK%'	[! (  		s   3	??fieldsc                 X    d}| j                         D ]  \  }}|s	|d| d| dz  } |S )Nr   - u   ：r+   )r?   )r\   detail_infolabelrO   s       r   build_detail_infora   l   s?    KuRwc%33K ' r(   answeratlas_resultsc                     |s| S d}|j                         D ]X  \  }}t        |t              s|j                         D ]/  \  }}t        |t              s|s|D ]  }|d| d| d| dz  } 1 Z | |z   S )Nu   

---

**参考图册：**
r^   z: [ `z` ](z)
)r?   
isinstancedictlist)rb   rc   atlas_section	node_name	node_datarV   urlsurls           r   append_atlas_sectionrm   t   s    6M - 3 3 5	9i&(0tdD)d#%2eWE%SE)MM  $  1 !6 M!!r(   raw_contentoriginal_image_pathstemperaturecontent_labelc                   K   |rt         d   j                  ||       }nt         d   j                  |       }t         d   }t               }d}d}t        j                  d |d|dg|	      2 3 d {   }	||	z  }||	z  }|s|j                  |       (7 #6 |r|j                         n| }t        |      }t        ||
      }t        |      }|S w)Nformat_user_simple)rq   rn   format_user_with_image_examples)rn   format_systemr   user)rolecontent)modelsystem_promptmessagesrp   )original_paths)
r   formatr   r	   open_api_chat_streamsend_stream_contentr   r:   r   r'   )
rn   ro   rp   rq   format_user_contentformat_system_promptstream_handlerrb   accumulated_contentchunks
             r   stream_format_and_postprocessr      s      ,-ABII'# J 

 --NOVVcnVo)/:/1NF 55*!.ABC	 	De 	%u$../BC	D   &V\\^;F%f-F&v>RSF$V,FMs0   A+C-B1B2B5CCB:C)g333333?N)$__doc__typingr   r   r   r   r   promptsr   modelsAPI.model_apir	   utils.function_trackerr
   r   utils.image_utilsr   r   r   r   rW   rJ   r   workflows.history_managerr    r!   r"   r#   r'   r:   rE   floatrP   r[   ra   rm   r    r(   r   <module>r      s1  
 8 7 " ) P L  	 C HSM 0 h g# # 3 3 2c5j)9 4S> V[ tCy 3 d38n  
" 
"T#s(^ 
" 
"$ 	$$s)$ $ 	$
 	$r(   tx"""
统一历史对话管理器
整合所有分散的 parse_history / _parse_history / build_history_str / filter_image_urls 逻辑
"""

import json
from typing import Any, Dict, List, Optional


class HistoryManager:
    """统一的历史对话管理器，提供解析、截断、格式化、过滤等功能"""

    def __init__(
        self,
        max_messages: int = 10,
        max_assistant_chars: int = 300,
    ):
        """
        Args:
            max_messages: 保留的最近消息条数
            max_assistant_chars: assistant 角色内容截断字符数
        """
        self.max_messages = max_messages
        self.max_assistant_chars = max_assistant_chars

    # ==================== 解析 ====================

    def parse(self, history_message: Any) -> List[Dict[str, Any]]:
        """
        解析历史消息为列表，保留最近 max_messages 条。
        兼容字符串和列表输入，替代所有 parse_history / _parse_history。
        """
        if not history_message:
            return []
        try:
            data = json.loads(history_message) if isinstance(history_message, str) else history_message
            return data[-self.max_messages:] if isinstance(data, list) else []
        except Exception:
            return []

    # ==================== 截断 ====================

    def truncate(self, messages: List[Dict[str, Any]], keep_recent: Optional[int] = None) -> List[Dict[str, Any]]:
        """按数量截断，保留最近 keep_recent 条"""
        if not messages:
            return []
        n = keep_recent if keep_recent is not None else self.max_messages
        return messages[-n:]

    # ==================== 格式化 ====================

    def to_prompt_str(
        self,
        messages: List[Dict[str, Any]],
        recent_count: Optional[int] = None,
        assistant_truncate: Optional[int] = None,
    ) -> str:
        """
        格式化为 "用户: xxx\\n助手: xxx" 纯文本字符串，用于 prompt 注入。
        替代 build_history_str。
        """
        if not messages:
            return ""
        n = recent_count if recent_count is not None else self.max_messages
        trunc = assistant_truncate if assistant_truncate is not None else self.max_assistant_chars
        recent = messages[-n:]
        parts = []
        for m in recent:
            if isinstance(m, dict):
                role = m.get("role", "")
                content = (m.get("content") or "").strip()
                if role == "user":
                    parts.append(f"用户: {content}")
                elif role == "assistant":
                    parts.append(f"助手: {content[:trunc]}")
        return "\n".join(parts) if parts else ""

    def to_openai_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        格式化为 OpenAI messages 列表，直接传入 LLM。
        用于百科问答等需要完整消息格式的场景。
        """
        if not messages:
            return []
        result = []
        for m in messages:
            if isinstance(m, dict) and m.get("role") and m.get("content"):
                result.append({"role": m["role"], "content": m["content"]})
        return result

    # ==================== 请求预处理 ====================

    def preprocess_from_request(self, history_message: Any, exclude_last: bool = True) -> str:
        """
        处理前端传入的历史消息：解析、移除当前用户消息、序列化。
        对应 app.py 中 history_message 预处理逻辑。

        Args:
            history_message: 前端传入的历史消息，支持 str 或 list
            exclude_last: 是否移除最后一条（当前用户消息），默认 True

        Returns:
            处理后的 JSON 字符串
        """
        if not history_message:
            return ""
        try:
            data = json.loads(history_message) if isinstance(history_message, str) else history_message
        except (json.JSONDecodeError, TypeError):
            return ""
        if not isinstance(data, list):
            return ""
        if exclude_last and data:
            data = data[:-1]
        return json.dumps(data, ensure_ascii=False)

    # ==================== 状态初始化 ====================

    def init_history(self, history_message: Any) -> Dict[str, Any]:
        """
        一步完成历史消息解析，返回 history_message(str) + history_messages(list) 双字段。
        用于各工作流入口初始化 state，消除重复的 parse_history 调用。

        Args:
            history_message: 历史消息，支持 str 或 list

        Returns:
            {"history_message": str, "history_messages": list}
        """
        parsed = self.parse(history_message)
        raw = json.dumps(parsed, ensure_ascii=False) if parsed else ""
        return {"history_message": raw, "history_messages": parsed}

    # ==================== 过滤 ====================

    @staticmethod
    def filter_image_urls(history_message: Any) -> Any:
        """
        过滤历史消息中的图片URL，将多模态内容转为纯文本。
        替代 main_agent.filter_image_urls。
        """
        if not history_message:
            return history_message

        try:
            history_messages = json.loads(history_message) if isinstance(history_message, str) else history_message
        except (json.JSONDecodeError, TypeError):
            return history_message

        if not isinstance(history_messages, list):
            return history_messages

        filtered_messages = []
        for msg in history_messages:
            if not isinstance(msg, dict):
                filtered_messages.append(msg)
                continue

            new_msg = msg.copy()
            content = msg.get("content")

            if isinstance(content, list):
                text_parts = []
                for content_item in content:
                    if isinstance(content_item, dict):
                        if content_item.get("type") == "text":
                            text_value = content_item.get("text", "")
                            if text_value:
                                text_parts.append(text_value)
                    elif isinstance(content_item, str):
                        text_parts.append(content_item)

                if text_parts:
                    new_msg["content"] = "".join(text_parts)
                    filtered_messages.append(new_msg)
            else:
                filtered_messages.append(new_msg)

        return filtered_messages


# ==================== 模块级便捷实例 ====================
# 提供与旧函数签名兼容的模块级函数，方便渐进式迁移

_default_manager = HistoryManager()


def parse_history(history_message: Any) -> List[Dict[str, Any]]:
    """兼容旧调用的模块级函数"""
    return _default_manager.parse(history_message)


def build_history_str(
    history_messages: List[Dict[str, Any]],
    recent_count: int = 10,
    assistant_truncate: int = 300,
) -> str:
    """兼容旧调用的模块级函数"""
    mgr = HistoryManager(max_messages=recent_count, max_assistant_chars=assistant_truncate)
    return mgr.to_prompt_str(history_messages, recent_count=recent_count, assistant_truncate=assistant_truncate)


def filter_image_urls(history_message: Any) -> Any:
    """兼容旧调用的模块级函数"""
    return HistoryManager.filter_image_urls(history_message)


def preprocess_from_request(history_message: Any, exclude_last: bool = True) -> str:
    """兼容旧调用的模块级函数"""
    return _default_manager.preprocess_from_request(history_message, exclude_last=exclude_last)


def init_history(history_message: Any) -> Dict[str, Any]:
    """兼容旧调用的模块级函数"""
    return _default_manager.init_history(history_message)


>k$9
x/WШ"""
工作流：普通问答Agent（使用LangGraph）
输入：文本（转化后和原文本query）、图片描述、语音文本
步骤：
1. 使用RAG和GraphRAG检索相关信息
2. 生成回答
使用 OpenaiAPI 方法调用大模型，尽可能使用异步
"""
import sys
import os

# 添加项目根目录到Python搜索路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from typing import TypedDict, Optional, Dict, Any, List
from langgraph.graph import StateGraph, START, END
from workflows.history_manager import init_history

from tools.function_tool import (
    graph_rag_search
)
from tools.rag_tools import rag_search
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import track_function_calls, get_current_stream_handler, get_all_callbacks
from utils.image_utils import extract_image_paths, find_closest_image_path, normalize_markdown_images, get_image_prompt_guidance
from prompts import BAIKE_PROMPTS, COMMON_PROMPTS
import asyncio
import json
import re
import random


# =============== 定义状态 ===============
class QAState(TypedDict):
    """普通问答工作流状态"""
    extracted_text: str  # 已提取的文本（统一接口，只接收文本）
    combined_query: str
    retrieval_query: str  # 用于RAG/图谱检索的重写后query
    route_flag: str  # 路由标识
    history_message: str  # 历史消息（JSON格式）
    history_messages: List[Dict[str, Any]]  # 过滤后的历史消息列表
    need_retrieval: Optional[bool]  # 是否需要检索

    # RAG检索结果
    rag_search_result: Optional[List[Dict[str, Any]]]  # RAG检索结果
    graph_search_result: Optional[str]  # 图谱检索结果

    # 最终响应
    response: str  # 最终响应
    actions: List[Dict[str, Any]]  # 按钮信息列表 [{"type": "...", "label": "...", "icon": "..."}]
    suggestedReplies: List[Dict[str, Any]]  # 建议回复问题列表
    error_message: str  # 错误信息


# =============== 节点函数 ===============

def get_baike_history_context(state: QAState) -> Dict[str, Any]:
    """
    知识问答步骤：获取问答类历史信息
    问答工作流只关注历史问答记录，用于提供上下文
    """
    history_message = state.get("history_message", "") or ""
    return init_history(history_message)


async def judge_need_retrieval(state: QAState) -> Dict[str, Any]:
    """
    判断用户问题是否需要检索知识库
    """
    original_query = (state.get("combined_query") or state.get("extracted_text") or "").strip()
    history_messages = state.get("history_messages", []) or []
    
    prompt = BAIKE_PROMPTS["judge_need_retrieval"].format(
        history_messages=history_messages if history_messages else '无',
        original_query=original_query
    )
    
    need_retrieval = True
    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(prompt, model=None)
        if result:
            result = result.strip().lower()
            if result == "false":
                need_retrieval = False
    except Exception as e:
        print(f"判断是否需要检索失败: {e}")
        need_retrieval = True



    print(f"是否需要检索: {need_retrieval}")
    return {"need_retrieval": need_retrieval}


async def rewrite_query_with_history(state: QAState) -> Dict[str, Any]:
    """
    使用历史上下文对当前问题进行query重写，生成适合RAG/图谱检索的独立查询语句。
    只让大模型在有限的最近历史中挑选与当前问题语义相关的内容进行融合，避免简单拼接全量历史。
    """
    import json

    # 原始问题：优先使用 combined_query，其次使用 extracted_text
    original_query = (state.get("combined_query") or state.get("extracted_text") or "").strip()

    history_messages = state.get("history_messages", []) or []
    # 控制历史长度：只保留最近的若干条，避免上下文过长
    trimmed_history = history_messages[-8:] if history_messages else []

    try:
        history_str = json.dumps(trimmed_history, ensure_ascii=False)
    except Exception:
        history_str = str(trimmed_history)

    # 如果没有历史或当前问题过短，就直接跳过重写
    if not original_query:
        return {"retrieval_query": original_query}
    # 在构造 prompt 前，提取上一轮用户 query（如果有）
    last_user_query = ""
    if trimmed_history:
        # 从后往前找最近一条 role == "user" 的消息
        for msg in reversed(trimmed_history):
            if msg.get("role") == "user":
                last_user_query = msg.get("content", "").strip()
                break
    prompt = BAIKE_PROMPTS["rewrite_query_with_history"].format(
        last_user_query=last_user_query or '（无）',
        history_str=history_str,
        original_query=original_query
    )

    rewritten_query = original_query
    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(prompt, model=None)
        if result:
            candidate = result.strip().strip("“”\"'")
            # 只在模型返回的内容明显为单行短文本时替换，避免异常输出
            if candidate and len(candidate) <= 200 and "\n" not in candidate:
                rewritten_query = candidate
    except Exception as e:
        print(f"query 重写失败: {e}")


    title_options = [f"✨正在分析中，请稍等..."]
    start_event = {
        "type": "function_execution",
        "title": random.choice(title_options),
        "details": f"正在调取百科数据..."
    }
    for callback in get_all_callbacks():
        try:
            callback(start_event)
        except Exception:
            pass

    print("原始检索query:", original_query)
    print("重写后检索query:", last_user_query+rewritten_query)

    return {"retrieval_query":last_user_query+rewritten_query}


@track_function_calls
async def search_rag_and_graph(state: QAState) -> Dict[str, Any]:
    """
    进行文本知识检索和图谱知识检索
    """
    kb_id = None
    if state.get("route_flag") == "rules":
        kb_id = '3'

    # 优先使用重写后的检索query，其次使用 combined_query，最后回退到原始 extracted_text
    query = state.get("retrieval_query") or state.get("combined_query") or state.get("extracted_text", "")
    if "用户问题：" in query:
        query = query.split("用户问题：", 1)[1]

    print("Graph 检索query", query)
    extracted_text = state.get("extracted_text", "")
    if "用户问题：" in extracted_text:
        extracted_text = extracted_text.split("用户问题：", 1)[1]

    try:
        # 异步并行调用RAG检索和图谱检索
        print(kb_id)
        print(33333333333333333333333333333333333333)

        async def _do_rag_search():
            if kb_id:
                return await rag_search(
                    query=extracted_text,
                    kb_id=kb_id,
                    top_k=2
                )
            else:
                return await rag_search(
                    query=extracted_text,
                    top_k=2
                )

        async def _do_graph_search():
            return await graph_rag_search.ainvoke({
                "query": query,
                "top_k": 3
            })

        rag_result, graph_results = await asyncio.gather(
            _do_rag_search(),
            _do_graph_search()
        )

        # 处理 RAG 结果，提取成列表格式
        rag_search_result = []
        if rag_result.get("success", False):
            source_citation = rag_result.get("sourceCitation", {})
            for resource, items in source_citation.items():
                for item in items:
                    rag_search_result.append({
                        "text": item.get("text", ""),
                        "filename": item.get("filename", ""),
                        "resource": item.get("resource", ""),
                        "score": item.get("score", 0.0)
                    })

        # 只保留前 4 条数据
#        rag_search_result = rag_search_result[:2]
        rag_search_result = sorted(rag_search_result,key=lambda x:float(x.get("socre") or 0), reverse=True)[:4]

        return {
            "rag_search_result": rag_search_result,
            "graph_search_result": graph_results if isinstance(graph_results, str) else ""
        }
    except Exception as e:
        return {
            "rag_search_result": [],
            "graph_search_result": "",
            "error_message": f"检索失败: {str(e)}"
        }



async def generate_suggested_replies_baike(answer: str, question: str) -> List[Dict[str, Any]]:
    """
    生成针对问答结果的建议回复问题
    使用大模型生成两个相关问题
    """
    prompt = BAIKE_PROMPTS["generate_suggested_replies"].format(
        question=question,
        answer=answer[:500]
    )
    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(prompt, model=None, json_output=True)
        # 尝试解析JSON
        # 提取JSON部分
        json_match = re.search(r'\[.*\]', result, re.DOTALL)
        if json_match:
            json_str = json_match.group(0)
            suggested_replies = json.loads(json_str)
            # 验证格式
            if isinstance(suggested_replies, list) and len(suggested_replies) >= 2:
                # 确保每个元素都有title和content
                formatted_replies = []
                for reply in suggested_replies[:2]:
                    if isinstance(reply, dict) and "title" in reply and "content" in reply:
                        formatted_replies.append({
                            "title": str(reply["title"]),
                            "content": str(reply["content"])
                        })
                if len(formatted_replies) == 2:
                    return formatted_replies

        # 如果解析失败，返回默认问题
        return [
            {"title": "这个设备的具体工作原理是什么？", "content": "这个设备的具体工作原理是什么？"},
            {"title": "还有哪些相关的知识点？", "content": "还有哪些相关的知识点？"}
        ]
    except Exception as e:
        # 如果生成失败，返回默认问题
        return [
            {"title": "这个设备的具体工作原理是什么？", "content": "这个设备的具体工作原理是什么？"},
            {"title": "还有哪些相关的知识点？", "content": "还有哪些相关的知识点？"}
        ]


@track_function_calls
async def generate_answer(state: QAState) -> Dict[str, Any]:
    """
    正在生成问答结果
    """
    extracted_text = state.get("combined_query", "")
    rag_results = state.get("rag_search_result", [])
    graph_results = state.get("graph_search_result", "")
    history_messages = state.get("history_messages", []) or []
    need_retrieval = state.get("need_retrieval", True)
    print("history_message(qa)", history_messages)
    print("是否使用检索结果:", need_retrieval)

    try:
        # 1. 处理检索结果（如果有）
        rag_ctx_parts: List[str] = []
        file_name_list = []
        all_source_text = ""
        original_image_paths = []
        
        if need_retrieval:
            # 收集所有 RAG 结果文本（只取前 4 条）
            for item in sorted(rag_results or [], key=lambda x: float(x.get("score") or 0) if isinstance(x,dict) else 0, reverse=True)[:4]:
#            for item in (rag_results or [])[:1]:
                print(item)
                print(111111111111111111111111111)
                if isinstance(item, dict):
                    text = (item.get("text") or "").strip()
                    file_name = (item.get("filename") or "").strip()
                    if text:
                        rag_ctx_parts.append(text)
                    if file_name:
                        file_name_list.append(file_name)
            
            # 处理图谱结果
            print("123456", graph_results)
            if graph_results and "图谱检索完成，但未返回有效数据。" in graph_results:
                graph_results = ""
            print("654321", graph_results)
            
            # 从所有结果中提取图片路径
            if graph_results:
                all_source_text = graph_results + "\n" + "\n".join(rag_ctx_parts)
            else:
                all_source_text = "\n".join(rag_ctx_parts)
            original_image_paths = extract_image_paths(all_source_text)
            print("提取到的原始图片路径:", original_image_paths)
            
            # 发送事件通知（可选）
            title_options = [f"✨已综合 {len(rag_ctx_parts)} 条检索结果", f"✨本次检索策略为综合多源信息"]
            start_event = {
                "type": "function_execution",
                "title": random.choice(title_options),
                "details": f"综合了 {len(rag_ctx_parts)} 条检索结果"
            }
            for callback in get_all_callbacks():
                try:
                    callback(start_event)
                except Exception:
                    pass

        query_desc = extracted_text if extracted_text else "当前未明确描述问题"

        # 构建系统提示词
        if state.get("route_flag") == "rules":
            domain_desc = "舰船修理相关的法规、规范、行业标准及技术文件"
        else:
            domain_desc = "工业设备的结构原理、维护规程、故障诊断与维修操作"

        # ========== 第一步：专注于生成高质量内容 ==========
        # 根据是否有检索结果构建不同的提示词
        if need_retrieval and all_source_text.strip():
            content_system_prompt = BAIKE_PROMPTS["generate_answer_with_retrieval_system"].format(domain_desc=domain_desc)
            content_user_content = BAIKE_PROMPTS["generate_answer_with_retrieval_user"].format(
                extracted_text=extracted_text,
                rag_count=len(rag_ctx_parts),
                all_source_text=all_source_text
            )
        else:
            content_system_prompt = BAIKE_PROMPTS["generate_answer_without_retrieval_system"].format(domain_desc=domain_desc)
            content_user_content = BAIKE_PROMPTS["generate_answer_without_retrieval_user"].format(extracted_text=extracted_text)

        content_messages = []
        if history_messages:
            content_messages.extend(history_messages)
        content_messages.append({"role": "user", "content": content_user_content})

        # 第一步：生成内容
        raw_content = await OpenaiAPI.open_api_chat_without_thinking(
            model=None,
            system_prompt=content_system_prompt,
            messages=content_messages,
            temperature=0.5
        )

        # 过滤掉异常标签（如果有）
        raw_content = re.sub(r'ynchroneg>.*?ost switching>', '', raw_content, flags=re.DOTALL)
        raw_content = raw_content.strip() if raw_content else "抱歉，无法生成回答。"

        title_options = ["🤖 诊断分析中", "🤖 故障预检中"]
        start_event = {
            "type": "function_execution",
            "title": random.choice(title_options),
            "details": raw_content[:30] + "..."
        }
        for callback in get_all_callbacks():
            try:
                callback(start_event)
            except Exception:
                pass


        # ========== 第二步：专注于规范格式 ==========
        # 构建第二步的提示词：只关注格式规范，不修改内容
        format_system_prompt = COMMON_PROMPTS["format_system"]
        
        format_user_content = COMMON_PROMPTS["format_user_with_image_examples"].format(raw_content=raw_content)

        # 第二步：规范格式（流式输出）
        stream_handler = get_current_stream_handler()
        answer = ""
        accumulated_content = ""  # 用于逐步发送给前端的内容
        
        # 使用 async for 遍历流式生成器
        async for chunk in OpenaiAPI.open_api_chat_stream(
            model=None,
            system_prompt=format_system_prompt,
            messages=[{"role": "user", "content": format_user_content}],
            temperature=0.1
        ):
            answer += chunk
            accumulated_content += chunk
            # 每收到新的 chunk 就发送一次更新
            if stream_handler:
                stream_handler.send_stream_content(accumulated_content)

        answer = answer.strip() if answer else raw_content

        # LaTeX 公式空格规范化
        def normalize_latex_spacing(text: str) -> str:
            placeholder = "\x00DOUBLE_DOLLAR\x00"
            text = text.replace("$$", placeholder)
            text = re.sub(r'(?<!\s)\$', r' $', text)
            text = re.sub(r'\$(?!\s)', r'$ ', text)
            text = text.replace(placeholder, "$$")
            text = re.sub(r'(?<!\s)\$\$', r' $$', text)
            text = re.sub(r'\$\$(?!\s)', r'$$ ', text)
            return text

        answer = normalize_latex_spacing(answer)

        # 使用增强的图片路径匹配与规范化（仅在有检索结果时）
        if need_retrieval and original_image_paths:
            answer = normalize_markdown_images(answer, original_paths=original_image_paths)
        print("llm output", answer)

        # 生成建议回复问题
        suggested_replies = await generate_suggested_replies_baike(answer, extracted_text)

        return {
            "response": answer,
            "actions": [],
            "result_tag": "qa",
            "suggestedReplies": suggested_replies
        }
    except Exception as e:
        return {
            "response": f"生成回答失败：{str(e)}",
            "actions": [],
            "suggestedReplies": []
        }
def route_after_judge(state: QAState) -> str:
    """
    判断后的路由：根据need_retrieval决定下一步
    """
    need_retrieval = state.get("need_retrieval", True)
    if need_retrieval:
        return "rewrite_query_with_history"
    else:
        return "generate_answer"


# =============== 构建工作流 ===============
def create_baike_workflow():
    """创建普通问答工作流"""
    workflow = StateGraph(QAState)

    # 添加节点
    workflow.add_node("get_baike_history_context", get_baike_history_context)
    workflow.add_node("judge_need_retrieval", judge_need_retrieval)
    workflow.add_node("rewrite_query_with_history", rewrite_query_with_history)
    workflow.add_node("search_rag_and_graph", search_rag_and_graph)
    workflow.add_node("generate_answer", generate_answer)

    # 设置边
    workflow.add_edge(START, "get_baike_history_context")
    workflow.add_edge("get_baike_history_context", "judge_need_retrieval")
    workflow.add_conditional_edges(
        "judge_need_retrieval",
        route_after_judge,
        {
            "rewrite_query_with_history": "rewrite_query_with_history",
            "generate_answer": "generate_answer"
        }
    )
    workflow.add_edge("rewrite_query_with_history", "search_rag_and_graph")
    workflow.add_edge("search_rag_and_graph", "generate_answer")
    workflow.add_edge("generate_answer", END)

    # 编译工作流
    return workflow.compile()


# =============== 工作流执行函数 ===============
async def run_baike_workflow(
    extracted_text: str,
    combined_query: str,
    history_message: str = "",
    route_flag: str = ""
) -> Dict[str, Any]:
    """
    执行普通问答工作流（统一接口）

    Args:
        extracted_text: 文本描述（统一的输入参数）
        history_message: 历史消息（目前只接收，不做处理）

    Returns:
        工作流执行结果
    """
    # 创建并编译工作流
    app = create_baike_workflow()

    # 初始化状态（统一接口，只使用extracted_text和history_message）
    initial_state = {
        "extracted_text": extracted_text,
        "combined_query": combined_query,
        "retrieval_query": "",
        "route_flag": route_flag,
        "history_message": history_message,
        "history_messages": [],
        "need_retrieval": None,
        "rag_search_result": None,
        "graph_search_result": None,
        "response": "",
        "actions": [],
        "suggestedReplies": [],
        "error_message": ""
    }
    
    try:
        # 执行工作流（使用异步方式）
        final_state = await app.ainvoke(initial_state)
        
        # 检查是否有错误
        if final_state.get("error_message"):
            return {
                "response": f"普通问答工作流执行失败: {final_state['error_message']}",
                "actions": [],
                "result_tag": "qa",
                "suggestedReplies": []
            }
        
        # 统一输出格式：完全透传 generate_answer 的结果
        return {
            "response": final_state.get("response", ""),
            "actions": final_state.get("actions", []),
            "result_tag": "qa",
            "suggestedReplies": final_state.get("suggestedReplies", [])
        }
    
    except Exception as e:
        return {
            "response": f"普通问答工作流执行失败: {str(e)}",
            "actions": [],
            "result_tag": "qa",
            "suggestedReplies": []
        }



# =============== 测试 ===============
if __name__ == "__main__":
    import asyncio
    
    # 测试用例
    test_cases = [
        "船舰主发动机的安全警告是什么",
    ]
    
    async def test():
        for i, test_text in enumerate(test_cases, 1):
            print(f"\n{'='*60}")
            print(f"测试用例 {i}")
            print(f"{'='*60}")
            
            # ✅ 修复：传入 combined_query 参数
            result = await run_baike_workflow(
                extracted_text=test_text,
                combined_query=test_text
            )
            
            print(f"\n执行结果:")
            print(f"成功：{result.get('success', False)}")
            print(f"\n响应内容:")
            print(result.get("response", "无响应"))
    
    asyncio.run(test())





]H'x   """
故障诊断工作流 checkpointer 版本
"""
from typing import TypedDict, Optional, Dict, Any, List
from langgraph.graph import StateGraph, START, END
from langgraph.types import interrupt, Command
from tools.function_tool import graph_rag_search
from tools.rag_tools import rag_search
from tools.graph_tools import atlas_retrieval, format_atlas_results, extract_entity_names_from_history
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import get_all_callbacks
from utils.image_utils import extract_image_paths, normalize_markdown_images, get_image_prompt_guidance
from workflows.workflow_baike import run_baike_workflow
from workflows.workflow_utils import (
    safe_json_extract, parse_history, normalize_latex_spacing,
    remove_duplicate_content, convert_rag_result, calculate_info_completeness,
    emit_callback_event, build_history_str, build_detail_info,
    append_atlas_section, stream_format_and_postprocess,
)
from utils.word_generator import generate_report_word
from utils.intent_matcher import is_confirmation_intent
from config import KB_TREE_CONFIG, SERVER_CONFIG
from prompts import FAULT_DIAGNOSIS_PROMPTS, COMMON_PROMPTS
from tools.fault_record_db import record_fault_from_state
import json
import re
import random
import os
import time

class FaultDiagnosisState(TypedDict):
    """故障诊断工作流状态"""
    extracted_text: str
    combined_query: str
    history_messages: List[Dict[str, Any]]

    ship_number: str
    device_name: str
    fault: str
    additional_info: str
    fault_code: str
    fault_time: str
    fault_frequency: str
    tried_measures: str
    running_condition: str

    rag_search_result: Optional[List[Dict[str, Any]]]
    graph_search_result: Optional[str]
    deep_rag_results: Optional[Dict[str, Any]]

    response: str
    suggestedReplies: List[Dict[str, Any]]
    actions: List[Dict[str, Any]]
    error_message: str

    agent_decision: str
    agent_reasoning: str
    tools_to_call: List[str]
    missing_info: List[str]
    info_completeness: float

    matched_kb_id: str
    matched_kb_name: str

    iteration_count: int
    max_iterations: int
    scheme_generated: bool
    waiting_for_supplement: bool

    extracted_info: Dict[str, Any]
    has_rag_result: bool
    has_graph_result: bool
    ask_round: int
    user_confirmed_info: bool

    need_model_confirm: bool
    user_confirmed_model: bool

    user_feedback: str
    waiting_report_confirm: bool
    report_confirmed: bool

    initialized: bool
    current_node: str

    # 意图分类相关字段
    user_intent: str  # 用户初始意图: '维修', '百科'

    # 后续处理相关字段
    follow_up_intent: str  # 用户后续意图: 'not_solved', 'related_question', 'has_error', 'modify_info', 'other'
    user_feedback_for_regenerate: str  # 用户用于重新生成方案的反馈
    is_regenerating: bool  # 是否正在重新生成方案
    last_generated_scheme: str  # 最后一次生成的方案（用于基于反馈修改）
    scheme_type: str  # 方案类型：'normal' 普通方案，'deep' 深度方案
    deep_analysis_points: Optional[List[str]]  # 深度分析点（用于针对性检索）
    atlas_results: Optional[Dict[str, Any]]  # 图册检索结果
    last_combined_query: str  # 上一轮生成方案时的用户输入

def _preprocess_scheme_for_word(content: str) -> str:
    """
    预处理方案内容：将相对路径图片URL转为绝对URL
    图片格式解析和公式渲染由 word_generator.py 直接处理
    """
    if not content:
        return content

    base_url = SERVER_CONFIG.get("base_url", "").rstrip("/")

    kb_base_url = KB_TREE_CONFIG.get("url", "").rstrip("/")
    kb_host = ""
    if kb_base_url:
        from urllib.parse import urlparse
        kb_parsed = urlparse(kb_base_url)
        kb_host = f"{kb_parsed.scheme}://{kb_parsed.netloc}"

    # 知识库图片由知识库服务提供
    if kb_host:
        content = re.sub(
            r'(/api/v1/knowledge/files/[^)\s]+)',
            lambda m: f"{kb_host}{m.group(1)}" if not m.group(1).startswith("http") else m.group(1),
            content
        )
    elif base_url:
        content = re.sub(
            r'(/api/v1/knowledge/files/[^)\s]+)',
            lambda m: f"{base_url}{m.group(1)}" if not m.group(1).startswith("http") else m.group(1),
            content
        )

    # /picture/ 图片由本应用提供
    if base_url:
        content = re.sub(
            r'(/picture/[^)\s]+)',
            lambda m: f"{base_url}{m.group(1)}" if not m.group(1).startswith("http") else m.group(1),
            content
        )

    return content


def _generate_report_from_scheme(scheme_content: str, ship_number: str = "", device_name: str = "", fault: str = "") -> List[Dict[str, Any]]:
    """
    从方案内容直接生成报告并返回下载按钮
    
    Args:
        scheme_content: 方案内容（Markdown 格式）
        ship_number: 舷号
        device_name: 设备名称
        fault: 故障现象
    
    Returns:
        actions 列表，包含下载按钮（如果生成成功）
    """
    try:
        # 构建报告标题
        report_title = "维修方案报告"
        if ship_number:
            report_title = f"{ship_number} - {report_title}"
        if device_name:
            report_title = f"{report_title} - {device_name}"
        
        # 预处理方案内容：解析图片URL和公式格式
        processed_content = _preprocess_scheme_for_word(scheme_content)

        # 准备报告内容 - 直接使用方案内容，添加标题信息
        random_letters = ''.join(random.choices('ABCDEFGHIJKLMNOPQRSTUVWXYZ', k=2))
        report_number = time.strftime(f"{random_letters}-%Y-%m-%d-%H%M")
        compile_time = time.strftime("%Y-%m-%d %H:%M")
        
        # 构建报告内容
        report_content = f"""## **{report_title}**

报告编号：{report_number}
编制时间：{compile_time}

---

{processed_content}
"""
        
        # 确保 created_word 目录存在
        current_dir = os.path.dirname(os.path.abspath(__file__))
        parent_dir = os.path.dirname(current_dir)
        word_dir = os.path.join(parent_dir, "created_word")
        os.makedirs(word_dir, exist_ok=True)
        
        # 生成 Word 文档
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        safe_title = re.sub(r'[\\/:*?"<>|]', '_', report_title)
        file_name = f"{safe_title}_{timestamp}.docx"
        output_path = os.path.join(word_dir, file_name)
        
        word_result = generate_report_word(markdown=report_content,title=report_title,output=output_path)
        
        # 构建下载按钮
        actions = []
        if word_result and os.path.exists(word_result):
            base_url = SERVER_CONFIG.get("base_url", "")
            download_url = f"{base_url}/api/download/{file_name}"
            
            actions.append({"type": "download","label": f"{report_title}.docx","url": download_url,"fileName": file_name,"content": report_content})
            
            print(f"[_generate_report_from_scheme] 报告生成成功: {output_path}")
        
        return actions
        
    except Exception as e:
        print(f"[_generate_report_from_scheme] 生成报告失败: {e}")
        import traceback
        traceback.print_exc()
        return []

FAULT_INFO_WEIGHTS = {"ship_number": 0.20, "device_name": 0.20, "fault": 0.25, "fault_code": 0.08, "fault_time": 0.06, "fault_frequency": 0.06, "tried_measures": 0.06, "running_condition": 0.05, "additional_info": 0.04}

def _calculate_info_completeness(ship_number: str = "", device_name: str = "", fault: str = "", fault_code: str = "", fault_time: str = "", fault_frequency: str = "", tried_measures: str = "", running_condition: str = "", additional_info: str = "") -> float:
    values = {"ship_number": ship_number, "device_name": device_name, "fault": fault, "fault_code": fault_code, "fault_time": fault_time, "fault_frequency": fault_frequency, "tried_measures": tried_measures, "running_condition": running_condition, "additional_info": additional_info}
    return calculate_info_completeness(FAULT_INFO_WEIGHTS, values)

async def classify_intent(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    意图分类节点
    """
    combined_query = state.get("combined_query", "") or ""
    extracted_info = state.get("extracted_info", {}) or {}
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""

    # 如果已经提取过维修信息（有设备名或故障现象），说明已在维修流程中，继续维修流程
    if extracted_info or device_name or fault or ship_number:
        print("[classify_intent] 已在维修流程中，跳过意图分类")
        return {"user_intent": "维修","current_node": "extract_info",}

    system_prompt = FAULT_DIAGNOSIS_PROMPTS["classify_intent_system"]

    prompt = COMMON_PROMPTS["classify_intent_user"].format(combined_query=combined_query)

    try:
        response_text = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,json_output=True,system_prompt=system_prompt,messages=[])

        parsed = safe_json_extract(response_text)
        intent = "维修"
        if isinstance(parsed, dict):
            intent = parsed.get("intent", "维修")

        print(f"[意图分类] 用户意图: {intent}")

        if intent == "维修":
            return {"user_intent": intent,"scheme_generated": False,"current_node": "extract_info",}
        else:
            return {"user_intent": intent,"current_node": "follow_up_qa",}

    except Exception as e:
        print(f"[意图分类失败: {str(e)}，默认按维修处理")
        return {"user_intent": "维修","scheme_generated": False,"current_node": "extract_info",}

def _route_after_classify(state: FaultDiagnosisState) -> str:
    """意图分类后的路由"""
    intent = state.get("user_intent", "维修")
    if intent == "百科":
        return "follow_up_qa"
    return "extract_info"

async def extract_info(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    信息提取节点
    """
    if state.get("initialized", False):
        print("[extract_info] 已初始化，跳过")
        return {"current_node": "agent_think"}

    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []

    history_str = build_history_str(history_messages, recent_count=10)

    existing_info = []
    existing_ship_number = state.get("ship_number", "") or ""
    existing_device_name = state.get("device_name", "") or ""
    existing_fault = state.get("fault", "") or ""
    existing_fault_code = state.get("fault_code", "") or ""
    existing_fault_time = state.get("fault_time", "") or ""
    existing_fault_frequency = state.get("fault_frequency", "") or ""
    existing_tried_measures = state.get("tried_measures", "") or ""
    existing_running_condition = state.get("running_condition", "") or ""
    existing_additional_info = state.get("additional_info", "") or ""

    if existing_ship_number:
        existing_info.append(f"舷号: {existing_ship_number}")
    if existing_device_name:
        existing_info.append(f"设备名称: {existing_device_name}")
    if existing_fault:
        existing_info.append(f"故障现象: {existing_fault}")
    if existing_fault_code:
        existing_info.append(f"故障码: {existing_fault_code}")
    if existing_fault_time:
        existing_info.append(f"故障时间: {existing_fault_time}")
    if existing_fault_frequency:
        existing_info.append(f"故障频率: {existing_fault_frequency}")
    if existing_tried_measures:
        existing_info.append(f"已尝试措施: {existing_tried_measures}")
    if existing_running_condition:
        existing_info.append(f"运行工况: {existing_running_condition}")
    if existing_additional_info:
        existing_info.append(f"其他信息: {existing_additional_info}")

    existing_info_str = "\n".join(existing_info) if existing_info else "（无已提取信息）"

    system_prompt = FAULT_DIAGNOSIS_PROMPTS["extract_info_system"]

    prompt = COMMON_PROMPTS["extract_info_user"].format(
        biz_label="维修",
        existing_info_str=existing_info_str,
        history_str=history_str or '（无历史对话）',
        combined_query=combined_query
    )

    try:
        response_text = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,json_output=True,system_prompt=system_prompt,messages=[])

        parsed = safe_json_extract(response_text)
        if not isinstance(parsed, dict):
            parsed = {}

        new_ship_number = parsed.get("ship_number", "") or existing_ship_number
        new_device_name = parsed.get("device_name", "") or existing_device_name
        new_fault = parsed.get("fault", "") or existing_fault
        new_fault_code = parsed.get("fault_code", "") or existing_fault_code
        new_fault_time = parsed.get("fault_time", "") or existing_fault_time
        new_fault_frequency = parsed.get("fault_frequency", "") or existing_fault_frequency
        new_tried_measures = parsed.get("tried_measures", "") or existing_tried_measures
        new_running_condition = parsed.get("running_condition", "") or existing_running_condition
        new_additional_info = parsed.get("additional_info", "") or existing_additional_info

        extracted_info = {"ship_number": new_ship_number,"device_name": new_device_name,"fault": new_fault,"fault_code": new_fault_code,"fault_time": new_fault_time,"fault_frequency": new_fault_frequency,"tried_measures": new_tried_measures,"running_condition": new_running_condition,"additional_info": new_additional_info,}

        print(f"[信息提取] 舷号={extracted_info['ship_number']}, 设备={extracted_info['device_name']}, 故障={extracted_info['fault']}")

        return {**extracted_info,"extracted_info": extracted_info,"initialized": True,"current_node": "agent_think",}

    except Exception as e:
        print(f"信息提取失败: {str(e)}")
        return {"initialized": True,"current_node": "agent_think",}

async def agent_think(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    Agent 思考节点：基于当前状态决定下一步动作
    """
    combined_query = state.get("combined_query", "") or ""
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    fault_code = state.get("fault_code", "") or ""
    fault_time = state.get("fault_time", "") or ""
    fault_frequency = state.get("fault_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""
    history_messages = state.get("history_messages", []) or []

    scheme_generated = state.get("scheme_generated", False)
    has_rag_result = state.get("has_rag_result", False)
    has_graph_result = state.get("has_graph_result", False)

    rag_search_result = state.get("rag_search_result")
    graph_search_result = state.get("graph_search_result")
    iteration_count = state.get("iteration_count", 0)

    user_confirmed_info = state.get("user_confirmed_info", False)
    waiting_feedback = state.get("waiting_feedback", False)

    has_ship = bool(ship_number and ship_number.strip())
    has_device = bool(device_name and device_name.strip())
    has_fault = bool(fault and fault.strip())
    has_rag = (rag_search_result is not None and len(rag_search_result) > 0) or has_rag_result
    has_graph = (graph_search_result is not None and len(graph_search_result) > 100) or has_graph_result

    info_completeness = _calculate_info_completeness(ship_number=ship_number,device_name=device_name,fault=fault,fault_code=fault_code,fault_time=fault_time,fault_frequency=fault_frequency,tried_measures=tried_measures,running_condition=running_condition,additional_info=additional_info)

    MIN_COMPLETENESS_FOR_GENERATE = 0.25

    if scheme_generated:
        _re_diagnose_keywords = ["开始诊断", "信息已足够", "信息已足够，开始诊断", "开始", "诊断"]
        _is_re_diagnose = any(kw in combined_query for kw in _re_diagnose_keywords)
        if _is_re_diagnose:
            print(f"[重新诊断] 检测到重新诊断意图: '{combined_query}'，重置状态直接调用工具生成方案")
            tools_to_call = ["rag_search"]
            if device_name and fault:
                tools_to_call.append("graph_rag_search")
            return {"scheme_generated": False,"rag_search_result": None,"graph_search_result": None,"deep_rag_results": None,"has_rag_result": False,"has_graph_result": False,"is_regenerating": False,"user_feedback_for_regenerate": "","follow_up_intent": "","user_confirmed_info": True,"initialized": True,"iteration_count": 0,"ask_round": 0,"agent_decision": "call_tools","tools_to_call": tools_to_call,"current_node": "call_tools",}

        history_str = build_history_str(history_messages, recent_count=8, assistant_truncate=300)

        intent_system_prompt = FAULT_DIAGNOSIS_PROMPTS["agent_think_intent_system"]

        intent_prompt = FAULT_DIAGNOSIS_PROMPTS["agent_think_intent_user"].format(
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            fault=fault or '未提供',
            history_str=history_str or '无',
            combined_query=combined_query
        )

        try:
            intent_response = await OpenaiAPI.open_api_chat_without_thinking(
                query=intent_prompt,
                model=None,
                json_output=True,
                system_prompt=intent_system_prompt,
                messages=[]
            )

            parsed_intent = safe_json_extract(intent_response)
            intent = "other"
            if isinstance(parsed_intent, dict):
                intent = parsed_intent.get("intent", "other")

            print(f"[Agent 意图分析] 用户意图: {intent}")

            # 根据大模型判断的意图来决定下一步
            if intent == "generate_report":
                decision = "generate_report"
                reasoning = "用户请求生成报告"
                print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
                return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            elif intent == "modify_info":
                # 修改信息，跳转到 confirm_info，重置状态
                decision = "confirm_info"
                reasoning = "用户需要修改或补充信息"
                return {"agent_decision": decision,"agent_reasoning": reasoning,"rag_search_result": None,"graph_search_result": None,"deep_rag_results": None,"has_rag_result": False,"has_graph_result": False,"scheme_generated": False,"is_regenerating": False,"user_feedback_for_regenerate": "","follow_up_intent": "","user_confirmed_info": False,"initialized": False,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            elif intent == "has_error":
                decision = "handle_feedback"
                reasoning = "用户反馈方案有错误"
                print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
                return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            elif intent == "not_solved":
                decision = "analyze_follow_up_intent"
                reasoning = "已生成方案，分析用户后续意图"
                # 设置 follow_up_intent，让 analyze_follow_up_intent 直接知道
                return {"agent_decision": decision,"agent_reasoning": reasoning,"follow_up_intent": "not_solved","info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            elif intent == "related_question":
                decision = "analyze_follow_up_intent"
                reasoning = "已生成方案，分析用户后续意图"
                return {"agent_decision": decision,"agent_reasoning": reasoning,"follow_up_intent": "related_question","info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            else:
                # other 情况，直接跳转到 follow_up_qa，不需要经过 analyze_follow_up_intent
                decision = "follow_up_qa"
                reasoning = "其他意图，直接调用 baike"
                print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
                return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
        except Exception as e:
            print(f"[Agent 意图分析失败: {str(e)}")
            # 大模型判断失败，降级到原来的逻辑
            decision = "analyze_follow_up_intent"
            reasoning = "已生成方案，分析用户后续意图"
            print(f"[Agent 决策] decision={decision}, reasoning={reasoning} (降级)")
            return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}

    if not has_device or not has_fault:
        decision = "ask_user"
        missing_info = []
        if not has_device:
            missing_info.append("设备名称")
        if not has_fault:
            missing_info.append("故障现象")
        reasoning = f"缺少基本信息: {', '.join(missing_info)}"
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"missing_info": missing_info,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}

    if info_completeness < MIN_COMPLETENESS_FOR_GENERATE:
        decision = "ask_user"
        reasoning = f"信息完整性评分 {info_completeness} 低于最低要求 {MIN_COMPLETENESS_FOR_GENERATE}"
        missing_info = []
        if not ship_number:
            missing_info.append("舷号（可选）")
        if not fault_code:
            missing_info.append("故障码")
        if not fault_time:
            missing_info.append("故障时间")
        if not fault_frequency:
            missing_info.append("故障频率")
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"missing_info": missing_info or ["更多详细信息"],"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}

    if has_rag or has_graph:
        decision = "generate_response"
        reasoning = "信息充足，已有检索结果，直接生成回复"
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}    

    if not user_confirmed_info:
        decision = "confirm_info"
        reasoning = "信息充足，需要用户确认后再检索知识库"
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}    

    decision = "call_tools"
    reasoning = "信息充足，用户已确认，开始检索知识库"
    tools_to_call = ["rag_search"]
    if has_device and has_fault:
        tools_to_call.append("graph_rag_search")

    print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
    print(f"[Agent 提取] 舷号={ship_number}, 设备={device_name}, 故障={fault}")

    emit_callback_event(["🤖 Agent 思考中", "🤖 智能分析", "🤖 决策判断"], f"决策: {decision} | 理由: {reasoning[:50]}...")

    return {"agent_decision": decision,"agent_reasoning": reasoning,"tools_to_call": tools_to_call,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}    

async def ask_user(state: FaultDiagnosisState) -> Command:
    """
    询问用户节点：使用 interrupt 暂停等待用户输入
    """
    missing_info = state.get("missing_info", [])
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    fault_code = state.get("fault_code", "") or ""
    fault_time = state.get("fault_time", "") or ""
    fault_frequency = state.get("fault_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""
    combined_query = state.get("combined_query", "") or ""
    info_completeness = state.get("info_completeness", 0)
    ask_round = state.get("ask_round", 0)

    MAX_ASK_ROUNDS = 4
    if ask_round >= MAX_ASK_ROUNDS:
        print(f"[ask_user] 已达到最大询问轮次 {MAX_ASK_ROUNDS}，强制进入下一步")
        tools_to_call = ["rag_search"]
        if device_name and fault:
            tools_to_call.append("graph_rag_search")
        return Command(
            update={"ask_round": ask_round + 1,"current_node": "call_tools","tools_to_call": tools_to_call,},
            goto="call_tools"
        )

    existing_parts = []
    if ship_number:
        existing_parts.append(f"舷号: {ship_number}")
    if device_name:
        existing_parts.append(f"设备名称: {device_name}")
    if fault:
        existing_parts.append(f"故障现象: {fault}")
    if fault_code:
        existing_parts.append(f"故障码: {fault_code}")
    if fault_time:
        existing_parts.append(f"发生时间: {fault_time}")
    if fault_frequency:
        existing_parts.append(f"故障频率: {fault_frequency}")
    if tried_measures:
        existing_parts.append(f"已尝试措施: {tried_measures}")
    if running_condition:
        existing_parts.append(f"运行工况: {running_condition}")
    if additional_info:
        existing_parts.append(f"其他信息: {additional_info}")

    existing_str = "；".join(existing_parts) if existing_parts else "暂无"
    missing_str = "、".join(missing_info) if missing_info else "相关信息"

    system_prompt = COMMON_PROMPTS["ask_user_system"].format(biz_label="故障诊断", biz_label_short="诊断")

    prompt = COMMON_PROMPTS["ask_user_prompt"].format(
        info_completeness=info_completeness,
        existing_str=existing_str,
        missing_str=missing_str,
        combined_query=combined_query
    )

    response = ""
    try:
        response = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,system_prompt=system_prompt,messages=[])
        response = response.strip() if response else ""
    except Exception as e:
        print(f"[ask_user] API调用失败: {str(e)}")
        response = ""

    if not response:
        response = f"**【需要更多信息】**\n\n请补充：{missing_str}\n\n提供这些信息后，我可以更准确地为您诊断故障。"

    if existing_parts:
        existing_info_section = f"\n**📋 已获取的信息：**\n\n" + "\n".join(
            f"- {part}" for part in existing_parts) + "\n\n---\n"
        response = existing_info_section + response

    suggested_replies = []
    if "舷号" in missing_info:
        suggested_replies.append({"title": "补充舷号", "content": "舷号："})
    if "设备名称" in missing_info:
        suggested_replies.append({"title": "补充设备名称", "content": "设备名称："})
    if "故障现象" in missing_info:
        suggested_replies.append({"title": "补充故障现象", "content": "故障现象："})

    user_input = interrupt({"response": response,"suggestedReplies": suggested_replies,"waiting_for": "user_input","missing_info": missing_info,})

    user_query = user_input.get("query", "")

    update_dict = {"combined_query": user_query,"current_node": "agent_think","ask_round": ask_round + 1,}

    if user_query:
        extract_prompt = FAULT_DIAGNOSIS_PROMPTS["ask_user_extract"].format(
            missing_str=missing_str,
            user_query=user_query
        )

        try:
            extract_response = await OpenaiAPI.open_api_chat_without_thinking(query=extract_prompt,model=None,json_output=True,system_prompt="你是信息提取专家。",messages=[])
            extracted = safe_json_extract(extract_response)
            if isinstance(extracted, dict):
                if extracted.get("ship_number"):
                    update_dict["ship_number"] = extracted["ship_number"]
                    print(f"[ask_user] 提取到舷号: {extracted['ship_number']}")
                if extracted.get("device_name"):
                    update_dict["device_name"] = extracted["device_name"]
                    print(f"[ask_user] 提取到设备名称: {extracted['device_name']}")
                if extracted.get("fault"):
                    update_dict["fault"] = extracted["fault"]
                    print(f"[ask_user] 提取到故障现象: {extracted['fault']}")
        except Exception as e:
            print(f"[ask_user] 信息提取失败: {str(e)}")

    return Command(
        update=update_dict,
        goto="agent_think"
    )

async def confirm_info(state: FaultDiagnosisState) -> Command:
    """
    确认信息节点：重点询问用户是否需要补充信息
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    fault_code = state.get("fault_code", "") or ""
    fault_time = state.get("fault_time", "") or ""
    fault_frequency = state.get("fault_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""
    info_completeness = state.get("info_completeness", 0)

    existing_parts = []
    if ship_number:
        existing_parts.append(f"舷号: {ship_number}")
    if device_name:
        existing_parts.append(f"设备名称: {device_name}")
    if fault:
        existing_parts.append(f"故障现象: {fault}")
    if fault_code:
        existing_parts.append(f"故障码: {fault_code}")
    if fault_time:
        existing_parts.append(f"发生时间: {fault_time}")
    if fault_frequency:
        existing_parts.append(f"故障频率: {fault_frequency}")
    if tried_measures:
        existing_parts.append(f"已尝试措施: {tried_measures}")
    if running_condition:
        existing_parts.append(f"运行工况: {running_condition}")
    if additional_info:
        existing_parts.append(f"其他信息: {additional_info}")

    existing_str = "\n".join(f"- {part}" for part in existing_parts) if existing_parts else "暂无"

    additional_prompt = ""
    if not ship_number:
        additional_prompt = "\n\n💡 **提示**：如果您知道舷号，请补充，这将有助于我们更准确地生成报告。"

    response = f"""**📋 已收集到的信息：**

{existing_str}

**信息完整性评分：** {info_completeness:.0%}

---

**💡 请问是否需要补充其他信息？**
- 如故障码、故障时间、故障频率、已尝试措施、运行工况等
- 如果信息已足够，请点击"开始诊断"{additional_prompt}
"""

    emit_callback_event(["✅ 信息确认", "📋 请确认信息", "🔍 准备检索"], f"等待用户确认或补充信息 (完整性: {info_completeness:.0%})")

    suggested_replies = [{"title": "开始诊断", "content": "信息已足够，开始诊断"},{"title": "补充信息", "content": "我需要补充："}]

    user_input = interrupt({"response": response,"suggestedReplies": suggested_replies,"waiting_for": "user_confirm",})

    user_query = user_input.get("query", "")

    if await is_confirmation_intent(user_query):
        print(f"[confirm_info] 用户确认信息足够，准备调用工具")
        tools_to_call = ["rag_search"]
        if device_name and fault:
            tools_to_call.append("graph_rag_search")
        return Command(
            update={"user_confirmed_info": True,"current_node": "call_tools","tools_to_call": tools_to_call,},
            goto="call_tools"
        )
    else:
        print(f"[confirm_info] 用户需要补充信息: {user_query}")
        return Command(
            update={"user_confirmed_info": False,"combined_query": user_query,"initialized": False,"current_node": "extract_info",},
            goto="extract_info"
        )

async def call_tools(state: FaultDiagnosisState) -> Dict[str, Any]:
    """调用检索工具"""
    tools_to_call = state.get("tools_to_call", [])
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    additional_info = state.get("additional_info", "") or ""

    rag_results = state.get("rag_search_result")
    graph_results = state.get("graph_search_result")
    atlas_results = {}

    matched_kb_name = ""
    matched_kb_id = ""
    mapped_ship_number = ""

    if "rag_search" in tools_to_call and rag_results is None:
        from utils.ship_number_search import search_with_ship_number_strategy
        
        base_query = f"{device_name}发生{fault}该如何解决"
        
        rag_results, matched_kb_name, matched_kb_id, mapped_ship_number = await search_with_ship_number_strategy(base_query=base_query,ship_number=ship_number,top_k=5,search_type="fault")
        
        if not matched_kb_name:
            matched_kb_name = "通用知识库"

        print(f"RAG 检索来源: {matched_kb_name}")

    if mapped_ship_number and mapped_ship_number != ship_number:
        print(f"[call_tools] 舷号映射: '{ship_number}' -> '{mapped_ship_number}'，更新工作流状态")
        ship_number = mapped_ship_number

    if "graph_rag_search" in tools_to_call and graph_results is None:
        if device_name and fault:
            try:
                graph_query = f"{device_name}发生{fault}该如何解决"
                graph_results = await graph_rag_search.ainvoke({"query": graph_query})
                print(f"图谱检索完成，结果长度: {len(graph_results) if graph_results else 0}")
            except Exception as e:
                print(f"图谱检索失败: {str(e)}")
                graph_results = ""

    # 图册检索：只传入设备名称
    if device_name:
        try:
            print(f"[图册检索] 使用设备名称: {device_name}")
            atlas_result = await atlas_retrieval(node_names=[device_name], top_k=10)
            if atlas_result.get("success", False):
                atlas_results = atlas_result.get("data", {})
                print(f"[图册检索] 图册检索结果: {list(atlas_results.keys())}")
        except Exception as e:
            print(f"[图册检索] 图册检索失败: {str(e)}")

    has_rag = bool(rag_results and len(rag_results) > 0)
    has_graph = bool(graph_results and len(graph_results) > 100)

    if not has_rag and not has_graph:
        print(f"[call_tools] 未找到任何相关资料，需要用户确认使用模型能力")
        return {"rag_search_result": rag_results if isinstance(rag_results, list) else [],"graph_search_result": graph_results if isinstance(graph_results, str) else "","atlas_results": atlas_results,"matched_kb_id": matched_kb_id,"matched_kb_name": matched_kb_name,"ship_number": ship_number,"has_rag_result": False,"has_graph_result": False,"need_model_confirm": True,"current_node": "model_confirm",}

    return {"rag_search_result": rag_results,"graph_search_result": graph_results,"atlas_results": atlas_results,"matched_kb_id": matched_kb_id,"matched_kb_name": matched_kb_name,"ship_number": ship_number,"has_rag_result": has_rag,"has_graph_result": has_graph,"need_model_confirm": False,"current_node": "generate_response",}

async def model_confirm(state: FaultDiagnosisState) -> Command:
    """
    模型能力确认节点：当没有找到任何资料时，让用户确认是否使用模型本身能力
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""

    response = f"""**⚠️ 未找到相关资料**

抱歉，在知识库中未找到与以下信息相关的资料：
- 舷号：{ship_number or '未提供'}
- 设备名称：{device_name or '未提供'}
- 故障现象：{fault or '未提供'}

**💡 您可以选择：**
- 使用 AI 模型的知识库为您生成一般性建议
- 提供更详细的信息重新检索

请问是否使用 AI 模型为您生成建议？"""

    emit_callback_event(["🤖 AI 模型确认", "⚠️ 资料未找到", "💡 使用模型能力"], "使用模型自身知识进行回复")

    suggested_replies = [{"title": "使用 AI 模型", "content": "确认，使用 AI 模型生成建议"},{"title": "补充信息", "content": "我需要补充更多信息："},]

    user_input = interrupt({"response": response,"suggestedReplies": suggested_replies,"waiting_for": "model_confirm",})

    user_query = user_input.get("query", "")

    if "确认" in user_query or "AI" in user_query or "模型" in user_query:
        print(f"[model_confirm] 用户确认使用模型能力")
        return Command(
            update={"user_confirmed_model": True,"combined_query": user_query,"current_node": "generate_response",},
            goto="generate_response"
        )
    else:
        print(f"[model_confirm] 用户选择补充信息: {user_query}")
        return Command(
            update={"user_confirmed_model": False,"combined_query": user_query,"current_node": "agent_think",},
            goto="agent_think"
        )

async def generate_response(state: FaultDiagnosisState) -> Dict[str, Any]:
    """生成最终回复"""
    print("========================生成最终回复========================")
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    additional_info = state.get("additional_info", "") or ""
    fault_code = state.get("fault_code", "") or ""
    fault_time = state.get("fault_time", "") or ""
    fault_frequency = state.get("fault_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    rag_results = state.get("rag_search_result") or []
    graph_results = state.get("graph_search_result") or ""
    scheme_generated = state.get("scheme_generated", False)
    matched_kb_name = state.get("matched_kb_name", "")

    print("rag_results", rag_results)
    history_str = build_history_str(history_messages, recent_count=12, assistant_truncate=500)

    has_rag = rag_results and len(rag_results) > 0
    has_graph = graph_results and len(graph_results) > 100

    if not has_rag and not has_graph:
        if not ship_number and not device_name and not fault:
            system_prompt = COMMON_PROMPTS["generate_response_friendly_system"].format(biz_label="故障诊断")
            prompt = COMMON_PROMPTS["generate_response_friendly_user"].format(combined_query=combined_query)
        else:
            system_prompt = COMMON_PROMPTS["generate_response_no_rag_system"].format(biz_label="故障诊断")
            prompt = FAULT_DIAGNOSIS_PROMPTS["generate_response_no_rag_user"].format(
                ship_number=ship_number or '未提供',
                device_name=device_name or '未提供',
                fault=fault or '未提供',
                fault_code=fault_code or '未提供',
                fault_time=fault_time or '未提供',
                fault_frequency=fault_frequency or '未提供',
                tried_measures=tried_measures or '未提供',
                running_condition=running_condition or '未提供',
                additional_info=additional_info or '无'
            )

        try:
            response = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,system_prompt=system_prompt,messages=[])
            return {"response": response.strip() if response else "抱歉，未能找到相关资料。","suggestedReplies": [{"title": "提供更详细信息", "content": "我来提供更详细的信息"},],"current_node": "end",}
        except Exception as e:
            return {"response": f"抱歉，处理过程中出现错误: {str(e)}","suggestedReplies": [],"current_node": "end",}

    rag_ctx_parts: List[str] = []
    if isinstance(rag_results, str) and rag_results.strip():
        rag_ctx_parts = [rag_results.strip()]
    elif isinstance(rag_results, list):
        for item in sorted(rag_results or [], key=lambda x: float(x.get("score") or 0) if isinstance(x,dict) else 0, reverse=True)[:4]:
#        for item in rag_results[:8]:
            if isinstance(item, dict):
                text = (item.get("text") or "").strip()
                if text:
                    rag_ctx_parts.append(text)
            elif isinstance(item, str) and item.strip():
                rag_ctx_parts.append(item.strip())

    if len(graph_results) <= 50:
        graph_results = ""

    all_source_text = graph_results + "\n" + "\n".join(rag_ctx_parts) if graph_results else "\n".join(rag_ctx_parts)
    original_image_paths = extract_image_paths(all_source_text)
    print("提取到的原始图片路径:", original_image_paths)

    rag_answer = ""
    rag_type = "none"

    if graph_results and len(graph_results) > 50:
        rag_answer = graph_results
        rag_type = "graph"
    elif rag_ctx_parts:
        rag_answer = "\n\n".join(rag_ctx_parts)
        rag_type = "rag"

    if not rag_answer or rag_answer == "NO_RELEVANT_RESULT":
        system_prompt = COMMON_PROMPTS["generate_response_no_rag_simple_system"].format(biz_label="故障诊断")
        prompt = FAULT_DIAGNOSIS_PROMPTS["generate_response_no_rag_simple_user"].format(
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            fault=fault or '未提供'
        )

        try:
            response = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,system_prompt=system_prompt,messages=[])
            return {"response": response.strip() if response else "抱歉，未能找到相关资料。","suggestedReplies": [],"current_node": "end",}
        except Exception as e:
            return {"response": f"抱歉，处理过程中出现错误: {str(e)}","suggestedReplies": [],"current_node": "end",}

    rag_type = "图谱" if rag_type == "graph" else "文本"

    emit_callback_event([f"✨当前使用的检索类型为{rag_type}", f"✨本次检索策略为{rag_type}"], f"内容为{rag_answer[:50]}...")

    detail_info = ""
    if fault_code:
        detail_info += f"- 故障码/报警代码：{fault_code}\n"
    if fault_time:
        detail_info += f"- 故障发生时间：{fault_time}\n"
    if fault_frequency:
        detail_info += f"- 故障频率/持续时间：{fault_frequency}\n"
    if tried_measures:
        detail_info += f"- 已尝试的维修措施：{tried_measures}\n"
    if running_condition:
        detail_info += f"- 设备运行工况：{running_condition}\n"
    if additional_info:
        detail_info += f"- 其他相关信息：{additional_info}\n"

    is_regenerating = state.get("is_regenerating", False)
    user_feedback_for_regenerate = state.get("user_feedback_for_regenerate", "")
    is_follow_up = scheme_generated and (has_rag or has_graph) and not is_regenerating

    image_guidance = get_image_prompt_guidance()
    if is_regenerating and user_feedback_for_regenerate:
        prompt = COMMON_PROMPTS["generate_response_regenerating"].format(
            biz_label="维修",
            item_label="故障现象",
            item_name=fault or '未提供',
            item_action="分析故障原因，给出维修方案",
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            fault=fault or '未提供',
            detail_info=detail_info,
            user_feedback_for_regenerate=user_feedback_for_regenerate,
            rag_answer=rag_answer,
            image_guidance=image_guidance
        )
    elif is_follow_up:
        prompt = COMMON_PROMPTS["generate_response_follow_up"].format(
            biz_label="维修",
            item_label="故障现象",
            item_name=fault or '未提供',
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            fault=fault or '未提供',
            detail_info=detail_info,
            rag_answer=rag_answer,
            combined_query=combined_query,
            image_guidance=image_guidance
        )
    else:
        prompt = COMMON_PROMPTS["generate_response_normal"].format(
            biz_label="维修",
            item_label="故障现象",
            item_name=fault or '未提供',
            item_action="分析故障原因，给出维修方案",
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            fault=fault or '未提供',
            detail_info=detail_info,
            rag_answer=rag_answer
        )

    try:
        # ========== 第一步：专注于生成高质量内容 ==========
        content_system_prompt = COMMON_PROMPTS["generate_response_content_system"].format(biz_label="维修")

        raw_content = await OpenaiAPI.open_api_chat_without_thinking(model=None,system_prompt=content_system_prompt,messages=[{"role": "user", "content": prompt}],)

        raw_content = raw_content.strip() if raw_content else "抱歉，无法生成回答。"

        emit_callback_event(["🤖 诊断分析中", "🤖 故障预检中"], raw_content[:30] + "...")

        answer = await stream_format_and_postprocess(raw_content, original_image_paths, temperature=0.3)

#        scheme_source = f"# 本方案依据{rag_type}知识库生成。"
#        answer = f"{scheme_source}\n\n{answer}"
        answer = answer
#        answer = ""        

        atlas_results = state.get("atlas_results", {})
        answer = append_atlas_section(answer, atlas_results)

        if not is_follow_up:
            supplement_prompt = """

---

**💡 请您确认维修方案是否正确：**
- 如果方案有误或需要调整，请告诉我具体的错误之处
- 我会根据您的反馈重新生成更准确的方案

请问方案是否有需要修改的地方？"""
            answer += supplement_prompt

        suggested_replies = [{"title": "方案有误", "content": "方案有误，需要修改："},]

        # 生成报告并添加下载按钮
        actions = _generate_report_from_scheme(scheme_content=answer,ship_number=ship_number,device_name=device_name,fault=fault)

        if not is_follow_up:
            try:
                await record_fault_from_state({"ship_number": ship_number,"device_name": device_name,"fault": fault,"last_generated_scheme": answer,})
            except Exception as rec_err:
                print(f"[generate_response] 记录故障信息失败: {rec_err}")

        return {"response": answer,"actions": actions,"suggestedReplies": suggested_replies,"scheme_generated": True,"waiting_feedback": not is_follow_up,"last_generated_scheme": answer,"scheme_type": "normal","current_node": "end","last_combined_query": combined_query,}

    except Exception as e:
        return {"response": f"分析生成失败: {str(e)}","actions": [],"suggestedReplies": [],"current_node": "end",}

async def analyze_follow_up_intent(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    分析用户后续意图节点：直接使用 agent_think 已经判断好的意图
    agent_think 已经用大模型判断并设置了 follow_up_intent
    """
    # 直接使用已经判断好的意图
    intent = state.get("follow_up_intent", "other")

    print(f"[意图分析] 使用已判断的意图: {intent}")

    return {"follow_up_intent": intent,}

async def deep_rag_search(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    深层次RAG检索节点：分析之前方案并选择深度分析点进行检索
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    fault_code = state.get("fault_code", "") or ""
    additional_info = state.get("additional_info", "") or ""
    fault_time = state.get("fault_time", "") or ""
    fault_frequency = state.get("fault_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    last_generated_scheme = state.get("last_generated_scheme", "") or ""

    deep_results = {}
    deep_analysis_points = []

    emit_callback_event(["🔍 深度检索中", "🔍 多维度检索", "🔍 精细分析"], "分析问题并选择深度分析点")

    # ========== 第一步：分析之前方案和用户问题，选择深度分析点 ==========
    if last_generated_scheme or combined_query:
        try:
            history_str = build_history_str(history_messages, recent_count=8, assistant_truncate=300)

            detail_info = ""
            if fault_code:
                detail_info += f"- 故障码/报警代码：{fault_code}\n"
            if fault_time:
                detail_info += f"- 故障发生时间：{fault_time}\n"
            if fault_frequency:
                detail_info += f"- 故障频率/持续时间：{fault_frequency}\n"
            if tried_measures:
                detail_info += f"- 已尝试的维修措施：{tried_measures}\n"
            if running_condition:
                detail_info += f"- 设备运行工况：{running_condition}\n"
            if additional_info:
                detail_info += f"- 其他相关信息：{additional_info}\n"

            analysis_system_prompt = COMMON_PROMPTS["deep_rag_analysis_system"].format(biz_label="维修")

            analysis_prompt = COMMON_PROMPTS["deep_rag_analysis_user"].format(
                item_label="故障现象",
                item_name=fault or '未提供',
                ship_number=ship_number or '未提供',
                device_name=device_name or '未提供',
                fault=fault or '未提供',
                detail_info=detail_info,
                history_str=history_str or '（无历史对话）',
                last_generated_scheme=last_generated_scheme or '（无之前的方案）',
                combined_query=combined_query
            )

            analysis_response = await OpenaiAPI.open_api_chat_without_thinking(query=analysis_prompt,model=None,json_output=True,system_prompt=analysis_system_prompt,messages=[])
            print("深度分析点", analysis_response)
            parsed_analysis = safe_json_extract(analysis_response)
            deep_analysis_points = parsed_analysis
            print(f"[深度RAG] 选择的分析点: {deep_analysis_points}")
        except Exception as e:
            print(f"[深度RAG] 分析失败: {str(e)}")

    # ========== 第二步：对选中的分析点进行检索 ==========
    for idx, point in enumerate(deep_analysis_points):
        try:
            print(point)
            # 结合设备名和故障名进行检索，提高准确性
            search_query = point
            if device_name and device_name not in point:
                search_query = f"{device_name} {search_query}"
            if fault and fault not in search_query:
                search_query = f"{search_query} {fault}"
            
            rag_result = await rag_search(search_query, top_k=3)
            if rag_result.get("success", False):
                deep_results[f"analysis_point_{idx}"] = convert_rag_result(rag_result)
            else:
                deep_results[f"analysis_point_{idx}"] = []
        except Exception as e:
            print(f"[深度RAG] 分析点 {point} 检索失败: {str(e)}")
            deep_results[f"analysis_point_{idx}"] = []

    # ========== 第三步：图册检索 ==========
    atlas_results = {}
    try:
        # 从历史记录和当前信息中抽取实体名称
        entity_names = await extract_entity_names_from_history(history_messages=history_messages,device_name=device_name,fault=fault,last_generated_scheme=last_generated_scheme)
        
        if entity_names:
            print(f"[深度RAG] 图册检索实体: {entity_names}")
            atlas_result = await atlas_retrieval(node_names=entity_names, top_k=10)
            if atlas_result.get("success", False):
                atlas_results = atlas_result.get("data", {})
                print(f"[深度RAG] 图册检索结果: {list(atlas_results.keys())}")
    except Exception as e:
        print(f"[深度RAG] 图册检索失败: {str(e)}")

    return {"deep_rag_results": deep_results,"deep_analysis_points": deep_analysis_points,"atlas_results": atlas_results,"current_node": "generate_deep_response",}

async def generate_deep_response(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    生成深度响应节点：基于深度RAG结果进行深度润色和推理
    """
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    fault_code = state.get("fault_code", "") or ""
    fault_time = state.get("fault_time", "") or ""
    fault_frequency = state.get("fault_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""

    deep_rag_results = state.get("deep_rag_results", {})
    deep_analysis_points = state.get("deep_analysis_points", [])
    atlas_results = state.get("atlas_results", {})
    graph_results = state.get("graph_search_result", "") or ""
    original_rag_results = state.get("rag_search_result", [])

    # 整理深度分析点资料
    analysis_points_text = ""
    if deep_analysis_points:
        for idx, point in enumerate(deep_analysis_points):
            key = f"analysis_point_{idx}"
            results = deep_rag_results.get(key, [])
            if results:
                analysis_points_text += f"\n【分析点：{point}】\n"
                for i, item in enumerate(results[:2], 1):
                    if isinstance(item, dict):
                        text = item.get("text", "")
                        if text:
                            analysis_points_text += f"[{i}] {text}\n"

    # 整理原始RAG结果
    original_rag_text = ""
    if original_rag_results:
        original_rag_text = "\n【原始检索资料】\n"
        for i, item in enumerate(original_rag_results[:3], 1):
            if isinstance(item, dict):
                text = item.get("text", "")
                if text:
                    original_rag_text += f"[{i}] {text}\n"

    # 整理图册资料
    atlas_text = format_atlas_results(atlas_results)

    # 提取所有资料中的图片路径
    all_source_text = analysis_points_text + original_rag_text + atlas_text + graph_results
    original_image_paths = extract_image_paths(all_source_text)

    detail_info = ""
    if fault_code:
        detail_info += f"- 故障码/报警代码：{fault_code}\n"
    if fault_time:
        detail_info += f"- 故障发生时间：{fault_time}\n"
    if fault_frequency:
        detail_info += f"- 故障频率/持续时间：{fault_frequency}\n"
    if tried_measures:
        detail_info += f"- 已尝试的维修措施：{tried_measures}\n"
    if running_condition:
        detail_info += f"- 设备运行工况：{running_condition}\n"
    if additional_info:
        detail_info += f"- 其他相关信息：{additional_info}\n"

    # 构建深度分析点的提示
    analysis_points_prompt = ""
    if deep_analysis_points:
        analysis_points_prompt = f"\n【本次深度分析重点】\n" + "\n".join([f"- {p}" for p in deep_analysis_points]) + "\n"

    prompt = COMMON_PROMPTS["generate_deep_response"].format(
        biz_label="维修",
        item_label="故障现象",
        item_name=fault or '未提供',
        ship_number=ship_number or '未提供',
        device_name=device_name or '未提供',
        fault=fault or '未提供',
        detail_info=detail_info,
        combined_query=combined_query,
        analysis_points_prompt=analysis_points_prompt,
        analysis_points_text=analysis_points_text,
        original_rag_text=original_rag_text,
        graph_results=graph_results if len(graph_results) > 50 else '(无)'
    )

    try:
        # ========== 第一步：专注于生成高质量内容 ==========
        content_system_prompt = COMMON_PROMPTS["generate_deep_response_content_system"].format(biz_label="维修")

        raw_content = await OpenaiAPI.open_api_chat_without_thinking(model=None,system_prompt=content_system_prompt,messages=[{"role": "user", "content": prompt}],)

        raw_content = raw_content.strip() if raw_content else "抱歉，无法生成深度分析。"

        emit_callback_event(["🤖 诊断分析中", "🤖 故障预检中"], raw_content[:30] + "...")

        answer = await stream_format_and_postprocess(raw_content, original_image_paths, temperature=0.1)

        answer = append_atlas_section(answer, atlas_results)

        suggested_replies = [{"title": "方案有误", "content": "方案还是有问题："},]

        actions = _generate_report_from_scheme(scheme_content=answer,ship_number=ship_number,device_name=device_name,fault=fault)

        try:
            await record_fault_from_state({"ship_number": ship_number,"device_name": device_name,"fault": fault,"last_generated_scheme": answer,})
        except Exception as rec_err:
            print(f"[generate_deep_response] 记录故障信息失败: {rec_err}")

        return {"response": answer,"actions": actions,"suggestedReplies": suggested_replies,"scheme_generated": True,"last_generated_scheme": answer,"scheme_type": "deep","current_node": "end","last_combined_query": combined_query,}

    except Exception as e:
        return {"response": f"深度分析生成失败: {str(e)}","actions": [],"suggestedReplies": [],"current_node": "end",}

async def regenerate_scheme_from_feedback(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    基于用户反馈直接修改方案节点：使用之前保存的方案和用户反馈进行修改
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    additional_info = state.get("additional_info", "") or ""
    fault_code = state.get("fault_code", "") or ""
    fault_time = state.get("fault_time", "") or ""
    fault_frequency = state.get("fault_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""

    user_feedback = state.get("user_feedback_for_regenerate", "") or ""
    last_scheme = state.get("last_generated_scheme", "") or ""
    scheme_type = state.get("scheme_type", "normal")

    if not last_scheme:
        # 如果没有保存的方案，回退到重新检索
        print("[regenerate_scheme_from_feedback] 没有保存的方案，回退到重新检索")
        return {"is_regenerating": True,"rag_search_result": None,"graph_search_result": None,"has_rag_result": False,"has_graph_result": False,"scheme_generated": False,"current_node": "call_tools","tools_to_call": ["rag_search", "graph_rag_search"],}

    detail_info = ""
    if fault_code:
        detail_info += f"- 故障码/报警代码：{fault_code}\n"
    if fault_time:
        detail_info += f"- 故障发生时间：{fault_time}\n"
    if fault_frequency:
        detail_info += f"- 故障频率/持续时间：{fault_frequency}\n"
    if tried_measures:
        detail_info += f"- 已尝试的维修措施：{tried_measures}\n"
    if running_condition:
        detail_info += f"- 设备运行工况：{running_condition}\n"
    if additional_info:
        detail_info += f"- 其他相关信息：{additional_info}\n"

    emit_callback_event(["✏️ 修改方案中", "🔧 调整方案", "📝 优化方案"], f"根据反馈修改方案: {user_feedback[:30]}...")
    
    image_guidance = get_image_prompt_guidance()

    prompt = COMMON_PROMPTS["regenerate_scheme_from_feedback"].format(
        biz_label="维修",
        item_label="故障现象",
        item_name=fault or '未提供',
        item_action="分析故障原因，给出维修方案",
        ship_number=ship_number or '未提供',
        device_name=device_name or '未提供',
        fault=fault or '未提供',
        detail_info=detail_info,
        last_scheme=last_scheme,
        user_feedback=user_feedback,
        image_guidance=image_guidance
    )

    try:
        # ========== 第一步：专注于生成高质量内容 ==========
        content_system_prompt = COMMON_PROMPTS["regenerate_scheme_from_feedback_system"].format(biz_label="维修")
        
        # 构建第一步的内容提示词（简化格式要求）
        content_prompt = prompt.replace("【输出要求】", "【输出要求】\n- 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性\n- 可以适当使用简单的段落分隔，但不要使用复杂的格式")
        
        raw_content = await OpenaiAPI.open_api_chat_without_thinking(model=None,system_prompt=content_system_prompt,messages=[{"role": "user", "content": content_prompt}],)

        raw_content = raw_content.strip() if raw_content else "抱歉，无法根据反馈修改方案。"

        original_image_paths = extract_image_paths(last_scheme)
        answer = await stream_format_and_postprocess(raw_content, original_image_paths, temperature=0.3, content_label="维修方案")

        suggested_replies = [{"title": "方案有误", "content": "方案还是有问题："},]

        actions = _generate_report_from_scheme(scheme_content=answer,ship_number=ship_number,device_name=device_name,fault=fault)

        try:
            await record_fault_from_state({"ship_number": ship_number,"device_name": device_name,"fault": fault,"last_generated_scheme": answer,})
        except Exception as rec_err:
            print(f"[regenerate_scheme_from_feedback] 记录故障信息失败: {rec_err}")

        return {"response": answer,"actions": actions,"suggestedReplies": suggested_replies,"scheme_generated": True,"last_generated_scheme": answer,"scheme_type": scheme_type,"current_node": "end","last_combined_query": combined_query,}

    except Exception as e:
        print(f"[regenerate_scheme_from_feedback] 修改方案失败: {str(e)}")
        # 如果修改失败，回退到重新检索
        return {"is_regenerating": True,"rag_search_result": None,"graph_search_result": None,"has_rag_result": False,"has_graph_result": False,"scheme_generated": False,"current_node": "call_tools","tools_to_call": ["rag_search", "graph_rag_search"],}

async def follow_up_qa(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    后续问答节点：调用 baike 智能体处理用户的后续问题
    """
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""

    history_message_json = json.dumps(history_messages, ensure_ascii=False) if history_messages else ""

    context_prefix = ""
    if ship_number or device_name or fault:
        context_parts = []
        if ship_number:
            context_parts.append(f"舷号: {ship_number}")
        if device_name:
            context_parts.append(f"设备名称: {device_name}")
        if fault:
            context_parts.append(f"故障现象: {fault}")
        context_prefix = f"【当前故障诊断上下文】\n{'; '.join(context_parts)}\n\n"

    enhanced_query = f"{context_prefix}用户后续问题: {combined_query}"

    emit_callback_event(["💬 后续问答", "💬 执行指导", "💬 问题解答"], f"调用 百科 智能体: {combined_query[:30]}...")

    try:
        baike_result = await run_baike_workflow(extracted_text=enhanc`>ed_query,combined_query=enhanced_query,history_message=history_message_json,route_flag="baike")

        response = baike_result.get("response", "")
        suggested_replies = baike_result.get("suggestedReplies", [])

        return {"response": response,"suggestedReplies": suggested_replies,"actions": [],"scheme_generated": True,"current_node": "end",}

    except Exception as e:
        return {"response": f"处理您的问题时出现错误: {str(e)}","suggestedReplies": [],"actions": [],"current_node": "end",}

async def generate_report(state: FaultDiagnosisState) -> Dict[str, Any]:
    """报告生成节点"""
    from workflows.workflow_other_report import run_other_report_workflow

    combined_query = state.get("combined_query", "") or ""
    history_message = state.get("history_messages", [])
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""

    history_message_json = json.dumps(history_message, ensure_ascii=False) if history_message else ""

    try:
        report_result = await run_other_report_workflow(extracted_text=combined_query,combined_query=combined_query,history_message=history_message_json,route_flag="report")

        return {"response": report_result.get("response", ""),"actions": report_result.get("actions", []),"suggestedReplies": report_result.get("suggestedReplies", []),"scheme_generated": True,"current_node": "end",}
    except Exception as e:
        return {"response": f"报告生成失败: {str(e)}","actions": [],"suggestedReplies": [],"current_node": "end",}

async def handle_feedback(state: FaultDiagnosisState) -> Command:
    """
    处理用户反馈节点：接收用户对方案的反馈，提供上报和重新生成方案按钮
    """
    combined_query = state.get("combined_query", "") or ""
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""

    response = f"""**📝 已收到您的反馈**

感谢您对维修方案的建议！您的反馈已记录：

{combined_query}

---

**📋 反馈信息摘要：**
- 舷号：{ship_number or '未提供'}
- 设备名称：{device_name or '未提供'}
- 故障现象：{fault or '未提供'}
- 反馈内容：{combined_query[:100]}{'...' if len(combined_query) > 100 else ''}

---

**💡 您可以选择：**
- 点击「重新生成方案」根据您的反馈重新生成方案
- 点击「上报」将反馈提交给相关部门
- 继续对话获取更多帮助"""

    actions = [
        {"type": "content","label": "重新生成方案","text": "重新生成方案"},
        {"type": "content","label": "上报","text": "上报"}
    ]

    suggested_replies = []

    emit_callback_event(["📝 反馈处理", "📋 方案反馈", "✅ 反馈确认"], f"处理用户反馈: {combined_query[:30]}...")

    user_input = interrupt({"response": response,"actions": actions,"suggestedReplies": suggested_replies,"waiting_for": "feedback_confirm",})

    user_text = user_input.get("query", "") or ""

    if user_text == "重新生成方案":
        print(f"[handle_feedback] 用户选择重新生成方案")
        return Command(
            update={"user_feedback_for_regenerate": combined_query,"current_node": "regenerate_scheme_from_feedback",},
            goto="regenerate_scheme_from_feedback"
        )
    elif user_text == "上报":
        print(f"[handle_feedback] 用户选择上报反馈")
        return Command(
            update={"user_feedback": combined_query,"waiting_report_confirm": True,"current_node": "confirm_report",},
            goto="confirm_report"
        )
    else:
        print(f"[handle_feedback] 用户继续对话: {user_text}")
        return Command(
            update={"user_feedback": combined_query,"combined_query": user_text,"current_node": "agent_think",},
            goto="agent_think"
        )

async def confirm_report(state: FaultDiagnosisState) -> Dict[str, Any]:
    """
    上报确认节点：用户点击上报后确认完成
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    fault = state.get("fault", "") or ""
    user_feedback = state.get("user_feedback", "") or ""

    response = f"""**✅ 上报成功**

您的反馈已成功上报！

---

**📋 上报信息：**
- 舷号：{ship_number or '未提供'}
- 设备名称：{device_name or '未提供'}
- 故障现象：{fault or '未提供'}
- 反馈内容：{user_feedback[:100]}{'...' if len(user_feedback) > 100 else ''}

---

**💡 感谢您的反馈，相关部门将及时处理。**"""

    suggested_replies = [{"title": "生成维修报告", "content": "请帮我生成维修报告"},]

    emit_callback_event(["✅ 上报成功", "📋 反馈已提交", "🎉 完成"], "反馈上报成功")

    return {"response": response,"actions": [],"suggestedReplies": suggested_replies,"report_confirmed": True,"waiting_report_confirm": False,"current_node": "end",}

def _route_after_think(state: FaultDiagnosisState) -> str:
    """Agent 思考后的路由"""
    decision = state.get("agent_decision", "ask_user")

    return decision

def _route_after_intent(state: FaultDiagnosisState) -> str:
    """意图分析后的路由"""
    intent = state.get("follow_up_intent", "other")

    if intent == "not_solved":
        return "deep_rag_search"
    elif intent == "related_question":
        return "follow_up_qa"
    elif intent == "has_error":
        return "handle_feedback"
    elif intent == "modify_info":
        # 修改信息，重置相关状态，重新开始信息提取
        return "extract_info"
    else:
        return "follow_up_qa"

def _route_after_tools(state: FaultDiagnosisState) -> str:
    """检索工具调用后的路由"""
    need_model_confirm = state.get("need_model_confirm", False)
    if need_model_confirm:
        return "model_confirm"
    return "generate_response"

def create_fault_diagnosis_workflow(checkpointer=None):
    """
    创建故障诊断工作流（基于 Checkpointer 的状态持久化版本）
    """
    workflow = StateGraph(FaultDiagnosisState)

    workflow.add_node("classify_intent", classify_intent)
    workflow.add_node("extract_info", extract_info)
    workflow.add_node("agent_think", agent_think)
    workflow.add_node("ask_user", ask_user)
    workflow.add_node("confirm_info", confirm_info)
    workflow.add_node("call_tools", call_tools)
    workflow.add_node("generate_response", generate_response)
    workflow.add_node("follow_up_qa", follow_up_qa)
    workflow.add_node("model_confirm", model_confirm)
    workflow.add_node("generate_report", generate_report)
    workflow.add_node("handle_feedback", handle_feedback)
    workflow.add_node("confirm_report", confirm_report)
    workflow.add_node("analyze_follow_up_intent", analyze_follow_up_intent)
    workflow.add_node("deep_rag_search", deep_rag_search)
    workflow.add_node("generate_deep_response", generate_deep_response)
    workflow.add_node("regenerate_scheme_from_feedback", regenerate_scheme_from_feedback)

    workflow.add_edge(START, "classify_intent")
    workflow.add_conditional_edges("classify_intent", _route_after_classify, 
    {"extract_info": "extract_info","follow_up_qa": "follow_up_qa",})
    workflow.add_edge("extract_info", "agent_think")
    workflow.add_conditional_edges("agent_think", _route_after_think,
    {"ask_user": "ask_user","confirm_info": "confirm_info","call_tools": "call_tools","generate_response": "generate_response","follow_up": "follow_up_qa","follow_up_qa": "follow_up_qa","generate_report": "generate_report","handle_feedback": "handle_feedback","extract_info": "extract_info","analyze_follow_up_intent": "analyze_follow_up_intent",})
    workflow.add_conditional_edges("call_tools", _route_after_tools, {"model_confirm": "model_confirm","generate_response": "generate_response",})
    workflow.add_conditional_edges("analyze_follow_up_intent", _route_after_intent, {"deep_rag_search": "deep_rag_search","follow_up_qa": "follow_up_qa","handle_feedback": "handle_feedback","extract_info": "extract_info",})
    workflow.add_edge("deep_rag_search", "generate_deep_response")
    workflow.add_edge("generate_deep_response", END)
    workflow.add_edge("generate_response", END)
    workflow.add_edge("follow_up_qa", END)
    workflow.add_edge("generate_report", END)
    workflow.add_edge("regenerate_scheme_from_feedback", END)
    workflow.add_edge("handle_feedback", END)
    workflow.add_edge("confirm_report", END)

    return workflow.compile(checkpointer=checkpointer)

async def run_fault_diagnosis_workflow(extracted_text: str,combined_query: str,history_message: str = "",route_flag: str = "",previous_state_json: str = "",chat_id: str = "",message_id: str = "",checkpointer=None,user_response: Dict[str, Any] = None) -> Dict[str, Any]:
    """
    执行故障诊断工作流

    Args:
        extracted_text: 文本描述
        combined_query: 组合查询
        history_message: 历史消息（JSON格式）
        route_flag: 路由标识
        previous_state_json: 兼容参数（已废弃）
        chat_id: 聊天会话 ID
        message_id: 消息 ID
        checkpointer: LangGraph checkpointer 实例
        user_response: 用户恢复执行的响应数据

    Returns:
        工作流执行结果
    """
    thread_id = chat_id if chat_id else None

    config = {"configurable": {"thread_id": thread_id}} if thread_id else {}

    print(f"[DEBUG] run_fault_diagnosis_workflow: thread_id={thread_id}, checkpointer={checkpointer is not None}")

    if checkpointer is None:
        from checkpointer_config import checkpointer_manager
        checkpointer = await checkpointer_manager.get_async_checkpointer()

    app = create_fault_diagnosis_workflow(checkpointer=checkpointer)

    if thread_id:
        try:
            current_state = await app.aget_state(config)
            print(
                f"[DEBUG] current_state exists: {current_state is not None}, has values: {current_state.values is not None if current_state else False}, tasks: {len(current_state.tasks) if current_state else 0}")

            if current_state and current_state.values:
                saved_state = current_state.values
                print(
                    f"[Checkpointer] 发现已保存状态: ship_number={saved_state.get('ship_number')}, device_name={saved_state.get('device_name')}, fault={saved_state.get('fault')}")

                if current_state.tasks:
                    print(f"[Checkpointer] 恢复执行，注入用户响应")
                    resume_value = user_response if user_response else {"query": combined_query}
                    result = await app.ainvoke(Command(resume=resume_value), config)
                else:
                    # 只使用当前的输入，不拼接之前的！
                    merged_query = combined_query

                    # 如果当前输入是确认意图，且已有完整信息，直接视为用户已确认
                    _is_confirm = await is_confirmation_intent(combined_query)
                    _has_full_info = (saved_state.get("ship_number") and saved_state.get("device_name") and saved_state.get("fault"))
                    _override_confirmed = _is_confirm and _has_full_info and not saved_state.get("user_confirmed_info", False)

                    initial_state = {**saved_state,"combined_query": merged_query,"history_messages": parse_history(history_message),"initialized": False,"user_intent": "",}
                    if _override_confirmed:
                        print(f"[Checkpointer] 检测到确认意图，自动设置 user_confirmed_info=True")
                        initial_state["user_confirmed_info"] = True
                    result = await app.ainvoke(initial_state, config)
            else:
                initial_state = {"extracted_text": extracted_text,"combined_query": combined_query,"history_messages": parse_history(history_message),"ship_number": "","device_name": "","fault": "","additional_info": "",
                    "fault_code": "","fault_time": "","fault_frequency": "","tried_measures": "","running_condition": "","rag_search_result": None,"graph_search_result": None,"response": "",
                    "suggestedReplies": [],"actions": [],"error_message": "","agent_decision": "","agent_reasoning": "","tools_to_call": [],"missing_info": [],"info_completeness": 0.0,
                    "matched_kb_id": "","matched_kb_name": "","iteration_count": 0,"max_iterations": 5,"scheme_generated": False,"waiting_for_supplement": False,"extracted_info": {},
                    "has_rag_result": False,"has_graph_result": False,"is_execution_feedback": False,"execution_detail": "","ask_round": 0,"user_confirmed_info": False,"need_model_confirm": False,
                    "user_confirmed_model": False,"waiting_feedback": False,"user_feedback": "","waiting_report_confirm": False,"report_confirmed": False,"initialized": False,"current_node": "","user_intent": "","last_combined_query": "",}
                result = await app.ainvoke(initial_state, config)
        except Exception as e:
            print(f"[Checkpointer] 状态恢复失败: {e}")
            import traceback
            traceback.print_exc()
            result = {}
    else:
        initial_state = {"extracted_text": extracted_text,"combined_query": combined_query,"history_messages": parse_history(history_message),"ship_number": "","device_name": "","fault": "","additional_info": "","fault_code": "","fault_time": "",
            "fault_frequency": "","tried_measures": "","running_condition": "","rag_search_result": None,"graph_search_result": None,"response": "","suggestedReplies": [],"actions": [],"error_message": "","agent_decision": "","agent_reasoning": "","tools_to_call": [],
            "missing_info": [],"info_completeness": 0.0,"matched_kb_id": "","matched_kb_name": "","iteration_count": 0,"max_iterations": 5,"scheme_generated": False,"waiting_for_supplement": False,"extracted_info": {},"has_rag_result": False,"has_graph_result": False,
            "is_execution_feedback": False,"execution_detail": "","ask_round": 0,"user_confirmed_info": False,"need_model_confirm": False,"user_confirmed_model": False,"waiting_feedback": False,"user_feedback": "","waiting_report_confirm": False,"report_confirmed": False,"initialized": False,"current_node": "","user_intent": "","last_combined_query": "",}

        try:
            result = await app.ainvoke(initial_state, config)
        except Exception as e:
            print(f"[工作流执行失败] {str(e)}")
            import traceback
            traceback.print_exc()
            return {"response": f"故障诊断工作流执行失败: {str(e)}","actions": [],"result_tag": "fault_diagnosis","suggestedReplies": [],}

    if result is None:
        result = {}

    interrupts = result.get("__interrupt__", [])
    if interrupts:
        interrupt_data = interrupts[0].value if interrupts else {}
        print(f"[Interrupt] 工作流中断，等待用户输入: {interrupt_data}")
        return {"response": interrupt_data.get("response", "请提供更多信息"),"actions": interrupt_data.get("actions", []),"result_tag": "fault_diagnosis","suggestedReplies": interrupt_data.get("suggestedReplies", []),"waiting_for": interrupt_data.get("waiting_for", ""),}

    if result.get("error_message"):
        return {"response": f"故障诊断工作流执行失败: {result['error_message']}","actions": [],"result_tag": "fault_diagnosis","suggestedReplies": [],}

    route_flag = result.get("route_flag", "")
    if not route_flag:
        route_flag = "fault_diagnosis"

    return {"response": result.get("response", ""),"actions": result.get("actions", []),"result_tag": route_flag,"suggestedReplies": result.get("suggestedReplies", []),"route_flag": route_flag,}


a:|$x   """
操作指导工作流 checkpointer 版本
"""
from typing import TypedDict, Optional, Dict, Any, List
from langgraph.graph import StateGraph, START, END
from langgraph.types import interrupt, Command
from tools.function_tool import graph_rag_search
from tools.rag_tools import rag_search
from tools.graph_tools import atlas_retrieval, format_atlas_results, extract_entity_names_from_history
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import get_all_callbacks
from utils.image_utils import extract_image_paths, get_image_prompt_guidance
from utils.intent_matcher import is_confirmation_intent
from workflows.workflow_baike import run_baike_workflow
from workflows.workflow_utils import (
    safe_json_extract, parse_history, normalize_latex_spacing,
    remove_duplicate_content, convert_rag_result, calculate_info_completeness,
    emit_callback_event, build_history_str, build_detail_info,
    append_atlas_section, stream_format_and_postprocess,
)
from prompts import OPERATE_PROMPTS, COMMON_PROMPTS
import json
import re
import random

class OperateGuideState(TypedDict):
    """操作指导工作流状态"""
    extracted_text: str
    combined_query: str
    history_messages: List[Dict[str, Any]]

    ship_number: str
    device_name: str
    operation_item: str
    additional_info: str
    operation_code: str
    operation_time: str
    operation_frequency: str
    tried_measures: str
    running_condition: str

    rag_search_result: Optional[List[Dict[str, Any]]]
    graph_search_result: Optional[str]
    deep_rag_results: Optional[Dict[str, Any]]

    response: str
    suggestedReplies: List[Dict[str, Any]]
    actions: List[Dict[str, Any]]
    error_message: str

    agent_decision: str
    agent_reasoning: str
    tools_to_call: List[str]
    missing_info: List[str]
    info_completeness: float

    matched_kb_id: str
    matched_kb_name: str

    iteration_count: int
    max_iterations: int
    scheme_generated: bool
    waiting_for_supplement: bool

    extracted_info: Dict[str, Any]
    has_rag_result: bool
    has_graph_result: bool
    ask_round: int
    user_confirmed_info: bool

    need_model_confirm: bool
    user_confirmed_model: bool

    user_feedback: str
    waiting_report_confirm: bool
    report_confirmed: bool

    initialized: bool
    current_node: str

    # 意图分类相关字段
    user_intent: str  # 用户初始意图: '操作', '百科'

    # 后续处理相关字段
    follow_up_intent: str  # 用户后续意图: 'not_solved', 'related_question', 'has_error', 'modify_info', 'other'
    user_feedback_for_regenerate: str  # 用户用于重新生成方案的反馈
    is_regenerating: bool  # 是否正在重新生成方案
    last_generated_scheme: str  # 最后一次生成的方案（用于基于反馈修改）
    scheme_type: str  # 方案类型：'normal' 普通方案，'deep' 深度方案
    deep_analysis_points: Optional[List[str]]  # 深度分析点（用于针对性检索）
    atlas_results: Optional[Dict[str, Any]]  # 图册检索结果
    last_combined_query: str  # 上一轮生成方案时的用户输入

OPERATE_INFO_WEIGHTS = {"ship_number": 0.20, "device_name": 0.20, "operation_item": 0.25, "operation_code": 0.08, "operation_time": 0.06, "operation_frequency": 0.06, "tried_measures": 0.06, "running_condition": 0.05, "additional_info": 0.04}

def _calculate_info_completeness(ship_number: str = "", device_name: str = "", operation_item: str = "", operation_code: str = "", operation_time: str = "", operation_frequency: str = "", tried_measures: str = "", running_condition: str = "", additional_info: str = "") -> float:
    values = {"ship_number": ship_number, "device_name": device_name, "operation_item": operation_item, "operation_code": operation_code, "operation_time": operation_time, "operation_frequency": operation_frequency, "tried_measures": tried_measures, "running_condition": running_condition, "additional_info": additional_info}
    return calculate_info_completeness(OPERATE_INFO_WEIGHTS, values)

async def classify_intent(state: OperateGuideState) -> Dict[str, Any]:
    """
    意图分类节点
    """
    combined_query = state.get("combined_query", "") or ""
    extracted_info = state.get("extracted_info", {}) or {}
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""

    if extracted_info or device_name or operation_item or ship_number:
        print("[classify_intent] 已在操作流程中，跳过意图分类")
        return {"user_intent": "操作","current_node": "extract_info",}

    system_prompt = OPERATE_PROMPTS["classify_intent_system"]

    prompt = COMMON_PROMPTS["classify_intent_user"].format(combined_query=combined_query)

    try:
        response_text = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,json_output=True,system_prompt=system_prompt,messages=[])

        parsed = safe_json_extract(response_text)
        intent = "操作"
        if isinstance(parsed, dict):
            intent = parsed.get("intent", "操作")

        print(f"[意图分类] 用户意图: {intent}")

        if intent == "操作":
            return {"user_intent": intent,"scheme_generated": False,"current_node": "extract_info",}
        else:
            return {"user_intent": intent,"current_node": "follow_up_qa",}

    except Exception as e:
        print(f"[意图分类失败: {str(e)}，默认按操作处理")
        return {"user_intent": "操作","scheme_generated": False,"current_node": "extract_info",}

def _route_after_classify(state: OperateGuideState) -> str:
    """意图分类后的路由"""
    intent = state.get("user_intent", "操作")
    if intent == "百科":
        return "follow_up_qa"
    return "extract_info"

async def extract_info(state: OperateGuideState) -> Dict[str, Any]:
    """
    信息提取节点
    """
    if state.get("initialized", False):
        print("[extract_info] 已初始化，跳过")
        return {"current_node": "agent_think"}

    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []

    history_str = build_history_str(history_messages, recent_count=10)

    existing_info = []
    existing_ship_number = state.get("ship_number", "") or ""
    existing_device_name = state.get("device_name", "") or ""
    existing_operation_item = state.get("operation_item", "") or ""
    existing_operation_code = state.get("operation_code", "") or ""
    existing_operation_time = state.get("operation_time", "") or ""
    existing_operation_frequency = state.get("operation_frequency", "") or ""
    existing_tried_measures = state.get("tried_measures", "") or ""
    existing_running_condition = state.get("running_condition", "") or ""
    existing_additional_info = state.get("additional_info", "") or ""

    if existing_ship_number:
        existing_info.append(f"舷号: {existing_ship_number}")
    if existing_device_name:
        existing_info.append(f"设备名称: {existing_device_name}")
    if existing_operation_item:
        existing_info.append(f"操作项目: {existing_operation_item}")
    if existing_operation_code:
        existing_info.append(f"操作代码: {existing_operation_code}")
    if existing_operation_time:
        existing_info.append(f"操作时间: {existing_operation_time}")
    if existing_operation_frequency:
        existing_info.append(f"操作频率: {existing_operation_frequency}")
    if existing_tried_measures:
        existing_info.append(f"已尝试措施: {existing_tried_measures}")
    if existing_running_condition:
        existing_info.append(f"运行工况: {existing_running_condition}")
    if existing_additional_info:
        existing_info.append(f"其他信息: {existing_additional_info}")

    existing_info_str = "\n".join(existing_info) if existing_info else "（无已提取信息）"

    system_prompt = OPERATE_PROMPTS["extract_info_system"]

    prompt = COMMON_PROMPTS["extract_info_user"].format(
        biz_label="操作",
        existing_info_str=existing_info_str,
        history_str=history_str or '（无历史对话）',
        combined_query=combined_query
    )

    try:
        response_text = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,json_output=True,system_prompt=system_prompt,messages=[])

        parsed = safe_json_extract(response_text)
        if not isinstance(parsed, dict):
            parsed = {}

        new_ship_number = parsed.get("ship_number", "") or existing_ship_number
        new_device_name = parsed.get("device_name", "") or existing_device_name
        new_operation_item = parsed.get("operation_item", "") or existing_operation_item
        new_operation_code = parsed.get("operation_code", "") or existing_operation_code
        new_operation_time = parsed.get("operation_time", "") or existing_operation_time
        new_operation_frequency = parsed.get("operation_frequency", "") or existing_operation_frequency
        new_tried_measures = parsed.get("tried_measures", "") or existing_tried_measures
        new_running_condition = parsed.get("running_condition", "") or existing_running_condition
        new_additional_info = parsed.get("additional_info", "") or existing_additional_info

        extracted_info = {"ship_number": new_ship_number,"device_name": new_device_name,"operation_item": new_operation_item,"operation_code": new_operation_code,"operation_time": new_operation_time,"operation_frequency": new_operation_frequency,"tried_measures": new_tried_measures,"running_condition": new_running_condition,"additional_info": new_additional_info,}

        print(f"[信息提取] 舷号={extracted_info['ship_number']}, 设备={extracted_info['device_name']}, 操作={extracted_info['operation_item']}")

        return {**extracted_info,"extracted_info": extracted_info,"initialized": True,"current_node": "agent_think",}

    except Exception as e:
        print(f"信息提取失败: {str(e)}")
        return {"initialized": True,"current_node": "agent_think",}

async def agent_think(state: OperateGuideState) -> Dict[str, Any]:
    """
    Agent 思考节点：基于当前状态决定下一步动作
    """
    combined_query = state.get("combined_query", "") or ""
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    operation_code = state.get("operation_code", "") or ""
    operation_time = state.get("operation_time", "") or ""
    operation_frequency = state.get("operation_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""
    history_messages = state.get("history_messages", []) or []

    scheme_generated = state.get("scheme_generated", False)
    has_rag_result = state.get("has_rag_result", False)
    has_graph_result = state.get("has_graph_result", False)

    rag_search_result = state.get("rag_search_result")
    graph_search_result = state.get("graph_search_result")
    iteration_count = state.get("iteration_count", 0)

    user_confirmed_info = state.get("user_confirmed_info", False)
    waiting_feedback = state.get("waiting_feedback", False)

    has_ship = bool(ship_number and ship_number.strip())
    has_device = bool(device_name and device_name.strip())
    has_operation_item = bool(operation_item and operation_item.strip())
    has_rag = (rag_search_result is not None and len(rag_search_result) > 0) or has_rag_result
    has_graph = (graph_search_result is not None and len(graph_search_result) > 100) or has_graph_result

    info_completeness = _calculate_info_completeness(ship_number=ship_number,device_name=device_name,operation_item=operation_item,operation_code=operation_code,operation_time=operation_time,operation_frequency=operation_frequency,tried_measures=tried_measures,running_condition=running_condition,additional_info=additional_info)

    MIN_COMPLETENESS_FOR_GENERATE = 0.25

    if scheme_generated:
        _re_diagnose_keywords = ["开始操作", "信息已足够", "信息已足够，开始操作", "开始", "操作"]
        _is_re_diagnose = any(kw in combined_query for kw in _re_diagnose_keywords)
        if _is_re_diagnose:
            print(f"[重新操作] 检测到重新操作意图: '{combined_query}'，重置状态直接调用工具生成方案")
            tools_to_call = ["rag_search"]
            if device_name and operation_item:
                tools_to_call.append("graph_rag_search")
            return {"scheme_generated": False,"rag_search_result": None,"graph_search_result": None,"deep_rag_results": None,"has_rag_result": False,"has_graph_result": False,"is_regenerating": False,"user_feedback_for_regenerate": "","follow_up_intent": "","user_confirmed_info": True,"initialized": True,"iteration_count": 0,"ask_round": 0,"agent_decision": "call_tools","tools_to_call": tools_to_call,"current_node": "call_tools",}

        history_str = build_history_str(history_messages, recent_count=8, assistant_truncate=300)

        intent_system_prompt = OPERATE_PROMPTS["agent_think_intent_system"]

        intent_prompt = OPERATE_PROMPTS["agent_think_intent_user"].format(
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            operation_item=operation_item or '未提供',
            history_str=history_str or '无',
            combined_query=combined_query
        )

        try:
            intent_response = await OpenaiAPI.open_api_chat_without_thinking(
                query=intent_prompt,
                model=None,
                json_output=True,
                system_prompt=intent_system_prompt,
                messages=[]
            )

            parsed_intent = safe_json_extract(intent_response)
            intent = "other"
            if isinstance(parsed_intent, dict):
                intent = parsed_intent.get("intent", "other")

            print(f"[Agent 意图分析] 用户意图: {intent}")

            if intent == "modify_info":
                decision = "confirm_info"
                reasoning = "用户需要修改或补充信息"
                return {"agent_decision": decision,"agent_reasoning": reasoning,"rag_search_result": None,"graph_search_result": None,"deep_rag_results": None,"has_rag_result": False,"has_graph_result": False,"scheme_generated": False,"is_regenerating": False,"user_feedback_for_regenerate": "","follow_up_intent": "","user_confirmed_info": False,"initialized": False,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            elif intent == "has_error":
                decision = "handle_feedback"
                reasoning = "用户反馈方案有错误"
                print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
                return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            elif intent == "not_solved":
                decision = "analyze_follow_up_intent"
                reasoning = "已生成方案，分析用户后续意图"
                return {"agent_decision": decision,"agent_reasoning": reasoning,"follow_up_intent": "not_solved","info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            elif intent == "related_question":
                decision = "analyze_follow_up_intent"
                reasoning = "已生成方案，分析用户后续意图"
                return {"agent_decision": decision,"agent_reasoning": reasoning,"follow_up_intent": "related_question","info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
            else:
                decision = "follow_up_qa"
                reasoning = "其他意图，直接调用 baike"
                print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
                return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}
        except Exception as e:
            print(f"[Agent 意图分析失败: {str(e)}")
            decision = "analyze_follow_up_intent"
            reasoning = "已生成方案，分析用户后续意图"
            print(f"[Agent 决策] decision={decision}, reasoning={reasoning} (降级)")
            return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}

    if not has_device or not has_operation_item:
        decision = "ask_user"
        missing_info = []
        if not has_device:
            missing_info.append("设备名称")
        if not has_operation_item:
            missing_info.append("操作项目")
        reasoning = f"缺少基本信息: {', '.join(missing_info)}"
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"missing_info": missing_info,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}

    if info_completeness < MIN_COMPLETENESS_FOR_GENERATE:
        decision = "ask_user"
        reasoning = f"信息完整性评分 {info_completeness} 低于最低要求 {MIN_COMPLETENESS_FOR_GENERATE}"
        missing_info = []
        if not ship_number:
            missing_info.append("舷号（可选）")
        if not operation_code:
            missing_info.append("操作代码")
        if not operation_time:
            missing_info.append("操作时间")
        if not operation_frequency:
            missing_info.append("操作频率")
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"missing_info": missing_info or ["更多详细信息"],"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}

    if has_rag or has_graph:
        decision = "generate_response"
        reasoning = "信息充足，已有检索结果，直接生成回复"
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}    

    if not user_confirmed_info:
        decision = "confirm_info"
        reasoning = "信息充足，需要用户确认后再检索知识库"
        print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
        return {"agent_decision": decision,"agent_reasoning": reasoning,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}    

    decision = "call_tools"
    reasoning = "信息充足，用户已确认，开始检索知识库"
    tools_to_call = ["rag_search"]
    if has_device and has_operation_item:
        tools_to_call.append("graph_rag_search")

    print(f"[Agent 决策] decision={decision}, reasoning={reasoning}")
    print(f"[Agent 提取] 舷号={ship_number}, 设备={device_name}, 操作={operation_item}")

    emit_callback_event(["🤖 Agent 思考中", "🤖 智能分析", "🤖 决策判断"], f"决策: {decision} | 理由: {reasoning[:50]}...")

    return {"agent_decision": decision,"agent_reasoning": reasoning,"tools_to_call": tools_to_call,"info_completeness": info_completeness,"iteration_count": iteration_count + 1,"current_node": decision,}    

async def ask_user(state: OperateGuideState) -> Command:
    """
    询问用户节点：使用 interrupt 暂停等待用户输入
    """
    missing_info = state.get("missing_info", [])
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    operation_code = state.get("operation_code", "") or ""
    operation_time = state.get("operation_time", "") or ""
    operation_frequency = state.get("operation_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""
    combined_query = state.get("combined_query", "") or ""
    info_completeness = state.get("info_completeness", 0)
    ask_round = state.get("ask_round", 0)

    MAX_ASK_ROUNDS = 4
    if ask_round >= MAX_ASK_ROUNDS:
        print(f"[ask_user] 已达到最大询问轮次 {MAX_ASK_ROUNDS}，强制进入下一步")
        tools_to_call = ["rag_search"]
        if device_name and operation_item:
            tools_to_call.append("graph_rag_search")
        return Command(
            update={"ask_round": ask_round + 1,"current_node": "call_tools","tools_to_call": tools_to_call,},
            goto="call_tools"
        )

    existing_parts = []
    if ship_number:
        existing_parts.append(f"舷号: {ship_number}")
    if device_name:
        existing_parts.append(f"设备名称: {device_name}")
    if operation_item:
        existing_parts.append(f"操作项目: {operation_item}")
    if operation_code:
        existing_parts.append(f"操作代码: {operation_code}")
    if operation_time:
        existing_parts.append(f"发生时间: {operation_time}")
    if operation_frequency:
        existing_parts.append(f"操作频率: {operation_frequency}")
    if tried_measures:
        existing_parts.append(f"已尝试措施: {tried_measures}")
    if running_condition:
        existing_parts.append(f"运行工况: {running_condition}")
    if additional_info:
        existing_parts.append(f"其他信息: {additional_info}")

    existing_str = "；".join(existing_parts) if existing_parts else "暂无"
    missing_str = "、".join(missing_info) if missing_info else "相关信息"

    system_prompt = COMMON_PROMPTS["ask_user_system"].format(biz_label="操作指导", biz_label_short="指导")

    prompt = COMMON_PROMPTS["ask_user_prompt"].format(
        info_completeness=info_completeness,
        existing_str=existing_str,
        missing_str=missing_str,
        combined_query=combined_query
    )

    response = ""
    try:
        response = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,system_prompt=system_prompt,messages=[])
        response = response.strip() if response else ""
    except Exception as e:
        print(f"[ask_user] API调用失败: {str(e)}")
        response = ""

    if not response:
        response = f"**【需要更多信息】**\n\n请补充：{missing_str}\n\n提供这些信息后，我可以更准确地为您指导操作。"

    if existing_parts:
        existing_info_section = f"\n**📋 已获取的信息：**\n\n" + "\n".join(
            f"- {part}" for part in existing_parts) + "\n\n---\n"
        response = existing_info_section + response

    suggested_replies = []
    if "舷号" in missing_info:
        suggested_replies.append({"title": "补充舷号", "content": "舷号："})
    if "设备名称" in missing_info:
        suggested_replies.append({"title": "补充设备名称", "content": "设备名称："})
    if "操作项目" in missing_info:
        suggested_replies.append({"title": "补充操作项目", "content": "操作项目："})

    user_input = interrupt({"response": response,"suggestedReplies": suggested_replies,"waiting_for": "user_input","missing_info": missing_info,})

    user_query = user_input.get("query", "")

    update_dict = {"combined_query": user_query,"current_node": "agent_think","ask_round": ask_round + 1,}

    if user_query:
        extract_prompt = OPERATE_PROMPTS["ask_user_extract"].format(
            missing_str=missing_str,
            user_query=user_query
        )

        try:
            extract_response = await OpenaiAPI.open_api_chat_without_thinking(query=extract_prompt,model=None,json_output=True,system_prompt="你是信息提取专家。",messages=[])
            extracted = safe_json_extract(extract_response)
            if isinstance(extracted, dict):
                if extracted.get("ship_number"):
                    update_dict["ship_number"] = extracted["ship_number"]
                    print(f"[ask_user] 提取到舷号: {extracted['ship_number']}")
                if extracted.get("device_name"):
                    update_dict["device_name"] = extracted["device_name"]
                    print(f"[ask_user] 提取到设备名称: {extracted['device_name']}")
                if extracted.get("operation_item"):
                    update_dict["operation_item"] = extracted["operation_item"]
                    print(f"[ask_user] 提取到操作项目: {extracted['operation_item']}")
        except Exception as e:
            print(f"[ask_user] 信息提取失败: {str(e)}")

    return Command(
        update=update_dict,
        goto="agent_think"
    )

async def confirm_info(state: OperateGuideState) -> Command:
    """
    确认信息节点：重点询问用户是否需要补充信息
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    operation_code = state.get("operation_code", "") or ""
    operation_time = state.get("operation_time", "") or ""
    operation_frequency = state.get("operation_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""
    info_completeness = state.get("info_completeness", 0)

    existing_parts = []
    if ship_number:
        existing_parts.append(f"舷号: {ship_number}")
    if device_name:
        existing_parts.append(f"设备名称: {device_name}")
    if operation_item:
        existing_parts.append(f"操作项目: {operation_item}")
    if operation_code:
        existing_parts.append(f"操作代码: {operation_code}")
    if operation_time:
        existing_parts.append(f"发生时间: {operation_time}")
    if operation_frequency:
        existing_parts.append(f"操作频率: {operation_frequency}")
    if tried_measures:
        existing_parts.append(f"已尝试措施: {tried_measures}")
    if running_condition:
        existing_parts.append(f"运行工况: {running_condition}")
    if additional_info:
        existing_parts.append(f"其他信息: {additional_info}")

    existing_str = "\n".join(f"- {part}" for part in existing_parts) if existing_parts else "暂无"

    additional_prompt = ""
    if not ship_number:
        additional_prompt = "\n\n💡 **提示**：如果您知道舷号，请补充，这将有助于我们更准确地提供操作指导。"

    response = f"""**📋 已收集到的信息：**

{existing_str}

**信息完整性评分：** {info_completeness:.0%}

---

**💡 请问是否需要补充其他信息？**
- 如操作代码、操作时间、操作频率、已尝试措施、运行工况等
- 如果信息已足够，请点击"开始操作"{additional_prompt}
"""

    emit_callback_event(["✅ 信息确认", "📋 请确认信息", "🔍 准备检索"], f"等待用户确认或补充信息 (完整性: {info_completeness:.0%})")

    suggested_replies = [{"title": "开始操作", "content": "信息已足够，开始操作"},{"title": "补充信息", "content": "我需要补充："}]

    user_input = interrupt({"response": response,"suggestedReplies": suggested_replies,"waiting_for": "user_confirm",})

    user_query = user_input.get("query", "")

    if await is_confirmation_intent(user_query):
        print(f"[confirm_info] 用户确认信息足够，准备调用工具")
        tools_to_call = ["rag_search"]
        if device_name and operation_item:
            tools_to_call.append("graph_rag_search")
        return Command(
            update={"user_confirmed_info": True,"current_node": "call_tools","tools_to_call": tools_to_call,},
            goto="call_tools"
        )
    else:
        print(f"[confirm_info] 用户需要补充信息: {user_query}")
        return Command(
            update={"user_confirmed_info": False,"combined_query": user_query,"initialized": False,"current_node": "extract_info",},
            goto="extract_info"
        )

async def call_tools(state: OperateGuideState) -> Dict[str, Any]:
    """调用检索工具"""
    tools_to_call = state.get("tools_to_call", [])
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    additional_info = state.get("additional_info", "") or ""

    rag_results = state.get("rag_search_result")
    graph_results = state.get("graph_search_result")
    atlas_results = {}

    matched_kb_name = ""
    matched_kb_id = ""

    if "rag_search" in tools_to_call and rag_results is None:
        from utils.ship_number_search import search_with_ship_number_strategy
        
        base_query = f"{device_name}进行{operation_item}的操作方案"
        
        rag_results, matched_kb_name, matched_kb_id, _mapped_ship_number = await search_with_ship_number_strategy(base_query=base_query,ship_number=ship_number,top_k=5,search_type="operate")
        
        if not matched_kb_name:
            matched_kb_name = "通用知识库"

        print(f"RAG 检索来源: {matched_kb_name}")

    if "graph_rag_search" in tools_to_call and graph_results is None:
        if device_name and operation_item:
            try:
                graph_query = f"{device_name}进行{operation_item}的操作方案"
                graph_results = await graph_rag_search.ainvoke({"query": graph_query})
                print(f"图谱检索完成，结果长度: {len(graph_results) if graph_results else 0}")
            except Exception as e:
                print(f"图谱检索失败: {str(e)}")
                graph_results = ""

    if device_name:
        try:
            print(f"[图册检索] 使用设备名称: {device_name}")
            atlas_result = await atlas_retrieval(node_names=[device_name], top_k=10)
            if atlas_result.get("success", False):
                atlas_results = atlas_result.get("data", {})
                print(f"[图册检索] 图册检索结果: {list(atlas_results.keys())}")
        except Exception as e:
            print(f"[图册检索] 图册检索失败: {str(e)}")

    has_rag = bool(rag_results and len(rag_results) > 0)
    has_graph = bool(graph_results and len(graph_results) > 100)

    if not has_rag and not has_graph:
        print(f"[call_tools] 未找到任何相关资料，需要用户确认使用模型能力")
        return {"rag_search_result": rag_results if isinstance(rag_results, list) else [],"graph_search_result": graph_results if isinstance(graph_results, str) else "","atlas_results": atlas_results,"matched_kb_id": matched_kb_id,"matched_kb_name": matched_kb_name,"has_rag_result": False,"has_graph_result": False,"need_model_confirm": True,"current_node": "model_confirm",}

    return {"rag_search_result": rag_results,"graph_search_result": graph_results,"atlas_results": atlas_results,"matched_kb_id": matched_kb_id,"matched_kb_name": matched_kb_name,"has_rag_result": has_rag,"has_graph_result": has_graph,"need_model_confirm": False,"current_node": "generate_response",}

async def model_confirm(state: OperateGuideState) -> Command:
    """
    模型能力确认节点：当没有找到任何资料时，让用户确认是否使用模型本身能力
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""

    response = f"""**⚠️ 未找到相关资料**

抱歉，在知识库中未找到与以下信息相关的资料：
- 舷号：{ship_number or '未提供'}
- 设备名称：{device_name or '未提供'}
- 操作项目：{operation_item or '未提供'}

**💡 您可以选择：**
- 使用 AI 模型的知识库为您生成一般性建议
- 提供更详细的信息重新检索

请问是否使用 AI 模型为您生成建议？"""

    emit_callback_event(["🤖 AI 模型确认", "⚠️ 资料未找到", "💡 使用模型能力"], "使用模型自身知识进行回复")

    suggested_replies = [{"title": "使用 AI 模型", "content": "确认，使用 AI 模型生成建议"},{"title": "补充信息", "content": "我需要补充更多信息："},]

    user_input = interrupt({"response": response,"suggestedReplies": suggested_replies,"waiting_for": "model_confirm",})

    user_query = user_input.get("query", "")

    if "确认" in user_query or "AI" in user_query or "模型" in user_query:
        print(f"[model_confirm] 用户确认使用模型能力")
        return Command(
            update={"user_confirmed_model": True,"combined_query": user_query,"current_node": "generate_response",},
            goto="generate_response"
        )
    else:
        print(f"[model_confirm] 用户选择补充信息: {user_query}")
        return Command(
            update={"user_confirmed_model": False,"combined_query": user_query,"current_node": "agent_think",},
            goto="agent_think"
        )

async def generate_response(state: OperateGuideState) -> Dict[str, Any]:
    """生成最终回复"""
    print("========================生成最终回复========================")
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    additional_info = state.get("additional_info", "") or ""
    operation_code = state.get("operation_code", "") or ""
    operation_time = state.get("operation_time", "") or ""
    operation_frequency = state.get("operation_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    rag_results = state.get("rag_search_result") or []
    graph_results = state.get("graph_search_result") or ""
    atlas_results = state.get("atlas_results", {})
    scheme_generated = state.get("scheme_generated", False)
    matched_kb_name = state.get("matched_kb_name", "")

    print("rag_results", rag_results)
    history_str = build_history_str(history_messages, recent_count=12, assistant_truncate=500)

    has_rag = rag_results and len(rag_results) > 0
    has_graph = graph_results and len(graph_results) > 100

    if not has_rag and not has_graph:
        if not ship_number and not device_name and not operation_item:
            system_prompt = COMMON_PROMPTS["generate_response_friendly_system"].format(biz_label="操作指导")
            prompt = COMMON_PROMPTS["generate_response_friendly_user"].format(combined_query=combined_query)
        else:
            system_prompt = COMMON_PROMPTS["generate_response_no_rag_system"].format(biz_label="操作指导")
            prompt = OPERATE_PROMPTS["generate_response_no_rag_user"].format(
                ship_number=ship_number or '未提供',
                device_name=device_name or '未提供',
                operation_item=operation_item or '未提供',
                operation_code=operation_code or '未提供',
                operation_time=operation_time or '未提供',
                operation_frequency=operation_frequency or '未提供',
                tried_measures=tried_measures or '未提供',
                running_condition=running_condition or '未提供',
                additional_info=additional_info or '无'
            )

        try:
            response = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,system_prompt=system_prompt,messages=[])
            return {"response": response.strip() if response else "抱歉，未能找到相关资料。","suggestedReplies": [{"title": "提供更详细信息", "content": "我来提供更详细的信息"},],"current_node": "end",}
        except Exception as e:
            return {"response": f"抱歉，处理过程中出现错误: {str(e)}","suggestedReplies": [],"current_node": "end",}

    rag_ctx_parts: List[str] = []
    if isinstance(rag_results, str) and rag_results.strip():
        rag_ctx_parts = [rag_results.strip()]
    elif isinstance(rag_results, list):
        for item in sorted(rag_results or [], key=lambda x: float(x.get("score") or 0) if isinstance(x,dict) else 0, reverse=True)[:4]:
#        for item in rag_results[:8]:
            if isinstance(item, dict):
                text = (item.get("text") or "").strip()
                if text:
                    rag_ctx_parts.append(text)
            elif isinstance(item, str) and item.strip():
                rag_ctx_parts.append(item.strip())

    if len(graph_results) <= 50:
        graph_results = ""

    all_source_text = graph_results + "\n" + "\n".join(rag_ctx_parts) if graph_results else "\n".join(rag_ctx_parts)
    original_image_paths = extract_image_paths(all_source_text)
    print("提取到的原始图片路径:", original_image_paths)

    rag_answer = ""
    rag_type = "none"

    if graph_results and len(graph_results) > 50:
        rag_answer = graph_results
        rag_type = "graph"
    elif rag_ctx_parts:
        rag_answer = "\n\n".join(rag_ctx_parts)
        rag_type = "rag"

    if not rag_answer or rag_answer == "NO_RELEVANT_RESULT":
        system_prompt = COMMON_PROMPTS["generate_response_no_rag_simple_system"].format(biz_label="操作指导")
        prompt = OPERATE_PROMPTS["generate_response_no_rag_simple_user"].format(
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            operation_item=operation_item or '未提供'
        )

        try:
            response = await OpenaiAPI.open_api_chat_without_thinking(query=prompt,model=None,system_prompt=system_prompt,messages=[])
            return {"response": response.strip() if response else "抱歉，未能找到相关资料。","suggestedReplies": [],"current_node": "end",}
        except Exception as e:
            return {"response": f"抱歉，处理过程中出现错误: {str(e)}","suggestedReplies": [],"current_node": "end",}

    rag_type = "图谱" if rag_type == "graph" else "文本"

    emit_callback_event([f"✨当前使用的检索类型为{rag_type}", f"✨本次检索策略为{rag_type}"], f"内容为{rag_answer[:50]}...")

    detail_info = ""
    if operation_code:
        detail_info += f"- 操作代码/报警代码：{operation_code}\n"
    if operation_time:
        detail_info += f"- 操作发生时间：{operation_time}\n"
    if operation_frequency:
        detail_info += f"- 操作频率/持续时间：{operation_frequency}\n"
    if tried_measures:
        detail_info += f"- 已尝试的操作措施：{tried_measures}\n"
    if running_condition:
        detail_info += f"- 设备运行工况：{running_condition}\n"
    if additional_info:
        detail_info += f"- 其他相关信息：{additional_info}\n"

    is_regenerating = state.get("is_regenerating", False)
    user_feedback_for_regenerate = state.get("user_feedback_for_regenerate", "")
    is_follow_up = scheme_generated and (has_rag or has_graph) and not is_regenerating

    image_guidance = get_image_prompt_guidance()
    if is_regenerating and user_feedback_for_regenerate:
        prompt = COMMON_PROMPTS["generate_response_regenerating"].format(
            biz_label="操作指导",
            item_label="操作项目",
            item_name=operation_item or '未提供',
            item_action="分析操作要点，给出操作指导方案",
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            operation_item=operation_item or '未提供',
            detail_info=detail_info,
            user_feedback_for_regenerate=user_feedback_for_regenerate,
            rag_answer=rag_answer,
            image_guidance=image_guidance
        )
    elif is_follow_up:
        prompt = COMMON_PROMPTS["generate_response_follow_up"].format(
            biz_label="操作指导",
            item_label="操作项目",
            item_name=operation_item or '未提供',
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            operation_item=operation_item or '未提供',
            detail_info=detail_info,
            rag_answer=rag_answer,
            combined_query=combined_query,
            image_guidance=image_guidance
        )
    else:
        prompt = COMMON_PROMPTS["generate_response_normal"].format(
            biz_label="操作指导",
            item_label="操作项目",
            item_name=operation_item or '未提供',
            item_action="分析操作要点，给出操作指导方案",
            ship_number=ship_number or '未提供',
            device_name=device_name or '未提供',
            operation_item=operation_item or '未提供',
            detail_info=detail_info,
            rag_answer=rag_answer
        )

    try:
        content_system_prompt = COMMON_PROMPTS["generate_response_content_system"].format(biz_label="操作指导")

        raw_content = await OpenaiAPI.open_api_chat_without_thinking(model=None,system_prompt=content_system_prompt,messages=[{"role": "user", "content": prompt}],)

        raw_content = raw_content.strip() if raw_content else "抱歉，无法生成回答。"

        emit_callback_event(["🤖 操作分析中", "🤖 方案生成中"], raw_content[:30] + "...")

        answer = await stream_format_and_postprocess(raw_content, original_image_paths, temperature=0.1)
#        answer = ""
        answer = append_atlas_section(answer, atlas_results)

        suggested_replies = [{"title": "方案有误", "content": "方案还是有问题："},]

        return {"response": answer,"actions": [],"suggestedReplies": suggested_replies,"scheme_generated": True,"last_generated_scheme": answer,"scheme_type": "deep","current_node": "end","last_combined_query": combined_query,}

    except Exception as e:
        return {"response": f"深度分析生成失败: {str(e)}","actions": [],"suggestedReplies": [],"current_node": "end",}

async def regenerate_scheme_from_feedback(state: OperateGuideState) -> Dict[str, Any]:
    """
    基于用户反馈直接修改方案节点：使用之前保存的方案和用户反馈进行修改
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    additional_info = state.get("additional_info", "") or ""
    operation_code = state.get("operation_code", "") or ""
    operation_time = state.get("operation_time", "") or ""
    operation_frequency = state.get("operation_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    combined_query = state.get("combined_query", "") or ""

    user_feedback = state.get("user_feedback_for_regenerate", "") or ""
    last_scheme = state.get("last_generated_scheme", "") or ""
    scheme_type = state.get("scheme_type", "normal")

    if not last_scheme:
        print("[regenerate_scheme_from_feedback] 没有保存的方案，回退到重新检索")
        return {"is_regenerating": True,"rag_search_result": None,"graph_search_result": None,"has_rag_result": False,"has_graph_result": False,"scheme_generated": False,"current_node": "call_tools","tools_to_call": ["rag_search", "graph_rag_search"],}

    detail_info = ""
    if operation_code:
        detail_info += f"- 操作代码/报警代码：{operation_code}\n"
    if operation_time:
        detail_info += f"- 操作发生时间：{operation_time}\n"
    if operation_frequency:
        detail_info += f"- 操作频率/持续时间：{operation_frequency}\n"
    if tried_measures:
        detail_info += f"- 已尝试的操作措施：{tried_measures}\n"
    if running_condition:
        detail_info += f"- 设备运行工况：{running_condition}\n"
    if additional_info:
        detail_info += f"- 其他相关信息：{additional_info}\n"

    emit_callback_event(["✏️ 修改方案中", "🔧 调整方案", "📝 优化方案"], f"根据反馈修改方案: {user_feedback[:30]}...")
    
    image_guidance = get_image_prompt_guidance()

    prompt = COMMON_PROMPTS["regenerate_scheme_from_feedback"].format(
        biz_label="操作指导",
        item_label="操作项目",
        item_name=operation_item or '未提供',
        item_action="分析操作要点，给出操作指导方案",
        ship_number=ship_number or '未提供',
        device_name=device_name or '未提供',
        operation_item=operation_item or '未提供',
        detail_info=detail_info,
        last_scheme=last_scheme,
        user_feedback=user_feedback,
        image_guidance=image_guidance
    )

    try:
        content_system_prompt = COMMON_PROMPTS["regenerate_scheme_from_feedback_system"].format(biz_label="操作指导")
        
        content_prompt = prompt.replace("【输出要求】", "【输出要求】\n- 请专注于内容的准确性、完整性和逻辑性，不要担心格式的美观性\n- 可以适当使用简单的段落分隔，但不要使用复杂的格式")
        
        raw_content = await OpenaiAPI.open_api_chat_without_thinking(model=None,system_prompt=content_system_prompt,messages=[{"role": "user", "content": content_prompt}],)

        raw_content = raw_content.strip() if raw_content else "抱歉，无法根据反馈修改方案。"

        original_image_paths = extract_image_paths(last_scheme)
        answer = await stream_format_and_postprocess(raw_content, original_image_paths, temperature=0.3, content_label="操作指导方案")

        suggested_replies = [{"title": "方案有误", "content": "方案还是有问题："},]

        return {"response": answer,"actions": [],"suggestedReplies": suggested_replies,"scheme_generated": True,"last_generated_scheme": answer,"scheme_type": scheme_type,"current_node": "end","last_combined_query": combined_query,}

    except Exception as e:
        print(f"[regenerate_scheme_from_feedback] 修改方案失败: {str(e)}")
        return {"is_regenerating": True,"rag_search_result": None,"graph_search_result": None,"has_rag_result": False,"has_graph_result": False,"scheme_generated": False,"current_node": "call_tools","tools_to_call": ["rag_search", "graph_rag_search"],}

async def follow_up_qa(state: OperateGuideState) -> Dict[str, Any]:
    """
    后续问答节点：调用 baike 智能体处理用户的后续问题
    """
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""

    history_message_json = json.dumps(history_messages, ensure_ascii=False) if history_messages else ""

    context_prefix = ""
    if ship_number or device_name or operation_item:
        context_parts = []
        if ship_number:
            context_parts.append(f"舷号: {ship_number}")
        if device_name:
            context_parts.append(f"设备名称: {device_name}")
        if operation_item:
            context_parts.append(f"操作项目: {operation_item}")
        context_prefix = f"【当前操作指导上下文】\n{'; '.join(context_parts)}\n\n"

    enhanced_query = f"{context_prefix}用户后续问题: {combined_query}"

    emit_callback_event(["💬 后续问答", "💬 执行指导", "💬 问题解答"], f"调用 百科 智能体: {combined_query[:30]}...")

    try:
        baike_result = await run_baike_workflow(extracted_text=enhanced_query,combined_query=enhanced_query,history_message=history_message_json,route_flag="baike")

        response = baike_result.get("response", "")
        suggested_replies = baike_result.get("suggestedReplies", [])

        return {"response": response,"suggestedReplies": suggested_replies,"actions": [],"scheme_generated": True,"current_node": "end",}

    except Exception as e:
        return {"response": f"处理您的问题时出现错误: {str(e)}","suggestedReplies": [],"actions": [],"current_node": "end",}

async def handle_feedback(state: OperateGuideState) -> Command:
    """
    处理用户反馈节点：接收用户对方案的反馈，提供上报和重新生成方案按钮
    """
    combined_query = state.get("combined_query", "") or ""
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""

    response = f"""**📝 已收到您的反馈**

感谢您对操作指导方案的建议！您的反馈已记录：

{combined_query}

---

**📋 反馈信息摘要：**
- 舷号：{ship_number or '未提供'}
- 设备名称：{device_name or '未提供'}
- 操作项目：{operation_item or '未提供'}
- 反馈内容：{combined_query[:100]}{'...' if len(combined_query) > 100 else ''}

---

**💡 您可以选择：**
- 点击「重新生成方案」根据您的反馈重新生成方案
- 点击「上报」将反馈提交给相关部门
- 继续对话获取更多帮助"""

    actions = [
        {"type": "content","label": "重新生成方案","text": "重新生成方案"},
        {"type": "content","label": "上报","text": "上报"}
    ]

    suggested_replies = []

    emit_callback_event(["📝 反馈处理", "📋 方案反馈", "✅ 反馈确认"], f"处理用户反馈: {combined_query[:30]}...")

    user_input = interrupt({"response": response,"actions": actions,"suggestedReplies": suggested_replies,"waiting_for": "feedback_confirm",})

    user_text = user_input.get("query", "") or ""

    if user_text == "重新生成方案":
        print(f"[handle_feedback] 用户选择重新生成方案")
        return Command(
            update={"user_feedback_for_regenerate": combined_query,"current_node": "regenerate_scheme_from_feedback",},
            goto="regenerate_scheme_from_feedback"
        )
    elif user_text == "上报":
        print(f"[handle_feedback] 用户选择上报反馈")
        return Command(
            update={"user_feedback": combined_query,"waiting_report_confirm": True,"current_node": "confirm_report",},
            goto="confirm_report"
        )
    else:
        print(f"[handle_feedback] 用户继续对话: {user_text}")
        return Command(
            update={"user_feedback": combined_query,"combined_query": user_text,"current_node": "agent_think",},
            goto="agent_think"
        )

async def confirm_report(state: OperateGuideState) -> Dict[str, Any]:
    """
    上报确认节点：用户点击上报后确认完成
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    user_feedback = state.get("user_feedback", "") or ""

    response = f"""**✅ 上报成功**

您的反馈已成功上报！

---

**📋 上报信息：**
- 舷号：{ship_number or '未提供'}
- 设备名称：{device_name or '未提供'}
- 操作项目：{operation_item or '未提供'}
- 反馈内容：{user_feedback[:100]}{'...' if len(user_feedback) > 100 else ''}

---

**💡 感谢您的反馈，相关部门将及时处理。**"""

    suggested_replies = [{"title": "继续对话", "content": "我还有其他问题"},]

    emit_callback_event(["✅ 上报成功", "📋 反馈已提交", "🎉 完成"], "反馈上报成功")

    return {"response": response,"actions": [],"suggestedReplies": suggested_replies,"report_confirmed": True,"waiting_report_confirm": False,"current_node": "end",}

async def analyze_follow_up_intent(state: OperateGuideState) -> Dict[str, Any]:
    """
    分析用户后续意图节点：直接使用 agent_think 已经判断好的意图
    agent_think 已经用大模型判断并设置了 follow_up_intent
    """
    intent = state.get("follow_up_intent", "other")

    print(f"[意图分析] 使用已判断的意图: {intent}")

    return {"follow_up_intent": intent,}


async def deep_rag_search(state: OperateGuideState) -> Dict[str, Any]:
    """
    深层次RAG检索节点：分析之前方案并选择深度分析点进行检索
    """
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    operation_code = state.get("operation_code", "") or ""
    additional_info = state.get("additional_info", "") or ""
    operation_time = state.get("operation_time", "") or ""
    operation_frequency = state.get("operation_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    last_generated_scheme = state.get("last_generated_scheme", "") or ""

    deep_results = {}
    deep_analysis_points = []

    emit_callback_event(["🔍 深度检索中", "🔍 多维度检索", "🔍 精细分析"], "分析问题并选择深度分析点")

    # ========== 第一步：分析之前方案和用户问题，选择深度分析点 ==========
    if last_generated_scheme or combined_query:
        try:
            history_str = build_history_str(history_messages, recent_count=8, assistant_truncate=300)

            detail_info = ""
            if operation_code:
                detail_info += f"- 操作代码：{operation_code}\n"
            if operation_time:
                detail_info += f"- 操作时间：{operation_time}\n"
            if operation_frequency:
                detail_info += f"- 操作频率/持续时间：{operation_frequency}\n"
            if tried_measures:
                detail_info += f"- 已尝试的措施：{tried_measures}\n"
            if running_condition:
                detail_info += f"- 设备运行工况：{running_condition}\n"
            if additional_info:
                detail_info += f"- 其他相关信息：{additional_info}\n"

            analysis_system_prompt = COMMON_PROMPTS["deep_rag_analysis_system"].format(biz_label="操作指导")

            analysis_prompt = COMMON_PROMPTS["deep_rag_analysis_user"].format(
                item_label="操作项目",
                item_name=operation_item or '未提供',
                ship_number=ship_number or '未提供',
                device_name=device_name or '未提供',
                operation_item=operation_item or '未提供',
                detail_info=detail_info,
                history_str=history_str or '（无历史对话）',
                last_generated_scheme=last_generated_scheme or '（无之前的方案）',
                combined_query=combined_query
            )

            analysis_response = await OpenaiAPI.open_api_chat_without_thinking(query=analysis_prompt,model=None,json_output=True,system_prompt=analysis_system_prompt,messages=[])
            print("深度分析点", analysis_response)
            parsed_analysis = safe_json_extract(analysis_response)
            deep_analysis_points = parsed_analysis
            print(f"[深度RAG] 选择的分析点: {deep_analysis_points}")
        except Exception as e:
            print(f"[深度RAG] 分析失败: {str(e)}")

    # ========== 第二步：对选中的分析点进行检索 ==========
    for idx, point in enumerate(deep_analysis_points):
        try:
            print(point)
            search_query = point
            if device_name and device_name not in point:
                search_query = f"{device_name} {search_query}"
            if operation_item and operation_item not in search_query:
                search_query = f"{search_query} {operation_item}"

            rag_result = await rag_search(search_query, top_k=3)
            if rag_result.get("success", False):
                deep_results[f"analysis_point_{idx}"] = convert_rag_result(rag_result)
            else:
                deep_results[f"analysis_point_{idx}"] = []
        except Exception as e:
            print(f"[深度RAG] 分析点 {point} 检索失败: {str(e)}")
            deep_results[f"analysis_point_{idx}"] = []

    # ========== 第三步：图谱检索 ==========
    graph_deep_results = ""
    try:
        if device_name and operation_item:
            graph_query = f"设备{device_name}，操作{operation_item}的操作指导方案"
            graph_deep_results = await graph_rag_search.ainvoke({"query": graph_query})
            if graph_deep_results:
                print(f"[深度RAG] 图谱检索结果长度: {len(graph_deep_results)}")
    except Exception as e:
        print(f"[深度RAG] 图谱检索失败: {str(e)}")

    # ========== 第四步：图册检索 ==========
    atlas_results = {}
    try:
        entity_names = await extract_entity_names_from_history(history_messages=history_messages,device_name=device_name,operation_item=operation_item,last_generated_scheme=last_generated_scheme)

        if entity_names:
            print(f"[深度RAG] 图册检索实体: {entity_names}")
            atlas_result = await atlas_retrieval(node_names=entity_names, top_k=10)
            if atlas_result.get("success", False):
                atlas_results = atlas_result.get("data", {})
                print(f"[深度RAG] 图册检索结果: {list(atlas_results.keys())}")
    except Exception as e:
        print(f"[深度RAG] 图册检索失败: {str(e)}")

    return {"deep_rag_results": deep_results,"deep_analysis_points": deep_analysis_points,"graph_search_result": graph_deep_results or (state.get("graph_search_result", "") or ""),"atlas_results": atlas_results,"current_node": "generate_deep_response",}


async def generate_deep_response(state: OperateGuideState) -> Dict[str, Any]:
    """
    生成深度响应节点：基于深度RAG结果进行深度润色和推理
    """
    combined_query = state.get("combined_query", "") or ""
    history_messages = state.get("history_messages", []) or []
    ship_number = state.get("ship_number", "") or ""
    device_name = state.get("device_name", "") or ""
    operation_item = state.get("operation_item", "") or ""
    operation_code = state.get("operation_code", "") or ""
    operation_time = state.get("operation_time", "") or ""
    operation_frequency = state.get("operation_frequency", "") or ""
    tried_measures = state.get("tried_measures", "") or ""
    running_condition = state.get("running_condition", "") or ""
    additional_info = state.get("additional_info", "") or ""

    deep_rag_results = state.get("deep_rag_results", {})
    deep_analysis_points = state.get("deep_analysis_points", [])
    atlas_results = state.get("atlas_results", {})
    graph_results = state.get("graph_search_result", "") or ""
    original_rag_results = state.get("rag_search_result", [])

    # 整理深度分析点资料
    analysis_points_text = ""
    if deep_analysis_points:
        for idx, point in enumerate(deep_analysis_points):
            key = f"analysis_point_{idx}"
            results = deep_rag_results.get(key, [])
            if results:
                analysis_points_text += f"\n【分析点：{point}】\n"
                for i, item in enumerate(results[:2], 1):
                    if isinstance(item, dict):
                        text = item.get("text", "")
                        if text:
                            analysis_points_text += f"[{i}] {text}\n"

    # 整理原始RAG结果
    original_rag_text = ""
    if original_rag_results:
        original_rag_text = "\n【原始检索资料】\n"
        for i, item in enumerate(original_rag_results[:3], 1):
            if isinstance(item, dict):
                text = item.get("text", "")
                if text:
                    original_rag_text += f"[{i}] {text}\n"

    # 整理图册资料
    atlas_text = format_atlas_results(atlas_results)

    # 提取所有资料中的图片路径
    all_source_text = analysis_points_text + original_rag_text + atlas_text + graph_results
    original_image_paths = extract_image_paths(all_source_text)

    detail_info = ""
    if operation_code:
        detail_info += f"- 操作代码：{operation_code}\n"
    if operation_time:
        detail_info += f"- 操作时间：{operation_time}\n"
    if operation_frequency:
        detail_info += f"- 操作频率/持续时间：{operation_frequency}\n"
    if tried_measures:
        detail_info += f"- 已尝试的措施：{tried_measures}\n"
    if running_condition:
        detail_info += f"- 设备运行工况：{running_condition}\n"
    if additional_info:
        detail_info += f"- 其他相关信息：{additional_info}\n"

    # 构建深度分析点的提示
    analysis_points_prompt = ""
    if deep_analysis_points:
        analysis_points_prompt = f"\n【本次深度分析重点】\n" + "\n".join([f"- {p}" for p in deep_analysis_points]) + "\n"

    prompt = COMMON_PROMPTS["generate_deep_response"].format(
        biz_label="操作指导",
        item_label="操作项目",
        item_name=operation_item or '未提供',
        ship_number=ship_number or '未提供',
        device_name=device_name or '未提供',
        operation_item=operation_item or '未提供',
        detail_info=detail_info,
        combined_query=combined_query,
        analysis_points_prompt=analysis_points_prompt,
        analysis_points_text=analysis_points_text,
        original_rag_text=original_rag_text,
        graph_results=graph_results if len(graph_results) > 50 else '(无)'
    )

    try:
        content_system_prompt = COMMON_PROMPTS["generate_deep_response_content_system"].format(biz_label="操作指导")

        raw_content = await OpenaiAPI.open_api_chat_without_thinking(model=None,system_prompt=content_system_prompt,messages=[{"role": "user", "content": prompt}],)

        raw_content = raw_content.strip() if raw_content else "抱歉，无法生成深度分析。"

        emit_callback_event(["🤖 分析中", "🤖 操作指导生成中"], raw_content[:30] + "...")

        answer = await stream_format_and_postprocess(raw_content, original_image_paths, temperature=0.1)

        answer = append_atlas_section(answer, atlas_results)

        suggested_replies = [{"title": "方案有误", "content": "方案还是有问题："},]

        return {"response": answer,"actions": [],"suggestedReplies": suggested_replies,"scheme_generated": True,"last_generated_scheme": answer,"scheme_type": "deep","current_node": "end","last_combined_query": combined_query,}

    except Exception as e:
        return {"response": f"深度分析生成失败: {str(e)}","actions": [],"suggestedReplies": [],"current_node": "end",}


def _route_after_think(state: OperateGuideState) -> str:
    """Agent 思考后的路由"""
    decision = state.get("agent_decision", "ask_user")

    return decision

def _route_after_intent(state: OperateGuideState) -> str:
    """意图分析后的路由"""
    intent = state.get("follow_up_intent", "other")

    if intent == "not_solved":
        return "deep_rag_search"
    elif intent == "related_question":
        return "follow_up_qa"
    elif intent == "has_error":
        return "handle_feedback"
    elif intent == "modify_info":
        return "extract_info"
    else:
        return "follow_up_qa"

def _route_after_tools(state: OperateGuideState) -> str:
    """检索工具调用后的路由"""
    need_model_confirm = state.get("need_model_confirm", False)
    if need_model_confirm:
        return "model_confirm"
    return "generate_response"

def create_operate_workflow(checkpointer=None):
    """
    创建操作指导工作流（基于 Checkpointer 的状态持久化版本）
    """
    workflow = StateGraph(OperateGuideState)

    workflow.add_node("classify_intent", classify_intent)
    workflow.add_node("extract_info", extract_info)
    workflow.add_node("agent_think", agent_think)
    workflow.add_node("ask_user", ask_user)
    workflow.add_node("confirm_info", confirm_info)
    workflow.add_node("call_tools", call_tools)
    workflow.add_node("generate_response", generate_response)
    workflow.add_node("follow_up_qa", follow_up_qa)
    workflow.add_node("model_confirm", model_confirm)
    workflow.add_node("handle_feedback", handle_feedback)
    workflow.add_node("confirm_report", confirm_report)
    workflow.add_node("analyze_follow_up_intent", analyze_follow_up_intent)
    workflow.add_node("deep_rag_search", deep_rag_search)
    workflow.add_node("generate_deep_response", generate_deep_response)
    workflow.add_node("regenerate_scheme_from_feedback", regenerate_scs!heme_from_feedback)

    workflow.add_edge(START, "classify_intent")
    workflow.add_conditional_edges("classify_intent", _route_after_classify, 
    {"extract_info": "extract_info","follow_up_qa": "follow_up_qa",})
    workflow.add_edge("extract_info", "agent_think")
    workflow.add_conditional_edges("agent_think", _route_after_think,
    {"ask_user": "ask_user","confirm_info": "confirm_info","call_tools": "call_tools","generate_response": "generate_response","follow_up": "follow_up_qa","follow_up_qa": "follow_up_qa","handle_feedback": "handle_feedback","extract_info": "extract_info","analyze_follow_up_intent": "analyze_follow_up_intent",})
    workflow.add_conditional_edges("call_tools", _route_after_tools, {"model_confirm": "model_confirm","generate_response": "generate_response",})
    workflow.add_conditional_edges("analyze_follow_up_intent", _route_after_intent, {"deep_rag_search": "deep_rag_search","follow_up_qa": "follow_up_qa","handle_feedback": "handle_feedback","extract_info": "extract_info",})
    workflow.add_edge("deep_rag_search", "generate_deep_response")
    workflow.add_edge("generate_deep_response", END)
    workflow.add_edge("generate_response", END)
    workflow.add_edge("follow_up_qa", END)
    workflow.add_edge("regenerate_scheme_from_feedback", END)
    workflow.add_edge("handle_feedback", END)
    workflow.add_edge("confirm_report", END)

    return workflow.compile(checkpointer=checkpointer)

async def run_operate_workflow(extracted_text: str,combined_query: str,history_message: str = "",route_flag: str = "",previous_state_json: str = "",chat_id: str = "",message_id: str = "",checkpointer=None,user_response: Dict[str, Any] = None) -> Dict[str, Any]:
    """
    执行操作指导工作流

    Args:
        extracted_text: 文本描述
        combined_query: 组合查询
        history_message: 历史消息（JSON格式）
        route_flag: 路由标识
        previous_state_json: 兼容参数（已废弃）
        chat_id: 聊天会话 ID
        message_id: 消息 ID
        checkpointer: LangGraph checkpointer 实例
        user_response: 用户恢复执行的响应数据

    Returns:
        工作流执行结果
    """
    thread_id = chat_id if chat_id else None

    config = {"configurable": {"thread_id": thread_id}} if thread_id else {}

    print(f"[DEBUG] run_operate_workflow: thread_id={thread_id}, checkpointer={checkpointer is not None}")

    if checkpointer is None:
        from checkpointer_config import checkpointer_manager
        checkpointer = await checkpointer_manager.get_async_checkpointer()

    app = create_operate_workflow(checkpointer=checkpointer)

    if thread_id:
        try:
            current_state = await app.aget_state(config)
            print(
                f"[DEBUG] current_state exists: {current_state is not None}, has values: {current_state.values is not None if current_state else False}, tasks: {len(current_state.tasks) if current_state else 0}")

            if current_state and current_state.values:
                saved_state = current_state.values
                print(
                    f"[Checkpointer] 发现已保存状态: ship_number={saved_state.get('ship_number')}, device_name={saved_state.get('device_name')}, operation_item={saved_state.get('operation_item')}")

                if current_state.tasks:
                    print(f"[Checkpointer] 恢复执行，注入用户响应")
                    resume_value = user_response if user_response else {"query": combined_query}
                    result = await app.ainvoke(Command(resume=resume_value), config)
                else:
                    merged_query = combined_query

                    _is_confirm = await is_confirmation_intent(combined_query)
                    _has_full_info = (saved_state.get("ship_number") and saved_state.get("device_name") and saved_state.get("operation_item"))
                    _override_confirmed = _is_confirm and _has_full_info and not saved_state.get("user_confirmed_info", False)

                    initial_state = {**saved_state,"combined_query": merged_query,"history_messages": parse_history(history_message),"initialized": False,"user_intent": "",}
                    if _override_confirmed:
                        print(f"[Checkpointer] 检测到确认意图，自动设置 user_confirmed_info=True")
                        initial_state["user_confirmed_info"] = True
                    result = await app.ainvoke(initial_state, config)
            else:
                initial_state = {"extracted_text": extracted_text,"combined_query": combined_query,"history_messages": parse_history(history_message),"ship_number": "","device_name": "","operation_item": "","additional_info": "",
                    "operation_code": "","operation_time": "","operation_frequency": "","tried_measures": "","running_condition": "","rag_search_result": None,"graph_search_result": None,"response": "",
                    "suggestedReplies": [],"actions": [],"error_message": "","agent_decision": "","agent_reasoning": "","tools_to_call": [],"missing_info": [],"info_completeness": 0.0,
                    "matched_kb_id": "","matched_kb_name": "","iteration_count": 0,"max_iterations": 5,"scheme_generated": False,"waiting_for_supplement": False,"extracted_info": {},
                    "has_rag_result": False,"has_graph_result": False,"is_execution_feedback": False,"execution_detail": "","ask_round": 0,"user_confirmed_info": False,"need_model_confirm": False,
                    "user_confirmed_model": False,"waiting_feedback": False,"user_feedback": "","waiting_report_confirm": False,"report_confirmed": False,"initialized": False,"current_node": "","user_intent": "","last_combined_query": "",}
                result = await app.ainvoke(initial_state, config)
        except Exception as e:
            print(f"[Checkpointer] 状态恢复失败: {e}")
            import traceback
            traceback.print_exc()
            result = {}
    else:
        initial_state = {"extracted_text": extracted_text,"combined_query": combined_query,"history_messages": parse_history(history_message),"ship_number": "","device_name": "","operation_item": "","additional_info": "","operation_code": "","operation_time": "",
            "operation_frequency": "","tried_measures": "","running_condition": "","rag_search_result": None,"graph_search_result": None,"response": "","suggestedReplies": [],"actions": [],"error_message": "","agent_decision": "","agent_reasoning": "","tools_to_call": [],
            "missing_info": [],"info_completeness": 0.0,"matched_kb_id": "","matched_kb_name": "","iteration_count": 0,"max_iterations": 5,"scheme_generated": False,"waiting_for_supplement": False,"extracted_info": {},"has_rag_result": False,"has_graph_result": False,
            "is_execution_feedback": False,"execution_detail": "","ask_round": 0,"user_confirmed_info": False,"need_model_confirm": False,"user_confirmed_model": False,"waiting_feedback": False,"user_feedback": "","waiting_report_confirm": False,"report_confirmed": False,"initialized": False,"current_node": "","user_intent": "","last_combined_query": "",}

        try:
            result = await app.ainvoke(initial_state, config)
        except Exception as e:
            print(f"[工作流执行失败] {str(e)}")
            import traceback
            traceback.print_exc()
            return {"response": f"操作工作流执行失败: {str(e)}","actions": [],"result_tag": "operate","suggestedReplies": [],}

    if result is None:
        result = {}

    interrupts = result.get("__interrupt__", [])
    if interrupts:
        interrupt_data = interrupts[0].value if interrupts else {}
        print(f"[Interrupt] 工作流中断，等待用户输入: {interrupt_data}")
        return {"response": interrupt_data.get("response", "请提供更多信息"),"actions": interrupt_data.get("actions", []),"result_tag": "operate","suggestedReplies": interrupt_data.get("suggestedReplies", []),"waiting_for": interrupt_data.get("waiting_for", ""),}

    if result.get("error_message"):
        return {"response": f"操作工作流执行失败: {result['error_message']}","actions": [],"result_tag": "operate","suggestedReplies": [],}

    route_flag = result.get("route_flag", "")
    if not route_flag:
        route_flag = "operate"

    return {"response": result.get("response", ""),"actions": result.get("actions", []),"result_tag": route_flag,"suggestedReplies": result.get("suggestedReplies", []),"route_flag": route_flag,}


 x%'"""
工作流：普通问答Agent（使用LangGraph）
输入：文本（转化后和原文本query）、图片描述、语音文本
步骤：
1. 使用RAG和GraphRAG检索相关信息
2. 生成回答
使用 OpenaiAPI 方法调用大模型，尽可能使用异步
"""
from typing import TypedDict, Optional, Dict, Any, List
from langgraph.graph import StateGraph, START, END
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import track_function_calls, get_current_stream_handler
import asyncio
import json
import re


# =============== 定义状态 ===============
class Othertate(TypedDict):
    """普通问答工作流状态"""
    extracted_text: str  # 已提取的文本（统一接口，只接收文本）
    combined_query: str
    route_flag: str  # 路由标识
    history_message: str  # 历史消息（JSON格式）
    history_messages: List[Dict[str, Any]]  # 过滤后的历史消息列表

    # RAG检索结果
    rag_search_result: Optional[List[Dict[str, Any]]]  # RAG检索结果
    graph_search_result: Optional[str]  # 图谱检索结果

    # 最终响应
    response: str  # 最终响应
    actions: List[Dict[str, Any]]  # 按钮信息列表 [{"type": "...", "label": "...", "icon": "..."}]
    suggestedReplies: List[Dict[str, Any]]  # 建议回复问题列表
    error_message: str  # 错误信息


# =============== 节点函数 ===============

def get_other_history_context(state: Othertate) -> Dict[str, Any]:
    """
    知识问答步骤：获取问答类历史信息
    问答工作流只关注历史问答记录，用于提供上下文
    支持格式：[{'role': 'user', 'content': '...'}, {'role': 'assistant', 'content': '...'}]
    返回消息列表（history_message已经在app.py中过滤过了）
    """
    import json

    history_message = state.get("history_message", "") or ""
    history_messages = []

    if history_message:
        try:
            # history_message已经在app.py中过滤过了，直接解析
            if isinstance(history_message, str):
                history_data = json.loads(history_message)
            else:
                history_data = history_message
            
            if isinstance(history_data, list):
                # 只取最近10条历史记录，避免上下文过长
                history_messages = history_data[-10:]
        except Exception as e:
            pass
    
    return {"history_messages": history_messages}


async def generate_suggested_replies_other(answer: str, question: str) -> List[Dict[str, Any]]:
    """
    生成针对问答结果的建议回复问题
    使用大模型生成两个相关问题
    """
    prompt = f"""
你是一个问答助手。根据以下问答内容，生成两个用户可能关心的后续问题。

【用户问题】
{question}

【回答内容】
{answer[:500]}

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与当前问答内容相关，能够帮助用户进一步了解相关信息
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {{"title": "问题1的标题", "content": "问题1的完整内容"}},
    {{"title": "问题2的标题", "content": "问题2的完整内容"}}
]

只输出JSON，不要有其他文字说明。
"""
    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(prompt, model=None)
        # 尝试解析JSON
        # 提取JSON部分
        json_match = re.search(r'\[.*\]', result, re.DOTALL)
        if json_match:
            json_str = json_match.group(0)
            suggested_replies = json.loads(json_str)
            # 验证格式
            if isinstance(suggested_replies, list) and len(suggested_replies) >= 2:
                # 确保每个元素都有title和content
                formatted_replies = []
                for reply in suggested_replies[:2]:
                    if isinstance(reply, dict) and "title" in reply and "content" in reply:
                        formatted_replies.append({
                            "title": str(reply["title"]),
                            "content": str(reply["content"])
                        })
                if len(formatted_replies) == 2:
                    return formatted_replies

        # 如果解析失败，返回默认问题
        return [
            {"title": "这个设备的具体工作原理是什么？", "content": "这个设备的具体工作原理是什么？"},
            {"title": "还有哪些相关的知识点？", "content": "还有哪些相关的知识点？"}
        ]
    except Exception as e:
        # 如果生成失败，返回默认问题
        return [
            {"title": "这个设备的具体工作原理是什么？", "content": "这个设备的具体工作原理是什么？"},
            {"title": "还有哪些相关的知识点？", "content": "还有哪些相关的知识点？"}
        ]


@track_function_calls
async def generate_answer(state: Othertate) -> Dict[str, Any]:
    """
    正在生成问答结果
    """
    extracted_text = state.get("combined_query", "")
    history_messages = state.get("history_messages", []) or []
    print("history_message(qa)", history_messages)

    try:
        # 构建系统提示词
        system_prompt = """我是AI助手，根据历史信息和用户问题进行回答。
请基于以上信息，给出准确、专业的回答。如果有历史问答上下文，请结合历史对话内容理解当前问题。"""

        # 构建消息列表
        messages = []
        
        # 添加历史消息
        if history_messages:
            messages.extend(history_messages)
        
        # 添加当前用户查询
        messages.append({"role": "user", "content": f"用户问题：{extracted_text}"})

        # 调用LLM生成回答（异步，禁用thinking）
        answer = await OpenaiAPI.open_api_chat_without_thinking(
            model=None,
            system_prompt=system_prompt,
            messages=messages
        )

        # 过滤掉 <think> 标签（如果有）
        import re
        answer = re.sub(r'<think>.*?</think>', '', answer, flags=re.DOTALL)
        answer = answer.strip() if answer else "抱歉，无法生成回答。"

        # 返回按钮：确认结果、重新生成
        actions = []

        # 生成建议回复问题
        suggested_replies = await generate_suggested_replies_other(answer, extracted_text)

        return {
            "response": answer,
            "actions": actions,
            "result_tag": "other",
            "suggestedReplies": suggested_replies
        }
    except Exception as e:
        return {
            "response": f"生成回答失败: {str(e)}",
            "actions": [],
            "suggestedReplies": []
        }


# =============== 构建工作流 ===============
def create_qa_workflow():
    """创建普通问答工作流"""
    workflow = StateGraph(Othertate)

    # 添加节点
    workflow.add_node("get_other_history_context", get_other_history_context)
    workflow.add_node("generate_answer", generate_answer)

    # 设置边
    workflow.add_edge(START, "get_other_history_context")
    workflow.add_edge("get_other_history_context", "generate_answer")
    workflow.add_edge("generate_answer", END)

    # 编译工作流
    return workflow.compile()


# =============== 工作流执行函数 ===============
async def run_other_workflow(
        extracted_text: str,
        combined_query: str,
        history_message: str = "",
        route_flag: str = ""
) -> Dict[str, Any]:
    """
    执行普通问答工作流（统一接口）

    Args:
        extracted_text: 文本描述（统一的输入参数）
        history_message: 历史消息（目前只接收，不做处理）

    Returns:
        工作流执行结果
    """
    # 创建并编译工作流
    app = create_qa_workflow()

    # 初始化状态（统一接口，只使用extracted_text和history_message）
    initial_state = {
        "extracted_text": extracted_text,
        "combined_query": combined_query,
        "history_message": history_message,
        "history_messages": [],
        "response": "",
        "actions": [],
        "suggestedReplies": [],
        "error_message": ""
    }

    try:
        # 执行工作流（使用异步方式）
        final_state = await app.ainvoke(initial_state)

        # 检查是否有错误
        if final_state.get("error_message"):
            return {
                "response": f"普通问答工作流执行失败: {final_state['error_message']}",
                "actions": [],
                "result_tag": "qa",
                "suggestedReplies": []
            }

        # 统一输出格式：完全透传 generate_answer 的结果
        return {
            "response": final_state.get("response", ""),
            "actions": final_state.get("actions", []),
            "result_tag": "other",
            "suggestedReplies": final_state.get("suggestedReplies", [])
        }

    except Exception as e:
        return {
            "response": f"普通问答工作流执行失败: {str(e)}",
            "actions": [],
            "result_tag": "other",
            "suggestedReplies": []
        }


# =============== 测试 ===============
if __name__ == "__main__":
    import asyncio

    # 测试用例
    test_cases = [
        "什么是主机？",
        "主机的作用是什么？"
    ]


    async def test():
        for i, test_text in enumerate(test_cases, 1):
            print(f"\n{'=' * 60}")
            print(f"测试用例 {i}")
            print(f"{'=' * 60}")

            result = await run_other_workflow(extracted_text=test_text)

            print(f"\n执行结果:")
            print(f"成功: {result.get('success', False)}")
            print(f"\n响应内容:")
            print(result.get("response", "无响应"))


    asyncio.run(test())

md
xUQ"""
通用报告生成工作流

统一接口说明：
- 输入：extracted_text（用户输入文本）、history_message（历史消息）
- 输出：{"response": str, "actions": List[Dict], "route_flag": str}

功能：
1. 从历史对话中提取关键信息
2. 根据用户需求生成通用报告
3. 支持图片插入到报告对应位置
"""
import asyncio
import re
import random
from typing import TypedDict, List, Dict, Any, Literal
from langgraph.graph import StateGraph, START, END
import os
import sys

current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
if parent_dir not in sys.path:
    sys.path.append(parent_dir)

from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import track_function_calls
from utils.word_generator import generate_report_word
from config import SERVER_CONFIG
import json


def _extract_images_from_text(text: str) -> List[Dict[str, str]]:
    """从文本中提取图片URL和描述信息"""
    if not text:
        return []

    images = []
    url_pattern = r'https?://[^\s<>"{}|\\^`\[\]]+\.(?:png|jpg|jpeg|gif|bmp|webp)'
    urls = re.findall(url_pattern, text, re.IGNORECASE)

    for url in urls:
        url = url.strip()
        if url.startswith('`') and url.endswith('`'):
            url = url[1:-1]

        summary = ""
        url_index = text.find(url)
        if url_index != -1:
            after_url = text[url_index + len(url):]
            result_match = re.search(
                r'(?:\*\*图片识别结果：\*\*|图片识别结果[：:]|识别结果[：:])\s*(.*?)(?=\n\n\n|\n\n[A-Za-z\u4e00-\u9fa5]|$)',
                after_url,
                re.DOTALL
            )
            if result_match:
                summary = result_match.group(1).strip()[:300]

        images.append({
            "url": url,
            "summary": summary or "用户上传的图片"
        })

    return images


from workflows.history_manager import init_history, build_history_str


class OtherReportState(TypedDict):
    """通用报告工作流状态"""

    extracted_text: str
    combined_query: str

    history_message: str
    history_messages: List[Dict[str, Any]]

    report_title: str
    report_theme: str
    report_text: str
    extracted_images: List[Dict[str, str]]

    response: str
    actions: List[Dict[str, Any]]
    route_flag: Literal["", "report"]
    suggestedReplies: List[Dict[str, Any]]

    error_message: str


async def extract_report_info(state: OtherReportState) -> Dict[str, Any]:
    """
    步骤一：提取报告相关信息
    """
    from utils.function_tracker import get_all_callbacks

    combined_query = state.get("combined_query", "") or state.get("extracted_text", "") or ""
    history_messages = state.get("history_messages", [])
    history_message = state.get("history_message", "")

    extracted_images = _extract_images_from_text(history_message)

    history_context = build_history_str(history_messages, recent_count=10, assistant_truncate=200)

    if not history_context and history_message:
        history_context = history_message

    loading_prompts = [
        {"title": "提取报告相关信息中...", "details": f"历史消息数: {len(history_messages)}条"},
        {"title": "🔍 正在分析历史对话内容...", "details": f"共处理 {len(history_messages)} 条消息"},
        {"title": "📊 解析报告信息中...", "details": f"已加载 {len(history_messages)} 条历史记录"},
        {"title": "🔑 整理对话数据...", "details": f"当前历史消息: {len(history_messages)} 条"},
        {"title": "💬 提取关键信息...", "details": f"历史对话总数: {len(history_messages)}条"},
    ]
    selected_prompt = random.choice(loading_prompts)
    parent_event = {
        "type": "function_execution",
        "title": selected_prompt["title"],
        "details": selected_prompt["details"],
    }
    for callback in get_all_callbacks():
        try:
            callback(parent_event)
        except Exception:
            pass

    prompt = f"""
你是一名专业的报告编写专家。
请根据以下信息生成报告标题和主题。

【用户输入】
{combined_query}

【历史对话上下文】
{history_context if history_context else "（无）"}

【输出要求】
输出一个JSON对象，包含以下字段：
- report_title：报告标题（简洁明了，不超过20个字，格式根据内容自动判断，如"XXX分析报告"、"XXX总结报告"等）
- report_theme：报告主题（用一句话概括报告的核心主题，用于指导后续报告内容生成，不超过50个字）

仅输出 JSON 对象，不要附加任何解释。
"""

    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            model=None,
            json_output=True
        )
        parsed_result = json.loads(result)
        if isinstance(parsed_result, dict):
            report_title = parsed_result.get("report_title", "通用报告")
            report_theme = parsed_result.get("report_theme", "")
        else:
            report_title = "通用报告"
            report_theme = ""
    except Exception as e:
        report_title = "通用报告"
        report_theme = ""

    return {"report_title": report_title, "report_theme": report_theme, "extracted_images": extracted_images}


async def generate_report_text(state: OtherReportState) -> Dict[str, Any]:
    """
    步骤二：生成报告文本
    """
    from utils.function_tracker import get_all_callbacks
    import time

    report_title = state.get("report_title", "通用报告")
    report_theme = state.get("report_theme", "")
    combined_query = state.get("combined_query", "") or state.get("extracted_text", "") or ""
    history_messages = state.get("history_messages", [])
    extracted_images = state.get("extracted_images", []) or []

    loading_prompts = [
        {"title": "✍️ 生成报告文本中...", "details": f"报告标题: {report_title}"},
        {"title": "🎯 正在撰写报告...", "details": f"报告标题: {report_title}"},
        {"title": "📋 构建报告中...", "details": f"报告标题: {report_title}"},
        {"title": "📝 汇总生成报告...", "details": f"报告标题: {report_title}"},
    ]
    selected_prompt = random.choice(loading_prompts)
    start_event = {
        "type": "function_execution",
        "title": selected_prompt["title"],
        "details": selected_prompt["details"]
    }
    for callback in get_all_callbacks():
        try:
            callback(start_event)
        except Exception:
            pass

    history_context = build_history_str(history_messages, recent_count=10, assistant_truncate=300)

    if not history_context and not combined_query:
        return {
            "report_text": "",
            "response": "【无法生成报告】\n\n缺少历史对话信息和用户输入，请先进行相关对话。",
            "actions": [],
            "route_flag": "report",
            "suggestedReplies": [],
            "error_message": "缺少历史对话信息和用户输入"
        }

    random_letters = ''.join(random.choices('ABCDEFGHIJKLMNOPQRSTUVWXYZ', k=2))
    report_number = time.strftime(f"{random_letters}-%Y-%m-%d-%H%M")
    compile_time = time.strftime("%Y-%m-%d %H:%M")

    image_section = ""
    if extracted_images:
        image_parts = []
        for idx, img in enumerate(extracted_images, 1):
            image_parts.append(f"图片{idx}：{img['url']}")
            summary = img.get('summary') or img.get('description', '')
            if summary:
                image_parts.append(f"识别结果：{summary}")
            image_parts.append("")
        image_section = "\n".join(image_parts)

    prompt = f"""
<role>
你是一名专业的报告编写专家。
你的任务是根据用户需求和历史对话生成一份正式的报告。
</role>

<user_requirement>
{combined_query}
</user_requirement>

<report_theme>
{report_theme if report_theme else "根据内容自动确定"}
</report_theme>

<history_context>
{history_context if history_context else "（无历史对话上下文）"}
</history_context>

{f'''<user_images>
{image_section}
</user_images>''' if extracted_images else ''}

<output_rules>

必须严格遵守以下规则：

1. 输出为 **正式报告文本**
2. **使用段落形式，如果需要表格，必须使用 Markdown 表格格式**
3. **输出内容必须基于历史对话信息，不得编造不实信息**
4. 不得输出解释说明
5. 所有内容使用完整中文句子
6. **【重要】每个段落首行必须缩进两个中文字符，使用两个全角空格"　　"开头，例如："　　这是段落内容。"**
7. 根据报告主题自动选择合适的报告结构，可以是分析报告、总结报告、调研报告等
8. **报告内容必须紧扣报告主题，确保内容相关性和连贯性**
{"9. **报告中必须包含用户上传的图片信息，在相关部分引用图片URL**" if extracted_images else ""}

</output_rules>

<title_format_rules>

**标题格式规范（必须严格遵守）：**

1. **报告主标题**：使用二级标题格式，即 `## **标题内容**`，例如：`## **智能运维系统项目总结报告**`
2. **章节大标题**：使用三级标题格式，即 `### **标题内容**`，例如：`### **一、项目概述**`
3. **小节标题**：使用四级标题格式，即 `#### **标题内容**`，例如：`#### **1. 项目背景**`
4. 所有标题必须加粗，使用 `**标题内容**` 格式
5. 标题前后各空一行

</title_format_rules>

<paragraph_format_rules>

**段落格式规范（必须严格遵守）：**

1. 每个段落必须以两个全角空格"　　"开头
2. 正确示例：
　　本项目旨在开发一套智能运维系统，用于提升企业IT运维效率。
　　系统采用微服务架构设计，支持高并发访问。
3. 错误示例（缺少缩进）：
本项目旨在开发一套智能运维系统。
4. 段落之间空一行

</paragraph_format_rules>

<report_template>

## **{report_title}**

报告编号：{report_number}
编制时间：{compile_time}

### **一、概述**

　　介绍背景与目的。

### **二、主要内容**

　　阐述核心问题与关键分析过程。

### **三、备品备件**

　　列出本次维修或操作涉及的备品备件的名称（如有机油滤芯、密封圈、螺栓、传感器等），不要输出表格。如果没有涉及备件，请写"无"。

### **四、结论**

　　总结结果并提出结论性观点。
{"- **附件图片：**" + chr(10) + chr(10).join([f"![图片{idx}]({img['url']})" for idx, img in enumerate(extracted_images, 1)]) if extracted_images else ""}

</report_template>

<final_rule>
只输出完整报告正文，不要任何解释说明。每个段落首行必须使用"　　"（两个全角空格）缩进。所有标题必须使用对应级别的Markdown格式并加粗。
</final_rule>
"""

    try:
        report_text = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            model=None,
            messages=history_messages
        )
        if not report_text:
            report_text = "抱歉，当前无法生成报告，请稍后重试。"

        word_dir = os.path.join(parent_dir, "created_word")
        os.makedirs(word_dir, exist_ok=True)

        import time
        timestamp = time.strftime("%Y%m%d_%H%M%S")
        safe_topic = re.sub(r'[\\/:*?"<>|]', '_', report_title)
        file_name = f"{safe_topic}_{timestamp}.docx"
        output_path = os.path.join(word_dir, file_name)

        word_result = generate_report_word(
            markdown=report_text,
            title=report_title,
            output=output_path
        )

        actions: List[Dict[str, Any]] = []

        if word_result and os.path.exists(word_result):
            base_url = SERVER_CONFIG.get("base_url")
            download_url = f"{base_url}/api/download/{file_name}"

            actions.append({
                "type": "download",
                "label": f"{report_title}.docx",
                "url": download_url,
                "fileName": file_name,
                "content": report_text
            })
            
            try:
                from tools.fault_statistics import save_spare_parts_metadata, extract_spare_parts_from_text, extract_info_from_filename
                
                spare_parts = await extract_spare_parts_from_text(report_text)
                
                print(f"[备件提取] 提取到 {len(spare_parts)} 个备件: {spare_parts}")
                
                # 无论有没有备件都保存元数据
                device = ""
                ship_number = ""
                fault_name = ""
                # 优先从文件名中提取（最准确）
                file_info = await extract_info_from_filename(file_name)
                if file_info:
                    if file_info.get("device"):
                        device = file_info["device"]
                    if file_info.get("ship_number"):
                        ship_number = file_info["ship_number"]
                    if file_info.get("fault_name"):
                        fault_name = file_info["fault_name"]
                # 如果从文件名没提取全，再尝试从历史消息中提取
                if not device or not ship_number or not fault_name:
                    if history_messages:
                        for msg in reversed(history_messages):
                            if isinstance(msg, dict) and msg.get("role") == "user":
                                content = msg.get("content", "")
                                if not device:
                                    device_match = re.search(r'设备[名称]*[：:]\s*([^\n,，]+)', content)
                                    if device_match:
                                        device = device_match.group(1).strip()
                                if not ship_number:
                                    ship_match = re.search(r'舷号[：:]\s*(\d+)', content)
                                    if ship_match:
                                        ship_number = ship_match.group(1).strip()
                
                print(f"[备件保存] 设备: {device}, 舷号: {ship_number}, 故障: {fault_name}, 文件: {output_path}")
                save_spare_parts_metadata(output_path, spare_parts, device, ship_number, fault_name)
            except Exception as e:
                print(f"[备件提取错误] {str(e)}")
                import traceback
                traceback.print_exc()
        else:
            error_msg = f"\n\n[注意] Word 文档生成失败"
            report_text += error_msg

        suggested_replies = await generate_suggested_replies(report_text)

        return {
            "report_text": report_text,
            "response": report_text,
            "actions": actions,
            "route_flag": "report",
            "suggestedReplies": suggested_replies,
            "__details__": "报告生成完成"
        }
    except Exception as e:
        return {
            "report_text": f"生成报告失败: {str(e)}",
            "response": f"生成报告失败: {str(e)}",
            "actions": [],
            "route_flag": "report",
            "suggestedReplies": [
                {"title": "如何优化报告内容？", "content": "如何优化报告内容？"},
                {"title": "有哪些改进建议？", "content": "有哪些改进建议？"}
            ],
            "error_message": str(e),
            "__details__": f"生成报告失败: {str(e)}"
        }


async def generate_suggested_replies(report: str) -> List[Dict[str, Any]]:
    """
    生成针对报告的建议回复问题
    """
    prompt = f"""
你是一个专业的报告助手。根据以下报告内容，生成两个用户可能关心的后续问题。

【报告内容】
{report[:500]}

请生成两个简洁、实用的问题，这些问题应该：
1. 不得出现需要归档和下载等操作相关的问题
2. 与报告内容相关，能够帮助用户更好地理解或使用报告
3. 问题要具体、可操作
4. 每个问题不超过20个字

请以JSON格式输出，格式如下：
[
    {{"title": "问题1的标题", "content": "问题1的完整内容"}},
    {{"title": "问题2的标题", "content": "问题2的完整内容"}}
]

只输出JSON，不要有其他文字说明。
"""
    try:
        answer = await OpenaiAPI.open_api_chat_without_thinking(
            query=prompt,
            model=None
        )
        json_match = re.search(r'\[.*\]', answer, re.DOTALL)
        if json_match:
            json_str = json_match.group(0)
            suggested_replies = json.loads(json_str)
            if isinstance(suggested_replies, list) and len(suggested_replies) >= 2:
                formatted_replies = []
                for reply in suggested_replies[:2]:
                    if isinstance(reply, dict) and "title" in reply and "content" in reply:
                        formatted_replies.append({
                            "title": str(reply["title"]),
                            "content": str(reply["content"])
                        })
                if len(formatted_replies) == 2:
                    return formatted_replies

        return [
            {"title": "如何优化报告内容？", "content": "如何优化报告内容？"},
            {"title": "有哪些改进建议？", "content": "有哪些改进建议？"}
        ]
    except Exception as e:
        return [
            {"title": "如何优化报告内容？", "content": "如何优化报告内容？"},
            {"title": "有哪些改进建议？", "content": "有哪些改进建议？"}
        ]


def create_other_report_workflow():
    """创建通用报告工作流"""
    graph = StateGraph(OtherReportState)

    graph.add_node("extract_info", extract_report_info)
    graph.add_node("generate_text", generate_report_text)

    graph.add_edge(START, "extract_info")
    graph.add_edge("extract_info", "generate_text")
    graph.add_edge("generate_text", END)

    return graph.compile()


async def run_other_report_workflow(
        extracted_text: str,
        combined_query: str,
        history_message: str = "",
        route_flag: str = ""
) -> Dict[str, Any]:
    """
    执行通用报告工作流（供主Agent / app.py 调用）

    Args:
        extracted_text: 主Agent合并后的文本描述
        combined_query: 用户问题
        history_message: 历史消息（JSON格式字符串）
        route_flag: 路由标识

    Returns:
        {
            "response": str,
            "actions": List[Dict[str, Any]],
            "route_flag": str,
            "suggestedReplies": List[Dict[str, Any]]
        }
    """
    app = create_other_report_workflow()

    initial_state: OtherReportState = {
        "extracted_text": extracted_text,
        "combined_query": combined_query,
        **init_history(history_message),
        "report_title": "",
        "report_theme": "",
        "report_text": "",
        "extracted_images": [],
        "response": "",
        "actions": [],
        "route_flag": "",
        "suggestedReplies": [],
        "error_message": ""
    }

    return await app.ainvoke(initial_state)


if __name__ == "__main__":
    async def test():
        history_message = json.dumps(
            [
                {"role": "user", "content": "我需要生成一份项目总结报告"},
                {"role": "assistant", "content": "好的，我可以帮您生成项目总结报告，请提供相关项目信息。"},
                {"role": "user",
                 "content": "项目名称：智能运维系统，项目周期：2024年1月-2024年6月，主要成果：完成了系统架构设计和核心模块开发"}
            ],
            ensure_ascii=False,
        )

        result = await run_other_report_workflow(
            extracted_text="项目名称：智能运维系统，项目周期：2024年1月-2024年6月，主要成果：完成了系统架构设计和核心模块开发",
            combined_query="用户问题：请生成项目总结报告",
            history_message=history_message
        )

        print("====== 报告文本 ======")
        print(result["response"])
        print("\n====== 推荐问题 ======")
        for reply in result.get("suggestedReplies", []):
            print(f"- {reply['title']}: {reply['content']}")
        print("\n====== 操作按钮 ======")
        for action in result.get("actions", []):
            print(f"- {action.get('label', 'Unknown')}: {action.get('type', 'Unknown')}")


    asyncio.run(test())





Acxբ^HoS/_Bclass HistoryQAAnalysisState(TypedDict):
    """历史问答分析extracted_itemp	+"		'analysis_items(state: HistoryQAAnalysis95^
pre_2/相关历史问答数据 解析历史问答mqI 整理历史g 提取对话3情报分析与知识管理专家。
请从以下【用户输入】中抽取用于统计分析的结构化信息。

【用户[n
【抽取规则S根据历史对话内容生成一个简洁的标题，格式为"XXX故障处理报告"，不超过20个字）
- items：抽取录数组，每条记录包含：
  - topic：问题主题（如 设备、系统、管理、流程、保障、训练 等）
  - key_entity：关键对象或名词
  - conclusion：结论 / 判断 / 回答要点
  - action_suggestion：建议或行动若无可为空）
  - date：时间（若无法判断可为空）
- images：图片信息数组（仅当有用户上传图片时提取，每条记录包含）：
  - url：图片URL（直接从【用户上传图片信息】中提取）
  - summary：片内容摘要（根据图片识别结果提炼关键信息，如设备类型、故障现象、异常情况等，不超过1007字）

【输出要求】
1. 仅输出 JSON 对象
2. =:
3. 如果没有图片信息，images字段返回空数组+8N~lN
itemspitems", [])+l*3历史问答分析报告")
            model_imagespimages", [])

i9mN	@items = parsed_result if isinstance(parsed_result, list) else []+@itle = "历史问答分析报告"
            model_images = []
8#extracted_items = []
        report_title = "历史问答分析报告"
        model_images = []

    final_images = pre_extracted_images if pre_extracted_images else model_images

    return {"extracted_items": extracted_items, "report_title": report_title,Kfinal_images}


# @track_function_calls
async def generate_analysis_report_text(state: HistoryQAAnalysisState) -> Dict[str, AnyPJ2extracted_items = state.get("extracted_items", [])/历史问答分析报告")^
4
=def summarize_extracted_items(items) -> str:
        """将抽取结果转为中文描述，兼容 list / dict"""

        if nlot items:
            return "未提取到有效分析数据"

        # 如果是单个 dict，转为 list
AitemsOitems = [items]

        # 如果不是 list，直接返回
        if not isinstance(items, list):
            return "分析据格式异常"

        topics = set()
        entities = set()

        for item in items:
            if not isinstance(itemO    continue

            topic = item.get("topic")
            entity = item.get("key_entity")

            if topic:
                topics.add(str(topic))
            if entity:
                entities.add(str(entity))

        topic_text = "、".join(list(topics)[:5]) if topics else "未识别"
        entity_text = "、".join(list(entities)[:5]) if entities else "未识别"

        return f"识别主题 {len(items)} 条，涉及主题：{topic_text}；关键对象：{entity_text}"

    details_te/xt = summarize_extracted_items(extracted_items)/,9📄 生成分析报告文本", "details": details_text},,2正在撰写分析报告", "details": details_text-: 生成历史问答分析报告", "details": details_text-4 构建分析报告结构", "details": details_text-A 汇总历史问答数据生成报告", "details": details_textB@c分枓J问答9Z设备运维与故障分析7?、历史对话和抽取信息生成一份正式的故障处理M4extracted_items>
{extracted_items}
</extracted_items术 /有表格生成，生成表格必须arkdown表格，不要html形式**
3. **如果给定结果在历史对话信息中没有，\可以进行删除**
4. **输出内容必须严格按照历史对话信息内容进行生成@!和不相干信息**
5_!6. 不要使用列表符号
7{!&0。
8. **每个段落首行必须缩进，使用*7　　）实现首行缩进两个中文字符的效果"@故障信息;#Ir' {report_title}

报告编号： ' {compile_time}
事件类型： 设备故障诊断与处置

一、事件概述
　　简要说明故障发生背景、报警况、系统影响以及运维团队启动排查流程的情况。

二、故障信息
　　说明设备名称、型号、所K属系统、报警时间、故障现象以及参与处置人员。
{"　　)1　　)m三、故障排查过程
　　按照时间顺序描述排查步骤，包括：用户反馈 → 初步判断 → 数据分析  现场检查 → 故障确认。

四、维修措施
　　描述维修人员采取的具体维修步骤，包括设备停、拆卸检查、更换部件、紧固连接、恢复运行和测试过程。

五、后续建议
　　提出预防类似故障的改进措施，例如：维护周期优化、知识库记录、巡检项目增加、技术培训等。

六、总结
　>总结本次故障原因、处理效果以及经验意义。*\*分枓,,ZS-r9t# action#     "type": "regenerate",
        #     "label": "重新生成",
        #     "icon": "report"
        # })

        suggest9-
_qa_report:[],
#I :/分析;A# error_event = {
        #+#     "title": "步骤二失败：生成分析报告",
        #     "details": f"错误: {str(e)}",
        #     "has_result": False
        # }
        #].<#     try:
        #         callback(error_event)
        #8
#         pass
-;分枓Q=;"分枓Q=;Ls'=+分枓Q=I
_qa_report=?历史问答分析= !使用大模型生成两个相关=78据分析助手。根据以下历史问答分析报告K>8分析报告>分析报告2?3分析结果k?问题分布m<问题分布aEjDO问题分布m<问题分布aEwHhistory_qa_analysis_workflow():
    graph = StateGraph(HistoryQAAnalysis9F%tems", extract_analysis_items)@FFanalysisF3temsGextract_itemsF[6# @track_function_calls
async def run_qa_report_agent(`HGa,
    * = None
> app = create_history_qa_analysisJ HistoryQAAnalysis/Jextracted_items": []K or []J/J2Kimport asyncio

K!分析最近的历史问答数据LT历史问答分析L数据 M'hL3请重点关注设备故障和维护相关的内容MXqa_report_agent^N3请重点关注设备故障和维护相关的内容O10重点关注设备故障和维护相关的内容QOP历史问答分析O>xy@"""
工作流：受控 ReAct Text2SQL 统计智能体

架构（简洁直接，无多轮交互）：
  用户问题
    ↓
  Router Node（判断：统计分析 / 维修反馈 / 普通问答）
    ├── 普通问答 → final_answer → END
    ├── 维修反馈 → repair_feedback → final_answer → END
    └── 统计分析 → text2sql_tool（内部闭环）→ final_answer → END

text2sql_tool 内部闭环：SQL生成 → SQL审查 → SQL Guard → SQL执行
"""
import sys
import os
import json
import re
from datetime import datetime
from typing import TypedDict, Optional, Dict, Any, List

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

from langgraph.graph import StateGraph, START, END
from modelsAPI.model_api import OpenaiAPI
from prompts import TEXT2SQL_PROMPTS
from tools.text2sql_tool import text2sql_tool
from tools.fault_statistics import repair_feedback_statistics_tool


# ============================================================
# 状态定义
# ============================================================

class StatisticsState(TypedDict):
    # 输入
    extracted_text: str
    combined_query: str
    route_flag: str
    history_message: str
    history_messages: List[Dict[str, Any]]

    # 路由结果
    route_result: Optional[str]  # "statistics" / "feedback" / "normal"

    # Text2SQL 结果
    sql: Optional[str]
    sql_result: Optional[Dict[str, Any]]

    # 维修反馈结果
    feedback_result: Optional[Dict[str, Any]]
    feedback_params: Optional[Dict[str, Any]]

    # 输出
    response: str
    actions: List[Dict[str, Any]]
    suggestedReplies: List[Dict[str, Any]]
    error_message: str


# ============================================================
# Node 1: Router Node
# ============================================================

async def router_node(state: StatisticsState) -> Dict[str, Any]:
    """
    路由判断：统计分析 / 维修反馈 / 普通问答
    """
    question = state.get("combined_query") or state.get("extracted_text", "")

    prompt = TEXT2SQL_PROMPTS["router"].format(question=question)

    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(
            prompt, model=None, json_output=True
        )

        json_match = re.search(r'\{.*\}', result, re.DOTALL)
        if json_match:
            parsed = json.loads(json_match.group(0))
            route = parsed.get("route", "statistics").strip().lower()
            if route in ("statistics", "feedback", "normal"):
                return {"route_result": route}

    except Exception as e:
        print(f"路由判断失败: {str(e)}")

    return {"route_result": "statistics"}


# ============================================================
# Node 2: Text2SQL Node
# ============================================================

async def text2sql_node(state: StatisticsState) -> Dict[str, Any]:
    """
    调用受控 Text2SQL 工具
    内部闭环：SQL生成 → SQL审查 → SQL Guard → SQL执行（含重试）
    """
    question = state.get("combined_query") or state.get("extracted_text", "")
    current_date = datetime.now().strftime("%Y-%m-%d")

    result = await text2sql_tool(question=question, current_date=current_date)

    return {
        "sql": result.get("sql", ""),
        "sql_result": result
    }


# ============================================================
# Node 3: Repair Feedback Node
# ============================================================

async def repair_feedback_node(state: StatisticsState) -> Dict[str, Any]:
    """
    处理维修反馈类问题（走外部API）
    """
    question = state.get("combined_query") or state.get("extracted_text", "")
    params = await _extract_feedback_params(question)

    try:
        result = await repair_feedback_statistics_tool.ainvoke(params)
        return {"feedback_result": result, "feedback_params": params}
    except Exception as e:
        return {"feedback_result": {"success": False, "error": str(e)}, "feedback_params": params}


async def _extract_feedback_params(question: str) -> Dict[str, Any]:
    """从用户问题中提取维修反馈参数"""
    current_date = datetime.now().strftime("%Y-%m-%d")

    prompt = f"""从以下问题中提取维修反馈统计参数，返回JSON格式。

当前日期：{current_date}

用户问题：{question}

需要提取的参数：
- source: 来源筛选（好评/差评/反馈），如果没有则为空字符串
- start_date: 开始日期（格式：YYYY-MM-DD），如果没有则为空字符串
- end_date: 结束日期（格式：YYYY-MM-DD），如果没有则为空字符串

时间映射：
- "近一个月" → start_date = 当前日期前30天
- "近一周" → start_date = 当前日期前7天
- "近三个月" → start_date = 当前日期前90天

输出格式：
{{"source": "", "start_date": "", "end_date": ""}}
只输出JSON。"""

    try:
        result = await OpenaiAPI.open_api_chat_without_thinking(
            prompt, model=None, json_output=True
        )
        json_match = re.search(r'\{.*\}', result, re.DOTALL)
        if json_match:
            parsed = json.loads(json_match.group(0))
            params = {}
            if parsed.get("source"):
                params["source"] = parsed["source"]
            if parsed.get("start_date"):
                params["start_date"] = parsed["start_date"]
            if parsed.get("end_date"):
                params["end_date"] = parsed["end_date"]
            return params
    except Exception:
        pass

    return {}


# ============================================================
# Node 4: Final Answer Node
# ============================================================

async def final_answer_node(state: StatisticsState) -> Dict[str, Any]:
    """
    将查询结果转为自然语言回答
    """
    route_result = state.get("route_result", "statistics")
    question = state.get("combined_query") or state.get("extracted_text", "")

    if route_result == "feedback":
        return await _format_feedback_answer(state, question)
    elif route_result == "normal":
        return {
            "response": "您的问题似乎不属于统计分析类问题，请尝试更具体的统计查询，例如：\"最近一个月哪个故障最多\"、\"101舰备件消耗情况\"等。",
            "actions": [],
            "suggestedReplies": [
                {"title": "故障频次统计", "content": "最近一个月哪个故障最多"},
                {"title": "备件消耗统计", "content": "101舰近一个月备件消耗"},
                {"title": "维修反馈", "content": "近一个月维修差评情况"}
            ]
        }
    else:
        return await _format_statistics_answer(state, question)


async def _format_statistics_answer(state: StatisticsState, question: str) -> Dict[str, Any]:
    """格式化统计分析结果"""
    sql_result = state.get("sql_result", {})

    if not sql_result.get("success", False):
        error = sql_result.get("error", "未知错误")
        return {
            "response": f"统计分析执行失败：{error}",
            "actions": [],
            "suggestedReplies": [
                {"title": "故障频次统计", "content": "最近一个月哪个故障最多"},
                {"title": "备件消耗统计", "content": "近一个月备件消耗排名"}
            ]
        }

    rows = sql_result.get("rows", [])
    sql = sql_result.get("sql", "")
    row_count = sql_result.get("row_count", 0)

    # 使用 LLM 生成自然语言回答
    result_data = json.dumps(rows[:20], ensure_ascii=False, indent=2)

    prompt = TEXT2SQL_PROMPTS["final_answer"].format(
        question=question,
        sql=sql,
        row_count=row_count,
        result_data=result_data
    )

    try:
        answer = await OpenaiAPI.open_api_chat_without_thinking(prompt, model=None)
        response = answer.strip()
    except Exception:
        response = _simple_format_result(rows, row_count)

    return {
        "response": response,
        "actions": [],
        "suggestedReplies": _generate_suggested_replies(question)
    }


async def _format_feedback_answer(state: StatisticsState, question: str) -> Dict[str, Any]:
    """格式化维修反馈结果"""
    feedback_result = state.get("feedback_result", {})
    feedback_params = state.get("feedback_params", {})

    if not feedback_result.get("success", False):
        return {
            "response": "维修反馈统计失败，请稍后重试。",
            "actions": [],
            "suggestedReplies": []
        }

    feedback_data = feedback_result.get("feedbackData", [])
    total_count = feedback_result.get("totalCount", 0)
    source_distribution = feedback_result.get("sourceDistribution", {})
    source = feedback_params.get("source", "")
    start_date = feedback_params.get("start_date", "")
    end_date = feedback_params.get("end_date", "")

    if not feedback_data:
        source_desc = f"【{source}】" if source else ""
        time_desc = f"（{start_date} 至 {end_date}）" if start_date and end_date else ""
        return {
            "response": f"未找到{source_desc}维修反馈统计数据{time_desc}。",
            "actions": [],
            "suggestedReplies": [
                {"title": "查看差评", "content": "统计近一个月维修差评情况"},
                {"title": "查看好评", "content": "统计近一个月维修好评情况"}
            ]
        }

    response_parts = []
    source_desc = f"【{source}】" if source else ""
    time_desc = f"（{start_date} 至 {end_date}）" if start_date and end_date else ""
    response_parts.append(f"为您统计{source_desc}的维修反馈数据{time_desc}。\n")

    if source_distribution:
        dist_str = "、".join([f"{k} {v} 条" for k, v in source_distribution.items()])
        response_parts.append(f"核心结论：共收到维修反馈 {total_count} 条（{dist_str}）。\n")

    response_parts.append("排名 | 标题 | 来源 | 反馈人 | 时间")
    response_parts.append("--- | --- | --- | --- | ---")

    for item in feedback_data:
        rank = item.get("rank", 0)
        title = str(item.get("title", ""))[:30]
        item_source = str(item.get("source", "未知"))
        user_name = str(item.get("user_name", "-"))
        created_at = str(item.get("created_at", "-"))[:10]
        response_parts.append(f"{rank} | {title} | {item_source} | {user_name} | {created_at}")

    return {
        "response": "\n".join(response_parts),
        "actions": [],
        "suggestedReplies": [
            {"title": "查看差评", "content": "统计近一个月维修差评情况"},
            {"title": "查看好评", "content": "统计近一个月维修好评情况"},
            {"title": "查看近一周反馈", "content": "统计近一周维修反馈情况"}
        ]
    }


def _simple_format_result(rows: List[Dict[str, Any]], row_count: int) -> str:
    """简单格式化查询结果（LLM生成失败时的兜底）"""
    if not rows:
        return "未查询到相关数据。"

    columns = list(rows[0].keys())
    parts = [f"共查询到 {row_count} 条记录。\n"]
    parts.append(" | ".join(columns))
    parts.append(" | ".join(["---"] * len(columns)))

    for row in rows[:10]:
        values = [str(row.get(col, ""))[:30] for col in columns]
        parts.append(" | ".join(values))

    if row_count > 10:
        parts.append(f"\n... 还有 {row_count - 10} 条记录")

    return "\n".join(parts)


def _generate_suggested_replies(question: str) -> List[Dict[str, Any]]:
    """根据问题生成建议回复"""
    return [
        {"title": "故障频次统计", "content": "最近一个月哪个故障最多"},
        {"title": "备件消耗统计", "content": "近一个月备件消耗排名"},
        {"title": "按系统统计", "content": "动力系统近一个月故障统计"},
        {"title": "按舷号统计", "content": "101舰近一个月故障统计"}
    ]


# ============================================================
# 条件路由
# ============================================================

def route_after_router(state: StatisticsState) -> str:
    """Router 之后的路由"""
    route = state.get("route_result", "statistics")
    if route == "feedback":
        return "feedback"
    elif route == "normal":
        return "normal"
    else:
        return "statistics"


# ============================================================
# 构建工作流
# ============================================================

def create_statistics_workflow():
    """
    创建受控 Text2SQL 统计工作流

    架构（简洁直线型，无多轮交互）：
    START
      ↓
    router_node
      ├── normal → final_answer_node → END
      ├── feedback → repair_feedback_node → final_answer_node → END
      └── statistics → text2sql_node → final_answer_node → END
    """
    workflow = StateGraph(StatisticsState)

    # 添加节点
    workflow.add_node("router_node", router_node)
    workflow.add_node("text2sql_node", text2sql_node)
    workflow.add_node("repair_feedback_node", repair_feedback_node)
    workflow.add_node("final_answer_node", final_answer_node)

    # 入口
    workflow.add_edge(START, "router_node")

    # Router 分支
    workflow.add_conditional_edges(
        "router_node",
        route_after_router,
        {
            "statistics": "text2sql_node",
            "feedback": "repair_feedback_node",
            "normal": "final_answer_node"
        }
    )

    # 各分支 → final_answer → END
    workflow.add_edge("text2sql_node", "final_answer_node")
    workflow.add_edge("repair_feedback_node", "final_answer_node")
    workflow.add_edge("final_answer_node", END)

    return workflow.compile()


# ============================================================
# 统一入口
# ============================================================

async def run_statistics_workflow(
    extracted_text: str,
    combined_query: str,
    history_message: str = "",
    route_flag: str = ""
) -> Dict[str, Any]:
    """
    执行统计工作流（统一接口）
    """
    app = create_statistics_workflow()

    initial_state = {
        "extracted_text": extracted_text,
        "combined_query": combined_query,
        "route_flag": route_flag,
        "history_message": history_message,
        "history_messages": [],
        "route_result": None,
        "sql": None,
        "sql_result": None,
        "feedback_result": None,
        "feedback_params": None,
        "response": "",
        "actions": [],
        "suggestedReplies": [],
        "error_message": ""
    }

    try:
        final_state = await app.ainvoke(initial_state)

        if final_state.get("error_message"):
            return {
                "response": f"统计工作流执行失败: {final_state['error_message']}",
                "actions": [],
                "result_tag": "statistics",
                "suggestedReplies": []
            }

        return {
            "response": final_state.get("response", ""),
            "actions": final_state.get("actions", []),
            "result_tag": "statistics",
            "suggestedReplies": final_state.get("suggestedReplies", [])
        }

    except Exception as e:
        return {
            "response": f"统计工作流执行失败: {str(e)}",
            "actions": [],
            "result_tag": "statistics",
            "suggestedReplies": []
        }


# ============================================================
# 测试
# ============================================================

if __name__ == "__main__":
    import asyncio

    test_cases = [
        "最近一个月哪个故障最多",
        "统计101舰的备件消耗情况",
        "近三个月动力系统故障频次排名",
        "统计维修反馈差评情况",
        "连杆异常磨损怎么修",
    ]

    async def test():
        for i, test_text in enumerate(test_cases, 1):
            print(f"\n{'='*60}")
            print(f"测试用例 {i}: {test_text}")
            print(f"{'='*60}")

            result = await run_statistics_workflow(
                extracted_text=test_text,
                combined_query=test_text
            )

            print(f"\n响应:")
            print(result.get("response", "无响应"))

    asyncio.run(test())

Ḽx7"""
工作流公共工具函数
提取自 workflow_fault_diagnosis.py 和 workflow_operate.py 的共享代码
"""

from typing import TypedDict, Optional, Dict, Any, List
from prompts import COMMON_PROMPTS
from modelsAPI.model_api import OpenaiAPI
from utils.function_tracker import get_all_callbacks, get_current_stream_handler
from utils.image_utils import extract_image_paths, normalize_markdown_images
import json
import re
import random


def safe_json_extract(text: str) -> Optional[Any]:
    if not text:
        return None
    cleaned = text.strip()
    cleaned = re.sub(r"```json\s*", "", cleaned, flags=re.IGNORECASE)
    cleaned = re.sub(r"```\s*", "", cleaned)
    m = re.search(r"\[[\s\S]*\]", cleaned)
    if m:
        try:
            return json.loads(m.group(0))
        except Exception:
            pass
    m = re.search(r"\{[\s\S]*\}", cleaned)
    if m:
        try:
            return json.loads(m.group(0))
        except Exception:
            pass
    try:
        return json.loads(cleaned)
    except Exception:
        return None


from workflows.history_manager import parse_history, build_history_str, filter_image_urls, init_history  # noqa: F401


def normalize_latex_spacing(text: str) -> str:
    placeholder = "\x00DOUBLE_DOLLAR\x00"
    text = text.replace("$$", placeholder)
    text = re.sub(r'(?<!\s)\$', r' $', text)
    text = re.sub(r'\$(?!\s)', r'$ ', text)
    text = text.replace(placeholder, "$$")
    text = re.sub(r'(?<!\s)\$\$', r' $$', text)
    text = re.sub(r'\$\$(?!\s)', r'$$ ', text)
    return text


def remove_duplicate_content(text: str) -> str:
    if not text or len(text) < 10:
        return text

    lines = text.split('\n')
    result = []
    seen_segments = set()

    for line in lines:
        line = line.rstrip()
        if not line:
            result.append(line)
            continue

        normalized_line = line.strip().lower()
        if normalized_line in seen_segments:
            continue

        seen_segments.add(normalized_line)
        result.append(line)

    cleaned_text = '\n'.join(result)
    return cleaned_text


def convert_rag_result(rag_result):
    if not rag_result or not rag_result.get("success", False):
        return []
    source_citation = rag_result.get("sourceCitation", {})
    flat_results = []
    for resource, items in source_citation.items():
        for item in items:
            flat_results.append(item)
    return flat_results


def calculate_info_completeness(weights: Dict[str, float], values: Dict[str, str]) -> float:
    score = 0.0
    for field, weight in weights.items():
        value = values.get(field, "") or ""
        if value and str(value).strip():
            score += weight
    return round(score, 2)


def emit_callback_event(title_options: List[str], details: str):
    start_event = {"type": "function_execution", "title": random.choice(title_options), "details": details}
    for callback in get_all_callbacks():
        try:
            callback(start_event)
        except Exception:
            pass


def build_detail_info(fields: Dict[str, str]) -> str:
    detail_info = ""
    for label, value in fields.items():
        if value:
            detail_info += f"- {label}：{value}\n"
    return detail_info


def append_atlas_section(answer: str, atlas_results: Dict[str, Any]) -> str:
    if not atlas_results:
        return answer
    atlas_section = "\n\n---\n\n**参考图册：**\n"
    for node_name, node_data in atlas_results.items():
        if isinstance(node_data, dict):
            for title, urls in node_data.items():
                if isinstance(urls, list) and urls:
                    for url in urls:
                        atlas_section += f"- {title}: [ `{title}` ]({url})\n"
    return answer + atlas_section




async def stream_format_and_postprocess(
    raw_content: str,
    original_image_paths: List[str],
    temperature: float = 0.3,
    content_label: str = None,
) -> str:
    if content_label:
        format_user_content = COMMON_PROMPTS["format_user_simple"].format(
            content_label=content_label,
            raw_content=raw_content,
        )
    else:
        format_user_content = COMMON_PROMPTS["format_user_with_image_examples"].format(raw_content=raw_content)

    format_system_prompt = COMMON_PROMPTS["format_system"]

    stream_handler = get_current_stream_handler()
    answer = ""
    accumulated_content = ""

    async for chunk in OpenaiAPI.open_api_chat_stream(
        model=None,
        system_prompt=format_system_prompt,
        messages=[{"role": "user", "content": format_user_content}],
        temperature=temperature,
    ):
        answer += chunk
        accumulated_content += chunk
        if stream_handler:
            stream_handler.send_stream_content(accumulated_content)

    answer = answer.strip() if answer else raw_content
    answer = remove_duplicate_content(answer)
    answer = normalize_markdown_images(answer, original_paths=original_image_paths)
    answer = normalize_latex_spacing(answer)

    return answer


EbY|8hBl