{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "350fb575",
   "metadata": {},
   "source": [
    "<p>\n",
    "<font size='5' face='Georgia, Arial'>IIC2233 Apunte Programación Avanzada</font><br>\n",
    "<font size='1'> Modificado en 2019-1 al 2026-2 por Equipo Docente IIC2233. </font>\n",
    "</p>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f1aa21e",
   "metadata": {},
   "source": [
    "# Tabla de contenidos\n",
    "\n",
    "1. [*Client-side script*](#Client-side-script)\n",
    "    1. [Ejemplo consumiendo una API (método `get`)](#Ejemplo-consumiendo-una-API-(método-get))\n",
    "    2. [Retorno de una API](#Retorno-de-una-API)\n",
    "    3. [Uso de `post`](#Uso-de-post)\n",
    "    4. [Autenticación en _headers_](#Autenticación-en-headers)\n",
    "    5. [Caso aplicado: API de GITHUB](#Caso-aplicado:-API-de-GITHUB)\n",
    "2. [Resumiendo](#Resumiendo)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37a9b257",
   "metadata": {},
   "source": [
    "## *Client-side script*\n",
    "\n",
    "Primero, nos enfocaremos en el punto de vista del cliente al momento de utilizar *webservices*, por lo que veremos cómo efectuar *requests* a un servidor que mantiene un servicio web. En Python, la librería `requests` nos permite interactuar con servicios disponibles en algún *web service*. La librería, además, integra los métodos para serialización en JSON.\n",
    "\n",
    "Para instalar la librería `requests`, en cualquier terminal debes correr el comando `python3 -m pip install requests`. Otra opción, es ejecutar la siguiente celda, que instalará la librería en el mismo entorno en que estés corriendo este jupyter (de todas maneras recomendamos instalarlo desde la consola).\n",
    "\n",
    "Recuerda que si `python3` no funciona, probar con `python`, `py` o `py3`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f2bb4de0",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: requests in ./.venv/lib/python3.12/site-packages (2.32.5)\n",
      "Requirement already satisfied: charset_normalizer<4,>=2 in ./.venv/lib/python3.12/site-packages (from requests) (3.4.5)\n",
      "Requirement already satisfied: idna<4,>=2.5 in ./.venv/lib/python3.12/site-packages (from requests) (3.11)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in ./.venv/lib/python3.12/site-packages (from requests) (2.6.3)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in ./.venv/lib/python3.12/site-packages (from requests) (2026.2.25)\n"
     ]
    }
   ],
   "source": [
    "!python3 -m pip install requests"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "740b7b18",
   "metadata": {},
   "source": [
    "Para generar una petición mediante `GET` usamos el método `get(url)` que recibe por argumento el llamado al recurso.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "493f3713",
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "# Esta url contiene la dirección del web service \n",
    "# y los parámetros que se requiren para la consulta\n",
    "url = 'https://api.github.com/repos/IIC2233/Syllabus/contents/Actividades'\n",
    "respuesta = requests.get(url)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83963be7",
   "metadata": {},
   "source": [
    "Luego podemos usar `.status_code` para saber el código  de estado de la consulta."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "20617c7a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Status: 200\n"
     ]
    }
   ],
   "source": [
    "print(f'Status: {respuesta.status_code}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "d4646969",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      ".keep https://github.com/IIC2233/Syllabus/blob/main/Actividades/.keep\n",
      "AC1 https://github.com/IIC2233/Syllabus/tree/main/Actividades/AC1\n",
      "AC2 https://github.com/IIC2233/Syllabus/tree/main/Actividades/AC2\n",
      "AC3 https://github.com/IIC2233/Syllabus/tree/main/Actividades/AC3\n",
      "AC4 https://github.com/IIC2233/Syllabus/tree/main/Actividades/AC4\n",
      "AC5 https://github.com/IIC2233/Syllabus/tree/main/Actividades/AC5\n"
     ]
    }
   ],
   "source": [
    "# El output de esta respuesta particular\n",
    "# puede ser transformado con .json() a un diccionario o una lista\n",
    "# en este caso, fue a una lista\n",
    "data = respuesta.json()\n",
    "for file in data:\n",
    "    print(file[\"name\"], file[\"html_url\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "94f689e4",
   "metadata": {},
   "source": [
    "## Ejemplo consumiendo una API (método `get`)\n",
    "\n",
    "A continuación vamos a experimentar con la API de [_DummyJSON_](https://dummyjson.com/). Esta nos entrega distintos tipo información falsa en formato JSON. Por ejemplo, usuarios, productos, recetas, etc.\n",
    "\n",
    "En primer lugar, todas las APIs tendrán una **URL BASE**, que consiste en un _link_ de prefijo que toda consulta debe tener. Para el caso de _DummyJSON_, esta URL BASE es `\"https://dummyjson.com/\"`. Por lo tanto, cualquier solicitud que hagamos, debe partir con ese prefijo.\n",
    "\n",
    "Luego, tenemos los **_endpoint_**. Para efectos del curso, podemos considerar estos **_endpoints_** como las diferentes rutas que dispone la API para hacer consultas. Para el caso de _DummyJSON_, algunos **_endpoints_** son\n",
    "\n",
    "* `products/`: nos retornará información de productos.\n",
    "* `recipes/`: nos retornará información de recetas.\n",
    "* `carts/` nos retornará información de carros de compra.\n",
    "* `image/`: nos retornará imágenes personalizadas.\n",
    "\n",
    "Por lo tanto, para consultar esta api, deberemos combinar la **URL BASE** con un **_endpoint_**. De este modo, a URL final sería `\"https://dummyjson.com/products\"`, `\"https://dummyjson.com/recipes\"`, entre otros. Siempre que visitemos una API, esta nos detallará los diferentes _endpoints_ que tiene.\n",
    "\n",
    "Vamos a probar 2 **_endpoints_** de _DummyJSON_."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "be4a710d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "200\n"
     ]
    }
   ],
   "source": [
    "import requests\n",
    "\n",
    "\n",
    "BASE = \"https://dummyjson.com/\"\n",
    "endpoint_1 = \"recipes/\"\n",
    "\n",
    "respuesta = requests.get(BASE + endpoint_1)\n",
    "\n",
    "# imprimir el status_code\n",
    "print(respuesta.status_code)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a29ed463",
   "metadata": {},
   "source": [
    "Ahora vamos a ver el contenido de la consulta"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "54f4a9b2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Llaves:  dict_keys(['recipes', 'total', 'skip', 'limit'])\n"
     ]
    }
   ],
   "source": [
    "data = respuesta.json()\n",
    "print(\"Llaves: \", data.keys())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "b14dfcf2",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "50"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data[\"total\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "27713f73",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'id': 1,\n",
       " 'name': 'Classic Margherita Pizza',\n",
       " 'ingredients': ['Pizza dough',\n",
       "  'Tomato sauce',\n",
       "  'Fresh mozzarella cheese',\n",
       "  'Fresh basil leaves',\n",
       "  'Olive oil',\n",
       "  'Salt and pepper to taste'],\n",
       " 'instructions': ['Preheat the oven to 475°F (245°C).',\n",
       "  'Roll out the pizza dough and spread tomato sauce evenly.',\n",
       "  'Top with slices of fresh mozzarella and fresh basil leaves.',\n",
       "  'Drizzle with olive oil and season with salt and pepper.',\n",
       "  'Bake in the preheated oven for 12-15 minutes or until the crust is golden brown.',\n",
       "  'Slice and serve hot.'],\n",
       " 'prepTimeMinutes': 20,\n",
       " 'cookTimeMinutes': 15,\n",
       " 'servings': 4,\n",
       " 'difficulty': 'Easy',\n",
       " 'cuisine': 'Italian',\n",
       " 'caloriesPerServing': 300,\n",
       " 'tags': ['Pizza', 'Italian'],\n",
       " 'userId': 166,\n",
       " 'image': 'https://cdn.dummyjson.com/recipe-images/1.webp',\n",
       " 'rating': 4.6,\n",
       " 'reviewCount': 98,\n",
       " 'mealType': ['Dinner']}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data['recipes'][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "478cbfab",
   "metadata": {},
   "source": [
    "Cómo podemos notar, nos entregó la información completa de una receta.\n",
    "\n",
    "Ahora vamos a hacer una consulta al endpoint de `\"products/\"`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ecf9dc1a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['Essence Mascara Lash Princess', 'Eyeshadow Palette with Mirror']"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "endpoint_2 = \"products/\"\n",
    "\n",
    "respuesta = requests.get(BASE + endpoint_2)\n",
    "\n",
    "data = respuesta.json()\n",
    "[product['title'] for product in data['products'][:2]]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f9742cd7",
   "metadata": {},
   "source": [
    "### Parámetros de una consulta\n",
    "\n",
    "Independientemente del tipo de consulta (`GET`, `POST`, ...), cada **_endpoint_** puede tener sus parámetros para personalizar la consulta. \n",
    "\n",
    "Por un lado, _DummyJSON_ tiene algunos parámetros que sirve para cualquier **_endpoint_**. Algunos de estos son:\n",
    "- `\"limit\"`: nos permite indicar la cantidad de elementos a obtener. Por defecto es 30, pero ahora vamos a cambiarlo a 3.\n",
    "- `\"select\"`: nos permite indicar qué información queremos recibir. Por defecto nos entrega toda la información, lo cambiaremos para que solo nos entregue el nombre de los ítems.\n",
    "\n",
    "Por otro lado, el **_endpoint_** de `\"recipes/search/\"` nos permite buscar recetas con alguna palabra en específico. Para esto, tendremos que utilizar el parámetro `\"q\"`. Busquemos las recetas que contengan el texto `\"Chicken\"`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3e3084db",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'id': 4, 'name': 'Chicken Alfredo Pasta'},\n",
       " {'id': 5, 'name': 'Mango Salsa Chicken'},\n",
       " {'id': 11, 'name': 'Chicken Biryani'},\n",
       " {'id': 12, 'name': 'Chicken Karahi'},\n",
       " {'id': 20, 'name': 'Butter Chicken (Murgh Makhani)'}]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Los parámetros los podemos pasar de dos formas:\n",
    "\n",
    "# 1. Directamente en el URL de la request. En este caso será todo lo que esté\n",
    "# después del '?' serán parámetros, donde cada uno de ellos está separado por un '&' \n",
    "\n",
    "endpoint_3 = \"recipes/search?limit={}&select={}&q={}\"\n",
    "respuesta = requests.get(BASE + endpoint_3.format(5, 'name', 'chicken'))\n",
    "\n",
    "data = respuesta.json()\n",
    "data['recipes']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "5d1f645b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'id': 4, 'name': 'Chicken Alfredo Pasta'},\n",
       " {'id': 5, 'name': 'Mango Salsa Chicken'},\n",
       " {'id': 11, 'name': 'Chicken Biryani'}]"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 2. Como un argumento del método. Para esto haremos un diccionario\n",
    "# con cada parámetro y su valor.\n",
    "\n",
    "endpoint_3 = \"recipes/search/\"\n",
    "parametros = {\"limit\": 3, \"select\": \"name\", \"q\": \"chicken\"}\n",
    "respuesta = requests.get(BASE + endpoint_3, params=parametros)\n",
    "\n",
    "data = respuesta.json()\n",
    "data['recipes']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c4834b0",
   "metadata": {},
   "source": [
    "\n",
    "Adicionalmente, en algunas ocasiones podemos entregar argumentos por medio del _endpoint_. Un ejemplo es el _endpoint_ de `\"image/\"`, que nos permite crear imágenes de portes, colores y textos personalizados, para esto tendremos que adaptar nuestro _endpoint_ y utilizar parámetros. El formato del _endpoint_ es el siguiente:\n",
    "```\n",
    "\"image/SIZE/BACKGROUND_COLOR/FONT_COLOR\"\n",
    "```\n",
    "donde:\n",
    "* `SIZE` es el porte de la imagen (ancho x alto) en pixeles. Por ejemplo: `150x200`\n",
    "* `BACKGROUND_COLOR` es el color del fondo en formato HEX. Por ejemplo: `008080`. Por defecto este valor es gris.\n",
    "* `FONT_COLOR` es el color de la fuente en formato HEX. Por ejemplo: `ffffff`. Por defecto este valor es negro.\n",
    "\n",
    "Además, con los parámetros se puede indicar lo siguiente:\n",
    "* `text`: contenido del texto a poner en la imagen. Por defecto son las dimensiones de la imagen. \n",
    "* `fontFamily`: fuente utilizada para escribir el texto. El conjunto de fuentes a utilizar se indica en la documentación del _endpoint_.\n",
    "\n",
    "Puedes revisar con mayor detalle los parámetros que presenta este _endpoint_ en el [siguiente link](https://dummyjson.com/docs/image)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "5e9ba1d9",
   "metadata": {},
   "outputs": [],
   "source": [
    "consulta = \"image/\"\n",
    "porte = \"400x200/\"\n",
    "color_fondo = \"82944b/\"\n",
    "color_fuente = \"d4d2bc\"\n",
    "\n",
    "endpoint_4 = consulta + porte + color_fondo + color_fuente\n",
    "\n",
    "parametros = {\n",
    "    \"text\": \"Todos somos Pepa lovers\",\n",
    "    \"fontFamily\": \"ubuntu\"\n",
    "}\n",
    "\n",
    "respuesta = requests.get(BASE + endpoint_4, params=parametros)\n",
    "link_imagen = respuesta.url"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "5c142baf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import display, HTML, Image\n",
    "from os import path\n",
    "\n",
    "with open(path.join('data', 'img_personalizada.png'), 'wb') as file:\n",
    "    file.write(respuesta.content)\n",
    "\n",
    "display(Image(path.join('data', 'img_personalizada.png')))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d31c131",
   "metadata": {},
   "source": [
    "Te invitamos a cambiar los valores del _endpoint_ y los párametros para crear tus propias imágenes. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05f9a39a",
   "metadata": {},
   "source": [
    "### Retorno de una API"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ee6bf11",
   "metadata": {},
   "source": [
    "Como vimos antes, existen requests que nos retornan la información en un JSON:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "30bc3a9b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'recipes': [{'id': 1, 'name': 'Classic Margherita Pizza'},\n",
       "  {'id': 2, 'name': 'Vegetarian Stir-Fry'},\n",
       "  {'id': 3, 'name': 'Chocolate Chip Cookies'},\n",
       "  {'id': 4, 'name': 'Chicken Alfredo Pasta'},\n",
       "  {'id': 5, 'name': 'Mango Salsa Chicken'},\n",
       "  {'id': 6, 'name': 'Quinoa Salad with Avocado'},\n",
       "  {'id': 7, 'name': 'Tomato Basil Bruschetta'},\n",
       "  {'id': 8, 'name': 'Beef and Broccoli Stir-Fry'},\n",
       "  {'id': 9, 'name': 'Caprese Salad'},\n",
       "  {'id': 10, 'name': 'Shrimp Scampi Pasta'}],\n",
       " 'total': 50,\n",
       " 'skip': 0,\n",
       " 'limit': 10}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import requests\n",
    "from json import JSONDecodeError\n",
    "\n",
    "\n",
    "BASE = \"https://dummyjson.com/\"\n",
    "endpoint_1 = \"recipes/\"\n",
    "parametros = {\"limit\": 10, \"select\": \"name\"}\n",
    "\n",
    "respuesta = requests.get(BASE + endpoint_1, params=parametros)\n",
    "respuesta.json()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11460e0b",
   "metadata": {},
   "source": [
    "Pero también hay algunas que entregan la información en otro formato:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "29e1eefd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "El contenido de la response no se encuentra en formato JSON, sino que su contenido es \"image/png\"\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "b'\\x89PNG\\r\\n\\x1a\\n\\x00\\x00\\x00\\rIHDR\\x00\\x00\\x01\\x90\\x00\\x00\\x00\\xc8\\x08\\x06\\x00\\x00\\x00\\xc6\\x15\\xb7\\xe2\\x00\\x00\\x00\\tpHYs\\x00\\x00\\x03\\xe8\\x00\\x00\\x03\\xe8\\x01\\xb5{Rk\\x00\\x00\\x14&IDATx\\x9c\\xed\\x9c\\xf7{\\x1c\\xd5\\x15\\x86\\xf9\\xff\\xa4\\xd0BI\\xa3\\xa4\\x10\\x02\\x01\\x12\\x1ez\\x08\\x0f\\xc9\\x017l\\xdc-W\\x15[\\x96mY\\x92eYV\\x97{\\xef\\x85\\xfc?7\\xcfw\\xc7W\\x9e]\\xedJ.\\x04\\x9dC\\xde\\x1f\\xbe\\x07vvvg\\xe6=\\xdf\\x9eo\\xee\\xbd#?c\\xdb;\\x12\\x82\\x01\\x1e\\xc0\\x03x\\x00\\x0f\\xd8c2x\\x06\\xd3`\\x1a<\\x80\\x07\\xf0\\x00\\x1e\\xb0\\'`@\\x80`\\x1c\\x9a\\x07\\x1e\\xc0\\x03x \\x11 \\x98\\x80F\\x80\\x07\\xf0\\x00\\x1eH?\\x15\\x03F \\x98\\x8d\\x86\\x83\\x07\\xf0\\x00\\x1eH\\x04\\x08&\\xa0\\x11\\xe0\\x01<\\x80\\x07\\x12#\\x10L@#\\xc0\\x03x\\x00\\x0f$\\xcf\\x0c\\x98\\xc2rP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\x88\\xe8\\x01\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00\\xf9?\\xd6\\xea\\x9d/\\xa4\\x91\\x895\\xa9g\\xf0\\xc3\\x15?\\x17\\xf4\\xd30\\xd8s\\xe8\\xbdtrfs\\xb2\\xed\\x9d0\\xc7w\\xe9i\\x19\\x10 \\x0eM\\xb4f\\xd7\\x0bi\\xd7\\xc0;\\xcb\\xea\\x9b\\x1d\\xcf>\\xd5q6\\xec\\xfbU\\xfa\\xcf\\xfd\\xf944\\xfe\\xed\\x8a_sd\\xad\\xd9\\xf5b\\xda\\xd1\\xffV\\x0e\\xe2\\xde\\xa3\\x1f\\xe5&\\xbd\\xa5\\xe7\\xf5\\xf4\\xcd\\x8e_\\xac\\xf8\\xb95k|vs\\xae9\\x01\\xb2\\xf2\\xb5\\xb0\\x9f\\x81\\x08\\x10\\x87\\xda\\xda\\xf7\\x87\\xfc#_Nkv\\xfd\\xf2\\xa9\\x8eC\\x80\\xfc8\\xf5\\x1a\\x9d\\\\\\xdb\\xb2>\\xb7n\\x9dH\\xfd#\\x9f\\xaf\\xb8\\x9f\\xea\"@V\\xbe\\x06\\xf63\\x12\\x01\\xe2P\\xab\\xba\\x9e\\xcb!RtlbMnH\\x07G\\xfe\\xd1\\xb0\\xfdi\\xef\"\\t\\x90\\x1f7@v\\x1e|\\'}\\xbf\\xef7is\\xcf\\xeb\\xa9w\\xe8\\xe3t\\xe5\\xeaP\\xde~`\\xf8\\xd3\\x15\\xf7T\\x11\\x01\\xb2\\xf25\\xb0\\x9f\\x91\\x08\\x90\\x00:x\\xec\\xcb\\xdc\\x88v\\r\\xbc\\xdb\\xf2\\xfdU;\\x9fO\\xddG\\xfe\\x9e\\x0e\\x1f\\xff*O\\xa3\\xac\\xde\\xf9|\\xcb\\xfd\\xbe\\xedz6\\xed=\\xf4~\\x1a8\\xf6e\\xdaw\\xe4\\x83\\xb4\\xb9\\xf7\\x8d\\xb6SX\\x9a\\x82\\xd1q\\xb5\\xef\\x96\\xbe7[~\\xdfw{^M}G?N\\x87\\xc7\\xbeN}G?\\xca\\xcds\\xa9\\xeb\\xd8\\xd2\\xfbF\\xea\\x1f\\xfe,\\x1d\\x1a\\xfd*\\xed;\\xf2\\xb7\\xb4n\\xd7KM\\xfbt\\xa6\\xae\\xfe?\\xa7\\x81\\xd1\\x7f\\xa6\\x03\\xc3\\x9f\\xe7\\x80[|\\r\\xcf\\xa5m\\xfb\\xff\\x98\\xaf\\xb3\\x7f\\xe4\\x8b\\xd4s\\xf4\\xc3\\x85\\xfd\\xd6\\xefy%\\xf5\\x0e~\\x94\\xfa\\x8f}\\xf1`\\x8a\\xaf\\xf5yl\\xee}=\\x87\\xf1\\xc0\\xe8\\x97i[\\xdf\\xef\\xdb\\\\\\xdb+\\xa9o\\xe8\\x93|m\\n\\x83\\x8d\\xdd\\xbf]6@\\x9a\\xf7\\xd1\\xf9\\xdc\\xbf;\\x9b.\\\\\\x1ah<~\\x8d\\xed\\xd6\\x16lW\\xef|1u\\xf5\\xbf\\x9d\\xa7\\xc3t-\\xba\\xd6\\xb5\\xbb\\x17\\x8f6UgM\\x97\\x89\\x83\\xaee\\xf7\\xc0\\xbb\\xb9\\xc6O\\x1a \\xdb\\xf7\\xff)\\xb3\\xd717u\\xff\\xae\\xe1\\xbd\\x1d\\x07\\xdeJ\\xdb\\x0f\\xbc\\xb5\\xe83\\x1b\\xf6\\xfd:\\xb3\\xd69\\x97m\\xaakfw\\xfc\\xab|~\\xad\\xa6\\xf26\\xf5\\xbc\\x96\\xf6\\x1d\\xfe \\x1fK\\x1e\\xfa~\\xefC\\xeft\\x1d|;\\xb3\\xa9\\xae\\xe9\\xaf\\xb9\\xe6+\\xfd\\x1bD\\x1d-\\x19\\x10 \\xc1\\x03D?\\xea\\x9b7\\xc7\\xf2\\xfb?\\xdc{8u\\xa2F\\\\\\xdfO\\xcd\\xed\\xea\\xb5\\xe1\\x86)\\x96\\xfbwg\\x16\\x05\\x88~\\xec\\x13\\xb3[\\x1e\\xec3\\xf7@\\xf3ir~{\\xfa\\xb6\\xeba#\\xe8\\x1e\\xfc0\\x7f^\\xba}\\xebd\\xdegbnk\\xdbk86\\xa1&;\\x97\\xee\\xdd\\x99Jw\\xefL\\xe4\\xfd\\xeb\\xd3;j\\x90g/\\xeco\\xb8\\x8e\\x1f\\xee\\xcd\\xa4\\xc1\\xb1\\x7f7|\\xcf\\xf4\\xa9\\xaeESE\\xf7\\xefN\\xa7\\xd93\\xbb\\xd3\\x0f\\xf7f\\x1b\\xb6\\x9f>\\xd7\\xd3\\xd4\\xbc:\\xd3\\xf8\\xcc\\xc6\\x85k*\\xc7\\xd1wj\\xd4W\\xf6S\\xb8\\xdd\\xbb;\\x9d\\x9b\\x7f\\xb9\\xb6\\xa9S\\xdb\\x1f;@\\xa4\\xeb\\xd7Gs}\\xca\\xf1OLo\\xc8\\xc7\\xd7\\xb5\\x95\\xf3\\x1d\\x9d\\xfc\\xae\\xe13\\xaa_\\xf35\\x8a\\x9b\\x9aj}?5\\xe7\\xfc\\xde\\x83s\\xd5\\xff_\\xb9z4?\\x1c\\xf18\\x01\\xa2\\x1b\\x90\\xb9\\xb3{\\x9a\\xd8\\xcf\\xa7\\xe3S\\xdf-\\xec7szg\\xaeu\\x9d\\x9341\\xb7%\\x1f[\\xebv\\x85\\xdd\\xdd;\\x93\\x0b\\xe7\\xa5\\xff^\\xbc<\\xd00\\xdd:6\\xb5~\\xd1\\xf5)\\x04\\xb5\\xa6w\\xea\\\\w~}\\xe7\\xf6\\xc9\\\\W\\xfd\\xff\\xd66!\\x8f:V\\x9c\\x01\\x01\\x128@\\xd4to\\xdd\\x1eO7n\\x8e\\xe5;D5K\\xddE^\\xbf~,\\xff\\x00\\xd7\\xedyy\\xa1q\\xe9G\\xac\\x06\\xa0\\xbb=\\xdd\\xb9\\xea\\xeeX\\xc1\\xd1\\x1c GOX\\xde\\xa6F\\xa7\\x1f\\xbd\\xee,K\\x83\\xd4\\x13[\\xf5\\xc6X5\\x86\\xaaq\\xe8;u7\\xda\\xea\\xfc\\xd7\\xef\\xad\\x16\\xeb\\xf5\\xf4Oi\\xe8\\xba\\xc3\\xaf\\xdfU\\xcf\\x9d\\xd9\\x9d\\x1b\\xabF\\x06jR\\x1a\\xdd\\xcc\\x9f\\xa9\\x9a\\x9a\\x9aR\\xd9O\\xcd^\\x8d\\xa5|Vw\\xf3\\xba^\\xed\\xa7\\xbb^\\xdd\\xfd\\xea\\xbc\\'\\xe7\\xb6\\xe6m\\x1a\\x99\\x95\\xcf\\x1e>\\xfeu\\xde\\xa6&\\xaa\\xcf\\xeb\\xdcGN\\xae\\xca\\xdb\\xaafY\\xed\\xa7\\xa0\\xbdt\\xe5\\xc8\\xc2]\\xf5\\xaa%\\xaem\\xa9\\x00\\xd15($.\\\\:\\x98_\\xeb\\xee\\xbe\\xe2\\xb8:_\\xa3\\xa4`\\xaa\\xa6\\xbf\\xfe\\xd2\\x10 g/\\xf4\\xe5sTh\\xab\\xa6\\x1a\\xc5h\\xbf=\\x87\\xdf_\\xd8OAQj\\xac\\xe6\\xab\\xd1\\x92\\xf692\\xf6\\xf5c\\x05\\xc8\\xf8\\xcc\\xa6\\xbcM\\xb5\\xd7w\\xae\\xdd\\xfdR\\x9a\\x9c\\xdf\\xb60m\\xaa}4\\x1a\\xca\\xc7?\\xf4^\\xed\\xfb:\\xb3\\xf7N\\x9f\\xef\\xcd\\xafu\\xfd\\n\\x8ds\\x17\\x0fd\\x7f\\xe9}\\xf9M\\x9f\\x1b\\x9b\\xda\\xb0\\xe8xe\\xe4\\xa8\\x87\\x10\\xc4Zu\\xd6\\xf6zPj$\\xe4\\xf1a\\x04\\xd4\\x91\\x19\\x10 \\x81\\x03\\xa44$M\\xe3\\xd4\\xb7\\xab\\xc9h{\\xb9{\\xd74M\\xf5#^\\xbf\\xcc\\x1aHg\\x0e\\xa4\\xcbW\\x06\\x17M\\xff\\xa8\\x81\\xdd\\xbd3\\xb5p\\x07\\xaaQ\\xc4\\xf9\\x8b\\xfdm\\xa7\\x89\\xeaR\\x93on\\xd2u\\xa9\\xf1(<\\xd4\\xf4\\xeb\\xdb\\xd5T\\xcaq\\xea\\x01\\xa2&U\\xdf\\xaf\\x84\\x9e\\xa6\\xc8\\x1a\\xbf\\xb3\\x1ez\\x9dy$\\xa0ph\\x9e\\xbeQ\\xc3\\xd3w*(\\xf4\\xfa\\xf6\\xad\\xf1t1O;u>\\xd1\\x1a\\x88\\xa6\\xfc4UW\\xd6@\\xd4D\\xb5\\x9f\\x82N\\xc1T\\xff\\xdeu\\xbb_^4\\nQ\\x80\\xcc\\x9f\\xdd\\xdbp\\x0c\\x05\\xaeF!\\x1a\\xa5\\xb5;\\x0f\\xd5B7\\x0e\\x1a-<j\\x80(l5\\x1a:}\\xae\\xbba?\\x05\\x97n\\x12t\\xce\\xd5~/\\xe4\\x1b\\x10\\x8d\\xe0\\xca>\\x9aJ\\xac7|]C\\xab =wa\\xff\\xc2\\xf7\\xd4\\x03\\xa4>\\xa2\\x95\\xf6\\x0f}\\x92\\xb7k\\x1ar\\xa5\\x7fs\\xa8\\xe3\\x91\\x18\\x10 \\x81\\x03d\\xfa\\xd4\\x8e\\x07Oc\\xbd\\xd8\\xf4\\xe3\\x7f6OAhZ\\xa2~\\xf7\\xa89\\xe7\\xa5\\x02dc\\xf7k-\\x83F*w\\xea\\xd5\\xe2}\\xc7\\xc2\\xc2\\xfe\\xa5\\xcb\\x87s\\xb3l\\x9e\\xdahTg:{\\xbe/\\xef\\x7f\\xea\\xdc\\xbe\\xbc\\x0eS\\x0f\\x1e\\xad\\x9f\\xe4\\xc61T5\\xda\\xba\\xd4\\xd8t\\x17_\\x1a^\\xab\\x00\\xd1\\xe7\\x9a\\xf9\\xa89\\x95Q\\x8f^k\\x8e=\\x8f>j\\r\\xb09\\x80\\xca\\x1c\\xff\\xf0\\x83k\\xbdtu0O\\xad\\xb4[SZ\\xee)\\xac\\x1b7\\x8e\\xa7\\x03#\\x9f\\xe5}4\\x9a\\xc8SL\\xd7\\x86r\\x03\\xadK\\xd7Wo\\xfa\\xad\\x02D:s\\xbe77\\xfb\\xc2Nw\\xe6\\x1aa\\xe9\\x9a\\xf4\\xf9\\xf1\\xe9\\x8dy\\xcaMSw\\x8f\\x1a Z\\xbf\\xd0k\\x8d^\\x9a\\xf7-\\xa3\\x10\\x85\\x9c^\\xeb\\x9c\\xaa\\xe9\\xb8\\xce\\x85iI\\x9d\\x8fF,z\\xadp\\xd3tV\\xf3\\xf5)\\xb4\\xb5_\\xf9\\\\\\xbb\\x00\\xd1\\xf7\\x88\\x99\\xf6\\xd5\\xd4\\x98F^+\\xfd\\xdbC\\x1dK2 @\\x02\\x07\\x88\\x02BA\\xd1\\xeaNYM\\xf6\\xcc\\xf9\\x9e\\x86\\x91\\x8a\\x9a\\xc5R\\x01\\xa2\\xb9f\\xbdV\\x03m\\xfe\\xbe2=R_[Q\\xf3\\xd2\\xf4L^w\\xb9=\\x9e\\x17\\xe6\\xdb]\\x83\\x9a\\x85\\x16\\xcf\\xaf\\xdd\\x18\\xc9\\xfb_\\xbe:\\x98\\x17\\xf1\\xf5\\x9e\\xd6B\\xb4M\\xc1\\xd2\\xfc\\xb9\\xb2\\xe6Q\\x02\\xaaU\\x80\\x94\\xa9\\x8f\\xc6\\xe9\\x95\\x8e\\xccFM\\xb0,\\x9ck\\x1f5\\xbd\\xe6ch\\xb1\\xb6\\x99\\xaf\\xc2V#\\x1fmWS^\\xea\\x8f-K\\x80\\x88\\xb3\\xceE\\xd3\\x89\\xd5]xg\\xc3\\x08\\xa2\\n\\x95\\xd1\\xdc\\xe0\\x9b5:\\xb9n\\xd9\\x00),\\xb4\\xa8\\xac\\x10\\xd1\\xba\\x8f^\\xeb\\x0e_\\xebVz\\xadQ\\xc2\\xe3\\x04\\xc8\\xde\\xc3\\x1fTk\\x10\\xc3U\\xd0\\xd5U\\xd6*\\xca\\xc3\\x11e\\x84Pq\\xea\\xcc\\xb5\\xd44c\\xd9\\xff\\xfc\\xa5\\xfe\\x85\\xe3\\xb7R\\t\\xe2v\\x01R\\x82V5\\xd2H\\xaaZ\\xc7\\xean\\xf1\\xb0\\x052\\'\\x0c\\x08\\x10\\x07Ex\\xd2\\x0091\\xf3}\\x9b\\xb9\\xf7W\\x1a\\x16\\xb5\\xd5\\xe8\\xeb\\xf3\\xd9\\xed\\x02\\xa4\\x9aN\\x99\\xcb\\x0b\\xe6\\x8b\\x1aO^|\\x9eo\\xb9\\x16\\xa0\\xa7\\x7f\\xd4L\\xd4\\xd8\\x9bGC\\xcd\\xd2\\\\\\xbd\\x9a\\x95\\xd61\\xb4\\x86R_\\x0cV\\x03n\\xde\\xff\\xc2\\xe5C\\xb9\\x81\\x97\\xd7O\\x1a :/\\xbdn5\\xbdS\\x1a\\xe5\\xa6\\x9e\\xc6\\'\\x8f$\\x85\\xee\\xb5k\\xc3\\xf9\\x98\\xed\\x1a\\xd9R\\x8b\\xe8\\x0f\\xd5\\x99\\xaf\\xb9U04\\xab]\\x80(\\xac\\x0b\\x0b\\x8d\\x96\\xaa@|\\xb8.%\\xe9n\\xffq\\x02\\xa4Lo\\xd6\\xd7\\xb7\\x8at\\x0e\\x1a\\r\\x94\\xf0\\xd6\\x7fu\\xfc\\xa9\\xb9m\\xf9F\\xa2\\x99\\xb9\\xd6s4\\x9aZz4\\xbat\\x80\\xd4\\xa7/uNy\\xd48\\xbdx\\xd4\\x88:\\\\0 @\\x02\\x07\\x88\\x1aw\\xabi\\x99\\xd2\\xd0\\xca\\xe2\\xb3\\xe6\\xb9\\xb5~\\xa1\\xe6R\\x7f\\xdc\\xb2\\xd5\\xdf\\x81\\x9c\\xbfx 7\\xba\\xfac\\x95\\n$\\xadE\\\\\\xce\\xf3\\xf7\\xad\\xcf\\xf1\\xc8\\xd8\\xbf\\xaau\\x886\\x8f\\xfc6Kw\\xcb\\x9a\\xd3\\xaf\\x9a\\xc5\\xf3\\xf9\\x8eSk\\x06\\xf5\\xe6S\\x9a\\x94\\xee\\xae\\x9f6@\\xca\\x14\\x90\\xee\\x90\\xeb\\x8d^\\xd3&j\\x8aW\\xaf\\x1dm\\xbb\\xe6\\xa1\\x91\\x93\\xbe\\x7f\\xdb\\xfej\\xfa\\xee\\xc9\\x02\\xa4#/6k\\x8aG\\x8fH/\\x17 z\\x1a\\xa9\\xbeM\\xd39\\xf5p\\xd7(\\xa7<\\xbd\\xf48\\x01Rn:\\xcazO\\x19I\\xdc\\xbay\\xa2\\xe1\\xa1\\x06\\xad[)\\x0c\\x9a\\x83L\\xa3\\x03\\xf1\\xd7\\xc8C\\xc7\\xaaOE\\x16\\x9f\\xca\\x0bO\\x1b EZ\\xa4_j\\xdd\\x07u\\xac(\\x03\\x02$\\xf4c\\xbc\\x9d\\xf9\\x8eZ\\xef\\xcd\\x9e\\xde\\x9d\\xa7\\x99\\xca4\\x87~\\xe0\\xf5\\x1fw5M4\\x97\\x173u\\xd7\\xaag\\xf4K3\\xa9\\x07\\x88\\x16F\\x15 \\x9a\\xeb\\xd6T\\x96\\xde\\xd3\\xbc\\xb4\\x1a\\xef\\xc3\\xe9\\xab\\xce\\xdcX\\xb4.\\xa2\\x06\\xa6\\x86\\xa1\\x05W->\\xb7zf_k+\\n\\x8c\\xa1\\xf1o\\xf2y\\xe8)$\\x1d\\xa3\\xde$\\xf7\\x0f\\x7f\\x9a\\xcfO\\x8b\\xccZ\\xfc\\xd7\\x82\\xbb\\x02F\\xe7Q=\\xd1\\xf3\\xf4\\x01\\xa2\\xbf\\xb9\\xd0w\\xaaA\\xeb\\x1ct>j\\x9ej\\xea\\xbbjOA\\x89\\x9d\\xde\\xd7\\x88MOni\\x1f\\x85L\\xbb\\xb5\\x90G\\r\\x10\\xad\\x1fU\\x8f1O\\xe5\\xbbj\\xd5K|5\\x15Y\\xafU\\xf5\\x18\\xef\\\\f<x\\xc2\\xd2\\xd8\\xf4\\x86\\xfch\\xec\\x9d\\xdb\\x93\\x0b\\x7f\\x9f\\xa1\\xa7\\xa5\\xd4\\xf45uX\\xb8\\xea|\\x97[\\x03Q\\xbd\\x8a_\\xca\\xf9V\\x0f]\\xcc\\xe5@\\xd0w\\xc9\\x1f\\xfa\\x1e\\xdd44\\x8f\\xca\\xaa\\xb5\\xa4\\xea1h\\x05k\\xfd=\\x85\\xff\\xc5\\xcb\\x87\\xf2{\\xba&\\xd5Q\\xebK\\x1a\\t\\xd7\\xa7>\\xdb\\x05\\x88F\\xca\\xdaW~\\xd2\\xf5\\x9c\\x9c\\xd5~s\\xd9g+\\xfd\\x1bD\\x1d-\\x19\\x10 \\x01\\xcc\\xa1\\xf9wM\\xf7\\xb4ZT\\xd4\\x94Pi\\x84\\xfaQ\\xaa\\x91\\xeb\\x07\\xd7\\xea\\x0f\\xca\\xd4`u7\\xa7&\\xa6\\x06\\xae\\xf9x\\xbd\\xae?\\x1aZ\\x1a\\x9d\\xe6\\x9e\\xb5OYK\\xa9\\x1f[\\xcdKMVa\\xa4\\xe6\\xab&\\xaf\\x86\\xd1n\\xf4\\xa1\\xa7\\xa3t\\x1c\\xed\\xa7\\xfdu\\xdc\\xeaQ\\xda\\x97\\x16\\x05\\x81\\xa6\\xac4m\\xa2f9=\\xdf\\xb5h\\xcaL\\xd3\\x1a\\x9a\\xf3\\xafo\\xd3#\\xb0\\xe2\\xa3\\x7f\\x8f\\xaa\\xf9\\xc9\\xb1\\xe6?\\x92T\\x88h!\\xbf\\xfa\\xdb\\x89\\x99|^\\xf5\\xcf\\xa9\\t\\xea\\x91\\xe2\\x12,j\\xd2j\\xe4K\\xfd-\\x82\\xa6\\xdet\\xfc\\xf5{_]\\xb6\\x96Z\\xf7Q\\xe8+$t\\x9d7o\\x1e\\xcf\\xc7\\xab\\x87\\x93\\xde\\xd3hL5\\xa8\\x1a\\xf9d>\\x87\\xb2f\\xb4\\xc0\\xb5\\xef\\xcd\\xcc\\xbd\\xe2:\\x93?\\xa7\\x00n\\xb5\\x86U$_h\\xc4\\xaa\\xda\\xe9f\\xa1lW\\x80V\\xa3\\xcf\\xd9\\xec\\x0f}\\xaf\\xfe\\xd8\\xaf\\xd5w\\xe8\\x11oM\\xa7\\xb5\\x9a\\xae\\xcc\\x8f}O\\xacM\\xd7\\xae\\x8f\\xe4\\xeb\\xd3M\\x85\\xd6F4b*\\xfb(\\x14\\xc5\\xab\\xf9\\xdfr+\\xf5\\xd7gT\\x1f\\x05\\x9a\\xae\\xe5i\\xff\\xcd7\\xd4\\xf1?c@\\x80`0~`\\xce<\\xd0n\\r\\x04\\xc1\\xc0\\x9c1 @\\x1c\\x14\\x01\\xc1\\x80\\x00\\xc1\\x03\\x16\\x90\\x01\\x01\\xe2\\xa0\\x08\\x08\\x06\\x04\\x08\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x03\\x02\\xc4A\\x11\\x10\\x0c\\xf0\\x00\\x1e\\xb0\\x80\\x0c\\x08\\x10\\x07E@0\\xc0\\x03x\\xc0\\x022 @\\x1c\\x14\\x01\\xc1\\x00\\x0f\\xe0\\x01\\x0b\\xc8\\x80\\x00qP\\x04\\x04\\x03<\\x80\\x07, \\x83\\xff\\x02\\xee\\x98\\x1b\\x1e\\x91\\x08\\xe7\\x01\\x00\\x00\\x00\\x00IEND\\xaeB`\\x82'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "consulta = \"image/\"\n",
    "porte = \"400x200/\"\n",
    "color_fondo = \"82944b/\"\n",
    "color_fuente = \"d4d2bc\"\n",
    "\n",
    "endpoint_4 = consulta + porte + color_fondo + color_fuente\n",
    "\n",
    "parametros = {\n",
    "    \"text\": \"Todos somos Pepa lovers\",\n",
    "    \"fontFamily\": \"ubuntu\"\n",
    "}\n",
    "\n",
    "respuesta = requests.get(BASE + endpoint_4, params=parametros)\n",
    "try:\n",
    "    respuesta.json()\n",
    "except JSONDecodeError:\n",
    "    content_type = respuesta.headers['Content-Type']\n",
    "    print('El contenido de la response no se encuentra en formato JSON, ' \\\n",
    "          f'sino que su contenido es \"{content_type}\"')\n",
    "\n",
    "respuesta.content"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39e7c05e",
   "metadata": {},
   "source": [
    "### Uso de `post`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5f89f460",
   "metadata": {},
   "source": [
    "En el caso de la API con la que hemos estado haciendo estas pruebas, solo se ofrecen servicios para realizar consultas, lo que se puede llevar a cabo utilizando el método `GET` del protocolo HTTP. Sin embargo, muchas veces queremos crear recursos en nuestro servidor, como por ejemplo un comentario en Instagram, y para esto debemos utilizar el método `POST` del protocolo.\n",
    "\n",
    "Siguiendo con el uso de `DummyJSON`, ahora utilizaremos la API para crear un nuevo producto. En la práctica no estará ocurriendo nada en el servidor, puesto que es solo una simulación, pero en la vida real uno esperaría que como respuesta a nuestra *request* se cree una entrada en la base de datos del servicio que estamos utilizando. \n",
    "\n",
    "A diferencia del método `GET`, cuando utilizamos el método `POST` podemos enviar información a la API utilizando el parámetro `data`, al cual podemos pasarle un diccionario de Python con la información que queremos enviar.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "1cc4d649",
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "\n",
    "BASE = \"https://dummyjson.com/\"\n",
    "endpoint_5 = \"products/add\"\n",
    "\n",
    "# Los datos del producto que vamos a crear:\n",
    "data = {\n",
    "    'title': 'Comida de Pepa',\n",
    "    'description': 'Alimento esencial de una tortuga',\n",
    "    'price': 2233,\n",
    "    'rating': 5,\n",
    "}\n",
    "\n",
    "respuesta = requests.post(BASE + endpoint_5, data=data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "4d8f314f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "201\n",
      "Created\n"
     ]
    }
   ],
   "source": [
    "# Vemos que obtenemos un código de que nuestro producto fue creado\n",
    "print(respuesta.status_code)\n",
    "print(respuesta.reason)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "6463a688",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dict_keys(['id', 'title', 'price', 'rating', 'description'])\n"
     ]
    }
   ],
   "source": [
    "# Esta API nos retorna un JSON con el mismo recurso creado, notese que se le asignó un id al artículo\n",
    "data = respuesta.json() \n",
    "print(data.keys())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "b7875eae",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'id': 195,\n",
       " 'title': 'Comida de Pepa',\n",
       " 'price': '2233',\n",
       " 'rating': '5',\n",
       " 'description': 'Alimento esencial de una tortuga'}"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eb0363a2",
   "metadata": {},
   "source": [
    "### Autenticación en _headers_"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54f74b18",
   "metadata": {},
   "source": [
    "Aparte del método `post`, tambien tenemos `.put()`, `.patch()` o `.delete()`. Generalmente, este tipo de requests repercuten en la modificación de una base de datos, y para lograr esto, muchas veces es necesario tener una autorización previa. \n",
    "\n",
    "Es aquí que surge la necesidad de ocupar el parámetro `headers` que permite incluir información en la cabezara de la solicitud incuyendo, por ejemplo, un token especial de acceso que a la API le sirve para identificarte y verificar si tienes los permisos. \n",
    "\n",
    "Utilizar este parámetro es análogo a `data`. Solo es necesario crear un diccionario e incluirlo en la _requests_. Las llaves del diccionario puede cambiar según la API que queramos acceder."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "d5f07722",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Token: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwidXNlcm5hbWUiOiJlbWlseXMiLCJlbWFpbCI6ImVtaWx5LmpvaG5zb25AeC5kdW1teWpzb24uY29tIiwiZmlyc3ROYW1lIjoiRW1pbHkiLCJsYXN0TmFtZSI6IkpvaG5zb24iLCJnZW5kZXIiOiJmZW1hbGUiLCJpbWFnZSI6Imh0dHBzOi8vZHVtbXlqc29uLmNvbS9pY29uL2VtaWx5cy8xMjgiLCJpYXQiOjE3Nzc1NTg0MzEsImV4cCI6MTc3NzU2MDIzMX0.aRfS7E5C7_ffNVpzl0g9CXpXakpkAi-vDLe8RTssMkg\n"
     ]
    }
   ],
   "source": [
    "# Primero obtendremos una key (en este caso un token), para poder\n",
    "# hacer consultas que necesitan autentificación.\n",
    "url = 'https://dummyjson.com/auth/login'\n",
    "body = {'username': 'emilys', 'password': 'emilyspass', 'expiresInMins': 30}\n",
    "\n",
    "response = requests.post(url, data=body)\n",
    "data = response.json()\n",
    "\n",
    "TOKEN = 'Bearer ' + data['accessToken']\n",
    "print('Token:', TOKEN)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "e2251309",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "200"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Ahora, utilizaremos el token obtenido en la celda anterior para obtener\n",
    "# información sobre el usuario correspondiente.\n",
    "\n",
    "url = 'https://dummyjson.com/auth/me'\n",
    "header = {'Authorization': TOKEN}\n",
    "\n",
    "respuesta = requests.get(url, headers=header)\n",
    "respuesta.status_code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "2034afef",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'id': 1,\n",
       " 'firstName': 'Emily',\n",
       " 'lastName': 'Johnson',\n",
       " 'maidenName': 'Smith',\n",
       " 'age': 29,\n",
       " 'gender': 'female',\n",
       " 'email': 'emily.johnson@x.dummyjson.com',\n",
       " 'phone': '+81 965-431-3024',\n",
       " 'username': 'emilys',\n",
       " 'password': 'emilyspass',\n",
       " 'birthDate': '1996-5-30',\n",
       " 'image': 'https://dummyjson.com/icon/emilys/128',\n",
       " 'bloodGroup': 'O-',\n",
       " 'height': 193.24,\n",
       " 'weight': 63.16,\n",
       " 'eyeColor': 'Green',\n",
       " 'hair': {'color': 'Brown', 'type': 'Curly'},\n",
       " 'ip': '42.48.100.32',\n",
       " 'address': {'address': '626 Main Street',\n",
       "  'city': 'Phoenix',\n",
       "  'state': 'Mississippi',\n",
       "  'stateCode': 'MS',\n",
       "  'postalCode': '29112',\n",
       "  'coordinates': {'lat': -77.16213, 'lng': -92.084824},\n",
       "  'country': 'United States'},\n",
       " 'macAddress': '47:fa:41:18:ec:eb',\n",
       " 'university': 'University of Wisconsin--Madison',\n",
       " 'bank': {'cardExpire': '05/28',\n",
       "  'cardNumber': '3693233511855044',\n",
       "  'cardType': 'Diners Club International',\n",
       "  'currency': 'GBP',\n",
       "  'iban': 'GB74MH2UZLR9TRPHYNU8F8'},\n",
       " 'company': {'department': 'Engineering',\n",
       "  'name': 'Dooley, Kozey and Cronin',\n",
       "  'title': 'Sales Manager',\n",
       "  'address': {'address': '263 Tenth Street',\n",
       "   'city': 'San Francisco',\n",
       "   'state': 'Wisconsin',\n",
       "   'stateCode': 'WI',\n",
       "   'postalCode': '37657',\n",
       "   'coordinates': {'lat': 71.814525, 'lng': -161.150263},\n",
       "   'country': 'United States'}},\n",
       " 'ein': '977-175',\n",
       " 'ssn': '900-590-289',\n",
       " 'userAgent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.93 Safari/537.36',\n",
       " 'crypto': {'coin': 'Bitcoin',\n",
       "  'wallet': '0xb9fc2fe63b2a6c003f1c324c3bfa53259162181a',\n",
       "  'network': 'Ethereum (ERC20)'},\n",
       " 'role': 'admin'}"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "respuesta.json()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "4eada5e7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "401\n",
      "Unauthorized\n"
     ]
    }
   ],
   "source": [
    "# Finalmente, comprobemos cómo se comporta la request cuando NO entregamos el token.\n",
    "url = 'https://dummyjson.com/auth/me'\n",
    "\n",
    "respuesta = requests.get(url)\n",
    "\n",
    "print(respuesta.status_code)\n",
    "print(respuesta.reason)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "de52867c",
   "metadata": {},
   "source": [
    "### Caso aplicado: API de GITHUB"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8dd21bb7",
   "metadata": {},
   "source": [
    "A continuación, te presentamos un caso aplicado para crear una _issue_ en un repositorio de Github mediante su API.  Las _GitHub Issues_ son elementos que puede crear en un repositorio para planear, analizar y realizar un seguimiento del trabajo. Por ejemplo, [aquí](https://github.com/scikit-learn/scikit-learn/issues) podemos observar como una librería de _Machine Learning_ utiliza las _issues_ para que los usuarios reporten información sobre la librería.\n",
    "\n",
    "En este caso, para crear una _issue_, la API de Github pide que el `data` a enviar sea un diccionario en su forma de _string_, es decir, `json.dumps(data)`.\n",
    "\n",
    "Además, para que este caso aplicado funcione correctamante, se requiere:\n",
    "\n",
    "1. Completar `github_repo` con el nombre de tu repositorio de github dado en el curso. Por ejemplo: `\"prueba-iic2233-2026-1\"`\n",
    "2. Completar `token` con un _access token_ generado en Github. Puedes generar uno en [esta página](https://github.com/settings/tokens/new). Este _token_ debe tener al menos el siguiente permiso para poder crear una issue: _repo: Full control of private repositories_."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "1d87640d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "401"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import json\n",
    "import requests\n",
    "\n",
    "github_repo = 'prueba-iic2233-2026-1'\n",
    "TOKEN = \"ghp_token\"\n",
    "\n",
    "body = {\n",
    "    'title': \"Creando una issue con la API\",\n",
    "    'body': \"Ahora tengo el poder para hacer issues desde Python! 🎉\"\n",
    "}\n",
    "\n",
    "my_headers = {\n",
    "    'Authorization': 'token ' + TOKEN,\n",
    "    'Accept': 'application/vnd.github.v3+json'\n",
    "}\n",
    "\n",
    "url = f\"https://api.github.com/repos/IIC2233/{github_repo}/issues\"\n",
    "\n",
    "respuesta = requests.post(url, data=json.dumps(body), headers=my_headers)\n",
    "respuesta.status_code"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ff56a5f",
   "metadata": {},
   "source": [
    "Si la celda anterior arrojó un `201`. Significa que el _token_ utilizado y el `github_repo` estaban correctos, así que se creó la _issue_. Ejecuta la siguiente celda para ver el _link_ a dicha issue."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "db7b91ef",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hubo un error al crear la issue. Status code: 401\n"
     ]
    }
   ],
   "source": [
    "if respuesta.status_code == 201:\n",
    "    print(\"Issue creada exitosamente!\")\n",
    "    print(\"Puedes verla en:\", respuesta.json()[\"html_url\"])\n",
    "else:\n",
    "    print(\"Hubo un error al crear la issue. Status code:\", respuesta.status_code)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec21d858",
   "metadata": {},
   "source": [
    "**Te invitamos a consumir diferentes APIs desde Python para poner a prueba este contenidos**. Algunas ideas de estudio pueden ser:\n",
    "- Revisar los diferentes _endpoint_ que tenía [_DummyJSON_](https://dummyjson.com/) para inventar más información.\n",
    "- Revisar la documentación de [OMDb API](http://www.omdbapi.com/#usage) para buscar películas.\n",
    "- Usar la APi de [pokemon](https://pokeapi.co/docs/v2#pokemon) para buscar información de tu pokemon favorito.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b2ba4f5",
   "metadata": {},
   "source": [
    "Ahora que conocemos los métodos principales de `ThreadPoolExecutor`, vamos a ver en la práctica la diferencia entre la forma **secuencial** y la forma **concurrente** de enviar requests, comparando el tiempo total de cada enfoque al obtener 10 recetas de la API de _DummyJSON_."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51415ca5",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "## Resumiendo\n",
    "\n",
    "Todas las APIs tienen:\n",
    "* Una **URL BASE**, que consiste en un _link_ de prefijo que toda consulta debe tener. \n",
    "* Uno o más **_endpoint_**, que -para efectos del curso- son las diferentes rutas que dispone la API para hacer consultas.\n",
    "\n",
    "En lo que respecta a las consultas (_requests_):\n",
    "* Independiente de su tipo (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`), podrán **utilizar los parámetros o el *body*** para entregar información adicional a la API.  \n",
    "* Dependiendo de su tipo (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`), puede **cambiar la forma en que se comporte el _endpoint_** (si es que se encuentra definido para más de un tipo de consulta).\n",
    "* Se utilizarán los *headers* para enviar las **credenciales de autentificación**, en caso de qeu sean necesarias para realizar la consulta.\n",
    "\n",
    "En lo que respecta a las respuestas (_responses_):\n",
    "* Los datos asociados a la respuesta se encontrarán en el ***body*** y, dependiendo de la información transmitida, estos **podrán ser distintos tipos de datos** (HTML, JSON, imágenes, etc.)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "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
}
