From 5ca37a489e384e4f9541b385c75efe37f994a91b Mon Sep 17 00:00:00 2001 From: KohlerHECTOR Date: Mon, 24 Jul 2023 16:01:53 +0200 Subject: [PATCH 01/80] Add small user guide intro --- docs/user_guide.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 56875986e..5bbc22851 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -6,11 +6,19 @@ User guide ========== -If you are new to rlberry, check the :ref:`Tutorials` below and the :ref:`the quickstart` documentation. -In the quick start, you will learn how to set up an experiment and evaluate the -efficiency of different agents. +Introduction +------------ +Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to +the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and +deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. +Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). +In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). + +.. If you are new to rlberry, check the :ref:`Tutorials` below and the :ref:`the quickstart` documentation. +.. In the quick start, you will learn how to set up an experiment and evaluate the +.. efficiency of different agents. -For more information see :ref:`the gallery of examples`. +.. For more information see :ref:`the gallery of examples`. Tutorials From de0678f4bd639d38fecf48ff62279f53ff931e54 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 14:07:01 +0000 Subject: [PATCH 02/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/user_guide.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 5bbc22851..3fdc8cd44 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -8,10 +8,10 @@ User guide Introduction ------------ -Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to -the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and -deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. -Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). +Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to +the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and +deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. +Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). .. If you are new to rlberry, check the :ref:`Tutorials` below and the :ref:`the quickstart` documentation. From ad0b97b0c07a60b3ca8bd2e9bf1d8e5654135fac Mon Sep 17 00:00:00 2001 From: KohlerHECTOR Date: Mon, 24 Jul 2023 17:30:04 +0200 Subject: [PATCH 03/80] Some draft of a plan for the user guide --- docs/user_guide.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 docs/user_guide.md diff --git a/docs/user_guide.md b/docs/user_guide.md new file mode 100644 index 000000000..2135c3e29 --- /dev/null +++ b/docs/user_guide.md @@ -0,0 +1,30 @@ +# User Guide +## Introduction +Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to +the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and +deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. +Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). +In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). +## Set up an experiment +Some text about an experiment: a comparison of 2 rl agents on a given environment. +### Environment +Some text about MDPs. +### Agent +Some text about what an agent is. +### ExperimentManager +Some text about the goal of experiment. +### Logging +### Analyse the results +## Experimenting with Deep agents +### Torch Agents +### Policy and Value Networks +### Stable Baselines 3 +## Experimenting with Bandits. +## Reproducibility +### Seeding +### Saving and Loading Agents +### Saving and Loading Data +## Advanced Usage +### Custom Agents +### Custom Environments +### Transfer Learning From 4b8a53540a56c64d0553e6c8cd9bb477996c964c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:31:43 +0000 Subject: [PATCH 04/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 2135c3e29..8aef7e761 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -8,7 +8,7 @@ In this user guide, we take you through the core features of rlberry and illustr ## Set up an experiment Some text about an experiment: a comparison of 2 rl agents on a given environment. ### Environment -Some text about MDPs. +Some text about MDPs. ### Agent Some text about what an agent is. ### ExperimentManager From a43fe655f9a865bb04e28fef85ce80f14c789faf Mon Sep 17 00:00:00 2001 From: KohlerHECTOR Date: Mon, 24 Jul 2023 17:59:18 +0200 Subject: [PATCH 05/80] some text --- docs/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 8aef7e761..2135c3e29 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -8,7 +8,7 @@ In this user guide, we take you through the core features of rlberry and illustr ## Set up an experiment Some text about an experiment: a comparison of 2 rl agents on a given environment. ### Environment -Some text about MDPs. +Some text about MDPs. ### Agent Some text about what an agent is. ### ExperimentManager From b97174e142dcd99eb8a625e50d7f947075ec7135 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:59:37 +0000 Subject: [PATCH 06/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/user_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 2135c3e29..8aef7e761 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -8,7 +8,7 @@ In this user guide, we take you through the core features of rlberry and illustr ## Set up an experiment Some text about an experiment: a comparison of 2 rl agents on a given environment. ### Environment -Some text about MDPs. +Some text about MDPs. ### Agent Some text about what an agent is. ### ExperimentManager From f0d2076de370bc1f29e4f207019fb26f757b6643 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 21 Sep 2023 15:26:36 +0200 Subject: [PATCH 07/80] update userguide installation page : remove ffmpeg(added in setup.py) and deprecated gymnasium part. --- docs/installation.rst | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/docs/installation.rst b/docs/installation.rst index 699798fe5..2c11dc247 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -14,10 +14,6 @@ First, we suggest you to create a virtual environment using $ conda create -n rlberry $ conda activate rlberry -OS dependency -------------- - -In order to render videos in rlberry, `ffmpeg `_ must be installed. Latest version (0.5.0) ------------------------------------- @@ -36,14 +32,10 @@ Install the development version to test new features. .. code:: bash - $ pip install git+https://github.com/rlberry-py/rlberry.git#egg=rlberry[default] + $ pip install rlberry[default]@git+https://github.com/rlberry-py/rlberry.git .. warning:: - - When using Python 3.10, there seem to be a problem when installing PyOpenGL-accelerate. For - now, we advise people to use Python 3.9 with PyOpenGL==3.1.5 and PyOpenGL-accelerate==3.1.5. - It is also possible to use rlberry without installing PyOpenGL-accelerate but this could cause - rendering to be slow. + For `zsh` users, `zsh` uses brackets for globbing, therefore it is necessary to add quotes around the argument, e.g. :code:`pip install 'rlberry[default]@git+https://github.com/rlberry-py/rlberry.git'`. Previous versions @@ -53,14 +45,14 @@ If you used a previous version in your work, you can install it by running .. code:: bash - $ pip install git+https://github.com/rlberry-py/rlberry.git@{TAG_NAME}#egg=rlberry[default] + $ pip install rlberry[default]@git+https://github.com/rlberry-py/rlberry.git@{TAG_NAME} replacing `{TAG_NAME}` by the tag of the corresponding version, -e.g., :code:`pip install git+https://github.com/rlberry-py/rlberry.git@v0.1#egg=rlberry[default]` +e.g., :code:`pip install rlberry[default]@git+https://github.com/rlberry-py/rlberry.git@v0.1` to install version 0.1. .. warning:: - For `zsh` users, `zsh` uses brackets for globbing, therefore it is necessary to add quotes around the argument, e.g. :code:`pip install 'git+https://github.com/rlberry-py/rlberry.git#egg=rlberry[default]'`. + For `zsh` users, `zsh` uses brackets for globbing, therefore it is necessary to add quotes around the argument, e.g. :code:`pip install 'rlberry[default]@git+https://github.com/rlberry-py/rlberry.git@v0.1'`. Deep RL agents @@ -72,15 +64,8 @@ Deep RL agents require extra libraries, like PyTorch. .. code:: bash - $ pip install git+https://github.com/rlberry-py/rlberry.git#egg=rlberry[torch_agents] + $ pip install rlberry[torch_agents]@git+https://github.com/rlberry-py/rlberry.git $ pip install tensorboard -* JAX agents (**Linux only, experimental**): - - -* Stable-baselines3 agents with Gymnasium support: - (https://github.com/DLR-RM/stable-baselines3/pull/1327) -.. code:: bash - - $ pip install git+https://github.com/DLR-RM/stable-baselines3@feat/gymnasium-support - $ pip install git+https://github.com/Stable-Baselines-Team/stable-baselines3-contrib@feat/gymnasium-support +.. warning:: + For `zsh` users, `zsh` uses brackets for globbing, therefore it is necessary to add quotes around the argument, e.g. :code:`pip install 'rlberry[torch_agents]@git+https://github.com/rlberry-py/rlberry.git'`. From c00258534644dde1abe03e1aea8eccde759611c8 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 22 Sep 2023 10:47:29 +0200 Subject: [PATCH 08/80] update CSS to distinguish "code" from "output" --- docs/themes/scikit-learn-fork/static/css/theme.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/themes/scikit-learn-fork/static/css/theme.css b/docs/themes/scikit-learn-fork/static/css/theme.css index c1170f1cc..7bc733770 100644 --- a/docs/themes/scikit-learn-fork/static/css/theme.css +++ b/docs/themes/scikit-learn-fork/static/css/theme.css @@ -90,8 +90,12 @@ div.highlight { div.highlight-none{ max-height: 300px; overflow-y: auto; + background-color: #ddd; } +div.highlight-python{ + background-color: #f8f8f8; + } div.highlight pre { padding: 0.2rem 0.5rem; @@ -1252,7 +1256,7 @@ table.sk-sponsor-table td { /* pygments - highlighting */ .highlight .hll { background-color: #ffffcc } -.highlight { background: #f8f8f8; } +.highlight { background: none; } .highlight .c { color: #408090; font-style: italic } /* Comment */ .highlight .err { border: 1px solid #FF0000 } /* Error */ .highlight .k { color: #007020; font-weight: bold } /* Keyword */ From 047ff8d0d389f85bc89cee42fbf488570129dd8e Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 22 Sep 2023 15:32:32 +0200 Subject: [PATCH 09/80] rename agentManager -> experimentManager --- .../quick_start_rl/agent_manager_diagram.png | Bin 67234 -> 0 bytes .../experiment_manager_diagram.png | Bin 0 -> 77336 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/basics/quick_start_rl/agent_manager_diagram.png create mode 100644 docs/basics/quick_start_rl/experiment_manager_diagram.png diff --git a/docs/basics/quick_start_rl/agent_manager_diagram.png b/docs/basics/quick_start_rl/agent_manager_diagram.png deleted file mode 100644 index b678634a9b04accc19b619140abf6221919d3085..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67234 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

{S9eC)Q2u!LN^1#dfAIR;MDjkh%tQmoHa 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 literal 0 HcmV?d00001 From 2831f03e3482aa6e46bfe2c8abe07a9b1f2956e4 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 22 Sep 2023 15:33:11 +0200 Subject: [PATCH 10/80] update CSS to distinguish "code" from "output" with markDown --- docs/themes/scikit-learn-fork/static/css/theme.css | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/themes/scikit-learn-fork/static/css/theme.css b/docs/themes/scikit-learn-fork/static/css/theme.css index 7bc733770..108cdd4b2 100644 --- a/docs/themes/scikit-learn-fork/static/css/theme.css +++ b/docs/themes/scikit-learn-fork/static/css/theme.css @@ -92,7 +92,11 @@ div.highlight-none{ overflow-y: auto; background-color: #ddd; } - +div.highlight-default{ + max-height: 300px; + overflow-y: auto; + background-color: #ddd; +} div.highlight-python{ background-color: #f8f8f8; } From a119c0eb4e915b2fb1d187ef7c677270c2506321 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 22 Sep 2023 16:33:51 +0200 Subject: [PATCH 11/80] updating quickstart --- docs/basics/quick_start_rl/quickstart.rst | 62 ++++++++++++----------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/docs/basics/quick_start_rl/quickstart.rst b/docs/basics/quick_start_rl/quickstart.rst index 21341dac4..fced10319 100644 --- a/docs/basics/quick_start_rl/quickstart.rst +++ b/docs/basics/quick_start_rl/quickstart.rst @@ -40,13 +40,19 @@ In this tutorial, we will use the :class:`~rlberry.envs.finite.chain.Chain` environment, which is a very simple environment where the agent has to go from one end of a chain to the other end. + .. code:: python env_ctor = Chain env_kwargs = dict(L=10, fail_prob=0.1) - # chain of length 10. With proba 0.2, the agent will not be able to take the action it wants to take/ + # chain of length 10. With proba 0.1, the agent will not be able to take the action it wants to take/ env = env_ctor(**env_kwargs) + +The agent has two actions, go to the left of to the right, but it might +move to a random direction according to a failure probability +``fail_prob=0.1``. + Let us see a graphical representation .. code:: python @@ -103,15 +109,12 @@ Let us see a graphical representation [libx264 @ 0x564b9e570340] Weighted P-Frames: Y:0.0% UV:0.0% [libx264 @ 0x564b9e570340] kb/s:13.85 - -The agent has two actions, go to the left of to the right, but it might -move to a random direction according to a failure probability -``fail_prob=0.1``. +| .. video:: ../../video_chain_quickstart.mp4 :width: 600 - :align: center +| Defining an agent and a baseline -------------------------------- @@ -121,6 +124,11 @@ We will compare a RandomAgent (which plays random action) to the is a algorithm that is designed to perform an efficient exploration. Our goal is then to assess the performance of the two algorithms. +There are a number of agents that are already coded in rlberry. See the +module :class:`~rlberry.agents.Agent` for more informations. + +Or, as we want for the RandomAgent, you can code your own agent : + .. code:: python # Create random agent as a baseline @@ -134,19 +142,15 @@ Our goal is then to assess the performance of the two algorithms. observation, info = self.env.reset() for ep in range(budget): action = self.policy(observation) - observation, reward, done, _ = self.env.step(action) + observation, reward, terminated, truncated, info = self.env.step(action) def policy(self, observation): return self.env.action_space.sample() # choose an action at random - # Define parameters - ucbvi_params = {"gamma": 0.9, "horizon": 100} -There are a number of agents that are already coded in rlberry. See the -module :class:`~rlberry.agents.Agent` for more informations. -Agent Manager +Experiment Manager ------------- One of the main feature of rlberry is its :class:`~rlberry.manager.ExperimentManager` @@ -157,7 +161,7 @@ class. Here is a diagram to explain briefly what it does. :align: center -In a few words, agent manager spawns agents and environments for training and +In a few words, ExperimentManager spawns agents and environments for training and then once the agents are trained, it uses these agents and new environments to evaluate how well the agent perform. All of these steps can be done several times to assess stochasticity of agents and/or environment. @@ -170,19 +174,21 @@ We want to assess the expected reward of the policy learned by our agents for a time horizon of (say) :math:`T=20`. To do that we use 10 Monte-Carlo simulations, i.e., we do the experiment -10 times for each agent and at the end we take the mean of the 10 -obtained reward. +10 times for each agent and at the end we take the mean of the obtained reward. -This gives us 1 value per agent. We do this 10 times (so 10 times 10 -equal 100 simulations) in order to have an idea of the variability of -our estimation. +To check variability, we can train many instance of the same agent with ``n_fit`` (here 1) +Each instance of agent will train with a specific budget ``fit_budget`` (here 100). +Remark that ``fit_budget`` may not mean the same thing among agents. -In order to manage the agents, we use an Agent Manager. The manager will +In order to manage the agents, we use an Experiment Manager. The manager will then spawn agents as desired during the experiment. .. code:: python + # Define parameters + ucbvi_params = {"gamma": 0.9, "horizon": 100} + # Create ExperimentManager to fit 1 agent ucbvi_stats = ExperimentManager( UCBVIAgent, @@ -205,6 +211,7 @@ then spawn agents as desired during the experiment. baseline_stats.fit() + .. parsed-literal:: [INFO] Running ExperimentManager fit() for UCBVI with n_fit = 1 and max_workers = None. @@ -212,6 +219,7 @@ then spawn agents as desired during the experiment. [INFO] Running ExperimentManager fit() for RandomAgent with n_fit = 1 and max_workers = None. [INFO] ... trained! +| Evaluating and comparing the agents : .. code:: python @@ -307,37 +315,31 @@ Then, we fit the two agents and plot the data in the writer. .. code:: python - # Create ExperimentManager to fit 4 agents using 1 job + # Create ExperimentManager for UCBI to fit 10 agents ucbvi_stats = ExperimentManager( UCBVIAgent2, (env_ctor, env_kwargs), fit_budget=50, init_kwargs=ucbvi_params, n_fit=10, - parallelization="process", - mp_context="fork", - ) # mp_context is needed to have parallel computing in notebooks. + ) ucbvi_stats.fit() - # Create ExperimentManager for baseline + # Create ExperimentManager for baseline to fit 10 agents baseline_stats = ExperimentManager( RandomAgent2, (env_ctor, env_kwargs), fit_budget=5000, n_fit=10, - parallelization="process", - mp_context="fork", ) baseline_stats.fit() - # Create ExperimentManager for baseline + # Create ExperimentManager for OptimalAgent to fit 10 agents opti_stats = ExperimentManager( OptimalAgent, (env_ctor, env_kwargs), fit_budget=5000, - n_fit=10, - parallelization="process", - mp_context="fork", + n_fit=1, ) opti_stats.fit() From 2570e22f19a080529aa749552b338d8e5aa1ecaf Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 27 Sep 2023 09:29:47 +0200 Subject: [PATCH 12/80] updating quickstart doc from .rst to .md --- docs/basics/quick_start_rl/quickstart.md | 399 ++++++++++++++++++++++ docs/basics/quick_start_rl/quickstart.rst | 397 --------------------- docs/conf.py | 2 +- docs/user_guide.rst | 20 +- 4 files changed, 410 insertions(+), 408 deletions(-) create mode 100644 docs/basics/quick_start_rl/quickstart.md delete mode 100644 docs/basics/quick_start_rl/quickstart.rst diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md new file mode 100644 index 000000000..6177ef308 --- /dev/null +++ b/docs/basics/quick_start_rl/quickstart.md @@ -0,0 +1,399 @@ +(quick_start)= + +Quick Start for Reinforcement Learning in rlberry +================================================= + +$$\def\CC{\bf C} +\def\QQ{\bf Q} +\def\RR{\bf R} +\def\ZZ{\bf Z} +\def\NN{\bf N}$$ + +Importing required libraries +---------------------------- + +```python +import numpy as np +import pandas as pd +import time +from rlberry.agents import UCBVIAgent, AgentWithSimplePolicy +from rlberry.envs import Chain +from rlberry.manager import ( + ExperimentManager, + evaluate_agents, + plot_writer_data, + read_writer_data, +) +from rlberry.wrappers import WriterWrapper +``` + +Choosing an RL environment +-------------------------- + +In this tutorial, we will use the [Chain](rlberry.envs.finite.chain.Chain) +environment, which is a very simple environment where the agent has to +go from one end of a chain to the other end. + +```python +env_ctor = Chain +env_kwargs = dict(L=10, fail_prob=0.1) +# chain of length 10. With proba 0.1, the agent will not be able to take the action it wants to take/ +env = env_ctor(**env_kwargs) +``` + +The agent has two actions, go to the left of to the right, but it might +move to a random direction according to a failure probability +`fail_prob=0.1`. + +Let us see a graphical representation + +```python +env.enable_rendering() +observation, info = env.reset() +for tt in range(5): + observation, reward, terminated, truncated, info = env.step(1) + done = terminated or truncated +video = env.save_video("video_chain.mp4", framerate=5) +``` + +```none +ffmpeg version n5.0 Copyright (c) 2000-2022 the FFmpeg developers + +: built with gcc 11.2.0 (GCC) configuration: \--prefix=/usr + \--disable-debug \--disable-static \--disable-stripping + \--enable-amf \--enable-avisynth \--enable-cuda-llvm \--enable-lto + \--enable-fontconfig \--enable-gmp \--enable-gnutls \--enable-gpl + \--enable-ladspa \--enable-libaom \--enable-libass + \--enable-libbluray \--enable-libdav1d \--enable-libdrm + \--enable-libfreetype \--enable-libfribidi \--enable-libgsm + \--enable-libiec61883 \--enable-libjack \--enable-libmfx + \--enable-libmodplug \--enable-libmp3lame + \--enable-libopencore\_amrnb \--enable-libopencore\_amrwb + \--enable-libopenjpeg \--enable-libopus \--enable-libpulse + \--enable-librav1e \--enable-librsvg \--enable-libsoxr + \--enable-libspeex \--enable-libsrt \--enable-libssh + \--enable-libsvtav1 \--enable-libtheora \--enable-libv4l2 + \--enable-libvidstab \--enable-libvmaf \--enable-libvorbis + \--enable-libvpx \--enable-libwebp \--enable-libx264 + \--enable-libx265 \--enable-libxcb \--enable-libxml2 + \--enable-libxvid \--enable-libzimg \--enable-nvdec \--enable-nvenc + \--enable-shared \--enable-version3 libavutil 57. 17.100 / 57. + 17.100 libavcodec 59. 18.100 / 59. 18.100 libavformat 59. 16.100 + / 59. 16.100 libavdevice 59. 4.100 / 59. 4.100 libavfilter 8. 24.100 + / 8. 24.100 libswscale 6. 4.100 / 6. 4.100 libswresample 4. 3.100 + / 4. 3.100 libpostproc 56. 3.100 / 56. 3.100 + +Input \#0, rawvideo, from \'pipe:\': + +: Duration: N/A, start: 0.000000, bitrate: 7680 kb/s Stream \#0:0: + Video: rawvideo (RGB\[24\] / 0x18424752), rgb24, 800x80, 7680 kb/s, + 5 tbr, 5 tbn + +Stream mapping: + +: Stream \#0:0 -\> \#0:0 (rawvideo (native) -\> h264 (libx264)) + +\[libx264 @ 0x564b9e570340\] using cpu capabilities: MMX2 SSE2Fast SSSE3 +SSE4.2 AVX FMA3 BMI2 AVX2 \[libx264 @ 0x564b9e570340\] profile High, +level 1.2, 4:2:0, 8-bit \[libx264 @ 0x564b9e570340\] 264 - core 164 +r3081 19856cc - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - + - options: cabac=1 ref=3 +deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy\_rd=1.00:0.00 +mixed\_ref=1 me\_range=16 chroma\_me=1 trellis=1 8x8dct=1 cqm=0 +deadzone=21,11 fast\_pskip=1 chroma\_qp\_offset=-2 threads=2 +lookahead\_threads=1 sliced\_threads=0 nr=0 decimate=1 interlaced=0 +bluray\_compat=0 constrained\_intra=0 bframes=3 b\_pyramid=2 b\_adapt=1 +b\_bias=0 direct=1 weightb=1 open\_gop=0 weightp=2 keyint=250 +keyint\_min=5 scenecut=40 intra\_refresh=0 rc\_lookahead=40 rc=crf +mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip\_ratio=1.40 +aq=1:1.00 Output \#0, mp4, to \'video\_chain.mp4\': Metadata: encoder : +Lavf59.16.100 Stream \#0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, +progressive), 800x80, q=2-31, 5 fps, 10240 tbn Metadata: encoder : +Lavc59.18.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer +size: 0 vbv\_delay: N/A frame= 6 fps=0.0 q=-1.0 Lsize= 4kB +time=00:00:00.60 bitrate= 48.8kbits/s speed=56.2x video:3kB audio:0kB +subtitle:0kB other streams:0kB global headers:0kB muxing overhead: +32.212582% \[libx264 @ 0x564b9e570340\] frame I:1 Avg QP: 6.94 size: 742 +\[libx264 @ 0x564b9e570340\] frame P:5 Avg QP:22.68 size: 267 \[libx264 +@ 0x564b9e570340\] mb I I16..4: 95.2% 0.0% 4.8% \[libx264 @ +0x564b9e570340\] mb P I16..4: 1.2% 2.1% 2.0% P16..4: 0.2% 0.0% 0.0% 0.0% +0.0% skip:94.6% \[libx264 @ 0x564b9e570340\] 8x8 transform intra:8.2% +inter:0.0% \[libx264 @ 0x564b9e570340\] coded y,uvDC,uvAC intra: 6.5% +12.3% 11.4% inter: 0.0% 0.0% 0.0% \[libx264 @ 0x564b9e570340\] i16 +v,h,dc,p: 79% 1% 20% 0% \[libx264 @ 0x564b9e570340\] i8 +v,h,dc,ddl,ddr,vr,hd,vl,hu: 0% 0% 100% 0% 0% 0% 0% 0% 0% \[libx264 @ +0x564b9e570340\] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 52% 22% 19% 1% 0% 3% 1% +3% 1% \[libx264 @ 0x564b9e570340\] i8c dc,h,v,p: 92% 4% 3% 0% \[libx264 +@ 0x564b9e570340\] Weighted P-Frames: Y:0.0% UV:0.0% \[libx264 @ +0x564b9e570340\] kb/s:13.85 +``` +
+ + + + + +Defining an agent and a baseline +-------------------------------- + +We will compare a RandomAgent (which plays random action) to the +[UCBVIAgent](rlberry.agents.ucbvi.ucbvi.UCBVIAgent), which is a algorithm that is designed to perform an +efficient exploration. Our goal is then to assess the performance of the +two algorithms. + +There are a number of agents that are already coded in rlberry. See the +module [Agent](rlberry.agents.Agent) for more +informations. + +Or, as we want for the RandomAgent, you can code your own agent : + +```python +# Create random agent as a baseline +class RandomAgent(AgentWithSimplePolicy): + name = "RandomAgent" + + def __init__(self, env, **kwargs): + AgentWithSimplePolicy.__init__(self, env, **kwargs) + + def fit(self, budget=100, **kwargs): + observation, info = self.env.reset() + for ep in range(budget): + action = self.policy(observation) + observation, reward, terminated, truncated, info = self.env.step(action) + + def policy(self, observation): + return self.env.action_space.sample() # choose an action at random +``` + +Experiment Manager +------------------ + +One of the main feature of rlberry is its +[ExperimentManager](rlberry.manager.ExperimentManager) +class. Here is a diagram to explain briefly what it does. + +![](experiment_manager_diagram.png){.align-center} + +In a few words, ExperimentManager spawns agents and environments for +training and then once the agents are trained, it uses these agents and +new environments to evaluate how well the agent perform. All of these +steps can be done several times to assess stochasticity of agents and/or +environment. + +Comparing the expected rewards of the final policies +---------------------------------------------------- + +We want to assess the expected reward of the policy learned by our +agents for a time horizon of (say) $T=20$. + +To do that we use 10 Monte-Carlo simulations, i.e., we do the experiment +10 times for each agent and at the end we take the mean of the obtained +reward. + +To check variability, we can train many instance of the same agent with +`n_fit` (here 1) Each instance of agent will train with a specific +budget `fit_budget` (here 100). Remark that `fit_budget` may not mean +the same thing among agents. + +In order to manage the agents, we use an Experiment Manager. The manager +will then spawn agents as desired during the experiment. + +```python +# Define parameters +ucbvi_params = {"gamma": 0.9, "horizon": 100} + +# Create ExperimentManager to fit 1 agent +ucbvi_stats = ExperimentManager( + UCBVIAgent, + (env_ctor, env_kwargs), + fit_budget=100, + eval_kwargs=dict(eval_horizon=20, n_simulations=10), + init_kwargs=ucbvi_params, + n_fit=1, +) +ucbvi_stats.fit() + +# Create ExperimentManager for baseline +baseline_stats = ExperimentManager( + RandomAgent, + (env_ctor, env_kwargs), + fit_budget=100, + eval_kwargs=dict(eval_horizon=20, n_simulations=10), + n_fit=1, +) +baseline_stats.fit() +``` + +```none +\[INFO\] Running ExperimentManager fit() for UCBVI with n\_fit = 1 and +max\_workers = None. \[INFO\] \... trained! \[INFO\] Running +ExperimentManager fit() for RandomAgent with n\_fit = 1 and max\_workers += None. \[INFO\] \... trained! +``` + +
+ +Evaluating and comparing the agents : + +```python +output = evaluate_agents([ucbvi_stats, baseline_stats], n_simulations=10, plot=True) +``` + +```none +\[INFO\] Evaluating UCBVI\... \[INFO\] \[eval\]\... simulation 1/10 +\[INFO\] \[eval\]\... simulation 2/10 \[INFO\] \[eval\]\... simulation +3/10 \[INFO\] \[eval\]\... simulation 4/10 \[INFO\] \[eval\]\... +simulation 5/10 \[INFO\] \[eval\]\... simulation 6/10 \[INFO\] +\[eval\]\... simulation 7/10 \[INFO\] \[eval\]\... simulation 8/10 +\[INFO\] \[eval\]\... simulation 9/10 \[INFO\] \[eval\]\... simulation +10/10 \[INFO\] Evaluating RandomAgent\... \[INFO\] \[eval\]\... +simulation 1/10 \[INFO\] \[eval\]\... simulation 2/10 \[INFO\] +\[eval\]\... simulation 3/10 \[INFO\] \[eval\]\... simulation 4/10 +\[INFO\] \[eval\]\... simulation 5/10 \[INFO\] \[eval\]\... simulation +6/10 \[INFO\] \[eval\]\... simulation 7/10 \[INFO\] \[eval\]\... +simulation 8/10 \[INFO\] \[eval\]\... simulation 9/10 \[INFO\] +\[eval\]\... simulation 10/10 +``` + +
+ +![image](output_10_1.png){.align-center} + +Comparing the agents during the learning period +----------------------------------------------- + +In the previous section, we compared the performance of the **final** +policies learned by the agents, **after** the learning period. + +To compare the performance of the agents **during** the learning period +(in the fit method), we can estimate their cumulative regret, which is +the difference between the rewards gathered by the agents during +training and the rewards of an optimal agent. Alternatively, if the we +cannot compute the optimal policy, we could simply compare the rewards +gathered during learning, instead of the regret. + +First, we have to record the reward during the fit as this is not done +automatically. To do this, we can use the +[WriterWrapper](rlberry.wrappers.writer_utils.WriterWrapper) +module, or simply the [writer](rlberry.agents.Agent.writer) attribute. + +```python +class RandomAgent2(RandomAgent): + name = "RandomAgent2" + + def __init__(self, env, **kwargs): + RandomAgent.__init__(self, env, **kwargs) + self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") + + +class UCBVIAgent2(UCBVIAgent): + name = "UCBVIAgent2" + + def __init__(self, env, **kwargs): + UCBVIAgent.__init__(self, env, **kwargs) + self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") +``` + +To compute the regret, we also need to define an optimal agent. Here +it's an agent that always chooses the action that moves to the right. + +```python +class OptimalAgent(AgentWithSimplePolicy): + name = "OptimalAgent" + + def __init__(self, env, **kwargs): + AgentWithSimplePolicy.__init__(self, env, **kwargs) + self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") + + def fit(self, budget=100, **kwargs): + observation, info = self.env.reset() + for ep in range(budget): + action = 1 + observation, reward, terminated, truncated, info = self.env.step(action) + done = terminated or truncated + + def policy(self, observation): + return 1 +``` + +Then, we fit the two agents and plot the data in the writer. + +```python +# Create ExperimentManager for UCBI to fit 10 agents +ucbvi_stats = ExperimentManager( + UCBVIAgent2, + (env_ctor, env_kwargs), + fit_budget=50, + init_kwargs=ucbvi_params, + n_fit=10, +) +ucbvi_stats.fit() + +# Create ExperimentManager for baseline to fit 10 agents +baseline_stats = ExperimentManager( + RandomAgent2, + (env_ctor, env_kwargs), + fit_budget=5000, + n_fit=10, +) +baseline_stats.fit() + +# Create ExperimentManager for OptimalAgent to fit 10 agents +opti_stats = ExperimentManager( + OptimalAgent, + (env_ctor, env_kwargs), + fit_budget=5000, + n_fit=1, +) +opti_stats.fit() +``` + +```none +\[INFO\] Running ExperimentManager fit() for UCBVIAgent2 with n\_fit = +10 and max\_workers = None. \[INFO\] \... trained! \[INFO\] Running +ExperimentManager fit() for RandomAgent2 with n\_fit = 10 and +max\_workers = None. \[INFO\] \... trained! \[INFO\] Running +ExperimentManager fit() for OptimalAgent with n\_fit = 10 and +max\_workers = None. \[INFO\] \... trained! +``` + +Remark that `fit_budget` may not mean the same thing among agents. For +OptimalAgent and RandomAgent `fit_budget` is the number of steps in the +environments that the agent is allowed to take. + +The reward that we recover is recorded every time env.step is called. + +For UCBVI this is the number of iterations of the algorithm and in each +iteration, the environment takes 100 steps (`horizon`) times the +`fit_budget`. Hence the fit\_budget used here + +Next, we estimate the optimal reward using the optimal policy. + +Be careful that this is only an estimation: we estimate the optimal +regret using Monte Carlo and the optimal policy. + +```python +df = plot_writer_data(opti_stats, tag="reward", show=False) +df = df.loc[df["tag"] == "reward"][["global_step", "value"]] +opti_reward = df.groupby("global_step").mean()["value"].values +``` + +Finally, we plot the cumulative regret using the 5000 reward values. + +```python +def compute_regret(rewards): + return np.cumsum(opti_reward - rewards[: len(opti_reward)]) + + +# Plot of the cumulative reward. +output = plot_writer_data( + [ucbvi_stats, baseline_stats], + tag="reward", + preprocess_func=compute_regret, + title="Cumulative Regret", +) +``` + +![image](output_19_0.png){.align-center} diff --git a/docs/basics/quick_start_rl/quickstart.rst b/docs/basics/quick_start_rl/quickstart.rst deleted file mode 100644 index fced10319..000000000 --- a/docs/basics/quick_start_rl/quickstart.rst +++ /dev/null @@ -1,397 +0,0 @@ -.. _quick_start: - -.. highlight:: none - -Quick Start for Reinforcement Learning in rlberry -================================================= - -.. math:: - - - \def\CC{\bf C} - \def\QQ{\bf Q} - \def\RR{\bf R} - \def\ZZ{\bf Z} - \def\NN{\bf N} - - -Importing required libraries ----------------------------- - -.. code:: python - - import numpy as np - import pandas as pd - import time - from rlberry.agents import UCBVIAgent, AgentWithSimplePolicy - from rlberry.envs import Chain - from rlberry.manager import ( - ExperimentManager, - evaluate_agents, - plot_writer_data, - read_writer_data, - ) - from rlberry.wrappers import WriterWrapper - -Choosing an RL environment --------------------------- - -In this tutorial, we will use the :class:`~rlberry.envs.finite.chain.Chain` -environment, which is a very simple environment where the agent has to go from one -end of a chain to the other end. - - -.. code:: python - - env_ctor = Chain - env_kwargs = dict(L=10, fail_prob=0.1) - # chain of length 10. With proba 0.1, the agent will not be able to take the action it wants to take/ - env = env_ctor(**env_kwargs) - - -The agent has two actions, go to the left of to the right, but it might -move to a random direction according to a failure probability -``fail_prob=0.1``. - -Let us see a graphical representation - -.. code:: python - - env.enable_rendering() - observation, info = env.reset() - for tt in range(5): - observation, reward, terminated, truncated, info = env.step(1) - done = terminated or truncated - video = env.save_video("video_chain.mp4", framerate=5) - - -.. parsed-literal:: - - ffmpeg version n5.0 Copyright (c) 2000-2022 the FFmpeg developers - built with gcc 11.2.0 (GCC) - configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec --enable-nvenc --enable-shared --enable-version3 - libavutil 57. 17.100 / 57. 17.100 - libavcodec 59. 18.100 / 59. 18.100 - libavformat 59. 16.100 / 59. 16.100 - libavdevice 59. 4.100 / 59. 4.100 - libavfilter 8. 24.100 / 8. 24.100 - libswscale 6. 4.100 / 6. 4.100 - libswresample 4. 3.100 / 4. 3.100 - libpostproc 56. 3.100 / 56. 3.100 - Input #0, rawvideo, from 'pipe:': - Duration: N/A, start: 0.000000, bitrate: 7680 kb/s - Stream #0:0: Video: rawvideo (RGB[24] / 0x18424752), rgb24, 800x80, 7680 kb/s, 5 tbr, 5 tbn - Stream mapping: - Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (libx264)) - [libx264 @ 0x564b9e570340] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 - [libx264 @ 0x564b9e570340] profile High, level 1.2, 4:2:0, 8-bit - [libx264 @ 0x564b9e570340] 264 - core 164 r3081 19856cc - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=2 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=5 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 - Output #0, mp4, to 'video_chain.mp4': - Metadata: - encoder : Lavf59.16.100 - Stream #0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, progressive), 800x80, q=2-31, 5 fps, 10240 tbn - Metadata: - encoder : Lavc59.18.100 libx264 - Side data: - cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A - frame= 6 fps=0.0 q=-1.0 Lsize= 4kB time=00:00:00.60 bitrate= 48.8kbits/s speed=56.2x - video:3kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 32.212582% - [libx264 @ 0x564b9e570340] frame I:1 Avg QP: 6.94 size: 742 - [libx264 @ 0x564b9e570340] frame P:5 Avg QP:22.68 size: 267 - [libx264 @ 0x564b9e570340] mb I I16..4: 95.2% 0.0% 4.8% - [libx264 @ 0x564b9e570340] mb P I16..4: 1.2% 2.1% 2.0% P16..4: 0.2% 0.0% 0.0% 0.0% 0.0% skip:94.6% - [libx264 @ 0x564b9e570340] 8x8 transform intra:8.2% inter:0.0% - [libx264 @ 0x564b9e570340] coded y,uvDC,uvAC intra: 6.5% 12.3% 11.4% inter: 0.0% 0.0% 0.0% - [libx264 @ 0x564b9e570340] i16 v,h,dc,p: 79% 1% 20% 0% - [libx264 @ 0x564b9e570340] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 0% 0% 100% 0% 0% 0% 0% 0% 0% - [libx264 @ 0x564b9e570340] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 52% 22% 19% 1% 0% 3% 1% 3% 1% - [libx264 @ 0x564b9e570340] i8c dc,h,v,p: 92% 4% 3% 0% - [libx264 @ 0x564b9e570340] Weighted P-Frames: Y:0.0% UV:0.0% - [libx264 @ 0x564b9e570340] kb/s:13.85 - -| - -.. video:: ../../video_chain_quickstart.mp4 - :width: 600 - -| - -Defining an agent and a baseline --------------------------------- - -We will compare a RandomAgent (which plays random action) to the -:class:`~rlberry.agents.ucbvi.ucbvi.UCBVIAgent`, which -is a algorithm that is designed to perform an efficient exploration. -Our goal is then to assess the performance of the two algorithms. - -There are a number of agents that are already coded in rlberry. See the -module :class:`~rlberry.agents.Agent` for more informations. - -Or, as we want for the RandomAgent, you can code your own agent : - -.. code:: python - - # Create random agent as a baseline - class RandomAgent(AgentWithSimplePolicy): - name = "RandomAgent" - - def __init__(self, env, **kwargs): - AgentWithSimplePolicy.__init__(self, env, **kwargs) - - def fit(self, budget=100, **kwargs): - observation, info = self.env.reset() - for ep in range(budget): - action = self.policy(observation) - observation, reward, terminated, truncated, info = self.env.step(action) - - def policy(self, observation): - return self.env.action_space.sample() # choose an action at random - - - - -Experiment Manager -------------- - -One of the main feature of rlberry is its :class:`~rlberry.manager.ExperimentManager` -class. Here is a diagram to explain briefly what it does. - - -.. figure:: experiment_manager_diagram.png - :align: center - - -In a few words, ExperimentManager spawns agents and environments for training and -then once the agents are trained, it uses these agents and new environments -to evaluate how well the agent perform. All of these steps can be -done several times to assess stochasticity of agents and/or environment. - -Comparing the expected rewards of the final policies ----------------------------------------------------- - - -We want to assess the expected reward of the policy learned by our agents -for a time horizon of (say) :math:`T=20`. - -To do that we use 10 Monte-Carlo simulations, i.e., we do the experiment -10 times for each agent and at the end we take the mean of the obtained reward. - -To check variability, we can train many instance of the same agent with ``n_fit`` (here 1) -Each instance of agent will train with a specific budget ``fit_budget`` (here 100). -Remark that ``fit_budget`` may not mean the same thing among agents. - -In order to manage the agents, we use an Experiment Manager. The manager will -then spawn agents as desired during the experiment. - - -.. code:: python - - # Define parameters - ucbvi_params = {"gamma": 0.9, "horizon": 100} - - # Create ExperimentManager to fit 1 agent - ucbvi_stats = ExperimentManager( - UCBVIAgent, - (env_ctor, env_kwargs), - fit_budget=100, - eval_kwargs=dict(eval_horizon=20, n_simulations=10), - init_kwargs=ucbvi_params, - n_fit=1, - ) - ucbvi_stats.fit() - - # Create ExperimentManager for baseline - baseline_stats = ExperimentManager( - RandomAgent, - (env_ctor, env_kwargs), - fit_budget=100, - eval_kwargs=dict(eval_horizon=20, n_simulations=10), - n_fit=1, - ) - baseline_stats.fit() - - - -.. parsed-literal:: - - [INFO] Running ExperimentManager fit() for UCBVI with n_fit = 1 and max_workers = None. - [INFO] ... trained! - [INFO] Running ExperimentManager fit() for RandomAgent with n_fit = 1 and max_workers = None. - [INFO] ... trained! - -| Evaluating and comparing the agents : - -.. code:: python - - output = evaluate_agents([ucbvi_stats, baseline_stats], n_simulations=10, plot=True) - - -.. parsed-literal:: - - [INFO] Evaluating UCBVI... - [INFO] [eval]... simulation 1/10 - [INFO] [eval]... simulation 2/10 - [INFO] [eval]... simulation 3/10 - [INFO] [eval]... simulation 4/10 - [INFO] [eval]... simulation 5/10 - [INFO] [eval]... simulation 6/10 - [INFO] [eval]... simulation 7/10 - [INFO] [eval]... simulation 8/10 - [INFO] [eval]... simulation 9/10 - [INFO] [eval]... simulation 10/10 - [INFO] Evaluating RandomAgent... - [INFO] [eval]... simulation 1/10 - [INFO] [eval]... simulation 2/10 - [INFO] [eval]... simulation 3/10 - [INFO] [eval]... simulation 4/10 - [INFO] [eval]... simulation 5/10 - [INFO] [eval]... simulation 6/10 - [INFO] [eval]... simulation 7/10 - [INFO] [eval]... simulation 8/10 - [INFO] [eval]... simulation 9/10 - [INFO] [eval]... simulation 10/10 - - - -.. image:: output_10_1.png - :align: center - -Comparing the agents during the learning period ------------------------------------------------- - -In the previous section, we compared the performance of the **final** policies learned by -the agents, **after** the learning period. - -To compare the performance of the agents **during** the learning period -(in the fit method), we can estimate their cumulative regret, which is the difference -between the rewards gathered by the agents during training and the -rewards of an optimal agent. Alternatively, if the we cannot compute the optimal -policy, we could simply compare the rewards gathered during learning, instead of the regret. - -First, we have to record the reward during the fit as this is not done -automatically. To do this, we can use the :class:`~rlberry.wrappers.writer_utils.WriterWrapper` -module, or simply the `Agent.writer` attribute. - -.. code:: python - - class RandomAgent2(RandomAgent): - name = "RandomAgent2" - - def __init__(self, env, **kwargs): - RandomAgent.__init__(self, env, **kwargs) - self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") - - - class UCBVIAgent2(UCBVIAgent): - name = "UCBVIAgent2" - - def __init__(self, env, **kwargs): - UCBVIAgent.__init__(self, env, **kwargs) - self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") - -To compute the regret, we also need to define an optimal agent. Here -it’s an agent that always chooses the action that moves to the right. - -.. code:: python - - class OptimalAgent(AgentWithSimplePolicy): - name = "OptimalAgent" - - def __init__(self, env, **kwargs): - AgentWithSimplePolicy.__init__(self, env, **kwargs) - self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") - - def fit(self, budget=100, **kwargs): - observation, info = self.env.reset() - for ep in range(budget): - action = 1 - observation, reward, terminated, truncated, info = self.env.step(action) - done = terminated or truncated - - def policy(self, observation): - return 1 - -Then, we fit the two agents and plot the data in the writer. - -.. code:: python - - # Create ExperimentManager for UCBI to fit 10 agents - ucbvi_stats = ExperimentManager( - UCBVIAgent2, - (env_ctor, env_kwargs), - fit_budget=50, - init_kwargs=ucbvi_params, - n_fit=10, - ) - ucbvi_stats.fit() - - # Create ExperimentManager for baseline to fit 10 agents - baseline_stats = ExperimentManager( - RandomAgent2, - (env_ctor, env_kwargs), - fit_budget=5000, - n_fit=10, - ) - baseline_stats.fit() - - # Create ExperimentManager for OptimalAgent to fit 10 agents - opti_stats = ExperimentManager( - OptimalAgent, - (env_ctor, env_kwargs), - fit_budget=5000, - n_fit=1, - ) - opti_stats.fit() - - -.. parsed-literal:: - - [INFO] Running ExperimentManager fit() for UCBVIAgent2 with n_fit = 10 and max_workers = None. - [INFO] ... trained! - [INFO] Running ExperimentManager fit() for RandomAgent2 with n_fit = 10 and max_workers = None. - [INFO] ... trained! - [INFO] Running ExperimentManager fit() for OptimalAgent with n_fit = 10 and max_workers = None. - [INFO] ... trained! - -Remark that ``fit_budget`` may not mean the same thing among agents. For -OptimalAgent and RandomAgent ``fit_budget`` is the number of steps in -the environments that the agent is allowed to take. - -The reward that we recover is recorded every time env.step is called. - -For UCBVI this is the number of iterations of the algorithm and in each -iteration, the environment takes 100 steps (``horizon``) times the -``fit_budget``. Hence the fit_budget used here - -Next, we estimate the optimal reward using the optimal policy. - -Be careful that this is only an estimation: we estimate the optimal -regret using Monte Carlo and the optimal policy. - -.. code:: python - - df = plot_writer_data(opti_stats, tag="reward", show=False) - df = df.loc[df["tag"] == "reward"][["global_step", "value"]] - opti_reward = df.groupby("global_step").mean()["value"].values - -Finally, we plot the cumulative regret using the 5000 reward values. - - -.. code:: python - - def compute_regret(rewards): - return np.cumsum(opti_reward - rewards[: len(opti_reward)]) - - - # Plot of the cumulative reward. - output = plot_writer_data( - [ucbvi_stats, baseline_stats], - tag="reward", - preprocess_func=compute_regret, - title="Cumulative Regret", - ) - - - -.. image:: output_19_0.png - :align: center diff --git a/docs/conf.py b/docs/conf.py index e7ceb34d2..b3350a6f6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,7 +50,7 @@ "myst_parser", ] -myst_enable_extensions = ["amsmath"] +myst_enable_extensions = ["amsmath","attrs_inline"] # myst_enable_extensions = [ # "amsmath", # "colon_fence", diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 8405d52a0..821087a1f 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -8,17 +8,17 @@ User guide Introduction ------------ -Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to -the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and -deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. -Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). -In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). +.. Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to +.. the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and +.. deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. +.. Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). +.. In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). -.. If you are new to rlberry, check the :ref:`Tutorials` below and the :ref:`the quickstart` documentation. -.. In the quick start, you will learn how to set up an experiment and evaluate the -.. efficiency of different agents. +If you are new to rlberry, check the :ref:`Tutorials` below and the :ref:`the quickstart` documentation. +In the quick start, you will learn how to set up an experiment and evaluate the +efficiency of different agents. -.. For more information see :ref:`the gallery of examples`. +For more information see :ref:`the gallery of examples`. Tutorials @@ -41,7 +41,7 @@ Quick start: setup an experiment and evaluate different agents .. toctree:: :maxdepth: 2 - basics/quick_start_rl/quickstart.rst + basics/quick_start_rl/quickstart.md basics/DeepRLTutorial/TutorialDeepRL.rst From 668aa30cc8394830028d68d1ae507538fbbebcf7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 07:36:31 +0000 Subject: [PATCH 13/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/quick_start_rl/quickstart.md | 8 ++++---- docs/conf.py | 2 +- docs/themes/scikit-learn-fork/static/css/theme.css | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 6177ef308..ff85bb9aa 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -167,10 +167,10 @@ class RandomAgent(AgentWithSimplePolicy): return self.env.action_space.sample() # choose an action at random ``` -Experiment Manager +Experiment Manager ------------------ -One of the main feature of rlberry is its +One of the main feature of rlberry is its [ExperimentManager](rlberry.manager.ExperimentManager) class. Here is a diagram to explain briefly what it does. @@ -275,7 +275,7 @@ cannot compute the optimal policy, we could simply compare the rewards gathered during learning, instead of the regret. First, we have to record the reward during the fit as this is not done -automatically. To do this, we can use the +automatically. To do this, we can use the [WriterWrapper](rlberry.wrappers.writer_utils.WriterWrapper) module, or simply the [writer](rlberry.agents.Agent.writer) attribute. @@ -328,7 +328,7 @@ ucbvi_stats = ExperimentManager( fit_budget=50, init_kwargs=ucbvi_params, n_fit=10, -) +) ucbvi_stats.fit() # Create ExperimentManager for baseline to fit 10 agents diff --git a/docs/conf.py b/docs/conf.py index b3350a6f6..47d2757f3 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,7 +50,7 @@ "myst_parser", ] -myst_enable_extensions = ["amsmath","attrs_inline"] +myst_enable_extensions = ["amsmath", "attrs_inline"] # myst_enable_extensions = [ # "amsmath", # "colon_fence", diff --git a/docs/themes/scikit-learn-fork/static/css/theme.css b/docs/themes/scikit-learn-fork/static/css/theme.css index 108cdd4b2..f4f6efb8d 100644 --- a/docs/themes/scikit-learn-fork/static/css/theme.css +++ b/docs/themes/scikit-learn-fork/static/css/theme.css @@ -90,12 +90,12 @@ div.highlight { div.highlight-none{ max-height: 300px; overflow-y: auto; - background-color: #ddd; + background-color: #ddd; } div.highlight-default{ max-height: 300px; overflow-y: auto; - background-color: #ddd; + background-color: #ddd; } div.highlight-python{ background-color: #f8f8f8; From 89aff8c0e66def0cce050e93e25af794b5a5a531 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 27 Sep 2023 16:43:16 +0200 Subject: [PATCH 14/80] fix pandoc mistakes --- docs/basics/quick_start_rl/quickstart.md | 167 ++++++++++------------- 1 file changed, 74 insertions(+), 93 deletions(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index ff85bb9aa..8cf564835 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -57,75 +57,47 @@ video = env.save_video("video_chain.mp4", framerate=5) ``` ```none -ffmpeg version n5.0 Copyright (c) 2000-2022 the FFmpeg developers - -: built with gcc 11.2.0 (GCC) configuration: \--prefix=/usr - \--disable-debug \--disable-static \--disable-stripping - \--enable-amf \--enable-avisynth \--enable-cuda-llvm \--enable-lto - \--enable-fontconfig \--enable-gmp \--enable-gnutls \--enable-gpl - \--enable-ladspa \--enable-libaom \--enable-libass - \--enable-libbluray \--enable-libdav1d \--enable-libdrm - \--enable-libfreetype \--enable-libfribidi \--enable-libgsm - \--enable-libiec61883 \--enable-libjack \--enable-libmfx - \--enable-libmodplug \--enable-libmp3lame - \--enable-libopencore\_amrnb \--enable-libopencore\_amrwb - \--enable-libopenjpeg \--enable-libopus \--enable-libpulse - \--enable-librav1e \--enable-librsvg \--enable-libsoxr - \--enable-libspeex \--enable-libsrt \--enable-libssh - \--enable-libsvtav1 \--enable-libtheora \--enable-libv4l2 - \--enable-libvidstab \--enable-libvmaf \--enable-libvorbis - \--enable-libvpx \--enable-libwebp \--enable-libx264 - \--enable-libx265 \--enable-libxcb \--enable-libxml2 - \--enable-libxvid \--enable-libzimg \--enable-nvdec \--enable-nvenc - \--enable-shared \--enable-version3 libavutil 57. 17.100 / 57. - 17.100 libavcodec 59. 18.100 / 59. 18.100 libavformat 59. 16.100 - / 59. 16.100 libavdevice 59. 4.100 / 59. 4.100 libavfilter 8. 24.100 - / 8. 24.100 libswscale 6. 4.100 / 6. 4.100 libswresample 4. 3.100 - / 4. 3.100 libpostproc 56. 3.100 / 56. 3.100 - -Input \#0, rawvideo, from \'pipe:\': - -: Duration: N/A, start: 0.000000, bitrate: 7680 kb/s Stream \#0:0: - Video: rawvideo (RGB\[24\] / 0x18424752), rgb24, 800x80, 7680 kb/s, - 5 tbr, 5 tbn - -Stream mapping: - -: Stream \#0:0 -\> \#0:0 (rawvideo (native) -\> h264 (libx264)) - -\[libx264 @ 0x564b9e570340\] using cpu capabilities: MMX2 SSE2Fast SSSE3 -SSE4.2 AVX FMA3 BMI2 AVX2 \[libx264 @ 0x564b9e570340\] profile High, -level 1.2, 4:2:0, 8-bit \[libx264 @ 0x564b9e570340\] 264 - core 164 -r3081 19856cc - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - - - options: cabac=1 ref=3 -deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy\_rd=1.00:0.00 -mixed\_ref=1 me\_range=16 chroma\_me=1 trellis=1 8x8dct=1 cqm=0 -deadzone=21,11 fast\_pskip=1 chroma\_qp\_offset=-2 threads=2 -lookahead\_threads=1 sliced\_threads=0 nr=0 decimate=1 interlaced=0 -bluray\_compat=0 constrained\_intra=0 bframes=3 b\_pyramid=2 b\_adapt=1 -b\_bias=0 direct=1 weightb=1 open\_gop=0 weightp=2 keyint=250 -keyint\_min=5 scenecut=40 intra\_refresh=0 rc\_lookahead=40 rc=crf -mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip\_ratio=1.40 -aq=1:1.00 Output \#0, mp4, to \'video\_chain.mp4\': Metadata: encoder : -Lavf59.16.100 Stream \#0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, -progressive), 800x80, q=2-31, 5 fps, 10240 tbn Metadata: encoder : -Lavc59.18.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer -size: 0 vbv\_delay: N/A frame= 6 fps=0.0 q=-1.0 Lsize= 4kB -time=00:00:00.60 bitrate= 48.8kbits/s speed=56.2x video:3kB audio:0kB -subtitle:0kB other streams:0kB global headers:0kB muxing overhead: -32.212582% \[libx264 @ 0x564b9e570340\] frame I:1 Avg QP: 6.94 size: 742 -\[libx264 @ 0x564b9e570340\] frame P:5 Avg QP:22.68 size: 267 \[libx264 -@ 0x564b9e570340\] mb I I16..4: 95.2% 0.0% 4.8% \[libx264 @ -0x564b9e570340\] mb P I16..4: 1.2% 2.1% 2.0% P16..4: 0.2% 0.0% 0.0% 0.0% -0.0% skip:94.6% \[libx264 @ 0x564b9e570340\] 8x8 transform intra:8.2% -inter:0.0% \[libx264 @ 0x564b9e570340\] coded y,uvDC,uvAC intra: 6.5% -12.3% 11.4% inter: 0.0% 0.0% 0.0% \[libx264 @ 0x564b9e570340\] i16 -v,h,dc,p: 79% 1% 20% 0% \[libx264 @ 0x564b9e570340\] i8 -v,h,dc,ddl,ddr,vr,hd,vl,hu: 0% 0% 100% 0% 0% 0% 0% 0% 0% \[libx264 @ -0x564b9e570340\] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 52% 22% 19% 1% 0% 3% 1% -3% 1% \[libx264 @ 0x564b9e570340\] i8c dc,h,v,p: 92% 4% 3% 0% \[libx264 -@ 0x564b9e570340\] Weighted P-Frames: Y:0.0% UV:0.0% \[libx264 @ -0x564b9e570340\] kb/s:13.85 + ffmpeg version n5.0 Copyright (c) 2000-2022 the FFmpeg developers + built with gcc 11.2.0 (GCC) + configuration: --prefix=/usr --disable-debug --disable-static --disable-stripping --enable-amf --enable-avisynth --enable-cuda-llvm --enable-lto --enable-fontconfig --enable-gmp --enable-gnutls --enable-gpl --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libdav1d --enable-libdrm --enable-libfreetype --enable-libfribidi --enable-libgsm --enable-libiec61883 --enable-libjack --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-libpulse --enable-librav1e --enable-librsvg --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtheora --enable-libv4l2 --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxcb --enable-libxml2 --enable-libxvid --enable-libzimg --enable-nvdec --enable-nvenc --enable-shared --enable-version3 + libavutil 57. 17.100 / 57. 17.100 + libavcodec 59. 18.100 / 59. 18.100 + libavformat 59. 16.100 / 59. 16.100 + libavdevice 59. 4.100 / 59. 4.100 + libavfilter 8. 24.100 / 8. 24.100 + libswscale 6. 4.100 / 6. 4.100 + libswresample 4. 3.100 / 4. 3.100 + libpostproc 56. 3.100 / 56. 3.100 + Input #0, rawvideo, from 'pipe:': + Duration: N/A, start: 0.000000, bitrate: 7680 kb/s + Stream #0:0: Video: rawvideo (RGB[24] / 0x18424752), rgb24, 800x80, 7680 kb/s, 5 tbr, 5 tbn + Stream mapping: + Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (libx264)) + [libx264 @ 0x564b9e570340] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 + [libx264 @ 0x564b9e570340] profile High, level 1.2, 4:2:0, 8-bit + [libx264 @ 0x564b9e570340] 264 - core 164 r3081 19856cc - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=2 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=5 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 + Output #0, mp4, to 'video_chain.mp4': + Metadata: + encoder : Lavf59.16.100 + Stream #0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, progressive), 800x80, q=2-31, 5 fps, 10240 tbn + Metadata: + encoder : Lavc59.18.100 libx264 + Side data: + cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A + frame= 6 fps=0.0 q=-1.0 Lsize= 4kB time=00:00:00.60 bitrate= 48.8kbits/s speed=56.2x + video:3kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 32.212582% + [libx264 @ 0x564b9e570340] frame I:1 Avg QP: 6.94 size: 742 + [libx264 @ 0x564b9e570340] frame P:5 Avg QP:22.68 size: 267 + [libx264 @ 0x564b9e570340] mb I I16..4: 95.2% 0.0% 4.8% + [libx264 @ 0x564b9e570340] mb P I16..4: 1.2% 2.1% 2.0% P16..4: 0.2% 0.0% 0.0% 0.0% 0.0% skip:94.6% + [libx264 @ 0x564b9e570340] 8x8 transform intra:8.2% inter:0.0% + [libx264 @ 0x564b9e570340] coded y,uvDC,uvAC intra: 6.5% 12.3% 11.4% inter: 0.0% 0.0% 0.0% + [libx264 @ 0x564b9e570340] i16 v,h,dc,p: 79% 1% 20% 0% + [libx264 @ 0x564b9e570340] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 0% 0% 100% 0% 0% 0% 0% 0% 0% + [libx264 @ 0x564b9e570340] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 52% 22% 19% 1% 0% 3% 1% 3% 1% + [libx264 @ 0x564b9e570340] i8c dc,h,v,p: 92% 4% 3% 0% + [libx264 @ 0x564b9e570340] Weighted P-Frames: Y:0.0% UV:0.0% + [libx264 @ 0x564b9e570340] kb/s:13.85 ```
@@ -227,10 +199,10 @@ baseline_stats.fit() ``` ```none -\[INFO\] Running ExperimentManager fit() for UCBVI with n\_fit = 1 and -max\_workers = None. \[INFO\] \... trained! \[INFO\] Running -ExperimentManager fit() for RandomAgent with n\_fit = 1 and max\_workers -= None. \[INFO\] \... trained! + [INFO] Running ExperimentManager fit() for UCBVI with n_fit = 1 and max_workers = None. + [INFO] ... trained! + [INFO] Running ExperimentManager fit() for RandomAgent with n_fit = 1 and max_workers = None. + [INFO] ... trained! ```
@@ -242,19 +214,28 @@ output = evaluate_agents([ucbvi_stats, baseline_stats], n_simulations=10, plot=T ``` ```none -\[INFO\] Evaluating UCBVI\... \[INFO\] \[eval\]\... simulation 1/10 -\[INFO\] \[eval\]\... simulation 2/10 \[INFO\] \[eval\]\... simulation -3/10 \[INFO\] \[eval\]\... simulation 4/10 \[INFO\] \[eval\]\... -simulation 5/10 \[INFO\] \[eval\]\... simulation 6/10 \[INFO\] -\[eval\]\... simulation 7/10 \[INFO\] \[eval\]\... simulation 8/10 -\[INFO\] \[eval\]\... simulation 9/10 \[INFO\] \[eval\]\... simulation -10/10 \[INFO\] Evaluating RandomAgent\... \[INFO\] \[eval\]\... -simulation 1/10 \[INFO\] \[eval\]\... simulation 2/10 \[INFO\] -\[eval\]\... simulation 3/10 \[INFO\] \[eval\]\... simulation 4/10 -\[INFO\] \[eval\]\... simulation 5/10 \[INFO\] \[eval\]\... simulation -6/10 \[INFO\] \[eval\]\... simulation 7/10 \[INFO\] \[eval\]\... -simulation 8/10 \[INFO\] \[eval\]\... simulation 9/10 \[INFO\] -\[eval\]\... simulation 10/10 + [INFO] Evaluating UCBVI... + [INFO] [eval]... simulation 1/10 + [INFO] [eval]... simulation 2/10 + [INFO] [eval]... simulation 3/10 + [INFO] [eval]... simulation 4/10 + [INFO] [eval]... simulation 5/10 + [INFO] [eval]... simulation 6/10 + [INFO] [eval]... simulation 7/10 + [INFO] [eval]... simulation 8/10 + [INFO] [eval]... simulation 9/10 + [INFO] [eval]... simulation 10/10 + [INFO] Evaluating RandomAgent... + [INFO] [eval]... simulation 1/10 + [INFO] [eval]... simulation 2/10 + [INFO] [eval]... simulation 3/10 + [INFO] [eval]... simulation 4/10 + [INFO] [eval]... simulation 5/10 + [INFO] [eval]... simulation 6/10 + [INFO] [eval]... simulation 7/10 + [INFO] [eval]... simulation 8/10 + [INFO] [eval]... simulation 9/10 + [INFO] [eval]... simulation 10/10 ```
@@ -351,12 +332,12 @@ opti_stats.fit() ``` ```none -\[INFO\] Running ExperimentManager fit() for UCBVIAgent2 with n\_fit = -10 and max\_workers = None. \[INFO\] \... trained! \[INFO\] Running -ExperimentManager fit() for RandomAgent2 with n\_fit = 10 and -max\_workers = None. \[INFO\] \... trained! \[INFO\] Running -ExperimentManager fit() for OptimalAgent with n\_fit = 10 and -max\_workers = None. \[INFO\] \... trained! + [INFO] Running ExperimentManager fit() for UCBVIAgent2 with n_fit = 10 and max_workers = None. + [INFO] ... trained! + [INFO] Running ExperimentManager fit() for RandomAgent2 with n_fit = 10 and max_workers = None. + [INFO] ... trained! + [INFO] Running ExperimentManager fit() for OptimalAgent with n_fit = 10 and max_workers = None. + [INFO] ... trained! ``` Remark that `fit_budget` may not mean the same thing among agents. For @@ -367,7 +348,7 @@ The reward that we recover is recorded every time env.step is called. For UCBVI this is the number of iterations of the algorithm and in each iteration, the environment takes 100 steps (`horizon`) times the -`fit_budget`. Hence the fit\_budget used here +`fit_budget`. Hence the fit_budget used here Next, we estimate the optimal reward using the optimal policy. From 9409244676bfacddd834fdef721f563f5f326392 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 27 Sep 2023 16:43:56 +0200 Subject: [PATCH 15/80] updating TutorialDeepRL doc from .rst to .md --- docs/basics/DeepRLTutorial/TutorialDeepRL.md | 567 +++++++++++++++++ docs/basics/DeepRLTutorial/TutorialDeepRL.rst | 591 ------------------ docs/user_guide.rst | 6 +- 3 files changed, 570 insertions(+), 594 deletions(-) create mode 100644 docs/basics/DeepRLTutorial/TutorialDeepRL.md delete mode 100644 docs/basics/DeepRLTutorial/TutorialDeepRL.rst diff --git a/docs/basics/DeepRLTutorial/TutorialDeepRL.md b/docs/basics/DeepRLTutorial/TutorialDeepRL.md new file mode 100644 index 000000000..f9390e64d --- /dev/null +++ b/docs/basics/DeepRLTutorial/TutorialDeepRL.md @@ -0,0 +1,567 @@ +(TutorialDeepRL)= + +Quickstart for Deep Reinforcement Learning in rlberry +===================================================== + +In this tutorial, we will focus on Deep Reinforcement Learning with the +**Advantage Actor-Critic** algorithm. + +Imports +------- + +```python +from rlberry.envs import gym_make +from rlberry.manager import plot_writer_data, ExperimentManager, evaluate_agents +from rlberry.agents.torch import A2CAgent +from rlberry.agents.torch.utils.training import model_factory_from_env +``` + +Reminder of the RL setting +-------------------------- + +We will consider a MDP $M = (\mathcal{S}, \mathcal{A}, p, r, \gamma)$ +with: + +- $\mathcal{S}$ the state space, +- $\mathcal{A}$ the action space, +- $p(x^\prime \mid x, a)$ the transition probability, +- $r(x, a, x^\prime)$ the reward of the transition $(x, a, x^\prime)$, +- $\gamma \in [0,1)$ is the discount factor. + +A policy $\pi$ is a mapping from the state space $\mathcal{S}$ to the +probability of selecting each action. The action value function of a +policy is the overall expected reward from a state action. +$Q^\pi(s, a) = \mathbb{E}_{\tau \sim \pi}\big[R(\tau) \mid s_0=s, a_0=a\big]$ +where $\tau$ is an episode +$(s_0, a_0, r_0, s_1, a_1, r_1, s_2, ..., s_T, a_T, r_T)$ with the +actions drawn from $\pi(s)$; $R(\tau)$ is the random variable defined as +the cumulative sum of the discounted reward. + +The goal is to maximize the cumulative sum of discount rewards: + +$$J(\pi) = \mathbb{E}_{\tau \sim \pi}\big[R(\tau) \big]$$ + +Gymnasium Environment +--------------------- + +In this tutorial we are going to use the [Gymnasium library (previously +OpenAI's Gym)](https://gymnasium.farama.org/api/env/). This library +provides a large number of environments to test RL algorithm. + +We will focus only on the **CartPole-v1** environment, although we +recommend experimenting with other environments such as **Acrobot-v1** +and **MountainCar-v0**. The following table presents some basic +components of the three environments, such as the dimensions of their +observation and action spaces and the rewards occurring at each step. + + | Env Info | CartPole-v1 | Acrobot-v1 | MountainCar-v0 | + |:----------------------|:------------|:----------------------------|:---------------| + | **Observation Space** | Box(4) | Box(6) | Box(2) | + | **Action Space** | Discrete(2)| Discrete(3) | Discrete(3) | + | **Rewards** | 1 per step | -1 if not terminal else 0 | -1 per step | + +Actor-Critic algorithms and A2C +------------------------------- + +**Actor-Critic algorithms** methods consist of two models, which may +optionally share parameters: + +- Critic updates the value function parameters w and depending on the +algorithm it could be action-value $Q_{\varphi}(s,a )$ or state-value +$V_{\varphi}(s)$. +- Actor updates the policy parameters $\theta$ for +$\pi_{\theta}(a \mid s)$, in the direction suggested by the critic. + +**A2C** is an Actor-Critic algorithm and it is part of the on-policy +family, which means that we are learning the value function for one +policy while following it. The original paper in which it was proposed +can be found [here](https://arxiv.org/pdf/1602.01783.pdf) and the +pseudocode of the algorithm is the following: + +- Initialize the actor $\pi_{\theta}$ and the critic $V_{\varphi}$ + with random weights. +- Observe the initial state $s_{0}$. +- for $t \in\left[0, T_{\text {total }}\right]$ : + - Initialize empty episode minibatch. + - for $k \in[0, n]:$ \# Sample episode + - Select a action $a_{k}$ using the actor $\pi_{\theta}$. + - Perform the action $a_{k}$ and observe the next state + $s_{k+1}$ and the reward $r_{k+1}$. + - Store $\left(s_{k}, a_{k}, r_{k+1}\right)$ in the episode + minibatch. + - if $s_{n}$ is not terminal: set + $R=V_{\varphi}\left(s_{n}\right)$ with the critic, else $R=0$. + - Reset gradient $d \theta$ and $d \varphi$ to 0 . + - for $k \in[n-1,0]$ : \# Backwards iteration over the episode + - Update the discounted sum of rewards + $R \leftarrow r_{k}+\gamma R$ + + - Accumulate the policy gradient using the critic: + + $$d \theta \leftarrow d \theta+\nabla_{\theta} \log \pi_{\theta}\left(a_{k}\mid s_{k}\right)\left(R-V_{\varphi}\left(s_{k}\right)\right)$$ + + - Accumulate the critic gradient: + +$$d \varphi \leftarrow d \varphi+\nabla_{\varphi}\left(R-V_{\varphi}\left(s_{k}\right)\right)^{2}$$ + +- Update the actor and the critic with the accumulated gradients using + gradient descent or similar: + +$$\theta \leftarrow \theta+\eta d \theta \quad \varphi \leftarrow \varphi+\eta d \varphi$$ + +Running A2C on CartPole +----------------------- + +In the next example we use default parameters for both the Actor and the +Critic and we use rlberry to train and evaluate our A2C agent. The +default networks are: + +- a dense neural network with two hidden layers of 64 units for the + **Actor**, the input layer has the dimension of the state space + while the output layer has the dimension of the action space. The + activations are RELU functions and we have a softmax in the last + layer. +- a dense neural network with two hidden layers of 64 units for the + **Critic**, the input layer has the dimension of the state space + while the output has dimension 1. The activations are RELU functions + apart from the last layer that has a linear activation. + +```python +""" +The ExperimentManager class is compact way of experimenting with a deepRL agent. +""" +default_agent = ExperimentManager( + A2CAgent, # The Agent class. + (gym_make, dict(id="CartPole-v1")), # The Environment to solve. + fit_budget=3e5, # The number of interactions + # between the agent and the + # environment during training. + eval_kwargs=dict(eval_horizon=500), # The number of interactions + # between the agent and the + # environment during evaluations. + n_fit=1, # The number of agents to train. + # Usually, it is good to do more + # than 1 because the training is + # stochastic. + agent_name="A2C default", # The agent's name. +) + +print("Training ...") +default_agent.fit() # Trains the agent on fit_budget steps! + + +# Plot the training data: +_ = plot_writer_data( + [default_agent], + tag="episode_rewards", + title="Training Episode Cumulative Rewards", + show=True, +) +``` + +```none +[INFO] Running ExperimentManager fit() for A2C default with n_fit = 1 and max_workers = None. +INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 +[INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead +``` + +
+ +```none +Training ... +``` + +
+ +```none +[INFO] [A2C default[worker: 0]] | max_global_step = 5644 |episode_rewards = 196.0 | total_episodes = 111 | +[INFO] [A2C default[worker: 0]] | max_global_step = 9551 | episode_rewards = 380.0 | total_episodes = 134 | +[INFO] [A2C default[worker: 0]] | max_global_step = 13128 | episode_rewards = 125.0 | total_episodes = 182 | +[INFO] [A2C default[worker: 0]] | max_global_step = 16617 | episode_rewards = 246.0 | total_episodes = 204 | +[INFO] [A2C default[worker: 0]] | max_global_step = 20296 | episode_rewards = 179.0 | total_episodes = 222 | +[INFO] [A2C default[worker: 0]] | max_global_step = 23633 | episode_rewards = 120.0 | total_episodes = 240 | +[INFO] [A2C default[worker: 0]] | max_global_step = 26193 | episode_rewards = 203.0 | total_episodes = 252 | +[INFO] [A2C default[worker: 0]] | max_global_step = 28969 | episode_rewards = 104.0 | total_episodes = 271 | +[INFO] [A2C default[worker: 0]] | max_global_step = 34757 | episode_rewards = 123.0 | total_episodes = 335 | +[INFO] [A2C default[worker: 0]] | max_global_step = 41554 | episode_rewards = 173.0 | total_episodes = 373 | +[INFO] [A2C default[worker: 0]] | max_global_step = 48418 | episode_rewards = 217.0 | total_episodes = 423 | +[INFO] [A2C default[worker: 0]] | max_global_step = 55322 | episode_rewards = 239.0 | total_episodes = 446 | +[INFO] [A2C default[worker: 0]] | max_global_step = 62193 | episode_rewards = 218.0 | total_episodes = 471 | +[INFO] [A2C default[worker: 0]] | max_global_step = 69233 | episode_rewards = 377.0 | total_episodes = 509 | +[INFO] [A2C default[worker: 0]] | max_global_step = 76213 | episode_rewards = 211.0 | total_episodes = 536 | +[INFO] [A2C default[worker: 0]] | max_global_step = 83211 | episode_rewards = 212.0 | total_episodes = 562 | +[INFO] [A2C default[worker: 0]] | max_global_step = 90325 | episode_rewards = 211.0 | total_episodes = 586 | +[INFO] [A2C default[worker: 0]] | max_global_step = 97267 | episode_rewards = 136.0 | total_episodes = 631 | [INFO] [A2C default[worker: 0]] | max_global_step = 104280 | episode_rewards = 175.0 | total_episodes = 686 | +[INFO] [A2C default[worker: 0]] | max_global_step = 111194 | episode_rewards = 258.0 | total_episodes = 722 | +[INFO] [A2C default[worker: 0]] | max_global_step = 118067 | episode_rewards = 235.0 | total_episodes = 755 | +[INFO] [A2C default[worker: 0]] | max_global_step = 125040 | episode_rewards = 500.0 | total_episodes = 777 | +[INFO] [A2C default[worker: 0]] | max_global_step = 132478 | episode_rewards = 500.0 | total_episodes = 792 | +[INFO] [A2C default[worker: 0]] | max_global_step = 139591 | episode_rewards = 197.0 | total_episodes = 813 | +[INFO] [A2C default[worker: 0]] | max_global_step = 146462 | episode_rewards = 500.0 | total_episodes = 835 | +[INFO] [A2C default[worker: 0]] | max_global_step = 153462 | episode_rewards = 500.0 | total_episodes = 849 | +[INFO] [A2C default[worker: 0]] | max_global_step = 160462 | episode_rewards = 500.0 | total_episodes = 863 | +[INFO] [A2C default[worker: 0]] | max_global_step = 167462 | episode_rewards = 500.0 | total_episodes = 877 | [INFO] [A2C default[worker: 0]] | max_global_step = 174462 | episode_rewards = 500.0 | total_episodes = 891 | +[INFO] [A2C default[worker: 0]] | max_global_step = 181462 | episode_rewards = 500.0 | total_episodes = 905 | +[INFO] [A2C default[worker: 0]] | max_global_step = 188462 | episode_rewards = 500.0 | total_episodes = 919 | +[INFO] [A2C default[worker: 0]] | max_global_step = 195462 | episode_rewards = 500.0 | total_episodes = 933 | +[INFO] [A2C default[worker: 0]] | max_global_step = 202520 | episode_rewards = 206.0 | total_episodes = 957 | +[INFO] [A2C default[worker: 0]] | max_global_step = 209932 | episode_rewards = 500.0 | total_episodes = 978 | +[INFO] [A2C default[worker: 0]] | max_global_step = 216932 | episode_rewards = 500.0 | total_episodes = 992 | +[INFO] [A2C default[worker: 0]] | max_global_step = 223932 | episode_rewards = 500.0 | total_episodes = 1006 | +[INFO] [A2C default[worker: 0]] | max_global_step = 230916 | episode_rewards = 214.0 | total_episodes = 1024 | +[INFO] [A2C default[worker: 0]] | max_global_step = 235895 | episode_rewards = 500.0 | total_episodes = 1037 | +[INFO] [A2C default[worker: 0]] | max_global_step = 242782 | episode_rewards = 118.0 | total_episodes = 1072 | +[INFO] [A2C default[worker: 0]] | max_global_step = 249695 | episode_rewards = 131.0 | total_episodes = 1111 | +[INFO] [A2C default[worker: 0]] | max_global_step = 256649 | episode_rewards = 136.0 | total_episodes = 1160 | +[INFO] [A2C default[worker: 0]] | max_global_step = 263674 | episode_rewards = 100.0 | total_episodes = 1215 | +[INFO] [A2C default[worker: 0]] | max_global_step = 270727 | episode_rewards = 136.0 | total_episodes = 1279 | +[INFO] [A2C default[worker: 0]] | max_global_step = 277588 | episode_rewards = 275.0 | total_episodes = 1313 | +[INFO] [A2C default[worker: 0]] | max_global_step = 284602 | episode_rewards = 136.0 | total_episodes = 1353 | +[INFO] [A2C default[worker: 0]] | max_global_step = 291609 | episode_rewards = 117.0 | total_episodes = 1413 | +[INFO] [A2C default[worker: 0]] | max_global_step = 298530 | episode_rewards = 147.0 | total_episodes = 1466 | +[INFO] ... trained! +INFO: Making new env: CartPole-v1 INFO: Making new env: CartPole-v1 +[INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead +``` + +
+ +![image](output_5_3.png){.align-center} + +```python +print("Evaluating ...") +_ = evaluate_agents( + [default_agent], n_simulations=50, show=True +) # Evaluate the trained agent on +# 10 simulations of 500 steps each. +``` + +```none +[INFO] Evaluating A2C default... +``` + +
+ +```none +Evaluating ... +``` + +
+ +```none +[INFO][eval]... simulation 1/50 +[INFO][eval]... simulation 2/50 +[INFO][eval]... simulation 3/50 +[INFO][eval]... simulation 4/50 +[INFO][eval]... simulation 5/50 +[INFO][eval]... simulation 6/50 +[INFO][eval]... simulation 7/50 +[INFO][eval]... simulation 8/50 +[INFO][eval]... simulation 9/50 +[INFO][eval]... simulation 10/50 +[INFO][eval]... simulation 11/50 +[INFO][eval]... simulation 12/50 +[INFO][eval]... simulation 13/50 +[INFO][eval]... simulation 14/50 +[INFO][eval]... simulation 15/50 +[INFO][eval]... simulation 16/50 +[INFO][eval]... simulation 17/50 +[INFO][eval]... simulation 18/50 +[INFO][eval]... simulation 19/50 +[INFO][eval]... simulation 20/50 +[INFO][eval]... simulation 21/50 +[INFO][eval]... simulation 22/50 +[INFO][eval]... simulation 23/50 +[INFO][eval]... simulation 24/50 +[INFO][eval]... simulation 25/50 +[INFO][eval]... simulation 26/50 +[INFO][eval]... simulation 27/50 +[INFO][eval]... simulation 28/50 +[INFO][eval]... simulation 29/50 +[INFO][eval]... simulation 30/50 +[INFO][eval]... simulation 31/50 +[INFO][eval]... simulation 32/50 +[INFO][eval]... simulation 33/50 +[INFO][eval]... simulation 34/50 +[INFO][eval]... simulation 35/50 +[INFO][eval]... simulation 36/50 +[INFO][eval]... simulation 37/50 +[INFO][eval]... simulation 38/50 +[INFO][eval]... simulation 39/50 +[INFO][eval]... simulation 40/50 +[INFO][eval]... simulation 41/50 +[INFO][eval]... simulation 42/50 +[INFO][eval]... simulation 43/50 +[INFO][eval]... simulation 44/50 +[INFO][eval]... simulation 45/50 +[INFO][eval]... simulation 46/50 +[INFO][eval]... simulation 47/50 +[INFO][eval]... simulation 48/50 +[INFO][eval]... simulation 49/50 +[INFO][eval]... simulation 50/50 +``` + +
+ +![image](output_6_3.png){.align-center} + +Let's try to change the neural networks' architectures and see if we can +beat our previous result. This time we use a smaller learning rate and +bigger batch size to have more stable training. + +```python +policy_configs = { + "type": "MultiLayerPerceptron", # A network architecture + "layer_sizes": (64, 64), # Network dimensions + "reshape": False, + "is_policy": True, # The network should output a distribution + # over actions +} + +critic_configs = { + "type": "MultiLayerPerceptron", + "layer_sizes": (64, 64), + "reshape": False, + "out_size": 1, # The critic network is an approximator of + # a value function V: States -> |R +} +``` + +```python +tuned_agent = ExperimentManager( + A2CAgent, # The Agent class. + (gym_make, dict(id="CartPole-v1")), # The Environment to solve. + init_kwargs=dict( # Where to put the agent's hyperparameters + policy_net_fn=model_factory_from_env, # A policy network constructor + policy_net_kwargs=policy_configs, # Policy network's architecure + value_net_fn=model_factory_from_env, # A Critic network constructor + value_net_kwargs=critic_configs, # Critic network's architecure. + optimizer_type="ADAM", # What optimizer to use for policy + # gradient descent steps. + learning_rate=1e-3, # Size of the policy gradient + # descent steps. + entr_coef=0.0, # How much to force exploration. + batch_size=1024 # Number of interactions used to + # estimate the policy gradient + # for each policy update. + ), + fit_budget=3e5, # The number of interactions + # between the agent and the + # environment during training. + eval_kwargs=dict(eval_horizon=500), # The number of interactions + # between the agent and the + # environment during evaluations. + n_fit=1, # The number of agents to train. + # Usually, it is good to do more + # than 1 because the training is + # stochastic. + agent_name="A2C tuned", # The agent's name. +) + + +print("Training ...") +tuned_agent.fit() # Trains the agent on fit_budget steps! + + +# Plot the training data: +_ = plot_writer_data( + [default_agent, tuned_agent], + tag="episode_rewards", + title="Training Episode Cumulative Rewards", + show=True, +) +``` + +```none +[INFO] Running ExperimentManager fit() for A2C tuned with n_fit = 1 +and max_workers = None. +INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 +[INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead +``` + +
+ +```none +Training ... +``` + +
+ +```none +[INFO] [A2C tuned[worker: 0]] | max_global_step = 6777 | episode_rewards = 15.0 | total_episodes = 314 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 13633 | episode_rewards = 14.0 | total_episodes = 602 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 20522 | episode_rewards = 41.0 | total_episodes = 854 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 27531 | episode_rewards = 13.0 | total_episodes = 1063 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 34398 | episode_rewards = 42.0 | total_episodes = 1237 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 41600 | episode_rewards = 118.0 | total_episodes = 1389 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 48593 | episode_rewards = 50.0 | total_episodes = 1511 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 55721 | episode_rewards = 113.0 | total_episodes = 1603 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 62751 | episode_rewards = 41.0 | total_episodes = 1687 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 69968 | episode_rewards = 344.0 | total_episodes = 1741 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 77259 | episode_rewards = 418.0 | total_episodes = 1787 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 84731 | episode_rewards = 293.0 | total_episodes = 1820 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 91890 | episode_rewards = 185.0 | total_episodes = 1853 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 99031 | episode_rewards = 278.0 | total_episodes = 1876 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 106305 | episode_rewards = 318.0 | total_episodes = 1899 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 113474 | episode_rewards = 500.0 | total_episodes = 1921 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 120632 | episode_rewards = 370.0 | total_episodes = 1941 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 127753 | episode_rewards = 375.0 | total_episodes = 1962 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 135179 | episode_rewards = 393.0 | total_episodes = 1987 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 142433 | episode_rewards = 500.0 | total_episodes = 2005 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 149888 | episode_rewards = 500.0 | total_episodes = 2023 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 157312 | episode_rewards = 467.0 | total_episodes = 2042 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 164651 | episode_rewards = 441.0 | total_episodes = 2060 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 172015 | episode_rewards = 500.0 | total_episodes = 2076 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 178100 | episode_rewards = 481.0 | total_episodes = 2089 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 183522 | episode_rewards = 462.0 | total_episodes = 2101 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 190818 | episode_rewards = 500.0 | total_episodes = 2117 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 198115 | episode_rewards = 500.0 | total_episodes = 2135 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 205097 | episode_rewards = 500.0 | total_episodes = 2151 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 212351 | episode_rewards = 500.0 | total_episodes = 2166 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 219386 | episode_rewards = 500.0 | total_episodes = 2181 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 226386 | episode_rewards = 500.0 | total_episodes = 2195 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 233888 | episode_rewards = 500.0 | total_episodes = 2211 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 241388 | episode_rewards = 500.0 | total_episodes = 2226 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 248287 | episode_rewards = 500.0 | total_episodes = 2240 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 255483 | episode_rewards = 500.0 | total_episodes = 2255 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 262845 | episode_rewards = 500.0 | total_episodes = 2270 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 270032 | episode_rewards = 500.0 | total_episodes = 2285 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 277009 | episode_rewards = 498.0 | total_episodes = 2301 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 284044 | episode_rewards = 255.0 | total_episodes = 2318 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 291189 | episode_rewards = 500.0 | total_episodes = 2334 | +[INFO] [A2C tuned[worker: 0]] | max_global_step = 298619 | episode_rewards = 500.0 | total_episodes = 2350 | +[INFO] ... trained! +INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 +[INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead +``` + +
+ +![image](output_9_3.png){.align-center} + +```python +print("Evaluating ...") + +# Evaluating and comparing the agents : +_ = evaluate_agents([default_agent, tuned_agent], n_simulations=50, show=True) +``` + +
+ +```none +Evaluating ... +``` + +
+ +```none +[INFO] Evaluating A2C default... +[INFO] [eval]... simulation 1/50 +[INFO] [eval]... simulation 2/50 +[INFO] [eval]... simulation 3/50 +[INFO] [eval]... simulation 4/50 +[INFO] [eval]... simulation 5/50 +[INFO] [eval]... simulation 6/50 +[INFO] [eval]... simulation 7/50 +[INFO] [eval]... simulation 8/50 +[INFO] [eval]... simulation 9/50 +[INFO] [eval]... simulation 10/50 +[INFO] [eval]... simulation 11/50 +[INFO] [eval]... simulation 12/50 +[INFO] [eval]... simulation 13/50 +[INFO] [eval]... simulation 14/50 +[INFO] [eval]... simulation 15/50 +[INFO] [eval]... simulation 16/50 +[INFO] [eval]... simulation 17/50 +[INFO] [eval]... simulation 18/50 +[INFO] [eval]... simulation 19/50 +[INFO] [eval]... simulation 20/50 +[INFO] [eval]... simulation 21/50 +[INFO] [eval]... simulation 22/50 +[INFO] [eval]... simulation 23/50 +[INFO] [eval]... simulation 24/50 +[INFO] [eval]... simulation 25/50 +[INFO] [eval]... simulation 26/50 +[INFO] [eval]... simulation 27/50 +[INFO] [eval]... simulation 28/50 +[INFO] [eval]... simulation 29/50 +[INFO] [eval]... simulation 30/50 +[INFO] [eval]... simulation 31/50 +[INFO] [eval]... simulation 32/50 +[INFO] [eval]... simulation 33/50 +[INFO] [eval]... simulation 34/50 +[INFO] [eval]... simulation 35/50 +[INFO] [eval]... simulation 36/50 +[INFO] [eval]... simulation 37/50 +[INFO] [eval]... simulation 38/50 +[INFO] [eval]... simulation 39/50 +[INFO] [eval]... simulation 40/50 +[INFO] [eval]... simulation 41/50 +[INFO] [eval]... simulation 42/50 +[INFO] [eval]... simulation 43/50 +[INFO] [eval]... simulation 44/50 +[INFO] [eval]... simulation 45/50 +[INFO] [eval]... simulation 46/50 +[INFO] [eval]... simulation 47/50 +[INFO] [eval]... simulation 48/50 +[INFO] [eval]... simulation 49/50 +[INFO] [eval]... simulation 50/50 +[INFO] Evaluating A2C tuned... +[INFO] [eval]... simulation 1/50 +[INFO] [eval]... simulation 2/50 +[INFO] [eval]... simulation 3/50 +[INFO] [eval]... simulation 4/50 +[INFO] [eval]... simulation 5/50 +[INFO] [eval]... simulation 6/50 +[INFO] [eval]... simulation 7/50 +[INFO] [eval]... simulation 8/50 +[INFO] [eval]... simulation 9/50 +[INFO] [eval]... simulation 10/50 +[INFO] [eval]... simulation 11/50 +[INFO] [eval]... simulation 12/50 +[INFO] [eval]... simulation 13/50 +[INFO] [eval]... simulation 14/50 +[INFO] [eval]... simulation 15/50 +[INFO] [eval]... simulation 16/50 +[INFO] [eval]... simulation 17/50 +[INFO] [eval]... simulation 18/50 +[INFO] [eval]... simulation 19/50 +[INFO] [eval]... simulation 20/50 +[INFO] [eval]... simulation 21/50 +[INFO] [eval]... simulation 22/50 +[INFO] [eval]... simulation 23/50 +[INFO] [eval]... simulation 24/50 +[INFO] [eval]... simulation 25/50 +[INFO] [eval]... simulation 26/50 +[INFO] [eval]... simulation 27/50 +[INFO] [eval]... simulation 28/50 +[INFO] [eval]... simulation 29/50 +[INFO] [eval]... simulation 30/50 +[INFO] [eval]... simulation 31/50 +[INFO] [eval]... simulation 32/50 +[INFO] [eval]... simulation 33/50 +[INFO] [eval]... simulation 34/50 +[INFO] [eval]... simulation 35/50 +[INFO] [eval]... simulation 36/50 +[INFO] [eval]... simulation 37/50 +[INFO] [eval]... simulation 38/50 +[INFO] [eval]... simulation 39/50 +[INFO] [eval]... simulation 40/50 +[INFO] [eval]... simulation 41/50 +[INFO] [eval]... simulation 42/50 +[INFO] [eval]... simulation 43/50 +[INFO] [eval]... simulation 44/50 +[INFO] [eval]... simulation 45/50 +[INFO] [eval]... simulation 46/50 +[INFO] [eval]... simulation 47/50 +[INFO] [eval]... simulation 48/50 +[INFO] [eval]... simulation 49/50 +[INFO] [eval]... simulation 50/50 +``` + +
+ +![image](output_10_3.png){.align-center} diff --git a/docs/basics/DeepRLTutorial/TutorialDeepRL.rst b/docs/basics/DeepRLTutorial/TutorialDeepRL.rst deleted file mode 100644 index 99dbe4425..000000000 --- a/docs/basics/DeepRLTutorial/TutorialDeepRL.rst +++ /dev/null @@ -1,591 +0,0 @@ -Quickstart for Deep Reinforcement Learning in rlberry -===================================================== - -.. highlight:: none - -.. - Authors: Riccardo Della Vecchia, Hector Kohler, Alena Shilova. - -In this tutorial, we will focus on Deep Reinforcement Learning with the **Advantage Actor-Critic** algorithm. - - -Imports ------------------------------ - -.. code:: python - - from rlberry.envs import gym_make - from rlberry.manager import plot_writer_data, ExperimentManager, evaluate_agents - from rlberry.agents.torch import A2CAgent - from rlberry.agents.torch.utils.training import model_factory_from_env - - -Reminder of the RL setting --------------------------- - -We will consider a MDP :math:`M = (\mathcal{S}, \mathcal{A}, p, r, \gamma)` with: - -* :math:`\mathcal{S}` the state space, -* :math:`\mathcal{A}` the action space, -* :math:`p(x^\prime \mid x, a)` the transition probability, -* :math:`r(x, a, x^\prime)` the reward of the transition :math:`(x, a, x^\prime)`, -* :math:`\gamma \in [0,1)` is the discount factor. - -A policy :math:`\pi` is a mapping from the state space :math:`\mathcal{S}` to the probability of selecting each action. -The action value function of a policy is the overall expected reward -from a state action. -:math:`Q^\pi(s, a) = \mathbb{E}_{\tau \sim \pi}\big[R(\tau) \mid s_0=s, a_0=a\big]` -where :math:`\tau` is an episode -:math:`(s_0, a_0, r_0, s_1, a_1, r_1, s_2, ..., s_T, a_T, r_T)` with the -actions drawn from :math:`\pi(s)`; :math:`R(\tau)` is the random -variable defined as the cumulative sum of the discounted reward. - -The goal is to maximize the cumulative sum of discount rewards: - -.. math:: J(\pi) = \mathbb{E}_{\tau \sim \pi}\big[R(\tau) \big] - -Gymnasium Environment ---------------- - -In this tutorial we are going to use the `Gymnasium library (previously OpenAI’s Gym) -`__. This library provides a large -number of environments to test RL algorithm. - -We will focus only on the **CartPole-v1** environment, although we recommend experimenting with other environments such as **Acrobot-v1** -and **MountainCar-v0**. -The following table presents some -basic components of the three environments, such as the dimensions of -their observation and action spaces and the rewards occurring at each -step. - -===================== =========== ========================= -Env Info CartPole-v1 Acrobot-v1 MountainCar-v0 -===================== =========== ========================= -**Observation Space** Box(4) Box(6) Box(2) -**Action Space** Discrete(2) Discrete(3) Discrete(3) -**Rewards** 1 per step -1 if not terminal else 0 -1 per step -===================== =========== ========================= - -Actor-Critic algorithms and A2C -------------------------------- - -**Actor-Critic algorithms** methods consist of two models, which may -optionally share parameters: - -- Critic updates the value function parameters w and depending on the algorithm it could be action-value -:math:`Q_{\varphi}(s,a )` or state-value :math:`V_{\varphi}(s)`. -- Actor updates the policy parameters :math:`\theta` for -:math:`\pi_{\theta}(a \mid s)`, in the direction suggested by the -critic. - -**A2C** is an Actor-Critic algorithm and it is part of the on-policy -family, which means that we are learning the value function for one -policy while following it. The original paper in which it was proposed -can be found `here `__ and the -pseudocode of the algorithm is the following: - -- Initialize the actor :math:`\pi_{\theta}` and the critic - :math:`V_{\varphi}` with random weights. -- Observe the initial state :math:`s_{0}`. -- for :math:`t \in\left[0, T_{\text {total }}\right]` : - - - Initialize empty episode minibatch. - - for :math:`k \in[0, n]:` # Sample episode - - - Select a action :math:`a_{k}` using the actor - :math:`\pi_{\theta}`. - - Perform the action :math:`a_{k}` and observe the next state - :math:`s_{k+1}` and the reward :math:`r_{k+1}`. - - Store :math:`\left(s_{k}, a_{k}, r_{k+1}\right)` in the episode - minibatch. - - - if :math:`s_{n}` is not terminal: set - :math:`R=V_{\varphi}\left(s_{n}\right)` with the critic, else - :math:`R=0`. - - Reset gradient :math:`d \theta` and :math:`d \varphi` to 0 . - - for :math:`k \in[n-1,0]` : # Backwards iteration over the episode - - - Update the discounted sum of rewards - :math:`R \leftarrow r_{k}+\gamma R` - - Accumulate the policy gradient using the critic: - - .. math:: - - - d \theta \leftarrow d \theta+\nabla_{\theta} \log \pi_{\theta}\left(a_{k}\mid s_{k}\right)\left(R-V_{\varphi}\left(s_{k}\right)\right) - - - Accumulate the critic gradient: - -.. math:: - - - d \varphi \leftarrow d \varphi+\nabla_{\varphi}\left(R-V_{\varphi}\left(s_{k}\right)\right)^{2} - -- Update the actor and the critic with the accumulated gradients using - gradient descent or similar: - -.. math:: - - - \theta \leftarrow \theta+\eta d \theta \quad \varphi \leftarrow \varphi+\eta d \varphi - -Running A2C on CartPole ------------------------ - -In the next example we use default parameters for both the Actor and the -Critic and we use rlberry to train and evaluate our A2C agent. The -default networks are: - -- a dense neural network with two hidden layers of 64 units for the - **Actor**, the input layer has the dimension of the state space while - the output layer has the dimension of the action space. The - activations are RELU functions and we have a softmax in the last - layer. -- a dense neural network with two hidden layers of 64 units for the - **Critic**, the input layer has the dimension of the state space - while the output has dimension 1. The activations are RELU functions - apart from the last layer that has a linear activation. - -.. code:: python - - """ - The ExperimentManager class is compact way of experimenting with a deepRL agent. - """ - default_agent = ExperimentManager( - A2CAgent, # The Agent class. - (gym_make, dict(id="CartPole-v1")), # The Environment to solve. - fit_budget=3e5, # The number of interactions - # between the agent and the - # environment during training. - eval_kwargs=dict(eval_horizon=500), # The number of interactions - # between the agent and the - # environment during evaluations. - n_fit=1, # The number of agents to train. - # Usually, it is good to do more - # than 1 because the training is - # stochastic. - agent_name="A2C default", # The agent's name. - ) - - print("Training ...") - default_agent.fit() # Trains the agent on fit_budget steps! - - - # Plot the training data: - _ = plot_writer_data( - [default_agent], - tag="episode_rewards", - title="Training Episode Cumulative Rewards", - show=True, - ) - - -.. parsed-literal:: - - [INFO] Running ExperimentManager fit() for A2C default with n_fit = 1 and max_workers = None. - INFO: Making new env: CartPole-v1 - INFO: Making new env: CartPole-v1 - [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead - - -.. parsed-literal:: - - Training ... - - -.. parsed-literal:: - - [INFO] [A2C default[worker: 0]] | max_global_step = 5644 | episode_rewards = 196.0 | total_episodes = 111 | - [INFO] [A2C default[worker: 0]] | max_global_step = 9551 | episode_rewards = 380.0 | total_episodes = 134 | - [INFO] [A2C default[worker: 0]] | max_global_step = 13128 | episode_rewards = 125.0 | total_episodes = 182 | - [INFO] [A2C default[worker: 0]] | max_global_step = 16617 | episode_rewards = 246.0 | total_episodes = 204 | - [INFO] [A2C default[worker: 0]] | max_global_step = 20296 | episode_rewards = 179.0 | total_episodes = 222 | - [INFO] [A2C default[worker: 0]] | max_global_step = 23633 | episode_rewards = 120.0 | total_episodes = 240 | - [INFO] [A2C default[worker: 0]] | max_global_step = 26193 | episode_rewards = 203.0 | total_episodes = 252 | - [INFO] [A2C default[worker: 0]] | max_global_step = 28969 | episode_rewards = 104.0 | total_episodes = 271 | - [INFO] [A2C default[worker: 0]] | max_global_step = 34757 | episode_rewards = 123.0 | total_episodes = 335 | - [INFO] [A2C default[worker: 0]] | max_global_step = 41554 | episode_rewards = 173.0 | total_episodes = 373 | - [INFO] [A2C default[worker: 0]] | max_global_step = 48418 | episode_rewards = 217.0 | total_episodes = 423 | - [INFO] [A2C default[worker: 0]] | max_global_step = 55322 | episode_rewards = 239.0 | total_episodes = 446 | - [INFO] [A2C default[worker: 0]] | max_global_step = 62193 | episode_rewards = 218.0 | total_episodes = 471 | - [INFO] [A2C default[worker: 0]] | max_global_step = 69233 | episode_rewards = 377.0 | total_episodes = 509 | - [INFO] [A2C default[worker: 0]] | max_global_step = 76213 | episode_rewards = 211.0 | total_episodes = 536 | - [INFO] [A2C default[worker: 0]] | max_global_step = 83211 | episode_rewards = 212.0 | total_episodes = 562 | - [INFO] [A2C default[worker: 0]] | max_global_step = 90325 | episode_rewards = 211.0 | total_episodes = 586 | - [INFO] [A2C default[worker: 0]] | max_global_step = 97267 | episode_rewards = 136.0 | total_episodes = 631 | - [INFO] [A2C default[worker: 0]] | max_global_step = 104280 | episode_rewards = 175.0 | total_episodes = 686 | - [INFO] [A2C default[worker: 0]] | max_global_step = 111194 | episode_rewards = 258.0 | total_episodes = 722 | - [INFO] [A2C default[worker: 0]] | max_global_step = 118067 | episode_rewards = 235.0 | total_episodes = 755 | - [INFO] [A2C default[worker: 0]] | max_global_step = 125040 | episode_rewards = 500.0 | total_episodes = 777 | - [INFO] [A2C default[worker: 0]] | max_global_step = 132478 | episode_rewards = 500.0 | total_episodes = 792 | - [INFO] [A2C default[worker: 0]] | max_global_step = 139591 | episode_rewards = 197.0 | total_episodes = 813 | - [INFO] [A2C default[worker: 0]] | max_global_step = 146462 | episode_rewards = 500.0 | total_episodes = 835 | - [INFO] [A2C default[worker: 0]] | max_global_step = 153462 | episode_rewards = 500.0 | total_episodes = 849 | - [INFO] [A2C default[worker: 0]] | max_global_step = 160462 | episode_rewards = 500.0 | total_episodes = 863 | - [INFO] [A2C default[worker: 0]] | max_global_step = 167462 | episode_rewards = 500.0 | total_episodes = 877 | - [INFO] [A2C default[worker: 0]] | max_global_step = 174462 | episode_rewards = 500.0 | total_episodes = 891 | - [INFO] [A2C default[worker: 0]] | max_global_step = 181462 | episode_rewards = 500.0 | total_episodes = 905 | - [INFO] [A2C default[worker: 0]] | max_global_step = 188462 | episode_rewards = 500.0 | total_episodes = 919 | - [INFO] [A2C default[worker: 0]] | max_global_step = 195462 | episode_rewards = 500.0 | total_episodes = 933 | - [INFO] [A2C default[worker: 0]] | max_global_step = 202520 | episode_rewards = 206.0 | total_episodes = 957 | - [INFO] [A2C default[worker: 0]] | max_global_step = 209932 | episode_rewards = 500.0 | total_episodes = 978 | - [INFO] [A2C default[worker: 0]] | max_global_step = 216932 | episode_rewards = 500.0 | total_episodes = 992 | - [INFO] [A2C default[worker: 0]] | max_global_step = 223932 | episode_rewards = 500.0 | total_episodes = 1006 | - [INFO] [A2C default[worker: 0]] | max_global_step = 230916 | episode_rewards = 214.0 | total_episodes = 1024 | - [INFO] [A2C default[worker: 0]] | max_global_step = 235895 | episode_rewards = 500.0 | total_episodes = 1037 | - [INFO] [A2C default[worker: 0]] | max_global_step = 242782 | episode_rewards = 118.0 | total_episodes = 1072 | - [INFO] [A2C default[worker: 0]] | max_global_step = 249695 | episode_rewards = 131.0 | total_episodes = 1111 | - [INFO] [A2C default[worker: 0]] | max_global_step = 256649 | episode_rewards = 136.0 | total_episodes = 1160 | - [INFO] [A2C default[worker: 0]] | max_global_step = 263674 | episode_rewards = 100.0 | total_episodes = 1215 | - [INFO] [A2C default[worker: 0]] | max_global_step = 270727 | episode_rewards = 136.0 | total_episodes = 1279 | - [INFO] [A2C default[worker: 0]] | max_global_step = 277588 | episode_rewards = 275.0 | total_episodes = 1313 | - [INFO] [A2C default[worker: 0]] | max_global_step = 284602 | episode_rewards = 136.0 | total_episodes = 1353 | - [INFO] [A2C default[worker: 0]] | max_global_step = 291609 | episode_rewards = 117.0 | total_episodes = 1413 | - [INFO] [A2C default[worker: 0]] | max_global_step = 298530 | episode_rewards = 147.0 | total_episodes = 1466 | - [INFO] ... trained! - INFO: Making new env: CartPole-v1 - INFO: Making new env: CartPole-v1 - [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead - - - -.. image:: output_5_3.png - - -.. code:: python - - print("Evaluating ...") - _ = evaluate_agents( - [default_agent], n_simulations=50, show=True - ) # Evaluate the trained agent on - # 10 simulations of 500 steps each. - - -.. parsed-literal:: - - [INFO] Evaluating A2C default... - - -.. parsed-literal:: - - Evaluating ... - - -.. parsed-literal:: - - [INFO] [eval]... simulation 1/50 - [INFO] [eval]... simulation 2/50 - [INFO] [eval]... simulation 3/50 - [INFO] [eval]... simulation 4/50 - [INFO] [eval]... simulation 5/50 - [INFO] [eval]... simulation 6/50 - [INFO] [eval]... simulation 7/50 - [INFO] [eval]... simulation 8/50 - [INFO] [eval]... simulation 9/50 - [INFO] [eval]... simulation 10/50 - [INFO] [eval]... simulation 11/50 - [INFO] [eval]... simulation 12/50 - [INFO] [eval]... simulation 13/50 - [INFO] [eval]... simulation 14/50 - [INFO] [eval]... simulation 15/50 - [INFO] [eval]... simulation 16/50 - [INFO] [eval]... simulation 17/50 - [INFO] [eval]... simulation 18/50 - [INFO] [eval]... simulation 19/50 - [INFO] [eval]... simulation 20/50 - [INFO] [eval]... simulation 21/50 - [INFO] [eval]... simulation 22/50 - [INFO] [eval]... simulation 23/50 - [INFO] [eval]... simulation 24/50 - [INFO] [eval]... simulation 25/50 - [INFO] [eval]... simulation 26/50 - [INFO] [eval]... simulation 27/50 - [INFO] [eval]... simulation 28/50 - [INFO] [eval]... simulation 29/50 - [INFO] [eval]... simulation 30/50 - [INFO] [eval]... simulation 31/50 - [INFO] [eval]... simulation 32/50 - [INFO] [eval]... simulation 33/50 - [INFO] [eval]... simulation 34/50 - [INFO] [eval]... simulation 35/50 - [INFO] [eval]... simulation 36/50 - [INFO] [eval]... simulation 37/50 - [INFO] [eval]... simulation 38/50 - [INFO] [eval]... simulation 39/50 - [INFO] [eval]... simulation 40/50 - [INFO] [eval]... simulation 41/50 - [INFO] [eval]... simulation 42/50 - [INFO] [eval]... simulation 43/50 - [INFO] [eval]... simulation 44/50 - [INFO] [eval]... simulation 45/50 - [INFO] [eval]... simulation 46/50 - [INFO] [eval]... simulation 47/50 - [INFO] [eval]... simulation 48/50 - [INFO] [eval]... simulation 49/50 - [INFO] [eval]... simulation 50/50 - - - -.. image:: output_6_3.png - - -Let’s try to change the neural networks’ architectures and see if we can -beat our previous result. This time we use a smaller learning rate -and bigger batch size to have more stable training. - -.. code:: python - - policy_configs = { - "type": "MultiLayerPerceptron", # A network architecture - "layer_sizes": (64, 64), # Network dimensions - "reshape": False, - "is_policy": True, # The network should output a distribution - # over actions - } - - critic_configs = { - "type": "MultiLayerPerceptron", - "layer_sizes": (64, 64), - "reshape": False, - "out_size": 1, # The critic network is an approximator of - # a value function V: States -> |R - } - -.. code:: python - - tuned_agent = ExperimentManager( - A2CAgent, # The Agent class. - (gym_make, dict(id="CartPole-v1")), # The Environment to solve. - init_kwargs=dict( # Where to put the agent's hyperparameters - policy_net_fn=model_factory_from_env, # A policy network constructor - policy_net_kwargs=policy_configs, # Policy network's architecure - value_net_fn=model_factory_from_env, # A Critic network constructor - value_net_kwargs=critic_configs, # Critic network's architecure. - optimizer_type="ADAM", # What optimizer to use for policy - # gradient descent steps. - learning_rate=1e-3, # Size of the policy gradient - # descent steps. - entr_coef=0.0, # How much to force exploration. - batch_size=1024 # Number of interactions used to - # estimate the policy gradient - # for each policy update. - ), - fit_budget=3e5, # The number of interactions - # between the agent and the - # environment during training. - eval_kwargs=dict(eval_horizon=500), # The number of interactions - # between the agent and the - # environment during evaluations. - n_fit=1, # The number of agents to train. - # Usually, it is good to do more - # than 1 because the training is - # stochastic. - agent_name="A2C tuned", # The agent's name. - ) - - - print("Training ...") - tuned_agent.fit() # Trains the agent on fit_budget steps! - - - # Plot the training data: - _ = plot_writer_data( - [default_agent, tuned_agent], - tag="episode_rewards", - title="Training Episode Cumulative Rewards", - show=True, - ) - - -.. parsed-literal:: - - [INFO] Running ExperimentManager fit() for A2C tuned with n_fit = 1 and max_workers = None. - INFO: Making new env: CartPole-v1 - INFO: Making new env: CartPole-v1 - [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead - - -.. parsed-literal:: - - Training ... - - -.. parsed-literal:: - - [INFO] [A2C tuned[worker: 0]] | max_global_step = 6777 | episode_rewards = 15.0 | total_episodes = 314 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 13633 | episode_rewards = 14.0 | total_episodes = 602 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 20522 | episode_rewards = 41.0 | total_episodes = 854 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 27531 | episode_rewards = 13.0 | total_episodes = 1063 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 34398 | episode_rewards = 42.0 | total_episodes = 1237 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 41600 | episode_rewards = 118.0 | total_episodes = 1389 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 48593 | episode_rewards = 50.0 | total_episodes = 1511 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 55721 | episode_rewards = 113.0 | total_episodes = 1603 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 62751 | episode_rewards = 41.0 | total_episodes = 1687 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 69968 | episode_rewards = 344.0 | total_episodes = 1741 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 77259 | episode_rewards = 418.0 | total_episodes = 1787 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 84731 | episode_rewards = 293.0 | total_episodes = 1820 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 91890 | episode_rewards = 185.0 | total_episodes = 1853 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 99031 | episode_rewards = 278.0 | total_episodes = 1876 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 106305 | episode_rewards = 318.0 | total_episodes = 1899 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 113474 | episode_rewards = 500.0 | total_episodes = 1921 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 120632 | episode_rewards = 370.0 | total_episodes = 1941 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 127753 | episode_rewards = 375.0 | total_episodes = 1962 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 135179 | episode_rewards = 393.0 | total_episodes = 1987 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 142433 | episode_rewards = 500.0 | total_episodes = 2005 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 149888 | episode_rewards = 500.0 | total_episodes = 2023 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 157312 | episode_rewards = 467.0 | total_episodes = 2042 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 164651 | episode_rewards = 441.0 | total_episodes = 2060 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 172015 | episode_rewards = 500.0 | total_episodes = 2076 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 178100 | episode_rewards = 481.0 | total_episodes = 2089 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 183522 | episode_rewards = 462.0 | total_episodes = 2101 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 190818 | episode_rewards = 500.0 | total_episodes = 2117 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 198115 | episode_rewards = 500.0 | total_episodes = 2135 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 205097 | episode_rewards = 500.0 | total_episodes = 2151 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 212351 | episode_rewards = 500.0 | total_episodes = 2166 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 219386 | episode_rewards = 500.0 | total_episodes = 2181 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 226386 | episode_rewards = 500.0 | total_episodes = 2195 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 233888 | episode_rewards = 500.0 | total_episodes = 2211 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 241388 | episode_rewards = 500.0 | total_episodes = 2226 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 248287 | episode_rewards = 500.0 | total_episodes = 2240 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 255483 | episode_rewards = 500.0 | total_episodes = 2255 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 262845 | episode_rewards = 500.0 | total_episodes = 2270 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 270032 | episode_rewards = 500.0 | total_episodes = 2285 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 277009 | episode_rewards = 498.0 | total_episodes = 2301 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 284044 | episode_rewards = 255.0 | total_episodes = 2318 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 291189 | episode_rewards = 500.0 | total_episodes = 2334 | - [INFO] [A2C tuned[worker: 0]] | max_global_step = 298619 | episode_rewards = 500.0 | total_episodes = 2350 | - [INFO] ... trained! - INFO: Making new env: CartPole-v1 - INFO: Making new env: CartPole-v1 - [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead - - - -.. image:: output_9_3.png - - -.. code:: python - - print("Evaluating ...") - - # Evaluate each trained agent on 10 simulations of 500 steps each. - _ = evaluate_agents([default_agent, tuned_agent], n_simulations=50, show=True) - - -.. parsed-literal:: - - [INFO] Evaluating A2C default... - - -.. parsed-literal:: - - Evaluating ... - - -.. parsed-literal:: - - [INFO] [eval]... simulation 1/50 - [INFO] [eval]... simulation 2/50 - [INFO] [eval]... simulation 3/50 - [INFO] [eval]... simulation 4/50 - [INFO] [eval]... simulation 5/50 - [INFO] [eval]... simulation 6/50 - [INFO] [eval]... simulation 7/50 - [INFO] [eval]... simulation 8/50 - [INFO] [eval]... simulation 9/50 - [INFO] [eval]... simulation 10/50 - [INFO] [eval]... simulation 11/50 - [INFO] [eval]... simulation 12/50 - [INFO] [eval]... simulation 13/50 - [INFO] [eval]... simulation 14/50 - [INFO] [eval]... simulation 15/50 - [INFO] [eval]... simulation 16/50 - [INFO] [eval]... simulation 17/50 - [INFO] [eval]... simulation 18/50 - [INFO] [eval]... simulation 19/50 - [INFO] [eval]... simulation 20/50 - [INFO] [eval]... simulation 21/50 - [INFO] [eval]... simulation 22/50 - [INFO] [eval]... simulation 23/50 - [INFO] [eval]... simulation 24/50 - [INFO] [eval]... simulation 25/50 - [INFO] [eval]... simulation 26/50 - [INFO] [eval]... simulation 27/50 - [INFO] [eval]... simulation 28/50 - [INFO] [eval]... simulation 29/50 - [INFO] [eval]... simulation 30/50 - [INFO] [eval]... simulation 31/50 - [INFO] [eval]... simulation 32/50 - [INFO] [eval]... simulation 33/50 - [INFO] [eval]... simulation 34/50 - [INFO] [eval]... simulation 35/50 - [INFO] [eval]... simulation 36/50 - [INFO] [eval]... simulation 37/50 - [INFO] [eval]... simulation 38/50 - [INFO] [eval]... simulation 39/50 - [INFO] [eval]... simulation 40/50 - [INFO] [eval]... simulation 41/50 - [INFO] [eval]... simulation 42/50 - [INFO] [eval]... simulation 43/50 - [INFO] [eval]... simulation 44/50 - [INFO] [eval]... simulation 45/50 - [INFO] [eval]... simulation 46/50 - [INFO] [eval]... simulation 47/50 - [INFO] [eval]... simulation 48/50 - [INFO] [eval]... simulation 49/50 - [INFO] [eval]... simulation 50/50 - [INFO] Evaluating A2C tuned... - [INFO] [eval]... simulation 1/50 - [INFO] [eval]... simulation 2/50 - [INFO] [eval]... simulation 3/50 - [INFO] [eval]... simulation 4/50 - [INFO] [eval]... simulation 5/50 - [INFO] [eval]... simulation 6/50 - [INFO] [eval]... simulation 7/50 - [INFO] [eval]... simulation 8/50 - [INFO] [eval]... simulation 9/50 - [INFO] [eval]... simulation 10/50 - [INFO] [eval]... simulation 11/50 - [INFO] [eval]... simulation 12/50 - [INFO] [eval]... simulation 13/50 - [INFO] [eval]... simulation 14/50 - [INFO] [eval]... simulation 15/50 - [INFO] [eval]... simulation 16/50 - [INFO] [eval]... simulation 17/50 - [INFO] [eval]... simulation 18/50 - [INFO] [eval]... simulation 19/50 - [INFO] [eval]... simulation 20/50 - [INFO] [eval]... simulation 21/50 - [INFO] [eval]... simulation 22/50 - [INFO] [eval]... simulation 23/50 - [INFO] [eval]... simulation 24/50 - [INFO] [eval]... simulation 25/50 - [INFO] [eval]... simulation 26/50 - [INFO] [eval]... simulation 27/50 - [INFO] [eval]... simulation 28/50 - [INFO] [eval]... simulation 29/50 - [INFO] [eval]... simulation 30/50 - [INFO] [eval]... simulation 31/50 - [INFO] [eval]... simulation 32/50 - [INFO] [eval]... simulation 33/50 - [INFO] [eval]... simulation 34/50 - [INFO] [eval]... simulation 35/50 - [INFO] [eval]... simulation 36/50 - [INFO] [eval]... simulation 37/50 - [INFO] [eval]... simulation 38/50 - [INFO] [eval]... simulation 39/50 - [INFO] [eval]... simulation 40/50 - [INFO] [eval]... simulation 41/50 - [INFO] [eval]... simulation 42/50 - [INFO] [eval]... simulation 43/50 - [INFO] [eval]... simulation 44/50 - [INFO] [eval]... simulation 45/50 - [INFO] [eval]... simulation 46/50 - [INFO] [eval]... simulation 47/50 - [INFO] [eval]... simulation 48/50 - [INFO] [eval]... simulation 49/50 - [INFO] [eval]... simulation 50/50 - - - -.. image:: output_10_3.png diff --git a/docs/user_guide.rst b/docs/user_guide.rst index 821087a1f..1bc2cee23 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide.rst @@ -6,8 +6,8 @@ User guide ========== -Introduction ------------- +.. Introduction +.. ============ .. Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to .. the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and .. deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. @@ -42,7 +42,7 @@ Quick start: setup an experiment and evaluate different agents :maxdepth: 2 basics/quick_start_rl/quickstart.md - basics/DeepRLTutorial/TutorialDeepRL.rst + basics/DeepRLTutorial/TutorialDeepRL.md Agents, hyperparameter optimization and experiment setup From ac592fa77f44417a8e7a9538f56cef63f185beb0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 14:46:25 +0000 Subject: [PATCH 16/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/DeepRLTutorial/TutorialDeepRL.md | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/basics/DeepRLTutorial/TutorialDeepRL.md b/docs/basics/DeepRLTutorial/TutorialDeepRL.md index f9390e64d..5c3204b04 100644 --- a/docs/basics/DeepRLTutorial/TutorialDeepRL.md +++ b/docs/basics/DeepRLTutorial/TutorialDeepRL.md @@ -41,7 +41,7 @@ The goal is to maximize the cumulative sum of discount rewards: $$J(\pi) = \mathbb{E}_{\tau \sim \pi}\big[R(\tau) \big]$$ -Gymnasium Environment +Gymnasium Environment --------------------- In this tutorial we are going to use the [Gymnasium library (previously @@ -160,9 +160,9 @@ _ = plot_writer_data( ``` ```none -[INFO] Running ExperimentManager fit() for A2C default with n_fit = 1 and max_workers = None. -INFO: Making new env: CartPole-v1 -INFO: Making new env: CartPole-v1 +[INFO] Running ExperimentManager fit() for A2C default with n_fit = 1 and max_workers = None. +INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead ``` @@ -205,7 +205,7 @@ Training ... [INFO] [A2C default[worker: 0]] | max_global_step = 181462 | episode_rewards = 500.0 | total_episodes = 905 | [INFO] [A2C default[worker: 0]] | max_global_step = 188462 | episode_rewards = 500.0 | total_episodes = 919 | [INFO] [A2C default[worker: 0]] | max_global_step = 195462 | episode_rewards = 500.0 | total_episodes = 933 | -[INFO] [A2C default[worker: 0]] | max_global_step = 202520 | episode_rewards = 206.0 | total_episodes = 957 | +[INFO] [A2C default[worker: 0]] | max_global_step = 202520 | episode_rewards = 206.0 | total_episodes = 957 | [INFO] [A2C default[worker: 0]] | max_global_step = 209932 | episode_rewards = 500.0 | total_episodes = 978 | [INFO] [A2C default[worker: 0]] | max_global_step = 216932 | episode_rewards = 500.0 | total_episodes = 992 | [INFO] [A2C default[worker: 0]] | max_global_step = 223932 | episode_rewards = 500.0 | total_episodes = 1006 | @@ -221,7 +221,7 @@ Training ... [INFO] [A2C default[worker: 0]] | max_global_step = 291609 | episode_rewards = 117.0 | total_episodes = 1413 | [INFO] [A2C default[worker: 0]] | max_global_step = 298530 | episode_rewards = 147.0 | total_episodes = 1466 | [INFO] ... trained! -INFO: Making new env: CartPole-v1 INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 INFO: Making new env: CartPole-v1 [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead ``` @@ -275,28 +275,28 @@ Evaluating ... [INFO][eval]... simulation 23/50 [INFO][eval]... simulation 24/50 [INFO][eval]... simulation 25/50 -[INFO][eval]... simulation 26/50 +[INFO][eval]... simulation 26/50 [INFO][eval]... simulation 27/50 [INFO][eval]... simulation 28/50 [INFO][eval]... simulation 29/50 [INFO][eval]... simulation 30/50 [INFO][eval]... simulation 31/50 [INFO][eval]... simulation 32/50 -[INFO][eval]... simulation 33/50 +[INFO][eval]... simulation 33/50 [INFO][eval]... simulation 34/50 [INFO][eval]... simulation 35/50 [INFO][eval]... simulation 36/50 [INFO][eval]... simulation 37/50 [INFO][eval]... simulation 38/50 [INFO][eval]... simulation 39/50 -[INFO][eval]... simulation 40/50 +[INFO][eval]... simulation 40/50 [INFO][eval]... simulation 41/50 [INFO][eval]... simulation 42/50 [INFO][eval]... simulation 43/50 [INFO][eval]... simulation 44/50 [INFO][eval]... simulation 45/50 [INFO][eval]... simulation 46/50 -[INFO][eval]... simulation 47/50 +[INFO][eval]... simulation 47/50 [INFO][eval]... simulation 48/50 [INFO][eval]... simulation 49/50 [INFO][eval]... simulation 50/50 @@ -375,9 +375,9 @@ _ = plot_writer_data( ```none [INFO] Running ExperimentManager fit() for A2C tuned with n_fit = 1 -and max_workers = None. -INFO: Making new env: CartPole-v1 -INFO: Making new env: CartPole-v1 +and max_workers = None. +INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead ``` @@ -433,8 +433,8 @@ Training ... [INFO] [A2C tuned[worker: 0]] | max_global_step = 291189 | episode_rewards = 500.0 | total_episodes = 2334 | [INFO] [A2C tuned[worker: 0]] | max_global_step = 298619 | episode_rewards = 500.0 | total_episodes = 2350 | [INFO] ... trained! -INFO: Making new env: CartPole-v1 -INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 +INFO: Making new env: CartPole-v1 [INFO] Could not find least used device (nvidia-smi might be missing), use cuda:0 instead ``` @@ -488,7 +488,7 @@ Evaluating ... [INFO] [eval]... simulation 27/50 [INFO] [eval]... simulation 28/50 [INFO] [eval]... simulation 29/50 -[INFO] [eval]... simulation 30/50 +[INFO] [eval]... simulation 30/50 [INFO] [eval]... simulation 31/50 [INFO] [eval]... simulation 32/50 [INFO] [eval]... simulation 33/50 @@ -518,7 +518,7 @@ Evaluating ... [INFO] [eval]... simulation 6/50 [INFO] [eval]... simulation 7/50 [INFO] [eval]... simulation 8/50 -[INFO] [eval]... simulation 9/50 +[INFO] [eval]... simulation 9/50 [INFO] [eval]... simulation 10/50 [INFO] [eval]... simulation 11/50 [INFO] [eval]... simulation 12/50 From 0d8e81c887385ff2d388cae493372cb210170466 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 29 Sep 2023 09:56:56 +0200 Subject: [PATCH 17/80] add warning about seeding --- docs/basics/DeepRLTutorial/TutorialDeepRL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/basics/DeepRLTutorial/TutorialDeepRL.md b/docs/basics/DeepRLTutorial/TutorialDeepRL.md index 5c3204b04..71e28cb52 100644 --- a/docs/basics/DeepRLTutorial/TutorialDeepRL.md +++ b/docs/basics/DeepRLTutorial/TutorialDeepRL.md @@ -112,6 +112,8 @@ $$\theta \leftarrow \theta+\eta d \theta \quad \varphi \leftarrow \varphi+\eta d Running A2C on CartPole ----------------------- + **warning :** depending on the seed, you may get different results, and if you're (un)lucky, your default agent may learn and be better than the tuned agent. + In the next example we use default parameters for both the Actor and the Critic and we use rlberry to train and evaluate our A2C agent. The default networks are: From dfa2e2af40bbc72f190dcc729e123f7eba532b29 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 3 Oct 2023 15:55:37 +0200 Subject: [PATCH 18/80] adding temporarily userguide2 with a link from index --- docs/index.rst | 2 ++ docs/{user_guide.md => user_guide2.md} | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) rename docs/{user_guide.md => user_guide2.md} (72%) diff --git a/docs/index.rst b/docs/index.rst index e37669089..16e4d04c2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -9,6 +9,8 @@ An RL Library for Research and Education ======================================== + +:ref:`new user guide` **Writing reinforcement learning algorithms is fun!** *But after the fun, we have lots of boring things to implement*: run our agents in parallel, average and plot results, diff --git a/docs/user_guide.md b/docs/user_guide2.md similarity index 72% rename from docs/user_guide.md rename to docs/user_guide2.md index 8aef7e761..36faf6777 100644 --- a/docs/user_guide.md +++ b/docs/user_guide2.md @@ -1,3 +1,6 @@ +(user_guide2)= + + # User Guide ## Introduction Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to @@ -6,8 +9,10 @@ deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, an Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). ## Set up an experiment -Some text about an experiment: a comparison of 2 rl agents on a given environment. +Some text about an experiment: a comparison of 2 rl agents on a given environment. ### Environment +This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). [(Wikipedia)](https://en.wikipedia.org/wiki/Reinforcement_learning) The environment is typically stated in the form of a Markov decision process (MDP). +You can find the guide for environment [here](environment_page). Some text about MDPs. ### Agent Some text about what an agent is. From 7b6e146ec61680e88889fef50ba92b0e45933aac Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 3 Oct 2023 16:02:38 +0200 Subject: [PATCH 19/80] adding 'environment' page --- .../user_guide_video/_env_page_Breakout.mp4 | Bin 0 -> 5420 bytes .../_env_page_MountainCar.mp4 | Bin 0 -> 11062 bytes .../user_guide_video/_env_page_chain.mp4 | Bin 0 -> 11558 bytes docs/basics/environment/environment.md | 171 ++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 docs/_video/user_guide_video/_env_page_Breakout.mp4 create mode 100644 docs/_video/user_guide_video/_env_page_MountainCar.mp4 create mode 100644 docs/_video/user_guide_video/_env_page_chain.mp4 create mode 100644 docs/basics/environment/environment.md diff --git a/docs/_video/user_guide_video/_env_page_Breakout.mp4 b/docs/_video/user_guide_video/_env_page_Breakout.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..ea2311c0bfeef1b3d1d18831a00e058334c3d51b GIT binary patch literal 5420 zcmb_gc|26>8$ZX`lO<#cjYOMe#xj-+M!5*tLW>%+F~e+T#(FJN3N0#2WvLm3tWnpJ zt4OL_iPoEFQPEAI674SYdk=N%-rw)P`+Gm1?|Gl|EZ_Hep7)$HXAT5G=x{*-m%-<- zAV>;AW&lf4ECtKrT4Nyyk`L$6Xb_}wmqjHBfKRQgj6_oP(CuaG^FEK$2Tgm?eMYa} z#9QL5(Pn50hetzWZS2uJOM81P8f$BdCEM5lgNHeAu<-G7b2qa_6M|O(Pb!T9468WY z1STz9fVRY7tjsJiSbLzP3j|yT3yZk8IP+KrmBwL`*ybEwgaxvSIbFbF0v`@nz~Hd? z4rmIAOrqeiXdW#bZ-u7P$V?6;3XgTbIAG8uHi?Z=VNM?}u z$RZ3LZKkd`8Y6-(AOjnROJfrwI9y{(V@sAm5N5V{>*L$2_kE-sjmSw-7tl$PWbzSzd zju|jgF1E?_VJ{HQt+{-?NAda+*|4bApNf{%!rDyt9R>XdH|l697R+^7MhSC%Vf~oA zrP|kedej?T>Q!jI;gWv7&_`h?@Z#Rh&(Aq!f6BVTUvk23!alriq`Gsh9gY3du6R*T z!RMT^Tp>3%tR_mOW_&6nKQ4l|(>KB7w3oimqfxaIr}4YYK(*kr4)=>E);+IUZY0(7 zT0OZ5vgrMJIZkNxJiDV-YVq}_xVZYM5J^8K>C)hdtaZ=ayjCjJw~#NVCx0G45jVF_Yy0FlT43N-D+v?Kk^g{q?_rJA?S1vv*!#xuUG zeYeY}hpjYM__Vd*!?Tuwr`(aC^ojR_yU2xc z83w4z1Gv=&O{2uD=SfW_?>$uN4X`1Q{rv2{-M{VLYul_{Hz%lMSd@_morsLn6nmw_ z%6Cj1y>z&5r$3%X$p%lX1VZ6r=Bm``^6e0J0oEvW@r^B(uk?^Zk}&muX^do zev%9^x9t(}qojmADu*f>SvHO#JUvbDIRAcc>JT{`cRX0X-a_-fD01_|AoYz4&*1d- zNVS*Be%4U`*_x(xpPyRexb}FsY@BZcf%I^zV%B+#$~hOXcmzS@8owhIKIPEeR^pm* z&nzgh9Zu}&NJYz}J@3r8Vc2TCv~Dlun8D5`@>Nh{{+d;?Dq;A2dMW!85+sj4=B1r^ z9N^wP>Z#&n2V0Mu+i%f%KzP<}_quoJMdL*o*;`4lyy=AYvrAwpKUhQ(xTeCV-%f7r zERk(qP*fmX-uJl1TzlVUOgF9O0-H~nUadhJ(3*RU6^YP(3<~<9eZ`#E< zVY5YIYEd${sO(r)W9E}9%k2Q?I#@)BbWMd~$GScB9;%}?+Z7^jCf8jxUVbL@Fw4a0 z{nXp8HFA5(->Ob!KDd2h+S*+1U`$r>PFJUAt3sNim0E-YjPuS@S%Wf3nT+LLX-h{L)N1O_1&LuB$+DYl>gpy z5BFz?VTP~!bwXHM7m_NTAWC;rGhHFE4{H6rE_EtNc^MzFvr@yQD8SqF_oq0P zeUx*G9N3qm-yk*(P*rz1c*rQKwA-USOKwe7E+9~aMP*=LoL(<0Ypb9akL?6H2Ut{& z^z~JmSLS)HU5hlVTNS^9dol4vEa4QiZ`Y&Ykb3u%QOXPR_nmBbA#eF%xHGSJ{$u8+ z=136DBox+w?lEV(cL2)@SpnI-ej`as6aKN%A#c0M=0(43SP?Xp;_XFDIc+_sj-Y%0 z*pr5N%iW$;DDJ~u9W}rwM#lY~!tpyn(VsYX!TQqQT>x%@L&&yXPMbkjsyP<4mCCZ;oe{$gEa27OJ2my6t>`}i`B2SzhU(m4D!eybG>IBYjMd>X&+X2PvB!|uEPn?TE9B9u7Xod4l zMo9~)Sz9g*=x~I>H{S~^-!Ap4H{@aZrRx>1%isI1Y>M0Fw6ugUpc-v$Y)CS7J4q1^ z{ZZB#v=v0M2;#Xjslw$8UpFmrOFMgHcyAaM(o=ChdzOnGZ&JzLwEF=i?e|tk^`!+n z{PPpXR=>@%Z|o6lyq2}QA}WDYvtdG<=QeTs(>?W-x6!=7vBjUTL+W<|Q0E;2BG*gX zjpt-vl1Y62a?6^Z%fNz0u-F{g$(s5<{O1ieOX*j9p))Tn|Gla>B{Tx>+N^Ws*#qE) zClpzIuPCRXwO#e|pv2JbW>Hy5UCHiKF?J;%P~_9qa@&SJJiIAAdHh`nJ3qSa>E~l9 zL5JG`fi6Mp|8);8D((t2n6DGLt5;Hqisi2dR%KYsooRlfo$Cj9GtkV3#XO{~Zn0hi zm2RP#)z*%qs7f@jY$p`OeNUy>j%aHSdD_dJ*CIcW?%H{{^hmgQ-Kn4g>5QnuWjBot zhVx!zt_@BbPzcFwIcY!D=V_=+ z2)TuqIy5s~ASEC5!$BQejO&H(lA~8U{2GHI{I)PQ{&+w!$isplJ}^^}d0YGI;mgIN zqA%$JGNhkP?)-VD(PZbg>izOc+s5u+dSm-SH`$8>LPB7111Qs~c6_YTtsv5Iq5GU| zRBtrYvbS6ojqi9^otss9x&K_7{m!ErWM?&%-mF$r=Rwye2@#ao;5*|-KMaQG2#b$O z&2eICJ5Tf^DZg?Zl^#<&0jP1XxCzIUl_ z-5lC|DtjZwqH4(+(|2u}7UcYeAec!I_sui`%DLjZoxNZnKZ%*lJzI!9til_FQ)IlR+#?$r$6&Cw=g zwKII@boa$~yVBAWPF`Ov+IqNdC1>rU3M5%r{0X^G+CDq|f(f15B@`M3`Ks3b^%JqF z)vM$CPXtDj7-6;h1}-V1!QwASk75s9y*4kV^s?yKdWzJN0_O#bHy!T<_GN@3 z$@fka`f*?2ZVFcjUrX-pwY=xz8%f;n?Ron{BP4YVI9m}!`m+~w(3_ka8}m=y8;IKU z3eqy%4wJgZgVm$Dpi1Rm!dp>AYa81Y>tuSo`{#l%Us&V_3II>joV%ySYJ;B?D9S_T zVl9h1-m1_~Q})7J7q*ybb-SkJcm0_U|61XyptLaC(H} z2)j<6y5FL9lb_`3(HX>9iZ5*aC|MhZnT*@)tJ}^JmwTFwEsF=Vp@c%i*=}ffTS=xx zs_?Hh^1REN{RSX*YrN^y%k7l{mD+o4ocEcEGGj>%V`Wr)UdhG$>_yiC3-|#};?B&I zOmD`ac=@0uJ?XsNPU|@~B}TRV4cCvbk=@XTMJ_XGUkfpPnNubwgy88TGPgh4?06W3 z7XpWsghE%(r-}hIjNv)(_5-oszd0X1{RCCy5~1}ZyEAu9gn9Kw#|loc3h`?4T^$X9 zPx?NKmsBmwJ<0n(xFMmC;`vm0XI^`{1PPCJ`*r%URTpcE#$L^(Ww^F+3&ISTiVo# zgZ&Wd;}?5{mX3NEpQD=s9Lklcv)a1?Ib)7yB$mbJ8Wo~MYOC->%vofBMh294S z|GXEN1uWjM=pu3%$DTQrc;m!2s#G&<=Je*5AdCyV;N5eS``q{jqK&@aVt+XBGVOv= zL$~L#FIL_4HXYlPDl3AMeHw>#b@lVEy^VcvXX+f_Q-(#qA-$Yg=TIup=n@LAf!#yi zP>7Q0JttAgBe6r>%8uDi$dztK5WSpvDS%q6!EGB#ZeCE5A~YOR*l;T-4!mtS8w5<2 zY1w?L^i;m@dvKY&La|pa?%AXMlOWax7Rw{KzlwU9`lVNIvlNsSbRZj(Dny`D`2rAlH|dQ6s2K32xn?MY&E#iCChc<3j3B_ zE0nCUs;keXHrKH!8Cge-P^A3zZuFH*y@ljTfpRWEY&!eAanO9F4ipNo*asoCJqkfG z7Ay`Y7ATplSUMHVKMd3h2$Ee0!QcOX6D1nMnN(8ZZJGdh*Yn~}f)`5f_0M&@AT^MnV9O=Z#$A5;?fgBlJ5jab$U>5pkI zrq0^*sNi2P5)1}nSBl{=(X%qjkuM-Kft=45@V{*c;**JdkpVL@e&n3h6oaxofQSGY z|LrlW|9;e#NWcm5oo5wHg_I;uA)N>?*Yvq&q%2Yeg+Ryw)&ADCAPk0N=_7;J7PW&2 zZN6Zpu?Q2giUso32n-F7FVb*iAbJ3pOZo0=I;#WCpRp-^oxhzUr%22U7nuL8T^`{B zWdAR|f18i&kM)71zSaG2dH+_Y9@qm4vJe1;_-j0@wtA_~8MNcw|Ncm;u-V z1OkKrgaH@=I0GPSAaAh38}}|qOG)?AC9!mODlJ{>vMjmm5=#hzAl(MtEvblfgMvya5@H}FjZ%V2 ze$RT2=bZPv-*vs;Ki^#YdnWFfx$n7m=6U8C5C{Zu!QSw8_rrLBKzJZr4nP7PfPi{= zOF=;(5V4Cd5(xtF)_6I?u>j8_LW1-2nvdG+T`TYOS~4!rK;ChG-42qFk%EXo5Ex%1 z1S%~L@s*I5heDvTvQQ^!X@H<73NVNnnrQ2aNI}#sH33d%Bmy94V!UslkSW1|~0X!IQtUCtnrvO2~o!|&% zD8v`(qAUq1dfKIZulXU#e*aj#DkzvNr)Fx*$o*4@$+{AO0p1d zzZ-xk@Pzp~D?>%a0U_W4@p2DBI>T@pp@0O;7mjvCDnn%;2sdAh7aRtNLLpdRBnsv3 z2bAQ30Cx_?ppnWF(92LL#0Bn$g?amVx_jd|{!rlK4a2y&_#v^% zA`%d+n=c>%D3XAnFc?p`8&HG&Zj^xdq1+L`V174mR+f+!|Fa15 zaz_JIh#vxpMk4&N%2MLEVfw;xKJ`WVxdGz72-sid;^@8zWrVK_#LEeAEY2*TqAVdP zDh~0%8KW#NDgzX~af*NC@E~Owd7!}$i}Y5Og1CDFvjjv0Fo}RJxDOBjxakCigFxi- z$hatw?D^T@&KZG>V%Fe01)Nsb=6)^;h`t}ze@|JSccu92}nT%p;Pi0s{kg0rW% zMo;SQ*i$h7YkIkQOOZjzfQ>Jj(Z<;;R6(J8TMrj(CNEE<+)0?V5#f7E#}fHj9PRn} zsW8#9#B1t07s}Mn^)9-KIox4-@MW4AZInZ@Ske2Pr5E`1pNkZ^kkWh$rg(mR z=S6cX=YE+*NvJrTV*|`wK=q3jPk!_KopeDl*6Co)9h)am%UdF5JH3HagZLQpGSkGnDIG)gnHP>`XeSaC??x`7SkWOqbuQN)O;lRR9aRX>@Iy{c z)R}&`k=cUZMidY2jmOkI{emP3AbUHP5(fk@K8RrDXfsbPbrI53A5MOynKaH#Ag?n* z@$I?y;CPr7%lzUAz8sM&g{Xw|k4eSi<$95+EoYwDgM_%S*3WA<*Y;f^$SarqX!~iV z{Jx!jpi|@$;dEV6JubRvmgWi}P61IklZLKT8H;~=;W*w~FyCmgnm4O0er$V?#G@0J zAa~^a;k}gU*jtq&mXC<5_`Yue3KM%k6Cz2iqf9Q3BTI5H5G3SG#p-X4mJ|eUb><*R5P^k@sJAN+1FTAnm&UB5Wno)oRbTN#7(=Izj2hZIFp3(1dNyZzWG%O4ItkS*X>na+OY4(#dh@K1_?>zZC4p)z&YE{FPPmb3;N zzQVA3DDDYBd?y28owf(e1h7k_Uyb)#FJYF9cO3Tydg6z^sCwbqCJUeAUEIaZ&rSFpggXJEP%+|uj~vK}wvyK0^{ z)!#h2IR1K^Y4uZWG*6e5V%GAqehhPwGKmi}!QehK*Os-$V~%I0#fL=ja1@Ch$t4H# zH;@TZ8}tvxSrbqT?@YBYn1wcXk?uN(>T`nKz_7zmfE~yEbT4YjC!)2*6_+_PlxLrJ zv_(BQh-&CJw0S9U>*;vjY9i(wZf0UCG9qTS5AL%Stlnj)-YBkgj>_dOF&fnvz4u&< zZfWi1LyG{zku*mk&rgSwd{6F|`OVBpt&ej1w)hB&s<#^zgz#*6IONTa~7V| zxcG`d#SV=kA)!2nUvdn^m*cDQe5n{4(sG#~ey^+H$@cm7%Z3Ba+lk0#vQfH^D`yJC zN<5Pgy@-D5Dm&;A!#3s>;Vsrw(YMNSdVYLEBRLJZ2f|ZsyGrI&JpqGP)45*E?L{07 zzGC2g+8h$@3i2a7r;~h~Q`S^uyCina%GNdS5Z+zN1f1#!M6$BzfB0g1{9-xN8 z>~`Ngn7or*c#>AUIqlG}(W=M@rOpw1k^pt)!@nMBvYwcbnx1LrUFIf|FbSnrCG9o$gZQGn~b>@^OE!&wR@w74cvv-Rg45@xJ(7qq8`2PGEc#$<` zjGsS9UMg0M^YzZX>uS47NdM;g?~Ub8=`ZZzdsHhp-7qk_`govzjsAI5?t8pS`kbdz zlY1Ha?^US}3K5j1Y#PDzWY?MYV?*7t&fe6Con#)luIwS$lk0*h73G;?C4asGgML&O z+Z;ECe@*1FX`j4vG0IhJbL5`o^E#PlabJh!R9Y)(Da!gJFrw&4N(Z)8&xzeqvtF0) zFdfY1rHM;f-C28=r8DfY-+vtM^ey&dB3@L|!`kk(cldjK5g3CXgHoxMHIUZ_ z+ffo`Bj4&t^NEqyMS~9zpUpN}%E!Ax%*G5#`}uD=i#2DStXSP#iDAn*3Yyk;JX$Xff)>El%Vo1?BII$}a!>As^coGjLN4uU}UT2}jb z(p442cAM561?Qxs?T4dScZJ1MXYSt@(BiXwvy!h6wHW82G?nXy1FlU3VQ_lF!c!4 zZfTwx|W6phD6(LLcT!a7hVynce+UpM06I+#NIaBEi3eF9U@wh9;MU0iLf z%Wc{i)HCLDw%&QZbexG=2Ti66lr;H$!nQpyHdTW*yd#d#Z5rZ9O|$E{MvjhspT1Cf6^QZ&I;&^|+cnmSM~t(;=<6gDa>(%Tf5=?i)GwXffI*ktSO2*J@WUw$L1@-10r? zxcEfl+)A9yS18gC1Ztps6*e=_uEJ|w*?;JlT6J9S7|*tK5HewD>NQ;G*kHgRTzHDJ3{!im@rzplS(kH*5cLW2I|aW*O2dBOnm`9fLbimwkN zd0`2t)vAEzs#L5;rnM6*mPxQb&p2nKzY;@<|X>fXg83C(EJIDLa!KRfTiZ z=TG|-KFfv@scU3;?_Jh$9d98Vd2oid9RrEXJvh1e;{nf6`KL_jr4;tNHO=YoSB5@w zoMEnSJ|=2=D?m~z2YJW2@kW1E0zd4l@K+*%)lmae=gBVGN_Jy{eP>s`mow%r711g0 z8J@*tNi=(_zRq0`L!L0xexu|fYxg4M>mzyJFoBO$&@U>ZIC^x%I>>-3X>w&yJUG$Z z9wJ}m&*pbp7+Wu=t?9qL(L5-zGTWkWFIc(yq1{vL9Abn}F( z`sbv58-o&RUz)W43V)(Ls&lhDp7u#z8jA0_UlE@WRp^{M+CZ_B@E5$N8f!1nK`ej8DX z9TCtT+SN1+*Lcr(^kb_hpGffC&zFJCw^e=lCpDC92f0D>n=ZNGpxOu!2z*IBhX+C@k2m~|BEB=N*pL%8eD)|H=K$vZ4^Zi0qZh$#K@TG4G#sugS(N3EB<=FMd-dD)yljktBALCA9Hox2lT7t}4nx{zS)HmB#o^7`z$%Z_ut*z6&_%xV#`C*>w z=o-x3)Q9Csc=bXZD*qx6Iv@a%i2acfp~b+!(MQiMjkFsHABazwHb(#504+)PR)9r=Uk{PrnhGO*`Dkt|1*dEoGdSG_F(Yb^ArAH2CNq# z25cgr>)#+?6}1$@v2fAuXt-w)QG+dyn&R(dxDy_#KP%gd6Lu0M0g z@;gj6)>M7oS|XiMgT3~2Tkvdna`~Ix&i-rZv+kzZd*(i~RpmCbAbDimB$@q37D9W#|HDqB~~FN3rwCn`cbkEz=;9Fkc} zHV(qx2s*rLvploZdj$wZtLIb!BSvK#&>8@T1GvBe&H=9K>_Y1t(At-dy$h~r?;9&Z zz*5jgjjh<9U8&eLf>2ZviLBrKXp&Df`1-Q9Kv3sM6kOh)=E z6_LZMo+`w6!XH?}PP8gsj?;1WUa8TEd*ASM@D0N?9q-kaa5=4KVeIq3KmZ57_&s{l zlWz;WCuH*_4KG}}^I?w=FT}m&uUi9LGwL}b`U|9HNO8`dzXsc_Q#XIl+3#)c$uNj7 zO82a5GXxW(T+)>{HgP9xReC~PJ0+cegPhY=ESu?pvYI7XX!(3Q33jYJbIeFU?p^9F`b7)@ogV=IL#@7@J6nN=&r0hB{iUqlY79|P9 zgv$qUS;HG!L(SZnWDx<@pd)MjUC4)+uZ=5FLKzQ6RqL~7xMpON(jE&u&V6!W=V>>e zOvk8V`J+uqvy7llrUTMsr{a&%?>^m=DgR`0AFvIrUa+ApW$=4;p%39214-;xsWbJp z%wr%_`jT>xWlBbu|Ke z&6X9`Z4!k)lza-JytzA=y+$&?$H-ZFGU2UN_EMKE9OzLUTuAoY=f<@HwiZ&Zl-E;R z!e=SNscz1o!iU*SDbB<~a%jXbdC+&k)mJ$M6G!2g>6>i&X zKaABQ4CGFhLbTLX5%flSdr@4|M z*k~tTlPIRc-4`Gj{S_V$ZJf${Ud8gI@zLV~BZl* zdKqEDDtoqZ()T!kMFV=LVQ=O7&e`WLE^Vh=L2fe+Q+x$aHE~P6qa=tdvvGo*u|E zw;@FDp`#Mm0KT*SBhY0Do(4#)sOS3sR|FcTp$GA1mQ3&}vLY!`zp*`BsN>8oVylq? zn%Nt7ER?2_#6R^})z3~3u8-QxU9#7U*p0fXRt2}mp zR>6mS*_Zf6$@bUYSKRYDoH0f;%e}CIS`?yMwH;~ve1plj?qy4yXfbAgWojL+7dB;n z#TbhJnV)la4GkVd5YKB?N!G9*g02%O!U48m_1v~U z_M5+VNRY8lcpTEclw&{CA@1cjH4^9Zk=-vzl$4;H1Pwm}_h+$ZA+Dp!c1|rp@``pk zi!E%EYPS}IuaW2Qr;tzGf{&=&c3|O>cDJpkWC2}>PT?;=qKH9*DV*v?4 zaN*%^pO}k#m}Gps6}*jK+^mxjPJGjP6?%`?uSMeOc4h=_e`Wv|{`l;Ts)~E zmwj6@nQA7*cW#$(W1c$g!ztP;cl0%;gcLhPqup*D*L9YNow?njln=$3#tbe{_{&Aq z@x85^o3!huQaI6LV%t+E1EECd$LSR<<%uWBs2UD%c0O@;6xp5&_n9 z^&HOs_K|n(3O)#&v4bLsky#IUXEjZICJyZ!rLgVjzm;=C{Y`*cGp|x@yk*v~YR~@X zIR=i6Cl#omUC!Bz&Ly9ryMY9a+idC{3U4kf7Hcg<)?6~58aOFbylZ%=V<#oC@^1B@ z^GKdH?bU{8Bf+W6gXSJu0fO6V{6oX&$D@aRD)ZNYff=Y5!2aPg_zPxxyAFMhzS4L1 z$o10S)!2T~PkL$^iUw(rnI}2X(U2xPgpiR%?nS5uEILJ~w(n93fmSEDcL!j5b)`ps7)rhu3%xZwJ4 zS6&05CfI#d>Ga21s>?^hA&_}I4*IN=}Uld=JqtU|-n zj_(c^T(YEHXvL=m+YV}q>_b_Udr>8{wEgm%h1zO{8F@9?K4J!}T}4CZ@J|zR_oW+C zA^OQLn7eD6qrZd~JXGpjIWhl!FSzQl-Hk8% z!9=B@w$$pouDJM6Y3D>q0>1c@4b=;_0ek$MpZpI|51cGRb3LS6$TJ^vf4=r{AmEG9 z^`ii(H)GAEd*;rK?`EME$9==Kc^Ql-*89m(0_1qvC}*J$m+06#uhq0Jthi&F+^oWa zWV|wHS7pD{-MH?~PE#zkQ~2fhXE&a}kBdUtiF&>{x1P1SP>FttTXwnO#)qBxw0mE4 zEV-&6W(=Oafe9-KM|w|Nb1jqGtuZD~({~v;JdQgkr7=lqQRp+|8Aa9!Q~oHeB~b?q zHB~Pt`+MJ48o8HGycwFOJK~Bmh>5=EMf!-!NDW+tthu1s|9!W-CvBnr@%KLF!QB30 zv}L>kR#DW|`TO#7Ih0tD?j{qDNZ?@~pwtXpFz|aajO(VeMpOLC#>h@;Uy2qc=UNZE z02$q%CYEWEYZqfjt-I3X`q6J^e&49fRPB3A|BPd1h5t$INmoq7_0D(0?KJ*ZZtDgE z>k^nvJ!c4rP~4}J>-kv$74AC(%==zkB0QXW%#vYsL?fdF()8SqFU`E@I7Fer?NjE) zS}vp4zVnQ72MwM2i;B+oWZJ|QMFzJ8TDcmK_!U+seJATo?0yH9Tm9b7KU3#gh_v6Q zKj0g-)OVZpUZV$VsV(>rrayA8@*HNl?JtP%yA~FA#%?0cL+N$Kf~w`I6&Ns%Oq+gm zR>;vVz%8(=f|q^xrV5Y+B3C<#6gi`M*V7!5 zI9s1v2wdyY;3p(Wdw)qNr*@fP^ez2`c^eZQo=}Y+XB&(%dM%uqz8`PGBGTX)?M-uX zn@q%g{MZZ7jd;!q=i;S4#ZmtQdTk<)8-^OZfZGGr3)cSL`&BLnJBikbK0X{sdKW4B zxX14dlR&{F9%r>cqkDApy+NdzLk(}n6*+kR(4aSIHn5{Iy-~E@Yd~*&bT9YhhL(%L z!D2^Qaq1FVOgrPV_XPMqZ=r>6U6~cTU&oml>NT`ODC!JNE|odW0=iZO7ZUwmuZ)vg zd!*;IPED)QqqE5FxZVyKSHpMV**^X_x_!||wXs!sS#f**isY`X&J5G^)>i{Xnhik3 z6>uTR@1QZXpOj)8i?^AoQ0E($Kav6Y9)*m!fykpw?G)(*pR$ts-^zVSJikw6E<3uu z&Bb}#c&g>@^&Bj>EbO&)>ld5gw#jqH^*Te0WxXE_7)9vn9r#{G+OMIPXlKHY?- z5XzsXR+tMFoktxL7EYcvPuFHGTfDg7`zXz5=$u^+Z=^w$L-nc>$ECiIQya%(O6#q8 zJKc}ABhPx4bLziO*L0~ZSac8qbx_?=G{+?~&aj0I!peqNGIPCgBf0|hwEBP?3B`Y1Br&W*BIj|!@~vWD`0;gTEaLQ&J!Ms(zDZ}Z+tBtvdjX*~qG7+22~|8u#! zb(REtvjP7sL5Y~R2r7Ifh0x~Qp-lOMd;&4joR%I83+t53tm~bZlls+iu@qy&%jcVO zbD!jM+8mjhv7&R^5A*si)0V{FZHvZ8wzjP4$YmHuk`-~2D|H&_D8Js86wPJ!(ULJR zpd^y`nP|p8R;%ir@tMn1xZ|%gwC8;`&M1>~ZBvAC#OHa>)y!jh|QPJv!Mt?7D zDiCT>R!1HWOVL9)Z`ehWHqz&0ijEB+l_uHtsw;?!bBp>?t^PY)%VA;N*y@ck-bjcH zH(BShP$j28L6Fb0g$Izi$0k0?cTJ0Y5hJFfQ4i9BEV1yQRdX96q>y&1_ojTF7*2A&rx6KFGbh(cxX(J{n0D_8K_YIj#Ds*TrkIF zcC%CTa;1MTbB^!DrW?(~3pGCBgqrebI6`-Cda%?f%2R#6#n%b9YAb*XF@J?b^+t+X zof$eb6MkCuiM=SQ8_RfH7djNz&@S3zhybY|=4Gdd*_?OZ|0* z_=>f2UAkOaGKtf&9?-k%!kj$l zkp99Vk{e-xiJ)+@`M|HN;+zB_MvPC0@7qRs;BW8E7(Se$Go616eUA~0mxN!zrAGWB<>s9Bi|ntBANqJvZAm9fd~*@7!2;6ALSL`<_zTjNcd|Y5aA#Q3~W39 zX#LL$K==ncNv#k;x3)(!O_krB#sBa9=LVn0u*QiynZSD=dgL4|Ddrt16P}H!a%~& zFZ%nUAb*tcflEqGD4?9>hxPkCAvm5m+&w!W$EAPj{MCSG4VbM56mh_%|Kj+g`5#Zl zbKGGB?)IK0*crrrz5rr!1@hW=YFU!Y3%^!B+(U_yUL*qyB6Qna8s_Q+BpCg$zZ{EG zh3iEMcNY*yw7__A4#y>2I{@$<#NWKQ;0D?N=l{xaFZlngYj8K4E@2!AG^ohlO` z(F1is04xCb0KfpS1CRy~4*=Kp5dbduwE^S;G9*Cm0ze0V1b__yjsTPa@B;_~fNRIS zq~P@8^q2v_=@kZm`lCL-d!7b>UwdnemCu@*2hn2CKhHi16pug zLMYAH!jzU^O1GfX%tL}KSS$-fa5Y2>MoT=LTnx-;cHRz%GbA(^5gg(;>CvHKNi-8W z-PFK@Zeom(?4%@)wUJS3YN}yML`Y~{G%MCHE+O2A=*5to6cdej;y6hWaj}Wkv|v^c zE7;bUmJk|dYf1|V4T_EnjgjT*4Tm;%ua}lVFe;lV_H%| zXmoT$B7&^atU`j55D*+6V@pRSutGB8Vnc0BjP;F;X<@9yq(Dw$R0N0M_^lwG6Brj3 zmKd63YhXf4VkaPpL|YSDbX;5%i;WtAe{sgN#OR1%WXoR!ofezG?;|)OhLuFv5fPgd znh?!GOb8zoot(f*4-Afr;jofWI~av1DS;Ici&P-S1Qx*)mcWV$O+>*83go0CI3fh~ z9Tdn4VQ~mAf&zmgScya@5ecDuzfwaZ!r4hdh!)2QjSUQs;~?s9BnOE`g{C9jwkGEE zKVV=?L@a935`#lyLxYo(Y|ZF|nF%Z+qzR#kY$To#9Qa@E67+;%+u(#ST1*g%E8!Mu z*qWFc(rNL8Gq!X?luz*-LNUK)rP*4{Lx{wrP>!t`ErNpv2_*y?L!^rpkH()EO~3&Z zRYG%fz-7=i@D5I|o$;K?rd)F50_MvEm2L)zigE$S=tpM#u7R}R`lFbFm$^2o4o?=; z!K2e@kJle6mwbnP+;;;sq(vOw&geM0k^Wpj21si?oSt{B$$$6o$`SXjVmRYL=$Mnu zpnl@W6$n@DMorRk?py2`S$X{}B{MRJQ-${k4ZL@#0h1hZZL8m!@4IQ3XIb%`BXc zOcUP40BoD@wqtM9F>^UwGAvE72M3bF524fcBw7#`x=pu}WJt5fC+#K_bH%p90wY)u z&jZ*ackRZW?+PRc%rfl;5bEi01j(%eOqlgS8~b#jTwE9RN~)k~``njm z)EZ`P7o}L^I(9*_P19AJbB`lCZ$3SFfTOh=!%0syqi}GG2H3peTx~+17X#o}B~mUW zHY>NCeLWNyGGfNV2Wv{YEnM}pwI!X_Bh5wUKH!q&pXYMhq!Lgp$YA;!4v|Y<Q8Nqf%^{}y5f4s`2?+sD){y_N|siW)o1`MBtE=TZ0C{GB`Q(0j_uCT9vAvnB+CO` zY}?sc62-#vkPLQ?Bmerzro&StJ$49yGBf8``mX{M!ZH*FwI`-WOTZy-_rmSXHeN>FWYJvxGFt1$~P!a*|m@Rpd z2{7B?TH$&R)2*}YxN;+Mw=`_NkknCR_ST9bBoRBqhL<_L0tdp+$gN1pPcZv@;c!rUxLIh1M=N13Mp%^NK<8|Rk# zq2v#IX`5WQ!WAxKWo2lf()+V~@ioQ!jB`EcfoeF**PIY^J;+hF+qoqsew~PL%K%XT=UCK7k7<+TYIkY zhX=bJ_BV~W<=H%x8a;ZxOzdaf{bxNzSFkPBlZPaqubpJ9E0_pA_Gzh!WJY80z;SKQ zydA3xp0~&WSr={-_Oz4(2)c0rwlG1V;kC=6@t0*>)79k;1hKng7EXRo;gU!7GZ(F& zE8fV1hyoL?22Up+GbN{@yg4tqCVc0Z*zJs$95Jp?E}CX-q&*N`o(;QcpDQI>uY1OW z^aot55*N3C9!+qJUNX1+HTW?^H;MR|zudpFdEzV;n++mVECW;V5&p$MDRc{#P*PG? zNu)q7_?MG}2~))BAjrm0ev*OGK(>wd{yeBUSBooh0d+=FD(fs_Z%{Ydpi4C)Q_$ihpw6`9kyemYF@G@kzMS2YIovEH zOhT)q02Ssk#fjYLpc)8&ViUF!KXFrBEe*|_Vd&nrb=m86&q^mB7RX_46&0T8n^QvnhhtJ;#>fET!V?#K{i)%M7*p;Skd#u;}H=>vJN4x zrzpG|OJ&643RIC`33b0SH4uz@qW)zr;tsf?E#e`Ge)bcU9a|W9mh=|#2%)SF$=A?} zsevDU(ddwOfFq^_2gVox^%T+&)<_44{U@c#L;Sww^Bs0@hN*`GMD+*^gD01RFXN=k z%T}$}2;vKXLObW~(}@@<4_rv<#>82xwEOUQovnpiA6}-|Zvv6??-qVjN)$m6O*I z?C0+2;)-0p5?2uI-~%EvOgnPu*a}L$bN-ADF@|*cCOLado=*$r8t}WMa0I^qKY|d8 z>*E9sok6xN22maXE77EBL@i!K-CfvM3`8aYsT->yYM3U6%wN_a1P0Oofs8dMx-Pj( z@j4;7_o7@)KF54qnP1D7$L?`2OSNd3MX5$J5h#JUz;bRpU$>W=LM9D6*nVUBN4!tU zyN9SBx2oE#563`qcN{(XSV2?x@mh6! zGV$wVM8-XFeLc0>1+BW9sWz?p$#`0pZP#Dw#m;)A|&9Jda(A*<31l!W4cmpaYy^!`1nMZ16Q@)OozG2$!d-C z&%8T!X=MP7Kd3~!$e>tG+~s}6MwmSwOP-$S9-ZZCmo+p*D}DS-u9g0D=C!z)bq`E; zRQBFatU4gfY4hH8bgRZwX2^@Ai4>0mx{TpPwR_)rq~AAeWViY^c`7cRvGPm60iS)6 zKbz;<y!Le+ zPnwiF6?@B!v}&m97x}9}+gFEW>3T&bY##&TwZ30GEHJgmg?n1Id2S5%=(T!UVcV}e zcR{}QnOxEd!ihje8dHEl$pJ7i(snTmP*6X!YnUPfu3SAvq&*1(9j*#<3+I@di6*b4 zJQfsqfNcjA{*Z%`cJl^Ls|>Cfhfsxu0x@e5a8*vSK-g~MAnAw*GcrlJT(o1JR?^4Zwm6 zf>L3O#Ywu)cM0-@NPdoPdvPsGIg=WZRe#rT>^j=nkfxIT%s=Yf;4)gU6vcC1b4RBOqqQmEmF6c&JG_ zjstN<1ZY7!@?HSzf_g_q4F<&>|HJ&6AAMgO#z3SICstfC5Kjyy2p~ty|HEa*Fc<++ zncV8pr5h-JMRjRpw`bVA5sEQx#K00hiy6)lE{s_x$bb_B3(1UcP#YJ)m}N590(wD$ zl4Tfe;{*`scgQy5w=U6UQ4fF`0Tr%ov0|36=r9f@H0n!H`kW);_e0zh2zKJ<0H$0Z zMay{UxYWCw{WT6zNO=t5Fpy{^xMqF*!%h*Wd_*2+34l;BfzqP^tU!-z!kL;$QRQS3 z^EV%6-a`NuX~bQo9J3;7p>A{rpaCf*ZGTByRyz~0Q?&NW;vF)%%8WujeiyO@!mEzpPDV{i#%5`x~M{oZ=fy`t5Ef!AEE&WY0`m{B;9;SXtp!73&p(yquc_02x#XjtH5#H&N(do>- zM}K;9o%aq4pX-kw_qN~5)##A=F>IMMX7mqA`J?W~VGdZn{0d3+RGE^x;vX3!us2)t z^(UH}qsw}qKlYKsNSy$RTtAN}#mzGt`;K0gXl9aEGGH|t0y2np1K9^BxiX1{Y=XkZ zFI!0bDJg0t&c{)7r7R_C`SSxS1Q%=rK#;%l?xvhhr92)8qh;%NE>adV1zUkMj?T)I z>s?eoZXltbq>rXPijPB)=c{oBpI5X%G#cQDkSK1kJRP4B-id=YQ;bUC$y87-&zOAd zK)!0kRnBBc;}nKKU7chQlrEOV1i4He~|5Ja1dE6=j`Mt zrHSU@Eg{vm&$Bbu#O!=CG$73xsqCcJ#xlYW2Bu zP==3#wx>AmrVZB_C& zW40Dn9KZP^3LJ4loKj9kiHJOOGo#u#E`UL#ha)gskSWP9==9E53Pz|mGAM8r_%-%` zbj+FDA>#^ICsfggNx#J3jL>qIk@M|~3kwKNrDWe)dGAjzOnzOQ{e(RL^wb=gDDai|8!ppLr;mvl683`rVVzL9%?gTb?Fcw;pWnPLL>ebf2DPOjf z=k>~{UH-Xu|Mj4w*Q$?>E)B!O$}t!4!wh#zEy2}kVl?wE!xv$R_ShWqFy99<*%$Oc ziAglnti*T*-1VC_3V~QHzn4p0)XU7*US>1! zH*w^s;sm!pMt@K<8~=jVIUXfe6x536a6_yA=)sO)BIuElX@0D1HiKZHQDQ}SYQ?GJ zmh#&!c7Xq1qv&-MN1)QkG9akMK>nB{nNIdd%F<4;0$Bji7~#p4g1XeWf~rXdviE zvTG<7r%Q9q_xPp}y>`b;_eS@y`7^N0W& zl6ivH0dBz=LK;JMld)EGBM<%2Cb*k8;OgHLENyyXr@R_FwRrN&?_BWsciwHN$avMR*6f} zNY6ouV8w*^vptqCRwYFh^B^F}TJ)+F0oXgz2%kcRO|T3>WU3+x9qF1~iB@n4c|z#5 zJVuw|F6?;K8nI(vsO{LMpa1w??s}qN9q7|BIk`0P%h3p`v;WjfIeE{%sgMIN^53sk ze&X1rkbKnpV-s&^)2hzG7we12L0zS_L$kZ)ip83FgN>1XO0QX1XKI{AW64#I(1dd9 zZP(S?-V7fal-wB=uvSO(hdVjJi=B8Y>vp*PB^0I*xd*lG>91s!_V!F#?B^}pvV7kn zan%C*BP4?*t3=nvdEQw~YpWUj9`Ny3TujEkC+{jO+!dEw>DxY>B|Clb#KGt-#xJXC z!*xb(CjT(n&ElCxz2TUhE18RFRrz`qFsa)1=>Sj zNx2L6*L;*0dKd19Vbi8(j zJX9G7e|G9P=hyoNfrEPvcO~rHr_1|Z{b=g$+Hi)5ym~cT>EJqhq0yPTAW^7|pZVHl zvCV3FMs@f1*e(b8nZ;L5mgNU1Jysqqc_gVIYL|HX)k2wHGv?ojJ{*mwH~R%HG&!f4 z_(pXnBXiRp=MIjfN{?`x%FS)fFQ=As?B+Y#550wj=~e)6*Y1E_+NR90JWD0%aia~{ zmDivRqQ4vWeVM$lVeOeuVeHwD+k5>j#qpdWQswr~X8x2RmG4-Qo?+42*iUk|pBCy= z2Ar%93y^#9V8aR7YQt4=V&D4pqp7K!NxO~@ujUrhcYgWs>EeR=rDu+PyYy&V#l$d7&_;<8GK!jaM=%V9x?0xRCBlo8cP(_yow@B}=hX=>bi&wES?@ym`=`%~% zVUhhwzV5)OarN?>bNl|$Os_Pt92y8%+ST#u{KYB*vWD{X!?!cb-An3MX7`?xG7%my zFH^@9*tZ9bJP#B!H{7em=b+A1u>(1LGm;s3Z_YTf>f%1vL_74^( zDPOf5pP`xBb=mN`%E3$7wah!_A#1B*2X!}Hj$xEK9safMq_EG^+M(%$(2yd!!s2a} z)0HRB*-zBa?!1n){nSE|+57yGy^qSCEv1bP`GYrjCkJQgq*<7|hb7%@X&jh#`=Y7; z6&U%v$G+Nm8c~N8T_qkByOmf^t&RP;>8Z&%Q=#+P3svWroKe11In^1;UX7f2U{`W% zQLp6I-Q3NY$Qi*cR~}=D!;OP?71;SW*~urBwItyD=e`|lPyK(~Ss{E*t!#j_f2|Se zaUZSi>c+WN3o7?eAI46f-g8Jy#X>FcqkGNH0n)p8uYUhoNA8%N{GlZ*5N7bpQ1hv@ z?SzcI!A0#|yBFzxIjp~(NTrkm!vE=%#Uc$6?ZuhB2GULi=O5&23l6pEEWQ0&Y*j18 z(OF*KaZCS}UEW%&%w9cpwb&5L@aW_glSrl*eOU~861bE<9TJyEv#jFZ`8 zcj6Z9oIJ7pV?$1CrG2-{60*Oh?{{hG(N6<9TfcuF-mUkJF45xurry40Z>q(KRhrRz zBb+1d>&i@eyuHOfFXtJlWV~kYS+5NH_CdG3*onzi?u`z?)%AD#{}^sHHb^l6r}l(*DFc(AbM)~d57_uJUsT5#Mn&T(0QzU*Uim1at~$KB;ypmlj(q;=?t z_3vqqe)uwx$6j_NLwt_~X3V$b`>b#22?|XEDRo_E^_HJarhds>@HiuGv2>vB2l4HX z4uz{M)4u;=p|3Pv723aIb;Y@;6mM7c%WJbYAhem>fur*IlN_u!s$2XKEK$p*3@png*ef7^&ynm9&%=>`zi)!d%S8EZ<sD2;V&Y~sW6q^D_q`@BB5 zRF34UO2#zhm?#MCRXB zV!O|75*il!;>}P+9CxsTdc@3^+1=Y2kh=gZ))kLtOs!dH+x_jFnaumJkyE9c8TQGT zr%QT?;l^Z%N&MdSWVO2@vfq0)j{We_))c?naOJYmBh5Xbtsi%%o!L{m z`TZ+oueP! zot$~eNv7=3%TQ3=&J|cN>FrOw@d~v)!FU0j5Z;9}Qo}EjVYaf1`e|8=*e9zKo z#d~<&kBs+q8qJm|{iWBHdxAXF-R(Oq!rrOB=~O<8X6enE8zr|b%4_PluTyTpBxfwL zF>;{vr~4Fo7Xa3F2bVa_n6EbtV;jA0TY&w}S1m8{gjbFhJZvoAuih(G@=w#zOEWAI z(q!sZShKatq~-QDC>OjtF@_#nKm|J(OQiAGlWW^K#AkuCr56<@AR)(ktXKMyC(G0{I$rTJ?3>hz8=NHgHB;o})-86` zw=(Ud=VTWYCXe*|YE#P=oL8;&!ZX#*(V#Pu^2}i7`!{U++wEIc{oJLeeF?wpx6<;L zc}$5y6H9QR*78pqT&ZOjUbIScduryt)Km?3nihz&GuFF#rYhL9GGOU!%O9&w%m}X~ zQNjh!KG0q*=C9bmh^=Yxdhq1)^VA;0mOcB5ZBJ-S^uB(S`>5UWYpGs51G)3SuC(x9 z8x;BAaOC`XUt@18wgq1G0d}?I@SN($*Virol>ETyYx_s_qZ@dG*pCG=*JLEKS8bl! zsJ-~jrHSq5Hg%p3<@xqFDiswtxd?SVtWaL^>dRQ2MsV1z>R&B;cKUJs4d<3c9qB3_ z*mJ{?1vO1KjyA5*bh$xdJ6(9aGhwTadR=H?8&0v!C%SvGBEK_oa~qoeHU3NXH1m*CEq0}6|Fuz(XS&@~ z9)6VaHYK+i%vNskITg1SUykQqugLpQ+GFeX>t+XeeBJDfS!#l(C4Ny{E5&zedkwt( z$Q)KQZeOiFRC-xdBev9I)&ur*pq{BMo*54FMdM#*?hd;NLQwnBgU)jac{hDOIP%o>1Dz^ilJ_VzNtC>!m%d!CF@vc z-H*}z+P!JrgXyD68|-e5*7Z5tG+qPx@cs{Pmzd}u6TkD~lxMf+syyj;zMRIuscC_x z*o!31$GvgBsvFnH*J)a%*Ns!0R{I=I+N@lh_$|sg@6*qMejAgQ>t1(S%Ul(2k6*cr z%#2yDy@S3d=+I2%fSJ!1=OySTz4}pmyYtY}H2)u&>kgV8rHv=+WnZ^w%-*tDd($fO z$_p+_*$*ABB=mP)FKGIpV}lt#)Qx9h?QSm|^QbYo?l;z#(#7EUl0lDMBf^+q7cz9DT?1GdS~!o*B@=D z-~YV+qo4n)Uos5|dGH0bLqn1h5u_R#otVVO@GT|uQvTRXDvk+>U?CbUCgeYTH$mvR zu(FXaX}}JNPWYn(h%Y$*!bI&&e9`I3iVcYlC3r{<=$pPU1jweu@Rk1CZ0(TWG}RFF z;UFQ5E`lzeoDfa>4U@=;NkP#FKAo79_;)}Eo`b|ktf(fgf9vEUkmDXegzRtF{uc+I z?cX=W>1ot7M_L`Q5RjPe1;ubw*F0r3U#6l#0^&xdjoR;HV(62O_x*P@xxXeR2o #0:0 (rawvideo (native) -> h264 (libx264)) +[libx264 @ 0x5644b31f07c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 AVX512 +[libx264 @ 0x5644b31f07c0] profile High, level 1.3, 4:2:0, 8-bit +[libx264 @ 0x5644b31f07c0] 264 - core 163 r3060 5db6aa6 - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=2 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 +Output #0, mp4, to '_env_page_chain.mp4': + Metadata: + encoder : Lavf58.76.100 + Stream #0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, progressive), 800x80, q=2-31, 25 fps, 12800 tbn + Metadata: + encoder : Lavc58.134.100 libx264 + Side data: + cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A +frame= 21 fps=0.0 q=-1.0 Lsize= 11kB time=00:00:00.72 bitrate= 128.4kbits/s speed=29.6x +video:10kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 10.128633% +[libx264 @ 0x5644b31f07c0] frame I:1 Avg QP:29.04 size: 6175 +[libx264 @ 0x5644b31f07c0] frame P:12 Avg QP:24.07 size: 220 +[libx264 @ 0x5644b31f07c0] frame B:8 Avg QP:22.19 size: 124 +[libx264 @ 0x5644b31f07c0] consecutive B-frames: 33.3% 38.1% 28.6% 0.0% +[libx264 @ 0x5644b31f07c0] mb I I16..4: 56.0% 0.0% 44.0% +[libx264 @ 0x5644b31f07c0] mb P I16..4: 8.4% 1.6% 1.7% P16..4: 1.1% 0.0% 0.0% 0.0% 0.0% skip:87.3% +[libx264 @ 0x5644b31f07c0] mb B I16..4: 0.2% 0.5% 0.9% B16..8: 4.1% 0.0% 0.0% direct: 0.1% skip:94.3% L0:48.8% L1:51.2% BI: 0.0% +[libx264 @ 0x5644b31f07c0] 8x8 transform intra:9.0% inter:23.5% +[libx264 @ 0x5644b31f07c0] coded y,uvDC,uvAC intra: 45.6% 37.1% 36.1% inter: 0.2% 0.0% 0.0% +[libx264 @ 0x5644b31f07c0] i16 v,h,dc,p: 51% 13% 35% 1% +[libx264 @ 0x5644b31f07c0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 0% 0% 100% 0% 0% 0% 0% 0% 0% +[libx264 @ 0x5644b31f07c0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 33% 16% 40% 1% 4% 2% 2% 1% 0% +[libx264 @ 0x5644b31f07c0] i8c dc,h,v,p: 91% 5% 4% 0% +[libx264 @ 0x5644b31f07c0] Weighted P-Frames: Y:8.3% UV:8.3% +[libx264 @ 0x5644b31f07c0] ref P L0: 21.9% 0.0% 65.6% 12.5% +[libx264 @ 0x5644b31f07c0] ref B L0: 52.5% 47.5% +[libx264 @ 0x5644b31f07c0] kb/s:93.39 +``` +
+ + + + +## Load Gymnasium environment +```python +from rlberry.envs import gym_make +from gymnasium.wrappers.record_video import RecordVideo + +#If you want an output video of your env, you have to : +# - add a 'render_mode' parameter at your gym_make +# - add a 'RecordVideo' wrapper around the gymnasium environment. +env = gym_make("MountainCar-v0", render_mode="rgb_array") +env = RecordVideo(env,video_folder= "./", name_prefix="MountainCar") +# else, this line is enough: +# env = gym_make("MountainCar-v0") + +observation, info = env.reset() +for tt in range(50): + env.step(env.action_space.sample()) +env.close() +``` + +```none +[your path]/.conda/lib/python3.10/site-packages/gymnasium/wrappers/record_video.py:94: UserWarning: WARN: Overwriting existing videos at [your path] folder (try specifying a different `video_folder` for the `RecordVideo` wrapper if this is not desired) + logger.warn( +[your path]/.conda/lib/python3.10/site-packages/gymnasium/core.py:311: UserWarning: WARN: env.is_vector_env to get variables from other wrappers is deprecated and will be removed in v1.0, to get this variable you can do `env.unwrapped.is_vector_env` for environment variables or `env.get_wrapper_attr('is_vector_env')` that will search the reminding wrappers. + logger.warn( +Moviepy - Building video [your path]/MountainCar-episode-0.mp4. +Moviepy - Writing video [your path]/MountainCar-episode-0.mp4 + +Moviepy - Done ! +Moviepy - video ready [your path]/MountainCar-episode-0.mp4 +``` + +
+ + + + + +## Load Atari environment + +```python +from rlberry.envs import atari_make +from gymnasium.wrappers.record_video import RecordVideo + + +#If you want an output video of your env, you have to : +# - add a 'render_mode' parameter at your atari_make +# - add a 'RecordVideo' wrapper around the gymnasium environment. +env = atari_make("ALE/Breakout-v5", render_mode="rgb_array") +env = RecordVideo(env,video_folder= "./", name_prefix="Breakout") +# else, this line is enough: +# env = atari_make("ALE/Breakout-v5") + +observation, info = env.reset() +for tt in range(50): + observation, reward, terminated, truncated, info = env.step(env.action_space.sample()) + # if the environment is terminated or truncated (no more life), it need to be reset + if terminated or truncated: + observation, info = env.reset() +env.close() +``` + +```none +A.L.E: Arcade Learning Environment (version 0.8.1+53f58b7) +[Powered by Stella] +[your path]/.conda/lib/python3.10/site-packages/gymnasium/core.py:311: UserWarning: WARN: env.is_vector_env to get variables from other wrappers is deprecated and will be removed in v1.0, to get this variable you can do `env.unwrapped.is_vector_env` for environment variables or `env.get_wrapper_attr('is_vector_env')` that will search the reminding wrappers. + logger.warn( +[your path]/.conda/lib/python3.10/site-packages/gymnasium/utils/passive_env_checker.py:335: UserWarning: WARN: No render fps was declared in the environment (env.metadata['render_fps'] is None or not defined), rendering may occur at inconsistent fps. + logger.warn( +Moviepy - Building video [your path]/Breakout-episode-0.mp4. +Moviepy - Writing video [your path]/Breakout-episode-0.mp4 + +Moviepy - Done ! +Moviepy - video ready [your path]/Breakout-episode-0.mp4 +``` + +
+ + + + +## Create your own environment + **warning :** For advanced users only + +You need to create a new class that inherits from [gymnasium.Env](https://gymnasium.farama.org/api/env/) or one of it child class like [Model](rlberry.envs.interface.Model) (and RenderInterface/one of it child class, if you want an environment with rendering). + +Then you need to make the specific functions that respect gymnasium template (as step, reset, sample, ...). + +You can find examples in "sources" of [Acrobot](rlberry.envs.Acrobot), [MountainCar](rlberry.envs.classic_control.MountainCar) or [Chain](rlberry.envs.finite.Chain) (and their parent classes). From 1eb644398f47ba93e951ecf87da6dd4dd03883fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 14:03:08 +0000 Subject: [PATCH 20/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/environment/environment.md | 30 ++++++++++++++------------ docs/index.rst | 2 +- docs/user_guide2.md | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/basics/environment/environment.md b/docs/basics/environment/environment.md index 8fa0aaa56..936c8065c 100644 --- a/docs/basics/environment/environment.md +++ b/docs/basics/environment/environment.md @@ -12,17 +12,17 @@ from rlberry.envs.finite import Chain env = Chain(10, 0.1) env.enable_rendering() for tt in range(20): - #Force to go right every 4 steps to have a better video render. - if(tt%4==0): + # Force to go right every 4 steps to have a better video render. + if tt % 4 == 0: env.step(1) - else: + else: env.step(env.action_space.sample()) env.render(loop=False) video = env.save_video("_env_page_chain.mp4") env.close() ``` -```none +```none ffmpeg version 4.4.2-0ubuntu0.22.04.1 Copyright (c) 2000-2021 the FFmpeg developers built with gcc 11 (Ubuntu 11.2.0-19ubuntu1) configuration: --prefix=/usr --extra-version=0ubuntu0.22.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared @@ -50,7 +50,7 @@ Output #0, mp4, to '_env_page_chain.mp4': encoder : Lavc58.134.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A -frame= 21 fps=0.0 q=-1.0 Lsize= 11kB time=00:00:00.72 bitrate= 128.4kbits/s speed=29.6x +frame= 21 fps=0.0 q=-1.0 Lsize= 11kB time=00:00:00.72 bitrate= 128.4kbits/s speed=29.6x video:10kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 10.128633% [libx264 @ 0x5644b31f07c0] frame I:1 Avg QP:29.04 size: 6175 [libx264 @ 0x5644b31f07c0] frame P:12 Avg QP:24.07 size: 220 @@ -82,11 +82,11 @@ video:10kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ov from rlberry.envs import gym_make from gymnasium.wrappers.record_video import RecordVideo -#If you want an output video of your env, you have to : +# If you want an output video of your env, you have to : # - add a 'render_mode' parameter at your gym_make # - add a 'RecordVideo' wrapper around the gymnasium environment. env = gym_make("MountainCar-v0", render_mode="rgb_array") -env = RecordVideo(env,video_folder= "./", name_prefix="MountainCar") +env = RecordVideo(env, video_folder="./", name_prefix="MountainCar") # else, this line is enough: # env = gym_make("MountainCar-v0") @@ -96,7 +96,7 @@ for tt in range(50): env.close() ``` -```none +```none [your path]/.conda/lib/python3.10/site-packages/gymnasium/wrappers/record_video.py:94: UserWarning: WARN: Overwriting existing videos at [your path] folder (try specifying a different `video_folder` for the `RecordVideo` wrapper if this is not desired) logger.warn( [your path]/.conda/lib/python3.10/site-packages/gymnasium/core.py:311: UserWarning: WARN: env.is_vector_env to get variables from other wrappers is deprecated and will be removed in v1.0, to get this variable you can do `env.unwrapped.is_vector_env` for environment variables or `env.get_wrapper_attr('is_vector_env')` that will search the reminding wrappers. @@ -104,7 +104,7 @@ env.close() Moviepy - Building video [your path]/MountainCar-episode-0.mp4. Moviepy - Writing video [your path]/MountainCar-episode-0.mp4 -Moviepy - Done ! +Moviepy - Done ! Moviepy - video ready [your path]/MountainCar-episode-0.mp4 ``` @@ -123,24 +123,26 @@ from rlberry.envs import atari_make from gymnasium.wrappers.record_video import RecordVideo -#If you want an output video of your env, you have to : +# If you want an output video of your env, you have to : # - add a 'render_mode' parameter at your atari_make # - add a 'RecordVideo' wrapper around the gymnasium environment. env = atari_make("ALE/Breakout-v5", render_mode="rgb_array") -env = RecordVideo(env,video_folder= "./", name_prefix="Breakout") +env = RecordVideo(env, video_folder="./", name_prefix="Breakout") # else, this line is enough: # env = atari_make("ALE/Breakout-v5") observation, info = env.reset() for tt in range(50): - observation, reward, terminated, truncated, info = env.step(env.action_space.sample()) + observation, reward, terminated, truncated, info = env.step( + env.action_space.sample() + ) # if the environment is terminated or truncated (no more life), it need to be reset if terminated or truncated: observation, info = env.reset() env.close() ``` -```none +```none A.L.E: Arcade Learning Environment (version 0.8.1+53f58b7) [Powered by Stella] [your path]/.conda/lib/python3.10/site-packages/gymnasium/core.py:311: UserWarning: WARN: env.is_vector_env to get variables from other wrappers is deprecated and will be removed in v1.0, to get this variable you can do `env.unwrapped.is_vector_env` for environment variables or `env.get_wrapper_attr('is_vector_env')` that will search the reminding wrappers. @@ -150,7 +152,7 @@ A.L.E: Arcade Learning Environment (version 0.8.1+53f58b7) Moviepy - Building video [your path]/Breakout-episode-0.mp4. Moviepy - Writing video [your path]/Breakout-episode-0.mp4 -Moviepy - Done ! +Moviepy - Done ! Moviepy - video ready [your path]/Breakout-episode-0.mp4 ``` diff --git a/docs/index.rst b/docs/index.rst index 16e4d04c2..3ea87fcef 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -9,7 +9,7 @@ An RL Library for Research and Education ======================================== - + :ref:`new user guide` **Writing reinforcement learning algorithms is fun!** *But after the fun, we have diff --git a/docs/user_guide2.md b/docs/user_guide2.md index 36faf6777..e3d14ef09 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -11,7 +11,7 @@ In this user guide, we take you through the core features of rlberry and illustr ## Set up an experiment Some text about an experiment: a comparison of 2 rl agents on a given environment. ### Environment -This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). [(Wikipedia)](https://en.wikipedia.org/wiki/Reinforcement_learning) The environment is typically stated in the form of a Markov decision process (MDP). +This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). [(Wikipedia)](https://en.wikipedia.org/wiki/Reinforcement_learning) The environment is typically stated in the form of a Markov decision process (MDP). You can find the guide for environment [here](environment_page). Some text about MDPs. ### Agent From f52aa3da2a46fd7f9d1372c8a32789dfbb750b17 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 3 Oct 2023 16:54:01 +0200 Subject: [PATCH 21/80] updating comments --- docs/basics/environment/environment.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/docs/basics/environment/environment.md b/docs/basics/environment/environment.md index 936c8065c..efbcf452a 100644 --- a/docs/basics/environment/environment.md +++ b/docs/basics/environment/environment.md @@ -2,7 +2,7 @@ # How to use an environment -This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). With rlberry, you can load an existing environment, or create your own. +This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). With rlberry, you can load an existing environment, or create your own custom environment. ## Load rlberry environment @@ -18,6 +18,8 @@ for tt in range(20): else: env.step(env.action_space.sample()) env.render(loop=False) + +#env.save_video is only available for rlberry envs and custom env (with 'RenderInterface' as parent class) video = env.save_video("_env_page_chain.mp4") env.close() ``` @@ -78,11 +80,13 @@ video:10kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ov ## Load Gymnasium environment +Gymnasium can give you some classic environment. You can load theme with [gym_make](rlberry.envs.gym_make). More information [here](https://www.gymlibrary.dev/environments/classic_control/). + ```python from rlberry.envs import gym_make from gymnasium.wrappers.record_video import RecordVideo -# If you want an output video of your env, you have to : +# If you want an output video of your Gymnasium env, you have to : # - add a 'render_mode' parameter at your gym_make # - add a 'RecordVideo' wrapper around the gymnasium environment. env = gym_make("MountainCar-v0", render_mode="rgb_array") @@ -117,13 +121,16 @@ Moviepy - video ready [your path]/MountainCar-episode-0.mp4 ## Load Atari environment +A set of Atari 2600 environment simulated through Stella and the Arcade Learning Environment. More information [here](https://www.gymlibrary.dev/environments/atari/index.html#atari). + +[atari_make](rlberry.envs.atari_make) add wrappers on gym.make, to make it easier to use on Atari games. ```python from rlberry.envs import atari_make from gymnasium.wrappers.record_video import RecordVideo -# If you want an output video of your env, you have to : +# If you want an output video of your Atari env, you have to : # - add a 'render_mode' parameter at your atari_make # - add a 'RecordVideo' wrapper around the gymnasium environment. env = atari_make("ALE/Breakout-v5", render_mode="rgb_array") @@ -168,6 +175,6 @@ Moviepy - video ready [your path]/Breakout-episode-0.mp4 You need to create a new class that inherits from [gymnasium.Env](https://gymnasium.farama.org/api/env/) or one of it child class like [Model](rlberry.envs.interface.Model) (and RenderInterface/one of it child class, if you want an environment with rendering). -Then you need to make the specific functions that respect gymnasium template (as step, reset, sample, ...). +Then you need to make the specific functions that respect gymnasium template (as step, reset, ...). More information [here](https://www.gymlibrary.dev/content/environment_creation/) You can find examples in "sources" of [Acrobot](rlberry.envs.Acrobot), [MountainCar](rlberry.envs.classic_control.MountainCar) or [Chain](rlberry.envs.finite.Chain) (and their parent classes). From 4854537a8794de343610083b6f0fb286b7f862dc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 3 Oct 2023 14:54:21 +0000 Subject: [PATCH 22/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/environment/environment.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics/environment/environment.md b/docs/basics/environment/environment.md index efbcf452a..942b2cece 100644 --- a/docs/basics/environment/environment.md +++ b/docs/basics/environment/environment.md @@ -19,7 +19,7 @@ for tt in range(20): env.step(env.action_space.sample()) env.render(loop=False) -#env.save_video is only available for rlberry envs and custom env (with 'RenderInterface' as parent class) +# env.save_video is only available for rlberry envs and custom env (with 'RenderInterface' as parent class) video = env.save_video("_env_page_chain.mp4") env.close() ``` From c2c6914509748e3aeec20441897060b588d4b64d Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 3 Oct 2023 16:58:08 +0200 Subject: [PATCH 23/80] add basewrapper to the doc "Environments" --- docs/api.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api.rst b/docs/api.rst index 1969d1658..2c8bda9d5 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -101,6 +101,7 @@ Base class :template: class.rst envs.interface.Model + envs.basewrapper.Wrapper Spaces ------ From 069b98df79c4578aa7d848ef5e37a3e6c1a67cc9 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 3 Oct 2023 17:01:43 +0200 Subject: [PATCH 24/80] updating video breakout --- .../user_guide_video/_env_page_Breakout.mp4 | Bin 5420 -> 5982 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/_video/user_guide_video/_env_page_Breakout.mp4 b/docs/_video/user_guide_video/_env_page_Breakout.mp4 index ea2311c0bfeef1b3d1d18831a00e058334c3d51b..de95a44763f47c582ea8dffad44f69271e5d97a8 100644 GIT binary patch delta 4167 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 N1_RU~%C?}#{{ZH++<5>1 From 5f7f1a562788a68f476e20fd388c42067193ac4e Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 11 Oct 2023 09:28:55 +0200 Subject: [PATCH 25/80] add empty experimentManager page --- docs/basics/userguide/experimentManager.md | 1 + docs/user_guide2.md | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 docs/basics/userguide/experimentManager.md diff --git a/docs/basics/userguide/experimentManager.md b/docs/basics/userguide/experimentManager.md new file mode 100644 index 000000000..5e7f6a416 --- /dev/null +++ b/docs/basics/userguide/experimentManager.md @@ -0,0 +1 @@ +(experimentManager_page)= diff --git a/docs/user_guide2.md b/docs/user_guide2.md index e3d14ef09..7e55f196d 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -14,22 +14,22 @@ Some text about an experiment: a comparison of 2 rl agents on a given environmen This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). [(Wikipedia)](https://en.wikipedia.org/wiki/Reinforcement_learning) The environment is typically stated in the form of a Markov decision process (MDP). You can find the guide for environment [here](environment_page). Some text about MDPs. -### Agent +### Agent Some text about what an agent is. ### ExperimentManager -Some text about the goal of experiment. +Some text about the goal of experimentManager. [here](experimentManager_page). ### Logging ### Analyse the results ## Experimenting with Deep agents -### Torch Agents -### Policy and Value Networks -### Stable Baselines 3 -## Experimenting with Bandits. +### Torch Agents +### Policy and Value Networks +### Stable Baselines 3 +## Experimenting with Bandits. ## Reproducibility ### Seeding ### Saving and Loading Agents ### Saving and Loading Data -## Advanced Usage -### Custom Agents -### Custom Environments -### Transfer Learning +## Advanced Usage +### Custom Agents +### Custom Environments +### Transfer Learning From 922b11479fed549dfa987cdc1640e2386aaf5639 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 11 Oct 2023 09:31:39 +0200 Subject: [PATCH 26/80] change path for environment.md --- docs/basics/{environment => userguide}/environment.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/basics/{environment => userguide}/environment.md (100%) diff --git a/docs/basics/environment/environment.md b/docs/basics/userguide/environment.md similarity index 100% rename from docs/basics/environment/environment.md rename to docs/basics/userguide/environment.md From fadbdb660b98b6e0d2b3e991771bf0472820ff07 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 11 Oct 2023 07:32:32 +0000 Subject: [PATCH 27/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/user_guide2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_guide2.md b/docs/user_guide2.md index 7e55f196d..1bf9cf476 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -23,7 +23,7 @@ Some text about the goal of experimentManager. [here](experimentManager_page). ## Experimenting with Deep agents ### Torch Agents ### Policy and Value Networks -### Stable Baselines 3 +### Stable Baselines 3 ## Experimenting with Bandits. ## Reproducibility ### Seeding From ba559169e27ee6f9c85a0b5077078c791ee522a2 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 13 Oct 2023 10:53:49 +0200 Subject: [PATCH 28/80] Add experimentManager userguide page --- .../_experimentManager_page_CartPole.mp4 | Bin 0 -> 17019 bytes .../basics/userguide/expManager_multieval.png | Bin 0 -> 18049 bytes docs/basics/userguide/experimentManager.md | 261 ++++++++++++++++++ docs/user_guide2.md | 3 +- 4 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 docs/_video/user_guide_video/_experimentManager_page_CartPole.mp4 create mode 100644 docs/basics/userguide/expManager_multieval.png diff --git a/docs/_video/user_guide_video/_experimentManager_page_CartPole.mp4 b/docs/_video/user_guide_video/_experimentManager_page_CartPole.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..c9ae206f82222ba64741e16b816028d90b81d42b GIT binary patch literal 17019 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 Ugu*V{1vyE|2#LuGiHeB)e``ha9smFU literal 0 HcmV?d00001 diff --git a/docs/basics/userguide/expManager_multieval.png b/docs/basics/userguide/expManager_multieval.png new file mode 100644 index 0000000000000000000000000000000000000000..480e9aa5a2fc4903d892ecd954b0228e919165f8 GIT binary patch literal 18049 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 + + + +## Compare with other agent +Now you can compare this agent with another one. Here, we gonna compare it with the same agent, but with a bigger fit budget, and some fine tuning. + + + **warning :** add this code after the previous one. +```python +second_experiment = ExperimentManager( + PPOAgent, #Agent Class + (env_ctor, env_kwargs), #Environment as Tuple(constructor,kwargs) + fit_budget=int(10000), #Budget used to call our agent "fit()" + init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), #Arguments for the Agent’s constructor. + eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, #Number of agent instances to fit. + agent_name="PPO_second_experiment" + env_id, #Name of our agent (for saving/printing) + seed=42, +) + +second_experiment.fit() + +output = evaluate_agents([first_experiment,second_experiment], n_simulations=5, plot=True) #evaluate the 2 experiments on 5 simulations +print(output) +``` + +```none +[INFO] 14:39: Running ExperimentManager fit() for PPO_second_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 2496 | fit/policy_loss = -0.0443466454744339 | fit/value_loss = 33.09639358520508 | fit/entropy_loss = 0.6301112174987793 | fit/approx_kl = 0.0029671359807252884 | fit/clipfrac = 0.0 | fit/explained_variance = 0.4449042081832886 | fit/learning_rate = 0.0003 | +[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 5472 | fit/policy_loss = -0.020021788775920868 | fit/value_loss = 171.70037841796875 | fit/entropy_loss = 0.5415757298469543 | fit/approx_kl = 0.001022467389702797 | fit/clipfrac = 0.0 | fit/explained_variance = 0.1336498260498047 | fit/learning_rate = 0.0003 | +[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 8256 | fit/policy_loss = -0.016511857509613037 | fit/value_loss = 199.02989196777344 | fit/entropy_loss = 0.5490894317626953 | fit/approx_kl = 0.022175027057528496 | fit/clipfrac = 0.27083333395421505 | fit/explained_variance = 0.19932276010513306 | fit/learning_rate = 0.0003 | +[INFO] 14:39: ... trained! +[INFO] 14:39: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished +[INFO] 14:39: Evaluating PPO_second_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + + PPO_first_experimentCartPole-v1 PPO_second_experimentCartPole-v1 +0 20.6 200.6 +1 20.5 286.7 +2 18.9 238.6 +3 18.2 248.2 +4 17.7 271.9 +``` +As we can see in the output or in the following image, the second agent succeed better. + +![image](expManager_multieval.png){.align-center} + +
+ +## Output the video +If you want to see the output video of the trained Agent, you need to use the RecordVideo wrapper. As ExperimentManager use tuple for env parameter, you need to give the constructor with the wrapper. To do that, you can use [PipelineEnv](rlberry.envs.PipelineEnv) as constructor, and add the wrapper + the env information in its kwargs. + + **warning :** You have to do it on the eval environment, or you may have videos during the fit of your Agent. + +```python +env_id = "CartPole-v1" +env_ctor = gym_make #constructor for training env +env_kwargs = dict(id=env_id) #kwars for training env + +eval_env_ctor = PipelineEnv #constructor for eval env +eval_env_kwargs = { #kwars for eval env (with wrapper) + "env_ctor": gym_make, + "env_kwargs": {"id": env_id, "render_mode":"rgb_array"}, + "wrappers": [(RecordVideo,{"video_folder":"./","name_prefix":env_id})] #list of tuple (class,kwargs) +} + +third_experiment = ExperimentManager( + PPOAgent, #Agent Class + (env_ctor, env_kwargs), #Environment as Tuple(constructor,kwargs) + fit_budget=int(10000), #Budget used to call our agent "fit()" + eval_env = (eval_env_ctor, eval_env_kwargs), #Evaluation environment as tuple + init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), #settings for the Agent + eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, #Number of agent instances to fit. + agent_name="PPO_third_experiment" + env_id, #Name of the agent + seed=42, +) + +third_experiment.fit() + +output3 = evaluate_agents([third_experiment], n_simulations=15, plot=False) #evaluate the experiment on 5 simulations +print(output3) + +``` + + +```None +[INFO] 17:03: Running ExperimentManager fit() for PPO_third_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 1536 | fit/policy_loss = -0.0001924981625052169 | fit/value_loss = 34.07163619995117 | fit/entropy_loss = 0.6320618987083435 | fit/approx_kl = 0.00042163082980550826 | fit/clipfrac = 0.0 | fit/explained_variance = -0.05607199668884277 | fit/learning_rate = 0.0003 | +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 3744 | fit/policy_loss = -0.02924121916294098 | fit/value_loss = 0.8705029487609863 | fit/entropy_loss = 0.6485489010810852 | fit/approx_kl = 0.0006057650898583233 | fit/clipfrac = 0.0 | fit/explained_variance = 0.9505079835653305 | fit/learning_rate = 0.0003 | +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 5856 | fit/policy_loss = -0.008760576136410236 | fit/value_loss = 2.063389778137207 | fit/entropy_loss = 0.5526289343833923 | fit/approx_kl = 0.017247432842850685 | fit/clipfrac = 0.08645833283662796 | fit/explained_variance = 0.9867914840579033 | fit/learning_rate = 0.0003 | +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 8256 | fit/policy_loss = -0.016511857509613037 | fit/value_loss = 199.02989196777344 | fit/entropy_loss = 0.5490894317626953 | fit/approx_kl = 0.022175027057528496 | fit/clipfrac = 0.27083333395421505 | fit/explained_variance = 0.19932276010513306 | fit/learning_rate = 0.0003 | +[INFO] 09:45: Evaluating PPO_third_experimentCartPole-v1... +[INFO] Evaluation:Moviepy - Building video /CartPole-v1-episode-0.mp4. +Moviepy - Writing video CartPole-v1-episode-0.mp4 + +Moviepy - Done ! +Moviepy - video ready /CartPole-v1-episode-0.mp4 +.Moviepy - Building video /CartPole-v1-episode-1.mp4. +Moviepy - Writing video /CartPole-v1-episode-1.mp4 + +Moviepy - Done ! +Moviepy - video ready /CartPole-v1-episode-1.mp4 +.... Evaluation finished + + PPO_third_experimentCartPole-v1 +0 175.0 +1 189.0 +2 234.0 +3 146.0 +4 236.0 +``` + + + + + + +## Some advanced settings +Now an example with some more settings. (check the [API](rlberry.manager.ExperimentManager) to see all of them) + +```python +sfrom rlberry.envs import gym_make +from rlberry.agents.torch import PPOAgent +from rlberry.manager import ExperimentManager, evaluate_agents + + +env_id = "CartPole-v1" +env_ctor = gym_make +env_kwargs = dict(id=env_id) + +fourth_experiment = ExperimentManager( + PPOAgent, #Agent Class + train_env=(env_ctor, env_kwargs), #Environment to train the Agent + fit_budget=int(15000), #Budget used to call our agent "fit()" + eval_env=(env_ctor, env_kwargs), #Environment to eval the Agent (here, same as training env) + init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), #Agent setting + eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). + agent_name="PPO_second_experiment" + env_id, #Name of the agent + n_fit=4, #Number of agent instances to fit. + output_dir="./fourth_experiment_results/", #Directory where to store data. + parallelization="thread", #parallelize agent training using threads + max_workers=2, #max 2 threads with parallelization + enable_tensorboard=True, #enable tensorboard logging +) + +fourth_experiment.fit() + +output = evaluate_agents([fourth_experiment], n_simulations=5, plot=False) #evaluate the experiment on 5 simulations +print(output) + +``` + +```none +[INFO] 10:28: Running ExperimentManager fit() for PPO_second_experimentCartPole-v1 with n_fit = 4 and max_workers = 2. +[INFO] 10:28: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 1248 | fit/policy_loss = -0.0046189031563699245 | fit/value_loss = 17.90558624267578 | fit/entropy_loss = 0.6713765263557434 | fit/approx_kl = 0.008433022536337376 | fit/clipfrac = 0.00416666679084301 | fit/explained_variance = -0.027537941932678223 | fit/learning_rate = 0.0003 | +[INFO] 10:28: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 1344 | fit/policy_loss = -0.0015951147070154548 | fit/value_loss = 30.366439819335938 | fit/entropy_loss = 0.6787645816802979 | fit/approx_kl = 6.758669769624248e-05 | fit/clipfrac = 0.0 | fit/explained_variance = 0.03739374876022339 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 2784 | fit/policy_loss = 0.0009148915414698422 | fit/value_loss = 29.08318328857422 | fit/entropy_loss = 0.6197206974029541 | fit/approx_kl = 0.01178667601197958 | fit/clipfrac = 0.012499999906867742 | fit/explained_variance = 0.0344814658164978 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 2880 | fit/policy_loss = 0.001672893762588501 | fit/value_loss = 27.00239372253418 | fit/entropy_loss = 0.6320319771766663 | fit/approx_kl = 0.003481858177110553 | fit/clipfrac = 0.0 | fit/explained_variance = 0.15528488159179688 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 4224 | fit/policy_loss = -0.022785374894738197 | fit/value_loss = 91.76630401611328 | fit/entropy_loss = 0.5638656616210938 | fit/approx_kl = 0.0017503012204542756 | fit/clipfrac = 0.0 | fit/explained_variance = -0.7095993757247925 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 4320 | fit/policy_loss = 0.0013483166694641113 | fit/value_loss = 31.31000518798828 | fit/entropy_loss = 0.589007556438446 | fit/approx_kl = 0.015259895473718643 | fit/clipfrac = 0.11979166707023978 | fit/explained_variance = -0.045020341873168945 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 5856 | fit/policy_loss = 0.00605475390329957 | fit/value_loss = 44.3318977355957 | fit/entropy_loss = 0.625015377998352 | fit/approx_kl = 0.00823256652802229 | fit/clipfrac = 0.002083333395421505 | fit/explained_variance = 0.4239630103111267 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 5856 | fit/policy_loss = 0.0038757026195526123 | fit/value_loss = 68.52188873291016 | fit/entropy_loss = 0.5918349027633667 | fit/approx_kl = 0.003220468061044812 | fit/clipfrac = 0.006250000186264515 | fit/explained_variance = -0.18818902969360352 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 7488 | fit/policy_loss = -0.009495516307651997 | fit/value_loss = 101.06624603271484 | fit/entropy_loss = 0.5486583709716797 | fit/approx_kl = 0.003257486969232559 | fit/clipfrac = 0.0 | fit/explained_variance = 0.1193075180053711 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 7488 | fit/policy_loss = -0.008390605449676514 | fit/value_loss = 3.112384080886841 | fit/entropy_loss = 0.5489932894706726 | fit/approx_kl = 0.004215842578560114 | fit/clipfrac = 0.06250000121071934 | fit/explained_variance = 0.9862392572686076 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 9024 | fit/policy_loss = -0.037699855864048004 | fit/value_loss = 7.979381561279297 | fit/entropy_loss = 0.5623810887336731 | fit/approx_kl = 0.004208063241094351 | fit/clipfrac = 0.015625000465661287 | fit/explained_variance = 0.927260547876358 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 9024 | fit/policy_loss = -0.03145790100097656 | fit/value_loss = 136.57496643066406 | fit/entropy_loss = 0.6083818078041077 | fit/approx_kl = 0.00015769463789183646 | fit/clipfrac = 0.0 | fit/explained_variance = 0.020778536796569824 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 10560 | fit/policy_loss = -0.005346258636564016 | fit/value_loss = 45.43724060058594 | fit/entropy_loss = 0.5453484654426575 | fit/approx_kl = 0.0029732866678386927 | fit/clipfrac = 0.0010416666977107526 | fit/explained_variance = 0.5737246572971344 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 10656 | fit/policy_loss = -0.034032005816698074 | fit/value_loss = 8.352469444274902 | fit/entropy_loss = 0.5558638572692871 | fit/approx_kl = 0.00012727950525004417 | fit/clipfrac = 0.0 | fit/explained_variance = 0.9023054912686348 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 12192 | fit/policy_loss = -0.014423723332583904 | fit/value_loss = 4.224886417388916 | fit/entropy_loss = 0.5871571898460388 | fit/approx_kl = 0.00237840972840786 | fit/clipfrac = 0.00833333358168602 | fit/explained_variance = 0.9782726876437664 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 12192 | fit/policy_loss = 0.002156441332772374 | fit/value_loss = 0.6400878429412842 | fit/entropy_loss = 0.5812122821807861 | fit/approx_kl = 0.002348624635487795 | fit/clipfrac = 0.0031250000931322573 | fit/explained_variance = -7.9211273193359375 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 13728 | fit/policy_loss = -0.009624089114367962 | fit/value_loss = 0.2872621715068817 | fit/entropy_loss = 0.5476118922233582 | fit/approx_kl = 0.005943961441516876 | fit/clipfrac = 0.045833333022892477 | fit/explained_variance = -2.098886489868164 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 13824 | fit/policy_loss = -0.002612883923575282 | fit/value_loss = 142.26548767089844 | fit/entropy_loss = 0.5882496237754822 | fit/approx_kl = 0.001458114362321794 | fit/clipfrac = 0.0 | fit/explained_variance = 0.11501973867416382 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 1440 | fit/policy_loss = -0.0015770109603181481 | fit/value_loss = 19.095449447631836 | fit/entropy_loss = 0.6553768515586853 | fit/approx_kl = 0.0036005538422614336 | fit/clipfrac = 0.0 | fit/explained_variance = -0.02544558048248291 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 1440 | fit/policy_loss = 0.010459281504154205 | fit/value_loss = 24.7592716217041 | fit/entropy_loss = 0.6623566746711731 | fit/approx_kl = 0.003298681229352951 | fit/clipfrac = 0.0 | fit/explained_variance = -0.06966197490692139 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 2976 | fit/policy_loss = 0.016300952062010765 | fit/value_loss = 38.56718826293945 | fit/entropy_loss = 0.6324384212493896 | fit/approx_kl = 0.0001397288142470643 | fit/clipfrac = 0.0 | fit/explained_variance = 0.06470108032226562 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 3072 | fit/policy_loss = -0.04757208749651909 | fit/value_loss = 49.06455612182617 | fit/entropy_loss = 0.5877493023872375 | fit/approx_kl = 0.014825299382209778 | fit/clipfrac = 0.05000000027939677 | fit/explained_variance = 0.162692129611969 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 4608 | fit/policy_loss = 0.010635286569595337 | fit/value_loss = 63.65742874145508 | fit/entropy_loss = 0.54666668176651 | fit/approx_kl = 0.014807184226810932 | fit/clipfrac = 0.1291666661389172 | fit/explained_variance = 0.17509007453918457 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 4704 | fit/policy_loss = 0.007104901131242514 | fit/value_loss = 60.899166107177734 | fit/entropy_loss = 0.5803811550140381 | fit/approx_kl = 0.016342414543032646 | fit/clipfrac = 0.10000000083819031 | fit/explained_variance = 0.14491546154022217 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 6240 | fit/policy_loss = -0.017549103125929832 | fit/value_loss = 131.22430419921875 | fit/entropy_loss = 0.5248685479164124 | fit/approx_kl = 0.0007476735045202076 | fit/clipfrac = 0.0 | fit/explained_variance = 0.18155068159103394 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 6336 | fit/policy_loss = -0.009597748517990112 | fit/value_loss = 306.9555358886719 | fit/entropy_loss = 0.5775970220565796 | fit/approx_kl = 0.0005952063947916031 | fit/clipfrac = 0.0 | fit/explained_variance = -0.3066709041595459 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 7872 | fit/policy_loss = -0.0011599212884902954 | fit/value_loss = 0.3407192528247833 | fit/entropy_loss = 0.41181233525276184 | fit/approx_kl = 0.01260202657431364 | fit/clipfrac = 0.19791666492819787 | fit/explained_variance = 0.975825097411871 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 7968 | fit/policy_loss = -0.047126080840826035 | fit/value_loss = 30.541654586791992 | fit/entropy_loss = 0.5876209139823914 | fit/approx_kl = 0.0013518078485503793 | fit/clipfrac = 0.0 | fit/explained_variance = 0.7769163846969604 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 9504 | fit/policy_loss = -0.005419999361038208 | fit/value_loss = 2.6821603775024414 | fit/entropy_loss = 0.4786674976348877 | fit/approx_kl = 0.002310350304469466 | fit/clipfrac = 0.0 | fit/explained_variance = 0.5584505200386047 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 9600 | fit/policy_loss = -0.0188402459025383 | fit/value_loss = 175.68919372558594 | fit/entropy_loss = 0.5457869172096252 | fit/approx_kl = 0.0003522926417645067 | fit/clipfrac = 0.0 | fit/explained_variance = 0.37716150283813477 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 11136 | fit/policy_loss = 0.002097398042678833 | fit/value_loss = 0.04328225180506706 | fit/entropy_loss = 0.520216166973114 | fit/approx_kl = 2.282687091792468e-05 | fit/clipfrac = 0.002083333395421505 | fit/explained_variance = 0.9905285472050309 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 11232 | fit/policy_loss = -0.02607026696205139 | fit/value_loss = 0.9695928692817688 | fit/entropy_loss = 0.544611930847168 | fit/approx_kl = 0.0014795692404732108 | fit/clipfrac = 0.008333333488553762 | fit/explained_variance = 0.775581106543541 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 12768 | fit/policy_loss = -0.00431543355807662 | fit/value_loss = 0.1664377897977829 | fit/entropy_loss = 0.5166257619857788 | fit/approx_kl = 0.01913692243397236 | fit/clipfrac = 0.2750000006519258 | fit/explained_variance = 0.950390450656414 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 12864 | fit/policy_loss = -0.01600167714059353 | fit/value_loss = 1.0876649618148804 | fit/entropy_loss = 0.5791975259780884 | fit/approx_kl = 0.015078354626893997 | fit/clipfrac = 0.05416666679084301 | fit/explained_variance = 0.957294762134552 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 14208 | fit/policy_loss = -0.007962663657963276 | fit/value_loss = 0.4722827970981598 | fit/entropy_loss = 0.5429236888885498 | fit/approx_kl = 0.011440296657383442 | fit/clipfrac = 0.029166666604578496 | fit/explained_variance = -2.395857334136963 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 14304 | fit/policy_loss = -0.00023897241044323891 | fit/value_loss = 0.37554287910461426 | fit/entropy_loss = 0.5310923457145691 | fit/approx_kl = 0.0071893795393407345 | fit/clipfrac = 0.18125000046566128 | fit/explained_variance = -2.975414991378784 | fit/learning_rate = 0.0003 | +[INFO] 10:29: ... trained! +[INFO] 10:29: Evaluating PPO_second_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + + PPO_second_experimentCartPole-v1 +0 164.0 +1 142.0 +2 180.0 +3 500.0 +4 500.0 +``` + +
+ +- In the output you can see the learning of the workers 0 and 1 first, then 2 and 3 (4 fit, but max 2 threads with parallelization). +- You can check the tensorboard logging with `tensorboard --logdir `. \ No newline at end of file diff --git a/docs/user_guide2.md b/docs/user_guide2.md index 1bf9cf476..ce5d1337c 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -17,7 +17,8 @@ Some text about MDPs. ### Agent Some text about what an agent is. ### ExperimentManager -Some text about the goal of experimentManager. [here](experimentManager_page). +This is one of the core element in rlberry. The ExperimentManager allow you to easily make an experiment between an Agent and an Environment. It's use to train, optimize hyperparameters, evaluate and gather statistics about an agent. +You can find the guide for ExperimentManager [here](experimentManager_page). ### Logging ### Analyse the results ## Experimenting with Deep agents From fc0e90a9006e36d798042bf36202431c621ab0f1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 08:55:54 +0000 Subject: [PATCH 29/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/userguide/experimentManager.md | 142 ++++++++++----------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/docs/basics/userguide/experimentManager.md b/docs/basics/userguide/experimentManager.md index e19c903a7..c9c4d80e3 100644 --- a/docs/basics/userguide/experimentManager.md +++ b/docs/basics/userguide/experimentManager.md @@ -27,20 +27,20 @@ first_experiment = ExperimentManager( eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). n_fit=1, #Number of agent instances to fit. agent_name="PPO_first_experiment" + env_id, #Name of the agent - seed=42, + seed=42, ) -first_experiment.fit() +first_experiment.fit() output = evaluate_agents([first_experiment], n_simulations=5, plot=False) #evaluate the experiment on 5 simulations print(output) ``` ```none -[INFO] 14:26: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. -[INFO] 14:26: ... trained! -[INFO] 14:26: Evaluating PPO_first_experimentCartPole-v1... -[INFO] Evaluation:..... Evaluation finished +[INFO] 14:26: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:26: ... trained! +[INFO] 14:26: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished PPO_first_experimentCartPole-v1 0 15.0 @@ -67,25 +67,25 @@ second_experiment = ExperimentManager( eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). n_fit=1, #Number of agent instances to fit. agent_name="PPO_second_experiment" + env_id, #Name of our agent (for saving/printing) - seed=42, + seed=42, ) -second_experiment.fit() +second_experiment.fit() output = evaluate_agents([first_experiment,second_experiment], n_simulations=5, plot=True) #evaluate the 2 experiments on 5 simulations print(output) ``` ```none -[INFO] 14:39: Running ExperimentManager fit() for PPO_second_experimentCartPole-v1 with n_fit = 1 and max_workers = None. -[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 2496 | fit/policy_loss = -0.0443466454744339 | fit/value_loss = 33.09639358520508 | fit/entropy_loss = 0.6301112174987793 | fit/approx_kl = 0.0029671359807252884 | fit/clipfrac = 0.0 | fit/explained_variance = 0.4449042081832886 | fit/learning_rate = 0.0003 | -[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 5472 | fit/policy_loss = -0.020021788775920868 | fit/value_loss = 171.70037841796875 | fit/entropy_loss = 0.5415757298469543 | fit/approx_kl = 0.001022467389702797 | fit/clipfrac = 0.0 | fit/explained_variance = 0.1336498260498047 | fit/learning_rate = 0.0003 | -[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 8256 | fit/policy_loss = -0.016511857509613037 | fit/value_loss = 199.02989196777344 | fit/entropy_loss = 0.5490894317626953 | fit/approx_kl = 0.022175027057528496 | fit/clipfrac = 0.27083333395421505 | fit/explained_variance = 0.19932276010513306 | fit/learning_rate = 0.0003 | -[INFO] 14:39: ... trained! -[INFO] 14:39: Evaluating PPO_first_experimentCartPole-v1... -[INFO] Evaluation:..... Evaluation finished -[INFO] 14:39: Evaluating PPO_second_experimentCartPole-v1... -[INFO] Evaluation:..... Evaluation finished +[INFO] 14:39: Running ExperimentManager fit() for PPO_second_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 2496 | fit/policy_loss = -0.0443466454744339 | fit/value_loss = 33.09639358520508 | fit/entropy_loss = 0.6301112174987793 | fit/approx_kl = 0.0029671359807252884 | fit/clipfrac = 0.0 | fit/explained_variance = 0.4449042081832886 | fit/learning_rate = 0.0003 | +[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 5472 | fit/policy_loss = -0.020021788775920868 | fit/value_loss = 171.70037841796875 | fit/entropy_loss = 0.5415757298469543 | fit/approx_kl = 0.001022467389702797 | fit/clipfrac = 0.0 | fit/explained_variance = 0.1336498260498047 | fit/learning_rate = 0.0003 | +[INFO] 14:39: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 8256 | fit/policy_loss = -0.016511857509613037 | fit/value_loss = 199.02989196777344 | fit/entropy_loss = 0.5490894317626953 | fit/approx_kl = 0.022175027057528496 | fit/clipfrac = 0.27083333395421505 | fit/explained_variance = 0.19932276010513306 | fit/learning_rate = 0.0003 | +[INFO] 14:39: ... trained! +[INFO] 14:39: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished +[INFO] 14:39: Evaluating PPO_second_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished PPO_first_experimentCartPole-v1 PPO_second_experimentCartPole-v1 0 20.6 200.6 @@ -101,7 +101,7 @@ As we can see in the output or in the following image, the second agent succeed
## Output the video -If you want to see the output video of the trained Agent, you need to use the RecordVideo wrapper. As ExperimentManager use tuple for env parameter, you need to give the constructor with the wrapper. To do that, you can use [PipelineEnv](rlberry.envs.PipelineEnv) as constructor, and add the wrapper + the env information in its kwargs. +If you want to see the output video of the trained Agent, you need to use the RecordVideo wrapper. As ExperimentManager use tuple for env parameter, you need to give the constructor with the wrapper. To do that, you can use [PipelineEnv](rlberry.envs.PipelineEnv) as constructor, and add the wrapper + the env information in its kwargs. **warning :** You have to do it on the eval environment, or you may have videos during the fit of your Agent. @@ -126,10 +126,10 @@ third_experiment = ExperimentManager( eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). n_fit=1, #Number of agent instances to fit. agent_name="PPO_third_experiment" + env_id, #Name of the agent - seed=42, + seed=42, ) -third_experiment.fit() +third_experiment.fit() output3 = evaluate_agents([third_experiment], n_simulations=15, plot=False) #evaluate the experiment on 5 simulations print(output3) @@ -138,23 +138,23 @@ print(output3) ```None -[INFO] 17:03: Running ExperimentManager fit() for PPO_third_experimentCartPole-v1 with n_fit = 1 and max_workers = None. -[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 1536 | fit/policy_loss = -0.0001924981625052169 | fit/value_loss = 34.07163619995117 | fit/entropy_loss = 0.6320618987083435 | fit/approx_kl = 0.00042163082980550826 | fit/clipfrac = 0.0 | fit/explained_variance = -0.05607199668884277 | fit/learning_rate = 0.0003 | -[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 3744 | fit/policy_loss = -0.02924121916294098 | fit/value_loss = 0.8705029487609863 | fit/entropy_loss = 0.6485489010810852 | fit/approx_kl = 0.0006057650898583233 | fit/clipfrac = 0.0 | fit/explained_variance = 0.9505079835653305 | fit/learning_rate = 0.0003 | -[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 5856 | fit/policy_loss = -0.008760576136410236 | fit/value_loss = 2.063389778137207 | fit/entropy_loss = 0.5526289343833923 | fit/approx_kl = 0.017247432842850685 | fit/clipfrac = 0.08645833283662796 | fit/explained_variance = 0.9867914840579033 | fit/learning_rate = 0.0003 | -[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 8256 | fit/policy_loss = -0.016511857509613037 | fit/value_loss = 199.02989196777344 | fit/entropy_loss = 0.5490894317626953 | fit/approx_kl = 0.022175027057528496 | fit/clipfrac = 0.27083333395421505 | fit/explained_variance = 0.19932276010513306 | fit/learning_rate = 0.0003 | -[INFO] 09:45: Evaluating PPO_third_experimentCartPole-v1... +[INFO] 17:03: Running ExperimentManager fit() for PPO_third_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 1536 | fit/policy_loss = -0.0001924981625052169 | fit/value_loss = 34.07163619995117 | fit/entropy_loss = 0.6320618987083435 | fit/approx_kl = 0.00042163082980550826 | fit/clipfrac = 0.0 | fit/explained_variance = -0.05607199668884277 | fit/learning_rate = 0.0003 | +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 3744 | fit/policy_loss = -0.02924121916294098 | fit/value_loss = 0.8705029487609863 | fit/entropy_loss = 0.6485489010810852 | fit/approx_kl = 0.0006057650898583233 | fit/clipfrac = 0.0 | fit/explained_variance = 0.9505079835653305 | fit/learning_rate = 0.0003 | +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 5856 | fit/policy_loss = -0.008760576136410236 | fit/value_loss = 2.063389778137207 | fit/entropy_loss = 0.5526289343833923 | fit/approx_kl = 0.017247432842850685 | fit/clipfrac = 0.08645833283662796 | fit/explained_variance = 0.9867914840579033 | fit/learning_rate = 0.0003 | +[INFO] 17:03: [PPO_third_experimentCartPole-v1[worker: 0]] | max_global_step = 8256 | fit/policy_loss = -0.016511857509613037 | fit/value_loss = 199.02989196777344 | fit/entropy_loss = 0.5490894317626953 | fit/approx_kl = 0.022175027057528496 | fit/clipfrac = 0.27083333395421505 | fit/explained_variance = 0.19932276010513306 | fit/learning_rate = 0.0003 | +[INFO] 09:45: Evaluating PPO_third_experimentCartPole-v1... [INFO] Evaluation:Moviepy - Building video /CartPole-v1-episode-0.mp4. Moviepy - Writing video CartPole-v1-episode-0.mp4 -Moviepy - Done ! +Moviepy - Done ! Moviepy - video ready /CartPole-v1-episode-0.mp4 .Moviepy - Building video /CartPole-v1-episode-1.mp4. Moviepy - Writing video /CartPole-v1-episode-1.mp4 -Moviepy - Done ! +Moviepy - Done ! Moviepy - video ready /CartPole-v1-episode-1.mp4 -.... Evaluation finished +.... Evaluation finished PPO_third_experimentCartPole-v1 0 175.0 @@ -199,7 +199,7 @@ fourth_experiment = ExperimentManager( enable_tensorboard=True, #enable tensorboard logging ) -fourth_experiment.fit() +fourth_experiment.fit() output = evaluate_agents([fourth_experiment], n_simulations=5, plot=False) #evaluate the experiment on 5 simulations print(output) @@ -207,46 +207,46 @@ print(output) ``` ```none -[INFO] 10:28: Running ExperimentManager fit() for PPO_second_experimentCartPole-v1 with n_fit = 4 and max_workers = 2. -[INFO] 10:28: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 1248 | fit/policy_loss = -0.0046189031563699245 | fit/value_loss = 17.90558624267578 | fit/entropy_loss = 0.6713765263557434 | fit/approx_kl = 0.008433022536337376 | fit/clipfrac = 0.00416666679084301 | fit/explained_variance = -0.027537941932678223 | fit/learning_rate = 0.0003 | -[INFO] 10:28: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 1344 | fit/policy_loss = -0.0015951147070154548 | fit/value_loss = 30.366439819335938 | fit/entropy_loss = 0.6787645816802979 | fit/approx_kl = 6.758669769624248e-05 | fit/clipfrac = 0.0 | fit/explained_variance = 0.03739374876022339 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 2784 | fit/policy_loss = 0.0009148915414698422 | fit/value_loss = 29.08318328857422 | fit/entropy_loss = 0.6197206974029541 | fit/approx_kl = 0.01178667601197958 | fit/clipfrac = 0.012499999906867742 | fit/explained_variance = 0.0344814658164978 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 2880 | fit/policy_loss = 0.001672893762588501 | fit/value_loss = 27.00239372253418 | fit/entropy_loss = 0.6320319771766663 | fit/approx_kl = 0.003481858177110553 | fit/clipfrac = 0.0 | fit/explained_variance = 0.15528488159179688 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 4224 | fit/policy_loss = -0.022785374894738197 | fit/value_loss = 91.76630401611328 | fit/entropy_loss = 0.5638656616210938 | fit/approx_kl = 0.0017503012204542756 | fit/clipfrac = 0.0 | fit/explained_variance = -0.7095993757247925 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 4320 | fit/policy_loss = 0.0013483166694641113 | fit/value_loss = 31.31000518798828 | fit/entropy_loss = 0.589007556438446 | fit/approx_kl = 0.015259895473718643 | fit/clipfrac = 0.11979166707023978 | fit/explained_variance = -0.045020341873168945 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 5856 | fit/policy_loss = 0.00605475390329957 | fit/value_loss = 44.3318977355957 | fit/entropy_loss = 0.625015377998352 | fit/approx_kl = 0.00823256652802229 | fit/clipfrac = 0.002083333395421505 | fit/explained_variance = 0.4239630103111267 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 5856 | fit/policy_loss = 0.0038757026195526123 | fit/value_loss = 68.52188873291016 | fit/entropy_loss = 0.5918349027633667 | fit/approx_kl = 0.003220468061044812 | fit/clipfrac = 0.006250000186264515 | fit/explained_variance = -0.18818902969360352 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 7488 | fit/policy_loss = -0.009495516307651997 | fit/value_loss = 101.06624603271484 | fit/entropy_loss = 0.5486583709716797 | fit/approx_kl = 0.003257486969232559 | fit/clipfrac = 0.0 | fit/explained_variance = 0.1193075180053711 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 7488 | fit/policy_loss = -0.008390605449676514 | fit/value_loss = 3.112384080886841 | fit/entropy_loss = 0.5489932894706726 | fit/approx_kl = 0.004215842578560114 | fit/clipfrac = 0.06250000121071934 | fit/explained_variance = 0.9862392572686076 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 9024 | fit/policy_loss = -0.037699855864048004 | fit/value_loss = 7.979381561279297 | fit/entropy_loss = 0.5623810887336731 | fit/approx_kl = 0.004208063241094351 | fit/clipfrac = 0.015625000465661287 | fit/explained_variance = 0.927260547876358 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 9024 | fit/policy_loss = -0.03145790100097656 | fit/value_loss = 136.57496643066406 | fit/entropy_loss = 0.6083818078041077 | fit/approx_kl = 0.00015769463789183646 | fit/clipfrac = 0.0 | fit/explained_variance = 0.020778536796569824 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 10560 | fit/policy_loss = -0.005346258636564016 | fit/value_loss = 45.43724060058594 | fit/entropy_loss = 0.5453484654426575 | fit/approx_kl = 0.0029732866678386927 | fit/clipfrac = 0.0010416666977107526 | fit/explained_variance = 0.5737246572971344 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 10656 | fit/policy_loss = -0.034032005816698074 | fit/value_loss = 8.352469444274902 | fit/entropy_loss = 0.5558638572692871 | fit/approx_kl = 0.00012727950525004417 | fit/clipfrac = 0.0 | fit/explained_variance = 0.9023054912686348 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 12192 | fit/policy_loss = -0.014423723332583904 | fit/value_loss = 4.224886417388916 | fit/entropy_loss = 0.5871571898460388 | fit/approx_kl = 0.00237840972840786 | fit/clipfrac = 0.00833333358168602 | fit/explained_variance = 0.9782726876437664 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 12192 | fit/policy_loss = 0.002156441332772374 | fit/value_loss = 0.6400878429412842 | fit/entropy_loss = 0.5812122821807861 | fit/approx_kl = 0.002348624635487795 | fit/clipfrac = 0.0031250000931322573 | fit/explained_variance = -7.9211273193359375 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 13728 | fit/policy_loss = -0.009624089114367962 | fit/value_loss = 0.2872621715068817 | fit/entropy_loss = 0.5476118922233582 | fit/approx_kl = 0.005943961441516876 | fit/clipfrac = 0.045833333022892477 | fit/explained_variance = -2.098886489868164 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 13824 | fit/policy_loss = -0.002612883923575282 | fit/value_loss = 142.26548767089844 | fit/entropy_loss = 0.5882496237754822 | fit/approx_kl = 0.001458114362321794 | fit/clipfrac = 0.0 | fit/explained_variance = 0.11501973867416382 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 1440 | fit/policy_loss = -0.0015770109603181481 | fit/value_loss = 19.095449447631836 | fit/entropy_loss = 0.6553768515586853 | fit/approx_kl = 0.0036005538422614336 | fit/clipfrac = 0.0 | fit/explained_variance = -0.02544558048248291 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 1440 | fit/policy_loss = 0.010459281504154205 | fit/value_loss = 24.7592716217041 | fit/entropy_loss = 0.6623566746711731 | fit/approx_kl = 0.003298681229352951 | fit/clipfrac = 0.0 | fit/explained_variance = -0.06966197490692139 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 2976 | fit/policy_loss = 0.016300952062010765 | fit/value_loss = 38.56718826293945 | fit/entropy_loss = 0.6324384212493896 | fit/approx_kl = 0.0001397288142470643 | fit/clipfrac = 0.0 | fit/explained_variance = 0.06470108032226562 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 3072 | fit/policy_loss = -0.04757208749651909 | fit/value_loss = 49.06455612182617 | fit/entropy_loss = 0.5877493023872375 | fit/approx_kl = 0.014825299382209778 | fit/clipfrac = 0.05000000027939677 | fit/explained_variance = 0.162692129611969 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 4608 | fit/policy_loss = 0.010635286569595337 | fit/value_loss = 63.65742874145508 | fit/entropy_loss = 0.54666668176651 | fit/approx_kl = 0.014807184226810932 | fit/clipfrac = 0.1291666661389172 | fit/explained_variance = 0.17509007453918457 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 4704 | fit/policy_loss = 0.007104901131242514 | fit/value_loss = 60.899166107177734 | fit/entropy_loss = 0.5803811550140381 | fit/approx_kl = 0.016342414543032646 | fit/clipfrac = 0.10000000083819031 | fit/explained_variance = 0.14491546154022217 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 6240 | fit/policy_loss = -0.017549103125929832 | fit/value_loss = 131.22430419921875 | fit/entropy_loss = 0.5248685479164124 | fit/approx_kl = 0.0007476735045202076 | fit/clipfrac = 0.0 | fit/explained_variance = 0.18155068159103394 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 6336 | fit/policy_loss = -0.009597748517990112 | fit/value_loss = 306.9555358886719 | fit/entropy_loss = 0.5775970220565796 | fit/approx_kl = 0.0005952063947916031 | fit/clipfrac = 0.0 | fit/explained_variance = -0.3066709041595459 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 7872 | fit/policy_loss = -0.0011599212884902954 | fit/value_loss = 0.3407192528247833 | fit/entropy_loss = 0.41181233525276184 | fit/approx_kl = 0.01260202657431364 | fit/clipfrac = 0.19791666492819787 | fit/explained_variance = 0.975825097411871 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 7968 | fit/policy_loss = -0.047126080840826035 | fit/value_loss = 30.541654586791992 | fit/entropy_loss = 0.5876209139823914 | fit/approx_kl = 0.0013518078485503793 | fit/clipfrac = 0.0 | fit/explained_variance = 0.7769163846969604 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 9504 | fit/policy_loss = -0.005419999361038208 | fit/value_loss = 2.6821603775024414 | fit/entropy_loss = 0.4786674976348877 | fit/approx_kl = 0.002310350304469466 | fit/clipfrac = 0.0 | fit/explained_variance = 0.5584505200386047 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 9600 | fit/policy_loss = -0.0188402459025383 | fit/value_loss = 175.68919372558594 | fit/entropy_loss = 0.5457869172096252 | fit/approx_kl = 0.0003522926417645067 | fit/clipfrac = 0.0 | fit/explained_variance = 0.37716150283813477 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 11136 | fit/policy_loss = 0.002097398042678833 | fit/value_loss = 0.04328225180506706 | fit/entropy_loss = 0.520216166973114 | fit/approx_kl = 2.282687091792468e-05 | fit/clipfrac = 0.002083333395421505 | fit/explained_variance = 0.9905285472050309 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 11232 | fit/policy_loss = -0.02607026696205139 | fit/value_loss = 0.9695928692817688 | fit/entropy_loss = 0.544611930847168 | fit/approx_kl = 0.0014795692404732108 | fit/clipfrac = 0.008333333488553762 | fit/explained_variance = 0.775581106543541 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 12768 | fit/policy_loss = -0.00431543355807662 | fit/value_loss = 0.1664377897977829 | fit/entropy_loss = 0.5166257619857788 | fit/approx_kl = 0.01913692243397236 | fit/clipfrac = 0.2750000006519258 | fit/explained_variance = 0.950390450656414 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 12864 | fit/policy_loss = -0.01600167714059353 | fit/value_loss = 1.0876649618148804 | fit/entropy_loss = 0.5791975259780884 | fit/approx_kl = 0.015078354626893997 | fit/clipfrac = 0.05416666679084301 | fit/explained_variance = 0.957294762134552 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 14208 | fit/policy_loss = -0.007962663657963276 | fit/value_loss = 0.4722827970981598 | fit/entropy_loss = 0.5429236888885498 | fit/approx_kl = 0.011440296657383442 | fit/clipfrac = 0.029166666604578496 | fit/explained_variance = -2.395857334136963 | fit/learning_rate = 0.0003 | -[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 14304 | fit/policy_loss = -0.00023897241044323891 | fit/value_loss = 0.37554287910461426 | fit/entropy_loss = 0.5310923457145691 | fit/approx_kl = 0.0071893795393407345 | fit/clipfrac = 0.18125000046566128 | fit/explained_variance = -2.975414991378784 | fit/learning_rate = 0.0003 | -[INFO] 10:29: ... trained! -[INFO] 10:29: Evaluating PPO_second_experimentCartPole-v1... -[INFO] Evaluation:..... Evaluation finished +[INFO] 10:28: Running ExperimentManager fit() for PPO_second_experimentCartPole-v1 with n_fit = 4 and max_workers = 2. +[INFO] 10:28: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 1248 | fit/policy_loss = -0.0046189031563699245 | fit/value_loss = 17.90558624267578 | fit/entropy_loss = 0.6713765263557434 | fit/approx_kl = 0.008433022536337376 | fit/clipfrac = 0.00416666679084301 | fit/explained_variance = -0.027537941932678223 | fit/learning_rate = 0.0003 | +[INFO] 10:28: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 1344 | fit/policy_loss = -0.0015951147070154548 | fit/value_loss = 30.366439819335938 | fit/entropy_loss = 0.6787645816802979 | fit/approx_kl = 6.758669769624248e-05 | fit/clipfrac = 0.0 | fit/explained_variance = 0.03739374876022339 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 2784 | fit/policy_loss = 0.0009148915414698422 | fit/value_loss = 29.08318328857422 | fit/entropy_loss = 0.6197206974029541 | fit/approx_kl = 0.01178667601197958 | fit/clipfrac = 0.012499999906867742 | fit/explained_variance = 0.0344814658164978 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 2880 | fit/policy_loss = 0.001672893762588501 | fit/value_loss = 27.00239372253418 | fit/entropy_loss = 0.6320319771766663 | fit/approx_kl = 0.003481858177110553 | fit/clipfrac = 0.0 | fit/explained_variance = 0.15528488159179688 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 4224 | fit/policy_loss = -0.022785374894738197 | fit/value_loss = 91.76630401611328 | fit/entropy_loss = 0.5638656616210938 | fit/approx_kl = 0.0017503012204542756 | fit/clipfrac = 0.0 | fit/explained_variance = -0.7095993757247925 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 4320 | fit/policy_loss = 0.0013483166694641113 | fit/value_loss = 31.31000518798828 | fit/entropy_loss = 0.589007556438446 | fit/approx_kl = 0.015259895473718643 | fit/clipfrac = 0.11979166707023978 | fit/explained_variance = -0.045020341873168945 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 5856 | fit/policy_loss = 0.00605475390329957 | fit/value_loss = 44.3318977355957 | fit/entropy_loss = 0.625015377998352 | fit/approx_kl = 0.00823256652802229 | fit/clipfrac = 0.002083333395421505 | fit/explained_variance = 0.4239630103111267 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 5856 | fit/policy_loss = 0.0038757026195526123 | fit/value_loss = 68.52188873291016 | fit/entropy_loss = 0.5918349027633667 | fit/approx_kl = 0.003220468061044812 | fit/clipfrac = 0.006250000186264515 | fit/explained_variance = -0.18818902969360352 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 7488 | fit/policy_loss = -0.009495516307651997 | fit/value_loss = 101.06624603271484 | fit/entropy_loss = 0.5486583709716797 | fit/approx_kl = 0.003257486969232559 | fit/clipfrac = 0.0 | fit/explained_variance = 0.1193075180053711 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 7488 | fit/policy_loss = -0.008390605449676514 | fit/value_loss = 3.112384080886841 | fit/entropy_loss = 0.5489932894706726 | fit/approx_kl = 0.004215842578560114 | fit/clipfrac = 0.06250000121071934 | fit/explained_variance = 0.9862392572686076 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 9024 | fit/policy_loss = -0.037699855864048004 | fit/value_loss = 7.979381561279297 | fit/entropy_loss = 0.5623810887336731 | fit/approx_kl = 0.004208063241094351 | fit/clipfrac = 0.015625000465661287 | fit/explained_variance = 0.927260547876358 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 9024 | fit/policy_loss = -0.03145790100097656 | fit/value_loss = 136.57496643066406 | fit/entropy_loss = 0.6083818078041077 | fit/approx_kl = 0.00015769463789183646 | fit/clipfrac = 0.0 | fit/explained_variance = 0.020778536796569824 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 10560 | fit/policy_loss = -0.005346258636564016 | fit/value_loss = 45.43724060058594 | fit/entropy_loss = 0.5453484654426575 | fit/approx_kl = 0.0029732866678386927 | fit/clipfrac = 0.0010416666977107526 | fit/explained_variance = 0.5737246572971344 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 10656 | fit/policy_loss = -0.034032005816698074 | fit/value_loss = 8.352469444274902 | fit/entropy_loss = 0.5558638572692871 | fit/approx_kl = 0.00012727950525004417 | fit/clipfrac = 0.0 | fit/explained_variance = 0.9023054912686348 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 12192 | fit/policy_loss = -0.014423723332583904 | fit/value_loss = 4.224886417388916 | fit/entropy_loss = 0.5871571898460388 | fit/approx_kl = 0.00237840972840786 | fit/clipfrac = 0.00833333358168602 | fit/explained_variance = 0.9782726876437664 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 12192 | fit/policy_loss = 0.002156441332772374 | fit/value_loss = 0.6400878429412842 | fit/entropy_loss = 0.5812122821807861 | fit/approx_kl = 0.002348624635487795 | fit/clipfrac = 0.0031250000931322573 | fit/explained_variance = -7.9211273193359375 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 0]] | max_global_step = 13728 | fit/policy_loss = -0.009624089114367962 | fit/value_loss = 0.2872621715068817 | fit/entropy_loss = 0.5476118922233582 | fit/approx_kl = 0.005943961441516876 | fit/clipfrac = 0.045833333022892477 | fit/explained_variance = -2.098886489868164 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 1]] | max_global_step = 13824 | fit/policy_loss = -0.002612883923575282 | fit/value_loss = 142.26548767089844 | fit/entropy_loss = 0.5882496237754822 | fit/approx_kl = 0.001458114362321794 | fit/clipfrac = 0.0 | fit/explained_variance = 0.11501973867416382 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 1440 | fit/policy_loss = -0.0015770109603181481 | fit/value_loss = 19.095449447631836 | fit/entropy_loss = 0.6553768515586853 | fit/approx_kl = 0.0036005538422614336 | fit/clipfrac = 0.0 | fit/explained_variance = -0.02544558048248291 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 1440 | fit/policy_loss = 0.010459281504154205 | fit/value_loss = 24.7592716217041 | fit/entropy_loss = 0.6623566746711731 | fit/approx_kl = 0.003298681229352951 | fit/clipfrac = 0.0 | fit/explained_variance = -0.06966197490692139 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 2976 | fit/policy_loss = 0.016300952062010765 | fit/value_loss = 38.56718826293945 | fit/entropy_loss = 0.6324384212493896 | fit/approx_kl = 0.0001397288142470643 | fit/clipfrac = 0.0 | fit/explained_variance = 0.06470108032226562 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 3072 | fit/policy_loss = -0.04757208749651909 | fit/value_loss = 49.06455612182617 | fit/entropy_loss = 0.5877493023872375 | fit/approx_kl = 0.014825299382209778 | fit/clipfrac = 0.05000000027939677 | fit/explained_variance = 0.162692129611969 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 4608 | fit/policy_loss = 0.010635286569595337 | fit/value_loss = 63.65742874145508 | fit/entropy_loss = 0.54666668176651 | fit/approx_kl = 0.014807184226810932 | fit/clipfrac = 0.1291666661389172 | fit/explained_variance = 0.17509007453918457 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 4704 | fit/policy_loss = 0.007104901131242514 | fit/value_loss = 60.899166107177734 | fit/entropy_loss = 0.5803811550140381 | fit/approx_kl = 0.016342414543032646 | fit/clipfrac = 0.10000000083819031 | fit/explained_variance = 0.14491546154022217 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 6240 | fit/policy_loss = -0.017549103125929832 | fit/value_loss = 131.22430419921875 | fit/entropy_loss = 0.5248685479164124 | fit/approx_kl = 0.0007476735045202076 | fit/clipfrac = 0.0 | fit/explained_variance = 0.18155068159103394 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 6336 | fit/policy_loss = -0.009597748517990112 | fit/value_loss = 306.9555358886719 | fit/entropy_loss = 0.5775970220565796 | fit/approx_kl = 0.0005952063947916031 | fit/clipfrac = 0.0 | fit/explained_variance = -0.3066709041595459 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 7872 | fit/policy_loss = -0.0011599212884902954 | fit/value_loss = 0.3407192528247833 | fit/entropy_loss = 0.41181233525276184 | fit/approx_kl = 0.01260202657431364 | fit/clipfrac = 0.19791666492819787 | fit/explained_variance = 0.975825097411871 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 7968 | fit/policy_loss = -0.047126080840826035 | fit/value_loss = 30.541654586791992 | fit/entropy_loss = 0.5876209139823914 | fit/approx_kl = 0.0013518078485503793 | fit/clipfrac = 0.0 | fit/explained_variance = 0.7769163846969604 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 9504 | fit/policy_loss = -0.005419999361038208 | fit/value_loss = 2.6821603775024414 | fit/entropy_loss = 0.4786674976348877 | fit/approx_kl = 0.002310350304469466 | fit/clipfrac = 0.0 | fit/explained_variance = 0.5584505200386047 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 9600 | fit/policy_loss = -0.0188402459025383 | fit/value_loss = 175.68919372558594 | fit/entropy_loss = 0.5457869172096252 | fit/approx_kl = 0.0003522926417645067 | fit/clipfrac = 0.0 | fit/explained_variance = 0.37716150283813477 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 11136 | fit/policy_loss = 0.002097398042678833 | fit/value_loss = 0.04328225180506706 | fit/entropy_loss = 0.520216166973114 | fit/approx_kl = 2.282687091792468e-05 | fit/clipfrac = 0.002083333395421505 | fit/explained_variance = 0.9905285472050309 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 11232 | fit/policy_loss = -0.02607026696205139 | fit/value_loss = 0.9695928692817688 | fit/entropy_loss = 0.544611930847168 | fit/approx_kl = 0.0014795692404732108 | fit/clipfrac = 0.008333333488553762 | fit/explained_variance = 0.775581106543541 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 12768 | fit/policy_loss = -0.00431543355807662 | fit/value_loss = 0.1664377897977829 | fit/entropy_loss = 0.5166257619857788 | fit/approx_kl = 0.01913692243397236 | fit/clipfrac = 0.2750000006519258 | fit/explained_variance = 0.950390450656414 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 12864 | fit/policy_loss = -0.01600167714059353 | fit/value_loss = 1.0876649618148804 | fit/entropy_loss = 0.5791975259780884 | fit/approx_kl = 0.015078354626893997 | fit/clipfrac = 0.05416666679084301 | fit/explained_variance = 0.957294762134552 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 2]] | max_global_step = 14208 | fit/policy_loss = -0.007962663657963276 | fit/value_loss = 0.4722827970981598 | fit/entropy_loss = 0.5429236888885498 | fit/approx_kl = 0.011440296657383442 | fit/clipfrac = 0.029166666604578496 | fit/explained_variance = -2.395857334136963 | fit/learning_rate = 0.0003 | +[INFO] 10:29: [PPO_second_experimentCartPole-v1[worker: 3]] | max_global_step = 14304 | fit/policy_loss = -0.00023897241044323891 | fit/value_loss = 0.37554287910461426 | fit/entropy_loss = 0.5310923457145691 | fit/approx_kl = 0.0071893795393407345 | fit/clipfrac = 0.18125000046566128 | fit/explained_variance = -2.975414991378784 | fit/learning_rate = 0.0003 | +[INFO] 10:29: ... trained! +[INFO] 10:29: Evaluating PPO_second_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished PPO_second_experimentCartPole-v1 0 164.0 @@ -259,4 +259,4 @@ print(output)
- In the output you can see the learning of the workers 0 and 1 first, then 2 and 3 (4 fit, but max 2 threads with parallelization). -- You can check the tensorboard logging with `tensorboard --logdir `. \ No newline at end of file +- You can check the tensorboard logging with `tensorboard --logdir `. From 5ebff6b1a6d8e50826b3a62e9d04c02eb0b28ac8 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 13 Oct 2023 10:58:26 +0200 Subject: [PATCH 30/80] typo correction --- docs/basics/userguide/experimentManager.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics/userguide/experimentManager.md b/docs/basics/userguide/experimentManager.md index c9c4d80e3..ca0a7e963 100644 --- a/docs/basics/userguide/experimentManager.md +++ b/docs/basics/userguide/experimentManager.md @@ -175,7 +175,7 @@ Moviepy - video ready /CartPole-v1-episode-1.mp4 Now an example with some more settings. (check the [API](rlberry.manager.ExperimentManager) to see all of them) ```python -sfrom rlberry.envs import gym_make +from rlberry.envs import gym_make from rlberry.agents.torch import PPOAgent from rlberry.manager import ExperimentManager, evaluate_agents From 57f0168b3d5fe88927e40ae0ffe5bf9223ccb686 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 13 Oct 2023 08:59:25 +0000 Subject: [PATCH 31/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/userguide/experimentManager.md | 118 ++++++++++++--------- 1 file changed, 70 insertions(+), 48 deletions(-) diff --git a/docs/basics/userguide/experimentManager.md b/docs/basics/userguide/experimentManager.md index ca0a7e963..6e793d13a 100644 --- a/docs/basics/userguide/experimentManager.md +++ b/docs/basics/userguide/experimentManager.md @@ -14,25 +14,29 @@ from rlberry.agents.torch import PPOAgent from rlberry.manager import ExperimentManager, evaluate_agents -env_id = "CartPole-v1" #Id of the environment +env_id = "CartPole-v1" # Id of the environment -env_ctor = gym_make #constructor for the env -env_kwargs = dict(id=env_id) #give the id of the env inside the kwargs +env_ctor = gym_make # constructor for the env +env_kwargs = dict(id=env_id) # give the id of the env inside the kwargs first_experiment = ExperimentManager( - PPOAgent, #Agent Class - (env_ctor, env_kwargs), #Environment as Tuple(constructor,kwargs) - fit_budget=int(100), #Budget used to call our agent "fit()" - eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). - n_fit=1, #Number of agent instances to fit. - agent_name="PPO_first_experiment" + env_id, #Name of the agent + PPOAgent, # Agent Class + (env_ctor, env_kwargs), # Environment as Tuple(constructor,kwargs) + fit_budget=int(100), # Budget used to call our agent "fit()" + eval_kwargs=dict( + eval_horizon=1000 + ), # Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, # Number of agent instances to fit. + agent_name="PPO_first_experiment" + env_id, # Name of the agent seed=42, ) first_experiment.fit() -output = evaluate_agents([first_experiment], n_simulations=5, plot=False) #evaluate the experiment on 5 simulations +output = evaluate_agents( + [first_experiment], n_simulations=5, plot=False +) # evaluate the experiment on 5 simulations print(output) ``` @@ -60,19 +64,26 @@ Now you can compare this agent with another one. Here, we gonna compare it with **warning :** add this code after the previous one. ```python second_experiment = ExperimentManager( - PPOAgent, #Agent Class - (env_ctor, env_kwargs), #Environment as Tuple(constructor,kwargs) - fit_budget=int(10000), #Budget used to call our agent "fit()" - init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), #Arguments for the Agent’s constructor. - eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). - n_fit=1, #Number of agent instances to fit. - agent_name="PPO_second_experiment" + env_id, #Name of our agent (for saving/printing) + PPOAgent, # Agent Class + (env_ctor, env_kwargs), # Environment as Tuple(constructor,kwargs) + fit_budget=int(10000), # Budget used to call our agent "fit()" + init_kwargs=dict( + batch_size=24, n_steps=96, device="cpu" + ), # Arguments for the Agent’s constructor. + eval_kwargs=dict( + eval_horizon=1000 + ), # Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, # Number of agent instances to fit. + agent_name="PPO_second_experiment" + + env_id, # Name of our agent (for saving/printing) seed=42, ) second_experiment.fit() -output = evaluate_agents([first_experiment,second_experiment], n_simulations=5, plot=True) #evaluate the 2 experiments on 5 simulations +output = evaluate_agents( + [first_experiment, second_experiment], n_simulations=5, plot=True +) # evaluate the 2 experiments on 5 simulations print(output) ``` @@ -107,33 +118,38 @@ If you want to see the output video of the trained Agent, you need to use the Re ```python env_id = "CartPole-v1" -env_ctor = gym_make #constructor for training env -env_kwargs = dict(id=env_id) #kwars for training env +env_ctor = gym_make # constructor for training env +env_kwargs = dict(id=env_id) # kwars for training env -eval_env_ctor = PipelineEnv #constructor for eval env -eval_env_kwargs = { #kwars for eval env (with wrapper) +eval_env_ctor = PipelineEnv # constructor for eval env +eval_env_kwargs = { # kwars for eval env (with wrapper) "env_ctor": gym_make, - "env_kwargs": {"id": env_id, "render_mode":"rgb_array"}, - "wrappers": [(RecordVideo,{"video_folder":"./","name_prefix":env_id})] #list of tuple (class,kwargs) + "env_kwargs": {"id": env_id, "render_mode": "rgb_array"}, + "wrappers": [ + (RecordVideo, {"video_folder": "./", "name_prefix": env_id}) + ], # list of tuple (class,kwargs) } third_experiment = ExperimentManager( - PPOAgent, #Agent Class - (env_ctor, env_kwargs), #Environment as Tuple(constructor,kwargs) - fit_budget=int(10000), #Budget used to call our agent "fit()" - eval_env = (eval_env_ctor, eval_env_kwargs), #Evaluation environment as tuple - init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), #settings for the Agent - eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). - n_fit=1, #Number of agent instances to fit. - agent_name="PPO_third_experiment" + env_id, #Name of the agent + PPOAgent, # Agent Class + (env_ctor, env_kwargs), # Environment as Tuple(constructor,kwargs) + fit_budget=int(10000), # Budget used to call our agent "fit()" + eval_env=(eval_env_ctor, eval_env_kwargs), # Evaluation environment as tuple + init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), # settings for the Agent + eval_kwargs=dict( + eval_horizon=1000 + ), # Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, # Number of agent instances to fit. + agent_name="PPO_third_experiment" + env_id, # Name of the agent seed=42, ) third_experiment.fit() -output3 = evaluate_agents([third_experiment], n_simulations=15, plot=False) #evaluate the experiment on 5 simulations +output3 = evaluate_agents( + [third_experiment], n_simulations=15, plot=False +) # evaluate the experiment on 5 simulations print(output3) - ``` @@ -185,25 +201,31 @@ env_ctor = gym_make env_kwargs = dict(id=env_id) fourth_experiment = ExperimentManager( - PPOAgent, #Agent Class - train_env=(env_ctor, env_kwargs), #Environment to train the Agent - fit_budget=int(15000), #Budget used to call our agent "fit()" - eval_env=(env_ctor, env_kwargs), #Environment to eval the Agent (here, same as training env) - init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), #Agent setting - eval_kwargs=dict(eval_horizon=1000), #Arguments required to call rlberry.agents.agent.Agent.eval(). - agent_name="PPO_second_experiment" + env_id, #Name of the agent - n_fit=4, #Number of agent instances to fit. - output_dir="./fourth_experiment_results/", #Directory where to store data. - parallelization="thread", #parallelize agent training using threads - max_workers=2, #max 2 threads with parallelization - enable_tensorboard=True, #enable tensorboard logging + PPOAgent, # Agent Class + train_env=(env_ctor, env_kwargs), # Environment to train the Agent + fit_budget=int(15000), # Budget used to call our agent "fit()" + eval_env=( + env_ctor, + env_kwargs, + ), # Environment to eval the Agent (here, same as training env) + init_kwargs=dict(batch_size=24, n_steps=96, device="cpu"), # Agent setting + eval_kwargs=dict( + eval_horizon=1000 + ), # Arguments required to call rlberry.agents.agent.Agent.eval(). + agent_name="PPO_second_experiment" + env_id, # Name of the agent + n_fit=4, # Number of agent instances to fit. + output_dir="./fourth_experiment_results/", # Directory where to store data. + parallelization="thread", # parallelize agent training using threads + max_workers=2, # max 2 threads with parallelization + enable_tensorboard=True, # enable tensorboard logging ) fourth_experiment.fit() -output = evaluate_agents([fourth_experiment], n_simulations=5, plot=False) #evaluate the experiment on 5 simulations +output = evaluate_agents( + [fourth_experiment], n_simulations=5, plot=False +) # evaluate the experiment on 5 simulations print(output) - ``` ```none From db9d43d3a0e99d38510a36ec0299adff145395cf Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 17 Oct 2023 16:48:38 +0200 Subject: [PATCH 32/80] add Agent in new userguide --- .../user_guide_video/_agent_page_CartPole.mp4 | Bin 0 -> 29524 bytes .../user_guide_video/_agent_page_chain1.mp4 | Bin 0 -> 14893 bytes .../user_guide_video/_agent_page_chain2.mp4 | Bin 0 -> 12634 bytes .../_agent_page_frozenLake.mp4 | Bin 0 -> 23847 bytes docs/basics/userguide/agent.md | 422 ++++++++++++++++++ docs/user_guide2.md | 9 +- 6 files changed, 428 insertions(+), 3 deletions(-) create mode 100644 docs/_video/user_guide_video/_agent_page_CartPole.mp4 create mode 100644 docs/_video/user_guide_video/_agent_page_chain1.mp4 create mode 100644 docs/_video/user_guide_video/_agent_page_chain2.mp4 create mode 100644 docs/_video/user_guide_video/_agent_page_frozenLake.mp4 create mode 100644 docs/basics/userguide/agent.md diff --git a/docs/_video/user_guide_video/_agent_page_CartPole.mp4 b/docs/_video/user_guide_video/_agent_page_CartPole.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..9fe3fd2b5d66d50ee91c5c22204d9019d042950a GIT binary patch literal 29524 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 literal 0 HcmV?d00001 diff --git a/docs/_video/user_guide_video/_agent_page_chain1.mp4 b/docs/_video/user_guide_video/_agent_page_chain1.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..4d6e11e4abf38352e6fe8ff7c80593c6e9691ba6 GIT binary patch literal 14893 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 literal 0 HcmV?d00001 diff --git a/docs/_video/user_guide_video/_agent_page_chain2.mp4 b/docs/_video/user_guide_video/_agent_page_chain2.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..df26af82f2e65348e87ad0a0f329ceac0f372924 GIT binary patch literal 12634 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 literal 0 HcmV?d00001 diff --git a/docs/_video/user_guide_video/_agent_page_frozenLake.mp4 b/docs/_video/user_guide_video/_agent_page_frozenLake.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..1892eecd4d8b940c71370f770268c7d2ebce8344 GIT binary patch literal 23847 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 + + + +If we use random actions on this environment, we don't have good results (the cross don't go to the right) + +### With agent + +With the same environment, we will use an Agent to choose the actions instead of random actions. + +```python +from rlberry.envs.finite import Chain +from rlberry.agents.dynprog import ValueIterationAgent + +env = Chain(10, 0.1) #same env +agent = ValueIterationAgent(env, gamma=0.95) #creation of the agent +info = agent.fit() #Agent's training (ValueIteration don't use budget) +print(info) + +#test the trained agent +env.enable_rendering() +observation, info = env.reset() +for tt in range(50): + action = agent.policy(observation) #use the agent's policy to choose the next action + observation, reward, terminated, truncated, info = env.step(action) #do the action + done = terminated or truncated + if done: + break #stop if the environement is done +env.render(loop=False) + +# env.save_video is only available for rlberry envs and custom env (with 'RenderInterface' as parent class) +video = env.save_video("_agent_page_chain2.mp4") +env.close() +``` + +```none +{'n_iterations': 269, 'precision': 1e-06} + pg.display.set_mode(display, DOUBLEBUF | OPENGL) + _ = pg.display.set_mode(display, DOUBLEBUF | OPENGL) +ffmpeg version 4.4.2-0ubuntu0.22.04.1 Copyright (c) 2000-2021 the FFmpeg developers + built with gcc 11 (Ubuntu 11.2.0-19ubuntu1) + configuration: --prefix=/usr --extra-version=0ubuntu0.22.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --arch=amd64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-librsvg --enable-libmfx --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared + libavutil 56. 70.100 / 56. 70.100 + libavcodec 58.134.100 / 58.134.100 + libavformat 58. 76.100 / 58. 76.100 + libavdevice 58. 13.100 / 58. 13.100 + libavfilter 7.110.100 / 7.110.100 + libswscale 5. 9.100 / 5. 9.100 + libswresample 3. 9.100 / 3. 9.100 + libpostproc 55. 9.100 / 55. 9.100 +Input #0, rawvideo, from 'pipe:': + Duration: N/A, start: 0.000000, bitrate: 38400 kb/s + Stream #0:0: Video: rawvideo (RGB[24] / 0x18424752), rgb24, 800x80, 38400 kb/s, 25 tbr, 25 tbn, 25 tbc +Stream mapping: + Stream #0:0 -> #0:0 (rawvideo (native) -> h264 (libx264)) +[libx264 @ 0x5570932967c0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2 AVX512 +[libx264 @ 0x5570932967c0] profile High, level 1.3, 4:2:0, 8-bit +[libx264 @ 0x5570932967c0] 264 - core 163 r3060 5db6aa6 - H.264/MPEG-4 AVC codec - Copyleft 2003-2021 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=2 lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0 qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00 +Output #0, mp4, to '_agent_page_chain.mp4': + Metadata: + encoder : Lavf58.76.100 + Stream #0:0: Video: h264 (avc1 / 0x31637661), yuv420p(tv, progressive), 800x80, q=2-31, 25 fps, 12800 tbn + Metadata: + encoder : Lavc58.134.100 libx264 + Side data: + cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A +frame= 51 fps=0.0 q=-1.0 Lsize= 12kB time=00:00:01.92 bitrate= 51.9kbits/s speed=48.8x +video:11kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 12.817029% +[libx264 @ 0x5570932967c0] frame I:1 Avg QP:29.06 size: 6089 +[libx264 @ 0x5570932967c0] frame P:18 Avg QP:18.13 size: 172 +[libx264 @ 0x5570932967c0] frame B:32 Avg QP:13.93 size: 37 +[libx264 @ 0x5570932967c0] consecutive B-frames: 15.7% 0.0% 5.9% 78.4% +[libx264 @ 0x5570932967c0] mb I I16..4: 46.4% 0.0% 53.6% +[libx264 @ 0x5570932967c0] mb P I16..4: 5.9% 0.8% 1.3% P16..4: 0.4% 0.0% 0.0% 0.0% 0.0% skip:91.6% +[libx264 @ 0x5570932967c0] mb B I16..4: 0.1% 0.0% 0.2% B16..8: 1.6% 0.0% 0.0% direct: 0.0% skip:98.1% L0:58.9% L1:41.1% BI: 0.0% +[libx264 @ 0x5570932967c0] 8x8 transform intra:6.3% inter:14.3% +[libx264 @ 0x5570932967c0] coded y,uvDC,uvAC intra: 46.1% 37.1% 35.7% inter: 0.0% 0.0% 0.0% +[libx264 @ 0x5570932967c0] i16 v,h,dc,p: 55% 7% 38% 1% +[libx264 @ 0x5570932967c0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 0% 0% 100% 0% 0% 0% 0% 0% 0% +[libx264 @ 0x5570932967c0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 33% 14% 41% 0% 4% 3% 2% 1% 1% +[libx264 @ 0x5570932967c0] i8c dc,h,v,p: 87% 5% 7% 1% +[libx264 @ 0x5570932967c0] Weighted P-Frames: Y:5.6% UV:5.6% +[libx264 @ 0x5570932967c0] ref P L0: 10.5% 5.3% 73.7% 10.5% +[libx264 @ 0x5570932967c0] ref B L0: 59.2% 27.6% 13.2% +[libx264 @ 0x5570932967c0] ref B L1: 96.2% 3.8% +[libx264 @ 0x5570932967c0] kb/s:40.59 +``` +
+ + + +The agent has learned how to obtain good results (the cross go to the right). + + + + + + +## Load StableBaselines3 as rlberry Agent +With rlberry, you can load algorithm from [StableBaselines3](https://stable-baselines3.readthedocs.io/en/master/guide/algos.html) and wrap it in rlberry Agent. To do that, you need to use [StableBaselinesAgent](rlberry.agents.stable_baselines.StableBaselinesAgent). + + +```python +from rlberry.envs import gym_make +from gymnasium.wrappers.record_video import RecordVideo +from stable_baselines3 import PPO +from rlberry.agents.stable_baselines import StableBaselinesAgent + +env = gym_make("CartPole-v1", render_mode="rgb_array") +agent = StableBaselinesAgent(env, PPO, "MlpPolicy", verbose=1) #wrap StableBaseline3's PPO inside rlberry Agent +info = agent.fit(10000) #Agent's training +print(info) + +env = RecordVideo(env, video_folder="./", name_prefix="CartPole") #wrap the env to save the video output +observation, info = env.reset() #initialize the environment +for tt in range(3000): + action = agent.policy(observation) #use the agent's policy to choose the next action + observation, reward, terminated, truncated, info = env.step(action) #do the action + done = terminated or truncated + if done: + break #stop if the environement is done +env.close() +``` + +```none +Using cpu device +Wrapping the env with a `Monitor` wrapper +Wrapping the env in a DummyVecEnv. +--------------------------------- +| rollout/ | | +| ep_len_mean | 22 | +| ep_rew_mean | 22 | +| time/ | | +| fps | 2490 | +| iterations | 1 | +| time_elapsed | 0 | +| total_timesteps | 2048 | +--------------------------------- +----------------------------------------- +| rollout/ | | +| ep_len_mean | 28.1 | +| ep_rew_mean | 28.1 | +| time/ | | +| fps | 1842 | +| iterations | 2 | +| time_elapsed | 2 | +| total_timesteps | 4096 | +| train/ | | +| approx_kl | 0.009214947 | +| clip_fraction | 0.102 | +| clip_range | 0.2 | +| entropy_loss | -0.686 | +| explained_variance | -0.00179 | +| learning_rate | 0.0003 | +| loss | 8.42 | +| n_updates | 10 | +| policy_gradient_loss | -0.0158 | +| value_loss | 51.5 | +----------------------------------------- +----------------------------------------- +| rollout/ | | +| ep_len_mean | 40 | +| ep_rew_mean | 40 | +| time/ | | +| fps | 1708 | +| iterations | 3 | +| time_elapsed | 3 | +| total_timesteps | 6144 | +| train/ | | +| approx_kl | 0.009872524 | +| clip_fraction | 0.0705 | +| clip_range | 0.2 | +| entropy_loss | -0.666 | +| explained_variance | 0.119 | +| learning_rate | 0.0003 | +| loss | 16 | +| n_updates | 20 | +| policy_gradient_loss | -0.0195 | +| value_loss | 38.7 | +----------------------------------------- +[INFO] 16:36: [[worker: -1]] | max_global_step = 6144 | time/iterations = 2 | rollout/ep_rew_mean = 28.13 | rollout/ep_len_mean = 28.13 | time/fps = 1842 | time/time_elapsed = 2 | time/total_timesteps = 4096 | train/learning_rate = 0.0003 | train/entropy_loss = -0.6860913151875139 | train/policy_gradient_loss = -0.015838009686558508 | train/value_loss = 51.528612112998964 | train/approx_kl = 0.009214947000145912 | train/clip_fraction = 0.10205078125 | train/loss = 8.420166969299316 | train/explained_variance = -0.001785874366760254 | train/n_updates = 10 | train/clip_range = 0.2 | +------------------------------------------ +| rollout/ | | +| ep_len_mean | 50.2 | +| ep_rew_mean | 50.2 | +| time/ | | +| fps | 1674 | +| iterations | 4 | +| time_elapsed | 4 | +| total_timesteps | 8192 | +| train/ | | +| approx_kl | 0.0076105352 | +| clip_fraction | 0.068 | +| clip_range | 0.2 | +| entropy_loss | -0.634 | +| explained_variance | 0.246 | +| learning_rate | 0.0003 | +| loss | 29.6 | +| n_updates | 30 | +| policy_gradient_loss | -0.0151 | +| value_loss | 57.3 | +------------------------------------------ +----------------------------------------- +| rollout/ | | +| ep_len_mean | 66 | +| ep_rew_mean | 66 | +| time/ | | +| fps | 1655 | +| iterations | 5 | +| time_elapsed | 6 | +| total_timesteps | 10240 | +| train/ | | +| approx_kl | 0.006019583 | +| clip_fraction | 0.0597 | +| clip_range | 0.2 | +| entropy_loss | -0.606 | +| explained_variance | 0.238 | +| learning_rate | 0.0003 | +| loss | 31.1 | +| n_updates | 40 | +| policy_gradient_loss | -0.0147 | +| value_loss | 72.3 | +----------------------------------------- +None + +Moviepy - Building video /CartPole-episode-0.mp4. +Moviepy - Writing video /CartPole-episode-0.mp4 + +Moviepy - Done ! +Moviepy - video ready /CartPole-episode-0.mp4 +``` + +
+ + + + + +## Create your own Agent + **warning :** For advanced users only + +rlberry requires you to use a **very simple interface** to write agents, with basically +two methods to implement: `fit()` and `eval()`. + +You can find more information on this interface [here(Agent)](rlberry.agents.agent.Agent) (or [here(AgentWithSimplePolicy)](rlberry.agents.agent.AgentWithSimplePolicy)) + +The example below shows how to create an agent. + + +```python +import numpy as np +from rlberry.agents import AgentWithSimplePolicy + + +class MyAgentQLearning (AgentWithSimplePolicy): + name = "QLearning" + # create an agent with q-table + + def __init__( + self, env, exploration_rate=0.01, learning_rate=0.8,discount_factor=0.95, **kwargs + ): # it's important to put **kwargs to ensure compatibility with the base class + # self.env is initialized in the base class + super().__init__(env=env, **kwargs) + + state_space_size = env.observation_space.n + action_space_size = env.action_space.n + + self.exploration_rate = exploration_rate #percentage to select random action + self.q_table = np.zeros((state_space_size, action_space_size)) #q_table to store result and choose actions + self.learning_rate = learning_rate + self.discount_factor=discount_factor #gamma + + + + + def fit(self, budget, **kwargs): + """ + The parameter budget can represent the number of steps, the number of episodes etc, + depending on the agent. + * Interact with the environment (self.env); + * Train the agent + * Return useful information + """ + n_episodes = budget + rewards = np.zeros(n_episodes) + + for ep in range(n_episodes): + observation, info = self.env.reset() + done = False + while not done: + action = self.policy(observation) + next_step, reward, terminated, truncated, info = self.env.step(action) + #update the q_table + self.q_table[observation, action] = (1 - self.learning_rate) * self.q_table[observation, action] + self.learning_rate * (reward + self.discount_factor * np.max(self.q_table[next_step, :])) + observation = next_step + done = terminated or truncated + rewards[ep] += reward + + info = {"episode_rewards": rewards} + return info + + def eval(self, **kwargs): + """ + Returns a value corresponding to the evaluation of the agent on the + evaluation environment. + + For instance, it can be a Monte-Carlo evaluation of the policy learned in fit(). + """ + + return super().eval() #use the eval() from AgentWithSimplePolicy + + def policy(self, observation, explo=True): + state = observation + if explo and np.random.rand() < self.exploration_rate: + action = env.action_space.sample() # Explore + else: + action = np.argmax(self.q_table[state, :]) # Exploit + + return action + +``` + + + **warning :** It's important that your agent accepts optional `**kwargs` and pass it to the base class as `Agent.__init__(self, env, **kwargs)`. + +You can use it like this : + +```python + +from gymnasium.wrappers.record_video import RecordVideo +from rlberry.envs import gym_make + +env = gym_make("FrozenLake-v1", render_mode="rgb_array",is_slippery=False) #remove the slippery from the env +agent = MyAgentQLearning(env, exploration_rate=0.25,learning_rate = 0.8,discount_factor = 0.95) +info = agent.fit(100000) #Agent's training +print("----------") +print(agent.q_table) #display the q_table content +print("----------") + +env = RecordVideo(env, video_folder="./", name_prefix="FrozenLake_no_slippery") #wrap the env to save the video output +observation, info = env.reset() #initialize the environment +for tt in range(3000): + action = agent.policy(observation,explo=False) #use the agent's policy to choose the next action (without exploration) + observation, reward, terminated, truncated, info = env.step(action) #do the action + done = terminated or truncated + if done: + break #stop if the environement is done +env.close() +``` + + +```none +---------- +[[0.73509189 0.77378094 0.77378094 0.73509189] + [0.73509189 0. 0.81450625 0.77378094] + [0.77378094 0.857375 0.77378094 0.81450625] + [0.81450625 0. 0.77378094 0.77378094] + [0.77378094 0.81450625 0. 0.73509189] + [0. 0. 0. 0. ] + [0. 0.9025 0. 0.81450625] + [0. 0. 0. 0. ] + [0.81450625 0. 0.857375 0.77378094] + [0.81450625 0.9025 0.9025 0. ] + [0.857375 0.95 0. 0.857375 ] + [0. 0. 0. 0. ] + [0. 0. 0. 0. ] + [0. 0.9025 0.95 0.857375 ] + [0.9025 0.95 1. 0.9025 ] + [0. 0. 0. 0. ]] +---------- + +Moviepy - Building video /FrozenLake_no_slippery-episode-0.mp4. +Moviepy - Writing video /FrozenLake_no_slippery-episode-0.mp4 + +Moviepy - Done ! +Moviepy - video ready /FrozenLake_no_slippery-episode-0.mp4 +0.7 + +``` + + + + + + + +## Use experimentManager + +This is one of the core element in rlberry. The ExperimentManager allow you to easily make an experiment between an Agent and an Environment. It's use to train, optimize hyperparameters, evaluate and gather statistics about an agent. +You can find the guide for ExperimentManager [here](experimentManager_page). \ No newline at end of file diff --git a/docs/user_guide2.md b/docs/user_guide2.md index ce5d1337c..3fdd6646d 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -12,10 +12,13 @@ In this user guide, we take you through the core features of rlberry and illustr Some text about an experiment: a comparison of 2 rl agents on a given environment. ### Environment This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). [(Wikipedia)](https://en.wikipedia.org/wiki/Reinforcement_learning) The environment is typically stated in the form of a Markov decision process (MDP). -You can find the guide for environment [here](environment_page). -Some text about MDPs. +You can find the guide for Environment [here](environment_page). + +Some text about MDPs.(?) ### Agent -Some text about what an agent is. +In Reinforcement learning, the Agent is the entity to train to solve an environment. It's able interact with the environment: observe, take actions, and learn through trial and error. +You can find the guide for Agent [here](agent_page). + ### ExperimentManager This is one of the core element in rlberry. The ExperimentManager allow you to easily make an experiment between an Agent and an Environment. It's use to train, optimize hyperparameters, evaluate and gather statistics about an agent. You can find the guide for ExperimentManager [here](experimentManager_page). From 71cb78d2da4df2eda1a17da194d8e8f35d77e753 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 17 Oct 2023 14:49:52 +0000 Subject: [PATCH 33/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/userguide/agent.md | 108 ++++++++++++++++++++------------- 1 file changed, 65 insertions(+), 43 deletions(-) diff --git a/docs/basics/userguide/agent.md b/docs/basics/userguide/agent.md index 4d086f77c..4afd968bc 100644 --- a/docs/basics/userguide/agent.md +++ b/docs/basics/userguide/agent.md @@ -38,20 +38,22 @@ With the same environment, we will use an Agent to choose the actions instead of from rlberry.envs.finite import Chain from rlberry.agents.dynprog import ValueIterationAgent -env = Chain(10, 0.1) #same env -agent = ValueIterationAgent(env, gamma=0.95) #creation of the agent -info = agent.fit() #Agent's training (ValueIteration don't use budget) +env = Chain(10, 0.1) # same env +agent = ValueIterationAgent(env, gamma=0.95) # creation of the agent +info = agent.fit() # Agent's training (ValueIteration don't use budget) print(info) -#test the trained agent +# test the trained agent env.enable_rendering() observation, info = env.reset() for tt in range(50): - action = agent.policy(observation) #use the agent's policy to choose the next action - observation, reward, terminated, truncated, info = env.step(action) #do the action + action = agent.policy( + observation + ) # use the agent's policy to choose the next action + observation, reward, terminated, truncated, info = env.step(action) # do the action done = terminated or truncated if done: - break #stop if the environement is done + break # stop if the environement is done env.render(loop=False) # env.save_video is only available for rlberry envs and custom env (with 'RenderInterface' as parent class) @@ -90,7 +92,7 @@ Output #0, mp4, to '_agent_page_chain.mp4': encoder : Lavc58.134.100 libx264 Side data: cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A -frame= 51 fps=0.0 q=-1.0 Lsize= 12kB time=00:00:01.92 bitrate= 51.9kbits/s speed=48.8x +frame= 51 fps=0.0 q=-1.0 Lsize= 12kB time=00:00:01.92 bitrate= 51.9kbits/s speed=48.8x video:11kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 12.817029% [libx264 @ 0x5570932967c0] frame I:1 Avg QP:29.06 size: 6089 [libx264 @ 0x5570932967c0] frame P:18 Avg QP:18.13 size: 172 @@ -135,18 +137,24 @@ from stable_baselines3 import PPO from rlberry.agents.stable_baselines import StableBaselinesAgent env = gym_make("CartPole-v1", render_mode="rgb_array") -agent = StableBaselinesAgent(env, PPO, "MlpPolicy", verbose=1) #wrap StableBaseline3's PPO inside rlberry Agent -info = agent.fit(10000) #Agent's training +agent = StableBaselinesAgent( + env, PPO, "MlpPolicy", verbose=1 +) # wrap StableBaseline3's PPO inside rlberry Agent +info = agent.fit(10000) # Agent's training print(info) -env = RecordVideo(env, video_folder="./", name_prefix="CartPole") #wrap the env to save the video output -observation, info = env.reset() #initialize the environment +env = RecordVideo( + env, video_folder="./", name_prefix="CartPole" +) # wrap the env to save the video output +observation, info = env.reset() # initialize the environment for tt in range(3000): - action = agent.policy(observation) #use the agent's policy to choose the next action - observation, reward, terminated, truncated, info = env.step(action) #do the action + action = agent.policy( + observation + ) # use the agent's policy to choose the next action + observation, reward, terminated, truncated, info = env.step(action) # do the action done = terminated or truncated if done: - break #stop if the environement is done + break # stop if the environement is done env.close() ``` @@ -206,7 +214,7 @@ Wrapping the env in a DummyVecEnv. | policy_gradient_loss | -0.0195 | | value_loss | 38.7 | ----------------------------------------- -[INFO] 16:36: [[worker: -1]] | max_global_step = 6144 | time/iterations = 2 | rollout/ep_rew_mean = 28.13 | rollout/ep_len_mean = 28.13 | time/fps = 1842 | time/time_elapsed = 2 | time/total_timesteps = 4096 | train/learning_rate = 0.0003 | train/entropy_loss = -0.6860913151875139 | train/policy_gradient_loss = -0.015838009686558508 | train/value_loss = 51.528612112998964 | train/approx_kl = 0.009214947000145912 | train/clip_fraction = 0.10205078125 | train/loss = 8.420166969299316 | train/explained_variance = -0.001785874366760254 | train/n_updates = 10 | train/clip_range = 0.2 | +[INFO] 16:36: [[worker: -1]] | max_global_step = 6144 | time/iterations = 2 | rollout/ep_rew_mean = 28.13 | rollout/ep_len_mean = 28.13 | time/fps = 1842 | time/time_elapsed = 2 | time/total_timesteps = 4096 | train/learning_rate = 0.0003 | train/entropy_loss = -0.6860913151875139 | train/policy_gradient_loss = -0.015838009686558508 | train/value_loss = 51.528612112998964 | train/approx_kl = 0.009214947000145912 | train/clip_fraction = 0.10205078125 | train/loss = 8.420166969299316 | train/explained_variance = -0.001785874366760254 | train/n_updates = 10 | train/clip_range = 0.2 | ------------------------------------------ | rollout/ | | | ep_len_mean | 50.2 | @@ -254,8 +262,8 @@ None Moviepy - Building video /CartPole-episode-0.mp4. Moviepy - Writing video /CartPole-episode-0.mp4 -Moviepy - Done ! -Moviepy - video ready /CartPole-episode-0.mp4 +Moviepy - Done ! +Moviepy - video ready /CartPole-episode-0.mp4 ```
@@ -282,12 +290,17 @@ import numpy as np from rlberry.agents import AgentWithSimplePolicy -class MyAgentQLearning (AgentWithSimplePolicy): +class MyAgentQLearning(AgentWithSimplePolicy): name = "QLearning" # create an agent with q-table def __init__( - self, env, exploration_rate=0.01, learning_rate=0.8,discount_factor=0.95, **kwargs + self, + env, + exploration_rate=0.01, + learning_rate=0.8, + discount_factor=0.95, + **kwargs ): # it's important to put **kwargs to ensure compatibility with the base class # self.env is initialized in the base class super().__init__(env=env, **kwargs) @@ -295,13 +308,12 @@ class MyAgentQLearning (AgentWithSimplePolicy): state_space_size = env.observation_space.n action_space_size = env.action_space.n - self.exploration_rate = exploration_rate #percentage to select random action - self.q_table = np.zeros((state_space_size, action_space_size)) #q_table to store result and choose actions + self.exploration_rate = exploration_rate # percentage to select random action + self.q_table = np.zeros( + (state_space_size, action_space_size) + ) # q_table to store result and choose actions self.learning_rate = learning_rate - self.discount_factor=discount_factor #gamma - - - + self.discount_factor = discount_factor # gamma def fit(self, budget, **kwargs): """ @@ -318,10 +330,14 @@ class MyAgentQLearning (AgentWithSimplePolicy): observation, info = self.env.reset() done = False while not done: - action = self.policy(observation) + action = self.policy(observation) next_step, reward, terminated, truncated, info = self.env.step(action) - #update the q_table - self.q_table[observation, action] = (1 - self.learning_rate) * self.q_table[observation, action] + self.learning_rate * (reward + self.discount_factor * np.max(self.q_table[next_step, :])) + # update the q_table + self.q_table[observation, action] = ( + 1 - self.learning_rate + ) * self.q_table[observation, action] + self.learning_rate * ( + reward + self.discount_factor * np.max(self.q_table[next_step, :]) + ) observation = next_step done = terminated or truncated rewards[ep] += reward @@ -337,7 +353,7 @@ class MyAgentQLearning (AgentWithSimplePolicy): For instance, it can be a Monte-Carlo evaluation of the policy learned in fit(). """ - return super().eval() #use the eval() from AgentWithSimplePolicy + return super().eval() # use the eval() from AgentWithSimplePolicy def policy(self, observation, explo=True): state = observation @@ -347,7 +363,6 @@ class MyAgentQLearning (AgentWithSimplePolicy): action = np.argmax(self.q_table[state, :]) # Exploit return action - ``` @@ -356,25 +371,32 @@ class MyAgentQLearning (AgentWithSimplePolicy): You can use it like this : ```python - from gymnasium.wrappers.record_video import RecordVideo from rlberry.envs import gym_make -env = gym_make("FrozenLake-v1", render_mode="rgb_array",is_slippery=False) #remove the slippery from the env -agent = MyAgentQLearning(env, exploration_rate=0.25,learning_rate = 0.8,discount_factor = 0.95) -info = agent.fit(100000) #Agent's training +env = gym_make( + "FrozenLake-v1", render_mode="rgb_array", is_slippery=False +) # remove the slippery from the env +agent = MyAgentQLearning( + env, exploration_rate=0.25, learning_rate=0.8, discount_factor=0.95 +) +info = agent.fit(100000) # Agent's training print("----------") -print(agent.q_table) #display the q_table content +print(agent.q_table) # display the q_table content print("----------") -env = RecordVideo(env, video_folder="./", name_prefix="FrozenLake_no_slippery") #wrap the env to save the video output -observation, info = env.reset() #initialize the environment +env = RecordVideo( + env, video_folder="./", name_prefix="FrozenLake_no_slippery" +) # wrap the env to save the video output +observation, info = env.reset() # initialize the environment for tt in range(3000): - action = agent.policy(observation,explo=False) #use the agent's policy to choose the next action (without exploration) - observation, reward, terminated, truncated, info = env.step(action) #do the action + action = agent.policy( + observation, explo=False + ) # use the agent's policy to choose the next action (without exploration) + observation, reward, terminated, truncated, info = env.step(action) # do the action done = terminated or truncated if done: - break #stop if the environement is done + break # stop if the environement is done env.close() ``` @@ -402,7 +424,7 @@ env.close() Moviepy - Building video /FrozenLake_no_slippery-episode-0.mp4. Moviepy - Writing video /FrozenLake_no_slippery-episode-0.mp4 -Moviepy - Done ! +Moviepy - Done ! Moviepy - video ready /FrozenLake_no_slippery-episode-0.mp4 0.7 @@ -419,4 +441,4 @@ Moviepy - video ready /FrozenLake_no_slippery-episode-0.mp4 ## Use experimentManager This is one of the core element in rlberry. The ExperimentManager allow you to easily make an experiment between an Agent and an Environment. It's use to train, optimize hyperparameters, evaluate and gather statistics about an agent. -You can find the guide for ExperimentManager [here](experimentManager_page). \ No newline at end of file +You can find the guide for ExperimentManager [here](experimentManager_page). From 9e7fef843cb01a701ba6c6297e4301ca8ead1dfa Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 14 Nov 2023 15:46:44 +0100 Subject: [PATCH 34/80] add logging page --- docs/basics/userguide/logging.md | 93 ++++++++++++++++++++++++++++++++ docs/user_guide2.md | 4 +- 2 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 docs/basics/userguide/logging.md diff --git a/docs/basics/userguide/logging.md b/docs/basics/userguide/logging.md new file mode 100644 index 000000000..d19d0812f --- /dev/null +++ b/docs/basics/userguide/logging.md @@ -0,0 +1,93 @@ +(logging_page)= + +# How to logging your experiment + +To get informations and readable result about the training of your algorithm, you can use different logger. + +## Set rlberry's logger level + +```python +from rlberry.envs import gym_make +from rlberry.agents.torch import PPOAgent +from rlberry.manager import ExperimentManager, evaluate_agents + + +env_id = "CartPole-v1" # Id of the environment + +env_ctor = gym_make # constructor for the env +env_kwargs = dict(id=env_id) # give the id of the env inside the kwargs + + +first_experiment = ExperimentManager( + PPOAgent, # Agent Class + (env_ctor, env_kwargs), # Environment as Tuple(constructor,kwargs) + fit_budget=int(100), # Budget used to call our agent "fit()" + eval_kwargs=dict( + eval_horizon=1000 + ), # Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, # Number of agent instances to fit. + agent_name="PPO_first_experiment" + env_id, # Name of the agent + seed=42, +) + +first_experiment.fit() + +output = evaluate_agents( + [first_experiment], n_simulations=5, plot=False +) # evaluate the experiment on 5 simulations +print(output) +``` + +```none +[INFO] 15:50: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 15:51: ... trained! +[INFO] 15:51: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + PPO_first_experimentCartPole-v1 +0 15.0 +1 16.0 +2 16.0 +3 18.0 +4 15.0 +``` + +As you can see, on the previous output, you have the "[INFO]" output (from [ExperimentManager](rlberry.manager.ExperimentManager)) + + +You can choose the verbosity of your logger + +But, with [rlberry.logging.set_level(level='...')](rlberry.utils.logging.set_level), you can select the level of your logger to choose what type of information you want. +For examle, you can have only the "CRITICAL" information, for this add this lines on top of the previous code, then run it again : +```python +import rlberry +rlberry.utils.logging.set_level(level='CRITICAL') +``` + +```none + PPO_first_experimentCartPole-v1 +0 15.0 +1 16.0 +2 16.0 +3 18.0 +4 15.0 +``` +As you can see, on the previous output, you don't have the "INFO" output anymore (because it's not a "CRITICAL" output) + + + +## Writer +To keep informations during and after the experiment, rlberry use a 'writer'. The writer is stored inside the [Agent](agent_page), and is updated in its fit() function. + +By default (with the [Agent interface](agent_page)), the writer is [DefaultWriter](rlberry.utils.writers.DefaultWriter). + +To keep informations about the environment inside the writer, you can wrap the environment inside [WriterWrapper](rlberry.wrappers.WriterWrapper). + + +To get the data, saved during an experiment, in a Pandas DataFrame, you can use [plot_writer_data](rlberry.manager.plot_writer_data) on the [ExperimentManager](rlberry.manager.ExperimentManager) (or a list of them). +Example [here](../../auto_examples/demo_bandits/plot_mirror_bandit). + +To plot the data, saved during an experiment, you can use [plot_writer_data](rlberry.manager.plot_writer_data) on the [ExperimentManager](rlberry.manager.ExperimentManager) (or a list of them). +Example [here](../../auto_examples/plot_writer_wrapper). + + + diff --git a/docs/user_guide2.md b/docs/user_guide2.md index 3fdd6646d..f38c52737 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -14,7 +14,7 @@ Some text about an experiment: a comparison of 2 rl agents on a given environmen This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). [(Wikipedia)](https://en.wikipedia.org/wiki/Reinforcement_learning) The environment is typically stated in the form of a Markov decision process (MDP). You can find the guide for Environment [here](environment_page). -Some text about MDPs.(?) +Some text about MDPs.(?) ### Agent In Reinforcement learning, the Agent is the entity to train to solve an environment. It's able interact with the environment: observe, take actions, and learn through trial and error. You can find the guide for Agent [here](agent_page). @@ -23,6 +23,8 @@ You can find the guide for Agent [here](agent_page). This is one of the core element in rlberry. The ExperimentManager allow you to easily make an experiment between an Agent and an Environment. It's use to train, optimize hyperparameters, evaluate and gather statistics about an agent. You can find the guide for ExperimentManager [here](experimentManager_page). ### Logging +Logging is used to keep a trace of the experiments. It's include runing informations, data, and results. +You can find the guide for Logging [here](logging_page). ### Analyse the results ## Experimenting with Deep agents ### Torch Agents From cb71225fc8c2a91967cadff84782e93022d79c85 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 15:08:40 +0000 Subject: [PATCH 35/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .github/workflows/preview.yml | 4 ++-- docs/basics/userguide/logging.md | 24 +++++++++++------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index c568ef9a7..17cbae857 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -47,7 +47,7 @@ jobs: - name: Install and configure Poetry uses: snok/install-poetry@v1 - + - name: Install dependencies and build doc run: | set +e @@ -56,7 +56,7 @@ jobs: poetry run sphinx-build docs ../_build echo "exitcode=$?" >> $GITHUB_ENV cd .. - + - uses: actions/checkout@v4 with: # This is necessary so that we have the tags. diff --git a/docs/basics/userguide/logging.md b/docs/basics/userguide/logging.md index d19d0812f..616df75dd 100644 --- a/docs/basics/userguide/logging.md +++ b/docs/basics/userguide/logging.md @@ -38,11 +38,11 @@ output = evaluate_agents( print(output) ``` -```none -[INFO] 15:50: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. -[INFO] 15:51: ... trained! -[INFO] 15:51: Evaluating PPO_first_experimentCartPole-v1... -[INFO] Evaluation:..... Evaluation finished +```none +[INFO] 15:50: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 15:51: ... trained! +[INFO] 15:51: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished PPO_first_experimentCartPole-v1 0 15.0 1 16.0 @@ -54,13 +54,14 @@ print(output) As you can see, on the previous output, you have the "[INFO]" output (from [ExperimentManager](rlberry.manager.ExperimentManager)) -You can choose the verbosity of your logger +You can choose the verbosity of your logger But, with [rlberry.logging.set_level(level='...')](rlberry.utils.logging.set_level), you can select the level of your logger to choose what type of information you want. For examle, you can have only the "CRITICAL" information, for this add this lines on top of the previous code, then run it again : -```python +```python import rlberry -rlberry.utils.logging.set_level(level='CRITICAL') + +rlberry.utils.logging.set_level(level="CRITICAL") ``` ```none @@ -83,11 +84,8 @@ By default (with the [Agent interface](agent_page)), the writer is [DefaultWrite To keep informations about the environment inside the writer, you can wrap the environment inside [WriterWrapper](rlberry.wrappers.WriterWrapper). -To get the data, saved during an experiment, in a Pandas DataFrame, you can use [plot_writer_data](rlberry.manager.plot_writer_data) on the [ExperimentManager](rlberry.manager.ExperimentManager) (or a list of them). +To get the data, saved during an experiment, in a Pandas DataFrame, you can use [plot_writer_data](rlberry.manager.plot_writer_data) on the [ExperimentManager](rlberry.manager.ExperimentManager) (or a list of them). Example [here](../../auto_examples/demo_bandits/plot_mirror_bandit). -To plot the data, saved during an experiment, you can use [plot_writer_data](rlberry.manager.plot_writer_data) on the [ExperimentManager](rlberry.manager.ExperimentManager) (or a list of them). +To plot the data, saved during an experiment, you can use [plot_writer_data](rlberry.manager.plot_writer_data) on the [ExperimentManager](rlberry.manager.ExperimentManager) (or a list of them). Example [here](../../auto_examples/plot_writer_wrapper). - - - From 72452c41673601201419d886c216abc9d8d150e1 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 14 Nov 2023 16:16:32 +0100 Subject: [PATCH 36/80] update tests to be run --- .../agents/torch/tests/test_torch_training.py | 50 ++++++++++--------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/rlberry/agents/torch/tests/test_torch_training.py b/rlberry/agents/torch/tests/test_torch_training.py index fe5fb722c..d55bd2084 100644 --- a/rlberry/agents/torch/tests/test_torch_training.py +++ b/rlberry/agents/torch/tests/test_torch_training.py @@ -4,29 +4,31 @@ from rlberry.agents.torch.utils.models import default_policy_net_fn # loss_function_factory -assert isinstance(loss_function_factory("l2"), torch.nn.MSELoss) -assert isinstance(loss_function_factory("l1"), torch.nn.L1Loss) -assert isinstance(loss_function_factory("smooth_l1"), torch.nn.SmoothL1Loss) -assert isinstance(loss_function_factory("bce"), torch.nn.BCELoss) +def test_loss_function_factory(): + assert isinstance(loss_function_factory("l2"), torch.nn.MSELoss) + assert isinstance(loss_function_factory("l1"), torch.nn.L1Loss) + assert isinstance(loss_function_factory("smooth_l1"), torch.nn.SmoothL1Loss) + assert isinstance(loss_function_factory("bce"), torch.nn.BCELoss) # optimizer_factory -env = get_benchmark_env(level=1) -assert ( - optimizer_factory(default_policy_net_fn(env).parameters(), "ADAM").defaults["lr"] - == 0.001 -) -assert optimizer_factory(default_policy_net_fn(env).parameters(), "ADAM").defaults[ - "betas" -] == (0.9, 0.999) -assert ( - optimizer_factory(default_policy_net_fn(env).parameters(), "RMS_PROP").defaults[ - "lr" - ] - == 0.01 -) -assert ( - optimizer_factory(default_policy_net_fn(env).parameters(), "RMS_PROP").defaults[ - "alpha" - ] - == 0.99 -) +def test_optimizer_factory(): + env = get_benchmark_env(level=1) + assert ( + optimizer_factory(default_policy_net_fn(env).parameters(), "ADAM").defaults["lr"] + == 0.001 + ) + assert optimizer_factory(default_policy_net_fn(env).parameters(), "ADAM").defaults[ + "betas" + ] == (0.9, 0.999) + assert ( + optimizer_factory(default_policy_net_fn(env).parameters(), "RMS_PROP").defaults[ + "lr" + ] + == 0.01 + ) + assert ( + optimizer_factory(default_policy_net_fn(env).parameters(), "RMS_PROP").defaults[ + "alpha" + ] + == 0.99 + ) From 7f2ecbdf3987f37873ab30371f5238e7713c147b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 15:21:27 +0000 Subject: [PATCH 37/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/agents/torch/tests/test_torch_training.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rlberry/agents/torch/tests/test_torch_training.py b/rlberry/agents/torch/tests/test_torch_training.py index d55bd2084..0fe61a880 100644 --- a/rlberry/agents/torch/tests/test_torch_training.py +++ b/rlberry/agents/torch/tests/test_torch_training.py @@ -3,6 +3,7 @@ from rlberry.envs.benchmarks.ball_exploration.ball2d import get_benchmark_env from rlberry.agents.torch.utils.models import default_policy_net_fn + # loss_function_factory def test_loss_function_factory(): assert isinstance(loss_function_factory("l2"), torch.nn.MSELoss) @@ -10,11 +11,14 @@ def test_loss_function_factory(): assert isinstance(loss_function_factory("smooth_l1"), torch.nn.SmoothL1Loss) assert isinstance(loss_function_factory("bce"), torch.nn.BCELoss) + # optimizer_factory def test_optimizer_factory(): env = get_benchmark_env(level=1) assert ( - optimizer_factory(default_policy_net_fn(env).parameters(), "ADAM").defaults["lr"] + optimizer_factory(default_policy_net_fn(env).parameters(), "ADAM").defaults[ + "lr" + ] == 0.001 ) assert optimizer_factory(default_policy_net_fn(env).parameters(), "ADAM").defaults[ From b8a198a0987e71b0bd88c6807e2681e570707c6f Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 24 Nov 2023 09:28:56 +0100 Subject: [PATCH 38/80] move import inside def _make_tuple_env(env): to avoid circular import on other checks --- rlberry/utils/check_agent.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rlberry/utils/check_agent.py b/rlberry/utils/check_agent.py index d0fc9e961..4a8d59342 100644 --- a/rlberry/utils/check_agent.py +++ b/rlberry/utils/check_agent.py @@ -1,5 +1,3 @@ -from rlberry_research.envs import Chain, Pendulum -from rlberry_research.envs.benchmarks.ball_exploration import PBall2D from rlberry.manager import ExperimentManager import numpy as np from rlberry.seeding import set_external_seed @@ -20,15 +18,18 @@ def _make_tuple_env(env): env, str ): # If env param is a str, we use the corresponding "by default" env, and return it as tuple if env == "continuous_state": + from rlberry_research.envs.benchmarks.ball_exploration import PBall2D env_ctor = PBall2D env_kwargs = {} elif env == "discrete_state": + from rlberry_research.envs import Chain env_ctor = Chain env_kwargs = {} elif env == "vectorized_env_continuous": env_ctor = gym_make env_kwargs = dict(id="CartPole-v1") elif env == "continuous_action": + from rlberry_research.envs import Pendulum env_ctor = Pendulum env_kwargs = {} else: From 2a458d7cd1eb2e0a36297ba343a64f14a8ff21fd Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 24 Nov 2023 09:29:59 +0100 Subject: [PATCH 39/80] update the 2 quickstarts with the new module separation (research/scool/main) --- docs/basics/DeepRLTutorial/TutorialDeepRL.md | 4 ++-- docs/basics/quick_start_rl/quickstart.md | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/basics/DeepRLTutorial/TutorialDeepRL.md b/docs/basics/DeepRLTutorial/TutorialDeepRL.md index 71e28cb52..c366429b9 100644 --- a/docs/basics/DeepRLTutorial/TutorialDeepRL.md +++ b/docs/basics/DeepRLTutorial/TutorialDeepRL.md @@ -12,8 +12,8 @@ Imports ```python from rlberry.envs import gym_make from rlberry.manager import plot_writer_data, ExperimentManager, evaluate_agents -from rlberry.agents.torch import A2CAgent -from rlberry.agents.torch.utils.training import model_factory_from_env +from rlberry_research.agents.torch import A2CAgent +from rlberry_research.agents.torch.utils.training import model_factory_from_env ``` Reminder of the RL setting diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 8cf564835..77659cb9e 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -16,8 +16,9 @@ Importing required libraries import numpy as np import pandas as pd import time -from rlberry.agents import UCBVIAgent, AgentWithSimplePolicy -from rlberry.envs import Chain +from rlberry.agents import AgentWithSimplePolicy +from rlberry_scool.agents import UCBVIAgent +from rlberry_research.envs import Chain from rlberry.manager import ( ExperimentManager, evaluate_agents, From bef16c084fdee8a5b2566ae3768e89d2ba79c8b9 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 24 Nov 2023 11:26:01 +0100 Subject: [PATCH 40/80] Update the (begin of the) userguide with the new module separation (research/scool/main) --- docs/basics/userguide/agent.md | 10 ++++++---- docs/basics/userguide/environment.md | 14 ++++++++------ docs/basics/userguide/experimentManager.md | 11 ++++++++--- docs/basics/userguide/logging.md | 8 ++++---- docs/user_guide2.md | 4 ++++ 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/docs/basics/userguide/agent.md b/docs/basics/userguide/agent.md index 4afd968bc..634bf2750 100644 --- a/docs/basics/userguide/agent.md +++ b/docs/basics/userguide/agent.md @@ -6,11 +6,12 @@ In rlberry, you can use existing Agent, or create your own custom Agent. You can ## Load rlberry Agent -An agent need an environment to train. We'll use the same environment as in the [environment](environment_page) section of the user guide. +An agent need an environment to train. We'll use the same environment as in the [environment](environment_page) section of the user guide. +("Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)") ### without agent ```python -from rlberry.envs.finite import Chain +from rlberry_research.envs.finite import Chain env = Chain(10, 0.1) env.enable_rendering() @@ -33,10 +34,11 @@ If we use random actions on this environment, we don't have good results (the cr ### With agent With the same environment, we will use an Agent to choose the actions instead of random actions. +For this example, you can use "ValueIterationAgent" Agent from "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)" ```python -from rlberry.envs.finite import Chain -from rlberry.agents.dynprog import ValueIterationAgent +from rlberry_research.envs.finite import Chain +from rlberry_scool.agents.dynprog import ValueIterationAgent env = Chain(10, 0.1) # same env agent = ValueIterationAgent(env, gamma=0.95) # creation of the agent diff --git a/docs/basics/userguide/environment.md b/docs/basics/userguide/environment.md index 942b2cece..8416a1f57 100644 --- a/docs/basics/userguide/environment.md +++ b/docs/basics/userguide/environment.md @@ -6,8 +6,10 @@ This is the world with which the agent interacts. The agent can observe this env ## Load rlberry environment +You can find some environments in our other projects "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" and "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)". +For this example, you can load "Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" ```python -from rlberry.envs.finite import Chain +from rlberry_research.envs.finite import Chain env = Chain(10, 0.1) env.enable_rendering() @@ -80,7 +82,7 @@ video:10kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ov ## Load Gymnasium environment -Gymnasium can give you some classic environment. You can load theme with [gym_make](rlberry.envs.gym_make). More information [here](https://www.gymlibrary.dev/environments/classic_control/). +Gymnasium can give you some classic environment. You can load theme with [gym_make](rlberry.envs.gym_make). More information [here](https://gymnasium.farama.org/environments/classic_control/). ```python from rlberry.envs import gym_make @@ -121,9 +123,9 @@ Moviepy - video ready [your path]/MountainCar-episode-0.mp4 ## Load Atari environment -A set of Atari 2600 environment simulated through Stella and the Arcade Learning Environment. More information [here](https://www.gymlibrary.dev/environments/atari/index.html#atari). +A set of Atari 2600 environment simulated through Stella and the Arcade Learning Environment. More information [here](https://gymnasium.farama.org/environments/atari/). -[atari_make](rlberry.envs.atari_make) add wrappers on gym.make, to make it easier to use on Atari games. +The function "[atari_make()](rlberry.envs.atari_make)" add wrappers on gym.make, to make it easier to use on Atari games. ```python from rlberry.envs import atari_make @@ -175,6 +177,6 @@ Moviepy - video ready [your path]/Breakout-episode-0.mp4 You need to create a new class that inherits from [gymnasium.Env](https://gymnasium.farama.org/api/env/) or one of it child class like [Model](rlberry.envs.interface.Model) (and RenderInterface/one of it child class, if you want an environment with rendering). -Then you need to make the specific functions that respect gymnasium template (as step, reset, ...). More information [here](https://www.gymlibrary.dev/content/environment_creation/) +Then you need to make the specific functions that respect gymnasium template (as step, reset, ...). More information [here](https://gymnasium.farama.org/tutorials/gymnasium_basics/environment_creation/) -You can find examples in "sources" of [Acrobot](rlberry.envs.Acrobot), [MountainCar](rlberry.envs.classic_control.MountainCar) or [Chain](rlberry.envs.finite.Chain) (and their parent classes). +You can find examples in our other github project "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" with [Acrobot](https://github.com/rlberry-py/rlberry-research/blob/main/rlberry_research/envs/classic_control/acrobot.py), [MountainCar](https://github.com/rlberry-py/rlberry-research/blob/main/rlberry_research/envs/classic_control/mountain_car.py) or [Chain](https://github.com/rlberry-py/rlberry-research/blob/main/rlberry_research/envs/finite/chain.py) (and their parent classes). diff --git a/docs/basics/userguide/experimentManager.md b/docs/basics/userguide/experimentManager.md index 6e793d13a..0736cc67b 100644 --- a/docs/basics/userguide/experimentManager.md +++ b/docs/basics/userguide/experimentManager.md @@ -4,13 +4,15 @@ It's the element that allow you to make your experiments on [Agent](agent_page) and [Environment](environment_page). You can use it to train, optimize hyperparameters, evaluate, compare, and gather statistics about your agent on a specific environment. You can find the API doc [here](rlberry.manager.ExperimentManager). -It's not the only solution, but it's the compact (and recommended) way of experiment with an agent. +It's not the only solution, but it's the compact (and recommended) way of experiment with an agent. + +For these examples, you will use the "PPO" torch agent from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" ## Create your experiment ```python from rlberry.envs import gym_make -from rlberry.agents.torch import PPOAgent +from rlberry_research.agents.torch import PPOAgent from rlberry.manager import ExperimentManager, evaluate_agents @@ -117,6 +119,9 @@ If you want to see the output video of the trained Agent, you need to use the Re **warning :** You have to do it on the eval environment, or you may have videos during the fit of your Agent. ```python +from rlberry.envs import PipelineEnv +from gymnasium.wrappers.record_video import RecordVideo + env_id = "CartPole-v1" env_ctor = gym_make # constructor for training env env_kwargs = dict(id=env_id) # kwars for training env @@ -192,7 +197,7 @@ Now an example with some more settings. (check the [API](rlberry.manager.Experim ```python from rlberry.envs import gym_make -from rlberry.agents.torch import PPOAgent +from rlberry_research.agents.torch import PPOAgent from rlberry.manager import ExperimentManager, evaluate_agents diff --git a/docs/basics/userguide/logging.md b/docs/basics/userguide/logging.md index 616df75dd..6e7bc4d05 100644 --- a/docs/basics/userguide/logging.md +++ b/docs/basics/userguide/logging.md @@ -2,13 +2,13 @@ # How to logging your experiment -To get informations and readable result about the training of your algorithm, you can use different logger. - +To get informations and readable result about the training of your algorithm, you can use different logger. ## Set rlberry's logger level +For this examples, you will use the "PPO" torch agent from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" ```python from rlberry.envs import gym_make -from rlberry.agents.torch import PPOAgent +from rlberry_research.agents.torch import PPOAgent from rlberry.manager import ExperimentManager, evaluate_agents @@ -79,7 +79,7 @@ As you can see, on the previous output, you don't have the "INFO" output anymore ## Writer To keep informations during and after the experiment, rlberry use a 'writer'. The writer is stored inside the [Agent](agent_page), and is updated in its fit() function. -By default (with the [Agent interface](agent_page)), the writer is [DefaultWriter](rlberry.utils.writers.DefaultWriter). +By default (with the [Agent interface](rlberry.agents.Agent)), the writer is [DefaultWriter](rlberry.utils.writers.DefaultWriter). To keep informations about the environment inside the writer, you can wrap the environment inside [WriterWrapper](rlberry.wrappers.WriterWrapper). diff --git a/docs/user_guide2.md b/docs/user_guide2.md index f38c52737..3076ea6ac 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -8,6 +8,10 @@ the core ExperimentManager (add ref), rlberry provides the user with a set of ba deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). + +To run all the examples, you will need to install "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" and "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)" too. (Add some code with the best solution poetry?, pip?, git link ??? ) + + ## Set up an experiment Some text about an experiment: a comparison of 2 rl agents on a given environment. ### Environment From f8ba38768cbcdd70f34ef461f35afa52c5c6d12b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:26:39 +0000 Subject: [PATCH 41/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/basics/userguide/agent.md | 2 +- docs/basics/userguide/environment.md | 2 +- docs/basics/userguide/experimentManager.md | 2 +- docs/basics/userguide/logging.md | 2 +- rlberry/utils/check_agent.py | 3 +++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/basics/userguide/agent.md b/docs/basics/userguide/agent.md index 634bf2750..d9ed4e2a1 100644 --- a/docs/basics/userguide/agent.md +++ b/docs/basics/userguide/agent.md @@ -6,7 +6,7 @@ In rlberry, you can use existing Agent, or create your own custom Agent. You can ## Load rlberry Agent -An agent need an environment to train. We'll use the same environment as in the [environment](environment_page) section of the user guide. +An agent need an environment to train. We'll use the same environment as in the [environment](environment_page) section of the user guide. ("Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)") ### without agent diff --git a/docs/basics/userguide/environment.md b/docs/basics/userguide/environment.md index 8416a1f57..192f4864f 100644 --- a/docs/basics/userguide/environment.md +++ b/docs/basics/userguide/environment.md @@ -6,7 +6,7 @@ This is the world with which the agent interacts. The agent can observe this env ## Load rlberry environment -You can find some environments in our other projects "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" and "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)". +You can find some environments in our other projects "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" and "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)". For this example, you can load "Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" ```python from rlberry_research.envs.finite import Chain diff --git a/docs/basics/userguide/experimentManager.md b/docs/basics/userguide/experimentManager.md index 0736cc67b..166ef5c3a 100644 --- a/docs/basics/userguide/experimentManager.md +++ b/docs/basics/userguide/experimentManager.md @@ -4,7 +4,7 @@ It's the element that allow you to make your experiments on [Agent](agent_page) and [Environment](environment_page). You can use it to train, optimize hyperparameters, evaluate, compare, and gather statistics about your agent on a specific environment. You can find the API doc [here](rlberry.manager.ExperimentManager). -It's not the only solution, but it's the compact (and recommended) way of experiment with an agent. +It's not the only solution, but it's the compact (and recommended) way of experiment with an agent. For these examples, you will use the "PPO" torch agent from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" diff --git a/docs/basics/userguide/logging.md b/docs/basics/userguide/logging.md index 6e7bc4d05..e038f7ce4 100644 --- a/docs/basics/userguide/logging.md +++ b/docs/basics/userguide/logging.md @@ -2,7 +2,7 @@ # How to logging your experiment -To get informations and readable result about the training of your algorithm, you can use different logger. +To get informations and readable result about the training of your algorithm, you can use different logger. ## Set rlberry's logger level For this examples, you will use the "PPO" torch agent from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" diff --git a/rlberry/utils/check_agent.py b/rlberry/utils/check_agent.py index 4a8d59342..8c433d66d 100644 --- a/rlberry/utils/check_agent.py +++ b/rlberry/utils/check_agent.py @@ -19,10 +19,12 @@ def _make_tuple_env(env): ): # If env param is a str, we use the corresponding "by default" env, and return it as tuple if env == "continuous_state": from rlberry_research.envs.benchmarks.ball_exploration import PBall2D + env_ctor = PBall2D env_kwargs = {} elif env == "discrete_state": from rlberry_research.envs import Chain + env_ctor = Chain env_kwargs = {} elif env == "vectorized_env_continuous": @@ -30,6 +32,7 @@ def _make_tuple_env(env): env_kwargs = dict(id="CartPole-v1") elif env == "continuous_action": from rlberry_research.envs import Pendulum + env_ctor = Pendulum env_kwargs = {} else: From 790c9f92d5c7dba21c29d8b80cd34522a12a2ca8 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 24 Nov 2023 15:25:15 +0100 Subject: [PATCH 42/80] Update the example with the new module separation (research/scool/main) --- examples/demo_agents/demo_SAC.py | 4 ++-- examples/demo_agents/video_plot_dqn.py | 2 +- examples/demo_agents/video_plot_mdqn.py | 2 +- examples/demo_agents/video_plot_rs_kernel_ucbvi.py | 4 ++-- examples/demo_agents/video_plot_rsucbvi.py | 4 ++-- examples/demo_agents/video_plot_vi.py | 2 +- .../demo_env/example_atari_atlantis_vectorized_ppo.py | 4 ++-- .../demo_env/example_atari_breakout_vectorized_ppo.py | 4 ++-- examples/demo_env/video_plot_acrobot.py | 4 ++-- examples/demo_env/video_plot_apple_gold.py | 2 +- examples/demo_env/video_plot_atari_freeway.py | 4 ++-- examples/demo_env/video_plot_gridworld.py | 2 +- examples/demo_env/video_plot_mountain_car.py | 4 ++-- ...ideo_plot_old_gym_compatibility_wrapper_old_acrobot.py | 2 +- examples/demo_env/video_plot_springcartpole.py | 6 +++--- examples/demo_experiment/params_experiment.yaml | 8 ++++---- examples/demo_experiment/rsucbvi_alternative.yaml | 2 +- examples/demo_experiment/run.py | 4 ++-- examples/demo_network/run_client.py | 6 +++--- examples/demo_network/run_remote_manager.py | 6 +++--- examples/demo_network/run_server.py | 5 +++-- long_tests/rl_agent/ltest_mbqvi_applegold.py | 4 ++-- long_tests/torch_agent/ltest_a2c_cartpole.py | 4 ++-- long_tests/torch_agent/ltest_ctn_ppo_a2c_pendulum.py | 2 +- long_tests/torch_agent/ltest_dqn_montaincar.py | 2 +- long_tests/torch_agent/ltest_dqn_vs_mdqn_acrobot.py | 4 ++-- 26 files changed, 49 insertions(+), 48 deletions(-) diff --git a/examples/demo_agents/demo_SAC.py b/examples/demo_agents/demo_SAC.py index 83ad063cb..6c05d4c63 100644 --- a/examples/demo_agents/demo_SAC.py +++ b/examples/demo_agents/demo_SAC.py @@ -9,8 +9,8 @@ import time import gymnasium as gym -from rlberry.agents.torch.sac import SACAgent -from rlberry.envs import Pendulum +from rlberry_research.agents.torch.sac import SACAgent +from rlberry_research.envs import Pendulum from rlberry.manager import AgentManager diff --git a/examples/demo_agents/video_plot_dqn.py b/examples/demo_agents/video_plot_dqn.py index fd8e91f36..814278acf 100644 --- a/examples/demo_agents/video_plot_dqn.py +++ b/examples/demo_agents/video_plot_dqn.py @@ -23,7 +23,7 @@ from rlberry.envs import gym_make from torch.utils.tensorboard import SummaryWriter -from rlberry.agents.torch.dqn import DQNAgent +from rlberry_research.agents.torch.dqn import DQNAgent from rlberry.utils.logging import configure_logging from gymnasium.wrappers.record_video import RecordVideo diff --git a/examples/demo_agents/video_plot_mdqn.py b/examples/demo_agents/video_plot_mdqn.py index d1f84f449..2160142c3 100644 --- a/examples/demo_agents/video_plot_mdqn.py +++ b/examples/demo_agents/video_plot_mdqn.py @@ -23,7 +23,7 @@ from rlberry.envs import gym_make from torch.utils.tensorboard import SummaryWriter -from rlberry.agents.torch.dqn import MunchausenDQNAgent +from rlberry_research.agents.torch.dqn import MunchausenDQNAgent from rlberry.utils.logging import configure_logging from gymnasium.wrappers.record_video import RecordVideo diff --git a/examples/demo_agents/video_plot_rs_kernel_ucbvi.py b/examples/demo_agents/video_plot_rs_kernel_ucbvi.py index 8a012d274..abd322e29 100644 --- a/examples/demo_agents/video_plot_rs_kernel_ucbvi.py +++ b/examples/demo_agents/video_plot_rs_kernel_ucbvi.py @@ -11,8 +11,8 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_rs_kernel_ucbvi.jpg' -from rlberry.envs import Acrobot -from rlberry.agents import RSKernelUCBVIAgent +from rlberry_research.envs import Acrobot +from rlberry_research.agents import RSKernelUCBVIAgent from rlberry.wrappers import RescaleRewardWrapper env = Acrobot() diff --git a/examples/demo_agents/video_plot_rsucbvi.py b/examples/demo_agents/video_plot_rsucbvi.py index 0ea30caf0..354474cbd 100644 --- a/examples/demo_agents/video_plot_rsucbvi.py +++ b/examples/demo_agents/video_plot_rsucbvi.py @@ -11,8 +11,8 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_rsucbvi.jpg' -from rlberry.agents import RSUCBVIAgent -from rlberry.envs.classic_control import MountainCar +from rlberry_research.agents import RSUCBVIAgent +from rlberry_research.envs.classic_control import MountainCar env = MountainCar() horizon = 170 diff --git a/examples/demo_agents/video_plot_vi.py b/examples/demo_agents/video_plot_vi.py index 65f4e4b8f..bca4b28a7 100644 --- a/examples/demo_agents/video_plot_vi.py +++ b/examples/demo_agents/video_plot_vi.py @@ -11,7 +11,7 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_vi.jpg' -from rlberry_research.agents.dynprog import ValueIterationAgent +from rlberry_scool.agents.dynprog import ValueIterationAgent from rlberry_research.envs.finite import Chain env = Chain() diff --git a/examples/demo_env/example_atari_atlantis_vectorized_ppo.py b/examples/demo_env/example_atari_atlantis_vectorized_ppo.py index 6fc1c187b..33f27c4f2 100644 --- a/examples/demo_env/example_atari_atlantis_vectorized_ppo.py +++ b/examples/demo_env/example_atari_atlantis_vectorized_ppo.py @@ -16,12 +16,12 @@ from rlberry.manager import ExperimentManager from datetime import datetime -from rlberry.agents.torch import PPOAgent +from rlberry_research.agents.torch import PPOAgent from gymnasium.wrappers.record_video import RecordVideo import shutil import os from rlberry.envs.gym_make import atari_make -from rlberry.agents.torch.utils.training import model_factory_from_env +from rlberry_research.agents.torch.utils.training import model_factory_from_env initial_time = datetime.now() diff --git a/examples/demo_env/example_atari_breakout_vectorized_ppo.py b/examples/demo_env/example_atari_breakout_vectorized_ppo.py index d96221dc3..fd112df0f 100644 --- a/examples/demo_env/example_atari_breakout_vectorized_ppo.py +++ b/examples/demo_env/example_atari_breakout_vectorized_ppo.py @@ -16,12 +16,12 @@ from rlberry.manager import ExperimentManager from datetime import datetime -from rlberry.agents.torch import PPOAgent +from rlberry_research.agents.torch import PPOAgent from gymnasium.wrappers.record_video import RecordVideo import shutil import os from rlberry.envs.gym_make import atari_make -from rlberry.agents.torch.utils.training import model_factory_from_env +from rlberry_research.agents.torch.utils.training import model_factory_from_env initial_time = datetime.now() diff --git a/examples/demo_env/video_plot_acrobot.py b/examples/demo_env/video_plot_acrobot.py index 45aa18a4d..db23804a7 100644 --- a/examples/demo_env/video_plot_acrobot.py +++ b/examples/demo_env/video_plot_acrobot.py @@ -11,8 +11,8 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_acrobot.jpg' -from rlberry.envs import Acrobot -from rlberry.agents import RSUCBVIAgent +from rlberry_research.envs import Acrobot +from rlberry_research.agents import RSUCBVIAgent from rlberry.wrappers import RescaleRewardWrapper env = Acrobot() diff --git a/examples/demo_env/video_plot_apple_gold.py b/examples/demo_env/video_plot_apple_gold.py index 9e6eb34c6..1f939b40b 100644 --- a/examples/demo_env/video_plot_apple_gold.py +++ b/examples/demo_env/video_plot_apple_gold.py @@ -11,7 +11,7 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_apple_gold.jpg' from rlberry_research.envs.benchmarks.grid_exploration.apple_gold import AppleGold -from rlberry_research.agents.dynprog import ValueIterationAgent +from rlberry_scool.agents.dynprog import ValueIterationAgent env = AppleGold(reward_free=False, array_observation=False) diff --git a/examples/demo_env/video_plot_atari_freeway.py b/examples/demo_env/video_plot_atari_freeway.py index f8e22f2f9..e9e17b648 100644 --- a/examples/demo_env/video_plot_atari_freeway.py +++ b/examples/demo_env/video_plot_atari_freeway.py @@ -16,7 +16,7 @@ from rlberry.manager import ExperimentManager from datetime import datetime -from rlberry.agents.torch.dqn.dqn import DQNAgent +from rlberry_research.agents.torch.dqn.dqn import DQNAgent from gymnasium.wrappers.record_video import RecordVideo import shutil import os @@ -54,7 +54,7 @@ ), ), # The Environment to solve. init_kwargs=dict( # Where to put the agent's hyperparameters - q_net_constructor="rlberry.agents.torch.utils.training.model_factory_from_env", + q_net_constructor="rlberry_research.agents.torch.utils.training.model_factory_from_env", q_net_kwargs=cnn_configs, max_replay_size=50000, batch_size=32, diff --git a/examples/demo_env/video_plot_gridworld.py b/examples/demo_env/video_plot_gridworld.py index 872b46fbb..01ef4f233 100644 --- a/examples/demo_env/video_plot_gridworld.py +++ b/examples/demo_env/video_plot_gridworld.py @@ -12,7 +12,7 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_gridworld.jpg' -from rlberry_research.agents.dynprog import ValueIterationAgent +from rlberry_scool.agents.dynprog import ValueIterationAgent from rlberry_research.envs.finite import GridWorld diff --git a/examples/demo_env/video_plot_mountain_car.py b/examples/demo_env/video_plot_mountain_car.py index 42ff1d497..011fb8691 100644 --- a/examples/demo_env/video_plot_mountain_car.py +++ b/examples/demo_env/video_plot_mountain_car.py @@ -10,8 +10,8 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_montain_car.jpg' -from rlberry.agents.mbqvi import MBQVIAgent -from rlberry.envs.classic_control import MountainCar +from rlberry_scool.agents.mbqvi import MBQVIAgent +from rlberry_research.envs.classic_control import MountainCar from rlberry.wrappers import DiscretizeStateWrapper _env = MountainCar() diff --git a/examples/demo_env/video_plot_old_gym_compatibility_wrapper_old_acrobot.py b/examples/demo_env/video_plot_old_gym_compatibility_wrapper_old_acrobot.py index 90f3eb11b..fff06ce51 100644 --- a/examples/demo_env/video_plot_old_gym_compatibility_wrapper_old_acrobot.py +++ b/examples/demo_env/video_plot_old_gym_compatibility_wrapper_old_acrobot.py @@ -12,7 +12,7 @@ from rlberry.wrappers.tests.old_env.old_acrobot import Old_Acrobot -from rlberry.agents import RSUCBVIAgent +from rlberry_research.agents import RSUCBVIAgent from rlberry.wrappers import RescaleRewardWrapper from rlberry.wrappers.gym_utils import OldGymCompatibilityWrapper diff --git a/examples/demo_env/video_plot_springcartpole.py b/examples/demo_env/video_plot_springcartpole.py index 7669ef62a..24ae6478a 100644 --- a/examples/demo_env/video_plot_springcartpole.py +++ b/examples/demo_env/video_plot_springcartpole.py @@ -13,8 +13,8 @@ """ # sphinx_gallery_thumbnail_path = 'thumbnails/video_plot_springcartpole.jpg' -from rlberry.envs.classic_control import SpringCartPole -from rlberry.agents.torch import DQNAgent +from rlberry_research.envs.classic_control import SpringCartPole +from rlberry_research.agents.torch import DQNAgent from gymnasium.wrappers.time_limit import TimeLimit model_configs = { @@ -24,7 +24,7 @@ } init_kwargs = dict( - q_net_constructor="rlberry.agents.torch.utils.training.model_factory_from_env", + q_net_constructor="rlberry_research.agents.torch.utils.training.model_factory_from_env", q_net_kwargs=model_configs, ) diff --git a/examples/demo_experiment/params_experiment.yaml b/examples/demo_experiment/params_experiment.yaml index c1899ef38..08cc68b83 100644 --- a/examples/demo_experiment/params_experiment.yaml +++ b/examples/demo_experiment/params_experiment.yaml @@ -5,8 +5,8 @@ # """ description: 'RSUCBVI in NRoom' seed: 123 -train_env: 'examples/demo_examples/demo_experiment/room.yaml' -eval_env: 'examples/demo_examples/demo_experiment/room.yaml' +train_env: 'examples/demo_experiment/room.yaml' +eval_env: 'examples/demo_experiment/room.yaml' agents: - - 'examples/demo_examples/demo_experiment/rsucbvi.yaml' - - 'examples/demo_examples/demo_experiment/rsucbvi_alternative.yaml' + - 'examples/demo_experiment/rsucbvi.yaml' + - 'examples/demo_experiment/rsucbvi_alternative.yaml' diff --git a/examples/demo_experiment/rsucbvi_alternative.yaml b/examples/demo_experiment/rsucbvi_alternative.yaml index ce1b71826..8fc5b0d22 100644 --- a/examples/demo_experiment/rsucbvi_alternative.yaml +++ b/examples/demo_experiment/rsucbvi_alternative.yaml @@ -3,6 +3,6 @@ # Demo: rsucbvi_alternative.yaml # ===================== # """ -base_config: 'examples/demo_examples/demo_experiment/rsucbvi.yaml' +base_config: 'examples/demo_experiment/rsucbvi.yaml' init_kwargs: gamma: 0.9 diff --git a/examples/demo_experiment/run.py b/examples/demo_experiment/run.py index 87741dd66..a6da381c8 100644 --- a/examples/demo_experiment/run.py +++ b/examples/demo_experiment/run.py @@ -4,11 +4,11 @@ ===================== To run the experiment: -$ python examples/demo_examples/demo_experiment/run.py examples/demo_examples/demo_experiment/params_experiment.yaml +$ python examples/demo_experiment/run.py examples/demo_experiment/params_experiment.yaml To see more options: -$ python examples/demo_examples/demo_experiment/run.py +$ python examples/demo_experiment/run.py """ from rlberry.experiment import load_experiment_results diff --git a/examples/demo_network/run_client.py b/examples/demo_network/run_client.py index 5098f5311..d86222fe1 100644 --- a/examples/demo_network/run_client.py +++ b/examples/demo_network/run_client.py @@ -3,9 +3,9 @@ Demo: run_client ===================== """ -from rlberry.network.client import BerryClient -from rlberry.network import interface -from rlberry.network.interface import Message, ResourceRequest +from rlberry_research.network.client import BerryClient +from rlberry_research.network import interface +from rlberry_research.network.interface import Message, ResourceRequest import numpy as np diff --git a/examples/demo_network/run_remote_manager.py b/examples/demo_network/run_remote_manager.py index 83df52486..4cde939ed 100644 --- a/examples/demo_network/run_remote_manager.py +++ b/examples/demo_network/run_remote_manager.py @@ -4,10 +4,10 @@ ===================== """ from rlberry.envs.gym_make import gym_make -from rlberry.network.client import BerryClient -from rlberry.network.interface import ResourceRequest +from rlberry_research.network.client import BerryClient +from rlberry_research.network.interface import ResourceRequest -from rlberry.agents.torch import REINFORCEAgent +from rlberry_research.agents.torch import REINFORCEAgent from rlberry.manager import ExperimentManager, MultipleManagers, RemoteExperimentManager from rlberry.manager.evaluation import evaluate_agents, plot_writer_data diff --git a/examples/demo_network/run_server.py b/examples/demo_network/run_server.py index a8b9b04c7..1d1573db2 100644 --- a/examples/demo_network/run_server.py +++ b/examples/demo_network/run_server.py @@ -5,9 +5,10 @@ """ from rlberry_research.network.interface import ResourceItem from rlberry_research.network.server import BerryServer -from rlberry.agents import ValueIterationAgent +from rlberry_scool.agents import ValueIterationAgent from rlberry_research.agents.torch import REINFORCEAgent, A2CAgent -from rlberry_research.envs import GridWorld, gym_make +from rlberry_research.envs import GridWorld +from rlberry.envs import gym_make from rlberry.utils.writers import DefaultWriter if __name__ == "__main__": diff --git a/long_tests/rl_agent/ltest_mbqvi_applegold.py b/long_tests/rl_agent/ltest_mbqvi_applegold.py index 5aa85aa25..7f8f88e68 100644 --- a/long_tests/rl_agent/ltest_mbqvi_applegold.py +++ b/long_tests/rl_agent/ltest_mbqvi_applegold.py @@ -1,5 +1,5 @@ -from rlberry.envs.benchmarks.grid_exploration.apple_gold import AppleGold -from rlberry.agents.mbqvi import MBQVIAgent +from rlberry_research.envs.benchmarks.grid_exploration.apple_gold import AppleGold +from rlberry_scool.agents.mbqvi import MBQVIAgent from rlberry.manager import ExperimentManager, evaluate_agents import numpy as np diff --git a/long_tests/torch_agent/ltest_a2c_cartpole.py b/long_tests/torch_agent/ltest_a2c_cartpole.py index ce22dc0f3..634cd03ab 100644 --- a/long_tests/torch_agent/ltest_a2c_cartpole.py +++ b/long_tests/torch_agent/ltest_a2c_cartpole.py @@ -1,7 +1,7 @@ from rlberry.envs import gym_make -from rlberry.agents.torch import A2CAgent +from rlberry_research.agents.torch import A2CAgent from rlberry.manager import ExperimentManager -from rlberry.agents.torch.utils.training import model_factory_from_env +from rlberry_research.agents.torch.utils.training import model_factory_from_env import numpy as np # Using parameters from deeprl quick start diff --git a/long_tests/torch_agent/ltest_ctn_ppo_a2c_pendulum.py b/long_tests/torch_agent/ltest_ctn_ppo_a2c_pendulum.py index 01b10b29f..8a9dc114d 100644 --- a/long_tests/torch_agent/ltest_ctn_ppo_a2c_pendulum.py +++ b/long_tests/torch_agent/ltest_ctn_ppo_a2c_pendulum.py @@ -1,5 +1,5 @@ from rlberry.envs import gym_make -from rlberry.agents.torch import A2CAgent, PPOAgent +from rlberry_research.agents.torch import A2CAgent, PPOAgent from rlberry.manager import ExperimentManager, plot_writer_data, evaluate_agents import seaborn as sns import matplotlib.pyplot as plt diff --git a/long_tests/torch_agent/ltest_dqn_montaincar.py b/long_tests/torch_agent/ltest_dqn_montaincar.py index 553fc9580..aeb526de0 100644 --- a/long_tests/torch_agent/ltest_dqn_montaincar.py +++ b/long_tests/torch_agent/ltest_dqn_montaincar.py @@ -1,5 +1,5 @@ from rlberry.envs import gym_make -from rlberry.agents.torch import DQNAgent +from rlberry_research.agents.torch import DQNAgent from rlberry.manager import ExperimentManager, evaluate_agents import numpy as np diff --git a/long_tests/torch_agent/ltest_dqn_vs_mdqn_acrobot.py b/long_tests/torch_agent/ltest_dqn_vs_mdqn_acrobot.py index 9d17ea936..fff12aa09 100644 --- a/long_tests/torch_agent/ltest_dqn_vs_mdqn_acrobot.py +++ b/long_tests/torch_agent/ltest_dqn_vs_mdqn_acrobot.py @@ -1,6 +1,6 @@ from rlberry.envs import gym_make -from rlberry.agents.torch import DQNAgent -from rlberry.agents.torch import MunchausenDQNAgent as MDQNAgent +from rlberry_research.agents.torch import DQNAgent +from rlberry_research.agents.torch import MunchausenDQNAgent as MDQNAgent from rlberry.manager import ExperimentManager, evaluate_agents, plot_writer_data import matplotlib.pyplot as plt import seaborn as sns From 8bf748efe50eedc3c05c5a38d500404be3c42aca Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 28 Nov 2023 10:47:17 +0100 Subject: [PATCH 43/80] update Dummy agent to improve coverage --- rlberry/utils/tests/test_writer.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/rlberry/utils/tests/test_writer.py b/rlberry/utils/tests/test_writer.py index 504301800..a7f04c8b1 100644 --- a/rlberry/utils/tests/test_writer.py +++ b/rlberry/utils/tests/test_writer.py @@ -21,6 +21,8 @@ def fit(self, budget, **kwargs): for ii in range(budget): if self.writer is not None: self.writer.add_scalar("a", ii, ii) + scalar_dict = dict(multi1=1, multi2=2) + self.writer.add_scalars("multi_scalar_test", scalar_dict) time.sleep(1) return None @@ -41,12 +43,17 @@ def test_myoutput(capsys): # or use "capfd" for fd-level n_fit=1, default_writer_kwargs={"log_interval": 1}, ) - agent.fit(budget=3) + budget_size = 22 + agent.fit(budget=budget_size) assert agent.agent_handlers[0].writer.summary_writer == None - assert list(agent.agent_handlers[0].writer.read_tag_value("a")) == [0, 1, 2] + assert list(agent.agent_handlers[0].writer.read_tag_value("a")) == list( + range(budget_size) + ) assert agent.agent_handlers[0].writer.read_first_tag_value("a") == 0 - assert agent.agent_handlers[0].writer.read_last_tag_value("a") == 2 + assert ( + agent.agent_handlers[0].writer.read_last_tag_value("a") == budget_size - 1 + ) # start at 0 captured = capsys.readouterr() # test that what is written to stderr is longer than 50 char, From b6a0c11a69696e78e58dc2abbc8292fd97911c32 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 28 Nov 2023 17:03:28 +0100 Subject: [PATCH 44/80] update introduction from Userguide --- docs/user_guide2.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/user_guide2.md b/docs/user_guide2.md index 3076ea6ac..c652ad771 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -3,13 +3,18 @@ # User Guide ## Introduction -Welcome to rlberry. Use rlberry's ExperimentManager (add ref) to train, evaluate and compare rl agents. In addition to -the core ExperimentManager (add ref), rlberry provides the user with a set of bandit (add ref), tabular rl (add ref), and -deep rl agents (add ref) as well as a wrapper for stablebaselines3 (add link, and ref) agents. -Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging (add refs). -In this user guide, we take you through the core features of rlberry and illustrate them with examples (add ref) and API documentation (add ref). +Welcome to rlberry. +Use rlberry's [ExperimentManager](experimentManager_page) to train, evaluate and compare rl agents. +Like other popular rl libraries, rlberry also provides basic tools for plotting, multiprocessing and logging . In this user guide, we take you through the core features of rlberry and illustrate them with [examples](/auto_examples/index) and [API documentation](/api) . -To run all the examples, you will need to install "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" and "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)" too. (Add some code with the best solution poetry?, pip?, git link ??? ) +To run all the examples, you will need to install "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" and "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)" too. + + + [rlberry-research](https://github.com/rlberry-py/rlberry-research) : + It's the repository where our research team keeps some agents, environments, or tools compatible with rlberry. It's a permanent "work in progress" repository, and some code may be not maintained anymore. + +[rlberry-scool](https://github.com/rlberry-py/rlberry-scool) : +It's the repository used for teaching purposes. These are mainly agents or very basic environments, in a version that makes it easier for students to learn. ## Set up an experiment From 320b2f3f79c4e8314ff96005ff2395d6a950f543 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 29 Nov 2023 16:21:04 +0100 Subject: [PATCH 45/80] add link to the userguide --- docs/index.rst | 2 +- docs/user_guide2.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index 0db9f3f4e..3b21a3ff1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -29,7 +29,7 @@ In addition, rlberry_: * Provides **implementations of several RL agents** for you to use as a starting point or as baselines; * Provides a set of **benchmark environments**, very useful to debug and challenge your algorithms; * Handles all random seeds for you, ensuring **reproducibility** of your results; -* Is **fully compatible with** several commonly used RL libraries like `Gymnasium `_ and `Stable Baselines `_. +* Is **fully compatible with** several commonly used RL libraries like `Gymnasium `_ and `Stable Baselines `_ (see :ref:`userguide/agents`). diff --git a/docs/user_guide2.md b/docs/user_guide2.md index c652ad771..a1df32b1d 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -38,7 +38,7 @@ You can find the guide for Logging [here](logging_page). ## Experimenting with Deep agents ### Torch Agents ### Policy and Value Networks -### Stable Baselines 3 + ## Experimenting with Bandits. ## Reproducibility ### Seeding From ebb74517b07cd39baab1ac702df7ab8166bdb99d Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 30 Nov 2023 11:12:25 +0100 Subject: [PATCH 46/80] add initial userguide for seeding --- docs/basics/userguide/seeding.md | 196 +++++++++++++++++++++++++++++++ docs/user_guide2.md | 3 + 2 files changed, 199 insertions(+) create mode 100644 docs/basics/userguide/seeding.md diff --git a/docs/basics/userguide/seeding.md b/docs/basics/userguide/seeding.md new file mode 100644 index 000000000..0785108e2 --- /dev/null +++ b/docs/basics/userguide/seeding.md @@ -0,0 +1,196 @@ +(seeding_page)= + +# How to seed your experiment + +Rlberry has a class [Seeder](rlberry.seeding.seeder.Seeder) that conveniently wraps a [NumPy SeedSequence](https://numpy.org/doc/stable/reference/random/parallel.html), and allows you to create independent random number generators for different objects and threads, using a single [Seeder](rlberry.seeding.seeder.Seeder) instance. It works as follows: + +## Basics +Suppose you want generate 5 random Integer between 0 and 9. + +If you run this code many time, you should have different outputs. +```python +from rlberry.seeding import Seeder + +seeder = Seeder() + +result_list = [] +for _ in range(5): + result_list.append(seeder.rng.integers(10)) +print(result_list) +``` + +run 1 : +```none +[9, 3, 4, 8, 4] +``` +run 2 : +```none +[2, 0, 6, 3, 9] +``` +run 3 : +```none +[7, 3, 8, 1, 1] +``` + + +But if you fix the seed as follow, and run it many time... You should have the same 'random' numbers every time : +```python +from rlberry.seeding import Seeder + +seeder = Seeder(123) + +result_list = [] +for _ in range(5): + result_list.append(seeder.rng.integers(10)) +print(result_list) +``` + +run 1 : +```none +[9, 1, 0, 7, 4] +``` +run 2 : +```none +[9, 1, 0, 7, 4] +``` +run 3 : +```none +[9, 1, 0, 7, 4] +``` + +## In rlberry + +### classic usage +Each [Seeder](rlberry.seeding.seeder.Seeder) instance has a random number generator (rng), see [here](https://numpy.org/doc/stable/reference/random/generator.html) to check the methods available in rng. + +[Agent](agent_page) and [Environment](environment_page) `reseed(seeder)` functions should use `seeder.spawn()` that allow to create new independent child generators from the same seeder. So it's a good practice to use single seeder to reseed the Agent or Environment, and they will have their own seeder and rng. + +When writing your own agents and inheriting from the Agent class, you should use agent.rng whenever you need to generate random numbers; the same applies to your environments. +This is necessary to ensure reproducibility. + +```python +from rlberry.seeding import Seeder + +seeder = Seeder(123) # seeder initialization + +from rlberry.envs import gym_make +from rlberry_research.agents import RSUCBVIAgent + + +env = gym_make("MountainCar-v0") +env.reseed(seeder) # seeder first use + +agent = RSUCBVIAgent(env) +agent.reseed(seeder) # same seeder + +# check that the generated numbers are differents +print("env seeder: ", env.seeder) +print("random sample 1 from env rng: ", env.rng.normal()) +print("random sample 2 from env rng: ", env.rng.normal()) +print("agent seeder: ", agent.seeder) +print("random sample 1 from agent rng: ", agent.rng.normal()) +print("random sample 2 from agent rng: ", agent.rng.normal()) +``` + +```none +env seeder: Seeder object with: SeedSequence( + entropy=123, + spawn_key=(0, 0), +) +random sample 1 from env rng: -1.567498838741829 +random sample 2 from env rng: 0.6356604305460527 +agent seeder: Seeder object with: SeedSequence( + entropy=123, + spawn_key=(0, 1), + n_children_spawned=2, +) +random sample 1 from agent rng: 1.2466559261185188 +random sample 2 from agent rng: 0.8402527193117317 + +``` + + +### multi-threading +If you want use multi-threading, a seeder can spawn other seeders that are independent from it. +This is useful to seed two different threads, using seeder1 in the first thread, and seeder2 in the second thread. +```python +from rlberry.seeding import Seeder + +seeder = Seeder(123) +seeder1, seeder2 = seeder.spawn(2) + +print("random sample 1 from seeder1 rng: ", seeder1.rng.normal()) +print("random sample 2 from seeder1 rng: ", seeder1.rng.normal()) +print("-----") +print("random sample 1 from seeder2 rng: ", seeder2.rng.normal()) +print("random sample 2 from seeder2 rng: ", seeder2.rng.normal()) +``` +```none +random sample 1 from seeder1 rng: -0.4732958445958833 +random sample 2 from seeder1 rng: 0.5863995575997462 +----- +random sample 1 from seeder2 rng: -0.1722486099076424 +random sample 2 from seeder2 rng: -0.1930990650226178 +``` + + + +## External libraries +You can also use a seeder to seed external libraries (such as torch) using the method `set_external_seed`. +It will be usefull if you want reproducibility with external libraries. In this example, you will use `torch` to generate random numbers. + +If you run this code many time, you should have different outputs. +```python +import torch + +result_list = [] +for i in range(5): + result_list.append(torch.randint(2**32, (1,))[0].item()) + +print(result_list) +``` + +run 1 : +```none +[3817148928, 671396126, 2950680447, 791815335, 3335786391] +``` +run 2 : +```none +[82990446, 2463687945, 1829003305, 647811387, 3543380778] +``` +run 3 : +```none +[3887070615, 363268341, 3607514851, 3881090947, 1018754931] +``` + + + +If you add to this code a [Seeder](rlberry.seeding.seeder.Seeder), use the `set_external_seed` method, and re-run it, you should have the same 'random' numbers everytime. + +```python +import torch +from rlberry.seeding import set_external_seed +from rlberry.seeding import Seeder + +seeder = Seeder(123) + +set_external_seed(seeder) +result_list = [] +for i in range(5): + result_list.append(torch.randint(2**32, (1,))[0].item()) + +print(result_list) +``` + +run 1 : +```none +[693246422, 3606543353, 433394544, 2194426398, 3928404622] +``` +run 2 : +```none +[693246422, 3606543353, 433394544, 2194426398, 3928404622] +``` +run 3 : +```none +[693246422, 3606543353, 433394544, 2194426398, 3928404622] +``` diff --git a/docs/user_guide2.md b/docs/user_guide2.md index a1df32b1d..f8a65424a 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -42,6 +42,9 @@ You can find the guide for Logging [here](logging_page). ## Experimenting with Bandits. ## Reproducibility ### Seeding +In rlberry you can use a seed to generate pseudo-"random number". Most of the time, it allow you to re-run the same algorithm with the same pseudo-"random number", and make your experiment reproducible. +You can find the guide for Seeding [here](seeding_page). + ### Saving and Loading Agents ### Saving and Loading Data ## Advanced Usage From c66f85f80efde2d7db17ccbf933dc7b4e9acd887 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 30 Nov 2023 14:56:16 +0100 Subject: [PATCH 47/80] add ExperimentManager example with(out) seed --- docs/basics/userguide/seeding.md | 182 ++++++++++++++++++++++++++++++- 1 file changed, 181 insertions(+), 1 deletion(-) diff --git a/docs/basics/userguide/seeding.md b/docs/basics/userguide/seeding.md index 0785108e2..01c3755e7 100644 --- a/docs/basics/userguide/seeding.md +++ b/docs/basics/userguide/seeding.md @@ -58,6 +58,8 @@ run 3 : [9, 1, 0, 7, 4] ``` +
+ ## In rlberry ### classic usage @@ -109,6 +111,184 @@ random sample 2 from agent rng: 0.8402527193117317 ``` +
+ +### With ExperimentManager +For this part we will use the same code from the [ExperimentManager](ExperimentManager_page) part. +3 runs without the seeder : + +```python +from rlberry.envs import gym_make +from rlberry_research.agents.torch import PPOAgent +from rlberry.manager import ExperimentManager, evaluate_agents + + +env_id = "CartPole-v1" # Id of the environment + +env_ctor = gym_make # constructor for the env +env_kwargs = dict(id=env_id) # give the id of the env inside the kwargs + + +first_experiment = ExperimentManager( + PPOAgent, # Agent Class + (env_ctor, env_kwargs), # Environment as Tuple(constructor,kwargs) + fit_budget=int(100), # Budget used to call our agent "fit()" + eval_kwargs=dict( + eval_horizon=1000 + ), # Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, # Number of agent instances to fit. + agent_name="PPO_first_experiment" + env_id, # Name of the agent +) + +first_experiment.fit() + +output = evaluate_agents( + [first_experiment], n_simulations=5, plot=False +) # evaluate the experiment on 5 simulations +print(output) +``` + + +Run 1: +```none +[INFO] 14:47: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:47: ... trained! +[INFO] 14:47: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + PPO_first_experimentCartPole-v1 +0 20.8 +1 20.8 +2 21.4 +3 24.3 +4 28.8 +``` + +Run 2 : +```none +[INFO] 14:47: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:47: ... trained! +[INFO] 14:47: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + PPO_first_experimentCartPole-v1 +0 25.0 +1 19.3 +2 28.5 +3 26.1 +4 19.0 +``` + +Run 3 : +```none +[INFO] 14:47: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:47: ... trained! +[INFO] 14:47: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + PPO_first_experimentCartPole-v1 +0 23.6 +1 19.2 +2 20.5 +3 19.8 +4 16.5 +``` + + +
+ +**Without the seeder, the outputs are different (non-reproducible).** + +
+ +3 runs with the seeder : + +```python +from rlberry.envs import gym_make +from rlberry_research.agents.torch import PPOAgent +from rlberry.manager import ExperimentManager, evaluate_agents + +from rlberry.seeding import Seeder + +seeder = Seeder(42) + +env_id = "CartPole-v1" # Id of the environment + +env_ctor = gym_make # constructor for the env +env_kwargs = dict(id=env_id) # give the id of the env inside the kwargs + + +first_experiment = ExperimentManager( + PPOAgent, # Agent Class + (env_ctor, env_kwargs), # Environment as Tuple(constructor,kwargs) + fit_budget=int(100), # Budget used to call our agent "fit()" + eval_kwargs=dict( + eval_horizon=1000 + ), # Arguments required to call rlberry.agents.agent.Agent.eval(). + n_fit=1, # Number of agent instances to fit. + agent_name="PPO_first_experiment" + env_id, # Name of the agent + seed=seeder, +) + +first_experiment.fit() + +output = evaluate_agents( + [first_experiment], n_simulations=5, plot=False +) # evaluate the experiment on 5 simulations +print(output) +``` + +Run 1: +```none +[INFO] 14:46: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:46: ... trained! +[INFO] 14:46: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + PPO_first_experimentCartPole-v1 +0 23.3 +1 19.7 +2 23.0 +3 18.8 +4 19.7 +``` + +Run 2 : +```none +[INFO] 14:46: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:46: ... trained! +[INFO] 14:46: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + PPO_first_experimentCartPole-v1 +0 23.3 +1 19.7 +2 23.0 +3 18.8 +4 19.7 +``` + + +Run 3 : +```none +[INFO] 14:46: Running ExperimentManager fit() for PPO_first_experimentCartPole-v1 with n_fit = 1 and max_workers = None. +[INFO] 14:46: ... trained! +[INFO] 14:46: Evaluating PPO_first_experimentCartPole-v1... +[INFO] Evaluation:..... Evaluation finished + PPO_first_experimentCartPole-v1 +0 23.3 +1 19.7 +2 23.0 +3 18.8 +4 19.7 +``` + + +
+ + +**With the seeder, the outputs are the same (reproducible).** + + +
+ + + ### multi-threading If you want use multi-threading, a seeder can spawn other seeders that are independent from it. @@ -133,7 +313,7 @@ random sample 1 from seeder2 rng: -0.1722486099076424 random sample 2 from seeder2 rng: -0.1930990650226178 ``` - +
## External libraries You can also use a seeder to seed external libraries (such as torch) using the method `set_external_seed`. From 86274a708f348bd61fc7bf12c11ea8e5c8856c88 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 30 Nov 2023 15:13:26 +0100 Subject: [PATCH 48/80] word update --- docs/basics/userguide/agent.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/basics/userguide/agent.md b/docs/basics/userguide/agent.md index d9ed4e2a1..03e8ec79b 100644 --- a/docs/basics/userguide/agent.md +++ b/docs/basics/userguide/agent.md @@ -5,7 +5,7 @@ In Reinforcement learning, the Agent is the entity to train to solve an environm In rlberry, you can use existing Agent, or create your own custom Agent. You can find the API [here](/api) and [here](rlberry.agents.Agent) . -## Load rlberry Agent +## Use rlberry Agent An agent need an environment to train. We'll use the same environment as in the [environment](environment_page) section of the user guide. ("Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)") @@ -128,8 +128,8 @@ The agent has learned how to obtain good results (the cross go to the right). -## Load StableBaselines3 as rlberry Agent -With rlberry, you can load algorithm from [StableBaselines3](https://stable-baselines3.readthedocs.io/en/master/guide/algos.html) and wrap it in rlberry Agent. To do that, you need to use [StableBaselinesAgent](rlberry.agents.stable_baselines.StableBaselinesAgent). +## Use StableBaselines3 as rlberry Agent +With rlberry, you can use algorithm from [StableBaselines3](https://stable-baselines3.readthedocs.io/en/master/guide/algos.html) and wrap it in rlberry Agent. To do that, you need to use [StableBaselinesAgent](rlberry.agents.stable_baselines.StableBaselinesAgent). ```python From ca573ac022212e689e6731ca08d0614b3b9b0db1 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 30 Nov 2023 15:40:11 +0100 Subject: [PATCH 49/80] word update --- docs/basics/userguide/environment.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/basics/userguide/environment.md b/docs/basics/userguide/environment.md index 192f4864f..fe8406df6 100644 --- a/docs/basics/userguide/environment.md +++ b/docs/basics/userguide/environment.md @@ -2,12 +2,12 @@ # How to use an environment -This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). With rlberry, you can load an existing environment, or create your own custom environment. +This is the world with which the agent interacts. The agent can observe this environment, and can perform actions to modify it (but cannot change its rules). With rlberry, you can use an existing environment, or create your own custom environment. -## Load rlberry environment +## Use rlberry environment You can find some environments in our other projects "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" and "[rlberry-scool](https://github.com/rlberry-py/rlberry-scool)". -For this example, you can load "Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" +For this example, you can use "Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" ```python from rlberry_research.envs.finite import Chain @@ -81,8 +81,8 @@ video:10kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ov -## Load Gymnasium environment -Gymnasium can give you some classic environment. You can load theme with [gym_make](rlberry.envs.gym_make). More information [here](https://gymnasium.farama.org/environments/classic_control/). +## Use Gymnasium environment +Gymnasium can give you some classic environment. You can use theme with [gym_make](rlberry.envs.gym_make). More information [here](https://gymnasium.farama.org/environments/classic_control/). ```python from rlberry.envs import gym_make @@ -122,7 +122,7 @@ Moviepy - video ready [your path]/MountainCar-episode-0.mp4 -## Load Atari environment +## Use Atari environment A set of Atari 2600 environment simulated through Stella and the Arcade Learning Environment. More information [here](https://gymnasium.farama.org/environments/atari/). The function "[atari_make()](rlberry.envs.atari_make)" add wrappers on gym.make, to make it easier to use on Atari games. From fc7cb113fddfd250364990903e0d3ff097281d06 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Mon, 4 Dec 2023 15:43:41 +0100 Subject: [PATCH 50/80] update poetry after update on rlberry-scool --- poetry.lock | 860 +++++++++++++++++++++++++--------------------------- 1 file changed, 408 insertions(+), 452 deletions(-) diff --git a/poetry.lock b/poetry.lock index 9f1db6b27..f1af250b3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "absl-py" @@ -61,13 +61,13 @@ test = ["gym (>=0.23,<1.0)", "pytest (>=7.0)"] [[package]] name = "alembic" -version = "1.12.1" +version = "1.13.0" description = "A database migration tool for SQLAlchemy." optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "alembic-1.12.1-py3-none-any.whl", hash = "sha256:47d52e3dfb03666ed945becb723d6482e52190917fdb47071440cfdba05d92cb"}, - {file = "alembic-1.12.1.tar.gz", hash = "sha256:bca5877e9678b454706347bc10b97cb7d67f300320fa5c3a94423e8266e2823f"}, + {file = "alembic-1.13.0-py3-none-any.whl", hash = "sha256:a23974ea301c3ee52705db809c7413cecd165290c6679b9998dd6c74342ca23a"}, + {file = "alembic-1.13.0.tar.gz", hash = "sha256:ab4b3b94d2e1e5f81e34be8a9b7b7575fc9dd5398fccb0bef351ec9b14872623"}, ] [package.dependencies] @@ -76,7 +76,7 @@ SQLAlchemy = ">=1.3.0" typing-extensions = ">=4" [package.extras] -tz = ["python-dateutil"] +tz = ["backports.zoneinfo"] [[package]] name = "autorom" @@ -191,13 +191,13 @@ files = [ [[package]] name = "certifi" -version = "2023.7.22" +version = "2023.11.17" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, + {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, ] [[package]] @@ -335,35 +335,6 @@ files = [ {file = "cloudpickle-3.0.0.tar.gz", hash = "sha256:996d9a482c6fb4f33c1a35335cf8afd065d2a56e973270364840712d9131a882"}, ] -[[package]] -name = "cmake" -version = "3.27.7" -description = "CMake is an open-source, cross-platform family of tools designed to build, test and package software" -optional = true -python-versions = "*" -files = [ - {file = "cmake-3.27.7-py2.py3-none-macosx_10_10_universal2.macosx_10_10_x86_64.macosx_11_0_arm64.macosx_11_0_universal2.whl", hash = "sha256:d582ef3e9ff0bd113581c1a32e881d1c2f9a34d2de76c93324a28593a76433db"}, - {file = "cmake-3.27.7-py2.py3-none-manylinux2010_i686.manylinux_2_12_i686.whl", hash = "sha256:8056c99e371ff57229df2068364d7c32fea716cb53b4675f639edfb62663decf"}, - {file = "cmake-3.27.7-py2.py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:68983b09de633fc1ce6ab6bce9a25bfa181e41598e7c6bc0a6c0108773ee01cb"}, - {file = "cmake-3.27.7-py2.py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8bd1e1fa4fc8de7605c663d9408dceb649112f855aab05cca31fdb72e4d78364"}, - {file = "cmake-3.27.7-py2.py3-none-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:c981aafcca2cd7210bd210ec75710c0f34e1fde1998cdcab812e4133e3ab615d"}, - {file = "cmake-3.27.7-py2.py3-none-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1b9067ce0251cba3d4c018f2e1577ba9078e9c1eff6ad607ad5ce867843d4571"}, - {file = "cmake-3.27.7-py2.py3-none-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b8a2fcb619b89d1cce7b52828316de9a1f27f0c90c2e39d1eae886428c8ee8c6"}, - {file = "cmake-3.27.7-py2.py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:499b38c77d52fb1964dbb38d0228fed246263a181939a8e753fde8ca227c8e1e"}, - {file = "cmake-3.27.7-py2.py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:2fb48c780f1a6a3d19e785ebbb754be79d369e25a1cb81043fab049e709564da"}, - {file = "cmake-3.27.7-py2.py3-none-musllinux_1_1_i686.whl", hash = "sha256:7bf96237ba11ce2437dc5e071d96b510120a1be4708c631a64b2f38fb46bbd77"}, - {file = "cmake-3.27.7-py2.py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:009058bdf4f488709f38eaa5dd0ef0f89c6b9c6b6edd9d5b475a308ef75f80bb"}, - {file = "cmake-3.27.7-py2.py3-none-musllinux_1_1_s390x.whl", hash = "sha256:591f6b056527aefec009bc61a388776b2fc62444deb0038112a471031f61aeca"}, - {file = "cmake-3.27.7-py2.py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:bd40d46dbad3555d5b3ce054bef24b85f256b19139493773751ab6f2b71c1219"}, - {file = "cmake-3.27.7-py2.py3-none-win32.whl", hash = "sha256:bdbf0256f554f68c7b1d9740f5d059daf875b685c81a479cbe69038e84eb2fb9"}, - {file = "cmake-3.27.7-py2.py3-none-win_amd64.whl", hash = "sha256:810e592b606d05a3080a9c19ea839b13226f62cae447a22485b2365782f6b926"}, - {file = "cmake-3.27.7-py2.py3-none-win_arm64.whl", hash = "sha256:72289361866314f73be2ae63ddee224ff70223dcef9feb66d0072bf17e245564"}, - {file = "cmake-3.27.7.tar.gz", hash = "sha256:9f4a7c7be2a25de5901f045618f41b833ea6c0f647115201d38e4fdf7e2815bc"}, -] - -[package.extras] -test = ["coverage (>=4.2)", "flake8 (>=3.0.4)", "path.py (>=11.5.0)", "pytest (>=3.0.3)", "pytest-cov (>=2.4.0)", "pytest-runner (>=2.9)", "pytest-virtualenv (>=1.7.0)", "scikit-build (>=0.10.0)", "setuptools (>=28.0.0)", "virtualenv (>=15.0.3)", "wheel"] - [[package]] name = "codecov" version = "2.1.13" @@ -392,13 +363,13 @@ files = [ [[package]] name = "colorlog" -version = "6.7.0" +version = "6.8.0" description = "Add colours to the output of Python's logging module." optional = true python-versions = ">=3.6" files = [ - {file = "colorlog-6.7.0-py2.py3-none-any.whl", hash = "sha256:0d33ca236784a1ba3ff9c532d4964126d8a2c44f1f0cb1d2b0728196f512f662"}, - {file = "colorlog-6.7.0.tar.gz", hash = "sha256:bd94bd21c1e13fac7bd3153f4bc3a7dc0eb0974b8bc2fdf1a989e474f6e582e5"}, + {file = "colorlog-6.8.0-py3-none-any.whl", hash = "sha256:4ed23b05a1154294ac99f511fabe8c1d6d4364ec1f7fc989c7fb515ccc29d375"}, + {file = "colorlog-6.8.0.tar.gz", hash = "sha256:fbb6fdf9d5685f2517f388fb29bb27d54e8654dd31f58bc2a3b217e967a95ca6"}, ] [package.dependencies] @@ -608,13 +579,13 @@ files = [ [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -666,53 +637,53 @@ typing = ["typing-extensions (>=4.8)"] [[package]] name = "fonttools" -version = "4.44.0" +version = "4.46.0" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1cd1c6bb097e774d68402499ff66185190baaa2629ae2f18515a2c50b93db0c"}, - {file = "fonttools-4.44.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9eab7f9837fdaa2a10a524fbcc2ec24bf60637c044b6e4a59c3f835b90f0fae"}, - {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f412954275e594f7a51c16f3b3edd850acb0d842fefc33856b63a17e18499a5"}, - {file = "fonttools-4.44.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50d25893885e80a5955186791eed5579f1e75921751539cc1dc3ffd1160b48cf"}, - {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:22ea8aa7b3712450b42b044702bd3a64fd118006bad09a6f94bd1b227088492e"}, - {file = "fonttools-4.44.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df40daa6c03b98652ffe8110ae014fe695437f6e1cb5a07e16ea37f40e73ac86"}, - {file = "fonttools-4.44.0-cp310-cp310-win32.whl", hash = "sha256:bca49da868e8bde569ef36f0cc1b6de21d56bf9c3be185c503b629c19a185287"}, - {file = "fonttools-4.44.0-cp310-cp310-win_amd64.whl", hash = "sha256:dbac86d83d96099890e731cc2af97976ff2c98f4ba432fccde657c5653a32f1c"}, - {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e8ff7d19a6804bfd561cfcec9b4200dd1788e28f7de4be70189801530c47c1b3"}, - {file = "fonttools-4.44.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8a1fa9a718de0bc026979c93e1e9b55c5efde60d76f91561fd713387573817d"}, - {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05064f95aacdfc06f21e55096c964b2228d942b8675fa26995a2551f6329d2d"}, - {file = "fonttools-4.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31b38528f25bc662401e6ffae14b3eb7f1e820892fd80369a37155e3b636a2f4"}, - {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:05d7c4d2c95b9490e669f3cb83918799bf1c838619ac6d3bad9ea017cfc63f2e"}, - {file = "fonttools-4.44.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6999e80a125b0cd8e068d0210b63323f17338038c2ecd2e11b9209ec430fe7f2"}, - {file = "fonttools-4.44.0-cp311-cp311-win32.whl", hash = "sha256:a7aec7f5d14dfcd71fb3ebc299b3f000c21fdc4043079101777ed2042ba5b7c5"}, - {file = "fonttools-4.44.0-cp311-cp311-win_amd64.whl", hash = "sha256:518a945dbfe337744bfff31423c1430303b8813c5275dffb0f2577f0734a1189"}, - {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:59b6ad83cce067d10f4790c037a5904424f45bebb5e7be2eb2db90402f288267"}, - {file = "fonttools-4.44.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c2de1fb18198acd400c45ffe2aef5420c8d55fde903e91cba705596099550f3b"}, - {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84f308b7a8d28208d54315d11d35f9888d6d607673dd4d42d60b463682ee0400"}, - {file = "fonttools-4.44.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:66bc6efd829382f7a7e6cf33c2fb32b13edc8a239eb15f32acbf197dce7a0165"}, - {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a8b99713d3a0d0e876b6aecfaada5e7dc9fe979fcd90ef9fa0ba1d9b9aed03f2"}, - {file = "fonttools-4.44.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b63da598d9cbc52e2381f922da0e94d60c0429f92207bd3fb04d112fc82ea7cb"}, - {file = "fonttools-4.44.0-cp312-cp312-win32.whl", hash = "sha256:f611c97678604e302b725f71626edea113a5745a7fb557c958b39edb6add87d5"}, - {file = "fonttools-4.44.0-cp312-cp312-win_amd64.whl", hash = "sha256:58af428746fa73a2edcbf26aff33ac4ef3c11c8d75bb200eaea2f7e888d2de4e"}, - {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9ee8692e23028564c13d924004495f284df8ac016a19f17a87251210e1f1f928"}, - {file = "fonttools-4.44.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dab3d00d27b1a79ae4d4a240e8ceea8af0ff049fd45f05adb4f860d93744110d"}, - {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f53526668beccdb3409c6055a4ffe50987a7f05af6436fa55d61f5e7bd450219"}, - {file = "fonttools-4.44.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3da036b016c975c2d8c69005bdc4d5d16266f948a7fab950244e0f58301996a"}, - {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b99fe8ef4093f672d00841569d2d05691e50334d79f4d9c15c1265d76d5580d2"}, - {file = "fonttools-4.44.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6d16d9634ff1e5cea2cf4a8cbda9026f766e4b5f30b48f8180f0e99133d3abfc"}, - {file = "fonttools-4.44.0-cp38-cp38-win32.whl", hash = "sha256:3d29509f6e05e8d725db59c2d8c076223d793e4e35773040be6632a0349f2f97"}, - {file = "fonttools-4.44.0-cp38-cp38-win_amd64.whl", hash = "sha256:d4fa4f4bc8fd86579b8cdbe5e948f35d82c0eda0091c399d009b2a5a6b61c040"}, - {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c794de4086f06ae609b71ac944ec7deb09f34ecf73316fddc041087dd24bba39"}, - {file = "fonttools-4.44.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2db63941fee3122e31a21dd0f5b2138ce9906b661a85b63622421d3654a74ae2"}, - {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb01c49c8aa035d5346f46630209923d4927ed15c2493db38d31da9f811eb70d"}, - {file = "fonttools-4.44.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46c79af80a835410874683b5779b6c1ec1d5a285e11c45b5193e79dd691eb111"}, - {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b6e6aa2d066f8dafd06d8d0799b4944b5d5a1f015dd52ac01bdf2895ebe169a0"}, - {file = "fonttools-4.44.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63a3112f753baef8c6ac2f5f574bb9ac8001b86c8c0c0380039db47a7f512d20"}, - {file = "fonttools-4.44.0-cp39-cp39-win32.whl", hash = "sha256:54efed22b2799a85475e6840e907c402ba49892c614565dc770aa97a53621b2b"}, - {file = "fonttools-4.44.0-cp39-cp39-win_amd64.whl", hash = "sha256:2e91e19b583961979e2e5a701269d3cfc07418963bee717f8160b0a24332826b"}, - {file = "fonttools-4.44.0-py3-none-any.whl", hash = "sha256:b9beb0fa6ff3ea808ad4a6962d68ac0f140ddab080957b20d9e268e4d67fb335"}, - {file = "fonttools-4.44.0.tar.gz", hash = "sha256:4e90dd81b6e0d97ebfe52c0d12a17a9ef7f305d6bfbb93081265057d6092f252"}, + {file = "fonttools-4.46.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d4e69e2c7f93b695d2e6f18f709d501d945f65c1d237dafaabdd23cd935a5276"}, + {file = "fonttools-4.46.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:25852f0c63df0af022f698464a4a80f7d1d5bd974bcd22f995f6b4ad198e32dd"}, + {file = "fonttools-4.46.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adab73618d0a328b203a0e242b3eba60a2b5662d9cb2bd16ed9c52af8a7d86af"}, + {file = "fonttools-4.46.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cf923a4a556ab4cc4c52f69a4a2db624cf5a2cf360394368b40c5152fe3321e"}, + {file = "fonttools-4.46.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:87c214197712cc14fd2a4621efce2a9c501a77041232b789568149a8a3161517"}, + {file = "fonttools-4.46.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:156ae342a1ed1fe38e180de471e98fbf5b2b6ae280fa3323138569c4ca215844"}, + {file = "fonttools-4.46.0-cp310-cp310-win32.whl", hash = "sha256:c506e3d3a9e898caee4dc094f34b49c5566870d5a2d1ca2125f0a9f35ecc2205"}, + {file = "fonttools-4.46.0-cp310-cp310-win_amd64.whl", hash = "sha256:f8bc3973ed58893c4107993e0a7ae34901cb572b5e798249cbef35d30801ffd4"}, + {file = "fonttools-4.46.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:982f69855ac258260f51048d9e0c53c5f19881138cc7ca06deb38dc4b97404b6"}, + {file = "fonttools-4.46.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c23c59d321d62588620f2255cf951270bf637d88070f38ed8b5e5558775b86c"}, + {file = "fonttools-4.46.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0e94244ec24a940ecfbe5b31c975c8a575d5ed2d80f9a280ce3b21fa5dc9c34"}, + {file = "fonttools-4.46.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a9f9cdd7ef63d1b8ac90db335762451452426b3207abd79f60da510cea62da5"}, + {file = "fonttools-4.46.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ca9eceebe70035b057ce549e2054cad73e95cac3fe91a9d827253d1c14618204"}, + {file = "fonttools-4.46.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8be6adfa4e15977075278dd0a0bae74dec59be7b969b5ceed93fb86af52aa5be"}, + {file = "fonttools-4.46.0-cp311-cp311-win32.whl", hash = "sha256:7b5636f5706d49f13b6d610fe54ee662336cdf56b5a6f6683c0b803e23d826d2"}, + {file = "fonttools-4.46.0-cp311-cp311-win_amd64.whl", hash = "sha256:49ea0983e55fd7586a809787cd4644a7ae471e53ab8ddc016f9093b400e32646"}, + {file = "fonttools-4.46.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7b460720ce81773da1a3e7cc964c48e1e11942b280619582a897fa0117b56a62"}, + {file = "fonttools-4.46.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8bee9f4fc8c99824a424ae45c789ee8c67cb84f8e747afa7f83b7d3cef439c3b"}, + {file = "fonttools-4.46.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3d7b96aba96e05e8c911ce2dfc5acc6a178b8f44f6aa69371ab91aa587563da"}, + {file = "fonttools-4.46.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e6aeb5c340416d11a3209d75c48d13e72deea9e1517837dd1522c1fd1f17c11"}, + {file = "fonttools-4.46.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c779f8701deedf41908f287aeb775b8a6f59875ad1002b98ac6034ae4ddc1b7b"}, + {file = "fonttools-4.46.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce199227ce7921eaafdd4f96536f16b232d6b580ce74ce337de544bf06cb2752"}, + {file = "fonttools-4.46.0-cp312-cp312-win32.whl", hash = "sha256:1c9937c4dd1061afd22643389445fabda858af5e805860ec3082a4bc07c7a720"}, + {file = "fonttools-4.46.0-cp312-cp312-win_amd64.whl", hash = "sha256:a9fa52ef8fd14d7eb3d813e1451e7ace3e1eebfa9b7237d3f81fee8f3de6a114"}, + {file = "fonttools-4.46.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c94564b1f3b5dd87e73577610d85115b1936edcc596deaf84a31bbe70e17456b"}, + {file = "fonttools-4.46.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4a50a1dfad7f7ba5ca3f99cc73bf5cdac67ceade8e4b355a877521f20ad1b63"}, + {file = "fonttools-4.46.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89c2c520f9492844ecd6316d20c6c7a157b5c0cb73a1411b3db28ee304f30122"}, + {file = "fonttools-4.46.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5b7905fd68eacb7cc56a13139da5c312c45baae6950dd00b02563c54508a041"}, + {file = "fonttools-4.46.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8485cc468288e213f31afdaf1fdda3c79010f542559fbba936a54f4644df2570"}, + {file = "fonttools-4.46.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:87c3299da7da55394fb324349db0ede38114a46aafd0e7dfcabfecd28cdd94c3"}, + {file = "fonttools-4.46.0-cp38-cp38-win32.whl", hash = "sha256:f5f1423a504ccc329efb5aa79738de83d38c072be5308788dde6bd419969d7f5"}, + {file = "fonttools-4.46.0-cp38-cp38-win_amd64.whl", hash = "sha256:6d4a4ebcc76e30898ff3296ea786491c70e183f738319ae2629e0d44f17ece42"}, + {file = "fonttools-4.46.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9a0e422ab79e5cb2b47913be6a4b5fd20c4c7ac34a24f3691a4e099e965e0b8"}, + {file = "fonttools-4.46.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:13ac0cba2fc63fa4b232f2a7971f35f35c6eaf10bd1271fa96d4ce6253a8acfd"}, + {file = "fonttools-4.46.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:795150d5edc595e1a2cfb3d65e8f4f3d027704fc2579f8990d381bef6b188eb6"}, + {file = "fonttools-4.46.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d00fc63131dcac6b25f50a5a129758438317e54e3ce5587163f7058de4b0e933"}, + {file = "fonttools-4.46.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3033b55f401a622de2630b3982234d97219d89b058607b87927eccb0f922313c"}, + {file = "fonttools-4.46.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e26e7fb908ae4f622813e7cb32cd2db6c24e3122bb3b98f25e832a2fe0e7e228"}, + {file = "fonttools-4.46.0-cp39-cp39-win32.whl", hash = "sha256:2d0eba685938c603f2f648dfc0aadbf8c6a4fe1c7ca608c2970a6ef39e00f254"}, + {file = "fonttools-4.46.0-cp39-cp39-win_amd64.whl", hash = "sha256:5200b01f463d97cc2b7ff8a1e3584151f4413e98cb8419da5f17d1dbb84cc214"}, + {file = "fonttools-4.46.0-py3-none-any.whl", hash = "sha256:5b627ed142398ea9202bd752c04311592558964d1a765fb2f78dc441a05633f4"}, + {file = "fonttools-4.46.0.tar.gz", hash = "sha256:2ae45716c27a41807d58a9f3f59983bdc8c0a46cb259e4450ab7e196253a9853"}, ] [package.extras] @@ -729,6 +700,41 @@ ufo = ["fs (>=2.2.0,<3)"] unicode = ["unicodedata2 (>=15.1.0)"] woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] +[[package]] +name = "fsspec" +version = "2023.12.0" +description = "File-system specification" +optional = true +python-versions = ">=3.8" +files = [ + {file = "fsspec-2023.12.0-py3-none-any.whl", hash = "sha256:f807252ee2018f2223760315beb87a2166c2b9532786eeca9e6548dfcf2cfac9"}, + {file = "fsspec-2023.12.0.tar.gz", hash = "sha256:8e0bb2db2a94082968483b7ba2eaebf3949835e2dfdf09243dda387539464b31"}, +] + +[package.extras] +abfs = ["adlfs"] +adl = ["adlfs"] +arrow = ["pyarrow (>=1)"] +dask = ["dask", "distributed"] +devel = ["pytest", "pytest-cov"] +dropbox = ["dropbox", "dropboxdrivefs", "requests"] +full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"] +fuse = ["fusepy"] +gcs = ["gcsfs"] +git = ["pygit2"] +github = ["requests"] +gs = ["gcsfs"] +gui = ["panel"] +hdfs = ["pyarrow (>=1)"] +http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"] +libarchive = ["libarchive-c"] +oci = ["ocifs"] +s3 = ["s3fs"] +sftp = ["paramiko"] +smb = ["smbprotocol"] +ssh = ["paramiko"] +tqdm = ["tqdm"] + [[package]] name = "future" version = "0.18.3" @@ -741,13 +747,13 @@ files = [ [[package]] name = "google-auth" -version = "2.23.4" +version = "2.24.0" description = "Google Authentication Library" optional = true python-versions = ">=3.7" files = [ - {file = "google-auth-2.23.4.tar.gz", hash = "sha256:79905d6b1652187def79d491d6e23d0cbb3a21d3c7ba0dbaa9c8a01906b13ff3"}, - {file = "google_auth-2.23.4-py2.py3-none-any.whl", hash = "sha256:d4bbc92fe4b8bfd2f3e8d88e5ba7085935da208ee38a134fc280e7ce682a05f2"}, + {file = "google-auth-2.24.0.tar.gz", hash = "sha256:2ec7b2a506989d7dbfdbe81cb8d0ead8876caaed14f86d29d34483cbe99c57af"}, + {file = "google_auth-2.24.0-py2.py3-none-any.whl", hash = "sha256:9b82d5c8d3479a5391ea0a46d81cca698d328459da31d4a459d4e901a5d927e0"}, ] [package.dependencies] @@ -852,69 +858,69 @@ test = ["objgraph", "psutil"] [[package]] name = "grpcio" -version = "1.59.2" +version = "1.59.3" description = "HTTP/2-based RPC framework" optional = true python-versions = ">=3.7" files = [ - {file = "grpcio-1.59.2-cp310-cp310-linux_armv7l.whl", hash = "sha256:d2fa68a96a30dd240be80bbad838a0ac81a61770611ff7952b889485970c4c71"}, - {file = "grpcio-1.59.2-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:cf0dead5a2c5a3347af2cfec7131d4f2a2e03c934af28989c9078f8241a491fa"}, - {file = "grpcio-1.59.2-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:e420ced29b5904cdf9ee5545e23f9406189d8acb6750916c2db4793dada065c6"}, - {file = "grpcio-1.59.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b230028a008ae1d0f430acb227d323ff8a619017415cf334c38b457f814119f"}, - {file = "grpcio-1.59.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a4a3833c0e067f3558538727235cd8a49709bff1003200bbdefa2f09334e4b1"}, - {file = "grpcio-1.59.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6b25ed37c27e652db01be341af93fbcea03d296c024d8a0e680017a268eb85dd"}, - {file = "grpcio-1.59.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73abb8584b0cf74d37f5ef61c10722adc7275502ab71789a8fe3cb7ef04cf6e2"}, - {file = "grpcio-1.59.2-cp310-cp310-win32.whl", hash = "sha256:d6f70406695e3220f09cd7a2f879333279d91aa4a8a1d34303b56d61a8180137"}, - {file = "grpcio-1.59.2-cp310-cp310-win_amd64.whl", hash = "sha256:3c61d641d4f409c5ae46bfdd89ea42ce5ea233dcf69e74ce9ba32b503c727e29"}, - {file = "grpcio-1.59.2-cp311-cp311-linux_armv7l.whl", hash = "sha256:3059668df17627f0e0fa680e9ef8c995c946c792612e9518f5cc1503be14e90b"}, - {file = "grpcio-1.59.2-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:72ca2399097c0b758198f2ff30f7178d680de8a5cfcf3d9b73a63cf87455532e"}, - {file = "grpcio-1.59.2-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:c978f864b35f2261e0819f5cd88b9830b04dc51bcf055aac3c601e525a10d2ba"}, - {file = "grpcio-1.59.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9411e24328a2302e279e70cae6e479f1fddde79629fcb14e03e6d94b3956eabf"}, - {file = "grpcio-1.59.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb7e0fe6ad73b7f06d7e2b689c19a71cf5cc48f0c2bf8608469e51ffe0bd2867"}, - {file = "grpcio-1.59.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c2504eed520958a5b77cc99458297cb7906308cb92327f35fb7fbbad4e9b2188"}, - {file = "grpcio-1.59.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2171c39f355ba5b551c5d5928d65aa6c69807fae195b86ef4a7d125bcdb860a9"}, - {file = "grpcio-1.59.2-cp311-cp311-win32.whl", hash = "sha256:d2794f0e68b3085d99b4f6ff9c089f6fdd02b32b9d3efdfbb55beac1bf22d516"}, - {file = "grpcio-1.59.2-cp311-cp311-win_amd64.whl", hash = "sha256:2067274c88bc6de89c278a672a652b4247d088811ece781a4858b09bdf8448e3"}, - {file = "grpcio-1.59.2-cp312-cp312-linux_armv7l.whl", hash = "sha256:535561990e075fa6bd4b16c4c3c1096b9581b7bb35d96fac4650f1181e428268"}, - {file = "grpcio-1.59.2-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:a213acfbf186b9f35803b52e4ca9addb153fc0b67f82a48f961be7000ecf6721"}, - {file = "grpcio-1.59.2-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:6959fb07e8351e20501ffb8cc4074c39a0b7ef123e1c850a7f8f3afdc3a3da01"}, - {file = "grpcio-1.59.2-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e82c5cf1495244adf5252f925ac5932e5fd288b3e5ab6b70bec5593074b7236c"}, - {file = "grpcio-1.59.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:023088764012411affe7db183d1ada3ad9daf2e23ddc719ff46d7061de661340"}, - {file = "grpcio-1.59.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:da2d94c15f88cd40d7e67f7919d4f60110d2b9d5b1e08cf354c2be773ab13479"}, - {file = "grpcio-1.59.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6009386a2df66159f64ac9f20425ae25229b29b9dd0e1d3dd60043f037e2ad7e"}, - {file = "grpcio-1.59.2-cp312-cp312-win32.whl", hash = "sha256:75c6ecb70e809cf1504465174343113f51f24bc61e22a80ae1c859f3f7034c6d"}, - {file = "grpcio-1.59.2-cp312-cp312-win_amd64.whl", hash = "sha256:cbe946b3e6e60a7b4618f091e62a029cb082b109a9d6b53962dd305087c6e4fd"}, - {file = "grpcio-1.59.2-cp37-cp37m-linux_armv7l.whl", hash = "sha256:f8753a6c88d1d0ba64302309eecf20f70d2770f65ca02d83c2452279085bfcd3"}, - {file = "grpcio-1.59.2-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:f1ef0d39bc1feb420caf549b3c657c871cad4ebbcf0580c4d03816b0590de0cf"}, - {file = "grpcio-1.59.2-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:4c93f4abbb54321ee6471e04a00139c80c754eda51064187963ddf98f5cf36a4"}, - {file = "grpcio-1.59.2-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:08d77e682f2bf730a4961eea330e56d2f423c6a9b91ca222e5b1eb24a357b19f"}, - {file = "grpcio-1.59.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ff16d68bf453275466a9a46739061a63584d92f18a0f5b33d19fc97eb69867c"}, - {file = "grpcio-1.59.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4abb717e320e74959517dc8e84a9f48fbe90e9abe19c248541e9418b1ce60acd"}, - {file = "grpcio-1.59.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:36f53c2b3449c015880e7d55a89c992c357f176327b0d2873cdaaf9628a37c69"}, - {file = "grpcio-1.59.2-cp37-cp37m-win_amd64.whl", hash = "sha256:cc3e4cd087f07758b16bef8f31d88dbb1b5da5671d2f03685ab52dece3d7a16e"}, - {file = "grpcio-1.59.2-cp38-cp38-linux_armv7l.whl", hash = "sha256:27f879ae604a7fcf371e59fba6f3ff4635a4c2a64768bd83ff0cac503142fef4"}, - {file = "grpcio-1.59.2-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:7cf05053242f61ba94014dd3a986e11a083400a32664058f80bf4cf817c0b3a1"}, - {file = "grpcio-1.59.2-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:e1727c1c0e394096bb9af185c6923e8ea55a5095b8af44f06903bcc0e06800a2"}, - {file = "grpcio-1.59.2-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d573e70a6fe77555fb6143c12d3a7d3fa306632a3034b4e7c59ca09721546f8"}, - {file = "grpcio-1.59.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31176aa88f36020055ace9adff2405a33c8bdbfa72a9c4980e25d91b2f196873"}, - {file = "grpcio-1.59.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:11168ef43e4a43ff1b1a65859f3e0ef1a173e277349e7fb16923ff108160a8cd"}, - {file = "grpcio-1.59.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:53c9aa5ddd6857c0a1cd0287225a2a25873a8e09727c2e95c4aebb1be83a766a"}, - {file = "grpcio-1.59.2-cp38-cp38-win32.whl", hash = "sha256:3b4368b33908f683a363f376dfb747d40af3463a6e5044afee07cf9436addf96"}, - {file = "grpcio-1.59.2-cp38-cp38-win_amd64.whl", hash = "sha256:0a754aff9e3af63bdc4c75c234b86b9d14e14a28a30c4e324aed1a9b873d755f"}, - {file = "grpcio-1.59.2-cp39-cp39-linux_armv7l.whl", hash = "sha256:1f9524d1d701e399462d2c90ba7c193e49d1711cf429c0d3d97c966856e03d00"}, - {file = "grpcio-1.59.2-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:f93dbf58f03146164048be5426ffde298b237a5e059144847e4940f5b80172c3"}, - {file = "grpcio-1.59.2-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:6da6dea3a1bacf99b3c2187e296db9a83029ed9c38fd4c52b7c9b7326d13c828"}, - {file = "grpcio-1.59.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5f09cffa619adfb44799fa4a81c2a1ad77c887187613fb0a8f201ab38d89ba1"}, - {file = "grpcio-1.59.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c35aa9657f5d5116d23b934568e0956bd50c615127810fffe3ac356a914c176a"}, - {file = "grpcio-1.59.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:74100fecaec8a535e380cf5f2fb556ff84957d481c13e54051c52e5baac70541"}, - {file = "grpcio-1.59.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:128e20f57c5f27cb0157e73756d1586b83c1b513ebecc83ea0ac37e4b0e4e758"}, - {file = "grpcio-1.59.2-cp39-cp39-win32.whl", hash = "sha256:686e975a5d16602dc0982c7c703948d17184bd1397e16c8ee03511ecb8c4cdda"}, - {file = "grpcio-1.59.2-cp39-cp39-win_amd64.whl", hash = "sha256:242adc47725b9a499ee77c6a2e36688fa6c96484611f33b1be4c57ab075a92dd"}, - {file = "grpcio-1.59.2.tar.gz", hash = "sha256:d8f9cd4ad1be90b0cf350a2f04a38a36e44a026cac1e036ac593dc48efe91d52"}, -] - -[package.extras] -protobuf = ["grpcio-tools (>=1.59.2)"] + {file = "grpcio-1.59.3-cp310-cp310-linux_armv7l.whl", hash = "sha256:aca028a6c7806e5b61e5f9f4232432c52856f7fcb98e330b20b6bc95d657bdcc"}, + {file = "grpcio-1.59.3-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:19ad26a7967f7999c8960d2b9fe382dae74c55b0c508c613a6c2ba21cddf2354"}, + {file = "grpcio-1.59.3-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:72b71dad2a3d1650e69ad42a5c4edbc59ee017f08c32c95694172bc501def23c"}, + {file = "grpcio-1.59.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0f0a11d82d0253656cc42e04b6a149521e02e755fe2e4edd21123de610fd1d4"}, + {file = "grpcio-1.59.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60cddafb70f9a2c81ba251b53b4007e07cca7389e704f86266e22c4bffd8bf1d"}, + {file = "grpcio-1.59.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6c75a1fa0e677c1d2b6d4196ad395a5c381dfb8385f07ed034ef667cdcdbcc25"}, + {file = "grpcio-1.59.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e1d8e01438d5964a11167eec1edb5f85ed8e475648f36c834ed5db4ffba24ac8"}, + {file = "grpcio-1.59.3-cp310-cp310-win32.whl", hash = "sha256:c4b0076f0bf29ee62335b055a9599f52000b7941f577daa001c7ef961a1fbeab"}, + {file = "grpcio-1.59.3-cp310-cp310-win_amd64.whl", hash = "sha256:b1f00a3e6e0c3dccccffb5579fc76ebfe4eb40405ba308505b41ef92f747746a"}, + {file = "grpcio-1.59.3-cp311-cp311-linux_armv7l.whl", hash = "sha256:3996aaa21231451161dc29df6a43fcaa8b332042b6150482c119a678d007dd86"}, + {file = "grpcio-1.59.3-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:cb4e9cbd9b7388fcb06412da9f188c7803742d06d6f626304eb838d1707ec7e3"}, + {file = "grpcio-1.59.3-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:8022ca303d6c694a0d7acfb2b472add920217618d3a99eb4b14edc7c6a7e8fcf"}, + {file = "grpcio-1.59.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b36683fad5664283755a7f4e2e804e243633634e93cd798a46247b8e54e3cb0d"}, + {file = "grpcio-1.59.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8239b853226e4824e769517e1b5232e7c4dda3815b200534500338960fcc6118"}, + {file = "grpcio-1.59.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0511af8653fbda489ff11d542a08505d56023e63cafbda60e6e00d4e0bae86ea"}, + {file = "grpcio-1.59.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e78dc982bda74cef2ddfce1c91d29b96864c4c680c634e279ed204d51e227473"}, + {file = "grpcio-1.59.3-cp311-cp311-win32.whl", hash = "sha256:6a5c3a96405966c023e139c3bcccb2c7c776a6f256ac6d70f8558c9041bdccc3"}, + {file = "grpcio-1.59.3-cp311-cp311-win_amd64.whl", hash = "sha256:ed26826ee423b11477297b187371cdf4fa1eca874eb1156422ef3c9a60590dd9"}, + {file = "grpcio-1.59.3-cp312-cp312-linux_armv7l.whl", hash = "sha256:45dddc5cb5227d30fa43652d8872dc87f086d81ab4b500be99413bad0ae198d7"}, + {file = "grpcio-1.59.3-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:1736496d74682e53dd0907fd515f2694d8e6a96c9a359b4080b2504bf2b2d91b"}, + {file = "grpcio-1.59.3-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:ddbd1a16138e52e66229047624de364f88a948a4d92ba20e4e25ad7d22eef025"}, + {file = "grpcio-1.59.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcfa56f8d031ffda902c258c84c4b88707f3a4be4827b4e3ab8ec7c24676320d"}, + {file = "grpcio-1.59.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2eb8f0c7c0c62f7a547ad7a91ba627a5aa32a5ae8d930783f7ee61680d7eb8d"}, + {file = "grpcio-1.59.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8d993399cc65e3a34f8fd48dd9ad7a376734564b822e0160dd18b3d00c1a33f9"}, + {file = "grpcio-1.59.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0bd141f4f41907eb90bda74d969c3cb21c1c62779419782a5b3f5e4b5835718"}, + {file = "grpcio-1.59.3-cp312-cp312-win32.whl", hash = "sha256:33b8fd65d4e97efa62baec6171ce51f9cf68f3a8ba9f866f4abc9d62b5c97b79"}, + {file = "grpcio-1.59.3-cp312-cp312-win_amd64.whl", hash = "sha256:0e735ed002f50d4f3cb9ecfe8ac82403f5d842d274c92d99db64cfc998515e07"}, + {file = "grpcio-1.59.3-cp37-cp37m-linux_armv7l.whl", hash = "sha256:ea40ce4404e7cca0724c91a7404da410f0144148fdd58402a5942971e3469b94"}, + {file = "grpcio-1.59.3-cp37-cp37m-macosx_10_10_universal2.whl", hash = "sha256:83113bcc393477b6f7342b9f48e8a054330c895205517edc66789ceea0796b53"}, + {file = "grpcio-1.59.3-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:73afbac602b8f1212a50088193601f869b5073efa9855b3e51aaaec97848fc8a"}, + {file = "grpcio-1.59.3-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d61de1950b0b0699917b686b1ca108690702fcc2df127b8c9c9320f93e069"}, + {file = "grpcio-1.59.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd76057b5c9a4d68814610ef9226925f94c1231bbe533fdf96f6181f7d2ff9e"}, + {file = "grpcio-1.59.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:95d6fd804c81efe4879e38bfd84d2b26e339a0a9b797e7615e884ef4686eb47b"}, + {file = "grpcio-1.59.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0d42048b8a3286ea4134faddf1f9a59cf98192b94aaa10d910a25613c5eb5bfb"}, + {file = "grpcio-1.59.3-cp37-cp37m-win_amd64.whl", hash = "sha256:4619fea15c64bcdd9d447cdbdde40e3d5f1da3a2e8ae84103d94a9c1df210d7e"}, + {file = "grpcio-1.59.3-cp38-cp38-linux_armv7l.whl", hash = "sha256:95b5506e70284ac03b2005dd9ffcb6708c9ae660669376f0192a710687a22556"}, + {file = "grpcio-1.59.3-cp38-cp38-macosx_10_10_universal2.whl", hash = "sha256:9e17660947660ccfce56c7869032910c179a5328a77b73b37305cd1ee9301c2e"}, + {file = "grpcio-1.59.3-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:00912ce19914d038851be5cd380d94a03f9d195643c28e3ad03d355cc02ce7e8"}, + {file = "grpcio-1.59.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e58b3cadaa3c90f1efca26ba33e0d408b35b497307027d3d707e4bcd8de862a6"}, + {file = "grpcio-1.59.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d787ecadea865bdf78f6679f6f5bf4b984f18f659257ba612979df97a298b3c3"}, + {file = "grpcio-1.59.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0814942ba1bba269db4e760a34388640c601dece525c6a01f3b4ff030cc0db69"}, + {file = "grpcio-1.59.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fb111aa99d3180c361a35b5ae1e2c63750220c584a1344229abc139d5c891881"}, + {file = "grpcio-1.59.3-cp38-cp38-win32.whl", hash = "sha256:eb8ba504c726befe40a356ecbe63c6c3c64c9a439b3164f5a718ec53c9874da0"}, + {file = "grpcio-1.59.3-cp38-cp38-win_amd64.whl", hash = "sha256:cdbc6b32fadab9bebc6f49d3e7ec4c70983c71e965497adab7f87de218e84391"}, + {file = "grpcio-1.59.3-cp39-cp39-linux_armv7l.whl", hash = "sha256:c82ca1e4be24a98a253d6dbaa216542e4163f33f38163fc77964b0f0d255b552"}, + {file = "grpcio-1.59.3-cp39-cp39-macosx_10_10_universal2.whl", hash = "sha256:36636babfda14f9e9687f28d5b66d349cf88c1301154dc71c6513de2b6c88c59"}, + {file = "grpcio-1.59.3-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:5f9b2e591da751ac7fdd316cc25afafb7a626dededa9b414f90faad7f3ccebdb"}, + {file = "grpcio-1.59.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a93a82876a4926bf451db82ceb725bd87f42292bacc94586045261f501a86994"}, + {file = "grpcio-1.59.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce31fa0bfdd1f2bb15b657c16105c8652186eab304eb512e6ae3b99b2fdd7d13"}, + {file = "grpcio-1.59.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:16da0e40573962dab6cba16bec31f25a4f468e6d05b658e589090fe103b03e3d"}, + {file = "grpcio-1.59.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d1d1a17372fd425addd5812049fa7374008ffe689585f27f802d0935522cf4b7"}, + {file = "grpcio-1.59.3-cp39-cp39-win32.whl", hash = "sha256:52cc38a7241b5f7b4a91aaf9000fdd38e26bb00d5e8a71665ce40cfcee716281"}, + {file = "grpcio-1.59.3-cp39-cp39-win_amd64.whl", hash = "sha256:b491e5bbcad3020a96842040421e508780cade35baba30f402df9d321d1c423e"}, + {file = "grpcio-1.59.3.tar.gz", hash = "sha256:7800f99568a74a06ebdccd419dd1b6e639b477dcaf6da77ea702f8fb14ce5f80"}, +] + +[package.extras] +protobuf = ["grpcio-tools (>=1.59.3)"] [[package]] name = "gymnasium" @@ -951,13 +957,13 @@ toy-text = ["pygame (>=2.1.3)", "pygame (>=2.1.3)"] [[package]] name = "identify" -version = "2.5.31" +version = "2.5.32" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.31-py2.py3-none-any.whl", hash = "sha256:90199cb9e7bd3c5407a9b7e81b4abec4bb9d249991c79439ec8af740afc6293d"}, - {file = "identify-2.5.31.tar.gz", hash = "sha256:7736b3c7a28233637e3c36550646fc6389bedd74ae84cb788200cc8e2dd60b75"}, + {file = "identify-2.5.32-py2.py3-none-any.whl", hash = "sha256:0b7656ef6cba81664b783352c73f8c24b39cf82f926f78f4550eda928e5e0545"}, + {file = "identify-2.5.32.tar.gz", hash = "sha256:5d9979348ec1a21c768ae07e0a652924538e8bce67313a73cb0f681cf08ba407"}, ] [package.extras] @@ -965,24 +971,24 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.4" +version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.5" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.6-py3-none-any.whl", hash = "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f"}, + {file = "idna-3.6.tar.gz", hash = "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca"}, ] [[package]] name = "imageio" -version = "2.31.5" +version = "2.33.0" description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." optional = false python-versions = ">=3.8" files = [ - {file = "imageio-2.31.5-py3-none-any.whl", hash = "sha256:97f68e12ba676f2f4b541684ed81f7f3370dc347e8321bc68ee34d37b2dbac9f"}, - {file = "imageio-2.31.5.tar.gz", hash = "sha256:d8e53f9cd4054880276a3dac0a28c85ba7874084856a55a0294a8ae6ed7f3a8e"}, + {file = "imageio-2.33.0-py3-none-any.whl", hash = "sha256:d580d6576d0ae39c459a444a23f6f61fe72123a3df2264f5fce8c87784a4be2e"}, + {file = "imageio-2.33.0.tar.gz", hash = "sha256:39999d05eb500089e60be467dd7d618f56e142229b44c3961c2b420eeb538d7e"}, ] [package.dependencies] @@ -990,17 +996,18 @@ numpy = "*" pillow = ">=8.3.2" [package.extras] -all-plugins = ["astropy", "av", "imageio-ffmpeg", "psutil", "tifffile"] -all-plugins-pypy = ["av", "imageio-ffmpeg", "psutil", "tifffile"] +all-plugins = ["astropy", "av", "imageio-ffmpeg", "pillow-heif", "psutil", "tifffile"] +all-plugins-pypy = ["av", "imageio-ffmpeg", "pillow-heif", "psutil", "tifffile"] build = ["wheel"] dev = ["black", "flake8", "fsspec[github]", "pytest", "pytest-cov"] docs = ["numpydoc", "pydata-sphinx-theme", "sphinx (<6)"] ffmpeg = ["imageio-ffmpeg", "psutil"] fits = ["astropy"] -full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "itk", "numpydoc", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx (<6)", "tifffile", "wheel"] +full = ["astropy", "av", "black", "flake8", "fsspec[github]", "gdal", "imageio-ffmpeg", "itk", "numpydoc", "pillow-heif", "psutil", "pydata-sphinx-theme", "pytest", "pytest-cov", "sphinx (<6)", "tifffile", "wheel"] gdal = ["gdal"] itk = ["itk"] linting = ["black", "flake8"] +pillow-heif = ["pillow-heif"] pyav = ["av"] test = ["fsspec[github]", "pytest", "pytest-cov"] tifffile = ["tifffile"] @@ -1036,20 +1043,20 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "7.0.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-7.0.0-py3-none-any.whl", hash = "sha256:d97503976bb81f40a193d41ee6570868479c69d5068651eb039c40d850c59d67"}, + {file = "importlib_metadata-7.0.0.tar.gz", hash = "sha256:7fc841f8b8332803464e5dc1c63a2e59121f46ca186c0e2e182e80bf8c1319f7"}, ] [package.dependencies] zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] @@ -1212,16 +1219,6 @@ files = [ {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, ] -[[package]] -name = "lit" -version = "17.0.4" -description = "A Software Testing Tool" -optional = true -python-versions = "*" -files = [ - {file = "lit-17.0.4.tar.gz", hash = "sha256:ee2e180128e770abc6aed3a02de2daf09d81b7d30225e315205d3599c311d304"}, -] - [[package]] name = "llvmlite" version = "0.41.1" @@ -1257,13 +1254,13 @@ files = [ [[package]] name = "mako" -version = "1.2.4" +version = "1.3.0" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = true -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Mako-1.2.4-py3-none-any.whl", hash = "sha256:c97c79c018b9165ac9922ae4f32da095ffd3c4e6872b45eded42926deea46818"}, - {file = "Mako-1.2.4.tar.gz", hash = "sha256:d60a3903dc3bb01a18ad6a89cdbe2e4eadc69c0bc8ef1e3773ba53d44c3f7a34"}, + {file = "Mako-1.3.0-py3-none-any.whl", hash = "sha256:57d4e997349f1a92035aa25c17ace371a4213f2ca42f99bee9a602500cfd54d9"}, + {file = "Mako-1.3.0.tar.gz", hash = "sha256:e3a9d388fd00e87043edbe8792f45880ac0114e9c4adc69f6e9bfb2c55e3b11b"}, ] [package.dependencies] @@ -1387,39 +1384,39 @@ files = [ [[package]] name = "matplotlib" -version = "3.8.1" +version = "3.8.2" description = "Python plotting package" optional = false python-versions = ">=3.9" files = [ - {file = "matplotlib-3.8.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e11ab864323fa73ac1b7849688d9671c47a2665242e899785b4db1a375b547e1"}, - {file = "matplotlib-3.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:43a9d40feb63c9e31a0b8b069dcbd74a912f59bdc0095d187126694cd26977e4"}, - {file = "matplotlib-3.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608ea2951838d391e45dec2e644888db6899c752d3c29e157af9dcefb3d7d8d5"}, - {file = "matplotlib-3.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82ec95b02e894561c21e066bd0c716e4b410df141ce9441aa5af6cd937e4ade2"}, - {file = "matplotlib-3.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e3ad1759ad4a5245172c6d32b8ada603a6020d03211524c39d78d25c9a7dc0d2"}, - {file = "matplotlib-3.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:20a0fdfd3ee836179047f3782be060057b878ad37f5abe29edf006a1ff3ecd73"}, - {file = "matplotlib-3.8.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7658b7073c1d6a2922ecc0ed41602410fae88586cb8a54f7a2063d537b6beaf7"}, - {file = "matplotlib-3.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf6889643d4560fcc56f9f0941f078e4df0d72a6c3e4ca548841fc13c5642664"}, - {file = "matplotlib-3.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff842e27bc6a80de08c40e0bfdce460bd08080e8a94af131162b6a1b8948f2cc"}, - {file = "matplotlib-3.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f99d07c0e753717775be7be39ab383453b4d8b629c9fa174596b970c6555890"}, - {file = "matplotlib-3.8.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f34b46dbb1db1f09bfa937cd5853e5f2af232caeeff509c3ab6e43fd33780eae"}, - {file = "matplotlib-3.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1fcb49b6baf0375281979cbf26695ec10bd1cada1e311893e89533b3b70143e7"}, - {file = "matplotlib-3.8.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:e17674ee127f78f26fea237e7f4d5cf910a8be82beb6260fedf358b88075b823"}, - {file = "matplotlib-3.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d921c0270647ab11c3ef283efaaa3d46fd005ba233bfb3aea75231cdf3656de8"}, - {file = "matplotlib-3.8.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2afe7d2f8c9e35e94fbcfcfd9b28f29cb32f0a9068cba469cf907428379c8db9"}, - {file = "matplotlib-3.8.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5a504ff40f81d6233603475a45497a6dca37a873393fa20ae6f7dd6596ef72b"}, - {file = "matplotlib-3.8.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cd54bbf089953140905768ed4626d7223e1ad1d7e2a138410a9c4d3b865ccd80"}, - {file = "matplotlib-3.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:27502d2452208ae784c19504644f09f83742809143bbeae147617640930aa344"}, - {file = "matplotlib-3.8.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:f55fb5ff02d999a100be28bf6ffe826e1867a54c7b465409685332c9dd48ffa5"}, - {file = "matplotlib-3.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:afb72822ae410d62aa1a2920c6563cb5680de9078358f0e9474396c6c3e06be2"}, - {file = "matplotlib-3.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43cf368a4a1d8cbc426944806e5e183cead746647a64d2cdb786441546235967"}, - {file = "matplotlib-3.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c54c55457c7f5ea4dfdba0020004fc7667f5c10c8d9b8010d735345acc06c9b8"}, - {file = "matplotlib-3.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e3bb809b743653b5aab5d72ee45c8c937c28e147b0846b0826a54bece898608c"}, - {file = "matplotlib-3.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:c1b0ecaa0d1f4fe1e30f625a2347f0034a89a7d17c39efbb502e554d92ee2f61"}, - {file = "matplotlib-3.8.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ca84deaa38cb64b7dd160ca2046b45f7b5dbff2b0179642e1339fadc337446c9"}, - {file = "matplotlib-3.8.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed3b29f54f6bbf3eaca4cbd23bc260155153ace63b7f597c474fa6fc6f386530"}, - {file = "matplotlib-3.8.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:0d24c47a1bb47e392fbcd26fe322e4ff3431653ac1e8718e4e147d450ae97a44"}, - {file = "matplotlib-3.8.1.tar.gz", hash = "sha256:044df81c1f6f3a8e52d70c4cfcb44e77ea9632a10929932870dfaa90de94365d"}, + {file = "matplotlib-3.8.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:09796f89fb71a0c0e1e2f4bdaf63fb2cefc84446bb963ecdeb40dfee7dfa98c7"}, + {file = "matplotlib-3.8.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f9c6976748a25e8b9be51ea028df49b8e561eed7809146da7a47dbecebab367"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b78e4f2cedf303869b782071b55fdde5987fda3038e9d09e58c91cc261b5ad18"}, + {file = "matplotlib-3.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e208f46cf6576a7624195aa047cb344a7f802e113bb1a06cfd4bee431de5e31"}, + {file = "matplotlib-3.8.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:46a569130ff53798ea5f50afce7406e91fdc471ca1e0e26ba976a8c734c9427a"}, + {file = "matplotlib-3.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:830f00640c965c5b7f6bc32f0d4ce0c36dfe0379f7dd65b07a00c801713ec40a"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d86593ccf546223eb75a39b44c32788e6f6440d13cfc4750c1c15d0fcb850b63"}, + {file = "matplotlib-3.8.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a5430836811b7652991939012f43d2808a2db9b64ee240387e8c43e2e5578c8"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9576723858a78751d5aacd2497b8aef29ffea6d1c95981505877f7ac28215c6"}, + {file = "matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba9cbd8ac6cf422f3102622b20f8552d601bf8837e49a3afed188d560152788"}, + {file = "matplotlib-3.8.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:03f9d160a29e0b65c0790bb07f4f45d6a181b1ac33eb1bb0dd225986450148f0"}, + {file = "matplotlib-3.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:3773002da767f0a9323ba1a9b9b5d00d6257dbd2a93107233167cfb581f64717"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:4c318c1e95e2f5926fba326f68177dee364aa791d6df022ceb91b8221bd0a627"}, + {file = "matplotlib-3.8.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:091275d18d942cf1ee9609c830a1bc36610607d8223b1b981c37d5c9fc3e46a4"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b0f3b8ea0e99e233a4bcc44590f01604840d833c280ebb8fe5554fd3e6cfe8d"}, + {file = "matplotlib-3.8.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7b1704a530395aaf73912be741c04d181f82ca78084fbd80bc737be04848331"}, + {file = "matplotlib-3.8.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533b0e3b0c6768eef8cbe4b583731ce25a91ab54a22f830db2b031e83cca9213"}, + {file = "matplotlib-3.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:0f4fc5d72b75e2c18e55eb32292659cf731d9d5b312a6eb036506304f4675630"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:deaed9ad4da0b1aea77fe0aa0cebb9ef611c70b3177be936a95e5d01fa05094f"}, + {file = "matplotlib-3.8.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:172f4d0fbac3383d39164c6caafd3255ce6fa58f08fc392513a0b1d3b89c4f89"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7d36c2209d9136cd8e02fab1c0ddc185ce79bc914c45054a9f514e44c787917"}, + {file = "matplotlib-3.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5864bdd7da445e4e5e011b199bb67168cdad10b501750367c496420f2ad00843"}, + {file = "matplotlib-3.8.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef8345b48e95cee45ff25192ed1f4857273117917a4dcd48e3905619bcd9c9b8"}, + {file = "matplotlib-3.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:7c48d9e221b637c017232e3760ed30b4e8d5dfd081daf327e829bf2a72c731b4"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:aa11b3c6928a1e496c1a79917d51d4cd5d04f8a2e75f21df4949eeefdf697f4b"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1095fecf99eeb7384dabad4bf44b965f929a5f6079654b681193edf7169ec20"}, + {file = "matplotlib-3.8.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:bddfb1db89bfaa855912261c805bd0e10218923cc262b9159a49c29a7a1c1afa"}, + {file = "matplotlib-3.8.2.tar.gz", hash = "sha256:01a978b871b881ee76017152f1f1a0cbf6bd5f7b8ff8c96df0df1bd57d8755a1"}, ] [package.dependencies] @@ -1610,43 +1607,47 @@ numpy = ">=1.22,<1.27" [[package]] name = "numpy" -version = "1.26.1" +version = "1.26.2" description = "Fundamental package for array computing in Python" optional = false -python-versions = "<3.13,>=3.9" -files = [ - {file = "numpy-1.26.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:82e871307a6331b5f09efda3c22e03c095d957f04bf6bc1804f30048d0e5e7af"}, - {file = "numpy-1.26.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdd9ec98f0063d93baeb01aad472a1a0840dee302842a2746a7a8e92968f9575"}, - {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d78f269e0c4fd365fc2992c00353e4530d274ba68f15e968d8bc3c69ce5f5244"}, - {file = "numpy-1.26.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ab9163ca8aeb7fd32fe93866490654d2f7dda4e61bc6297bf72ce07fdc02f67"}, - {file = "numpy-1.26.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:78ca54b2f9daffa5f323f34cdf21e1d9779a54073f0018a3094ab907938331a2"}, - {file = "numpy-1.26.1-cp310-cp310-win32.whl", hash = "sha256:d1cfc92db6af1fd37a7bb58e55c8383b4aa1ba23d012bdbba26b4bcca45ac297"}, - {file = "numpy-1.26.1-cp310-cp310-win_amd64.whl", hash = "sha256:d2984cb6caaf05294b8466966627e80bf6c7afd273279077679cb010acb0e5ab"}, - {file = "numpy-1.26.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cd7837b2b734ca72959a1caf3309457a318c934abef7a43a14bb984e574bbb9a"}, - {file = "numpy-1.26.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c59c046c31a43310ad0199d6299e59f57a289e22f0f36951ced1c9eac3665b9"}, - {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d58e8c51a7cf43090d124d5073bc29ab2755822181fcad978b12e144e5e5a4b3"}, - {file = "numpy-1.26.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6081aed64714a18c72b168a9276095ef9155dd7888b9e74b5987808f0dd0a974"}, - {file = "numpy-1.26.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:97e5d6a9f0702c2863aaabf19f0d1b6c2628fbe476438ce0b5ce06e83085064c"}, - {file = "numpy-1.26.1-cp311-cp311-win32.whl", hash = "sha256:b9d45d1dbb9de84894cc50efece5b09939752a2d75aab3a8b0cef6f3a35ecd6b"}, - {file = "numpy-1.26.1-cp311-cp311-win_amd64.whl", hash = "sha256:3649d566e2fc067597125428db15d60eb42a4e0897fc48d28cb75dc2e0454e53"}, - {file = "numpy-1.26.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d1bd82d539607951cac963388534da3b7ea0e18b149a53cf883d8f699178c0f"}, - {file = "numpy-1.26.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:afd5ced4e5a96dac6725daeb5242a35494243f2239244fad10a90ce58b071d24"}, - {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a03fb25610ef560a6201ff06df4f8105292ba56e7cdd196ea350d123fc32e24e"}, - {file = "numpy-1.26.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcfaf015b79d1f9f9c9fd0731a907407dc3e45769262d657d754c3a028586124"}, - {file = "numpy-1.26.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e509cbc488c735b43b5ffea175235cec24bbc57b227ef1acc691725beb230d1c"}, - {file = "numpy-1.26.1-cp312-cp312-win32.whl", hash = "sha256:af22f3d8e228d84d1c0c44c1fbdeb80f97a15a0abe4f080960393a00db733b66"}, - {file = "numpy-1.26.1-cp312-cp312-win_amd64.whl", hash = "sha256:9f42284ebf91bdf32fafac29d29d4c07e5e9d1af862ea73686581773ef9e73a7"}, - {file = "numpy-1.26.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb894accfd16b867d8643fc2ba6c8617c78ba2828051e9a69511644ce86ce83e"}, - {file = "numpy-1.26.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e44ccb93f30c75dfc0c3aa3ce38f33486a75ec9abadabd4e59f114994a9c4617"}, - {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9696aa2e35cc41e398a6d42d147cf326f8f9d81befcb399bc1ed7ffea339b64e"}, - {file = "numpy-1.26.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5b411040beead47a228bde3b2241100454a6abde9df139ed087bd73fc0a4908"}, - {file = "numpy-1.26.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1e11668d6f756ca5ef534b5be8653d16c5352cbb210a5c2a79ff288e937010d5"}, - {file = "numpy-1.26.1-cp39-cp39-win32.whl", hash = "sha256:d1d2c6b7dd618c41e202c59c1413ef9b2c8e8a15f5039e344af64195459e3104"}, - {file = "numpy-1.26.1-cp39-cp39-win_amd64.whl", hash = "sha256:59227c981d43425ca5e5c01094d59eb14e8772ce6975d4b2fc1e106a833d5ae2"}, - {file = "numpy-1.26.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:06934e1a22c54636a059215d6da99e23286424f316fddd979f5071093b648668"}, - {file = "numpy-1.26.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76ff661a867d9272cd2a99eed002470f46dbe0943a5ffd140f49be84f68ffc42"}, - {file = "numpy-1.26.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:6965888d65d2848e8768824ca8288db0a81263c1efccec881cb35a0d805fcd2f"}, - {file = "numpy-1.26.1.tar.gz", hash = "sha256:c8c6c72d4a9f831f328efb1312642a1cafafaa88981d9ab76368d50d07d93cbe"}, +python-versions = ">=3.9" +files = [ + {file = "numpy-1.26.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3703fc9258a4a122d17043e57b35e5ef1c5a5837c3db8be396c82e04c1cf9b0f"}, + {file = "numpy-1.26.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cc392fdcbd21d4be6ae1bb4475a03ce3b025cd49a9be5345d76d7585aea69440"}, + {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36340109af8da8805d8851ef1d74761b3b88e81a9bd80b290bbfed61bd2b4f75"}, + {file = "numpy-1.26.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcc008217145b3d77abd3e4d5ef586e3bdfba8fe17940769f8aa09b99e856c00"}, + {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3ced40d4e9e18242f70dd02d739e44698df3dcb010d31f495ff00a31ef6014fe"}, + {file = "numpy-1.26.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b272d4cecc32c9e19911891446b72e986157e6a1809b7b56518b4f3755267523"}, + {file = "numpy-1.26.2-cp310-cp310-win32.whl", hash = "sha256:22f8fc02fdbc829e7a8c578dd8d2e15a9074b630d4da29cda483337e300e3ee9"}, + {file = "numpy-1.26.2-cp310-cp310-win_amd64.whl", hash = "sha256:26c9d33f8e8b846d5a65dd068c14e04018d05533b348d9eaeef6c1bd787f9919"}, + {file = "numpy-1.26.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b96e7b9c624ef3ae2ae0e04fa9b460f6b9f17ad8b4bec6d7756510f1f6c0c841"}, + {file = "numpy-1.26.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aa18428111fb9a591d7a9cc1b48150097ba6a7e8299fb56bdf574df650e7d1f1"}, + {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06fa1ed84aa60ea6ef9f91ba57b5ed963c3729534e6e54055fc151fad0423f0a"}, + {file = "numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96ca5482c3dbdd051bcd1fce8034603d6ebfc125a7bd59f55b40d8f5d246832b"}, + {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:854ab91a2906ef29dc3925a064fcd365c7b4da743f84b123002f6139bcb3f8a7"}, + {file = "numpy-1.26.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f43740ab089277d403aa07567be138fc2a89d4d9892d113b76153e0e412409f8"}, + {file = "numpy-1.26.2-cp311-cp311-win32.whl", hash = "sha256:a2bbc29fcb1771cd7b7425f98b05307776a6baf43035d3b80c4b0f29e9545186"}, + {file = "numpy-1.26.2-cp311-cp311-win_amd64.whl", hash = "sha256:2b3fca8a5b00184828d12b073af4d0fc5fdd94b1632c2477526f6bd7842d700d"}, + {file = "numpy-1.26.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a4cd6ed4a339c21f1d1b0fdf13426cb3b284555c27ac2f156dfdaaa7e16bfab0"}, + {file = "numpy-1.26.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5d5244aabd6ed7f312268b9247be47343a654ebea52a60f002dc70c769048e75"}, + {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a3cdb4d9c70e6b8c0814239ead47da00934666f668426fc6e94cce869e13fd7"}, + {file = "numpy-1.26.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa317b2325f7aa0a9471663e6093c210cb2ae9c0ad824732b307d2c51983d5b6"}, + {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:174a8880739c16c925799c018f3f55b8130c1f7c8e75ab0a6fa9d41cab092fd6"}, + {file = "numpy-1.26.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f79b231bf5c16b1f39c7f4875e1ded36abee1591e98742b05d8a0fb55d8a3eec"}, + {file = "numpy-1.26.2-cp312-cp312-win32.whl", hash = "sha256:4a06263321dfd3598cacb252f51e521a8cb4b6df471bb12a7ee5cbab20ea9167"}, + {file = "numpy-1.26.2-cp312-cp312-win_amd64.whl", hash = "sha256:b04f5dc6b3efdaab541f7857351aac359e6ae3c126e2edb376929bd3b7f92d7e"}, + {file = "numpy-1.26.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4eb8df4bf8d3d90d091e0146f6c28492b0be84da3e409ebef54349f71ed271ef"}, + {file = "numpy-1.26.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1a13860fdcd95de7cf58bd6f8bc5a5ef81c0b0625eb2c9a783948847abbef2c2"}, + {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64308ebc366a8ed63fd0bf426b6a9468060962f1a4339ab1074c228fa6ade8e3"}, + {file = "numpy-1.26.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baf8aab04a2c0e859da118f0b38617e5ee65d75b83795055fb66c0d5e9e9b818"}, + {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d73a3abcac238250091b11caef9ad12413dab01669511779bc9b29261dd50210"}, + {file = "numpy-1.26.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b361d369fc7e5e1714cf827b731ca32bff8d411212fccd29ad98ad622449cc36"}, + {file = "numpy-1.26.2-cp39-cp39-win32.whl", hash = "sha256:bd3f0091e845164a20bd5a326860c840fe2af79fa12e0469a12768a3ec578d80"}, + {file = "numpy-1.26.2-cp39-cp39-win_amd64.whl", hash = "sha256:2beef57fb031dcc0dc8fa4fe297a742027b954949cabb52a2a376c144e5e6060"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1cc3d5029a30fb5f06704ad6b23b35e11309491c999838c31f124fee32107c79"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94cc3c222bb9fb5a12e334d0479b97bb2df446fbe622b470928f5284ffca3f8d"}, + {file = "numpy-1.26.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe6b44fb8fcdf7eda4ef4461b97b3f63c466b27ab151bec2366db8b197387841"}, + {file = "numpy-1.26.2.tar.gz", hash = "sha256:f65738447676ab5777f11e6bbbdb8ce11b785e105f690bc45966574816b6d3ea"}, ] [[package]] @@ -1672,162 +1673,145 @@ doc = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pydata-sphinx-theme (>=0.13.3)", test = ["matplotlib", "pytest", "pytest-cov"] [[package]] -name = "nvidia-cublas-cu11" -version = "11.10.3.66" +name = "nvidia-cublas-cu12" +version = "12.1.3.1" description = "CUBLAS native runtime libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-manylinux1_x86_64.whl", hash = "sha256:d32e4d75f94ddfb93ea0a5dda08389bcc65d8916a25cb9f37ac89edaeed3bded"}, - {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-win_amd64.whl", hash = "sha256:8ac17ba6ade3ed56ab898a036f9ae0756f1e81052a317bf98f8c6d18dc3ae49e"}, + {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"}, + {file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"}, ] -[package.dependencies] -setuptools = "*" -wheel = "*" - [[package]] -name = "nvidia-cuda-cupti-cu11" -version = "11.7.101" +name = "nvidia-cuda-cupti-cu12" +version = "12.1.105" description = "CUDA profiling tools runtime libs." optional = true python-versions = ">=3" files = [ - {file = "nvidia_cuda_cupti_cu11-11.7.101-py3-none-manylinux1_x86_64.whl", hash = "sha256:e0cfd9854e1f2edaa36ca20d21cd0bdd5dcfca4e3b9e130a082e05b33b6c5895"}, - {file = "nvidia_cuda_cupti_cu11-11.7.101-py3-none-win_amd64.whl", hash = "sha256:7cc5b8f91ae5e1389c3c0ad8866b3b016a175e827ea8f162a672990a402ab2b0"}, + {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"}, + {file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"}, ] -[package.dependencies] -setuptools = "*" -wheel = "*" - [[package]] -name = "nvidia-cuda-nvrtc-cu11" -version = "11.7.99" +name = "nvidia-cuda-nvrtc-cu12" +version = "12.1.105" description = "NVRTC native runtime libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_cuda_nvrtc_cu11-11.7.99-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:9f1562822ea264b7e34ed5930567e89242d266448e936b85bc97a3370feabb03"}, - {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:f7d9610d9b7c331fa0da2d1b2858a4a8315e6d49765091d28711c8946e7425e7"}, - {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:f2effeb1309bdd1b3854fc9b17eaf997808f8b25968ce0c7070945c4265d64a3"}, + {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"}, + {file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"}, ] -[package.dependencies] -setuptools = "*" -wheel = "*" - [[package]] -name = "nvidia-cuda-runtime-cu11" -version = "11.7.99" +name = "nvidia-cuda-runtime-cu12" +version = "12.1.105" description = "CUDA Runtime native Libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:cc768314ae58d2641f07eac350f40f99dcb35719c4faff4bc458a7cd2b119e31"}, - {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:bc77fa59a7679310df9d5c70ab13c4e34c64ae2124dd1efd7e5474b71be125c7"}, + {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"}, + {file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"}, ] -[package.dependencies] -setuptools = "*" -wheel = "*" - [[package]] -name = "nvidia-cudnn-cu11" -version = "8.5.0.96" +name = "nvidia-cudnn-cu12" +version = "8.9.2.26" description = "cuDNN runtime libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_cudnn_cu11-8.5.0.96-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:402f40adfc6f418f9dae9ab402e773cfed9beae52333f6d86ae3107a1b9527e7"}, - {file = "nvidia_cudnn_cu11-8.5.0.96-py3-none-manylinux1_x86_64.whl", hash = "sha256:71f8111eb830879ff2836db3cccf03bbd735df9b0d17cd93761732ac50a8a108"}, + {file = "nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9"}, ] [package.dependencies] -setuptools = "*" -wheel = "*" +nvidia-cublas-cu12 = "*" [[package]] -name = "nvidia-cufft-cu11" -version = "10.9.0.58" +name = "nvidia-cufft-cu12" +version = "11.0.2.54" description = "CUFFT native runtime libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_cufft_cu11-10.9.0.58-py3-none-manylinux1_x86_64.whl", hash = "sha256:222f9da70c80384632fd6035e4c3f16762d64ea7a843829cb278f98b3cb7dd81"}, - {file = "nvidia_cufft_cu11-10.9.0.58-py3-none-win_amd64.whl", hash = "sha256:c4d316f17c745ec9c728e30409612eaf77a8404c3733cdf6c9c1569634d1ca03"}, + {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"}, + {file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"}, ] [[package]] -name = "nvidia-curand-cu11" -version = "10.2.10.91" +name = "nvidia-curand-cu12" +version = "10.3.2.106" description = "CURAND native runtime libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_curand_cu11-10.2.10.91-py3-none-manylinux1_x86_64.whl", hash = "sha256:eecb269c970fa599a2660c9232fa46aaccbf90d9170b96c462e13bcb4d129e2c"}, - {file = "nvidia_curand_cu11-10.2.10.91-py3-none-win_amd64.whl", hash = "sha256:f742052af0e1e75523bde18895a9ed016ecf1e5aa0ecddfcc3658fd11a1ff417"}, + {file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"}, + {file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"}, ] -[package.dependencies] -setuptools = "*" -wheel = "*" - [[package]] -name = "nvidia-cusolver-cu11" -version = "11.4.0.1" +name = "nvidia-cusolver-cu12" +version = "11.4.5.107" description = "CUDA solver native runtime libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_cusolver_cu11-11.4.0.1-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:72fa7261d755ed55c0074960df5904b65e2326f7adce364cbe4945063c1be412"}, - {file = "nvidia_cusolver_cu11-11.4.0.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:700b781bfefd57d161443aff9ace1878584b93e0b2cfef3d6e9296d96febbf99"}, - {file = "nvidia_cusolver_cu11-11.4.0.1-py3-none-win_amd64.whl", hash = "sha256:00f70b256add65f8c1eb3b6a65308795a93e7740f6df9e273eccbba770d370c4"}, + {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"}, + {file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"}, ] [package.dependencies] -setuptools = "*" -wheel = "*" +nvidia-cublas-cu12 = "*" +nvidia-cusparse-cu12 = "*" +nvidia-nvjitlink-cu12 = "*" [[package]] -name = "nvidia-cusparse-cu11" -version = "11.7.4.91" +name = "nvidia-cusparse-cu12" +version = "12.1.0.106" description = "CUSPARSE native runtime libraries" optional = true python-versions = ">=3" files = [ - {file = "nvidia_cusparse_cu11-11.7.4.91-py3-none-manylinux1_x86_64.whl", hash = "sha256:a3389de714db63321aa11fbec3919271f415ef19fda58aed7f2ede488c32733d"}, - {file = "nvidia_cusparse_cu11-11.7.4.91-py3-none-win_amd64.whl", hash = "sha256:304a01599534f5186a8ed1c3756879282c72c118bc77dd890dc1ff868cad25b9"}, + {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"}, + {file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"}, ] [package.dependencies] -setuptools = "*" -wheel = "*" +nvidia-nvjitlink-cu12 = "*" [[package]] -name = "nvidia-nccl-cu11" -version = "2.14.3" +name = "nvidia-nccl-cu12" +version = "2.18.1" description = "NVIDIA Collective Communication Library (NCCL) Runtime" optional = true python-versions = ">=3" files = [ - {file = "nvidia_nccl_cu11-2.14.3-py3-none-manylinux1_x86_64.whl", hash = "sha256:5e5534257d1284b8e825bc3a182c6f06acd6eb405e9f89d49340e98cd8f136eb"}, + {file = "nvidia_nccl_cu12-2.18.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:1a6c4acefcbebfa6de320f412bf7866de856e786e0462326ba1bac40de0b5e71"}, ] [[package]] -name = "nvidia-nvtx-cu11" -version = "11.7.91" -description = "NVIDIA Tools Extension" +name = "nvidia-nvjitlink-cu12" +version = "12.3.101" +description = "Nvidia JIT LTO Library" optional = true python-versions = ">=3" files = [ - {file = "nvidia_nvtx_cu11-11.7.91-py3-none-manylinux1_x86_64.whl", hash = "sha256:b22c64eee426a62fc00952b507d6d29cf62b4c9df7a480fcc417e540e05fd5ac"}, - {file = "nvidia_nvtx_cu11-11.7.91-py3-none-win_amd64.whl", hash = "sha256:dfd7fcb2a91742513027d63a26b757f38dd8b07fecac282c4d132a9d373ff064"}, + {file = "nvidia_nvjitlink_cu12-12.3.101-py3-none-manylinux1_x86_64.whl", hash = "sha256:64335a8088e2b9d196ae8665430bc6a2b7e6ef2eb877a9c735c804bd4ff6467c"}, + {file = "nvidia_nvjitlink_cu12-12.3.101-py3-none-win_amd64.whl", hash = "sha256:1b2e317e437433753530792f13eece58f0aec21a2b05903be7bffe58a606cbd1"}, ] -[package.dependencies] -setuptools = "*" -wheel = "*" +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.1.105" +description = "NVIDIA Tools Extension" +optional = true +python-versions = ">=3" +files = [ + {file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"}, + {file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"}, +] [[package]] name = "oauthlib" @@ -2050,13 +2034,13 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "3.11.0" +version = "4.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, ] [package.extras] @@ -2162,13 +2146,13 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] [[package]] name = "pyasn1" -version = "0.5.0" +version = "0.5.1" description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "pyasn1-0.5.0-py2.py3-none-any.whl", hash = "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57"}, - {file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"}, + {file = "pyasn1-0.5.1-py2.py3-none-any.whl", hash = "sha256:4439847c58d40b1d0a573d07e3856e95333f1976294494c325775aeca506eb58"}, + {file = "pyasn1-0.5.1.tar.gz", hash = "sha256:6d391a96e59b23130a5cfa74d6fd7f388dbbe26cc8f1edf39fdddf08d9d6676c"}, ] [[package]] @@ -2253,17 +2237,18 @@ files = [ [[package]] name = "pygments" -version = "2.16.1" +version = "2.17.2" description = "Pygments is a syntax highlighting package written in Python." optional = true python-versions = ">=3.7" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, + {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, ] [package.extras] plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyopengl" @@ -2499,7 +2484,7 @@ rlberry = "*" type = "git" url = "https://github.com/rlberry-py/rlberry-scool.git" reference = "HEAD" -resolved_reference = "b534a999289909c6c1b589658a71d22490452de7" +resolved_reference = "8de72c094ecb0183fdda66adcd814c555940678d" [[package]] name = "rsa" @@ -2517,36 +2502,36 @@ pyasn1 = ">=0.1.3" [[package]] name = "scipy" -version = "1.11.3" +version = "1.11.4" description = "Fundamental algorithms for scientific computing in Python" optional = false -python-versions = "<3.13,>=3.9" -files = [ - {file = "scipy-1.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:370f569c57e1d888304052c18e58f4a927338eafdaef78613c685ca2ea0d1fa0"}, - {file = "scipy-1.11.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:9885e3e4f13b2bd44aaf2a1a6390a11add9f48d5295f7a592393ceb8991577a3"}, - {file = "scipy-1.11.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e04aa19acc324a1a076abb4035dabe9b64badb19f76ad9c798bde39d41025cdc"}, - {file = "scipy-1.11.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e1a8a4657673bfae1e05e1e1d6e94b0cabe5ed0c7c144c8aa7b7dbb774ce5c1"}, - {file = "scipy-1.11.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7abda0e62ef00cde826d441485e2e32fe737bdddee3324e35c0e01dee65e2a88"}, - {file = "scipy-1.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:033c3fd95d55012dd1148b201b72ae854d5086d25e7c316ec9850de4fe776929"}, - {file = "scipy-1.11.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:925c6f09d0053b1c0f90b2d92d03b261e889b20d1c9b08a3a51f61afc5f58165"}, - {file = "scipy-1.11.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:5664e364f90be8219283eeb844323ff8cd79d7acbd64e15eb9c46b9bc7f6a42a"}, - {file = "scipy-1.11.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00f325434b6424952fbb636506f0567898dca7b0f7654d48f1c382ea338ce9a3"}, - {file = "scipy-1.11.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f290cf561a4b4edfe8d1001ee4be6da60c1c4ea712985b58bf6bc62badee221"}, - {file = "scipy-1.11.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:91770cb3b1e81ae19463b3c235bf1e0e330767dca9eb4cd73ba3ded6c4151e4d"}, - {file = "scipy-1.11.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1f97cd89c0fe1a0685f8f89d85fa305deb3067d0668151571ba50913e445820"}, - {file = "scipy-1.11.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dfcc1552add7cb7c13fb70efcb2389d0624d571aaf2c80b04117e2755a0c5d15"}, - {file = "scipy-1.11.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:0d3a136ae1ff0883fffbb1b05b0b2fea251cb1046a5077d0b435a1839b3e52b7"}, - {file = "scipy-1.11.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bae66a2d7d5768eaa33008fa5a974389f167183c87bf39160d3fefe6664f8ddc"}, - {file = "scipy-1.11.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2f6dee6cbb0e263b8142ed587bc93e3ed5e777f1f75448d24fb923d9fd4dce6"}, - {file = "scipy-1.11.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:74e89dc5e00201e71dd94f5f382ab1c6a9f3ff806c7d24e4e90928bb1aafb280"}, - {file = "scipy-1.11.3-cp312-cp312-win_amd64.whl", hash = "sha256:90271dbde4be191522b3903fc97334e3956d7cfb9cce3f0718d0ab4fd7d8bfd6"}, - {file = "scipy-1.11.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a63d1ec9cadecce838467ce0631c17c15c7197ae61e49429434ba01d618caa83"}, - {file = "scipy-1.11.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:5305792c7110e32ff155aed0df46aa60a60fc6e52cd4ee02cdeb67eaccd5356e"}, - {file = "scipy-1.11.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9ea7f579182d83d00fed0e5c11a4aa5ffe01460444219dedc448a36adf0c3917"}, - {file = "scipy-1.11.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c77da50c9a91e23beb63c2a711ef9e9ca9a2060442757dffee34ea41847d8156"}, - {file = "scipy-1.11.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15f237e890c24aef6891c7d008f9ff7e758c6ef39a2b5df264650eb7900403c0"}, - {file = "scipy-1.11.3-cp39-cp39-win_amd64.whl", hash = "sha256:4b4bb134c7aa457e26cc6ea482b016fef45db71417d55cc6d8f43d799cdf9ef2"}, - {file = "scipy-1.11.3.tar.gz", hash = "sha256:bba4d955f54edd61899776bad459bf7326e14b9fa1c552181f0479cc60a568cd"}, +python-versions = ">=3.9" +files = [ + {file = "scipy-1.11.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc9a714581f561af0848e6b69947fda0614915f072dfd14142ed1bfe1b806710"}, + {file = "scipy-1.11.4-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:cf00bd2b1b0211888d4dc75656c0412213a8b25e80d73898083f402b50f47e41"}, + {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9999c008ccf00e8fbcce1236f85ade5c569d13144f77a1946bef8863e8f6eb4"}, + {file = "scipy-1.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:933baf588daa8dc9a92c20a0be32f56d43faf3d1a60ab11b3f08c356430f6e56"}, + {file = "scipy-1.11.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8fce70f39076a5aa62e92e69a7f62349f9574d8405c0a5de6ed3ef72de07f446"}, + {file = "scipy-1.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:6550466fbeec7453d7465e74d4f4b19f905642c89a7525571ee91dd7adabb5a3"}, + {file = "scipy-1.11.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f313b39a7e94f296025e3cffc2c567618174c0b1dde173960cf23808f9fae4be"}, + {file = "scipy-1.11.4-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:1b7c3dca977f30a739e0409fb001056484661cb2541a01aba0bb0029f7b68db8"}, + {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00150c5eae7b610c32589dda259eacc7c4f1665aedf25d921907f4d08a951b1c"}, + {file = "scipy-1.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:530f9ad26440e85766509dbf78edcfe13ffd0ab7fec2560ee5c36ff74d6269ff"}, + {file = "scipy-1.11.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5e347b14fe01003d3b78e196e84bd3f48ffe4c8a7b8a1afbcb8f5505cb710993"}, + {file = "scipy-1.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:acf8ed278cc03f5aff035e69cb511741e0418681d25fbbb86ca65429c4f4d9cd"}, + {file = "scipy-1.11.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:028eccd22e654b3ea01ee63705681ee79933652b2d8f873e7949898dda6d11b6"}, + {file = "scipy-1.11.4-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2c6ff6ef9cc27f9b3db93a6f8b38f97387e6e0591600369a297a50a8e96e835d"}, + {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b030c6674b9230d37c5c60ab456e2cf12f6784596d15ce8da9365e70896effc4"}, + {file = "scipy-1.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad669df80528aeca5f557712102538f4f37e503f0c5b9541655016dd0932ca79"}, + {file = "scipy-1.11.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce7fff2e23ab2cc81ff452a9444c215c28e6305f396b2ba88343a567feec9660"}, + {file = "scipy-1.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:36750b7733d960d7994888f0d148d31ea3017ac15eef664194b4ef68d36a4a97"}, + {file = "scipy-1.11.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e619aba2df228a9b34718efb023966da781e89dd3d21637b27f2e54db0410d7"}, + {file = "scipy-1.11.4-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:f3cd9e7b3c2c1ec26364856f9fbe78695fe631150f94cd1c22228456404cf1ec"}, + {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d10e45a6c50211fe256da61a11c34927c68f277e03138777bdebedd933712fea"}, + {file = "scipy-1.11.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91af76a68eeae0064887a48e25c4e616fa519fa0d38602eda7e0f97d65d57937"}, + {file = "scipy-1.11.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6df1468153a31cf55ed5ed39647279beb9cfb5d3f84369453b49e4b8502394fd"}, + {file = "scipy-1.11.4-cp39-cp39-win_amd64.whl", hash = "sha256:ee410e6de8f88fd5cf6eadd73c135020bfbbbdfcd0f6162c36a7638a1ea8cc65"}, + {file = "scipy-1.11.4.tar.gz", hash = "sha256:90a2b78e7f5733b9de748f589f09225013685f9b218275257f8a8168ededaeaa"}, ] [package.dependencies] @@ -2580,17 +2565,17 @@ stats = ["scipy (>=1.3)", "statsmodels (>=0.10)"] [[package]] name = "setuptools" -version = "68.2.2" +version = "69.0.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a"}, - {file = "setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87"}, + {file = "setuptools-69.0.2-py3-none-any.whl", hash = "sha256:1e8fdff6797d3865f37397be788a4e3cba233608e9b509382a2777d25ebde7f2"}, + {file = "setuptools-69.0.2.tar.gz", hash = "sha256:735896e78a4742605974de002ac60562d286fa8051a7e2299445e8e8fbb01aa6"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] @@ -2920,13 +2905,13 @@ sqlcipher = ["sqlcipher3-binary"] [[package]] name = "stable-baselines3" -version = "2.1.0" +version = "2.2.1" description = "Pytorch version of Stable Baselines, implementations of reinforcement learning algorithms." optional = true python-versions = ">=3.8" files = [ - {file = "stable_baselines3-2.1.0-py3-none-any.whl", hash = "sha256:1c1736feb37f4f859132dfaedb7f5d181d9a4012f750d179644cf2ccd200029c"}, - {file = "stable_baselines3-2.1.0.tar.gz", hash = "sha256:31e26d078de88740e292cac34b607ffcddb26a07eeb47fecfac3015ce52bdeb0"}, + {file = "stable_baselines3-2.2.1-py3-none-any.whl", hash = "sha256:ccb3405e244c3f0b284b3487436d99c782f1243229aa466cb4ceba93807e7428"}, + {file = "stable_baselines3-2.2.1.tar.gz", hash = "sha256:7db00bea41c82448d9243529059a9bc8131c0fe751098bd05e3d8822d2978a4d"}, ] [package.dependencies] @@ -2938,10 +2923,10 @@ pandas = "*" torch = ">=1.13" [package.extras] -docs = ["sphinx (>=5.3,<7.0)", "sphinx-autobuild", "sphinx-autodoc-typehints", "sphinx-copybutton", "sphinx-rtd-theme", "sphinxcontrib.spelling"] -extra = ["autorom[accept-rom-license] (>=0.6.1,<0.7.0)", "opencv-python", "pillow", "psutil", "pygame", "rich", "shimmy[atari] (>=1.1.0,<1.2.0)", "tensorboard (>=2.9.1)", "tqdm"] -extra-no-roms = ["opencv-python", "pillow", "psutil", "pygame", "rich", "shimmy[atari] (>=1.1.0,<1.2.0)", "tensorboard (>=2.9.1)", "tqdm"] -tests = ["black", "isort (>=5.0)", "mypy", "pytest", "pytest-cov", "pytest-env", "pytest-xdist", "pytype", "ruff"] +docs = ["sphinx (>=5,<8)", "sphinx-autobuild", "sphinx-copybutton", "sphinx-rtd-theme (>=1.3.0)", "sphinxcontrib.spelling"] +extra = ["autorom[accept-rom-license] (>=0.6.1,<0.7.0)", "opencv-python", "pillow", "psutil", "pygame", "rich", "shimmy[atari] (>=1.3.0,<1.4.0)", "tensorboard (>=2.9.1)", "tqdm"] +extra-no-roms = ["opencv-python", "pillow", "psutil", "pygame", "rich", "shimmy[atari] (>=1.3.0,<1.4.0)", "tensorboard (>=2.9.1)", "tqdm"] +tests = ["black (>=23.9.1,<24)", "mypy", "pytest", "pytest-cov", "pytest-env", "pytest-xdist", "ruff (>=0.0.288)"] [[package]] name = "sympy" @@ -3020,57 +3005,55 @@ files = [ [[package]] name = "torch" -version = "2.0.0" +version = "2.1.1" description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration" optional = true python-versions = ">=3.8.0" files = [ - {file = "torch-2.0.0-1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:c9090bda7d2eeeecd74f51b721420dbeb44f838d4536cc1b284e879417e3064a"}, - {file = "torch-2.0.0-1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:bd42db2a48a20574d2c33489e120e9f32789c4dc13c514b0c44272972d14a2d7"}, - {file = "torch-2.0.0-1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:8969aa8375bcbc0c2993e7ede0a7f889df9515f18b9b548433f412affed478d9"}, - {file = "torch-2.0.0-1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ab2da16567cb55b67ae39e32d520d68ec736191d88ac79526ca5874754c32203"}, - {file = "torch-2.0.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:7a9319a67294ef02459a19738bbfa8727bb5307b822dadd708bc2ccf6c901aca"}, - {file = "torch-2.0.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:9f01fe1f6263f31bd04e1757946fd63ad531ae37f28bb2dbf66f5c826ee089f4"}, - {file = "torch-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:527f4ae68df7b8301ee6b1158ca56350282ea633686537b30dbb5d7b4a52622a"}, - {file = "torch-2.0.0-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:ce9b5a49bd513dff7950a5a07d6e26594dd51989cee05ba388b03e8e366fd5d5"}, - {file = "torch-2.0.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:53e1c33c6896583cdb9a583693e22e99266444c4a43392dddc562640d39e542b"}, - {file = "torch-2.0.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:09651bff72e439d004c991f15add0c397c66f98ab36fe60d5514b44e4da722e8"}, - {file = "torch-2.0.0-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d439aec349c98f12819e8564b8c54008e4613dd4428582af0e6e14c24ca85870"}, - {file = "torch-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:2802f84f021907deee7e9470ed10c0e78af7457ac9a08a6cd7d55adef835fede"}, - {file = "torch-2.0.0-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:01858620f25f25e7a9ec4b547ff38e5e27c92d38ec4ccba9cfbfb31d7071ed9c"}, - {file = "torch-2.0.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:9a2e53b5783ef5896a6af338b36d782f28e83c8ddfc2ac44b67b066d9d76f498"}, - {file = "torch-2.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ec5fff2447663e369682838ff0f82187b4d846057ef4d119a8dea7772a0b17dd"}, - {file = "torch-2.0.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:11b0384fe3c18c01b8fc5992e70fc519cde65e44c51cc87be1838c1803daf42f"}, - {file = "torch-2.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:e54846aa63855298cfb1195487f032e413e7ac9cbfa978fda32354cc39551475"}, - {file = "torch-2.0.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:cc788cbbbbc6eb4c90e52c550efd067586c2693092cf367c135b34893a64ae78"}, - {file = "torch-2.0.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:d292640f0fd72b7a31b2a6e3b635eb5065fcbedd4478f9cad1a1e7a9ec861d35"}, - {file = "torch-2.0.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6befaad784004b7af357e3d87fa0863c1f642866291f12a4c2af2de435e8ac5c"}, - {file = "torch-2.0.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:a83b26bd6ae36fbf5fee3d56973d9816e2002e8a3b7d9205531167c28aaa38a7"}, - {file = "torch-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:c7e67195e1c3e33da53954b026e89a8e1ff3bc1aeb9eb32b677172d4a9b5dcbf"}, - {file = "torch-2.0.0-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:6e0b97beb037a165669c312591f242382e9109a240e20054d5a5782d9236cad0"}, - {file = "torch-2.0.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:297a4919aff1c0f98a58ebe969200f71350a1d4d4f986dbfd60c02ffce780e99"}, + {file = "torch-2.1.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:5ebc43f5355a9b7be813392b3fb0133991f0380f6f0fcc8218d5468dc45d1071"}, + {file = "torch-2.1.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:84fefd63356416c0cd20578637ccdbb82164993400ed17b57c951dd6376dcee8"}, + {file = "torch-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:0a7a9da0c324409bcb5a7bdad1b4e94e936d21c2590aaa7ac2f63968da8c62f7"}, + {file = "torch-2.1.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:1e1e5faddd43a8f2c0e0e22beacd1e235a2e447794d807483c94a9e31b54a758"}, + {file = "torch-2.1.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:e76bf3c5c354874f1da465c852a2fb60ee6cbce306e935337885760f080f9baa"}, + {file = "torch-2.1.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:98fea993639b0bb432dfceb7b538f07c0f1c33386d63f635219f49254968c80f"}, + {file = "torch-2.1.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:61b51b33c61737c287058b0c3061e6a9d3c363863e4a094f804bc486888a188a"}, + {file = "torch-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:1d70920da827e2276bf07f7ec46958621cad18d228c97da8f9c19638474dbd52"}, + {file = "torch-2.1.1-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:a70593806f1d7e6b53657d96810518da0f88ef2608c98a402955765b8c79d52c"}, + {file = "torch-2.1.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:e312f7e82e49565f7667b0bbf9559ab0c597063d93044740781c02acd5a87978"}, + {file = "torch-2.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:1e3cbecfa5a7314d828f4a37b0c286714dc9aa2e69beb7a22f7aca76567ed9f4"}, + {file = "torch-2.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:9ca0fcbf3d5ba644d6a8572c83a9abbdf5f7ff575bc38529ef6c185a3a71bde9"}, + {file = "torch-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:2dc9f312fc1fa0d61a565a0292ad73119d4b74c9f8b5031b55f8b4722abca079"}, + {file = "torch-2.1.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:d56b032176458e2af4709627bbd2c20fe2917eff8cd087a7fe313acccf5ce2f1"}, + {file = "torch-2.1.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:29e3b90a8c281f6660804a939d1f4218604c80162e521e1e6d8c8557325902a0"}, + {file = "torch-2.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:bd95cee8511584b67ddc0ba465c3f1edeb5708d833ee02af1206b4486f1d9096"}, + {file = "torch-2.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b31230bd058424e56dba7f899280dbc6ac8b9948e43902e0c84a44666b1ec151"}, + {file = "torch-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:403f1095e665e4f35971b43797a920725b8b205723aa68254a4050c6beca29b6"}, + {file = "torch-2.1.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:715b50d8c1de5da5524a68287eb000f73e026e74d5f6b12bc450ef6995fcf5f9"}, + {file = "torch-2.1.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:db67e8725c76f4c7f4f02e7551bb16e81ba1a1912867bc35d7bb96d2be8c78b4"}, ] [package.dependencies] filelock = "*" +fsspec = "*" jinja2 = "*" networkx = "*" -nvidia-cublas-cu11 = {version = "11.10.3.66", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-cupti-cu11 = {version = "11.7.101", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-nvrtc-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cuda-runtime-cu11 = {version = "11.7.99", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cudnn-cu11 = {version = "8.5.0.96", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cufft-cu11 = {version = "10.9.0.58", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-curand-cu11 = {version = "10.2.10.91", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusolver-cu11 = {version = "11.4.0.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-cusparse-cu11 = {version = "11.7.4.91", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nccl-cu11 = {version = "2.14.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} -nvidia-nvtx-cu11 = {version = "11.7.91", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cudnn-cu12 = {version = "8.9.2.26", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nccl-cu12 = {version = "2.18.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} sympy = "*" -triton = {version = "2.0.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} +triton = {version = "2.1.0", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""} typing-extensions = "*" [package.extras] +dynamo = ["jinja2"] opt-einsum = ["opt-einsum (>=3.3)"] [[package]] @@ -3095,38 +3078,26 @@ telegram = ["requests"] [[package]] name = "triton" -version = "2.0.0" +version = "2.1.0" description = "A language and compiler for custom Deep Learning operations" optional = true python-versions = "*" files = [ - {file = "triton-2.0.0-1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38806ee9663f4b0f7cd64790e96c579374089e58f49aac4a6608121aa55e2505"}, - {file = "triton-2.0.0-1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:226941c7b8595219ddef59a1fdb821e8c744289a132415ddd584facedeb475b1"}, - {file = "triton-2.0.0-1-cp36-cp36m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4c9fc8c89874bc48eb7e7b2107a9b8d2c0bf139778637be5bfccb09191685cfd"}, - {file = "triton-2.0.0-1-cp37-cp37m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d2684b6a60b9f174f447f36f933e9a45f31db96cb723723ecd2dcfd1c57b778b"}, - {file = "triton-2.0.0-1-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9d4978298b74fcf59a75fe71e535c092b023088933b2f1df933ec32615e4beef"}, - {file = "triton-2.0.0-1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:74f118c12b437fb2ca25e1a04759173b517582fcf4c7be11913316c764213656"}, - {file = "triton-2.0.0-1-pp37-pypy37_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9618815a8da1d9157514f08f855d9e9ff92e329cd81c0305003eb9ec25cc5add"}, - {file = "triton-2.0.0-1-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1aca3303629cd3136375b82cb9921727f804e47ebee27b2677fef23005c3851a"}, - {file = "triton-2.0.0-1-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e3e13aa8b527c9b642e3a9defcc0fbd8ffbe1c80d8ac8c15a01692478dc64d8a"}, - {file = "triton-2.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f05a7e64e4ca0565535e3d5d3405d7e49f9d308505bb7773d21fb26a4c008c2"}, - {file = "triton-2.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb4b99ca3c6844066e516658541d876c28a5f6e3a852286bbc97ad57134827fd"}, - {file = "triton-2.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47b4d70dc92fb40af553b4460492c31dc7d3a114a979ffb7a5cdedb7eb546c08"}, - {file = "triton-2.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fedce6a381901b1547e0e7e1f2546e4f65dca6d91e2d8a7305a2d1f5551895be"}, - {file = "triton-2.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75834f27926eab6c7f00ce73aaf1ab5bfb9bec6eb57ab7c0bfc0a23fac803b4c"}, - {file = "triton-2.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0117722f8c2b579cd429e0bee80f7731ae05f63fe8e9414acd9a679885fcbf42"}, - {file = "triton-2.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bcd9be5d0c2e45d2b7e6ddc6da20112b6862d69741576f9c3dbaf941d745ecae"}, - {file = "triton-2.0.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42a0d2c3fc2eab4ba71384f2e785fbfd47aa41ae05fa58bf12cb31dcbd0aeceb"}, - {file = "triton-2.0.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:52c47b72c72693198163ece9d90a721299e4fb3b8e24fd13141e384ad952724f"}, -] - -[package.dependencies] -cmake = "*" + {file = "triton-2.1.0-0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:66439923a30d5d48399b08a9eae10370f6c261a5ec864a64983bae63152d39d7"}, + {file = "triton-2.1.0-0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:919b06453f0033ea52c13eaf7833de0e57db3178d23d4e04f9fc71c4f2c32bf8"}, + {file = "triton-2.1.0-0-cp37-cp37m-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae4bb8a91de790e1866405211c4d618379781188f40d5c4c399766914e84cd94"}, + {file = "triton-2.1.0-0-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:39f6fb6bdccb3e98f3152e3fbea724f1aeae7d749412bbb1fa9c441d474eba26"}, + {file = "triton-2.1.0-0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:21544e522c02005a626c8ad63d39bdff2f31d41069592919ef281e964ed26446"}, + {file = "triton-2.1.0-0-pp37-pypy37_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:143582ca31dd89cd982bd3bf53666bab1c7527d41e185f9e3d8a3051ce1b663b"}, + {file = "triton-2.1.0-0-pp38-pypy38_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:82fc5aeeedf6e36be4e4530cbdcba81a09d65c18e02f52dc298696d45721f3bd"}, + {file = "triton-2.1.0-0-pp39-pypy39_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:81a96d110a738ff63339fc892ded095b31bd0d205e3aace262af8400d40b6fa8"}, +] + +[package.dependencies] filelock = "*" -lit = "*" -torch = "*" [package.extras] +build = ["cmake (>=3.18)", "lit"] tests = ["autopep8", "flake8", "isort", "numpy", "pytest", "scipy (>=1.7.1)"] tutorials = ["matplotlib", "pandas", "tabulate"] @@ -3154,36 +3125,35 @@ files = [ [[package]] name = "urllib3" -version = "2.0.7" +version = "2.1.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, + {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.6" +version = "20.25.0" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, - {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -platformdirs = ">=3.9.1,<4" +platformdirs = ">=3.9.1,<5" [package.extras] docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] @@ -3206,20 +3176,6 @@ MarkupSafe = ">=2.1.1" [package.extras] watchdog = ["watchdog (>=2.3)"] -[[package]] -name = "wheel" -version = "0.41.3" -description = "A built-package format for Python" -optional = true -python-versions = ">=3.7" -files = [ - {file = "wheel-0.41.3-py3-none-any.whl", hash = "sha256:488609bc63a29322326e05560731bf7bfea8e48ad646e1f5e40d366607de0942"}, - {file = "wheel-0.41.3.tar.gz", hash = "sha256:4d4987ce51a49370ea65c0bfd2234e8ce80a12780820d9dc462597a6e60d0841"}, -] - -[package.extras] -test = ["pytest (>=6.0.0)", "setuptools (>=65)"] - [[package]] name = "zipp" version = "3.17.0" From 5f0b5a91d794fb42764af8378dab0bc03657a84e Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 5 Dec 2023 16:25:40 +0100 Subject: [PATCH 51/80] add save/load experiment user guide --- docs/basics/userguide/save_load.md | 158 +++++++++++++++++++++++++++++ docs/user_guide2.md | 23 ++++- 2 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 docs/basics/userguide/save_load.md diff --git a/docs/basics/userguide/save_load.md b/docs/basics/userguide/save_load.md new file mode 100644 index 000000000..8b35c4a59 --- /dev/null +++ b/docs/basics/userguide/save_load.md @@ -0,0 +1,158 @@ +(save_load_page)= + +# How to save/load an experiment + + +For this example, we'll use the same code as [ExperimentManager](ExperimentManager_page) (from User Guide), and use the save and load functions. + +## how to save an experiment + +To save your experiment, you have to train it first (with `fit()`), then you just have to use the `save()` function. + +Train the Agent : +```python +from rlberry.envs import gym_make +from rlberry_scool.agents.tabular_rl import QLAgent +from rlberry.manager import ExperimentManager + +from rlberry.seeding import Seeder + +seeder = Seeder(123) # seeder initialization + +env_id = "FrozenLake-v1" # Id of the environment +env_ctor = gym_make # constructor for the env +env_kwargs = dict( + id=env_id, is_slippery=False +) # give the id of the env inside the kwargs + + +experiment_to_save = ExperimentManager( + QLAgent, # Agent Class + (env_ctor, env_kwargs), # Environment as Tuple(constructor,kwargs) + init_kwargs=dict( + gamma=0.95, alpha=0.8, exploration_type="epsilon", exploration_rate=0.25 + ), # agent args + fit_budget=int(300000), # Budget used to call our agent "fit()" + n_fit=1, # Number of agent instances to fit. + seed=seeder, # to be reproductible + agent_name="PPO" + env_id, # Name of the agent + output_dir="./results/", # where to store the outpus +) + +experiment_to_save.fit() +print(experiment_to_save.get_agent_instances()[0].Q) # print the content of the Q-table +``` +Then save: +```python +experiment_to_save.save() # save the model inside the 'output_dir' +``` + +```none +[INFO] 11:11: Running ExperimentManager fit() for PPOFrozenLake-v1 with n_fit = 1 and max_workers = None. +[INFO] 11:11: agent_name worker episode_rewards max_global_step + PPOFrozenLake-v1 0 0.0 178711 +[INFO] 11:11: ... trained! +/home/jteigny/my_projects/work_in_progress/rlberry/rlberry_userguide/user_guide/rlberry/utils/writers.py:108: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation. + df = pd.concat([df, pd.DataFrame(self._data[tag])], ignore_index=True) +[[0.73509189 0.77378094 0.77378094 0.73509189] + [0.73509189 0. 0.81450625 0.77378094] + [0.77378094 0.857375 0.77378094 0.81450625] + [0.81450625 0. 0.77377103 0.77378092] + [0.77378094 0.81450625 0. 0.73509189] + [0. 0. 0. 0. ] + [0. 0.9025 0. 0.81450625] + [0. 0. 0. 0. ] + [0.81450625 0. 0.857375 0.77378094] + [0.81450625 0.9025 0.9025 0. ] + [0.857375 0.95 0. 0.857375 ] + [0. 0. 0. 0. ] + [0. 0. 0. 0. ] + [0. 0.9025 0.95 0.857375 ] + [0.9025 0.95 1. 0.9025 ] + [0. 0. 0. 0. ]] +[INFO] 11:11: Saved ExperimentManager(PPOFrozenLake-v1) using pickle. +``` + +After this run, you can see the 'print' of the q-table, and should find a folder named according to the `output_dir` parameter (here `results`), with the data about your experiment. +In this folder, you should find : +- `manager_obj.pickle` and folder `agent_handler`, the save of your experiment and your agent. +- `data.csv`, the episodes result during the training process + + +## How to load a previous experiment? +In this example you will load the experiment saved in the part 1. + +To load an experiment previously saved, you need to : +- Locate the file you want to load +- use the function `load()` from the class [ExperimentManager](rlberry.manager.ExperimentManager.load). + +```python +import pathlib +from rlberry.envs import gym_make +from rlberry.manager.experiment_manager import ExperimentManager + + +path_to_load = next( + pathlib.Path("results").glob("**/manager_obj.pickle") +) # find the path to the "manager_obj.pickle" + +loaded_experiment_manager = ExperimentManager.load(path_to_load) # load the experiment + +print( + loaded_experiment_manager.get_agent_instances()[0].Q +) # print the content of the Q-table +``` +If you want to test the agent from the loaded Experiment, you can add : + +```python +env_id = "FrozenLake-v1" # Id of the environment +env_ctor = gym_make # constructor for the env +env_kwargs = dict( + id=env_id, is_slippery=False +) # give the id of the env inside the kwargs +test_env = env_ctor(**env_kwargs) # create the Environment + +# test the agent of the experiment on the test environment +observation, info = test_env.reset() +for tt in range(50): + action = loaded_experiment_manager.get_agent_instances()[0].policy(observation) + next_observation, reward, terminated, truncated, info = test_env.step(action) + done = terminated or truncated + if done: + if reward == 1: + print("Success!") + break + else: + print("Fail! Retry!") + next_observation, info = test_env.reset() + observation = next_observation +``` + +```none +[[0.73509189 0.77378094 0.77378094 0.73509189] + [0.73509189 0. 0.81450625 0.77378094] + [0.77378094 0.857375 0.77378094 0.81450625] + [0.81450625 0. 0.77377103 0.77378092] + [0.77378094 0.81450625 0. 0.73509189] + [0. 0. 0. 0. ] + [0. 0.9025 0. 0.81450625] + [0. 0. 0. 0. ] + [0.81450625 0. 0.857375 0.77378094] + [0.81450625 0.9025 0.9025 0. ] + [0.857375 0.95 0. 0.857375 ] + [0. 0. 0. 0. ] + [0. 0. 0. 0. ] + [0. 0.9025 0.95 0.857375 ] + [0.9025 0.95 1. 0.9025 ] + [0. 0. 0. 0. ]] +Success! +``` + +As you can see, we haven't re-fit the experiment, and the q-table is the same as the one previously saved (and the Agent can finish the environment). + +## Other informations + +The `save` and `load` can be use if : +- you want to train your agent on a computer, and test/use it on others. +- you have a long training, and you want to do some 'checkpoints'. +- you want to do the training in more than once (only if your agent has "fit(x) then fit(y), is the same as fit(x+y)") diff --git a/docs/user_guide2.md b/docs/user_guide2.md index f8a65424a..36c539d1a 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -42,11 +42,26 @@ You can find the guide for Logging [here](logging_page). ## Experimenting with Bandits. ## Reproducibility ### Seeding -In rlberry you can use a seed to generate pseudo-"random number". Most of the time, it allow you to re-run the same algorithm with the same pseudo-"random number", and make your experiment reproducible. -You can find the guide for Seeding [here](seeding_page). +In rlberry you can use a seed to generate pseudo-"random number". Most of the time, it allow you to re-run the same algorithm with the same pseudo-"random number", and make your experiment reproducible.You can find the guide for Seeding [here](seeding_page). + +### Saving and Loading Experiment +You can save and load your experiments. +It could be useful in many way : +- don't repeat the training part every time. +- continue a previous training (or doing checkpoint). + +You can find the guide for Saving and Loading [here](save_load_page). +### Saving and Loading Agents +### Saving and Loading Data + + -### Saving and Loading Agents -### Saving and Loading Data ## Advanced Usage ### Custom Agents ### Custom Environments From ff6a71fe8cc866937d96f8f14b1a9df0d4c03d4b Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Tue, 16 Jan 2024 09:43:29 +0100 Subject: [PATCH 52/80] UCBVI in now in rlberry_research --- docs/basics/quick_start_rl/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 77659cb9e..e26bd7745 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -17,7 +17,7 @@ import numpy as np import pandas as pd import time from rlberry.agents import AgentWithSimplePolicy -from rlberry_scool.agents import UCBVIAgent +from rlberry_research.agents import UCBVIAgent from rlberry_research.envs import Chain from rlberry.manager import ( ExperimentManager, From 66880e66a88fab4be76e525df9a2856eb8874cc5 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 09:26:13 +0100 Subject: [PATCH 53/80] first corrections from review --- docs/basics/quick_start_rl/quickstart.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index e26bd7745..00d9101f1 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -31,19 +31,19 @@ from rlberry.wrappers import WriterWrapper Choosing an RL environment -------------------------- -In this tutorial, we will use the [Chain](rlberry.envs.finite.chain.Chain) +In this tutorial, we will use the Chain(from [rlberry_scool]((https://github.com/rlberry-py/rlberry-scool))) environment, which is a very simple environment where the agent has to go from one end of a chain to the other end. ```python env_ctor = Chain env_kwargs = dict(L=10, fail_prob=0.1) -# chain of length 10. With proba 0.1, the agent will not be able to take the action it wants to take/ +# chain of length 10. With proba 0.1, the agent will not be able to take the action it wants to take. env = env_ctor(**env_kwargs) ``` -The agent has two actions, go to the left of to the right, but it might -move to a random direction according to a failure probability +The agent has two actions, going left or going right, but it might +move in the opposite direction according to a failure probability `fail_prob=0.1`. Let us see a graphical representation @@ -111,16 +111,12 @@ video = env.save_video("video_chain.mp4", framerate=5) Defining an agent and a baseline -------------------------------- -We will compare a RandomAgent (which plays random action) to the -[UCBVIAgent](rlberry.agents.ucbvi.ucbvi.UCBVIAgent), which is a algorithm that is designed to perform an +We will compare a RandomAgent (which select random action) to the +UCBVIAgent(from [rlberry_research]((https://github.com/rlberry-py/rlberry-research))), which is a algorithm that is designed to perform an efficient exploration. Our goal is then to assess the performance of the two algorithms. -There are a number of agents that are already coded in rlberry. See the -module [Agent](rlberry.agents.Agent) for more -informations. - -Or, as we want for the RandomAgent, you can code your own agent : +You can code your RandomAgent agent : ```python # Create random agent as a baseline From cc505c37a7d65da0f77f5a82f603f117a59caeb4 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 09:45:40 +0100 Subject: [PATCH 54/80] update link and typo --- docs/basics/quick_start_rl/quickstart.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 00d9101f1..0b0fa45e6 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -31,7 +31,7 @@ from rlberry.wrappers import WriterWrapper Choosing an RL environment -------------------------- -In this tutorial, we will use the Chain(from [rlberry_scool]((https://github.com/rlberry-py/rlberry-scool))) +In this tutorial, we will use the Chain(from [rlberry_scool](https://github.com/rlberry-py/rlberry-scool)) environment, which is a very simple environment where the agent has to go from one end of a chain to the other end. @@ -112,11 +112,11 @@ Defining an agent and a baseline -------------------------------- We will compare a RandomAgent (which select random action) to the -UCBVIAgent(from [rlberry_research]((https://github.com/rlberry-py/rlberry-research))), which is a algorithm that is designed to perform an +UCBVIAgent(from [rlberry_research](https://github.com/rlberry-py/rlberry-research)), which is a algorithm that is designed to perform an efficient exploration. Our goal is then to assess the performance of the two algorithms. -You can code your RandomAgent agent : +This is the code to create your RandomAgent agent : ```python # Create random agent as a baseline From bc7a9f04a86985ed07f7a5f36aafdc41161fa592 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 10:39:20 +0100 Subject: [PATCH 55/80] update "center alignment" for images --- docs/basics/quick_start_rl/quickstart.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 0b0fa45e6..9a4b52cbf 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -143,7 +143,10 @@ One of the main feature of rlberry is its [ExperimentManager](rlberry.manager.ExperimentManager) class. Here is a diagram to explain briefly what it does. -![](experiment_manager_diagram.png){.align-center} + +```{image} experiment_manager_diagram.png +:align: center +``` In a few words, ExperimentManager spawns agents and environments for training and then once the agents are trained, it uses these agents and @@ -237,7 +240,9 @@ output = evaluate_agents([ucbvi_stats, baseline_stats], n_simulations=10, plot=T
-![image](output_10_1.png){.align-center} +```{image} output_10_1.png +:align: center +``` Comparing the agents during the learning period ----------------------------------------------- @@ -374,4 +379,6 @@ output = plot_writer_data( ) ``` -![image](output_19_0.png){.align-center} +```{image} output_19_0.png +:align: center +``` From 61cea45c98bbf8da1c924cbb2c2f83e814942a53 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 10:51:54 +0100 Subject: [PATCH 56/80] typo --- docs/basics/quick_start_rl/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 9a4b52cbf..ad852f26e 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -151,7 +151,7 @@ class. Here is a diagram to explain briefly what it does. In a few words, ExperimentManager spawns agents and environments for training and then once the agents are trained, it uses these agents and new environments to evaluate how well the agent perform. All of these -steps can be done several times to assess stochasticity of agents and/or +steps can be done several times to assess the stochasticity of agents and/or environment. Comparing the expected rewards of the final policies From 2fb38275dbd3956d73047b5d2e4df309ccea8c63 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 11:53:44 +0100 Subject: [PATCH 57/80] update text on comparing agents --- docs/basics/quick_start_rl/quickstart.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index ad852f26e..0f0292492 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -160,18 +160,19 @@ Comparing the expected rewards of the final policies We want to assess the expected reward of the policy learned by our agents for a time horizon of (say) $T=20$. -To do that we use 10 Monte-Carlo simulations, i.e., we do the experiment -10 times for each agent and at the end we take the mean of the obtained -reward. +To evaluate the agents during the training, we can (arbitrary) use 10 Monte-Carlo simulations (```n_simulations``` in eval_kwargs), i.e., we do the evaluation 10 times for each agent and at the end we take the mean of the obtained reward. To check variability, we can train many instance of the same agent with -`n_fit` (here 1) Each instance of agent will train with a specific +`n_fit` (here, we use only 1 to be faster). Each instance of agent will train with a specific budget `fit_budget` (here 100). Remark that `fit_budget` may not mean the same thing among agents. In order to manage the agents, we use an Experiment Manager. The manager will then spawn agents as desired during the experiment. +To summarize: +We will train 1 agent (```n_fit```) with a budget of 100 (```fit_budget```). During the training, the evaluation will be on 10 Monte-Carlo run (```n_simulations```), and we doing it for both Agent (```UCBVIAgent``` and ```RandomAgent```) + ```python # Define parameters ucbvi_params = {"gamma": 0.9, "horizon": 100} From 3efb754a474ba99eca268a3e9ab71e462d0802c7 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 12:12:03 +0100 Subject: [PATCH 58/80] add link to comparison page --- docs/basics/comparison.md | 1 + docs/basics/quick_start_rl/quickstart.md | 2 ++ 2 files changed, 3 insertions(+) diff --git a/docs/basics/comparison.md b/docs/basics/comparison.md index cd57d4a3b..75041a9c0 100644 --- a/docs/basics/comparison.md +++ b/docs/basics/comparison.md @@ -1,3 +1,4 @@ +(comparison_page)= # Comparison of Agents diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 0f0292492..b59c384c9 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -245,6 +245,8 @@ output = evaluate_agents([ucbvi_stats, baseline_stats], n_simulations=10, plot=T :align: center ``` + : For more in depth methodology to compare agents, you can check [here](comparison_page) + Comparing the agents during the learning period ----------------------------------------------- From f8493c0f6958f5660d115ffada1f6980ac4b4ec1 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 12:14:21 +0100 Subject: [PATCH 59/80] typo --- docs/basics/quick_start_rl/quickstart.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index b59c384c9..23fe1e834 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -256,7 +256,7 @@ policies learned by the agents, **after** the learning period. To compare the performance of the agents **during** the learning period (in the fit method), we can estimate their cumulative regret, which is the difference between the rewards gathered by the agents during -training and the rewards of an optimal agent. Alternatively, if the we +training and the rewards of an optimal agent. Alternatively, if we cannot compute the optimal policy, we could simply compare the rewards gathered during learning, instead of the regret. From 49099922a032cf16935832227212b0299b651123 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 14 Feb 2024 16:14:36 +0100 Subject: [PATCH 60/80] update from review --- docs/user_guide2.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/user_guide2.md b/docs/user_guide2.md index 36c539d1a..ebe05895e 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide2.md @@ -2,6 +2,9 @@ # User Guide + +You can find a compacted version [here](#compacted-version). + ## Introduction Welcome to rlberry. Use rlberry's [ExperimentManager](experimentManager_page) to train, evaluate and compare rl agents. @@ -35,11 +38,15 @@ You can find the guide for ExperimentManager [here](experimentManager_page). Logging is used to keep a trace of the experiments. It's include runing informations, data, and results. You can find the guide for Logging [here](logging_page). ### Analyse the results +In construction ## Experimenting with Deep agents ### Torch Agents +In construction ### Policy and Value Networks +In construction ## Experimenting with Bandits. +In construction ## Reproducibility ### Seeding In rlberry you can use a seed to generate pseudo-"random number". Most of the time, it allow you to re-run the same algorithm with the same pseudo-"random number", and make your experiment reproducible.You can find the guide for Seeding [here](seeding_page). @@ -52,7 +59,9 @@ It could be useful in many way : You can find the guide for Saving and Loading [here](save_load_page). ### Saving and Loading Agents +In construction ### Saving and Loading Data +In construction ### Custom Agents +In construction ### Custom Environments +In construction ### Transfer Learning +In construction + + +# Compacted version +## Set up an experiment +- [Environment](environment_page) +- [Agent](agent_page) +- [ExperimentManager](experimentManager_page) +- [Logging](logging_page). +- [Analyse the results (In construction)]() +## Experimenting with Deep agents +- [Torch Agents (In construction)]() +- [Policy and Value Networks (In construction)]() +- [Experimenting with Bandits (In construction)]() +## Reproducibility +- [Seeding](seeding_page) +- [Save & Load Experiment](save_load_page) +- [Save & Load Agents (In construction)]() +- [Save & Load Data (In construction)]() +## Advanced Usage +- [Custom Agents (In construction)]() +- [Custom Environments (In construction)]() +- [Transfer Learning (In construction)]() From 67ed9ea45cd7f91ed035b9c0b7a9ac356a8ad943 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 15 Feb 2024 10:27:24 +0100 Subject: [PATCH 61/80] update "notes" icon --- docs/basics/quick_start_rl/quickstart.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 23fe1e834..9bb3503c0 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -245,7 +245,7 @@ output = evaluate_agents([ucbvi_stats, baseline_stats], n_simulations=10, plot=T :align: center ``` - : For more in depth methodology to compare agents, you can check [here](comparison_page) + : For more in depth methodology to compare agents, you can check [here](comparison_page) Comparing the agents during the learning period ----------------------------------------------- @@ -385,3 +385,11 @@ output = plot_writer_data( ```{image} output_19_0.png :align: center ``` + + + + + + + + : For more informations on plots and visualisation, you can check [here (in construction)](visualisation_page) From 03cc647ff828bb35dfb29663512d7ab32be42a58 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 15 Feb 2024 10:29:57 +0100 Subject: [PATCH 62/80] typo --- docs/basics/userguide/agent.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/basics/userguide/agent.md b/docs/basics/userguide/agent.md index 03e8ec79b..f6a5b0a35 100644 --- a/docs/basics/userguide/agent.md +++ b/docs/basics/userguide/agent.md @@ -1,12 +1,12 @@ (agent_page)= # How to use an Agent -In Reinforcement learning, the Agent is the entity to train to solve an environment. It's able interact with the environment: observe, take actions, and learn through trial and error. +In Reinforcement learning, the Agent is the entity to train to solve an environment. It's able to interact with the environment: observe, take actions, and learn through trial and error. In rlberry, you can use existing Agent, or create your own custom Agent. You can find the API [here](/api) and [here](rlberry.agents.Agent) . ## Use rlberry Agent -An agent need an environment to train. We'll use the same environment as in the [environment](environment_page) section of the user guide. +An agent needs an environment to train. We'll use the same environment as in the [environment](environment_page) section of the user guide. ("Chain" environment from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)") ### without agent @@ -129,7 +129,7 @@ The agent has learned how to obtain good results (the cross go to the right). ## Use StableBaselines3 as rlberry Agent -With rlberry, you can use algorithm from [StableBaselines3](https://stable-baselines3.readthedocs.io/en/master/guide/algos.html) and wrap it in rlberry Agent. To do that, you need to use [StableBaselinesAgent](rlberry.agents.stable_baselines.StableBaselinesAgent). +With rlberry, you can use an algorithm from [StableBaselines3](https://stable-baselines3.readthedocs.io/en/master/guide/algos.html) and wrap it in rlberry Agent. To do that, you need to use [StableBaselinesAgent](rlberry.agents.stable_baselines.StableBaselinesAgent). ```python @@ -442,5 +442,5 @@ Moviepy - video ready /FrozenLake_no_slippery-episode-0.mp4 ## Use experimentManager -This is one of the core element in rlberry. The ExperimentManager allow you to easily make an experiment between an Agent and an Environment. It's use to train, optimize hyperparameters, evaluate and gather statistics about an agent. +This is one of the core element in rlberry. The ExperimentManager allows you to easily make an experiment between an Agent and an Environment. It is used to train, optimize hyperparameters, evaluate and gather statistics about an agent. You can find the guide for ExperimentManager [here](experimentManager_page). From 714e36fd5d767d707c7fd8f230ae8bee3c0fd3e3 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 15 Feb 2024 10:36:49 +0100 Subject: [PATCH 63/80] add informations about gymnasium --- docs/basics/userguide/environment.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/basics/userguide/environment.md b/docs/basics/userguide/environment.md index fe8406df6..bc470e4e6 100644 --- a/docs/basics/userguide/environment.md +++ b/docs/basics/userguide/environment.md @@ -82,7 +82,9 @@ video:10kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing ov ## Use Gymnasium environment -Gymnasium can give you some classic environment. You can use theme with [gym_make](rlberry.envs.gym_make). More information [here](https://gymnasium.farama.org/environments/classic_control/). +Gymnasium is a project that provides an API for all single agent reinforcement learning environments, and includes implementations of common environments: cartpole, pendulum, mountain-car, mujoco, atari, and more.More information [here](https://gymnasium.farama.org/environments/classic_control/). + +In rlberry, you can use Gymnasium environment with [gym_make](rlberry.envs.gym_make). Here, we will use ```MountainCar-v0```, one of the "Classic Control environments". ```python from rlberry.envs import gym_make From 0fd46d0a3e117bc3f182892ed48290fc7ac0567f Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 15 Feb 2024 15:06:04 +0100 Subject: [PATCH 64/80] update images and visualisation part --- docs/basics/quick_start_rl/Figure_1.png | Bin 0 -> 12492 bytes docs/basics/quick_start_rl/Figure_2.png | Bin 0 -> 109571 bytes docs/basics/quick_start_rl/Figure_3.png | Bin 0 -> 66623 bytes docs/basics/quick_start_rl/output_10_1.png | Bin 6004 -> 0 bytes docs/basics/quick_start_rl/output_19_0.png | Bin 20886 -> 0 bytes docs/basics/quick_start_rl/quickstart.md | 77 +++++---------------- 6 files changed, 19 insertions(+), 58 deletions(-) create mode 100644 docs/basics/quick_start_rl/Figure_1.png create mode 100644 docs/basics/quick_start_rl/Figure_2.png create mode 100644 docs/basics/quick_start_rl/Figure_3.png delete mode 100644 docs/basics/quick_start_rl/output_10_1.png delete mode 100644 docs/basics/quick_start_rl/output_19_0.png diff --git a/docs/basics/quick_start_rl/Figure_1.png b/docs/basics/quick_start_rl/Figure_1.png new file mode 100644 index 0000000000000000000000000000000000000000..61bdfd114d22ede5165c7f516ff42d0fdc91f276 GIT binary patch literal 12492 zcmeHtXH-;a*X0ET6|1c#hBv}xI zgf!*kF{*3CaI1?e)hTxATNU43)^}>xHwEyWrU>}$y%4|hElbhcOabKy86PcGM~u$i3<33ujAqp>TltVdHh)7VGY(JtgfaO)7NKS)ti3{ zUtd|wu{(c$3(Gpf*Yb5&Mc#Y4Z)ZIq6celeZP|)V z8#l&vbaYf?a&vMf-MxF)|ISL{=naGnE&J)yx>Bz>wq_%D_rj)JD;?vxWkk#_b%H69 z`-!ruDt$;sS6BDU*|W8>qs4L4)6+&Ryab_gifK9DjqBGheEY+|(^D?a18)-W@F?Q& zmlI5gREb~kazvTLCi0_~Y6R2&?k~PRWs#7S)N*NaONxz+?XoYJ`1Xd^Lo`oBSyg^A zc-QXT9NV^~x0QHURYl2vzs^Ds$;Ty!)~e~MM9HOGzrK78j|_ETZi;?!Mp?Who<83# zu9tu1(IpcTNz?L8lf%tA?VgN)YuBz>pT1L`ZC15CQtE1K%iO#2^6}Z+;^QYy)a6*z zur+cL1l_M9Tcl!ST}WlOy~WIU_dr8dbi6~HkGi@#mx6ckc8{Tb6b*0h(ibmZ=3acx z-0HKmpp(;n?HY4It8I60uds+ndUj{rw(moYalclEH}ZU?IghrTTeaL*=yh)%dk|sx zVR2zD^^- zssHWUP90@Tum1W=KuRkA!d!WIxyGeSmu}oS%S?<}ZPg_l931vgzI^#&$awkkrF@0h zUTJCFn#6NywbseozJ2><*^p^aFjbSF9L9Ef8R1*v`F-!*atXKb%UHCBp|rHLvl8HG zy6%pM@A~!YY4N+20$nQ=?7RLjYkakwl~qVYGLgfxg5=g(S@kZwRp`nRU@*eJqZvwdaDQC`{slLXt`k?WP<&ko38tg}= zW5&nFYZ3k#db$2)B$P(?K4p2V6tumtW%pVGv9Ltd=*<3_BpqWRtYU7f+nOD?@w@+f zq4z$Q^9n*p|D;XWHHNeD%?QS5WJhtUfAVm)EGto_w(00}@y(_c0!Joy3f7JAE%6)n z+A|RsSFr8yYdIZpv7V$S@};)RJdlZdEjU9h0$CT{Muj*g24F0D@PJrB$->w3x~ z`NnKsdvlK67B5Xc+~#^>HK!Q0B2+X4fwA+1-`inltJ-9B=Qqoc`v+fdE~|WacyOd> zw0=0RU5w&?>(;001m(%@Fr%gj0Dg@9Ru8u6*W7ls;gVK49#giI>OdaZoU30ITipjU z4)K#Wx$ruWPzgUsVPRoGcHN`X>1ULcCtDn(;F#${2djn2KJ=AEPz%@$**}?6k24tZSrHKtLT9mXwS9NwSuRki zd`u$?QNH+v?R%rGKo;{v?x}_?|tlM!?UABUS1wk9D#P!wgED zhns}X0987QwrLR?H*6?QtcsA119lC!6lhW?ltT&l5>FTMefn!`|=Wj zR)bfxJ_AVY(8m*7ZSxv(qNAh358II_mZlng7T0S?dhZ6%}gO0A^t?N3R;%duEb(Smj>ALm>7f2W+#w-v8`1LbcgoJOE1MaoB zxG3X3(Z|B@neFGFnVW0Ai>)i0l1e2E2W}k%im4C1{rg)g9~^j- z=}N}#tMx2bmKGOi@u->uaY08kS__?QRFJa>VRfQPKhHL@6(LV}M#Zsp(2w-ZT&0=F`8^ zy4HaZe_d6j`t@}HqeT#aT{BTGoHgIc^8!!K-;bUBchNreHAsOZF0}Zb%7+_8SiI%LA8Yn>;}&sq@QNfBDF5S8Qw~ zg|+d1NnT$T8@ubq&6`FNbmNzP5zI*a?J#>Idx%nlH{-T8T!Jaq8TrOfDj#g*rfS^w5(LS_R_+haI4_EcXv>lo|xQ3y~%N( z9AJ~L#}TEA85Aa)RYlFdQCNJ$x`xXf{5KV6dt*CZvCIOmsGn<@An)+h|B8&zA6%FXLNNR$T;@J^hWy_(rTaC=#x=~NLJU-s6LfPQBkP} z<4)bbmq43yzhQ$Sp(rhwtw33o9tJGs@q+OBuS48*_a4yuJ+E z;aX}pUEEsalBOP~7}l~^LPG7g-+l}ESrNmK&ijt6&BrGQO;YYPSQlaj`lxP0w_?tkUryy>~dZAa ze{a!l{5377#Br2TUQtm~?8XQV3E4v-se<2H9-+Ku8;AY4qP-*e;nC{qYR6Wm1`9x( zjQ4zgAg=;RCCH@LR8;h9{f6s2uf-`6SYleyNTISr?+2{_uHM*4c@OQEH`yER?=uMw z54UtUj@1vKqDqL0R;JBUGy=FJN&fEC_wo7b%eYDDOZ6n*moHv8j&(d=-P7CEC4d_9 zPsAQ8og1lnZ2WQpoKA?JUkNRV-ZSe5e(b!N=#QIt$hyuiHLz){LYyuVR*|5v_$^2V zn9Y}hK8s7*KHkvv3(LbA?8r1L_Sx5$APfH)1RA<$K1zduOC)NOwF-8!Ll(PKwR+Vm zb#yMnf%r+sJ!^4a^p6ebIW}$HoQNLH$hkG>$ZWE|26;!Z=G8IH!=V-3G{+IK4h9{$ zceML)2?37i>P<%KQNWDYeIrN;h9&M=UOVs=FETFQd%->Oh}Z13 znIx6SY9xm3iCy@r-DFPiA_Z&BlA|y6JhTgb_;B!n7-({;R+{5volf)mHGcn;3x0I0 zllGmRovxniiLxg^`sN&q-C-4b!YZ6TX_h>H{@i^yx54@}tL9}hvoxTxPLA!ROP%7G z_oAXQL2^P4ZzhP47e8x9wuo{7_u=|5BkvSIi)$#$^5w}uw(+T{ynQ=84N%UjYih)c zRIXlqvUZykS$-&BLNZG+QHZy#8eVNY`!nCjB`R|-9 z>+G@pjlpD1bU{t@o*T|9?2Yo6m~1er=(g{l@93Jjc>-0sY3tvoyiX!dDM;JeIz4c^ zeCpl1>lPT%OH@nCR1#4p2OFCIjt0x+SI{8n6**^Q77hr_%*?z)Wilvo2Di>u4B$!_ zZq94wK@E&)a;RN-(ZV7Ho&Fw*j)7CiS{@lb3i9<&Y>BBES(u|qeAmvHrE5EgoEL5J|3`l^^l^w5Y({!qSGSF9Gpn&%7FFJk)VzpjHBq*XP*MF&n>Jnk`9VjrW*MS3GdkRL>Ns?m_Z+t|2(h7fU|4T%{)oTzWAsRvVWux64oa5t zl-=gE@hxzE^6l;*GVl=bp#$|9gOj-X(HSsLmHQIMtQs=wP=z0rl^rcv_}(0T$R->L zQI7eiT}5BX++3~{$-IaIAwQYy`*h-j-!JMoj@o$2MoG)s)3-Ur>tl}nJ`{-PQyZ4H zTt0@?TDIgriFat2i}V>%2EPaaeElN`m_O%VH5qQF8__mFikoWlP^~Wb^Ep@|b>N8+ zAO=+-VC#WI4YGz`JPf2kZ)%R1p~X|~?d?ZI>!_*SeGRC5!|PLA9av=3e5hom=V9UE z?4a=QkK+3!*^0!{!5Od7wvv#@$P92_NsH?E>T+FUW3tA_7dZ3|G@3%18-YivMZ!F+tCf6vSjA`^D2`|mq>|(q~25XC9ed9IlIPe)AF}( zKR&Z*&NN@3(Kdtx2fHS&W@8f)M${ZlxQe_$6v#LaB_ouDQH4QOYF6-ic4!p}0Xzd0 zgSKb9y3HvpAkgRk3}rjCdH8#AY+RhM9QyU6rVhHHrj0zE?Yf}}$V;ntv^}$+JX+w5 zSg6(F{0xWl9rS?br&=6><`)*^8R&ev?F+hkdy}x3EYs>&N+gK~*{^D-Wg^thAz0Dr zb1%#czh$1z+P{DQLF>;FUVuR%5U0lrQBqfrw|h-RHWXvq1;oTuHu9@b)3h_Zuky|_ zF%vPfUl`5C4Mfz`!c;rC8olhxx12{>Qa(h=4&rRGKAK$j^D|T%x2#J|n4KInQlG&w zCTF4^Kp;FvHuYqK1mGi&fkRk3864wBLp`ySB`W`!)2AQHeh|O3ax047 z%__T_0mODWS2eM)iV^aVk5r-*TrIdTJI|;JL0?Ed|0b{ZUA~1WpQXG*wk_rkGGx+` zVDjZAFUbMf)~>DpKHMxHbO9*Vz^GEN`?pJmo>p0Yh>#8kskE$5?|;yqpv;M`=<|K# z`431PY06awC8A#}Z64M(G&HPRffO1$1|Wf&*Hq*(%ECZzo%}k0``=oVz%BcZ17_>N zN^vBPeIIv<8Wx`qlK*~RF>ss3Kfvxy*;$AerlzKah+-`&HGZVENEn=pyl%VKg!(^{ zP=4iXaZQq{6=E7+h7wrZTa5^v)i|qEHS5UZ~oaQPy!2C(b^IrLH`fB zBKr!7z5M)xe%!WdFf!1&BzrH+S^$ll-{9<$sfwIsWaonDsOL2De59(dKqZ^-=p$Z^ z<6V@ZIA9-@>t_{?=mgkMU;3@dHGav8R%n5%eL2*rVJ1f(Wh_ zFDAnGdH!l-8Tcxo!gUim0oe`I9bOaP@20eE6HPc^czz zF!isud}_K_v9D!DtZhpl1YMSRrqmTb`<%ZWE3)mT>aWi=VEfQ4%47e*Rq;xj?WtPl zMxJH)B6y{kCii47-%d?ln#QooxKF2(7-z?2*jz_*sQ|CTHLAkKW%2et^7?35!2;ux zlLc5vDW!ew3BwzUPi(u?q%W>re-l$()f^V~}S(7Wve1-DktJ;4R zycks@X@8ipo$=hbGNNjld3ts*%L)=yd1a;6@#EJFJ%%NnhCY89IZyZ+U8&R3v6vqF z!ckb|@1D4$!|_9bO*!jm>0BnzIVnXmNoe=(6RTFO8febT0{yjg0Xy|QV=}R_3`EFe6YAg^?-g1l{y8w)IUrm@fq<~|DHie z?j~a9(TM~{MR_+m{fj|0%{jG#>VjLe@A_dwNi(j(bh?d}s~~oL5qfy)F|M+$cS=@u zrKV-lpu7ielkSvUdi&>Y|3Ci7?>mG}n}n|3kbCzuIn;r4Lcvd1BtXT%=o_Hu%Q4`8 z<@{R7_ihd3#!D`!I@T{>tVo)fHPEd8=4A>X7mRD8vI>M%^TOQrcYP1YI@}kgx zzzKfcXU8m<#i;rSD19uw3M!XIuR`9rMX_JlE=os$&(KJh+F=78Yz15LxNTnZ$d+dv zX&vQ{{wtqb?Hx20T$~XRvCV`ovvN#p-t*zBY!UKT5WmJ52N;%8ibTb8bU_Ul90FSR zsl5XFPx}&{n-to6B%HcNDO&b%HA4U24qrcf#%d z$3_1#w}55}yk`1q5IScnH+-g??egyCC?1^ejUHe8ZJ;*gD_J!@Zd8?fl%Fq!Jrvxv z>o|yNy%Mii*G%SHT>iG(-pvqkRS14P+3M0xp^;SL)tfg)2j4vZeML8X5BkEe9c}vY zH9KJYuv zs2)(ONUmWq-t`U~SPlInw1p$*&{LoUMmZ_n+42bb#o)(BC-k0Nx?yi`AAJA50EN^L zVY=tKF?v=9K0$9UY5iF(uhm&Uq(r=IZC;E0ZRp|YcJu{pI04lU?MhRSvrRl{$2mAS zEI_xzC5*5A=)tyi9DYQ+aP?VaM3dI7O>3bRL{Q65u{RLGiR*VO3LH3~nQPVXJ)L{Q zhS)#;Sb0iOaX?}5tHK1@Apw8@tv2x-H!c{t#=g8FI|oZa7nq{BrqpYFsVI&O)XqOJ zP@C?(PzzbeYqmd$7LTTovTViLT2jJ8Ef)_8%bh2?15nef zv9T+4DVj$P_?zM| zxNdcU4^;&+tE}_T*quVL^N&0H7kQaBu&nbF78b6_Hmx{l{&5H3(BN?~I{YvZn>Rtc z4Ujj{)yuf`fLEP`j~9jEf&K@1cnI0=ow&I+WBM>5^_k>1Zj4{SR8P}zc>*e@Rd;zv zQ-MPgxfk+dWy@yAE5u8l>BIaZ8wnUx0|{Y<)o5LVS9`nw> zZW%U5!^VajqXm^dm+T3b7UyO`>&dfr&B${e*25c~24@PFc1TQAiA$S z(r9VY=!bKMuExXWuw9!RTDRwevVuE(>A$NeGwQR5WXRJHFW5%F~pZx-}|0T@&=p3{$! zETzIr(aX;JvKRFyK1_#&VkDse?+ln&4_iQlQjdz1Wp0E)01`b-F>i97mX1W#MJ=65 zXCP4Yj~zRveddh6S=%ypxrV?g7`JWy^Kgu9KzAbb=QIdB^^om5bQgns=3fq) z4P@lCWkWr%B7?PFx4=FDqYY-=Jw5K(hb(K~qJNxBhY;$J2K79u|EXCOh;ChWsF=aP zgFG0-X;^nXT2*s&v=Dn+05-WOGIE30Z{E~D@ay}rrmEZqL#tM=sn$?a-FoDFI`WG& zunb2XK0h|DFZ*qoXhn89&P$~M12kuW|usN=o< z17wNd2M=7tR z0prkVFZFT)jiJzNi-r$jo2`(OwD|dXPabLelX#zrCe^v`!}2vAQzKgN*cKTIOFxjV zn2bndfx$Ta6hv}9w{9kHVX@QKR9CNF%_zL}wYa!g4l^;5<{yv3O;N{$6vuGYuyY!u z6bK&M~#cuw0?$jbO)8IZT%eZh&Lo%($Fb$R|1Ltk9&0{np|1gWxc?^okDeNX! z3kC-NC9gqB>dC0oacp5U?8*cI(=qbOZOHan66^G-{Aypom!h$#UnX~l zc#$M&*Vf{2?=_vQJt!5V<}o))HzEZon2ciQVQ;EIEGy|+Tv%AxLje9kNey5iS3yeMe}L1L(f zSTcdSL-w#FiXpX9p@1sW$Uz14h-si1dO7BQmd^BWlZ^p+G|kU!N=CMcU>eTWHq+k0 zA=l*1TJm;)je(k^ATu5){n#whc=`xvl3G|D*9sViLfwGC&P+V_aG*w2p$^9z5)zU? zG6JQ*Z8KVPgRMn*WR;DN=Nta~`sXt`(u_CbT2@0ns{s1aXkpev`> z)>26l?lRhjw7-V{mM5!2VRxuL9|eWDhHU=<-STroPf4>JW=|sKxGWLNK;o!{%1BwA zKmYs_c|nDPMLu9*Vbq6yk!lR11>{u+8hOdc2G+BhfO`4yx4Yf@6T%L9&%1(JsE{Qo zXuJHT_3OV(ngWVANRyu`;y_|cF(7a zvkmmco~f%{Z`Y$6sdkY6N;e~={e!4cl^_fW zxjLQ;UPLc(7wNQFRwpjxMDCIy1sWRaB|Xvh$0FLry{lw%Qx_=72SjQlBP z01y=NgF|pf^V;0g;C5#KbIEvwCVSt^4QF%EvQ~g3tq29plP9l7LH4g2hZjSsmY-^Y z_0#=;mEeydn8&2i1jH{+XBgG8qnHq)Cm$N0NZR2(dtIngz+;LqX2o<4cH-{{b@=#1-b! zRm**=z{Kuz9W;;0qA%)kAGWQ9N>Mlz|4l6Ac5 zNGV2B01wzP1BjasV8K7CuGa8^R~zL-3ezB#{Wmxb?>dffm65S&MEBO3^=9e_g9=gB zi=hK05MC-k5QV=-dcl3H;}}U1ajGRr^ORoyW;*Gr<28~nxZ+`W_3Bkxmy^&8TJ)(V zv7d!8Bi@CD;7B4zb7Nv#-FhQQYpCZ#WE#`~080u^R0d`Uhm8>?8_A6nFP-jWslf1o zJUvVIX=1~E;1njc#&4|f6*|hayhGC)gCOK8NV61f1Rn)^G9hBuR$S2L*2@C~Ap0(w zSpJbL_*JB4&VdPFE=lh>qkA|ys)a?rUE6j-Xmye=({wO0J{961X<6sEj2dPb6ls(5 z7a~h9c^6|qo#m%He#a?SV}xT8%v4$C@HKu4xY1+M%OwSC99dJIU9@(VVFp;keClyd zJPpqgfU2gjH1F`LRGknY1)=Cp0062#G$8{N(CW`mOe9TS|57!MQ5>)Fcl_n=-&4^n zPyDq}wJ#+pipE#v^cz}FMD;yX$GRj{Ub3v3yuPCj%GrWH9WNIq1BU~RD{Khu zA#N65`wp>-#A|(UR&tIAyaB#qGY{q&dEhKbe26`D8*yx60NtNFy1gn9$xO>w)fR~@ zzvIZI3JMC`2U3z?l%~CXdz!2V?jr@gLxC)Wmfz3p{qj?$`j5{k&MUMYTORktHRwLF PnV_6fIhlF<;z|fu2B1oswNVk%Lpn$YRcf-)#A}EcZ5)w*xgMx%~cY}mm>V7z~E5qAafsgCS5b7ii)9Na#p=8(5rw9R9=H>0!ABT*SlYs9{>T%>;9D6qZ<>l%naOwS zDWjtzDlW+JnM&Ox?aSImsoKK2g7YUX{oBQ^6$O7URK$mj7Qi15-#cy1I#QYAQT)$C z9AEo^4J!D*kB;MD7S#Xx(k(7{dFg*1<3CKWv;OCs)R7Ni++6>8xC-baUYY*qQI^<3 zB8~f>M`SwQJJ>V*|2(!WO3?>e|MM_o4gCM#;{WSHjoY5C@cLnQIaFF@7C!kJuq2Wq zY&Yw=&~7cRk1AH*!hh!ecb z^bw*m*KhC?yuN6fEppC;=ATU&5gzr zQ7yiUi_3VeOQCbG11%oCgudAEfE;0V zb~c>S$eH+=fq}!xjN4L*c}&aaOy7uww$MZyKk$mDtHMp;J|{Dj!n5voA|fNpyw4oD zo|Ut)4gLNd@G(XVrze@W3oLKc{!-V{eiy^P!kV0XX6QO$34?V~HD2x5Egg*+cWL+@ zkUsiwA6rA}>i&zqG?inoann%K!}Y-wK`V;$qpi>`dM~`sX^uD<-Uljao}2j|zlJJp zrb@xKV|E#ibyPJTao1m;Z&mNL;_|=#&Fl^8qWW*2c$xEtw#47wdoa|U7!icu#nhap zv2iRYTfWZHSA(EX*z1octxiX)8Zlt*I~8Mbs(JR{o#C)2Mf(0PGdz$l(;SeUu?(>V z1ssx8Qe50w zvz8IbZ{E2qfeDV0I8h2HY7Bo&dUq6@@rIm|5_9EAvEdI`>F?j#m9{gr^QT~|f5A$7 zc$*|dT-)%4`Sz{W`owoFVB_z&4a!}o!4blPd7UnV2Ac2e>}g{Z7EGMj=yzyH3 znN(C=oigLT6x~v$XY7*%H>umHq_MKKefM*>YR=bsxjVk7vQkLoxD}U|4`w}PVEJF?TV05?~G%zxwd^!@=?KFu$uUW0{(O0L10tXDR%jc|)%a z9e=QBdkG2(x`VykOW*az#K*@6=YbP!OvL8qo8A(vUX@nO)#!9yKzQ4zB(u|rvb?BlC{gKGp)#o1^+!2Gjg{UkoOs&#P8Q5-FmCh~r82Juht1*YXe`myX14w*(|59e zM|m-lSJBH$eAeg0Xxg!d8~jf1whb$-Z#AAS;^NVX=}ZyM6OYIdh@zJ?98<$$Ve}5| z#3Gk_ZSlWe?2j7QnV#+~e96y`$I9BOg*y8F#oP@&r(UtVP%3_3K946X{*|qy+i=BD zyfUbaM)<$Es$Ju) zuV24HEy5l=b3mP4Y=0*Ndt6~cm!}M~t68Bi^t(C|*{%O;KcpsXI*=u!oTq&{(eJCs zQIK=~($uufsSN@&kvuKmEPI%`-tibw*QLsHB(;LYjs&NX!fo0C(-wLi@S^TVBYONk z=g!c$I$ciGn6E9)E#`ju4INernmf|Z*!RrxzL1bA$9%G}FZ)r|lx-b+Z@N3J*#*P* za*1IHw2gLX;y%`RKpwMX0-ARhsLLquHbSnLZ=qfYI>_mk@lC|h))=PzZugy7JgoWl zaMC=~2i6RCgc5_#eK6MUROlKQM1sN9KH0k#Q|r1}|5RW9kb7JZ!gWRgpg}4=6F&iO zHosFf*NM%Vmi6`V*RN&3JMUeCbE0T!dfT?)=m{S6eJs$?gkiB%jR3No zjx}Agi)&SUOH*Ic>q;i8=({}%pMfwBB9?YTA%0|ZT-#l1(mQZZHD_IHW-~) z&}*Ha>=HKjq`E;faJ1;De#IN|yBZl$pEEpFnS^M;W-<^+UD`i-FMvU5Xb%UiT3AO{ zcj1@tTzjp{7L&(e!eW|JUyI-Mn%^QgRUPb~(*hW-_d?yb%ewXwGcVCg8qYZh#JBk@ zzCYyxH3ixNRfga7nTd}jKnw&T^RRlbUNQvI&5vQJA3h8W50l+S&0VevJ1j*DFM^%w z$PT5C0Hd1B@A_|M-WEyd#P^p=(60*}6)<%PK_jhR%kU~anf3ZuR>oiA0U+Txe4tIM z8`Mn$*{Az_M86C6?(J9ZyY+mzh6xaNrkT47)Q93YDuO|C7JR*-G*R=;by- zZ-&{P=;*X7MpJh*o;2*1*#I!^dmj%{;a1 zOb64verFGnsD|^+!YF=T%U@rsW`7>fdf7cOH0(tZ&~`&hbX;hB6#?E%#pPy6>N*f^ zQZ?&Y=|}Ldrj&_lt$E%nUkB_GL+7h%Iohh;R%2t#=$edQ3Agg zKsWWtOK`%!sU+SlTU;~~@;I$@_d16h2f0<`Fl|fbcM37Co!LS?Y@I zvZSUf=bqU@?>;qReu{D0trvPJ`0YCA^0!JjVhI4oQXGCt^*>yA@H6`_qM##E(*Y`x6>v=uZ-_>7jpoNEm&e`-??K`wp>uAsm%Y$RB z7)9j|v7EP$)msiXhW0^=MZgLQ3-=p#eF*328_#FPZS*;-E!vCCyEKt z1!$f^^erhV2_mHNKP>hbZuS|d?!O{}HXUGb#^1+a&0+v}GKX3%z!9UxMx5#W76K4j z)Oz|fyd@BGiL&Vw1MrgY$LgXiY)iE~FZwg00jK#`UQYJ-vw8=qh6Hh%@qY*yfbUTd zDzvn;gr>#*O0qEm2GDh=@zti@>FH7|+K9_+y~j8pzP`%h6&kKgB;B97uOcecKvlTpPTN{=8is(0s~bzj1V-~kLZI{Jjxz8QYn z!RzY}s11aHpsrU25Y!TYfH<2EPUi!w7b7_Lj;HLFpfLgQ`!)h`ye>L7T2QkP_ye47 z2@G*XBO^NB zoaffp)4!QFQD8%05O|((n~R3%7r-ITnlAvIatE}>;pXZDAeiIk)?i$R(Wfs>*9Wpw zglwK^{+YBY=>Q)-CR;9akyYvp8z2%1XqbYRxJ$wNJPOPr0^Wv05*Pr>@MV`Tg@tko z3K%#z+g+7CUo(^*OE84eP z&2UXk96V~m;o|*m#NSCyw*BoLDW>huFIWc3JG_1wmONVFxlRcZovWR;>QaFRy2ZwP z{)jPNk4{z1sVTs?-S1HE8v1ABq^i}*YyEk~FNG`AsOPRH-rQ8-_XWAE(%#f$Zev7} z`GZt89UpkEwsa+(G9_AGlJpth?yS|s>d^xWjgm(*o>?Dnb(eei2-@s-62fdp>!j{| zeJ=j7an)$8pub+szWyTbHRr(We1qG)*()Q-`)~B*$Tb_LQ)A)gsDl26iFe)&ni|Y@5W^F^gY%SA|9-=bxFaU+-nr-RA!FMs2GiaL1aW^A&4~K-0!T%cmSwGfCFP)ogbmWrU6700a}a0*4HXCz&~Ip znLy-1)Ad#p&;m+9;Vc3O!u=sN)!~=m7z|e2c>V?;p{ACtlBO8Y{OVv5NBaODv;w4! z0TbCO`flGrt~U?PC2sctXu5$w@u3F5?ajamV5l_XW22)X2DUXA&_^T?T_%Dx+t%%b zj2ZjU`JJ{gFeBUnK)~F6`RhY)qPiG1fDk~eQUFp9kiPiLg7)mSO97*tb{= z1}-wY^()hB2`-_X$N~FCCvDK6v7x6PQRo_px%{K#eqU ziMsDQ(oMHfQ;70m_sWr?!(Fu1_#PY1hOIV3lXl732a3eaUmrHq6g*vsZ?q{yIcJYO zU*Va3@K^|o?GJC1Ww5YaQk^@xeNQqy|5sx>Y!l(uS`@c3ttp48ntkWB7(&U=U7zct#OQ$PmN+_!Ii>(8hf*&1ettVPM*J zMBTc_XVDERC7d-QthQDRoC8jnM8(&F0#&B+4QFahT6^g|-?M`iXiP)B7C@Q#IXS`y zK>+8gic{WEib03{peF@Vpu=w!R#PCC5)0QV@CGCv(8r*ZWW{h-&v!~CtW`oQzu1#< z-F{`auT17mviu^LpZ~^(-W4v{Lb4g@RAG~(eG{;eos&FU8jJ47MV|_|PAh$W6HhO*{P!vU&pWmb$sy{cgQ4+2o)Ydzi`z$%ELW^~NjEVu7{gf7wTy2Ix%nPUVz6BwGR! z)(Y6cK#8%`<@QS{IWMoeVL%eI4`&@{t7rE7Kb`X*r2_>5P(ZVxPihI`f~mjE{!G`1 z9FLom9`%ed^?`}{QK<((Ll8GF)r_)*ELQf9`S&=5U{d*|W9-&)2Ee)OOjjc1Acq#>003 zTT|WG=0D-{vAjvgyyUF!v2GlHuZgs}EXxbv=B7w=#gHa^H;Iao+C`o>f14%SD`Ubf zEw@lDCs-DJ!P6REwoagrsHR&GQSU1rpGE0#1X~r?AoUC#FdA>JcFhNK6i$z;nxdg; zjZ(4zVnxJ{#KaQa5BFb_0DKe)kRmc-+`z7Zoc*5Nti*jmK@5)h9EC`Po?W9m5QYZ< zHz1U{)SMKs*17#S!%q3X!fVbQL%_#z$2msif8ZRdW zEiK}26YFRdjg9p8Ui3$Ho` zBLnS1#MJb_*iiy6A%c=!4_XxN8`d-ggeee+$XYx zmpk-&+HKAU=xh)6Ab9~O1kFHl@@Kd??fOzs@H4*ws8QyN?cph+PIo1*Pt74wx*9z5 z1f)(|2sO2}0{|N|11kyXLJmJzlIHU_S22&zl$JUoSc7AO@C<^c4sl%J9w815-zrMOy`pH?+4$x@~5N(MdVk~(&j|S;5 z?m&(tow{c`EmCAyL&D&5NDQfC-;jxnz1@RW;>>+4?75%X=Gn2d~U9xQsN zo!^ClH$aj4Wo8&JdQ<$reG@PQ@}S7d+sBTo+G(nJdxt|BOAv^a!K4cU?$_!gb8O;u?O>IDgSdu z>!1=tG_Xn}fP@d}L$kgYHZUy1eOjQ0wpTkW9i+k{{{$AmRC%f;7)dg{tsRUOWzw@6 znr#P-*oR%R%F{pkcpFYfvlDB}z|n|`w#<3v#SrkrACErGJRXDf=iw5e$1xU6BWE)> zi$foWhZW!z)P~CrqXqxM$4>U-mPd5KJn$J=yOBw{&lpsQd>k?mG;|YreKxpQ4fCIp zCS~nTD!|`JXvc0{$8%{iuw|3>;?2yn(gbj#Zkp1a$LP^Z|Ww zA3$}Lu9O4&4+55|L@DvZPYQN*3!h+=h>MAp?_7anPWYS>>==-mTL64QYj$$c0KO2U z_5}#UEX_kZ0645-rQ5KUl0s)W5E@mwfb*0$?N9sWK_ndvzA=Sn zS7J1RPj{P%NcsK2IG*xbX;{bEnnlkqj^d|-LV0${)vk`8P5sj970GlJRLE_}f83G! z^Wwp8iu^l7k644{(KXK(S}#3_tYc{&^AT+2ZmUDKc6JL8*7t$CVFJWY0B+j=vW-mQ z)LR51x35O(i$R0i9O7>|1*oj(FsS;(M9}ujQ=&)7b500=! z-@z??JI_HLUett);|x{Du@5eDVqzgyYhvg!{(DzZ@m^9GmV6|Wr^b zlGTwEE1Xxg{Y~34)GUvcRr28$IqeaAC!{?{M$7F$T6z{ef$=Jk&myy1etH5CzRb+e znINL|V1?tOERTD$auzHC=Yu=GM^mlG<6((EqxfXX!P`h4{p@0DbP^(&UlN!>kDXm2 zkN>h6YyDc1pDfurD8oJpdT3<8udImmVNhZHz^h%CT+h#Xk{|y2()I2@HxqHuzfA!8 zOxdf!oD88hGo^s);-BKE`o~Yd6gL<$Vkjy{zZpeRGv+@`%Ua2|MKWt>W+9Tl2Zl|F zbuX>`G$-Er+igN`)6>QN6|S>Ggho&69$y}OAo}_e6w2f~Y3l${jZhhKxCe!Dss$!G z1|KI|sM)-H?vOow4T5cwUEu(ytC~)NN?8Z~eaCmWEQeZ5UF1Zj?yie^eWRhzFRZRG z2Ej!_7=bWuuJvT$pCH|T$%tBIS1R@QyoT4&*2&}mOme`V)#@Cq_gwLzg=Vvps%lS`&S!Of7cA%|)ofVmQHMuxq z+B>z`<4|uz4>+I^b=v)bK{DH9WKetl>%yvgLDk|R1+oqXXQM6?1l=KZt#awXgf8)H z)skh(lp%kYb7d9!etG&>JPSH*uPHd*emlyI6BI?tK3iD}3jbw`pnU_@LZxRAk0H{z z{HIgP+K*p|*Zy3B)`zQ4CN0~JDm8m5FE(}jgzZ~u~piP?a z49g66SrhPG$9`xov6`mx6P`@TXtpR+L(_-I;ZH&cEqvXess=0 zA)@!Q&=*`Ofm@F+KajwTdV-ZE4NI*=q&C4q)Q&q@nZ8MC-1en4c<0U>)88@aCLznW z@M_oR7fx){UPJWzt%>PUI2+C42*Z6zW<^w$ur&w1#ih4<+WLK){jhrs4}Z>C%1tiz z9sLxvq3C8p>6Uoqnhy`hNl=iv(O*S`^skPM}*`s$y%5SdjqUS$;*R*_e&jDHb=Rp%ekS8L4aV#pa07wN4 zxE|H>iFa;_!U*}#)+|+yhjH_<2k#wnjM>mF&jP(l z@^83=lJT3;_nF3wt5#ftb|N=FEKeSe(CO)1Gx>@IanR_62MKUbEelQ2_*C>ORkjsQ z4bsMBo4u`~XNt+_FxUDA%E;DzmG87sqc` z%wpNE^y!zuRPt-=5~HlsaGvL5Q%b^o;XigT{F!7g4EG)HHOD=uKQG>5H!(a~R{gTo z#8964xlu)itJSzz2y^VodZ9HRpGk5YA3-L`Bv~)38~mb66z)93=P5SCG;Kw94dm_*cy2TfvV^!4f%qe{gNs+sjz|Z_<&T z?@uKeHdE6KmsQJ3`LmPN5F1A_%co;zBx*hyWLljf-4xIxhG85%#OYj+S04YQ#@r>L zm#v&)*f=}LYT?am9`4MZ8=Xm6(zJxt9u+%;Jr(~cv_Ewbfn4_DRTlWFxEJBXNi>Ib zyDwzNA#dD1pIa=U)b2fJN7T~?{0dHFZAm#a~6grn-Eqhwl zQ(^B@`!t8nTTmnnHlOg2XYlTm=igu80|y3Te`u(8nFQPQ`+{hE%d2c<4E0b@tpdw1G`;bJ`l<&a|x**5YZBmK&N9)$w z+QHG(UeI_(jQCTn?`G?U76t}YEPvyniMSD2ff4CK5`jfW`5{@2* zhrd@?>{Pk)_HTWZBX7PFQ7>hc96ReZk$nfhQ?PcrK}$4UZ&Cr-`B=K2uc4_r_rKc8 z0O79FqY}Sppe+h&oq_xf17!X|LN_oA7a&s8baT-Jnf==@9$p~dSXnu&XNN8VceZsz z&p4V;@)U+k$0w8fS)%H_z(?5vj@9p{v&|}#B+q1e4wNs zWW@u)=}X1Onwnd&5(ik29n+gGUbTfeiT%HEf7bEjh4VaVrT6Sdb{2^xPK}|q?`2(WPIGTp-4ys+w!Pf(t0lTBq`(O^n7dkU9%LmtnJwVSS^Y=(wG{_|WQdybJq zkLBIoS}XA;dx7qNlwP9#Ap?e%gYFND`5ad{5}N8S7|D6dh$o{k)s^EmQwQ%%K|1`gO7Vgqjg$g)UzNnJ1Q=u zJE7^1V&-jB%_8KE0E;Tm90(81AoVdJN3o+{z52nb^vwuIJ+P`FiVm6a;iRmK0k}NP zz@Z2Nf?Jj~u+AZ$EB=ns;@tJloITL}mI4VSVX$owZyNWzxw^9)%^w0_vnfy#+1LhN za)Rta7eBCjdp`)`Li;pXVU_py{Uan~egQ_v@4jbpxk%a63^=~SPxjB~mcXjnp7;(@ zmF{ofy))Y!&IhJ7YrtPz3NF-=h&!;$9p?QpbBc=apoCZB<-tQ3z1G!8iEnVM)U}AF z7<3+iMu4dydB&_Rd1kTQc=1PMHO1T>XwFMOi@+4P#W54mLEvAF{%f=L9*&A(bG>1u zQCP-G1h$==eM7#FOS!wp9zy$efyQPaqj|) z&PJB3L^HPT&Qz-9h#Ir{&adZhi23bus8NX3qr@NXD{b%)A1y07gEtLiQZjUsFN@nl z2PYYO6+)A1gZQ&-12Z>2QP@x2{#rt+;;!^vukou^id9$S_zuxUhy<_6b27&sp)7~* zCEr9dsK-a=6`o`6>{lfE&e45U^~2F3TusQNB;Z5dx5c*kQHe|3*h^zqIg{$t*mv)v z{Ikc*@7R4_PD+Sxje40c4>rF;ccpQilt85l*|hF0wB?z%g%T=(j`i%>GtFnusPl(_ zVqaOg*I8Ur(*N~wXAZ;Oj(@8_o9y4|g<2kZk7eS^c}%J1FIpd&))Wpt=Y0Bvgz^*w zKunn*2T8$LC}9QsGsPy~=dJx1xD+NJ3J1l6qADTn=4HAI1rm=6MXD|WhdfjehGa-< z0`ZG|5FNNhD6t2FqN8=YjWke*6Lj76tX@z9`+IGKOCTo-oR4jPC~Q*ny{~m3TaMpm zvOH@V^w~&|C8U!JCFp>Xm1%CX9{T04i2H!244Ji1Lh8Ba1`7S%Ts=Y}&|ALO@Wji#ljOB*8Z|EXBvDrKESlZo$yK67t53h-jpAHkA z9`D|cXKwC+SM5D9nI>*-oJ(3O{zzVZ!xuZOUWc_PnW0{J7$KL-~DeveFy5`5T_U-3+iOQLL0>-1*&P_ua>@ zP1ZAf)0^GrCpg=@y)QD+wteveTtYXewWJUfQgALWda4V%W@0_WO?7)u{OL@S`x*UQ zeb>W?3>(Z4wF5_uN?}CTELG(Kn-r0}p2++PsrQntJfC@Gru9^gxJjn0s0mPfPQj5( z@v$>n=lhdKhYxGVkU_J3WEXu$Bx&lH( zK9`qkQeBW?4LRH}pbZhugHq@M%1Xr!k3l7#UBeMYhUX?btoiB7^kB~7Y6M79($U_u zID<`}2e}l2cSy+cf<)Rtp~=Zf`yTG9`Ml)kt+zvI5wLNPEZGB=>=KA41;cHujknt*^Px^B`*^8Syv+? zFBe!iw8VlnMaGt;_N>Ob+k^Q{8{YmNZStjQeC}MO0qYPbK&&T(!dK&^VB>qleEaCJ zmvH(Yv~JZvlC=7=MRs+C*W zjNFT__B~6R9_x%nMZ~v`V_}qf)?E6oG@-8gV@M`eW(g&{Mdu!R8m)QJ$^+lU#fp(d zchzQZ-+{{)CuJ`>?h-z0xN||5ogszE?Q;7J4dt>6n|czwJ5wZlyss4E)T*z14Kvwa zYF?1S?UJkM*A2Fxz@43|u=5BneZR%h_QKYk*IvQxFQsY2>Q~1)Z`vH3o|20TLR9-? zm4Ej6OO(P|=};|72}}nNBi_*0)g=eXZRI1ve{SON$Oy)bj@wcn;*-~_*L#5smoP|j z{U-y1kYx&=DWY*d+Ab@*<>GfyQBgZE>nW=Jx3;$Sq2xeuQmVKc52R;;lpgF~pb@;_ zLXzHd_cof)EAH=posGYrLMES8O~GDucf^i_l5Yj)iP6^tnkUwBw>}c&m+KP~ z3ow0k(@|ED37_S$iNn=X3qN-D*s7)*7IB;`eDd*Fb&FS*^wI(2f}FHRarnwz;ahu%D%U$+;}|He3l!5yHKZPY1i>kHAduy`a=G%MpAA3Sx_BG> zr&i#TOOV;{m*O49tboL@6xO_AwZSKM<3h2>+_G~S*dj045f3Lne$pCD5=@JXBa0{s z&wbCNi1Yrj(hVI8=7YNH_s~nr%7}ZCLj|sXCUNcqnHdVJ{tE^HbHN;#;_d)M z!eCNoKQ!!j8&06R39TM$>7jbhJuslrw%VUL=c6drM^Ki31Z3K9aQ<&QUIM7o47yM} z(9vgheJKGhy@{l;t-k$@0D3!cePYtZcB8y%Mf>5yYTaQ-+=lK1fHZtFaL6MdC%wf} z8mC|Kf(xwM9taX5ci_#79gz+oGMZCaNdYVkDoJkngKkKa&8)kEv@@11fle?^hkwjP| ze?ybeZ_}`b1FnM*Q9j}cfrX>TlV)HU-^*|JWl+!73t>ug;Gh+?BkC+c4iIULsYlQk zioI0)Vg*aGnSJ!|Hn?s9sAD5=eSf!JLp>VC=d}6=LftgNw(TDTtpff+Kp)hV0|0eP z06lc3@SE>_mb$_Quyp)S<%tlKTc?-SZ__X8*! z1@Oi^u-H1G|A#_JAOsI(nE8MyR1e}oGJVaft1ql4%dt^wFPb(!r9xJdo%a%rOeWCU z>;Lw(0f)oiW~#E|(-Lr?2-L+km>;E!>554L*lOr|w(>8u6UkGHm2BvU4TYk>Wgim| z?rw#m58&r8aGu{>UpatK{o+9nZ|GJnl=jxr(+dTGq3oO-#J!h&kM6%*>Ws$qbp}2+ z^6KJ5$-sc-U&8~u16YWBz_t!-&IX5AwSB})3GS!4VfciI-jRBd5o!O*sF{Z;mxsiX zGwwZ>e-0T<#{;S|1I>wmCNoh5Y@BXPy|i{0BkDYEvsh``I}!QkAJ|=j1>&WV#4!?; z%2Q#to!+V@2ifD=AX|tEdPcK;@B5~a)!*lN8~tGgO=j~Q6=f+kdg}#QDxo6}M|U{v zJX*n5B0oq+AxiemAp7AhggbB{ZjF7?0!<&#*i$fy>jn$xNTI6@P%O%-q=91SvxX9g z1_C#aSK|6~Nd!FMFc2DO1@37ul&bwl@kR>u%;%f^Qv@t=Kp;ej9p^aK@AA$yAiM|| zh@6H&mu#TJaXjs$kv|6we-O??gF>n7s`?6GqJUEw3-RH2r+gh85IEt0!dB4EGyxZ? z^!3o)GywgTKM(!8A!FW&7w$a+QY2795!yC#&L>$=rhT_bs<>wLL%Wmf|GNz}|35Yq zNtNB;!>r=AM2&Ml1>rB1x3lTw$VyZ5w$N|Lgg;KW`}oE4?^UTj7h|`?%7#Tm5GdFV zS9bV#tI4zF__D8Z@O_on;hJcM0>{ z?QqQBZtHZvf6@{2(2`{u%|DBSE1PIUV~1M0?NZ;F8l0zR&fJY4K$vK2LJS4WAf^P$ z+~z$v1I&M%Kr_gtNs?nerK6*pbOcB$r7t@x3kIBNLMW6DoBhxLk!ta|Gj+{Q2U_Tc zQuX$?p6=r>43rl;RhiD<`ilNfI^_xLK}^Qt+e1dr9B-ah&;?lpZFlKTYRCK?+r0j+ zIE8QfTbfRX{`%=Y5D&#Au$J$PljxVPGAl~@$wSV>3xo~Bi9&3$dbEIQ3{qRp< zj+BfBHM0aPMd(h_03ay<)lov`Ab^Qiz=bgj4Z0clO+us23o>B`ZG9WtSl; zFKnMwt2u}6t^J2c1l8x`guN18x0V;A%(2PJ4B0U4&5H6_jf$>8PSoOcTP}BjC)e|r z{3#KRa+uNjB;(QJuZNoTw`swR2yn%a9@?d)(l&xN=q?!`yDD`zrQo_>OIsqNLBUq< zGGc|ezE#Q+w*}~tz@s(oQ&@^g}Ie5nMUcNN=&Eo+|m)SgH%$=>D zBtH{XyGI060;F}?IZSX`@P~QSYLw?LY2DzY=y8Ur-Lh^CwmzBiDMl;hjtmdIsBw=1 z=p62cRc8fXC|$z4&*?e6BrDQ!AT`>m#u@sIv3H>VTl@ z%`s4|Bp)8_H5vLmqU<@!UF@C8h}zXBPDb8kRFZDL;;MWdP*?;e=eAAJPi>i+s@}Y38|0m?khA^5)DTmJJ+;NR-PV0hH0a^;3f*bb z_MD!77ljq(5aws3%^}g!pA`I_8-=oF9$p_ZgcofQw}gxyzoOYNvr8?CDxGLhPWVvi zPB<1rVKN}%GZ*DCl^wpJ|Kar5pgo3^j$7LQcKm~tn0I6hFmm(OlLTCm9pa`@vCIMf zERaR2E$8@L5=X8#@TdK@m%ATk3??$>jy3r#VFnD3+U~BUEs~A0>J6C+UlP^__y)o~ zRz*NR9NFf#K;y^6GKaBb)A|1uw)<10Op6<7ayjP{)Hu+=xL7FA>LR`obFzK0yQ z4o9U0j;BnCfx`ydZ5V9WNaoDX>i=8z`S(IbiQ{rp`v{%pCaDvv{ zy=17VK26g&;F!=aPcac&6DbSdPFMd3hTOkc9!PLt)M@DJI|~9)4J7(CpFH_A6JWO{ z!^%LVf|Z*)n|~yc&|ygV=pji*I`yys-fuCU{O5S0BN?&bB&(L~FaqfxXx$d%s%nHx zcQ051@9B6YNkR*rBJAkyHodgH&q^a#Efkqg=-I4%aGEB<9>-(CpBFV={Gmr( z?O|JNRIT%9N7bE*A793nj72!X3yF#6Tz!tW~pp46*-7O5m6~Wjk;7k{w8h$y* z57R<)pZf9taicqp;W0D%ilF+AjAPEc)aRg0+&FoY?47~wT#9Zl&X}$~3)ex5pVNXZ5*hX;B-SC=t_h^_mYfSMfL+0iGl9W%%*`k z-mWi>@y!IA^$(MiNQ6j_$}Jw^^=9Ru&g$8D#00VAnFKAA;tZP~8SoXvQZi^q8WznQ)wC>5 z_i7SrG(~G?pPxuIowNG2%8KTiB-sgKG>^%2L2l|cR#pLQldPI?B=i;Kh$SsNO2sO1 zUJMKKSC@{UHjcn;*&wio3n)ZzoTbq07 zz#brPP=pw_0ryfs&F*G#j^e$~5KcHyI=u7c7M?dg<49J@GkKPXRyl#3)%5@d`Bqu# zKQ|wza}n8i%A9$yZ|l^}VLmx;ZY9sDvE1j#j_$F-GONd)jv!-NR!xazOi`%d{q!r> z3II4m8{Qw((wj;$F>&WwIf)&DsPNy-VM1&V5s$2%Bp#a%vj6+1E(YBO(s@iCqZjLk z)Y-l-E?Pe}8+63WHp^XwFWXiz$_{C5u5T~OFmCEI5{WL@kzm9bT6L}&yRTcV-CGq? zIF_N9;+Kaf+AfGx3=ZhUHH*kdF&VaCP_vxo*`)5eaAG|G-FN z#1RpQji^nRk1j_qo%+v!WsnUBRkbEn#2(O$VbtvmrI9N6#5TyR9rHGCm>$i8eCGWi z;#$h`mu`XtidcLmr7^5hB^7@yn#W|N;p4c>NOU!4$H@l?RQM?DV9boZ(|exT39e+T zlE_pfZmInK4m+v_-9JpqU4Ks?9+488V-=4jgdY_gtT5+q>tlF;G@E=95qA|<%#+TY z!})~8HYY-b9VJ$W|0aC-oo*h3e-ZL$UMEHoi)9e?I^$;NU7N*SU2O_E*qvf0HF4x~ zTIA~#GU?*>)f5w>XK3q%1v=Cjxl;NGcLUyyj<0;c5?l2yer>`m@>4&W@~(B;C;tth z|E@j}8*(O_nvL+yQsD3rX{F{L<$btX92HW2#=gFYMp9lOhvH@I+mIlt&|DFmV+As4 z!BT&k?WvsFhf9dZIUzW_YF6mC9HKZvzaYAM!a|+@y!eq`AVlmGyDy}0q+56OjP}Q1 zoV*c{G82tUCDw+O&J@#Ylf^%xZAYeja}4$PTZlhG`ji0uDlo{t9F}5sdKh0ohvnFP zDM!{u`csKMfa&(*p=LJ1mp_=>+U{e$8sNFa8KDrywKmvk(lcxXo17!YQG>$QRMAkv z)vUYgohc6=j#luot1Yg*NFCSNf_~Nl#5OL?}-G%4P_`1>~FGB=9`7`6& zaZD2K^D)tadmdj5wqp6=HBRQ!y%gyI|B^@N1PSPGoGWcU)$0+X`@b@L8}AxkPV-1J zR+$Ffk*V^dOVvRrKY&9g8;Q*(1lED6G|=O$^Ju`o2Jlo1JXwI~2KV<_f3wj^?nj&M;6UTY?NgRz^f z{ldie8IEzs5a3>ec@N+gVOJ>VmLJZ)>vZQt=uC-rSKfX1koAWTcNazn19Vnwsh(Gm z1gGMn&|VVRgca)tvk9y|cttsbe@Mf`FoyKUiqLh!*Q^tpd}&U;_lLoMCI;Eb(XP(? zjzMy};rjBH$syddrc+J&=wRmdqz$iJlyP0;wq+Ko%0 zlEpOMKq)a>K3@OVXX|RFAbfLpU(c&ci2+vRXKcH6Rnt6=-P|GtNA51r8C(eMP14b~ zMKy`TVK&7T{`ISo?snS{W+TDeNQ-C^0~)x3N{~I*Ji$Z70zScs^o`^sn^!H zhGjj!oz;u4GU4yc&mXt=xp}Pd7hEhThh7ti8 zQo2jJQ@TqAL`qQ_q`Of2dH(Nv&iM#mhCS@H*1higx_(#j8IRFGT0k_BvQ|=X za^``8*n{^!-l9FFz<(pTTm>Yr*!vRGkt*B}>BkYp~ z;g#24{@Hgc(+??CZ@sHE8ibNGBp_va;odjFrV*m};Iz<3tV?@N=ku51(tN^oc!^Y3 zq@%hiED)3AO(bxwF>0y7LxlQzPp-gVaK?*%s*H#?xIZ>(`G_>Uh&mIE?_srCyKz9% z5|ciedlLfMU7$vh+Xp0m?v{5VVlc(xgcb_CqM^6HJZ7N*rx$$u^OghR9EU1$eEx)? zoZ)Aupit}PNNv{B+=cSkf$0SM4x#d2*wW6M*88CWlb)OSRIFcH-Tzt^k664Wj%ZBk z7ZDXgoXC9GGwCIngD(G{llZErY|di2Kp^yuH8W|vPR{!$oDk|FB+f)>Y>DRMXH?N9 zzfRmLVU&u8{Ub+}ml2YWAE|(5f6-2u5Wjm(IMNdCRz<+tI-3=vgFEqv=2ty;-ggOX z0}zk#!N6%&DgnO!dr7${82Y3NbO;H9XU!!;&KI~K8gT+bcyK~?7DtaUu+bmcpXDrM zL8Sk!gzd!aboAJK*ZURS0?5&7tgu=4qwjrBBWOC3j#T`1T&)Kyeowr!plP$}W&C|O z+t9NZIJeF}-UfCfUOkFux!qR5OW1e1WJWT`pF<#GwJnPrUD2awp3tPI6Jx(71d-E= zpT(|6Qm?iprwJ6fI`K^^4jqx*mkd3kxRRGJng(gd+|Swsh$os>sc#@rCTS=?s*urd z(0AH|lrRrhQr+UyVCL^uMndqrKMs}@y^OBgsw{#Du}x_h;AD}7Mwe3vt> zFGIevYD>1RY}jET?+e^d$|3~ z2jqmiq1|TbgKn`}#cPkkH3Q+3H&JjU)&Z3sB+Uy!t80%wg%6KB9^#vofMNzYNI37b zUFQ(Ku;}y#Y*&!|6@vP(5~yo}lZ{1xkpOneH24x3mE!Nw=2@R~YAc9#4Zs}owS+Sx z^Eerj^P~oS-=53b_K{x_Z`^u^sAmm|Qc`{zgtzeE^FoYf5*tRPB1L~FSz3~m#_k}w z9gRcRth+QG&7xL;Pe+9IGV-Z{KR+X8eZiyIX_*`jQkzRP8ZEJ}bME35m*H}OC!Cv| z=(lnWt$G&)7f=ALxJ^~ZhJ9vpD5ebb+E)Tk2-I}+B3GM~_Vu4A@FqRTtg-Yb$`DsK z9ZK`{QDXj6?-KiawS_sE!yx3(tC0A-D9D_yZvEpAWxO9zn-D#GezV;1>;N50^@Ujt zIB0goIORDDjWad`i!woOOd^48)ZgZc(#|iraUb^IB2QL0=TfzLhEfKlOK5erU@5*j z)pnP<>?nrNvxML4a?EimPLumOV-5LeNCSQ6DnLsZyw1%^*7bTcN^cOC>A6(Ym8K<` zM(Ay}>`7_YFqCNfJ7jJ)n(&x>Sg#Y+%}!vRnG$uiwY?tGKEm+7y;+ z{XxmHu8H5;kx>>Rjj~0CSEWwhqS)Z~i^Vj3K2V{t1p?Shb#%JfGPL(0bK|P@v70}K zs|X=VLSq!7Le78bkxl|&q%Szk`Uj0VDD1K-X}Gu!9M|2}=!^)J(z<&DUbg;Uf$gwjZE!5$fII?ugK{j0z@&I@^Tnw2a;e6l5j?hxPF5QAzJYb!N;Zw z%s0&c+q^itHoyg+KD2jRqD9CRKV(a}Eo}zu*z)h*c_}LVwhOZgH1mQ%4aTH+zdU9p zKooYkJU^6>3u!ndrGn;;8Tzw(Ef@-|3*7{ABFlJKPd(>ns789EGuGdjPO&DH&OaOg z74@$uIA~K~Ols5-gZL`?gZP<8en#=u4gFpD3}}$)(EV z?G0&4C(E;dn%obfIb|lSY{{%BSVW~nu2_+C4&v6SWV)_Z>O^_rL6RvIH{TxuTL458 z3>4^c|69|-@B!i1>GwK?lFuPjX?T%n31ye5<5TIBG%7wk|2 zXPb&ZE)vM76x->qaE&JWbI`8#gIvre@|aAA*${2A=1EW}Ny+b>X@TDX}gp zCRrYD!#_NEDqhdi}sks?W_F7H_Yz4U&uz#@2T9VlY$e;9-=vo-e*s~z=w!JUrFl;>tby! zrNQPw<#GkD2ie*}k6@6faG`bVdEqb6d;ib|(`XT1zIdXGwBKDd1cmk`sCJ5DJyyU* z-%BPFcy|9z;h$7JyoX?t@Zb4#42;(BiQSxB^hvT|k6qCCtNJ<}EQ+M39}{{gl#C6h zdQMiALC`_2P(AnqaaWKjwBeJl@~BTIc>k7{2b#2qAI_^Tnd(7|fP-{=@}n#`L;oWY z=D|r{Yid^)9Dey+#dar5-k`*kNQONfW?+`#(OiXJ9`6P_X$r?SU;Gw6TBl!S2|2g3 z^m;4u(l%gOW$KBc6*HPPg$dUPe9R76a1>hSbOrH2Mv6Ek=G#(v&e~l;?F|2W&l$UR zb2J6*8whA7#{W-vVV0eRreT5FHd61JaO~~zxXYKC!P(&2r7@u<9D_Z`7dAZjVXD*p zGd0AP95o7T80{P(D>vcZ7A2J;XwhG!l_$g;E6YvWy(B?oCv^!{IO_L~ovxiK_cvCJ z0A3+M4ai;if7P9)_lHdHP3~w3i|Ys8p*J!7!&%F1Gr}B{$`B#dgf!qj$8^}pxd+LC zDI1AHp$#=*ii{OBZqPlI7E>-%F)aIvUh!jNhMT_iTFdMEECD06>o8ta8lm)h&>*Q$ z6O&oJ+AzsSoRH_F|9xKL7CQ{O{Pyzc;VbDPQXj!WelR`D7Z(|7ncRDL;m+1aq|O^L zTIIHk(Ugi|pLzw5_kHQGp-C!8@Lm^`&U7gHA86DY40ag#vHC@hVBw9o^Th&zUbmp_ z=Vv?}B)uMgomi9$*ijfH(NH|Y8(_-L2*Au{BYbmHJFX<#$wa*3|&kLU||P4bB*Ps)fyTU%f8Yp+MDz zxt8!{K;c(1j6jnT<7;*A*ucSn)-V`Hj9v!7GNta^0iYBF;8g1XfQ%RpBmzLYy#!>< z7_N+EkmnWET7|T>o zu*Q|gncXQ20*ta(VgR-EkB%)8OOJji#xsi%hb{xkQC(s!72wfv3@Qa%>Lzu;YTfD z1%-mz+S|AOUabuSa@sI^U?>d?!iNDxt>&Bz28#lS7jeU10JIs563r9PvAWab2;RFP zd3COx&8qJofV#%g_KZK@`V4*4OY-jZ2QSaMKQt3_teLalMkXz>?gf)Oy@0gUV$Z#& z5Ty87g}B&TUHh7UK4SVo4KbdBPPx0V=JC0MOoAplNW&`ONSwIUAdpz zH4@~LaXpUaYDbeTyA|WbXrl{QSJGuoE!?8D`KY+Ki#s{2uY8D6feF&HTUg}KqA`?ZS z2$cRcYf&$TeqwDFm`x6A^Y6G`3oLUb&dBgmTuPQC^*^>d^ z7y*=XGpgjNzvERFm?-Dni)JLv_?gwgR(YEIOlQpG&3mu@QjD+_Tj!=cP+#KtVfHUU z_I(O$kC7xcKvx0yxKk3$OigVEqsSfd06GXWhQV`I!txgn!xID?y)hW>NAt6!XK7O!PtrFULDBxCXC-TiX0vsCC?yv1-6?K+2Q+0rmF_WQcJ;xwcn7_D4ag8M(?8cFfq;5%SM}2o`SeSC(r9<}065u5e2ZBe4tFpiAbY)*rg)uu>`N))P%K4?n~!@OQ0^~Z zo~y)C@aN?8^0zY@eP(OZZ$K%gZ#&?L`3f2|(fK?eE-cx`oJ3V2;PD$OEAapV1;`pu z1FdHrb^RwpA7Oiwg-!>GQUf}@;$me0g*f?aVv?YR{}X+7wOn7O ztG1i_Q6UJ9XKaDhn;(_h-1h1R3(6eOcoK>ed;@2y!9f!kUZC5#hg$BCR?p;VY$(1*>he;XmId zzEvH)>RKC3F2y%R3Tymh{A0bTxcWPS&$+NxjGvkwxECV46~>(vY1?qEb&!2n1R z!-N2Q7Vpve!8gVL-@sj3L&N5c)~}8g z4AT#44qPf%5bO|Ea)DUv5Xyw2 zlO$Z{G-B2Ox+Lzfr^kxVye%LZ#OR1HmV)KLi}5ZY;BF6z;#2zLW0$w`IbSqUXV+Ez zRQ~BOzQ|W9>MKP%_bi-`RK>P$8M>xu0pLrr8@XRRUJ|R7D&r(SFAo3k==C@6(*9D= zFP1Xi04*U27h*(67fs!w4FoE(33-&RZUgq7c@qGGXrv#oBMaTin@5JopD^!~Tq`En?fu=EN*OJYuc zj}OF=2El}}d32g{Gn&cGU1C;AxO&fUVtX_eXtBG~ajoSKB<QC_dS~JkK(?O>7+8Q+$W&&rOygwnJLaQKzj%689gGN5n1Hu$(UQ~ zgo9TfF^G-oZg=oO7A z8?abwWbz#nx+kH_On7srJ5?YY{w%SzxL{K;ieOCvj>|5oS{Ge%t_Ad=F)C|+E1&i|<8(FMqU=Ox&Z7w@9y$nVYK-ehZ zAP`p5>!c+3kf~oEfeM+%7eh3C#9PjQJT6p5_H)vO#~3It>lbKlX>?r@`PL2DO?0!F z_qA-o5cD3SwnN|hIEorQSU+Buw=f_H+iZ-2RN@TmFMd)7n;ZoMiDEq{S;4l%dlvmS>v0 zx&fBj;5upbYZBL;b0vp<1*HYp702fYK0MA5f7)s5LeMV2ktCZ)(EuM0Tslrhw&{1v z?0{$Bi;#`{fzE9;@v@M~vLBP*v5Sv5l*lxS1^>c0^V;@}{(CY!HuAhW))&k1xh2Hq zgQGK^O3qqODejI&eqc$N3Aw)8d=<-FE zCe?}(d$V1Y31)@He~4bS(fdjJ_kD94{tE4qgI!^~!rC<;AebE5w1iKgMf_Jc5#HdO zV${c@AK?{ouG2bheq8VreU|T*&7v+sk2Aj#ihh6BghNJF*UqLa#V4b44ACnF?J9wc zB?(>zl<1#e+W{ki$DBUB)qBLQpbI^0UHBn=&34TI7j1K!+h!3RA9?$igngU&d}m>V z{5-jlA~eK1l~B4kKk`7k_~E4orH5Zxh@oju&m0H_2njSZd1=R7EaEMp(0Jb!8xMC&*iZy30O{5wkt5Cg1aW`>{$nWvU3=lsskb*EnV zC5P2{D-gg%=EX&18NB^Lx&@P#mS|5U)-GN|HRFAGqYKenMILC@r~A_^X1A4eA9RAf2DsJ0Zc{ z1Ak&AwS)r8P7*TqUur-qQwGCv1lP1Qqco{;ji>06l&>(aphop+X(? zj3Bqm)uUaPLgYOIN$k9?H9{>iGCKM9f#;yP+G&~%e-L3z57Hg?v!v@639~o#_XRgB zpDl)O4IG8Cvs$euiq-|~+;Fnps{Z{j?-;iA$-i*p>tb1?hj4(OR_HrKzclR-43;ay1 zAA4oU52ef)^2^~3(%=zsAVrM8^^5o!2#8jub1y_lA{@~|cQ}-pZ-$YcV48IQi!|ri z%#AC9QN`fb$mpL`2CSch`QuR}QG7`f3Akk>pMro$H)_8UUtkAB$QY)_CYHdZEsc9U?p4S4v@ z$My;dQ@m?p3ZBw|WAA;}FKqF-vPP@!$UpW11f6{+dh*oM5vYz;Q5vX-)p5>KS`Hp# z=*J{qMmF21j*O_fmu}%lJSl_Ti6fm_B=mWjV`RDEYGmywJVc1Pn~KUr3k&PMtr&Ow99O7s$*@kL zdr{yVXc3)wLL#>X6i|?;^(Z}_(C@{vUFGl;I@g+zI4yX}%Sw7I5uL5LfI=A1vVN^2 zgzyoNR+^mr4$U=ymqYDzGRVh_B()9j5$|v1ExdV-KWd?;As{cri7ZWQ}|m=dPa(uX~;L{tBtD#i&N#v-c%v$Gs*yo50l z&f$tB?u);WXlKyG9#|zqNqHPH{4JW_ukypP?iXILF~`k z47M*k-w1?|guwP+;(J(PYae<;-8t|d+@35&N(}!x_OW_KA|$Khp70(8**x^$B?ICg z6*`0K%&n%aHejjdcG8CRVR+nkqhXIP!fd~k_}B^_LIZEI?rxmddlG`}5nMq_tk{FmL^cWbFdZ(j6*~RsJzx)0iHvr&f45@_} zi3f|)u1_($>P%6?nR$1*T0hg-NL0Ohp4rpKpb#?`?KPeqPiT{oSQs1ltL5tIugs(u zFt^_#xymt`DGk}$xoUO&@GoYJh@Ur7a0 zWs5cay_tO!D)BT$FdTgE&E@kMdPT7q>8G{U20DiRI0+?gpLq(Oex(SZc!68~mtBXn zm>;#)gR7f|9o#-H|xq34LJ11$?tHw`7hF_qVU$dT2_DPZ(! z1w`Eni)e90dlI?txI2jMW+G;MRh2pQG5mw@6{RS-LsIxIJuxG$&K;Eq;+-X@6*glK zQ^S&>H^ZN7-3R>~HMqG)-@4bX98*f{3Z{EH4cOeOhP#cPGyiAK4ZrZ6NDMK&RR`KX z6CU4rGd-%wq<3El-xZK-K79BKvF`dz72m=R!n?j+5MD0`KBoS!RbHfIhVx>3K~IR! zYNV;_W+p2IyKC@s#71t#E+4BQ!8X3EavHv_|dB^=TGL(=^G2)-{?3eCD{k z_3`a}83&*>Z%LPB{!UNkhgl(u}Nt4kBdN? zgrP+c-3Y_1eEL#i*pEy8ZzXeFhg_O&O3KDx9ZK4&OcpG)*o?d6%NX7De)f;1r&*pP zGY^f)Fh$30r&DMaOhnBvE0M&9$4VuIW4jzybzZf|Tn?@irT?URzBzv{JtM}E7R`QO zB<@w(YVqtv%1;>=dRnH@u{YdKNTO^+*Oy2C=NoG*DXLo3>5_dCGIw(t)P`k#Rp%dU zNHT=_#a-A+;#4_xH9dzX?oKT*wwL1?IA5Uuy6JIYnWVJU(p1Q=$XX}&cb7LM@n?(9 z%ZzR|hpE@)0^60HIObRRSM9IEr1F1pztE+&U!?`ZVWL=Luf%L-MXDVsMNbn&BHJQe z${1(EwQ!6^I*4?c-ZD}untfL>^$EqT(tOCp%I7df>*I#)kXjF>#ETVD$m0YxVLRZB zj-5_(HgZymyJ6uMnSxZ_EiXn5`Ch(?`9%(9Gg?Y`EksdOtkoN}Bw6HYDV^_`e*0Bj zGC8HDvZ46lN-x*C-hU%fU(S{pNREP3g{t`-Gp4cg@GEHr*Ath&q^S4;kf6ls)6*HO z*B{=XGlZ1@j|79kC7nSxzsbVkymoS@V67YPau>GaY{9F)2L_jK*GN}PUxwPcmK1aQ ziU;f+&Vi3saodETF7F|We+LI!U4Q;HnylcQ+~7|X=uJOzY(!pGFH@QG#Oq$VncGam zjTUzKb?;Xg0%7mt2httt$Iv zE+S(E{J#0x3Yus=;EVE`QQd>_i%Iw!H;yAiuDGe#A>z;V_P2@UF z4@~quxs>!Nlcov;nv}&*qFnZqCg(^QL3fTV7l{ zSd$AcPyX~tH>2F$hRhGD)>3xTYPPvXp>_9=SyN!7z)1;9_j2#0rD2QhG58YOZ2_Wp zzBfEUHcqcNj8HfDdg%r;NgScoaV6b?a1&uC8ScQ)Jk~@ytj1}C<|WxOQ7MZ(0CtCq zf8VGb$Ds8a{%Cf>U?mu8b&@SHmq_<)Z1Ntslu|lW97@1ip_%=Pyn9BBuZR>q?K#tA zVi0?7{l{}%8hdms%+dv-XRe2x!&(Zga6$}6t+9k{^nOl^w=TWlXklek*QK8(rD$Hj z1lY1%cp%(su`aDbR1=O}tTL{-Dd9n4^=L&QeY>-|_$}E#mBf!g4Ni)9ZOMQ=u*Y8n z;qBy}g><=oHq{2^qVwGNk$8OTKBl)$A56lEFEwZys@~hufgE$9OcoK{3kko?_EzKB zV(cgzR$1RB)m&*!{fOnlxvQwYh$DjlCR!T7QYSy=S=OZ$LMTwTyuEe+gw7r6OP zmuB6h9rC%9l%(W5Fk!0=(h#|FDUjU}!k=WjNmS9RGGP4M!Kl>f#Td_9RT-WZP0pS_ z0nMd3H@AP=gx%1MX}72rgx{Eq*fKPaxYKDanjPMch)N2|dZMXlz#g7RYcE2XzP(cz zL+{2mQc?F>FNpnRlw2IXAsRSd8wFHFXK_Ndn`-kE7e-vGoCRRm>@5{sc19m<ME( zx%g#iJS=bjyd1k@D*F;P1g){c+V9Vy_Bqx}8>B2{@pd?kgzdxI%6>9wVo|uw$<@JH zg^U1w92ZSP8UG4ct_Jv`=wVf+d7N^aVPW32*~dT*i($caX`Fbh<^5+KU$yFF#x#_6 z?2BPqNy_+#6e9XG9x0L_!7Vn++4(Pgzv(4tYT2GxG52a#Ju9gedb}}A4 zaDcc2DqbMkggkkVQu}w(xAKLAv*Jkb|sIF;|w`I zzSoS1a}t1PecXs4$NB__7-rr9(uEC30$~y$Um4V6wae+Zq3F~`FjMg=Go&@tl{2k8 zW1n18EJ1ba?ayt;}zD`RavP~Yvw*xf0F5hkMILb8kpA!X#%px zqOCmi97{^@IP=m9ILNE%Ybop6(mmqC3LxIvx=bw(5lx$%MRb8Es+!pF2GziR|Lql%dy1Wss`C{^ z`IY}Zs*&bIIWqR29wN;|9-Fm9i*YuUC$g(o-)4?h5D}DFP85ArpF$fDu!d3Wjg?RN zo<{tsV~_`JS)!w-(WghL+Vr&jK?0X_nYaeu2=tIgvIMxB*vU&8m6ozFDs^n8R)B^< zPp-|j@Kji>b%x28pfpV9I!NV<%1`*uhnkWfS@g15c=Vp+Tdx30?^W-MdvW-GNHRVp z$&j|P-ZT;*+A(~$SSI4mmrp|;P@y|Wh_?;65(cqixTZhC(0*?Bxwmst_0?BCkgz6e zVU4CS#K;t^Ki3mlr-U3jEfVO3))1KnRmNKMe~jm=#1@fmum zo@L7Lr#Q&r@9j!!PCb-mzoG+FkHSmb%^Cmb`D z{_-5u)@MGbGx~y*Gvbl3+khW+0In?%OZ6w30Hcz=-e9a_v^88i)k@FD^$Sk zJi#7VdqU&!|GtMAAc`6C8nK;%x_3iC)r62}lV^)Qm$ob0_CCubfI97UPGkket%SI>+u0+Jxe5M-xOeXA=I zm`|#xDj>!K8a^~rUmPb3_dlpj_;dDt^E*`iItNru0EAa*7Do=X5iUGHt&n0`oj3IC zfAmdVBTt5&^O0>wQ$(S_=UV#XoI9vUr9 zy8f=Lb}lk!t&KI<;Tmqnd@4049e+2Z1XdBDIUA}NNt1-I>Bo;MS_srpP=hh4XV~Ac zPNRR5I!102L{*ci?V1_xAd%psDC*hBN>I}&ZM#zYuFwFk58RO7L7InJd-QM2(On7| zrCYdwY8+pVFaz1$(9szxvM(F9x*AA%$OBf8QE^lhtR8~$awDijRiL4ijk4InL``?PhlLn@T^T) z90Ex@%JhgEct!*8VjLdDshQ$e7xf`l%tBeoHkEj+ zhz0LT@DPiB;O1~=@j_k{PNr2T?@6Uw_U#)ZHPy_b4jPd=fqW^|Hf|=r;(#1hi|wAH zLqapLg2GtNfRiB@S29`b1)Vc*ptFt*M_al_9S48)LS~y$Q(IY6F~q4#%db#>{16kH z3Bb&YfXpO7g(0%)zsF>Mjfr3d_~aN1C&13e;H4e_p=e8^PY7ebE1NiL*AY~IpYLeO z_VGUyVp^=zIl3VVigIKc_PchWR8;i9uQ}uvAI7tfKTNa+dzb$5afkC0ES#x-MH}H8 zw>7<+icqt4d4auq$7tRuqEy0eTcSZx22!&^>u|k}R{UAjW{Zq4+Dcm7J>e2j?cR#k zDjn>Dgu*B29d&bUtaSug@Jrds(m;^nFunI9H4yFEt&=AIxvsH1;#u>MGQtRCLR z73V<}|14J{*7kk+(5UnXXe^tMpDJ+o(HJatL3KT02rr2VgR++KJ>pRoR2{uX(c)2i z^FOQ?`KhdW;N`ZM>TnHaMK@5GrLJ-eeOSW6;PTqyzKQAIsnwtKX2Hrx$^c^1P?yC{ zcu@VXvVS5))dbinoV)l#RD1(Yq50C}Es@?&APa&3zvmQqBs38HhXPprG$0R5D$>6{ z*I5`2)Oa=(pMu|a%bA&(bs%Lx5s0`0A(lHlm!=&EWB-sdBv+@DgcB4}VnaamoAxd0 z2l^`VbY2JLEb>eXT{9f2srtHzmU+n&$gdMH8GI{d`1jH5i^Ck!IabV8>H7?#X3`f? zEB)zcSUkP{-;?|EME%t6o(3GIqi^I<15*!x!pacxt*s%~ebp%YGN_n6)8WL-PSuc$ z)@}vcjWfEG#w{l4oA=8vmUJn#rHl9*fiWUBrqe`LRc7Atp&3H$}!S}G9x~n0(mAtKo;BxL{tP11HiIS4B!Od^$pA49*1G%HQ(OJj{`x< z3;;ByEEqTqaFCC&c*(e@Y5cT_PyfuK&FcAQRUumUnTIT;Cyue3e5$VeX4y3y9&xD) zE}_iau>t24s>osbRvC9Dfllb}tG~Bsx!|Nv0N3s7I3(jU?p!Znj|Z{hckxY%ZB@VI zElOGJxnA6v`e~X2r;J;KXS0S6M~cD+EV*Y=_ptR+3f;>E1D(1FWJs!c*ldbxjBC{w zo`oiiR6FQON&R`Rw;jrD*-TE;phCD@OqgZ#Yv!L_bk0+MWrsb|_?Sut;n}B!;h$zg zxr*t>Ue2VcQClU*D}mYp%@}~B0usBlhcTHkK*B(>4<@h}liUg5sW63_~#gyKlsb#lt{o0#>1OE)6!olkg|2}o7FW+tL!oR60`ySV%* z`w(5DoAJ4$DcE!JSL=o6x&qEd>LyDOntW(}5(czU8S{qwDNq#dST64ga&*T)rn99T z3LaBdnCz{~;_ko5u`InmObxrbh_h693Bf3>7+89XZT*07TlB4Wxw#;^38G|1vaM5s+=pz|M$?|cCB_?YPS=ERrXm#k z_Mae;mdox&o+cWZ&LoxF>zc(GZ*;H;w4;#p5s4)oEP#I#!9?}Ix$6;#q>GG!|Cf^2 zfiy_hFz4g-!{cX)h6+ELuf7>?cuL@Lnu0!ee6*Mcrpdm9H`riCF$X;0`>d|sR-FOB zbF`v%*pHt9@v1;tAzYSe)f|)S24ulb0E-%kQ`E=m_C;ms%VOV>R7R*Q5bG9*d|ycqE&79@SM< zCt4Oip_kjua9WovDfTv7c;|k$Q0QArWMy=t@oI1JNvyQc%(DZ#4g0dsVGE=@UJ+%x zZQ!r@?=~);0k|l98V?}Z2J^o4{5k*BFFNmY20*d4fE;hOBSzl^TXP^;*|MLi3CJu5 zuyiS$m<^1Cok#>1piuSL@>gRUY3zmPNk^dxsmTVzpCM zI4}R}j>%SoV!K{FcDgAt{JTY8kQ!f3nr_!+q=QMTEDp8t z5dJ9lTO_w$?M#wa*}eOG?__TW7PGgg^Hd91QK0_<&@l8W=D<@WO#IdF1O4Eb^73+4 z{@*|l$`G);n9}Yrzst_1$8eU+yS(`@_$tf>4#dqH>J#@5u+!P~krIzt3Na0)sHM7^ z{lVRTzx>uSsF*`sDb1Ktk&nQfy=gNx+>2F}a~5#nqH2ZpP&4L8U0S`mG27EA@ngIuTidqG zT`Q$X@uGcKFmHrtB78z^lRD!WWpuo&LWLq%Y~TcsB^u=#9W>E-Q}W*mik-w9b-F|iWT2YTgLB>A=SuCRD)WK#}YBnk6IjBAi39t z1@N>WXh0Aj2Z$fD9<*ZuTpBUK-2h+ok(7m_?c}UR;pd&6Y3QsDiR)MPOEMPcLx_7y zYxLslv=*T!kP-3vkA0DCx~`zvCcM#X4G`0o5G*+?#4RLUHl^`^V&q6JdWMc)6blbJ z(I784dLs#{v=MGG<4xO>_iSZS>Q9lQ{0H09EG`AE2uvt*Tv~NzRk;Wjl17%;@a_1P zj|c|mivFy~_|+_blZH7xT=D^DqN&MmIx4>4>F(96IRXoB(wjKK1-oH&D=*x`Cq#s; zf+=hW;?2c&PIxRnL5dBJa~GWzyOZu)gl;awR)*=U_Cf3ME1wyOkm85^q6ITU(1MQZ zZj=n86&?QIAA-T5WA>{f^<8yVz7)`i@@2#mtV#}pA^YqLS(Ux-d4Gj3=cbL9d!DM;IW(6`n_V-GFI+c1?`Bz6sSN09O`t^j3=efi+s{8e zOn8jJ04;|!)K)P`=$=?jeK{W|9_i{m%ADO}I6AwITm}|_RGV$iQ)~Jqu?3TPt^6g= z8#0+NaEokrc8I% ztARg=c2f-B=YBk0@%^YK@H;Kar&ZADhvV1M_X*6vLEIFkrmCtc^`yz(cC;J^gl6j| z{ZjKU`|v3dui#*po1nSXO85p9*S?L>LOQoE?7EXN^O1i*htb9PL6|byXs+V_AW_7s4tNKMYQ_wGQhBO^^K{VQT^{LVF^6c%^Z=K?g=fW;g@2Y z?{Vso`FB5uxH$t)Jm_R)WepygE4CMv2TfKzXFsq%%#uBT_~vT#3DW)OElKj&l}@&d zxVNOYe0HAfT~5qYj$0!BRg2OC?!Vz&pZ2SoI>3co;fN9)vR1cM*p|+=G?UN|T7NpR zFc)G3GV+zgt#o!#_pxWV;fQ^m=3-`W{8yL8zYT5_BE4X;7Beg$C2;F=z==?I#dBv~DhQ}1I#qDhB6JAj3Q_Ge%zz5DAJbC$ga>QJnE|edzL<+w}hPSvJ8;_R3lO*8Hg$vDWrg)Jp3I+VvG~d%q#u!Rc zEQ3sa2*;8J3R_YlN=oYgqJBKwCx@5==yU(y`-sJCw>@l?AXi+;*;c#F(|^&f5^avB z2RE`NX_N@X$F}vBrsVDY5k=ge2OIa)EasO(1mkP7MDD$+T@-s9*jU8O;rhtlYWxY2 z^f9M!P-H3uCoY39Gy_nD6@YUKz! z1b%*M14_3KAvX?f2C!*=+o+F4TOPDHU+kers#YyTAKwSOe{?Fw0l4%>OK4hy$N5V5 z>pMyJmDo{{KUi^IXg}CMXW%4iXqL<+8H-IPAW=Z2pCiUv)weZ*ozAy+Lktwwkvy&V zK1|N?Z&P8PJsNr%@giy?XmgREp@yz5Itr@@(9IQ={pr?2Jc#tG;6#l}hE1+=AqGl1 z4=ZgPK_`_6;YhvEcQ|ybF z+c%CzY>%J2d_}0}67mZ~$d+M!XmU~Uv_W!QUCJMg&#tznp5K?X{yqY>f8hAyv(jqs ztjz*c+hj)z*I%=F)-n}jAW2(Ei~sI-=GE&3&ZyLFwS z5AAnK<&Qb}>v|k}v{??r^_%4&N@d8lTHheH)C4(Uatmk5Xo z82QLM-xa$gkuU%It3Fl+ZLP1aBNiG<8k6jId;X#F-1}V$kV(b*>84u;&mfEiBwgrd zS`;RSe0i#Rj>j(*(8p#Qut~2-ut~4W{=!0iQjxWJ480cwp^dYM*YoK)qD)HF>J4y1MtN{K+P4|WCgs#MpAl#z+03Vsd@md1e^FupPWa`umK?$R0SNm@dxdf!tbg&?J?@|&Ocr2cuM$2$b23J-zSHO(sk$cagK0I_o{+4 zhZO@O2(V-OeczqAX^|3E?N#F^F7TBsPF4-Cq7V58>-)|3}LS z#NZtxK*>0f2O4$GJY-58(*l0wtYin_Yvqw3epkAk!Ct;TXV34IGCxOs6_+X5a}>vI zdvYCAK3|HdG2%vq2ix^pDz<<>{y!|8WmFtZ*R^M0(BSUw9^BpC-7OH@Eog9e3vR*f zh9JRRgS!WJ2_7JC^L*d@owa(c>h7xQI%n^FZ4lwkQ)0|6Co~Nmlmrvd{4O(Mt?C$5{OmQ}0Q4NEcOlNeVg3;SH{kKTy+;FE49A~?V|;l!4l7b{3sdq|K8lN} zi2hAf)NHYHIF`4OqWN6CddNd7%$GPQJ6yydjY%FwRC!35^j{OjxgD;);ozZ6-?-IUX_l2ERFT**ltnBgAPN=bCW zpTAVdqQV5z85i0}DZI5~3+2H-11ysP0O}qe`1U8C7r>T-K>#WN1qkR12dp-Y5jCeq zM~KNOB7-Lz)9R6eqc`^;i?=%C193fNl{Dpf8m~Xn{D{Us^CVL^H=wwDz+jHll#!zF zktc`H=%PjV!gyymz$)$GWNN%fs}^i0-y}2q%WVZgGS8&ev!q~ILR;nFmqq*5Nm3(2 z6y~pQiy(d!quUW_lG@x*IkWM zAwZ1a;^N{37}O2G$u9@^OUS{vPO6qP)%4uN$x0$O)X^~Sd+DcPd)G0k$whRGq{qxu z#xSa5KbooO1QZ%YP*-rZUGF zVRnpj@#c(j_ZVMb1nAi`ZfoHwyoy7=V2O79h+!1x$7UKK9X+*^)rI)FZl7o}%;wUk z{JcsuF`?v_nw+_nY8~v~b$LjOMi`{a?X z+AwDtw-<=$X{lqga^_*7d!%m)hA$x@~d6c6Wxgm+~-lVw`)a}9Vu#UjK%)L&Jn?Z zmAtvKB@d4uJ})Xtr@lY;aF;K?&V*j#F(HH$xy@-D# z_AOt*A6uvr1PDxjr>F=Y%VB!bjgYjw2r~uK%tZ*>m9-rmZ^gUJO$1ruN=W=TDhllz z9wptqtKe2Vy-vNLOzI^_Q$-|-yoWs)s(vj=6;uWxi;;nKtib+e$%uQQ_emQx8y}Xz zWQ;*9ZC#_KOV?S3J$=wxfidNG9;5aCG`1AU`aI3wj~XL8A-#JKiMx`|vp*a5d5Ws? zuAznkqIOR_7Ry8Tydq|VkEw7r6Gn00U;$D2+mATaYk@bR{^g-7G6ys*6-i=4K)My{kvCjM@)b6Y33kHh@qlQ$LGr5#s z>PJ<{I2SF%x5-i+s(oL+62LJMgiql!4JA+>fNX2p^J%pnmTjpsD9#5I){b$ECXzux zueOrfj-1Q?g9oUtxIwgE1Y+OAg%mM3@I#iQ zYG_Gm{%RY$xk|QU%B^8EDOEU?9F?ezQ?b)jH8uQjq39RUN%gn%|H}Uvs`RA-v4VS> z61SY2U3ILEQ>M376I<)axDmZ)Bc8+r+9rvx?{fJ?7g?v@my$mE3)o%nC*RF?mdmXI zWtxwQu>o;ai3MWC+VYDT2-KJkv#UMg!sxi*YLg@Cd>v}2D8myk@Q%YrwyjhMDmG6b zlx%$X@dXq#{Viz_QoI=>Z`z*PAD{%0%ZNYAt7*mHP1;K4@qnOmF*#0Pzd!7r(NF$} zv4XM?9z1|BjL}9+?1D@dSOLp6uyPFVc`|Rf(K(IKQtjy|rT)zh-|g@9mMG^_iIb56 z=qDzyGePwLG2#&b1p~=$v04lurMq7M*5woOs%M;%PgYY|4I4Ym#JdBoe*?2JA2U@_ zk{d-Q?TU!fXu`TZ`S=tlNM!tuie(&-F^GNDdB#`x{eSqH0*7YPbbb(rT(m! zyNP*7gJjiV!Ra?`x2W0n0yrb5&zOpB+kB-)g{wCR&1R+{+VFF@t+ycM8&2!ma9|-S za4)X9Xw8g}S2pOSw>2LjL*wVyO%Z|oenvUxb_NwTX7$`6lC>nA^Zje1=92`G?jyOqX2#0#AO5{tA;cg|ZUAD5VVhAG}p2i?<{mv|JHpa-(i@ zQl`L8w$$ReoJZ8sOGM07pts-w0BKgCe$3H#M+DXcC%|vN4xl;!YQS4C0K!-Yn!oQ+ z16_Y|FHM00wdIUCV30{CSie62rthF@zGeM=;x>;d2BOQv#jY`Ri8NIihjVLSGMcZE$nj3Mo% zKgj_TIf}a?jwXBuE}Ykn0AoM^K44ze3L}x3w@+*77LyN4Vhrh(8WUszkHm4dK-4fJ zxy?D2C-+)%R=7I5@Xf!o zh`<0!AbNU!9s*d9-w_#sZ-;@t%k7(Czpl7x1XKNJUr&XnO_+pGFZF?tNafxb+tiQB zSE)bR*gtJ2Vzlj=bPViC1@1@4_DU_Q<#a}_;`flpE}YdVP}||a|JM>9PtfW}kz5P5 zL=VYSz+&?;^v=9_U`lhQO>Fn*d49M(IM{_c2+`UeTcX#Y2O-re)Pd(ysIs;rcgy5b zlqVO^iHJF)3MefT^v5$}C*f-}t@BEv#A0 zEF8H&@j7pda&mHlK<{np!5Ca<5J2>sSzljIDZBG^x8_Ogg5A*Mjo17r8(q~(_03N8_PU?Wb`y=n;DMz6MXG{z_!^nJtr!{#(ew{)4{jh_r`d3f=grQjo{{pD$IisCO}T(PWEe$^aH+{dU4b}w$zj7?W4DFJfO zeRDtnP%X(D=ox@P0D1?O<>wjudl<^&=0jJ6MS{=|-~iws>Am1uxn^Li8u^9SA*XU> zw>Vy7%^a?#Rn&q)fk<5oYm_oc<0@aL@Myf-qK~#EVi@NQ=kdj*r(&14rdy$xuGeE&G`cDy&Jbex zKta$zmPCcJpeX`-7Cru6GshPvP|#^fv1Kr0bM()Ie&QxLRYNeu(Uex4+hj{}kVra> zEJ>ElAUhngrdg$O!`o?Hgygu9>6*S-q63F4o++cUDzp8uNRyWV?ueT zMBA;wJ=b)i5tj(%df?<2gd@6YQ8O8#LK^Rg*-3+bi!z~rn7_~t$f9NyGFag1oR@!W z0jdbon|n#Wo1LI5pky77CEiHuf7v}G$1BwHzETF}M7MihsRV~$SUx8Vuiit&8ohn$ z)mBmejoz>)E5*)!;jCh2bX^%B_>zr*x_R=oZpayg=f&HIq`ROVZlo`c ztx(Q=vYKGbB%>80$F@UncKA*9EczU+JUOeE~2>{o%V*<-795Mk`hcdvh;Ih+3 z)&Fl-^kGC%{i7`FjLv95NFGV);uG!_zrI`yj`E_xZ99gS0*kFn3Cv|5>5LLRPQ6sMsWLQVyNTSFgdKY?c1|ki!3Lh&3SR)13fy4Cv6T_WlL$dx)-xCQR4(uL<-n z!KWj`B98au_<}?!$Lbe}qZ=xiBNOWy#d_*HgP#dF@3xGbB0iPpLHOfknudTTdr)c- zRYF_4ImY_$H_)n(Igh!Cd-YcJEw2AI$4>LZCT-R4nlic|s+HMFhYn?Ro79G&7Cy@? z%e4gbnTgdd_Y2J=QT4itfQl~8=uCZSj!iWBHX?+GFIgO42nk@7VHx;ke`fBY#e-x- zmT-(hNW8%LKpciQP)vC*`Q0_q3n1kPio|t(L=%S^&rd!1>?6|dciBVjNI@Fcg=^HZ z$|@x!_M0<=+*(;PEKXzuU*kZdxSb~Ra$6>{_m!};T=7ZfzIJ(tp5_ylocggS-haBr z-p(RAY`>?wo z;9=N6sGz9T)FX`}(G@RU4OxFD3Iu}WeyAl+qIt=Q6C?VGLUhEP=yC@HMLF@vCOag| zb;=a~_~4S2pCqP1qFj&^2nT4mS{zetvz;taNvA;PaSh4!e6hJ57aUyuyi zJrMsgg}}3+T-|Y(Q+*Bdn+S9wA!;M{reX=gbB%Y+YnYDAO@+yiOgF z6MFn+?wGe5-vnINqT~-P?N{&itW05|yH&|?1tB=aP08$qI!>C-HWmQxT-hC{T8QYv&h3X06-4tUvlR8nEX$#?=p zZnSuo9nD{aXpD0%gUaWQgz6@r zw_HMHsRpteDflw7b&;~6Tx*?+o-Krvy2;u=%cyVAu z02E?jfL>?^$ecQ}{qv0U{Je^o+n3>;rNZ+yJ22s;^?J-W`IgnpOfp%asw9G1*Nzgs z=Su8?m#x*_$3)&44y=rUuX(4+RPvwFmdIB{?Wa>!t2wGuv_}1N%s1G@UpRO-)fhq@9mwJ4dxoSsz~eu_}~N0V?MA!6V~Mr)nUoIYLcZD<9@?yFdZ=Cf7stWu(P@rPwK1-mhz zYx=(1@pL~S15Ym+5b%J%=Xw&*DCaEC(VXL<1=`ZqQi=%p5z<;VMKG9I{b|c1_^j!X zJS7Fgrmv;oyJKk-t_{knC2YuU`Wq(eiC0k;HCej-{5@GP3_o)heHI?w5<(nRo{3mO zNT;dv^`pYTvSf=_K7Vp6>H1A3v zK`=g0tAi?F7uYrVxVEJ}<;=$8p(`_UnC9S}u$B|5S^m)=V@@s}M%a!Z4TubUJvI4X z)>ikcCl)rg*=mz5?@4*FGXN&j6E6=c#H6yN4SQI>w6b4IXU7XL;5BELy{in#2 ztdK}K)ZM3dRX~eK|09zerW7raY0v+LU$S|m79VVTFzDe{>`AookrIhESQHH(N-Ie> z0r$3N{t0J+EZUjwT(vCvGu1H^&8qU~C4S(Mv?jgYzFASHVt#r!*!ht_QzM(0S^Qh) z6Ak=VOlE}Bxy+zQLZda5FFq*=2@C}!^70|(nqtk0_E)j9C6qZa z2xL*e=vi6YbBT}NOi^@D7b@?~mU7=ek^vMsfS|*Eha`ixf%@W5uGePNyAH7Sl;RuL zd4F3g8^aAh@;IVDYX215E7sRUHA<|#S?7?g_spU*pc0KoUUlHc zQ5i8oDew_hQcIxZezYKdq~JiA%v!!jRx++s)^QrCG!bcrAB z#8^^xmd@+8rux3LI>W8V%KYIDdr6xhjO!Yt1H%5DsynFpyp*il-YF^9=y86mK0b}X z0g@<4(E|TO29_**i+8|WgJ~}mlWskzuKSH2kU2J7cKtO69{PLDSo+t%&_ANPMdqEG zW_shD)0OMb2&Px!miMq)%)KyP1K|kNYR>m!{|3j%>cFX_*~Uemz6z}`*srtbzDO0J z0@cH8C~8$9%w>W+w?~&U0xNaUF}yb5Uqu4|MrE9ArtET8OXE+U=6_kO5m8J=;(>ni zCIx*MMfu1UPL`wCVL~@3Ri7r3Fq$hGDiBjK0Mouw245j}hq*Zb@s_=#fQ+=zXF=$= zO9;Lu$_=4o3n#=M{K*I%pftvwtNo~Xpy5|j@$j3~7J9|v?N|JX4(fK*pFV#{G7K2| zHj@^hF0@@B_H}xBIkH0I`}>$%w?jTS51`8c=(@)5N~dW@)yYeQQTd^Q$a_WF?oaW_ z*+sbI4Ms($a{_1*T@!K1r{@%5lKZ)Gff8YKWyraRJ*d|>uI-{sOezaed*Dz`BUb{v zIReo%)h7s>w=<%oMl@7q*Lo&c_Mpy$aa z|L8%61qGpBxGN+VSGLKwU~;nIcU7liMD#(3rW;n5e5IegeDqAzW|FMbOhf6-|-#~Sc{_vD1O(4}&+5zO|3tPrA~^=bYZ zcL{!tW6E)AyQGpYUKK&Ih@{L!kj}dH(}kwqSW6`*e6BQKP23pp4I|BlNEktIxpUwNHL5VW9aQ*dc4r^ zqZ*B0kV-vKbfuJj&SUj?(bz~SVI%Uu$(YIdD^`tRTK$@=m=U{wk;T>E*!n=XS5T<$ zAVQWRwa#?9`9fNHOZdk@T_{g#~{)Tl_htFe@_?IE)l13*bA3oU)h@V7h zw**-k$V>ihP}U|s>&u@@QPzQGbYS@jwq)Qb0R#77@5pLI&V|xGp8Bs^V+Ct5&Zv&V z?U>&~w8Z90Z-V-7eTazXhzUQ=Mi{UeFDxwZ-Y;9ci|yZgJj<;vl%VaGKU2d~K(CAB zN9{u)2UdknVjU;In<)5(pJ z6Jem3m}GuB#EPfWc|AuGpXjsMXry{sRX;)kzl{rpc_ftuCm15AW5{Hy1f;@>e@-#Z z7oD+)^a6i~gY8h|Js@C5l7vr_kIkw700ihz^N_NB|J4>KMD+P6UNfC99!-$~2NNFB zmd@-O`3oA)zw{mxu>wU&(I4ZWi3@gcUNC4BzMyea)hSIgoJP)?D<)7KBh%8JwkvQC+%Ia8MBPK_4|x~Pf?b?E9lCjCZaM#imUg)FcV2x~Y9CM& z^e&0~MJiXCk~0P<5%JzkW9)_$uyn;{vFYqW;ha;Qet@LVLlo#qVZXEcpoFHovuty5 zO^#sL8jj3=45)|M9n*Ja$lzpa@3akbfn`X*gP1#m;l#)oLgDCjevH6T(qi?jwsT7e zn0L>&3yR}oZSpi(VQa->&fEM|_LG>Vihi!>w6WL3;^{76G=7zYES0E(WpQaJRnbEz zV{^M%QI@Lz8~HFsl1(QyKPZdIU^b5?yOTK{q_VhFC}E|6?ugHWTj_AUC8Fr30`06` zcu0=1Gmb5~VEw-uvoh#gb~e?1LNUkMrAh}MMTWv!o5H0EWML90Y0(h9EUuHVaXW zpM?J2K)6ez`sL#%&9sz5uqJ7!DvT)GN#WGi_ZSeb&A2MAR5|84uB$*Hd;hrPsCD{> zoQ|%PA}<|cEsSUwFZM%5wD&j^hOU+>2HsqrM?+&f zf}?%__n^(mkuyF!OAMk5dhww2)7>n+V|G^~5^)w2!J6VjOSty|!3I;Z1?isQ? zGq>eemt)V;9jC`v9H(Td0N|s^8`vbb3nNGnHwEIM0on1|)*B9Bo^gMld5Kj$&6XO_ z+)FJ*m0j4q(t_fYj6XO%_3D)jIhfD&s%ssk0U4UMz3spu;fdPTYH*stHwy0RwZ+(> zAF=NCb{2%`PL81{v0x8oV%>&PbQAk(2?Ls!8;h&O4u|s1@Vjx`l%d+?*+^u>m5nkq z<{>=bT9SS=R3whvG0o$`(lS3~nkos`u2!CX?Qu@Qx^2z$V zmcsHH?F)uESbKw=3XeAekymYJ+j>p?s`hzKkAgDln3IK=8TFqC2HC|TJt08_=_dt7 za(_GoGxAP(%WW@u(#t&cL5dlDN*O()Km6{no7I|KBpf~nuj%5-9TFST(C%;OCtj*Vr7R$*PJ~D4r3&ttq@3%3!yoE5d5sIh5O;h`JfTBG=%TDiVAn zT$`o}a6*`DMJjhX2GP3j5LbWV(Sxn7bBZey(76Z$^pKyg+n@JZ+S{Px&hh8DTP)lt zFTb(`4$PH@^MpatsJ}jmrLAmH;M}6Xbd1}DE;}Kb&k7E=^ zq5|!<=FqZ}X%XN1-afj&_cZia(0W&Ut7-r(yBM6i_XZ39AftM`&z`lWm96gPzqurj zndx*f3p-eeu^2T?(>I~*cBCr1>?GG9BUqox^XFBZSR&O*7x>Y8s65}nZmLs#{^{Ag z-sRv@I@t)5Xgj;?hQc4%aB-w1wo=k&3}Gi_)|@}A>#Hll3vuUkj0`=sU;n~%6#XcL zroO9EUDp0!DG(GwVQZ*RMWCvmDy=4lIO(8=M1RqvQ^j3W><%BUlL`W5ul)xmUw5$K z0~Hk3!rp1wsixZYU0wUZIRrG9qW8b}g6d1V@CV~g**w<=Oo;}$##LtwKVW&w2%9wH z93OaM;d&KR3&lJyqPSZc#nL&eZA^!U+-t{@Y9kK+li$!>3YoFe!)gPlDr`(OpGAG< zwAl`d8XCZ|PU783m@_kD)6=uTLkHZK{2y_Ze<0f|1Cly8`&W#tc$6!AIUWbt*&Rck zW{(1sGGd1XyXnkY<>JVk@YyN7~kopnYX^9d?i!O&@e_Jf~Cs zo@5QOK&cdnW-BU%O^ht32M-`a*;9fb$i0|=MW3b?5h^R7zxiaCD1DnpVD%fDGh#~dcHOWXR z^vrxW#-uVd|CkI=xn+@Xvx8$8iiI1CfHE+S{S^lNMQ^vLsF-wYm3=v#S=!BvK70%s zIZZ^)L484@pxK>D+e+Q^*u2TIa-VURSCk+5pd`th88n+WuGJ*-6s~J@?t`SS1~mgW zzwAV${>nIGxVKSv5lL_3Cg01|0&EIMm}7uYy0F!p$Gw0Q7V%z_r@5GBEmjDw6nNc& zHPoYBXPD2Y{51S87?YTB3`!vCeQ2F>v^1eW1XvAKl<<8*fKc0C6h zto>;VVWl4adK@x{akyT+mm<*6fN)Kf-_+~&RD`XZuon1?4|z@_;pz$1>6 zVfx3^N+w|R#K)r;`W~15ul4sHLi|orx3Hj87C7hp|5i^+mFy+Pq$*=tZwOdYM5cE9 zU49BI+L@fQIWY}wlre*+r>cprZ04c}fX=eI#ulMSPl;5$>({u|CT=Zs0oi#0vz=}P z^}MXjmA0~ijg}TdfHWP?;2*hsR!qG5(+B=W$uKy{CLU-) z5wJxHg*lD|63nE5+IB5mHY`PQ%p~iX{R^k}-=`t|roYLsjQ5LX)*qgO=iW@|C&Lqh znxIqt5+oNj;}p#TO9Xz9Yv>Zi{u&4EeIl{YORx+AH}BwbMHuko$wuroR~BOb)M6bz zX*OPQ{{a(sr-y`rKxRR=_GA9P|Lox#nWf$`yu92=cw>ok(*;P!jzaYF9zG1Ub>{4?CBn0cC=k{hvK9L{0XavG96yNTZmTTGYso?jskP za1PWGiOdXA;b|dOhONiyO%3j%poPn7Sgr2py-Ckzsiq#g1jXIdTdHP2#`eGMxE<% zuJxU@RuH}ljz!Sl5#2J%Q||KHIO1xqMXU8JvWms86wMu}LFwx1Myd!uL7?GK2AY?Q z*HX&P@U|s;quQ5lwFJ$FICvxJN&BqS%LaOGqK+s`8gh9pLI@H!$XwB*6%M95AlHn% z1ZL7ry~DqM%I)77x|7E0NFL!A+tPehO|8#{u{AVIYvTz25l{@WNBE0)AgAexkEcF@ zrQM?x(LLEVwii@b>P;7v?%YV}2?C_K2_3DbwcpLTGUCO}{=JzhmtV2bo^PcvWxBVt z8rn>06@fY%D>&KetKpgEc8E2cs62>Gx(l~2tl1HD^`YVGHPKi9#zFKsR52X|J|{*; zj(p|Q9O|Hk37IViVuH_i?x>cUWjY=SILi_R@;0TkVYygLud+%=5?^+virKkrRYp+j z#Emnd^BPCge!=Y%yHtZ_4~9Ryx*&-NiO*6@KE#yYOCuzX6Xl!6RF)n6o?j*-*|RkW zX^SaSMZB;%Kh(D$2bsNEaGGmx!KQgib!m49odiVxGFoP->5x*VP&)-Jd=@(Z(Z2kq zSk=}NSc0#QdaraAVGm}j5yCXl3@I%Bhy-bpCu|tVP!$5zwTA+ zokOLksG?2}C7&d3bb8a(H1kA09*wqmCWjDT`bIBLw>R;@-o5l=SXr3KJW{kn$i|DG zG0A_^#kbXLimlv;y44h9ZUm;(Sl7@{z}vOfs$3=6~c(lz9UxnUzt5 zIKuJ+`HLVfBuZ4Ix67DPm;6bWWNnd{@X$BckW|r1OzObTNzSC_sb2qJY(w|>v#ok$ zxvc@4*RCCiBMa%^S8fbYWkh&Sw|~A%Su$OB873C8)VmCo|NVQMBgpp0!488Cia%Va z=w=@xaD1xPm zEQih*tip!gd}?4UxV<=D^Uzd`HO?t0J&X;@9oggd*&EL!(}wD)v==>^j=I?B6KY?0 zW3>TIe>6Tb6aks@`Am3yf3)zQVzTn>qO1K8nl?JE*J)3i8vGffnFobr2`vKiac#)>GMT@)C9mFGOgCHhpN- zI%Pu2zt*}VpY&lO>a!~j2G(-I|g!DFhDnq`ciF*J~;`K91_jW%! zs8g9<3^yBy^~$X^G7}!)@?g?!vAz(S9mF$I-cz{AsGV&ak7QS+$)}G9jlh$F_4)Jr ztGXs8z3hd0*5|7kX)NBll%Rhf2Z0pC=_zkFB>hJEm;Gs_Bb|W-_~=A*$<={rrG&&^ zbU~J;L9-}3+Pk&JTyah1H_|O3yOk+BX4Qh;Mqi;uh%UeIJ9p9__THZ4n|AU-*kj}4@k_1@+||fbX;|{ zsdd<2|2VdIyJq}crCH~Jg(5K?PZcd#Fp_aM(!E(S0&Zk|l`|j!1?t2sJphU*W;BI% z7a-5b0FEVKdRNt?Oj=)mC4B*PKQGkPuQ~p7kg*d0Bloi5e41zNOibMuZnZ!&zujnzrJb9#5s z4r3ma?hs|B81DRT>=Ncz(I(1iqKDH87Sljg2fYI7Q~$ea8>a1uVvHmlLEZ3dyPc(9 z2Hi4G(Sfjz0&w!1A{J<}oJI40eK5LEOlFqg5&g^~FNG!#;eUz`1je7R71Gb_*(zFwKyV2fHU5uSgG;NtGnrlJ>aD9n3!iAjwHLb|jzB-Ag~EQ^$n zW7}OT+L`FaDPSh|H0F0YC>*c&-IEZgirZkNCbgQ@@;+~t0mN8;|t2hxpTz~zQ>z_Z`g*JjnCE0h=R}@JR122Db zgXRA@Pa*MecN7|%+L5e-Hku-)2tMRR7gB@<4{1beOcBbO5O(`?F|lzeWT5lfoB& zf8$%=-+8tHyPIl`L7)Cp?7(4uILmT%|MkyBgd@nnBuBFOa_RKn1^1W0e@GXbLJlof zA<}aZ{Z&;*{PrN`vE`s9&V3cDnb-XtxsYQ|VROAD@EPx_qyR^rg)Edn1cjCT8X+clocywMT z3RFKI{9~9-*{!A(j^>iN3}s{|9&G=%748AD&iBi`^Lzc95B2K{+&xQ4Yw_jMU~g_u zQrLLC*B{0XMiLv6z8>g*k>!xve-rWin>*X_a~IFM+sAQm!pFpG*VS8n&Xj}M&xx-R z!oeTRhfPzNup_Q8z=i^PQzu0#8mQ-*{Mle&I!YJQX;&&M?_Xn0X_3d(=Ag zk(%J7FXekEag@UBMiRW<6cY--yS{LQc_xiu+ic1np)LO32gZcb}Jfs6@O3WfS<8BR2#P6qEHaS*pY*2r}dKl#ZR9F>T(K z@$5*DKBH;Z#eXvQ+J8Q+8$LQJe{QiFPrpft|1WeRU~u2zN-J!J;aNz#E1I8X&T6Pw zn?R6}6K#Q+6lt8i652!D+U-);xMBAN_m()eKxPhz#u;q==7(O+N`iROb-z6c3JPAy z-Q@Dq(OrQ|)pV0z(N_Kk_H?~6n1OC=>r|nr=PRN+rWrS&X5R93=XL=?=f{9eR&a?XPC&ZlSzb4fG z4E`xxwL>T+{^&5I(#Wu2$Qcjixl29J2-^~wmqqgTTV!?6nU)%S#M}ed%2K&4u}QdR z_A4`#ja>=ER0n^#It@zf`HMH-Nu^ry=&go-C=9#dC+-wcoPcZ7gfv?9vRI4>3X1)E z*)vntdgv8Thy#v5Ki}yfjeozVKqwKV97b$Hg26EGYY2Gtt$V>#5e&{1@cNxr_obAd zh9_NR4(pvV^nRkh>}csccWAxfpZq*AG4Wz5W;zqi;)%F)YS&%#nDiU_%I8PS_- zOIn{9%pW82qz>0Ma=Cv&#sNd`3@~iN7)hFavo9;cG!0-C?}|FZvrfutp2AreF5*(+ z_`cBegn`cZX)E^(={n`^=44=E+w-ZTs6#uV#w)tDd&<%OW4PCr4fgD%A!uZ8SZgDR z41Eqx`CE{LsNDQ_qqlLq9%q%r54cZN-?}QI0}0{i&ll5R)u50G+Wv(j_!oSvYxkA; zG~7X`NuF8QyYOB7U;5OHP#eZ#HAsJwy|KIX)C1%ACm-I!0nVpjs}`9Iv+N5wY#)74 zk8fu@kYRwwv*}$dzu$+~55yux0%E2`#y|i(_x>@^65siH?lk=VQvZ8EO1>9wEs17#EMbx{HI=b3cUi3lMV~gC1`IBPKf@@%AusUg2>X;b9nDYe#Cn6CK!I3Uw~>O zCvUX=PG6Lq5s{zOK|?X69qmW&jCK;olF0xL(gNvVlObd^4y*H48>}$u+#@kQUO!EE zJmzfA7=uO-(!RrhAVEO37K)CEKNm~e9){o{-&8Mv9Tc9Jn%d2_s|ADJ>%GfOwwUj^ zL$`N#I~{-Q^RuxTwLw8%FZ8t7a)k7;A09k1j#Er!pzz0)RL_6K*yBS zrGg8Wcm`Vk9_Vn^Y#iih2v-KdC4F0+tfYaYM~nWnABQe+Y_ov@Q_stE*M*OVRw6S| zR73sZ)v5>xAyrFgBCQm30BxU|{PQIe{(^VuJuKjSwJr88YkucWX_}5)Z2S~E9^L45 z7e6e`vFHeryhOKs)1ElF+Ww^Tz0qa*Q%!1IuEvw-D*MH(V{@qH}CexPj+O_!cdku5a>dsbu9C)HS zwC3HaX1HjWrYGn`W-LhTYq8M^!9b=S}m z^4}E4cqmDA_nscfn$^ZyM;*>58Md`+Sc2|fHb3`=i;)UET)R{enVAd&d-I5Rd{#lC zpw|0UyRS4Rpw{EEZ-`T`%frH+FWCHr7%DQRX$%bgKEWmiwik+9pGzI4&L*T7HV0T~>2MujwHIMqHUE4Q`+gG2+Aho`gi*kzmVj_W zG;LMpyn{&82JO7kndXsti;ddzY%n8rsyfwb{yl#0N&tscRL>(b%Gq~lwiO8*JL!5Q&1?}S~7KX-j#QbR9K8+0WjRvE%Y&u`)gA=*C^+jp4(i%I$8)?3`c+MtnknHmf^k952cp`F|O#W!J!G%1UJ zrnvpZ9EuwHfqB%@#HF;C7revYP%~8~hpAtUqP?2VS^RWXlo(68W@#pBd)V4BRZBnf zg$0)Ka9(B`wnkQaG>Z&8(&=Z!6GP!C9m1)A)GX&$BT6z@HCn@i(2!2`XW0XKU%=sQi${s|35u+<({EkXGGShK<_s zwzi#d$l^AsnC3!M*!ijiYwDYhp-3EB-7TAC_z9ZbBXC& z`H8!HE2ia}5ll-p{Gl>#a#FI3$o+$A)t zelRz|48?H4xUtf-p%sM$90=pURA@HUSE|gK*K7E4RO-6jMIiXE*I@2udssGxV1izH zW>%)J=js)Tw{_KSiFb@|dNNjhzH4Z#DiX1m!Ux~)FV8w`N=9O3sTa25-D(s;6a4l)gN4r4@R8 z!4y(I)4dOtR9~^nLLXhHO(26^<3kYc*bda;nC!DCY9Ww!a?~iD7F~@rBP!bHu7aqx zvEHDlvt18L9-+R?F!1qXt@%j+dids_?)Id`sJ)cpxLvFGL!w)NvpPcl8T4?EQWEO8 zs4{_wohjZ;8Wjt)?wI$ZI|GVq*v&abZ=o1KzOkjC*$5q|QJBKb3MT7Smr}Gdr5`QN8CYe`AjzrF7Vb6q` z&X=AlZ}w9vz_1MdM$`ryw4Sm{4-6Ya&ZFEq$0Bb}R{{%jxc^eu=8YS_a{q*4rF(nm zRt<#hG)H)pbCbk3E}Sm_P2Rdx#swa;a7}Y~e7p|oT5OJRQG4^w)XI3ZH}t-6*LLS zH_4j8ZxEcIXm$^ehMyLx%{xygLp8mMQv)?kq%?_~w`$h%fvyMAXrcTE+H%) z{ZIw{o0YQ*TVK2+wg)e!t+SZ65G0MHXU0uDM-VQO4y<&h#CwbfbL2rzWCxx?E^K>2 zyqHK4i&|-lv)K5fX#e3me^u3z-|FAy@EG1f{Csb@G7B9<8`V0Ie@uxfG7O;##*G<< ztqtMdhnN;HIKI`m);jXaKYCw&5!>HsVho=1>5xQg{YbmY3R0C!GYpI>m`og9W9>it zTi#R8cAdG3mgUYzdZy*X1}()4vStf1yn#Z`reKi9a=yj7Cgc*!U-_X%qb$xoke9$} z279%v8&l*J9E6A8P@@u$u$=vc8MD52+`P7TA_TU505vo8*WED~Mu|4B2e$$b5A4KaRR2fPHTdQI{q4`4ZQEXMSzB$jylmTc-D%m& zUUn_}u4UWi!m|1F{XPG|Ij?ixzTVgMi9`Zld}?C90~t6ZL-zPo01xEsZ+|FS<)GVL z#49h)ji!LOj7a$1E;cchU*`H5QZR^XDLvU~tB$l*s?N;3j7P71^f3+lv}pD%g61b(sB?G}3mBnYvxhkR40|17O~PXe!!2z&2Cw#YBT(W(#nJ4Dn$;6d^8htbLmw z;RKbp(i*sk6G&Rn$1xaFxiY2FRQ}bg&eX$UV8`sGl6=wmox_dJ?o>7P6xEL0`s&-y zvlpA@X{-Xn&;nT@hQaWtdQE~^(paGFD<4pbzuJM)!ioE+QtCq1bOIfKHGTs_i?)7q z5cX-mE^ObV{upt+3hGBQ{Q&EKwh(Rx@+^GNmb=k8SVe**#OW}?W7Vc(R~8_?2^Ld} z!exL?sR}OQ6_cmg^3wS-V}hsivWk7v@(RP4!D2ElM2ob1r8U@9yXs;SAc5wP0+QJD zc9a<()lwXl7TkdnBfIS7^dDymlq0rCcajwhkebBcjKvg`uD{*dQA8;pf`d8i>vCK_MglK1ZzKq z>jgg6LUDXko0?$!Q-L@)-$s!y*?ffXhyLZt$70Xl)i4fTG5>CuyX|Obg2lT3Z#tfF z-}4YTi=x>EvN^n#uIK`GAvdzJ@5c{~$5GWi-_+WXqn3;kCpKBzsp? z@8VB~CHQovqi$%H0mh|fEZSH!UHa!>rlKw6pbd#~4J`b`Q}PT}6;z=?*wt`@LWClw zC89)ZC(W&+K|qrA3k)(kN;P|d0#O75HFA(qQ~hR)=|(J3%~WC<-)KmPQ9nuZWG zcqhgW1!{^qS`abT<7QTHz-*3kzM5D(U?CliGhv%GN6_tp569A@`Xq?21A_d_U7abj z!e`_nK zg`aD6W#K^8bY_qnAsNe|R)&%5@=Y&wqxa^S#DABk=~?Sig_CIU`T@swN}-9iOw!!5 zw&5zQYUz8X#RMKG{2S(jb%}dJQG6f%Brvp7buSyG8MlI+veH>z=$)-JIXfT~ZLLbs z`-{~VlO6Qrl_H(Q=h*F_sa+2%3)#fHtTGx<>!T6@4;Vo;=9?Jr%Uq;rVs^Et1xU}W zBT85)RQ8G49CKuVqJq#I#q4(WXQ?OPDX;;z zy*6czBOWZPUbbzN^bs5}bw+%WO4A8{Wk^vS9LJE?1#_I6Ke z+;7@UZR+AuyGb96{HP%_t4)&l`@+xeP=)`+gYScWj>3a#o&zzU{O*`if)FPM=jGeviUXmFN;G5y9UwW z#$@0FL?0yzVb#~ABP0|w?Q(^-$*HolYH$}dlvaXf&h8=ZyUXL8)4)}w3}p-p3DfTv znGm*vvTiV|*#HtT^7Yaj4_Gi;>2?>eNvE0TGubeINZB2&6fOG^6hyK|B5Y#J zdXIYJ_>}4r!r-}s)c22htI_BYCwv1vGO1w1BA;IMJvJ&})jmhiI53;aTn0$Vj~_L^ z5>xh7IMGIE${K5GUS(o*CItCftdWj%7mtCoIjk%}i&*Q(c6VEfO)cpYZIWB$CZ`+K#?b zowy|K;AxIDu<8sA`$jWn{{C*C3Lyr1prCmuotin;Sej5>Hj5ea80}AwrRhJH#xte~ z6(J-oe;dcTz6d+9fSNqz^i6i{NJtp;Rq$mAc~T?Q@vje^djAT1+_4PkM~G9}v4Ges zk`yU^PJfsb6SCr~ zS^hiZ`0gWxmQ2D&TBxu?iGnc+GukgXD3q&y@{4H!D&m;%%`Bgx^g?RVTG(ZyX%o%MBMLM+n3{~E8n_+pKO z^!nfxb*%^hGHsliIQC{l??SC_nr4O%@k9-24sl^ps-Cl4SN!4>C=O#*uT<3IZsH&e z;#H>v@NZTck2%@ga`ZsoS*u8lBzQ&R!}}}t4gWf_hcc%f|5Hyl(qEp;s3<5uxE(%} z>1d{?iG}yH&oqkAY&IRwV*|;i+w3D{ziNJso0E}b1dd7gGukr`9<_c}jpB%MS%^~? zV?)^OmHN+D8b!0IhGG4kGaLB205yXDF&{v&V8`LD5(~cRR^(20 zql_aI24MOdp%XA1M-g!^2H<~>2>}&USj(!RDN@j-vR6-^EQ)L@IyZxsG(^N@ihd9u zM8rb5n0$dB_2|wz&^fkEn~S=-+Stv89Pvqu*A>m@Kqh3QxJQbnr6u=`VJ(AV7h%vI zb&+e6&D0H0J_a4ssN^{Y@0oc~RfmMi)~Mb>eY_sY-}3!3-TcY_ogM@+sL()|whKN; zEE75pDH)cASxQqx{Gj=^xIoXdnl7c~WXLh;{d-6kEQ{eXB%*61>nChQ?xrDqTShp_ zqdWU<>*9HD&~sVNWa-TKYmTcJzt|5A{cFoi5NALL5&KdABp9dHqDml>QPFH2c~8Lv z^oL}Wk&|r~%iwH`_|~%Gab$1Wd`*z$kv;4ZrG`01iSd8vh23 zU7~(-3^AhaBA50?BP=}@Ax2${6JDv5`5i48iH5xkC#prE#wuqZ!V6G!JGXx=YZOv; z+k7-+u?Q+G1CO1*ILVb5ZmAJs7=w?<;Pmy@h2R_N%JK z03o~+-XwSqZF81h6C?C^n)SB9Wi#Pr<_43CH^=akTZjfqZiNmP(Of}#d=4?7R-Xke z_6Nn{kkl$9=`YP$+M&Do;JZJGR$-uYkkr&3SGhH!{S|pX2Y~6IxaHB8dk`cSOn?y7 zMUk-wlG}`=uJ4siBNS6V%Cze^VJk>dzI@5~uuWmH@B`E6yKpY^h9>;a(oUNwg%IFF zeZ{8MXLJ*Ofo3c?9WM~w^+k0gaf5ScO9ZS+up9i;K`2;>0HtN(Q;evPdTP1zm{;b- zpe-{eEzUnZECDhZ=3U(sEpr$=L1BK%|MJm97Tgy{VeWo4%RC;B`qsg+Y263BEc=uN z+|Iq3yKU+XPpmhWmDA~~5gGxVa}UyWu|W`6lOBO?j+L;z8pM7yM?Tk6H78&MQng&B zf8ZtO!|W%;8;8}08Hj@O{*_FJzaGDAqCfOB*=7qqN01WWcUFmEzoD&V0 zED?s*xMoN>J*YxW%;LEH?E#{&{A@B;Gtz18lMjJ6L1!=18%WQev2 z3tylPngdwO&?J`5q{c3~aDea`oXTYePOXU?@6-+_d?Ct;v&mcej?5R*J05}{i4u06&j{SU2%SZ-ssChVnzozFkEhqYq_ekci}Hi)m*Tr$G@sGIa5{Lq6U(h$UoaBk1&x zyT_pWxL*RTv}HnK30zU$W{7@=-WffnDy|^x8W^PCFTmB{)kgX6gyhntIAc_(aMSn} zUoRYYwu+JNSkG$IEY#eBqnXUO#}H!64}8+>yfuAxEdQWC>O+0`?#i(9ny8#}RYrPT zl`y{vCtKk`XSSe&Fye!{8Q<~)aI&6&Yt%>6BmZF?QNKvV`gr%eX;wdjS&p(pV&Bn0 zPQKWJscfACt*8}28GJ{g)UwkKxGkZaiM$AIpSfA+lCJQnu$)l_VgYAjcU$qcc^*eprcTr^^Z z{VLtE_F?a$@s4*$4np=!2({lrx+?)ngYt33uXn8T=id4rI9a2fZ%^t#Mh@zAENN%u&$}Cq2ehyDB)H$oC zew1a>{Bv{j>DP1!uiHmQlY^H*0jCx2{X;1;bfcG3|A8Z4{h5IZ01a*2qfCpZ$g_86O51%vL5^VCe!s!|BvhppHuXu2vbIhB^X70RtI+$M_2q7Na31E!y zj-5R@rhqBA(f0F4Kg|(eXyw_bv4JY6N#m1wge3mBs~}H1{+fYFQ3{Ht6mo!RemKun zEgD1Ue7T1)!w*4h&*E5p+{F=CoqxEX{_qY$VCnRC0O>C4mng6>*#4G0@6i1!sYQK% zmO;x6N=QfSOJc_`kw&E{g_cHTDfKRPPcU@(aA#JUOBEUVM&(gd|TMo~Sg$4XxH@_M4qPD$hGD?oB z_kYuqJ3kZTT&*)-7K{ZZ*Obm+pHBtB=xf5p)|Cm2$Dj3^?*P2Ee$awWNh+24nT~!a zDc4>&KdPAjDc6q2n{j!~;uO7)b9;dQ%etP=wO|_r^!(%te|{)+)ieSZ z6&i$kdU9~{K+pJkEC){i4*?~DO=no?DKagNkjj6wO5>=U3(dG2UW@cneA z53GOuE{$OIykL;^)4Zg?{Jbp9|I(jZ76Nmj<6pp!Dsg+C#CZNe9Fy)#OPhv7pN* z{L{7A;xhhQ<%RN!Ew?IS3mD ztBqlu;0sOTXX&@`>Hz25S`P$Zl4KFwr+NSaIwu;9GgF?BKA_kllNH1Ckh6YFBg)Be z&Cgnb-e${F%Yi<5P5x9=g$XWWF_m-Juq@Yuwkb*Bg2EWpK1+Q_eJ~2W4oh{krJS#> znlOqNp*;WXUlwkbvX#HFL`c!+TQqueka#CS68ooZl1=;Do(ZZBW)%yq*KN;f(JV@kc|BDep}$fyml# zXyFC#x?x@Oy#rgGLu`Adu5?o#Mh8dlvg`2&SkAwc+jpK`;C@< z(Ps`c>z@JxPvIz#pVjcvMmAUd^HCG9^H?{L&m>R6w10%2ehuD2#bKnIAt|b@kUySf z%H>guHK|;?VD_)}LO6$K5(e(MhhpS0r_lN85jB_v{P8Ko0* z$N1*G&qqDdw&mfo9C^3BsxF<@osJ9RMQGXMM_|WFQ0AX*mFPl1QC+>letf%cadx|$ z4sH{Ph0ICWG+?eNy+jPP)VabSqyy|655!3)+79(j1;*&P-Jz?wV!@>Hm!@SlU%Of9 z3DctF+Uc*xvh;k6nP{we|IfSf5`dKhefYL>9R{?8k9l(TKIgF6&(w>I(+xuhd@iLg z$~`z>v~k#Glp?bLzZ3~vGeRc3qL6B-*9s*UQCmeO*Wdp12w8;MHH)1AnEO>?%@5+Q z&iJUoI1{M25YkL|p<6kYPT9e+Q+ z8J-{}MqY#Qkt#}Yz*LB5y@E4q+903nAt%@nkm!yQ2Xma(Mpt?2bz+-}{ZX(lP>$`* zb|1xsn4Y$dRu5DqYQXoU4ujxr;Iw`RlJx5Jnu3{p{L5-=sx&t$2a;ISa=*Da(AK#Y zJTe585<&_?;crb^{wwKf9T0A9^K9*N8jlBsPM3rczky%9h+q*>wm`lOL{pe=9@UwPX zvp8RDX%yn;2=#VT*zSJe3Ycy*iP{P9ozW9pa;YnKmj9Bi!Mo#O@TRhv!fBxG*iBX% zip6oZ+Gf67y1@(D=ck{f^Tg=%Tn~ju zvc3Su|AGRe<9lYRwIoO@zP?Qsq*S;4O4O%Q9{IVBs$n?31#jQ^oaPFyEIg2FR{Lx1 zyO}%{<4>J%qI@6|;}k`cJ>?clhm)eawRRg-L4fEm|5=xg7p!E0CP*Ujm}qQG&9={9 zIt?`YP%Pz0?EDWU%kIZvpFB;o+PmpeZj%tjiKk#J|)D)@vBme4ykfQ~fGBRlcz|$Qx(pcJ8?yT!vi2`4g z5eD1j06Z0G^KmXTidjo3%-|L+jc*2)wy5FnaLKVW?y%ft4@sV+=|~8U)XOI$YFrna z(f@&dD!%C5;*XUaOC^Xk5zI56KjAz{vpPB+8d==I>NXPm6Z6M8RS)Oo^D9rawO6fj zg5{^x~;zG2b7E~6m-(mKI|_~!u*}@maE`6L@==HbH67bR33ZPUI9aJ#KYte zYvtO;C$u0@Zp_J01J7W7o@9)NANddE#nq6gycj1d%D8b!ye@;X zaQ~a4y+-Fi+BKIk(czBxLW?DVbOwJFasAh z2rY#~71ILPtT$??b!@ldFB58!ZV4`#uA)s(IOh+-%GEKmz>Zq-?!d&x2>Q~)0eL9_ z`yHq3-ti7D^6T)}?ZEr%bdSZ#8Te;Qc-2?$+iv0EWqh!5BS_CeQRa8Bb#HMMm9zi; zz-zqfb;gH)r=^Q>x701fN>E*>a-gs$RycqbAm|wP&adf@rj*(qdVr$mB%^6 z<=zWXTo|`4qF$gc!1eu03i%k|DMykD@f#kz{e1DRP1MA78SMp8q^6&Ry>{~pJlsT0 zq*IVBdYX{^cdAorWIpa0oY8`v*oVbDPybrdix+Ne&5VHtL_YZE{^r8vfB&CnMvNq4 zJA2%3+FZML%mfRrB2rR>n58cD*-iShnJ6cSIDOwo&G{4MSV3Z8P?f}Z3wGwJN@kAS zF`(|dRShbu>Occ@EZi$O%pCTmqhy6kIyc(P1-umcW7cC;xzIgEuE$3~1;P1CN!Z}~ zTDNnuD7m#z*FU}lWyJtUo*JHg1}BJ`U|_S?SA)luoDZD$CE`8M$jXy}itZ>Z$pV_3 z2dC)S-LCa$Dj8iZJPdgW`1Y4QISmf-nmdjEB%&L5JYrU)x6^xMQAgwC&!B_NX{TwSeV#|>huu&B7KSH49f9cfguPIVT*X3mH{MBJNZ1|85?aD2s zerN$_*Gnfm1G5^TgY=G2_a}@Q4-LrlQHML?nShVO-uN>#fnR(Fis1mGKt_#<+23^Q znCb59`c+Qrm(+exnC;%;uc&;xH2BF*P2F4cH}DiWQ={dLftJj9zNVZZT&Vp3 z8luKqwcWFGr%i7 z*7{?v!&1Lu&k@xo?i16pOHd$6Bz$4F!Hweg8@U{hI#Wfl8j%}3H>GxP5Q z9K!EoZb;6~%6`+ou3S^*kJUb#xJ{5m?`Yb);9Y82_Qk}J-33SAS)~S_Cu^^@C0UJZ9%OFGlj$h8kUVne%dXasdgs)*x(6v}V?uvs3Og9xN z%2dcNu{%Sb@~9uA<~bG;X`p%?&xbm>vXGZ@;?<yB!IGnW$ry;BdYiD0q&8Z-6-czJO;fIw)llr(jiVaB;{M z1ZV<$T_R;6V8cgbIUA(S8e{DrZL*rX+1PqEzvpq;Q2|w=RK6e(3nfzOU+?We*oy^? zu;v9x3t$qX8f79#&Zcu7CYhhX-7fK%ZGSs{(ytDwO}nCK490X-;g_A?hn3%G7*mUM z@j0b-s(T;meNVrQ5I{%!eC1oMml^j}Y+V9#*ORxpDmW)65qwS}IJT(qkv;hK@DwJh z_9RmjhR74wo(}O?@WHXY$>BrWzwK}vD0o)t1+t!&ykpd~J0vDWE&fXg#Uk_&Z=f>X z1MTcr^@1Y(XyL>Xb*}oqd+$}@lY5(9N_U;>d2IaVnOmgforIYc^?GhO{Vh}ZH~(RD z%k3k}pWC-*X7SUNo8M;cEa4R8zlTF-52p&sBOow4aIiNz2;y<%hmUwW;|_}-An&4K zL}b}QiQ&hU{b4#}<0w+pv>#V2v8LQ~ko8lQg&;t~w`Hy(v5J&xkrWRp$tFCrdr33PklbgyD_V@W_L^a-^T!=IEZNN+D2l_cvvX z8Ba0SASum~teEq;bXppWHN{Ey;XwLr>G%{TB2K9=+!Q3pstIsK5%+tB1&~5^gHnRY z)y*^Ou5X!8fRSq#0#{kgv-{zH^4x=3{(>g~YD7p!bz+m-1<{09{F;W5xA7O)8?{dZ z>uR8$NiDUpO(ZN7MDU#%Bv}~Ez`XO8jQb|P<|r9h139#TYTCSSn&DKKT(wJTFy?J- zr9U(5uKHBt(GVsS?Bu`PsrV26q%+ug-6PMp9QAS<{jYv&X~u502GN1)pfZ1-R4#UU;KPS;q479ia+eH(NE#U2@2jAUzcgZWVv@#mN~^BGYrpks$xv`4pT z1X!%2Ynnr)fLMw!jaQUQH&FMhhM9!mESvw(d|}Jt`l+0Q(FQKDP6Q$T4i7_2P00W= z=Dv*R%t767hDw{{>M_D~pDP0(bA&_L;RMUoO4>9$6o4`qkIwXg5u8dQ(LA z#ym}|HL|uG1P2uOR(#XHoH+i6;I#d}8vg>C$R<~*ei|9g%+rtyNu$x2oc%Qzv!Kv; z%I|m5*iaQ~4WZcn&jzP7O?(5i$N2fmq>@)zvDs7ds-kRCVF%*^&sHrAsdf}qU{=VC z3*3{c2~~nbg4z-ff35*%%!Lq)k?39@0zRNS{EftqP=Lr6;3Vs+vx|C{u^P(eUlX{K%sQ(r@f8o z!{U;1V=jsr@v;1&)ODKVa~7Bv@DVbN^2rCI{uXNg2W7&sbO1hwBW#h;sgEQ4$fiNH zY@^H~B8^vI;LyX3J@K~3fI9TP7Txf>QfQdRSvTq%k zPv~T56D6svhjZ)j`okwga=_^mw08FrJi*W%i0)R~%$H7HyDW;C)pwtpY{>E8=qDxc z8)@a{INspf9OKwnt+h%+f7(|Wp{qjVnpJO$uj!YHX^WSG0&Kjz#44tQf+S=+VYSbZ zImC+HmP(u%cEprLbGkIaPoW#x^J7R~kSKam(-yxqVK?KUy=emdWYg?9nhNqi-$SM} zMaW6y-KTWXi=Hdol>-oOl^mC2Aj7PW168;N`L=5?xYSiP2(KLap!Hkh)be=5!2rKA zg~HPLc6EHEC69^OnA{{~977>DLV?Nk%xiGM1uYpggU|v}4jCWwk*?YK7u;}0W-!(k zgGu1O7vhNYDLR8RjTRChnG4+eXrGE%_e{6u6_&G4O#<@?L*Gmsx~V4;i6tQd?=z-a zB(x`$MVEl~fe~hB@M8sgJTn|FZ>2774dJw0_Q*|n?n*2aMq73i$C)nb-u@L$k5)2N zQw@{b+?Tp4^1>u|_Q&RtwC+@53Eaf`JsAQ^rq(u@f_9c{&#ST84*S^h)SN?qWP z0mS|Mg=X*v?yO4WG#>RUwJWH{#S@xHlTOD7nU?j%^Z`~V24*3!YD$nUJ{js1Qf@ny zrSlO_6W$Pmts3c{4lh0?a&|eg~?9l6`0kxB!~I zM0eI?bOS@2n&)4y*i|X_Hwey5na1Pp%$P2Us2#lsH6MzgigGfH>ZvPYpkxppx*ve$ z2sqU8L$Jit^4=*;w-ES;A84IvIu4yGOu4`y&CKT`UPvxx?$MF5ADd3d^TBDx(uB1>4nE12mNjc}n(Ow;2UvmtzFd_s) zZ^m~xj!8^Dz`Vzs#i071F?qFCEl(%6My6$H;E~z6e*`ELc@LEd*k54)HFi*BCyxC5 z2u`k|u&@P`TOk9gtWAQ8@=EZ?pmASMkiHI}q4pK_OE?CyY*JxBIG3qvLFUC=sn4#v z@2XHgPLN$rxkw^lefYOxzyMw;i3awr*Rfh@4weAIbmH*$ag5Uq58#nnG5xetbagV^ zFM_}OqxS~%lOC^`;cl1jKh)C+meG5Ui@^$tV}r+hj}||S4h)@3bwAn>>I*kD$M}jA z>ZdvEf)Uw_+jU5tw&hPh(_JzlnGOq0(ToHWA65GA?VxJtYKO@q_}#@9R%L6dHyZv; z^>=cIqNJrW_|D!FG1QH)UNSfu(hK*6_EClClm~jy39beuN6XUS*FM`_OnTRlpk0yU z#TD>_PD|Taw}@qWUbp!HyYwTTRZ26Uajx>aTV@f4WFfl5OHR!EtgL(Yu@CfZRbZn_ zJIMzScIdu(OJTcTZ5-_|r$$}z`m&zn6i(?zPP6J4|6SPgv^ZHXs#I z15DAjMuP#X!|mZjV0XAKWGu^_=l!m(F0~7%7#?6uSurh7VbpaXghVhqxQ1Wdf&|Tg zE&k`BTC=)A%xMOKLA1KDAY?`x7<1yK)M=Vp8TooTUu+-YyFjWq?3-98e5h^+l=fML zUIK8ao$|W_PI~+RP;MeEA+F-|_gz9-MZ24Sa~ee2-5RF*rJN+_^_MWeo1-V;R6XlM z^IzaQ1`-*21AgSv%BQX$0mPdzYro16#+hx_Xn{b0uO=)i8_Sfv?;^^PXQ5Xo%FF5b zKNKYtqYsEXf#Z!&G9p0BgN3WO9SUP>ZfhBwuiq|kV$A9>?UhP|dv==_Yc{~1%AU#+ zAdw7vN1J2&BCaS(odT*4Xn^}y-}}x)1GxjSpq0e|96}$Ij2p(gnG4LrYm=rkSzKe% zBRZDosD7YR{6yq?V>E->R}B;k`-b%o{#V;dCnoz*aR6eOwU61b&B^)=fP5fV_Fg}Y zIE2VQUrK_Y3Ge7l%g@vnv!fk7M8Kf6bK7q%gu9weG=9^G?X`<8v~me0;mhu59#DC-s`MgboZRO?m$GCtvDbuRCBf z{69=NQCJJ$tWOXRSLA~*<9cY=wq&Y?h(9@KMR;K0%DK}NIOh@0cj}aT%(CbcSM;PITewL!ske2G zVEpf|66}3>i$wN}4D?G-+MCIn=Yvt5EU`5{it(dsy3Lg~=8U!qSt;^_>a7E2X87Kw~{HJD&4y?3ir zT0q$?`g(u!L$}_mF_M-Ru3tIG#lnp>H0ZhKhEdOU`=#ZBqpI(jqY$oaUzV61G4E&z z4aWkU(jf&8F;X%nM5M7U0C`!KT)I?-pi`^UG8gH*w+-NUl&L@vS0e`C&lh-w1N6HJ z$wSlg5LbffDHV%+fq$=BXu~#>-zH^$%-*q_apet(wu2*N7)pNwTW+-TPiR;d=yYm? zhsnhM))Qo@iPrnD*zxt?5UUX@&+MoyZrUb*$4KZ8IqOP)$o&rusRv5!V`4>Tz?y40 z-(?GfM0ijyANhK~dN9G&Ou6FOtw#Glp{S{!*T}HM6l2NgBG31Tv}Uh&{sydZ0gBG=}HH zu)ptr$AG~A_t#n8L5X!GEM_M9=7&`xFsio7yCRIHZp#=+0yelZgpb^7p`FkhYqV%^T));iGt*>OxN zE#Mmh=Gt^SOjSdsfM{Dexg+@}#}8Y&auQkY3WGx6IiD-CjB@x`ncP`J2>h8IM3!FU z1m^$|=kh`KeG`!!0!Z-|TBEq?FA>`6{{03Hb`=r>0W-D?`Wo+>@RPYvZo=Ug{AOg8 z{djV*!q~w1WVa>&;k~6I;;bwqjIN6CJM(1+Co$tTY(j4#u+`q&mw1rvEC5C6<0KX&UoF3N& z-B9;;xwYo^ZFz^+hl3qcHg7^SQUM$m{~0;nEmV6C=+291`^|Z6`@VNk+wbUm>FLu2n-WEk6 z3TG#Oc+qAZo)W)ua4huL)CC>(p)KqB1KFA<8Y$1k?k4xs*>H9~*I^4`X-9<_96}s& z>@&CGM>+ma45y0=JsU!^^nM&Rqq=Y>BCVTi#nd0t$*~7kbbquo5@eZ9nU#mAl_LTk zSJ5QAB0dN?p7qCbJR6v{zJJFFeO|UcH*W<5X@uslcW|*{h^^8*rVRwxp~>?11`BS~ zuC(7c8}uj2$zqdwcPP;v&*(a{Wp>*WFBEJ#Mijl;~~(Wi$7wG zx-+7&xl9>yIFm{8H5DTgymi6ZKQVuN(VM|JAW%zTK_rd)+_Z5@TBy~{|J#^(A;}m z5ZO5TWxabD|4*J3!I$n}Wi#{Pu92k>h2APA{+)%wXGPNoZa(f~P=#pMfnG#uvcFEY z$jV92#|G&2$ag9lI!n*^#Lw&R91GiH_I_MdE&D_O1YY!B+~-h6zvrvSCFXPW+f7&d z<$prmHok99U2opcD_t+dcI_8m{v%@$#mI_P{Y|k#x4S8;O#0N+){}etXTuLmJ-cq4 z9QZYAFqARq85eKudIP>dZ#wzyx6fW#1{of`u_PYY;UeI2@Q7{=?>|y>;DN#yxS@s-w5LsGJh8z zEBF51e)nX3zLT+Xe|FFaa%lfocV}FyJfN??4D~31s@-)V>OeH)@b-8IB7g&YZfjA- zZptg3ZsrByE-ntnO3%6yd@$|HUm_pLLWD8lYLXn=_uBs4AEZQleBBzt9Q|+-(z4aZ zbBIcdjW)1MFA_c1W`FK?$o{8yC@sZ^?tP!PRPv1B^65}?Q|@pfu&}Hsz*0=1p4`Jp z*e+E=)k}WCXuU@)DS%4mshi87);`O$RV~rS7PV-gkwW~3iCL_x2)wwr2{SlLeyla| zRO@8GzsnaFyawJ%v4HzYP`k8eB(zZ>62VGuvAfab9k=tLX~P^>)cp^;-}1$Xc13in zs$o@<_&TTauh$!eRnshMzs6fAv(Ef36Cp&(`{EV1oor!c09i3K@<`B!jV6D*v$uUR zl)J;j%m2KFkooO%KAUh9db=Y4jq13A_Ku|(Yp!y`Gw8x?-Or1~gZy-bH@eRaPpF!HKtCG~#h`8NfBG!% zI-B1~^M7s+GgtRkHmz%w#)O2xx(JX~=(KQZ70p>0nwj-K-UY?|g&HduMn$Tj%7zAf zo-Po5ZmWE)Zpa3ZNpf18*MuwUAJ_T&xew zME=Hr`t7{xPNZkx;8FdI2ZgUj2^t~0^njqA-Cj6c9`!R|l; zfhRlpld~pwJ||q2ri1|dbv}LI@kul+zJ>IDVU5}Y&3BRMs{9aN9NDIZ444Z&=2-}T*GsT)I8Qr4@)hQfE6a=IrP03|PvmTTqrxD>x1$|P+TFG0Oh7tq zo;4vJ&7kjb00r6cF|M&qoZ5+>m7~+RUw##ElONUYN~G!gRCL^8S&hC-F2sJ!uJh|3 zm1y%fIs*)AeOpqU<5V1HFm*RMK$3k!D5-4cf63rRs;RhPFTxOqMhVkKw|~L5u@2Xi^noHehy2aB$S&=i)QorT6JPDYVyHcqOVfSWDzGi~gc% z!-uNL>F=eiU<^(eoX&>VNsU0O1+VhH&42J4;Qf`!1FRd@1zW)W&921* zI!9j52d{fi=vp_iyom-Ba#QjYV`w7>r8NrMzTU-^LBbRs+q;(CfV`|M#RzAGcGI{( zr`?)>(DV79_&S@1wT%~Do7LtisQ4-!|CgKlAkq6E<7rp^?=V1%G6Onk$@9F=CUGn@ zhM$jl74bZ-;Pfe{&vWA%0M`AAcRp=iG0?T)pR1^kDEkgte8Muqvh7OP7I;4~o~-s4 zVR;_+v$US_8HG)r!!ZvzC$2_b(XBL5TIIgf{e&M{q35rU`dj8JXV+T9eI)BzPwJZp z>`^)WEO70d2a3W0ju<{WU?BTLf|!y(3|d#pE0-F{Gn(3_;NN_<9#5BI)qU+HE=S8p zscTk1Z21z|iS06d$mr6 zwIl3(ulHsW`n(du7^&kVny0UZbtS633lHze#&E9b+5Wn8`Nf5 zEW*a=JM^JTNHo-Zn6rJEmBCa^`$|L#a`WOl(`=&bDZHNd3|Sx(Fd>O}ApY^SyUfy3 zBwgFM2w(6%+}!SbeD8O3;Bjn&Dch=USI^|VT#fA>;6|zo8PC7+~`he|onV8cn$GaBX+1Y8)^8XZCt;e%>X=#M-8h(55c}9vhqNJaxiWaHT!Yl0d z+_@^nFmsV52a~?Gt6?Wm%qntzzRIt)$*N{-`qR0_=3au zC$H)JixxBXBd7lUYsmH@FA-)(UZhJ)w)urk6t2BMz@jQSrL0gV*K`#PF%W^d=N!NhDlpZKh22um>d;A2U=fMqu18I6am7o%#6IdZ{L6!%=Fv*~jk`(=6;H zD4i=uS5Skl5<)y_L`|g%z9F@z{Dp>GWXnF5d91Ho+fl z`+j_iKMq<<++kKg2AaKYtZ1YIFD@L9@9*#V=Bv>&ybGTD^q*m0cNJb?^q-a&&MVAY zWW2PAqTz_57Xd#gTC;S-4o@db9Ye=(y zOl6F6W)|zUn`|Fv!rw->AQ4M8RdZ|kKeFB`s;%$s!rc+v9f}rrhvH5JFHW%(x8hcc z1Z#^FcPLui-62ri3&o*0w79#R{Qln==jL2wjN~F?>}0RC_FD6O-Z`1f4wd4z0cRf5 zZ#ovJ4<7+23S>jgCy@#`T;Hoo8&UAvJ+vy^kh}G^UCar~atR8sP6h#l-7e34KUYUU zKm4w;-jti@!o4jxJRM3gL$&Fl`77^B*^y=(smHSN^1J)}8T~1+66MmfEG9TO&H=$=CnQDechhJK?Q77&lf^}`dm#(`x*OD09nQrHA z4QELzj(lVO9)?>SLFuEe*OS<0xOCGkUOx!(G&GC))_&*TzEPHaHDmYOcaCeUyt<}I zNh=%~4ES+aVhF^j-D%#{T+Y&OoJlGLzwn_(dcO1hxA*gi?yD|bx0f!>fhiV!aRVlZ<+xcB zZiKu;q`2%CnOq5;c!Ad#)E^qOuyN~nkoD;(euPdRKzL11f7+rNpVOId)GWmZH&;Iu zL>DXD!{n9f`Dh#N?NgdzF~yKydJDW0cNs8B2QmMyCv5siIIQ4N+RcAc>wc0Lzrvdk zBUv}4_&)V3E;nQ#{KYotD=en{J`}V*Mtx=8lBm1+do4)U{$<$3Ai{+-3{1LWxl$Ee zHrZoxes#POmRyJeK?i1yy{IcXZtaX*2bsLb+%ki&+K>EFva=kO+TR2-&Ob zqydf#18xhEeqDb8)qU5A<~sbuacPKU(d6aj$)7z7Z#a{W1*1+-xAofj|1(NRWZ|4J zVKvoJVQGZvzNh3?N5<;4P)VxV5b@i7Hhmdm-PK0s)Bv3LSWOr&jjBsd;g&^3mVXs$euH>u7 zd$M|JI5TJzlk^4=49u%@?ap1sskZ!rZ{px;?_Knped+iFj<031^{r9C>7WErrH8@J z*Ckc9IS)zZJ87_~_A|4qICL&6L8Fd%P5l%B&(Pzny%oJban<_#)4Z_6iihmGc*_@sHr`{Z0s|jY zqrV{C;0%pSl)nmM;%O3iCXm5pxD7(g(5$sal<97oIco#UrHOA7^(fXy2{8sKWEkN> zsW&pFU>S@e8>S{w8)-c{D6ug>WCft`PTlb&gAlGnRje$#u~LbaDpo3;`~nOl#Mx)* z_){c7qS(j;EFBNl;%?yC#RM;ed~(_;Kd5=WS=jBayyU};Wk&fbqde`YxLZkSUraX# z(PHe+vMDP7!{L~aCS9)B;GRGBGa0ARMI}=hzy~VYFW(t`I;ihjacud=ymvSDU0l6QuK!IgGb(D6Axp~s zoMw-(__fD70RKd%+FGjbG)P8HJ|%JYWsR~+BpC_D{V8nSM2o-Y&ZOwz9R1-4V`pvbt zZF-X4#QZ5*2hHf&cJ~}fZ&%^6uJ_4$u(-g5((ll+A2gy?J@hX)s$FsQd4=7NciDDv z_&gV8zmS37U<8f0j4lR~{|NdtG?@!mJt0THpZAoA5kk%46P_^|1aPGM;Hu`7dQbY> z`l{)~RDHN;jE|`5AqxM;P08T$%Ze{gY8evc!0MFFdU~pStwI0X%YmISVzQpzvKC!- z4DK$oHybF}*+PTPZitA?wB&E;xC!$acLmESO+ZSp;kFDNwtugSpCc1sL;O|>K9;J; z3>!>fGTWIyy`*}7gG*v51*h7=rdy*z-|Va16Z8Wj0GPk=O>QA8rpWpH@7BK(n48oS zS=#0Pt9)?erHw)p|6$89l*Ly@8;s$Y6!$It^I~r(DjgbXW?s!6lRz92ojq#*GGI}O zN+vLivhO+BF$V!fzGM)OX0e2@Jv2Q*=B;O_0ny+1L$t{aal#J9y4s(1`M0*;2Tf3i zZ!r=33}}7u(`47;>g__hs8&jF1<7O{5~A@-sXEq@PxtZ{LjQ<(WsiU@%?jcibrLLh zi3CC7t8sV1p?9B-Uu^rnM$~mn3KYDvUF)6!RRS4FgF9ggjVGBc2c}=?%Jw<&RVlw0L(G`)DNYF-fWH>o{lb(jM;AUP0WFdu00p& z=AiTsteA5UnQgLuP2`MY@T1#K9@?-h;r;botB!<|gcsyiNCUi1z##7u`{a86U&Y-F zBd}^~GEjFR96>lo$!e~wK0ZcI$V~Re`76f3Rq^A$2u^Un&O+G;;JPD#mO_R?Wzw7` zqvBr?cZ3aS27}xeU0Jk^z0AJ1YQF_|0Zl(QH4w6XB&mFwt`l~TofyFfzZA_GtRiP5 z*oCkeMB9Q7Q4d3Xw=04_{jK$@I7ywrJaWbbM!kmlK>el8EY7K@%tkFk9C4yDZvuyu z;M&TZh@af1OsY}%Zd5K)axVDp&C(S*7_LR9D$C2fa#k+NuR|&u39>zGn)iQDq8JT{ zydwQ=r{Wp-LB`q-_X>9r8&;HH*JL--$SZ2D6 zFCFvFRITGNzeuU1lY#US^ob((zP+ye|QzW+(`o!erBJuSk$r zSy`-nVVt8P4wZQT*ghC;)k^v?V>ao1KiKSGf~{Z(H^XoW0^{sv01z8a-=*IYk>p|7 z3_wm=nAWU0?G*(ThsYqG;j2BbS({yCovry`VO>C0Q*e>QZ2jxmvPfmO07-Tvn&0ix zxD~`>fl-M#7jRdJ?PCxl=GfGDj3~)D5sin7F`ePt#H1mDckEB68TaZ_lbxqAUr~2HkK;Bh%I3uZn1j z)AqpTSKrvpYCq+;QSjiw33je$EenZH$-d>T%wt8Rk)X8QHJJSGl)Uax!B_2l7 zKgt1?W*>)tc+1l1pnmp^VUGag;_xd`T02k5B$MsF-IO<@@j}9JAMMjisXn&8MN~_` z8F?khRNbxq(W6e3%QsAMoq#ygC$=PU1mKRV!8|n&-0@6NyXGywrX*Ww*YFfH$UFe4- zrK2+U01HRhuWt0o?&g)D)O_`JC_iCS1r8rbD>>hLtLzgDu4o|G_eR+M*pTW=SU6IY zO4-)Ck|TPAL8YN@@W7e>Ykk$%hg~!-UBpGT;8bdI+yOq_!Sk2pgrHhe1N_(XmZUep zX$BIh*SQ4M>7B`eR-pSh9sm`p1_%)@1y^7R@?12#+}}Qc#&OR=GoEljGG4B1X25i2 zHvbX{o^sJ9|*1577Jdko>Fe`S#c;$i0Q@#pUt0RCu1~0#!j7CvC?4w31MF zDN~>qg~4cDO1$q$(1hgS?g%*ESDO}#j>pL>dG3Us$QilbyXC?^3PyEca@frfseLn7 zow{(4S)m0D*vPY)ltsLZpoeuZC(5biYD3PYNCy{GmV=x0H9lMH*e9Dya7(u*HTf z;*~%eR3P!ss}aG;=xO$*^7SNCqPj#?l^dGAK(8dnY@nEyqsmglhAiC{P*wDbKSqLh z4o%jo(+kA^BI7#Q5iFeFt?N7ypD(71$@}A)E-3g_Y6W{lVq~inT$AjH=Cew5OF8?I zBC?%N2};ds9&Ju#+_(0DOb@efSQSxIE+@kK}*&#u!NlkQ|lp4nPWM`nd2Qk-% z(hv}K^W?wxV^$*P)=yr_csWdqJ3NSWL_^@D@nU9^U(se=Y2-+z9~PBW&Pc!!KZ^C!>J!RaOzJZbGKl8 zMU1DR=m`$1w^tf~?vpmiQsB&3<3uAR<8Y)?d|(KG>37w=^O=lBvF}-}WG&b3wT!Om z#QFbqGKKaablWyHDcs-m_me9GWJk_!sj*sO!)!Fsk(74ag&^uz)&Y*RrWE!%DkA5; zUWKHS^>+BytOgCDWbBX`V$*0j8|$(HZChf6H4D6&gE}aGrH(_q&L3uL*4=yL?1JvU zT>Cs8_VYBwS?xYd_fI?+HRd@+P&|`>QAiMpf_#LSn;++d&bQQ>(SV_=jX6J{{Ae9T z5ad1W8)QkJ2agzj{p%v}0NSlT28fMUaMBeTp}AxkbV;J(<0OS={v3VO&o`ZiN$5Wj zsv>eTXr1+#@Us0de=Wv7dy;tYaW(pHp#rlBy0J5>bm-p*iz{0I!{B%Akv9bSBUYBN zr|obEz^gxYZPdp|JlAcTWSdl~iQF2Xi=kyRAwyKylrKP$0`LNilzEKLT)^uyw`6PZ z=UuI7azL+40-nLp(3_ahvou!4iW8ZqE|I)mod#E=ehxFc+~RhlkYVtd*q-~D^jiFSudyx7<3{x(N{$=Y zbUtMtYEbI35_LAGOC$Mq+aEewe5u!}!uvcRUy9ZsI|QCyn_Zb(D=B@gQm*peiY7k7 zf3`e_g+=XuT-#r8jLVbPMGbc~&QH!~X787lC29}~)Mw6YLLfAMU5J+juLi8~D=1Q! zgGD0BvG>m6aOt`9*(4qQ^L`|rbco_mMN!qI(1)>Uf-uh9-r>drhHB-2;c2k}Ak7x0 z5Y6r|ZUt;)FGPd6S1>CkXY8YRGlLTm>?QUZEB^F0xwjlH(Hwq5EY<=!?nXPlHG-<1 zZS2l&9UKVS!_Gufa0ap`pJE&oJ^t8qBwj0}hgPK+vDAbySJ4lKQ;9-sX0=EhTGne| zk)du4&z`YMntf>QHGtt3_1wRcfoF~A_O6dXH0 zEL#X;T>!592P1@K<^tau7!`S?L*zU!g?T!guhLgwp^N{z+4P+qw3HYm)0oMA<;+Hq zr%C>G$CNo2YQ z$}%R&wv=MXQVgAP6rx370xa1-#0z*e?2R^7|H#d@^C%O%82`S2Ok)`T{F+u|r@ZD2 zSU{9>_S*?b68v*QCT2X=M>mV5BNhToxC7{XDo_yxpu&D|rpSNWFj;yYcq(ciiiBlZ z`mDmB;r0$FGV#jvaw`?S1+z&AZe~wFGT{p69jO@TB}nXcNfPUR{bOV)>8R8_)z(Tg)@9OEaMNyi&^vEWku;e)O|UFGe~|2rKS% z48C~h)>Xu$+KAkI$m$MTuzBM)Nmi{(;s6a8`f0YMJD@s-PopiPVwx7n*5#5Y>Ie(R z1bZ2|Xkj;G8)VWJNYKeqqF!xUVPZy(wSnk$*MqejTf$2a(Os&u8w>tM(+6DKM)Ae{ zca|k-)B^Uo-_-X{d;}rHW}Zu@)jmBYh}#zhy8;MrDHCdO2ziHa!0(!VS+7P09`q15 zryNRTCS#AK_OxW!H83Pu+wQ`nD}CN>OCWV!kr>i6A_0$^FB!V`-YHd> zkRe!k-iw^;Vy&yiL%Pnx)&Mn;Gs1WNLU?+b8CHWlY#D4%m|a(dBEDOKx7#KK+`7J> zf;d;Y+7=$4hyDz84?E#;dWd~&2(Ng1Q7omyU$S# z9aL>{_~<85dVHYtTwmaO`RbCwL~*R-p*J6VS_RROf=xGG&qavris!JiQ(tbp zAA?}#)s)cO6i`_l>*9=fS#3Z7`n~;muuPOWaaC_nXk(C@>XXcBrokh$uRAD)4njU< z?OQ-m_A1M|@c{RmLLwI5fSU10ho{~W--;m8oJoGW>0k}mke!9RgEsgZ<=tTnvF7Pj!ON!!9D;d^BU`LCvbVNxu z)guAO*%?6cNqO)}n!h|{d3G(&cyLsZM3QA+2|0$nQmGS;NV%xrPisJ+NroMxK)RX& zF(+AX(9OcKjpd;W^z*&f9nG`0V^OXBwRxB?g!!F|j-@vLlS5hO#%q!ZyS?~XE#3+! zC|h~Xb^RJ}b>a}w>&*ZA(YYXh@3RV_$tvLnquk6v`U=i*Z?f>1w3w82hN0zs^&+Nm zjW4NUnd9r9%dbe={E>)l$m8Ya^?z33P{O^Zr_*Ig@B5e=O}Dxhio+$Lu&`#`&9bTi zmt*tB{hnVZ?M-lr3je#(^vvVj4H_wtjp>uW*Ho8O1_0o@8@1eIe?{Ekd<0@#R+Py4 z^W|Chqj654QRn@(lIBVTk`1E8+rRSQ9e-h8kFA|ioOYPWs?IF2%-pnR0}*mRF+ca$ zm?14li?e8d2BdL@SO8d;xk5wzo?w@Lvo2uw>wDOZEL|M~;#EECV$*#;O?bbx*8R_@ zob^lZlO!L_Hie1AQ-Ir?1)q6)y<)?3XXxM)Y5CDvDypmtEdqH{A-!^oXh+Y9j?Me- zR#b1x_P*6`sg2q7BZDJGrSzwN*aXF{9Q2S zN^%t4(jE+n>7GEL$}R zhfj$|(Hls!E)yT5TZ^xI$2Y@Ue+b}gxi@|+vVsjXIjz*`JT6Al%D#SFd69{5Q#TC# z?R@`KiS~q^{M)JbORIF0m&eNHcdZ^~pHJVnS9a1!F4u&{>cM=js}1I6G*8F+c~vyP z^?`UF?{bd!r(2hM&0CTs@lPNT6O@E~XfBXVu$k=(U;(cQVb}t5wy+{C`Jj z*9$zl`bW|?2EVtDRyr|pLJZ!qB^)b#Z*wKC$~WEjj>ThMy#sD%MQ5#KvK}9Iya+Oy zg`_`)Nx^@!%U92_nL8;;nzlS;=XeE0a(;N-`0#HeG(3sj!K04|3+m1vg|~DL_4k4N z^vUC*!`HCl|3czNF6}cs7RR5Pi7T*-b?@UKY4MEQ__Sm2oiv`KoyQu&$DW7=3g0-KZVt8s1)p4cK!uCAS}0 z0fy_L4#5sV(m{ z-#Z^Jo&vA6z3&kKpvUrr0f=%UV<*t<~ zj*7wP8uvfPki`k1?ulZ2MeI#1IHp@fsX8ZtyZA=T%bljDcSchFi`>Ynv~g2&R~5h0 zX)1?+uWhb==PTyGSIl_C4Wy81?v2aiu6Y@*-grA5w`}{zbfmx7L?DI3yByUE9da2h zsWXcp>ZKQk>XcaZ-?bLtKeE`k;sOt7|(E zHFTM`EyY~?H#nJZ4fYQo{vaN;x`%fM*owwAeZp3&&!#(Kj3W1$;Wln%*fxo|COp zr(9=8oK4h8Xc5j?KGR~~l7^7aeVL4CugZ}{R|-Ux|MnsG^yy(}uZ7(V9_J`Fi2z71 z3|v9#caVH@IF^@$Ay9C#cGH0LvO0UDq}9V3UF#q=?7RKO&&Ou{ar>QdX(ZO;(rszA z?KJrdgz&#VolXnQ(%iuL6*#K1P@UTaAt*MBMoSDjA3@4ZxER{jX0*!c_1<=AArDpSqN zd?Wfpy*7T$)kj*&C;$&w?Z37@=6G_qj-dv@P1U8ptSCuGe0QKWnR`_B@FgiY8QK)S zFy^-=`*VHP)Yd_Hbku>`=$K;-+hci=tmXwP}Cj)!El${HMyxer+dVU=- zn;E@w|6B4`gNmrcENFL)A4xLxdC@eoIo6IuA?VwSxb*zw6f&jFjG{gs-pV2c-v_bq zfrv~_Q{BqH$s@E2m^!uxnAcc`gZu|B7N9BV?03ggeYP#?h|AczD zRk${k_=;ChlPM1C>*AUOpFvFP=dnm8`-ArJ065OY`B3&F zLd3}%H{ke~IYnkaeZIEJe#>&^$Kmi~rk)bUU`|5S+XS`j z=|(3+rO)*822@fq3daol0iz9afiEdv-XYRkGIyMmjvv}(6BD$XrA&!@o1bJxzn=vU#cbKXA(Npus}!eOC>)ev^Bzp#PPD>isT-miJnkDE5yA zp1ChINQ?Kgv7R$^il`a+BoPn+*vKDQj`zRaRf;DI^AkwmW%?em^!x09TXov* z+i;q0KQ5lQjsFSvVDJ<1%Dc=Fx^q+d3FO4hQ$q{ODSAxX4t*tfcF%N7#v>ZOdS!nF zxn~tGVU8tel;r&8o35axzaF&y!1{Y9m17v~Y;H_km~r~9rvG)d-P=XS#U(7T0eey8 zKZGouu;}wK$wuknEI9_7XpjUSQbv(RVjeoD^>LBu7)vTsI;j{UZ_a;Yp{TGG5VsGz z!oMCsYp7h(^TzOz3xm#RadOPME1~aa=40V#qSHy@=^$EySr=wDugS?^zPB&(P||U5 zQ;+57rd6ljOA*%Mx<#Gma-I1Q<$fYBbn$!^lg>EzK~EVHug)1F*Qd5a$t`l*93L+b z#uXn}r4(#Tk-~`Sc&#Z|tc;k$_5R?VVb0B4!`y!F6u&6Lk9{eZ9rLo&5U7HK zv>)iu%&4FeY-$%W2siw~e5GgPsPvwyv6n2@Fin5%T_@!?fzO9|dNp)OQ#O>!Dz(i& zbOZgF-pQm1W|_(i@g737GB^ch@&5Vtj4%05zv8|}jWMv4!x91k)MLWgaX7$m;X(?= z+!#c4TId)0)U$Z{D>(NKjLC9nH9%D>BeJa5W|1!P##zs<%pll0*H=QU23nW8LzxQCIu28=)_^vRY#{a-rB-xRo_v;0ZDB8ALwnJGwwD3^4W56L^XfB>J_%oNA!+fuN)QXMT! zLx~)rpS3$!jkKnHM1S+ON6Vk=#;IrSj{{q!k=)mJ)z*=p#%4X!kp=kT=sYJ341;%t z30u5y9aV%CO!2kF;`6@#i)8`DTeSK$2ossetrWbkC*`T!3e0^45*$u}$*F{|p%thg z61EF;G`pZG5~#eH>%B92O|-w-7-C=)zh35mLvKkknnun-dOW`s5#~^rPhC5p#uuT? z@M||9o(MtNl=WO>aj|8r(@FW508*(r&^p(3W@g3Wg@^qF2nhv0ELg3drZ0R$Hi4pR z2*6_%XIwS^Sw!v_g1NJF>Y^93hRHSIyR54+!+g5UEd9(#n>*s94JrsB@ybrcLW5C- zMlRZqNEZvmv00MywPu_-PD50{93Ctt?%A}Tj&s=Up^XD( z=DDY!>?iG#pl%K75c~)fi=`}I&D=x|6!?3z&oBc#4gB{~r2ck2i-an?)II4x$~;M?A`o(nfX7fng?8=gsDxUta=WI@bGT<)^d)TqLS}$eJeqd%mpXiJZM_?nPi? z1-Bd%qMwHgA^$6$X+?5>VI~FVp4&%NK`4{a0;n@f1b#`({Fvk+J*FtZiU)jf>Hnl4 z+UFRlI$QQkdQV7o^+89St$L(U@hze*dp5N>+sH539_%S=z>4Wz?7`WXaS6f(5J7bK zwlg?t*W~^1&3iriE5&FPG94C^@; ztRQ)g8!f@0bm&u^HZ3CMX=8E5!>Mac zCf+LEf9;rToc-cBDn(K_3#X9&RR}BEzN0P`iqR$yLxB0}pMn!*bnRM?Gjf?(sL^xG zrl4q2jb11fvZ)Xg92-deoK{8}oe>wqo^R4=FzTpElr)MjMWbClR0hwf7xk;s0O)(gDU`kb(5n+iu}e?;&omrNns6i`g2 zeKyP0ig4)9ck~}V<4cnE4uu5CAVp3({MO=A{O2!F71G6%Z&hq3pbqxN`FPrVAfDv} zDsCQkrmu!BD%&pvz0S!IL=4EG$-tQN=8gCtB~%S0;nm@yS;o3bh+4(FFbM;e1G9Hc z3M;OG@d_4bUlNC>9J(x4ByoZ%~0DvJGKXDKEhFH)NYG z=oJBoQIdi>C1_>hX6562`RPq4;`7m`H%3=2#W;U`KfLCHZ||^UXM=#VP8!~D6Gf4a zLf_!^?2l&HK2%|~QY43V{*JLcHTH5_8F~?5wSB+lFpx>vZ5cne_+fG-DT*&A^Qwq5 zQL~}3+s9^YEaK;XBsQjpi)QvZ-4AQ|#M_ezTaG(80+CUE^84!k2rMRp@+oDx7HR z)r>(&Se)y1B;`{@MMH;7I;w*?g1m|FAE1|vEIWmH{1@1~@CrN_D?uIBOQl=fRkVzO z>KY{)88X(vP#4bWN!L7hFE^{QB`~ab4QwwW6xAoNs_-G?Sm^()p+^nKHFOTj`N+?$ z0$9;+APe$!{19^5?2)#RLz&ey*HTP246taXrsw!(&oecM7BUZH3`kNu=SNEc$&?1+ z!I1sT<9s$r<09V*f?`3>?KBwy7M)3ic6T4b3^#7G@Tk&HkVygC_o0ZtOA)a}pg>cI##U0*|vDS!7_8ARsw_YBI%E zdT`IO$8Qj$WZ)A4eaM#eTn?NMC@jsznrq67olPZpFhUrR{4TmJyqh{K<2D!@=FEcM zpAoUX{0$&Dw)jrON_z#WvqNs2(=C%wXWHD=M#fY16PMk3{Ty|&$oSBqm1E`x5f_aA z`JECcEJ~l5NL;>3hHV-iA;u@tPnvI^y7YECBhV;kSCjhcuMf@zu8kg^R<$mqdlWZ+ z*+`}jzV|J=a{0j0Z_i}t|VII=tH`gi6}ZKCp3Kr~9Awh)L6XS?g1BX$Lt zLeuc&35S|gV8#41!j17AW+R+nA%>a_RR0JpwgBTMS9{L!l3ME^O_lji(iTzezQ2hr z=Pt@X0g{WNlbZ~|GVvC*DwA6m_C(H9zrAf??AxHSW*f#hbg>`Nc800&`kp-ahlXlO zUQqu+ee@S;h)kb>B@r_Di0|_SYXWG_FR%DAWNCx< zPKDs4{sIqWw~x1*%uCaf0{Y{h>;t~-OuRad+f;LK@~0PZ?eM>E_kQWhV$yP@Hd0l} zg{twg?y+)#<#=*atxbD|CGX6H7j{M6MB;@0_&7Nj z&=t+H(yOi#KxRsHpK(DsNb#jK{;5Zuxp9Lfe(@x9d#lUmPmC`$Qe^wd5x;nxv;U;u ziGoa{w>@g+Cps2&e*r+f{Lw$OGb^eoPA=qq*hhs>5oszsYc)OWuAx@_3b~rGMI+R8jls$WRIeBB;s^6w%Q8$E6D3!e8rNP^%ga->670V#su-ngr3n_3buYK zKxB~^>tf=NOOh7(P-$PhB~CD=3;@@*b!yK0Pli8wqRw0U;iba$Jo~42IFYd2RK5>( z9qyiwel;E}wrn6u|00Fn59l9ou$3(RI+H4b4g2cnHq5Cvq=I;d77&9KD9%P$6*AO> zolVJ_tCG>@zLDnp6C)GjU0bB_Z?hm%FM8W&V#R{I&>7=Z!44Xd){oi{__id!D#G;z z{%*prUzI05R)(>XHOf?17~!d-8iss)X9|6p@`*kRFD0uLCUo3|85%!KP*brIMj0rq*ahx5&D*LO&R}eF3^y>RI?B}%zp2SbqDBv zJmfmO`p8B>bT#D9V|LYSqW@WQeVS-U=Do4_Mv8$01idi)-`4*f=+tFxD@8~G{yfYp zSyKL02q+crtjD5v1698hW^u6{b3mn6H|AqGimc9NsALQ2y_mUh9zJ>#RKR|hokqvw z0)oN)1c+d?5efN$pdOEqDMSyN%fC_*T<}R_&@fosiFfRm-5APVrC@QcHw(U-`c{P- zdn&fn#MLr@Xl^vmfr(VD;*BrFeXTeyBgq}vYZs^=3dOXyyj5- zVO34@c8P=IBVC5Ss0O8?*rPln6$lp?ZV4Tm1!QVGubWPq z)A_!{65kRZq~z@VIw&OZ1@fgF5d)g}fyW-Hny*;Ufl^*L)o=6f_jhZ!2sxx(?r~^d zOS>hnlA^zCaWAl7HKB-=u*D2hN+_=A$WHwmgRi;dsbY;=aysckf7(cJO|;$POF5-_ zH?NbbZ4SJu4c~fGVf8G2b>RGB{=SRB9&@bvuX zhkFZAqL`r%JC|x)?<@}#)kFnIh8Jz5rh20uDr$$Y={$y%F=q_MlJ)&AZdrSpM39J?pxgiV2s7aS(V5WBj_n_wu zvE~iaT_a{>oLOJf#zNSpv{NQAm*n+wk<4mplEB}$t5(|Db$aeandCO#?tt)4DAYj4 zdfYndwyeUi;_GzM)&lO|*XSVgrFT^=mU3ok4d%RXM7$;DaL#;ZXeKTMp{jQ})wm>e22mzAo$H81NPiP#L1{ zkseW&c%%$$lhc0N@|bH(D+O`dL%^+4+ON%g$tOMKBNhyB2mY*u%FEW&p-PDAOI@T7W00z zDgamDzejFL}SWfb7DD;8W}bd^EZpsW=pDMH07?{K}J~rW=5p0O;$n0{n=0 zncjb27M=4qxqW4JQ$TX$PLL=2n z5cv>$eA)y3QGq2p0Oh<(!SY=A4ZtO^UV?ZMn~_H$?zk(xf6}C1nLCc^_8|JN(CAxp z-HiL(SjsjOEz=1jybu2;07#)If{`_$;fkt`;RH@TqT}}+-M3PaC~zF_t+IC3!b>zi zV6U&IBbKU5gbZ*-$GT44T=b6lQ2V*@wp*md!d!z#$7|1K?Fay78uXcp(+4qe8^2K6z{= z#x)zOAIeyj=B6DtDj;ATbAPt5LjNxW0{j-8x+{OvmRTF&r_i}s7zf!sOP}IdGp>(b z)4K4QS26a&{qD(!uavIUwV}JdSVjW!xlsbI8xzUy4+?Rf|;$>lU4(MfGX-lKqIS57x5V>9-NZ%{SytcvUkIGP;>TK z$kMC}-x9C>4endElr|yF@dCnfNcXLThU-y2eDRZnC{6O6mB&A;X2g9(K=~ z6*lXXF@BcFH^qORY-zaBrK9QbQCXEGMDha6ql(TQh-6+_m3tf0TjH;>w zfK}S}Y`km^or=-{G>vdu<|HY2lpSe|ky=72v75{4;aFFf8!f^Nb>c&Wvvj^ns?-A7 z1YVS@Uwt|%;Lwm}v-AA20WTZ0L_cCo&^mkg`Mz|xzdHu60c+Flhhdst#xZvsn8;ZY zDG0I1{U@8S>HyhP_~ue@h90z+Y-bRjk!-Zb&BkNw8fCxE6sgbFlizi3roN)W7YDjv zi^*dvMXqAKKb*D)S5KbJ?o3ZKz|)|G%zxXtAFxec9v$ye&_9FYS_sTI5qrAx0TYh6 z1F< zN_u2xhV=rT61ie6#s>nS2T}}ZA;J1RYy`k{cj%J> zSNHLof9We^zgxT9OTzr?zGo9-02kS3ZJV<9A0Bx4P$@TYD7wfQ9ENVcbw_cd!jZ{! zHjN)guwf*&F>1fjcu`r)Bn{i!{TZa-yI#Q{!6EHaHbZ8}U$A045@FkV6Tqaw4g*9j zo+Y0?AN~es7QJJU#eUw?DcuvbS;q7mOkGVajClrxD?>3WlpDy;5(QG@*?}s|QbWte zn3#{rBBo|tT-z3=o9U#=5F*#>%I?GZ|7JX@(7DT-eBI=nWy?&AIm;{b>b>U@_uO9) z-*0IExKP~l{2oZg7qScT>sYjJVv#}HV7^Ss8K~E#h?m8fX_X!rPC|}A6}$N}cTydE ztoA9A$*c+9JV$ZOeyY)tyew{72&=Vy-mdpg%)uEy2> z9CZ9o$N~twR{UO=T$Jdo=~ViVbUZyAJ;8;p@+;-6lY@U_@<$)N@c*?ybp2oTK77;v zDC32v^q22`PCfB{op5U8>%aGXmt#!-8d6nY)+>}J?R}NGx>b9_)y64KZkh3>q)^T%^9_`UPwaL;WLzf{(tEX-TCdvCQNw%0lcWX{)LDU(XU8xC#l zG3CD;abLts&}eQ#$kQ`aW$L@1o5&5?wbP;943e9d?z6NK)5?@0%?&XWm%;dDMji66 zM#gag!Zb8P;*>CLL+-_aGf#zJ@~i{sBw{W$L&&-jtwDiSX6-!lizqQ;kd)gpFWk98 z6@_lgLx;aGX(zb!bcw0IAd1Xy|Y!^49bZn?Aa>U6ecZitc0td$sQwH~r0xIMxfe(36IZ`cdpE2aA@d z@Uay7PxiIi(e@7i^*Xux*MB^-(3xpN@=JZlZy8wa%zvQ}kQcH+bm6sOY8Mdll_lA2+F?p#9r{d3Vj;)_ErYz+)eu`Cn~W8(#SS zxZ9W;*4r>09A?n#IH!wAY1;o|6EGSi3q9HM`897py@N0F_>C+p>c6k-&e>T6^uUi#r0)ADQFT(`&wzixyl0t2M|K@7*nm#HR`>-}b^s*^F1+ zkHI=yJCo_hr2W5*ozzwn#Q%7xTyVdl@wuce9j}}hq#h0R7~JK4yt#?@9%VC*Hnz|E z?B(?bMxDOZ^7Nbac*^?nqlZ6VD>6K8dVjshzXF3tu>8^5|M5l5*>ttmD>kbIpPrR2 zk9TxQci9;GEP0_3UCX;tNwpzc@<|xNI}_0YpVK~?$aM)i(w1(>c2EPn!*_hq{%~}n z?1WHHt9J7})SoTABQ>0zT8h}KXn(v3ba8~8Pa62z{tYQRf82Xo=V`6{NwSD`+?Cad zzT-$$of6N6z0v>fsJ}mM_GM*zcyV1MXutF=59W2az^r$azQE5yl<}3eT-sR)CviA0 z(6(PUeZ4wv8d5tOy?Rqv*(cSpaO?N(Hc#=!Q}m^zb_vj(G>!r5S@ef!Vl z2ez>0UW;x4R~e1nYT9t4;g*V5C>KOH{qk>64KPL;aLifp zQ~q5Y@sK}J(nw^g8*aPEw_bDdf27}=GhQx>kox*@k{X3g_ce>t@5tX|A>Y=1Wi1)q5 z64gI2g2X~f|8Tl|r61p*M|$R|uB!cs%8yI`6R7oNR>X>l7j#AR)XLpEi0tq#o84_? z;_O)2Ex0K`>Z>CE*DUY8cfS7*Utby3R`+}zg1bX-*A|L96nEF+?(SZKyHi|?Q>19I z(okFj#kD|iDXsghD|10#kVN0ckaYdzRP-luY>4pL`$dz;6ZIn0 zGVI9?9v{U49*`H_#K<39sA!TarZECplMI?90p2vXwaewL|BY{Ft2c9B8e)H1r&i?` zRMwB73zi{1OYCoLr0>7^d?bEn?Z5TDRRsW`coOM!aFua&MFzb8NB9rW;res?pWeJw0OhCYoE7icB}drK0+#!-^2KRCnW_$ka#YXjzg{b< zzPsI%i|lij2b|!Td6YS|H4aF~h(K}`=&Z>yXx6iM#6lA_v)}$U-69VTgN?Pzcc?(` zXd;KWn{;C&682o2UJE2}>HtWf@e(kc?)0ol z2!6G(gCEcQABu<@@Wb^RgRN|a$kME>j0WpYdnjXZS0GW5Og`0X@`3x$)lY9+IMDjn zM;$x&p8d=DebL@e{Y|?~wuIBm$fF($g*F7-C9azVJnx-M8^Gl)3gGoQ196FPbB7;l zXF~JS2svZ$jzZMO%jb`Up8H(^6V>PK#{z2qs&Vbn)Zo|`8wxk7Ct4I{8hL%1{$Z`E z2=j{Gr=L>~t24iM%-uG^2fjA_P2knHu1PoAa;q=4gnOWUegAw2YIOsZtRT#R7iBl( zXKgv9eFMcX1MCv%fy{n6)TbXP*3{=f*wIJ{iA{M$oX-D_&CqZS-iYuO^^g2;_}s4{ zj(Gp42*r)`px1)1|JuxhJyNG`8>0udEyNl@HA<1UjdKwsS&_&=Kd5oaj zN<^7Fb`$^}nWgg_!|HD(o(CZVko`9o;`H;0p(1<#UT-LojNNmbjpKNi2$fYWVl;VL)&cnwNQNvR7n?r;&d zbbXmbrr=&}LjBrDK15O6irf^kh%!$Q!Rfj+y!+_Hzg`*Yz#`xr5O6(lnSWp&r*Lwx zeez{9ZXbejy81+Z`!|K7N#5B)9LF_`SfKE4NWI8OV5f^O;Ry<%%lcP@H{Xg9M+APL zpk^jN2tScN+$R3@++L}MooAK|)y=&dT;H-Q?D7L#QxwNW8ix@i${1hXrN1AJZ7CTP z%$(qA-IH5x-N#VHE-70T%XJyFt~N`4i_KeDR6zqPFiUV5Kwj>;^iBsS&))R?%*Y5!k+1j&@iu*qL2j30T-Sq%zEp3?E9Ln{iCCbUQT> zYk5%%02VY`zf5>uD%TSBzqU3>{b$wUyVi$>R_10m*8UUD&3d1{yP;~!g+sJM;U>t+ zn&9?TJ4Z#-ffVh}-yUb0*zZKcCASM;}DjAu3SQ*nf{Ltz5rycA%|-TaqpKf=z9Ix11~0qqas{ z!%(jg3ogg{mJskV*TQ;2L~+yw)A6=%-g7Svw=OPR&J~byt(JmH@EA_u3hpD|oiZ$?3(MD{^cND{I3Z zHVe_q??WW|6wRY@iuq$c$pCk$3f*=_O)%M*9`@d-4-LGK(i=9TQ=o*unKr?eM&n!& zh*5j<2^ARoBiiW3CGiD?25*Y!#}ow&mVCBDPK6(V)$jS zpKp*UF30U%2Zv`rVz~gAXP zXb3vWG25okkpLDyAIO;h!-!fz7;)mjT6*yd&wsZ4@0Q^&o}I zZcEbjO^Qn(I_IiDjBh!%NzgGn08$QXeW<+_EEVn~bJq9)au;ENyZB1Pmv?I@0EY@9 zI9QTU-JCb>xBZW(&@nq3Xg~wNAL)bOuh_(nMu?*`3irCfz!~%zaq`xE5VmHP+T2gB zZp<6^Dbn|OoVeQRB>@G6f(>npqc_MaB?d} zRaJHI2o2j5wLe*G_X@NE01>r(#?5VdvDh}wVEkoEj12mo654*Y9P=WS zTR#GMHk-t9Q}|Wfzcs^^f6cp`uWFT#TPiLXpR@=t8o7b1&CIPvvWZ}{9;<4AOp z^KOuX8p@|hnm^uxs+fnh&QIWSiKK7HA({e_<(Q@y+qVuKB-}jRqxq_{^*IXQ$((xnrvxtjNgX3_}SPz+-_K^>K@@%iqg=*S}n4?DGV>l zAEJcazKDNO5q`eNDc{paKnAO+CNeg_wm6@aD_qNkY?Ymt>6wSe55#hPf0U~!k0hSM zE$@2_5o_U!o6C^NegA;8|BLv;0Q1EI1erG3GU=ugbgaTHu`#%8K~+ z(g_8>puvaAB5%EMtq@ao4o}~97ZfKBk8>;wcE#}zU}N1b%$(XR^DU+piBb=&Ub@4$ zgJ+JBg6LGtL6jSFQUzN zqf{WFGoI5?{qlEe9zJGV(kBXkXQpIJHM~6$z8EA~ST!aOsguIt+RgS}bgAkHF+G`` zpYQOh6rjW3s`ag=JP_ZY9xJlS4TEr01)Bq10EOJAV%^|ZqX_*R%Qg09+TiDzw=v{w z4&DULEN%m@tA483MJRX{u!N7NB_>F8kPf}bWx@8iS@{GUSgzUW)_QVzz#)WB2zA=% zeFWlM;^8FC(9^&-aH9kj;edVl#vc1s#e(f}uN5G;nnbd{UkCwavXq&c$3`4K^ey?; z(yA}gNP5;>LsJFqzhNA`NNm-~_B21zuMM|o4^P)$gUiA>tY3tL<_5Ey5#SW1dCm;Z z92O^o-yp{f%Rlx5L1$kq|J~5Td65@CMS^OW0#0Y%@=Oy$PMa!06g8G1RnbApQfxDS zJY0-sQSl;Vglm3xdjU}G^F_Xfdz*aqc#|;<_~UL8wcSVVM_DW*9nAvk_=I@agpWnt zNwq;-T`Jm!aNWRZS72ICMuItyimS>%heU>Yj4s7uEo46c=Mc?9g;5qISuR*0PH`gc zQF07xYQQBPJGfU3M#lTe(de9@r>@p70XH+0>gIw`EI3o~e-#NQ`PNFKEZTm=lp%hz z6fuoI3O@sYldWIiX$!nNtUB58)vp3K@r<*ofGX(*oy7A+@x32)9x4+AE{kcwfNV{v zB>fd`y;RD=p_o~TdN>(<{D8N^ylkj_J=L&nb%RKw_vz#$mb`+3#^`fs%jn!sB$K8k z&&wfF*f52=E+FlHe0ob}!LApD6P!I*f|~*5$bcVD3r#yM6Fd7~<;%n6%f;>&F7cFy zFg-2m(3O1#O_b4Nymg3}kQ6B#?o%UXIY%`SQ4QYX4j_g)2$BUz&olO5e4qh?_2a?rfNjdh3AK(B*s`y9+vg zC`kotb+y?lRZ93I6B)oNj5@&k8&Oiqfj*azajOuVPQ=^ZepnyCtdDzN9=0TSRil5l zmd%Ky=maP$<LP2+z>1P@+Re!yoez#S&^ew(?+RmdEK| zwTYrHLvK;dwIpj`nEFr*GT;(NCr)o=tK8y~Vxa<#InkH#40bq1XWL>OhvAH?5v4-rfzaR{Bq|$6v zn!oRD3JX@>9%6+da9#=T4xl`>+)F73XV;c%h!bOUOLJUkW|ma zi~-@f9sMSfCzMRVoTJ~vJYmJo;Hv?n4%WSNqd!MwS6~5c<>%OXb8c|OV(edIkz0-Y zILfGkVHA(WCrg_(bDWGGrT@g1t4P}?l=JUX-@+XH^ME;Cs6$cO3qM4$K=sw|fJ{$^ z)Zi8)-++7IZW!(^;e|%j{jVx3f*_(lC?UFISwXaH=OdM2D7TSm(z}on4e3B4290A{K4dyqZVxYj?#yASFD;$oTnH@^ zvO@wEx;%=L1K-o^5{r(P=KKjZ+`>aRGWm;=-Bit%A*-nB=q*Tx8fdI)9szxbaL2=& zcfw{wmuuL>l`pWk?FPw`rB$(gDCVKFrsQh~=g!ygVp~N=u%=&-Hgb-O{}k7s&Ge#p zf(?!%W@M6OEU)y%%coOvR+LPWVytC~iePLHai0_6QBSYhdG#xenl>#^8l}vXBoPDoCbu#%-KX&07;Ec9VhS-{9F+8?&6(dIU{v*h6ua)-^AmyIj zEoDF7DbxgWr-Sl$Y4w+fw*y>6E$yOXG6^!mQm% z<=J>iH;MMNO)|$y@n}0+k1u1L>*HpHOH)^3VUMiBxWB`Wzzd`-`(rU6cQ~^y&>Mjg1XGObyKk3WWP0Tp)>1*wz|qpmW2-#0Bg>Gz z5tam38%gW_pznIrmq@f@ktyG2;mBAFmUr6XlZ#LV+t*z`Xz^dl+>*s7vJo$0wcGMk z0+eLM^+g%O+%#!Bkg=a_!qf@a0bH=hOoIE;bnW(lY`45DKvG4iBo1{n)K0t-9uks` zGE&2@QZTp-HEIrFSH8?oU89#SHR)DfWyzed(s|tc41giZeVn~QI`d<&RNPZTcAPyO z*)Svj6$XLTUYu&}Bp>T$Ib7G(FQ@i3O|ua~dth>39Tl;+#K>?q1){j^)eR$AdP_n< zQT+(&UL?tf!7MN19~#Z`HRlPeF&Hw)KGR=)s-RWE4)yhf z1{k3pF@DBY_TFc)f0C4(BP#qB{!HEl)CMxDSft}IA5VM}LG+2R6&__)qL;)ZUXqp4 zW0qAXV8n9)Oh7X&7}U^=2pX99H91eRpt-wXLO{T4p~EXBn@w-iskhe;^MsHd_!@z_ z8*QTVf)~MJ+*}7HCSk9#)g(rT73ha($ZD)S!wr4!a& z`{y90$G<=KLZk9&4L8Ghvya5Wu1rgTaV)~tR;bbhV8+METv|FJHm1?ss82stbh&1f zia&e+y4Lv1^cBz&6>@80d{zCbTWb|CSY#v2o4Z>Y@5#B`nPTCXwOLr}|6xNEIOJuQ zRNhn^5Zp!ZSRxBp%d$_n%(O=2e=2$F21LhW_(7|7{Slf)y?=XMSoX;xd;gqC%R)8D zJ?ZFDJ(*z!B6mErHx?+$&)}e-+c3hl9W*dV&p#n$^f5@h^3X;#d^(7|#C5t&Bogxz z>*NPT^tAklgYU+h$3gVNME=e~o-a>iWA+7m;RNl^-_LleB+c^=x)|%;AHaYJB3B#X z)GGWZ+3ymP{+dnP9`kV04|l!v4r!KJx6eh@yfO`kfVoZWKQ7c|R>Ygh#t#+xKZ*;h z|JN-Ac$~E_$*c7VZun&SpZYchQ<>d&FBMrdq^J#+I^q^%^h)+ZuJ*LwVa?k5(HMdY z>xUAQ8%2_pay*s_{x@`*&s`5iT#-x}kk*1Omi4>EG z8}qYh!@p1;?nWtiZOPSI^s`2j&(!t`3e(oIptG`y;6-9uuOG5$13g7 zVnQ9u)5=z;+QY&_fFLI_?ps>+O+wPsklOjAeld*-A!MSbIMRb8@VE`N6JGPVD8mIb zRS476-P|IOwt#O5GjbTvS=FxmhLEXD4=v*MZG|RcHG%TT-U@6(^U|n{{;v46U^*rx zi3<$g7627s?<}O0>G)#=!F-L~dD^^G9zq5d*V_`BGIXI|CNvnry%R%_zFHD_-Wc8K zLp?~6>2xW2gs6qgn$TI2Xz93)c zonQmg@;^j*bj8gXS05plE+*|;NSs>=PhjBXN2DX6pBrK7ASie8V6zM0YGMgMym>pi z(LcNI!4gBLoy4?ZH6IVu0IW}5udn+rp9@;!+oP<1?*coTsAZ**x28T!6YNXYWo!G8 z>AbZSv<~pHGE1E>lIfSIB4SgT8S6ygM4qXuo(IkksM4}L z^s})-lbgmWHQgEn;QL)TX4UxpLiFLMuOQZ2+8R~J@Ggr#O&UP!;a}W28*vqZbUJSC zqwI*9z9yCg*5Jp>YdwqM)7(WP2}pkZXHf)?xH0#dA2IUDb?8#{DExq|psV%Y^0=~B zt2I_MwcP0hXclV*8j>|OY|)M~;bdrd!4b(18@=RGWo zn8Gf)oj$lNwBosNF_19SPqrkd7kBrcLMn)>)(XioU2uqT3->>U0;Dn`V+7Wc1a3& z^ZZ?FDRMolaQC{bIBoAQ)3SCm$VwP816~Sv7boDVjK|9I!Z-U`U{$~M$lVar#hL+r zm+qEdrz#<=(>$7Pcao0)U>s!{7H)CEm^#&>N2v9SyPL=f8ac<+=uwB-Wgk|fqsVa?tWDPMpZCX4Y~|l;_qgoBzL;o^_LY$=4tr~3 z0#^=%QOh(r(YGjXWqB8Zk}_bi#WKHoU&G};lm5LDTiy>*VyC4+gwJQ6{11RSB&V*J zZzjm%Ak00g#3FbOaFWZ>^!6HkiQf$rE=9!B%=WpPPqmlZa2#dU?Bp$rLlE~pLoJRHELRsB9u&bxJo}4Jjc861 zJqtJQB7Ksqj1qzeJQWg){ho<=)tDFzCgMj2(=yM6>ZtLF1_~kLOQf1IOE%`>g^vw2 zf^8VbUXY^AKl^O``4S&IQFEb#G!-exItHU7aM;%YU@2Grw)|tA!^^?!Ez-42YEzOzE$p)SWx!oq{)3l8{}{Zzhqnd72b03T4sN||Mma!*CN(W=H!E>9gkgU)2t zPFuqEOW)NVz}a3@-weF2VEwwU%SQ9=vFg0)wk;ve%sh1GAuw0#L&}FSqAN}Vn2)=5 zy9wx@$;$czlaQpQ|5xaA7nP8*d2MA@||6L+dmu zcigiY$81_DcPMs4R+`nML~eHERLYri9u2>P~U4kygsL9 zRA2b^+){V{5sU(Si6xhOl{f&Y-$H{n z6-h1Nyb4 z=a1i1ddbzBYfe|D7E!;%^GN{{5R|;Gom&gY-t>e(1oh|AGV!sVibwmiN>}j9{=Kv# zWnR1Tb1BlYFk8AINC%$n-|9RH(*$s?3&gm7LGc(~wM@bmNJ~RfeImu*{x>2yb7qX4 zu{dZ^fT%kxM9z=E1A=w2Q5>e_Cln*f8fW3X^~)=cv*l8xmtum)6@k>%seZch_Ghzw zD5p{dw$@h-f>%6*yBaIUBp#w5Nye`005=Sk3?g{GqC##}GPjDCv{uq8xg(O%JvuNd zHADU(wq76&ku$>YpOb1+7h1ABV!jshRt0A+E&uYwcBB*dr*L;N{#%?9b`YdDF5dw% z+lXDh_90xJqra|9qK)DUTolpffN%-QGsU?#f>tTKoGq!0;ug0-mgV^F{M#s*U@@A< z7Dp&1yAP3%S2d_o!Hs|6fmQrxA$+11%I(TQ4{Y=e16iLUYFt(E6~T< zn&*$a`UG?U7SBWGB>KH}`>d`u6WlW2flAdXkb?T{coqviZsB^y7CRMhlliJ+c_xTn&?1MGdXM2IX>Z6JZkTYkXm@%FcoQxaR? zH+{(nyk^O)k3T+h)#j2L z^T&boKbCYO+{I}$=^5%Ojlte2+#kQ(BXlq+_PWP2)5i5j?cYm9zSsIVrAUJ&dvodN z9Fv5Mo#bCd;~e|<>W;7GG(3xt<$G{20UAGw(zRT6QVFPD&d_!?>zy^+H;eGr=Gn{l zC()&G2E8zS=FFL`cg`inwIGr_;PJ7NwOP|u8rj?uR0_5j_=mhUKT661yM}z!i5GZP zv&iV4v%kb<5D)(=c(Djxe%I07*|@0sAjE#SVo^o%9-Zng<~zu+fi;b_Or2@`!~pf_mn|843PvOmDjk#6L*rC%eA; z`&*2H3w!%&#k@xOmrUcb4G?K-w2f7?0Fk&mh|z?gdQf9)8;w$a!WQwSoIV8!BqD+J zx4t!T%Wy82Efe+(qm&>OFhlpW+W164kZSaVc+yrnJj$N7H?m#;m{DE6pGK30e4wmLAa|c~MhQiVpg%4>ieBYODpQs#`ceFoL~a&dx)(zj z>imvW#7IRkubJdGiO=g~faZ|~J}sH2CIam2%A-Vri01xos|r8W$#8;*didFq_JamO zBY3-SK0i%Z3E~{-aNC4Dc0%rOXu$}aeV@UItb%$SuO((cHl}=?ldGMO{JtC+p$Qw{NcF3J$(&Ht-)WwW zI1}MLlCZNvyIv$7hS>=!yl|y%_f-)|Vc$6LZ+@k<@W8vj*=Dr+@5H?(kQV?(4cw)F z0Zfl(BPfztXY@@u-06QRiWO9=;m5rKD1al4L&olwUMFOp zAVKZTX~p$EZ^qkdEXCPux?p_TCp4{l^JAt^V}v4Rd7$7*jF|b8?u6Whr0F4hc!>#7 zBdBKOb?vdek;)BB5J8OSn}j`o-C^TSjJXyrAMqL#AieuL)X3?7#n8#Pf-U%j1m|MJo{n^NL`kHncW5$+vZQG65HLl@h{srD}m|o?I z=a#i^@*uRih+7r4;q~ zp#`UbeY=23v`FaqZX>IXX7*n*?rVzB?QEL|Bu{i7RHY9JGiNJ)`D5b&9Q^hIA;UUp zr}^6Tr4|iQG{*WA!}H^D_x0}q zBUsr-=>y8+i-IWXl$^6u_y#K4rk1L=V)JQ0EwgzTXFb#SR_|&q5^*3ZV!UH8VPS zThu8;P=(MV{#<^4lP27G`Aq297hzIj^HL<5-uh|`*Bbcjq=_s;@R>UeDsWu0kM%xn$-twM&z+sP}ywv*LM!w0aGHc(%dGu=eNY)Osgvu(tSf1w z+NR#HMyx##ONXJ^SQoD+?b_8TO4H}TVCP+#G;3L`z?s9#RvY0zjfaFp|CG&9( zdAOt36MR{Y@;ckzNipgTbihMhkYr7<=3Q_&PW$LT+8)4lYc`E^*ygFn+0JqEd*7^E z4M8*h)i34=enTsq0pMu(@ zo?`*yM(#a8-82uf>HI>EsxcNb(nC{f&5@n3q653CSiB~6c+IUCi(WSo{MP8T?j ze`eG6%+^=DVt=FE!<$@x*kb9s2-I%!&^A_|QKUI(Z*( zzS{)lKsfcK>`#32BT65f>2%tpScUVqlKu)prqt6m~9f`&ln8uv*d10 zP41ogrJ}sQ6;nZqx%acTJTqoY-z}|8#B+9x8X|SCzZLRAbbJ+Gh6NqlPbS*{-1nA2 z7x^waE`{#Vn+QKOD? z%&TF7S+&c%diu7CzM3q$dWZVhw}9H9gk{x#M^>5|!VBIN!4}9w6229=|J3ULSdH?jWv_{Htm?If*=1p;ZEnqPgS1pCA7&hOrEBQGuX_xZVQZ8 zMc&XBst>Pcp2%yML$e$*E-|;)P*h^HwM5?`FlEoL)x|99%z=qL2vf)TeyPUGD|C*T z<^hAWGH$Sr_$?{dulMGuK?G*{HS#8=ELr~An8G!V46VjGiP9W5^M5`5tZW*qDXlR9 z{c6F6OOAf~wbSIDJ?Fedh2<7fiVe}Bb_9;Km-@mn&=xZgNh=19R&7-;{L=)kBjU@8NW16&MX^;Q;&DOxZ zG_B}6SC2~j!$t1KhTCzz@!PT!3=J&5$siLHz2C!d^|@xiSr^PHe+EO2L0(rFTU=BQ ztxArPSI4>gw5La&->tf_`p0e0am!XgNE>wK9)14C!Ac)+7j)LVQ9d;rU@;l+ zas3I01^a2UIP<={VICi@pI7B7vvHf%(cqKr{P}E=_$6mku}tPGQZcpI_|f)5uI{&n)LuaqjiNi@UQOr z@i|llEll0+u06<0p+fi%aSQ|RK!xe`M$iM#HNaT(k{*LJ{=_}OOt}%;%sS5MFbp;x zOj6)KSIk1aX4+$s5)j!culByg+uI3kj$ZY9B$jN0EXB7XA&`zUQe|={dhO0pC=1hxr5?EeUVyi7qhNGZye$-NPrIQHxkW5lx zt*>}q9n^^D=HW%W81rQcK{Z%PJYe-pl1-i`a`=eL$P{QxIPv$?R=LwZXlXV0EMJEq zLN9jz4fN9rLW6kowD^tHM;(QmR?7apMRSgP-^Zn5JJ^z?$GGfU)KGR@f)i{@aqv@@ z-&qsP(1!YEzG-d9iTljkP9qt>`#I&rr_&WP<7^_z5V?p2%Pul`gbZkT!fV}O=GBPm z^wULq?r!O^M*P{x0kDW8jYjAse^6pvj9`C%EEJCag+IUo_IqTNpjk7#+BOQ|Uc`T+ zq57<8O+;dr`43Du*7e(_%!49sO_0H|6u-6VpFRUyjw8=DLJYXuw0YupH6;nXLc zFCW+_lofD2|JM<>w3stnDzA&cOah!RM*8C9MB1#6er!|*d{0rpLx!{(`aZU|7s!uU)F}G|Ojm)W;c@RAaBcV7;o}-UN#8BX@$1s>8tZ71MI(*NT)yD7=~1-cqV+s)0 zQvWyL`iA6aBwetJJvObilXa@mM0Is)(R~{);%a8)8j*b+6rZN50pKmLT(hw>?GH%u zfKe(>3KcB*yz)?KuJ(yqTrb4A!!G9oVOjRorr!8LU<(w{j?-fv+FTJMT<(Ck6Hykc zYiC%imAt9>eQW;NJ90$~w%phxtIq zRd?4n2jol5rRSDWUtwZ1eoK*KyWHV~*ZpSKo6@;L5)Rl~WZ*SO#7c~e;CvE-E5GAp z4RqN#=|gLBbuXz(h za>r}4t4*UMwEY$SC=W3)H)}gLPC2)F6KuO~^{!!)^m_kTuWJQCyJCFfKR)Saif2S$ zHkLyjH&g~Em}Iam>5>3T3iXXk z&&HuDF*Z5sS`ryncLp7u+MjAU0xXoNF(ERaQ1;_Q7HT~-+^n{}oS?TexyVN*z7P{s z|3!gtteS>6%L!^-mL|EJnMg7_|Ni_Z1XWh(ukH>RA33^;y{WiSYp+&?dV$HLtS^eF z0)wpo7uRx)Od`^g|RRU>Z*2dM#drb6n+7dGDM)>0scC{#7z$>OA*s8Q)% z@wAL-j@sH$Z>%Q?yoqyDIuWp)r&iDheUQp)SUPt@-FcwJg*(EVLZ8U;H(gESb$Qr^ zSV`H0zEJ#kLN!fqYppk0HMc6%1#r&gVS4j?LZ>)M?q#r*DQid4x^ zJq0D1)@Fk2oAHeExBo0DK*RO^Kkq@~3%kMuniNPrsAZ9JUeMP2rA_qjt#i$6I;33% zTt40>fyI~dKz1`44fSB&;r@R7U@wkR&2uAlzN)A1V!X;EL1(nz`m@^)vP6rTh_ZeL z=$XC#qZ@!s}>`i#^8F9t~&qCzm5I+$N(Gg zyrsPDsk`eQJ2DlHW<5c>e}1UtEjU^WxOVg^>iEptr(=sN zEca)LIy#@-ei9wtVB-nZ_~x>rBlzn%np@oWPhXiDgULur;k7@YxFDi~gDzxy!jW9QbF#*C-WVnv`nd2?so;*SGtEb3+vE1LXnqM~N?ELGrb zjMaNCBu|qx)C(*~07sIbvH^x+I*IDLd}lQU?4JFfQA#rt2fi$aE7$ZJI7JAGauRi( zN%=k&DP+n%Eh$^G3}&KMIlqyqWwvUIQl^c>H_B8}kpvkedF81Lj=BgG+^qLGtBSd# zb&KDAC* zSa5t7g;XONtaX>+w|H`WYFIs~vnf}F%z;X%m-`TI1mVt|CU;_KHq#vg44Rzn`&HE; zoaim?H)CE{{&KGV=wjvtHL%C@wqd|ccduUaHC)&fG^8eL`(Te(g9bfJ^U?#&(#z!$ z1vdlg*ezH8z?SrwL`Yde!Dod8dlPw1c35`zZ>%9JQ-NeE(4*c8(gclwy9b}#ox`eF zmLGz)MJwIbR^lQ{%l549Jg0$^N&WM_raA2_V^cB^Llt|1&l+N$r~Nh|>T4?#)=0h} z&>4Pam;FTB-NT{jFXo#BYebYD8H3=cdbI4AuPU;qH;o4Yv%cN(6JF@y8}t2K)oiIp zzGQP|)ds}u!1q5I!1<~U6a1${Kg9YY^E&2;)!oRp zVZ~4~nOXu^?%8T55ArB0jx?>Mg3v#K(Ac0pC|OI{riVb|$CD6X>-j)~J;h`P;vXK$ zp6!uEVLRE5aqqq81!@CR2_G>zDuT)O$UB}NIV@R15{iIgghMiU(=wfKQ_nx#WJm_( zZwy7UJ~Pa0zVrPq;UG%$c+q82a~{K%MqLINQpK?BAQ|$Bi!sUiAcF+xbN8nmM}C@A z4Lf$$4ktqRR0lYa*jkIbE0hTYxv;oa>#xt25mOso2=O+?0S_E_4)zNf@W&&0QJ}3q z1cBMXPGuc#Z`(ndiD!BCQJjG#OQlziNbc>>b)gK=-{|?z!^VkIpdS5CBE3%rD>L6tjC_%Q6?uJjI4MVuCg%SNR0z%!o7T)k zpFH>d{_Pf1dvYT1A!_-e(?w^UP2xMn^0E%5$Z(;5TggdzpO^Yt#d-Bo3{RD~pP!Nb zj}H8ws<>9J1!;PgHK!}xT)=K_8m8%gwyGmYlS?c{f&b+#GaKCYSX0r8#hu=+haxr`U@J{imOw`u)G-k51VY}uw62B79P(lbyp=Zh%U%J|Lm<5saGj{fy!E!9 z3*TMr-6{As#ynuNK-dMIwVjOmW~w*W{uiwdf@%}jWecq2M?Cv)L|bL-(G?w}F0on3 zAyMI}%b0t$*yA4~f&p_qQJ+3+-OU4C!@fO(J=+z{UT3jIqlg}XUWh6JSDs^qC_cpt z;7VR+?rOGb^~SH8ct=WlKQXv}X@SGFll+5X(y>Fc>hwOLEO-V|#|*OrV2aTQHz^0v zXG5~4p!W@S<9PK71Cs&WQeJwSkA32{5xiC7ABvid4};OfaaU#rc2dZ%MNM%wM2@np zUre<6w=sRBW8&! zo_ts(OdQbZU{@q&8hzww?7I&7wlj@prQo3$&Um(-n>ydUTahL%#$`AD>238Y%=%gb z*GlZ*^{GhIere!di2OSJmYLhP4sZQt^vA7MHuaJjhhyZnHgVUCMw~7ncP@7zBSnN^ z5b8Ev&Piy|smp(4@wSU3jhj}NxSC)D4Kc;#umHR+@$K@=hJ5e$LC1bFEh5+uTX>hA zCVXU*7pK%s<=9K0gB4M866r!b1(FlVc_NkuHLe>+q18A`vmNJ5_gFJ$xM*iF%aO_^ zYF#B^c3lsmzkR`|1*nJ|!>`&ZwEXCdQ1))kgzSsoXClMTzXI#e;|LKO5X2C0O)+BCtiPalV*nA6ij<=%1SfY;}pf@-!Ug(+Z9%8PzXp1u~=UvCR$4 zl~pXe=(H=NIn+d)3csRhCI2~)vHAYfq&L8CfonBX91Ab=$>vRV?X$+7FW?LUG_kIV7W$LI!?x6^+2BI?ZLMbCr@f z)?+x5j7GlHoQ8S~HpI?)C0VU1q{IsCRMS3Vt&%6i;dm19I40@YRMS1yBjQK!ugc+nJNowTatj(SpQrrykMD$EWjV1l}!tpw-?}3YH_kCd>54 zlH|nT(oLAnO~nhKtV{rSoo$tiJ8)ES^XW^8+{}O~@REWqfWmkfVtKy{c_*Dlt=#WD ztc<2^yAPLL_v%6hte7DZoD%`MR^t@?>G5K_bA2$XZ##@s9&mqwFV^&POMMv<)V~Vb z!IT_BL_x6=Xv4lnZX>_5a9Kifa9r)7wBpwMwSXbrv|OV*5F+LrNWS$lBw9kyS8vJp zo8{7+x9H|e9$7q*-l*eYQq>gOkkc%g{njRFid8wQ%>E;R80Yx%VK18Kf5 zA`Wo6?;j^Eba#HZ1-yZ`-zmK4o)&_cuOfM)3d{1HrB+}yV@NeqF%E1MTb?m8FXf{L zdp!$w($Cqr1zw1wP@Xb)eiijC6(^5Ru5MkUNeyVZ@CK@y%OxVywTEy^=Bf+v;BUe$O88fYWNg+RZS^F!6OOv6N^~KweC=)- z+=UCdh^q+?VeZsY%s?;Cr~tm74rPdY(il`S?+`2`6{u2hQnriA<#gW&OU5Ll98mA` z?M=eOQ_CyUWXc-jILf_(a)KqYp>-owg1F@sBF29_ZFK0Sof83QrTGfba60&_Esw_iV_NQCw2W_Z)YA3_1FIKv1G|MmJqU}Y{^nzBKy)NjG~BPY*8UJC7QAC zyS^$*B1xsPD_hoPNS09~`!HdqFk?)Nb>?@b=l8q5&wtPJ*UxpiuH(9x&pG$G@Av(> z&p7ww$(U!d)jr~AF1k!v3dA@?NEv=g=OfmMS?5oWZwp>5Q_uG;OixH)*Mc4t zJ*RNX%|-YcnSFi71j4VmhO&DZtngc3qtG?+C0;LW_0_l-$KvvJ4a! zYDMt4sspCFt6C)riRf1}*j_SJq2|8nNzvTvUoYO2%JTd8Y{Ag#p`?+;;o+AYeYBKO z7u&pJ&`nv5%U9dNCaG6$>i3*36p8BGA$RUy8?ArItuqF_gm^T&fZj`dFQ#NIbPsNO z1~K!tIY8ri-*LV&NUzV8z~a9(7w$G0e{k7?TnW6TDwp$Q>cIy5?n+1BeEY0I?fU1n zESWd9B%FqSr5W9hw^{J_A~#zaNU$NDfe?3Fds*(SGZ$WCc)~M&zPrA(EPGmG-ov`w zerS=Q@nk597=aX%%{d4oVh5e}_?%JAAzVO(K-_!DHzE8IxQdT2P6);xf2tr?jCwT} z%6Zki5~*9@jNeEPknLADuW~yI9>8$SF%yc^>{d^TGX8 z_P*;i%f!&vcaT~yEOF2FAM3|jXT4f1Gkw(TJFVx>H9sCJbwv15Ht!%fSMUzvw~6OT z4{LnxGdXPt(Xy|rh9>RYm59PxN1b2L&1JSl1VPSlcSAmPSZW{0r9aRLQXYo6*hmE) zkmbzcFU97Hc|Uv&HfS&_br62m13}@LK4}=|Ff+TfU^s1jEDruWqy(8TQ2TdyHXPrb z6(i)~ESgH8VgjerGq(Jn;latEHIMJM1T~sOp`599vP2-{_QrQ^GiNM7xQyaY#8{J* zEr*L47sQTtpln625uDs3nJVKC=!5fFB2g9G1m%tc->B0rzWf^Uo5u zOUsO<38r`z=M+^=+3snwht4We(5&)7)NF}q@jl4laR+md)ND3~F}E`X*dJ=kyJS{d z?Q8jX6$JlOY)LM8?P)=P1=DGdP1s?PgpAK6ozG;pPJf1)%VX6@6yvlT6}&+77}ql4 zZIbiC-Rvk-!i6JScJ0svt4j}J4&IQyIu3|O@7A1_^DbMQN8CrZ;~!>Yp+8R!OVIR= z=_TBjKXtYYZst0#l@-9b70Df^|654FLTubFZ97Uu$l-iclD4=QnC0p7ulXH%OBqs+wxb`e^A>=qSjS;0&Bofd`k5qgv9^^{)!^|*6EM4uu4yFttrJgFr1 zaGj55)z>U^8(LbBE)XR|?uH&a`|U4}Yj0DOE@gD7Y5%IZ_*QmF?v(btqE3Uvd{va< zH-0b|FJl-I_>+a#zPSh7jy%ySD@(%&IMxYgFsdw-m2L?3Xo(_i=Avz629cGOv@o8R z7TQKB#I?7!UZ@klsCUu<{8Knrx0;Hh=de$?V^w5b+Ko$xj5(sLbh>6cw8bv62@0hZ zmn)@rRPP1#%^~j7y|231b@JvY_Y$mDj1tglQBZc)%Cz0{O(2idARWyUl$CbLn)`{? zq!KB%TZmk-t@n?~KOenk zlEI&$AbO9t@`QY^pUvqCQS?h+PJvAxfU*Wgib?UNr~n^xDZ%y3gW`nn-goC4rGAi} zs(UHUt4ZCuFQX-p(>K%WrB2ld|9JJm56Re)eSb-KyNn-qh#~f@7;<=B9kR`M^acb) zivL`(s-|yDhG0((X#{5aXuD-fQRVs7Fp8XN+hSf%htLbs#T2VG&^F3zH12K(^WFC4MClBV9#5~f3AKBe-h~u0I z*3!~~K&}M_7R^2QGeN4^eo0BwYNvuFZ|l9*)>k)C1(@Kp@a=VlB3!I?NGEv$kI!6R z4_TUOmWVf>jho8J$$A1i;Js-7v8SdM%Fe;Tam~+5ZL=n4P_StR{MvPf|w48ctj7)%;N+x2tlo zOl*8&f?6IJzUbXHe*NS4JHOyBrzC(iOUlZ4i?)VeR{4Fe!042elr%857B3(WnQ)Cn zT*P{<9_YwK$Tvc*&xjUna30I!&(F^f0^RhUUMxFQ5%#O>WmPEE)AB-`K5}8E5JlD> ztGw$R46e?2cEs#aS_$y=RhA8#6Q&uBZO#Qv1k^`sCp->p9YddfZyeFeSgVZHezbuc z&?n|ndb+ZcL1nGsAP;-BSGS-7=h&uq)zw~cZRCP= zwR;D9@Q}@kJY3I6H!fet4--awqP$MQ2Qp-g(W7XXZlNJKG4oM(d2bDm++AB>e!Fq0 z?%g}^arfVCJzo#Vbn&(8Wt=*HK6T@J4R(zCOZC`yYtk3tA}QWcUU;TGBf zr+re)j@I-^Sc-lb|j18}tO;zITf>sK93GKiP1B zMZ4I;&-R;$+Q6jP3qf+ zM;uf39l2bvDZ{3$d;o;$s zsHUcqkapH1ZZ#HE(O7*6_aFB;w1n>1Bk{DcaSUGTiQW5~PXF=E5ux+Ffj;=%`r9g^ z{4%Qr1;2nmacyn(5?X{6XW-%)+B3%J(};2gxEan75D<`SgwnlS?i>#S4k9lN(>(-% zDQ3v%$J}_AuR?+hPEMwAa0^;rd_CY_H#Ob+f?H6=)ZX5nfWp%+I6CGuEI84FinK2! z{g6C?M<3T{oD(UCWNbp73v_B(+Su3-#;G9@Cep1FI=j2OlKc1T@2^BUuL75r&*@c2 zIS5BBzjJDfFj~MB!9t8X-n!HaYPS3q8L4nJm^EP8dUJKYfmn!IA(dnj1`H?|@>DbR zOJ;-^kXi2^=emlPIH8=uKEbfI*U5w@*LW5{GOMyIhl{)_E9)5Z zElLNb&;Cq1WC04tgZviiS86yjO&ATE>KR^!jEx_prKJMQgC~uB`8s@H!n}{yfv0Q| zi%#e+FD+RH25P#Ysi%9<0+dG~<4lT}5laBZ&g#TCXqL4?gej2oQ>f4VoG9qepiMKGnf zGVj;CNrqQidiwn*F!>xrguYwY{67DQ_x(Fpnr^EC54_5-d2dYR7ZfC%XxkKUc5x{) zgz09t@Wr340d6dO>ORX6Fau8vu=t&RJW%L-jG)TFp7!>r(WX0ZSlJcUHo0LCg2bvk%+ zK1Z6W%t|=N+#r9KXBM&4d1U0Wa6)meZa}_M(poxB($GP%MB1HJPzz0r)*+ zVg9##(vW~i)c;W#Yh-;A$d%K(8~bX;)PY|IcOSSrBgB{y3IfZJqiwNJ2e_uWMvg_X zT|1EQ^jK~o+XgZq0&^6~01!|`>(&j>$T^P!9=vDgi`=fTl$4a6x_I!|)tp(dMO$`1 zH6L0v%qB<=j*q7}sKsYw2)=b~7LO`u<%)tuZVkDo9u&EM?53M}bm&O{_ zMqDnGIrP!fv?oCVXKh!O?MrRcy8q4&(S&Jt{SZ$~kOJU$%yU|)W;id-cw1fe9!bG} zw2JMqZooZ9ZSijHil$#`x9{Hd`q7m>3Icxm-r~`>@Wx}oQ-HaWSt{DLfz@QGHw#Hv zzS2i$*`np1PGQ)>e*ftY`;o)}>_bPl2Emv|h|n1Tj8a%AIocX- zz{+hV0BpKJ0Io+5fpX-&DF9~cgCHRRx(R0P(jVi1E}v4$7G~XZg_#_ETMGJT6^V}#>p1DWfASQdz-=w)PX?pBkLz{^tuBWRD4aS^N8MM)zgBN$3W%lbG* zr#DAa0f+jg(;vLtnB#tx#VsudmY0_o zYBy=bk{2(OX7@kV_TmD_>BGQ}jU@v`2P_9^?}+7Qfvr2xI~DO%6|ubl*D-}gDB~4_ zop}V~@cV#?gfQB|EP#8ASEkW=YugwwUMn>{5M=5+6IQ!qKzNz6v$K{>u0ZR0IDlgW z|A2+CgR(^__S+lBAEYlO8`JdGL|{IE=K}+_53EXs(3QaByy)bq(7F3(R#?>5u=VTB zmv7(J3K!S7xVeKD%j*fC30Yqps&wE7VMn*H z!+;$O!K4(=WS~iOuzH{(hZ)OwhJeZT7;XiGHG)JYb3r)Gq5$_aL{JIX(RY3l3!p@r z6(YXBKK&sKNw^DiwX2a>xLrJS4$8@v#hoRebWW)V$D#|C#M?PKCV~wBH2_xuQmab| zj{o*8o=>9z0#Lv6Zrir2gW5hgXcXSCRMT5^`{zZZtJ=fPU*FzPK_>ud;EfH`F6m&< zg`=djbPq)9E*ZWvr)<*kwe_H*8$Am%6G;ufyH1)4JwnIFgUmJJVCqRZvh5=6{{rc6(dH|qU zdaiwOnzrG_Oe}zMEDK+6-?_sQmW?r7#G{6r0|ojUeZI!Atk%nN%#ChV*|0-8V{!}+ zelR%=g9(Xix~1VF88p_yzYGumF8*4CBeF_HzVkU6*i#a&arO8JX(5xHD(YM~(E#58 zkZo{!Is+tdHpu0-PSJl53*^ioP+86rQZ>5{+?|Zh$jHF7fO6+DizZo27s((-5~fiU zn^4xGjQOp36qF2vL2PMQSXh9RBGpQJLYd)1Y;<}n`+jv#^Vr>5+ZcXntTT2_frmin z&u3QxRv2r#b0lJS5#a@DWzyo}#}lno0Z2P&jiS?|s>l2(fSj z6THJaG_wN!5%iGN^U!v-^6)lwvxHPlJzN}|JsfP!XuT}m+-;qm9*KTT?}a&_gh;3m^8GyIibK0U%_SbzJ~ zt5*lqa!G%#N-kG90ymB(^c&nBfX}>r_fGh#hI9*00J11~cXl26_NdZxYupE)%PFOm zq^GCngIIu2%jKV5AN)vJ)4mj5pQZ4JOQN`4dbkM()R1{VpSHT_E6GsISClkD9yUKG ze77sRD|`-?qDXaT(!J-N*B^9I+*2e_Qc~LQqHtb_Q)X{}VjS>F(Eax}Kc5n${dh_H zR(Wf`B(1sV4Y10dl{g$tx8oU9H)HIX-YYS_Z(hzk*kA163cU75tvz|>NhB9d9oc$) zTrPSa@(`fZ_%s&N``qjm*Z9?eGjmsCa=})C(Tl&9xRe67h0<@06smV$UtNUu`c`NTx@@iO-XtC?VC&lDHmF_$RCA4L0(?o`oF(ZW8>q|OLgBJEO(oaeSCb+oQo7! zuioXJmX=lw_y!V(xXpy~CDm!Rbl86C{3Yhb#>Svs%?BP^g6oTURPEmYQeHbk?njSY zFV7CLmemUHDkrkG4`xee57}sFXar%=_}^A590}}y|HLSKL`|4&{dtn1+fA@ugCA-g zr!kXNUYEC=V?%?3gF#r-KG1Skq_mmY{kZse*Tq*PW&;_bk`q()u5@6{<^oXxA}5pP z-vVK3ZNe&>@+^SWu*-G;TL$x8G3!+v2dFbO3_ z&Ez;F>@V9*+C)!h(4iRmn@P{S$oL$mUV?``g_lw6>PVYauYz`aE5mdADVXQ(rOtP; zF)=~-;+MCRj9&w z!{=zdgr+z=b#+r+ECY|E_T+t0<_cy{1>3Yf!BY(|M>A0ej2c+ zmzK=@|MWb(x7Kp8`^BZfuzsuT3%vi@?;raJU-{Sh-Y8C?(y;x)y;ZQFf%h(cs%u8;DbB#ZkdvW1- zQ(_W7Qf^tiyr@V4jdsIBsJN+VCeVMn){y|(nDg5^rZK3p2p>JlJm}?UWktl;+1t}a zErY6zg%rT@w_bG{vM2Fa{vc%H;?m?!R*9om9JbC3U_iuV1YSQ!J*SSAPvLV+!I1F1 z*r~hfw(d)L0Om-|O@Q*+Jcm(9yHM@@YdnhaO+R#rMt~~$Q&alI1qE_bmF8g{?MM;@ zD38R*r#)~EU>JuYdy=v^*h+(k^ZtjbH-oCdyeY=fZ-50zgcJZa#)7_hvOCLyh$(A1 zx3m4T(sRA`3~ZF);=+tg)XbubLI^F!voGLLhi!O<0Ti!_*P3=<-VEaL**EF2`ix8$ zH~osi#KED?O^SPMKL6sP6hnesz{TXCB|t%UHhS) zE9Dc^&A<495_u&R{AIV1W!)DK5ASUE%brUg??jseUv631El*ERxOCD4-Cd5>hq9PD z6cRa%qe@CxEv&80hw~KmT3?7#`|nH6fGc0S>y{fuYUawBu6&QZo+$qGspDtzBLqaj z=Kw)zzMI7gDk|RqY(PQW0aq8N-I4rrZ_u?7u|AY*5PFaoQ&3(N-sI$RsT*C!Er{>P%;kR5euGTZ10iuo74i`!9G^C-zrW9I{@!rtt1QIurbuTGktAI2mm{zlE5W@HMuqDeT2OT(Qy**YWq zQNKV(U^AEu!@#R!&FC<$E_;Y<%gs8?71L@UgX)OOyelH+5R?G1o5R`uBHM`|0AlKX zp)J7uR~z9XdIT zfEU}7Tnce70q8{o*up;7tFpKWrA#^WStdPu4YtG*DB+`W$Le1WlFK5#M~tAg-2Nlf z5r&WNO9j@KNxNX7n^m3R_R+tXj z@O=OIQ$|;p7!({%?hq;W@84rHEvM`=r)7UHi2IK=MqI}pKUwT~m?>jr#Q=B6CIEYq zTNDA9xTLp_8aPN<85wW*HC0w}*+lep=jwjq^4VX=+6&BcjiwYFM)~lhM30f+o_7)U z4#e!O)iv168F%SHRrjxTb%QlCGCm>=Ft+rK^|Ad+VucVOB9nxt7*1X=x`A1qhpyiPL$O-IAZrsYFC zXM%wA9Q=GV05?xC9p7@J#omsN>O@cp69e$c4WzOhf%bn{XLiz{&g5Z=;B&rF7@LuC ztHCfz{BjZB^wCGE=3Nzr_(kx|uj8c#2c0Cw3#ra6?W+8$85)9=IqCT@PGyRR7EO8%;m4!ebbFmF+=w>|?U$4acMu>ji4V%7u&;4V;#+zHZ! zYO!|OsRQhTh;C{>+$V;vNWhR@6w*eme^1Ms0Se&N=ts6*?Kn%8*ZBW+BaM{%nJ!EMaoP^k0|Z^}%lq_0;E8-_0*RG(ZmqCGqjcj~lDQ^mih`<#&TL`^Vel@DC4hrf;+f0Kym&=00 z=;-LeULZ>N{B$q+^MDuy;EpfEL^YYDhsz2~8s4 z5XLQ5qbAbM&Q4NMUmmf)EAbWfi$;N0o@oImzexF=D4iNsiE*h#NXN#;CaWxQe)RTA zpRdc>!&Lb4p!)#K>LNgxZan^(f9w&4>`GAPX@FSX#z2JKqWTJk`Np~BZ`ZtqLHUIF z(zo!*M$b>JShNyk5}(GfKaG(SKt}!toj#kzg%vhK_f^t`h``3___EhRaTH+NH=M7` z<-KbNkEed4AQdKXV4jG;ItF)|*&Z}}(k=Z8nzA>{S4p`oZv3=*l*nfAdS%7J&|^rJ ztHp28($aDfOjcLCx>z_4dp(q7S^y2S3-rq@4aWWH`D?xcSJ{h4M+>3&OU9^k688E9G%ydM*L<8UKl#jA zl@3@WtV*11i}7$%svjTJ^!osblLvrAlbMk*hKD?o2UM)>Kgr`ThiL_L$1nhVhU2XX zb-+QiT3=k{*_Su#3c0N)3?6>`^eJEV9kC)1B60eqiCvKtB%|Ycjf<}-^1x#< zJ$NAd?=>Kuud0IqrxJQ`S?{qN$*qYu^aGqB1@9SG`N{4K zpQW3Cl!4V!j4KlD0Z;HSlI)Qjpjuk``YAlFOEMdv8ze-?nGd?7=1~`cfMJ3<#1Rtn zSl752Jp#t)J){X(#b0^zgPOv(-Z5|dgWCNdXj|-jsJeI2iQbPgq`V z$j-A)Wa4CYf_EFY*qK;Zl;e6Vt}}ZS%-_?WXK*~NqF>jm7MBKa{JuavlijvPpGjQY z*cWt%{MFthcM8%jGurq(fihgHh*ym4>|I%sq5EHPI2M3LcysCk?3`n%Cd?Sv!6}Je zg#M2gy#JTGV-1o0vwlc#{U0ypZst+RXv)aSBIDxXrkY6@;14zeYPxuwZ>fN@pYd{AK^ zBqTgT(d@kwfE=*qtDW84xc|9KdiWzrNzTW8;m+Vf5tU*Q=o0_Ec>O;wCLk|v#khq7 zAKDvIO<`Ys1>Y+nUrF8BGv(|e-9iXJ+cNA)IPc%TulVI~K#jeH4muKyJKw&2^TB_` z)uqSZjWBt5NA`}atgHqjA$Sa$Q9IAfGCs3(NWlz%A$B2+feF0qZG?VV_{Y3U>Z-Hed zSvX<}AOh|>m(k8M^>?_FaknPQyYm#|vnIBgXCK%IUmY%dKD5APoih?^g8j_K7oQSAbOl643i1z~t);TEjS z(fsm(a^k|$I}SO0eRAM-y@rhzSmJ9K8BrfK0WdMYzWl48sM!9B#OMv!1(>4OaO0fy zp6{G?ZjJ0q@)F5L%dkA7#3Cky-!a_J^6M z2QGBFwSCyhG59kf4MF!Y1HGo$WXW;sjMi15zLfuoO_- z13>r}!76nCzw>HG$IadSpbZ@#hVFf1>-~jx0kHJ&XWBPB;2PQ*FYQQR(!Mla+k0^; zJn6vK1e!m5TVTcn1H%}m^Vj93yE6?H(>uTyg$oYW6sD)Uvv*n_0!94+@Pyw3nbCko zGi(d8UHt?o6-`$kY`z6~-siN@4>M}aN3~vHt39ZwfG^5F=Yy{Mi3kRf1f_iOv%44w z;Gwa?lba^;oB$xKTH&L-#bc(zG=ih&U?17pt#dSlV&MavXrsAA+`!K9UyGm-p98Pk zo?53Pfj}IA(epv)BR_)*Y&WEe;JfS8(>jSU{(qfPOt}nX>y5RPhwdoXMWGT?w+jj z8$UxxtA4_EqXsG2_VMv2*e2siXTE`^TcWo(Fj~`9M-1CtGA~}d7&Ir3WLP2%AnUT3 z!};Q6WevSooV0{03YGl0t26wcXaa`NG>L&8%J6-)=%Z1CV z=Y%OJq5AErUQXc3LxkTc1>Ge*q z%yf5PW=nq>Giwh)PPPV$^Epfg0nZ4Bf5s&=@Vt%n4E(OtOWcH)^d6^ zc8^DwnOIq6G&S$QwohZDkU+W`U@Ne7TcKYHRH`7@Pai*igqN64&jR$_&T**zXOPy& zc|(b+uP*c3&Pc7|ZyJ?3 zjnaa@ewDfeDA55L_=326`NT3T@PR=d3Sfu|^jA20F#^^jUmz8bI&k|q0B-6lsu7|m zhQR>Am!pJt|8=^LADL%-mLmbP`R9XM_oro*EP{(fg3ieLtda1cS{l5}YQj4_@Sf6) z-uU>b?CZl!{}8fARv=?p*r}VBGc~;jry|gGu}@}B&V52+;@TZNlZeWUHd724gvS1n zv-KkLf|rdw5$9I2jOMo@&D?+D7ET&YU8MF0D9uYI80TlTTPWzHL3z#$Lom=->4)fF;lJ zr0g4f_0Ro6II#R`^xWdK8!ZC47+04sN8wGErwC7}t+gt?Wn5bGJAho8fDL~@jR`Ku zruInn>d$$r8mwXgsq~~#dqlgupZEDd_$SOUcRO^k7#m_rKLfMm-{0-ad9&hxM|w~~ z+~5l(e&FJD=o%YKqH#vi|ItuSeD+UukPOvc?2+&Pd}?}0G(;?Px()D9^XA|M1bGzt zZ)Vzj@fb1E{oQAC=973qY16G9$bP8m_F9G?JM6x`q%;Ompq94wRc5LRg9wm7q=Ihr zpr3)3zy%B$I3d{I;q(D1iWEcqUvW^La3GPJmxlqlOg!_Jbto~^*T)8S8|ztV^~2|jzPr)jMKMBm6k+5PAU+XI710304>!QpqQF)5ZsIwYajFr?=8Tp6#xWG zyx>Ofv)_&t8j@z<)PMx^yQrwB4U|AsRTVeP5g->BO@V1}29{CE$b9w3`|rRw0Vq%C zN(nH0uN5T*ySgQMl{w3;gI?h45};RJ|4C{!L0w<|A-Gc`8CNCi`J!!=@=qrhyZbQ1lv10tG=ETgby7+$Z`4}+2GQMQP$14 z;lRZW934~xC@nxxzxVcbz$TOMUejG+?_CT?Bbu~K z0ndW12x1PS2$~mX2q4}iqy0pvVJ@zqswyidhe_?beh8JRXf}#2)-GHENh`#t0SnJc>jCP(0(US;aIW|-?{e#T z0Q(1UDg=9B#{LIL5o-0+dA}}Focq`kJNF=htb^;_F>7dCs7>e2M0V#l$6P+n8MFdr z7l;&}-F_m#0}U9i*B5)sfaAym9WO<#uA&k_S`AAJu!i4&6?N6^)biKLAK0N4`smBE zfMUFT`_^SdmA^(H@&7GRRH5SlK(p6$cnfB$lmadgU@IIj`+ygDy$Q?!At1~5y|yP2 z`C1z^)4=a`0n)_$=LarepveHw{dZp~iC2?c?j4YUvtiZ%K7H4n2b0MFbDllXT2fDY29bfBH?fWMG3G3 zw5)S+aj$Js2R;f==pytC4Cmr7^QRPlA+mm~Cb&w7x&oF8B%!LRsG73C4+B8MG^vhKLB0Z#+$j093Hz{YT7D1PGl# zydVXd(k(Fjv17pdIe~)%wE?iG1P12H>gr-BzE~SfeIXt^5&LmgnD>E*CrB#0ZS09L z)j>)KEo_Mvef)@>qDF*)V9_mUD|z}khdi~@3<1HOK1h-AeN}RAmdR)rqqTnUCzI18 zGzh@^-x*kF8L%gI%ox!ztXI+>@hAorQ+_8?9r-%@o*r>a+6B4a?;SLXMjNO#^Li}R z6%^IxOP}a0Svt9hHjrvjxcP%KHKbzx0&u1br!27hmdN^)pz7A3StW22tLOz(;%wM0>DJZXx^qRI+%@)cw_rpDB4thT)QR_fau_vvMFW`e2w4O*=xqkeSX<@=R zkP0}C@PP}F=iIf<^K(mo%bWhZZIw3wrU{#|efbbtYH6=37wR60)cLHp{#7lcGa*%cL>n_EDz-7Z8H2}`}A zF11|Jxk=b$83nC4{=5)Sk?3^#FK8s`Z&e?DPjnnQAeWVX4dZ~5(Us} znYy&FPBn(k#+=sF6tH#G#IHP>Kza_@IO@VX7x=CqUJzKhgd0DIL%snE;HrDK74^bl zx)v{$&++Xhuj+qJM5$;BIAp-c%={JjtUgoa6u?0Qdh08^=RlS(G}p1AarvlQk5WKo zG<0AN$|FWg?wF>wkX4QgiWd$}K|e|EVwpdTh?V4=P;EEHkx3|d{(|BZ5& z2m?&`;f?1ZJ_i1K_Y1IAbng8UF#T5v*W-A7GL?VHjVINbtA z`|uesa3T%ZH7`&X^K}9{YaT+29zrnvEr|MyrdJr-y9$#%YM%uJ2%o{h7c-Ec-#MkR zia5UaS}V(fWuX#%+%C&S-{fKB_!~5h1`^K4h+_2Ouj6wH?Iv36S;|{!Tn1agZ=Y4y zawLXGJw`*il1U?EBT&Z%9}!`(E&T-qRl!{Zv;j9_67F6%4BeLX-2)G&Me(k<-1J)J zM@g015DRyZW2Nh|oCp~088}oC1r7}?fq1I z&SJ_#4$xvB$gRIDAwUd&=vMSw{XrygZt?@-Ba}s5c9~^W-cZ;ju_@0{&aHVK`5>L! zqQ0c9$9SEO%fr#{orf(C-b|v|ZFi#5(|BGSG94l8my!9E#-Ew$`V0^yNM`Sm%97a8 zudh8*jP5{IR#sBk8d-qwtowke{gzI44Y21R%ODtRPFm-si%7RiE~e&?_|>_Ta`se zZy}9RT{usZL{jB2nt>SUdZ#(%^Dl=OeuJW|Pq>jfB)LO2F~HzGY6l`K?2brvK#CI0 z_c>ebqC1uOjh%(SV~!q5u&h6!pR%y)8y@=NJW7MU8I9KS+|hZxWFXIW&!$C=#sD4J zw0T2&c~b`4tJG0XdSkgtON03d23p(pt&i+hcaGmew;>>L#8?e#abdyV9*X4(`V@@k z;CK`i1k&6);D|^C>Qb4#0mHfJ024mq2N1{<99cYDra`>{@6#8_D)=48-M1e{-ya}1 z*R0Y(jHfJM{%}JEe9-?@+%qoG{(+s&AMsk{79&qkWr_J)I;hQ1HQ=F4Mp+lyXK*b>t3Oz&7@bGM6$FHr}LZ$NFtVi z6(SFe1|Zym;GEZ(6eM5d2?u`QlqY;VYtlS=5pZ_+Od0G*0$ETX-L*Wu+Y64j6uzsF z#W$z=zUqdM2)jmf=#|qc2H!`Q{p?7_%T!%nHbT%sDiaqp)uD5hGAT6_%KrW>8RhE} zl2Cy@iB7f6*ok3#ITohqs-V^B;$|gfS&kfqy|AkHsE%r;pqesA<8pdLt-eHl{#!Fh zf$2?}s|8iT1V#{aeDVb}_71UH&}p&;-YY!-{3iso5|1Bxzy|_4S5sTs^3=C^uJr=L zoJy5Y7Cfd@`GovTNHiDb51V9W#?Xm0hC7@*gC17(ZQl)L+s&m|kfh9_mOCY$J2;Ri zyIqSzF>)BQ*4I~O1$)YPLId-LlSx~0>^rtJhBjM==Y@BG)tkutQ6uVj%QIy|I$b9D zG4!2s>W{l#*aC`4D7GBxB*EYwPX@>d^1QY{8_sb8b21`d`qfur4Ds4EpEl@Y#2C-G z+V8F(6uvdnmCwhiRcx`<&fy^T%t;IjQ?C_c{>LSRHX>i>NF*%ytpq{N zcM)bDm^G3TOjEbt%01<+LPwZjVg)@5MsHK2kMDu=`|WLq`q^C{{IFv;yBeXq3UGAp z<%kqnQ(~3Ql+KSi!3dt34RhAqlBd-~^??5C?y(WyjCXVhXGD8^5u74Ds$KC{$5TFr zg|Whc6>;=bV)w(Kd&%+K35O|lJ1u*3W&!-Vw zB$8@o67pWR&=*W;+qfmZK$zCC;j8FEKNjlbx^15 zNM9vJP>w?R|(Y4gv@V)I-%L_@elv-k#fI?bt*_Uq`9Yw9b)OT_Irwo{u&8 zQgt5;Ce)SQJBKs~A$O!|@-#*9#%GmVd3aGfTPBWQ5pcA&tL&m}RkX`ksu=Gdpl_Lw zu0(^e5|xWRkyyXO(^;hGB$)dkUUOl>g;Ie^0-<+|`0<-}{$?(33jN2ZK62_Q4o=E; z>GH?T(IJ%zuWpa)o9ry}$l^d>P^yw!317@oUm%N2^0VK}&0iN{WjH(M&AkZ!CGm@I z;X6N1LFE(8!>!*I+}IMOyhG(rs>ih3K73FmQ->5b<=Y=^{pb8_>D{_(IgNpDSsC|d zs`gg@4y3l5<&Y#4USOPR)iC4r!{{b^mWkV$r-N9R+Yios;@a!RMjm~dCzbJNbyIW_ zW=1QXK6tWib110cZqTB8$`P>&GUCC}6q)q>)(l3Clak#VgFa}3)^&#IU$*86FY|9< zU}hk<|KhtG8EmHWdw6Xb8@q@9;^EB@`_N(x?U3I04O*T@7#QKC88jk49J0pflKN74 z-Z%M}=itbLC@&6a@p_d~TZ}GLHuQXH#`nz8^CqemSveUWTUTkaeNGhgl^z zIM*UPpUt$`bg)RFQzx^N-cl;My%Whe&g2P0y0$>%TXS+XhysOcc&W7Rm!p`I z)jy|TPhwzJoZU6vV!PI5)`&-V9@lS|nXf7^6Gkj+beU zg8c${l!w_)wRj?CC6@$)WM|c#I%Z z*a@E#Yfjd<7CPlq>8EX%;cbHWXltUXd)dX5lNT@6c~_LkQy+XSqs@_s9;42-wQQH} zq?0f~S%4z^?{^eJud@?E!d6}c*H|#KAwvq{C4P;Mhe~MXdAihK1%I0vN53C5zTJ?X zuxj6u^hNw4Y4U_^^nT?yLUw-S>YZ`+l|7QgWj!$19jp<3-&g`!>5Qs&UbrCPb{?@t z3~66NF+HMFeE90#Bed>S?1hqxA|mBgr-l6|m4R$ZY(#Ded(e--Y^cKG5k%%P^|fv4 z`y*6zKkE2V%C4hYx`H@5^^<*9Wi}TxIu{43D@q^3;J0>~S(#K>t7uf?*}zu=DDr}u z1gZb=<)G5j1~dgSiIF7B=^_Gt%0jZDNuaeGi>s7Rq8X$;t}{uffE^{rTz;E+e5G|D|#48DaK zflsN$1ngC%7>IfpYufHO-+n5iCB^Cy$}g`~IZCIg z=R)YN?W~bI9Y;Y;BK5=lWt@boi1!S!wSg@2YQK7KP9VkE;}O;~Qqk`n^Y@Ik-5!YQ z2L7B@DtKMC>N@D#=R!8yb-z)SVz3gg{OP;1bSp5kVmS)$E3hB;1}7Ryj<_ddD;@>XcSFU3?MD|NOEW8YV(8~@&W?!inURW9kpB&RO z-G+!WsIDoKDFwFh2`R^^5G}?^TioUW>FJ-=uVa!E8XVX?A{OH#PpLiwE6vHUZ{O9C7`6Mns87>w&_8VPze$LoS_d(O=jR`p`%*AI>C z98Wu#>uo9Kr zLa1M(Irt}{Rs5z859#=gq?4s!VoYKQKA4buk$y0tMdWqGm9-wW&`roZCD!jl5W{3s zYOFkuZj8w}F7~eESv?*u=pQFs35YlevL>IAd`)PHQ){oK-;UX^Cfdn8wI-t{QzltJ zI^4U@fbe2nt|RGcOT73P*YHZ2J1}Q+c>sk^>W;MBjj-f#G-!_Y5*VV_mOW@= zI{JHJ=@EG_Q7hu*h|PIoXEGr?8e+BZw0(FT6W`xWqx4lj1=6Xa_>#o$)GrLQ z;d5x1{v7E2nz_aU>UA&-)evvf9X%e=lE9o%%IhKg`|WzyctWpKF!${lv@XZo%+ipa z8Op|Zmw!i2b|M}kk^~#6_;M^iLbuAZuLI6;f3P15*SHtBO@B4TwJ1%&3W8M8Cn&RQ z7ou)JTTvROucgqB#Oco0EF&RyzsR@tKWa7Q*zVo^PKLFTE+t$|+8Z=ns`H%9m$8lV zf+7XYDN+k3O^D`f!?~>mKX{QuX6}nX-0Qm@sUPk(U4+*Vf2UM4miGSJa?1TL0kNm3 zOZRfusB_=Rh^9x#w`M!M?&2Wy+RCTihCG`y*Nu_LR;0o-Q5D`ZKevc-*{aOc2{&@O7z94@8&UUD)S;=)cP{( zP5vQA1`3)7KiY%je&%1hye2R?>}~7jNB0xYa?q9Md<kPd#N62 zNGkc&I|f^gNL$tJ=~q^aYaTi&X5G(J2tcl4o6PWfpxPd`2mA4mM~yg+K!Z+M>550m zT==Q7(IDmm2I%jqp^O@4s?y{5o}yNRK1sVt%HI0{%6Jt{H&sQ?i;fbGV`Wl&MUFA` z)qj84wdIGxS}|{3C#B%-os(3oiMOry2H%{h6Q$F;epInYhCO;xTEOex!&c35V9N$2 z^b}G3Y)1{--vdaIJ~8AU;HGuRLnpB zbiqA%c5lch>IH@1G-;GGcKvfq&IWPXHOj}fjS-L(|*hH9u1I6bh--v$8d^IpEEX--%H^~7~- z1`SIz`sBHH<1LBcRSp(|K%$*N+}o)xOHdocxlq8-1nf5-saaWJ!j6 zGEFWff4`n-a)1Kg0ymp&Q|o+WO-*~@%1)^)?*LIPYglbuzEFVeMtd9bO&i^07%$;| zNA~aV+N+24#R6?w%4{+-URehi8XOwq{dGz9)oKoTyrIlgE*qZ`8VF_xZ-2ZS^m03K z!kwD%}LsF~EpVDoJ+Op=0z7h_}Px0DTpds)Vaiq1}D)AgOsBFmo95jn6SW9vWFVp{} zA*KB@C9ln+ycf+TzBnC!OD7Eh`Ymxrb^^0&{2>!vp<31gZ7HV@$ApanLFpZIo4yau zQ(DP%- zbhULc_od{>)3a+lfc3_IYegU;apn5){?40^)92ri#MtNBKn2hrQXCfGc%`XZ@ z6MOQ7zmuCxbl7A_KQSla8ZFI_Owv<&O5Jy>g2LZ1j?|%Y+x{|L1^1xjo6pQ1C_;H{ zQ_8B`M85?hfarC^J36+m8}wGs&(Atq>EB0Wu}2nsj4sV@tE+)3b{S`_e9$G@k>AIH z7*y=3#ut6CKY&_hlqOTX@X{G*ju&3{T6jw3-dw=&vk>~}Sm=dF*gKnUe_muuyK!PWR07wrnJx_ibSKjfVr)`314e!f9k)JohEjJ7Mw{{cuGS%Mn)ZK;(Ik;vKcZZ1{lixJD>9@0ZoB1taUzX6_X!NUEB`W*uVW7B&3;lLdpEB+p%L62ReK>T)I%uCS8^% z>clq2b7jq%YyQd_y<-i!dWcXnU!l!uxQ;Ihqm|e~q^e8m+XcN%_Xzy%@KVE$$qzY5 zXr+zUUF;a4HBxf#Go6QM8atk2|MwcXBk0^J`Kc;_C304?MIAy;c5&O$#EZwal-WG^ zJv>2b%b)n7P%~z|Qu|A~3v-kB-M&;?@0D|n@%#S{6(c7piYHQ?l|DCPc$;jFl0Z|N zwrsx!e^oPRk>3+Rj<8hn*-YuEQ7D=1u}tg4O4I zXdg)7OB)M+_>D06#n-swt?yDnA5Iv=o3EM;O^viam6-SK`2D!u4QbhL)+3a{T&(aQ z&}_StPKlRjy8h>4s9`c|3{vE5e(?8DE#^l;Oq*`PwrL@Gs`Hvkwf__Xq|B?@SzHZj zB?Ud~DbzD)GVEAxa+(#BT9T50({or+ zQ9)wKH~%VfJ-jd8iXyAlt*rczB85)4LNzaO8nA^C{2h_Z5H6O}XDHXZoEH$=VcB!E zvFN>VquVs+l+Rge8i!pAhjB160ZHl4es#z66MB?C)#Zos?+orTw0@heg9GTmN&4>~ zw2X`PLav(K@o3R|zryo#)jShLmth_I5efC|ydb8TxpHPI)w@3|2r6i2uHD+OoAL6k!s4cP& zpEh{#3HvjjcDzjaw0?mOA>=2@>!;Rlf1x*eldw$?Z_!vg8?(z;`PBO=wWwIy!4}-tBKgGjSla8`Ok*+8f7q_y`)d9CIbS8W-Ci%Xucuh7tv;*(!z3feTTz zH)Ai3ijNYI9v|+LXuUyeMm=8^wo*~TYku+|mGOqkCJCisFHzeORxs)+xCM)59#^3G z>C8|P(pv2SGWpNp1TK?IVNC7e8J1QQl!pxIJAz zmL#RvE_cG15*1l18X+Z%P@g+n4-pUQPj$0)iQzf;-FDq6mcud#H43U$c~fOQXq<3} zWb`>TkGehcw=mt{J9K_>TWw>W%N#A}C9Yjo>9F==*Tap475{}MaZQPBoNMfU47I3`A#X7T<=0AW-e$MMo{(DSec-C3;nJ%dbYyl zj=IxFtDWe#%E(-kxgq0gJ*6KdP~^g5qkag+KhkcPVV9>q_oquPJD)VCy%e zg=GF{mXQC(>m-cK>tl&Z9nMGFR}KH4cj2+duRqPWbfB+i2Fm|GiBfpelJSTGu}$Z8~aOmqK(m zMy+3}U7Rc257G^JYW(UG<2SL@*|c7%PBu2A;?#=7Me^@ux0DT0<*32yg65+Q9TDw6 zcON_O&qqJa$0^Hl`tgKxbX*))FLfXM4lUwXZrt~WSaCC(qK@xWbnW@X!ZUXIn?>Sk z+HJ7~fq_>u6qkq~jLRn0!D)`TP4u~E+*)V`5r409_uf#+Y5if!8l*@3etTlfp-cVH zlHLH@%G0)*nq!!!Vnju?j-r`{?XjRA<jYu+_o)V`Ik(rZ>cP zr+@cbW*3a17izr!JWYPRwSP@;sn%=>Su z3J(Pk?z|e_xB>^FFjeM^Ef|fv(3CJO&6UW@&xy*}1F3%l;das8VC^Ph+wJEZwZ&XWzr&+Q_)_k(`@1k4i6!v+6fmxEncxE7 z-rAv@iP_#9)3ZwnYkb`Qn6tunx!Tv!}(*D z1gp2<1o#c5b6X0@vwLs4!LO0h{sDui=B#Gc2`y6eW^#6NZPbGOa-1-qN9ptenZyt1 zqs8p6`x>ZbGYa&>^EPyB`l$Od=PycizMpX?UyKS z%=}dBlWcTsj2e(HgBaMM7C-W{<3}Hlc%Nu$d>ln`zZ46>(XbJ6GN@Kqans+kV$5b5 zwPB8;l4GtO%$MgEi~f9dg=>&IjCgK3cUqKLp6?lYkfWOI8N_biTWXELpS8E}m6n+3 zRs$&Qhj(TOFFn1sa20c?WFWi81ZwRTCfko;7eiu0o$!X*7mn(RZxej^x%zF@GMS3M zYJcxM`Rc0A_%1m?d23a_R}Vo5ee_5dPM;kq_86TWaI{~Q2`>y>ehJ$hcl;^IJQ5I&wPLEM_%BSn%eg-qs0kjqX|&HitFI?uU_)U_XNsI{ z82qmUcnx+9?4rJZ&CuN`B?1BhA_CG3-QA4>N=SzaB10=ul1fN-Bb|ea zfQs~hGy>9y3W!L&=i*+^dY`r4wcaoH{Xu5tigWhaXP^K7x3h9*(uzYICce^P6l#j_ zlYFlbpp%qeb$|na?G*9eneHzvf7_A>`!NbyqT?F#QNvVNL?DZ3>bzl7sz38Zq>=Wq z2>r$$y1XzF;I2!eV-jGT(4D4k$N_z396j6mJ6-JOgio1!5R!lOv`Z%g~$B7jJdHQT%IHGREsb7$pf8ducvC(NQ!A~SRmIVK0?2!SNQZSwAQzB zo{Sd-{+m>JDHR|M*$|sBzrngB;UN5t*a&h*houzg87^M=gE4b$i{vjJ87vy%%~0Xr zV|h2$xIs&XnFHKgPUk6`*r6SDAIYkpZnon~-bf!Yr;-e#(vGn-Dq;m(v!k`Ty@ml} z;jzc8xih+Ww}AHW(tl6X+tT@b@*zGGnTp?xC`3C;tG*grv~B)7R#yv`fe!b*k|Ga> z5$-*qY@UzbR4hZjTS+sf;g-@!1*UYS8!E-MX5KTN6PNnZNxK}i@Cbx8-Ab|j94DEZ zSC;tE*>^K^2U)cuX>^VDCuyvIW^RrZjk!r@8XvY*j`K zRaR_c^cYdmhv+xSvzicFUFZ|n#%dNVL&BzQ#+F+A55rLj;c`D>o}>v}Y{Dwry)w!m z~7rc;t;&6PWMIUU0mGx zo!-hEVr#AvkLwm!1VQ3OL(nKbRGi$vChV)ccN5wr)fYkM1ky)VDuu&0bzQ#=m_TO8ONd2@74 zh{OqX0QA&44Fjk%W#W_L?2lW#?TG(IR4q2JB4kR5`$B^@g%?Uddavm08TiAfZsuLiz$dtAKr=eIQSG1p#CbVG3p`}&j_ z!}qJKeq)TYQ4Xo^(`q(;Hld%bO-`6qQ*>FD{GbA zt=EF~QelSgtkUXiqeJqU90XnqOo-yKcpOhUA+%HL#H*!lTFXHm-Z# zzI3%4tEgeKR+6d1yZe)ZbBc%@9wv!pdi&3GekY4-FWx-!zfFvShMBtvt6avPH8kma zMTc1L9YQO>tum)uLj=hmE#kmH8Yusiz<=AeDak_3bpqM)u%t8X8zWkk}U#b?mOV=iv*@6n1%&h4L`oUxcT8&z}E>}#-VDiBh6fn zA5CHiv#_&N@NOp7{aGhf>8#S9=r8$Jsch>Z_;c5fFQ5G0j303a2Lt)hB9C8`KQ@sn z--~OwTH8nDygWM{b%Wlth7ba#z9)ZI89u+3oe9wvN_PObE5Lcsnp!&n%KlzZ$MphS zG9WXAt%SYcx=0i#+gzt&>$*O>Sxu#=f^yC8yP##iV}$?h!3)!4}N?_d+DR&yxPaVtJh z1u{1?BT%4BOirfplL5bK0))yrzTe&x!7l~?C17(X%yH=ebO4yGM*GtrxKg!wjD`su zVjG{mgIX%{WPingy74fEy+M6|fS70O)K1?0Z`;+5NVf1HGP&3CFMyhYO#cDbQQhY0 z{3H`)2b+PH0R<)vyXRuWH~c)JS=XV`YLgCOZ}l|)DG(E#0CDwufatmbL}Rdl=;80d zev+zm;Bp4`({nWigeS>+Mz?y4@=3vVqp~KK6-3-x$h^L=-{RJJknBm zRg>QEFGNqY%gD5G7(9ueRJvZD`yNjsC)C1=GHDoAo^IyOni3$SogJ5HeRPicVBS1@ z4T%9(OLP>o}b1cL4s>!le%nUlSD!1sHW zP+xCae239NfJGz!AY?GSz{hhftnvlA>Fc=Hp>qb7ZVt0VI7h7eSgrXljZzK;6ka^y zK2W?U`}o>}G52}Co;9^MahW_s`kRVDq=78sXOSQh`D=A@LdF#nu+bG;WA{UzCkFn1 z0-z89VJtja!3a^H#p%WcIG`}#T_~N{tQ{J076mqB@?+p_d)X>5o@J5E__*WqC5S$Y z>X_xCTDb4zjNyKUc@_t%q@VX{GUZ={iMa{t2fd6JOVjtSwbn4{(|N{*N@nzV#j%Nt zN`_i8>B3re_7A|}xq0*WH6#jxeVefU7U;`i=E{4Zza_7jhyk*G1mw~2Qx$$LXTO02 zIsl$ruY-1bfRuX=c#ppULrO2q{HwVhdIM`FF=#9?(x6a3L;o`7pz4pC2Zom8Ms!%; zl?7aR)7EsPG(5EekJhe@W1t_6!4sISnB|jaw~tQ;IGfQwb2xGKzlxp}%N#C7jmFk_ zaL3H`1Vugi{XMU#i9SL8OaizXg#oVYF>qa;y-fsO&;HEqRdWDO1auU9*uewaK33M& zmfsUxSSQ zthME3uj9cN>!yGRSqY20 zhzcP?#GS9X3@}rEGfmYT8h$fXNW%~2YTsa0hLolQAD-K>A4IM5<2Z~DjXi&+m^=JV zANi8M^qy_YoV508LqSwtgIhRiM5&iOh7rV&I=1kO{F~52+P<1_ziZ4%-|LKi+CzkBWrXA6{?c1iLk_W8vR?{EXV zlE}jc6wq)H4pu6IS=?+)N^ap;eqrBpK4K9ZiGG!{VNOic$Z<<{iJ5Z$F@F7>p4V@= zuGj;glQmYbI;GF3e(n6eb@VurHZ_Rv;h31qi&4Xani%zVBnKgpS zdK^Xrj9aM}sr1gOs1bTn28R&RXbsILuDVrmw;W=A?)<6Y`@g;8;zu-ZkbRCKAWrdz zwG%U-g|QVEh3)B2E{D25qQ2fT;~|-2XkNM6HYm$2I`+MO_=e4!sE^YrLih2mcq0fM zI$16X&Yj@2{L^*Iu8oDa!eiaKH=X_&4HLHzpcakm%H z49s*8p@qbbZZwC7$+*8+hFHzE9P9|zg$-Y5Hnb3MI0XMUo!P)utmc0e*GWR>gVkX# zcDOHi>-;SqT7=2{#+tXXym<7B0NT0;`;$@J$f(v@L?haLzY|IVT;KqmoC8wP%p=jFh z8aN4(eq2Zj{n8`pO#7tSWB1#ADZ_BX<#>vS#QD@!Hb7UzGGU~jf{@ZXnG&Z6sLMFOrq(Ep%UhQo9Iy4ZFo z1Yez9(c*0<`|xyI*Z^kHSE*)|WXjK_s@p>}72|O!SCdfa`*86v^V_uP{)g5nw^yLV zI@^RvxY}VgwTTG2;|i*!B(q4gX;B+yQ5vXx=EaR4DCB8#W!=xjv~`{s*h1CZb4b1@y?dh!XE-fUnB3v z)|rdZBjS1+oMx89{3`85bWWQh7m-Om1=5pdL;@|A5*oy|=W7Kz@os*jo?I>6N`8qV}Bzn=EUp8FS#Gp}ttxnA20s zp9DuTUwr^I5|mBd*`9Fkt{zh#8>qWG2Liik&EGUHHff#TO(~bhxgxLQQq9#7s5ubT0(+56!?fY7B;Ne2i)OX+WCZxn!L+A z$v7$tM(n6mHb!5QnVKzO!&OhMtpm;%1L*hG7;Boxv+g*C1f%<2T$*CJS|tJET^}7_ zQOS!3gtuc4q`ZlsTlc3HyX~y4V_^$30N=b6aUzCbGbR9M&;hIxbHWnPouC`(h0Tm| zd0Jp8&ay-G(=L~KF2lX`bL)Jl_PnskY;JQ5p&sg{Ma@BkQdHd<(&|5_T#QX>6kI;w0sPS5kd>Y1l& z_Oj(iV{zIlQOCJcmLp&eHMB5<-v3&U2N>wYl5zl<2$K-WuiS~faUB?q(8r`1Jab!B zC$dhqpI%9~hZaBMrs~f`rM^AYBj7+p-68J!#nWJ2Il}CZbo#Ze`ooRcB`brs{$ZP+ z)R0T@kc!?+F{pdUn$F^2!orZiktDEkWaZfz85S0B;tyyPJC`+3rv~K>6I{rv;)XQq z5d!u{cuP6UO-7Bi>-fjns-brC66O1YY&VLj zD6Y}k3R~OEy83tZs*zEHL|OMd3n_G{O%{qNigPQgX5RK{mLc%95lO$$B}XFH6f0tCPmyi$$G)hv2D-x;(li3@lNcdL<`@yKVA zp@;lkkXK@JcqkXLDUg^@5}r<>-)wP30D4Eju1jYAoqg;L*FT02z|PO+22ccGnO$+` z7G~-&SQK5eOZYc&W3cEZwA3K>AIiXZBLMb{2JU*!%avw?kYt)G=3x@C z{Nu-8yAjEVq6cx=pGa5q@&zZrR)-)a2xiO0Miw)ZFe8t3kOmA64`TSyN8)Q|pP|zs+@QLqq`KBtkZw~Jv z2#JYjmEHr~kNk!PS{Q*;rziK9OSj+-n6>#RtA?_$NsfOwn8%(!qu(i8m5SM10o7Jn z{n?vn82wPJn;iqAe}F$Sa%SfPfU@oZ#@J1$Fl{|_ORQ=Z|fG3{3|l z>DMrU{d0!cwTs6Pkj7lTYf_5rt87G`;&i9z15_Cl`29)SATsi39B2kK$C#SLWftI#0r zBnR)@9>m+e1oi|_H(mw<3LgUIZ~~a#w%f8y{xqLZf%2P-BFJ{`ctW4Wz^c3MAV#nu z?nXP;#){TtXw!q`C|=+@xHaB_i>U?H=lcMO2psTX03-n*Z($o_C4E5;W9#NW7!wf+ zp_qzG3l1sg?j{skfmHr8`8-cNxY1CsdKQ+HH~>=qLjY?AaB*R{=mosV7mNi^$$eRU z0N^tPfU#g%MGvzNz!FptIREcQHw8c!0q=STnH|ERvTskq<+%CL4|%lZ+n2hdrH$9CHVKddfnarTKTV@9?sML`-KMj#P`Ix2?H~ley!dvRFn}q>DJjVW`0Vch zpaG|SjvQSaE-h||%*2?y6ZpndB$_bwI*4EYyfHHxJL@-1gK-&-y_`RDT?Kvy0 zUh-+(15d*q)Vt3d0RQUEy`c}F=+7zl1E4S!0|LYWrssR9ZQq99TSpPRV34^GM)N)X z0a%R3@^*-)eF$DrIHe9O0;3wP-5K-KX=-WZO%gmA`I32y!VUo0j3-MgD#AGk`v-_T zuo=n8;h+FmJM^`|g$5?80qmiQEEddUPQblCH_+FoJn&_5@V;Ayu*UAub>>6kta<+| zbcj*LQtpbSq@(!j{SPpG8GPU6n>TN6uF3x2Dsa6n z6T3rY_%r0NxiZ4$_k0K>``sH^j>|FeFFLzV!3s05eCCz}!mjn~b5y0NoBsEq5`eD) z1if-MfUx;r-ghy8%ToFx|KvmhwAAq);7&hEc$QBH>GP+;rzHSLPW?+JPL<~1B`C%{ ztzxUiM(&<0E$5uEBKkWJIg9vyWi}#k_;B?;9}AdnaCr#ojwd;v97RBh9p<>*y!-j- zCfw+Q=Bn<0kO)9M1F(o2P9IYee*-=T+z$n&EuJL+-X<;hbIk5s`y)gEDz>C-6S-;699*Z4}ka_3P`S;e0)Uo&+*`Z1;+|dyjKaX`u~=N z9|=-81Sgb*WyqA!MTN}H6PlMJ`q7`M{ItCcoAise$_>EwI6XVpMfBT2j zG4{aul-$_cSt-g|ujo(K||;pLz9fNu-KPA0s!Rd~jbRp?!`zV3%{`M?Y%<`vemS}Rp;$L^(-hhIoh&zaa;(UIGZ8+M{Kf|D z0wf~9e=$RgU?EaS7A5d6?99)%v)I zE=nH`ot9wj1i2!En_y$$Pr66zh6SFB+gs=9Vw{w`#6qY%xT=Y*=Lo)GAPFvb^=uSjpg`yS4dCbyQ8cx<&{`-SzsGruI1X~Vr0xTgakDP^J&R84% z0>+Df*Pw;8OlJOURsF(8OWr;_|Bj^mV1B(1zKDB18BjW&esi8(4#3I%+jz3ug7G%U zEgrcDNN`EUK{k18+va>S>JFJNH-P=EXl5V}sj@^_Kf|9-Uxx4W=2tSnd9glU8$5F& zCrFvbcqb$?t2g^w0={w};l-B#n_1ds)4fgpKf~@{S{9etuI9Qp{jdkG84oV`9LRV` z>mdG#_$T3}c;Gy-Rh?;XRHj8IcMqSQjD@iS`JRm>=(GazUZ#0skof(U7(~zDua9p0 zRj@c*SwI5{P5{pm!1S7_YPDxOV|v8l4~I`{*M4QhDP36%3|q|6%tS8dNsd z5dmE^C$l&?qdSYfI84gyJsMxToA&9zhJg*%mYWZK6D6qk@7kFK8@@KyN9&?D*5wv)@a4Q1|I*Wf_|Tbt`%_ufWw6rifUL#&^eXddf+ptL_? zX*+*shb~w^X4)1HMQ2lRIY!!=?GKN``3B-*K+tQ6RUP1y2@NPJj|uE$zIsmr897erC=U4*u)A4aLZVX1 zfwj_jCo>U`^d<7M1#?%w(*AG;N(cfe8Wk+}#{Oh}9y(fuUM&8HGlWd~Jso0G!sKP; z(oDWE-Blzomd-`=zeG_MH(mJ8| z!v}pE=EsSLc9YA6_`??if(pJZsk9BQs^;HxmRzgIG=7Z!^qHHLE21@K_trxkOe{Gu z)X0a<3gH&{aEyQE4kDLC*rif={8E~-TkNQ>QYJ|K2e@9+(+}LOWOEPiZZPW(yB{we z#xX(4X1Q^|{QBRslZr3O2m>OMJ?~)ro%!3YY6?%sNL$=Rb+!VaVq&RzDnu?99#RWT zh>OCiKZ_Ed(^XJH3}y^1@iCTZs2+mNc;<4 zFW6yJL#4wMGw-`KlKzabd&AQx5O}J82#*S}LH4|PGvlG5eS%{9(=OqVuhahIDjWlY zVPQsHJYWZvS@_>M0ycEw`ptO#VLB3xd_`)zOnN&7jZHLW*+bf$C|!~iEpRN53o@1# z}x;ChsQO==3b*^!La;L;7J#2l`8 zeHy{IbhGrSH?R*bKFXd>S2|DdaJ%Y9(KR#usMf{Q?w(g3cPMg-w5 zg6A{vSG3xh@XK&M9e6?)Ct!_nTqEM1y_vimTAK`WzxSCMY-{VdjwgRP{RVFP?aIde zR!?GcFT-vHb{l@^*@r1+A~et21~KqL4B@wa=V}aU;z{nh8fKml9Q9<&=U+}XDz4ro z++n6B(<0j$N8r|n0HZEX4ASJMYZA_yTT)r=yD`lL1t6~naT);cqv0udAIQM}(g9I> zsI`xr&dvwLbbJYBoX!)=Zvhaw5{LTln)Bax&u0SywPyq%(m>|kf9@*orfXC+abZ9hIi znw+^LM!}W3g}M6oFB8&QUxcn?_`+4bdmG??F-D}g7i?Pr*2;Y=D;J}(BniVCPkEuH zY1FxVbZBvelaDK6Y*gHX`A0)-Ns){Fv&nPNy^?G9@kd6IRbhh~IbZIb(xrgmwzhFZ z-oKNkXr5W6F^%mY(4*V1Hc3PUqR;ZoG3z=&8{LAIZ9C^g{OgWn9{f ze(7`|4ZRK*hXr1ak*0XyeKrx5Eguttc8a@o0$A^edfo~P>DPU9G^+eHY zdA}cN#OQ_K_?zPEx8aq_l3MRG5WnXf;llY&?5R>Mesm+~3Z73F9}L5AXNGtjRoF_z zxqWUrgENpX&$~h{gAvFHcYC0>7bp<0^0B?&W4CH+|EU7vvhUYk>?jFML1N~i`%hX| zStUU+dZ?yK?x=+qnO44d5DZ*s#~f`35?1pe=E>Sd*f8n+8$Akxg`faH0VfoyGD5kB zgjLUtT&?66`ke5doRH8tlDH}9`e4`<#rG}#)YtM1(2#y_52hE~ect|i0I5M)brU0-fP+N*+QV^MF;mr;k;?`g06 zHY5S(hsF=R9|y1eemsWpR|A5ul*ZpWYR{3Z1nAF8U~C$sdb(N2w1zds`C6>|wj0B)#VEgS`{_~ubX9yf*e*{^3w)1ScbqjTXR?uLwGYLxIWgB=Ja9~H z_+7WG;7|nOXybK`RrO)h!MpT{&-dkxlmKy1;*g68!4bix6M67gKlPVxNYXLZ$b3n% zl0AC-7iXxrG4Q))ZlK-DZ!jz;y{1u?3u{IXUV7Y&#sk#C8{5kjI(b;p3@#2gTqj(3 zL|)wQXH$wPW`w)z{h{9`XXH6buiCMt4Vc^wzw`BG!JG>HXxlf((A?d)LMuD^8);7> zU2sCF7?7uWYujMMIkdbG7JJ|Xq>p_JT0hksZs-RQf}AGrO+mEyVSkRk)^)zt#*b}zy3206JQpuWoEo$)4(x!7zgzAs z)K`-{!lmlDwQLQ(P)GWa9xcm_fr^cv1Cp+M* z-#Q-^bpFBc^qK}H@A~@LQyAIZKDc{XPpK7ki`OS;Uk|MF8#(hhR4Pl$un zD0YsXg#wlWZtLWMZ$iS0qv_+PHi3Z=aS!P#ix>W)kQRy@TR+?VWBEkKuC9M^BTxEC zY1`Vdyh6&by}x1&xiL!xtczhQltlyAkW?Ej043@$qv`HM@&?vl6Ae?&qoD$D|=pW|K(8yZBb&A0=4bEV$@A&LyE-o|T3E_vAJU)E?m20T2 z)SFuYLGPX~gcm%PcS6YO+K+t_{qUp&Kj3_i%G$Ui|LJYwb`lGg*D!s_aehdU9L^}_ zl>VHMePrB{!M0&1&zU}<+3k><38QN`L-;&Gq_RU!1+KGR(qV=BB^&l`HhZ)}&>JQ6 zyDJz8XCXsvwM6S?nu0@lg6K#1_EHE@mJ;{*;#sCZn*@^K_bovh46Y55c?MA)k|hTG zU_|uZRt9G#4vUn(luEt(lN;2LlOk z=*N(dRVTC}GIlI)5^>;rwTs}%;}^vi|FVg#52b`1Rh>!b*!J}G`ngeE%LcC55%_}o{(7ohJ`Jo*B;ngq&aWwFA)Z zhoCha$Axxtq4&zYN)k!!7ysb*Ef`Yp@5*=No1DT$L283sQ=!2iqnN}8SP~eLVN)(m>SCWo8SCF zzHqcfhsXu`YEUW<`}zi_^X>oTsVe)EWe(zl6UP1h{ikaeeISZ+DLw?!wqJfM4tAkc zp85#Y`Gv_?`HFn*(9QCdLt0FsG?R^tl#6?t#jquDdY+@~));c{Xo>hrUvswlw>PbuC?^{&s z!VsiQev6i>IOV{VyHXbshb5dTe#DZ}xeX3I)zA_B=XrdqBBIkRlo2=Hyo+;JAv6Ey zMi+1Vio=IvY86PHr)=TIP8ZyG_~6d;(j)f~K#M0W7+F6DhcsJn4MecIKyieq$lS>T z3&i}Njk8j%QlDGpTVF#9JFr7IrNrjcmkHTkvU)fhFNGZRJBfg$!I*hx=_XECGJpJ) zDvj8i1%qU%oWE*JvSau|WpB`iO_8^ zBy$nnjlQ%=k3>~zB9iCGDzs2B)d$_(ZiBifhNBP>=6$G3zwYMi-s`b|{L95sDVjIB zjye~WrS)NQ)h1`Dx^d;I3Qbca^%hGfCr&9i=<)vcJ{L)Dr_cw)?4Z04fYp8AF~lUF5vgsyx?%B)cHb3Pm7Tj)2)S_H^stgvKh9Z3^g)zs&MxvsoAgKwQWRwBor9nz6uL*S|0Q8;fqe#9jgrf*hR4s&|jHm)g`*tg!8rFj@9#$A+*7`;6Wc=?m#6A>=rD@%*UI<)>U4yj9H#eCY}s zr=8pysK}oARYdN@Mo&#Dk1_LhZM#apBdXr?S>0d0^_&mq7H`%8I{BRm&$va_?eGrc zY~qQ#1fR)oB{fvtHyV&q27VL7BH;RiHZ@USrHIFmTFbtD`}T#M(g8##lB1$R#6jvR zqht98bm+T9yGFAIv=VP*cwFEPc~KX|u6#aaD8WO}ajhIAs9EAwTk zLH_j0(<$e+n-a6gfHd)Mjs>h18qAJ7{2YkVW{J8t4OGlUNDGY)p^V1rju*vG-Xw|M zK95_UARf1}5uO5FTKGHfkb!(EYzC1vOU7bFVSKKc)BMdm4zGwTV5MTPR(g)t)eEy+ zQ9bvYy^Zy;N55^SV8T09ck_Hf=x4nY-b-Vq;r?DsU>BpaBO7nBk5|KoQNf@MF;B!5 z4eHo{2kJp2otg-c{CuVQ>sI=vWzp-o!kFVTW^Msp1dmz-y=3+x__5WvfR&PsT(fI% zSHJXu#MHvb8KvicAGt|mnZpMoPp`)5^U)5g@j}T1j{5zMrDDIOFx7BzO%^nY(cOj0 z51~WVHan1Ps@XTRdgp%$)6OO(Iwa=eDar5IRLt%r8fPc?*lcv@IV)Bd*XxpZ=SA8f z4f(rozc8G7q1r{!)=#Te!?pJzAH03OSHe?syq*oc`zO`*J}r5_bSIg2JY;@t$eo-m zbT1b9t8s`EJxnE*#5IWMp_fafQ6X}Q6JO7)s{1WF^|yS>nUtr z=Z-r%M0qI%#uTA zd`rEC9uGwqG4me3;P;{9mooEvCpd7sIyJFGJ96F{VUQQeWyWc61vx>$aSe#6yN#Y) znz2`*z(*S{HLvv>+65P~HhH;&rU(?8W>B0^^6@O!Q_!@R*hElV!m7mlsnq9O?~-gd7_&vZtHrKl@?tW ze=BLYW=HUOR5nH7hnDQTF{E?S9U;h@gp)LYp@CmgX4>y5u^?_b&O#0@HXYH#^J&R3 zj6_pSmezxWLnE=hijt05f(AglGUF@79^{m%*^w}U7nxlYN6BsP9KgAoB}og?PO-aJ z$;}A5x&z~orseTw! z;nU(3X{+qsXF6(bbwAYwyW|aL1k<_Sk3Ewji67VR?lzA}YZLi2Hwlh!+ERKqdcKUR zvXqNBJZMD(eToYXpil>IqH|T%Jev(f-QcTnc`$v!Swi>pkaK6KLVs+RjmToY@zFD9 z$_6jzH%q!~P_xh{d7Dh@PBOkU8p;*smJc?U{^i=-<+zc+EZuk1IBkR6cjcDZq@5Cb zbu>o4_%|D))gF4@Oe8FYXze3!tfJ0WBzd)n{$NO)`i3ojC3MdjiSWu-eWqDZFmr-f z@+0wj^v0(#IVGZ%Rm3^lpBAZ?>qIif9l?u2mM;HMKN2IrD8_xrCD5pF`Jd(3H5)Ix<)GQx}Eu= zG?W)fP@&!9HdEP{aynL`)}?<_NI^Ngm+sedGoHZ2;Mn?*qEn#=q8sAIY04Q$-H*?9 z9_3;d1l3cB5(oC2OqiP{3BvmC+}u01C33YQyYF)4cE3EshbLpVzewT~XARUACy-eB zzAQB9`L?etP`K_I&t7Pgfl=RCvy z7a+`o=B}?rlyYkB&?ytaQ>7&`S6p>uw1Q81{;P!tC?Ibs(w7i$AD9+yP9%PE94-e~ zx)ljqw+-JauKPk1njLPHk1f)+9RLzg%uxDQdtS&8eklyS{8cZ~8s8v)6?ZOljvGqUH}s6ON=(c*y1dXX=dIoC2$G1% zk&Zg9 zwD*tb_Mg!d0ZU*hgc^US8(%XpTsS56l~Q_CzzPmt`BB}t0Q*hZKO&~z97M&#)Jq^7 z)qS#bYA|UWAWD{f7?-N3d;Ws0s%bdQO6Zck!1LCH*8{szyaqH*?5%xKl{7g>$d$kj zuTcnbU}|QcGv_QpiZW!QTsFO*#FdBL-oKu-U~?B0J{TujMapn*@{V)TB?bn4)SFFZ zYUM|MJ=LasYN-QMqLIwkd7>}zM zwv(7loWZqir0w$;&@I-hWjYqOQRF_Au5CR%e&(f_=gj)IYacw%8LVERQqC%EMDe9J zS6H+v>h>B}`oi%jf=dHruXzUiVP_5ofs;(x_t!*gc{Qhu?qbe}X~<1q)x9Yk>GpJa zu)OuV*o03JYhJ`%I^yh`SBll7>jK?tbmEVv!?^P1H^Z7N@LW^}n0e=TBn}=qf0kzm zY@`lIUmX0ba??3f+(uoC@LUbFTUL5fPHtL)&WWFNP}5M#`G{|tnGG_| z7bBY8-PnuVF>BVgH2LBIe%(+2vER|g*}uS(qW@5Uvj*%Qu&6N+oY8|)5lP;sn^DZ} zLgSg)x6j|Ce{xjU(_elV#}xI^LG<9-^Rt|?2|mpCeO%9mT~W@06)gyLF#HH@y+I*! zso->IU>>zaN%N+F?Rmn$Zs_1nsBIDY)0I0V&FXhP4zrkxTm@$xbRR>FZa8pN37$Bb zJu;p=z*Ed_WfNj1Pk_KK$5ci3Cj@$jh;iN`g1lPz8%C`zr(d?Hh-r&^YIr$XjqEiTaaxRuY+k*n0e*zKKO-uGE zx)e1y+m0+yz0mE3*4q!B4@dsh)2%7S(vzh%ofZjbP{+7dC35_}H!*tPN;_duFy!T* z2Qm{Oh1etZC-tVl)244=N?O7%R_vCU?a`vbx6a^oci=piGOMz|ykD<+A1ebtM5;^q0qY? z&70(=O|S7%2AnfQ<|8@8)1eYIv>L6!l3;}MYXnPLHZBvIKe<3jL=oJN5psb!nTEJk zV4Wf&F1oB_iR>PE#H>|T(yP**S?`A6MYZk}g(R-?l!c$nTJ81dfOK@h#N89?akNru z@yj#ehE|#RoaXpJ7LB9`uw9;-Q>>`+e%!#1M?8Aq6{Nh)?@nrY{`C^mj)(CjKwWAM zVYiDjM5J>Zlzsg55CEh7pGiHZ@nL!!5S9+M0s}6xW>zn^Q*7=ZKfkI`0bZj*V_DGY zs6UC|pGUtpu6suGy7rFXCxpzIxN)gF*GlAhP@nKw-z`k7!GXrf+c-;;OlwTvG7pN@ zHj=CNLxy*@nVw?CyFE3J%{(Kw*PjermM39)#;nc$8V@>hH1mtgKj6nJ*NJb@l?G{s zG8J!CiGW@}5>H{MPnhbnvyDIq^TJiD-Oi{Wv7jrwgdQZ4COia5qM>ymLAlHx3UBwa zlw&`V*v5E`w8%K8_@szUpN<_`JhL=r+$p`k+`a0Wj3dul^DaI~75r0e`)9O{+LpdG z!y{JpbYzwTFJyA+xQ>Np?c|A(my^%?Q*F-qAPn)=;El4u8Fg2Zz7gm^) zamW)Wy=xZC2b`Y%V}H;IPOU1(TJfkRc+`d)41F~$={7%q5wCJ9ZHcmoIbE0ATBrD&airw}^ot=4Tc(9V7nrnC`+urRq&TO{3XkHIrqRN%G1rk?YJ)_-PJ$q ziB5A92Y{P}O0E2g=m!rl(;|A8o^45?GC$$;FJ6b3vgn>9tWZhLyDai{Rb!neh|O7F zlkcROx&^%5_PR3Cex^ss{Wv6|K7=8Dkc4Oogv=1k*~F9SP2H*#rOV07>Zz^0bxiIJ zIlnc+S^ep+f|P_s!sR`7`9OGjmNBtf%{GP{L?}uXB6)^e_V@TqCXefbz*zmIda3Dk zX&(i6=+pM$szs=Lxq%wQ3J9Rah+%4In zQU))~>hzsBy;Lf)@%z!4_vFk^Q?KCIk=>|?4TZb;#Wp6EbzQ~1d>rkOhx8!H21^&% zAopX<1z&Ix(WwThkKjOs>&B&x5@i-{*Q&(YG#?d^i7;7K?iw+mws@PtVTWeGhP^Lj`Nug00j3EWEfZ` zY6pbxOYQ2#KhmoHGuL03k0VC}WE56GFhvLZ(uqx7+twAA{DA{4767XT4TkKwOQCgzpRS*pM7x?6S~#Z~WU4ltS|)LkkG zf=aT#*hB9N%&i)~1$_b(x{*wsB-~+{>_VF00^PR3&bN*{^Qk8{nrH`VJX$fu8NkvWyk1kL>3p*A2OzQc^orZZPEFiX_2x3E*7V?@_Pg{p<&t|qMw#u zz!OJ|WKPqB+Sa2E&5GDG7Uw+DS@y(N*=A?Y9Mx8@{U4$G(9`&X@~GX5sgaE7zYI!8 z!aOT9zd_Vu$3zl!P+*Pk%Po%Mq7$LOzNR2Z|G}BM^rkdPQLzykk%|S@z-%N%vTi_C z+$>5&mt4ez(M~I8P&y@awRCa?H?QA9z-(_V;RoJwi!b>!cRa}#DMBgP!P{<9mR&Wq zj841n&S9dg@e~PTI4|BYm|A1D)XCBJ{CHS2$MXc5#&N^oF>vrt#k#E0PgV zAoNbfrkt54LF2m6q3Sag?F&wjN@QTXVZ@W0CYIi+iOLXFv^TTd#Bq#;0q=Nh98;}qYYd?ct&TG;;@1QRIS4_$OeZMe_p-DI6 zud)1J?ik7pP)>L2vIt$}Li#t?qQ4Qpmd%fKyW4CUrH>xezUxPNlh?!`NJ(|hHKObx z)*-LeksG;pds~x7_WQ@nexWZ?;2~6mvO-U9TeTcsa+)l4bU$Ryl%Dl__$R0tOl%d&rOhralm|sPY#M4n=CRzD5jV9YOmY2~w z16YQ|o=@lQj%m%#tH6~oTihFsud!HFvPSfc;7a zb20FypO(PIX`SB7nY`PihEKfF5h#&De*OV#T8xdulur zC6Dh81qm|l1Or9~VYw5V{$mC8scdhv1D%qvzEi;`zu}ic7p!cclID!gn=+K%;G9co z8DvJ6klF9us7#{N9>)$h5zloXV^939KsJXhorYnyf$HPyO34B7pMHPVmqtWxNEg|- zAWe{mioBXd4*zIq6s4Kt$}RRGfj)OJUMsZvMhtpC)BU+Hy|*~~R~8YyJnozB^uUYD zxT{~zh^Azjo-MwJH-G)@G-Z?yKj=qeN*W=NozSQAIq%)hA{RrudfWJ{p%a2lrYd8s z)RMWn`Z47(yOf7f+=WrXE2OQENSM&(au9=)mQpeuXGlv`i+wr?gI9%(RwKKJmQXVy z@O_v>Ue%05QP0pz`+j52@Y~7+54N$?~71 z^nCkzlhelZSe?3C#@|%2()lS!4iH4-?o|e$WtXVR2UR3$uqbK=2_kYoU1X(my3i_br#OlqAU>I!+p&$qJ>P`{XPlyNJd* z6(8J$wY^^qX-3aoU%|32PGWaw7r|W!kVEawMV?vQ&E+{!BUzfGU2eU+R7I^9V@N<` zr3PF8=%iQpyeYg|6pO(69BSW)Y75JgL}qpxR$avRJ)dU9t4DCn;{^-qrM0L;56X(o z428&W?xszSBgh<(ZBzMzNi8qWv>Z2 z(f-I@e?PeEcqnz8BpOVaNvkZ9HDs6rmQARr=BG~mH`ZfFL>phU!n?WvPP@sDkCH?< z58XwW*7m%3Qq!1{IM44?RI;Y5b~gSCZ;$27ux4a8Iv4Pcqfei`f0=%~+XN>0it1bw(k^~j$}+>RA`b1EFhMAbE=Ot|NA0AsAC*ga3gZ&)kBPr^aO@xI zS4J6cE9P>p1A0Q>#EL9* zkgO_MSrI>7@3#%Fd<$0Ej^T?es3l!;4Wm2Ym0VMxPHCi<5r1UnYWwM)DgL}3J#&A& zQaQtz{?Zo)KY%42XzcH;$^BO7ex8?8_5r-6iFAWA;zQKw{@ab#17p^BE)AA~P|1dP zQ<`t$qf4{|(c6}=2Z$7lYxv#Pb4Z`W5V~sIjuNFJLtpL<&E8%)r4#>v<~7m zjR4-55p)?y&?qe*K}(;o+KT}j0qD+j#9vY2-YYkk0Tkpx#aAfZmZ5Y0SC;)jY+bCk zB6piCkM|EbEp7&49GZ>qu&}dGaYHgPd>Fk}3zDCo;FH_Wa5+W7ciR!HUhn{b_D(ek zBIVZ_mN8xT=!jJA`r1XwDPWZn_&<33jvswvvzoMw{L%DwfYIWx(loLd50j2SideZ3 zZCsML`1OljQc;Fp*4=W#TvctC7$sHX;Y?#(`;Zm*1SQ2sL7kovuYR%lkg^s3R2ye;spC;xjOBS7*t_@>tG%*7&P@(u~KnvBTbJjRcN(+sRU-Vm{Sop+MJWQwW@M zO@Ef2{X%043$}`it)@)v-+@4<5hVQ)Cw^u+?`&I*QOCEKRHafJ@uQR2;Zf@F@8mbD zr--HPsa?0EytfW$gM0@OMP6Ud&3P(n?y}Lm(SqHA&M=YIE|WSH$^zNloiO|7Y`B`3se@9wBv)E zG}wc#Cy?%t5yX~z)Lv#ocF80*>{Jb7pY??~-T^^fP7!ja1#VN;jFs6QvgPo?8+e9{ zG2iB%t5Mw9M@|>b&u{LA^9^3*$f$pXtCLZ4dFMj$A|p^vk&EtgJ1$H6zfX>3m;4el z^gcXqfRBqPq$e9g!kChEmj+!ff-A-hA;(aWbT&i)UCKf4gJjXPBGzQ}H`Wz)%$Am( z0oFhKsnd(A#FQ~3I0PS|*c;#hHp63dHcd-5*@?j5ywf4By^Q7SyH>r~&?&xsCWV5L znV+ivtCUN`mZappYyHR_F$5KFovL6$1;Gt&NcMPD60qw2Q0i#t=?4Wk!Y-} zDlS!?hqLLk>;RwRrs%lzeS@2j-EaI1{R2@noS&r;n_UZHFU9sw{+3~hlQ@D+O z>~~s>hOTad@1%|tzN>-xvzOCEcD9oc^)uA?o445q7$-WVlo86Z0%lI%eQhCI9L|E*lnt>SK_E`8p9?V5CXP6tU@`{`(JX3t9k`*X;^7 zUXIfT(fB=E8dh|v?$*M{o+INvHBs` zPK}3`wKAAS^uem4SBpEoT+eglZBiQjJ_1xghK#v+>4ELcGVM{Pi?1v#U$cy$Z*t5PL$9cs}?UPUG<8$-4kEdnCf z@|g$xE#q-G?w}TyFo2l52LnQkiR4;8AGo1Wi)3Bfo zr-)j6bO9N9K@X`w(VPN+yi@thMzU{!XJAT3K6)vuz$NwxJLry>-f%{h=Q{VE5J(c!mU4`}6Uu?7pd$SYwZ36w&;1-tKBjOAUR36+csdur zC@W2=LY#2-?xJQ?gzBq`!hekAZ6f6H6d6OCNgKq?^VXC};w-Mp z^M59^FQP|L#FTcbCW$5Of7xsmZRqiiu4N#Qv^4$xd%c$UEhN7hunO04Hzj#2I3=1+ zny5^|eEhAy1)PS@*eo-0q zVb$rmlqEqJ=`8Q+7!4Yy4Wjv$AY>O%Q6?8XN)#DWv`8MBL3xlG(xXq6F*M27U;D;~ z7VMT}`O$Io$Hz}bPG5_r1>^S?=!;W|&%31Z9r{{nV9$>dzq#cZSDL0O76e58=PLvT zAb5jXl-@$#Y*dU+i-rk|VA5$3#@K1(o%bg%oLBaQz+c@8!8wSvAo6) zdyJD!ETu?y^VZ5iy7KAJ&pKPJXDxJ2P${n-JanfZ7k+3=~;)~ zVbTt1;tpYC#`3(6CT;qdXfBkeAEpE(tl1~3KfVEqD*?mO5JT4J;2qTkF&o~~y_eV1 z;m+I>7L;p|+xJY~`EYOH(M*l$eNr}EGjs`vIK%;NIrf6lj7IRkG&@5gISao{vk)?vT~QZo2uYMtCUk7Xq=AJ(M=nMdhvTz2ZJWDS_vXR--q8 zmLkbk>TpjZEzM)L>Ps!pj|9}5KQT#|eB^D@5?mGvSa4usKhpD5wg`U_f3F=ZA;V0) z&>@}uVnePhvdOn6vsv7Fw!)yps~$Jkkj#dqXIPR+M-089Ivs3`wwbHY!>RE8fGBkt zhPSRIvB3HI{CJI@-38WeIed^x$SHt@hKdquSX(t;jT6H++wsPt%o{LTEmch1u~NJX z7qFlKPW+wXiTLSP4~@n|S+0RHR?wdYM+zxd=wO&`Zbap=bBYWRv=JOXibe#_CUDv= zOA9M%05wH@QrVY&W6h_Qq{d6kIu51F)bVcH)8$0x<)neI@w$EV>8yE9;(j2$sdWF1 zGZ9i&HWpi7xUdc9V2#Ja-DADAj>WayL!h7v)<_CB?<$vs?*&Q`;>=gHw)}DH-HreL zHd>Z5bEU5abvp)$ax9=xFnexa@CnCg!3Z~5U>0=Lvfqk+ zbN)`2Gx}pJ;j`~arD^ZCo3qehQh#cZ5G^`{K_o4&Z|e% z#~?0Rf-YD06^-m6ycZubh12ROd}%C{%5M)jVBAw~>_3ydUKq`-=JuePkXYITv<9zW z$jh~3QaM4lV+E=6Tf)o~tMUp1Y=SFC^WcwF*w^+>*T&itrjgGAX5YB{BGe-8xSJP6 z9;f6cTOSB(>6#+oai2IEZggO%Jq?&fMq36=4;b5r+}B*X9048v%Y-*>APXn%o{zzh zti~96vp5QSnPDInJ9yv-Mxtdw%o1&skYH$PNyzNU?#WN4+-ybG?#vv!{Y~yTiz6)?jMepDOyml67IKRM2&1yN z)dvRwk)Ov9M0k7oc{s%Rmxl-ht7GfsxRM`2Yk8htE%4AHLPg%8x7h5@ZyFE& zkk~@oll>74r>H(@k^gxn?F_h04_76taKAy!Sf3wXuP4q1+JG?|cB!tYp@tG-@f)ib zPM{)!9?@=V-&<(KX%^h^q8{4(exR`LLFnxo)I1%1`E+PL=o=$B3DMwz7(}Kig4`vb zZC^yji*nrC%+*yDco@_~anwHCuL$uhOyGP-e5EBK3ce_#y1l%@MU8Y7y0gE6T6eQ2 z1?{Dqn?cuo*z@HmbWxhl<-OG2-F+DR{o(pMzD<6tAXn zw1pE?L@2B7HF-U+T+9=Do@NpA))d%i>F-q&L`c0Dw%(6LDy^}+56za}tp%ECrtQ_l z&-f{+$49p&x1TSSc4SP7e$ukIfYv+{?MH1^r`-KjaS&~@!wbnOV)@4XhN_H9!5;53 zlr9y*$Axvm&AjL5r|r%U3>;_^0+FVv`-t7fY?GL>vcD50=i$6I$w$2~Zf-?QiGwFG zCEte^0G9GsB*yXt<-OcqX#3ryQN3+eyPb%azW;RmRmo=;4TN5n0LLVKn~$Q{O#rII zX;_Y7YwO5zTT1e@VYRdy$Cx=&Xb`9i+j4#Q$qfh*Mh zoAw5{x3ThP{%9itPiYAuF)S^=mn0Ri0(|)98yN-GiT?aIV-W7i6RMaP&@LWxn&a7n z3Wtf%mAflubAs}T@mNkWDn%o8?9dVJy=mx$#t8}~<;sZscHPyOL-_4wklHepij*-E z{_e(!-vyJ1iOGkqA1~DL<MvK6?cE}q*1^BKwnZM&u|M$ z0!P|*y{cM&rHBi#(x!XUL(mOZRLRP`{@#B`W9@Ic7E_#YJ27-NfAR9*5bVr$w~4++ z!MoO()mcuOykRZ~xb%#`?^Ho9*5JzXFQvcR#q)7@gGE@Z-?u;9uCBPRL%gr;k$IX0V`XLFL3M&Z0_`J?o6d6wRQ&z!z2|XtvgckV z?p0pH$X+-8P7<48_Y@!szk|FRqBHq@eobiEvkGynKMy3mMU4WrN&vQ-k?7ukuXmG@ z+PKFDk>^8S1vZTmG&3UzGQD~yGXxP%pT&?G<*KPJkE8-@w?O_B#erybtlSX4FoVjcaPIE2TwR$(f%jolR^u z{c~x;-Gc}u@z|NfoN;Xq5YEe}Zl-plVn_CYmTNnp>w;3UNLbx&O6{~&C+FSinmj!8 zAM5B#`|nE7CIn=U6e8fkx6o~0c!Ou)@*BYwfexQ>s^b2Hu8RK9J@f5`MY7M%UW>B( zK+)pM6?BfnLTPtFLQga_Hya_DAp=8_)OevIE^kAiVx*X%qKYLYoj_YJc+71qe)F3U ziHgN9bb&VOQ~fde+ZDHW)HZ&4c>tUt`0*+zk9JZVS0FB{<3sFBqc3 zHX2&P#t!`%Ej+zLpGCc2>r^`wf-B5`(1$clB6xv9_zmW7kP=W!4aY`K5GmZaGwnTw z6(&0@WyO@RTW_jt;*?dgszxN3V}%e5xqpk%r+2jypoK_BwvaCOfI1QP`D5DAhUFsA zUNFJtIqPfA?{cC=aK(YbQDMGSGe6R|$2g5G4cc@4)fH}d;TnM4kBo}Dr0tHP(c<&U z0YDME9QD!c-Ep9)N{y&;vv9e-tP^u_*z4gDONX*&1^U0s-07F#4xaM#f$*W8bwd$_ zB$b`rp2V?@j#p#+S9@8*k2H5r?cV&?du30Xvo{!0Vu9A}QGJ;VF(W?*4`Pc4h_gqG zvwBELCwZU6QE$W+-KhPSA=yJL4-x2{OWJLK^P<7s?dP!sr5{la{gfFIcb5CVk5~Z{ zlS~AJ8Pj6l0c%kOtYSX)hfhUJK|?{Y_*0miUz3!v`7%|BkMMvlv9OMt2cG?(HG_9H zqkfp1)eB~?&}B&elvQ4PFB9zv@63|V;_;Avw7(QY#b6F=>B;Wqn&8aj_nJX&EaXGN zR~5ARSCJU}Q@2wnu8-<$b#ddmJc(da{m0vbmbvD$Qj|%ifNj{m`?5w&{L+K_v)wi( zT{}zvVBnF%ae`C^5Ki0ap}?(lL}IDxsI-Gh_41`#c≻8eQ25o<#Mx?Uw}M>_j_t zI(MVi+v}uSP}5QN8VY}D@ja@}<^y`vX$c zks$iGQL^f0H)PIMU0S-r7K5v}W;M6i^DjWD+y1_%JKcnfF$V%Ft?B0MLG+nNj~p-% z0$&QC|M4m6G&j1T*YJnu=s%5HatK|o-#VdVUKi_L}_-nHPd*XOeuesvlI_?g#&uUjj zM%DDRAcFU`BJ!x0LK;p4SX!4EN&?308XFz0Z^20P;~c%bt=H)5-u7pev|*dN$$a@t zfj`vU1^ElfHY<~UANu+|=gfEC1jYhcyx)v1f~)&|_}lFDa*o56S7Q~jJ!xXEv>jJK zI8a1>JbO*fM`Zpv!UnVe9yrW+!8p3%z%!aL+uZoiaRzz!Kh_BLt~dHoqtYfH_zi@a z3Xs9rZAu)jB+y;yA;MG&WeKtBo%wJ0zwo&(PD&O0N!S@<7P}Y6?Te2-96=&v2}7tQ zFs!?;lwpUjFSS*%w#-uL<6~kB>0M8n44KXLsO&XEYikG$5uZ>Zv4O!cn_Hbn_Md~U zKga}tA`>^c&Su?fUqg`lW5vgByIHG$ly97EdO+PgDBi^N#B+gSDM(G@RkJo&kmxu5 zhEBiHi})`w1|rs*j3fUFD=1?1X(%-kwqBvZJd6}$b$C1N5a49}p4MfLAc9j?G0a^) z%|HhXsIr1V@SfbHiNB#DGYwt(i;JSJqUBE_Nh4G0D%`w{VJ%gNN^``;4@|6+I({CG zKT1U%?oD~(6W}g;o)vj{zGM+Ut$(q4dg}A@yo~yWbi*`DLI_BZ4=dXFNQTb8P47hA zE06+jdNojV6}iR;eQwU*%+)fat$aox0l8QR6S0R60`V z`0@L@GH6=Lc;GJsROy-VwEtFv1LexH+?%b>WuiB z5@BNyfMP=hsmPBgZT47#vtGp%A%(7gb)DJh33>6v_ya5|T#;g#;?Q!IVu@$dKaO90 z9JfHNDs0wI;RjFi2_kW4j1d?z2H-VFQ)Y}^`W4(p&%zC-N(SO5$>C)7bay{R1c$%L z(29JXCgTE`cMa5=f%B!&p3@s%c9xSDRzS;qLw3={9$)inxNmLt^(@4GKD_5Sb@VO5E|gelfmZhUvpTC>%LHNvuw4JAog)B^Al)Y8XNkYx83~E zfYPfDR6$|NfhMJ4P80KkLfk~=L~I}0(ZD$<>W%88&`&U+J&o%!=6h+e)})Du<+cS) zOkpVViHO$tqAQ<0@6uoJ$MLKnbOA$KnGSPQ>7q_fG|KWIuL#(_!Fp7@G zC>rfdfRL(y>vu{}fq}KU>UcAZUjX&SjQw7vRhlYharQ=3-e(6*DyOQDf|@6*l1Y_j zN`a3C!OHAG`7|@}D48jf%DcHvjIxXw$(7XZSJ|4*#7H%5UwRWs7YDJgibKe2S{pku zOX=mY)D_Qi1X8kDer~|ao$U$CQJ1DEN=D4fa$AHe@%)Sm1O`CFb}*H8u%OIQ^p$;A zu=seXBevHXuXB%Z6BTc}*_p7$qOu^k;q#i$t!6sdvL$9K4_#zt#NpW7)30uBd`=X7 zTcQYGWf5rltAx2?xHHoeeo!x_={S}rDQ$1ou#q$iAv(K=A@ojj(h)dV@CNa04SZDy z?^u+7cvS!FqO*!^=mvT#@$s~_Yr75a` z!;r1hftz#5uuQRrTicWDo==1NOs(pB${zjL$3nta{Dm2Y)Q0%o=2H_`@m{MKLum=! z@62U6QZnCW7wL0Yi;?+nBr?=b5VBVjk+zyX*lF;+v+EkMuXn=d$ONFO!~cnk={Ld# z{#e$3zIvZn%#r%R3(?u}$n4`Pl&GUWCX8*?rl1R+KNs9w?B7^7`y%R?UHs!NVc8hP z*?Jr$z)B5kMqGZoeSD0nYQvtG^^8pv$7#a6rKij4z%#E@7Wut>%n|eg0eMJ0w;mp>@1$= ztH^r#__>a*<;X8HmcatCNM}ii4Hb+pUaaQqU;A~~w|F!+$z(&oAvfoOm)U1PX5g*QvaU#riP(Kxg zxWHKycT>%c80kbXvD|Hz1-UxgkZNdGR*ns?a?oxmsf}))65`lhlp^_m_sHOp7iZ9r zrU9WCCw`uHd8jlib9M~9gv)OngJKp&HKR?|<R<5QX$2Zd>{(s*BFZ|BNMvtPCdyX z}`R+T2b| z>}uKl&OXGYiGdIDA2}2@-&CWr@#?-~)*a$)#V35Vew=3i=ZypUvD;4VvphEnR%4Xv zbiF&_Y42p6A%nk^gf)6lK|s_>Gh#e)*dV2H76Z@heq4to5lxpl9T^gLmG7pqVt1lt z-QkWJaevyKPX-mYYo?WVKTrwlv!4s&1?S&^Gz20AGl+NG?HjX*J$)07)o68QIh7E`mPwIR zYVvdCb`i9&k$a087Ba5I7X+5ST|9JLpf;V#<>ow5Cf#!XL0^5VS{2oOK^2@pAW91%v&S&qZQl`|~7!7RCOPLzi z+r!VE`vyI%_gQp7{k4^xDL_NMM}{9n>>Bz^k%J>tvIwh5DL7^{u-X9aQ5%s4F{wOQ z!e~&#N>W35WnMPD0VauZxJqQ)?dx#F&llqCF%yP6>*oj3GE9<=+Lw(F0!*dXoUwE_7_d&>zAxfPsf%|l6f9irSAW{Og9l$-x|AVm_#9m89_FNv zm$BxeJ^D;Tn1FXJEMxXtG=!&WMgnqie((&Oe~NeQ+mSybd*ye5M}MBwoJ+Ay2DgD9 zT8_N*)-Z|9X$6B@rzP2zS&14#5}c10UU0E6VrhEK@)K7^ZG`1mb$8BHJ%x1XW&h?h z+e<@6bFF67wod@3B<>@ygn^BdqZeFq0YWvUDdxEpnaj&+)IUj5R_v%HpGX8#b*mX*<0uA{L9BTs5(!#>WR( z9A%cBX0srhq|svWRP+w)t$RV|Mn`8j7cHJBmFc0ze3OUFr z&KE=Fa$$7ayF5Gun@Gvunis??`8`8Eo@cJi4u9FcivU3}@B6K<|BS3V5VJc#qyiMK z@nncggsjm~`-9#LS4(lR{7zL2XCT5adRUO+RhQ_7V;QPSQEv7Pu^TX{L+QQST6bo~ zlTreL{=LOsq`O1%2;M>8B@@Ibs(-?BL;jOPzZf($%?f+_!yH_zgE7pNIWLIYUY_B~ zY~PgZg@5DV)hKRbr%yLbLw-Fs_xM`dQU-aOQ-l~1CuL+W9JAP6#aCHXv%zXRPER*Y8pHL3Ys0;h4$aDT)HlB#C*N02Msb?d9v~iZqyGzfOrXG2wonNM z2}I83;`EzGh$H~)z>;gO>jSHwRm|I5z}9=TJpSj$c5ebEl!Itngv^E*F{ht$^> zW1bvhF+>6J1Gb0!Cm9n)9p#eU$|P5%_QBopRBo}=v(r;XT{k1#=v=!RhdrmOf$;9P z+xSCTbB68Emefv)hqcnC&Ns>5M@ugfD4bU8R(V0+qfZ$HwRt-2uoiAVjTe*B?g6CU0>8P zgfbly2(v$j4g-SwDuqcy(3DZ2XRc zj#zLyD*~MsWiJZ1nX^vbPg*R=X?kDFOnQS&e8@wfRAuN4og(yPwLf3w96_BYmi^+f z;?c)oph%?LPD&~|-*G5TQnJFM@v%8+$H+jIJMW`TI{cI-f|OpW;f_P@z9XN;*H-tN z&9(m}(62-$Y?rwzt&oUa58@sUzZJw%w*b6;%Q{YOb;xt2Nm8 zq+Mx-P^M&`N5S~rFs++>R+Wzf(AkouH;`7(n!2g)sU`p1A1#{eKyFLcM_5Wzo4Mmg?-{l!T zYC%6;g}$wKggrnYZ``|w`Bx2LktPlv-#aYXPea!|US{+$%1g_)qw+MA&)7Wcw!DA$ zW?7IKVQv%+sCM`#zrn&n4S28ISQ?}xFUSFTYqEtfDm|yEhzU)cU0clvr44)iif?H@;ysuY2O>Yl^q%=6cl2+;ZcWHFy z&Jv{bsdj8QNPu2#)SfV7%x1Tjx_9xYwgh7Bq+P9@6_@Hw)(UiqW938~+V4b7DhD9> zo^K{cX`-xFn2egy|B9j5H0D=tjhhM;f%#x~_vXV*>-__mIjR~sx`D{^bXzm}wAJUA zdnqUgZLPJ~c^zgk&{i~Z;A_e~JhU{m9oY&nM`P9+$Q7P0e+MP7eKD}Z$XQ0pF61}s zV@44{+=Xuw7G$(ivK0@iGHPp2jX?UG3*=ORFZO5hWYzP}6n-PfH1zaqT~8j0g9t~L z>)RlaFRWcE9+tGlq|Yt<1xr1nd+e7W*YdRf;G7@F6Es>*5(WtP>K7~C1dh56^RH~L zwXNRvHtP1GpUA%3$b<3Bk6uqF!eqhr_9LsxW-*+o;qM%tX0eFf9mg&of$5Q+Z|^QR za;Ex1^WTHeK)IgpzkTGAu_C3$_?0?(^HJ^u%%n_tBVEQ0ls<{-Ta{RpfxL}P3mps~ zVI%lb?vg#(L1woot;N)l(m+?1`tuGZN9YWgKAolbs~!TLkPd~?bg8SucG>pZnRY>? zUh!#^hwjhjUN=2gLa`rz=l!~-*nVYMhYj_WP)Sm>W?e&>ZU5~4)}j_uUi=R7v(B}u z7c~nKT7cU--A}t`%j_2u`O{fB^4qHmtI|-K=l#Pya35lR|8e!!6<}aP!R|cfECp#48;lODWur)&8tZoXoFLs$OH0|x~ z0J9bD|0XMtS}P&ev;MuLco=J%>;LcxAVf;`&si}axvoZiXa1TYzHHM})y?dxnXhu~ z5G55Xe$PS2wdP#ZntZI@^(Rd<-F9zi8)6DUM^>=xDkOy06qp@V1Y!1x@n+ccPq9g- zG1G8>O=QT&yoj5xba>IEk|q7FEL;~Oo^d<&F&fvJG}h8L!(&VHi5w5VZ4=+7;lr+3$(YNHj9>%YwQg6Dn(H&NyxPOKnJ z0J^cs*QeFm>K`td%Z^(0oCl=}-5{WeGqo5q?H3N!4lMz(4>-Wv4#|~*sGS!?q!S@g zE>2+>X&BmZE93fRcG!Lg`fSo=QMbx;xa=y}BAFb{mv>_%z$RF*_1BFh%S1}whx=<< zuB$jK^$5QJK5HRXiLU?DQ*r{rR4g>wBPGdq+Q%2nc_V`Z45@>+nQP-Ebl&w&u;(cb ze<{N~3U{1P*IWRQbl}QBCY6B($-m-{iS{2eiWg7Bt6W=QW!q@(r2LlNd=~nmG?Gbm zP@D(SWcB?%1UEFJi)1Bex+69`J1f-^rC-rB)OXyPGI|U>m_i~x&X#tU4@_(S)&m&q z#|I(5r~^YzRt}>BehY^bI4sbaXCWG7gTRooyCsUSqG9AFQtz~IOrU-eWU7(?q{B667R0?yXz*44oNahQn>+%#g5ae1>uX3~NqH{OtI4b%b zq(8q*CaG@bvi$sjE*16d6<-1Z_#enq&crW(A^opdtU9YxuY$iI0{AGf>XUW2o>472S5r;Segz)Jw z)!bb1DFtpGIGF}aaMZB=|5!!DKFCJQ^KU)Ir)m8O?SOVOcVVdVG~f9B@%o=FhNNTQ zv!uQvLhb)AL3r8y0<8?k?|na#jrqODU`xBC!1nfCnEIT0_XL-dc~dN4Pc~YKuchUf zvPPoEvLzQwZc6R)4^-o%zj%^1idNfNe`X$e3?FW{AoJm6z(G2y0C-ZyHZo_)x3dda1c#pv?zw&-8wnNme!z!X2_CfhhmcQiap{_xO3J zjOcPohn4aIvi{AzX8O)`sq&wMZi2Zvz;U>&8K%z{iK7R1+h!28mY@h>9vvba%$i~? zVWmYTGTScK6mjNZkhTR=#ztC^F|a>;Rg{K7LUuLlPo-(J0AxXXwCEz-t>&OUSz}IF zFmFKAsHcyX`)wT_;b@UWDMJ$uSMby6a>2HjWRV>i~4z9l+t89)5FGxQIMd zzz9r?%618f@u5BaKvv(Cd|l%vfuatx*v;)~OEY6}S`285RL(cH*S-Y)=ua=R&U2@S zB3=7z)jK&J+&6&dDOve;=m4Vi7EKqE@EU`0@v$|CsAn@wgSFfFJ7X14?Pe_*~L zM|C(!oNPKCeuhM|biS4zXLId-D0EHQRI&ZGqHYi*|HKoloE~P)ye4KtE)l=n|CcOB zvWPJ^XQHX=?iB-^)dRll8kSy5S!kmP$!?BPQ?Y2NBS~&f@DKKs6bRuQnV_CTP*G|% z9+8u!HS#}b9i`?cM))YcV~-j6lUOEV08GMuFkVcc83iCePnZ-=Ss8zAyRH2Fc6ZLb z@OlwHI1gPAxL-w_G`@eTQ$P_JDS4o08s3$jgrLirC}5LO@FW*1g0I%~LM<4aZ8#P1 zAtlB2-CCSI72oE+L%L4wA@Qu?!g8DvLLtw&UKQXx^PS|r5T=jOFI2U zJAh3=B_L1{UbSYZza9#F7MK>H*?&@v?19C^{jut(It8SCy8#CR=fA=64A~OrAsg~2 z&sji4LMbNakI~8~Ka{P;|9CS6sTtJBrvLFjfT{Y)(nzOQDgtHzp=?5L| zOjqtOsNI?7uz7Nf?|SfeXy3C1r|)}osriEkcDheB{1i5&`;#63bojTt)>sfeA8a7xqN zrhD%rrg%_a#mlg^^lS$ZBt$x4QRTF|up?xnKAFqJ{If@M1fi4Sd|>)CNAv0X-4PDqYF{X}NoL(MIw#whV2qsy4>-Iv8=1aLS(*X!tw zcT0N&kgTgf^ki;Ke$%Z)VrNSOyVXnM8S&ySEWf&UN+W?ia>dbv#R3RqF`(_DQbit# ziZXM7!vVxUhj#Byn%OfJmj|Npf0{={Sm4ar0y_$L^nes0y|@D7c__EprXopAD{!g@TIyj=fLbjYsulB#b`9Qf`_^8K zgt&-2q1v=wQ9+s8cOyy;X>}8OZl+n0#WZB50q3uUm?O@G8nEm+WR*)6TC5!P_i`l& zz(Qb6Sd1z`o-t#qvX}fE@5l7!f)zDPv~FHD&%;%F!3fOVBZanARdjl+Cer6yq*BIU zHz#SH650J(acwN4q~T)+2{m7+nE-{yhSn-0MdHSIYeJ>rbii>oDy8YO|W zN01XOz6WGKb@e@C&HMjV_SHdEM%}w83JORl(v5_ObbA0vMQNlPDQToz=|%x~n-I?Fqf9}1`oRNX|ob&E?ul1~Ffe!RVKERcWFim6S z-$6z?ph2W!tyu78QO>Bc6|~et;n%)zBs7K)Tvnv|Kdw_9ET|8gVk z4K!;bJH7kOW@YU1=_ejOQGhn&fQVymM6H^8z<$3?!CxX%+2A78VMVC{${7W1QPnK=IMD=So;{XrzT}S>3lM} z8>PhsxxO+d_BNlFj&JlEN|`v^nDw0)9EYU4tmvHF>o}ioJ@4e(l9Xua4;4qrAhX$- zOI)eug#e`NHp#YRlawVi%`@N<=3{Q#PfE~PfsFEls9(|*^cFeq!98h+VrS`QzyM;R zxj~H!jpnk7&;Uy)1^sVoua*+z=YodyDf-LpIGin7WH^+5C#^4I*nSh{>HPELQzskI z%en9I-{M})63?N1X=Zn~vJ%LT>|SLIrvA}do%=108!EHfX~(Nh&JM+xp+iHzm+ud9 z76{ohFRqrS5B%aIR#6$|TWea)mn>hdwN7sn1!kA*KU3_?b>uX;?$Erz^2pA7!omXc z?+@wo#K-)O(5LCsK5t*QQ$c+R{g#yV7W9~_q06$!#AmI?In?T+Dx{aZxKI z@R=slBdGfK2*tGD_2>0c${0X<>)WIXwDMGQ$M0o3tO#~H;vsqT{-ly(O|y`c&_j_e zN3k1bDyCW<1FT0rwKwt>eezQE>@l!M>9Dj-4NmG03Yd85Wo~w%P4&vng17M~i_yXi z^G{OIZG^I?DX^cyn zenT9{QQO$n;5jEbQ_3UEPaUhi68~!T%#dS%k8eM&-{HM*GJRY-d(lu+jV+0NxS?4k zCN#Wt{G4Gdo}Z^i=BIGIg{_wVLZmQeu$izh!6fz;q~Ev;HRPKh=F&ewNC*9UnVl|@ zx~81`Q}Ul|*|&L`@;y~n0Jj{`Y8 z+@J3GKuH8+y;mu6!ULDYjPOt=Gw=!+E>n`>L__&5^O)0_4A7YG*`a%OCF zx&3Wm=cBo!HGKjb{;PTcS zz-Sg=#Uk2zoNqdd4%ln^_%|6#+vPV(Z5u){K8+@_Uo7y|MLLGGb}|u?YM?qhcr@34 zWw}wC`oK8yH&mLl*WQ<-#|~NXEu0GySGo_OzBf#EANpHjdliZ%5n1nGlnB^^3T{fGorL7GIHokI)R5B0hF=azw2+61JrxUTIuEDa6qlvPT!*Re-cqa|nb2|$U z|3JkXR4H4_`4+mT9-GpzCI0%t=-qNqhu7sFCd=8xY3}3{d-#;>{>}GaQkxqIt^atHUX z<+}#s<*DoKRBD3q)$7|0Ef;#WB7+F|fD|rnWqpY9LqB=a;Qoh3X4`3rt#fmd!7ghGc>LY6VBskLh`zSLV z*jn|N{W{EAGnk-VnkJGqe{DpX3DTFq9tT`Eip=F$m6c^z&&ML)w-`#_g4q&aKwr&w zP{BB&V*9c`rS54}2)f8;%6HDvEM&jU$=?deA~2JM_Ve(Vc=Tm(R3V67vsCktF}QK= ziJK`Y7xRa3qZ^As84QUT#mx=tt1~=?3>e6sh7FoTX)sX>o!>S*=cs$Gn=qD~_w0PW zq{N%LAUHLyyEn;I`AUY(Dsh`|$R$=?c_P=88_7VaZvZWqUrQJvqVVb@Dpy|o4!vY} zf!Qlqp;ifO;?TH3=uIppgBjUu&RYUu;3`y9m{O4z6#|oE#BL*7oK)D0*>za*Zx5S} zW3Th3Ic$>1znb9rEUAgnQ&qjws(~9U*;C-vFl|G}$i%O0qIV29Jgrmh5W-VM9!{BrPUT9P$vtQgYZ^}5| zs*DtUHt_rQ6#;<*Th&L9p-D|_t|nQ-uj$k>QD z8@|xtH9CBZnVm#6x8UWgI#kt;*D!59)1LX9vDVItJ51Sn{`3Gt??G#ox`$R(7&Wd^Y~nQAi&)UAkZT1ZLNV-le2^{kE_2SU51I8tKan4^TqF~H%c{4xPK?m zNdNeIarsWR8h@r?Bkwqaw;m!)N=eRn;M7p3UY8ZzEwaQ;9Qm`u7^!+kR+(BkeOY2o zW7N`^Z(C`U1dEN~;@Y8Lt*K{iF*7qaHvKm zC^8(VUT6osR%0rD67>^&URT#q+mt|d(Nu-SIxQ-;DAUd*h z(I%GLSfwgf;6-_vI1RroG+P!3^95$*NElH-&Hzzd65uS*hMe!>ZZ#N)SDP$<7usjO zO=$+sxAm)Qpc|}j!JGkark)*jVIzm6?x)_6QwCB~L*0$3i1Ol^vlcwYKS&{Z;w@cD zmosjQ!|k>ufhTag=T({R4rGKsR{w;OD{yC*dKgn|Qf=fI+w&j$nC1x-bQka@HXA6a zvu9?Q4y}F!bIwzGwzAET)BfzbUDX#}11uI@_RM+T(SD-E(ubl!SSpb(!g_e>!o+zj z2M+G6bEetGx8&5`Q|`{p5;dfX#|Sq$4%Zkt&o5BA&ngtI(EX3?RGXqOf7+i%(=d2L{+uIy?whnlMhZML zcA(`@!rEqD^7p$8qHmB=DmC|;!Hbo^rI9I{Pf!$oy%>vIXgueR?kJ3kW0ny}K$U1H z$h(PpVaO989Gz7>(7l@#)Rp5YNOkiI{=2r8T-L#}{NWU-PKGqox3RyS(4l>-SVI z)Jj8sDbwJtrvpQx#n|=~=?HqE**CIMmP)L^M7$&={JE>53DmO`uH+Pl`vs>|IjvIs zAKM`w0S**Pf`8*Jr^X*-wm2Sc#rEX zIEh#0;K%47Eqw!R&$#1Jc67MeJv7OOKZn90oZ1{HlrvMKs$bd`Jskma>}YU%K6FD3 z5!dQVtVapF!N;f%QA99)&dt8Uc#5+0Q)RK}LiLA5=<^drM=jgw87sxm>e{;jap3Jz zDwRl#>xCu-G>U&B{<$roskTMVz3apU+;TuLxm&->$tPJQa#(99wtBpr6yY%UY;4xk z`O<26+(>*&rRM6J=@SA`ZAlru(aXpZiIQ-gXIvDG$u*gaqu!I(X#7?&QR?Zn?tOQ7E z*0MKbRSLggOqLXZfqO=dpWVdeeo;@0wv!S<$k{|ZU!@O*H*~t52&nx`QHK_dRr{PYFB4^nhEO0zW^ckg_t^O_&vMuS;&kMpLH9yhyfv2i)kj4-IdI`-#WoF2YmT zjQV+RRhxWpNNU>u{W{|E{;vmNX#UTO^c4(jiM8_!nbPeJr5T8Ms$9@< zK3z5AO}u=w)Zgj0@;Wg8N_ykN%69SHRqv?{f4X2Z_B4%R5uyo`k<2JrpHC0{e!w2gHe(;u-*8a??tNX$C;j`0wR}bQKAxeKWyc_)Qonb zrL3F}FU9DwgQ$E3;1sDt67m)ThGk+g>FWGcPrsd5c-qn^`BLe9>9(#~qIA~w5Kyj7 zV_dJ_e%9$R-{nk$uC_lflf#W8w(+Tb>rsr~rQn~^_MA9O2a)*?A6L0Xe=3=aqo5y( zt-MOlZP3Iy>?>A^i}Rfci@Ehwz}S9Fz@64^De>u3IlAd@)Oe=9~x3poxo3v3q6`;=8YGa^}#g_unDl$%0pY= z{9@J+_b`#}Zjks}6__BnhObSy-%Mq5S*uldNzmEgv%Qu-6I|5zT@y>615Z(5ElvHkzAXiXwhBKb(-ILLyNO>f;+mv~Rz?r5NV|kX(FTLF6H?Lk4joj ze8BC@x-&QbGz2e58jYHm!?TZlj^RG{lo-90_-Lc{vkaH}rhMoGQ>N=~9JeOFy^&fv zvOXX>V@#l4JA8nI5Z@o~U3_l;q`W$Ab6?Y(PRq^?XbB1QpZAD<>B_miK5ZgC^{Jsr1~;-{-FG)m^2O-5 zo^A?sKHmdi_~4%xd5CM2lQFgr9yi^w&c~9vN_mf00mXOWJtpj_Y`J=TO*4 zymi)7?2FMo|3BBBvWEt}1Wq{kw`AE=BADWX~-;%?=KB{j|B!};oi`VjF@yNuH=%HT8Jp{KrN0;e$B8>#C*5_h4 zL5f{w;?xm^l${Um%rN*Cr}X7YX7tS>9QOc;Xg(%FRsgx)e3h>T3%@^~!&#BMC{>01 zfByVz6FOuU+KcPK8o$g+u%aOd+4)5qflu+|Xu?kYyWwr&ixoMB{dkjobjBENUtK1H z3{EA5IffXn#c6N$>l?p>>)Wr>S5v?1#Gbo~U)ZjhpjP18e-dnfD2&IlrSqjmiPTT$ zVVy7%r{xa$D9imMbYq|F80YDcN_z1FcGE!ikbYdZDFNE+OS!yhE@F3RMTr_&$R80n zw>IbnD(RCIjare#;7S^@CO|LOyxSjUe;eim{ae!N*+?BSxoNV0aE8C*Z+cxSyWe7> z;^Vk=eeHH^US5HEiNC|zP}uR4wV|(bktyefy{}buT?JqOb3_KXI( zabZ;w`Qx~e^a(r8^qv)-YzZ7XJ%*g|3hQ)=$5KcIDVV!Mje?Gb_G{toE0{GSsH3dh zk}T*Zd7hMu-*^H8R z($W@{egspG`StUT zD4HrilbxPEcZ{Qhd=IPvf6pKH9YKiSLPyNre!ml+}<)vrcwjb-C{{E&z%m4SuFpFV4{m)82m0V-y?SC~+b12No~# z;O@0Asi`wul>hzEcDT`P*V^neHd)NK_!G8Y)&v5u$s0Eu(;0u?9=GNr%SugsA08fF z;wavgD_VGvD^j@k?lr-zqViUm<|pO7%ZP2JDtG5?(!Uou@@IzENj*cqrg2TO*FXQ~G4O|c{GaQEKwAFb?NwBboH}3RRnpW9Nn=Fp{}Geu!K6NJB&>TXBXh^G zI*HqS=$qHoWt!!=r!eodJ10d1dP+~*+4PlXTCZs@&v=>TTq7oHvvEl;pdD}hNmt~> zP&W}$@>B}7g2p$pzJLEzUU%?yeX_dTG{KOg{h81%-tXVPZ7Q{DE;g*Q%gf={hlh@Z zwTBvH*yx`>f1Yq0w=^snO|wjP+vJaiql^d5j9Np9C)~Db8O}D66ejF?1erB{hGTkpgVVNyBlNwcVw$M3dJ+|$a-kL)SOh&$3FgqVbmDtm(J&lgy){YkCxyf?Ae{@8c9AoZ&`T<&b<`V6?@hDGzJ;S)_S$LaPR;Gdk%

U9bvM^C=S|$ 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 KU2@Rp%6|a@D7XOt diff --git a/docs/basics/quick_start_rl/output_19_0.png b/docs/basics/quick_start_rl/output_19_0.png deleted file mode 100644 index 1e2b61ceeaa80ad792facb11851a33c6d3b799e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20886 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 rRQ#Ah1K@)7z_ -```{image} output_10_1.png +```{image} Figure_1.png :align: center ``` @@ -282,29 +282,8 @@ class UCBVIAgent2(UCBVIAgent): self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") ``` -To compute the regret, we also need to define an optimal agent. Here -it's an agent that always chooses the action that moves to the right. -```python -class OptimalAgent(AgentWithSimplePolicy): - name = "OptimalAgent" - - def __init__(self, env, **kwargs): - AgentWithSimplePolicy.__init__(self, env, **kwargs) - self.env = WriterWrapper(self.env, self.writer, write_scalar="reward") - - def fit(self, budget=100, **kwargs): - observation, info = self.env.reset() - for ep in range(budget): - action = 1 - observation, reward, terminated, truncated, info = self.env.step(action) - done = terminated or truncated - - def policy(self, observation): - return 1 -``` - -Then, we fit the two agents and plot the data in the writer. +Then, we fit the two agents. ```python # Create ExperimentManager for UCBI to fit 10 agents @@ -325,15 +304,6 @@ baseline_stats = ExperimentManager( n_fit=10, ) baseline_stats.fit() - -# Create ExperimentManager for OptimalAgent to fit 10 agents -opti_stats = ExperimentManager( - OptimalAgent, - (env_ctor, env_kwargs), - fit_budget=5000, - n_fit=1, -) -opti_stats.fit() ``` ```none @@ -345,51 +315,42 @@ opti_stats.fit() [INFO] ... trained! ``` -Remark that `fit_budget` may not mean the same thing among agents. For -OptimalAgent and RandomAgent `fit_budget` is the number of steps in the -environments that the agent is allowed to take. +Remark that `fit_budget` may not mean the same thing among agents. For RandomAgent `fit_budget` is the number of steps in the environments that the agent is allowed to take. -The reward that we recover is recorded every time env.step is called. +The reward that we recover is recorded every time `env.step` is called. For UCBVI this is the number of iterations of the algorithm and in each iteration, the environment takes 100 steps (`horizon`) times the `fit_budget`. Hence the fit_budget used here -Next, we estimate the optimal reward using the optimal policy. - -Be careful that this is only an estimation: we estimate the optimal -regret using Monte Carlo and the optimal policy. -```python -df = plot_writer_data(opti_stats, tag="reward", show=False) -df = df.loc[df["tag"] == "reward"][["global_step", "value"]] -opti_reward = df.groupby("global_step").mean()["value"].values -``` -Finally, we plot the cumulative regret using the 5000 reward values. +Finally, we plot the reward: Here you can see the mean value over the 10 fited agent, with 2 options (raw and smoothed). ```python -def compute_regret(rewards): - return np.cumsum(opti_reward - rewards[: len(opti_reward)]) +# Plot of the reward. +output = plot_writer_data( + [ucbvi_stats, baseline_stats], + tag="reward", + title="Episode Reward", +) -# Plot of the cumulative reward. +# Plot of the reward. output = plot_writer_data( [ucbvi_stats, baseline_stats], tag="reward", - preprocess_func=compute_regret, - title="Cumulative Regret", + smooth=True, + title="Episode Reward smoothed", ) ``` -```{image} output_19_0.png +```{image} Figure_2.png +:align: center +``` +```{image} Figure_3.png :align: center ``` - - - - - - : For more informations on plots and visualisation, you can check [here (in construction)](visualisation_page) + : As you can see, different visualizations are possible. For more information on plots and visualisation, you can check [here (in construction)](visualisation_page) From 9d96258740b96feab73a254436df5e004342b6c4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 15 Feb 2024 14:06:23 +0000 Subject: [PATCH 65/80] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rlberry/manager/tests/test_plot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rlberry/manager/tests/test_plot.py b/rlberry/manager/tests/test_plot.py index d1fcb7f54..811f90d23 100644 --- a/rlberry/manager/tests/test_plot.py +++ b/rlberry/manager/tests/test_plot.py @@ -15,6 +15,7 @@ np.random.seed(42) + class RandomAgent(AgentWithSimplePolicy): name = "RandomAgent" From baca4e7772c29ee2271a17a9abc0f817527c0cc3 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 15 Feb 2024 15:31:49 +0100 Subject: [PATCH 66/80] switch old and new user guide --- docs/index.rst | 4 ++-- docs/{user_guide2.md => user_guide.md} | 4 ++-- docs/{user_guide.rst => user_guide2.rst} | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename docs/{user_guide2.md => user_guide.md} (98%) rename docs/{user_guide.rst => user_guide2.rst} (99%) diff --git a/docs/index.rst b/docs/index.rst index 3b21a3ff1..14dc178e2 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -4,7 +4,7 @@ :align: center .. _rlberry: https://github.com/rlberry-py/rlberry -../ + .. _index: @@ -12,7 +12,7 @@ An RL Library for Research and Education ======================================== -:ref:`new user guide` +:ref:`old user guide` **Writing reinforcement learning algorithms is fun!** *But after the fun, we have lots of boring things to implement*: run our agents in parallel, average and plot results, diff --git a/docs/user_guide2.md b/docs/user_guide.md similarity index 98% rename from docs/user_guide2.md rename to docs/user_guide.md index ebe05895e..c50599a89 100644 --- a/docs/user_guide2.md +++ b/docs/user_guide.md @@ -1,9 +1,9 @@ -(user_guide2)= +(user_guide)= # User Guide -You can find a compacted version [here](#compacted-version). +You can find a **compacted version** [here](#compacted-version). ## Introduction Welcome to rlberry. diff --git a/docs/user_guide.rst b/docs/user_guide2.rst similarity index 99% rename from docs/user_guide.rst rename to docs/user_guide2.rst index 1bc2cee23..5987c8d5b 100644 --- a/docs/user_guide.rst +++ b/docs/user_guide2.rst @@ -1,6 +1,6 @@ .. title:: User guide : contents -.. _user_guide: +.. _user_guide2: ========== User guide From b3f6246e20fdf65495ab69f93675fa021312d2a9 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 15 Feb 2024 16:50:00 +0100 Subject: [PATCH 67/80] update following review --- docs/basics/userguide/environment.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/basics/userguide/environment.md b/docs/basics/userguide/environment.md index bc470e4e6..a27f32c24 100644 --- a/docs/basics/userguide/environment.md +++ b/docs/basics/userguide/environment.md @@ -122,6 +122,8 @@ Moviepy - video ready [your path]/MountainCar-episode-0.mp4 +To customize the environments, you can use some wrappers. You can find the rlberry's wrappers and more information [here (in construction)](wrappers_page), or you can use [Gymnasium wrappers](https://gymnasium.farama.org/api/wrappers/) (or create your own). + ## Use Atari environment From 7d3f9d6bef2a6702fb4693ca363ceb98367aeef9 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Thu, 15 Feb 2024 16:57:56 +0100 Subject: [PATCH 68/80] typo --- docs/basics/userguide/experimentManager.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/basics/userguide/experimentManager.md b/docs/basics/userguide/experimentManager.md index 166ef5c3a..f637c85f8 100644 --- a/docs/basics/userguide/experimentManager.md +++ b/docs/basics/userguide/experimentManager.md @@ -2,9 +2,9 @@ # How to use the ExperimentManager -It's the element that allow you to make your experiments on [Agent](agent_page) and [Environment](environment_page). +It's the element that allows you to make your experiments on [Agent](agent_page) and [Environment](environment_page). You can use it to train, optimize hyperparameters, evaluate, compare, and gather statistics about your agent on a specific environment. You can find the API doc [here](rlberry.manager.ExperimentManager). -It's not the only solution, but it's the compact (and recommended) way of experiment with an agent. +It's not the only solution, but it's the compact (and recommended) way of doing experiments with an agent. For these examples, you will use the "PPO" torch agent from "[rlberry-research](https://github.com/rlberry-py/rlberry-research)" @@ -59,8 +59,8 @@ print(output) -## Compare with other agent -Now you can compare this agent with another one. Here, we gonna compare it with the same agent, but with a bigger fit budget, and some fine tuning. +## Compare with another agent +Now you can compare this agent with another one. Here, we are going to compare it with the same agent, but with a bigger fit budget, and some fine tuning. **warning :** add this code after the previous one. From 9116152c31be54858f5563ab1c7cf8a414aa97fd Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 16 Feb 2024 08:58:01 +0100 Subject: [PATCH 69/80] update new visualisation --- .../basics/userguide/expManager_multieval.png | Bin 18049 -> 18436 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/basics/userguide/expManager_multieval.png b/docs/basics/userguide/expManager_multieval.png index 480e9aa5a2fc4903d892ecd954b0228e919165f8..2ceeb5ff23d524f1692e41a794af35f6762e0725 100644 GIT binary patch literal 18436 zcmeHvbyU{ty6p$Hs4NqMFhB_bDFI0nNeSsx1f-E}FfmY;h;*n3NF$(hSfG*;B8?Is zNGc_L=j&Q~?{n@wr0`~bgf>AuLyl=>%m{5jwiJo)oe{2UC!B?P!!KO+F98;TA82U?QCN2U~X$8z$3!L ze{lCjM@Kt{BfPxU|NH=tt-TrV?zzRcxX2p2)7lOc3jI0qhvu17f;ojEb4m8Z(X+0R z!|iUaThu$Ieu&L=tXckkue@|H>-%cT(Lb)ARz9J<<>cWNuR>P+aX~HSsPtK7Wo0vE zyQ?Z+Uu`v8PP4Ij`H9uZff?&}{&|i4^f9eXfsxbn`y~X|{1JS1_2hz{rr}eiD9Op> zr}=~N`AIER+l`mwSz7IQhiUP*5jX8_3dOhT4+;&1Vs(SE8ebAvE{*R*?4jTTU)It5 zL7|kIuJ*;34j-rBXES#E{~!6EUa@ZNmK8xJGcz+s9Q*&ga^*@-U!O)xFIN2gp|bv8 zKe})G`v(;iNCaHpNJ)SF__*KMIJt*)Jj*B)z01p1ZFpwi`!P=cRN`)m!SzRvcFURx z@AiA6^05&=|LuKc<=Kav>XCDo#P;IbR|344Hmt&C`SO=lC)hTRU$w=K?b`QW-$afF zGzBO^wQk@V8Jx{6-o;>BmQ%a%2!>IySSdVVqS4+`4iH1tJfad9!} zY+~T40Or)THoauc6^Ivmld0sc@1IkXZA%tDiw+OWbgH}k{BYpK#ZP;^W(N}1ZrJeo z&ppQ*URY|T>KAAP28Dzq++z~s6c^VU{G6(0VUaXDF|d!9msc@d@WW3hgl2|n*m~dS z=;*cd^t=tx_wPTR?(jG>-dCm8`qG+BHp{F=LqWmc``6c1xW%zf&+)s?BW;PexyHG3 z=PbTtJdXBRbd#8DPzyhF?n+@%QK|tGR;MDUnUZT(!+i48sgF%fnwKtJ3Kw_FOwveA zdi(Z7l&Hh0A3uIn7k~QnDM{x=(&u!;^ljWa7Z+wHlQh$#U%!4G>9uLoCc%rfyBFri zYb+X`sobxqtghB@c7Ew_L_i>`N8=BQonoZ8o9c%T9~g!mzBh0z{H)-;efxG`Oibs= zxl=MS6`h?+I>D>8(iB#f_Ekk#R!52^sU_S~Ra2X6bErvl8vKmKiU|r1-fwGbd;QwA zT=4@34=R|On+HD4&K3+A(>zpS)Nx%QT3owEV!G{x{tk-tEjcA6jR*S`)0$mx-MVGb zmit3!7d`uW6MjmEQ-UK97vpFhtd%B=kP;RlLq@t=SG(U_*M>oGmj z80FHD7#YdPB<5V%%ii_%jb9XX-3>p#!EzQK#~raC4H=s_5xO zvU2e7D2X`_DZ9JpXVqkyRP@-1Y}vKT(rp3TsloX`h9Yx!XPi>hkwm;7Nx8BB7G8RK z`pN!J$6vjA^}VyC&5vE>)JS2M4VU!F zZ)cn?|hn@E3#tw@@KZ4#o;2C&YP!hLKd5} z`SZnR-(gSY7ZBLW$e7~qzfP3#ULDUWirw|YwjC+^6~pbWrz>VG6(6mpLG6|PvGM;@ zp(d4zLa~dR8fuR1E)OuA6p@vcPTsZBz3^7fc?~I^RGwkEMXpn3gS2U8XphoiLR@?@^!FlS zL;L&dc;0bvh-zmUcxg=sJMSqyNt&sNhEDLO#6Me9FTBC`2hQpg*JUc0htTLXOghw& z4t($^UjP4cGj02WW-KnmATS~#;s!m-h?SVvZ1zfe=9Jo6Q8BKn zs@m|}SY~E!E?G5BZl{EMHo5_K8Z#=pj)^42rY%<`%d|=rrBJ^m#`CAF*JPvS>_q(; zqy#6^5y#W|1

@H5Cs%^vkcWGA#B|cbRq(0b9YG^)!c&@e&?W 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 OitI_H6KThcuKYJicKWyg literal 18049 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 Date: Fri, 16 Feb 2024 10:57:59 +0100 Subject: [PATCH 70/80] update following review --- docs/basics/userguide/save_load.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/basics/userguide/save_load.md b/docs/basics/userguide/save_load.md index 8b35c4a59..ad815d9b9 100644 --- a/docs/basics/userguide/save_load.md +++ b/docs/basics/userguide/save_load.md @@ -42,17 +42,13 @@ experiment_to_save = ExperimentManager( experiment_to_save.fit() print(experiment_to_save.get_agent_instances()[0].Q) # print the content of the Q-table ``` -Then save: -```python -experiment_to_save.save() # save the model inside the 'output_dir' -``` ```none [INFO] 11:11: Running ExperimentManager fit() for PPOFrozenLake-v1 with n_fit = 1 and max_workers = None. [INFO] 11:11: agent_name worker episode_rewards max_global_step PPOFrozenLake-v1 0 0.0 178711 [INFO] 11:11: ... trained! -/home/jteigny/my_projects/work_in_progress/rlberry/rlberry_userguide/user_guide/rlberry/utils/writers.py:108: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation. +writers.py:108: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation. df = pd.concat([df, pd.DataFrame(self._data[tag])], ignore_index=True) [[0.73509189 0.77378094 0.77378094 0.73509189] [0.73509189 0. 0.81450625 0.77378094] @@ -73,7 +69,15 @@ experiment_to_save.save() # save the model inside the 'output_dir' [INFO] 11:11: Saved ExperimentManager(PPOFrozenLake-v1) using pickle. ``` -After this run, you can see the 'print' of the q-table, and should find a folder named according to the `output_dir` parameter (here `results`), with the data about your experiment. +After this run, you can see the 'print' of the q-table. +At the end of the fit, the data of this experiment are saved automatically. It will be saved according to the `output_dir` parameter (here `./results/`). If you don't specify the `output_dir` parameter, it will saved by default inside the `rlberry_data/temp/` folder. + +Or you can use temporary folder with: +``` + import tempfile + with tempfile.TemporaryDirectory() as tmpdir: +``` + In this folder, you should find : - `manager_obj.pickle` and folder `agent_handler`, the save of your experiment and your agent. - `data.csv`, the episodes result during the training process @@ -152,7 +156,7 @@ As you can see, we haven't re-fit the experiment, and the q-table is the same as ## Other informations -The `save` and `load` can be use if : +The `save` and `load` can be useful for : - you want to train your agent on a computer, and test/use it on others. - you have a long training, and you want to do some 'checkpoints'. - you want to do the training in more than once (only if your agent has "fit(x) then fit(y), is the same as fit(x+y)") From e242752fccb01930f47aec8162feb87074f33d11 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 16 Feb 2024 12:53:08 +0100 Subject: [PATCH 71/80] update from review --- docs/basics/userguide/save_load.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/basics/userguide/save_load.md b/docs/basics/userguide/save_load.md index ad815d9b9..5b63f53ba 100644 --- a/docs/basics/userguide/save_load.md +++ b/docs/basics/userguide/save_load.md @@ -71,12 +71,7 @@ writers.py:108: FutureWarning: The behavior of DataFrame concatenation with empt After this run, you can see the 'print' of the q-table. At the end of the fit, the data of this experiment are saved automatically. It will be saved according to the `output_dir` parameter (here `./results/`). If you don't specify the `output_dir` parameter, it will saved by default inside the `rlberry_data/temp/` folder. - -Or you can use temporary folder with: -``` - import tempfile - with tempfile.TemporaryDirectory() as tmpdir: -``` +(Or you can use temporary folder by importing `tempfile` librrary and using `with tempfile.TemporaryDirectory() as tmpdir:`) In this folder, you should find : - `manager_obj.pickle` and folder `agent_handler`, the save of your experiment and your agent. From e20a5fea70e4ba0017755adf401ff38fd1426073 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 16 Feb 2024 15:03:27 +0100 Subject: [PATCH 72/80] update from review --- docs/basics/DeepRLTutorial/TutorialDeepRL.md | 20 +++++++++++++++---- docs/basics/DeepRLTutorial/output_10_3.png | Bin 7028 -> 17372 bytes docs/basics/DeepRLTutorial/output_6_3.png | Bin 5602 -> 14470 bytes docs/basics/DeepRLTutorial/output_9_3.png | Bin 31265 -> 77582 bytes docs/basics/quick_start_rl/quickstart.md | 2 +- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/docs/basics/DeepRLTutorial/TutorialDeepRL.md b/docs/basics/DeepRLTutorial/TutorialDeepRL.md index c366429b9..65c07f8ce 100644 --- a/docs/basics/DeepRLTutorial/TutorialDeepRL.md +++ b/docs/basics/DeepRLTutorial/TutorialDeepRL.md @@ -229,7 +229,9 @@ INFO: Making new env: CartPole-v1 INFO: Making new env: CartPole-v1
-![image](output_5_3.png){.align-center} +```{image} output_5_3.png +:align: center +``` ```python print("Evaluating ...") @@ -306,7 +308,10 @@ Evaluating ...
-![image](output_6_3.png){.align-center} + +```{image} output_6_3.png +:align: center +``` Let's try to change the neural networks' architectures and see if we can beat our previous result. This time we use a smaller learning rate and @@ -442,7 +447,12 @@ INFO: Making new env: CartPole-v1
-![image](output_9_3.png){.align-center} + +```{image} output_9_3.png +:align: center +``` + + : For more information on plots and visualization, you can check [here (in construction)](visualization_page) ```python print("Evaluating ...") @@ -566,4 +576,6 @@ Evaluating ...
-![image](output_10_3.png){.align-center} +```{image} output_10_3.png +:align: center +``` diff --git a/docs/basics/DeepRLTutorial/output_10_3.png b/docs/basics/DeepRLTutorial/output_10_3.png index 15406e0d26805486280372bb124b83f9526e43b3..8a6c39010d1e4bf73d4cea79cab588b96bf32cea 100644 GIT binary patch literal 17372 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 PG6)1~VuPtP_PY9Ser`IZ diff --git a/docs/basics/DeepRLTutorial/output_6_3.png b/docs/basics/DeepRLTutorial/output_6_3.png index a94ce0cd7cef6fb81079bea51ad5d781518d4870..cebfcbd05665b53fea36cdf062c90770a0762856 100644 GIT binary patch literal 14470 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 icT>ZEaAH`MSqH_2qG(bw#}bZcU;AI{3mA_8 literal 5602 zcmd5=c|4SB`=2qEveg`uCBhj~QQ2mQgh|FS#~KyME@KPBSPSE+LqnlPnMNcL5#dw_ z)l}ph#=aZ!#4(C6nvyNvN9R4i-+SKe&)?@apU*STHTO36eP7r0{a)9VVsC39A-Yo( z27^fuEeQ@V7(5AjgtrJoEvX_Y#?VWUa+G*{3-pQGa)t)|-b%JSMS;P@e%O5A-J=O> zP@{f?nRA3=C@CV^E8G_r>=i*i8yayoz*{-WH=Gg>8iLcnYG4m2`$t5O4Ky|Xw_hVP z+)p!0=}HO=w&MtqU~)VrXLgi&-6Jx7YQfL?)m0=Cy%Z#de$ybAax~v$P+hlH{oR== zR%-pNecgeh553uQ(q%453fGccP%3rKU9vAVdRUM%aw>Y5^CQ;bQ|;EbGbrKQ^Z2jLUyTlp#d$paN|~R+`NhP@66vtpeNk|F z;fL4uS1~8Vg@_JKe+s_t9HEaX_4Ciq*A^ES&tfqF=5h)Oai5naGVl>)kvId?xpU{< z&&&kXixabtt*ovp$%W=JGBCs)rY7{`+Nggg+>ra0bD@Y~bL(JL*uh zU8d*fm7+(FUwU;COlB(x&t0MUC7LEWA^a>FF98=5{m|Ziqy+EOnaslYVQ7>MOO2(D ztdbqv7Ndi+Qyfx8_rvUDx6pOIWH;>oV&Ex9wj`Vt(h%r}&!D|=JPbJ`wqKc;Exc1K ziS2r*y;RSpaxD9qM;fL?GS5HjpN!#utm6NP;Op)vl1__cePC6yUAw!Ui|TJ16gvAW zJKCZ#6wZLJ!tDfP&T!jo`t}fap3d|WodJ3b zUyLNu-*h>vp5X?w7LT=sifFX5^TTfiPj<|cxEty@3Kon%(q5R0)kl z)(b(&G}^{+)$|e1IZV)y=!ktXD;K#SPTs=Hq%G|L&A~S2GKk60Bn~4+S5S)x$va!p zry|yt<;aVevH3k9Dv{>w`n6x?Kg~IhnelNBP#OPc zJ83E}o+5F{ga#>RL04I%Ox7j+$U+qtx{mJjXSK2n+Pkha=JIgJVP9@b*vV%BSAy|^ zare#D>4n05Ta);Q-RJGXqC0!quB#9Odw$Np$}FfanWxbX%a>Zvd+!=_s2%v|94AdS zMWOzsszisw(?7qWv*XN~KdB?bsE$HJ`mm$l`;YU4#uODXjNBug=k7({OR|h(#4LiDLC{~kaoVrY>nlBJ=C{uUpInlsOj7?PtU(Hq2btjTR z;+`+A+(UG*g7gumi%#%~@FBhJKVn2Ll!i1QX5c=*E$4`~rTYLe3PZ%%<-!--2c9Y* zFTs_9%FslIpy`o#o#B&rLPKTH#6XYSV-6LCvb%PqZa*ZwWSeOQ9q(ANT|OnJpct6J z^3#*2uVJ3tx6OMsrQ(hET(ER}v>O_N^~yU+IDkli#r?1}&-&V2XLe%qFi+z?Bf(y_ zHDr3?u9r;REW67br{)TlRRGvk=9maq&xwvHQGa5Ptul^d$+S%Bjbjeeb@oHsu0c$} z=l3x}i{GEV3SC3wobgTpW0!U4&b%{Y@1COTSjqhf`Mq+h{@P8vAeYU673PTs(j?0^(8 z^2u-Nan5Vjwb7{5e*l)$aj#l8Rx&#-dT8ApEcacl$5I?eJ&w{JNB73Y%-+j1Ts#L# zv2;}=kYS=^VX`$z(yWo+y66Pkfa~v!(dN}4tMqZRudf!W9p5}V%GB+OIOCfH*n#Dj zgsl2^$h)bMlUA%<$79$JrzUor95xd>(AyYhoD!7||B|5@( zXmK?&=0y|hH)Pn>N-2FjZeCzrh*zFITb&i`_6O%^rC=9tzkK=f_EBxbpR+ zUgS})0Fq))RUCyd@FF``@EAK2J+>cWAE5bkxk)#>i^JhS6RFgV z+L>v?u7>?+_k+LKC#2Xdx@>%>q;~dUV3U%lFv*$0Ij5F`#BNk6rHBkCTM^c_-!xq~ z!=JbL^esfdRxP7ulb29Sd8`c@EyE!~=Y>Kog+BiyF}o1bR=g3~U9u6cJ854N4@3V8 z25oW`NfPnZtWgG71&RTF1K*Nf^tLvCJF=pUeM@D0EZyaaD*9KpeBCa6oKyOvX`6|& z)U9OVK;Uj-+H_PAZzo6sBYn!`h3k?pU;?;udJyd0{WK|p9`C}yU>oV(#6SzE zQ4`^jPRqphXwxtOO7>Ilp3Iv!#-bSX(pGcka@LztI_Ak;TMPaZmKZR}Do2^x>knpN z+KxhcJVr`@Eya=&6qoc^4{oVj(R-5(^0ly`uk2L3xAI)U<-cQ)agv=y<4cx^s_?_Z zu-eM5QVg;DK2G_qUkjrK`?7&eFJzXtN96e2-f@O2@-^WQz3||s)AG{?RvisH55`Z? zA*gZ5ZM9JP;F?Zr1#HqzK-gvjU5EM1y_l0Gbe-1T4~|QUO>0|W6u=a|DuoG-wn+HLZdn=^J8539~acqwH5}hu-EF@4UwXO(6B;?ArioENF*x_1z(u` zKGo}0I+wi`M|yat7NG{^!U+4n!X|0*1!4y(Lo;KnY}<};*H5q z6TY`F0a+!K<@bHeSXV-vj502o(3l`Ki$cz*l7cx|Oske^T^1)X@A|E0nm9f4#yAki z3iGuYIK#bH|Bdtb%p4f?-K?=XY3$f(8JKv7M`!r%Y+J5mh=_Yb|${@gh* zFmU{7cj1@CMS-Q|-p9RTWB9qcQ8})6hFRlf1L+QdgNzC);m|Wbg5fRi7Q0K`5YG1x zGLI5mMGhb&Q)uNZGuAIO{jBj%U9VY6*KbjOSaKzdSagLhJY_f3{E>njKw&A9vTb?0 z{5X46L#%FKp7{TysYIj~>HX(K>c8Yz|5shifnGqxdl%WDQXR**9vqZd1IMfBo%bMx z92j^ex`YFdfO4Jzq`9-D#>8&?fU_!W2C#z-TnT)E#%a!F{P;Z#i_O+t5va%Y~1i=`qQ_U3!E5HPtL3ZUa zJ?5kS9&%@wJ7@p=*O2=j6sO`9V|O8)5FTnWH3Buh+=9uvG*;M=0Vp}1b#puiC6^8N zeHIRQQkKt2@mgr_)eq--AV%;vpq*wv`^Ri6%dD{q#mG<;UWa{mTMMARB~l(oG5zCE zn@LBDb~c{lyQ*nFlC_T*m|~}6Mc)U}R7v+6ifHz|gTcd%Z_?yB8a^(Azxay5z6Zth z4_-~FI}Ug}ZHQ?&*g7b&~$-zfHpbY9P$6Z50xd zlE%YhV;h#7NXu?LIJvaYLO3&=-P_wL8LAMKr2(DoHz%R4T;6Ct( zrwo}$S~q(dVocWNodd%>w=8**5}vf4KY(cOVE633KWPB^gA`_LQ^>la1F_#~0O^@Hn(@srX z-a|e^x~+)p5Pm3_1>*y{%;ia1txQbpsg8Z1Du@?Yg`b8DlcI(0cg#V?mBi)k#qtxc z;e^22@Kqt-XN>fmNz2ShXrnv)U>>dPc?7hg~=?KKIGjSH3Q%v&!a85d7c_t*O{b_pvO<4{Inek3>`b4gJ;2Eb{vtU zc#U}pz74+DqA>v#jd8<;&nhb8M1T%~pw?g-%~WMvq9FYnj0|b1%yrHXF(g=)N;@>U z{=&dEz5~8q)xi0Xwrh5qqbvQwIK5|0doe!eS?98PnilG@rZaJ&Y3xHq%OX`|O_*1Y z42xc#8VtYn6@iD(WzgDCx%Dq1`mZt%s~M!|5gMZtgLgg9ELuXp&_mDdXEc9;gH%Mc z{m*RL17P5K?$};9UddGK!WH9Lfn^oSY_NEbX@Dvx7av@gOXca zU(U73jtpOJGtipIxZ#8OW;1AsI9wmK(AP7$^Qdp_-gs%S6k< z`URj;kegMXOBp3 zM^d*Q&=}a*)6^-Yva0CZJ_W1%5qBvupEfAm;Q3Q2BM^%!+M*-Pxo<+Xq#I+_2xl%6VvEQsl^QsUZC&bZs<+iFGi!<((jst8 wg+_W$Tr(aw8#+Se$nRf&sY!mXKCR=6tXVRh3ds+kdMu1+W=nW@)bqmM09Lgp(*OVf diff --git a/docs/basics/DeepRLTutorial/output_9_3.png b/docs/basics/DeepRLTutorial/output_9_3.png index 4dc78d963ae111260894949e24121da50cfda486..80a69998ba9b2d876d4ca0819ebfb923dd78eec0 100644 GIT binary patch literal 77582 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

-?~7?HGm6(IUnhKl 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%0Dgh+|6$eM%xG^>M2B}# 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 d{J*hkF5)nc=JuRK`D*VL1Q* literal 31265 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 diff --git a/docs/basics/quick_start_rl/quickstart.md b/docs/basics/quick_start_rl/quickstart.md index 028b5bbab..a68ae3520 100644 --- a/docs/basics/quick_start_rl/quickstart.md +++ b/docs/basics/quick_start_rl/quickstart.md @@ -353,4 +353,4 @@ output = plot_writer_data( ``` - : As you can see, different visualizations are possible. For more information on plots and visualisation, you can check [here (in construction)](visualisation_page) + : As you can see, different visualizations are possible. For more information on plots and visualization, you can check [here (in construction)](visualization_page) From d129fc3816d558ec4c636b48414ac616a85fbf4b Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 16 Feb 2024 15:48:13 +0100 Subject: [PATCH 73/80] typo --- docs/basics/DeepRLTutorial/TutorialDeepRL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/basics/DeepRLTutorial/TutorialDeepRL.md b/docs/basics/DeepRLTutorial/TutorialDeepRL.md index 65c07f8ce..e0697d07f 100644 --- a/docs/basics/DeepRLTutorial/TutorialDeepRL.md +++ b/docs/basics/DeepRLTutorial/TutorialDeepRL.md @@ -130,7 +130,7 @@ default networks are: ```python """ -The ExperimentManager class is compact way of experimenting with a deepRL agent. +The ExperimentManager class is a compact way of experimenting with a deepRL agent. """ default_agent = ExperimentManager( A2CAgent, # The Agent class. From 768ae95707d70ad9ed84a5e3e8e6f3a693c7aa75 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Fri, 16 Feb 2024 15:52:21 +0100 Subject: [PATCH 74/80] typo --- docs/user_guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index c50599a89..bfcf4544c 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -37,7 +37,7 @@ You can find the guide for ExperimentManager [here](experimentManager_page). ### Logging Logging is used to keep a trace of the experiments. It's include runing informations, data, and results. You can find the guide for Logging [here](logging_page). -### Analyse the results +### Results analysis In construction ## Experimenting with Deep agents ### Torch Agents @@ -86,7 +86,7 @@ In construction - [Agent](agent_page) - [ExperimentManager](experimentManager_page) - [Logging](logging_page). -- [Analyse the results (In construction)]() +- [Results analysis (In construction)]() ## Experimenting with Deep agents - [Torch Agents (In construction)]() - [Policy and Value Networks (In construction)]() From e376bf3ecbad98aff7e0cb1ff6f8bedccfec7bca Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 21 Feb 2024 11:05:39 +0100 Subject: [PATCH 75/80] change .rst to .md --- docs/{index.rst => index.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{index.rst => index.md} (100%) diff --git a/docs/index.rst b/docs/index.md similarity index 100% rename from docs/index.rst rename to docs/index.md From adce03ca3d13deafeed882a399ef22e8d01d05d6 Mon Sep 17 00:00:00 2001 From: JulienT01 Date: Wed, 21 Feb 2024 11:12:17 +0100 Subject: [PATCH 76/80] rework of the index --- docs/index.md | 80 ++++++++++++-------------- docs/themes/scikit-learn-fork/nav.html | 7 ++- docs/user_guide2.rst | 6 -- 3 files changed, 42 insertions(+), 51 deletions(-) diff --git a/docs/index.md b/docs/index.md index 14dc178e2..b896b9b67 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,66 +1,60 @@ -.. image:: ../assets/logo_wide.svg - :width: 50% - :alt: rlberry logo - :align: center +(index)= -.. _rlberry: https://github.com/rlberry-py/rlberry - - -.. _index: - -An RL Library for Research and Education -======================================== - - -:ref:`old user guide` +```{image} ../assets/logo_wide.svg +:align: center +:width: 50% +:alt: rlberry logo +``` +## An RL Library for Research and Education **Writing reinforcement learning algorithms is fun!** *But after the fun, we have lots of boring things to implement*: run our agents in parallel, average and plot results, optimize hyperparameters, compare to baselines, create tricky environments etc etc! -rlberry_ **is here to make your life easier** by doing all these things with a few lines of code, -so that you can spend most of your time developing agents. **Check our** :ref:`the quickstart` +[rlberry](https://github.com/rlberry-py/rlberry) **is here to make your life easier** by doing all these things with a few lines of code, +so that you can spend most of your time developing agents. **Check our** [quickstart](quick_start) **and our** [Deep RL quickstart](TutorialDeepRL). +## Documentation Contents +You can find main documentation here : +- [Installation](installation) +- [User Guide](user_guide) +- [Using extrenal libraries](external) (like [Stable Baselines](stable_baselines) and [Gymnasium](Gymnasium_ancor)) +- [API](api) +- [Changelog](changelog) -In addition, rlberry_: +## Contributing to rlberry +If you want to contribute to rlberry, check out [the contribution guidelines](contributing). -* Provides **implementations of several RL agents** for you to use as a starting point or as baselines; -* Provides a set of **benchmark environments**, very useful to debug and challenge your algorithms; -* Handles all random seeds for you, ensuring **reproducibility** of your results; -* Is **fully compatible with** several commonly used RL libraries like `Gymnasium `_ and `Stable Baselines `_ (see :ref:`userguide/agents`). +## Useful tools +### ExperimentManager +This is one of the core element in [rlberry](https://github.com/rlberry-py/rlberry). The [ExperimentManager](rlberry.manager.experiment_manager.ExperimentManager) allow you to easily make an experiment between an [Agent](agent_page) and an [Environment](environment_page). It's use to train, optimize hyperparameters, evaluate and gather statistics about an agent. See the [ExperimentManager](experimentManager_page) page. - -Seeding & Reproducibility -========================== - -rlberry_ has a class :class:`~rlberry.seeding.seeder.Seeder` that conveniently wraps a `NumPy SeedSequence `_, +### Seeding & Reproducibilitys +[rlberry](https://github.com/rlberry-py/rlberry) has a class [Seeder](rlberry.seeding.seeder.Seeder) that conveniently wraps a [NumPy SeedSequence](https://numpy.org/doc/stable/reference/random/parallel.html), and allows us to create independent random number generators for different objects and threads, using a single -:class:`~rlberry.seeding.seeder.Seeder` instance. See :ref:`Seeding `. - - +[Seeder](rlberry.seeding.seeder.Seeder) instance. See the [Seeding](seeding_page) page. -Contributing to rlberry -======================= -If you want to contribute to rlberry, check out :ref:`the contribution guidelines`. +You can also save and load your experiments. +It could be useful in many way : +- don't repeat the training part every time. +- continue a previous training (or doing checkpoint). +See the [Save and Load Experiment](save_load_page) page. +### AdaStop +TODO : Text +[linked paper](https://hal-lara.archives-ouvertes.fr/hal-04132861/) +[GitHub](https://github.com/TimotheeMathieu/adastop) -Documentation Contents -====================== +### Visualization +TODO : -.. toctree:: - :maxdepth: 3 - installation - user_guide - external -.. toctree:: - :maxdepth: 2 - api - changelog +## And many more ! +Check the [User Guide](user_guide) to find more tools ! diff --git a/docs/themes/scikit-learn-fork/nav.html b/docs/themes/scikit-learn-fork/nav.html index 1bbd96a20..952f0923c 100644 --- a/docs/themes/scikit-learn-fork/nav.html +++ b/docs/themes/scikit-learn-fork/nav.html @@ -31,6 +31,9 @@