{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
},
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Greybox Fuzzing with Grammars\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"In this chapter, we introduce two important extensions to our syntactic fuzzing techniques:\n",
"\n",
"1. We show how to combine [parsing](Parser.ipynb) and [fuzzing](GrammarFuzzer.ipynb) with grammars. This allows to _mutate_ existing inputs while preserving syntactical correctness, and to _reuse_ fragments from existing inputs while generating new ones. The combination of parsing and fuzzing, as demonstrated in this chapter, has been highly successful in practice: The _LangFuzz_ fuzzer for JavaScript has found more than 2,600 bugs in JavaScript interpreters this way.\n",
"\n",
"2. In the previous chapters, we have used grammars in a _black-box_ manner – that is, we have used them to generate inputs regardless of the program being tested. In this chapter, we introduce mutational _greybox fuzzing with grammars_: Techniques that make use of _feedback from the program under test_ to guide test generations towards specific goals. As in [lexical greybox fuzzing](GreyboxFuzzer.ipynb), this feedback is mostly _coverage_, allowing us to direct grammar-based testing towards uncovered code parts. \n",
"\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"button": false,
"new_sheet": false,
"run_control": {
"read_only": false
},
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"**Prerequisites**\n",
"\n",
"* We build on several concepts from [the chapter on greybox fuzzing (without grammars)](GreyboxFuzzer.ipynb).\n",
"* As the title suggests, you should know how to fuzz with grammars [from the chapter on grammars](Grammars.ipynb)."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Background\n",
"First, we [recall](GreyboxFuzzer.ipynb#Ingredients-for-Greybox-Fuzzing) a few basic ingredients for mutational fuzzers.\n",
"* **Seed**. A _seed_ is an input that is used by the fuzzer to generate new inputs by applying a sequence of mutations.\n",
"* **Mutator**. A _mutator_ implements a set of mutation operators that applied to an input produce a slightly modified input.\n",
"* **PowerSchedule**. A _power schedule_ assigns _energy_ to a seed. A seed with higher energy is fuzzed more often throughout the fuzzing campaign.\n",
"* **MutationFuzzer**. Our _mutational blackbox fuzzer_ generates inputs by mutating seeds in an initial population of inputs.\n",
"* **GreyboxFuzzer**. Our _greybox fuzzer_ dynamically adds inputs to the population of seeds that increased coverage.\n",
"* **FunctionCoverageRunner**. Our _function coverage runner_ collects coverage information for the execution of a given Python function.\n",
"\n",
"Let's try to get a feeling for these concepts."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import fuzzingbook_utils"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"from GreyboxFuzzer import Mutator, Seed, PowerSchedule, MutationFuzzer, GreyboxFuzzer\n",
"from MutationFuzzer import FunctionCoverageRunner"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"The following command applies a mutation to the input \"Hello World\"."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'Lello World'"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Mutator().mutate(\"Hello World\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"The default power schedule assigns energy uniformly across all seeds. Let's check whether this works.\n",
"\n",
"We choose 10k times from a population of three seeds. As we see in the `hits` counter, each seed is chosen about a third of the time."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"{'A': 3411, 'B': 3298, 'C': 3291}"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"population = [Seed(\"A\"), Seed(\"B\"), Seed(\"C\")]\n",
"schedule = PowerSchedule()\n",
"hits = {\n",
" \"A\" : 0,\n",
" \"B\" : 0,\n",
" \"C\" : 0\n",
"}\n",
"\n",
"for i in range(10000):\n",
" seed = schedule.choose(population)\n",
" hits[seed.data] += 1\n",
"\n",
"hits"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"source": [
"Before explaining the function coverage runner, lets import Python's HTML parser as example..."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"from html.parser import HTMLParser"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"... and create a _wrapper function_ that passes each input into a new parser object."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def my_parser(inp):\n",
" parser = HTMLParser()\n",
" parser.feed(inp)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"The `FunctionCoverageRunner` constructor takes a Python `function` to execute. The function `run()` takes an input, passes it on to the Python `function`, and collects the coverage information for this execution. The function `coverage()` returns a list of tuples `(function name, line number)` for each statement that has been covered in the Python `function`."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"[('goahead', 140),\n",
" ('updatepos', 53),\n",
" ('goahead', 245),\n",
" ('handle_data', 448),\n",
" ('goahead', 136)]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"runner = FunctionCoverageRunner(my_parser)\n",
"runner.run(\"Hello World\")\n",
"cov = runner.coverage()\n",
"\n",
"list(cov)[:5] # Print 5 statements covered in HTMLParser"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Our greybox fuzzer takes a seed population, mutator, and power schedule. Let's generate 5000 fuzz inputs starting with an \"empty\" seed corpus."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import time\n",
"import random"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'It took the fuzzer 1.12 seconds to generate and execute 5000 inputs.'"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"n = 5000\n",
"seed_input = \" \" # empty seed\n",
"runner = FunctionCoverageRunner(my_parser)\n",
"fuzzer = GreyboxFuzzer([seed_input], Mutator(), PowerSchedule())\n",
"\n",
"start = time.time()\n",
"fuzzer.runs(runner, trials=n)\n",
"end = time.time()\n",
"\n",
"\"It took the fuzzer %0.2f seconds to generate and execute %d inputs.\" % (end - start, n)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'During this fuzzing campaign, we covered 33 statements.'"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"During this fuzzing campaign, we covered %d statements.\" % len(runner.coverage())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## Building a Keyword Dictionary\n",
"\n",
"To fuzz our HTML parser, it may be useful to inform a mutational fuzzer about important keywords in the input – that is, important HTML keywords. To this end, we extend our mutator to consider keywords from a _dictionary_."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [],
"source": [
"class DictMutator(Mutator):\n",
" def __init__(self, dictionary):\n",
" super().__init__()\n",
" self.dictionary = dictionary\n",
" self.mutators.append(self.insert_from_dictionary)\n",
" \n",
" def insert_from_dictionary(self,s):\n",
" \"\"\"Returns s with a keyword from the dictionary inserted\"\"\"\n",
" pos = random.randint(0, len(s))\n",
" random_keyword = random.choice(self.dictionary)\n",
" return s[:pos] + random_keyword + s[pos:]"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Let's try to add a few HTML tags and attributes and see whether the coverage with `DictMutator` increases."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'It took the fuzzer 10.16 seconds to generate and execute 5000 inputs.'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"runner = FunctionCoverageRunner(my_parser)\n",
"dict_mutator = DictMutator([\"\",\"\",\"\", \"='a'\"])\n",
"dict_fuzzer = GreyboxFuzzer([seed_input], dict_mutator, PowerSchedule())\n",
"\n",
"start = time.time()\n",
"dict_fuzzer.runs(runner, trials = n)\n",
"end = time.time()\n",
"\n",
"\"It took the fuzzer %0.2f seconds to generate and execute %d inputs.\" % (end - start, n)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Clearly, it takes longer. In our experience, this means more code is covered:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"data": {
"text/plain": [
"'During this fuzzing campaign, we covered 89 statements.'"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"\"During this fuzzing campaign, we covered %d statements.\" % len(runner.coverage())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"How do the fuzzers compare in terms of coverage over time?"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"from Coverage import population_coverage"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"slideshow": {
"slide_type": "subslide"
}
},
"outputs": [
{
"data": {
"image/png": "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IokUA8Vm9l74/imCpPKlpDYA4fOaRDaW9r+R7RvhrkOC1w32SvPOnXMus6Q9iZjZF8BKSQeHRacAi4DngRFh2QjguXTHlpBPpgYXGR54Khw+LOponMtYY8eO5e677654P3DgQEaNGlXx/he/+AV33XUXq1atYtiw4G9p3rx5vPTSSxXr/M///A933nlnjfvq1KkThx9+OIcffjiHHnooN9xwA9u3bwfYZftVufvuu9myZUvF+8GDB7N+/frEvmiei+o6kZ8BUyR9CPQEfgvcDpwmaQlwWvi+Rmmf9mTjF8HzwN/68F7nqnHccccxffp4CsYGAAAS30lEQVR0AGKxGF999RULFy6sWD59+nT69etH27Zteeqpp4DvJpHamDZtGvPnz+f999/n008/ZfTo0QC7bL8quyeRl156iebNmycVRyJKS0tTtu10i2SIr5nNAyrr0ziltttKe3NWrCx4blJpv79zGenmFxayaNW3dbrNQ9vuzU3fP6zK5f369WPs2LEALFy4kO7du7N69Wq++eYbGjduzEcffcSRRx7J8uXLOeuss5gzZw433ngjW7du5Z133uH6668HYNGiRfTv358VK1YwZswYrrzyymrjatKkCQ888AAdOnTg66+/5ttvv+Wss85iwYIFlJWVce211/LKK68giUsvvRQzY9WqVQwYMICWLVsybdo0OnXqxKxZs2jZsiV33XUXEydOBGDUqFGMGTOG5cuXM2jQII4//nimT59Ou3bteO6552jUqBF//vOfmTBhAjt27ODAAw/kkUceoXHjxowcOZIWLVowd+5cevbsyYsvvsj06dNp1aoVsViMrl27MnPmTFq2bFlH/0Lp4Ves15aFScSnO3GuWm3btqWwsJAVK1Ywffp0jj32WPr06cOMGTOYNWsWPXr0oEGDnYNTGjRowLhx4zjvvPOYN28e5513HgAff/wxr7zyCu+//z4333wzJSUlNe577733pnPnzixZsmSX8gkTJrBs2TLmzp3Lhx9+yIUXXsiVV15J27ZtmTZtGtOmTdtl/dmzZzNp0iTee+89Zs6cyZ///Gfmzp0LwJIlS7jiiitYuHAhzZs35+mnnwbgnHPO4V//+hcffPABhxxyCA8++GDF9v7973/z2muv8Yc//IGLLrqIKVOmAPDaa69xxBFHZF0CgeguNqwzaR97YrFwx55/XfaorsaQSv369WP69OlMnz6dq666is8//5zp06fTrFkzjjvuuIS2ceaZZ9KwYUMaNmzIfvvtx5dffkn79u1r/JyVX88V57XXXuOyyy6jsDA49bVo0aLabbzzzjv84Ac/YK+9gkE055xzDm+//TZDhgyhc+fO9OzZE4CjjjqK5cuXA7BgwQJuuOEG1q9fz6ZNmxg4cGDF9s4991wKCoIfoJdccglDhw5lzJgxTJw4kYsvvrjmg5GB/ExYW+XNWT5nlnM1Ku8XmT9/Pt27d6dv377MmDGjoj8kEQ0bNqx4XVBQkFB/wsaNG1m+fDldu3bdpdzMajXstbJEVFNcI0eO5L777mP+/PncdNNNu1ynUZ6MADp06EDr1q2ZOnUq7733HoMGDUo4rkyS9Ukk7X0iFTURTyLO1aRfv368+OKLtGjRgoKCAlq0aMH69euZMWMGxx577HfWb9q0KRs3btyjfW7atImf/OQnnH322eyzz65T8J1++uk88MADFSf8r7/+utr9nnjiiTz77LNs2bKFzZs38/e//50TTjih2v1v3LiRNm3aUFJSUtFcVZVRo0Zx0UUX8cMf/rCihpJtsj6JpJ03ZzmXsMMPP5yvvvqKvn377lLWrFmzStv/BwwYwKJFi+jZsydPPPFErfY1YMAAunfvzjHHHEPHjh3505/+9J11Ro0aRceOHenRowdHHHEEjz76KACjR49m0KBBDBgwYJf1e/XqxciRIznmmGPo06cPo0aN4sgjj6w2jltuuYU+ffpw2mmn0a1bt2rXHTJkCJs2bcrapiwAVVddy3QN2xxkz736Nmd03z99O512G7x5O9y0PuKbmThXvY8++ohDDjkk6jBcNWbNmsXYsWN5++23U7aPyv4fSJpdV7N+ZH/HeiTNWfIE4pzbI7fffjvjx4+vsckr03mbTG1ZmTdlOef22HXXXcdnn33G8ccfH3UoeyTrz4Zprw/EynxklnPOhbI+iaSdxXxklnPOhXKgT2QP6yJlJfDQ92FDcWLrb13vzVnOORfK+iSyx7ZtgBUzoF1vaHVwzesD7N8jtTE551yWyPokssd9IrHw6teeF8DRP97TrTnnQmPHjuV73/seY8aMAYKp4Dt06MBf/vIXIJgKvl27dgwfPpwrr7ySp556innz5rFq1SoGDx4MBFPBN2nShKuvvnqP45k8eTKnn346bdu2/c6ykSNH8uabb7L33nuzdetW+vbty2233Ua7du2AYGr4Rx99tMqZfZ999lm6du3KoYceCsCNN97IiSeeyKmnnrrHcWe6rG+X2eORthXTmGR9PnUuo6R7KviaTJ48mVWrVlW5/I477uCDDz5g8eLFHHnkkQwYMIAdO4JbYdc0Nfyzzz7LokWLKt6PGzcupQkkk6aS9zNneU3Ek4jLZS9fB1/Mr9tt7n84DKr6tj+pngq+qinay6d9B7jzzjvZtGkT3bt3Z9asWVx44YU0atSIGTNm0KhRo0rjlsTYsWP5+9//zssvv8zQoUN3mRr+4Ycf5s4770QSPXr04PLLL+f555/nzTff5De/+Q1PP/00t9xyC2eddRbDhg3j9ddf5+qrr6a0tJSjjz6a8ePH07BhQzp16sSIESN44YUXKCkp4W9/+xvdunXj/fffZ8yYMWzdupVGjRoxadIkDj74YCZPnsw//vEPtm3bxubNm2nXrh3Dhg1j6NChAFx44YWcd955DBkypG7+fRPkNZGKJOIjrpyrS6mcCr66KdorM2zYMHr37s2UKVOYN29elQkkXq9evfj44493KVu4cCG33norU6dO5YMPPuCee+7huOOOY8iQIdxxxx3MmzePLl26VKy/bds2Ro4cyRNPPMH8+fMpLS1l/PjxFctbtmzJnDlzuPzyyyvu4NitWzfeeust5s6dy7hx4/jVr35Vsf6MGTN46KGHmDp1KqNGjWLSpEkAbNiwgenTp1c0A6aT//z25iyXD6qpMaRSqqaCr26K9rpS2ZRQU6dOZdiwYRXzftU0lfzixYvp3LlzxWzCI0aM4P7776/oJzrnnHOAYCr5Z555BggSwogRI1iyZAmSdrl/ymmnnVaxz5NOOokrrriCNWvW8Mwzz/Af//EfFVPcp1NkNRFJBZLmSnoxfN9Z0nuSlkh6QlKDmrYBdXB7XPOp3Z1LlVRNBV/VnH+FhYXEYrGK9/HTsNfW3LlzvzPnVF1OJQ87v1v8VPL//d//zYABA1iwYAEvvPBClVPJA/zoRz9iypQpTJo0KbJJHKNszvo58FHc+98BfzCzg4BvgPQMlfI+EedSJlVTwVc1RXvr1q1Zs2YN69atY/v27bz44ou13raZce+997J69WrOOOOMXZadcsopPPnkk6xbtw6oeSr5bt26sXz5cpYuXQrAI488wkknnVTt/jds2FAxKmzy5MnVrjty5EjuvvtuAA47LJobj0Vy5pTUHjgTuBW4SkFqPxm4IFzlIeB/gPGVbiB0kIo55qVB8PoefI2SrWFQXhNxrq6VTwV/wQUX7FK2adOmKqeCv/322+nZs2dFx3pl4qdoB3aZov3GG2+kT58+dO7ceZep2EeOHMlll11WZcf6Nddcwy233MKWLVvo27cv06ZN26XPBoIT9a9//WtOOukkCgoKOPLII5k8eTLDhw/n0ksv5d57760YaQZQVFTEpEmTOPfccys61i+77LJqj9kvf/lLRowYwV133cXJJ59c7bqtW7fmkEMO4eyzz652vVSKZCp4SU8BtwFNgauBkcBMMzswXN4BeNnMulfy2dHAaICD2zQ96sM7h9CgcA8rVPX3gtN/A3vtu2fbcS6D+FTwuW/Lli0cfvjhzJkzh2bNmlW6Ts5NBS/pLGCNmc2W1L+8uJJVK81uZjYBmADQu3dva3DBX1MSp3POZbLXXnuNSy65hKuuuqrKBJIOUTRn9QOGSBoMFAF7A3cDzSUVmlkp0B6o+qog55zLc6eeeiorVqyIOoz0d6yb2fVm1t7MOgHDgalmdiEwDRgWrjYCeC7dsTmXa7L5zqVuz6Xj3z+TLja8lqCTfSmwL/BgxPE4l9WKiopYt26dJ5I8ZWasW7eOoqKilO4n0nGtZvYG8Eb4+lPgmCjjcS6XtG/fnuLiYtauXRt1KC4iRUVFtG/fPqX78IsjnMtR9evXp3PnzlGH4XJcJjVnOeecyzKeRJxzziXNk4hzzrmkRXLFel2RtBFYHHUcGaIl8FXUQWQIPxY7+bHYyY/FTgebWdO62FC2d6wvrqtL97OdpFl+LAJ+LHbyY7GTH4udJM2qq215c5ZzzrmkeRJxzjmXtGxPIhOiDiCD+LHYyY/FTn4sdvJjsVOdHYus7lh3zjkXrWyviTjnnIuQJxHnnHNJy9okIukMSYslLZV0XdTxpIKkiZLWSFoQV9ZC0quSloTP+4TlknRveDw+lNQr7jMjwvWXSBoRxXfZE5I6SJom6SNJCyX9PCzPx2NRJOl9SR+Ex+LmsLyzpPfC7/WEpAZhecPw/dJweae4bV0fli+WNDCab7TnJBVImivpxfB9Xh4LScslzZc0r3wIb1r+Rsws6x5AAfAJcADQAPgAODTquFLwPU8EegEL4sp+D1wXvr4O+F34ejDwMsFdIvsC74XlLYBPw+d9wtf7RP3dankc2gC9wtdNgX8Dh+bpsRDQJHxdH3gv/I5PAsPD8geAy8PXPwEeCF8PB54IXx8a/t00BDqHf08FUX+/JI/JVcCjwIvh+7w8FsByoOVuZSn/G8nWmsgxwFIz+9TMdgCPA0MjjqnOmdlbwNe7FQ8FHgpfPwScHVf+sAVmEtwpsg0wEHjVzL42s2+AV4EzUh993TGz1WY2J3y9EfgIaEd+Hgszs03h2/rhw4CTgafC8t2PRfkxego4RZLC8sfNbLuZLQOWkoW3YpDUHjgT+Ev4XuTpsahCyv9GsjWJtANWxr0vDsvyQWszWw3ByRXYLyyv6pjk1LEKmyCOJPgFnpfHImy+mQesIfgj/wRYb8GtpWHX71XxncPlGwhu+pYTx4Lg1tq/BGLh+33J32NhwP9Jmi1pdFiW8r+RbJ32RJWU5ftY5aqOSc4cK0lNgKeBMWb2bfAjsvJVKynLmWNhZmVAT0nNgb8Dh1S2Wvics8dC0lnAGjObLal/eXElq+b8sQj1M7NVkvYDXpX0cTXr1tmxyNaaSDHQIe59e2BVRLGk25dhtZPweU1YXtUxyYljJak+QQKZYmbPhMV5eSzKmdl6gjuD9iVojij/URj/vSq+c7i8GUETaS4ci37AEEnLCZq0TyaomeTjscDMVoXPawh+XBxDGv5GsjWJ/As4KByF0YCgk+z5iGNKl+eB8hETI4Dn4sr/Mxx10RfYEFZfXwFOl7RPODLj9LAsa4Tt1g8CH5nZXXGL8vFYtAprIEhqBJxK0Ec0DRgWrrb7sSg/RsOAqRb0oD4PDA9HLHUGDgLeT8+3qBtmdr2ZtTezTgTngKlmdiF5eCwk7SWpaflrgv/bC0jH30jUIwr2YCTCYIJROp8Av446nhR9x8eA1UAJwS+EHxO04b4OLAmfW4TrCrg/PB7zgd5x27mEoLNwKXBx1N8rieNwPEGV+kNgXvgYnKfHogcwNzwWC4Abw/IDCE58S4G/AQ3D8qLw/dJw+QFx2/p1eIwWA4Oi/m57eFz6s3N0Vt4di/A7fxA+FpafE9PxN+LTnjjnnEtatjZnOeecywCeRJxzziXNk4hzzrmkeRJxzjmXNE8izjnnkuZJxOUlSbdJ6i/pbNVyFujwWo33wpljT9ht2V8kHVq30YKkX9X1Np2rCz7E1+UlSVMJJu77LfCUmb1bi88OJ7iWIG1TyUvaZGZN0rU/5xLlNRGXVyTdIelD4GhgBjAKGC/pxkrW/Z6k18P7LbwuqaOkngTTaw8O79vQaLfPvCGpd/h6k6RbFdz7Y6ak1mH5ZEkPSHpb0r/DOaCQNFLSfXHbejGsLd0ONAr3NyW8Ovkf4XYXSDovRYfLuRp5EnF5xcyuIUgckwkSyYdm1sPMxlWy+n0E02X3AKYA95rZPOBGgntR9DSzrdXsbi9gppkdAbwFXBq3rBNwEkFt6AFJRdXEfB2wNdzfhQRTc68ysyPMrDvwz0S+u3Op4EnE5aMjCaZO6QYsqma9YwludgTwCMH0K7WxA3gxfD2bIHGUe9LMYma2hODGP91qsd35wKmSfifpBDPbUMu4nKsz2ToVvHO1FjZFTSaYmfQroHFQrHnAsTXUKqD204OX2M5OxzJ2/XvbfVsGlLLrD7tKaydm9m9JRxHMH3abpP+roiblXMp5TcTlDTObZ2Y92Xl73anAwGqapaYTzA4LcCHwTh2Gc66kepK6EEyet5jg9qY9w/IO7Hp3vZJwOnwktQW2mNlfgTsJbqHsXCS8JuLyiqRWwDdmFpPUzcyqa866Epgo6RpgLXBxHYayGHgTaA1cZmbbJL0LLCNorloAzIlbfwLwoaQ5wMPAHZJiBDM8X16HcTlXKz7E17k0kzSZYNryp2pa17lM581ZzjnnkuY1Eeecc0nzmohzzrmkeRJxzjmXNE8izjnnkuZJxDnnXNI8iTjnnEva/wOn0hcA/nUC2AAAAABJRU5ErkJggg==\n",
"text/plain": [
"