From fa74d43586035ac875f812dcf11472b04a09dcec Mon Sep 17 00:00:00 2001 From: seongyeon Date: Thu, 5 Feb 2026 20:20:02 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20Human-in-the-Loop=20=ED=8A=9C=ED=86=A0?= =?UTF-8?q?=EB=A6=AC=EC=96=BC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 모델 초기화 방식 변경: ChatOpenAI → init_chat_model - 그래프 시각화를 Excalidraw 기반 PNG로 변경 - assets 폴더에 excalidraw 소스 및 PNG 이미지 추가 --- .../06-LangGraph-Human-In-the-Loop.ipynb | 323 ++++++++++-- .../06-human-in-the-loop-graph.excalidraw | 471 ++++++++++++++++++ .../assets/06-human-in-the-loop-graph.png | Bin 0 -> 25277 bytes 3 files changed, 749 insertions(+), 45 deletions(-) create mode 100644 08-Core-Features/assets/06-human-in-the-loop-graph.excalidraw create mode 100644 08-Core-Features/assets/06-human-in-the-loop-graph.png diff --git a/08-Core-Features/06-LangGraph-Human-In-the-Loop.ipynb b/08-Core-Features/06-LangGraph-Human-In-the-Loop.ipynb index 0f0b45b..16554ea 100644 --- a/08-Core-Features/06-LangGraph-Human-In-the-Loop.ipynb +++ b/08-Core-Features/06-LangGraph-Human-In-the-Loop.ipynb @@ -18,10 +18,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "id": "de9d9d8d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# API 키를 환경변수로 관리하기 위한 설정 파일\n", "from dotenv import load_dotenv\n", @@ -32,10 +43,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "id": "6b5c6228", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "LangSmith 추적을 시작합니다.\n", + "[프로젝트명]\n", + "LangGraph-V1-Tutorial\n" + ] + } + ], "source": [ "# LangSmith 추적을 설정합니다. https://smith.langchain.com\n", "# !pip install -qU langchain-teddynote\n", @@ -56,12 +77,11 @@ "from typing_extensions import TypedDict\n", "\n", "from langchain_core.tools import tool\n", - "from langchain_openai import ChatOpenAI\n", + "from langchain.chat_models import init_chat_model\n", "from langgraph.checkpoint.memory import MemorySaver\n", "from langgraph.graph import StateGraph, START, END\n", "from langgraph.graph.message import add_messages\n", "from langgraph.prebuilt import ToolNode, tools_condition\n", - "from langchain_teddynote.graphs import visualize_graph\n", "from langchain_teddynote.tools import GoogleNews\n", "\n", "\n", @@ -87,8 +107,8 @@ "\n", "tools = [search_keyword]\n", "\n", - "# LLM 초기화\n", - "llm = ChatOpenAI(model=\"gpt-4o-mini\")\n", + "# LLM 초기화 (OpenAI 키 사용 시 gpt-5.2, gpt-4.1-mini 등으로 변경)\n", + "llm = init_chat_model(\"gpt-4.1-mini\")\n", "\n", "# 도구와 LLM 결합\n", "llm_with_tools = llm.bind_tools(tools)\n", @@ -141,7 +161,17 @@ "cell_type": "markdown", "id": "c8aa1673", "metadata": {}, - "source": "## 그래프 컴파일 (interrupt_before 설정)\n\n이제 그래프를 컴파일합니다. `compile()` 메서드의 `interrupt_before` 파라미터에 `[\"tools\"]`를 전달하면, `tools` 노드가 실행되기 전에 그래프 실행이 중단됩니다. 이를 통해 사람이 도구 호출을 검토하고 승인할 수 있는 기회를 제공합니다.\n\n또한 `checkpointer`를 설정하여 중단된 상태를 저장하고, 나중에 이어서 실행할 수 있게 합니다.\n\n> 참고 문서: [LangGraph Interrupts](https://langchain-ai.github.io/langgraph/concepts/interrupts/)\n\n아래 코드에서는 `interrupt_before`와 체크포인터를 설정하여 그래프를 컴파일합니다." + "source": [ + "## 그래프 컴파일 (interrupt_before 설정)\n", + "\n", + "이제 그래프를 컴파일합니다. `compile()` 메서드의 `interrupt_before` 파라미터에 `[\"tools\"]`를 전달하면, `tools` 노드가 실행되기 전에 그래프 실행이 중단됩니다. 이를 통해 사람이 도구 호출을 검토하고 승인할 수 있는 기회를 제공합니다.\n", + "\n", + "또한 `checkpointer`를 설정하여 중단된 상태를 저장하고, 나중에 이어서 실행할 수 있게 합니다.\n", + "\n", + "> 참고 문서: [LangGraph Interrupts](https://langchain-ai.github.io/langgraph/concepts/interrupts/)\n", + "\n", + "아래 코드에서는 `interrupt_before`와 체크포인터를 설정하여 그래프를 컴파일합니다." + ] }, { "cell_type": "code", @@ -152,28 +182,82 @@ "source": [ "########## 6. interrupt_before 추가 ##########\n", "\n", - "# 그래프 빌더 컴파일\n", - "graph = graph_builder.compile(checkpointer=memory)" + "# 그래프 빌더 컴파일 (interrupt_before 설정)\n", + "graph = graph_builder.compile(\n", + " checkpointer=memory,\n", + " interrupt_before=[\"tools\"], # tools 노드 실행 전 중단\n", + ")" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "id": "20e87724", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABCcAAAObCAYAAABgmuskAAAACXBIWXMAAAsTAAALEwEAmpwYAAAgAElEQVR4nOzde9SlV13Ycf8oXkvVWtTamxWlF9u1XFptbWtR6ZJKtd5qV63LVamuWhZiFVREEJKQhElCLpAhEC4hhBASyI2ECUlgSDIJ5DK53+aSSSYzmdyTCUkIqECfrt8J58w5533O5TnnOWc/z34+n7X2Isy878x5z+yZZH9n7/18QwEAAACQ0Dek/MkBAAAAxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJISJwAAAICkxAkAAAAgKXECAAAASEqcAAAAAJIS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EU7ALIl/6ewnpOhcVdFazUbG9aT5TaUyBoOED81q/i73G0ZYLQEA1JVwAq6CQUMKZQzMgXrOAVs4AIC6Ek7AVQ4pJjuTQhkDc6BecyD+JsTfBgCAOhNOQPK2D2FFfnOojEFGGOGQSwCA9wknYMjCitaKJqZZGmgNtDkw/HOg9Xe2GUI0gwhhBABAb8IJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJUubHeAAAACS0lEQVRwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAABSCScAAACAVMIJAAAAIJVwAgAAAEglnAAAAACKTP8PEzwUDELJ0k0AAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ + "from IPython.display import Image\n", + "\n", "########## 7. 그래프 시각화 ##########\n", - "# 그래프 시각화\n", - "visualize_graph(graph)" + "# 그래프 시각화 (Excalidraw로 생성된 PNG 이미지)\n", + "Image(filename=\"assets/06-human-in-the-loop-graph.png\")" + ] + }, + { + "cell_type": "markdown", + "id": "c77w16a7vh", + "metadata": {}, + "source": [ + "## 그래프 실행 및 Interrupt 테스트\n", + "\n", + "이제 그래프를 실행하여 `interrupt_before` 설정이 제대로 작동하는지 확인해 봅니다. \n", + "\n", + "도구 호출이 필요한 질문을 입력하면, `tools` 노드 실행 전에 그래프가 중단되는 것을 확인할 수 있습니다." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "id": "b26d4039", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "[messages]\n", + "\n", + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "AI 관련 최신 뉴스를 알려주세요.\n", + "\n", + "[messages]\n", + "\n", + "================================\u001b[1m Human Message \u001b[0m=================================\n", + "\n", + "AI 관련 최신 뉴스를 알려주세요.\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " search_keyword (call_hoctw7zDeOOFOPfxm1pnQmS0)\n", + " Call ID: call_hoctw7zDeOOFOPfxm1pnQmS0\n", + " Args:\n", + " query: AI\n" + ] + } + ], "source": [ "from langchain_teddynote.messages import pretty_print_messages\n", "from langchain_core.runnables import RunnableConfig\n", @@ -195,7 +279,6 @@ " input=input,\n", " config=config,\n", " stream_mode=\"values\",\n", - " interrupt_before=[\"tools\"], # tools 실행 전 interrupt(tools 노드 실행 전 중단)\n", "):\n", " for key, value in event.items():\n", " # key 는 노드 이름\n", @@ -214,14 +297,31 @@ "cell_type": "markdown", "id": "889d388e", "metadata": {}, - "source": "## 그래프 상태 확인\n\n그래프 상태를 확인하여 `interrupt_before` 설정이 제대로 작동했는지 확인해 봅니다. `get_state()` 메서드를 통해 현재 스냅샷을 가져오고, `next` 속성을 확인하면 다음에 실행될 노드를 알 수 있습니다.\n\n아래 코드에서는 스냅샷의 `next` 속성을 출력합니다." + "source": [ + "## 그래프 상태 확인\n", + "\n", + "그래프 상태를 확인하여 `interrupt_before` 설정이 제대로 작동했는지 확인해 봅니다. `get_state()` 메서드를 통해 현재 스냅샷을 가져오고, `next` 속성을 확인하면 다음에 실행될 노드를 알 수 있습니다.\n", + "\n", + "아래 코드에서는 스냅샷의 `next` 속성을 출력합니다." + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "id": "ebcdde46", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "('tools',)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# 그래프 상태 스냅샷 생성\n", "snapshot = graph.get_state(config)\n", @@ -234,14 +334,32 @@ "cell_type": "markdown", "id": "b80ebad2", "metadata": {}, - "source": "이전 튜토리얼에서는 `__END__`에 도달했기 때문에 `.next`가 존재하지 않았습니다.\n\n하지만 지금은 `.next`가 `('tools',)`로 지정되어 있습니다. 이는 `interrupt_before=[\"tools\"]` 설정으로 인해 `tools` 노드 실행 전에 그래프가 중단되었음을 의미합니다.\n\n다음으로 도구 호출 정보를 확인해 봅시다." + "source": [ + "이전 튜토리얼에서는 `__END__`에 도달했기 때문에 `.next`가 존재하지 않았습니다.\n", + "\n", + "하지만 지금은 `.next`가 `('tools',)`로 지정되어 있습니다. 이는 `interrupt_before=[\"tools\"]` 설정으로 인해 `tools` 노드 실행 전에 그래프가 중단되었음을 의미합니다.\n", + "\n", + "다음으로 도구 호출 정보를 확인해 봅시다." + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "id": "1570ed38", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \u001b[96mindex [0]\u001b[0m\n", + " \u001b[94mname\u001b[0m: \"search_keyword\"\n", + " \u001b[94margs\u001b[0m: {\"query\": \"AI\"}\n", + " \u001b[94mid\u001b[0m: \"call_hoctw7zDeOOFOPfxm1pnQmS0\"\n", + " \u001b[94mtype\u001b[0m: \"tool_call\"\n" + ] + } + ], "source": [ "from langchain_teddynote.messages import display_message_tree\n", "\n", @@ -256,14 +374,50 @@ "cell_type": "markdown", "id": "b7062b94", "metadata": {}, - "source": "## 그래프 이어서 실행 (Resume)\n\n다음으로는 이전에 종료된 지점 이후부터 **이어서 그래프를 진행**해 봅니다. LangGraph는 중단된 그래프를 쉽게 재개할 수 있는 기능을 제공합니다.\n\n그래프를 이어서 실행하려면 `stream()` 또는 `invoke()` 메서드에 입력값으로 `None`을 전달하면 됩니다. 이렇게 하면 현재 체크포인트 상태에서 이어서 실행됩니다.\n\n아래 코드에서는 `None`을 입력으로 전달하여 그래프를 이어서 실행합니다." + "source": [ + "## 그래프 이어서 실행 (Resume)\n", + "\n", + "다음으로는 이전에 종료된 지점 이후부터 **이어서 그래프를 진행**해 봅니다. LangGraph는 중단된 그래프를 쉽게 재개할 수 있는 기능을 제공합니다.\n", + "\n", + "그래프를 이어서 실행하려면 `stream()` 또는 `invoke()` 메서드에 입력값으로 `None`을 전달하면 됩니다. 이렇게 하면 현재 체크포인트 상태에서 이어서 실행됩니다.\n", + "\n", + "아래 코드에서는 `None`을 입력으로 전달하여 그래프를 이어서 실행합니다." + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "id": "8f48c339", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "Tool Calls:\n", + " search_keyword (call_hoctw7zDeOOFOPfxm1pnQmS0)\n", + " Call ID: call_hoctw7zDeOOFOPfxm1pnQmS0\n", + " Args:\n", + " query: AI\n", + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: search_keyword\n", + "\n", + "[{\"url\": \"https://news.google.com/rss/articles/CBMigwFBVV95cUxOOXZHM3FiX19LTVdjYTNsTnBfU2RadXRKM0dERUp6c19YOHhra09GdmJfWFpnWl9ueVVoeUpnWmxvQzFXdFk1QVR6WFBhb3JRX2VfbkJnNjk0UjhQU0RWLUQxWHEycFQ2RFREU0dhbDBxVW9Rbkp5b1g1eVJad0RrUE5pQdIBlwFBVV95cUxNU0FRSl94SjhvZDlFNzY4cklpY2NpMFF4ZEZGY01OcnBDZlUxeWl2M09pbWd5a1JxRmN2dmFHcXJacHBhV1pJZU8zQ1VNRHVBeklNa0wzQ0ZmZUdOZlBScVJ4ZmE1Q3BsSmZSZmZHcWxjMUdJSnVEOGhuYlBqQkpCaTFGZUd3dV9xak42dVltTEVDRzd3a2Q4?oc=5\", \"content\": \"ABC 대 CBC… AI는 중국인 전쟁 - 조선일보\"}, {\"url\": \"https://news.google.com/rss/articles/CBMibEFVX3lxTE5DaDhRMlE3dXRmdVJuVUFyY3ByVEFRMWhvS19aUmhHRC1kOE9LOVZDOGhKQ0NKMlFPTVMtMkFFYm82R1JaWGxBclZpUklyRmxNdzBCc09kb2VZSUNEV1lIemR3SzYwOEFKQ05GYg?oc=5\", \"content\": \"'AI 수혜'의 배신…美증시 집어삼킨 '클로드 코워크' 뭐길래 - 유니콘팩토리\"}, {\"url\": \"https://news.google.com/rss/articles/CBMiaEFVX3lxTE40UHNmMUNoYkUwemlZYklaaU5zbDNQS0RHVEtFWjFWNmpNdEtkREFGTDdZY3o2ckFleGowZUJJc0cxb2J3QVZaejNKTHlubGhLQ29ydXVSNmVQOVNmOTVZTDVScmFEN3pz?oc=5\", \"content\": \"AI 버블 우려보다 더 큰 충격…고평가 기술주에서 탈출 러시[오미주] - 머니투데이\"}, {\"url\": \"https://news.google.com/rss/articles/CBMic0FVX3lxTE9wLXZ2OHR2eUo4VGd0S0VyS0gzZDExOFBvTDFSNnNfcEtnRXFVaFNxaE9ZZ0VWd0RpY2VzWm5KeUdKZklVSFlwckVkSlNCRTlGM1pDNGZCRTFKX0k5VmJNdkg1NEpBSTBCNzNHNnlreVlTMDA?oc=5\", \"content\": \"앤스로픽發 AI 쇼크…SW·법률·광고 산업까지 흔들 - 마켓인\"}, {\"url\": \"https://news.google.com/rss/articles/CBMiTkFVX3lxTFBreXZmNEsxaXJiLXVPV2xhYkZrRGxDU0FBQXpoTjcyVXpJZFJlc0RDeVBTcXpiNThoUURZcGJQalRxcm9yNC1TYmxuSHJwUQ?oc=5\", \"content\": \"국가AI전략위-교육위, 현장과 연결된 AI 전환기 교육 정책 논의 - 전자신문\"}]\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "최근 AI 관련 뉴스 주요 내용입니다:\n", + "\n", + "1. ABC 대 CBC… AI는 중국인 전쟁 - 조선일보\n", + "2. 'AI 수혜'의 배신…미 증시 집어삼킨 '클로드 코워크' 뭐길래 - 유니콘팩토리\n", + "3. AI 버블 우려보다 더 큰 충격…고평가 기술주에서 탈출 러시 - 머니투데이\n", + "4. 앤스로픽發 AI 쇼크…SW·법률·광고 산업까지 흔들 - 마켓인\n", + "5. 국가AI전략위-교육위, 현장과 연결된 AI 전환기 교육 정책 논의 - 전자신문\n", + "\n", + "더 자세한 내용이 필요하시면 말씀해 주세요.\n" + ] + } + ], "source": [ "# `None`는 현재 상태에 아무것도 추가하지 않음\n", "events = graph.stream(None, config, stream_mode=\"values\")\n", @@ -276,17 +430,13 @@ " event[\"messages\"][-1].pretty_print()" ] }, - { - "cell_type": "markdown", - "id": "8d655b90", - "metadata": {}, - "source": "## 정리\n\n이제 `interrupt`를 사용하여 챗봇에 인간이 개입할 수 있는 실행을 추가하여 필요할 때 인간의 감독과 개입을 가능하게 했습니다. 이를 통해 추후 시스템 구현 시 잠재적인 UI를 제공할 수 있습니다.\n\n이미 **checkpointer**를 추가했기 때문에, 그래프는 **무기한** 일시 중지되고 언제든지 다시 시작할 수 있습니다." - }, { "cell_type": "markdown", "id": "76a3baa8", "metadata": {}, "source": [ + "## 상태 기록 조회 (State History)\n", + "\n", "아래는 `get_state_history` 메서드를 사용하여 상태 기록을 가져오는 방법입니다.\n", "\n", "상태 기록을 통해 원하는 상태를 지정하여 **해당 지점에서 다시 시작** 할 수 있습니다." @@ -294,10 +444,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "0b9d5d8d", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "메시지 수: 4 다음 노드: ()\n", + "--------------------------------------------------------------------------------\n", + "메시지 수: 3 다음 노드: ('chatbot',)\n", + "--------------------------------------------------------------------------------\n", + "메시지 수: 2 다음 노드: ('tools',)\n", + "--------------------------------------------------------------------------------\n", + "메시지 수: 1 다음 노드: ('chatbot',)\n", + "--------------------------------------------------------------------------------\n", + "메시지 수: 0 다음 노드: ('__start__',)\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], "source": [ "to_replay = None\n", "\n", @@ -315,14 +482,27 @@ "cell_type": "markdown", "id": "ff8faca6", "metadata": {}, - "source": "그래프의 모든 단계에 대해 체크포인트가 저장된다는 점에 **주목**할 필요가 있습니다. 이를 통해 특정 시점의 상태로 되돌아가 다시 실행할 수 있습니다.\n\n원하는 지점은 `to_replay` 변수에 저장합니다. 이를 활용하여 특정 시점에서 다시 시작할 수 있습니다." + "source": [ + "그래프의 모든 단계에 대해 체크포인트가 저장된다는 점에 **주목**할 필요가 있습니다. 이를 통해 특정 시점의 상태로 되돌아가 다시 실행할 수 있습니다.\n", + "\n", + "원하는 지점은 `to_replay` 변수에 저장합니다. 이를 활용하여 특정 시점에서 다시 시작할 수 있습니다." + ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "id": "6da2eeda", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('chatbot',)\n", + "{'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '1f102843-4f0c-65dc-8002-bd531a1f71d5'}}\n" + ] + } + ], "source": [ "# 다음 항목의 다음 요소 출력\n", "print(to_replay.next)\n", @@ -341,10 +521,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "id": "74548a50", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'configurable': {'thread_id': '1',\n", + " 'checkpoint_ns': '',\n", + " 'checkpoint_id': '1f102843-4f0c-65dc-8002-bd531a1f71d5'}}" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "to_replay.config" ] @@ -363,10 +556,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "id": "18f5474a", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=================================\u001b[1m Tool Message \u001b[0m=================================\n", + "Name: search_keyword\n", + "\n", + "[{\"url\": \"https://news.google.com/rss/articles/CBMigwFBVV95cUxOOXZHM3FiX19LTVdjYTNsTnBfU2RadXRKM0dERUp6c19YOHhra09GdmJfWFpnWl9ueVVoeUpnWmxvQzFXdFk1QVR6WFBhb3JRX2VfbkJnNjk0UjhQU0RWLUQxWHEycFQ2RFREU0dhbDBxVW9Rbkp5b1g1eVJad0RrUE5pQdIBlwFBVV95cUxNU0FRSl94SjhvZDlFNzY4cklpY2NpMFF4ZEZGY01OcnBDZlUxeWl2M09pbWd5a1JxRmN2dmFHcXJacHBhV1pJZU8zQ1VNRHVBeklNa0wzQ0ZmZUdOZlBScVJ4ZmE1Q3BsSmZSZmZHcWxjMUdJSnVEOGhuYlBqQkpCaTFGZUd3dV9xak42dVltTEVDRzd3a2Q4?oc=5\", \"content\": \"ABC 대 CBC… AI는 중국인 전쟁 - 조선일보\"}, {\"url\": \"https://news.google.com/rss/articles/CBMibEFVX3lxTE5DaDhRMlE3dXRmdVJuVUFyY3ByVEFRMWhvS19aUmhHRC1kOE9LOVZDOGhKQ0NKMlFPTVMtMkFFYm82R1JaWGxBclZpUklyRmxNdzBCc09kb2VZSUNEV1lIemR3SzYwOEFKQ05GYg?oc=5\", \"content\": \"'AI 수혜'의 배신…美증시 집어삼킨 '클로드 코워크' 뭐길래 - 유니콘팩토리\"}, {\"url\": \"https://news.google.com/rss/articles/CBMiaEFVX3lxTE40UHNmMUNoYkUwemlZYklaaU5zbDNQS0RHVEtFWjFWNmpNdEtkREFGTDdZY3o2ckFleGowZUJJc0cxb2J3QVZaejNKTHlubGhLQ29ydXVSNmVQOVNmOTVZTDVScmFEN3pz?oc=5\", \"content\": \"AI 버블 우려보다 더 큰 충격…고평가 기술주에서 탈출 러시[오미주] - 머니투데이\"}, {\"url\": \"https://news.google.com/rss/articles/CBMic0FVX3lxTE9wLXZ2OHR2eUo4VGd0S0VyS0gzZDExOFBvTDFSNnNfcEtnRXFVaFNxaE9ZZ0VWd0RpY2VzWm5KeUdKZklVSFlwckVkSlNCRTlGM1pDNGZCRTFKX0k5VmJNdkg1NEpBSTBCNzNHNnlreVlTMDA?oc=5\", \"content\": \"앤스로픽發 AI 쇼크…SW·법률·광고 산업까지 흔들 - 마켓인\"}, {\"url\": \"https://news.google.com/rss/articles/CBMiTkFVX3lxTFBreXZmNEsxaXJiLXVPV2xhYkZrRGxDU0FBQXpoTjcyVXpJZFJlc0RDeVBTcXpiNThoUURZcGJQalRxcm9yNC1TYmxuSHJwUQ?oc=5\", \"content\": \"국가AI전략위-교육위, 현장과 연결된 AI 전환기 교육 정책 논의 - 전자신문\"}]\n", + "==================================\u001b[1m Ai Message \u001b[0m==================================\n", + "\n", + "최신 AI 관련 뉴스입니다:\n", + "\n", + "1. \"ABC 대 CBC… AI는 중국인 전쟁\" - 조선일보\n", + "2. \"'AI 수혜'의 배신…美증시 집어삼킨 '클로드 코워크' 뭐길래\" - 유니콘팩토리\n", + "3. \"AI 버블 우려보다 더 큰 충격…고평가 기술주에서 탈출 러시\" - 머니투데이\n", + "4. \"앤스로픽發 AI 쇼크…SW·법률·광고 산업까지 흔들\" - 마켓인\n", + "5. \"국가AI전략위-교육위, 현장과 연결된 AI 전환기 교육 정책 논의\" - 전자신문\n", + "\n", + "더 자세한 내용을 원하시면 특정 뉴스 제목을 알려주세요.\n" + ] + } + ], "source": [ "# `to_replay.config`는 `checkpoint_id`는 체크포인터에 저장된 상태에 해당\n", "for event in graph.stream(None, to_replay.config, stream_mode=\"values\"):\n", @@ -375,11 +590,29 @@ " # 마지막 메시지 출력\n", " event[\"messages\"][-1].pretty_print()" ] + }, + { + "cell_type": "markdown", + "id": "2wsob5r5djl", + "metadata": {}, + "source": [ + "## 정리\n", + "\n", + "이번 튜토리얼에서는 `interrupt_before`를 사용하여 human-in-the-loop 워크플로를 구현하는 방법을 알아보았습니다.\n", + "\n", + "**핵심 내용:**\n", + "- `compile()` 메서드의 `interrupt_before` 파라미터를 사용하여 특정 노드 실행 전에 그래프를 중단할 수 있습니다.\n", + "- `checkpointer`를 설정하면 중단된 상태가 저장되어 나중에 이어서 실행할 수 있습니다.\n", + "- `get_state()` 메서드로 현재 상태를 확인하고, `get_state_history()`로 전체 상태 기록을 조회할 수 있습니다.\n", + "- 특정 `checkpoint_id`를 지정하여 원하는 시점에서 그래프를 재시작할 수 있습니다.\n", + "\n", + "이를 통해 필요할 때 인간의 감독과 개입을 가능하게 하는 에이전트 시스템을 구축할 수 있습니다." + ] } ], "metadata": { "kernelspec": { - "display_name": "langchain-kr-lwwSZlnu-py3.11", + "display_name": "langgraph-v1-tutorial", "language": "python", "name": "python3" }, @@ -393,9 +626,9 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.9" + "version": "3.11.13" } }, "nbformat": 4, "nbformat_minor": 5 -} \ No newline at end of file +} diff --git a/08-Core-Features/assets/06-human-in-the-loop-graph.excalidraw b/08-Core-Features/assets/06-human-in-the-loop-graph.excalidraw new file mode 100644 index 0000000..35ae695 --- /dev/null +++ b/08-Core-Features/assets/06-human-in-the-loop-graph.excalidraw @@ -0,0 +1,471 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "langgraph-tutorial", + "elements": [ + { + "id": "start-node", + "type": "ellipse", + "x": 200, + "y": 50, + "width": 120, + "height": 50, + "angle": 0, + "strokeColor": "#6b7280", + "backgroundColor": "#f3f4f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a0", + "roundness": { "type": 2 }, + "seed": 1001, + "version": 1, + "versionNonce": 1001, + "isDeleted": false, + "boundElements": [ + { "type": "text", "id": "start-node-text" }, + { "type": "arrow", "id": "arrow-start-chatbot" } + ], + "updated": 1700000000000, + "link": null, + "locked": false + }, + { + "id": "start-node-text", + "type": "text", + "x": 220, + "y": 62, + "width": 80, + "height": 25, + "angle": 0, + "strokeColor": "#6b7280", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a1", + "roundness": null, + "seed": 1002, + "version": 1, + "versionNonce": 1002, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "text": "__start__", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "start-node", + "originalText": "__start__", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "chatbot-node", + "type": "rectangle", + "x": 185, + "y": 170, + "width": 150, + "height": 70, + "angle": 0, + "strokeColor": "#ca8a04", + "backgroundColor": "#fef08a", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a2", + "roundness": { "type": 3 }, + "seed": 1003, + "version": 1, + "versionNonce": 1003, + "isDeleted": false, + "boundElements": [ + { "type": "text", "id": "chatbot-node-text" }, + { "type": "arrow", "id": "arrow-start-chatbot" }, + { "type": "arrow", "id": "arrow-chatbot-tools" }, + { "type": "arrow", "id": "arrow-chatbot-end" }, + { "type": "arrow", "id": "arrow-tools-chatbot" } + ], + "updated": 1700000000000, + "link": null, + "locked": false + }, + { + "id": "chatbot-node-text", + "type": "text", + "x": 215, + "y": 192, + "width": 90, + "height": 25, + "angle": 0, + "strokeColor": "#ca8a04", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a3", + "roundness": null, + "seed": 1004, + "version": 1, + "versionNonce": 1004, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "text": "chatbot", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "chatbot-node", + "originalText": "chatbot", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "tools-node", + "type": "rectangle", + "x": 60, + "y": 320, + "width": 150, + "height": 70, + "angle": 0, + "strokeColor": "#0d9488", + "backgroundColor": "#ccfbf1", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a4", + "roundness": { "type": 3 }, + "seed": 1005, + "version": 1, + "versionNonce": 1005, + "isDeleted": false, + "boundElements": [ + { "type": "text", "id": "tools-node-text" }, + { "type": "arrow", "id": "arrow-chatbot-tools" }, + { "type": "arrow", "id": "arrow-tools-chatbot" } + ], + "updated": 1700000000000, + "link": null, + "locked": false + }, + { + "id": "tools-node-text", + "type": "text", + "x": 105, + "y": 342, + "width": 60, + "height": 25, + "angle": 0, + "strokeColor": "#0d9488", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a5", + "roundness": null, + "seed": 1006, + "version": 1, + "versionNonce": 1006, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "text": "tools", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "tools-node", + "originalText": "tools", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "end-node", + "type": "ellipse", + "x": 310, + "y": 330, + "width": 120, + "height": 50, + "angle": 0, + "strokeColor": "#6b7280", + "backgroundColor": "#f3f4f6", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a6", + "roundness": { "type": 2 }, + "seed": 1007, + "version": 1, + "versionNonce": 1007, + "isDeleted": false, + "boundElements": [ + { "type": "text", "id": "end-node-text" }, + { "type": "arrow", "id": "arrow-chatbot-end" } + ], + "updated": 1700000000000, + "link": null, + "locked": false + }, + { + "id": "end-node-text", + "type": "text", + "x": 340, + "y": 342, + "width": 60, + "height": 25, + "angle": 0, + "strokeColor": "#6b7280", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a7", + "roundness": null, + "seed": 1008, + "version": 1, + "versionNonce": 1008, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "text": "__end__", + "fontSize": 16, + "fontFamily": 1, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "end-node", + "originalText": "__end__", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "arrow-start-chatbot", + "type": "arrow", + "x": 260, + "y": 100, + "width": 0, + "height": 70, + "angle": 0, + "strokeColor": "#6b7280", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a8", + "roundness": null, + "seed": 1009, + "version": 1, + "versionNonce": 1009, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "points": [[0, 0], [0, 70]], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "start-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0.5, 1] + }, + "endBinding": { + "elementId": "chatbot-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0.5, 0] + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "arrow-chatbot-tools", + "type": "arrow", + "x": 220, + "y": 240, + "width": 85, + "height": 80, + "angle": 0, + "strokeColor": "#0d9488", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a9", + "roundness": null, + "seed": 1010, + "version": 1, + "versionNonce": 1010, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "points": [[0, 0], [-85, 80]], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "chatbot-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0.25, 1] + }, + "endBinding": { + "elementId": "tools-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0.5, 0] + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "arrow-tools-chatbot", + "type": "arrow", + "x": 60, + "y": 355, + "width": 125, + "height": 150, + "angle": 0, + "strokeColor": "#ca8a04", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aA", + "roundness": null, + "seed": 1011, + "version": 1, + "versionNonce": 1011, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "points": [[0, 0], [-40, 0], [-40, -150], [125, -150]], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "tools-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0, 0.5] + }, + "endBinding": { + "elementId": "chatbot-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0, 0.5] + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": true + }, + { + "id": "arrow-chatbot-end", + "type": "arrow", + "x": 300, + "y": 240, + "width": 70, + "height": 90, + "angle": 0, + "strokeColor": "#6b7280", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 0, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aB", + "roundness": null, + "seed": 1012, + "version": 1, + "versionNonce": 1012, + "isDeleted": false, + "boundElements": null, + "updated": 1700000000000, + "link": null, + "locked": false, + "points": [[0, 0], [70, 90]], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "chatbot-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0.75, 1] + }, + "endBinding": { + "elementId": "end-node", + "focus": 0, + "gap": 1, + "fixedPoint": [0.5, 0] + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + } + ], + "appState": { + "theme": "light", + "viewBackgroundColor": "#ffffff", + "currentItemFontFamily": 1, + "gridSize": 20, + "gridStep": 5 + }, + "files": {} +} diff --git a/08-Core-Features/assets/06-human-in-the-loop-graph.png b/08-Core-Features/assets/06-human-in-the-loop-graph.png new file mode 100644 index 0000000000000000000000000000000000000000..5173802f31742eb3dd819acdedee5f22d56c661e GIT binary patch literal 25277 zcmeFZX&{vC+cY}_zKtkUvXrtL$yQmCL`AklStrYoy^yht+;x{^3$4mhlB{6{ zl`K(qlOa1}vW;bC-t(I2{w>e*et5sUpZ@<3EpyFz9_O)d=Wz}8w593J?c&=Z2-D2cN-TjY*o`?**bGYE+<7GYd*U5Lo*X&+@v3*f=LD*I3tP%fTcVbT%D&N`7 zue>{!e^*ONEcXd#vqRithdvO;|2iRm_~GDP?i1Ud8{`xbxhGn+CL-E?X-#N(pxPt# zbKb4UwpNo{L)&K`UXJo0)54Fl0qpK{XcTOIg8zr-27k%yL$iZ_%uZ&4zoEZ&0cxP= zg8%!~|K-O2@w%ay=(?I+bF1{%w*yC$?^hvG-KK#oj>XR34KPDc~s%f23KEW5EJ91#H*%eKrR|hoDV!17l zck`O|ACH$3hF;wSU|$iaL;OKp2_p-4w8ho+T)V}T<5T0Hk9oj=b17J zIkBHO-QW=nv@18K0j!-1KDL(V|Fw{ z=s@gt=&1l$Enu7K-7A%*50za#tH(~7b4_UYci|eOKz9knY4xoLFnsV zuy@>4(+Inibme#fh+CUAb>rk{q#n=aFx9Ifacy9ihBt*w@qj%1xSm%g1#fg${!T{JQW{E8VrT=!PD~O8CHp zpSiT)w75saENQqWuwQIKKI)*4DEk(J3jlZZWYyAP%!) zu)y4te)3R#zKRh8fSn&rYtDYPbi}9TTWM-2^6)gbG*q}7h>rvRaD`%gdU}g5PA-@y zeDc*|5~g4!EtKACqCys?NEu#!`}IS{*9cEXiCq^nnkvtB<5H7%mI~t zx6L(|W|3#v!NKSe1(eModUbve8;QpXb#b;9<3#C@OHBGO_L`I%vg%1A= zI9j*b`ayW!PnQ%+%3M^L8d9U+>s9v9wA;1Fe+|#<;UgI$!W?z;8pt*(+zBoC1LZ3pWZ^`t3}?82o{ymd-waL~QD1i7PGx@zA< zlWMp|$#1`?u`y3D47NCXQ6_r>`$b;4dsNeOwje=gZ<`jwh7czbRVlJPzR^VY9jW*3 zu$@ETryuo%`=vZ?R8J$_$8L`mDRCY*P~-wP;bKOTTNv_id+NJiZwmKIb%k^ZCOF!?qHEqPZEaZG>8Itp zFiMcxVT)poOFo_){uEh+G>OP~{3!G}g#N&-0ps)TC8Yr5fk+J0dkeF%e zjQ(7502fiD$^wu5g-J=So5&tyJB@_Zf0x4G5w$RM$XF@4zr{07pp**8Jk_(ltZRPH(LS`jW+O}_ninVL z5d5oUHD|dr$@Ef^W@&il!WeJ#ci?$t1TYq7oh0=)TM$oHmGGKt-F$qwYiFhW^sX%a zY}Q(B__ANmc=W4jty?3Fmk+g$Z)ql2|22||{i38mOMezY?ZDj@-SC(#3z@|}yJ00D zR#&~4xmcde$%}S9Vl@xtN&}a&hku}+fF%egSV@OhQYV{HT9ip6qr{NeD}N&csAeX* zFWiRPC3vB`!F6~&gu4jZq*swPu!f0rUO+2khW9t{OpWjyacjoHm@9@|znw1yEraMF z!)B^|-)Rr*M!r>v#HSv@<8Hoe)^@daT2a#&3^65JXEqXr(;hQI$v23mCs8Um?7f=W zB-C=>w^ZaXRv>kU;}T7bS5v_0v;Gy>ZhssowxG9kAKi&&XSxV88Q*mb(I~=HkMv2h z@v(D=WWcwuBrfUj!0A-AaLjRsJz8|yfd2c41={<;U<`SHgnrz(YNmVs%|~Jt`6K=r z2LB%QyZ5eyz6X__c$XN^)Ik0cD&nY5MUxuZDP$t!W8>}Mq)ZKlZ(31muhikqnaQ*~ z7Hu&U&C=O8oXH?#fk1lmy62urVo0keKK2B;>&3Gyy`c9E`^b!zc%H+}Dn*j12%X^J zs*x8GqjHf&lrL(xoftZn=ffwAbo=rdqxcz72E9FeWl_1+;b+9MnRWDcCihk?l%&s+ zJ_&hbM!5J<9Lq267T!RQjD-{=WNmjxB1dNf_=cnen)k=oktqt<;@BMnewA*GZCFvX z9X<;~v>6PXaU@g`qkhCYjcO|I(%IXTGb>PaG(OdK2g6~s_{ryl=0eLPg-4c}LF3lK zAo|*iz~J@YDHVQh)aDOkzYA{==`HzIE2OrCRf2M= zZQG+0b@zRwM(b)JB{=+YW{4_)VDf?V*i@SA_?KuEhkgLzT}|_~rkjVPjkV|+bQCPFQhN zbJ0d3?4K$1shOzX=)1wPc=reH7(?%b9S<(49f9tpP)@0b63^di@T42>_F7nF5S1n%f?IKq$UD3JCEq0f_ERS8^4$;atD!LW@I9)y?o zUhlK5k>a74wee+#Myf~}4Tg*gC@irz7x2hVh?O?}tiO%S30eD<$3wBF*3wmQS?eDt z>Nv{AZdbgk)+M{X_9JuINxf``=(VP2#fHC^w3gyT$+VwZHg!+8ouWjpp!9JC_`R7k z)OVZtJxJS3N+-_^R3v9g$c+=5)oA>loA$as?mspK6`#kE~BUmZZ&lgsd1YHNS(;c zUN(M_i)}YhvZwKm;(l7wS%ilkQLfW%x66~M;;tG-vwwxOZ=m{hgb_N%O{n>@!|fMm ziruA9RtV|6;&l($?6cwX@x*(4D*iasTG<|+*S$^1C^u;lR8uH@r0ztHdUnX~7sIj| z!U^upVzQUk-tA3g{&sqU@ua3arO{RN2kwRy|jlb!zh@Y3lEDxyp6N&RkINoM%;?WEMm&AT<} zf|wwsL#Q4p1=8vv=nDe)&zPaGm7}tjN;;%BO>a^3Po%t4<-+d=Yx6POZqq%N)fqj% z`{&-T1V1(M?++ky5W3pE2S0Uot4Z7b3q%^l*z#q*RQ&2kNqb#O=rkW3yRMUsE@G@i zhi?_N0v8RPGX?e(FF9wnyu{WR=FHow!POL1SLw%|s}Dzq?t9OIMTa>8a{G(8!D?oB zzm?tZvKnh9vr9dIxAzEJ37nbkIa)i3UNu^edp@F9;`Jx-{W;IwtfPe6^4GZZgntjG z0gaj2S|IkR`O>(ct7jZ`y!No;=vySVj4_jWEx$tVX zvE9*uQ4g;^p35&E%k9FR%fn1=V+`-`@5u;ayRrj1cM5--J~fR4Z<%BAY}BsXZj#VfIbfPiF%8yyl)NO0Yrg<*vnG^r0$^yKAUGvL zFnOCFdrE~Z117(folszk>p!tuI&k?Ccj~q+p89}o+7(F+=+q^iYx&t(ySnmXOJT(ZrOrq47H5hDcNOv4$=U=r@1^)tIS~ zeYflE|E4k)fEBR48LP;4M*{$|5797Aws+88Pm3%i#_u+RRN*51UVn{;-;*K1#;X0U z0vR`Ud#jJ?O_FiXE04>Xv>t;hkAWW9Ir07Y#HEGe|ouG9#R&+ z4LS$J2wf05cqTR}u4$%L|4bdP0DH7BQ2*$2r#=k0UQ1Wpn835SQu9vg?1nsd0d!i< zMG5Fv&*UN1#1V(CCGygWEyAJP6u^P#eY^9Ou9=J5x;7M8uPkoog~lua_~(5g_aNvg zKpDCQSGq?42MoS~_0LV z*_}I;8#r@km_7q@L}`P93xqmYF2_{oB_2z0M8HpsnNG-5=ROt@Z1Eo-*Lp*dcH1E> zm^R^FJ+*_ftr9T$(G$P{K>?zC++Dc;qG(HMuzA0pnqQ{BfIOrNLJ;(P&9hmz^YLfP z9Z(C5f632z?1^J8*_vu}HTY z3JD)=FS`AbNH*hw96csrmuaf=l<)`tXxI~ObmI1-8;ZD@%desOt$%IE>)`~UN_;6V z6fGWXwZk<21iB%O7gA)N;H;~@138zjVX66z4QgllW9|MTc&v ztR#?O^csA=mv%ph$1tux{LAEO`B|TV(e|x%)|0j4urL zhOT@uY1-LL-zj%%_2+B9kYDizlv)jj_wOF}?nUVxjO;narTJ7UZRbZ5*|L${8E1Xe?V+E!};w?l+brjCjN#~1|vPXY{cbwUrdp;x}{Bg8O zffQnzO!Yv2+?;G@OJmQ?1k`yY?$T)sKjA0YyZ(DP@tkZ7D{0f}NEM=NL}iXQe}9skTq0U7dX%d* zX2f1?#&Y`u4|b+rwCT zumen0Z7gt;#QE9Z+m0Cj_y%KRu077iG!dl|H^cN2MIrgtm`dgLvRmv1fc}#%4QjkR zXRI3}pNH|{BaXN?>q=69j^%5{co zd$UgTAdIMcPi&aH(#bgPfL!iXt6n`eIH8E%4cdnZi2~yWHsqX=F!mN$>1^gR%xVnO zs=3AuFcZ;32!jVes}_QSEef2H#X$Aoygttz?Eqjp_rz{_tmw>Jc6rrkc7eSm4Qw{< ztnzL{Xn#||?;yu$snR}4DK~LmhdY&@(s+6HBwYs7d487kFXNbGN3%z_B}pvk>8sP& zTNk9$IToen7P@(5Oo3%&Y0&TCdQE)NEP3N$9$T6PMN-^D_*!Gu za{5PxxmoKcYPosbc-#VVKLvc0GiEYkvW&7J?-2hma`zQ@b)Tuupbpy@$dq!s1~puE zd++wbKro%Mwne5{-Q*!a^~YH)evxII!(iCgkrxaq=kvdT-+qQg2sa5gjT=ae z11*Aim)nI0*AdFhGAo-SyZ6t-CZwD=55%)K$sMM&Uy@&e$^XC%&9ul)7;82(tP5cG zAAENPd~D;E!N4>h4KI*0nck8xqNfUU^F)C2X8VEYOu&7x+hw=n)^rY^ha4o%J0Ne1 zwnQj=Q>lQNEMp1%S>odD0!VV_?bTu%1L+`g{gxTmPQot#?PV}kF9DGU2aVv|{bP+f|A-i7GRTriD zjMqCN^htXPq^kLY^1;c6*5d|PZwvk?y++D6nHnW}tT^>eV(c?L+hu=${J}UoyU~5> zZXNDL(pne2)7f%PbCl~q#Qe(psL`JRqpq#xQFCsjYRdm3BKqjsbQAwA6X;`pDyx&&|*%fLM0i*jIAM$j_b` z6=b;Ex1L>9T=O*x%}G)oo2UI0no|@aX9fdmX4CQY1Ce11a~fGxpFg4j{xI4kJ~2o@ zq5tij>g9VPJ0oj&hgUvdE*|x=^10wiiEKoxOdi}^&0Ni|`Jz|%n<{V%c^GH5gi@|; z16&3@tkb~IKVGoK3eHsI7-pKizq8q2Z$Ut4FwT{(l5&)Sv)8N=!&Io0VMgkg-Cy+S zZL17geX*U=xJ}Kx%J7D1K>J89mY-);vs`UzCQ;x)_zFrP`;K*w7i}70D&$njuu81E zG5OVt#?&PkVN0UbZp(u6W=%KO?thJ{TI$gb=Dm0DDc~0u@7LSyn+^wyM-Qady$iWA zQJ7>}ysdl?S8{-)I>$K*WCMmJSTAbblqxZ2Q<_F4g z-s{Hff-Bh=b$&3U;k|cA%6o5mn=9j4WF_?rM^x>%;${#nUV?05a)~BL!mo?`m3nEz z>6A#L9M34G+W)vrFS?13w-zPbJBspEsz9y{7O%)QmQ{2Rt^J8{C^bqDUhOtD{X`BU zt}3dyVopzGIxg07^B+H+1}zaHJoya$3anWQK z?jedHMc$|-o!YqMG&LhptCRQH@|J`Zbv$jGzw^wOqzz>%*0sl!5sL1aA`*3`OJ`=0 z$}5h)Z3u6x7|x9osQ0U>Nf(LBnDI!zjnUynhAp`bTUjR!+UCzemX+HDYw^rQv!=cG z-F5bm{1)n}$?Z3IevgnP`1r%xXr0HCrg@^m7v}iF*HQP|u=cM~>*5o3x;IPtMv;kg zgwzex8rdX!`!3|hyIX#bHoU?&n;2?ubXu|GlHSKT0d;pygpNf@2IEBt8T=?G@;fQJiso9(Tcl{oP6dP^6rZ21xtzx6}sI_7G zbh#S8q%6*^@rGM=w1%IHb?f-f8b|I%BJvnX1t}h(G&M)24R@}UE&mFLNrY%mfqLWyh3cRtoLqMax!#^UHznMQE)wx=nIUg71^ zIDZRK`$6RB_?kA7NSAm=!1gZlI|a;Mf>XO};_gGircI8|7^6Eyt~Dj-C|#MO_C~bT zNrs1SZn|3$?U!cM@Z8Za;jk0|JVt4D++~Mu&CN^Ah(j;wqK#-*Hv{VZ`c$#hDoJ{6 zv2G+jK1^z!-obZvU27#``bj`dlcu5CW~fud_0cC8PQwfjLd=24T8tIGK$Eg?q|QN{ zr#6J>rNNmpz=2X5Uw(0H{5DDXrYNH~KyJC)==TF$sh)0o2XZZBS1NP+3 zt~LIp71rwMnO?%_<)6nQEPqno@Oidh?HWz4=+zWE-Dw zN<)m+ol(i&$V|=B&&I#X+{CKd=p(~-k7N(gxN5Ta+;fO1eSc3EdJQ6~i1N%F-+7y& z5M(aCp|bI?Gi$pWxRKl^hUUEdtzB=ELRm^n;BkuBY$4Sjh;kWg#%>&3&q3&Dk(ytt zI}zzAgn%%{(q^CU+hbh2D9-{$v5zhO}YTv&Z;KF|B?-+A@T%|qOys|xp0O!Zd_B_cDQ z`KmCgPnfEVV`WM?WQD1XIU+ho#&-&$KX}AujV{E zRrJJpC_zW{sot@%pFVXpE+eSO9^)w8z~!iiwRfU6G**Uhy=hP3e>+i)d=#SQF&nG7 z(3g`F;$*7(L=IPwOgt|zDlWk{bJRlKd4 zc11ueYOxN0nHvgKo$FC_ZE&X0J09Ig{g}Br(Tn+XDoo@&)BS{pZ8Em;w$I-9ir)}! zG95gEcAjZpp8pUsU)y7`S)qCVn~sSZ{hj3M&0#moW~WnA?aS1QVLbE@BM(W8R>;PI zi5t3;3kjp*6lv2yY;i!ELP7U3NDQmFM(e-~nt;M{$-V2V772U?HcPiAtF2wB?W#Ho z8KwToVLO24WRM;gMwYH>FwidUn{!dKB?$_K1(6Z9rm@j*@ET4_pk9!!CZQha*OncW zdtdzQHHa>tmDF)~1~pCCmWzG46-%Elav>S5Z+QTx`@o-}Zw^O2PugWr)O_>`!4}=n z(A&@}>G?&nBmmCgI?-J?G=7zBOmt5?7BMB_0N1}De&eyckILK(??L^MsYXKoGcnK0 zkL8w`2;1|L|G%mQDccn!J=h%5k{(Dm&MZ+aS3Szre~4?AiDTgDK0QPOXU7v6HFHoC z{X6jwyrarC_Wyc{+h@@E84HFH_)miJ+-5VN%3yCd;eS)JAYu+uSuAg<7rXtta!%}j zvmmcAl{bi6{`5qSnnk5)-u8d*`@@A!M}S(%XO!C+qMUUcsHy7zRZ~qSQ0h7b6{2nF zVqM*iyWIaNunsZ{EDw^ADfNL^2`=AFK(3$ve=*VbJuZ#|ZsjN?A58ulQ{KuJ)yE0) z(@AL60y3AkEO7FNi(gQ>@hfOkk;6XyzB@~<{V#rVY$ok+rlaI+RPzwWeXpMao{Qm@(zIW^Cx%N-pNqlfE3)g|5rDrq_qU^OO%L}3xL^C)*e_$e- zQN#f>_;Onv9(qaBdU%840#~yzM=H%STR^7pu`b%XoXpm+;>HjWgVu zlK;xau;2onhL+5zG`7}ptkjgqCHSm#hMDQ+!!36tm|QVfKBYFKck< zgT@MzUEcFqW_46%M`KKjzrH&HZgep5PNIcgeSEp}Ph*81#>?D7ci&plTZ1S~(O$lZ zhZ_Rp(Hrvc{VmMF*5(?7aEu{PUA&emop_z%A!LC21C8-;DlKnHWI>o&kPZxjFP;NanEc5VuL7Rx zGi*C06w2fI47jCx8MIsMBUfV;F!o9pl^$`tz*qpO!~F{wHKn>R!`u>8A%)hMdoG}d z3$BxyR4#AXZbdFJ5Zc!oW7`%(J$z-eJ&XEw+rPe+A}=iQ^4OpoB<&~k5V!!yQI>U* zgZC3<9>L(#_PL3I;|4=I@}C=GMmdP})UK|Zu^W3~ zZvaC$r$B!ikZq<`Tj(0HByz|iTzAU03bzk89Blr($0cx4uQzC5An{<1=Ki%AQDkGC zhucz=O1p&I?0vW`%%msvWm?{+(HcL-W74zXwJ-vYhTn7wb)viY)8vn^g&!K#Z{XSO z8RnyBZ6n*b477l3M;V5k&dX`8Ke7ZZ_z*NjHC@txP2JIa33C0$@aEfFs%fWk6Ho|J z`&LLE$WMc=Vha6;n$160>Ut(UfwG}Mclh1o5jd(>0ouoY2?#aW3k8urwr;Vfl-b4s zX1<$F_o0GRp+-4jHCku4s({?GYdb*bw6KD!QH2?;KR&8`Ma~Filpp{lu?{#3iDH(P z?W~e_6<7Rxza2SUp;kjs7jY`bZqtBK*+%UeH3EuAsqYp9&89%0Dg>I@I;~hl7gW9mALiJLJG1qStoaQ>4K^RMZ+W@Lc51js5rXflT z*`rr>F>yQ{{HoDLtA#@6u2O*dPcdPCEb-x52|eC&^fc6Qi3MI})j+^h8^m5u4b}k= zWWf?D1m#Y#P=+9NmPZ2brhp4&m;(^h0U{A_{NR5Xu-^gwT*v@8Iar~7znS}3OA->v zw3UpYeShJ!9WwA?L0U_Yp)`Dbv{g=a3uM5{dKMawr6*(wLXZ#Z+!hUUJOs7GuxxyY zG}%<33R<_%uK+0!PCU!JRK5Q0wh%n8Jiyfp=m{~?qVfNe1bn4n5<^4jKiL=Zn&%E9EwiP2Vdz4LIr!7dhN;O z!u}&aYWGtBR*AKE93h`87SpihAvDFZ@eGUf=y3FaKHhzhzjWKfpVC09Q-D=BEW2{0Z&LMp!!s|8ub5Zh%2>cz^(=rDR>TGj&&^ zT&)xoy~d*D2T~qr1Q;D)@}W?`R6{$)4I5FhtctP`sIn;(pKm@OS$eVm_uE#3Z(3aVb2925>A1x z$8tMoY!eto%bLtSg`6WSULZHSN6vPRnkp)V|?&c27WHSUqd z-?#)}XmRWIRV%2~lu6=gr%ZnN=$By17{#WFWF6%i%bi>FMa>OT{S&3pr8eNy0?1ze zG%PI^M$pF_AEN$25Bj)np*=iu(>(e*6EP@y8CHNJe?F+g&{N2e{Ex|hRAh0~UhM#e9<7{^q#Ost_Q&NoZbRI~p+gM0zyhX1L}zjXX@hr0V4;54 zB@e*^hp^pg6BVjV8G}TU|Le}*g(+@aH4l%!xS!I6HlP}4%emE0_&pa$C z?+RW^DRO;gbUxP~&jBu>;K14fuEUa4Vv6Ro6Gr|rm(lpcYF%Z5B=Vm;5gHRybhyJk zX2kMz9g)ELuK#h9EsX`EQpzoy*JW5H)^ZD6uEFU#@PyFs5jwYw-5-#?gD9W`xnKX- z^BVe?{GZIM!w9y!OX&LZun31Fpl%F<(?Ej7W%+oli0`oaA<_W!e1eYMCIb1e>?dPS z@CjI2!B$YWh@$QVK~FiBjFwb^mVieNiQHv>Gl}%Pk)8nJfPFSdP9Cwqb_0WhuCQ!i zpVntK=%X%6G4=xqLyIgQv2Pn}t}LPbIH+8)be0!bGfSW|unP#M(6T z69+)wXYD#OpON4Rg2P*uMx51AD3|J;_{s%2D>K>RJQO1vYz>b2`Yx<}m{ee6sR9c+ z5zJPkt^b0SSe^wE6+R~0U=#%u*vx_{gdu?{p>+%jue`NN1X2XDU2o*wE^~y5O<*(i z$vp~#&Dnur)=W(pm4;q0!Q>94{^pEEGhM=t=(9|6J9bKsa(_IuY6)&i{{cO8M1aT( z*`{LPXDpw*hLDHsyMd(Hx0LuY5pQ_}uHIiw)44@1v(GT|y6Eb@BWxev0CQGnMX%rQ z5*-nZsd7OcTMRJU1P!jSHumgqG>Y=pDJlNZv%??&cy+TAERy<A4KJ@|qW0XbztvOgR2f?Sc1B_4d$K!d4FGJIcVGt!0Rq1+QzT-eiWfvHTb ztE}-dOb1hHR$EKM*eh8+b?!aj3Fs$ubY~%gt^VxK9l%%^#oCWgNkb*qN>91!TH>Kf zRt7Z`Y1mAi0B`fETc6JacftQW9y-z~f?x}8iaCFtS?iQ4KNrB$l#)8KieOP zSIJNBs#1<87yIjSMptU}vkfubL3Hr7h9WFQMonK5!Is;ahcO0Q{`uj_GoP| zPV*rO1}e{z&|5Frh6dTk4a(fmj~7bH;LAKE|Fbm?2v1f>DvRpDhm<7@?O5dB3weUv zFq9)MU#i1`DM!!MBJ2sG{@gs5sRrcP?`B*$h*I0SH=7 z!7k;Nz<PZ&irec>A`}Wo~+ba{Vw=&Y?tColSKNKM*?EPp#{(LrSAMO zgHkV;zt;zh)l^J%awV9qVNSs6T!H{kk7%i=lyu>Zm$%?9!*tEPGSqtAgN?>6o9OZ+ z#~u4*VQ%k)QNWH*-`+NIOp>3g@(9=Zh~X=!|5~Yv_j+#>9|=a2K@Nz&(HQF{DO`{jt95!+GGXJ|XI!Wz z7>fDT&>E^gY@?G)V~Vu!pV^tG67Y`*uznZdf6UR0Ja5*;oCE03F(bS^Q4f*bom0mc6H216-c|qkH&k7>f!I)(}pHKO+`Q(O3!(8H19CRgxLi%x0AE3(2*{JRL^4 zta9FYWXuH4Ea0%;hmWM)h;fC7R_5E-sz6TmTwIYf8UrS~LDJRTTm%MB)Zk{FIZ==8 z&Vf|HIF>3+yY$2wml}h?jQAl0+@X=cQBrxJNpHJg!{B}Y6u zv-l-)m_Auoes-k6mxtAJEY)2FV@cu6u_XGlU;rikGV{f5^F(eRN!E+q_QzPAoBRJ` zMCi~c=6JW1Onl?3VNJfN3aD`uk?CEW)T>WqlfAZ;nz6^e|oGC9Q)Bm0<;w5J$psJ#)F{Vmyh* zD_eLT-vonOfWcttpJqG^t)=JCG1m|~qv^PE>-Mk`@NzgkLa5^`>)eEYT94^^T)L$k zzu!y_2?QGls@zn1Th$Z&+wKt?sG0x4Uf|LI-&fNpfhR~fZ%bGc>NKF@Qn`1iB2 zOZ@eJ%`zn*?!0|zdUO_NhJ^anUrMu~mu}r-ni(jqSiSM1t!z39xsIGb3s;nJFPl-i z%eTN7J&eBx)yx#|ji1H0yW=0JId%qB`LUzoQzDC6srw%{_-_Bf%mGRz(G7;DcL2s6 z0;GBtQ6(lr^I~Pdkkl~2dhgkgey&1hu4IqWYgo*yU*N7WSXkh zfAz}MO*iM>IPMbObnJ!SSP%NQ4F0*v@Y#K`!0D_+Avbu>eTM13!67dHF+BA(Wfv`9 zLb#1|?9oKDS^Z1krw8C6NcJsYy8d5RFS)O+i2n8N>s#KH(#=Muq?Jx)PTFUNTw(nE z!s$$5!k>9DW>dc7)feTtd;D7~rS}b*9<%+o1pnOP0Cic(#=qi3F-KM9g%C+CNT~JZwZFD(l@0YD6?*a1Lfhbs6&M+2YsnC zDj~(%`c8Om`?;ZA^M8YW@R5E2McHnwppqe+0s<-g*(n(`vGbPJdeg-s%B7(2+5|)i z9ZWX*7dY*Z_!`bPo98U>A6Peyt^S;>;w4}i5ntVh3vun>b;BQ+tqy*wd+@#Q4TNarEYssI;^-rt(BwIU)o3n&}wk{@|uG(99cm)|!P~rLI zhbwq-56m@5VyyAxQfkfC2$E4V$!G^?|G~E~i&8VxC#Tw%|Df5wv3K_V_I7InFfjd~YB=(jGmhTmp`W(7EP9m)hO~qg%nO`Kj`}!M(SD@GEpAvb?0@&%>*7~bl(P(s z1%Tw3faYydk(-s-8@=c;KvQO4bBi>xB8m6t(7tf4f93E{hD;*|L9@C0{+2&N~uFa@@ zs|AyBN=??_Hx;_&ad)j~3oV11zk4xzqbwY`1u24jl_xSM6F7P#=ZCRd5)h%y*dAip z!L^weqX{RIdwl8+{R89dd+-|{gKC}8TL3;1shTdAeZ95mdH|oIca@*{P$CcXR2TO{d=UZoI zJy2Do(2W2|%c$bJw$+UB)m<8x%XP@Vb+$HeizYkE*6ouTUnkiWzk4mGm774co;KFB zmh+tx&GdJz7H>--XU(lYJokNdW$t8DyY2GB`~IYOj`nAN08Hip0BgwcN`J~pyZqU5 zT&9=F&`)cX25d%gcEX(Wl6EpAZ(MsD$~Lf)i> zrdr0%iQkKUve~qr~F0#`5;7zI_M*aR-km__} z-jfpND3O#}?BEdYUq6?!s1Z3=dod|$pmaAa%(@H7F~Ygj{1UslHL!PPZ0fD!2>!=h z*f*k`)buY}@xZXPTLV`7&5gXM25hIdcyVZ`sgsM5`b1P6+THCGe*J)-#gvy1ZEDSR znP5XG{5YgJ-*OFX7s&`UX6IhaO%Qkx@k?Brq?_UGeSwL+Dw{dDxe-4y=3Yf7XU z55{2kQj>uu8*R#4+pRb(`1rY1?a1G+U1?1oNrY2&BB$(h&(DU;6G#n&FIUMEy%ZbA z#j(~8JX51*C+4KOZ~5oNe?Di`J8W$Ub7oY}ulAg{(PrE6)v}1$E{SvIQ_FUjG|z9& z#Wz=-^T0D0Ex+RkK^qv6fv8BAZ#^GYsWBwCR8;TsB{!avuM!iEYZqoSMxOAQ>w3&R z>GH{WgxNIcSsf@O&FEWoeV!+ z)n_5In~$CpBaRu)yuAH#y*JTV&(6Ipp0D&~{u<>OQLii5{h9}DCGP`4q358FgR%HU zZF!z!-JZ!Y{_OG|-|-9GF}F-BeesHg9+=vWmFhJ9g05sbrUH+3E)GAhQ` zizen#3no)N!=)Pp(hRZo@m#6K;B`OBZ~Cp2c2nohU@!do!KqQ()j6rQ?B`q~Mizfd z;r8WD0u!iPfAmb+@4Obph}fRARllu3bZkeG{RsgNyRzCgyH#&7s#0?AUzEwdc^?UZ zXm#Y<4TiGS`Vsy2?iO+tEp#!(5zfmc*IcQ$uzrqV0X@xffu0fb?|RxFQXOJ)0PRaBao zN1Rx$oRhmG=esp@`ttzcwO{qwN((u|n2;19vLso|0KbtqCu_}k=jTCryaf}eH{NtB zY+%^N%l_Ls<-^{A3wfmQl&Q>=$MIo1US&qtH*kAcjHzdu5_S883uTl^)mxKW*f9;J(sD8?mFAksA++CEi`39ll%CZU4^Krqp%0%LnOI z)N$Glvtw}38U@thfKF7y{=`*og{ES<%gn~WA=d%Zy7mKAG`UNKvnHwT6F8x|_tfF? zW)pu(OP|}5$Ms)tU)oR0z)1J?2q)shda1*G*mjNgzIaBkzDCipxu9A+=F;#;GFDA# zg!62`54^v6PY+S|{hUXsH(|ZJy>4UJDoJNTuX`o^ihrl4y^$O$ZW$Q_WVZ?3iD6Ph{d?ZYXhQoVF-H0T2Iy$6}Tgf4XZduXse1Yy|` zuqEz}p{5#6s8BS+!hv%eO}}{2|C7qxu)`Wvs;;6#bKvnBRntwDH*3~ghOC3m{T<}G z*Vs$-+j`I=WRj4edwaysvHJ4Y$k#&cYd@0Og>@p)YBY~LV1fg@Qu;u_ZeCgZpjUiP zI$X>JpJ*!~t`QWNEk*g;k6to&gw*ln5|?Mw{p1jH?+MSy@Xo&!#F0rddCL^arO(5o za$lf@pbW5{}iuFcor{o_Ghr}Q0Q7;lej9wQFuW(e&z(N$(o z0lxquT9-Jm@16;oYZg zXRCg|FzHH)_6VMOB#B6@EA;tpFflQz8~=vm@Wos4+m2lDYo2_SRaeog8U7}S9v(n0 z2b?SZp;8=PjDBk}(I=E-S=T9KX=GcI^X9M`J^VZA+Z|b7Rk5*m-3!SvexO zj+L922HcdL)^f@jNT>IQ(-R6$TtvP_e`zbfXdtY+S)p~8-?HLN*`-)StG$_8TM*d- zxnKXr0P2|r^4hu^e<9a}M-^=Y2k4WX8&$r23G3ei9t~u#ehNC3G>59|5ISkJtuyr3 zq=&}qj1Y59>DM_)b8=Z^bYqo=xKq_4f7_!=QKcS-E7wUcih3S~&3dcXJSnWMsA z+Uw4XpV{2N?HuplMz7^o$kn**GH#bi>)6yXg47U&Dx^$oz=XuKe3S4-jF#|D1u5nRSr7u_Jrp?D%nu zs2%gD(2_te<5y>>txs+B?DpXgin$-ysbBGPg~W$^NYu2+n_Wbk7|o+go~hupl;)IwQWrG{qU^!jSr@0Ia9$hON<)C zR~;Gn%?J54u~-k?gm;_iZ%F*%pTFp)(f*KVe^sCu{c9+v+-KRoj?#DDtKmzNl8&h8 z{pn3Hwc1$3j#nQdGVKyQq;I28RsT)6OV7kbKOSu2Pq|?m2QTsZQ?H&U3>cC=wzgf=BdPVF z4jkzf-KLORJ7VN*lQ46XPg?ujY^aM9WobMs<$!j6Cyk6GeqU6I^QvXs#R_rKe#9j` zNYb#%^xaHaDVJ*3XoKu4E*n$s>PRcrF5bF$N`gLKp74W#w7Y4th-&G%jp@$fV8O`W;xp**d-f79c=YHzfix`V=I+wh<*_%P4SpWynOFSb6k0g3|Caqu z%7FmC{Sm&L?C2t6Z_4useX?Tqjqqd2hU)@vZ)U+Pn66ruRO+t+~u)ZHBNV!rV@!+(zyh$|ZU%j!T)P z9M@@~^t9$O#7Hk36yoTjxujQ7M+b9Tav60@E_F1WGeU%1lB4H4o#%Aw{QvxMUe90q zD*f1bu-A^T=~?iC!9y&SZ&|BGi@>11RX<_w>;9e-;?C3^btN@UTq&o=ci`^ zA3x=17%Hu&f=?v9=yWxEuciB+*pxB)Z4k-bZmv@ z`pGwC?Qa~9D3AE+ZHK&{Yi`JBwK`k1vcmbvS0&}&+ydOtte0!JXe;4c)N)}ZZ*|4% z-SPGvN>N3}!@^S)V1`3$G4v|$t>~lLb=Ie>mf9ZQ$IhDZ!tf<7`XU2CpN zmghm> z`HCXf$Mjr0@JNk!Gv9EzIdBdb^Nr?6Ok>~R@jVk3O21LJ|0#Dzv&7+0SncSu1+)z`+U5zJ82xlW=B4#E?Q5p`o6(!l&+csmXSH?|v(W%0-eXWL$ z=eoyKettkVPAF=1Jcw*xzUom#`%J%2DHKebdK7Fr>}FHT!=Lc0i(&0+FWBsuSrl9e zJN?~g^H|57Rg+ijb28@VBb6gJjQLq8?6{k^Whq(_F0+iQxn4$3!noTKN_P){-}sg7 zkr4Hkbusoqrbj!K@;5b%+luO{s*r?Hp=8`KGti@PIuZH5^lYt*{nhja`xi<8AO58ksI_&m_OzTACAt*% zM`mjIYLePEgwppINd6{@fyfB2BWF?Wznb1+(xflc5_(5;mOQZMLtKyisz56XeB~74y7CsCENVC~TM5I}N zTWkqSTT3SKDKc=(yX}Pxsg?_C$>%}se z0$b>trm>w$tT9~b=+7O>2FR#yXMk5bDVd$T{q6-##m! zv%x5d>rDwmvN~}!Ct)XHX)AeTbt2ucGWmS1eNH&e^DAMh($${y4#=kX@A3VTe~FtqlP}+rK=#){OZapB zl7}|jj>x#f9mFZ+ng#p@XFYnOnjj@;GZ2%D7=0NcDlrEw)~O@s-}dgMt2ID9Kvoz? zn2+16g@^p^t8o4yLx9v>^>-x`nKgkoT2gIch*G%nr&LGC!}B+li2%y|B46I)iQn+5 zdJW3SAoCBYPJK$!5+vB|nDm9D4UiP(c8wvU<-PAkJX1QwwD;_`?brx~KO|(Dy>0i$ zj?_i3z5OwKy>6dtq7<3fV3&3)>=__i3COCiZ)yTpc$GmrBJ4!iD8i8bt`c8s^ZSfJ z@k6~+R%eUU$xL|bfsHJ_Y-7tXGmsKxars5t%|G9(541Q;bkSk~av^{m8Jr!4>uX!B z4z|3*+k?~)K?1}O?Rl!Yni@l-qjvL2=%9EwOXZU@U}8`qN2fb}0A;MV9s^ypxEWYa zX7-IuCZi0|_Jh^U4*;TQntv>_uAc6Su-}j{o=t_R8MUU}D)f318BDHipO!$iNKV=j zpxIPP3f>(RfMh*AgPAjxei>3(ts}kDr!_rFdiUi~N5j*>vfGaDVNA$qjEx6f5swB5 z2i@F$YQ~;!cmw2L-`+xMhK@mQO(5RO%SF3GN7^`!uST}Jt@ok+?pA_lRcf#}8nAK_ zv6@M8@YV=J$}HegIsIoaoG_-Ma&tQ&4+V?ExY=woU#6Wf)eu3o(1wO2M8e9uLef2? z)qFOy@5#Zy5d=fGa4)*6+&Ja3XvV&ycoXjmBzgZ`M5KT86Pevy^^RcKt(QlyyoDam zq{3ETK1a9)$B1Ctx&mKl3T4G*c_@awW81bQ9U(16iy^ZB%$_@Wyq+7ya6wqN5SQAtyXbuESR@+4ApmE}gwImXrf@w8WTamY4IefR z)?A>%Zs>e}C{IlOuzRpOQ(nk%xt*^g{pZ8ugc7Pab7M`nP#Kc|B*h`L0~C2zQSQNR zV&MB>Vi;ZlpmYgvj}jw((;mYw$CJSIVBKvdNPUsc_(I0FNS(@Sefd&gw)}OnoQTSE zKqWbHZlbnlpHr!=!XZ#s>mogwa&x9y>va$a%TNH)oHAEBwOoMr2vB*=1x zFuexQ>Oy(O|Ig}jX2