{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "9e6c8e57",
"metadata": {
"execution": {
"iopub.execute_input": "2022-02-19T02:24:42.995777Z",
"iopub.status.busy": "2022-02-19T02:24:42.992805Z",
"iopub.status.idle": "2022-02-19T02:24:43.689498Z",
"shell.execute_reply": "2022-02-19T02:24:43.689904Z"
},
"papermill": {
"duration": 0.748936,
"end_time": "2022-02-19T02:24:43.690154",
"exception": false,
"start_time": "2022-02-19T02:24:42.941218",
"status": "completed"
},
"tags": [
"remove_cell"
]
},
"outputs": [],
"source": [
"from abc import abstractmethod, ABC\n",
"from collections import defaultdict\n",
"from random import shuffle, random, sample, randint\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"from negmas import (\n",
" Action,\n",
" Agent,\n",
" NegotiatorMechanismInterface,\n",
" AgentWorldInterface,\n",
" Breach,\n",
" Contract,\n",
" Issue,\n",
" make_issue,\n",
" LinearUtilityFunction,\n",
" MechanismState,\n",
" Negotiator,\n",
" RandomNegotiator,\n",
" RenegotiationRequest,\n",
" SAONegotiator,\n",
" UtilityFunction,\n",
" World,\n",
" AspirationNegotiator,\n",
" dict2outcome,\n",
")\n",
"from negmas.serialization import to_flat_dict\n",
"from typing import Callable, List, Optional, Set, Dict, Any, Collection"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "22db3011",
"metadata": {
"execution": {
"iopub.execute_input": "2022-02-19T02:24:43.747750Z",
"iopub.status.busy": "2022-02-19T02:24:43.747084Z",
"iopub.status.idle": "2022-02-19T02:24:43.761387Z",
"shell.execute_reply": "2022-02-19T02:24:43.761999Z"
},
"papermill": {
"duration": 0.044776,
"end_time": "2022-02-19T02:24:43.762179",
"exception": false,
"start_time": "2022-02-19T02:24:43.717403",
"status": "completed"
},
"tags": [
"remove_cell"
]
},
"outputs": [
{
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# %matplotlib inline\n",
"import warnings\n",
"\n",
"warnings.filterwarnings(\"ignore\")\n",
"# setup disply parameters\n",
"from matplotlib import pylab as plt\n",
"from matplotlib.ticker import StrMethodFormatter\n",
"\n",
"float_formatter = StrMethodFormatter(\"{x:0.03f}\")\n",
"from IPython.core.display import display, HTML\n",
"\n",
"display(HTML(\"\"))\n",
"SMALL_SIZE = 14\n",
"MEDIUM_SIZE = 16\n",
"BIGGER_SIZE = 20\n",
"\n",
"plt.rc(\"font\", size=SMALL_SIZE) # controls default text sizes\n",
"plt.rc(\"axes\", titlesize=SMALL_SIZE) # fontsize of the axes title\n",
"plt.rc(\"axes\", labelsize=MEDIUM_SIZE) # fontsize of the x and y labels\n",
"plt.rc(\"xtick\", labelsize=SMALL_SIZE) # fontsize of the tick labels\n",
"plt.rc(\"ytick\", labelsize=SMALL_SIZE) # fontsize of the tick labels\n",
"plt.rc(\"legend\", fontsize=SMALL_SIZE) # legend fontsize\n",
"plt.rc(\"figure\", titlesize=BIGGER_SIZE) # fontsize of the figure title\n",
"plt.rc(\"figure\", figsize=(18, 6)) # set figure size\n",
"plt.rc(\"animation\", html=\"html5\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "8b18712e",
"metadata": {
"execution": {
"iopub.execute_input": "2022-02-19T02:24:43.843294Z",
"iopub.status.busy": "2022-02-19T02:24:43.814511Z",
"iopub.status.idle": "2022-02-19T02:24:43.845183Z",
"shell.execute_reply": "2022-02-19T02:24:43.845613Z"
},
"papermill": {
"duration": 0.063954,
"end_time": "2022-02-19T02:24:43.845790",
"exception": false,
"start_time": "2022-02-19T02:24:43.781836",
"status": "completed"
},
"tags": [
"remove_cell"
]
},
"outputs": [],
"source": [
"# just repeating the code from the previous tutorial\n",
"class AWI(AgentWorldInterface):\n",
" @property\n",
" def n_negs(self):\n",
" \"\"\"Number of negotiations an agent can start in a step (holiday season)\"\"\"\n",
" return self._world.neg_quota_step\n",
"\n",
" @property\n",
" def agents(self):\n",
" \"\"\"List of all other agent IDs\"\"\"\n",
" return list(_ for _ in self._world.agents.keys() if _ != self.agent.id)\n",
"\n",
" def request_negotiation(\n",
" self, partners: List[str], negotiator: SAONegotiator\n",
" ) -> bool:\n",
" \"\"\"A convenient way to request negotiations\"\"\"\n",
" if self.agent.id not in partners:\n",
" partners.append(self.agent.id)\n",
" req_id = self.agent.create_negotiation_request(\n",
" issues=self._world.ISSUES,\n",
" partners=partners,\n",
" negotiator=negotiator,\n",
" annotation=dict(),\n",
" extra=dict(negotiator_id=negotiator.id),\n",
" )\n",
" return self.request_negotiation_about(\n",
" issues=self._world.ISSUES, partners=partners, req_id=req_id\n",
" )\n",
"\n",
"\n",
"class TripsWorld(World):\n",
" ISSUES = [\n",
" make_issue((0, 100), \"cost\"),\n",
" make_issue(2, \"active\"),\n",
" make_issue((1, 7), \"duration\"),\n",
" ]\n",
"\n",
" def __init__(self, *args, **kwargs):\n",
" \"\"\"Initialize the world\"\"\"\n",
" kwargs[\"awi_type\"] = AWI\n",
" kwargs[\"negotiation_quota_per_step\"] = kwargs.get(\n",
" \"negotiation_quota_per_step\", 8\n",
" )\n",
" kwargs[\"force_signing\"] = True\n",
" kwargs[\"default_signing_delay\"] = 0\n",
" super().__init__(*args, **kwargs)\n",
" self._contracts: Dict[int, List[Contract]] = defaultdict(list)\n",
" self._total_utility: Dict[str, float] = defaultdict(float)\n",
" self._ufuns: Dict[str, UtilityFunction] = dict()\n",
" self._breach_prob: Dict[str, float] = dict()\n",
"\n",
" def join(self, x, ufun=None, breach_prob=None, **kwargs):\n",
" \"\"\"Define the ufun and breach-probability for each agent\"\"\"\n",
" super().join(x, **kwargs)\n",
" weights = (np.random.rand(len(self.ISSUES)) - 0.5).tolist()\n",
" weights = [_ / i.max_value for _, i in zip(weights, self.ISSUES)]\n",
" x.ufun = (\n",
" LinearUtilityFunction(\n",
" weights=weights, reserved_value=0.0, issues=self.ISSUES\n",
" )\n",
" if ufun is None\n",
" else ufun\n",
" )\n",
" self._ufuns[x.id] = x.ufun\n",
" self._breach_prob[x.id] = random() * 0.1 if breach_prob is None else breach_prob\n",
"\n",
" def simulation_step(self, stage: int = 0):\n",
" \"\"\"What happens in this world? Nothing\"\"\"\n",
" pass\n",
"\n",
" def get_private_state(self, agent: Agent) -> dict:\n",
" \"\"\"What is the information available to agents? total utility points\"\"\"\n",
" return dict(total_utility=self._total_utility[agent.id])\n",
"\n",
" def execute_action(\n",
" self, action: Action, agent: Agent, callback: Callable | None = None\n",
" ) -> bool:\n",
" \"\"\"Executing actions by agents? No actions available\"\"\"\n",
" pass\n",
"\n",
" def on_contract_signed(self, contract: Contract) -> None:\n",
" \"\"\"Save the contract to be executed in the following hoiday season (step)\"\"\"\n",
" super().on_contract_signed(contract)\n",
" self._contracts[self.current_step + 1].append(contract)\n",
"\n",
" def executable_contracts(self) -> Collection[Contract]:\n",
" \"\"\"What contracts are to be executed in the current step?\n",
" Ones that were signed the previous step\"\"\"\n",
" return self._contracts[self.current_step]\n",
"\n",
" def order_contracts_for_execution(\n",
" self, contracts: Collection[Contract]\n",
" ) -> Collection[Contract]:\n",
" \"\"\"What should be the order of contract execution? Random\"\"\"\n",
" shuffle(contracts)\n",
" return contracts\n",
"\n",
" def start_contract_execution(self, contract: Contract) -> Optional[Set[Breach]]:\n",
" \"\"\"What should happen when a contract comes due?\n",
" 1. Find out if it will be breached\n",
" 2. If not, add to each agent its utility from the trip\n",
" \"\"\"\n",
" breaches = []\n",
" for aid in contract.partners:\n",
" if random() < self._breach_prob[aid]:\n",
" breaches.append(\n",
" Breach(\n",
" contract,\n",
" aid,\n",
" \"breach\",\n",
" victims=[_ for _ in contract.partners if _ != aid],\n",
" )\n",
" )\n",
" if len(breaches) > 0:\n",
" return set(breaches)\n",
" for aid in contract.partners:\n",
" self._total_utility[aid] += self._ufuns[aid](\n",
" dict2outcome(contract.agreement, issues=self.ISSUES)\n",
" )\n",
" return set()\n",
"\n",
" def complete_contract_execution(\n",
" self, contract: Contract, breaches: List[Breach], resolution: Contract\n",
" ) -> None:\n",
" \"\"\"What happens if a breach was resolved? Nothing. They cannot\"\"\"\n",
" pass\n",
"\n",
" def delete_executed_contracts(self) -> None:\n",
" \"\"\"Removes all contracts for the current step\"\"\"\n",
" if self._current_step in self._contracts.keys():\n",
" del self._contracts[self.current_step]\n",
"\n",
" def contract_record(self, contract: Contract) -> Dict[str, Any]:\n",
" \"\"\"Convert the contract into a dictionary for saving\"\"\"\n",
" return to_flat_dict(contract)\n",
"\n",
" def breach_record(self, breach: Breach) -> Dict[str, Any]:\n",
" \"\"\"Convert the breach into a dictionary for saving\"\"\"\n",
" return to_flat_dict(breach)\n",
"\n",
" def contract_size(self, contract: Contract) -> float:\n",
" \"\"\"How good is a contract? Welfare\"\"\"\n",
" if contract.agreement is None:\n",
" return 0.0\n",
" return sum(\n",
" self._ufuns[aid](dict2outcome(contract.agreement, issues=self.ISSUES))\n",
" for aid in contract.partners\n",
" )\n",
"\n",
" def post_step_stats(self):\n",
" for aid, agent in self.agents.items():\n",
" self._stats[f\"total_utility_{agent.name}\"].append(self._total_utility[aid])\n",
"\n",
"\n",
"class Person(Agent, ABC):\n",
" @abstractmethod\n",
" def step(self):\n",
" ...\n",
"\n",
" @abstractmethod\n",
" def init(self):\n",
" ...\n",
"\n",
" @abstractmethod\n",
" def respond_to_negotiation_request(\n",
" self,\n",
" initiator: str,\n",
" partners: List[str],\n",
" mechanism: NegotiatorMechanismInterface,\n",
" ) -> Optional[Negotiator]:\n",
" ...\n",
"\n",
" def _respond_to_negotiation_request(\n",
" self,\n",
" initiator: str,\n",
" partners: List[str],\n",
" issues: List[Issue],\n",
" annotation: Dict[str, Any],\n",
" mechanism: NegotiatorMechanismInterface,\n",
" role: Optional[str],\n",
" req_id: Optional[str],\n",
" ) -> Optional[Negotiator]:\n",
" return self.respond_to_negotiation_request(initiator, partners, mechanism)\n",
"\n",
" def on_neg_request_rejected(self, req_id: str, by: Optional[List[str]]):\n",
" pass\n",
"\n",
" def on_neg_request_accepted(\n",
" self, req_id: str, mechanism: NegotiatorMechanismInterface\n",
" ):\n",
" pass\n",
"\n",
" def on_negotiation_failure(\n",
" self,\n",
" partners: List[str],\n",
" annotation: Dict[str, Any],\n",
" mechanism: NegotiatorMechanismInterface,\n",
" state: MechanismState,\n",
" ) -> None:\n",
" pass\n",
"\n",
" def on_negotiation_success(\n",
" self, contract: Contract, mechanism: NegotiatorMechanismInterface\n",
" ) -> None:\n",
" pass\n",
"\n",
" def set_renegotiation_agenda(\n",
" self, contract: Contract, breaches: List[Breach]\n",
" ) -> Optional[RenegotiationRequest]:\n",
" pass\n",
"\n",
" def respond_to_renegotiation_request(\n",
" self, contract: Contract, breaches: List[Breach], agenda: RenegotiationRequest\n",
" ) -> Optional[Negotiator]:\n",
" pass\n",
"\n",
" def on_contract_executed(self, contract: Contract) -> None:\n",
" pass\n",
"\n",
" def on_contract_breached(\n",
" self, contract: Contract, breaches: List[Breach], resolution: Optional[Contract]\n",
" ) -> None:\n",
" pass\n"
]
},
{
"cell_type": "markdown",
"id": "50d97a6f",
"metadata": {
"papermill": {
"duration": 0.02383,
"end_time": "2022-02-19T02:24:43.893406",
"exception": false,
"start_time": "2022-02-19T02:24:43.869576",
"status": "completed"
},
"tags": []
},
"source": [
"## Develop a new agent (for your simulation)\n",
"\n",
"In the previous tutorial, we implemented a world simulation called `TripsWorld` in which agents negotiated how to spend their holiday seasons. In this tutorial we will develop agents for this world and take it on a test-drive.\n",
"\n",
"\n",
"### Making a Random Agent for the Trips World\n",
"\n",
"Our random agent, will just use a random negotiator for everything and will not keep track of the history of other agents. That is the complete code which is self explanatory this time."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "2dd4b012",
"metadata": {
"execution": {
"iopub.execute_input": "2022-02-19T02:24:43.961841Z",
"iopub.status.busy": "2022-02-19T02:24:43.961199Z",
"iopub.status.idle": "2022-02-19T02:24:43.963610Z",
"shell.execute_reply": "2022-02-19T02:24:43.964043Z"
},
"papermill": {
"duration": 0.03881,
"end_time": "2022-02-19T02:24:43.964224",
"exception": false,
"start_time": "2022-02-19T02:24:43.925414",
"status": "completed"
},
"tags": []
},
"outputs": [],
"source": [
"class RandomPerson(Person):\n",
" def step(self):\n",
" # get IDs of all ogher agents from the AWI\n",
" agents = self.awi.agents\n",
" # request the maximum number of negotiations possible\n",
" for _ in range(self.awi.n_negs):\n",
" # for each negotiation, use a random subset of partners and a random negotiator\n",
" self.awi.request_negotiation(\n",
" partners=sample(agents, k=randint(1, len(agents) - 1)),\n",
" negotiator=RandomNegotiator(),\n",
" )\n",
"\n",
" def init(self):\n",
" # we need no initialization\n",
" pass\n",
"\n",
" def respond_to_negotiation_request(\n",
" self,\n",
" initiator: str,\n",
" partners: List[str],\n",
" mechanism: NegotiatorMechanismInterface,\n",
" ) -> Optional[Negotiator]:\n",
" # just us a random negotiator for everything\n",
" return RandomNegotiator()"
]
},
{
"cell_type": "markdown",
"id": "843af325",
"metadata": {
"papermill": {
"duration": 0.033196,
"end_time": "2022-02-19T02:24:44.023888",
"exception": false,
"start_time": "2022-02-19T02:24:43.990692",
"status": "completed"
},
"tags": []
},
"source": [
"### Testing the world\n",
"\n",
"We can now start world simulations using our new world and agent"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ab763a10",
"metadata": {
"execution": {
"iopub.execute_input": "2022-02-19T02:24:44.082266Z",
"iopub.status.busy": "2022-02-19T02:24:44.081377Z",
"iopub.status.idle": "2022-02-19T02:24:50.396570Z",
"shell.execute_reply": "2022-02-19T02:24:50.397364Z"
},
"papermill": {
"duration": 6.349259,
"end_time": "2022-02-19T02:24:50.397694",
"exception": false,
"start_time": "2022-02-19T02:24:44.048435",
"status": "completed"
},
"tags": []
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n",
" 0%| | 0/10 [00:00, ?it/s]\n",
" 10%|█████████████████▌ | 1/10 [00:00<00:01, 6.98it/s]\n",
" 20%|███████████████████████████████████▏ | 2/10 [00:00<00:03, 2.40it/s]\n",
" 30%|████████████████████████████████████████████████████▊ | 3/10 [00:01<00:03, 1.85it/s]\n",
" 40%|██████████████████████████████████████████████████████████████████████▍ | 4/10 [00:01<00:03, 1.86it/s]\n",
" 50%|████████████████████████████████████████████████████████████████████████████████████████ | 5/10 [00:02<00:03, 1.60it/s]\n",
" 60%|█████████████████████████████████████████████████████████████████████████████████████████████████████████▌ | 6/10 [00:03<00:02, 1.50it/s]\n",
" 70%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏ | 7/10 [00:04<00:01, 1.55it/s]\n",
" 80%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▊ | 8/10 [00:04<00:01, 1.55it/s]\n",
" 90%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▍ | 9/10 [00:05<00:00, 1.47it/s]\n",
"100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:06<00:00, 1.41it/s]\n",
"100%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 10/10 [00:06<00:00, 1.59it/s]\n"
]
}
],
"source": [
"world = TripsWorld(n_steps=10, construct_graphs=True)\n",
"for i in range(5):\n",
" world.join(RandomPerson(name=f\"a{i}\"))\n",
"world.run_with_progress()"
]
},
{
"cell_type": "markdown",
"id": "7e75b4bf",
"metadata": {
"papermill": {
"duration": 0.049469,
"end_time": "2022-02-19T02:24:50.491167",
"exception": false,
"start_time": "2022-02-19T02:24:50.441698",
"status": "completed"
},
"tags": []
},
"source": [
"Let's see what happened in this run. Firstly, how many negotiations were conducted over time. Our agents always conducted the maximum number of negotiations ($8$) and we had $5$ agents which means we expect $40$ negotiations at every step."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "75a618ca",
"metadata": {
"execution": {
"iopub.execute_input": "2022-02-19T02:24:50.613098Z",
"iopub.status.busy": "2022-02-19T02:24:50.587063Z",
"iopub.status.idle": "2022-02-19T02:24:50.872296Z",
"shell.execute_reply": "2022-02-19T02:24:50.872738Z"
},
"papermill": {
"duration": 0.342845,
"end_time": "2022-02-19T02:24:50.873014",
"exception": false,
"start_time": "2022-02-19T02:24:50.530169",
"status": "completed"
},
"tags": []
},
"outputs": [
{
"data": {
"image/png": "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v/2ttm3bpqSkJOXl5VnHXV1d9fLLL+vee+9VeHi4pk6dKkmaMWOGHnnkEUnS1KlT9Ze//EWjR4/WokWL5OnpqaefflrffPNNhWu88MIL6tevn5YsWSJ/f39Nnjy5QsABAAB4VQQAgFvan/70J506dUqJiYlKTExU8+bNFRwcrPDwcA0ZMkReXl7VntusWTOtXbtWjRs3Vnh4uHbs2KEuXbro5ZdfliQFBATo448/VmZmplq1avWza7NYLDp//rzmzp2r3r17S5IGDhyov/3tb8rMzFSfPn3Ut29fSVL79u0VFBRUaY7169fr7Nmz2rJli/VVl/79++v+++/X66+/bq31ypUrWrx4sQYOHChJatGihUaNGqVvv/222tc95s2bp6lTp2rJkiVasmSJWrRooXvvvVe9e/fWkCFD1KRJE7Vs2dJaV7du3fSb3/xGX375pXbt2qU333xT4eHhkq4/pfHYY48pMTFRq1evtl7jmWee0ZgxY6zHDB06VAkJCXr99dd/9u8TAIBbFcEFAAC3MB8fHyUnJysvL0/79+/X119/rbS0NH388cdavXq13nrrLQUEBFR5bkhIiBo3bixJuu222yRd/+P8hqZNm0qSLl++/Itqa9SokXbs2CGLxaJ///vfOnbsmL7//ntduXJFZrPZpjn279+v0NDQCutzNG3aVPfdd58yMjKsYyaTqcLTJTdeAbnZExcdOnTQ9u3blZWVpbS0NOvvbufOnUpISNCGDRuqfJXks88+U9OmTdWtW7cKv5uwsDC9//77FY7t379/hd9HRESEduzYYdO9AwDQUBBcAADQALRt21Zt27bV8OHDJV3/g3/SpElavny59XWM/+Th4VFprEmTJpXGfvr6yX+yWCw3rSsxMVFJSUkqLS3Vb37zG3Xr1k0uLi43Peenzp07J39//0rjHh4eKi0ttW67urpWWOfDycnJpvokqWPHjurYsaOefvppWSwWffjhh5o+fboSExM1Z86cSsefPXtWly9ftn4Lyk/dCIJu8PHxqbDdrFkznT9/vsaaAABoSAguAAC4RWVmZuqJJ57QunXrKr0OERYWpgEDBlR4KuHXuhEG/FRRUVG1x3/++edaunSp5s2bp9/97ncymUySrq+tYSsfH58q/9A/ceJElU9D2Grnzp164YUX9Le//U1t27a1jjdq1EgPP/yw3n777QpraPyUh4eHfHx8tHLlykr7/vN3dPny5QoB0enTp2/6+g4AAA0Ri3MCAHCLuvvuu+Xh4aF333230j6LxaKcnBzdeeedtXa9Jk2a6NKlSxXGbrbQ5OHDh9WoUSNFRUVZQ4uDBw/q6tWrNl+zS5cu+uKLLyoEJOfOnVN6evqv+qrSrl27ymQyVfm7Kykp0bFjx9SmTZsqzw0JCdH58+fVqlUrhYSEWH/ee+89/fWvf61w7L59+6z/Li0t1Z49e6p8UgMAgIaMJy4AALhFubq6avr06Zo5c6bOnz+vwYMH67bbbtPJkyf17rvv6vDhw3rzzTdr7XrBwcHauHGjNmzYoIEDB2rfvn366KOPqj2+S5cuslgsmjlzpu6//34dPnxY27dvV/PmzfX9998rLy9Pbdu2lbu7uw4cOKB77723whobkjRu3Dht3bpVo0aN0siRI+Xm5qZ169bptttus74W80u0atVK48eP1+rVq5WXl6e+ffvK3d1deXl52rZtm4qLi/X0009L+v9rfezatUuenp7q37+/AgMDNW7cOD3zzDNq2rSpPvroI73//vtau3ZthessX75cly9fVosWLbR582adO3dO48aN+8V1AwBwKyK4AADgFjZs2DC1bNlSb731lubNm6fS0lK1atVKvXr10v/8z/9UuT7ELzVkyBB9//33WrVqlZYuXaqePXtq5syZmj59epXHh4aGKjY2Vm+88YZ27typkJAQrVmzRh9//LFee+01HThwQG3bttXTTz+tdevWqVGjRlqzZk2FOVq0aKHk5GQtWrRIL7/8sho3bqwePXpo0aJF1kDhl5o8ebL8/f319ttva+bMmSovL1erVq3Uv39/jRw50vpNKp07d1Z4eLjWrVun5s2ba9y4cXr99de1aNEiLV68WFevXtVdd92l1atXW78l5Ya5c+dq1apVys3N1V133aWkpCQFBgb+qroBALjVOJXfbEUtAAAA1Lrt27crNjZWX3zxhby9veu6HAAADI01LgAAAAAAgGERXAAAAAAAAMPiVREAAAAAAGBYPHEBAAAAAAAMi+ACAAAAAAAYFsEFAAAAAAAwLIILAAAAAABgWAQXAAAAAADAsAguAAAAAACAYf0/7k7U2EaI8/AAAAAASUVORK5CYII=",
"text/plain": [
"