c9e28b8135
JetStream: anatomia de streams (storage/retention/limits), consumers pull durables con ack y cursor, dedup por Nats-Msg-Id, retencion workqueue, deliver policies. Simulador: boton ipywidgets que lanza 1 publisher -> N subscribers con miles de mensajes y grafica en movimiento (acumulado + throughput instantaneo).
528 lines
79 KiB
Plaintext
528 lines
79 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "05860b9f",
|
|
"metadata": {},
|
|
"source": [
|
|
"# NATS pub/sub — 03 · Procesos del sistema operativo reales\n",
|
|
"\n",
|
|
"En los notebooks 01 y 02 todo ocurrió dentro de un mismo kernel: varias conexiones `asyncio` simulaban procesos distintos. Eso es cómodo para explicar, pero NATS brilla precisamente cuando los participantes son **procesos del sistema operativo separados** —incluso en máquinas distintas— que solo comparten la dirección del broker y los nombres de subject.\n",
|
|
"\n",
|
|
"Aquí lanzamos **procesos reales** con `subprocess`:\n",
|
|
"\n",
|
|
"- un **publisher** (`procs/publisher.py`) que emite telemetría a `telemetria.cpu` y `telemetria.mem`;\n",
|
|
"- dos **subscribers** independientes (`procs/subscriber.py`), cada uno con su propio PID:\n",
|
|
" - `sub-todo` escucha `telemetria.>` (toda la telemetría),\n",
|
|
" - `sub-cpu` escucha solo `telemetria.cpu`.\n",
|
|
"\n",
|
|
"Cada proceso abre su propia conexión al broker. El publisher **no sabe** cuántos subscribers hay ni qué escuchan: solo publica a un subject. Ese es el desacople real."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "c5127085",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 0 · Broker + scripts de los procesos\n",
|
|
"\n",
|
|
"Arrancamos el broker (idempotente) y mostramos el código de los dos scripts que vamos a lanzar como procesos. Cada uno es un programa autónomo que se conecta a `nats://127.0.0.1:4222` y emite eventos como líneas JSON en su stdout, que el notebook recogerá."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "bb720c29",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Broker: already-running\n",
|
|
"Scripts de proceso en: /home/enmanuel/fn_registry/analysis/nats/notebooks/procs\n",
|
|
"\n",
|
|
"=== procs/publisher.py ===\n",
|
|
"#!/usr/bin/env python3\n",
|
|
"\"\"\"Publisher NATS como proceso del sistema operativo independiente.\n",
|
|
"\n",
|
|
"Se conecta al broker y publica una rafaga de mensajes de telemetria,\n",
|
|
"alternando entre los subjects `telemetria.cpu` y `telemetria.mem`.\n",
|
|
"No sabe ni le importa cuantos subscribers hay escuchando: solo conoce el\n",
|
|
"subject. Emite cada publicacion como linea JSON en stdout.\n",
|
|
"\"\"\"\n",
|
|
"import argparse\n",
|
|
"import asyncio\n",
|
|
"import json\n",
|
|
"import os\n",
|
|
"import random\n",
|
|
"import time\n",
|
|
"\n",
|
|
"import nats\n",
|
|
"\n",
|
|
"NATS_URL = \"nats://127.0.0.1:4222\"\n",
|
|
"\n",
|
|
"\n",
|
|
"def emit(event: dict) -> None:\n",
|
|
" print(json.dumps(event), flush=True)\n",
|
|
"\n",
|
|
"\n",
|
|
"async def main(count: int, interval: float) -> None:\n",
|
|
" pid = os.getpid()\n",
|
|
" nc = await nats.connect(NATS_URL, name=\"publisher\")\n",
|
|
" emit({\"event\": \"ready\", \"pid\": pid, \"name\": \"publisher\"})\n",
|
|
"\n",
|
|
" for i in range(count):\n",
|
|
" subject = \"telemetria.cpu\" if i % 2 == 0 else \"telemetria.mem\"\n",
|
|
" payload = json.dumps({\"i\": i, \"valor\": round(random.uniform(0, 100), 1)})\n",
|
|
" await nc.publish(subject, payload.encode())\n",
|
|
" emit({\"event\": \"published\", \"pid\": pid, \"subject\": subject, \"i\": i})\n",
|
|
" await asyncio.sleep(interval)\n",
|
|
"\n",
|
|
" await nc.flush()\n",
|
|
" emit({\"event\": \"done\", \"pid\": pid, \"name\": \"publisher\", \"published\": count})\n",
|
|
" await nc.drain()\n",
|
|
"\n",
|
|
"\n",
|
|
"if __name__ == \"__main__\":\n",
|
|
" parser = argparse.ArgumentParser(description=\"Publisher NATS de demostracion\")\n",
|
|
" parser.add_argument(\"--count\", type=int, default=8, help=\"Numero de mensajes a publicar\")\n",
|
|
" parser.add_argument(\"--interval\", type=float, default=0.15,\n",
|
|
" help=\"Segundos entre publicaciones\")\n",
|
|
" args = parser.parse_args()\n",
|
|
" asyncio.run(main(args.count, args.interval))\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"import subprocess, time, json\n",
|
|
"\n",
|
|
"NATS_CONTAINER = \"nats_demo\"\n",
|
|
"NATS_PORT = 4222\n",
|
|
"NATS_URL = f\"nats://127.0.0.1:{NATS_PORT}\"\n",
|
|
"\n",
|
|
"def _docker(*args, check=True):\n",
|
|
" return subprocess.run([\"docker\", *args], capture_output=True, text=True, check=check)\n",
|
|
"\n",
|
|
"def ensure_nats(name=NATS_CONTAINER, port=NATS_PORT):\n",
|
|
" \"\"\"Arranca un broker NATS en Docker de forma idempotente. Devuelve el estado.\"\"\"\n",
|
|
" out = _docker(\"ps\", \"-a\", \"--filter\", f\"name=^{name}$\", \"--format\", \"{{.State}}\", check=False).stdout.strip()\n",
|
|
" if out == \"running\":\n",
|
|
" state = \"already-running\"\n",
|
|
" elif out in (\"exited\", \"created\", \"paused\"):\n",
|
|
" _docker(\"start\", name)\n",
|
|
" state = \"started\"\n",
|
|
" else:\n",
|
|
" _docker(\"run\", \"-d\", \"--name\", name, \"-p\", f\"{port}:4222\", \"-p\", \"8222:8222\",\n",
|
|
" \"nats:latest\", \"-js\", \"-m\", \"8222\")\n",
|
|
" state = \"created\"\n",
|
|
" time.sleep(1.0)\n",
|
|
" return state\n",
|
|
"\n",
|
|
"from pathlib import Path\n",
|
|
"\n",
|
|
"PROCS = Path(r\"/home/enmanuel/fn_registry/analysis/nats/notebooks/procs\")\n",
|
|
"print(\"Broker:\", ensure_nats())\n",
|
|
"print(\"Scripts de proceso en:\", PROCS)\n",
|
|
"print()\n",
|
|
"print(\"=== procs/publisher.py ===\")\n",
|
|
"print(Path(PROCS / \"publisher.py\").read_text())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "3412b705",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"=== procs/subscriber.py ===\n",
|
|
"#!/usr/bin/env python3\n",
|
|
"\"\"\"Subscriber NATS como proceso del sistema operativo independiente.\n",
|
|
"\n",
|
|
"Se conecta al broker, se suscribe a uno o varios subjects y emite cada evento\n",
|
|
"como una linea JSON en stdout para que el proceso padre (el notebook) la lea.\n",
|
|
"Termina solo tras `--seconds` segundos.\n",
|
|
"\"\"\"\n",
|
|
"import argparse\n",
|
|
"import asyncio\n",
|
|
"import json\n",
|
|
"import os\n",
|
|
"import time\n",
|
|
"\n",
|
|
"import nats\n",
|
|
"\n",
|
|
"NATS_URL = \"nats://127.0.0.1:4222\"\n",
|
|
"\n",
|
|
"\n",
|
|
"def emit(event: dict) -> None:\n",
|
|
" \"\"\"Escribe un evento como linea JSON en stdout, con flush inmediato.\"\"\"\n",
|
|
" print(json.dumps(event), flush=True)\n",
|
|
"\n",
|
|
"\n",
|
|
"async def main(name: str, subjects: list[str], seconds: float) -> None:\n",
|
|
" pid = os.getpid()\n",
|
|
" nc = await nats.connect(NATS_URL, name=name)\n",
|
|
" received = 0\n",
|
|
" t0 = time.monotonic()\n",
|
|
"\n",
|
|
" async def handler(msg):\n",
|
|
" nonlocal received\n",
|
|
" received += 1\n",
|
|
" emit({\n",
|
|
" \"event\": \"msg\",\n",
|
|
" \"pid\": pid,\n",
|
|
" \"name\": name,\n",
|
|
" \"subject\": msg.subject,\n",
|
|
" \"data\": msg.data.decode(),\n",
|
|
" \"t\": round(time.monotonic() - t0, 4),\n",
|
|
" })\n",
|
|
"\n",
|
|
" for subject in subjects:\n",
|
|
" await nc.subscribe(subject, cb=handler)\n",
|
|
"\n",
|
|
" # Senal de que este proceso ya esta escuchando (el padre la espera).\n",
|
|
" emit({\"event\": \"ready\", \"pid\": pid, \"name\": name, \"subjects\": subjects})\n",
|
|
"\n",
|
|
" await asyncio.sleep(seconds)\n",
|
|
" emit({\"event\": \"done\", \"pid\": pid, \"name\": name, \"received\": received})\n",
|
|
" await nc.drain()\n",
|
|
"\n",
|
|
"\n",
|
|
"if __name__ == \"__main__\":\n",
|
|
" parser = argparse.ArgumentParser(description=\"Subscriber NATS de demostracion\")\n",
|
|
" parser.add_argument(\"--name\", required=True, help=\"Nombre logico del subscriber\")\n",
|
|
" parser.add_argument(\"--subjects\", required=True,\n",
|
|
" help=\"Subjects separados por coma (admite wildcards)\")\n",
|
|
" parser.add_argument(\"--seconds\", type=float, default=4.0,\n",
|
|
" help=\"Tiempo de escucha antes de terminar\")\n",
|
|
" args = parser.parse_args()\n",
|
|
" asyncio.run(main(args.name, args.subjects.split(\",\"), args.seconds))\n",
|
|
"\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"print(\"=== procs/subscriber.py ===\")\n",
|
|
"print((PROCS / \"subscriber.py\").read_text())"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e17dd705",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 1 · Lanzar los procesos y orquestarlos\n",
|
|
"\n",
|
|
"El notebook actúa de **orquestador**:\n",
|
|
"\n",
|
|
"1. Lanza los dos subscribers como procesos (`subprocess.Popen`), cada uno con su PID. Les damos 1.5 s para que conecten y se suscriban.\n",
|
|
"2. Lanza el publisher, que emite 8 mensajes y termina.\n",
|
|
"3. Espera a que los subscribers terminen solos (su `--seconds`) y recoge su stdout.\n",
|
|
"\n",
|
|
"Usamos `sys.executable` para que los procesos hijos usen el mismo intérprete (con `nats-py` instalado) que el kernel."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "f647029e",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Subscribers lanzados (PIDs del SO): {'sub-todo': 4191523, 'sub-cpu': 4191524}\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Publisher (PID 4191735) publicó 8 mensajes\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"\n",
|
|
"Total de entregas recibidas entre todos los procesos: 12\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"import subprocess, sys, json, time\n",
|
|
"\n",
|
|
"def lanzar_subscriber(nombre, subjects, seconds=4.5):\n",
|
|
" return subprocess.Popen(\n",
|
|
" [sys.executable, str(PROCS / \"subscriber.py\"),\n",
|
|
" \"--name\", nombre, \"--subjects\", subjects, \"--seconds\", str(seconds)],\n",
|
|
" stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True,\n",
|
|
" )\n",
|
|
"\n",
|
|
"# 1. Subscribers: procesos OS independientes\n",
|
|
"procs = {\n",
|
|
" \"sub-todo\": lanzar_subscriber(\"sub-todo\", \"telemetria.>\"),\n",
|
|
" \"sub-cpu\": lanzar_subscriber(\"sub-cpu\", \"telemetria.cpu\"),\n",
|
|
"}\n",
|
|
"print(\"Subscribers lanzados (PIDs del SO):\", {n: p.pid for n, p in procs.items()})\n",
|
|
"time.sleep(1.5) # que conecten y se suscriban antes de publicar\n",
|
|
"\n",
|
|
"# 2. Publisher: otro proceso OS, publica 8 mensajes y termina\n",
|
|
"pub = subprocess.run(\n",
|
|
" [sys.executable, str(PROCS / \"publisher.py\"), \"--count\", \"8\", \"--interval\", \"0.15\"],\n",
|
|
" stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True,\n",
|
|
")\n",
|
|
"pub_eventos = [json.loads(l) for l in pub.stdout.splitlines() if l.strip()]\n",
|
|
"print(f\"Publisher (PID {pub_eventos[0]['pid']}) publicó {sum(1 for e in pub_eventos if e['event']=='published')} mensajes\")\n",
|
|
"\n",
|
|
"# 3. Recoger stdout de los subscribers (terminan solos por --seconds)\n",
|
|
"eventos = []\n",
|
|
"for nombre, p in procs.items():\n",
|
|
" out, err = p.communicate(timeout=10)\n",
|
|
" for l in out.splitlines():\n",
|
|
" if l.strip():\n",
|
|
" eventos.append(json.loads(l))\n",
|
|
" if err.strip():\n",
|
|
" print(f\"[{nombre} stderr] {err.strip()[:200]}\")\n",
|
|
"\n",
|
|
"msgs = [e for e in eventos if e[\"event\"] == \"msg\"]\n",
|
|
"print(f\"\\nTotal de entregas recibidas entre todos los procesos: {len(msgs)}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "33dcf1f4",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 2 · Qué recibió cada proceso\n",
|
|
"\n",
|
|
"Cada subscriber es un PID distinto. `sub-todo` (suscrito a `telemetria.>`) recibe los 8 mensajes; `sub-cpu` (suscrito solo a `telemetria.cpu`) recibe únicamente los 4 de CPU. El broker filtró por subject sin que el publisher supiera nada de ello."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "01ae57ed",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"PID de cada proceso subscriber: {'sub-todo': 4191523, 'sub-cpu': 4191524}\n",
|
|
"\n",
|
|
"Mensajes recibidos por proceso y subject:\n",
|
|
"subject telemetria.cpu telemetria.mem\n",
|
|
"name \n",
|
|
"sub-cpu 4 0\n",
|
|
"sub-todo 4 4\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<div>\n",
|
|
"<style scoped>\n",
|
|
" .dataframe tbody tr th:only-of-type {\n",
|
|
" vertical-align: middle;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe tbody tr th {\n",
|
|
" vertical-align: top;\n",
|
|
" }\n",
|
|
"\n",
|
|
" .dataframe thead th {\n",
|
|
" text-align: right;\n",
|
|
" }\n",
|
|
"</style>\n",
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th>subject</th>\n",
|
|
" <th>telemetria.cpu</th>\n",
|
|
" <th>telemetria.mem</th>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>name</th>\n",
|
|
" <th></th>\n",
|
|
" <th></th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>sub-cpu</th>\n",
|
|
" <td>4</td>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>sub-todo</th>\n",
|
|
" <td>4</td>\n",
|
|
" <td>4</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
"subject telemetria.cpu telemetria.mem\n",
|
|
"name \n",
|
|
"sub-cpu 4 0\n",
|
|
"sub-todo 4 4"
|
|
]
|
|
},
|
|
"execution_count": 4,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"import pandas as pd\n",
|
|
"\n",
|
|
"df = pd.DataFrame(msgs)\n",
|
|
"# PID por nombre de proceso (demuestra que son procesos distintos)\n",
|
|
"pids = {e[\"name\"]: e[\"pid\"] for e in eventos if e[\"event\"] == \"ready\"}\n",
|
|
"print(\"PID de cada proceso subscriber:\", pids)\n",
|
|
"print()\n",
|
|
"\n",
|
|
"# Conteo de mensajes por (proceso, subject)\n",
|
|
"tabla = df.groupby([\"name\", \"subject\"]).size().unstack(fill_value=0)\n",
|
|
"print(\"Mensajes recibidos por proceso y subject:\")\n",
|
|
"print(tabla)\n",
|
|
"tabla"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "9a5ee65b",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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",
|
|
"text/plain": [
|
|
"<Figure size 700x320 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data",
|
|
"transient": {}
|
|
}
|
|
],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"\n",
|
|
"resumen = df.groupby(\"name\").size().reindex([\"sub-todo\", \"sub-cpu\"]).fillna(0).astype(int)\n",
|
|
"\n",
|
|
"fig, ax = plt.subplots(figsize=(7, 3.2))\n",
|
|
"barras = ax.bar(resumen.index, resumen.values, color=[\"#7c3aed\", \"#0891b2\"])\n",
|
|
"ax.bar_label(barras, padding=3)\n",
|
|
"ax.set_ylabel(\"mensajes recibidos\")\n",
|
|
"ax.set_title(\"Telemetría recibida por cada PROCESO (8 publicados: 4 cpu + 4 mem)\")\n",
|
|
"ax.set_ylim(0, 10)\n",
|
|
"for i, name in enumerate(resumen.index):\n",
|
|
" ax.text(i, -1.4, f\"PID {pids.get(name, '?')}\\n{('telemetria.>' if name=='sub-todo' else 'telemetria.cpu')}\",\n",
|
|
" ha=\"center\", va=\"top\", fontsize=8, color=\"#555\")\n",
|
|
"plt.tight_layout(); plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b8d60d73",
|
|
"metadata": {},
|
|
"source": [
|
|
"## 3 · Línea de tiempo de las entregas\n",
|
|
"\n",
|
|
"Ordenando los mensajes por su marca temporal (`t`, segundos desde que cada proceso arrancó) se ve cómo ambos subscribers reciben los mensajes de CPU casi a la vez (fan-out), mientras que los de memoria solo llegan a `sub-todo`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "1656576f",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "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xY+siImJUXuun7b127x5M/r27YuePXsiNTUV3377Lfz9/dWSpGHDhgEAOnTogB9//FGtjnbt2sHT07NC8Wmjy2MSgMeJpLW1Nb799ltYWFhALpejTZs28PDwwPfff4/u3bujSZMmGDZsGFxcXHDt2jXs378flpaW+O2337TWWZOfOboev01NTeHv74+ff/4ZPj4+sLW1RdOmTbXes1uWnj17YuHChXjllVcwePBg3L59G0uXLkWjRo3UPpcA3fdBRXz++efYv38/2rRpg1GjRsHf3x/379/HiRMnsHfvXq3PwCV6KjU1XCeRPqjMYxLmzZunVq54GOSSw9sXD1mdkJCgUT40NFRYWVkJExMT4eXlJYYOHSr++usvVZmKPCZBW/3QMpS6LsstzalTp0RISIgwMTERLi4uYtasWWLlypVahzF/muXk5OSIadOmiUaNGgkjIyNRv3590a5dOzF//nzVENOl7QchhMbw20VFRWLChAnCzs5OSCQS1TYtqw4hhEhJSRERERHC0dFRGBoaChcXF/Hqq6+KjRs3qpVLTEwU7du3F8bGxqJBgwZizpw54quvvhIAxM2bN1Xl4uPjRdu2bYWpqalwdnYWH3zwgWro7eL9dPnyZTF8+HDh5eUlTExMhK2trejUqZPYu3dvuduturi5uYmePXtqfS8lJUX0799fWFtbCxMTE9G6dWuxbds2tTLaHpMghBB79+4VwcHBwtTUVFhaWopevXqJs2fPaiwDOj4mQYjHw7S7uLgIqVSq0S43bdokXnrpJSGXy4VcLheNGzcW48aNE8nJyaoy2oZhF0KI5cuXi5YtWwpTU1NhYWEhAgICxAcffCCuX7+uKlPadgIgxo0bp3WblGx7ura5FStWCE9PTyGTydTaT1n7SttjEt5//33h5OQkTE1NRXBwsDhy5IjWYf5L2werVq0SgYGBwtjYWNjY2IiQkBCxZ88ejW2ye/du0axZM2FsbCwaN26s9TEgf//9t2jTpo0wMjISDRs2FAsXLtT6GIIlS5aU+iiIJymVSvHZZ58JNzc3YWxsLAIDA8W2bds09nHxoxy0/T3ZZnWN72kekyDE40e9+Pv7CwMDA40YEhMTRb9+/US9evWEsbGxcHNzE2FhYeKPP/5QlSnt0RK6HJOHDBki5HK5RkwhISGiSZMmGtO1tTddjt9CCHH48GHRsmVLYWRkpHbMLi2G4vdK9s+VK1cKb29vVduKiYnR+tmpbR9UZL2E0N6Xb926JcaNGydcXV2FoaGhcHR0FC+//LJYvny5qkxFvx8Ux3/nzh2t24GeXxIheGcmEVFtiYyMxHfffYfc3NxSb6B/XqSkpKBRo0ZYs2YN3nzzzdoOh2qQu7s7mjZtim3btlVZnWFhYUhLS1O7XJyI6HnASzSJiGrIgwcP1AbguHfvHtasWYOXXnrpuU/uAKjuKavopbVEJYn/fyZiyUspiYieB0zwiIhqSFBQEDp27Ag/Pz/cunULK1euRHZ2dqnPM3uerFq1CqtWrYKZmRnatm1b2+HQM04ikej8LDUiIn3DBI+IqIb06NEDGzduxPLlyyGRSPDCCy9g5cqVao9DeF6NHj0aPj4+2LBhg9rw8kRERFQxvAePiIiIiIhIT/A5eERERERERHqCCR4REREREZGe4D14T0mpVOL69euwsLBQPaiYiIiIiIjoaQkhkJOTA2dnZ0ilup2bY4L3lK5fvw5XV9faDoOIiIiIiPTU1atX0aBBA53KMsF7ShYWFgAeb3RLS8tajoaepFQqcefOHdjZ2en8iwc9X9hGqDxsI1QWtg8qD9sIlae8NpKdnQ1XV1dVzqELJnhPqfiyTEtLSyZ4dYxSqcTDhw9haWnJgyppxTZC5WEbobKwfVB52EaoPLq2kYrcCsYET48oMzJQdPIkRH4+JGZmMGjeHFIbm9oOi/7f/VyBxCsK5BcAZkZAoJsMtua8b7MuUGZkoOj0afadOoj9pu7iZ07dxX5Tt7Hv1F360ndqNMFzd3dHZGQkIiMja3KxKmlpafDw8EBiYiJatGhRKzFUB0VqKh6uW4fCgwcBpfJ/b0ilMOzQASaDB0Pm4VF7AT7nUm4p8UN8IeLOKqF44qmTMkkhOvpLERFsCC8H/qpXGxSpqTCMjUXu8ePsO3UM+03dxc+cuov9pm5j36m79K3v1PlI09LSIJFIkJSUVNuh1EmFCQnIGTdO82ABAEolCg8devx+QkLtBPicO5aiwKiVjzQOGACgEEDcOSVGrXyEYymK2gnwOVaYkIC8CRMgLZncAew7tYz9pu7iZ07dxX5TtxX99Rf7Th2lj32Hl2g+wxSpqciLigKKigAhSimkAJRK5EVFwWLpUv4yVINSbikx7ecCFCqAUvYOFEpACWDazwVYMcL4mfp16Fn2ZN+RsO/UKew3dRc/c+ou9puqoVAoUFhYWKV1KpVKFF29isyvvwZsbErvOwAgkaBgyRLIp0+HTMfREunppN9VYuG2AtiYlN53AEACYOG2R5j1uhEa1q/aviOTyaq0PqASCd7GjRsxY8YMXLp0CWZmZggMDMR///tf9OzZEy1atMCiRYtUZfv06QNra2vExsaqpuXk5CA8PBxbt26FtbU1PvzwQ4wbN67U5Xn8/4dDYGAgACAkJARxcXFQKpWYPXs2li9fjjt37sDPzw+ff/45XnnlFdW8x48fx5gxY3Du3Dk0bdoUH330kUb9Bw4cwOTJk3Hy5EnY2tpiyJAhmD17NgwM6n7u+3DduscfpmUdLIDH7yuVePjTT5B/+GHNBEf4Ib4QCmXZBwzg8fsKAayJL0R0P+OaCO25x75Td7Hf1F3sN3UX+83TEULg5s2byMzMrJa6lUVFkAwfrvM8d+7ehbSKE03SLjNfYGwblN95AEAC3LsFKHKq9p48IQQMDQ1hZ2dXZXVWKIu5ceMGwsPDMXfuXPTt2xc5OTk4dOgQRHkH+yfMmzcPH374IWbMmIHdu3fj3XffhY+PD7p27aq1/PHjx9G6dWvs3bsXTZo0gZGREQBg8eLFWLBgAb777jsEBgZi1apVeO2113DmzBl4e3sjNzcXr776Krp27Yoff/wRqampePfdd9XqvnbtGnr06IGhQ4fihx9+wPnz5zFq1CiYmJggOjq6IpumxikzMrSf5i+NQoHCgwehfPtt3shbA+7nCq2n+kujUAL7zynxbp6AjfzZu5n3WcK+U3ex39Rd7Dd1F/vN0ytO7uzt7WFmZlah0QrLI4qKoLh6tcLzyVxdIXkGTjY8y4oUAuKegFUF53OtJ4GBrGraiBACeXl5uHnzJm7dugVnZ+cqqbfCCV5RURH69esHNzc3AEBAQECFFhgcHIypU6cCAHx8fBAfH48vv/yy1ASvOJutV68eHB0dVdPnz5+PKVOmYNCgQQCAL774Avv378eiRYuwdOlSrFu3DkqlEitXroSJiQmaNGmCf//9F2+//baqjm+++Qaurq74+uuvIZFI0LhxY1y/fh1TpkzB9OnTtQ5V+ujRIzx69Ej1Ojs7u0LrX1WKTp7U/YO2mEKBolOnYBQSUj1BkUriFYXOH7bFFErgRJoCLzfhAb06se/UXew3dRf7Td3FfvN0FAqFKrmrV69eldevzM6GshKX4EmFgNTEpMrjof/JfiAgNahg5wGglEpgYlJ1PwKYmJhAqVTi7t27cHBwqJJLNit0EWnz5s3x8ssvIyAgAAMGDMCKFSuQkZFRoQUGBQVpvD537hwAYOzYsTA3N1f9lSY7OxvXr19HcHCw2vTg4GBVXefOnUOzZs1g8kTnKLnsc+fOISgoSO2XmuDgYOTm5uLff//Vuuw5c+bAyspK9efq6qrDWlc9kZ9fufny8qo4EtImv6Bm5yPdse/UXew3dRf7Td3FfvN0iu+5MzMzq54FVPSHkaedj3SmrHhu91TzlaU4X6mqe0ArlODJZDLs2bMHO3fuhL+/P5YsWQJfX1+kpqZCKpVqXKpZ0SBnzpyJpKQk1V9dNG3aNGRlZan+rlbitHtVkFTyQCSRy6s4EtLGzKhm5yPdse/UXew3dRf7Td3FflM1qvKyTDWVfbg5H4pe7aSV3OWVna8sVd3+Ktx6JBIJgoODMWPGDCQmJsLIyAhbtmyBnZ0dbty4oSqnUCjwzz//aMx/9OhRjdd+fn4AAHt7ezRq1Ej1B0B1z51C8b+hSS0tLeHs7Iz4+Hi1uuLj4+Hv7w8A8PPzw6lTp/Dw4cNSl+3n54cjR46oJabx8fGwsLBAg1JGLzI2NoalpaXaX20waN684p1fJoNBs2bVExCpCXSToaKXZ8ukwAvuVT+SEqlj36m72G/qLvabuov9pm6r9I8jpqZVHAmVVKkfOSTPxo8jFbr4+tixY/jjjz/QrVs32Nvb49ixY6oRLOVyOd577z1s374dXl5eWLhwodbRiOLj4zF37lz06dMHe/bswYYNG7B9+/ZSl2lvbw9TU1Ps2rULDRo0gImJCaysrDB58mRERUXBy8sLLVq0QExMDJKSkrB27VoAwODBg/HRRx9h1KhRmDZtGtLS0jB//ny1ut955x0sWrQIEyZMwPjx45GcnIyoqCi89957Wu+/q0ukNjYw7NBB95veZTIYdujAm91riK25BB39pTrf+C6TAp38pLzhvQaw79Rd7Dd1F/tN3cV+U32Ut29DmZX1dJUIAcWdO8CDB+UWlZibQ2prC4mFRbUNsNKxY0eNUe/rurS0NHh4eCAxMREtWrSosnoNZBJYmArklL9rHpMAliaosgFWqlOFWo+lpSUOHjyIRYsWITs7G25ubliwYAG6d++OwsJCnDx5EhERETAwMMB//vMfdOrUSaOO999/H3/99RdmzJgBS0tLLFy4EKGhoaUHaGCAr776CjNnzsT06dPRvn17xMXFYeLEicjKysL777+P27dvw9/fH1u3boW3tzcAwNzcHL/99hvGjh2LwMBA+Pv744svvsDrr7+uqtvFxQU7duzA5MmT0bx5c9ja2mLEiBH4+OOPK7JZao3J4MEojI9/PCR1Oc9VgVQKk/DwmguOEBFsiEPnH0FZxnOJgMfPVpFJgLeCDWsqtOce+07dxX5Td7Hf1F3sN1VPefs2socOBWrycQUGBjCLjobh/w9kWJ5nMVkrFhsbi8jISJ0eTeHq6oobN26gfv36VR5HPXMJch+Kcp/+AjzuP7bmdT+5AwCJqMgzDkhDdnY2rKyskJWVVSuXaxYmJDx+8Oz/P1xWg0wGSKWQz5gBwxdfrPH4apNSqcTt27dhb29fa2dkj6UoMO3nAiiU0PrLqkz6+MN2zkAjtPHi5TI1qbjvCIUCEvadOqUu9Zu6cBypS/iZo64utY+61G+eJQ8fPkRqaio8PDzUBuYrungRue+8U+PxyBcsgKGOlzZXJsGrK0mhrgleQUGB6nat6pL7UOBaRhlJnuRxcudiI4F5FY6eWUwIgdzcXFy9ehWenp5q7RCoXK7BT6tnnOGLL8Ji6VIYhoQ8/mB90v9fImOxdOlz8UFbF7XxkmHFCGN08pdCVqK3FV8ms2KEMT9sa4Hhiy9CvmQJlG3aaN5bxL5Tq9hv6i5+5tRd7Df6Qdd774YOHYoDBw5g8eLFkEgkkEgkSEtLwz///IPu3bvD3NwcDg4OeOutt3D37t1S63n06BEmTZoEFxcXyOVytGnTBnFxcar3Y2NjYW1tjW3btsHX1xdmZmbo378/8vPzsXr1ari7u8PGxgYTJ05UGy+jrHrj4uIwbNgwZGVlqWIvfv60u7s7Zs2ahYiICFhaWmL06NFIS0uDRCJRDcCoUCgwYsQIeHh4wNTUFL6+vli8eHG52+zMmTN49dVXYWlpCQsLC7Rv3x4pKSkwN5Fg9pThiBzVF0sXzkS7AAe08rVG9JS3UVBYAEsTwK2+BE0be2gkxi1atKiTz87mA1D0gMzDA/IPP4Ty7bdRdOoURF4eJHI5DJo14/0PdYCXgxTR/Yzxbp7AiTQF8gse36D7gruM90DUMpmHBwrfeQdWkZFQnj7NvlOHsN/UXfzMqbvYb54fixcvxoULF9C0aVPMnDkTAGBoaIjWrVtj5MiR+PLLL/HgwQNMmTIFYWFh2Ldvn9Z6xo8fj7Nnz2L9+vVwdnbGli1b8Morr+D06dOq257y8/Px1VdfYf369cjJyUG/fv3Qt29fWFtbY8eOHbh8+TJef/11BAcHY+DAgeXW265dOyxatAjTp09HcnIyAKg9Hm3+/PmYPn06oqKitMasVCrRoEEDbNiwAfXq1cPhw4cxevRoODk5ISwsTOs8165dQ4cOHdCxY0fs27cPlpaWiI+PR1FREYDHP4LEH9wHK3NT7Px9P9KupGH82OHwaFAPc+Z8Vok9VLuY4OkRqY0NHyhbh9nIJXyobB0ltbaGAftOncR+U3fxM6fuYr/Rf1ZWVjAyMoKZmRkcHR0BALNnz0ZgYCA+++x/CcmqVavg6uqKCxcuwMfHR62O9PR0xMTEID09Hc7OzgCASZMmYdeuXYiJiVHVU1hYiGXLlsHLywsA0L9/f6xZswa3bt2Cubk5/P390alTJ+zfvx8DBw7UqV4rKytIJBJV7E/q3Lkz3n//fdXrtLQ0tfcNDQ0xY8YM1WsPDw8cOXIEv/zyS6kJ3tKlS2FlZYX169fD0PDxPaglt4eRkRFiYlbBzMwMbVo2RcbtmZg8eTI+/XR2rV+CXVHs/UREREREz7iTJ09i//79amfDiqWkpGgkNKdPn4ZCodCY/ujRI9SrV0/12szMTJXcAYCDgwPc3d3VluPg4IDbt29XqN7StGrVqtwyS5cuxapVq5Ceno4HDx6goKCgzBE2k5KS0L59e1Vyp03z5s3VHngfFBSkujfOTceBb+oKJnhERERERM+43Nxc9OrVC1988YXGe05OTlrLy2Qy/P3335CVuKf2yeStZFIkkUi0TlP+/8BLutZbGrlcXub769evx6RJk7BgwQIEBQXBwsIC8+bNw7Fjx0qdx7QKnisolUpRcmzKwpocZbUCmOARERERET1jjIyM1AY2eeGFF7Bp0ya4u7vDQIfn6AUGBkKhUOD27dto3759lcWlS70lY6+I+Ph4tGvXDu88McppSkpKmfM0a9YMq1evRmFhYaln8U6ePIkHDx6oksGjR4/C3Nwcrq6uAAA7OzvcuHFDVT47OxupqamVWofq9mxdUEpERERERHB3d8exY8eQlpaGu3fvYty4cbh//z7Cw8ORkJCAlJQU7N69G8OGDdOaTPn4+OCNN95AREQENm/ejNTUVBw/fhxz5szB9u3bKx2XLvW6u7sjNzcXf/zxB+7evYv8/Hyd6/f29sZff/2F3bt348KFC/jkk0+QkJCgVmbLli1o3Lix6vX48eORnZ2NQYMG4a+//sLFixexZs0a1SAvwONHMowYMQJnz57Fjh07EBUVhfHjx6vuv+vcuTPWrFmDQ4cO4fTp0xgyZIjGGcq6ggkeEREREdEzZtKkSZDJZPD394ednR0KCgoQHx8PhUKBbt26ISAgAJGRkbC2ti51kJCYmBhERETg/fffh6+vL/r06YOEhAQ0bNjwqWIrr9527dph7NixGDhwIOzs7DB37lyd6x4zZgz69euHgQMHok2bNrh3757a2TwAyMrKUkve6tWrh3379iE3NxchISFo2bIlVqxYoXY27+WXX4a3tzc6dOiAgQMH4rXXXlN7BMK0adMQEhKCV199FT179kSfPn3U7k2sS/ig86dU2w86p9LVpQfQUt3ENkLlYRuhsrB9PPtKe9C58vZtZA8dCtTkPVaGhrCMjYXU3r7mlkkAHj9XMDMzE7/++muNL7s6HnTOe/CIiIiIiJ4gtbeHZWwslFlZT1eREChSKGAgkwGSsp9FKLWyYnJHVYIJHhERERFRCVJ7+6dOuIQQEEVFkBkYQFJOgkdUVZjgERERERHRcys2Nra2Q6hSvGCciIiIiIhITzDBIyIiIiIi0hNM8IiIiIiIiPQEEzwiIiIiIiI9wQSPiIiIiIhITzDBIyIiIiIi0hN8TAIRERERUQk3s5TIyn+6OoQQUCgEZDJluc/BszIDHK2q99xLx44d0aJFCyxatKhal1OV0tLS4OHhgcTERLRo0aK2w3kmMMEjIiIiInrCzSwlBi99hAJFVdVYfkVGMmDdOGOdk7xnMVkrFhsbi8jISGRmZpZb1tXVFTdu3ED9+vWrPzA9wUs0iYiIiIiekJWPKkzudFOgwFOfMdQ3BQUFkMlkcHR0hIEBz0vpigkeEREREdEzZOjQoThw4AAWL14MiUQCiUSCtLQ0/PPPP+jevTvMzc3h4OCAt956C3fv3i21nkePHmHSpElwcXGBXC5HmzZtEBcXp3o/NjYW1tbW2LZtG3x9fWFmZob+/fsjPz8fq1evhru7O2xsbDBx4kQoFAqd6o2Li8OwYcOQlZWlij06OhoA4O7ujlmzZiEiIgKWlpYYPXo00tLSIJFIkJSUBABQKBQYMWIEPDw8YGpqCl9fXyxevLjM7RUXFweJRILdu3cjMDAQpqam6Ny5M27fvo2dO3fCz88PlpaWGDx4MPLz/5dlK5VKzJkzR7Ws5s2bY+PGjU9db3VjKkxERERE9AxZvHgxLly4gKZNm2LmzJkAAENDQ7Ru3RojR47El19+iQcPHmDKlCkICwvDvn37tNYzfvx4nD17FuvXr4ezszO2bNmCV155BadPn4a3tzcAID8/H1999RXWr1+PnJwc9OvXD3379oW1tTV27NiBy5cv4/XXX0dwcDAGDhxYbr3t2rXDokWLMH36dCQnJwMAzM3NVTHNnz8f06dPR1RUlNaYlUolGjRogA0bNqBevXo4fPgwRo8eDScnJ4SFhZW53aKjo/H111/DzMwMYWFhCAsLg7GxMdatW4fc3Fz07dsXS5YswZQpUwAAc+bMwY8//ohvv/0W3t7eOHjwIN58803Y2dkhJCSk0vVWNyZ4RERERETPECsrKxgZGcHMzAyOjo4AgNmzZyMwMBCfffaZqtyqVavg6uqKCxcuwMfHR62O9PR0xMTEID09Hc7OzgCASZMmYdeuXYiJiVHVU1hYiGXLlsHLywsA0L9/f6xZswa3bt2Cubk5/P390alTJ+zfvx8DBw7UqV4rKytIJBJV7E/q3Lkz3n//fdXrtLQ0tfcNDQ0xY8YM1WsPDw8cOXIEv/zyS7kJ3uzZsxEcHAwAGDFiBKZNm4aUlBR4enqq1m3//v2YMmUKHj16hM8++wx79+5FUFAQAMDT0xN//vknvvvuO7UEryL11gQmeEREREREz7iTJ09i//79amfDiqWkpGgkeKdPn4ZCodCY/ujRI9SrV0/12szMTJXcAYCDgwPc3d3VluPg4IDbt29XqN7StGrVqtwyS5cuxapVq5Ceno4HDx6goKBApxE2mzVrphazmZmZKgkrnnb8+HEAwKVLl5Cfn4+uXbuq1VFQUIDAwMBK11sTmOARERERET3jcnNz0atXL3zxxRca7zk5OWktL5PJ8Pfff0Mmk6m992TyZmhoqPaeRCLROk2pVFao3tLI5fIy31+/fj0mTZqEBQsWICgoCBYWFpg3bx6OHTtWbt1Pxq3LegDA9u3b4eLiolbO2Ni40vXWBCZ4RERERETPGCMjI7WBTV544QVs2rQJ7u7uOo04GRgYCIVCgdu3b6N9+/ZVFpcu9ZaMvSLi4+PRrl07vPPOO6ppKSkplaqrLP7+/jA2NkZ6erra5ZjPAo6iSURERET0jHF3d8exY8eQlpaGu3fvYty4cbh//z7Cw8ORkJCAlJQU7N69G8OGDdOaTPn4+OCNN95AREQENm/ejNTUVBw/fhxz5szB9u3bKx2XLvW6u7sjNzcXf/zxB+7evVuhESa9vb3x119/Yffu3bhw4QI++eQTJCQkqJXZsmULGjduXOl1AAALCwtMmjQJ//nPf7B69WqkpKTgxIkTWLJkCVavXv1UdVc3JnhERERERM+YSZMmQSaTwd/fH3Z2digoKEB8fDwUCgW6deuGgIAAREZGwtraGlKp9q/8MTExiIiIwPvvvw9fX1/06dMHCQkJaNiw4VPFVl697dq1w9ixYzFw4EDY2dlh7ty5Otc9ZswY9OvXDwMHDkSbNm1w7949tbN5AJCVlaUaofNpzJo1C5988gnmzJkDPz8/vPLKK9i+fTs8PDyeuu7qJBFCiNoO4lmWnZ0NKysrZGVlwdLSsrbDoScolUrcvn0b9vb2pR7Y6PnGNkLlYRuhsrB9PPsePnyI1NRUeHh4wMTERDX9ZpYSg5c+qtGHnRvJgHXjjOFoxbb0PBFCIDc3F1evXoWnp6daOwQql2vwHjwiIiIioic4Wkmxbpwxsp7y2dRCCCgUCshkMkgkkjLLWpmByR1VCSZ4REREREQlOFpJ4Wj1dHUIIVBUpISBgbTcBI+oqvBnAiIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiOi5plQqazsEeo5V9UMNOMgKERERET2XjIyMIJVKcf36ddjZ2cHIyKhKB0N5PMhKEQwMDDjICmkQQqCgoAA3b96EVCqFkZFRldTLBI+IiIiInktSqRQeHh64ceMGrl+/XuX1CyGgVCohlXIUTdJOCAGJRAIPD48qe54mEzwiIiIiem4ZGRmhYcOGKCoqgkJRtU82VyqVuHfvHurVq1dlX95Jv0gkEty/f7/Kzt4BTPCIiIiI6DknkUhgaGgIQ0PDKq1XqVTC0NAQJiYmTPBIK6VSWeVnd9nSiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zwiIiIiIiI9AQTPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSEwa1HQBVHWVGBopOnoTIz4fEzAwGzZtDamNT22ER1XnKjAwUnT7NvkNUAfzMIaoc9h2qbkzw9IAiNRUP161D4cGDgFL5vzekUhh26ACTwYMh8/CovQCJ6ihFaioMY2ORe/w4+w6RjviZQ1Q57DtUU+rEJZru7u5YtGhRbYfxTCpMSEDOuHGaBwsAUCpReOjQ4/cTEmonQKI6qjAhAXkTJkBaMrkD2HeISsHPHKLKKfrrL/YdqjF1IsGjylGkpiIvKgooKtI8WKgKKYCiIuRFRUGRmlqzARLVUU/2HQn7DpFO+JlDVDmSq1eRHx3NvkM1hgneM+zhunWPDwhClF1QCECpxMOffqqZwIjqOPYdoopjvyGqHIOtW9l3qEZVWYK3ceNGBAQEwNTUFPXq1UOXLl2Ql5eHjh07IjIyUq1snz59MHToULVpOTk5CA8Ph1wuh4uLC5YuXVruMv/991+Eh4fD1tYWcrkcrVq1wrFjxwAA0dHRaNGiBb777ju4urrCzMwMYWFhyMrKUs2va2x1kTIjQ/tp/tIoFCg8eBDKjIzqDYyojmPfIao49huiylFmZGi/FaA07DtUBaokwbtx4wbCw8MxfPhwnDt3DnFxcejXrx9Eeb9UPGHevHlo3rw5EhMTMXXqVLz77rvYs2dPqeVzc3MREhKCa9euYevWrTh58iQ++OADKJ/oQJcuXcIvv/yC3377Dbt27UJiYiLeeeedp1rXR48eITs7W+2vNhSdPKn7waKYQoGiU6eqJyCiZwT7DlHFsd8QVY7i5MnSbwUodSb2HXo6VTKK5o0bN1BUVIR+/frBzc0NABAQEFChOoKDgzF16lQAgI+PD+Lj4/Hll1+ia9euWsuvW7cOd+7cQUJCAmxtbQEAjRo1Uivz8OFD/PDDD3BxcQEALFmyBD179sSCBQvg6OhYofiKzZkzBzNmzKjUvFVJ5OdXbr68vCqOhOjZwr5DVHHsN0SVIx48qNx87Dv0FKrkDF7z5s3x8ssvIyAgAAMGDMCKFSuQUcFTy0FBQRqvz507BwAYO3YszM3NVX8AkJSUhMDAQFVyp03Dhg1VyV1xnUqlEsnJyRWK7UnTpk1DVlaW6u/q1auVrutpSMzMKjefXF7FkRA9W9h3iCqO/YaociSmppWbj32HnkKVJHgymQx79uzBzp074e/vjyVLlsDX1xepqamQSqUal2oWFhZWqP6ZM2ciKSlJ9QcAppXsME+qTGzGxsawtLRU+6sNBs2bA9IK7j6ZDAbNmlVPQETPCPYdoopjvyGqHFnz5hDsO1TDqmyQFYlEguDgYMyYMQOJiYkwMjLCli1bYGdnhxs3bqjKKRQK/PPPPxrzHz16VOO1n58fAMDe3h6NGjVS/QFAs2bNkJSUhPv375caU3p6Oq5fv65Wp1Qqha+vLwDoHFtdJLWxgWGHDrp/4MpkMOzQAVIbm+oNjKiOY98hqjj2G6LKkdrYQNm6NfsO1agqSfCOHTuGzz77DH/99RfS09OxefNm3LlzB35+fujcuTO2b9+O7du34/z583j77beRmZmpUUd8fDzmzp2LCxcuYOnSpdiwYQPefffdUpcZHh4OR0dH9OnTB/Hx8bh8+TI2bdqEI0eOqMqYmJhgyJAhOHnyJA4dOoSJEyciLCxMdf+drrHVVSaDBwMyGSCRlF1QIgGkUpiEh9dMYER1HPsOUcWx3xBVTtFrr7HvUI2qkgTP0tISBw8eRI8ePeDj44OPP/4YCxYsQPfu3TF8+HAMGTIEERERCAkJgaenJzp16qRRx/vvv4+//voLgYGBmD17NhYuXIjQ0NBSl2lkZITff/8d9vb26NGjBwICAvD5559DJpOpyjRq1Aj9+vVDjx490K1bNzRr1gzffPON6n1dY6urZB4ekM+YARgYlP7LkEwGGBhAPmMGZB4eNRsgUR31ZN8p9dIZ9h0iNfzMIaoc4eoKs+ho9h2qMRJRkWcZPEOio6Px66+/qu7Zqy7Z2dmwsrJCVlZWrd2Pp0hNxcOffnr8jCKF4n9v/P9pfpPw8OfyYKFUKnH79m3Y29tDWtHr3+m5UJiSguzVqyE7dkx9CPjnvO/Q//A4oomfOf/D9kHlebKNiCtX2HdIQ3nHkcrkGkzwnlJdSPCKKTMyUHTqFEReHiRyOQyaNXuur+HmBy+Vp7iN1DcygvL0afYd0sDjSOn4mcP2QeXT1kbYd+hJ1ZHgVclz8KhukNrYwCgkpLbDIHrmSK2tYcC+Q1Qh/Mwhqhz2HapuensGr6ZkZWXB2toaV69erfUzeKROqVTizp07sLOz4y+rpBXbCJWHbYTKwvZB5WEbofKU10ays7Ph6uqKzMxMWFlZ6VQnz+A9pZycHACAq6trLUdCRERERET6KCcnR+cEj2fwnpJSqcT169dhYWEBSXnD31KNKv7Fg2dXqTRsI1QethEqC9sHlYdthMpTXhsRQiAnJwfOzs46nwXmGbynJJVK0aBBg9oOg8pgaWnJgyqViW2EysM2QmVh+6DysI1QecpqI7qeuSvGi4GJiIiIiIj0BBM8IiIiIiIiPcEEj/SWsbExoqKiYGxsXNuhUB3FNkLlYRuhsrB9UHnYRqg81dFGOMgKERERERGRnuAZPCIiIiIiIj3BBI+IiIiIiEhPMMEjIiIiIiLSE0zw6Jl08OBB9OrVC87OzpBIJPj111/LnefRo0f46KOP4ObmBmNjY7i7u2PVqlXVHyzVisq0kbVr16J58+YwMzODk5MThg8fjnv37lV/sFQr5syZgxdffBEWFhawt7dHnz59kJycXO58GzZsQOPGjWFiYoKAgADs2LGjBqKlmlaZ9rFixQq0b98eNjY2sLGxQZcuXXD8+PEaiphqWmWPIcXWr18PiUSCPn36VF+QVKsq20YyMzMxbtw4ODk5wdjYGD4+PhX6rGGCR8+kvLw8NG/eHEuXLtV5nrCwMPzxxx9YuXIlkpOT8dNPP8HX17cao6TaVNE2Eh8fj4iICIwYMQJnzpzBhg0bcPz4cYwaNaqaI6XacuDAAYwbNw5Hjx7Fnj17UFhYiG7duiEvL6/UeQ4fPozw8HCMGDECiYmJ6NOnD/r06YN//vmnBiOnmlCZ9hEXF4fw8HDs378fR44cgaurK7p164Zr167VYORUUyrTRoqlpaVh0qRJaN++fQ1ESrWlMm2koKAAXbt2RVpaGjZu3Ijk5GSsWLECLi4uOi+Xo2jSM08ikWDLli1l/gK2a9cuDBo0CJcvX4atrW3NBUd1gi5tZP78+Vi2bBlSUlJU05YsWYIvvvgC//77bw1ESbXtzp07sLe3x4EDB9ChQwetZQYOHIi8vDxs27ZNNa1t27Zo0aIFvv3225oKlWqBLu2jJIVCARsbG3z99deIiIio5giptunaRhQKBTp06IDhw4fj0KFDyMzM1OkqE3r26dJGvv32W8ybNw/nz5+HoaFhpZbDM3j0XNi6dStatWqFuXPnwsXFBT4+Ppg0aRIePHhQ26FRHREUFISrV69ix44dEELg1q1b2LhxI3r06FHboVENycrKAoAyfwQ6cuQIunTpojYtNDQUR44cqdbYqPbp0j5Kys/PR2FhIX9YfE7o2kZmzpwJe3t7jBgxoibCojpElzaydetWBAUFYdy4cXBwcEDTpk3x2WefQaFQ6Lwcg6eOlOgZcPnyZfz5558wMTHBli1bcPfuXbzzzju4d+8eYmJiajs8qgOCg4Oxdu1aDBw4EA8fPkRRURF69epVocuA6dmlVCoRGRmJ4OBgNG3atNRyN2/ehIODg9o0BwcH3Lx5s7pDpFqka/soacqUKXB2dtb4UYD0j65t5M8//8TKlSuRlJRUc8FRnaBrG7l8+TL27duHN954Azt27MClS5fwzjvvoLCwEFFRUTotiwkePReUSiUkEgnWrl0LKysrAMDChQvRv39/fPPNNzA1Na3lCKm2nT17Fu+++y6mT5+O0NBQ3LhxA5MnT8bYsWOxcuXK2g6Pqtm4cePwzz//4M8//6ztUKgOqkz7+Pzzz7F+/XrExcXBxMSkGqOjukCXNpKTk4O33noLK1asQP369WswOqoLdD2OKJVK2NvbY/ny5ZDJZGjZsiWuXbuGefPmMcEjepKTkxNcXFxUyR0A+Pn5QQiBf//9F97e3rUYHdUFc+bMQXBwMCZPngwAaNasGeRyOdq3b4/Zs2fDycmpliOk6jJ+/Hhs27YNBw8eRIMGDcos6+joiFu3bqlNu3XrFhwdHaszRKpFFWkfxebPn4/PP/8ce/fuRbNmzao5QqpturaRlJQUpKWloVevXqppSqUSAGBgYIDk5GR4eXlVe7xU8ypyHHFycoKhoSFkMplqmp+fH27evImCggIYGRmVuzzeg0fPheDgYFy/fh25ubmqaRcuXIBUKtX5A5v0W35+PqRS9UNi8cGVY1HpJyEExo8fjy1btmDfvn3w8PAod56goCD88ccfatP27NmDoKCg6gqTakll2gcAzJ07F7NmzcKuXbvQqlWrao6SalNF20jjxo1x+vRpJCUlqf5ee+01dOrUCUlJSXB1da2hyKmmVOY4EhwcjEuXLqmSf+Dxd1YnJyedkrviBRM9c3JyckRiYqJITEwUAMTChQtFYmKiuHLlihBCiKlTp4q33npLrXyDBg1E//79xZkzZ8SBAweEt7e3GDlyZG2tAlWziraRmJgYYWBgIL755huRkpIi/vzzT9GqVSvRunXr2loFqmZvv/22sLKyEnFxceLGjRuqv/z8fFWZt956S0ydOlX1Oj4+XhgYGIj58+eLc+fOiaioKGFoaChOnz5dG6tA1agy7ePzzz8XRkZGYuPGjWrz5OTk1MYqUDWrTBspaciQIaJ37941EC3Vhsq0kfT0dGFhYSHGjx8vkpOTxbZt24S9vb2YPXu2zstlgkfPpP379wsAGn9DhgwRQjw+YIaEhKjNc+7cOdGlSxdhamoqGjRoIN577z21Dkb6pTJt5KuvvhL+/v7C1NRUODk5iTfeeEP8+++/NR881Qht7QOAiImJUZUJCQlRtZliv/zyi/Dx8RFGRkaiSZMmYvv27TUbONWIyrQPNzc3rfNERUXVePxU/Sp7DHkSEzz9Vtk2cvjwYdGmTRthbGwsPD09xaeffiqKiop0Xi6fg0dERERERKQneA8eERERERGRnmCCR0REREREpCeY4BEREREREekJJnhERERERER6ggkeERERERGRnmCCR0REREREpCeY4BEREREREekJJnhERERERER6ggkeET33kpOT4ejoiJycnNoO5anFxsbC2tq6RpcZHR2NFi1aVOsyJBIJfv3112pdRseOHREZGVmty9B3dXUb1tW46oKzZ8+iQYMGyMvLq+1QiKiKMMEjIr1UkS9006ZNw4QJE2BhYVG9QRER1TH+/v5o27YtFi5cWNuhEFEVYYJHRM+19PR0bNu2DUOHDq3tUEgPFRQUaExTKBRQKpW1EA3VtMLCwtoOQSfDhg3DsmXLUFRUVNuhEFEVYIJHRHpn6NChOHDgABYvXgyJRAKJRIK0tDSt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",
|
|
"text/plain": [
|
|
"<Figure size 900x300 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data",
|
|
"transient": {}
|
|
}
|
|
],
|
|
"source": [
|
|
"fig, ax = plt.subplots(figsize=(9, 3))\n",
|
|
"colores = {\"telemetria.cpu\": \"#ef4444\", \"telemetria.mem\": \"#3b82f6\"}\n",
|
|
"y_de = {\"sub-todo\": 1, \"sub-cpu\": 0}\n",
|
|
"for e in msgs:\n",
|
|
" ax.scatter(e[\"t\"], y_de[e[\"name\"]], color=colores[e[\"subject\"]], s=80, zorder=3)\n",
|
|
"ax.set_yticks([0, 1]); ax.set_yticklabels([\"sub-cpu\", \"sub-todo\"])\n",
|
|
"ax.set_xlabel(\"t (segundos desde el arranque de cada proceso)\")\n",
|
|
"ax.set_title(\"Timeline de entregas — rojo: telemetria.cpu, azul: telemetria.mem\")\n",
|
|
"ax.grid(axis=\"x\", alpha=0.3)\n",
|
|
"from matplotlib.patches import Patch\n",
|
|
"ax.legend(handles=[Patch(color=c, label=s) for s, c in colores.items()], loc=\"upper right\")\n",
|
|
"plt.tight_layout(); plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "5914c849",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Resumen del análisis\n",
|
|
"\n",
|
|
"A lo largo de los tres notebooks hemos visto cómo distintos procesos envían datos por pub/sub con NATS:\n",
|
|
"\n",
|
|
"- **01** — el modelo base: publishers y subscribers desacoplados por un broker, *fan-out* y *wildcards*.\n",
|
|
"- **02** — patrones de orden superior: *queue groups* (reparto de carga), *request/reply* (RPC) y *JetStream* (persistencia y replay).\n",
|
|
"- **03** — **procesos del SO reales**: el desacople de verdad. El publisher no conoce a sus subscribers; el broker enruta por subject. Añadir o quitar procesos consumidores no cambia ni una línea del publisher.\n",
|
|
"\n",
|
|
"Esa es la idea central de NATS: **los procesos se comunican por nombres de subject, no por direcciones**, y el broker se encarga del resto.\n",
|
|
"\n",
|
|
"### Limpieza (opcional)\n",
|
|
"\n",
|
|
"Para parar el broker cuando termines:\n",
|
|
"\n",
|
|
"```python\n",
|
|
"import subprocess\n",
|
|
"subprocess.run([\"docker\", \"stop\", \"nats_demo\"]) # detener\n",
|
|
"subprocess.run([\"docker\", \"rm\", \"nats_demo\"]) # eliminar\n",
|
|
"```"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3 (ipykernel)",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.12.3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|