diff --git a/ai-ml/gemini-multimodal/vertex_ai_practical_multimodal_use_cases_with_gemini.ipynb b/ai-ml/gemini-multimodal/vertex_ai_practical_multimodal_use_cases_with_gemini.ipynb new file mode 100644 index 0000000..d4dd50f --- /dev/null +++ b/ai-ml/gemini-multimodal/vertex_ai_practical_multimodal_use_cases_with_gemini.ipynb @@ -0,0 +1,1055 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "VEqbX8OhE8y9", + "tags": [] + }, + "source": [ + "# Practical multimodal use cases with Gemini on Vertex AI\n", + "\n", + "\n", + "\n", + " \n", + "
\n", + " \n", + " \"Google
Run in Colab\n", + "
\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "| | |\n", + "|-|-|\n", + "|Author(s) | [Eric Dong](https://github.com/gericdong)|" + ], + "metadata": { + "id": "8j-NqQ1IX06A" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "VK1Q5ZYdVL4Y" + }, + "source": [ + "## Overview\n", + "\n", + "What are the applications of multimodality with Gemini? This session will cover a variety of different multimodal use cases for text, images, and video, and provide some ideas on how to apply multimodality to practical business scenarios.\n", + "\n", + "\n", + "In this session, you will learn how to use the Python SDK to work with Gemini 1.5's native multimodality and long context window capabilities. You'll explore:\n", + "\n", + "- **Single modality**: Working with text, PDF, image, audio and video inputs individually.\n", + "- **Multimodality**: Combining different input types for more complex interactions.\n", + "- **Real-world use case**: A practical e-commerce example to demonstrate Gemini's capabilities.\n" + ] + }, + { + "cell_type": "markdown", + "source": [ + "![image.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAXoAAACSCAYAAABLwAHLAAAMP2lDQ1BJQ0MgUHJvZmlsZQAASImVVwdYU8kWnltSIbQAAlJCb4KIlABSQmgBpHcbIQkQSoyBoGJHFhVcCyoWsKGrIoqdZkfsLIq9LxYUlHWxYFfepICu+8r35vvmzn//OfOfM+fOvXMHAPUTXLE4B9UAIFeUL4kJ9mckJacwSN2ABIyBLqADMpeXJ2ZFRYUDWAbbv5d3NwAia686yLT+2f9fiyZfkMcDAImCOI2fx8uF+CAAeBVPLMkHgCjjzafmi2UYVqAtgQFCvFCGMxS4SobTFHiv3CYuhg1xKwBkVS5XkgGA2mXIMwp4GVBDrQ9iJxFfKAJAnQGxT27uZD7EqRDbQBsxxDJ9ZtoPOhl/00wb0uRyM4awYi7yQg4Q5olzuNP/z3T875KbIx30YQWraqYkJEY2Z5i3W9mTw2RYFeJeUVpEJMRaEH8Q8uX2EKPUTGlIvMIeNeTlsWHO4HMGqBOfGxAGsSHEQaKciHAln5YuDOJADFcIOk2Yz4mDWA/ihYK8wFilzSbJ5BilL7Q+XcJmKflzXIncr8zXA2l2PEup/zpTwFHqY2qFmXGJEFMhtigQJkRArAaxY152bJjSZkxhJjti0EYijZHFbwFxjEAU7K/QxwrSJUExSvvS3LzB+WKbMoWcCCXen58ZF6LID9bK48rjh3PBLgtErPhBHUFeUvjgXPiCgEDF3LFugSg+VqnzQZzvH6MYi1PFOVFKe9xMkBMs480gdskriFWOxRPy4YJU6OPp4vyoOEWceGEWNzRKEQ++DIQDNggADCCFNQ1MBllA2N7b0AvvFD1BgAskIAMIgIOSGRyRKO8RwWssKAR/QiQAeUPj/OW9AlAA+a9DrOLqANLlvQXyEdngKcS5IAzkwHupfJRoyFsCeAIZ4T+8c2HlwXhzYJX1/3t+kP3OsCATrmSkgx4Z6oOWxEBiADGEGES0xQ1wH9wLD4dXP1idcSbuMTiP7/aEp4QOwiPCdUIn4fYkYZHkpyjHgk6oH6TMRdqPucCtoKYr7o97Q3WojOviBsABd4F+WLgv9OwKWbYybllWGD9p/20GPzwNpR3FiYJShlH8KDY/j1SzU3MdUpHl+sf8KGJNG8o3e6jnZ//sH7LPh23Yz5bYQuwAdhY7iZ3HjmANgIEdxxqxNuyoDA+trify1TXoLUYeTzbUEf7D3+CTlWUyz6nWqcfpi6IvXzBN9o0G7Mni6RJhRmY+gwV3BAGDI+I5jmA4Ozm7ACDbXxSfrzfR8n0D0W37zs3/AwDv4wMDA4e/c6HHAdjnDl//pu+cDRNuHSoAnGviSSUFCg6XXQjwK6EO3zR9uH+ZAxs4H2fgBryAHwgEoSASxIFkMBFGnwnXuQRMBTPBPFACysAysAqsAxvBFrAD7Ab7QQM4Ak6CM+AiuAyug7tw9XSBF6APvAOfEQQhITSEjugjJoglYo84I0zEBwlEwpEYJBlJRTIQESJFZiLzkTKkHFmHbEZqkH1IE3ISOY90ILeRh0gP8hr5hGKoKqqNGqFW6EiUibLQMDQOnYBmoFPQQrQYXYKuQavRXWg9ehK9iF5HO9EXaD8GMBVMFzPFHDAmxsYisRQsHZNgs7FSrAKrxuqwZvicr2KdWC/2ESfidJyBO8AVHILH4zx8Cj4bX4yvw3fg9XgrfhV/iPfh3wg0giHBnuBJ4BCSCBmEqYQSQgVhG+EQ4TR8l7oI74hEoi7RmugO38VkYhZxBnExcT1xD/EEsYP4mNhPIpH0SfYkb1IkiUvKJ5WQ1pJ2kY6TrpC6SB/IKmQTsjM5iJxCFpGLyBXkneRj5CvkZ+TPFA2KJcWTEknhU6ZTllK2UpoplyhdlM9UTao11ZsaR82izqOuodZRT1PvUd+oqKiYqXioRKsIVeaqrFHZq3JO5aHKR1UtVTtVtup4VanqEtXtqidUb6u+odFoVjQ/Wgotn7aEVkM7RXtA+6BGV3NU46jx1eaoVarVq11Re6lOUbdUZ6lPVC9Ur1A/oH5JvVeDomGlwdbgaszWqNRo0rip0a9J1xylGamZq7lYc6fmec1uLZKWlVagFl+rWGuL1imtx3SMbk5n03n0+fSt9NP0Lm2itrU2RztLu0x7t3a7dp+Olo6LToLONJ1KnaM6nbqYrpUuRzdHd6nuft0bup+GGQ1jDRMMWzSsbtiVYe/1huv56Qn0SvX26F3X+6TP0A/Uz9Zfrt+gf98AN7AziDaYarDB4LRB73Dt4V7DecNLh+8ffscQNbQzjDGcYbjFsM2w38jYKNhIbLTW6JRRr7GusZ9xlvFK42PGPSZ0Ex8ToclKk+Mmzxk6DBYjh7GG0croMzU0DTGVmm42bTf9bGZtFm9WZLbH7L451Zxpnm6+0rzFvM/CxGKsxUyLWos7lhRLpmWm5WrLs5bvraytEq0WWDVYdVvrWXOsC61rre/Z0Gx8babYVNtcsyXaMm2zbdfbXrZD7VztMu0q7S7Zo/Zu9kL79fYdIwgjPEaIRlSPuOmg6sByKHCodXjoqOsY7ljk2OD4cqTFyJSRy0eeHfnNydUpx2mr091RWqNCRxWNah712tnOmedc6XxtNG100Og5oxtHv3KxdxG4bHC55Up3Heu6wLXF9aubu5vErc6tx93CPdW9yv0mU5sZxVzMPOdB8PD3mONxxOOjp5tnvud+z7+8HLyyvXZ6dY+xHiMYs3XMY28zb673Zu9OH4ZPqs8mn05fU1+ub7XvIz9zP77fNr9nLFtWFmsX66W/k7/E/5D/e7Ynexb7RAAWEBxQGtAeqBUYH7gu8EGQWVBGUG1QX7Br8IzgEyGEkLCQ5SE3OUYcHqeG0xfqHjortDVMNSw2bF3Yo3C7cEl481h0bOjYFWPvRVhGiCIaIkEkJ3JF5P0o66gpUYejidFR0ZXRT2NGxcyMORtLj50UuzP2XZx/3NK4u/E28dL4lgT1hPEJNQnvEwMSyxM7k0YmzUq6mGyQLExuTCGlJKRsS+kfFzhu1biu8a7jS8bfmGA9YdqE8xMNJuZMPDpJfRJ30oFUQmpi6s7UL9xIbjW3P42TVpXWx2PzVvNe8P34K/k9Am9BueBZund6eXp3hnfGioyeTN/MisxeIVu4TvgqKyRrY9b77Mjs7dkDOYk5e3LJuam5TSItUbaodbLx5GmTO8T24hJx5xTPKaum9EnCJNvykLwJeY352vBHvk1qI/1F+rDAp6Cy4MPUhKkHpmlOE01rm243fdH0Z4VBhb/NwGfwZrTMNJ05b+bDWaxZm2cjs9Nmt8wxn1M8p2tu8Nwd86jzsuf9XuRUVF70dn7i/OZio+K5xY9/Cf6ltkStRFJyc4HXgo0L8YXChe2LRi9au+hbKb/0QplTWUXZl8W8xRd+HfXrml8HlqQvaV/qtnTDMuIy0bIby32X7yjXLC8sf7xi7Ir6lYyVpSvfrpq06nyFS8XG1dTV0tWda8LXNK61WLts7Zd1meuuV/pX7qkyrFpU9X49f/2VDX4b6jYabSzb+GmTcNOtzcGb66utqiu2ELcUbHm6NWHr2d+Yv9VsM9hWtu3rdtH2zh0xO1pr3GtqdhruXFqL1kpre3aN33V5d8DuxjqHus17dPeU7QV7pXuf70vdd2N/2P6WA8wDdQctD1Ydoh8qrUfqp9f3NWQ2dDYmN3Y0hTa1NHs1HzrseHj7EdMjlUd1ji49Rj1WfGzgeOHx/hPiE70nM04+bpnUcvdU0qlrrdGt7afDTp87E3Tm1FnW2ePnvM8dOe95vukC80LDRbeL9W2ubYd+d/39ULtbe/0l90uNlz0uN3eM6Th2xffKyasBV89c41y7eD3ieseN+Bu3bo6/2XmLf6v7ds7tV3cK7ny+O/ce4V7pfY37FQ8MH1T/YfvHnk63zqMPAx62PYp9dPcx7/GLJ3lPvnQVP6U9rXhm8qym27n7SE9Qz+Xn4553vRC/+Nxb8qfmn1UvbV4e/Mvvr7a+pL6uV5JXA68Xv9F/s/2ty9uW/qj+B+9y331+X/pB/8OOj8yPZz8lfnr2eeoX0pc1X22/Nn8L+3ZvIHdgQMyVcOW/AhisaHo6AK+3A0BLBoAOz2fUcYrzn7wgijOrHIH/hBVnRHlxA6AO/r9H98K/m5sA7N0Kj19QX308AFE0AOI8ADp69FAdPKvJz5WyQoTngE1RX9Ny08C/KYoz5w9x/9wCmaoL+Ln9F80XfGLl8L3QAAAAimVYSWZNTQAqAAAACAAEARoABQAAAAEAAAA+ARsABQAAAAEAAABGASgAAwAAAAEAAgAAh2kABAAAAAEAAABOAAAAAAAAAJAAAAABAAAAkAAAAAEAA5KGAAcAAAASAAAAeKACAAQAAAABAAABeqADAAQAAAABAAAAkgAAAABBU0NJSQAAAFNjcmVlbnNob3QV8DiGAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB1mlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4xNDY8L2V4aWY6UGl4ZWxZRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+Mzc4PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6VXNlckNvbW1lbnQ+U2NyZWVuc2hvdDwvZXhpZjpVc2VyQ29tbWVudD4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+Clj+ZKwAAAAcaURPVAAAAAIAAAAAAAAASQAAACgAAABJAAAASQAAHfkbIv/8AAAdxUlEQVR4AexdCYBOVfv/jdk3M5ixhZCUvjCfJcRHQiUVsrShVSVlyy5rsiVFkkl76hOpiO+fskSLSkiWrIlmmLGbMRuz/J/nnHvu+46hzGuYd3kOc+/Z7jnP+Z17fud5n3vvOX4A8uhPnCAgCAgCgoCXIuBH7RKi99LOlWYJAoKAIMAICNHLfSAIeDkCAf7+yM3NRW6e6HRe3tXnbZ4Q/XmhkQRBwDsQiI6KREZGJrJOn/GOBkkrCo2AEH2hIZMLBAHPQqDmVVWRfPgoTqakepbgIm2RISBEX2RQSkGCgHsi0LbVf7Bx8+9IOnTEPQUUqS45AkL0lxxiqUAQKF4ERg58Ch8u+AJ/7PureAWR2osNASH6YoNeKhYELg8CX3wUj+nx72H56h8uT4VSi9shIETvdl0iAgkCRYdASHAQtq39EvM+W4rhz79UdAVLSR6FgBC9R3WXCCsIFA6BezregZcnjEBS8mE0anM3zpzJLlwBktsrEBCi94pulEYIAgUR8PPzw/JFc1Hr6uoq8d5H+2HNDz8VzCgxXo+AEL3Xd7E00FcRqB9XGwvefQ3BQYEEgR/mf74Ug0ZNRHa2aPW+dk8I0ftaj0t7fQIB1uaH9u+FXo/2AHnVJ/D7Ew7ggZ59sVfevvGJe8C5kUL0zmiIXxDwEgRKRUfh84/eQrWqlRXJc7N4GYSJL83E7Hc+9JJWSjMuFAEh+gtFSvIJAh6EwJB+vfHkY91Jm/eziZ7FP378BNp0uA+HjxzzoNaIqBeLgBD9xSIo1wsCboZAnetrkTb/NvxKEMmz3YacPmpBFy39CoOee57WvjmtI+To9QgI0Xt9F0sDfQmBiPBwTJs0Fq1v+k8+cjcBHvBp6ekYMHQMlq1c7UvQ+HRbheh9uvul8d6EAGvv93Rqj+efG4YSpM2z8+PtJpT5xlqiWEdj1+696NLjcVroLMWbIJC2nAcBIfrzACPRgoAnIcAkf0urlpg4bhQiI8KV6IrkyWdxu/L4Gb6nyDU//IgBw8bg6DGx13tSX7siqxC9K6jJNYKAmyFQ69prEP/qNJQrW1ZJph/B5qlXK7VSzwyvhzsflY82Ipk7fyHGTXoJOTk5btYiEacoERCiL0o0pSxB4DIjwJp8ndrXY9zIEah5dQ2qXavsHM+Dm8P6rAI28XMka/z88dT7/52PGbPm4FRams4kR69DQIje67pUGuRLCNSvVw8vTZqAsrExWk2nxhtiJ643vK8JXgHjIH6eDDhDHmn2i5b+H0aOm4jMzEyVSw7ehYDTreBdDZPWCALejEBoaCjatG6F/n2eQWxMGdVUQ/AcYA7PF3YCQ/E753GKy8vLxfJVq0mzj8fO3XsU+Tsli9fDEeC+th7PeHhLRHxBwEcQiIyMxNDBg3FrmzYIVOvYaNI2GryfeuLKphttl+ez1t4LAqQnBMpH/zlPQmIiXprxGpZ+uaxgZonxWASE6D2260RwX0OgZMmSaNq0Kfr37Y9YMtU4NHKtq2m7vOW3wNGkzxOBRfxmxBOpO663tHsTwaacL5bi3bkfkXa/Wx7UesGNZrrdC5oiTRAEvBOBsLAwtGlzKzp06IiaNWsiJChIMbPiZTo4vzKpEbDs8JxmQcJno/FzlPLzWQXoQOSeT+uncPLhw/h53S946933FeGzLV+cZyLA/Sy955l9J1J7KQL+/v4IIRt82dhyqFe/Abp1fxAVK1YkUj5bWzdE7vSA1cLEJnIzwumsrmdN3iJszsPJ+uhUho60SoJ6M2flqm8w/9PP6EOrPUihj6xO0/IJuUL8Nkbu7uEuFaJ3914S+bwWAf+AAISFhiEqKhqVq1RBjatrosqV1VChQkXUqHE12FzD5hcHIVuETYhoUw1D45gAbILndE5iRx4zSVhBHW1lMPnUWeVVyTqP5WUZ+F37vxIS8cfevUg8cAA7du3Czp27SfM/hNSUVGRmZclDXAd0buXjvhWid6suEWF8CQGlvYeEIrpUKVxz7XWo36Ah6tSth/LlKyKY9nv19y+h4OCB6iBix5BVcZzGmroT4fNFDo3dutaKcx7ypky+1ORXJhzS1s2kocqiA5tumOxTUlOxl8h+zXffY/3Gjdi3f796B5+1fDHvMFru57ifHXeN+8knEgkCPodACTLdsEZfN64eateNQ5MmzVCmTAxKGCYmRJjUNUmbh6p6GOuQTjM2dz0ZOIhbhzX5O5M5UwFfr+NMeaB9Zs9gJ2nvK79Zha1bt2HTb7/Jx1UedlcK0XtYh4m4voUAa/wREZHo3PV+3PNAD4SS9m9r7hZj80l7mcytSDMRcJoV58jHcYxjHkqo0gzBM7lzAofpSBo8E/ykKZOxddtWZZcXjZ2A8UCne9UDBReRBQFfQyC2bDl07nI/br39TpQuXVqTOzE2D2L1GiXxtCZ1JmpN2o7XKw1afvTLQPvViQ5W0D7n5GTjt982Yd7H/8WKFSvpoWuuuVjOHooA97H+jeahDRCxBQFfQoA1/PJk1uk3cDgaNmxCm4uwTq6dMueYAEWxt6D2T7Hqvx72KjuH1STBa9WnYcb0l/H18q/U2zVW0XLycAS4n4XoPbwTRXzfQyCU3tR5uGdvtG3XHpH0Zg6PYk30mrXz2eoteNhcwwPeOK3t65y8n+zuXTswY8bL+OWXn+WhqgHJS85C9F7SkdIM30OAzTQ3tboVfZ8dgaiSUTaL86BWhE4H208zgSOOyd3S6FUkrU2/ZhWmTZ2E5OQk3wPSB1rM3SwavQ90tDTRexGoV78Rho2epN7MMcNZP2xlotdDXGvzlp+gUOn0sDU3Nwcb1v+MYUMGICMj3XtB8vGWCdH7+A0gzfcOBBo2boaBw8YpslcPZNV78Dy8tdNEb2nxiv7Zn4eVK5ZhysSxSCfbvDjvRUCI3nv7VlrmYwi0vaMT+gwcCf8A5we0rL1rvV4bcgzZAwcS9+Opx7vh5InjPoaU7zVXiN73+lxa7KUIMKE/+Ngz6PLAIwgo4a94nQe40eu1Vq8bf/BAAoYPegr79+31UjSkWc4ICNE7oyF+QcDDEYiILIlRL0xH7biG1BJLe6dRbpM9xWZnn8HUCSOx8uulHt5aEf9CERCiv1CkJJ8g4CEI1LuhKcZMmkXr5PjbH0ex6Ibs1/34LSaOHYh02SPWQ3r04sX0OqJXH5Dwb1RSZviNAnGCgK8hUII+our97Bjc0q4TNZ1eq2QbPT2cZabPpoXHenZvh0NJB30NFp9ur8cQvb9/AELDIhFTrjLKxFaij0RKIzIqBqXJX7Z8VXUODS+JgMAQlCD7JH+2nZWVSQsyZeLEsUN0Y+/FsUMJOH4kkTSZFIpLwtHkfUg9eQTZZ3jVPfnM26dHgpc1vmRUKbwy51OUiSmrX6Xk9hHZz58bj7lvv3rRreXxGBwSjPDwCFKo8pB2KoXGmyxTXFhgeVIOpo1keHtI9qeeOoWszCxk0zIURencmuj9iLBjidhvvKkT4hq2JnIvg6hSZRFB54CAIGWBZEWFLZF85juaF11SYY6z4lWaCZNak0OafnpaKk4eT0b6qRM4+NcOrF3xIfbt+AUZ6aesnHQSJwh4KAJMGo/2HobbO9xPLSCNnkb60cNJGDf0Cezbu8vlVvGvg7j6jWmRte70KmcsQkND1JjLSE9HYsJ+vPnGdCQnHVBxLlfiAxcyjpWuqISeDz+KWtfWQlhYuDKzpWdk4MiRw4h/+01aJXRTkW3j6HZEHxwchvJXVMe1/2qMO7v2RcXKNR3dbhE5R+Tl6W/7cpnO9X+VzyZ+zsO/VQ3xW3mY/Fl3V/k4QI53yuFw1ukMbPx+EX5eOQ8H920lrf8gcot4ZtU1ylEQuPQI1K7XGM+9EI/AwEBV2Y/ffY1p4weqh7Gu1B5DO149+fQQtLj5Npo4rC9teRLhwujA57S0U5g1YzJW0INe/kUtriAC3B/3dO6KAX0GIJy2ibRoyM7IOHLckv8twaSpk3Hk6BE7zVWPKdPV64vsuuCQMNLc70azlp1xzfWNaWnWUlS2+VBbQ2EAUSRNqfrs0OKNMHwL2po9XWSuy7XinYle5eMJRJWnfw3k5uQiOXEX9u3eiLVfvYfdm78VwjfgytljEAgKDsbkWZ+iUpVqdOf74cWxT+On71a4JH8omWjG0gPe2rXrk4mBS2Nm12TPJEJDyOHIDPrJ/Pfx9hszhOwdqChfEJlphg0ahi53dyarhJ6Az8piB5mbNvy6gRaw64fDpOVfjCtWouefL6GhEahTvyV69pmm7O/MuIaYuWH6VtIxedbdlEc2QRVDWr3Zt5LTGBh9jZkETFk6zRC8OVvZScPXGj1frScPPus6OC4pYRc+euUJJOz5FWeyMlQdchAEPAGBdp0fQo/HByMzIw0PdbjBHiOFkT2ANNDxL85BnX83psv0GFOboFijk4elM9mzn5c6Hj9mINasWlaYqrw+b5e7u2L0iFFE8gEX3NbV365Gn2f7qGcgF3zRWRmLjej9aTZr0eZe3HbXY7jmX42UhmA08Xwy5iNwLa4229ANx0Rv3XhmQrCJmgoxfi6P/TbBm7C+Z1U857EnDTuvg+zP0LvH29cvx7qVH2Hz2sXIyT7Nl4gTBNwagUh6KDvzg1VYu/p/mP3ScJdkbXZTWwwaORW885UidKsUQ/AcNH7n84HEv/DEwx3ouZcsr8AYBRLnLZz3Ka6mvYDzOUVrfLCcpjk9exJxpdFrsH0H9sEPP/7g0kTNpZoiTRWX5RxbrgrGvLgIlavW0neIEYO5m/zOmnl+gdjE4tC+WXzmaouv1XWK8AkcY6ax0ygf/RDQ+WmCcC5HE7yuV5enfyk459ETBeWhQn7fsBxzp3RDRtrJ/OJJSBBwQwSen7EQi+fHY913XxVaOn67pveg8bi5TXt1LZtt2GlCJwOOYhAadXTmX+h6BPPIhHq4OHn8YCxftpgv8XnXvFkLxM98Q4PDREMgMa8wVraf4zhopXOAvQs/+wTjJoxR2zpy9sI6roPLuSwuPCIKbdo9jA739qXXviqqOp0r50azs8/k55vHEL9Ks9J1Vmdy5lRujBVHGYw5R5E/pSii53iVT9ej/CqOaZ2v5XQrL/tU2LrG9vvh+OEErFjwIn766h3k0OuZ4gQBd0Wge6/nsPyLD3EwYW+hRQymrQvHTX0fV19bW11r1rC3d6kiBlEkT2OHyURxvXXm8KqvF2Py84PUtb5+GDvqebLN3/O3MJAOqkmeczGAxDnsdu/Zha4PdEJmpmsPuJ2K0gVeqmNkVGkMGvUB4hq0ol1xuFrtrHZQoCChq0ZSVjbVaPo1Z45zXG/InWM0qVtv0jiVydm1Rk/1cD4qQJ91WRzSYU43k4IVp8rlsk1efeZNk/ds+RYfTumO9NRjlCpOEHA/BBo1b4ed29bTNySFX2s+NCwCU+MXo2y5K0hD5xHAZK7HoSZ4Dus/TmPbPaey43zbNq/HwKfv0xE+fnxz9jto0rgpI/MPSDDO+fPw20w3tWlKq4y6tpQ0l6Z77x+qdjWZ7Xq1/90CfYfG081SRVXmXKldOXnUw1aLgJ3r06SuCZgB4GuMlq/8Kqyv4LwOTZ7jKD+XSfHKRs95+Y/zKb/1QJfzOMVr049+AqDzOuo1zwiMzf+PLd9h0RsDcPDPLbpgKkecIOAuCFxx5dU4cfQQfdRUeFMjE/3k1xehbIVKtJG4g34MufNYZj87FXfW+beNP2N4/+4q3dcPs197C82aNtfEQ5jZPMjEQ05ZLxQL2Sk6D6WnpJxE69uaI93FPQMcJeq6ivTIgt98Wzf6cGMySkaV0S2ziNdUZLVREa+OY5EYC0rhRAoy0bJHU7FF3BxPKjp/QXb6dCbSUk8gNeU4PfhJVbbzgKAQhISVRHhkaYTTV7RBwaH0MIk+siKZDFEr7Z8K54US7InDqtZh43dMEiwFy8IEz45/IZjzCTLlLJjxJHb/6trra7okOQoCRY8AP5DNJII4czqr0IUH07gZPvk9Mt3E2YTOhM9O/TCnccgjVv2xnz3k1KRAhy+/mIdZ00bpSB8/DhwwFA91f0zRmg0FY0YB5hWFncUp1snOtnXbZjz0yH3IdPHbBFWHXVoReoJDwnFHpyfxcK+JqhUsuP7J50SqHEd/hnAdjbNIXV2kheLPrNPp4efBA3tx/Ggydm9fh3Xff4F9ezbTJ9iGenXecx1L0EOlGPpFEdeoLa6p2wJRZSoipnw1NQmQLUmBz2Ar7Z8QV2YejqAU5Vc+Ttfy8qSTyw91KYJzcZ6TRxIwd9J9SNi53spNJ3GCQDEj4E+v8vG3Ia4s88EPYx96eixa3tZFEZExzJgPpjhs+5m0aOzw6GXH5/EjHsf6n1YXMwLuUf11ta7Hhx8sRABZOWz3twzsSHzrnXjMnPUyfezm2tIIjpLsmi/ew53d/fFx6NC1D4JIs2anu17fCEZ71jWxCEygmjCV36J/9udQw/bs3IAvF83BwcQ92P/HFrWuhqNEzlV4xxNRxarX0RILVdG07cOoWacFafwBJKeDuLlUlounEU3w+qzCdpxl+rHCJ2kNnQUvP4I9m1ZRjDhBwPMRqNekNZ4Z/iqthhmgRqYhc6WBUvPMIzceyRxnzjt/34hRAx5w+Utcz0cufwt4NdE5sz9AgwaN8iecN8RI5uHYsaN4pm9PbN6y6bw5/ylBl/RPuQqRHhgUjAceHYMu9w+wyZ0vN0SvbwNNplw5hx0UbwjVT2nv+/duw+xpT+PP3ZtVzkt54AXSuvefjerX3YjQSPoqV93FTOKWnZ4qN2RvNHyWnV/N1No/S+eHU7RI2rvj2iNxF2v14gQB70Cgz8jXEXfDzUT2jt2rNMH7WURPv8tpQGsNH2Q+TcGEEY/SQ+CN3gFAEbWiZYvWmDTxFfpQNNQqUbOgDjBLOoeZc2ghugVzMWHSGOV3VQwu1cHBrpbidN29Dw3HfQ8Oo+3MgnQs9z4Jm78SXW2+OKuNvD7GV0vewfcrF2D7lrUXZJZxqv6ivKypXFGtNuKadkDT2x9DSVpATZO6lp9FZLLXcboN7DdEn0Tr4yx4pScO7JGb+6I6Qi52OwRYm+/+1Fg0a9MZ/rRgmiZ1oiXyGD8LzeR/hl43fnfmKKxZ/rn6QtbtGlOMAvFic+3v6ozBtOUjL2TG+BkLB/u1I75hXiGT9MKF/8W06ZMuek9fzVZF1PDmrbtiyOgPuPdViUyM7ExDdIiPulqVzgfV2FwcO3IQ44feTaaa4idKNu08MfYz1KjdTN29DLx5iKuJXreGH9ry84PTWemYPaQVkfyvOkGOgoCXIcBE1P7+fmjb5XH1lSc3j4c6j2Y15GmQnDx2GJNHPIjE/a6vkOllsJ2zOXFxDTB1ymuIjYll9Bx5NDUqW/yct2bijTmvFomyaxXrqMcVH98AjZrdiREvfKzWgufpyJC8ugOcw1YFdjqFeS3rZYvfxLx3X6C3A3iZYPdw/Kuk/k1d0a7HaETFVFJC5bfPa/I/QK9VLni5JxJFk3ePjhMpLikCZStURYNmtyEqOhZhEZE03HORlnKClkFOxA8rF6n9Hi6pAF5SOJtv2rXriMqVrkR0dGn6NUSmX3pf/jAtJ73sqyVITEwospYWCdFHly6HafHf0gYgVzoE4ymeCF5r6860zlm4Wkqmf/za1+hnbydb3jo3/Znnh8joGDzy3HxUo6WTWZvnPy0/vd9Ka9q/PaYjEmmlS3GCgC8h4Edvq7Epgh3v5lbwl7svoeF6W1lR5ge17NhccyFvERa2tosm+gh6cPnchPm4Pq65qrtAgdSIs28AQ/tM7tPGP4wDf7n/z7woWrKhS+/pqHVDO5qe9ESVTBuWzJv2GP7a+UthcZf8goAgIAhcNgQK8HJhaubZ/JGnJqMjrV1jyFxTIGvr+k+FzyJ7Ttv22/eYMvoBZZcvTJ3FmTeYllS+u9fLaNCqG44k/YkPJnVDgrxdU5xdInULAoLABSBwUURfq3YTjJz4ibLVMdE7k7xz3Uzs+jMKbbtf/+OXiuT1tn3OOd3fH1mqHDo+OQ2rP51OWw/+7P4Ci4SCgCDg8wi4TPT8cdHU11ejZq0GZIbX5hk+s13erFnD6BozjUF6L33JOnZQe/XgxsR52pnX0s+h9enFCQKCgCDgCQi4RPRM6B3v7U9mG1regJwiePYwyesIPtrmHBWgQ+Jfu9G7R5yQpAFEzoKAICAIXAYEXCL6CrR597hpS1GhYnUlojPRc8S5NHo200wY0RW//iKLfl2GfpUqBAFBQBCwEXCJ6Dvc0wc9n5mqNHab5LlIZ43e+FV0Ht5/4zl8MneqXbF4BAFBQBAQBC4PAoUm+rDwkpj53nq1tryziFzQud6ZZ1PO2tWfY+LIewuYcpyvF78gIAgIAoLApUGg0ER/93391fry5nVKI5Yhelur5wSy5R87moRxQzrQssIbTFY5CwKCgCAgCFxGBApF9CVphcfpb62lpX2r5BPRJnmKdZ4AWJtfvOBVvPnqYIrnxQPEFScCJWhJh+hy1RFd4SoEh0XRssz+8KdlpAODw+DnH0gbueQg+3QGsrMyaP3ybHponoV0+vL3aMLvyEg5UpyiF33dpISElSyLmCq1ERJOn58TNkEhEfAPDKZ2nyYM0mgv4Cxkn6FNbY4fwJGEbSqu6AUpWGJwWDRiKtVCeHR56qNABNCKsIHB4bRQYCD1Sw7O0LpKOSRXXm42Mk4dx9HE7Th1Ikn1X8HSfDsmunQsql91HUqXiUUA9XEILTsQFhpGoPghKzMdWXSvZ9MbdLwtaHJSAv7cuwOnUlO8DrRCEX2T5u0xaPT74F1n1HvzNFgMsStbvZNdnpE6fiwZT9x/vax9Ucy3zRW1mqJhx4GIKFMJIRGlEBweRaQRrH5x0dRcQDrqRvW8JZeIhEk/nUieiW//ppXYsGQGkf7hAtd4SoRfCX9Uq3cH6rTuRQRfCiGRRACBtGcC3cvKUeMtnwoyBmcyTyEj9QjSTxzAusVTcGgfLXehQCq6VpcguaqTXHGtn0BgSCStIVOGzmF67SjVR7xKpF4K2FRNo48moiwi+6PISj+JfVu+wfovZ+I0yevLjhWY5je3R4cuPREZGYXoUjFqWeAStLQm9y13tTrbflpqnJYeSKcXRlJOHqO/41iy+CP8j3bH8hbH7S040s/TuqcGzMDtHZ84Z+rZBfHaF/HTn8XST18/Z36JvHQI8DcOsdXqokqdVmhwVz8EhkXSjW16yDE569tdsToJ4xzPsun89kTO6fyPFvo5/OcmIvzpOLRnA1IP77Mn+6JsUVBoJOrfNZjILsIulgmOB6khOpNwnDTabd+8Tdru+b9tiIypgitqtUD9O4fSZFdatY6vVzc/FcitdXaOunQa5+M8vFLp8aQdWL94EpL3rkNW2gnnywrtjy5XA1Xr3oa4W56mXxS0bK2qRRO66QMuNJ98FOCwnptUC+x6GYPtP36C7WsX0IS0qUhfZf53y26oWL2uLYuSScniIFAj65afl2DXpm9suc7liaDtRVve9Tgi6WzaY5MweThObUlInoQ/t2PZ53POVYwdV7HyVWjY5Bbc26OftQSwxoiXTnaUz+UyvtaZrnbUyQGdlwtlbX/hx2/h29VfYscO2smOfk0Vhavf4Ea0vb3zBRW1Y/tmLJj/zgXl/btM3P78d8rf5H7z4+0oX7FagRxGm2fEDDHwblAjB7RDEm39J+7yIRBdoQZuvG8UKtduqTRWrtnuYGIv9ushZH3zoESj28BmT53bDqoCOK+5VXReNsWdTP4Df/yyBD/NH/+3JKuqKOQhLKocOo3+hjTuGHWlua/UMFQi0sFqT+LWlVge/4gyO51dTUBQqCL3Ste3QcnYqmqA6wJ1To2HdZVuulMR+SOMDIwEm7aOJmzGhqUvInH7aqdrLszLprP67QahMskVWaoiNUv3iu6d/PVyiazNa6f7gY9MUBxr+pPTOY5d9uk07F6/BGs+HnlOXHSuwh3b95pFaz3doTcaoXq4Kr35CNerpeD6Of7reS/guyWz/7aCmPJV0Wvkh7SlZxUlN5dlSJlXcuSydJwftqxfhWmju52zvPCIKHTp1h83NLuVXhKhTcydrlVycTl0Ja3BZmNlyuYCTZ3Gz2d2nIfdKdqPeuXXizD7tQlK69exrh87dX4Qg4fQN0hcvu7Ac58peTVNMoMHPuJ6ZdaV/w8AAP//k2qB/AAAQABJREFU7V0HgBW18x5671U6KqJIkyIq1YYdRFCxISJ2FEQRBUUBG3bFjmKHn2JBEUSkV0GlSRMERATpIL3f//tmkn377jjuHcI75P8Ct0kmyWQym3w7bza7m0lEkvCXZjjplDrywtuTJFOmTJKUFGnCPAjaPkIVGT1igLz05C2yf9/eNHknKvx7DeTIU1BqXnS71Luym2TKnNmfkghjnBx/lnDGgpPuTyVpFpJStLU6obMb8OKpT5JdWzbKqLdulz9nj5Sk/fs8o38V5y5QQq7oMVZy5i8aCBuedxyAl+ivuaNl9Fs3yd7dO4I+M2XKLPmKV5TGN74uRcvXiFR2NTDKKFomsXlNnkjhz7RkeauqFO00Qt2/b4/MGPa8zBv7tuzbuyvoP7VEpsxZpEDxE6TJja9JkdKnqP50DYUa+POTOURjkkstEiCjElQgJWsxDlYNI8iUJDu3/yNDXrlW1i2fg772R5ofQqrZ7a/LKfUutb5c35QhCynoNLN1rHKOHPiETBr65kF7KVqygtz2yCdStEQ5bUuW5JcZcmfmGXA8Gc/9Zay89Nj1UfyyZMkqpctVks493pGSpSoIpr2OWduiJvMMmcGAulB+ytd05vtiHYru+7O8tWGJzgdU2Lx5k9zX8VpZ9Nsc2f8v5nnLVm2lS9cntU/2lTxEzqjIuLHDpWuXdsmrpDvP8YX5psrgnq5vSNNLU+8wOaOeXVvIT5OHpcovUXD4NFCmSkM54+qH5biTz8Rk5WwH7yQ7I8HJRcJTSNO0K7SpjIzLKwhSPJdnbQNZEnyaFSywbO+u7fL71MEybVAv2b5plS865DgXgL7FI+MkV74i4OEkD+QBCWkD60yyYt4oGfX2TbLPAX1mAMBJ9W+QWs26Sbac+SG7Sh0ti9OPJ0YuItYXjwzapV3pIAWXPC8C0YGLftnMIfLT4B6yY/O66MJQjufmpLOulzqUK0deLUnOi0QCTjgwSzmUjEO4WOu6wjCd7T2fbZv+lkmDHpGls4aTfMjhUgD9yXUvU77UhYInuBEwPRhSBvY76n9PyORhBwf6IgD6W7sD6EuW1zbEZQVrxuDhgZj85k0fKy8nA/pLrrxTLr+mo+TJnVd1Ym2dXGhjFws9g+BLGaP5I6v9ks4+9I9pl0ekcjBmIH3DhjXy1mtPyPBhg5R2KIcrAPQPAOgPGigM5l1cgZ5Xzv8NXSW58uRLVTYqwVQqsn3bZrn6ouIOHFJtkij4txrAZKh0Rgs5/843ARx5Av0HQK383ZnxwK8nyZ8pL4CBN2sy7A8BG/MeBNlKublyK+MRwdHWLJ0p3790jWzb+LfRD/FIoL/84bGSK38xnVgG6jbHFFa0P1Ah1Mp5Y2R0v7YK9JkzZ5VTz+sgp136oK1c3z/qmfwh7ZCA4OeujY0Uq2kx8z44JshaDdOYtU+SP2cNlYmf3C379uz0DYKYcp3cqJ3UbtZDAcxamgC+N6VZgbYLJQM+XP+RYBcdAmLyQKD0fFlGa374G21k+YJxzCSvHlP+kttel8p1m0FftI4NOLVr9EUJmGbMvkd/+rhMSQvoS1SQ9t0HSJGS5bUNLXnfnvyzkB/+yG/e9DHySk+z6LNmzSZtOvSRxk2vRpnOBq2jMrGNk0Xbe7lI5y8F1tc2lmdr9qF/rOvruzGK+3UBcigkSZ8nOsv3wz6DZZ/+X0kE+i5dn3L8OGYKgGz4tLj82LHfyYPxsugrnlhDXnn3R3UJUEl+4fuRUyYGL+fgz16Rd/p2MWLieEQ0kDlLNoDZ3VKvZVdYrXkD3fvFHcAZCP68UBC/xu2cuVpBBZtdVscRfRTUIT9kfB6VmVR+Sk6SjSsWyvj3O8mqhVMOeewG9OMkZz5z3Wh3ri/tLdTvX7Dox/a7SQdXrWknqXbBvU4iL2Rk3IHcLsGxcpFrUPndWDwJFXyxI7mqns5Sa0hNLJrykfz0ZfcoF1aWrNnl1HPvlupN71WQ0a6TMU2WVZ4mF2EgMg4FBeR53WYb3441NI8D5WA9Py5fZ8uG5TLi7XayYeV81E5/uPjWN+SkOmbRszUBmJ0yYpoxDwTT0Z/2lqnfpWHRA+jbAeiLliivsnoejDVNnvgjYM+FRf9ar+skW7YcctXNPeQceBeiLwzWJnDTUBTy8bI5XuTL4C18ZllP/3yaFUBjW9IZXBTkN2/eKE/1ukemTBppFdJx9EAfNfdSaT8unkDf+PzWcv8j72OQnDwHBvrIVBS595b6smjBz6mIniD/Ww3QBVDvyoekbssHcT44HS2EzwEvxpyc0TRf08cotf+OgBZoxzbaljMxCHbeA56uTGsw7aoyYt9b1v4p3z3fUv5Z9XvAIT0JAn2zhwH0eQn01qv1ZVwioiXBoh8NoG8rZapdIPVveF3ouokaV6ihT3IBkwc5M5jxEunHA6qVagWnl6AFiJG0paA7MP3pq+6yaNL7KLdQsVZLOeOalwAu6s32ZLQ2XZPA9sqDB8ilciJJ4PK1rNxA3GpYZZXVtaPV6gPHmDysXjxZhr5yVXJyTPmLbnlTKgHoKShZezBmY00z4crGftZbpg0/ONAXBtC3fWig+uizuGnM8RrfJAC8DSBz5iSZD6B/vfd1cl7zW6TVTY9KVjQgFlm/3lL3cUQesrALQoQvaeScGtizkHJQxwb2luZRyajAeMuWTdL6itNl65bNKIk9EOjvfwAWPRnaQRvzTPs8zznP67ixw+Jj0VOZrdt2l+vaPaLCpHYwVYisX7dSOrarJ5s2rkmtaoL+LzRAYK/W9BZp2OZJyZItZ8ApsrwdCQQPEEYxoA43sDahltoGNQKSS3i6Z+1RNii2CprlQbNJsv7PX2XUazfJ5jWLg25jTRDoL+vmLHqyVObG2/MwcKbrZrTMHv68nH3bAMmeq0BQKWjDBk44Y4MlhEKm+adzFwkuXvLU9cc2yQPqsL4/smUEhh0flG5ZvUjGvkP31UopVeU8adTmHckEd8OB+EbRfP+KJtYTe4j0Z30kZxTmEQA9iKRbGY8Yl/IVmT60j8z8oS9I1gcKYwoXtn9TTqh9mQNi8DbmGjPtwZHk8YMeB9C/cVC+BPobHxwoRWDRE7AN4I2v5tFawRgXrwUzxsi4oe/KXQ9/IFmyZAnV92Dv2zHPsZo8PD+aJi8k9L6Cj5W/6YgyUz+sq7FrB7KCPQuUl9YjlS2SZNqPY6Tnw7fKtm1bSIwptGhJ183T0XWNnWdrMWqMV4v+pui6h5Dz7FNtmiNHLrm988ty/sU3RtWhMvxCCzOZO3uSPNaluezYHvvAoxgnMgfVwKnn3Chn3/KS0B3g1ymXq01DJByARZgA0Px61hNl5y1p3z75Z80SWbtkhqz7c67s37sbF44cUqhUZSlc9hQpVPpk9JEDUxmN+T9gol0E7I3s6lAOTUbmxuqFP8rIV6+TnVvXB21iSRDoL+023ix6NPD9B2JYlyrbtk1/6e6uvIXLu+Vn2gjqchSoz+Dj3ds3ybqlP+JiNEN96lmy5ZaCpTjuqpK3UDms7ixalwufbbjIDx6s3NedO/Il+ePnT6Vhu4+kQImTPBOVV5UEZjwdPrC1z+/H7p2Nf8+TtUunyY5/VkvmrFkhU1mcl+rYsXOiZM2eWyv7+hytMQ4xcYxZYgAPwHO0bf+slBGvX4Pzn75fW01vJtA3MytXLXDHE4wNpAGy7AP58YN6y8/fpw30bboOkMIK9BiF8okGavIjcG/euErPU7HjKgitf47FgNvK7SJjNH/R2L9/jyxdOFMWzvtJ/tmwFvM5ixQtXlqOP7GKVDy+quTKnVvl9hcACqBpnGvVGU4mfzBTv+xPLxIaM8exZ5I9e3bJ0493klEjvgQttnAFgP6+rn1SVOb4/TTzs23COFr0N6Wom15CiPWBm+YvWFQ6d3tH6px5UVAhDPIkKhO3IsaMGCgvP3WL7N27J6ifSBweDRSvWFMu7fI/yVesnJsPmA72XyedgTIhyU8TFrsKmLQE9DWLf5G5o/rLhuXzdOF4AI2SEOeSN+Bz5i8uFWtdLGVrNpWiFWpK7gLFrRpY7ndd8NzbzVum0B+RzpUx5o6UWUOfl+mD09hloK0jBwL9JQ+FgN6YG2vlH7mYaCv067v1rh7XBBHKsM13w1+zZfWiCbJ48nvYHbMKfvSUN9I4tzPjApe/RGWp1OBmgGst6LuSLnLfge/HRqyzX4ssr9Jgq+d2WfHrMCkPt41bIMqDbQkQlDZcf8c/fwPYp8j8sa/pLyCC/YEC783kyFNYKtZpJced1ARbR2tLVv1l5zgHTA2IrJNIX7ZMk+TnIY/LvDEHd60k7/+8m9+SE2rBR69jwDgc4JKn0oCwHBnzEz7vLb/EAPTXPzBQCpeERU+e1D154c+DNflqGhVYJ7wrJ6jj2mTCDedVfy0GuE+XEV/3k5V/LkwVh/irIE9ebEmu00gandNCKlc5TQoXLqZ9Uw72y+BlYZr9s4BlVsPGOmvGFOl45+UsjSnQovdA7/loQzL2k8txGj/uO3moS1uXO/ToAKyjmRUvWU4e6j1QKp1cJ7oglAsD/xcDnpf338TNKC74RDhsGsiWM49c1XsUALe6zQWoNwRtQT9JKbYNYv/vmqXy46e94OKYoFsf03tu+OuhQKlKckK9llL9orvN0nfn1/cXnG4k9My700/6np1bZWTf1rLqt4mBnGklCPQXO6AnD8+fMcHElhv6YpJ/PnJp1Y7TBX+tzPjqIfnr129l17aNvqa2OdiBbrLcBUtL6aqXSNWLHoaRny1ZdQNTHbHr16DOgJV0XchcZQwmvMnrV17SPlk87WO9+Gxe+3vUTVxrlNoxEyz7XNhSe47Ubv44dieVYAf4Q4/gbTqytsyHA7ObVi2QIc+eEyanmT633VtyPICegMc1z/6sL+aN5vOTvuglv4w4uEVfqHgFuY5AH7huvOwG6NweqW4YdMg+DfDdxQB9664aEHWsAPmvP+4jU8d9KRvWrkgX/nAXT5nyleTCS6+Xi5q3kWzOzWZjolpMDku5cboMXYD70fd997SSmb9MIjXNQKDv/ECfQIfWwOlTMxyRTagJ8QL60uVOkkf7fCWlypyYYgAe4H3MCv363i9ffwb/XyIcNg0QYBpc/wR22XRQnjoFcLCpYEcWKOiFet2DfeUr506UH167WXZuSZ/rJMQmlMwkhcqcIufc8a66eCQTby5iUoY7RtpnGat0OGxZu0y+faKJA9oQy1SSOQFcFz80QXLkLeIHitgWgOcfdEQerozykM5+uXQ2rZwrk95vI9vWL2OtQw7la18lNZv3MbcJuFAGAoH1wt58j4wZWOiAnik0CKqzGGHvzs2w4PvKwvFvAOD3GvEQjgT5xu3/JwVLVtbWHoSZ8X3qBQfyUDpzcyTJ969eru4hbRTD4Zyb3pKKp7l99Bg8wZfB9IDdMURi9MBo0pe9ZfqI17U8tQOB/hr8Qo24bqwt25OnuVGML90mpBvguwsA8rxhu27VUnn/pQ6y+F9uAOGDhk0vvlZuvLWbFCxYRGWgLtGNBpUplA7T5875Re657dKYHqS6nBb9A8+APzn4+eIYJ4vG42ZstwfaJqOmP5tmTxVOqCq9XxgmhYuU1MnKLsLArnkcvLjP9W4rY+G+SYTDp4ESJ9aW5g99BasNO1AQvNvEevCajwAuKfvhOpv8ySPy64g3NW11D88xT+HSUq/141Lx9CvAEFMIHRrY23QiCGreicY8n5Ce9umD8tvYd2ISgkB/0YMT1EfP9gz+guLz2q8VsRCpiA5I3rjyV5n28S2yJZ2+aM8yHPOJ1gp1r5Oalz8DMuDGC+EXq3UPCagPJzDVwaBlOGhsOtq1da3M+qa7rJgzJBiXVT60YwGAfIMbP5A8vE/h+wWrUDKgKw2H5XAtTfjg5pg7PLttBOjZiP2Ql/4BhcP5KYN7y4wYgP5qAn1xuG7QOALwdlGkm0bp6EPLmGc6oCfJquUL5AOA/Io/5h4WPXI0dc84Vzp2fRGYVwJjsou116mO1Y/bEVmH8/uWNufI0iULIOHBgwf6oBaZqhadMRAU8GZsnID+xMqnyVOvjJTceFhKrRI/YgijeSeUm9rS4/7LZPrUESFR458sU7Gq3IFHq6k8Lxdjrj+NcQznPXCSRq+tX6eR+pG2rMt6DMqDcUAjX4JNsjrMs7LWtQTrLZz6tUz4pIcVpHLkRfWiTh9KpbNaaQ3q3LFCnjOEOUdzBXv37Jbx790n8+CLP1KBwNfk1n5SsW4LiMHl58YIGahDzH2TyrlPKNr6P2bKsKfPjck9QaC/sCuBvhh0ZwPjKDVpWXYZ6FXVYBSlbVmzSEa92AivJTi894rqXP2WlKnRQrvT9RnpWHuPnBOmOP+SLV7KnrRXZg7pJkunfsiMa/fvoxPObCu1muPRenc+PG81zJwcJjNkw7zag18U3zxVT3Zvpzsr7dD4RgI9HpgCE/LxUODzBGMWEJwnf9lLZo08uEVfEBb91fd9KoUC140DdMffAN3AnX3wFwNjzjbekF27crH07dECN2pXpy18OmpQNy1b3yVtb3/ELjTo0wf2z3KSNO0LMDFf6HOfDP3mI09JNVag7/pcMK/Jh/OasQ9McuaMH/utdI+HRX/SKXXlmdfHCP1YBwocNKXU6Yp0t45NZTbeS5GR4fiT68ojr06A5vjOF1xtIQwVyeDTzPKPNxIVnJkHwfKWtvJIWtvgoLG2jaQNjDIF7VFs9UL1vXuB7SGc/I0dLx/df6bmUjuUrX62XN7ta90bru0CF4XxsF5wtELZi10A0wY9KdO/fi41loeNniNvYWl48xtStsaF1r8NTMfNg9e5ptErb36OextPZ84YkqYMHuiz58GTsWDgeWlM3vinQOrG7fsg4z07t8iPH7SRtb+PT7Of9FYoenwDOf269yUrXq3APnX+k4kXkGldsCqYz7ACS7TewnEvy4JRz8R0wbNGsR15E7nJ7d9I4dJ4tw9CFHCEQMSX7d+7E88fXA33zVStn9ahUZu3pAKB3vH2sefH/uhX5/+pg2MD+isB9IUB+GwbuGeQoW+egM5rlr7KAHvpmaerRq9juMn/7tPXy4KZY6J1T2EOQ8iWLbs89sxAqVm7YWi8vNDYeQzAnn3ZkOXrL/rLqy92S9N901xdN1yf5IXGGtz8CFFYRIu++wM3ujqHHrGXSA8H4HPyqfXk2TfGYYBeoJSVlIkrf+DOJjJv9uSUleJIMaDHjT8IxvUXBe7I64BRto9pVGCe9QgdAdAjzbJ9aKz1fR2MU616387TdXy8MWNWHDsn5/CvBetDK+IAi2r3TnmxdUFPSBHTN3/V46OkxIl1omSIVDQZfZ79rZw3Ub55shl21Bx414ave7jiXAVKypXPzNEblaYnKp3cIQ114QatWkZ+x+a18kXXlPd7kstDoG/6gFn0+1WJnGUW9JyFT4rqGmXsC2Hu90/KwlHPa/pwH/jsQsPbhku+klUC1l4y9s60j1nB55lmybrF42XqxzfojiejHd5jmerN5fRr3nb9GjjqJREAxQujSQe5kOQL6H764j5sA/1fTEI0bPO2VKjZTOt6OPBWPDmT5uNpAPrZo9Ky6CtKq86fSkG4bnhjlSHKileQNxqLtQwxLfvB7z4ok7/vzyZHLJQpe6L0fW+cZM+ePRiXHx87DcbLUvyf/tNYeaTrDbJr546DytT8Cu66ObAhpnp1E4jTecK4ofED+ufeHK+CE+x14YaGkZz2wJ1ny7xfjwagN4s+AG4ojfrjnwffoIx0FOzH2dI6yGg9gHxQ19XR8nBa25FK3qafoI7WI08rp0W/36W1Dg6vtysn2/9Zq+2TH0rhJWXNHvwS2+kKWCvUd5yiqnoZ+TKxLx9rKv/8nb790VHMDiFTse4V0gBb7zKH9vbrrxfK68CXCqbszI588RJZs+jgOxQU6LtMxM1Y77pha+hSL7zGyxlXOEfUvPFe/8dUmfR2c/hMD6/LJqyWyud2lUpN7nMkyhUJKofLMh0O+3HD9ecBbWX1bz+EyYc1nRv77Rvf9i3u55QEX8jmBULs5VEwcb3OG4k3b4701uXBRWlww9tSvmZz48MLBxgpT72IgD8ytLoZT/u6l/yaJtBXkCvu/UwKAejJx6x3Ajpv9JK/c9egTHffkD86WDx7nLz3VGvMJUyGIxhy5coj3R//ULdgUhY/PnbJtMXUAedfJlm+fJF0aH+BbNt68Cdlm19xE3bdPBu01/Nk7KKO1K+5bm6Moh9KhuJGz9RkXCpXOV0t+szUMIIH9tQaPnj3eTJnJkA2A0PYdWNgHg3AHhg90DNPJfB0kcZgNOSRsDJSrVynV1Qbm3A8uub6K4It1KpVDtEyaBn4vdfxNFm/fD6zKUK9K7vLGXjtsLqgUGqgaZpXKU1UbcfkhPfuxxOiB7eiUnRyGAhZ8UK1czt8JiVObqgKoCyqByS8PtgN0/ybO/xZmT3kCVJIPmAg0J9/vwG9nROM2zFVPmhFoFfrnhyQ3rdnh/w8sL2smjf8gDwPF7Fg6ZpS/zaCtbvgHIAxz5IKhXPMWsyvXTJepn14DS5Wh77DRtke5MC3dda7/gMpWvEs7TPQMAQwmVzsMn9M+1BmDO4KPaYNmvWvfxvPVPCBKcCau8p6sPd5+ud5Yn4G0M8ZffC5WKBYRWlxL3z0xSoogFNfdM0Qaqg1s+DZF4HeQJ4vjBv06u0y76dhB9HC4Sni2K5t96C0vuE+JxP4Bhc1QjuyPEBWhh3bt0mbK2vLP5sOvsMtDPQcKduzLz9fjGS0uAE998/3eW0Ufr7k5FhUoMBKc3kuQD+hHu58scz8aZTWzaiDB3ouL8qlwA5FUm4P6pSNABINzgbkbKNgQgvcjc3GlwnuHowVGcuDh9a1HPtT/qyjE4B9sq7ph2mGSPtMMqBbE1n5249WkOzY+qnxcNvUZQvtz7fn5AifA7LdtGqxDIHLZvPqpcm4xCd76gUdpVbLXpATCwCCUiYdpxszCV7+lXNHyqR3btCHilKTjkB/3n0TJbu36D0f8uU/7cBae138s3KOTHm3pezeti41toeFTpfaeQ8uFF7gdKC6Rt1C9es11BPXMAFq4ltNZeuatHdlhJqmO8mb5Kdd8TIA+cqotgZIERLzhKqVc4fK1IG3xHTxOfP6flKuhvnoycnzMPcNz7yjIfHLNz1jAvrLO9J1UxG8AOxoZ4BOycAPgE/zUvfLu7I1eNDvnZ6XyO6d2yjCEQ+nn3WhPPzkxzo2ezcO5OJAEQjOOnadBEa7rkUNWbtmhWVSOTaD66bzA88rz6BKiGewUFA4Hq6bhx9oE1Q71ATZh5ZQSjbHV6ohT7z8veTPX1gLuag4QL+4VL5QvvdDLWXqxG9TMoojJQB6zBTKqUCP/j2oe4zQMtAJGp5mQG15f1Fgueexj+NgZYzZ6oZADQUs0rqqWU5XX25p39z3+VmPC2X53HEkR4X8xcrLjX1/1ZuwLPD9M80+eFAxkOS4Foz5QMa+fTd+gRw5a5HdphYKl6shF+PdNHanDLJhgFEPU+mVz87F9g0rZMSzjfHBkgO7rNgHgf5cAL133VBfPFE6dkuaAjRt1IWjnpXfRj4NypEP9W8fJflLVg868pLpegiWsMmFqSJrF4+Vnz68Kqh/JBN0LZ3UpLN2YfIYKFEa5jVGgum1iyfIlA9ax+TqOuM6AH11+OgdU46LQEdYjli62q3MGNJT5o5J26JvRqCHRe95KT/yVavegTyIWcCWLzcb/GYHmTXxM+skDkd+0OStT35W+QzYQxc09E+5GXx8312Xya8zpxgxlSOB/l4CPRvpxEb7MBM3y6lXWvQPd40D0JerWEV6PfcN3hFR1gSDQAHI+9GFFmDfZ+6Q74f0T2WI8SET6B92u278z/4Dg7oHYQNLqttb8Hw6nqeUi0JpbnUw7UGXJK3jxq95ppGwMhsv67Cd2Sks83UyyWc9mgLox6dQTN0WXeSsa3tpD16uSCXj5/Psa8iTzWX5rCPn+/V9pRZnzpJdWj77O+4nFLS5C2DXcaJBkrvy2bwBHcr94blzZeOfv6TGToH+nM6w6PMUVV36BUFd2EXENfX94AI39sUzZNu6JanyPJwF1a94Q0pVp9VM7dtCtZRm3cGdc7hFFox4TP6Y8ka48Iily9dtK9Uuw5OX+Mf/PA9M++XqOya4bPxrukzs1wxAv9uTU43rXdsPO6zMR+95kYdatUwgkM789CGP4RULaQP9ZXfToq9AMc2CB4MA7EEkP26lxH/ZteMfealDFbzWIG1ZKcvhCNmy58C3OP7ErsOsgVyUSeV18rEfn+/R5Rr5cfKIg3ZtQP+CttFDaOKQdzgQ6B+JB9AfV/oEefipQVK+4qnaf5Q1T6kcyHnhPny7h3z2UcoX9vjyeMQG9BN1CVKHBF7OmLC/nSQDdQMO4LrW86AcgDUq+jJU0XQA9ChLIl/tAGn+I015szaDAZ61sbNo/VrZwFRcN9c8M0X4bhvyYvAXV9eV0llGjts2rZaPOpxyxHZysP9YwtkdBkmpqheYvjlurxfqJCotMgtfY1o4+uVU2dKiP/tec92Qode5Y+4jVTb1sPnvuTLh1UbsKFWeh7PglIv7SNm67ZRleG36cxLua9/urTLj07ayfsm4MPmIpY87tZnUuooPpjlpnF/ZZovTD4Sm3JtXz5MJb16Ih+rS3qV1+jX9pEz1y7GUjAeXP3kQEzjLmSGNQD0DQD9/7MGBPj989Jd2+FToqw9utrI9GITBnmnSFk0fKp+/fOMR01tqjN8aOENKliwXjFPHDZls/KGxg0GfXrfhM6qfp8ZK6Ze1gOum6wtBHbAKBTIGCrnTNH5cnIC+cNHjpMujH0q1mlhEBwj68wN0v5C//fJNeevle9VqO0D1uJAiFj1B2NY+9UYM0NjJSwDXcubD5ciQ7sFFd+OgMUGd4/R0uyiQLyHeAmO7MBiFdcjd2hjo04Fvu28yYR/9GcKvMoUDn4C96bUF2KsNH7ALpt8QeIboS38eKuPf7eirHjT2ch60ki+MoXK4SpXz75bK53RQXeioaW2jgv2acbHSsA10zncyqV9r31OKOGe+EtJELfpienJUw66zQN9BXmAtvy3zvn0wBZ8jRTihyUNyfCPbeWMLNawJ9mrnnaldW9fIT+9fKts3LGX2iIeiJ5wtdW/4VIEoeWe8WepnK4Fqy+oFAPrz0wX05Emw54j15qvGpGK2gydHPnPoY7IgBqC/GDfxCxYtj3b8xeH89A7oyVtpatHDjfEFvlr17UvsKK6h90tDpFr1s/Rio2NE7xwnLz4M1KimcHj+ybvlh2EDlJ7agUAfcd0oA53jZGJ8cOTCQW6CAv0NqbGKmU6+yWdoVOM8eQvIPV3flPpNroii+0zYwiftx4lD5Bl823H3rp2+StzjIvjY8AVX3qv9qr6Q8oNkbGlMVPezX08ViJy6PGUGJKYazbOF1rU6ZEy+dnqtzAM3qVUaXY0nOguzmvHDMSyHtdVi6XfHyXjp2DLLuCNfeXBlr9GSGQ9t+GDtk/FxhXz8WvfNq0wcjR8D+3eTB7H26wQxutXTSix37YxthIcbrJazrl10HD/Hl/RMuEmZCZ/M0zrg5euyL+3WgTwLuBV02KP2bhbrL/pIoG8Mi9589GzPjvW/VlT/P2gk80zN+uJOWTEjfq/eqNigs5x4DnZEIXB8PHDxpwxJsmPjMpnyZkPdFZSy/PBTilRsKHXbfJFCHhVPhVSJVW9b1vyGm8TnxQT0dVr3k9LVaNG7OeVizbuxMyImzB7aQxaMS8OiL1pRLgLQF0DsLXryMgveLiI+j20QMuSNW+S3n785/ApLg2Pvl76VqgR6jjdqnDZWXoxs3AD6JzrID9+lDfSdHgi5bqgznhLHmwntB7S4AT2/1tO+wzPSrNVdB1SHygapvJW19PdZ0u0e7C7A11f+v4a7+y/B+8OP0+FzCnjXDgm6xAB4ZvXvl1fblMQj6JujVHVCveZy8b0fhR5CQjtbm4F1zKwjGQgyDwLPh9KDi5gR+GuEFcIgrbVJQxUG34ePWW7+dftForxR2V8QmLd7GWxMDsYjAGUng/JTkNca2g9p3zxUGi/22qLtkh8I9I0I9Hgy1tqzCwN2lcsLSXngA5/6bnPZ+AcekotTKF//Hql0bg90Dh3hH3XBQLE8GKh+UbZ55XSZ9m5TqxCHY+EKDaTujV/x7KE3J5kDIy+TxqBtBdBPihHoa19NoIePHgP0Y2TMHmhcWFdmlc8e9qj8lgbQ5wPAX3gngF5dN2gOeTyY2pspScONWFj0+3Ztk8GvtpFl88bFQYPRXfQKAz1HqqhsFyTWdDvPdfjPP9lBRsYE9C+aDv08pk71fEX3zQemeuAhrH8beI44Gw4aml15t9x6z7Oow+rRQRnwbENggsn2bf9Ihza1Ze3qP6Mr/j/JZc+VV+77BO/e4I4fpy9/EdRzqqoycNi1Y4u8en3xFJqpdn57Obs9fqJiq5wHDj8fwheNcJpMfB09TwRA/ccCllqflj4AYLIcDLQq22rC2hrNCKT7P+XJNq6up4cvJlrGNhTBxcBlzY98+nR1HbAoechBoO8UAXrPk/Wid/PgYoObcz/2awpAnZWczRHLlz/rHlj0jwb8bQmYLghOaqJxvPhbt+g7mf3Zv1+sQWdpJAj0ddoMttnnQMk34XoNAjLc7jn57dgs+loA+lJVnUXvGOlQwVDBn4zRHyHrVwD9wvGvBV0dKEGgv+DOQbDoKyjoeaveLHr46cmOrz5AJ/xQzOC+18rK36cdiNURpfV8ERZ9DVj0HBlPrfaGcSJh7iXrnvkXnrwrTaC/tMVNcm8XPLnNBggaYZ4EaU2RYK6buAF97XoXyGPPfg2BOFADBIpooiCmpG61k/Zcr7Yy7of4/YxWvRwlhwrVGsu1vb9XddCdw0nvAZm60T8eQF8N3/zH8NEnD3W44+aanjoDnFq1irXVxsqHxDAAkshfClZowB5pz3PE/3b5sXYO3I0lW6rcmvU0xP6ehG+vLi9ljPYo9PV9X1ofRMuj3AE7McfLR51MfP0yWZfK+2gU6Dty1w0sehUsuWwGqizat2u7TH3nQtmy6ldm4xLKnRkN9OyUy4C/cBjzT7UN4VfP/VLmDr6VhLiEQgr0tOgpBLVnc0FFchKYfAD6tQtkSqxAjxu8pWDRM+jFDLw9H4Iz+2FPfN3vnGG42R4D0J9/hwG9B0yCPcXOCsbqEkGaFv3Obevl61eulVVLU9+pRQmORHjshaEO6G3cKiM64tgNEymyravnAfSjhh/cdUOg79QFN2PZPiSwplWhds7Ik66buAF90eJlpP9nvwV7ukOyqaAK9CRi8VJEvr3yUbzF8v9jaHztY1L/qgcVgAl01AcDpwG1Y+Bn+fkT/ifDXmqr5cEBJ7o+tlXWvvx+R0I714i8mA54emas6d0kLq1RqC7zbKhtHQPP1+pqDZUvYKv1/IXKyUEe/OO/kDtGefsyFytHpAnqYZ524UiSqf2vk7/nHPiZCwJ9w3sI9PaLJxg3+DFo3qX37d4m0xTo51hhHI4E+hPOeYyS6H8PfCoSDlyvfsyr530h8+IM9LWvh0VP5FCLngmnLMxDBRSXJ9D/2C82i/40AP1xVZ3rBhzJU/tAygDPwI7pObDoF01I26I/7/ZBkh8WPYHe9s4bT+YJ8Fw1pO/atkG+6XtNhgH9qc5HbxckP04bt9cDNfvCk3emE+jtbATnB1mj2HGiAv31qu1/cyA3PwNS5cPXnvZ9/yepgO8sJg8BA55xLmhU4GcE219VWdbjSy//rwJ00P6FqdgWWUO3clK11IcqGIf9Tlmax+kc/1E3+WlwZJsVdUVdN7qxj9S4pIOqjmBh9ale46cFOh0IoFbqIgUXUsy2QjlN6OAkkUeEn9YBwf/i0IrIWx13Pl3npDF4a97yVlcvMkrgxYBWLehalwe2Yjtf10jMTx9wuyz/5cC//Aj0DTzQsy0H4XkoP2Wr/RHof3r3Alj08Qd6r3+TJnL0+idlzVwA/ddxtOjLN5BaN3yNng2QFI2hO50HdgDJzsc2AP3Ud86N6WZszSsJ9JeDL0aH9pxWPDDm8mdgzL+53z0qv8cA9Ofe9rnk80APnt5HT3BXUMUYFOjxzeEhr12DX8EZY9FXUaB37iQ3Rg7ZX+B07Di8+FTaQH/J5XDd4H330cFmjNLIGIHRBOyjf/TBOAE9O7386k64KRu9P16tGF2ElCpiebL+O/8PvzRVoFhZueXl6ZI9V34DT5wpri+DPcY+zzhJBvW8CB9/GEd1BYE/exvf9LxUv/B20Lw1bSedmB0Bloi+2Qe5e/7MadC+kdJyThtb3Jq1GiZf0JD2k9VhsfIlD9fAYgNzysG80ZCmcF5eR9dmmo7mqW1wmDnoHlk29QM2TBEI9PXvnqQPTGmh/noAH2aQ1sg6l724UfdT/wtlaxxdN2XP7CgnnP0Yxq8SqTxOw5Y2ETVN1838r2/RdDwOhQD0p8Gi98FA2KRTsUig3IjSBfSt3pGSBHq0I4tMPA/6i8H7qk0XLJs3/DEA/atehAPG9NGfDaDPX4QWvfEMx7qfHmfcLPr18m0GAf2jzw+VU+GjJ97pLw/OQsqLUakeNGYuSV6KEeg7PWBAz/YWrH1UFj1MHDskvkCfv0ARef/LJcE7b6LFQw4Shyf9zJ9Hy1MPX42bs9E7Sny7YzGufEZzufz+jyO7ZTAfItsuOQ3MjcGx79i8Xj55sKH8k+zdNMmBXgHVKYvtIzqO6NtjTbiuTkM0UGhkQ52WbB+hKRl0bWcZrWB12Bn/Y+qBEKHZhIzstvHtDwTm2pSdB33YjVTkYfXP+rKTLJvSX8uTHzzQZ8tdLCgK5FS5HBlptejjDfRn3CPHA+h9oH5s0Zp+TN8gIqyB6ybeQF/zOt5T89JFx55Ombetm49fQ7FZ9DVavSslTm2uoEyOOlIcgpecgbF2CfCf//2jsjgGi77JLc6iB8IryGPGMfYWvb9BuwsW/bDXYdH/EX+LnkBPi556M9eNjR0/OjRBeTWJOL1A79uF54vRjGncgZ6dP9X3B31wKsqSZwGDmz0eiLZu3SQ9Ol8ii+b/bOXH+JEul3PbPiV1m/kHlyJbKHkSCbgBWEIXqxdPly8ebw7AXxelGfJpCNdNTbpusBAJFf5PAdfXdmXcP78TO518mde/VcNkQadqbDvAVrpry7QBrwNpdqQ09mmVDOhZz9Wx5a3ttC9a2vgXuQFLJqA59w3ZMLCc4+f09XVnf3mvrMKn9A4UCPRndaBF77ZXkicZIIT7pXXPJ09/JtCvjt/N2DIE+iaPYdpH5Eo5Dro46Lr5XOZ/E1+LnkCv+iYKOb2p7nDwYEU9bl07H7qLDeirtXzXuW7IIzRapJnlWB0MKNAvmXhwiz5vkYr4StkXznVjbQmeBHnyUx89GBLsd+Fm7LDXW8uaDAD6Hs8B6GvU1zFTLq8/HS/ntMrLkiR5+ek70vTR03XT8QHsqmNbNkNQTCWBUzygCSx6um6u0zr/5mDSxcjhyusfkDa39oRQPB2BPCob85QxHEYP/1hefOLmMOmYTWfJlkPaPTtJipWvqnrg2qI+vE40DaLlMwlvxA5/9Rb4RvdE6wRn/qzWPYU7bw7c1qrb2s0kf80ZLRPxeuK9eDtipLdolgGjZGSf9f34vNZPx8wwWYLWUYko3lEZ3GDbsgYPEW2Pqu8zHui9Re/78C4iatJoSeq6mf5evIG+o1QE0Ae61cXJAUYUpymQ1s7/QhbEEegLwnVT8zo+WOQUjkglUxkj65aibksn0Jc8lT56Cwr24KFsk8ULYNEvmZQ20De+xYCegEd+/DMXiU/j1cWAG1r0372R0UAP4aBJlRGjVqAHxfRg+Zeeul1Gp7HrRoG+C4AewQO9ZpgPiHbueDP2sXgDfWV8barXc0OET8uqPHoMppOfVo4KOlZilzsay29zY/tUWdDwP5ioUL2JXNdzuLOeOXbTi92yUlgKDCtatGMBztOHHnhXQu3m90v96+yVv3a6nY7BlHkDOFPSX3jz5ffPXS27dxxbLjIF+rsmSbZkFn0wdvdLghb93t1bJEOAvvFjAYBSLoMBniA7N7SHuAYI9L/FE+jLNZAaCvQmhx4pHwS0GRQBmG3rFsgv/c+J6WZsVVj0HugVkMDYA5WCHTtCAS3e+d/3kKUxAH2j9hGgJy97JTFAE5JmQYYxee/evl6GZxDQPwKL/pTq9fVd+dSg/8WRGSeY8lFu/Nf4JVj0aQH9xbToAfTWhkc3YZRHdH7SeFj0XeNs0WeD1drz+SFS/bTGEMkGx9iL6WNP42mir/7pR1rjqyubSD4mQza8k6bt0+OkuFrzPPX4B2WYy4RDphsHOdCoIy7+D+6tneoHR6qe106atH8FPwn5clbXxrUjXx+YXIe9+N8+eZns3LLek4+JmEB/BoA+e+7iqk/VnY4d+tXYdMzB8qnJ6e9fEF/XTb2OUgFAr6s1rHHK5tcqYwT66BcOaW+ZOBwLEOiv/caAHfI4MVLIRVHoo59OoN+X9kvNql4BH32VFsrHAzx5B2lktC8cfiPQT07bom/Y/kvJh5uxCpZoR1DnH/M+7YH++zevzhDXzcPPDlPXDUQKZAvkxYh9muUvP522RX9xc7puXg50hWbBOSKvcJg4bkj8LXoKULVmQ3m678hAFvVRMsfVBykJYj4wtWf3LnnxyfYycVT83iHt+49XXK3JddKs07uKyB7cacmH949TF96a+nvhNOFbK8O6CstaofZFcgk+mpwZH2T32mTdSNpqM791/Ur56pHGsg3veD+WQva8BPrJ6qPn3OK00vHDgldNemUgtxcfoZjxQfyBvnzjnipLWO9cqKEloAt4DSz6jAD6sFyUibtY/Jzz9xYI9DPeiw3oT23RX4pXSf5krFndHCjPDI/cerlwRGxA3+DmLyQvgJ6ysX3EWo6k1XWDffQj3rxK1i6L/81YAj0tervweGC33+rUI885ZeffK33SBvqLAPSdAPQMbKuxHpBxk8fTzXVzrVX6F0d2E1oyaXPiwHo9/62cVvc8rRxmEGakaR5Q4e+/Fkv3jk1l3Zq/0u7gP1YjZ96CclW3z6XsKQ1UkV4HevMxNBa9AYn8fnyQefDTrWTJL9+FSqOTxfB64isfH4OXmtlXvVhqQAfu3mVBGv7279snX3avL+v+mM1qx0xQoL/TgN4DZyS2ieVBi9srZ8YZ6EurRd9TF6rJZTKlWE4gr10Qb6BvKNVh0WugcG6REjwCKZlA2E6gfz82oK/Swln0aOeBiDExgZx55IHxwh96yB9pWPR5cDO2QTsAPfbRs00Y7AmqZGvgaq6bH2DRZwTQd08G9FFPxnLIKqddqGIBerpu7uniLHrXHpEG6oFBVYo4wyx6CnF6/Uvkgcc+klxwWbj5QrJLU1SbTt4G5Vzjd2Qf73q57NixVeseK4e6F98h59/8LNwsWXXUXh8K7FAFx65/Tivr/pwrAx5qJHsO8ik0fgy87euLJFuufKZTMsBS4NGDm/ZD3qBN+fghvC3QLARkj4lAoK/ngJ6D9Hq0wdkcUx2jbO+urTLzQ3yUOY67bkqfDtdNE9xH4QlQcZhA8HnL6XHd/M9l4bfxdN00lKqt6boxC15B4wBysXz72nkA+rNjct1UuZwWfQsFIfLk2Bn7v9CQZdHIHrJsct8wKUWaQF+/3Zdq0SsP1FCLHhkCfPAJQdzr2I1dNyPfyhiLnkB/cvUGwUVHt6JAPr0YQeZAdtBiAXpa9Pd0gWuWuqNWfGxJUiyAPkldNxlg0VOC3Hny4zuKg6R6rSYmkDu6qa65IK0TDDfMsLvk0/efkE8/fMpmSFTL/2bmuBNOkxufHIVvh+Z2IGzrnKPxFr0CAfJUA105U794Rib/rycWiXfysHbK0LLnSDnulPpaYOBui9b0yulBdwbBHzf7lkxX900Sfi0cKyEAeuyjp62oOnCTKtApx48M99HP/LBp3IHeXDcpNU75uIh94M3YRd/Gb/dZgbINpZqz6DnNdJOc0x1lygSE0reSQkZa9DPTAfTFCPTkERqfppE34GJBkiyCRb9sStpAfxaAPk/hCgGIKg+w4A1dgr6CKdK7t6+T0RkE9N2e/U5OrgbXDeXB6EwmjNfpgRdMfYUhYgL9mOGfoCT1cFHzdmbRkwGC8eHRT/CIfhXoH8ogoKdwlaucjo+Gj8YntrIxqyE0l7zIKrvSoQQ+PPXWS51kLLZd/tdDvsLHSasHBkjpk8/UoXjXjP2AtX3lXh9c+Ezv2b1DH5Jat2xOmsOvfsHt0ujmF7UdwYw/DAnq5MWpEUmDN55eGvzoObImA97sl+ZADrECgf50WvQE+pBfXkGU40eCaf7tJ9B/FF+gL0WLHj56PR08YH6rMAcY7zq4buIN9KfComegWAyqN5c2ih0J9LM+iM2iP6V5f/FAT8achThoIPgxqBsHPvrfYwH6whXlzJvMoieIMqhFr7FZ9R5Uuetm9NtXyboM8NE/9Ax99GbRU5/+LZbehWP76rFGUdg3HUDP8ZKfqo6HiDoDvRLoe2Yk0FPINrf1llbX3oeTE9kdQroPHvQ4yRgY0UfdB7twpuED4mlZtdroKDxkzZ5Tmt7UR+pcdJuOieNS0GGcLM0z5kH5l2Gvyph3749pRPz26s39lkmmrNm1vvL3igz1YzMiCV/z+UjG97sLoL83Jv5HqhI/FLJvzw51p/ybPhTo75gsfh89Fet1qwnqgDT80aKfRYt+TfwemDpOgb6XCsXzq4s1lQFnDNAPCaQhmPipw3Q4GNA3icl1czKAvniVK9DcjVd5RQDfwB5EAP1ium7SsugB9Gc4oKdcBurgh/ZMG4AS8JN0e+WYfhkF9LDo/c1YjF7lRKwgzeEGf5nk1RiB/u776boJ69FWMs8NNaqvlgDjSWO/yXig52cGezz9pZxYuRbl8+svOu0WqBJdnbWrl0u/lzrKtElDPfk/E+eA3/ycGx6TuhfhXTSZ8L54NyaN3VjDaQ6Mi2zdXwtkQLfGeMIPT7HGGC7vMVxKV20ULFK7EUs9swfj6+Ot61fId0/j4xsr5mlZRhyy5sgjZ935HfypG+Sv6Z/K37MGH/JXlQzopxjQq17NgufQqU9aT3x5GkNGAX35Rr3Ru8mgEdZnihik9Qs+j7tFX+VqA3q1sL2Mejly8kIuhu3r5snsD2Oz6An0xU65QrkoFhkLOyrYGUiTsHjkI/Lnj33DNVKk8wDo6930leQtXEHBUgEUlj3VGPHPK+yp62bsOxkI9NUaBICuskFGArxdnGxoTCvQf5+268aA3tqRD4OLLO0yk8YdBUBPiU6vfyn89Z+pVR89hYIlEABVuHwfdou89MRNMnH0IHU96OiO8gO/ttXkmkekYUtY5fgVoziDs0Tg4djUnYDTZbGn4VfMvj0y/M27ZO7oD9M1whqX3C31b3haQc388Wzu7Ed0Gv2LKZPMG/WuTOp/t/afro4OQ2U+LV37hvek9Gmt7O2VUMhWfI90zuCusmHpxJgeyAmLQaCve7sDeo6aOnaKpq41uETGAH0nKd+wp8nBlUrZuDgD4ZB29PW/xR/oT7lqSABMJqQT0QGIp6UH6Cs3c0CvPCKDZUrvAzim3D2zeOTDaQJ9blr0bb+S3AB688eb9U618Y/AaUCaSfbAR59RQP9gH1r0znWDMdruIPvVYXJSA1iNiAj0Y2MGemtHtbGtD5rEgfGk8XDdPHiNLzrkmLzCUzPdjLjAW13fRa5r94hkOaC/3oDPMw53tmXzRhn8vxdkyKC++MbsDl/lqIzzFSklTVp3k1rn3qjfRuU4FHdwhgJ/MWlutfMi4OssnfmDfPtiG9m5dWO6xla0Qg1p1n2I5MTHwtmXD5p0N2IjdLzzZc9uGf/OnbJoIj58ECnwzY5cDB2Urd1aal37lq54vvBMAwTdC5nWL5ksK2d8Kmvm09qPfrdPakIdGOiTDQtj5DAJ9LPpo4+z66Zcw14hbOeZ1yWq591SNrp1sOh/Hxq/m7H5cTO2ylXfGnjoCg9NHpwrzNhA7dx1M/uj2Cx6D/TaGHzJGuyCEE4vGf2ILE/DoifQn45PHnIfPdsaqB84po9+HCz69X/Gfx+9An2URW+/XCIym055fPWZ22IC+g732a4bKs/rLYiVaGqlj77XQ0cB0FOc7DlySefu70r9s1uadO5ooMfFiYmFUWgcqsHpRsueHyp59an2svmf2EAgxCIuyZzY7njDo19Lmcr1bBxcKhiTB3MKwbEq4PvYjXcbxvQenoLdvgmfF0xn4EX0oi6DhA9QUYUMfomGb1AqXQtwwxsf3f7+uZZ4Yna61o/HIWf+kvi+61jJVbCMyklZU/zhPG/fsEwW4vW1q+fhhVtp7BAi0NeBRW83YyP8AhT1fWCAfKnZr/EG+rodpRwteq5Of3IIev4EUfFu5dJ1E3egv5puUSqJgiB42RiHAi36OR/F5qM/6TJa9LbG/bD9TVTm3XCV+5LRD8cI9IN11w3bKtDDdaMxuNhLzSxvQH9lhgB9V1j0las1jLiT3Fi9nH7sIMtrMQL9Xff11XFSWV5vPg7T6Lo5aoCegpUoVQEunM+lwgnVmMX84rBtluk64CiQ8PPO6igJ5CRZ+vtM+QzbL2f9NEp24dNwR0PIhm2T1Rq0kvPa9Iz62DfHoEDvBmF5G20E8PEqYrz24bvXbpVFU20HxKGMqUi5qnJFL+xuypkXzU2n1h/TJofFrgyFa5fOkHFvtpdNK+ZrnSN5yFeistRp+6EUOO5U6IQXO5PJYqbtjyfepzf+MVlmDrhedm9dk6poCvS3meuG7Rg09vz8fEJegf7jOFv0dTsZ0JtoyY5OYLdyadEvzgCLXoVyegotR5tGjpA+oH9PisJHz8AbpTgjmlZWSnNZFMUK9HVvjAZ6b9WTPdM+vwcW/fh3MwboH+gzHNsrI/vovWwaY8iM9Q+KeO2ZW9O26Ju1k7vu74s2kV9Xnodp0PjxRE0a9/XRBfQUkDdnH3/xOylb4RQ3BaABpIKF6kfhYvM722Th5wh34WGqX378Xvq9eI9s3rQ2We34ZkuUryKX3vq8lDv5DMmSPVfgj7evMSW36JGHeMkt+on/6y1TvuiT8g2V6RxK/Rv6SHX4633QewNudemlE50riLIC04i2rPlDRr/aRtYt+dk3O+wxLfjT230shcrV1Y4pg8oG1w1l2K+f1EJaXTnuFxAKNi6dJDM+vBI7czanKlME6PGuGzDWOYS25GsHRJrhA1PbZM4n58fXdQOgL0uL3smgA+Fq1RAhkkIffbwt+lPgukkeAumgOH73gHrdsT59Fn1RZ9GTt+fHhB+6py0d87D8NbVvchGi8nTd8CPmuo8eiM5VpP5v7rpBzcAXjgwt+gkZCPSVAfT+BjHH6LdU6sUIeQPq2IG+Q5dXVRdeb5xIXncRmshkAn23DNxHr1Ie4FANLzy79+H+wu/M2qmLAD21wcnlA1M+66mMd2zbIkO/fE2mjPlcVixboA9b+TZHMs6GbZPFy54sNZu0lroXtJMcufmlKOvRu2nM/Zwc6B3AoSqr78X7fWaO7C+j+nfBjdh/v92xUOnKcsmDgyVfsQrgbwKZ3kwOpegBO1GcQhltXfenTPmws/w9dwxkOnz3QDLhpnShcnXktKtfkfzHVcE5dHKgT/arIiD2uksC4CMLwCfY75fZA2+U1XO+MsWmciTQ174Vrht8M9bvriETz9OaYWmAxidjMwToG/R00nOJQhBdqS4dGhddN4uHxddHr0Dv5oKiUPK0Q5P0AH0l57ohKz9Uv6vH5zlsgh8t+tiBviJEBNBBJm6lpGjkl4XgT9An0OPJ2In9M8ai7/I0LHr/ZCzkUkscAvIhKbCOLIgAABJbSURBVI6VwjIm/fUYLfoOXSIXQbJgcKckKn3UAj39yidVqStde34CsC+rSvBzLDwCb/0SFTBvgj/W4bWN73DZuGGV/DZnMh6w+khm/zxK9iV/d7sy/PeH7HiVw6n1LgbAXy1lT6oreQrwjYkGTh7gdQw4EwRSDza+jBJ4Gscya9QHCvK7tqdusaZHar7FstoFd0j9G59BsxC4OybB156Q97r28Z6dO2Tp1EHy82c9ZOfm1F0lscrDVz2cdF4nOaHxnZIjH61tdmrjN8vdZCA9/KdbQ0FY/tP7eDd7Z5zf3Qft0oD+R91eacZB5GKiDdmvO0d7d26RuQPi7Lqp00nKuF03XODegNHFyrG70TGfMUA/NCITZKE8lIXnRIHFoQtdN3M/boLzsctJnHpU6TK4bk6O3IcL89Fxuz6YXjKqu6yYFgGzA3GlRV8bFn3uQhUdUHrAjMT00xNE+WTsBAD9hgy4GUugp4+ecvg/jhH/VacG8lYWC9BfCNdNh/tfDYCdfBi8DsPpSeMGS++j0aJXiXGoggcMOuEGbclSFXVyhUcRtXBdA78wGCvIcka6QBBdvXKJTBr9mUyfMkw24Y2NfMp2145tuJmbPos5a7bskgP+bt5gLVyyvFQ/63KpeuZlUqBoKciZWfahX3YdloNWvKf5NMfjP4JNMSkjrfffpg2RIS+3g5V5+Cxo8ucF9ILOA6VCnUtVP6RxqukFk8I60NNH25FTEg7UJY/8dOHsr5+SP2cMxQ3bv+FOOjjQkqMP7Dtb7oKw4mvLqZf2QFwr0If1Z7rQi13wFKvRyMNb/JuW/yLT3jwXln3a54xAX+vWH/U1xYFF7wTiBSX8y4Y++rmfxBfoSxLoYdHb4rTzoIsfhwjoW3oDXDfxtuhPvjJ0M9Yhif7C5kRG3ki4eb9uLnQXI9Bf+p4UcUBv4wYfTehsU10oXxz+GNM9Bov+eGzJBdAXrmBt0Y4uEW/VG4BantsrJ76XMUB//1PfBxY9x+e3guLs6vj1VwfoVMUbz6bto48GenK0VRo5LxG90kffu9tRsuvGrb+oiBPgBDxIdXvnV6TSyXW0jNMhYv3YIrApwqHaHysmB3otw4HxbrhFNq5bKevW/iVrVy2TDWtXIr9Cd+xs27JRdsLPT/BnP1nx/vxcuQtInvxFYKUXkQKFS0pBfMC7YLEyGucpUMxeBay8TZ597ASBoEU51IInQfOgM+nqMLJ6iGFWzxjxrox+/yHZvXMrWxz2kLdoWbng3oFS9PhaylvFoFz8IyWIOQUto3QWIcGnkreuXSZrF0+T1QunyJpFk2XL6sXYlsmvU0UH6i973qJSuHxtKVapgRQ9sQHcNFX1foWOH4CubiJ241w3kTx5GdCrbKizZ8dG+OVby8Y/JkV3lEpOgf4WWPRw3fiLF6v6vgimXFjkv4+uG1j02+O4vdKAHtsruU5VLou9TMz5svW/DZIl8XTdlGkgBvTQD+VQYXBgRnOa0CQt+nmHAPRkxjni17OOFWxhE2gg0Kdl0ecqbECfp1AFbUc5A788MuRFGl04tOgn9W8lG2AsxDsQ6CvTdUP5IJC/ACnAqw6IFEZ/HUA/Lo199B7o/Tj8PPEx6eTHMHn8UQ70JqZIIYDr/Y9+KKfWbATpIxOD5QoYjEN/Sg+GyTqELANhgmxQrnQDXjLgzVxv3SoYuzasH86zTjivabZHPfazT81StFEaAZNp765JKQfL9sE6njHyfRnRjy6JtK1VynSooeRJZ8gl3b7VF6mRhwEfZcc/Cqu0SEwSLTkdllbgGNiOJfgWJ3YGbd+4QrZt/BtgvFmfEcieuzCsrPLqmsmcNQer4b8bu9OP8VAWyk/1RWseBdSJY68xP3M465M2eF3vMBMshuOBgJ5jZbDzTPkt8Gbs3AHnxxno71WLnhJwgep4VRyT0WjQGrJ03Sz5rp0JG4djfgB95Sup64iOgm5B8vLy5WYG9I1jc93Aoi9cGU/GkoELTFpeJwknm/JfCqBfmYbrRoH+elr0FdGGM4xAb/zCVj3Bf/e2tTKZFn0GAP19tOi56wZyGNjbefVjN1m5ypLUoo8F6HXXjY7YFKm8mGQCk4kRw38G6ClswULFpQXeidP0spthYefDIAw0/OLw05Ggy6CnHIWeznpM+3KtE6a5tNbRNFVuIQB2V0dBCEXsw5c57NI2+9CJ7+9AdfyFgdzZbhs+7j1uQC+Z/v07aBeW0Po/EseyNZtKo/avYbdCaWUfyOsGzTyDj4NXJziC1lfQ9IBMfVnaqkTOj+apO/4pz0g91ZsvC8Ws6Mt27/hHFnz7kKz4+QOVKdZDAPT6UrPIWEw+5tmhcVOgH5hxQJ/qmCgfFixdNxkJ9FSVAQfRw86fz/Nm7LxPYgP6E+m6qdwyACGO2wMS0ww+/8fY2IE+F330RFDIZhY9rWMDO9KzgOnu7RkL9Nx1491KZtF7y15PsbPy4brBzdhxIw7+CgRa9AHQ2ylRyPe6C+vxPwX0FJwvPjujcXO5r8dH+sZLtcp4at1i5QwJaBy2m51GC5eRG6dEiAYeHmIVYMCLgM5TwPakMce//TiqFcw8y0hjAQIjAj2DtXHtyUf/GV9ljTob1yyTTx67TDasXKS8tGFcDpnUV39exwF4EwPegw+BdHw6DpOZYlBOktTWYJr1tI6VBXUA+pxvvD/BBloFNM1qGzsfpJNmPnNzzYR5eN85d9kw8Ib67EG346nY9D+pGwH60K4b5WrjC4+FnxKcm0FAT314w8UvVMtTVwZW8Qb6fGUawnXjLXrTl7e6KS+DyWo++nkDGktSDDdjT7wk4qM3LsYnzJt8mf9jTDdZ+dPBb8bSoq9Fi77Q8QqUfJEX2yuQogOCPNOMuY9+8nt03Ry57cJ+TMljWvS6vVKvRviWLcfo5GNdD/ykvfHcLTI+LdcNDN47sY+e7XwwHZruuMjs/NCi583Yo9hH7weQPD6uzIlyTbseckaj5sLtjB5Y6HrhADkRdS4iz4XC4GnM+T/fznDZA7sHbeS1JdsamAc8fN7zAkPzy6M//NuvAAd3jHWtfYcvBkzv2r5FZo0dIBM/f1Y2r8ugr2ZBP2Wrny9nXN9HCpaqbHpR5XAcFhQMmeSYNE4J9HqR08LQRQz5aDcJ88ZTb0BrudFUr8nqcxfQ9nWLZcHQ7rJ67hBrmM4jgf40+uhzR3z0XoZgXvBkYNpkBNCXqHOvlG3AD4/4RWnz1S9QP1zKvHFhvC36hnJSq+gXBrrlZQpzM4Tgwpux6QH6wmrRE6FsLpEvrfCIHtIH9Kdd9zV+mdJ1w3bRQE8fvQI9ygj0U97PGKDv/KRz3QDhOXIP7Pa64miZ33gWQJ+WRX9ZOwA9d92oCeaniuWpCAZOHCQnY9fN493/g0DPMfCVCafi5sbNHV+U0uUqGYhggJwsCjxusMGCxoi1jI01II84QosGei3TU+LrWPtwG5webU+aWe+cukyHAA91+MsgDPR/L5klQ9/qJCt+/0XfLaPiZOChUJkqck6Hj6RQWe5nhyA4cGwM1I/SmNY86Erg2Elz5Sx0Y2VF8/uH2kIBWgW1wkDPC4j5402XPr9p+QyZNbAdQOR38KL20h+ycddN+x8lK1w3JlOER3hcLOO7buJt0RPoy9Tv5YTy2vEyYgGrqo2+AUC/NI4+elr0lQH0BBI7/8nli8i5Y33sQH/CJe/DdWNPxgYc0AcBOhzo+18Wo0Vf8zo+MFURs8/4+BuwCvAAes5kbrFUix5AvzEDLPrOT46ARV/f9vVDHhr2lMsDPs+1z7/xbHsAPX7BHiRcAKC/ywE9J7da8zhRGqOdj3nyaNH/Z4He6yB/waJyUYs75KwmLaVU2UpuB4wDGJ2kmECMgcScSv6P7Q2ovAWP2DEN6FA9AYGBZZ5OThFgtzqWR5plcDuYe8f1BxbcUbMKnwCcOWag/Pz9u7IzHa8aVgGO8CE7dhbVuaqnHH/m1diOWJCjxV9kbNY9piKUYCqxMtWnU1wA7qyMgnA9WuhKdu1ZdqC/XVvWyvJpH8nvo57B9tIt1ugQj9FAb/J6GSw2xpSDQD+PN2PX/nqIvaW/WTTQR9pTHl34pm4UJElGAX1EKjtflIuBMjIwrz76AY1jct2ccDFdN63Q0g3SMdKdNo7k+S6jjz4t1w1cNjXVdQOghywETiKmgjwItqvF8mrRf5AxQH+vt+ghGEX0AO999gRmogfH8GYMFv0FcN34VyBQl+TJ4AFeY51I/3GL3oZlR+7RLlq8tNQ68yK5tNU9QteOH7rNR6qQ/0LgxAJoVS16q+SAPlJnv6rPgC0C7FRrakBvKte6UDJj/v29dKZM/uY1WTRjtGzesBKVXIfhQRwF6SzYSlr8xHpS68qeGuuKgVy0uHUaOrk5Jg2IU4K70zXrOBcWm9mfNQzahMrpi//71yH4Tmgf2bpqAXzzse/Rd9KkiAj0p90cvb3SX7jdUCAY/2OnFPbRHy1AHxmILV/KvHHhIFk6vF2k6Ain8mHXzUkthylweJ2l1uXODbgZO6BxzEBfuHIrBTRVvmNKgNOAmEkC1bKxMfjoAfQ11KI/Xnl61w15eP+8T++l6yaDgL6TA3p7BQL39ds4NXbgTx3wBvKbMVr0dN3wQmEzWLWneqPueM5YwsN/2nVjw0p5zJY9B3z3V8j5zdpLSQB+fu5zz+I+7oFFHbba2ZrQozQueKcg0hSYtNxdDKAxnfBQnAE44d7aE7jU/eDye/fulc0b18jff8yVqcP6ycIZP8iew/zwE7o6YiFLtpxSqVEbOeXc2yQPXpmQNbt9z5ZK4Zh5oH44i1RPIbq/CHhvi4E666OtNdI2rMc6e7Cj5p8Vc2TR6JewdXJETA9CsedYQgD09NGzgcrgZVeCysJCteh5MzaDLHqqRtesiakLFpJSSJUx/kDfUCpdYUDv5aAsXkYvF2O6buYPjA3oj7+YrpuWbKaBwKxjJ9gpMoHsdLFsXDf5OwaLnkCvN2PVHQKAAyPyUhAN4iTZu2O9/JiBQG9vr+QrDyifbbMMy8k0VfDWc3TdHHzXDS169dGjvl7ctGX0+aGCyZOvQHi8e2tm/1WgbDYj/xWbw9uYgF+qbGWpWKmGVKtzrpxSo7EUKnKcjpzCOsxRwX1eY1fm0x64eDFgmwjdQE/zOPBVyRvwANZCWO2/zx4vK5fMlnUrf8e71Hcd3oHFkVvOfEWl+ElnStlal0mZahfgnfbFtXfVAwcObQTWuWbtYhgpdzpDXaNpI7ix8A6dNYtlxayv8LrhUQD6mbJ35+F51YMK6A5ZsueV4+regW8c8K2d7txREM5+J7+rqk/5rpnVX/ZsW+VJRzzOW7q+FCh/vvZDcSgW5QrSXgIQdqybo+4bTzrScY4CFaRo1bYxdbNn2xpZO/vtmC7StOZzFavqYCnEHmPn8PWgChDZtGSEbPlrcqhSymS2XIWlZI0b4G4spIWqQ7IhPxwwI02voO3fs12WT/9EdvyzIiWjI0xpgPdeFSlRXmXB9cjJRPm8rIidDNMmfClLF808qER8gPSMRs20jtebb5+84Z9L58uYEQOTk9OdJ3+emqM68APk5U+sLtXrNpUqpzXBK5FPkJzYj8+thZmzZIOWcf8blr9NDbPa+eOHA+NLtPjx7L34249H72mx82MY27ZulpXL5gLYJ8j86SNl9bL5ADT9fXBU6+JQhMuWM5+UrtZUytVtIUUq1pHsOfNDX9kD3VFXsKHwB/CHCvQXDvWFC+B+vF+IFzz631cvGCPLf/lMNuIDzbG8xuBQZE20SWggoYHDr4H/BNCHh80rfS68p6Zg4RKSr0BRyV+wGEA/P8ArlwIX9+uzjoI8wIqvQ9iLJ1d3bt8m2/GFJ74mYfPG1bIF7pk9eKOjd0mE+zhm09ALQT9P4TL4SMhxwg95Z8M3cDPjA+SZ8P1bXjB5UeTTvXwtwu7tGxXgt29YDktqFUD/v/sL55g9p4mBJTQQgwb+c0Afw5gSVRIaSGggoYGEBkIaSAB9SBmJZEIDCQ0kNHAsaiAB9MfiWU2MKaGBhAYSGghpIAH0IWUkkgkNJDSQ0MCxqIEE0B+LZzUxpoQGEhpIaCCkgQTQh5SRSCY0kNBAQgPHogYSQH8sntXEmBIaSGggoYGQBhJAH1JGIpnQQEIDCQ0cixpIAP2xeFYTY0poIKGBhAZCGkgAfUgZiWRCAwkNJDRwLGogAfTH4llNjCmhgYQGEhoIaSAB9CFlJJIJDSQ0kNDAsaiBBNAfi2c1MaaEBhIaSGggpIH/A4L0oe9W7rrIAAAAAElFTkSuQmCC)" + ], + "metadata": { + "id": "9naL8y_ie4oG" + } + }, + { + "cell_type": "markdown", + "source": [ + "๐Ÿงก There are two levels of API platforms for Gemini API:\n", + "\n", + "- **Google AI for Developers**: Experiment, prototype, and deploy small projects.\n", + "\n", + "- **Vertex AI**: Build enterprise-ready projects on Google Cloud โœ…\n", + "\n", + "This notebook uses the Vertex AI to explore multimodal use cases with Gemini." + ], + "metadata": { + "id": "41y3sqIJW79s" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "QDU0XJ1xRDlL" + }, + "source": [ + "## Getting Started\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "N5afkyDMSBW5" + }, + "source": [ + "### Install Vertex AI AI SDK and other required packages\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kc4WxYmLSBW5", + "tags": [] + }, + "outputs": [], + "source": [ + "%%capture\n", + "\n", + "!pip install google-cloud-aiplatform" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Authentication" + ], + "metadata": { + "id": "aCFVWORUbuxx" + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JNDLW6CNA7dY" + }, + "outputs": [], + "source": [ + "from google.colab import auth\n", + "\n", + "\n", + "# Authenticate Colab user to Google Cloud\n", + "auth.authenticate_user()\n", + "\n", + "# Define Google Cloud project information\n", + "PROJECT_ID = \"\" # @param {type:\"string\"}\n", + "LOCATION = \"us-central1\" # @param {type:\"string\"}\n", + "\n", + "# Initialize Vertex AI\n", + "import vertexai\n", + "\n", + "vertexai.init(project=PROJECT_ID, location=LOCATION)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### Import libraries" + ], + "metadata": { + "id": "CIJcdXkveAOZ" + } + }, + { + "cell_type": "code", + "source": [ + "import vertexai.generative_models as genai\n", + "\n", + "import PIL.Image\n", + "from IPython.display import display, Markdown, Latex, Image, Audio, Video\n", + "from IPython.core.interactiveshell import InteractiveShell\n", + "\n", + "InteractiveShell.ast_node_interactivity = \"all\"" + ], + "metadata": { + "id": "tczKqvnjMSyA" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Gemini models\n", + "\n", + "The Gemini family of models are the most general and capable AI models we've ever built.\n", + "\n", + "- Ultra โ€” Our largest model for highly complex tasks.\n", + "- Pro โ€” Our best model for general performance across a wide range of tasks.\n", + "- Flash โ€” Our lightweight model, optimized for speed and efficiency\n", + "\n" + ], + "metadata": { + "id": "k6FDFTSMEyeU" + } + }, + { + "cell_type": "markdown", + "source": [ + "### Gemini 1.5 Pro and Gemini 1.5 Flash\n", + "\n", + "- `[Gemini 1.5 Pro](https://ai.google.dev/gemini-api/docs/models/gemini#gemini-1.5-pro): Optimized for complex reasoning tasks such as code and text generation, text editing, problem solving, data extraction and generation\n", + "- [Gemini 1.5 Flash](https://ai.google.dev/gemini-api/docs/models/gemini#gemini-1.5-flash): Fast and versatile performance across a diverse variety of tasks\n", + "\n", + "If you are not sure which model to use, try `gemini-1.5-flash`. `gemini-1.5-flash` is optimized for multimodal use cases where speed and cost are important.\n" + ], + "metadata": { + "id": "FB6fVsHHvA3_" + } + }, + { + "cell_type": "markdown", + "source": [ + "## Use the Gemini API\n", + "\n", + "These are the examples that demonstrate how to prompt a Gemini 1.5 model using the Gemini API." + ], + "metadata": { + "id": "CuG-TrB4_I2W" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "N7rZuTClfNs0" + }, + "source": [ + "#### Gemini 1.5 models\n", + "\n", + "Gemini 1.5 Pro and Gemini 1.5 Flash are multimodal models that support multimodal prompts. Use `GenerativeModel` to load a model.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "2998506fe6d1", + "tags": [] + }, + "outputs": [], + "source": [ + "GEMINI_FLASH_MODEL_ID = \"gemini-1.5-flash\" # @param {type:\"string\"}\n", + "\n", + "model = genai.GenerativeModel(GEMINI_FLASH_MODEL_ID)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "#### Generate content\n", + "\n", + "The `generate_content` method can handle a wide variety of use cases, including multi-turn chat and multimodal input, depending on what the underlying model supports." + ], + "metadata": { + "id": "XtTD01rIqqLN" + } + }, + { + "cell_type": "code", + "source": [ + "response = model.generate_content(\"What is the meaning of life?\")" + ], + "metadata": { + "id": "zqMCBUdyqTVh" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "#### Print model output\n", + "\n", + "In simple cases, the `response.text` accessor is all you need." + ], + "metadata": { + "id": "wbMbHCOyr8nv" + } + }, + { + "cell_type": "code", + "source": [ + "print(response.text)" + ], + "metadata": { + "id": "Jg5rDI6FsBbH" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "You can use `Markdown` to display formatted text." + ], + "metadata": { + "id": "P45hc5CrtUsC" + } + }, + { + "cell_type": "code", + "source": [ + "from IPython.display import Markdown\n", + "\n", + "Markdown(response.text)" + ], + "metadata": { + "id": "TYrE09q6tMrD" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "#### Streaming\n", + "\n", + "By default, the model returns a response after completing the entire generation process. You can also stream the response as it is being generated, and the model will return chunks of the response as soon as they are generated." + ], + "metadata": { + "id": "ahqKlqo0SNon" + } + }, + { + "cell_type": "code", + "source": [ + "response = model.generate_content(\"What is the meaning of life?\", stream=True)" + ], + "metadata": { + "id": "6JCEHzwwabRc" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "for chunk in response:\n", + " print(chunk.text)\n", + " print(\"_\" * 80)" + ], + "metadata": { + "id": "sYxFBoTBad0R" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### Configure model parameters\n", + "\n", + "You learn how to create structured instructions in a prompt and configure the Gemini API with the following configuration options:\n", + "\n", + "- [System instructions](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/prompts/system-instructions)\n", + "- [Generation parameters](https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/inference#parameters)\n", + "- [Safety settings](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/configure-safety-attributes)\n", + "\n", + "In this example, you ask the model to be a role of a travel assistant that helps build itineraries based on a location." + ], + "metadata": { + "id": "oFOMzxuH_Ee8" + } + }, + { + "cell_type": "code", + "source": [ + "from vertexai.generative_models import (\n", + " GenerationConfig,\n", + " HarmCategory,\n", + " HarmBlockThreshold,\n", + " Part\n", + ")\n", + "\n", + "instruction = (\"\"\"\n", + "You are a seasoned travel blogger and guide with a knack for unearthing hidden gems\n", + "and creating unforgettable travel itineraries.\n", + "\n", + "Your task focuses on trip inspiration, detailed planning, and seamless logistics based\n", + "on the location the customer is interested in. Document a potential user journey for\n", + "finding, curating, and utilizing a travel itinerary designed for this specific location.\n", + "\n", + "Format these itinerary into a table with columns Day, Location, Experiences,\n", + "Things to know and The How. The How column describes in detail how to accomplish the\n", + "plan for the experience recommended.\n", + "\"\"\")\n", + "\n", + "# Load a model with system instruction\n", + "model = genai.GenerativeModel(\n", + " model_name=GEMINI_FLASH_MODEL_ID,\n", + " system_instruction=instruction,\n", + ")\n", + "\n", + "# Set generation parameters\n", + "generation_config = GenerationConfig(\n", + " temperature=0.7,\n", + " top_p=1.0,\n", + " top_k=32,\n", + " candidate_count=1,\n", + " max_output_tokens=8192,\n", + ")\n", + "\n", + "# Set safety settings\n", + "safety_settings = {\n", + " HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,\n", + " HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,\n", + " HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,\n", + " HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_LOW_AND_ABOVE,\n", + "}\n" + ], + "metadata": { + "id": "yCnr-ext_W2l" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "prompt = \"\"\"\n", + "Location: Beijing\n", + "Itinerary:\n", + "\"\"\"\n", + "\n", + "# Set contents to send to the model\n", + "contents = [prompt]\n", + "\n", + "# Prompt the model to generate content\n", + "response = model.generate_content(contents,\n", + " generation_config=generation_config,\n", + " safety_settings=safety_settings)\n", + "\n", + "# Print formatted markdown text\n", + "Markdown(response.text)" + ], + "metadata": { + "id": "W8fJsu2Mx3xf" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Multimodal examples\n" + ], + "metadata": { + "id": "FPltGY11r-aW" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0GTyrWHugKFi" + }, + "source": [ + "### ๐Ÿ–ผ๏ธ Image understanding\n", + "\n", + "This example uses the Gemini API to analyze a product sketch (in this case, a drawing of a Jet Backpack), suggests marketing ideas for it.\n", + "\n", + "First, you download the image and load it with PIL:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JgbFtil0gLNf" + }, + "outputs": [], + "source": [ + "productSketchUrl = \"https://storage.googleapis.com/generativeai-downloads/images/jetpack.jpg\"\n", + "!curl -o jetpack.jpg {productSketchUrl}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "0rcYDbcDga8s" + }, + "outputs": [], + "source": [ + "img = PIL.Image.open('jetpack.jpg')\n", + "display(Image('jetpack.jpg', width=500))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "RJyRsfQi0tp6" + }, + "source": [ + "Then you can include the image in our prompt by just passing a list of items to `generate_content`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "UTgRAmEHOaAz" + }, + "outputs": [], + "source": [ + "prompt = \"\"\"This image contains a sketch of a potential product along with some notes.\n", + "Given the product sketch, describe the product as thoroughly as possible based on what you\n", + "see in the image, making sure to note all of the product features. Return output in json format:\n", + "{description: description, features: [feature1, feature2, feature3, etc]}\"\"\"\n", + "\n", + "image_file = Part.from_uri(\n", + " \"gs://generativeai-downloads/images/jetpack.jpg\", \"image/jpeg\"\n", + ")\n", + "\n", + "response = model.generate_content([image_file, prompt])\n", + "print(response.text)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "e873a42810be" + }, + "source": [ + "#### Generate marketing ideas\n", + "\n", + "Now using the image you can use Gemini API to generate marketing names ideas:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "GioGOu5xspug" + }, + "outputs": [], + "source": [ + "prompt = \"\"\"You are a marketing whiz and writer trying to come up with a name for the\n", + "product shown in the image. Come up with ten varied, interesting possible names in Chinese. Return the result\n", + "in array format, like this: ['name 1', 'name 2', ...]. Pay careful attention\n", + "to return a valid array in the format described above, and no other text.\n", + "The most important thing is that you stick to the array format.\"\"\"\n", + "\n", + "response = model.generate_content([image_file, prompt])\n", + "\n", + "names = eval(response.text)\n", + "print(names)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ Try it yourself ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘\n", + "\n", + "**Example images**\n", + "- https://storage.googleapis.com/cloud-samples-data/generative-ai/image/mooncake.png\n", + "- https://storage.googleapis.com/cloud-samples-data/generative-ai/image/a-man-and-a-dog.png\n", + "- https://storage.googleapis.com/cloud-samples-data/generative-ai/image/hurricane-ida.jpeg\n", + "\n", + "**Example prompts**\n", + "- Describe the image in detail in Chinese\n", + "- What is in the image? Tell me some fun facts about it.\n", + "- What is in the image? Write a poem in Shakespearean language in Chinese." + ], + "metadata": { + "id": "zqVa1AUsvycZ" + } + }, + { + "cell_type": "code", + "source": [ + "from urllib.parse import urlparse\n", + "\n", + "def convert_to_gs(url):\n", + " parsed = urlparse(url)\n", + " if parsed.netloc == \"storage.googleapis.com\":\n", + " path = parsed.path.lstrip(\"/\") # Remove leading slash from path\n", + " return f\"gs://{path}\"\n", + " else:\n", + " return url # Return original URL if not a storage.googleapis.com URL\n", + "\n", + "\n", + "your_image_url = \"\" # @param {type:\"string\"}\n", + "\n", + "!curl -o your_image.jpg {your_image_url}\n", + "your_image = PIL.Image.open('your_image.jpg')\n", + "display(Image('your_image.jpg', width=500))\n", + "\n", + "your_prompt = \"\" # @param {type:\"string\"}\n", + "\n", + "\n", + "image_file = Part.from_uri(\n", + " convert_to_gs(your_image_url), \"image/jpeg\"\n", + ")\n", + "\n", + "response = model.generate_content([your_prompt, image_file])\n", + "Markdown(response.text)" + ], + "metadata": { + "cellView": "form", + "id": "sTmK8odSwZrU" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M9IkzwizO6h7" + }, + "source": [ + "### ๐Ÿ“„ PDF and Document Summarization\n", + "\n", + "You can use Gemini to process PDF documents, and analyze content, retain information, and provide answers to queries regarding the documents.\n", + "\n", + "The PDF document example used here is the Gemini 1.5 paper (https://arxiv.org/pdf/2403.05530.pdf).\n", + "\n", + "![image.png](https://storage.googleapis.com/cloud-samples-data/generative-ai/image/gemini1.5-paper-2403.05530.png)" + ] + }, + { + "cell_type": "code", + "source": [ + "file_ref = Part.from_uri(uri = \"gs://cloud-samples-data/generative-ai/pdf/2403.05530.pdf\",\n", + " mime_type=\"application/pdf\")\n", + "\n", + "model.count_tokens([file_ref, 'Can you summarize this file as a bulleted list?'])" + ], + "metadata": { + "id": "6RfaobT8XJR0" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "response = model.generate_content(\n", + " [file_ref, 'Can you summarize this file as a bulleted list?']\n", + ")\n", + "\n", + "Markdown(response.text)" + ], + "metadata": { + "id": "76ClvKCkXUbE" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "### Identify and locate an image in the document" + ], + "metadata": { + "id": "1AcMJSH4a8a4" + } + }, + { + "cell_type": "code", + "source": [ + "!curl -o drawing1.png https://storage.googleapis.com/cloud-samples-data/generative-ai/image/drawing1.png\n", + "drawing = PIL.Image.open('drawing1.png')\n", + "display(Image('drawing1.png', width=200))" + ], + "metadata": { + "id": "a4_S24ujaOzs" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "image_file = Part.from_uri(\n", + " \"gs://cloud-samples-data/generative-ai/image/drawing1.png\", \"image/jpeg\"\n", + ")\n", + "\n", + "response = model.generate_content(\n", + " [file_ref, image_file, 'Find the drawing in the document and explain why the drawing appears there.']\n", + ")\n", + "\n", + "Markdown(response.text)" + ], + "metadata": { + "id": "mmNDbrA_XnW_" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## ๐Ÿ”Š Audio" + ], + "metadata": { + "id": "f6ViwXLbblzN" + } + }, + { + "cell_type": "markdown", + "metadata": { + "id": "h3olx5jGpXCn" + }, + "source": [ + "#### Audio summarization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "t1gnz_4TpD_f" + }, + "outputs": [], + "source": [ + "audio_file_url = \"https://storage.googleapis.com/cloud-samples-data/generative-ai/audio/pixel.mp3\"\n", + "\n", + "!curl -o audio.mp3 {audio_file_url}\n", + "\n", + "Audio(audio_file_url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "fv__QJHjpcKP" + }, + "outputs": [], + "source": [ + "prompt = \"\"\"\n", + " Please provide a short summary and title for the audio.\n", + " Provide chapter titles, be concise and short, no need to provide chapter summaries.\n", + " Provide each of the chapter titles in a numbered list.\n", + " Do not make up any information that is not part of the audio and do not be verbose.\n", + "\"\"\"\n", + "\n", + "audio_file = Part.from_uri(\"gs://cloud-samples-data/generative-ai/audio/pixel.mp3\",\n", + " mime_type=\"audio/mpeg\")\n", + "\n", + "response = model.generate_content(\n", + " [audio_file, prompt]\n", + ")\n", + "\n", + "Markdown(response.text)" + ] + }, + { + "cell_type": "markdown", + "source": [ + "### ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘ Try it yourself ๐Ÿ‘ ๐Ÿ‘ ๐Ÿ‘\n", + "\n", + "**Example audio**\n", + "- https://storage.googleapis.com/cloud-samples-data/generative-ai/audio/audio_summary_clean_energy.mp3\n", + "\n", + "**Example prompts**\n", + "- Transcribe this audio\n", + "- Transcribe this audio and translate it to Chinese" + ], + "metadata": { + "id": "a1h0CzbhdpIy" + } + }, + { + "cell_type": "code", + "source": [ + "your_audio_url = \"\" # @param {type:\"string\"}\n", + "\n", + "!curl -o test.mp3 {your_audio_url}\n", + "Audio(your_audio_url)\n", + "\n", + "your_prompt = \"\" # @param {type:\"string\"}\n", + "\n", + "audio_file = Part.from_uri(convert_to_gs(your_audio_url),\n", + " mime_type=\"audio/mpeg\")\n", + "\n", + "response = model.generate_content(\n", + " [audio_file, your_prompt]\n", + ")\n", + "\n", + "Markdown(response.text)" + ], + "metadata": { + "cellView": "form", + "id": "pqTGKykodFbo" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_U36v4TmswAG" + }, + "source": [ + "## ๐ŸŽฌ Video\n", + "\n", + "Native multimodal and long context capabilities on video interleaving with audio inputs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "EDswcPI0tSRk" + }, + "outputs": [], + "source": [ + "video_file_url = \"https://storage.googleapis.com/cloud-samples-data/generative-ai/video/pixel8.mp4\"\n", + "\n", + "!curl -o video.mp4 {video_file_url}\n", + "Video(video_file_url, width=450)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "R9isZfjzCYxw" + }, + "outputs": [], + "source": [ + "prompt = \"\"\"\n", + "Look through each frame in the video carefully and answer the question.\n", + "Only base your answers strictly on what information is available in the video attached.\n", + "Do not make up any information that is not part of the video and do not be too verbose.\n", + "\n", + "Questions:\n", + "- When does a red lantern first appear and what is written in the lantern? Provide a timestamp.\n", + "- What language is the person speaking and what does the person say at that time?\n", + "\"\"\"\n", + "\n", + "video_file = Part.from_uri(uri = \"gs://cloud-samples-data/generative-ai/video/pixel8.mp4\",\n", + " mime_type=\"video/mp4\")\n", + "\n", + "response = model.generate_content([video_file, prompt])\n", + "\n", + "print(response.text)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "sAO09UUcvL_L" + }, + "source": [ + "## Use Case: retail / e-commerce\n", + "\n", + "The customer shows you their living room:\n", + "\n", + "|Customer photo |\n", + "|:-----:|\n", + "| |\n", + "\n", + "\n", + "\n", + "Below are four wall art options that the customer is trying to decide between:\n", + "\n", + "|Art 1| Art 2 | Art 3 | Art 4 |\n", + "|:-----:|:----:|:-----:|:----:|\n", + "| ||||\n", + "\n", + "\n", + "How can you use Gemini 1.5, a multimodal model, to help the customer choose the best option?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4joag7vswfYw" + }, + "source": [ + "### Generating open recommendations\n", + "\n", + "Using the same image, you can ask the model to recommend a piece of furniture that would make sense in the space.\n", + "\n", + "Note that the model can choose any furniture in this case, and can do so only from its built-in knowledge." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Z82JDCTiwoxB" + }, + "outputs": [], + "source": [ + "# urls for room images\n", + "room_image_url = \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/living-room.png\"\n", + "\n", + "# load room images as Image Objects\n", + "def load_image_from_url(url):\n", + " file_name = url.split('/')[-1]\n", + " !curl -o {file_name} {url}\n", + " return Part.from_uri(convert_to_gs(url), \"image/jpeg\")\n", + "\n", + "room_image = load_image_from_url(room_image_url)\n", + "display(Image(room_image_url.split('/')[-1], width=300))\n", + "\n", + "prompt = \"Describe this room\"\n", + "response = model.generate_content([prompt, room_image])\n", + "Markdown(response.text)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nnSwtNKbxizu" + }, + "outputs": [], + "source": [ + "prompt1 = \"Recommend a new piece of furniture for this room\"\n", + "prompt2 = \"Explain the reason in detail\"\n", + "contents = [prompt1, room_image, prompt2]\n", + "\n", + "response = model.generate_content(contents)\n", + "Markdown(response.text)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "M8XU_0L_xB-_" + }, + "source": [ + "### Generating recommendations based on provided images\n", + "\n", + "Instead of keeping the recommendation open, you can also provide a list of items for the model to choose from. Here, you will download a few art images that the Gemini model can recommend. This is particularly useful for retail companies who want to provide product recommendations to users based on their current setup." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Dd05VvNHxGs1" + }, + "outputs": [], + "source": [ + "# Download and display sample artwork\n", + "art_image_urls = [\n", + " \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/room-art-1.png\",\n", + " \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/room-art-2.png\",\n", + " \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/room-art-3.png\",\n", + " \"https://storage.googleapis.com/cloud-samples-data/generative-ai/image/room-art-4.png\",\n", + "]\n", + "\n", + "\n", + "# Load wall art images as Image Objects\n", + "art_images = [load_image_from_url(url) for url in art_image_urls]" + ] + }, + { + "cell_type": "code", + "source": [ + "# To recommend an item from a selection, you will need to label the item number within the prompt.\n", + "# That way you are providing the model with a way to reference each image as you pose a question.\n", + "# Labeling images within your prompt also helps reduce hallucinations and produce better results.\n", + "prompt = \"\"\"\n", + " You are an interior designer.\n", + " For each piece of wall art, explain whether it would be appropriate for the style of the room.\n", + " Rank each piece according to how well it would be compatible in the room.\n", + "\"\"\"\n", + "contents = [\n", + " \"Consider the following art pieces:\",\n", + " \"art 1:\",\n", + " art_images[0],\n", + " \"art 2:\",\n", + " art_images[1],\n", + " \"art 3:\",\n", + " art_images[2],\n", + " \"art 4:\",\n", + " art_images[3],\n", + " \"room:\",\n", + " room_image,\n", + " prompt,\n", + "]\n", + "\n", + "display(Image(room_image_url.split('/')[-1], width=300))\n", + "print(\"\\n------Art1:-------\")\n", + "display(Image(art_image_urls[0].split('/')[-1], width=300))\n", + "print(\"\\n------Art2:-------\")\n", + "display(Image(art_image_urls[1].split('/')[-1], width=300))\n", + "print(\"\\n------Art3:-------\")\n", + "display(Image(art_image_urls[2].split('/')[-1], width=300))\n", + "print(\"\\n------Art4:-------\")\n", + "display(Image(art_image_urls[3].split('/')[-1], width=300))\n", + "\n", + "response = model.generate_content(contents)\n", + "Markdown(response.text)" + ], + "metadata": { + "id": "6uZYJkLPnWNk" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "print(\"\\nArt2: most appropriate!\")\n", + "display(Image(art_image_urls[1].split('/')[-1], width=300))" + ], + "metadata": { + "id": "S5k7ccJXQCTi" + }, + "execution_count": null, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "## Conclusions\n", + "\n", + "In this session, you've learned how to use Gemini 1.5's native multimodality and long context window capabilities to explore:\n", + "\n", + "- **Single modality**: Working with text, PDF, image, audio and video inputs individually.\n", + "- **Multimodality**: Combining different input types for more complex interactions.\n", + "- **Real-world use case**: A practical e-commerce example to demonstrate Gemini's capabilities.\n", + "\n", + "Next, you can continue to explore more examples on:\n", + "\n", + "- [Gemini API Cookbook](https://github.com/google-gemini/cookbook/)\n", + "- [Vertex AI Generative AI notebook samples](https://github.com/GoogleCloudPlatform/generative-ai)" + ], + "metadata": { + "id": "JZV7sMJ2n9PU" + } + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "Ase31I9QncRp" + }, + "execution_count": null, + "outputs": [] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "environment": { + "kernel": "python3", + "name": "common-cpu.m113", + "type": "gcloud", + "uri": "gcr.io/deeplearning-platform-release/base-cpu:m113" + }, + "kernelspec": { + "display_name": "Python 3", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file