From 617591ad42a03a72b8eecfda1d07b9eb1c0916ca Mon Sep 17 00:00:00 2001 From: Nuno Campos Date: Tue, 2 Apr 2024 14:51:14 -0700 Subject: [PATCH] Update time travel notebook --- examples/time-travel.ipynb | 295 ++++++++++++++++++++++++++++++------- 1 file changed, 245 insertions(+), 50 deletions(-) diff --git a/examples/time-travel.ipynb b/examples/time-travel.ipynb index c10c2cd5b..646e11628 100644 --- a/examples/time-travel.ipynb +++ b/examples/time-travel.ipynb @@ -225,7 +225,7 @@ "source": [ "from langgraph.prebuilt import ToolInvocation\n", "import json\n", - "from langchain_core.messages import FunctionMessage\n", + "from langchain_core.messages import FunctionMessage, AIMessage\n", "\n", "\n", "# Define the function that determines whether to continue or not\n", @@ -240,7 +240,7 @@ "\n", "\n", "# Define the function to execute tools\n", - "def call_tool(messages):\n", + "def call_tool(messages, config):\n", " # Based on the continue condition\n", " # we know the last message involves a function call\n", " last_message = messages[-1]\n", @@ -252,7 +252,7 @@ " ),\n", " )\n", " # We call the tool_executor and get back a response\n", - " response = tool_executor.invoke(action)\n", + " response = tool_executor.invoke(action, config)\n", " # We use the response to create a FunctionMessage\n", " function_message = FunctionMessage(content=str(response), name=action.tool)\n", " # We return a list, because this will get added to the existing list\n", @@ -347,7 +347,39 @@ "# Finally, we compile it!\n", "# This compiles it into a LangChain Runnable,\n", "# meaning you can use it as you would any other runnable\n", - "app = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])" + "app = workflow.compile(checkpointer=memory)" + ] + }, + { + "cell_type": "markdown", + "id": "e8aff75b-563e-42b1-969b-742201514fc3", + "metadata": {}, + "source": [ + "## Preview the graph" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c9ab60eb-679b-4eef-9e64-5ffbf3dffc70", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfMAAAIECAYAAAANcMd3AAAABmJLR0QA/wD/AP+gvaeTAAAgAElEQVR4nOzdd3hUZeL28W8yaaSRhIReEhACEpo06dKkKEoRXGAVQUBRQeyi7k9dX1dRRBQrsi6CgDQVkLKI0kIVSOgJJZRUEkjvk8m8f8wSRDokOZnk/lzXuTKZnJlzJ5Z7nuc0B6vVakVERETsVYKj0QlERETk9qjMRURE7JzKXERExM45GR1ARKS05eTkkJWVRXp6Ounp6VgsFrKzs8nLyytap6CggIyMjEteV6lSJdzc3Iq+N5lMeHt7A+Dr64uHhwfu7u54eXmVzi8i8j8qcxGxa2lpaURHRxMbG8u5c+eKlsTERJKSkkhMOse5c0lkZmaSlZlFWloqpXHcr7d3Zdw93PHw8MDf35+AgAAC/P2pWrUqAQEB+Pv74+/vT40aNahTpw4BAQElnknKLwcdzS4iZVl2djaRkZEcPXqUqKgooqOjOX3mDKdOnSImOob09LSidZ2cnKns50dlvyp4+vrh7eePt68f3r5+uLl74ObhgbunN67ulXB1q4S7lzeVPDwxmUw4u7jiUqlS0Xs54IDH/0bdF+RmZ1FQUFD0fUF+Hnk5OVitVrIy0snNziIvJ4fc7CyyMzLIy8kmNzuL9JRk0lOSyUxNJv38edJTzpOWfJ683Nyi93KrVIm6detSt05d6tatQ926dQkMDCQ4OJjg4GB8fX1L8K8sdi5BZS4iZUJaWhphYWEcPHiQiIgIIiIiiTwaSWxMDFarFZOTE1Vr1qJK9ZpUqVGLgJq18a9RkyrVaxJQsxZ+VWtcVr5lXV5ONufPJnA+Po5zCbEkxcZwLiGO5IQ4zifEkxB9mvz/Tf1X8Q+gcePGNGkcTKNGjQgJCaFVq1ZUr17d4N9CygCVuYiUvqSkJPbs2UNYWBh79u5l7969nDp5EqvVirevH7Xr30GNoAbUDGxAzcD61Kp/B9Xr1sPk5Gx09FJlLSwkKS6GuFNRxJ48QWzUcRJORRF36gRJ8XEAVKteg7tataJ167to1aoVrVu3pl69egYnl1KmMheRkhcXF8fWrVsJDQ1lc2go+8LCsFqtVKlajaCmzanftDl17mj0vyXY6Lh2ITsjndNHI4g6tJ8Th/Zz6vABoqOOU2ixUK16Ddq2aU3nzp3p1asXrVq1wtFRJy+VYypzESl+586d47///S+rV6/m9w0bSIiPx8XVlTuataTxXe1o0rodDVvchZeP9gMXp9zsLKIOHeDInp1E7v2DiL1/kJWZgY+PL126dKFfv77069ePwMBAo6NK8VKZi8jts1qt7N27l9WrV7Nq1Wr++GMXJpMTTdq0o1mHLjRp3Z47mrXE2cXF6KgVSqHFwumjERzZs5NDO7eyb9tmcrKyaNykCff170///v3p0qULzs4Va/dFOaQyF5Fbd+jQIZYsWcL38+dz4vhxfKr406LzPbTp3puWnbrh7mVfB6SVd4UWC5Hhe9iz8VcObg/l2MF9+Pj4MmDA/Tz66KP06NFD0/H2SWUuIjcnPj6eOXPmMH/BAg4dPEjVmrXo0PcBOt33IPXvbIaDg4PREeUGnY0+zdY1K9i66mdORR6hVu3ajBg+nDFjxtC4cWOj48mNU5mLyI3Ztm0bMz/7jGXLluHu6UWHvgPofN9AGrdqg4NGc3Yv+ngkW375ma2rfuJsTDQ9evRk4sRnuP/++zGZTEbHk2tTmYvI1RUWFrJw4UKmfTSd8LC9NGzWkr4jH6NT/4Ha/11OWQsLCduygbXz/0NY6EZq16nDs5Mm8eSTT+Lu7m50PLkylbmIXM5qtfLzzz/z+htvEBkZSef+D9Dv72No1KK10dGkFMWfPsma+f/ht6ULqOxdmf/7xxuMHTsWF32QK2tU5iJyqS1btvD88y+wZ89uOvYdwMMTX6RW/TuMjiUGSjt/jmVff8q6H+ZRs2YN3vvXvxg+fLjRseQilbmI2GRmZjJlyhS++OILWnbuxojnXiOoSVOjY0kZci4+jiWff8TvPy6iX7/+fP31V9SqVcvoWKIyFxGAjRs3Mnr0GJLT0hj92j/pOmCw0ZGkDDuyeydfvvECGcnnmTHjY0aPHm10pIouQYegilRwX3/9Nb1696Z6w8Z8/MsGFblcV5M27Zn283ruGTKcsWPHMmnSJCwWi9GxKjSVuUgFZbVaeeutt5gwYQJDnnyWFz+djU+VindP7eyMdOa8/xa7N/5aLrZTWlzc3Bj1yv/x4iff8M3s2fTvfx8ZGRlGx6qwVOYiFdSECRN47733mfTBTB5+5oUKebGXw3/s4Ok+nVg5ZxYWc8H1X1DGt2OE9r378eacxezas4f7Bwwg90/3aJfSozIXqYCmT5/ON7Nn89zHX1XoafWTRw6SnnweoEQ/zJTWdozSqEVr3pyzmLDwfYwdN87oOBWSk9EBRKR07d+/n1enTGHE5Fdp17OP0XFKRE5mBtvW/sLZ6NPkZGVSuYo/wa3aENK+U1GZHtgRyrH9YUWvObhzK9mZ6bTpfi+elX0AsFgK2P37r5yMOERGSjJu7u7UbtCQ9r36XXLd+UO7tpEUF4Obhydtu/fm9x8XcS4+jpadulFQYL7udsqDug0b8+y0z3l3/N/p368fI0aMMDpShaKj2UUqmB49ehKXnMq7C1eUy8uwHv5jB1OfGUNmWuplP+vU/wGen/4VAO9NGMXuDZfvv572068ENWlKocXCayMe5Ni+vZetU6NeEG98M5/qdQMB+GDi4+z8dQ1Va9clpH1Hfl/2AwB17gimWp2619xOeTPrrVfZt+lXjh87hoeHh9FxKgodzS5Skezdu5cNG35nxPNTymWRA3zy8jNkpqVSrU49hjz5LKOnvE1I+04AbF29gs0rlgFQrXZd/KpWK3pd1Vp1CGx8J65ubgCs/G5WUZHf1a0n948aR4OmzQHbldEWfvLBZdtOio3m92U/4FrJHZPJia4PDL7udsqbhye+SHJyMgsXLjQ6SoWiaXaRCmTRokXUCqxfVG7lTeq5RM7FxwFwZ5u7Gfb08zg5O9Nn+CgWf/YRNQLrU//OZgCMef0dqtWpx7f/+j8ARk95m3a9+ha9l7unNz2G/I1K7h6Mef0dAPJyshndoRl5uTnEn4q6bPtWq5Wm7Tryj2/mk5OdhaPJhKd35Wtup7ypXMWfdr368sMPixg7dqzRcSoMlblIBbJjx07ubNfB6BglpnKVADwr+5CZlsqGnxax67c1NG3bgeYdu9L74b9TtVadG36v3sNG0nvYSABSzydxNHwvh3ZtK/p5TnbWFV83cOxTOLu64uzqenu/jB0Lad+J7z94x+gYFYrKXKQCiU+Ip3XLdkbHKDEODg48/e50pj07HoulgKz0dHb99l92/fZfZr/zOi06dWP8m+8V7eu+FoulgJ+/+Zwd61Zz8shB/np40dWOSq8ZWL84fhW75l+jFpmZGWRkZODl5WV0nAqhfO40E5ErcnFxwVJQvs5z/qt2vfry1e+7GPbMCzRs3grHP92Le9/WTUx9eswNvc+0Z8ezYMZUog4foEmb9jz26lt89PP6og8CVzvmwE23CcWclwegu6uVIo3MRSqQoKAgYqOOGx2jxFitVs4nxBN38gQ9Bj/Mw8+8QHZGOuGhG/nug3c4Fx/LmWMRpJ5LxMe/KvxpdF1oLSx6fD4hnl3r1wJwd+/+vDRzdtHPsjPSAXDgyiNzJ+crFNhVtlNexUYdp0bNmrhW4F0NpU0jc5EKpEf37hzYvoX8cnqVrl3r1/JE9za8PeZhPn/tefJzc3H38qZtjz74BlQFwNnVFS8fXwCcnJ2LXht9NIKEM6fIycwg+Wx80fM5WZlFU+z/Xfgd6SnJ/3v+ypcudbzCiP1q2ymv9mxaT/fu3Y2OUaGozEUqkBEjRpCbk82GnxcbHaVEtOvZh6btOgK2i8I82q4xLwzsxd/bNCq6cMuAUeMxOdnKtVZQg6LX/jBzGk/f25Gj+8OoF3xn0elk+7ZtZkLP9kzo2Z5Zb0/BZLJNaGakpFB4gzcXudp2yqNj+8M4smcXox97zOgoFYrKXKQCqVatGk9NmMDimdOKRpjliYOjI6/PmseAx8ZTycMTc34+pyIOU2A24+3rx6hX/o8Rk18pWr9p2w7c3bt/0fdOzs7kZGXi4ubGSzNnU6NeEABJcTGkpyTzyItv8OjL/wAgLzeHAzu33lCuq22nvLFYCvjPv/6Pzp270KtXL6PjVCi6ApxIBZOamkrzFi2pVr8hr3z+n0sOECtPLAVmzp9NICMlGd+q1fENqHrVI9BTzyWSnpJMraAGRaN2AGthIYmx0Zjz86kV1OC2L7Rzte2UF99P/xdr5v2bP3btIiQkxOg4FUmCylykAtqxYwfde/Sg64MPMf7/3iu3V4OT0vPfhd/xzT9f49tvv+UxTbGXtgQdzS5SAd199938sHAhwx5+mKzUVJ55/xNcSunyonEnTzDt2fE3tG7syeMUmM3Ua9TkhtZ/9sPPqBd8Y+sarbz8HaxWK4s++4ilX3zMu+++qyI3iMpcpIJ68MEH+XXdOgYOHMTbo4fx8mffUrmKf4lv12zOJyH69A2tW2A2A9zw+ub8vFvOVdrKw9/BnJ/Pl/94ka2rlzN79mzGjLmxc/il+GmaXaSCi4yMpF///qSkpfP4G/+Pjv0eMDqS2IGj+/bw5esvkJp4lqVLl9C7d2+jI1VkumuaSEUXHBxMeFgYw4YMZvrzE5g2aSyp55OMjiVlVF5uDnOmvs3rIwYSHBTI/v37VORlgEbmIlJky5YtjB4zhrj4ePqOeIxB4ybi4e1tdCwpAywFZrb88jNLPv+I7LQ0PvzwA8aNG3fVMwSkVOlodhG5VFZWFp9++ikffPAhhQ4ODBz7FH1HjsbVrZLR0cQA1sJCtvzyE4s/+4hzCXE8+cQTvP7661SrVu36L5bSojIXkSvLyMjgiy++4N13/0UhcM/Aodz/2Pibuo2o2K/sjHQ2/LSY1fNmkxgbw5AhQ3jvvfdo0KDB9V8spU1lLiLXlpiYyKxZs/jyy69IOJtAu+696TNiNM3u7qTz08uhk4cPsnbhHEJ/+QlnJ2dGj36MZ555hoYNGxodTa5OZS4iN6awsJBVq1Yx45NP2PD771SpVp32vfvToe8AGt/VVvtO7di5+Fh2/rqGzcuXcvzQfho2bMTjj4/hiSeewMfHx+h4cn0qcxG5eUeOHGHhwoUsWLCQEyeOUyuwPh36PUCb7r25I6SFRux2IO7kCXZv/JXta1ZydH8Y/gEB/O3hhxk+fDgdOnTQhzP7ojIXkdvzxx9/sHDhQhYvWUJsTAw+VarQonN37urak5adu+FZWSO7siAvN4dDO7exd/PvhG/5nfgzp/Hx8eXBBx9g+PDh9OrVC1M5vU5/BaAyF5His3//ftauXcuq1avZtnUrhVYrdzRtRvBd7WjSuj2N72pbKleZE9t92I+G7+HInl1E7NlJZPgezPn5NG/Rgvv696dfv3506NBBBV4+qMxFpGSkpaWxfv16Nm3axKZNmzh06BAWi4W6DRrSqFUb7mh+F/WbNqNuw8Y4u7gYHdeuFVosxJ08QdSRgxw/EE7k3l1EHTlEocVC/QYN6NqlC926daNPnz7UqFHD6LhS/FTmIlI60tLS2Lp1K1u3bmXz5i2EhYWRlZWJk5MzdRs2ol7jEILuDCEwuAm1GzTSCP4qstLTiTt1glMRhzl55CCnjxzkVORhcnNycHJ2plmzZnTp3JnO/1tU3hWCylxEjFFYWMjRo0cJCwsjLCyMvXttX5OTzwPg6V2ZWkENqBF0B7XqN6BmYH1q1KtPleo1yv1++LycbJJiY0iMjSY26jixJ0+QcDqKmBPHSDlnu9Suh4cnzVu0oPVdrWjVqhUtW7YkJCQEF81yVEQqcxEpW+Li4oiIiODo0aNERERw5EgEkUcjiT5zhsLCQgDc3N2pVqsOftVrUKV6Tfyr16RK9Zp4+1XBy9cPb18/fPwDqOThafBvc6m83BwyUpJJSUokIyWZ9JRkUhLPcv5sPElxMZyPj+V8QjzpqSlFr6lWvTqNGzemcXAwwcHBNGnShEaNGhEYGIijzhoQG5W5iNiH3NxcTp48SXR0dNFy+vRpzpw5w5noaOLj4snKyrzkNc4urlT2s5W7u6cXLpUq4ebuibuXF65ulXCt5I67lzcubm64uLpe8rqr3d+9wGwmLyf7ku9zs7PJzc4iLyeb3OxssjLSyc/NIT8nm5zMTNKSz5Oecp7cnJxL3svVzY1q1apRp05dggLrUadOnaKlXr161KtXD29dG1+uT2UuIuVHTk4O586dIykpicTERJKSkjh37hznzp0jPT2drKwsMjMzSU1NIzMrk6ysLNLT08nMzKTAXFD0PlnZWZjz86+4DZPJhJfXxYJ1cHCgsk9lPDw88PDwwMvTEx8fn6Lvvb298ff3L1oCAgKoWrUqAQEBeHqWrZkDsVsqcxGRa5k8eTK7d+8mNDTU6CgiV6P7mYuIiNg7lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5lbmIiIidU5mLiIjYOZW5iIiInVOZi4iI2DmVuYiIiJ1TmYuIiNg5J6MDiIiUFT/++CNjxozBYrEUPZeXl0dhYSFeXl5Fzzk6OjJp0iTeeecdI2KKXMbBarVajQ4hIlIWZGZm4u/vT15e3nXX3bFjB+3bty+FVCLXlaBpdhGR//H09OTBBx/E2dn5muvVqVOHdu3alVIqketTmYuI/MnIkSMpKCi46s+dnZ157LHHcHBwKMVUItemaXYRkT/Jz88nICCA9PT0q65z8OBBmjZtWoqpRK5J0+wiIn/m4uLC0KFDrzrV3rRpUxW5lDkqcxGRvxgxYgRms/my552dnRk1apQBiUSuTdPsIiJ/UVhYSPXq1UlKSrrkeQcHB6KioggMDDQmmMiVaZpdROSvHB0d+fvf/37JVLujoyPt27dXkUuZpDIXEbmC4cOHXzLV7ujoyKOPPmpgIpGr0zS7iMhVBAUFcerUKQBMJhNxcXFUrVrV2FAil9M0u4jI1TzyyCM4OztjMpno1auXilzKLJW5iMhVXJhqt1gsjBw50ug4IlelaXYRkWto1qwZR48e5dy5c5fcbEWkDEnQXdNERK7hkUceYc+ePSpyKdNU5iIi1zB8+HCaNGlidAyRa1KZi0iFYDabiYmJ4cyZM5w+fZro6GjOnz9PcnIyycnnSE5OJDn5PHl5eRQUWMjIyAQgP78Ai6WQSpVcAHB3r4SrqwtOTk74+VXBzy/gf4sffn5+1KpVi3r16lG3bl3q1auHm5ubkb+2VBDaZy4i5UpWVhaHDx/mwIEDHDp0iIMHwzly5BCxsYkUFtr+d+fq6kidOs74+1vx87Pg52ehShXw8wNXV3B2Bk9P2/s5OYHJBBducZ6TA7m5UFAAyckXFkfOn3ciOdmB6OgCMjMtRXmqVfMlOLgxTZu2pFmzZjRt2pSQkBD8/PxK+08j5VeCylxE7Nrx48fZvn07O3bsYOvWDRw8GInFUoi7u4kmTUyEhOTTtCkEBkLduralRo2SzZScDGfO2JaTJ+HIETh0yJlDh6ykpNhur9qwYT06dOhKhw4d6dixI02bNsVkMpVsMCmvVOYiYl/S0tJYv349a9euYe3alcTEJOLq6kjr1ibuvttMhw7QqhUEBYFjGTz5NjYW9u+HHTtg+3Yndu6E9PQCfH296N27D3379qdv377UKOlPHFKeqMxFpOw7d+4cS5YsYfHi+YSG7sBqLaRdOyf69TPTqxfcdZdtetweWSxw+DD8/jusWePE5s1WcnMLadGiCUOHjmT48OEEBQUZHVPKNpW5iJRNeXl5LF26lAUL5vHrr+txcXFgwIBCHnywkHvvte3fLo9ycmDjRli5EpYudeLcOQvt29/FiBGj+Pvf/46vr6/REaXsUZmLSNkSExPDl19+yezZX5KamkafPg4MH27hgQfAw8PodKWroADWr4eFCx346ScTFouJkSMf4ZlnJtK8eXOj40nZoTIXkbIhIiKCf/7zLZYsWYq/vyNPPGHmiSdK/mA1e5GRAXPnwmefORMRYaZ79y68+eY7dOvWzehoYjzdaEVEjHX8+HEeffTvhIQ0Zf/+n5gzx8Lp02beektF/mdeXvD003D4sJl168DBYRv33HMPvXt3Z/v27UbHE4OpzEXEEDk5Obz11ps0bdqE0NBFfPFFIfv25TNyJLi4GJ2u7HJwgN694bffLISGgsWylY4dOzJgwH3ExsYaHU8Moml2ESl1a9eu5emnx3P+fDzvvlvAE0/YLs4it2bFCpg0yYn0dDfef/8jxo0bh4ODg9GxpPRoml1ESk9BQQGvvvoK/fv35847YzlwoICnn1aR364HHoDDhwuYNCmTiRMnMGBAf5KTk42OJaVII3MRKRUxMTEMGzaYAwf28s03Fv72N6MTlU87dsCwYc6YTFVZsuRn2rRpY3QkKXkamYtIyYuMjOTuu1uTkhLO9u0q8pJ0990QFmamceOzdO7ckRUrVhgdSUqBylxEStSRI0fo3r0zgYHJ7NxpJiTE6ETlX5UqsGpVASNHFjB06BB+/PFHoyNJCdM0u4iUmFOnTtGu3V2EhGSwcmVBhbvoi9GsVnjmGQe++caRNWv+S8+ePY2OJCVDF40RkZKRk5ND587tsVgi2LbNjLu70YnKlrQ0ePtt6NED7r+/5LZjtcKIEY789ps3u3fvo27duiW3MTGK9pmLSMmYPHkSJ08eYdkyFflfbd4MDRvCxx+D2Vyy23JwgNmzC6lWLYthwwZRWFhYshsUQ6jMRaTYhYeHM3v2v/niiwIaNDA6TdkTFgZJSbbHpXE6uIcHLFpkZs+ecObOnVvyG5RSp2l2ESl2997bg7S0UHbsMJd4WRUU2O4wFh4O586Bpyc0aQKDBkHlypev/8cfttuNpqdDp07Qty9s3w7Hj9uuPDd8+KXr799vu4vZqVPQuDF07Wr7+mc7d0JEhO18+ZEjbeuuWweRkdC0KQweDD4+tnV//x3+/W9YsMD2/aRJtlu4DhhQ8neCe+opB1asCODo0ZO4a7qkPEnAKiJSjA4ePGgFrOvXY7VaS3YpKMDavj1WuHxp2BDr8eOXrv/yy1gdHC5db9AgrEOH2h77+Fxc12LB+vrrWB0dL13fyQnre+9hLSy8uO5TT9l+VqkS1h9/xOrufulr6tW7mGXAgCvnDQsr+b9XQgJWV1dH69y5c4vvH7iUBfGaZheRYrVkyRJq1XKme/eS39bHH9tGxQD9+8PkydC6te37Y8fgH/+4uO7SpfDBB7YDwhwcYOBA6NABfvrJ9rO/+vZbePddKCy0neo1bhzUrm2bCZgyBZYsufw1ubnw0EMQEmIbcQcG2p4/fRqmTrU9DgqCmjUvviYwEFq0gEqVbvevcX3VqkHv3g4sXbqo5DcmpcvojxMiUr60bt3M+swzJT/KtFqxzpqFdcwYrJMmXXwuM/PiyLh164vPh4TYnnN0xLpjx8Xn58y5ODquXNn2XF4e1qpVL47WMzNtz5vNWOvWtT3fpMnF0fmFkTlgHTjw4nsfO3bx+fbtLz4/Y8bF53/6qXT+VheWb7/F6ubmbM3Jybntf9ZSZmhkLiLF69ixE7RoUTrbGjfOtv/5k0/g7FlYvhzeeOPizzMzbV/NZjhyxPb47ruhffuL64waZRux/tmJE5CYaHvcs6dtxH3+vO10sv79bc8fOQIJCZdneuqpi4/vuAP8/W2Pz5+/9d+zOLVsCbm5ZqKjo42OIsVItzcQkWKTkZFBeno2tWuXzvYKCmzT1z/+aDtC/K+H8144+O7MGbBYbI+vlK12bduHgQuOHbv4eNky23IlsbGX33M9IODS7y8cZ3Zh+0a78PvHxMTQsGFDY8NIsVGZi0ixyc7OBkpn/y/A0KHw88+2x1272vaD9+hh2299/Dg4/m/u0cvr4mv+ejOx7Gw4dOjS55ydLz5u2RKudq8SN7fLn3N1vfR7xzI2/3nhw8WFf1ZSPqjMRaTYBAQE4OLiRFxcQYlvKybmYpEPHnzp6Dk11fb1wsi8alXbaWppaba7iiUnXzwN7LffbNPof1a//sXHXl7wzTcXvz90yHb6W926Vz5H/EZOxfvzOqV9DZeYGNvX2qU1fSKloox9ZhQRe+bo6EjNmlU5ebLktxUbe/FxRsbFKfYvv7Sdbw62c8kvGDPG9jUz07bP/JtvbPvXR426/L2Dg23nfgOEhsKiRbZp8tOnbeemBwbaRuz5+beW3cXl4uODB22zCH/OWpJOnbJ9VZmXLypzESlW3br1YtUq5+uveJuaN794itevv9pO+QoKsh2A5vS/Ocfz5y/uq371VdsFXMBWnuPH2049q1IF6tSxPf/nEfO0abbRlAgAACAASURBVLYpaasV/vY3qF7dNmJPS7O9/6xZl5byzQgOvvj4zTdtl3a9cIpdSVu1Cpo3b0yVKlVKZ4NSKlTmIlKsHnpoKDt2FFwyci4JlSrZptYvHMN1+rRtRD51Knz4oe257GzbFdfANtW+ZQuMHQsNGtg+CIwcCVu3Xjzi/M/l3L07bNtmO2/dycn23i4u0Ls3zJ9/6RHxN6tbN9uugQtcXGyzCyWtsBB+/NGFwYN1Q/nyRpdzFZFilZeXR2BgLR5+OJkZM0r+fy+Fhbap47w824j3agec7dhhu6RqvXqXH6AXFGR7j+Bg22VZ/yo313aE+x13FO/BfQkJtg8JwcGXHnRXUubOhccfd+Tw4QgdyV6+6K5pIlK8XF1defvtf/HFFw6XnOJVUhwdbdPfTZpc+8jxt96yrePuDi+8YNvfnZdnu5LbmTO2dS7sJ/8rNzdo1qz4j9KvXt12tbjSKPLcXPjHP5wZO3asirwc0shcRIpdQUEBLVrcSbVqJ1m3rqBoH7aRFiywTatf4OZm259+4RakTk6wbx/ceacx+Urac8858O9/V+Lo0RNUr17d6DhSvDQyF5Hi5+TkxMKFS9m508Rrr5XCPT5vwIgR8J//XNzHnptrK3IHB9t55OvWld8iX7QIZsyw8vnnX6nIyymNzEWkxMybN49Rox5l1izbgWdlRXo6xMWByWQ7X/yvF3opT7Zuhb59nXj88aeYMeMTo+NIyUgoA5NfIlJePfLII0RFRTF+/Fvk51963XIjeXvblvJuwwYYMMBEnz738eGH04yOIyVIZS4iJerNN9/ExcWFZ555jfPnbRdquZGrpMntWbIERo0yMXDgQ8yd+z1OZeHABSkx2mcuIiVuypQpfP75F/y//+fEgAGmy66PLsXHbIbnnoOHH4Zx455i3rz5KvIKQPvMRaTU7Nixg2HDBmEynWf2bDM9exqdqHw5fBgef9yJgwed+eabb/nb33RxmApCR7OLSOm5++672bv3AK1a9aNXL3jkEVPRfcPl1uXk2HZftGrliMUSwq5de1TkFYzKXERKlb+/Pz/+uJzly5ezaVMATZo48cEHkJVldDL7Y7HAvHkQEuLMzJnuTJs2g+3bd9OkSROjo0kpU5mLiCEeeOABDh8+xpNPvsw771SiQQNnPvnk8tuRyuUKC20HuDVr5szo0Y507Tqcw4ePMnHiREwmk9HxxADaZy4ihjt37hzTpk1j5swZuLhYePTRAp5/3nYddbkoPR1++AE++cSFiAgzQ4YM5p133iX4z7dhk4ooQWUuImVGQkICX3/9NV9//RlJSck88IADo0dbuPfeW7/dqL2zWm13b5s714H58x1xdHThkUce45lnJmo6XS5QmYtI2WM2m1m2bBlffjmT0NDt+PiYGDLEwvDhVrp2tV25rbwLD4eFC2HRImdOnzYTEhLM+PFPM2rUKLwrwhVv5GaozEWkbIuJiWHZsmUsWTKfrVv/wNPTxD33FDJggJX+/aF2baMTFo+sLNi+HVauhJ9/duHMmXzq1KnOoEHDGDp0KJ07dzY6opRdKnMRsR9Hjx5l9erVrF37C5s2bSYvz0zTpq506JBHx47QoYPt3uD2IDbWNn2+bRts3+7Cnj1mrFYH2rZtRb9+D9CvXz/atGmDgy6XJ9enMhcR+5Sdnc2mTZvYtGkTv/22ln37DmE2F1ClijMtW1pp2rSApk2haVPb3dB8fY3KCUeOwKFDFxYT+/ebiI7Ox8nJRPPmTejY8R66dOlCr1698PPzMyao2DOVuYjYt3379tGnTx+CgoKYNm0ae/bs4cCBAxw4sIcjRyJJT88GwMfHibp1TdSrZyYwsJA6dSAgAPz8Ll1cXW33Oq9U6crbM5shM9N2jvf585CcfOly5gycPu3AmTPOnD5tJTHRdsN0V1dnmjS5gzvvbEmzZs1p3749bdu2xdPTs7T+VFJ+qcxFxH7t3r2bvn37EhISwsqVK/Hy8rpsnVOnThEREcGpU6c4c+YMp0+f5vTpY5w5c4bk5DSysq59YruHhwmTyYH09IJrrufq6oyfnze1a9emXr07qFvXdl5d69atad26NQ0aNNA10qWkqMxFxD5t2rSJAQMG0LVrV5YsWUKlqw2lryMvL4/k5OSiJS8vj7y8PLKzbSP6zMxMCgoK8PHxAcDFxQUPDw9MJhN+fn5Fi4eHx2XvHRoayujRo1m5ciWNGze+9V9W5NpU5iJif1atWsXQoUN58MEHmTt3Ls7OzkZHuqKsrCy8vb1xd3dn6dKl9OnTx+hIUj7pRisiYl9++OEHBg0axNChQ5k3b16ZLXIADw8PGjZsSGZmJv3792fmzJlGR5JySmUuInZj3rx5PPLIIzzxxBPMmTPHLvZBd+rUCWdnZwoLC3n22WcZO3YsZrPZ6FhSzqjMRcQufP7554waNYoXXniBmTNn2s35123atOHC3kyr1cp3331H165dSUpKMjiZlCcqcxEp86ZOncrEiRP58MMPef/9942Oc1PatGlDQcHFI+ELCgrYs2cPbdq04fDhwwYmk/JEB8CJSJlltVp56aWXmDFjBl999RVjx441OtJNy8/Px9PT87KpdScnJ1xcXFi0aBH333+/QemknNABcCJSNlksFp544gk++eQTvv32W7sscrCdynalu5sVFBSQk5PDgw8+yNSpUw1IJuWJylxEyhyLxcKYMWOYO3cuixcv5tFHHzU60m3p1KkTLle4h6vVaqWwsJApU6bowDi5LSpzESlT8vLyGDp0KMuWLWPlypUMGjTI6Ei3rU2bNlgslqv+3Gq1MmfOHHr16kVycnIpJpPyouyf1yEiFUZWVhaDBg3ijz/+4Ndff6VDhw5GRyoW1ytzR0dHLBYLjo6OJCcn62YrctN0AJyIlAmpqancd999HD9+nHXr1tGiRQujIxUbi8WCp6cnubmXXwfe2dkZHx8fpk2bZve7E8QwOgBORIyXmJhI9+7diYmJYcuWLeWqyAFMJhPNmze/5LkLF7wZPHgwJ06cUJHLbVGZi4ih4uPj6dGjB2lpaWzYsIFGjRoZHalEdOjQAWdn56KL3XTr1o127dpx5swZ3QZVbpvKXEQMc/LkSbp06YLVaiU0NJT69esbHanEtG3bFrPZTI0aNVi2bBnr16/n66+/ZteuXSxYsMDoeGLntM9cRAxx5MgRevfuTfXq1Vm7di3+/v5GRypRx48fZ86cObz22mu4u7sXPT9+/HhWr15NZGTkFW+jKnIDdAtUESl9e/bsoW/fvtx5552sXLkSb29voyMZJjExkeDgYCZNmsTbb79tdByxTzoATkRK1+bNm+nRowdt27Zl7dq1FbrIAapWrcobb7zBhx9+yKlTp4yOI3ZKI3MRKTVr1qxhyJAh3HvvvSxatAhXV1ejI5UJZrOZZs2a0aJFCxYtWmR0HLE/GpmLSOlYvnw5gwYNYsiQISxdulRF/ifOzs589NFHLF68mE2bNhkdR+yQRuYiUuK+//57Ro8ezfjx45k5cyaOjhpHXEn//v2Jj49n9+7dmEwmo+OI/dDIXERK1hdffMGoUaN44YUX+Pzzz1Xk1zB9+nQOHTrEd999Z3QUsTMamYtIiZk6dSpTpkxh6tSpvPTSS0bHsQsTJ05kyZIlHDt2DC8vL6PjiH3QyFxESsabb77JlClTmDFjhor8Jrz99tuYzWamTZtmdBSxIypzESlWVquVyZMn8+677/Ltt98yadIkoyPZFT8/P1599VU+/PBDzpw5Y3QcsROaZheRYmOxWBg7diwLFixg4cKFDB482OhIdik/P5+mTZvSqVMn5syZY3QcKft0BTgRKR75+fmMGDGCNWvW8NNPP3HvvfcaHcmuLV68mOHDh7Nz507atGljdBwp21TmInL7srOzGTRoEDt37mTVqlV06tTJ6EjlQpcuXTCZTGzcuNHoKFK26QA4Ebk9aWlp3HvvvezevZt169apyIvRtGnT2Lx5M8uXLzc6ipRxGpmLyC1LTk6mX79+REdHs27dOkJCQoyOVO4MHz6cP/74g8OHD+Pi4mJ0HCmbNDIXkVuTkJDAPffcQ2JiIlu2bFGRl5D33nuP2NhYvv76a6OjSBmmMheRm3bq1Cm6dOmC2WwmNDSUBg0aGB2p3AoMDGTSpEm88847pKenGx1HyiiVuYjclIiICLp06YK3tzebN2+mVq1aRkcq96ZMmUJhYSEffvih0VGkjFKZi8gN27t3L127diUwMJDff/+dgIAAoyNVCD4+Przyyit89NFHxMTEGB1HyiCVuYjckNDQUHr06EFISAhr1qyhcuXKRkeqUCZOnEhAQADvvvuu0VGkDFKZi8h1bdiwgX79+tG1a1dWr16Np6en0ZEqHDc3N9566y2++eYbjhw5YnQcKWN0apqIXNPKlSsZNmwYgwcP5rvvvsPJycnoSBVWYWEhd911F3fccQdLly41Oo6UHTo1TUSubsGCBQwePJjHHnuMefPmqcgN5ujoyDvvvMOyZcvYtm2b0XGkDNHIXESu6KuvvuLpp5/mpZde4v333zc6jvxJjx49KCgoYPPmzUZHkbJBI3MRudzUqVN56qmnVORl1Pvvv09oaCirVq0yOoqUERqZi8glpk6dypQpU5g+fTqTJ082Oo5cxZAhQzh69Cjh4eGYTCaj44ixNDIXERur1cpzzz3H66+/zuzZs1XkZdy7775LREQECxYsMDqKlAEamYsIFouF8ePH8/333zN//nweeughoyPJDRg9ejQbN24kMjJSN2Gp2DQyF6no8vPz+dvf/sYPP/zA8uXLVeR25K233iI+Pp45c+YYHUUMppG5SAWWnZ3NkCFDCA0NZfny5fTo0cPoSHKTnn76aX7++WeOHz9OpUqVjI4jxtDIXKSiyszM5IEHHmDnzp2sX79eRW6n3njjDVJTU5k1a5bRUcRAGpmLVEApKSn079+fU6dOsW7dOpo1a2Z0JLkNL774InPnzuXEiRN4eXkZHUdKn0bmIhVNQkIC99xzD/Hx8WzevFlFXg68+uqr5Obm8vnnnxsdRQyiMhepQE6fPk3Xrl3Jy8tjy5YtNGzY0OhIUgz8/f159tlnmTp1KikpKUbHEQOozEUqiMjISLp06YKLiwsbNmygTp06RkeSYvTiiy/i6OjIJ598YnQUMYDKXKQCOHToEN27d6d69eps2rSJGjVqGB1JilnlypV54YUX+Oijj0hMTDQ6jpQylblIOffHH3/QrVs3goOD+e2336hSpYrRkaSETJo0CXd3d6ZNm2Z0FCllKnORcmzjxo307NmTDh06sGbNGh3pXM55enry6quv8sUXX5CUlGR0HClFKnORcmrVqlX069eP++67jx9//BE3NzejI0kpmDBhAt7e3kyfPt3oKFKKVOYi5dAPP/zAoEGDePTRR5k/fz7Ozs5GR5JS4ubmxuTJk5k5c6ZG5xWIylyknJk1axYjR47kySef5KuvvsLRUf+ZVzRPP/007u7ufPrpp0ZHkVKi/8pFypHPPvuMJ598kpdeeolPP/0UBwcHoyOJATw8PJg8eTKffvqpzjuvIFTmIuXE1KlTmTRpEtOmTeP99983Oo4YbNKkSbi4uOi88wpCZS5i56xWKy+88AKvv/46s2bN4vnnnzc6kpQBnp6eTJw4kRkzZpCammp0HClhKnMRO2axWBg/fjwzZ85kwYIFjB071uhIUoY8++yzODo6MnPmTKOjSAlTmYvYqYKCAsaMGcO8efNYvHgxw4YNMzqSlDGVK1cuGp1nZGQYHUdKkMpcxA7l5eUxdOhQli1bxi+//MLAgQONjiRl1HPPPUdhYSGfffaZ0VGkBKnMRexMVlYW999/Pxs3buTXX3+lV69eRkeSMszHx4ennnqK6dOnk5WVZXQcKSEqcxE7kpqaSu/evTlw4AAbN26kQ4cORkcSO/Dcc8+Rk5PDN998Y3QUKSEOVqvVanQIEbm+s2fP0qdPH1JSUvj1119p1KiR0ZHEjjz77LP8+OOPnDhxAhcXF6PjSPFK0MhcxA6cOXOGrl27kp6ezoYNG1TkctNefPFFzp49yw8//GB0FCkBGpmLlHEnT56kV69euLm58euvv1KzZk2jI4mdeuSRR9izZw8HDx7UZX7LF43MRcqyw4cP07lzZ/z8/Ni8ebOKXG7Lyy+/TEREBKtXrzY6ihQzjcxFyqg9e/bQt29f7rzzTlauXIm3t7fRkaQcuO+++8jIyGDz5s1GR5Hio5G5SFm0efNmevToQbt27Vi7dq2KXIrNyy+/zJYtW9i2bZvRUaQYaWQuUsasXr2ahx56iAceeIB58+bpXuRS7Dp27EjVqlX5+eefjY4ixUMjc5GyZPny5QwePJiHHnqI77//XkUuJeKll15ixYoVHD582OgoUkxU5iJlxPfff89DDz3E2LFjmTNnDk5OTkZHknJq4MCBNG7cmI8++sjoKFJMVOYiZcDnn3/OqFGjeOGFF/jss8902pCUKAcHB55//nnmzZtHdHS00XGkGOj/GCIGmzp1KhMnTmTq1Km8//77RseRCuKRRx7B39+fzz//3OgoUgxU5iIGsVqtvPzyy0yZMoVPPvmEF1980ehIUoG4uroyYcIEZs2apRuwlAMqcxEDWK1WJk+ezPTp0/nPf/7DxIkTjY4kFdCTTz5JTk4OCxYsMDqK3CadmiZSyiwWC48//jgLFy5k4cKFDB482OhIUoE99thj7N69mwMHDuDg4GB0HLk1OjVNpDTl5+czbNgwli5dysqVK1XkYrhnn32WQ4cOsWHDBqOjyG3QyFyklGRnZzNo0CB27drFqlWr6Nixo9GRRADo0qUL/v7+/PTTT0ZHkVujkblIaUhNTeXee+8lPDycDRs2qMilTJk0aRIrVqwgKirK6Chyi1TmIiUsMTGR7t27ExUVxW+//UbLli2NjiRyiUGDBlGrVi2++OILo6PILVKZi9wmi8XCgw8+SHx8/GU/i4+Pp2fPnqSmprJlyxZCQkIMSChybU5OTkyYMIF///vfZGZmGh1HboHKXOQ2zZ8/nxUrVtCzZ0+Sk5OLnj916hRdunTBYrEQGhpKgwYNDEwpcm1PPPEE+fn5zJs3z+gocgt0AJzIbTCbzTRo0ICYmBhMJhPNmzdn48aNxMTE0Lt3b6pXr87atWvx9/c3OqrIdY0bN47NmzcTERGh09Tsiw6AE7kd3377LbGxsVitVgoKCjhw4ADdunWja9eu1K9fn99//11FLnZj4sSJHD16lPXr1xsdRW6SRuYityg3N5egoCDOnj3Ln/8zcnR0xNfXl2PHjuHr62tgQpGb17lzZ2rWrMnixYuNjiI3TiNzkVv11VdfkZSUxF8/DxcWFpKamsro0aMpKCgwKJ3IrRk3bhzLly8nMTHR6ChyE1TmIrcgKyuLd955B4vFcsWfWywWfvnlFx5//PHLyl6kLBs2bBju7u7MnTvX6ChyE1TmIrdg5syZpKWlXXMdi8XC3Llzef7550splcjtq1SpEsOHD2f27Nn6IGpHVOYiNyktLY333nvvqqNyAJPJBECjRo0ICQm55roiZc2TTz5JZGQkoaGhRkeRG6QyF7lJH3/8MdnZ2Vf8mZOTEwBt2rRhxYoVRERE8PjjjxeVu4g9aN68Oa1bt2b27NlGR5EbpKPZRW7C+fPnqVu37mVl7uzsjNVqZeDAgbz88su0bdvWoIQixeOrr77i+eefJzY2VmdllH06ml3kZnzwwQfk5+cD4ODggMlkwsPDgwkTJnDy5EmWLFmiIpdyYeTIkZhMJhYsWGB0FLkBGpmL3KCEhAQCAwPJy8sDoF69erzyyiuMGjUKd3d3g9OJFL8xY8awZ88e9u3bZ3QUuTaNzEVu1HvvvUdeXh6dOnVi+fLlREVFMWHCBBW5lFtjx45l//797N692+goch0amctNMZvNZGZmkpeXV7TfOD09veho7czMTMxmM2A7F/vClHR2dnbRiDY3N5ecnJyi90xJSbnh7d6KSpUq4ebmdt31vL29iw5Uc3FxwcPDA7Ad1GY2m5kzZw4PPvggbdq0AWzT7D4+PkWvv7Bf8cJrb3S7ImVZSEgInTp14uuvvzY6ilxdgsq8HMrKyiIjI4PMzEzS0tJIT08v+j4jI4PU1FQyMjLIz88nLS2tqChzc7PJyckkOzuLvLxcMjIyKCgoIDU1HYulkLS0rFvO5OrqiLv7haIED4+Lk0Lu7lZcXa9/U4fKlS04Ot78zR9SUx2wWq/9OovFSnr6xXVyc63k5Nj+08jLKyQ7+9ZPLfP0rISzs4nKlb0wmUz4+PhgMjnh7V0ZFxc3PDy8i4rf09MTFxcXfHx88PLywsvLC09PT7y8vIqe8/T0xNPTk8qVK99yJpEbNX36dP75z3+SkJCgD6dll8q8LEpPTyc5OZmUlBRSUlKKHv/5a2pqKikpiWRkpJOZmUFGRiYZGZmkpmZd9UIPTk4OeHk54ePjiKenrVR9fQsxmax4exfg7AyenuDmBpUqgYeHbR1vbzCZwNfX9tXbm6J14eJ6AO7u4Opqe3zhfcoTsxkuTBAUFEBGhu2xxQLp6bbHubmQkwNZWZCfb3veYoGUlIvr5efbfn5xXRP5+Y6kpzuQn+9AejqkpRWSmWkhL6/wqnkqV/bA09MdLy9bwfv4+OHl5Yuvrx++vr74+V369a/PiVxPfHw8derUYdGiRQwZMsToOHJlKvOSlp2dTVJSEgkJCSQlJRU9TkxMJCkpieRk22Ir7lSSk22j4L/y8XHG19eEnx/4+Vnx9c3Hx8eKl5etVD09bSXr43Pxe09P2/cX1ilvxVpRXPgAkZJi+/CQmWlbbIVve3zh+dRU2+OUFEdSUkwkJzuQkmIlObmAwsLL/1P39fXEz68yvr4++PpWoUqVGgQEVCUgIIBq1apRrVo1/P39qVq1KtWrV8fLy8uAv4AYrXfv3nh5efHjjz8aHUWuTGV+K8xmMwkJCURHRxMXF0dsbOyfCvssSUnxnD17lrNnz5GVlXvJaz08TFSr5ky1ag4EBJipUqUAX1/w8+OSr399TrcWltuVlgbJybYPBSkptsd//f78eUhKciIpyZGzZwtJTb30RjFubs4EBPhSrVoAVavWJCCgZlHRV6tWjbp161KjRg1q166tKdlyZM6cOTzxxBPExcVRpUoVo+PI5VTmf5WWlkZsbCwxMTHEx8cTHR39v6+niYs7TWxsHGfPphRNZTs4QPXqLgQEOFCtmoWqVQsICICqVaF6dQgIsC0XHuvAZ7En+fmQlASJiZCQYHuclPTnxybOnnXi7FkrZ88WYDZfnFWqUsWbGjWqUbdufWrUqE3t2rWpVasWNWvWpE6dOtSoUYOAgAADfzu5Uenp6dSoUYMZM2Ywbtw4o+PI5Spemefn5xMTE0NUVNSfluNERUVy4sQpUlMvHjHt6uqIn5+JmjWt1K9fQI0aULMmRV/r14c6dWz7j0XENsKPi4P4eIiKuvg4Ls6Z+Hgn4uIKiY/PK1rf1dWZWrWqU79+Q+rXv4P69esXLQ0aNLjkbAEx1sMPP8zZs2fZuHGj0VHkcuWzzFNSUoiMjOTIkSNERUVx8uRJTp48xsmTUcTHnytar0oVZ4KCHAkKyicoyEpQENSta1tq1ADNJokUv8xMiI62Ff3p03DypG05dcqJqCgH4uPNRev6+XkRFFSPoKBggoJsJR8cHEyTJk2oXr26gb9FxbNixQoGDhxIVFQUgYGBRseRS9lvmRcWFnL69Omi0o6MjCQy8iBHjhzh7NlkANzcHGnQwJmgIDP16xcSFASBgRAUZFu8vY39HUTkcrm5fy74C48dOHnSmRMnCklLs+3H9/HxJDi4IY0bN6dx48ZFJd+gQQOcNV1W7MxmMzVr1uTFF1/klVdeMTqOXMo+yjwxMZHw8HDCwsIIDw/nyJH9REYeJzfXdkGSatVcaNIEgoPzCQ7mf4+hXj1w1DXuRMqV+HiIiIDISNvXiAhHIiNNnD5txmoFJycT9evX4s47W9CixV20bNmSli1bajRZDJ566ik2bdrEoUOHjI4ilypbZW61WomKiioq7bCwPYSH7yUuLhGA2rVdaNXKQtOmlktKW7vVRCQ7G44etZX8kSNw5IgDYWHOnDhhprDQiq+vJy1btqBVq/ZFBd+kSZOi29bK9W3dupXOnTuzb98+mjdvbnQcucjYMk9LS2Pbtm1s3bqV0NCNhIWFkZ6ejcnkQKNGLrRqlU/LllZatYKWLcHf36ikImKvMjJg/34ID4ewMAgPd+HgwQLy8gpxc3OhefM76dChG507d6ZTp07UqFHD6MhlltVq5Y477uChhx5i6tSpRseRi0q3zKOjo9myZQvbtm1jy5bfOXgwgsJCK8HBbnTsmEf79lZatoRmzXQKl4iUHLPZNnoPD4fduyE01Jn9+wuwWKw0aFCbTp2607lzFzp37kzjxo1x0IUeirz22mv88MMPnDhxQn+XsqNkyzwjI4N169axatUvrF+/hujoszg7O9K6tYmOHc106QIdO9rOyRYRMVJGBmzfDlu3QmioEzt3WsnKslClijf33NOT++4bQP/+/alWrZrRUQ0VFhbGXXfdxa5du2jbtq3RccSm+Mv82LFjrFq1ilWrVrB58xYsFgt33+1Mnz75dO0Kbdtq1C0iZV9BgW1afutWWLfOxIYNVvLzrbRu3Zz77hvEfffdR+vWrSvk6LRhw4YMHjxYU+1lR/GU+b59+5g/fz7Lly/l6NGT+Po606ePhfvvL6RvX52vLSL2LzsbfvsNVq2CVauciYkxU726HwMGDGbEiJF07doVxwpy+syrr77K4sWLNdVedtx6mZ87d47//Oc/zJ37bw4ejCQoyIWhQ/Pp3x86dQIdIFq+7d8PJ07YHvfqZbuZi5EOHIDjx22Pe/a8sWsIbNxou2KZszPcf3+JxjPUrfxt5PrCw2H15XBBIwAAIABJREFUali2zJm9e83UqVOVkSPHMG7cOOrXr290vBK1Z88e2rRpw+7du2ndurXRcQQSsN6k8PBw66hRj1rd3JytPj5O1gkTsIaGYi0sxGq1ajFqSU3F+txzWFeuLJ3tTZyIFWzLwYPG//7PPnsxz/79N/aaNm1s63t5GZ+/JP8duJW/jZabWw4dwvraa1hr13a2Ojo6WO+7r6913bp11vKsQYMG1ldeecXoGGITf8NzQuHh4Qwa9ACtWrUiLGwhn3xiJiamgC++sI3ENdNinM2boWFD+Phj21G6UvHo3wFj3XknvPsunDxpZskSK7m567n33nvp2LEd69atMzpeiRgyZAiLFy/Gai0zlyqp0K5b5llZWbz66iu0adOaqKg1LFpkJTzczPjx4OFRGhHlesLCbHewAn2oqqiu9e/A5Mm2o7S3b4cGDUo/W0Xi5ASDB8P69QWEh0Pt2mH07duHAQP+P3t3HhdVuT9w/DPDDJsgi6KIK7ggCAoomOKGZpZGqblkKmWraan3XlvMMrt5r5q2WN42s7yW91eWlpZ7rqkoqKiogCuiCAqy78PM+f1xhAFBBVkOMzzv1+u8ZubMmTPfYQ7zPc9zvuc5w7l8+bLS4dWqMWPGcOnSJaKiopQORQDuemT76NGjPPHEY+Tm3mDlSgNhYQazTxbFxfD77/LxsNRUsLOTR5obNQocHCouHxkJu3ZBVpbcQ/Hww/KP5vnzYGkJEyaUX/7kSflYbXw8dO0KAwbIt2UdPiwPU6nRwMSJ8rLbt8sjW3XrJv9YlIx6t2sXREQYX7t7t3zd6tBQ+Tro1ZWVBT//LF/xKjtbPm2wb18ICbn7jkJ8vHz88OJF6N4dRo6s/NisXi8nnn374Pp18PGBwYOhdevyyx04YDzOO2ZM+R3HH3+EwkL584WGVu1zHT4s/90zMqBPn6q/riquXYM//4RTp8DCQh6VcNy4ys/aqOrnr81tICVFfh3IsZXEVZ33gPv/TqqyzZujHj1g7dpidu2CadP+xNfXm1Wrvmf06NFKh1YrAgMD8fDw4OeffyYgIEDpcIQ7dcD//vvvkrW1Vho6VCOlpCh/TKo+puJipN69jccXy06dOyOdP19++ddfR1Kpyi83ahTS2LHyfUdH47J6PdLcuUhqdfnlNRqkhQvL1xxMmyY/Z2ODtH49kq1t+de0b2+MJTS08nijoqr/+ffuRXJ2rnx948eXX7bsMfN//hPJzq788l26ICUklH/NuXNIbdpUXLedHdLnn5df9plnjM9fvlz+OScneb6fn3HenY4LGwxIf/97xfccMQLJ07Pmx8xXrUJq2rTi+l1ckI4cuf/PX5vbwJ3+NtV5j/v5TqqzzZv7VFCANH26SlKpVNIHH3wgmYvZs2dLHh4eSochSFISlc09evSoZGtrJT33nFoqLlb+H6G+piVLjD84w4cjzZqF1LOncd6ECcZlf/7ZOF+lQho5EqlPH+Pj25P5ihXG5Zs1Q3rhhfI/7D/9ZFy25EdWpZJ/CIOCkGbMQOrQwbj8Cy/Iy86YgeTmZpzfoQNSjx5IsbHV//xt28rr8PCQf4Q//hgpJMS47u+/Ny5bNpkDUr9+8t+rSxfjvBkzjMtfvGhcP8h/q+HDyyeQ774zLl9byfzHH8t/T6GhSH37lo/9fpN5eLjxu1apkIYORRo0yJi8WrVCys+/v89fm9vAvZJ5Vd7jfr6T6mzzjWX69FMklUolrVmzRjIHhw8flgDp2LFjSofS2FWezIODg6SBAzWNKpFLEtLXXyM9+2z5JJSTY/zB7dnTON/HR56nViMdOmScv2qV8cfKwUGeV1iI1KKFMcHn5MjzdTqkdu3k+V5expZKyY8syDsJJes+d844v3dv4/xPPjHO//XX+/vsSUnGdTzzjByzJMktijlzkL79Vq7YLVm+bDIfNar8ekqSWd++xvlPPWVc/pNPjPNjYpAsLeX5Tk5IaWny/NpK5t7exvlbthjnl00095vM+/evfBt49VU5QXbogLRnz/19/trcBu6VzKv6HtX5Tqq7zTemacYMpBYtnKSsrCzJ1BkMBqlt27bSO++8o3QojV3FavazZ89y4EAECxYUY2Fx+7Pm7YUXYOVKWLZMPp65YQO8/bbx+Zwc+bZkXGeABx6A3r2Nyzz9NNw+2uOFC3BDvvAbQ4bI12u+eVM+rjl8uDw/JgaSkyvGNG2a8X6nTsaLzdy8ef+fszItWxqPsa9aJT8eORJWrIAXX4QpU+SK3cqUrQtwdQUXF/l+erpx/u7d8q2VFTz3nHF+167y8fiS5SMja+XjAPL3VHKsuFkzeOgh43PPPlt5DURVSZIx1sDA8tvAwoXysflLl2DgQHleTT5/fWwDtf0eNdnmzd38+fJFpjZt2qR0KDWmUql47LHH2LBhg9KhNHoVkvn5WxUu/v71Hoviiovl00t69oRWreRk9skn8shPYCwAS0iQC5kA2rSpuJ7b5507Z7y/bp38Q1kyffml8bnExIrrKkmMJUqKl0rev7aoVPKOTMlgPxkZ8s7Mq6+CuzsMG2YcJOZ2t18m2tpavi0okG8vXZKvQQ0waJBcVFhW2QFbKrtMsiSVf1xcfK9PI7tyxfh3Gjiw/LXt1erKv7uqunrV+Pnc3Mo/16RJ+eK/mn7++tgGqvse9/pOarLNmzsnJ3B313L27FmlQ6kVjz/+OCdPnuTSpUtKh9KoVahmb9euHSBfF7ixJfSxY+G33+T7AwbIyXzwYLly9/x5YzIoO9pZWlr5deTlVfxB1mqN9/38oFevyt+/JAmWZWVV/nFdjhY5cqRccbxiBWzZAkePGn/Mt2+Xn4+Orvi626u2b696d3WV/wY6XeU/3levGu87OVV8/vbzpkuS6L2UTai3r6O4WN4pu19lE3JW1t2Xrennr49toLrvca/vpCbbvLnLy4OEhGI63L4XbKIGDRqEo6MjGzduZObMmUqH02hVSObe3t74+nbl/ffPsX59LTf/GrCrV42JfPRouTVRIiNDvi1JUi1ayF20mZlw6JCc0Eu6qHfurPjDVnZkR3t7OVmWOH1aTgzt2lV+6ldVTgUsu4zBcO/lKyNJ8t8gLk7uUpe7AmHbNnjtNTnxnTold4u6ulZv3TY28g96ZKS8josXy/9NNm403vf1lW/LJuLMTOP9a9eqPihK8+bG7+noUflvU5KkwsPlU+/ul5OTvP7UVPnUq8JCY0LctAmmT5dPO5s6VW55V/fzl1Uf20BV3qM630lNtnlz99FHoNFY8cgjjygdSq3QarU8/PDDbNiwQSRzBVXY/1ar1XzyyX/4/XeJ+fMViEghZVtM2dnGbsQvvpB/sKF8C+zZZ+XbnBz5eOmKFfLx9aefrrhuT08oOQ1z/3746Se5xXv5snxueocO8o99UdH9xW5pabx/6pTci3Cv1uLtfvtN/nEdOlT+bPn5ciJ87DFj8ra2vv+L5gwebLw/fbrcDZuaCgsWGOsPBg40/p3Knoe8cqXckk5Lg5dfrt77jhol3167Bq+8Iv9dSt63psaNk29TUuT7R47AsWMwb5783W7aZGxpV/fzV1dtbAP3Up3vpK63eVO1fj3Mn6/ivff+hcvtxzZM2OOPP86+ffu4WdvFPELV3ak07ptvvpHUapU0ZYq69PQac57y8sqf3tO+vfEUHY1GvrW1pbTC//p1pG7dyp/iBEidOhlPQSp7atquXeVPQ2re3Fj1rdGUr4YuW2UcE1M+zpKY3N3Lr/v2OLZvr97n1+vl06pKXm9lJZ/eVFJpDXJVe8nydxubvbIYi4qQxoypGGfJ1KyZXEVdsnx0tBxDyfNNmyJZWMhnCJT8fatSzX71avnzwC0s5EpzjQapY8eaVbPfvInk6nrnzzR27P1//trcBqpSzV6V96jud1Kdbd7cJ4MBadEiJAsLlfTqq69I5iYjI0OytLSUvv/+e6VDaazuPDb7c889xx9/bOK335rg66tl27aq7RyYKhsbuWu9c2f58eXLcstp8WJYskSel5cnj7YFclf7X3/B88/LQ2S6ucmjaB04YKwELttaCgmBgwfl4jqNRl63paXcEl6zpnw1dHUNHCgfGihhaVn9LmS1Wm5J/u1vcrdoYSGcOCG3nJo3h6VLa9aa1WrlUcLeeKN8C8/KCp54Qu567dTJON/HB/7v/4xnBmRnyyPL/fUXdOlS9fdt3Voe6ayk/kOvl4sbN26Uq6xrwtlZHilw1Kjyx4htbWH2bPjvf43zqvv5q6s2toF7qe53UpfbvCk5exYeekjL229b8K9/LeTTTz9TOqRa5+DgwMCBA0VVu5Lule4vX74sPf74oxIgPfaYhXT0qPJ7uXU56fVIFy4gnTkj37/TcuHhcmsmL6/icyWtGk/Pyl+bny+3kCp7bU2mpCS59VRUVLP1FBUhXbqEFBmJlJhYN+cCp6TI563rdPde9uxZpNTUmr9ncnL51m9tToWF8t/+3DnjOfq19fmV2AZq+zupq22+IU/x8UgvvqiStFq11KtXDykyMlIyZ8uXL5fs7Oyk/Px8pUNpjCofNKYymzdvlgID/SSVCmn4cAtp8+a7Jztzn4YNM3Yf/v3v8g94QQHS2rXGrsSyI8aJSUxiahxTRATS00+rJEtLteTu3kZauXKlVFxcLJm7q1evSiqVStq8ebPSoTRGSSpJkqS7Nt1vs2nTJj766AN27/6Ljh21PPtsERMnysVTjcn//id3q5ewtpa7cEuqejUauZv6TgOt1LW4OPlUu6r64Qe5y7SxEn8voSbS0mDtWvjuOy0RETp69PBixozZTJ48GW3ZYzBmrmfPngQGBvJl2cEEhPqQfNerplVmxIgRjBgxgpiYGL744gs++uh73n47k/79NYwdq2PEiIqDiJijp56Sjyf/+99yZXLJ6WgqlXyM8IMPlEvkIMd28WLVly8srLtYTIH4ewnVlZoKW7fCunVqNm8GjUbLqFGjWbr0Zfr37690eIp47LHHWLFiBZIkoWqM5x0qqNot89vpdDq2bt3KmjXfs3nzH2Rn5+PjY8mIEUWMGCFfPtPch4XNypJPfbKwkHsobh+AQxAE83DihFwoummTlsOHi7GwsGDQoAE89VQYo0ePxr7siFKNUGRkJEFBQRw/fpwePXooHU5jklzjZF5WUVER+/btY9OmTWza9BvnzsXj7Kxl2DA9Dz9soF+/8oNJCIIgNGTXr8tnqGzfDps3a7lyRYerqzPDhz/GiBGhDB06tNEn8LIMBgNubm7MnDmTOXPmKB1OY1K7yfx2586d448//mDTpg3s33+QwkIdbm6W9OtXTHCwnNx79DD/lrsgCKYhNlY+ne6vv+DgQUvOni3CwkJNQEB3RowYyYgRI+jZs6foQr6LZ555hosXL7Jv3z6lQ2lM6jaZl1VQUMCRI0fYv38/Bw7s48CB/aSnZ2Nvr+GBB1QEB+sICpJHhWrVqj4iEgShMcvIkMcJOHoU9u9XceCABSkpxdjaWhEU1Iv+/QfTt29f+vbtS9OyY9kKd/XTTz8xceJEbty4gXPJONdCXau/ZH47g8FATEwM+/fvZ//+vzhwYA+XLsljqrq6avHzM+Dnp8ffXx7wo2PHur3IiCAI5uvqVYiKkpP38eNqoqI0XLokjyXbsqUzffr0o3//gQQHBxMQENCoKtBrW3p6Oi1atOCHH35g/PjxSofTWCiXzCuTlpZGVFQUx48fvzUdITb2HMXFeuztNXTvrsbPrwgfH3nsZy+v6l/0QxAE85WeLp9mGBMjT1FRFhw/riY1VYdKpcLdvRX+/kH4+fXEz88Pf39/WrdurXTYZmfAgAF4eHiwatUqpUNpLBpWMq9MQUEB0dHRZZJ8BDExcWRk5ADg4KDB01ONl1cRXbsak3zHjuWH2BQEwTwYDPJwyyVJOzYW4uK0xMTAjRvyQA82NpZ07dqJHj2C8PPzK50cHBwUjr5xWLhwIR9//DHJycmoRZdqfWj4yfxOkpOTiYmJIS4ujtjYWGJjTxMXd4bLl5OQJAmNRoWHhyVduujo0MGAuzu4u8vnwLu7g6Oj0p9AEIQ7yc+HS5fKT/Hxai5c0BIXp6OgQL7Oa8uWznh5eeHp6UPXrl1v3fekXbt2Ioko6MSJE/j5+REZGUmvO13MXqhNppvM7yQvL4+4uLjSJH/hwgUuXTrHpUsXSUqSB5MGcHLS4u5uQYcOOtzd9aWJvkMHaNNGvvynIAh1Iy8PrlyRJzlRlyRtDZcuqbh+3XiB9ObNHXB3b0+HDl3w8OiIp6cn3t7eeHp64ij2yhus9u3b89xzzzFv3jylQ2kMzC+Z301RURFXr17l4sWLZaYLXLsWT1JSIhcvJpUua22txs1NQ6tWBtzcimnVSr4ymocHpffbtZOHbRUEwSg9XR5EKSnJeHvxIly7piEpScO1axLJyYWU/PJYWWlp3doVD4/OeHh0wsPDo3Tq1KmT6Bo3US+99BInT54kPDxc6VAag8aVzO8lKyuLhIQErly5QlJSEleuXOHatWtcu3aFK1cukZR0nRs30kuXt7BQ0bKlljZtoEWLYlxcDLi6ypdHdXGRb1u2lO+7uIjEL5gmSYKUFHlKTYXkZLhxQ3584wZcv64mJUVDYqKKa9d0FBUZSl/r4NCENm1a0bp1O9zc2tG2bVtatWpFmzZtaN26NW3btsXFxUXBTyfUld9++40nnniC69ev07zkutBCXRHJvLoKCwu5du0aiYmJXL16tTTpp6amkpKSTFJSIikpKaSkpKHT6cu9tnlzS1q0UNO8uYGWLXW0bCnh7CxfF9vJqfLbstdEF4Sa0uvli4Kkp1d+m5YmJ+nr19XcuKEmJUVFSkoxer3xZ0KtVuHi4oCLSzNcXFri6toOF5cWuLm54ebmRps2bXBzc6Nt27bY2toq+GkFJWVnZ9OsWTO+//57cYpa3RPJvC6lpaVx48aNW8k9heTk5DL3k7hxI5H09DTS0tJJT88iP7+owjqaNLHA2dkCJycVzs4GnJyKcXaWdwIcHcHOTp7s7cs/trOTH9vbix4Bc5KeDjk5kJ0t32ZlQWamfL9kSk+XB0SRk7OW9HT1rYStJzOzuMI6tVoLnJ2b4uTkiLNzM1xcWtGyZStatmxJ8+bNcXFxoVWrVri4uJQ+FsVlQlX069ePrl278s033ygdirkTybwhyc/PJz09nbS0tNLbsveNtymkpaWQmZlJdnYOOTl5ZGfn33G91tZq7OwsaNpUjYMD2NlJ2NnpsbPTY20NNjbQpIncC9C0qZz8HR3lW3t7+cIxtrbyZGVl3EFwcpLXr1aLgsGcHOPlb7Oy5BZwerp8m5UlX5UtN1eu0i4oMC6fmSkvk5EBxcVyki4oUJOTY0FWlvpWopbIydGTk6O/4/vb2lphZ2eLnZ0tTk5OODo64+zcEmdnZ5ycnO56a2dnV09/JaGxee+99/j222+5fPmy0qGYO5HMzUlGRgY5OTmlU0ZGBllZWaWPs7Ozyy2Tm5tLXl42hYX5ZGdnUVysIyMjg+JiPVlZ2RQVFZObW1DtOJycjCf4OzqqKRnGumlT4zj89vaG23oMJJycKrYab+fgUL2RADMy4F5beFaWBXq9caWSJJGRYbxgQNl1ZGYaMBhKXle++7kqbGwssba2xM6uCVqtBkdHRywsLHBwcEKrtcLOzgEbGxvs7Oywt7fH0dEROzu70snR0RF7e/vSx02bNsXBwUG0lIUG6eDBgwQHBxMXF0eXLl2UDsecVf965kLD5ejoWCen6uTn51NQUEBOTg46nY7MzEyKi4vJzMwEoLi4mOzsbAD0ej1ZWVlASVLMKF1PerqxeDAzMxODwVgoVVRURG5u7l3jKC4uJj4+rcL8vLw8iov1NG1a8epVtrZNsbKyvut6W7SwxsbGpty8sgmyadOmWNzaC7Gzsysd6rNJkyZY3ipqsLGxwdraunQZvV7PqFGj0Gg0fPDBB4wcOVK0gIVGJygoCAcHB7Zv3y6SeR0TLXPB5M2aNav0Ij4NSVpaGnPmzGHFihWMGDGC5cuX0759e6XDEoR6NWrUKAwGAxs2bFA6FHOWLPrmBKGOODs789VXX7Fnzx4uXLiAt7c3ixcvprj43ocTBMFcDB06lN27d6PT6e69sHDfRDIXhDo2YMAATpw4wbx583j33Xfp1asXhw8fVjosQagXQ4cOJTs7W2zzdUwkc0GoB1qtljfeeINTp07h4uJC3759eemll0rrCwTBXHXu3Bl3d3d27NihdChmTSRzQahHnTp1YseOHfz444/8+uuvdO3aldWrVysdliDUqQcffFAk8zomkrkgKGDs2LHExcURGhrKM888w6OPPkp8fLzSYQlCnRg6dCiRkZHlzm4RapdI5oKgECcnJ7766iv27t3LpUuX6NatG/Pnz6eoqOJIgIJgygYPHozBYGDfvn1Kh2K2RDIXBIX179+f48ePM2/ePBYvXkxgYCCHDh1SOixBqDXNmjXD19eX3bt3Kx2K2RLJXBAagLIFcq6urvTt25ewsDDS0ioOkiMIpmjw4MEimdchkcwFoQHp2LEj27Zt46effmLbtm1069ZNFMgJZiEkJISTJ0+SmpqqdChmSSRzQWiAxo4dS2xsLOPGjWPKlCmMGDFCFMgJJm3AgAGo1Wr27NmjdChmSSRzQWignJycWLZsGXv37uXy5ct4e3uLAjnBZDk4OBAQECC62uuISOaC0MD169ePqKgoFi5cyNKlS+nVqxfh4eFKhyUI1RYSEiKSeR0RyVwQTIBWq2XmzJmcOHECNzc3goODCQsL4+bNm0qHJghVFhISQkxMDNeuXVM6FLMjkrkgmJCOHTuydevW0gI5Hx8fUSAnmIwBAwZgaWkpjpvXAZHMBcEElYwgV1IgN3jwYOLi4pQOSxDuytbWll69eomu9jogkrkgmChHR0eWLVvGvn37SElJwd/fXxTICQ2eON+8bohkLggmLjg4mGPHjpUWyImRtoSGLCQkhAsXLnDlyhWlQzErIpkLghkoKZA7efIkHh4eDBkyhLCwMDFAh9Dg9O7dG61Wy/79+5UOxayIZC4IZsTDw4MtW7awYcMGdu/eXVogJ0mS0qEJAgBNmjTBz8+PAwcOKB2KWRHJXBDMUGhoKNHR0YwfP760QC42NlbpsAQBkMdOEC3z2iWSuSCYqZICuYiICLKzswkICGD+/PkUFhYqHZrQyPXr14/o6GhxffNaJJK5IJi5nj17cujQIRYuXMiHH36Ir68vO3fuVDosoRHr378/kiSJkQxrkUjmgtAIaDSa0gK5Tp06MXToUFEgJyjGxcWFzp07i+PmtUgkc0FoRNzd3dm8eXNpgZynpydff/21KJAT6p04bl67RDIXhEYoNDSUU6dOMWnSJKZNm0ZISIgokBPqVXBwMBEREWKQo1oikrkgNFIODg6lBXK5ubl0796dN998UxTICfWiX79+5Ofnc/ToUaVDMQsimQtCIxcQEEB4eDhLlizhP//5Dz4+Pvz5559KhyWYuS5duuDq6iq62muJSOaCIJQWyMXGxtK9e3ceeughwsLCSElJUTo0wYz17dtXJPNaIpK5IAilWrduzbp169iwYQN79uwRBXJCnQoODmb//v0YDAalQzF5IpkLglBBaGgoMTExvPjii0ybNo1BgwYRExOjdFiCmenXrx9paWmi+LIWiGQuCEKlmjRpwqJFi4iMjCQ/P58ePXrw5ptvUlBQoHRogpkICAjAzs5OdLXXApHMBUG4K39/fw4ePMiSJUv4/PPP8fX1ZceOHUqHJZgBjUZDUFCQGDymFohkLgjCPZUtkPPz8+Ohhx5i3LhxokBOqLH+/fuLlnktEMlcEIQqc3Nz4+eff2bjxo0cPnwYT09Pli1bJgqYhPsWHBzMxYsXuXr1qtKhmDSRzAVBqLayBXL/+Mc/GDRoEGfOnFE6LMEE9enTB41Gw8GDB5UOxaSJZC4Iwn2xtbVl0aJFHDlyhMLCQvz8/ESBnFBtdnZ29OjRQxw3ryGRzAVBqBE/Pz/Cw8NZvnw5X3zxBT4+Pmzfvl3psAQTIi66UnMimQuCUGNqtZoXX3yRmJgY+vbty7Bhwxg3bhw3btxQOjTBBAQHB3PixAkyMzOVDsVkiWQuCEKtcXNzY/Xq1WzcuJGIiAhRICdUSf/+/dHr9Rw+fFjpUEyWSOaCINS60NBQzpw5w0svvcTs2bMZOHAgp0+fVjosoYFydXWlffv2IpnXgEjmgiDUibIFcjqdDn9/f2bOnElubq7SoQkNUFBQEJGRkUqHYbJEMhcEoU716NGDgwcPsnz5clatWkX37t3Ztm2b0mEJDUxgYKBomdeASOaCINS5kgK52NhYgoODefjhhwkNDSUxMVHp0IQGIigoiBs3bnD58mWlQzFJIpkLglBvWrVqxerVq/njjz+Ijo7Gx8dHFMgJAPTq1QuNRkNERITSoZgkkcwFQah3I0aM4MyZM8ycOZPXX3+dAQMGcOrUKaXDEhTUpEkTvLy8xHHz+ySSuSAIirC1tWX+/PlERkai1+tLC+RycnKUDk1QSFBQkGiZ3yeRzAVBUFT37t05ePAgK1eu5IcffqB79+5s3bpV6bAEBQQGBnLkyBGKi4uVDsXkiGQuCILiVCoVYWFhnD59mn79+vHII48QGhoqrqTVyAQFBZGbm0tMTIzSoZgckcwFoQomTJjAkCFDlA7D7Lm6urJ69Wo2bdrEqVOnSgvk9Hq90qFVS2pqKqtWrSp97OTkxOLFi5ULyET4+vrSpEkT0dV+H0QyFwShwRk+fDhnzpxh1qxZvP766wQFBXHkyBGlw6qyl156ibVr15Y+njhxIr6+vgpGZBo0Gg3+/v6iCO4+iGQuCEKDZGNjw/z58zly5AhWVlb06dPHZArkDAYDKpWq9PHy5csZPny4ghGZDjES3P0RyVwwK99++y0BAQHY29sTFBTE77//Xu4OKesvAAAgAElEQVT5gQMHsn37dl599VXatm1L27ZtmT17NjqdrnQZg8HAP//5T3x9fWnXrh3vvvuuOA9aQb6+vhw4cICVK1eyZs0aunbtyvr16+97fStWrGDQoEG4uLgwefJk9u7dW/qcXq/nk08+wdvbu3Qb+vXXX8u9/l7b0IwZM9izZw/79++nV69eJCUlERISwn//+98qrwOgT58+/PTTT+Xe+6233uKll14qN+9e27ypCQwMJDo6mvz8fKVDMS2SIJi4mTNnSsHBwdLSpUslCwsLafz48dK6deukGTNmSCqVSlq/fn3psk2bNpXatGkj9e3bV/r888+lF154QQKkJUuWlC6zYMECycbGRvrwww+ltWvXSr169ZKsrKykwYMHK/HxhDKSkpKkyZMnS4D06KOPSgkJCdV6/XfffSdpNBpp7ty50vr166XHHntMatq0qZSamipJkiS9/fbbkkajkd5++21pw4YNpdvHqlWrStdxr21o+/btUkBAgNS9e3fpu+++k7KzsyVHR0dp0aJFVV6HJEmSpaWl9Omnn5aL/8knn5QGDRpU+rgq27ypuXDhggRIBw4cUDoUU5Ikkrlg8mbOnCk98MADkoODg/T000+Xe27s2LFS586dSx83bdpU6tmzp2QwGErn9e7dW3rwwQclSZKklJQUycLCQlq2bFnp82lpaVKTJk2kkJCQuv0gQpXt2rVL8vT0lBwcHKRPPvlEKi4uvudrdDqdZGNjI7355pul8/Lz86W2bdtKS5Yska5cuSJptVrpX//6V7nXPfXUU5Krq6tUVFQkSdK9tyFJkqSRI0dKw4cPL31cWTK/1zrulcwzMjKqtM2bohYtWkgff/yx0mGYkiTRzS6YhZycHDIzMwkMDOTo0aOlk7e3N+fOnSM1NbV02ZCQkHLHMzt37kxWVhYA0dHR6PV6Ro0aVfq8k5MTw4YNq78PI9xTSEgIUVFR1SqQO3v2LPn5+YwdO7Z0nrW1NZcvX2b27NkcP34cnU7H5MmTy70uLCyM5ORkLly4UO7977QNVecz1GQdx48fr/I2b2p69eoljptXk0bpAAShNhQWFgLwyiuvVPp8fHw8zZs3B8DFxaXcc9bW1qXHxM+ePQvIp0iV1bp1a9LT02s1ZqFmSgrknnrqKaZOnUqfPn2YNm0aCxYswN7evsLyJecut2rVqtz8koR66dIlVCoVbm5u5Z5v06YNAImJiXTt2hW4+zZUVTVdR3x8PFC1bd7UBAYGsmbNGqXDMCmiZS6YBY1G3i/966+/yM3NrTAFBASULlu2NXS7kh/u2xO3KVRQN1ZdunRh586dpQVyXl5erFu3rsJyDg4OAGRmZpabn56ejk6no1mzZkiSREZGRrnnb968CYCHh0fpvLttQ1VVlXUUFRWVe5yWloYkSYDcYwRV2+ZNTVBQEBcuXCj92wv3JpK5YBZsbGwA2LhxI7a2tqXT2rVrmTp1arkq4bvx8/MD5B/IEpIkiUEsGriyI8gNHjyYsWPHEhoaSkJCQukynp6eqFSqCtfMHjJkCFOnTsXb2xuAPXv2lHt+z5492NnZ0aFDh2rFU9MzIOzs7EhLSyt9bDAYiIuLK33s5eUF1Hybb4h69+4NILraq0Ekc8Es2NjYMHbsWL799ls+//xz0tPT2bFjBzNmzKBNmzZYWVlVaT2tW7dmwoQJvP7660RFRZGQkMCLL77I6dOn6/gTCLWhZcuWrF69ml27dnH+/Hm8vb1ZvHgxer2etm3bMn78eObOncuqVau4efMmy5Yt4+TJk8yZMwc/Pz8efvhhZs+ezaFDhygsLGTjxo18+OGHTJ06tVqtcTs7O2JiYvjrr7/u+xQrf39/vvnmGw4fPkx8fDzTp08nKSmp9PnOnTvXyjbfEDVr1gx3d3exE10NIpkLZuPrr79mxIgRzJw5E2dnZ55++mmefPJJ3nnnnWqt59tvv6VXr14EBwfToUMHYmJimDx5cq10rQr1Y9CgQRw7dozZs2fz7rvvEhgYSGRkJJ9//jn9+/fn+eefp3nz5rz11lt8+OGHdOrUCYDvv/++9Lu3sbHhhRde4OWXX2bJkiXVev+wsDDS09MZMGDAfSekjz/+GGdnZx544AE6depERkYGs2bNKrcd1tY23xCVfGdC1aikkgMwgmCiZs2axZEjR9i/fz8gH2dMTEykQ4cONUrA+fn5ZGZmViiGE0zLuXPnePnll9m9ezfPP/88S5cuRaPRkJiYSLt27bC0tKzwmvz8fJKTk3F3d7/v95UkifT0dJydnWsSPomJiTg4OGBnZ3fHZWprm29Ili5dykcffcS1a9eUDsUUJItkLpi8WbNmsW3bNubOnVsv7/fEE0+UHqMXTIMkSbz//vuliXzSpEkEBQUpHVad69WrV2kFvqnZuXMnDz74IElJSWKH+t6SxalpgllITk5m6dKl9fJew4YNE8ncxKhUKmxsbGjfvj1JSUl89tlnNG3alNatW1faMjcXr732mskm84CAAFQqFVFRUTzyyCNKh9PgiZa5YPJu72YXhHvZu3cvU6dOJSEhgXnz5jF79mwsLCyUDku4Tfv27XnppZd46623lA6loUsWBXCCIDQ6AwcO5OTJk8ybN493332XXr16icrpBsjf35+oqCilwzAJIpkLgtAoabVa3njjDaKjo2nevDl9+vThpZdeqvawrELdEcm86kQyFwShUevcuTPbt2/nu+++49dff6Vr166sXr1a6bAE5GR+8eLFCqP2CRWJZC4IQqNXMoJcXFwcoaGhPPPMM4SGhnL58mWlQ2vU/P39kSSJEydOKB1KgyeSuSAIwi1OTk589dVX7NmzhwsXLuDt7c38+fNNemhUU9a2bVuaN28uutqrQCRzQRCE2wwYMIATJ04wb948Fi9eTGBgIIcOHVI6rEbJz89PJPMqEMlcEAShEmUL5Fq0aEFwcLAokFOAKIKrGpHMBUEQ7qJTp05s376dH3/8URTIKcDf358zZ85QUFCgdCgNmkjmgiAIVTB27Fji4uIYO3YsU6ZM4dFHHyU+Pl7psMyev78/xcXF4sqF9yCSuSAIQhU5OTmxbNky9uzZw6VLl+jWrRvz58+nqKhI6dDMVpcuXbCzsxNd7fcgkrkgCEI19e/fn+PHj5crkAsPD1c6LLOkVqvx9fUVyfweRDIXBEG4DyUFcqdOncLV1ZXg4GDCwsJIS0tTOjSzI4rg7k0kc0EQhBro2LEj27Zt46effmLbtm1069ZNFMjVMn9/f06ePIler1c6lAZLJHNBEIRaUFIgN27cOKZMmcLgwYM5e/as0mGZBX9/f3Jzczl37pzSoTRYIpkLgiDUEkdHR5YtW8bevXu5ceMGfn5+okCuFvj4+KDVakVX+12IZC4IglDL+vXrR1RUFAsXLmTp0qX06tWLgwcPKh2WybKyssLLy0sk87sQyVwQBKEOaLVaZs6cycmTJ3Fzc6Nfv36EhYVx8+ZNpUMzSd27dyc6OlrpMBoskcwFQRDqkIeHB1u3bmXDhg3s2rVLFMjdJ19fX06dOqV0GA2WSOaCIAj1IDQ0lFOnTjF+/HimTJlCSEgIcXFxSodlMnx8fLh69ao49e8ORDIXBEGoJyUFcvv27SM1NRV/f3/mz59PYWGh0qE1eL6+vgBiWNc7EMlcEAShngUHB5cWyH344Yd0796dXbt2KR1Wg9a2bVscHR3FcfM7EMlcEARBARqNprRAzsPDgwcffJCwsDBSU1OVDq3B8vHxEcfN70Akc0EQBAW5u7uzZcsWNmzYwO7du/H09OTrr79GkiSlQ2twfHx8RMv8DkQyFwRBaABKCuQmTZrEtGnTCAkJITY2VumwGhRfX1+io6PFjk4lRDIXBEFoIBwcHFi2bBkRERHk5OSIArnb+Pr6kpmZSWJiotKhNDgimQuCIDQwAQEBHDp0iEWLFvHhhx/i6+vLzp07lQ5LcT4+PgCiq70SIpkLgiA0QCUFcrGxsfj6+jJ06NBGXyDn5ORE69atRRFcJUQyFwRBaMBat27NunXr2LBhA3v27Gn0BXIlx82F8kQyFwRBMAGhoaFER0eXFsgNGjSImJgYpcOqd2JY18qJZC4IgmAiyhbI5eXl0aNHD958881GVSDn4+PDmTNnKC4uVjqUBkUkc0EQBBMTEBBAeHg4S5Ys4fPPP8fHx4c///xT6bDqha+vL4WFhZw/f17pUBoUkcwFQRBMUEmBXExMDD169GDo0KGMGzeOlJQUpUOrU97e3mg0GnHc/DYimQsmJSMjg4sXL5abMjMzKSgoqDD/+vXrSocrCHWudevW/PLLL2zcuJFDhw6ZfYGclZUVHTt2FMfNb6OSzPUbF8zS9u3bGTZsWJWWXbBgAXPnzq3jiASh4cjNzeX9999n6dKl9O3bly+//BJvb2+lw6p1Y8eORa/Xs379eqVDaSiSRctcMCmDBw/G2dn5nsupVComTJhQDxEJQsPRpEkTFi1aRGRkJAUFBfj5+fHmm29SUFCgdGi1ytvbu1FW8t+NSOaCSdFoNDz11FNYWlrecRmVSkXPnj3x8PCox8gEoeHw9/fn0KFDLF++vLRAbseOHUqHVWu8vLy4cOECRUVFSofSYIhkLpicCRMm3PWf2MLCgrCwsHqMSBAaHrVazYsvvkhsbCz+/v489NBDjBs3jhs3bigdWo15eXmh0+m4cOGC0qE0GCKZCyanT58+tGnT5o7PGwwGxo4dW48RCULD5ebmxs8//8zGjRs5fPgwXbt2ZdmyZRgMBqVDu2+enp5YWFiIrvYyRDIXTI5KpWLy5MlotdoKz1lYWDBw4EBcXV0ViEwQGq7Q0FBiYmJ48cUX+cc//sHAgQM5ffq00mHdF2tra9q3by+SeRkimQsmadKkSeh0ukqfmzx5cj1HIwimwdbWlkWLFnHkyBGKiorw9/dn5syZ5Obm3vV1Z8+eJS8vr56irBovLy+RzMsQyVwwSd7e3nh6elaYr1arGTVqlAIRCYLp8PPzIzw8nOXLl7Nq1Sp69OjBtm3bKl3WYDDw1FNP8eyzz9ZzlHfn5eXFmTNnlA6jwRDJXDBZYWFh5braNRoNw4cPx9HRUcGoBME0lC2Q69u3Lw8//HClBXJffvklUVFRrF27lqVLlyoUbUVeXl7ExcWZ9LH/2iSSuWCyJk6cWO5iCwaDgUmTJikYkSCYnlatWrF69Wp+//13IiIi8PT0LC2QS05O5o033sBgMCBJEq+//jpbtmxROmRATuZ5eXkkJCQoHUqDIEaAE0xaYGAgR48eRZIkbGxsuHnzJjY2NkqHJQgmKS8vjw8++IB///vfBAUFYWtry549e0rrU9RqNXZ2dhw7doyOHTsqGmtGRgZOTk5s3ryZRx55RNFYGgAxApxg2sLCwrCwsECj0TBmzBiRyAWhBmxtbZk/fz6HDx8mJSWFHTt2lCs0NRgM5OfnExoaes+iubrm6OiIq6urKIK7RSRzwaSNHz8eSZIoLi5m4sSJSocjCGaha9eu5Ofno1ZXTBE6nY7z588zadIkxS/mIirajUQyF0xaixYtGDBgAE5OTgwZMkTpcATBLLz33nskJSXdsbhMp9OxYcMGlixZUs+RlSeSuZFI5oLJmzx5MhMnTkSj0SgdiiCYvOjoaJYuXVquuLQykiQxZ86cO57SVh+8vLxMduCb2iYK4IQGIy0tjYyMDDIzM8nJySE7O5vs7GwyMzPJyspCr9ej0+nIyckpfY1OpyMtLY3MzEzatWuHtbV16XM2Njaljx0dHbG3t8fe3h47OzuaNm2Ko6MjdnZ2uLi4VNqdKAiNjcFgoH///hw8eBCtVnvHgZlK1HVBnE6n4/r166Snp5dOGRkZpKenU1hYyPnz54mIiGDo0KEYDAZyc3NRq9U4ODiUrsPBwaF0npOTE46Ojjg5OeHk5ETz5s1xcnKq9bgVkCySuVDnsrKyuHTpEvHx8cTHx3PlyhVSUlJIuZFM0rUr3LiRQkpqOrpifYXXqlTgaKfF3kaFRq1CrQaHMjVuarWEg428CecWqigqVpU+l1MIumKQgIxcA9l5xRTrK27uarUKl2aOuLg0p2VLN1zd2uDi4oKbmxsdOnQonVxcXGr9byMIDc21a9c4cOAA+/fvJzw8nGPHjqHX67G0tKS4uLhC17tWq6V9+/YcPXqUpk2bVuu9JEkiPj6euLg4YmJibv0+XCYx8TJXr14lOfkmBkP5/1kbGwucnCywtlZhZQW2tvJ8jUbC3l6iuBiys9W31g8ZGfLzGRkG0tN13J7xbG2taNfOjdat29GmTQfatWtHp06d8PLywtPTs9qfSSEimQu1o7CwkNjYWGJiYjh16hRxcbFcPB9HfPxl0jKyS5dzdbakjbOKlk2LcbHT4+oILR3AxR5cHcHRFhxswc4K7KzlqTYV6CA7H7ILICMPcgogOQOuZ0JK9q37WWpScjRcTYNrN3Xob/2YNLG1xr1DW9w9uuDZ1QsvLy98fHzw8vLC3t6+dgMVhAYiOzubw4cPc/DgQQ4cOMDBgwfJycnBwsICtVpd2nofNWoU69atQ6VSVbqe3NxcoqKiiIyM5OjRI5w5c5y4uAvk5RUC4OpqSceO0Lq1jtatJdq1gzZtwM0NnJzkydERrGv4m5CRIU/p6ZCSAomJkJAg3yYmWpCQoOHcOR2FhfJOS5s2Leja1Zvu3QMIDAwkMDBQ8dPyKiGSuVB9aWlpREREEBkZSdSxo5yKPsHF+AT0egNajZpOrSzxdtPh3lyPuwt0uDW5u4DNnS9D3iAVFcOVmxCfCpduyLcXb0BcspaYRD35t/7h27dxpat3N/wDAgkKCiIwMPCuV3YTBFNlMBiIjY0lPDycgwcPsnfvXi5evIgkSfz73/9mzpw5AFy/fp1du3axe/duDh/ez+nTcej1BlxcLOnVS8LHR0fXruDtDZ6ecrJuKPR6iI+HmBh5io2FY8e0nDpVTHGxhLOzPYGBgfTrF8LgwYMJCgpSumZHJHPh7gwGAydPnmTv3r1ERBwm4tABzl+UR1zq0NKKQHcd3m4GurUBr9bQxRUsG0kdmkGSE/zpRDhzVb49dllDbKIeg0HCzbU5gUEPENS7D/3796d3795YWprY3owgVEFaWhr79+/n559/xsrKioiIA5w6FYdGo6J3bw19+hQRGAiBgdChg9LR3r/8fDh+HCIjITJSxZ49Gq5e1WFvb8PAgQN58MGHeeyxx3B3d6/v0EQyFyqKiYlh9+7d7Nr5J3t27+RmehbNmmoJ8jAQ5KEn0AOCOoKLSRxKqn/ZBXD0EkRcgIgLaiIuabiSUkQTW2v69QsmZPBQBg8eTEBAABYWFkqHKwj3LT8/n23btrF+/Tp+//03MjJy6NHDkiFDihgyBAYMADs7paOsW3FxsHMn7NypZvduNenpxQQE+DJ69HhGjx6Nl5dXfYQhkrkAer2e8PBw/vjjD9b/8n+cu5BAE2sL+nSGB7vpedAH/DuAuvJDYUIVXEuHA2fhz1NqtkTLyd3J0Z4Hhw7j0UdDGTVqlDjuLpiMiIgIvvlmBT/+uIbc3AL69tUwerSO0aOhfXulo1OOTge7d8P69fDbb1quX9fh59eN559/mYkTJ9blRaBEMm+s9Ho9W7du5Zdffub3jb9xMy0Tn/ZWjPQvZIQ/9HIHjWg01pnTV2HLCfjtmIbws3qsrSx56KGhjH5iHKNHj6ZJkyZKhygI5eTm5rJq1Sq+/vo/nDwZQ7dulrzwQhHjx4Orq9LRNTwGA+zfD999p2LtWjWSZMGYMWOZPv1VevfuXdtvJ5J5YxMbG8uqVav4/r/fknQ9hT5dtIwM0DEqEDq1VDq6xul6Jmw8Br8dteDPUxJWVlaMGz+BKVOeJTg4WOnwhEYuPT2d5cuX8+mnH5KXl8OTTxp4/nmJPn2Ujsx0ZGXB//4HK1ZoOXZMx+DBA5gz5x0efPDB2noLkcwbg+LiYn755Rc++/RjDoZH0M7Fkmf6F/F0f/BooXR0Qlmp2bDmAKzar+X4JR2end15efpMnnvuOezM/eCj0KBkZ2ezaNEiPvvsEzQaHa+8omPGDGjeXOnITNuuXfDvf1uwc6eeoCA/Fi36iJCQkJquViRzc5aXl8e3337LR0sXk3AlkSd6q3lhkJ7B3cTxb1MQFQ8r98CqvyywsrZl2iszefXVV2nRQuyBCXXHYDCwevVq3nrrNQoLM3jzzWKmTgVR0lG7IiNh/nwLNm/WM3r04yxZ8hEeHh73uzqRzM1RUVERn332GYv+vYC8vGymDDDw90ck0Qo3UWk58J8d8NkOLTmFKl6aOo133nkHZ2dnpUMTzExsbCxPP/0Ux46d4MUXJf75T4lmzZSOyrxt3Qp//7uWS5dg7tx5zJkz537OchHJ3Nz8+uuvvD77byQmXmXWMD1/e0ScQmYu8ovklvr7GzToVba8+94Cpk6dilarVTo0wQx8+eWX/OMfs/DxMfDNNzp8fZWOqPHQ6WDZMnjnHQt69uzFDz/8SIfqnZAvkrm5SEhI4NkpYezavZcn+6hZ9KSBdmKP2ixl5sG/NsCn29R4eHiwavUagoKClA5LMFF5eXlMmjSBjRt/5803Jd59F8T+oTKio2HiRC0JCZZ8//3/ERoaWtWXJotLRZmBX375Bb8ePiSdC+fgfPjfdJHIzZmDLXwwAc58YKCNVTz9gvuycOHCO157WhDu5ObNmwwZMpC//trCrl0SCxaIRK4kX1+IiNAxZkweo0aNZMWKFVV+rWiZmzCdTscrr0zj66+/4eUHVXw4UTK5sc+FmpEk+HgLvLVWTd++ffl53W80Ewc5hSq4du0aQ4YMoLAwgS1bdHh6Kh2RUNZ778nTggULeOutufdaXHSzm6qCggLGjxvDrj+38v1UPSN7KR2R6dkTA+m5oLWAR/2VjqZmouJh9DItds092P7nblq1aqV0SEIDlpuby8CBfcnNjWHXLh3mtLlER8P58/L9IUPANK5gWrkvvoDp0+G771bx9NNP321RkcxNUW5uLo+FjiDqyAE2zy7mgU5KR2SaAt+BIxfB3hqyViodTc1dTYOhi7XotK3YuXsf7RvzuJrCHRkMBsaMGcX+/Vs4dEjH/Z8NpazMTLnlOngwPPqocf6sWXIxGcDJk5h8Id9bb8GHH2r4889d9O/f/06LiWPmpuilF18g+thB9rwlErlg1MYZ9s3VYSclMerxRykoKFA6JKEB+u677/j99z/49VfTTeT79kHnzvDxx3IluDlbsABGjJAIC5tAfn7+HZcTydzErFy5kv/78Ud+eFlH93ZKRyM0NC5NYePfdVy+GMvs2f9QOhyhgcnKyuLtt9/g1VclTHmk4KgoSEmR76tuGwBr1iwID5enjh3rP7baplbDF1/oyci4zqJFi+64XCO58rR5uHLlCjNenc4bj0o8ZOJdR5U5mSAfx45Pga5uMKCrfFvW4fMQmwQaNUwMlpfdHg1xSdCtDYwOBEfbius+fF5ed0Ye9OkMoSZ+jPxu2jWDr54tZtynX/D44yMZOnSo0iEJDcTixYuRpCzefbf+jq4WF8Pvv8vXAU9NlS+J6uUFo0aBg0PF5a9dgz//hFOnwMICPD1h3DiwvfV/vWsXREQYl9+9W+5yDw0FZ2c5ycfFyc95ehpfV0Kvl3cG9u2D69fBx0fuqm/duvxyhw9DbCxoNDBxIsTHw/bt8rq7dYPRo6HuLoJWXsuW8O67xcyZs5Dp06dXOgqkOGZuQqZNe5kt61YSt0SHpRnthhkkmPcLLNwg3y+hsYD3x8Aboca97+mr4PMdYGMJa6bDpP9AXpHxNe2bw863oOOti8ZIEsz+H3y0ufx7jvCH88nyToC5HDO/XeiHFqRY9OBQxFGlQxEaAEmS8PBow+TJ1/jnP+vnPfV6CA6WE+PtOneGLVvKt57/+1+YMUO+MElZLi7ysj17wmOPyTsHt4uKAj+/ux8zP38eQkLg6tXyr7Wzgw8+gJdfNs6bPh0+/xxsbGDNGpg0CfLyjM+3by9fx7y+Wv8FBeDqquFf//qE6dOn3/60OGZuKvLz81nzw2pmDjOvRA7w7R74129yIm9mBy+EyMd/i/Uw5yf4uZIfggIdjPkEfNrCjGHQwUWefzkVFpf5R1972JjIVSoIDYC+XWBTlJzIzdlrI/QcjjxGdHS00qEIDcBff/1FfPw1Jkyov/f8+GNjIh8+XE60PXvKj8+dg3feMS576BBMmSIncpUKhg6FQYPkbuaUFLnlXVAA7u7gVqbHrkMH6NFDTrp3c+mS3AIvSeR9+sgx2dpCTg5MmwarVlV8XUEBjBkjt+BnzJDfD+DyZVi8uPp/k/tlbQ0jR+pZs6aSIBHd7CYjPDycrOw8nghUOpLaVVQMc9fK9x1t4fKn0MRKTuQd/wYJN2H+ehjbu/yxMUmCx3vBr3+TH786DDr/Xb5/8opxuX+uN97f/Bo83EO+/81ueOGbuvtcDUF/T2jppGXbtm34mnpJr1Bjhw4don17S7y8iu69cC1xcIBnn5VbviWt5dxcaNFCbuWePWtc9vXX5f9rtRoOHoSSS37PmAHLl4OVlbxjsGwZeHjIOwYg7zCMHHnvWN5+G67c+m345BOYOVO+Hxsr7wwUFcHf/w6PPw5OTsbXSZI879df5cevvir3KoDc8q9PDz8s8b//RaHX6yuM3y5a5iYiOjqalk5a2prZeCAXrsONW11qQ3zkFvfNHMjMh+F+8vyYREjOrPjaaWUuBdypJTS/dVWnm9nyrU5vbH03s4OHuhuXf3aQPJKaOVOpoGcHAyfr+xdHaJASEhLo0KF+j6q+8AKsXCkn4OvXYcMGOamWyMmRbyVJvooYQGCgMZEDLFwIGRlyy3rgwPuPZfdu+dbKCp57zji/a1e56x0gPd0YR1nTphnvd+pkvAzszZv3H8/9aN8edDo9SUkVuxVFy9xEZGZm4mxnfvte5z5vpRIAAA7mSURBVK4b76+LkKfKJKZBq9uKTW6/gIztrdHv9LdGNb1y03h/oFf5y76qVXJXfmYeZq1ZEz0Z6WlKhyE0AMnJSbRsWb/ncRUXy13R69fLx7Rvr9Aq6W27elXuzobyXegATZrUPI5Ll6Ak/w0aJPcUlPXoo7Btm3z/9Gl46KHyz7u4lH9cUlSn19c8tuooGdzn2rVrtGnTptxzIpmbCDs7O7Lzza9WUVump8ivPfS6w3mv1pUMU2t129arvm1fp2mZY2i62/7pivWQkFr1OE1VVoEaO3sTHgJLqDXNm7tw/rwWqL+EPnYs/PabfH/AALk7fPBg+Rj0+fPG/9myyfX24rfa4Ooqjzmv00FiYsXnyxbEle1iL2FlVf7x7b819SX11m+Wy+17F4hkbjI8PT1JvFnEzRy5y9hclL3Gur01rHje+Pj0VbCzlk+1uv1cUqh8XlnN7eWu9Mw8OHpJLrAraZ2Hn4fsRjCmysmrGp4J7ap0GEID0LZtW3bvrr8sdPWqMZGPHg3r1hmfy8iQb0v+h52c5K7r1FT5OHRhoTGBbtokV5b7+MDUqXIruuz/flWuL2RjI1e6R0bKp7xdvEi5AXM2bjTer6y85F6/NfUlIQHUahWtbz+PDnHM3GQEBwdjqdXy+zGlI6ldnq0goIN8f/9Z+OmQ3DV+ORWC34MOM8HvLblQ7n6MujVm/bV0eGUVZOVDajYs+LU2om/YTibApeQihgwZonQoQgPQo0cPzp8vqnBaVl0p2wLOzjZ2sX/xhbGFWbYVPm6cfJuSIt8/cgSOHYN58+TK8U2bjK1myzI9dadOya38e7XoBw823p8+Xa6mT02VR1iLiZHnDxwIAQHV/6z1Ze9e8PbujKVlxa5KkcxNhKOjIyNHjuTT7doKx51M3dKJ8vFuSYInPwPXaeAxS25Rayzg6+e479PxFowzdrd/8Sc4vwgtXoZdZ4znopurZdvUdOnkTt++fZUORWgAhg0bhpOTPT/+WD/v17278fj3jh3yKWXu7nIxmebW//PNm8bjzu+/L3eHg9xSDgyUT2M7dqsBM3YspaPWlb3C27vvytXllZ3LXtb778vd+wBbt0KXLvKx8JLT45o1g2++aTit8Nvp9fDTT1qefDKs0udFMjchc99+h5MJer7apXQktSvEGw6+Bz3d5eSdmi0n76G+sGYa9K7B+POtneDwP8G/g/xYb5AL6Tb+A4Z0q5XwG6Twc7D6L3h73nuoGuqvk1CvtFotY8dO4OuvtRTVw9lpNjZy13rJaVyXL8st4cWLYckSeV5enjyiG8ijtx0/Lo8MV/aa6ra2MHu2PKBMiYED5a77EpaWcuv/brRa+PFHeOMNuYK9hJUVPPGEXPjWqQFf62LtWkhJKWbCHQYKECPAmZh3332XDxb9i/D5evzM8KJYBTo4lyyfalbb12a/nikfJ+9k5i3y9FwIeFuLd88Q/ti0VSRzodSVK1fw8urCO+8U8MYb9fOeBoM8FGphodyirkrxWFGRfA66tTW0a1e+W72s5GR5B8HTs/wOQFWkpsKNG3ILXdPAq8fy8sDbW8tDD4Xx9deVDpAhLoFqavR6PUMGDyTpfAR75+pwraexgQXTUKiDkZ9YcDrFhagTp2jWzMwGJhBqbMGCBSxePJ+oKH2DbokKRjNnwg8/NCUu7gLNS05yL08kc1OUlJREyMB+GHKv8OebOtrVw+919zertlxcklys5tu2asv/MI0GcfW3uCQYu6zqyzbEz5hbCKM+seDIZVu27dhJYKCZDRco1IqCggL69+9DdvYZwsOLKj0VS2g4Vq6EF15QsWbNmjt2sQPJDbxzQahMq1at2PvXQYY9NIT+759l02wdPm3u/bqauHijasuVVJ1XdfnC+6xSr21Fxab9GW9kwehlGs6l2rNrzy78/Pzq/k0Fk2Rtbc3GjZvp3TuAMWNS+eOP4nuOay4oY8cOePllNW+/PfduiRwQx8xNWnp6OiMff5TIiMMsmaBn2oMNtxJTqDtbT8CUFVpsmrZk89YddO0qzisX7u3EiRMMHjwAb+88NmwoxtlZ6YiEstauhbAwNWPHjmf16jX3qn0RV00zZU5OTuzctZfX33ybmd+refxjC5IylI5KqC+5hTDrexi+BIY8MobjJ0+LRC5UWY8ePdi//xAJCS70768lPl7piIQSH38MEyaomDr1Ff773x+qVMQqWuZm4sCBA0ye+CQpN5KYE6rnb4/UfjW40DAYJPhhP7z1s5YcnSXL//MlkyZNUjoswUQlJiYyYsRDXL58li++KObJJ5WOqPFKTYUXXrBg40YDixYt5rXXXqvqS0XL3FwEBwdzOuYsb859j4WbbPB6Q8v/DhovNCKYhz0x8MB8Dc+uUPPomCmcPXdRJHKhRlq3bk14+BEmTZrKU0+pCAtTk56udFSNz9at0KOHhqNHXdi1a3d1EjkgBo0xKzY2NsydO5e4s+cZPOIpJn+hwvM1LV/uhPz6u4SxUMsMEvx6BPq8pyVkATi070dU1HG+/PIrWrRoce8VCMI92NjY8Nlnn/HHH3+wfbsjXbpo+OKL+r8qWGN04QKMGmXBI49A//6jOHHiDAPv41qvIpmbITc3N779dhWxsXE8+PgU/rbGkg5/0/L+r5Ao9rhNRmYefLkTvN/QMmaZClevhzlw4AA7/tyNb2VXgxCEGho+fDhxcRd5+umZzJqlISDAki1bKl66VKi51FR5NLpu3dScPevBtm3b+PHHtTjd57mC4ph5I3D9+nU+++wzvvpiOekZWTzUw4Ip/Yt5LACsqjlqklC3DBLsOQPf7VOzLlIFKgsmTprMP/4xWxS3CfXq7NmzvPba3/n9983/3979xTZ13QEc/9q+jpMQx3GGE4wvbZy0CckySJfarRhMagxKSwRqO9CyTYCmlUnp06S+8NSHPUx9oU97KkibBKqolkFHtELaJqgsHRDnTzsCtumoHRI7CYFcJ6b+f+09XJYU7V8HBJPmfKQjH7/Yvwff8/M9uuf3o6VF4tChDHv2FK7957fF5CQcPgxHjhgoKTHz5pu/pqurC+nBytCJojGrSTqd5vTp0/z+d0c52/sRllI9e1xZXnlWq48uEnth5PIweB3eH4L3Bo2EZjI85/o+P//FL+ns7MRisRQ6RGEVGx0d5a23fkN39x+pq5Po6sqwb5/WslT45gYG4MgRHSdO6KiqsvHGG4c4ePAga9aseRgfL5L5ahWJRDh27BjdfzjB8MjnmEsNvLQpxyvP5mjfBBWlhY7w2y2Z0e7A3x+G06MSU3NZ6pwyP9r7Uw4cOEBTU1OhQxSEe1y7do233z7Mu+8eJ51O8fLL8NprKi+8AAZDoaN7PM3MwPHjcPSohN+f5Zlnvsvrr/+K/fv3/9s2pg9AJHNBa75w5swZev50kg8/6kNVVVqcEj94KsPWBmjftNRGVLg/ag4+G4ePx+Djq0YG/CrJdI6mjfXs/fFP2LVrF62trYUOUxD+p2QySU9PD++881v6+v5CZaWBnTuz7N0L7e3/uSnKajE5CR98AD09Rnp7VUpKiuns/Bn79u1n69aty/W1IpkL91IUhf7+fvr7+znX14svcJ0iox53nYHn6zK4asFdBzW2Qkf6eLu5oG2de7+EwS8NDATgTkLFYbfRtr2dtjYP27dvR5aXuQ6vICyjQCBAd3c3J0++x8jIZaxWiRdfVPF48ng8UFNT6AiXXyoFFy9CXx/09hrxejOYzaV0dOzi1Vf30NHRQcny18sVyVz47yKRCP39/Zw/f57Bi59yxRcgm1WxVRThrlVprVFplqHJAfV2MK6y7bZcHoI34UoYrk7CcEiHNygxfjODTqfjKacD9/Pb2Lrth7S1tVFfX1/okAVhWQSDQU6dOsXZs39mYOBTEokUdXUmPJ4UW7aAy6X1EV/pD9DNz8PQEFy6BJ98YmBgAOJxldpaBx7PTnbv3s2OHTswmUyPMiyRzIX/TzweZ2RkBK/Xy+DgJUaGLnI9OIGq5jBKeurXG2myp2l05Kmr0u7ga2zgsIJhBV/E01EI3YLQrDZ8EbgSKcI3qRJPaYdxn9xgZ3NLKy73c7hcLtxu930fMxGElSyVSnHhwgX6+vo4d+5Dhoc/I5lMYzZLtLaCy5WluRkaG7Ve5OXlhY74X+XzMD4Ofj/4fDA6qsPrLSIQSJHPgyxXsW1bG21tHjweD06ns5DhimQuPLhUKoXP58Pn8zE2NsbVK2P4rv6N0HiYVDoDgFHSs2GtkZq1KrI1S7UF7BVgM0O1BdbdnVeWQdEj6uWXy8PcHW1LfHYBpqLa/OYCRBSYnjcQui0RnMmQTGul9CTJgLy+moaNTTR/bzONjY00NzfT2NhI+eO4IgnCYyCTyXD58mUGBwfxer0MDf2VQOA6qZS2PjgcRWzcmKO2NosswxNPgCyDw6G9ms0PP6ZsFmZnYWICwmG4cUObT0zo+OKLIvz+LImE9ke9urqSzZtbcLu34HK5cLlc2O32hx/U/RPJXFg++XyeqakpgsEgoVBocUTCE8xMh5menmH2lkI6c2+PUJNRT1mJAUupnvJSMJvylJlUykxL5agspaC/23tArwPJsNSaFCAaXyp0kcjouZMyEEvqicYhlshxJ5FbvKP+J4NBj+07Fdhsa7Gvl1lnl3E6ndTU1CwOWZYf9DyoIAiAqqoEg0H8fv/iCIX+zuTkODduREh8rWylJOmoqJCwWvVYrXms1hzl5doFbzJB6d3TN0VFkP5atctoVFsHMhk90aiEouhQlDyKkiMWu3fdWbeuElmW2bDBydNPN9DQ0EBTUxMNDQ0rYYdNJHOh8Obm5piZmWF2dhZFUYjFYsRiMRYWFpifn198H4/HAe1PQnTuFqD9dDOZDKqapbh46SETs8WKJGkH500mE2azmfLyciwWC2azGbPZTFlZGZWVldhsNmw2G1VVVd+oO5EgCMvv9u3bhMNhwuEwiqKgKArRaHRxHovFAEgkviKZ/OruPE5xceliK2irVSt3bDQasVqtVFRUYLVaF+c2mw1ZlnE4HA/7qNijJpK5IAiCIKxwomuaIAiCIKx0IpkLgiAIwgonkrkgCIIgrHD/AItcK/H6t+fgAAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import Image\n", + "\n", + "Image(app.get_graph().draw_png())" ] }, { @@ -362,7 +394,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "id": "cfd140f0-a5a6-4697-8115-322242f197b5", "metadata": {}, "outputs": [ @@ -370,7 +402,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "content='Hello Bob! How can I assist you today?' id='87e8b88a-b28e-4517-a62f-7b9baebd3329'\n" + "content='Hello Bob! How can I assist you today?' response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 86, 'total_tokens': 97}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-38594ccf-07c2-4fb5-a6bc-a6c36beb376f-0'\n" ] } ], @@ -378,8 +410,7 @@ "from langchain_core.messages import HumanMessage\n", "\n", "thread = {\"configurable\": {\"thread_id\": '3'}}\n", - "inputs = HumanMessage(content=\"hi! I'm bob\")\n", - "for event in app.stream(inputs, thread):\n", + "for event in app.stream(\"hi! I'm bob\", thread):\n", " for v in event.values():\n", " print(v)" ] @@ -394,23 +425,70 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "id": "23433643-d35d-4df4-80fe-a3002323cd4f", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "StateSnapshot(values=[HumanMessage(content=\"hi! I'm bob\", id='5a84a602-37d9-4903-9c3c-d0f892238580'), AIMessage(content='Hello Bob! How can I assist you today?', id='87e8b88a-b28e-4517-a62f-7b9baebd3329')], next=(), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-04-02T17:13:46.250299+00:00'}}, parent_config=None)" + "[HumanMessage(content=\"hi! I'm bob\", id='4ade65af-ee09-4a95-b913-ba936f4fbf61'),\n", + " AIMessage(content='Hello Bob! How can I assist you today?', response_metadata={'token_usage': {'completion_tokens': 11, 'prompt_tokens': 86, 'total_tokens': 97}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-38594ccf-07c2-4fb5-a6bc-a6c36beb376f-0')]" ] }, - "execution_count": 10, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "app.get_state(thread)" + "app.get_state(thread).values" + ] + }, + { + "cell_type": "markdown", + "id": "7f117f21-cabc-4c6a-b89a-e673085bc067", + "metadata": {}, + "source": [ + "### Let's get it to execute a tool" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "73eb35a7-b705-4d7b-9e4b-28f7e2130358", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "content='' additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}} response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 111, 'total_tokens': 133}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None} id='run-d3da860e-8c39-4d4a-8841-f7e59d12d861-0'\n", + "content='[{\\'url\\': \\'https://weather.com/weather/hourbyhour/l/USCA0987:1:US\\', \\'content\\': \"recents\\\\nSpecialty Forecasts\\\\nHourly Weather-San Francisco, CA\\\\nBeach Hazard Statement\\\\nSaturday, November 25\\\\n5 pm\\\\nClear\\\\n6 pm\\\\nClear\\\\n7 pm\\\\nClear\\\\n8 pm\\\\nMostly Clear\\\\n9 pm\\\\nPartly Cloudy\\\\n10 pm\\\\nPartly Cloudy\\\\n11 pm\\\\nPartly Cloudy\\\\nSunday, November 26\\\\n12 am\\\\nPartly Cloudy\\\\n1 am\\\\nMostly Cloudy\\\\n2 am\\\\nMostly Cloudy\\\\n3 am\\\\nMostly Cloudy\\\\n4 am\\\\nCloudy\\\\n5 am\\\\nCloudy\\\\n6 am\\\\nMostly Cloudy\\\\n7 am\\\\nMostly Cloudy\\\\n8 am\\\\nMostly Cloudy\\\\n9 am\\\\nMostly Cloudy\\\\n10 am\\\\nPartly Cloudy\\\\n11 am\\\\nPartly Cloudy\\\\n12 pm\\\\nPartly Cloudy\\\\n1 pm\\\\nPartly Cloudy\\\\n2 pm\\\\nPartly Cloudy\\\\n3 pm\\\\nPartly Cloudy\\\\n4 pm\\\\nPartly Cloudy\\\\n5 pm\\\\nPartly Cloudy\\\\n6 pm\\\\nPartly Cloudy\\\\n7 pm\\\\nPartly Cloudy\\\\n8 pm\\\\nPartly Cloudy\\\\n9 pm\\\\nMostly Clear\\\\n10 pm\\\\nMostly Clear\\\\n11 pm\\\\nMostly Clear\\\\nMonday, November 27\\\\n12 am\\\\nClear\\\\n1 am\\\\nMostly Clear\\\\n2 am\\\\nMostly Clear\\\\n3 am\\\\nPartly Cloudy\\\\n4 am\\\\nMostly Clear\\\\n5 am\\\\nMostly Clear\\\\n6 am\\\\nClear\\\\n7 am\\\\nClear\\\\n8 am\\\\nSunny\\\\n9 am\\\\nSunny\\\\n10 am\\\\nSunny\\\\n11 am\\\\nSunny\\\\n12 pm\\\\nMostly Sunny\\\\n1 pm\\\\nPartly Cloudy\\\\n2 pm\\\\nMostly Sunny\\\\n3 pm\\\\nMostly Sunny\\\\n4 pm\\\\nPartly Cloudy\\\\nRadar\\\\nSafety First!\\\\n Don\\'t Miss\\\\nIrresistible\\\\nWeather Wonders\\\\nOur Amazing World\\\\nCelestial Symphony\\\\nFried Turkey Fail\\\\nLook At That!\\\\n Health & Activities\\\\nSeasonal Allergies and Pollen Count Forecast\\\\nNo pollen detected in your area\\\\nCold & Flu Forecast\\\\nFlu risk is low in your area\\\\nWe recognize our responsibility to use data and technology for good. Changes For Critters\\\\nHurricane Tracker\\\\nStay Safe\\\\nAir Quality Index\\\\nAir quality is considered satisfactory, and air pollution poses little or no risk.\\\\n Take control of your data.\\\\n\"}]' name='tavily_search_results_json' id='25805743-0dc3-4a28-80a1-0cd9e556e6ac'\n", + "content='The current weather in San Francisco is as follows:\\n- 5 pm: Clear\\n- 6 pm: Clear\\n- 7 pm: Clear\\n- 8 pm: Mostly Clear\\n- 9 pm: Partly Cloudy\\n\\nFor more detailed and updated information, you can visit [this link](https://weather.com/weather/hourbyhour/l/USCA0987:1:US).' response_metadata={'token_usage': {'completion_tokens': 84, 'prompt_tokens': 684, 'total_tokens': 768}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-45171cbb-b4bd-47cd-9ae5-51718d45904b-0'\n" + ] + } + ], + "source": [ + "for event in app.stream(\"what is the weather in sf currently\", thread):\n", + " for v in event.values():\n", + " print(v)" + ] + }, + { + "cell_type": "markdown", + "id": "18d3141b-9f9a-4ad8-b475-400674848b16", + "metadata": {}, + "source": [ + "We can see it planned the tool execution, then executed the tool, and then emitted the final response. Let's see how we can have more control over this." + ] + }, + { + "cell_type": "markdown", + "id": "1c5d69cf-6de5-4a52-976a-3799aa39d6d5", + "metadata": {}, + "source": [ + "### Pause before tools" ] }, { @@ -418,12 +496,22 @@ "id": "06aaa787-32fe-404b-abeb-5b2ed94309fd", "metadata": {}, "source": [ - "Let's now show how we can update the state. This is very useful when you want to have a human-in-the-loop to validate (and potentially change) the action to take. If you notice above, we added `interrupt_before=[\"action\"]` - this means that before any actions are taken we pause. This is a great moment to allow the user to correct and update the state!" + "If you notice below, we added `interrupt_before=[\"action\"]` - this means that before any actions are taken we pause. This is a great moment to allow the user to correct and update the state! This is very useful when you want to have a human-in-the-loop to validate (and potentially change) the action to take. " ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 20, + "id": "5a68afc0-606f-4294-a872-b2b563be0d69", + "metadata": {}, + "outputs": [], + "source": [ + "app_w_interrupt = workflow.compile(checkpointer=memory, interrupt_before=[\"action\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 21, "id": "08ae8246-11d5-40e1-8567-361e5bef8917", "metadata": {}, "outputs": [ @@ -431,13 +519,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "content='' additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}} id='8e6ae8d5-a258-47aa-9e2c-1ca3e78add90'\n" + "content='I apologize for the inconvenience. Let me provide you with the current weather in San Francisco.' additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}} response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 260, 'total_tokens': 301}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None} id='run-19d40ebd-d551-4e36-8bd4-ed6ae5256954-0'\n" ] } ], "source": [ - "inputs = HumanMessage(content=\"what is the weather in sf currently\")\n", - "for event in app.stream(inputs, thread):\n", + "thread = {\"configurable\": {\"thread_id\": '4'}}\n", + "for event in app_w_interrupt.stream(\"what is the weather in sf currently\", thread):\n", " for v in event.values():\n", " print(v)" ] @@ -452,7 +540,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 22, "id": "5a53df78-6c25-4176-b049-02a02a713771", "metadata": {}, "outputs": [ @@ -463,13 +551,13 @@ " 'name': 'tavily_search_results_json'}}" ] }, - "execution_count": 12, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "current_values = app.get_state(thread)\n", + "current_values = app_w_interrupt.get_state(thread)\n", "current_values.values[-1].additional_kwargs" ] }, @@ -483,7 +571,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 23, "id": "060e2e33-1f6a-40ef-850e-161b308986fb", "metadata": {}, "outputs": [], @@ -494,24 +582,24 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 24, "id": "3210d003-e20e-47fa-b4f4-402fed7409f1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "{'configurable': {'thread_id': '3',\n", - " 'thread_ts': '2024-04-02T16:58:19.692203+00:00'}}" + "{'configurable': {'thread_id': '4',\n", + " 'thread_ts': '2024-04-02T21:49:50.740187+00:00'}}" ] }, - "execution_count": 14, + "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "app.update_state(thread, current_values.values)" + "app_w_interrupt.update_state(thread, current_values.values)" ] }, { @@ -524,23 +612,23 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 25, "id": "4a7dfaab-bfa7-47c7-8b93-2b06b3560809", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "StateSnapshot(values=[HumanMessage(content=\"hi! I'm bob\", id='1493cdf4-b7b5-46c9-a3e7-ad3b661fcb92'), AIMessage(content='Hello Bob! How can I assist you today?', id='028e0185-2ca4-4c1d-8660-93c17b839275'), HumanMessage(content='what is the weather in sf currently', id='76d6a5ff-d400-4edb-a264-b584107e2231'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, id='b143d5f6-5216-4a48-b76a-68b2f3eb6ff2')], next=('action',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-04-02T16:58:19.692203+00:00'}}, parent_config=None)" + "StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0'), FunctionMessage(content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629', 'content': 'Hourly weather forecast in San Francisco, CA. Check current conditions in San Francisco, CA with radar, hourly, and more.'}]\", name='tavily_search_results_json', id='9db65c5e-aaa2-4ee7-b149-0e57d2db5bf6'), AIMessage(content=\"You can check the hourly weather forecast in San Francisco, CA on AccuWeather's website. Here is the [link](https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629) to view the current conditions.\", response_metadata={'token_usage': {'completion_tokens': 60, 'prompt_tokens': 186, 'total_tokens': 246}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-c09b1f88-5e55-4b65-b82d-054d4fb2522f-0'), HumanMessage(content='what is the weather in sf currently', id='98cec2a0-26f7-4b9f-9491-2a893f58c591'), AIMessage(content='I apologize for the inconvenience. Let me provide you with the current weather in San Francisco.', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 260, 'total_tokens': 301}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-19d40ebd-d551-4e36-8bd4-ed6ae5256954-0')], next=('action',), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T21:49:50.740187+00:00'}}, parent_config=None)" ] }, - "execution_count": 15, + "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "app.get_state(thread)" + "app_w_interrupt.get_state(thread)" ] }, { @@ -553,7 +641,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 26, "id": "273d56a8-f40f-4a51-a27f-7c6bb2bda0ba", "metadata": {}, "outputs": [ @@ -561,13 +649,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "content=\"[{'url': 'https://forecast.weather.gov/zipcity.php?inputstring=San francisco,CA', 'content': 'Detailed Forecast. Today. Mostly sunny, with a high near 62. Light and variable wind becoming west southwest 5 to 8 mph in the afternoon. Tonight. Mostly clear, with a low around 49. West wind 5 to 8 mph becoming north northwest after midnight. Monday. Sunny, with a high near 67.'}]\" name='tavily_search_results_json' id='9b33eb74-b079-4615-9c8a-9f41b4e176ba'\n", - "content='The weather in San Francisco today is mostly sunny with a high near 62 degrees Fahrenheit. The wind is light and variable, becoming west-southwest at 5 to 8 mph in the afternoon. Tonight, it will be mostly clear with a low around 49 degrees Fahrenheit. Tomorrow is expected to be sunny with a high near 67 degrees Fahrenheit.' id='18ff870d-5d5d-40d9-9eca-72e345749b51'\n" + "content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629', 'content': 'San Francisco, CA Weather Forecast, with current conditions, wind, air quality, and what to expect for the next 3 days.'}]\" name='tavily_search_results_json' id='8f9238a2-e464-41d7-b3a5-e73ab75156bf'\n", + "content=\"You can check the current weather in San Francisco, CA along with the forecast for the next 3 days on AccuWeather's website. Here is the [link](https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629) to view the information.\" response_metadata={'token_usage': {'completion_tokens': 64, 'prompt_tokens': 377, 'total_tokens': 441}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-18cd2315-f103-46fe-ac9c-f7eea55e210e-0'\n" ] } ], "source": [ - "for event in app.stream(None, thread):\n", + "for event in app_w_interrupt.stream(None, thread):\n", " for v in event.values():\n", " print(v)" ] @@ -584,7 +672,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 27, "id": "8578a66d-6489-4e03-8c23-fd0530278455", "metadata": {}, "outputs": [ @@ -592,22 +680,26 @@ "name": "stdout", "output_type": "stream", "text": [ - "StateSnapshot(values=[HumanMessage(content=\"hi! I'm bob\", id='1493cdf4-b7b5-46c9-a3e7-ad3b661fcb92'), AIMessage(content='Hello Bob! How can I assist you today?', id='028e0185-2ca4-4c1d-8660-93c17b839275'), HumanMessage(content='what is the weather in sf currently', id='76d6a5ff-d400-4edb-a264-b584107e2231'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, id='b143d5f6-5216-4a48-b76a-68b2f3eb6ff2'), FunctionMessage(content=\"[{'url': 'https://forecast.weather.gov/zipcity.php?inputstring=San francisco,CA', 'content': 'Detailed Forecast. Today. Mostly sunny, with a high near 62. Light and variable wind becoming west southwest 5 to 8 mph in the afternoon. Tonight. Mostly clear, with a low around 49. West wind 5 to 8 mph becoming north northwest after midnight. Monday. Sunny, with a high near 67.'}]\", name='tavily_search_results_json', id='9b33eb74-b079-4615-9c8a-9f41b4e176ba'), AIMessage(content='The weather in San Francisco today is mostly sunny with a high near 62 degrees Fahrenheit. The wind is light and variable, becoming west-southwest at 5 to 8 mph in the afternoon. Tonight, it will be mostly clear with a low around 49 degrees Fahrenheit. Tomorrow is expected to be sunny with a high near 67 degrees Fahrenheit.', id='18ff870d-5d5d-40d9-9eca-72e345749b51')], next=(), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-04-02T16:58:23.633015+00:00'}}, parent_config=None)\n", + "StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0'), FunctionMessage(content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629', 'content': 'Hourly weather forecast in San Francisco, CA. Check current conditions in San Francisco, CA with radar, hourly, and more.'}]\", name='tavily_search_results_json', id='9db65c5e-aaa2-4ee7-b149-0e57d2db5bf6'), AIMessage(content=\"You can check the hourly weather forecast in San Francisco, CA on AccuWeather's website. Here is the [link](https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629) to view the current conditions.\", response_metadata={'token_usage': {'completion_tokens': 60, 'prompt_tokens': 186, 'total_tokens': 246}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-c09b1f88-5e55-4b65-b82d-054d4fb2522f-0'), HumanMessage(content='what is the weather in sf currently', id='98cec2a0-26f7-4b9f-9491-2a893f58c591'), AIMessage(content='I apologize for the inconvenience. Let me provide you with the current weather in San Francisco.', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 260, 'total_tokens': 301}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-19d40ebd-d551-4e36-8bd4-ed6ae5256954-0'), FunctionMessage(content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629', 'content': 'San Francisco, CA Weather Forecast, with current conditions, wind, air quality, and what to expect for the next 3 days.'}]\", name='tavily_search_results_json', id='8f9238a2-e464-41d7-b3a5-e73ab75156bf'), AIMessage(content=\"You can check the current weather in San Francisco, CA along with the forecast for the next 3 days on AccuWeather's website. Here is the [link](https://www.accuweather.com/en/us/san-francisco/94103/weather-forecast/347629) to view the information.\", response_metadata={'token_usage': {'completion_tokens': 64, 'prompt_tokens': 377, 'total_tokens': 441}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-18cd2315-f103-46fe-ac9c-f7eea55e210e-0')], next=(), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T21:49:56.166057+00:00'}}, parent_config=None)\n", "--\n", - "StateSnapshot(values=[HumanMessage(content=\"hi! I'm bob\", id='1493cdf4-b7b5-46c9-a3e7-ad3b661fcb92'), AIMessage(content='Hello Bob! How can I assist you today?', id='028e0185-2ca4-4c1d-8660-93c17b839275'), HumanMessage(content='what is the weather in sf currently', id='76d6a5ff-d400-4edb-a264-b584107e2231'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, id='b143d5f6-5216-4a48-b76a-68b2f3eb6ff2')], next=('action',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-04-02T16:58:19.692203+00:00'}}, parent_config=None)\n", + "StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0'), FunctionMessage(content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629', 'content': 'Hourly weather forecast in San Francisco, CA. Check current conditions in San Francisco, CA with radar, hourly, and more.'}]\", name='tavily_search_results_json', id='9db65c5e-aaa2-4ee7-b149-0e57d2db5bf6'), AIMessage(content=\"You can check the hourly weather forecast in San Francisco, CA on AccuWeather's website. Here is the [link](https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629) to view the current conditions.\", response_metadata={'token_usage': {'completion_tokens': 60, 'prompt_tokens': 186, 'total_tokens': 246}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-c09b1f88-5e55-4b65-b82d-054d4fb2522f-0'), HumanMessage(content='what is the weather in sf currently', id='98cec2a0-26f7-4b9f-9491-2a893f58c591'), AIMessage(content='I apologize for the inconvenience. Let me provide you with the current weather in San Francisco.', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 260, 'total_tokens': 301}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-19d40ebd-d551-4e36-8bd4-ed6ae5256954-0')], next=('action',), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T21:49:50.740187+00:00'}}, parent_config=None)\n", "--\n", - "StateSnapshot(values=[HumanMessage(content=\"hi! I'm bob\", id='1493cdf4-b7b5-46c9-a3e7-ad3b661fcb92'), AIMessage(content='Hello Bob! How can I assist you today?', id='028e0185-2ca4-4c1d-8660-93c17b839275'), HumanMessage(content='what is the weather in sf currently', id='76d6a5ff-d400-4edb-a264-b584107e2231'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}}, id='b143d5f6-5216-4a48-b76a-68b2f3eb6ff2')], next=('action',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-04-02T16:58:18.058645+00:00'}}, parent_config=None)\n", + "StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0'), FunctionMessage(content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629', 'content': 'Hourly weather forecast in San Francisco, CA. Check current conditions in San Francisco, CA with radar, hourly, and more.'}]\", name='tavily_search_results_json', id='9db65c5e-aaa2-4ee7-b149-0e57d2db5bf6'), AIMessage(content=\"You can check the hourly weather forecast in San Francisco, CA on AccuWeather's website. Here is the [link](https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629) to view the current conditions.\", response_metadata={'token_usage': {'completion_tokens': 60, 'prompt_tokens': 186, 'total_tokens': 246}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-c09b1f88-5e55-4b65-b82d-054d4fb2522f-0'), HumanMessage(content='what is the weather in sf currently', id='98cec2a0-26f7-4b9f-9491-2a893f58c591'), AIMessage(content='I apologize for the inconvenience. Let me provide you with the current weather in San Francisco.', additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 41, 'prompt_tokens': 260, 'total_tokens': 301}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-19d40ebd-d551-4e36-8bd4-ed6ae5256954-0')], next=('action',), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T21:49:45.798416+00:00'}}, parent_config=None)\n", "--\n", - "StateSnapshot(values=[HumanMessage(content=\"hi! I'm bob\", id='1493cdf4-b7b5-46c9-a3e7-ad3b661fcb92'), AIMessage(content='Hello Bob! How can I assist you today?', id='028e0185-2ca4-4c1d-8660-93c17b839275')], next=(), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-04-02T16:58:16.834223+00:00'}}, parent_config=None)\n", + "StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0'), FunctionMessage(content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629', 'content': 'Hourly weather forecast in San Francisco, CA. Check current conditions in San Francisco, CA with radar, hourly, and more.'}]\", name='tavily_search_results_json', id='9db65c5e-aaa2-4ee7-b149-0e57d2db5bf6'), AIMessage(content=\"You can check the hourly weather forecast in San Francisco, CA on AccuWeather's website. Here is the [link](https://www.accuweather.com/en/us/san-francisco/94103/hourly-weather-forecast/347629) to view the current conditions.\", response_metadata={'token_usage': {'completion_tokens': 60, 'prompt_tokens': 186, 'total_tokens': 246}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None}, id='run-c09b1f88-5e55-4b65-b82d-054d4fb2522f-0')], next=(), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T21:44:09.910235+00:00'}}, parent_config=None)\n", + "--\n", + "StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"weather in San Francisco today\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0')], next=('action',), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T21:44:06.248818+00:00'}}, parent_config=None)\n", + "--\n", + "StateSnapshot(values=[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0')], next=('action',), config={'configurable': {'thread_id': '4', 'thread_ts': '2024-04-02T21:44:04.515773+00:00'}}, parent_config=None)\n", "--\n" ] } ], "source": [ - "for state in app.get_state_history(thread):\n", + "for state in app_w_interrupt.get_state_history(thread):\n", " print(state)\n", " print('--')\n", - " if len(state.values) == 4:\n", + " if len(state.values) == 2:\n", " to_replay = state" ] }, @@ -621,23 +713,45 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 28, "id": "21e7fc18-6fd9-4e11-a84b-e0325c9640c8", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "StateSnapshot(values=[HumanMessage(content=\"hi! I'm bob\", id='1493cdf4-b7b5-46c9-a3e7-ad3b661fcb92'), AIMessage(content='Hello Bob! How can I assist you today?', id='028e0185-2ca4-4c1d-8660-93c17b839275'), HumanMessage(content='what is the weather in sf currently', id='76d6a5ff-d400-4edb-a264-b584107e2231'), AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}}, id='b143d5f6-5216-4a48-b76a-68b2f3eb6ff2')], next=('action',), config={'configurable': {'thread_id': '3', 'thread_ts': '2024-04-02T16:58:18.058645+00:00'}}, parent_config=None)" + "[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'),\n", + " AIMessage(content='', additional_kwargs={'function_call': {'arguments': '{\"query\":\"current weather in San Francisco\"}', 'name': 'tavily_search_results_json'}}, response_metadata={'token_usage': {'completion_tokens': 22, 'prompt_tokens': 88, 'total_tokens': 110}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'function_call', 'logprobs': None}, id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0')]" ] }, - "execution_count": 18, + "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "to_replay" + "to_replay.values" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "d4b01634-0041-4632-8d1f-5464580e54f5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('action',)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "to_replay.next" ] }, { @@ -645,12 +759,14 @@ "id": "29da43ea-9295-43e2-b164-0eb28d96749c", "metadata": {}, "source": [ + "### Replay a past state\n", + "\n", "To replay from this place we just need to pass its config back to the agent." ] }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 30, "id": "e986f94f-706f-4b6f-b3c4-f95483b9e9b8", "metadata": {}, "outputs": [ @@ -658,21 +774,100 @@ "name": "stdout", "output_type": "stream", "text": [ - "content=\"[{'url': 'https://www.accuweather.com/en/us/san-francisco/94103/current-weather/347629', 'content': 'Get the latest weather conditions and forecast for San Francisco, CA. See the temperature, humidity, wind, pressure, cloud cover, and alerts for the current hour and the next few days.'}]\" name='tavily_search_results_json' id='73ab98d6-d7cf-4812-9572-f58698394c9f'\n", - "content='You can check the current weather conditions and forecast for San Francisco, CA on [AccuWeather](https://www.accuweather.com/en/us/san-francisco/94103/current-weather/347629). This will provide you with information on temperature, humidity, wind, pressure, cloud cover, and alerts for the current hour and the next few days.' id='a54c0531-1683-4d61-87b6-ee7f66971c25'\n" + "content=\"[{'url': 'https://forecast.weather.gov/zipcity.php?inputstring=San francisco,CA', 'content': 'San Francisco CA 37.77°N 122.41°W (Elev. 131 ft) Last Update: 8:37 am PDT Apr 2, 2024. Forecast Valid: 9am PDT Apr 2, 2024-6pm PDT Apr 8, 2024 . ... Severe Weather ; Current Outlook Maps ; Drought ; Fire Weather ; Fronts/Precipitation Maps ; Current Graphical Forecast Maps ; Rivers ; Marine ; Offshore and High Seas; Hurricanes ;'}]\" name='tavily_search_results_json' id='8c02a3ff-3919-4e55-9c50-396abecbf654'\n", + "content='I found information on the weather in San Francisco. You can check the current weather in San Francisco by visiting this [link](https://forecast.weather.gov/zipcity.php?inputstring=San%20francisco,CA).' response_metadata={'token_usage': {'completion_tokens': 48, 'prompt_tokens': 259, 'total_tokens': 307}, 'model_name': 'gpt-3.5-turbo', 'system_fingerprint': 'fp_b28b39ffa8', 'finish_reason': 'stop', 'logprobs': None} id='run-c7eed90e-582b-4e3c-a23b-3b09e5bc7581-0'\n" ] } ], "source": [ - "for event in app.stream(None, to_replay.config):\n", + "for event in app_w_interrupt.stream(None, to_replay.config):\n", " for v in event.values():\n", " print(v)" ] }, + { + "cell_type": "markdown", + "id": "59910951-fae1-4475-8511-f622439b590d", + "metadata": {}, + "source": [ + "### Branch off a past state" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "id": "b084f141-5800-487b-b115-d2e58421b963", + "metadata": {}, + "outputs": [], + "source": [ + "branch_config = app_w_interrupt.update_state(to_replay.config, AIMessage(content='All done here!', id=to_replay.values[-1].id))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "1a7cfcd4-289e-419e-8b49-dfaef4f88641", + "metadata": {}, + "outputs": [], + "source": [ + "branch_state = app_w_interrupt.get_state(branch_config)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "5198f9c1-d2d4-458a-993d-3caa55810b1e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[HumanMessage(content='what is the weather in sf currently', id='c4e2e843-0f21-4a54-9f18-68ba5ee02f4a'),\n", + " AIMessage(content='All done here!', id='run-a324e2bc-2f34-433d-912b-473ef0e15b40-0')]" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "branch_state.values" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "id": "5d89d55d-db84-4c2d-828b-64a29a69947b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "()" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "branch_state.next" + ] + }, + { + "cell_type": "markdown", + "id": "cc168c90-a374-4280-a9a6-8bc232dbb006", + "metadata": {}, + "source": [ + "You can see the snapshot was updated and now correctly reflects that there is no next step." + ] + }, { "cell_type": "code", "execution_count": null, - "id": "b084f141-5800-487b-b115-d2e58421b963", + "id": "9ab115de-9b11-4e8b-8ace-c23e1369300b", "metadata": {}, "outputs": [], "source": []