Skip to content

Instantly share code, notes, and snippets.

@timeseries-ru
Created October 24, 2022 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save timeseries-ru/51d5dba546f89d3799fe91062f86fa6a to your computer and use it in GitHub Desktop.
Save timeseries-ru/51d5dba546f89d3799fe91062f86fa6a to your computer and use it in GitHub Desktop.
cat_hidden.ipynb
Display the source blob
Display the rendered blob
Raw
{
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {
"provenance": [],
"collapsed_sections": [],
"authorship_tag": "ABX9TyO5q9lFNRz2cGW/iNiVXHga",
"include_colab_link": true
},
"kernelspec": {
"name": "python3",
"display_name": "Python 3"
},
"language_info": {
"name": "python"
},
"accelerator": "GPU"
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
"<a href=\"https://colab.research.google.com/gist/timeseries-ru/51d5dba546f89d3799fe91062f86fa6a/cat_hidden.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"id": "tVkJHLcVtJRt"
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"import sympy"
]
},
{
"cell_type": "code",
"source": [
"curve_rho = \"\"\"\n",
"-(721 sin(t))/4+196/3 sin(2 t)-86/3 sin(3 t)-131/2 sin(4 t)+\n",
"477/14 sin(5 t)+27 sin(6 t)-29/2 sin(7 t)+68/5 sin(8 t)+1/10 sin(9 t)+\n",
"23/4 sin(10 t)-19/2 sin(12 t)-85/21 sin(13 t)+2/3 sin(14 t)+27/5 sin(15 t)+7/4 sin(16 t)+17/9 sin(17 t)-4 sin(18 t)-1/2 sin(19 t)+\n",
"1/6 sin(20 t)+6/7 sin(21 t)-1/8 sin(22 t)+1/3 sin(23 t)+3/2 sin(24 t)+13/5 sin(25 t)+sin(26 t)-2 sin(27 t)+3/5 sin(28 t)-1/5 sin(29 t)+\n",
"1/5 sin(30 t)+(2337 cos(t))/8-43/5 cos(2 t)+322/5 cos(3 t)-117/5 cos(4 t)-26/5 cos(5 t)-23/3 cos(6 t)+143/4 cos(7 t)-11/4 cos(8 t)-31/3 cos(9 t)-\n",
"13/4 cos(10 t)-9/2 cos(11 t)+41/20 cos(12 t)+8 cos(13 t)+2/3 cos(14 t)+6 cos(15 t)+17/4 cos(16 t)-3/2 cos(17 t)-29/10 cos(18 t)+\n",
"11/6 cos(19 t)+12/5 cos(20 t)+3/2 cos(21 t)+11/12 cos(22 t)-4/5 cos(23 t)+cos(24 t)+17/8 cos(25 t)-7/2 cos(26 t)-5/6 cos(27 t)-\n",
"11/10 cos(28 t)+1/2 cos(29 t)-1/5 cos(30 t)\"\"\".replace('\\n', '')\n",
"curve_phi = \"\"\" -(637 sin(t))/2-188/5 sin(2 t)-11/7 sin(3 t)-12/5 sin(4 t)+11/3 sin(5 t)-37/4 sin(6 t)+\n",
"8/3 sin(7 t)+65/6 sin(8 t)-32/5 sin(9 t)-41/4 sin(10 t)-38/3 sin(11 t)-47/8 sin(12 t)+5/4 sin(13 t)-41/7 sin(14 t)-7/3 sin(15 t)-\n",
"13/7 sin(16 t)+17/4 sin(17 t)-9/4 sin(18 t)+8/9 sin(19 t)+3/5 sin(20 t)-2/5 sin(21 t)+4/3 sin(22 t)+1/3 sin(23 t)+3/5 sin(24 t)-\n",
"3/5 sin(25 t)+6/5 sin(26 t)-1/5 sin(27 t)+10/9 sin(28 t)+1/3 sin(29 t)-3/4 sin(30 t)-(125 cos(t))/2-521/9 cos(2 t)-359/3 cos(3 t)+\n",
"47/3 cos(4 t)-33/2 cos(5 t)-5/4 cos(6 t)+31/8 cos(7 t)+9/10 cos(8 t)-119/4 cos(9 t)-17/2 cos(10 t)+\n",
"22/3 cos(11 t)+15/4 cos(12 t)-5/2 cos(13 t)+19/6 cos(14 t)+7/4 cos(15 t)+31/4 cos(16 t)-cos(17 t)+11/10 cos(18 t)-2/3 cos(19 t)+\n",
"13/3 cos(20 t)-5/4 cos(21 t)+2/3 cos(22 t)+1/4 cos(23 t)+5/6 cos(24 t)+3/4 cos(26 t)-1/2 cos(27 t)-1/10 cos(28 t)-1/3 cos(29 t)-1/19 cos(30 t)\n",
"\"\"\".replace('\\n', '') \n",
"\n",
"from sympy.parsing.sympy_parser import standard_transformations, implicit_multiplication_application\n",
"transformations = (standard_transformations + (implicit_multiplication_application,))\n",
"\n",
"cat_rho = sympy.parse_expr(curve_rho, transformations=transformations, evaluate=False)\n",
"cat_phi = sympy.parse_expr(curve_phi, transformations=transformations, evaluate=False)"
],
"metadata": {
"id": "8UYWyoVLtP7H"
},
"execution_count": 2,
"outputs": []
},
{
"cell_type": "code",
"source": [
"cat_points = np.array([\n",
" [cat_rho.evalf(subs={'t': t}), cat_phi.evalf(subs={'t': t})] for t in np.linspace(0, 2 * np.pi) \n",
"])\n",
"cat_points = cat_points / np.amax(cat_points) / 2\n",
"\n",
"square = 512\n",
"\n",
"def draw_cat(image=None, center=None, size=128, color=0.65, flip=False):\n",
" cat = np.zeros((size, size, 1))\n",
" points = cat_points.copy() * size\n",
" points += size / 2\n",
" cat = cv2.drawContours(cat, [points.astype(np.int32)], -1, color, -1)\n",
" cat = cat[::-1]\n",
" if flip:\n",
" cat = cat[:, ::-1]\n",
" if image is None:\n",
" image = np.zeros((square * 2, square * 2, 1))\n",
" if center is None:\n",
" center = [size * 2, size * 2]\n",
" image[\n",
" center[0] - cat.shape[0] // 2:center[0] + cat.shape[0] // 2,\n",
" center[1] - cat.shape[1] // 2:center[1] + cat.shape[1] // 2\n",
" ] = cat\n",
" return image[:square, :square].transpose(2, 0, 1)\n",
"\n",
"plt.imshow(draw_cat(flip=True)[0], cmap='gray');"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 269
},
"id": "741N2tfqw1Dy",
"outputId": "7dbe1b63-4d67-4a3b-b2db-e602224d25e2"
},
"execution_count": 3,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
],
"image/png": "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\n"
},
"metadata": {
"needs_background": "light"
}
}
]
},
{
"cell_type": "code",
"source": [
"!pip install skorch kornia"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "yZj3m6Hn6i8u",
"outputId": "7b0edb0c-650a-429a-c2dc-45eb18f7e818"
},
"execution_count": 4,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n",
"Requirement already satisfied: skorch in /usr/local/lib/python3.7/dist-packages (0.12.0)\n",
"Requirement already satisfied: kornia in /usr/local/lib/python3.7/dist-packages (0.6.8)\n",
"Requirement already satisfied: scikit-learn>=0.22.0 in /usr/local/lib/python3.7/dist-packages (from skorch) (1.0.2)\n",
"Requirement already satisfied: scipy>=1.1.0 in /usr/local/lib/python3.7/dist-packages (from skorch) (1.7.3)\n",
"Requirement already satisfied: tqdm>=4.14.0 in /usr/local/lib/python3.7/dist-packages (from skorch) (4.64.1)\n",
"Requirement already satisfied: tabulate>=0.7.7 in /usr/local/lib/python3.7/dist-packages (from skorch) (0.8.10)\n",
"Requirement already satisfied: numpy>=1.13.3 in /usr/local/lib/python3.7/dist-packages (from skorch) (1.21.6)\n",
"Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.22.0->skorch) (3.1.0)\n",
"Requirement already satisfied: joblib>=0.11 in /usr/local/lib/python3.7/dist-packages (from scikit-learn>=0.22.0->skorch) (1.2.0)\n",
"Requirement already satisfied: torch>=1.8.1 in /usr/local/lib/python3.7/dist-packages (from kornia) (1.12.1+cu113)\n",
"Requirement already satisfied: packaging in /usr/local/lib/python3.7/dist-packages (from kornia) (21.3)\n",
"Requirement already satisfied: typing-extensions in /usr/local/lib/python3.7/dist-packages (from torch>=1.8.1->kornia) (4.1.1)\n",
"Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /usr/local/lib/python3.7/dist-packages (from packaging->kornia) (3.0.9)\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"import torch\n",
"import torch.nn as nn\n",
"import torch.nn.functional as F\n",
"\n",
"size = 128\n",
"\n",
"class CatDataset(torch.utils.data.Dataset):\n",
" def __init__(self, length=300):\n",
" super(CatDataset, self).__init__()\n",
" self.length = length\n",
" def __len__(self):\n",
" return self.length\n",
" def __getitem__(self, index):\n",
" np.random.seed(index)\n",
" center = [\n",
" np.random.randint(size, square - size),\n",
" np.random.randint(size, square - size)\n",
" ]\n",
" cat_image = draw_cat(\n",
" center=center,\n",
" size=np.random.randint(16, size // 2) * 2,\n",
" color=np.random.uniform(),\n",
" flip=False\n",
" ).astype(np.float32)\n",
" return cat_image, cat_image\n",
"\n",
"plt.imshow(CatDataset()[1][0][0], cmap='gray');"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 269
},
"id": "LI6OajAb0s0u",
"outputId": "aeb95aba-2ad8-414e-aee9-49c685db935f"
},
"execution_count": 5,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
],
"image/png": "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\n"
},
"metadata": {
"needs_background": "light"
}
}
]
},
{
"cell_type": "code",
"source": [
"import kornia\n",
"\n",
"class CatModule(nn.Module):\n",
" def __init__(self, device='cuda'):\n",
" super(CatModule, self).__init__()\n",
"\n",
" self.device = device\n",
"\n",
" self.conv1 = nn.LazyConv2d(10, kernel_size=10)\n",
" self.drop1 = nn.Dropout(p=0.5)\n",
" self.drop2 = nn.Dropout(p=0.5)\n",
" self.fcl_1 = nn.LazyLinear(32)\n",
" self.fcl_2 = nn.LazyLinear(2 + 1 + 1)\n",
"\n",
" self.contour = torch.from_numpy(np.array(cat_points, dtype=np.float32)).to(device)\n",
" \n",
" def represent(self, X):\n",
" X = torch.relu(F.max_pool2d(self.drop1(self.conv1(X)), 5))\n",
" X = torch.relu(self.drop2(self.fcl_1(X.reshape(len(X), -1))))\n",
" X = torch.tanh(self.fcl_2(X)) * 0.5 + 0.5\n",
" \n",
" centered = X[:, :2]\n",
" sized = X[:, 2]\n",
" colored = X[:, 3]\n",
"\n",
" return centered.reshape(-1, 2), sized.flatten(), colored.flatten()\n",
" \n",
" def draw(self, centered, sized, colored):\n",
" result = []\n",
" for index in range(len(centered)):\n",
" cat = self.contour.clone() * sized[index] * size\n",
" recolored = torch.tensor([colored[index]] * 3, requires_grad=True).to(self.device).float()\n",
" result.append(kornia.utils.draw_convex_polygon(\n",
" torch.zeros(1, 1, square, square).to(self.device),\n",
" cat.reshape(1, -1, 2) + centered[index] * square,\n",
" recolored.unsqueeze(dim=0)\n",
" ))\n",
" return torch.flip(torch.cat(result, dim=0), dims=(2,))[:, :1].to(self.device).float()\n",
"\n",
" def forward(self, X):\n",
" centered, sized, colored = self.represent(X)\n",
" return self.draw(centered, sized, colored)"
],
"metadata": {
"id": "scLVl9Kw8W7O"
},
"execution_count": 6,
"outputs": []
},
{
"cell_type": "code",
"source": [
"plt.imshow(CatModule(device='cpu').draw(\n",
" torch.from_numpy(np.asarray([[0.15, 0.75]])),\n",
" torch.tensor([0.5]), \n",
" torch.from_numpy(np.asarray([0.5]))\n",
")[0][0].detach().numpy(), cmap='gray', vmin=0, vmax=1);"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 324
},
"id": "6sEdilUyDM2m",
"outputId": "7f4c78b0-1d89-4045-aa88-ca3749d40a57"
},
"execution_count": 7,
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"/usr/local/lib/python3.7/dist-packages/torch/nn/modules/lazy.py:178: UserWarning: Lazy modules are a new feature under heavy development so changes to the API or functionality can happen at any moment.\n",
" warnings.warn('Lazy modules are a new feature under heavy development '\n"
]
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
],
"image/png": "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\n"
},
"metadata": {
"needs_background": "light"
}
}
]
},
{
"cell_type": "code",
"source": [
"import skorch\n",
"\n",
"torch.cuda.empty_cache()\n",
"\n",
"class Loss(nn.Module):\n",
" def __init__(self):\n",
" super(Loss, self).__init__()\n",
" self.loss = nn.MSELoss()\n",
"\n",
" def forward(self, output, target):\n",
" return self.loss(output, target) * 100\n",
"\n",
"cat_net = skorch.NeuralNet(\n",
" CatModule,\n",
" lr=1e-1,\n",
" batch_size=10,\n",
" max_epochs=10,\n",
" criterion=Loss,\n",
" optimizer=torch.optim.SGD,\n",
" predict_nonlinearity=None,\n",
" iterator_train__shuffle=True,\n",
" device='cuda'\n",
")\n",
"\n",
"dataset = CatDataset()\n",
"cat_net.fit(dataset)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "x7U89rGGADaO",
"outputId": "c60f314d-eb58-4423-d785-851f7809783b"
},
"execution_count": 8,
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"/usr/local/lib/python3.7/dist-packages/torch/nn/modules/lazy.py:178: UserWarning: Lazy modules are a new feature under heavy development so changes to the API or functionality can happen at any moment.\n",
" warnings.warn('Lazy modules are a new feature under heavy development '\n"
]
},
{
"output_type": "stream",
"name": "stdout",
"text": [
" epoch train_loss valid_loss dur\n",
"------- ------------ ------------ ------\n",
" 1 \u001b[36m0.5864\u001b[0m \u001b[32m0.5765\u001b[0m 4.0984\n",
" 2 \u001b[36m0.5862\u001b[0m 0.5765 3.7608\n",
" 3 0.5871 0.5765 4.9028\n",
" 4 \u001b[36m0.5833\u001b[0m 0.5765 4.1246\n",
" 5 0.5873 0.5765 2.6006\n",
" 6 0.5866 0.5765 2.3509\n",
" 7 0.5848 0.5765 2.3468\n",
" 8 0.5840 0.5765 2.3343\n",
" 9 \u001b[36m0.5825\u001b[0m 0.5765 2.3281\n",
" 10 0.5855 0.5765 2.3698\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"<class 'skorch.net.NeuralNet'>[initialized](\n",
" module_=CatModule(\n",
" (conv1): Conv2d(1, 10, kernel_size=(10, 10), stride=(1, 1))\n",
" (drop1): Dropout(p=0.5, inplace=False)\n",
" (drop2): Dropout(p=0.5, inplace=False)\n",
" (fcl_1): Linear(in_features=100000, out_features=32, bias=True)\n",
" (fcl_2): Linear(in_features=32, out_features=4, bias=True)\n",
" ),\n",
")"
]
},
"metadata": {},
"execution_count": 8
}
]
},
{
"cell_type": "code",
"source": [
"test = CatDataset()[777][0]\n",
"\n",
"with torch.no_grad():\n",
" centered, sized, colored = cat_net.module_.represent(\n",
" torch.from_numpy(test).unsqueeze(dim=0).cuda()\n",
" )\n",
" centered = (centered[0].cpu().numpy() * square).astype(np.int32)\n",
" sized = int(sized[0].cpu().numpy() * size / 2) * 2\n",
" colored = (colored[0].cpu().numpy()).astype(np.float32)\n",
" \n",
"centered, sized, colored"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8LaKfFXmFIGk",
"outputId": "f89c1621-9d7f-4fec-bf4c-017ad972bc19"
},
"execution_count": 9,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"(array([245, 301], dtype=int32), 56, array(0.50742877, dtype=float32))"
]
},
"metadata": {},
"execution_count": 9
}
]
},
{
"cell_type": "code",
"source": [
"figure, axes = plt.subplots(ncols=3, sharey=True, figsize=(18, 6))\n",
"\n",
"axes[0].set_title('test image true')\n",
"axes[0].imshow(test[0], cmap='gray')\n",
"axes[1].set_title('from representation')\n",
"axes[1].imshow(draw_cat(center=centered, size=sized, color=colored.tolist())[0], cmap='gray')\n",
"axes[2].set_title('autoencoded/decoded')\n",
"axes[2].imshow(cat_net.predict(np.expand_dims(test, axis=0))[0][0], cmap='gray')\n",
"\n",
"plt.tight_layout();"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 468
},
"id": "ghj2FTIUBy-A",
"outputId": "e1a1d145-380a-4af5-bb62-32e3d5e18b82"
},
"execution_count": 10,
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
"<Figure size 1296x432 with 3 Axes>"
],
"image/png": "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AAAAg9XT05N/+qd/ygknnJCk87vupJNOyj/+4z92uTIY+QSDtM5JJ52Uv/3bv82UKVP6XWbLLbfM29/+9uVYFQAAAMvimGOOyRe/+MUF7z/72c92sRpYMQgGaZ1aay6//PJ8+tOfzne/+91+x5048sgjs/322y/n6gAAAFgac+fOzfHHH5/jjz8+SbLuuuvmggsuyPjx47tcGYxcgkFa69lnn83BBx+c888/v8/5q622WnbaaaeMGTNmOVcGAADA0pg9e3amTp2axx57LKNGjcoHPvCBHHbYYd0uC0YswSCt95GPfKTfqwZPOOGEfOYzn1nOFQEAALC0Lrrootx4443dLgNWCIJBWu/555/PJz7xiX7nH3roocuxGgAAAJbVUUcdlZkzZyZJDjnkkLzuda/rckUwMgkGab2enp787ne/y4wZM/qc/8pXvjJnn332cq4KAACApfXAAw9k3rx5SZLNNtssa6yxRpcrgpFpicFgKeWVpZSrSym3l1JuK6V8opn+slLKVaWU/2z+XKuZXkopp5RS7iml/LGU8obhPghYVjfffHOOPfbYPueVUrLllltms802W85VAQAAsDS+973v5WUve1m3y4ARbyBXDM5NckSt9a+TbJ/kY6WUv07yuSS/qLW+NskvmvdJskeS1zZtUpIpQ141DINf/vKX+Y//+I8+5+24447Zfffdl3NFAAAAAMNniY9brbU+lOSh5vXTpZQ7kmyY5D1JdmkWOzfJr5J8tpn+vVprTXJdKWXNUsormu3AiHXzzTfn7rvvzlZbbdXn/NGjRy/nigAAAFYMW2yxRc4///xul7HA5ptv3u0SYIWwxGCwt1LKq5O8Psn1SdbrFfY9nGS95vWGSab3Wu3PzTTBICPevvvum/vvvz/rr7/+i+b9y7/8S6655ppMnTq1C5UBAACMTGPGjMmNN96YCRMmdLsUYJAG/PCRUsqEJJckObzW+lTvec3VgXUwOy6lTCql3FhK8QxxRow5c+bkhz/8YZ/zxowZk1GjPK8HVkb6JABGCn0SK6px48Z1u4TF2muvvTJmzKCujYJWKJ1MbwkLlTI2yRVJfl5r/UYz7a4ku9RaHyqlvCLJr2qtW5RSzmheX7jocovZ/qBCRRhOa6+9dh577LE+573xjW/MzTffvJwrAgbhplrrtsuyAX0SAENEn0RrjBkzJs8888yIDgdrrZkwYUKeffbZbpcC3dBvnzSQpxKXJGcnuWN+KNi4PMmBzesDk/y41/QPNk8n3j7JTOMLsiK54oor+p03fvz45VgJAADAiuG5557rdgnAUhjIfZH/M8kBSXYrpUxt2juTfC3J20sp/5nkfzXvk+TKJPcluSfJWUk+OvRlw/DZeOON+5139dVXj+izYAAAAMvb3Llzs/POO3e7DGApDOSpxL9JUvqZ/bY+lq9JPraMdUFX7L333osdMNcYgwAAAC82b968bpcALAUpB/Ry4IEHZrXVVut2GQAAACuU+++/P1OmTOl2GcAgCQZJ0nngxkEHHZSHHnooO+64Y9Zcc81ul7Tcrbrqqm4TBgAAWApPPfVUjjjiiFxyySXdLgUYBM/qbrnNN988m266af71X/91wYM1fvvb3+a+++7Lxz7WuSP8mmuuWeJAshtssEG23nrr9PT05KqrrspAnnY9FDbccMNstdVWQ7Kt9773vXnnO985JNsCAABom+eeey7XX3999thjj7zkJS/pdjkLue6669zuDH0QDLbcP/zDP+Rzn/vci6a/5jWvyU9/+tMkyamnnpqpU6fm7LPPTpJMmDAhn/3sZxdafuutt85ee+2VefPm5fDDD8+pp5465LWuvvrq+cxnPrPQtG222SZ77rnnkO8LAACAwZs8eXJmz56dk046qdulLOTTn/50XnjhhW6XASOOYJAlOuywwzJjxozsv//+SZJx48Zlxx137HPZ0aNH57jjjsuoUaNyyimnLPO+t91220yePDlJssoqq2SHHXZY5m0uq1L6exYPAAAA3/zmNzNv3rx885vf7HYpwBIIBhmQNddcM7vsssuAlp0wYUImT56c6dOn59JLLx3UfsaNG5f1118/SXLVVVdlo402GlGXoI8ZMyZXX311v8EoAABA2/X09GTKlCkLLhxZddVVu1rPjBkzXC0I/fDwEYbFuHHjsssuuwwq1Ntjjz1yxBFHZNq0aZk2bVo233zzERUKzjdhwoRulwAAADCizZs3LyeffHKuuuqqbpeSY489NjfddFO3y4ARyRWDDJuPf/zjGTt2bD760Y8uNH3rrbfOxIkTX7T8fvvtl7XWWmt5lQcAAMAwO/PMM7PrrrtmtdVW63YpQB8Egy33zW9+M7vvvnu22WabYdn+pEmTsv322y80bc0118wmm2wyLPsDANpl1KhROe2007Lddtv1u8z73ve+/OlPf0pPT096enqWY3UA/OQnP8nMmTMFgzBCCQZb7sEHH8ysWbOGbfujR4/O61//+mHbPgDQXhMmTMhXv/rVTJo0abEPB7v99ttTa833v//9fOITn8hTTz21HKsE4M1vfnMeeOCBbpcB9EEwCADACmmjjTbKuHHjcuaZZ/Y5f8stt8zOO++csWPHJkkOOuigvPDCC/nUpz6VZ599dnmWCtBq73nPe7pdAtAPwSAAACukO++8M4ceemi/8zfddNPssMMOGTt2bM4+++yUUnLIIYdk1VVXzYEHHrgcK2AHjZ4AAB45SURBVAVoty996Utd3f++++6byy67LPfcc09X64CRSDBInn/++W6XAAAw5O69997ce++9KaVkxowZueiiizJu3Ljsv//+KaXkQx/6UObMmdPtMgFWWmPHjs1pp52WddZZp6t1vOENb8jLX/5ywSD0YVS3C6D7dt9992EdZxAAoJtqrbn00kvzwQ9+MI8//nhGjRqVAw44IKeddlrWWGONbpcHsFJaffXVc9JJJ+XDH/5wRo8e3e1ygH4IBsm8efNyzjnndLsMAIBhdfHFF+eaa65Z8P7DH/5wJk+enFVWWaWLVQGsfMaOHZvjjjsuH/3oR7tdCrAEgkGSJCeeeGK3SwAAGHbHHXdcnnjiiQXvJ06cmLPOOquLFQGsfKZMmSIUhBWEYJAkybRp03LYYYd1uwwAgGF144035sEHH1xo2i677NKdYgBWMuPHj89ZZ52Vgw46qNulLGTWrFmZO3dut8uAEUkwSJLO7cS333577r///m6XAgAwrHbeeedulwCw0llttdUyefLkETmm4NFHH53f//733S4DRiTBIAtcffXVufLKK7tdBgAAACuQUaNGZfLkySPyLrQ77rgjv/71r7tdBoxYgkEW8vWvf90j3Bdj3rx5mTRpUrfLAACWQSml2yUArFRGjRqVgw46KLXWEdfuvvvuXH/99d3+iGDEGtPtAhhZ7rnnnmy77ba55ZZbsvHGG3e7nBGn1pqbb76522UAwArr1a9+dZ5++uk8/vjjXavh2muv7dq+AVZGc+fOzTrrrDMiT7wYWxAWTzDIi8ycOTM777xzLrnkkrzxjW/sdjkAwEpg2223zV/91V/lnHPOyVVXXZVzzz03P/7xj/Pss88uWGafffbJ+PHj84c//CF33nnnoLY/f92BWGeddQa1bQCWbNasWd0uAVgKgkH6NG3atBx00EHZaaed8pWvfCVrr712t0saEU444QRnnABgKUyaNCkTJ05MkrzjHe/IO97xjpx33nkL/ZA8+OCDs8oqq+Taa6/NBz7wgfzpT3/qd3urrrpqvv71r79oXQAABk4wSL9uvfXW3Hrrrbnhhhty7bXXZswY/7lccskl6enp6XYZALBSOOCAA/qcvsMOO2TDDTdcEAyOHj06o0Z1hsZ+//vfn0996lMZPXp0ttpqqyGpY/31188JJ5yQI488cki2BwCwopD0sEQ33nhjdtppp1x66aVZf/31u10OANACv/zlL/PWt741zz//fL7whS9k7733TtIZ4H706NFDuq+xY8dmk002GdJtAgCsCASDDMh1112XU045JV/96le7XUrX/OY3v8mjjz7a7TIAoBXGjRuX6667rttlAACs1EZ1uwBWHJdffnluueWWbpfRNRdffHGmT5/e7TIAAAAAhoRgkAG77bbbcu+996bW2u1SAIAVzOc///ncfffd3S4DAIBeBIMMynvf+948/vjj3S4DAFjBPPbYY7n++uudYAQAGEEEgwxKrTXf/va3u10GALACmjhxYubNm9ftMgAAaAgGGbSTTjqp2yUAACugOXPm5Igjjuh2GQAANASDDNqjjz6aD37wg90uY7k77rjjsvXWW3e7DABYYfX09OS0007L4Ycfnr/85S/p6enpdklJOnXNmDGj22UAACx3gkEGraenJ3fddVfuu+++bpeyXE2YMCFjxozpdhkAsEKbO3duTj755Ky//vr5/ve/3+1ykiQPPPBAJk6c2O0yAACWO8EgS+Wpp57KY4891u0yAIAV2GGHHdbtEgAAWk0wyFLZYostst122y33/dZaU2vNpEmTsv/++3uyIQCswGbNmpWPf/zj3S4DAKC13BfJoL385S/PRRddtFz29dxzz+Whhx5KkjzyyCN5+9vfniR59tlnkyQ//vGPc8wxx2TvvffOJptsslxqAgCGxrx583LDDTfkySefzFprrdXtcgAAWscVgwzaXnvtlfHjxw/7fubMmZOjjz46m266aTbddNPssMMOmTVrVmbNmpWenp709PRk1qxZ+dSnPpUtttgi3/ve93LTTTcNe10AwNC57rrrcuKJJ3a7DACAVhIMMmjHHXfcctnPM888k+OPP35Ay86ZMycHHnhgDj744HzkIx/JzJkzh7k6AGCoXHnllbn99tu7XQYAQOsIBhmU0047balu9Zk3b14OOeSQPProo5k7d+4wVNbxxz/+MZtvvnle+tKXDts+AIChU0rJdtttl1e96lWDXnf27NmZPXt2Jk6cmK222iqHH354Zs+ebQxiAIABEgwyYOutt1622mqrjB49elDrzZo1K4cffnjOOuusbLDBBtljjz0yderUBeMEDqV11103f/M3f5MxY4Zn+MzNN988pZRh2TYAtNHOO++cU089NRMmTBjUejNmzMiECRMyYcKEnH322bn11ltzyimnZMKECbnggguEgwAAAyAYZEA23HDDnHXWWXnLW94yqPVmz56dL3zhCzn11FNTa83cuXPz7//+73n961+fL3/5y0N69eB6662X008/PbvtttuQbXNR5513XsaOHTts2weANhk3blz22WefjBrV9z9JZ8yYkVNPPbXf24znzJmTOXPmLAgBa62ZM2dO/u3f/i3z5s0btroBAFYatdautyRVG7lt/Pjx9Re/+EUdrJNPPrnus88+i932e9/73jplypQ+13/yyScHVeeb3/zmQdc4WHPmzKnjxo3r+t+Jpmn9thurPknTVph2xhln9Nvn9vT0LPh3xLbbblsPOOCAOm/evAXz+/t3wgEHHFAff/zxQfXvzzzzTD388MO7/nloK13TJ2mapmkjpfXbJ3U9FNThjdw2duzYuvrqq9drr712UP+4njdvXj399NPrS17ykgHt56CDDupzO4MJBtdee+06ffr0Adf41FNP1e985zt14403rltuueVCPzQWRzCoaSO++RGmaStAGzduXD399NPr3Llz++xrv/jFL9aNN964llIWrFNKqe9+97sX+++EMWPG1G9+85sv2ubTTz9df/3rX9eNN964/vSnP+2zj//hD3/Y9c9FW+maPknTNE0bKa3fPml4BmJjhTdhwoR85StfyeGHHz6o9Wqt+c53vpNDDz10mCrr269//etstNFGS1zunnvuybRp0/LOd74zs2fPTpKsssoq+cMf/pA3vvGNw10mALTehAkTcuyxx+aQQw550bzZs2fnhBNOyDHHHPOiebXWPPTQQwve33DDDS9a5t3vfncOO+ywBe8ffvjh3HnnnTnooIMybdq0JMnvf//77Lbbbhk3btyC5V544YXcdttty3RcAAArpGU9izUULd1PTrVebdSoUfXkk0/u82z64vzkJz+pRx99dB01atSg9resVwzuueee9ZFHHllsbTNnzqzHHnts3XHHHfvcxvbbbz+gYzzrrLPq6NGju/53pGlav83VGZo2gtvo0aPrKaec0mcfe+GFF9bPfvazi11/2223rbXWeskll9Q11ljjRfP32WefWmvnNuTjjz++3yFNvvzlLy+07/vvv7/rn422UjZ9kqZpmjZSmluJtYG3KVOm1J6enn6isRd74IEH6u6771432mijpdrfhhtuWH/2s5+9aLv77rvvgNb/7ne/u9j6jjrqqLrLLrssdhtrrrlm/fa3v73EY33DG97Q9b8fTdMW2/wI07QR3M4444w+/43x/e9/v66zzjpLXH/bbbetl112WV1vvfX6nL/PPvvUM888s+6+++6LPVE5duzYetRRRy3Y/7ve9a6ufzbaStn0SZqmadpIaW4lZsnGjx+fyZMnZ+LEiSmlLHH5p59+OrNmzcqb3vSmPPjgg0u93wceeCDTp09f8P7ZZ5/Nhz/84Vx88cVLvc1HH300v/nNbzJp0qTMnDkzc+bMWezyM2bMyE033ZT9998/q6yySp/LPP300wtuPwYABmf11VfPW9/61gX/xpg5c2YeffTR7LjjjnnmmWfy7LPPLnEbU6dOzX777Zdnnnmmz/k/+clP8rOf/SzPPffcYrczZ86c/O53v8usWbMye/bs/PrXvx78AQEArAQEgyRJXvKSl+TYY49daFye/rzwwgv52c9+lnPOOSeXXXbZkNXQ09OTK664IpdffnkuvPDCpd7ODTfckN133z1PPPHEoNabMmVK1lxzzXzpS1/qMxz8/Oc/n1tvvXWp6wKANttvv/1y11135a677kqSTJ48Ob/97W8HtY25c+dm7ty5/c4fzAm8a665JpMmTcptt92Wp556alB1AACsNJb18vahaOn+JZWtb309wa8/n/nMZ4Z8/2eddVY97rjjFnr64EDb/FuJp02bVj/96U/XzTbbbJlqOeKII150zFOnTq3bbLNN1/+eNE1bYnPblqZpmjZSmj5J0zRNGynNrcT0rZSSKVOmZOLEiYtdrqenJ+edd15OP/303HjjjUNex9e+9rU8+OCD8/8BNCg9PT3Zd999c+uttw7JFX0nn3xyenp68vWv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\n"
},
"metadata": {
"needs_background": "light"
}
}
]
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment