From b327f631a71993de11e1f18331e7977e59a49c28 Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 10 May 2024 20:36:58 +0200 Subject: [PATCH 01/27] First steps with Idefics and a general experimentation workflow --- .gitignore | 9 +- _testbed/README.md | 55 + _testbed/experiments.ipynb | 6810 +++++++++++++++++++++++++++++++++ _testbed/experiments.py | 1995 ++++++++++ _testbed/helpers.ipynb | 835 ++++ _testbed/helpers.py | 372 ++ _testbed/ocr_idefics.py | 184 + _testbed/ocr_metric.ipynb | 276 ++ _testbed/ocr_metric.py | 64 + _testbed/requirements.txt | 5 + _testbed/test_idefics.ipynb | 1497 ++++++++ _testbed/test_tesseract.ipynb | 638 +++ 12 files changed, 12735 insertions(+), 5 deletions(-) create mode 100644 _testbed/README.md create mode 100644 _testbed/experiments.ipynb create mode 100644 _testbed/experiments.py create mode 100644 _testbed/helpers.ipynb create mode 100644 _testbed/helpers.py create mode 100644 _testbed/ocr_idefics.py create mode 100644 _testbed/ocr_metric.ipynb create mode 100644 _testbed/ocr_metric.py create mode 100644 _testbed/requirements.txt create mode 100644 _testbed/test_idefics.ipynb create mode 100644 _testbed/test_tesseract.ipynb diff --git a/.gitignore b/.gitignore index c94304f9..8fc7b143 100644 --- a/.gitignore +++ b/.gitignore @@ -167,9 +167,8 @@ cython_debug/ .idea/ *.sh -_testbed/cleaner/ -*/_testbed/experiment/cache/** -*/_testbed/experiment/source/** - -!.gitkeep \ No newline at end of file +.DS_Store +_testbed/media/** +_testbed/cleaner/** +_testbed/model/** diff --git a/_testbed/README.md b/_testbed/README.md new file mode 100644 index 00000000..702df030 --- /dev/null +++ b/_testbed/README.md @@ -0,0 +1,55 @@ +# PanelCleaner Testbed + +## Overview +The **PanelCleaner** testbed serves as a dedicated area for experimenting and testing new ideas with *PanelCleaner* using Jupyter Notebooks. Currently, it focuses on **OCR** technologies, primarily using **Tesseract** and **IDefics** models. The testbed also begins the development of an evaluation framework to support future experiments. This project utilizes the `nbdev` literate programming environment. + +## Installation +To get started with the notebooks, you'll need Jupyter Lab/Notebook or any Python IDE that supports Jupyter notebooks like *VSCode* or *Google Colab*. +The setup mostly shares the same requirements as PanelCleaner and its CLI, with a few additional dependencies. +Here’s how to set up your environment: +1. Activate a virtual environment. +2. Navigate to the `_testbed` directory: + ```bash + cd _testbed + ``` +3. Install the required dependencies: + ```bash + pip install -r requirements.txt + ``` +Note: Each notebook may require the installation of additional dependencies. + +## Google Colab Support +The notebooks are ready to use on Google Colab, allowing you to run them directly on the platform without any extra setup or local GPU rigs. +Instructions to use Google Colab are included in the notebooks (TBD). + +## Install Test Images +The test images are not included in the repository but can be downloaded from the following link: +- [Test images](https://drive.google.com/drive/folders/101_1_20240229) + +After downloading, place the test images in the [media](media) directory. If you want to use your own, each image should have a corresponding text file with the same name, but with the extension `.txt`, which contains the ground truth data, one line per box (as calculated by PanelCleaner). Optionally, you can also include a `.json` file with the same name, specifying the language of the page: +```json +{ + "lang": "Spanish" +} +``` +If no language file is found, English will be used by default. In the near future, language detection will be automated. + +## Introduction to nbdev +[nbdev](https://nbdev.fast.ai/) is a **literate programming** environment that allows you to develop a Python library in Jupyter Notebooks, integrating exploratory programming, code, tests, and documentation into a single cohesive workflow. Inspired by **Donald Knuth**'s concept of literate programming, this approach not only makes the development process more intuitive but also eases the maintenance and understanding of the codebase. + +## Notebooks (WIP) + +#### [helpers.ipynb](helpers.ipynb) +This notebook includes utility functions and helpers that support the experiments in other notebooks, streamlining repetitive tasks and data manipulation. + +#### [ocr_metric.ipynb](ocr_metric.ipynb) +This notebook focuses on defining and implementing metrics to evaluate the performance and accuracy of OCR engines, crucial for assessing the effectiveness of OCR technologies in various scenarios. It currently develops a basic metric for evaluating OCR models. In the near future, additional metrics will be added, such as precision and recall using Levenshtein distance (edit distance). More importantly, it will introduce a metric tailored to the unique characteristics of Comics/Manga OCR, a topic currently unexplored in technical literature. + +#### [experiments.ipynb](experiments.ipynb) +This notebook details the development of the evaluation framework used in other notebooks, with Tesseract as a case study to illustrate the evaluation process. It's a work in progress, and will be updated continuously. If you're only interested in visualizing the results of the experiments, go directly to `Test_tesseract.ipynb` or `Test_idefics.ipynb`, which are much shorter and more to the point. + +#### [test_tesseract.ipynb](test_tesseract.ipynb) +This notebook is dedicated to testing the Tesseract OCR engine, offering insights into its capabilities and limitations through hands-on experiments. + +#### [test_idefics.ipynb](test_idefics.ipynb) +Similar to `test_tesseract.ipynb`, this notebook focuses on the IDefics LVM model, evaluating its performance and accuracy under different conditions. Here you can compare the results of the Tesseract OCR engine with the IDefics LVM model to see how the two compare in terms of accuracy and performance. diff --git a/_testbed/experiments.ipynb b/_testbed/experiments.ipynb new file mode 100644 index 00000000..6c8d3c81 --- /dev/null +++ b/_testbed/experiments.ipynb @@ -0,0 +1,6810 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#| default_exp experiments" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "# %reload_ext autoreload\n", + "# %autoreload 0\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# try: \n", + "# import fastcore as FC\n", + "# except ImportError: \n", + "# !pip install -q fastcore\n", + "# try:\n", + "# import rich\n", + "# except ImportError:\n", + "# !pip install -q rich\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note: we're using the `testbed` branch of PanelCleaner.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `Tesseract` OCR for Comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "from __future__ import annotations\n", + "\n", + "import dataclasses\n", + "import difflib\n", + "import functools\n", + "import json\n", + "import shutil\n", + "from collections import defaultdict\n", + "from enum import Enum\n", + "from pathlib import Path\n", + "from typing import Any\n", + "from typing import Callable\n", + "from typing import cast\n", + "from typing import Mapping\n", + "from typing import Self\n", + "from typing import TypeAlias\n", + "\n", + "import fastcore.all as FC\n", + "import ipywidgets as W\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import pcleaner.config as cfg\n", + "import pcleaner.ctd_interface as ctm\n", + "import pcleaner.image_ops as ops\n", + "import pcleaner.ocr.ocr as ocr\n", + "import pcleaner.structures as st\n", + "import torch\n", + "from IPython.display import clear_output\n", + "from IPython.display import display\n", + "from IPython.display import HTML\n", + "from ipywidgets.widgets.interaction import show_inline_matplotlib_plots\n", + "from loguru import logger\n", + "from pcleaner.ocr.ocr_tesseract import TesseractOcr\n", + "from PIL import Image\n", + "from PIL import ImageFilter\n", + "from rich.console import Console\n", + "from tqdm.notebook import tqdm\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "from helpers import *\n", + "from ocr_metric import *\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "import copy\n", + "\n", + "import fastcore.xtras # patch Path with some utils\n", + "import pcleaner.cli_utils as cli\n", + "import pcleaner.preprocessor as pp\n", + "import rich\n", + "from fastcore.test import * # type: ignore\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# pretty print by default\n", + "# %load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "console = Console(width=104, tab_size=4, force_jupyter=True)\n", + "cprint = console.print\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tesseract installation" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['tesseract 5.3.4',\n", + " ' leptonica-1.84.1',\n", + " ' libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp 1.4.0 : libopenjp2 2.5.2',\n", + " ' Found NEON',\n", + " ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n", + " ' Found libcurl/8.4.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.11 nghttp2/1.51.0']" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out = !tesseract --version\n", + "out\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install jpn_vert tesserac lang\n", + "> It has much better results than the default `jpn` language model.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "\n", + "Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best), or from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) trained for vertical Japanese text as found in manga.\n", + "\n", + "Note: I've not play much with this one, `managa-ocr` is surely a much better fit, but it can be educational to compare.\n", + "\n", + "I have copied models in my GDrive, and installed (in my Ubuntu, similar in Mac):\n", + "```bash\n", + "cd model\n", + "ln -s jpn_vert_tessdata_best.traineddata /usr/share/tesseract-ocr/5/tessdata/jpn_vert.traineddata\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(Path('/opt/homebrew/share/tessdata'),\n", + " ['afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n", + " 'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n", + " 'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n", + " 'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n", + " 'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n", + " 'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n", + " 'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n", + " 'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, script/Kannada, script/Khmer',\n", + " 'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n", + " 'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n", + " 'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out = !tesseract --list-langs\n", + "tessdata = Path(out[0].split('\"')[1])\n", + "tessdata, [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n",
+       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'),\n",
+       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'),\n",
+       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata')\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "langs = tessdata.ls()\n", + "cprint([p.resolve() for p in langs if 'eng' in p.name] + [p.resolve() for p in langs if 'jpn' in p.name])\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OCR results clean-up" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def remove_multiple_whitespaces(text):\n", + " return ' '.join(text.split())\n", + "\n", + " \n", + "def postprocess_ocr(text):\n", + " \"Basic postprocessing for English Tesseract OCR results.\"\n", + " return ' '.join(remove_multiple_whitespaces(text).splitlines()).capitalize()\n", + "\n", + "def accuracy_ocr_naive(text, ground_truth):\n", + " return sum(1 for a, b in zip(text, ground_truth) if a == b) / len(text)\n", + "\n", + "\n", + "def accuracy_ocr_difflib(text, ground_truth):\n", + " \"\"\"\n", + " Calculates the OCR accuracy based on the similarity between the OCR text and the ground truth text,\n", + " using difflib's SequenceMatcher to account for differences in a manner similar to git diffs.\n", + "\n", + " :param text: The OCR-generated text.\n", + " :param ground_truth: The ground truth text.\n", + " :return: A float representing the similarity ratio between the OCR text and the ground truth, \n", + " where 1.0 is identical.\n", + " \"\"\"\n", + " # Initialize the SequenceMatcher with the OCR text and the ground truth\n", + " matcher = difflib.SequenceMatcher(None, text, ground_truth)\n", + " \n", + " # Get the similarity ratio\n", + " similarity_ratio = matcher.ratio()\n", + " \n", + " return similarity_ratio" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ground truth" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def ground_truth_path(page_data: st.PageData):\n", + " path = Path(page_data.original_path)\n", + " return path.with_stem(path.stem + '_gt').with_suffix('.txt')\n", + "\n", + "\n", + "def read_ground_truth(page_data: st.PageData):\n", + " gts_path = ground_truth_path(page_data)\n", + " if gts_path.exists():\n", + " gts = gts_path.read_text(encoding=\"utf-8\").splitlines()\n", + " else:\n", + " gts = [\"\" for _ in range(len(page_data.boxes))]\n", + " return gts\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cropping" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def dilate_by_fractional_pixel(image, dilation_fraction, filter_base_size=3):\n", + " \"\"\"\n", + " Dilates an image by a specified fractional pixel amount. The function calculates \n", + " the necessary scaling factor and filter size based on the desired dilation fraction.\n", + "\n", + " :param image: A PIL Image object (1-bit mode).\n", + " :param dilation_fraction: The desired fractional pixel amount for dilation (e.g., 0.2).\n", + " :param filter_base_size: The base size of the dilation filter to apply on the scaled image.\n", + " This size is adjusted based on the scaling factor to achieve the\n", + " desired dilation effect.\n", + " :return: A PIL Image object after dilation, converted back to grayscale.\n", + " \"\"\"\n", + " # Calculate the scale factor based on the desired dilation fraction\n", + " scale_factor = int(1 / dilation_fraction)\n", + " \n", + " # Adjust the filter size based on the scale factor\n", + " # This ensures the dilation effect is proportional to the desired fraction\n", + " filter_size = max(1, filter_base_size * scale_factor // 5)\n", + "\n", + " # Convert the image to grayscale for more nuanced intermediate values\n", + " image_gray = image.convert(\"L\")\n", + "\n", + " # Resize the image to a larger size using bicubic interpolation\n", + " larger_size = (int(image.width * scale_factor), int(image.height * scale_factor))\n", + " image_resized = image_gray.resize(larger_size, Image.BICUBIC)\n", + "\n", + " # Apply the dilation filter to the resized image\n", + " dilated_image = image_resized.filter(ImageFilter.MaxFilter(filter_size))\n", + "\n", + " # Resize the image back to its original size using bicubic interpolation\n", + " image_dilated_fractional_pixel = dilated_image.resize(image.size, Image.BICUBIC)\n", + "\n", + " return image_dilated_fractional_pixel\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def extract_text(image, text_mask, box):\n", + " cropped_image = crop_box(box, image)\n", + " cropped_mask = crop_box(box, text_mask)\n", + " extracted = ops.extract_text(cropped_image, cropped_mask)\n", + " return cropped_image, cropped_mask, extracted\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lang\n", + "> language name to a language code \n", + "> every one has language codes: tesseract, comic-text-detector, earthlings...\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "_lang2pcleaner = {'English': st.DetectedLang.ENG, 'Japanese': st.DetectedLang.JA, 'Spanish': st.DetectedLang.ENG,\n", + " 'French':st.DetectedLang.ENG}\n", + "# _lang2tesseract = {'English': 'eng', 'Japanese': 'jpn'}\n", + "_lang2tesseract = {'English': 'eng', 'Japanese': 'jpn_vert', 'Spanish': 'spa', 'French': 'fra'}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "def lang2pcleaner(lang: str):\n", + " return _lang2pcleaner[lang]\n", + "\n", + "def lang2tesseract(lang: str):\n", + " return _lang2tesseract[lang]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Tesseract experiments" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PanelCleaner Configuration\n", + "> Adapt `PanelCleaner` `Config` current config to this notebook.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "config = cfg.load_config()\n", + "config.cache_dir = Path(\".\")\n", + "\n", + "cache_dir = config.get_cleaner_cache_dir()\n", + "\n", + "profile = config.current_profile\n", + "preprocessor_conf = profile.preprocessor\n", + "# Modify the profile to OCR all boxes.\n", + "# Make sure OCR is enabled.\n", + "preprocessor_conf.ocr_enabled = True\n", + "# Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", + "preprocessor_conf.ocr_max_size = 10**10\n", + "# Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", + "preprocessor_conf.suspicious_box_min_size = 10**10\n", + "# Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", + "preprocessor_conf.ocr_blacklist_pattern = \".*\"\n", + "\n", + "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + "model_path = config.get_model_path(gpu)\n", + "device = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n", + "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "media_path = Path(\"media/\")\n", + "\n", + "IMAGE_PATHS = sorted(\n", + " [_ for _ in media_path.glob(\"*\") if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n", + "\n", + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Results helper\n", + "> Dataclass helper to store and display results\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "@dataclasses.dataclass\n", + "class ResultOCR:\n", + " block_idx: int\n", + " image: Image.Image | None\n", + " ocr: str\n", + " page_data: st.PageData\n", + " gts: list[str]\n", + " description: str = dataclasses.field(default='', kw_only=True)\n", + "\n", + " def __post_init__(self): \n", + " if self.image is None:\n", + " cache_path = self.cache_path()\n", + " if cache_path.exists():\n", + " self.image = Image.open(cache_path)\n", + "\n", + " @property\n", + " def acc(self):\n", + " self._acc = accuracy_ocr_difflib(self.ocr, self.gts[self.block_idx])\n", + " return self._acc\n", + " @property\n", + " def suffix(self): return f\"{self.block_idx}_{self.description}\"\n", + "\n", + " def diff_tagged(self):\n", + " _, html2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr, False)\n", + " return f\"{html2}\"\n", + " \n", + " def cache_path(self, suffix: str | None = None):\n", + " suffix = self.suffix + (('_'+suffix) if suffix else '')\n", + " parent = Path(self.page_data.image_path).parent\n", + " img_name = Path(self.page_data.original_path).stem\n", + " box_image_path = parent / f\"{img_name}_{suffix}.png\"\n", + " return box_image_path\n", + " \n", + " def cache_image(self, image: Image.Image | None = None, suffix: str | None = None):\n", + " image = image or (self.image if not suffix else None)\n", + " box_image_path = self.cache_path(suffix)\n", + " if image and not box_image_path.exists():\n", + " image.save(box_image_path)\n", + " return box_image_path\n", + "\n", + "\n", + " def as_html(self):\n", + " acc_html = f\"
{self.acc:.2f}\"\n", + " box_image_path = self.cache_image()\n", + " html1 = get_columns_html([[box_image_path], [self.ocr + acc_html]])\n", + " html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr)\n", + " html2 = f\"
{html_str1}
{html_str2}
\"\n", + " return html1 + '\\n
\\n' + html2\n", + "\n", + " def __repr__(self): \n", + " return f\"{type(self).__name__}#block {self.block_idx:02}: {self.acc:.2f}||{self.ocr}\"\n", + " \n", + " def display(self): display(HTML(self.as_html()))\n", + " \n", + " def _ipython_display_(self): self.display()\n", + "\n", + " def to_dict(self):\n", + " d = dataclasses.asdict(self)\n", + " d['image'] = d['page_data'] = d['gts'] = None\n", + " return d\n", + "\n", + " # @classmethod\n", + " # def from_dict(cls, d: dict, page_data: st.PageData, gts: list[str]):\n", + " # return cls(**(d | {'page_data':page_data, 'gts':gts}))\n", + "\n", + "\n", + "@dataclasses.dataclass\n", + "class ResultOCRExtracted(ResultOCR):\n", + "\n", + " def __repr__(self): return super().__repr__()\n", + " def as_html(self):\n", + " html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr)\n", + " diff_html = f\"
{html_str1}
{html_str2}
\"\n", + " cropped_image_path = self.cache_image(None, \"cropped\")\n", + " cropped_mask_path = self.cache_image(None, \"mask\")\n", + " result_path = self.cache_image()\n", + " return '\\n
\\n'.join([\n", + " get_image_grid_html([cropped_image_path, cropped_mask_path, result_path], 1, 3), \n", + " acc_as_html(self.acc), \n", + " diff_html\n", + " ])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CropMethod\n", + "> Box cropping methods.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class CropMethod(Enum):\n", + " INITIAL_BOX = 'Initial box'\n", + " DEFAULT = 'Default'\n", + " DEFAULT_GREY_PAD = 'Default, grey pad'\n", + " PADDED_4 = 'Padded 4px'\n", + " PADDED_8 = 'Padded 8px'\n", + " EXTRACTED_INIT_BOX = 'Extracted, init box'\n", + " PADDED_4_EXTRACTED = 'Padded 4, extracted'\n", + " PADDED_8_EXTRACTED = 'Padded 8, extracted'\n", + " PADDED_8_DILATION_1 = 'Padded 8, dilation 1'\n", + " PAD_8_FRACT_0_5 = 'Pad 8, fract. 0.5'\n", + " PAD_8_FRACT_0_2 = 'Pad 8, fract. 0.2'\n", + "\n", + " @classmethod\n", + " def __display_names__(cls):\n", + " return dict(\n", + " zip([_.value for _ in cls], \n", + " cls))\n", + "\n", + "\n", + "CM = CropMethod\n", + "\n", + "_IMAGE_METHODS = [CM.INITIAL_BOX, CM.DEFAULT, CM.DEFAULT_GREY_PAD, \n", + " CM.PADDED_4, CM.PADDED_8]\n", + "_EXTRACTED_METHODS = [CM.EXTRACTED_INIT_BOX, CM.PADDED_4_EXTRACTED, \n", + " CM.PADDED_8_EXTRACTED, CM.PADDED_8_DILATION_1, \n", + " CM.PAD_8_FRACT_0_5, CM.PAD_8_FRACT_0_2]\n", + "\n", + "\n", + "def crop_by_image(method: CM, \n", + " box: st.Box, \n", + " base: Image.Image, \n", + " preproc: cfg.PreprocessorConfig,\n", + " ):\n", + " image = None\n", + " match method:\n", + " case CM.INITIAL_BOX :\n", + " image = crop_box(box, base)\n", + " case CM.DEFAULT:\n", + " padded2_4 = (\n", + " box.pad(preproc.box_padding_initial, base.size).right_pad(\n", + " preproc.box_right_padding_initial, base.size))\n", + " image = crop_box(padded2_4, base)\n", + " case CM.DEFAULT_GREY_PAD:\n", + " image = crop_box(box, base)\n", + " image = ops.pad_image(image, 8, fill_color=(128, 128, 128))\n", + " case CM.PADDED_4:\n", + " padded4 = box.pad(4, base.size)\n", + " image = crop_box(padded4, base)\n", + " case CM.PADDED_8:\n", + " padded4 = box.pad(8, base.size)\n", + " image = crop_box(padded4, base)\n", + " case _: pass\n", + " return image\n", + "\n", + "\n", + "def crop_by_extracted(method: CM, \n", + " box: st.Box, \n", + " base: Image.Image, \n", + " mask: Image.Image,\n", + " cropped_image_path: Path,\n", + " cropped_mask_path: Path,\n", + " dilated: dict[float, Image.Image]\n", + " ):\n", + " cropped_image, cropped_mask, image = None, None, None\n", + " if method in _EXTRACTED_METHODS:\n", + " if not cropped_image_path.exists() or not cropped_mask_path.exists():\n", + " match method:\n", + " case CM.EXTRACTED_INIT_BOX:\n", + " cropped_image, cropped_mask, image = extract_text(base, mask, box)\n", + " case CM.PADDED_4_EXTRACTED:\n", + " padded4 = box.pad(4, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(base, mask, padded4)\n", + " case CM.PADDED_8_EXTRACTED:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(base, mask, padded8)\n", + " case CM.PADDED_8_DILATION_1:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(\n", + " base, dilated[1], padded8)\n", + " case CM.PAD_8_FRACT_0_5:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(\n", + " base, dilated[0.5], padded8)\n", + " case CM.PAD_8_FRACT_0_2:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(\n", + " base, dilated[0.2], padded8)\n", + " case _: pass\n", + "\n", + " return image, cropped_image, cropped_mask\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ResultSet\n", + "> tagged nested dict to store image results keyed by box, and crop method\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "SubjIdT: TypeAlias = int\n", + "ImgIdT = SubjIdT\n", + "BoxIdT: TypeAlias = int\n", + "\n", + "class ResultSet(dict[BoxIdT, dict[CropMethod, ResultOCR]]): ...\n", + "\n", + "class ResultSetDefault(defaultdict[BoxIdT, dict[CropMethod, ResultOCR]]): ...\n", + "\n", + "def results_to_dict(results: ResultSet) -> dict[BoxIdT, dict[str, str]]:\n", + " d = {}\n", + " for box, box_methods in results.items():\n", + " for method, result in box_methods.items():\n", + " if box not in d:\n", + " d[box] = {}\n", + " d[box][method.name] = result.ocr\n", + " return d\n", + "\n", + "def dict_to_results(\n", + " image_idx: ImgIdT, \n", + " results_dict: dict[BoxIdT, dict[str, str]],\n", + " result_factory: Callable\n", + " ) -> ResultSetDefault:\n", + " results = ResultSetDefault(dict[CropMethod, ResultOCR])\n", + " for box_idx, box_methods in results_dict.items():\n", + " box_idx = int(box_idx)\n", + " for method, ocr in box_methods.items():\n", + " m = CM[method]\n", + " results[box_idx][m] = result_factory(image_idx, box_idx, m, ocr)\n", + " return results\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ExperimentContext\n", + "> Utility class to maintain shared state across all experiments.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "# class ExperimentSubject(Protocol):\n", + "# @property\n", + "# def exp(self) -> 'ExperimentContext': ...\n", + "# @property\n", + "# def idx(self) -> SubjIdT: ...\n", + "# def setup(self,\n", + "# exp: 'ExperimentContext',\n", + "# idx: Any,\n", + "# *args, **kwargs\n", + "# ): ...\n", + "\n", + "\n", + "# class ExperimentContext(Protocol):\n", + "# def subject_factory(self) -> Callable[..., ExperimentSubject]: ...\n", + "# def normalize_idx(self, idx: Any) -> SubjIdT: ...\n", + "# def experiment_subject(self, idx: Any, /, \n", + "# create: bool = False, *args, **kwargs) -> ExperimentSubject | None: \n", + "# \"\"\"Get or create an `ExperimentSubject` for the given identifier. \n", + "# Returns `None` if `idx` is out of domain range.\n", + "# \"\"\"\n", + "# ...\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ExperimentSubject:\n", + " exp: ExperimentContext\n", + " idx: SubjIdT\n", + "\n", + " def setup(self, exp: ExperimentContext, idx: Any, *args, **kwargs): \n", + " self.exp = exp\n", + " self.idx = cast(SubjIdT, exp.normalize_idx(idx))\n", + " return self\n", + "\n", + " def __new__(cls,\n", + " exp: ExperimentContext,\n", + " idx: Any,\n", + " *args, **kwargs):\n", + " self = exp.experiment_subject(idx)\n", + " if self is None:\n", + " self = super().__new__(cls)\n", + " self = exp.experiment_subject(idx, new_subject=self, *args, **kwargs)\n", + " if self is None:\n", + " raise ValueError(f\"Can't create new subject with idx: {idx}: out of range\")\n", + " return self\n", + "\n", + "\n", + "class ExperimentContext:\n", + " \"Class to maintain shared state across all file-based experiments within the experiment domain.\"\n", + "\n", + " subject_cls: Callable[..., ExperimentSubject]\n", + " def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls\n", + "\n", + " def normalize_idx(self, idx: int | str | Path) -> SubjIdT | None:\n", + " nidx = None\n", + " if isinstance(idx, int) and idx < len(self._paths):\n", + " nidx = idx\n", + " elif isinstance(idx, str):\n", + " try:\n", + " nidx = [_.name for _ in self._paths].index(idx)\n", + " except Exception:\n", + " pass\n", + " elif isinstance(idx, Path):\n", + " idx = idx.resolve()\n", + " if idx in self._paths:\n", + " nidx = self._paths.index(idx)\n", + " return nidx\n", + " \n", + " def path_from_idx(self, idx: int | str | Path):\n", + " _idx = self.normalize_idx(idx)\n", + " if _idx is None:\n", + " raise ValueError(f\"{_idx} not found in context.\")\n", + " path = Path(self._paths[_idx])\n", + " if not path.exists():\n", + " raise ValueError(f\"{path} not found in context.\")\n", + " return path\n", + " \n", + " @property\n", + " def count(self): return len(self._paths)\n", + " @property\n", + " def cache_dir(self): return Path(\".cache/\")\n", + " @functools.lru_cache()\n", + " def _cache_dir(self, idx: SubjIdT):\n", + " # create one folder for each image to cache and save results\n", + " path = self.path_from_idx(idx)\n", + " cache_dir = self.cache_dir / path.stem\n", + " cache_dir.mkdir(parents=True, exist_ok=True)\n", + " return cache_dir\n", + " def subject_cache_dir(self, idx: int | str | Path):\n", + " return self._cache_dir(idx)\n", + "\n", + " def empty_cache(self, idx: SubjIdT | None = None):\n", + " cache_dir = self.cache_dir\n", + " if idx is None:\n", + " shutil.rmtree(cache_dir, ignore_errors=True)\n", + " cache_dir.mkdir(parents=True, exist_ok=True)\n", + " else:\n", + " path = Path(self._paths[idx])\n", + " cache_dir = cache_dir / path.stem\n", + " for p in cache_dir.glob(\"*\"):\n", + " p.unlink(missing_ok=True)\n", + " if not any(cache_dir.iterdir()):\n", + " cache_dir.rmdir()\n", + "\n", + " def empty_cache_warn(self, idx: SubjIdT | None=None, *, warn: bool=True, out: W.Output | None=None):\n", + " def on_confirm_clicked(b):\n", + " try:\n", + " self.empty_cache(idx)\n", + " print(\"Cache cleared successfully.\")\n", + " except Exception as e:\n", + " print(f\"Failed to clear cache: {e}\")\n", + " finally:\n", + " for widget in confirmation_box.children:\n", + " widget.close()\n", + "\n", + " def on_cancel_clicked(b):\n", + " print(\"Cache clear cancelled.\")\n", + " for widget in confirmation_box.children:\n", + " widget.close()\n", + "\n", + " if out is None:\n", + " out = W.Output()\n", + " with out:\n", + " if FC.IN_NOTEBOOK:\n", + " confirm_button = W.Button(description=\"Confirm\")\n", + " cancel_button = W.Button(description=\"Cancel\")\n", + " confirm_button.on_click(on_confirm_clicked)\n", + " cancel_button.on_click(on_cancel_clicked)\n", + " label = W.Label('Are you sure you want to clear the cache? This action cannot be undone.')\n", + " confirmation_box = W.VBox([label, W.HBox([confirm_button, cancel_button])])\n", + " display(confirmation_box)\n", + " else:\n", + " on_confirm_clicked(None)\n", + "\n", + " def experiment_subject(self, idx: SubjIdT | str | Path, /, \n", + " new_subject: ExperimentSubject | None = None, *args, **kwargs) -> ExperimentSubject | None:\n", + " \"Cached subject. If provided, `new_subject` replaces value at the index.\"\n", + " if (nidx := self.normalize_idx(idx)) is None:\n", + " return None\n", + " if new_subject is None:\n", + " subject = self._subjects.get(nidx)\n", + " else:\n", + " new_subject.setup(self, nidx, *args, **kwargs)\n", + " self._subjects[nidx] = subject = new_subject\n", + " return subject\n", + "\n", + " def reset(self):\n", + " self._subjects.clear()\n", + " self._cache_dir.cache_clear()\n", + " \n", + " def __init__(self, paths: list[Path], root: Path | None = None):\n", + " self._root = (root or Path('.')).resolve()\n", + " self._paths = [p.resolve().relative_to(self._root) for p in paths]\n", + " self._subjects: dict[SubjIdT, ExperimentSubject] = {}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`ExperimentSubject`s are singletons" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "exp = ExperimentContext([Path('a'), Path('b')])\n", + "subj = exp.experiment_subject(5)\n", + "test_eq(subj, None)\n", + "\n", + "_ = exp.experiment_subject(1)\n", + "test_is(_, None)\n", + "\n", + "subj1 = ExperimentSubject(exp, 1)\n", + "_ = exp.experiment_subject(1)\n", + "test_eq(_ is not None, True)\n", + "test_is(_, subj1)\n", + "test_is(subj1, ExperimentSubject(exp, 1))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can't create `ExperimentSubject`s beyond `ExperimentContext` domain." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "test_fail(lambda:ExperimentSubject(exp, 2), 'out of range')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ImageContext\n", + "> A utility class to maintain image state for a `OCRExperimentContext`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "ImgSpecT: TypeAlias = ImgIdT | str | Path\n", + "\n", + "class ImageContext(ExperimentSubject):\n", + " \"\"\"\n", + " A utility class to maintain image state for a ExperimentContext.\n", + " This class encapsulates state necessary for conducting OCR experiments.\n", + "\n", + " Attributes:\n", + " json_data (dict): JSON data loaded from cached files.\n", + " page_data (st.PageData): PanelClaner page data.\n", + " base_image (Image.Image): The base image loaded from the page data.\n", + " mask (Image.Image): The mask image used for text detection.\n", + " gts (list[str]): Ground truth data for the text in the images.\n", + " ocr_model (str): Name or identifier of the OCR model used.\n", + " mocr (ocr.OCRModel): OCR model configured for the experiment.\n", + " mask_dilated1 (Image.Image): Image mask dilated by 1 pixel.\n", + " mask_dilated05 (Image.Image): Image mask dilated by 0.5 pixels.\n", + " mask_dilated02 (Image.Image): Image mask dilated by 0.2 pixels.\n", + "\n", + " Methods:\n", + " init(config: cfg.Config, img_path: Path, cache_dir: Path, ocr_model: str):\n", + " Initializes the experiment context. It also handles the generation of text boxes \n", + " if they are not already present.\n", + "\n", + " setup_ground_truth():\n", + " Loads or initializes ground truth data for the experiment based on the page data.\n", + "\n", + " setup_crop_masks():\n", + " Prepares various dilated versions of the mask image to be used in different cropping \n", + " strategies during the experiments.\n", + " \"\"\"\n", + " exp: ExperimentContext\n", + " idx: ImgIdT\n", + " base_image: Image.Image\n", + " mask: Image.Image\n", + " json_data: dict | None\n", + " page_data: st.PageData\n", + " # ocr_model: str\n", + " # mocr: ocr.OCRModel\n", + " # postprocess_ocr: Callable[..., str]\n", + " _page_lang: str\n", + " _gts: list[str]\n", + " _mask_dilated1: Image.Image | None\n", + " _mask_dilated05: Image.Image | None\n", + " _mask_dilated02: Image.Image | None\n", + " \n", + "\n", + " # # this methods will be set downstream, declared here to make the type checker happy\n", + " # def result(self: Self, \n", + " # box_idx: int, method: CropMethod, ocr: bool = True, reset: bool=False) -> ResultOCR: ...\n", + " # def summary_box(self: Self, box_idx: int): ...\n", + "\n", + " def to_dict(self):\n", + " return {\n", + " 'image_idx': self.idx,\n", + " 'page_lang': self.page_lang,\n", + " }\n", + " \n", + " @property\n", + " def image_idx(self): return self.idx\n", + " @property\n", + " def cache_dir(self): \n", + " return self.exp.subject_cache_dir(self.idx)\n", + " cache_dir_image = cache_dir\n", + " \n", + " @property\n", + " def image_info(self): \n", + " img = self.base_image\n", + " w, h = img.size\n", + " print_size_in = size(w, h, 'in', 300)\n", + " print_size_cm = size(w, h, 'cm', 300)\n", + " required_dpi = dpi(w, h, 'Modern Age')\n", + " return (w, h), print_size_in, print_size_cm, required_dpi\n", + "\n", + " @property\n", + " def original_image_path(self): return Path(self.page_data.original_path)\n", + " @property\n", + " def image_path(self): return Path(self.page_data.image_path)\n", + " @property\n", + " def image_name(self): return self.original_image_path.name\n", + " @property\n", + " def image_size(self): return self.base_image.size\n", + " @property\n", + " def image_dim(self):return size(*self.image_size)\n", + " @property\n", + " def image_dpi(self): return dpi(*self.image_size)\n", + " @property\n", + " def image_print(self):\n", + " return self.image_size, self.image_dim, self.image_dpi\n", + " @property\n", + " def image_name_rich(self):\n", + " siz, dim, res = self.image_print\n", + " return f\"{self.image_name} - {siz[0]}x{siz[1]} px: {dim[0]:.2f}x{dim[1]:.2f}\\\" @ {res:.2f} dpi\"\n", + " \n", + " def setup_page_lang(self, page_lang: str | None = None):\n", + " path = Path(self.page_data.original_path).with_suffix('.json')\n", + " metadata = json.load(open(path)) if path.exists() else {}\n", + " if 'lang' in metadata and (page_lang == metadata['lang'] or page_lang is None):\n", + " self._page_lang = metadata['lang']\n", + " return\n", + " self._page_lang = metadata['lang'] = page_lang or 'English'\n", + " json.dump(metadata, open(path, 'w'), indent=2)\n", + " @property\n", + " def page_lang(self):\n", + " if self._page_lang == None:\n", + " self.setup_page_lang()\n", + " return self._page_lang\n", + " \n", + " @property\n", + " def boxes(self): return self.page_data.boxes\n", + " \n", + " def setup_ground_truth(self):\n", + " self._gts = read_ground_truth(self.page_data)\n", + " @property\n", + " def gts(self): \n", + " if self._gts is None:\n", + " self.setup_ground_truth()\n", + " return self._gts\n", + " \n", + " @functools.lru_cache(typed=True)\n", + " def dilated_mask(self, fraction: float):\n", + " return dilate_by_fractional_pixel(self.mask, fraction)\n", + " \n", + " def mask_dilated1(self): \n", + " if self._mask_dilated1 is None:\n", + " self._mask_dilated1 = self.mask.filter(ImageFilter.MaxFilter(3))\n", + " return self._mask_dilated1\n", + " \n", + " def mask_dilated05(self): \n", + " if self._mask_dilated05 is None:\n", + " self._mask_dilated05 = self.dilated_mask(0.5)\n", + " return self._mask_dilated05\n", + " \n", + " def mask_dilated02(self): \n", + " if self._mask_dilated02 is None:\n", + " self._mask_dilated02 = self.dilated_mask(0.2)\n", + " return self._mask_dilated02\n", + " \n", + " def dilated(self):\n", + " return {1: self.mask_dilated1(),\n", + " 0.5: self.mask_dilated05(),\n", + " 0.2: self.mask_dilated02(),}\n", + "\n", + " def __new__(cls,\n", + " exp: ExperimentContext,\n", + " idx: ImgSpecT,\n", + " *args, **kwargs) -> Self:\n", + " return super().__new__(cls, exp, idx, *args, **kwargs) # type: ignore\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# OCRExperimentContext" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class OCRExperimentContext(ExperimentContext):\n", + " \"\"\"\n", + " A utility class to maintain shared state across all experiments within OCR domain.\n", + " This class encapsulates state necessary for conducting PanelCleaner OCR experiments.\n", + " \"\"\"\n", + "\n", + " config: cfg.Config\n", + " image_paths: list[Path]\n", + " # OCR engine -> Image index -> Box index -> Crop method -> Result\n", + " _results: dict[str, dict[ImgIdT, ResultSet]]\n", + "\n", + " \n", + " engines = {\n", + " 'Tesseract': cfg.OCREngine.TESSERACT, \n", + " 'Idefics': None, \n", + " 'manga-ocr': cfg.OCREngine.MANGAOCR}\n", + "\n", + " # subject_cls: ImageContext\n", + " # def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls\n", + "\n", + " @classmethod\n", + " def get_config(cls, cache_dir: Path | None = None) -> cfg.Config:\n", + " config = cfg.load_config()\n", + " config.cache_dir = cache_dir or Path(\".\")\n", + " profile = config.current_profile\n", + " preprocessor_conf = profile.preprocessor\n", + " # Modify the profile to OCR all boxes.\n", + " # Make sure OCR is enabled.\n", + " preprocessor_conf.ocr_enabled = True\n", + " # Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", + " preprocessor_conf.ocr_max_size = 10**10\n", + " # Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", + " preprocessor_conf.suspicious_box_min_size = 10**10\n", + " # Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", + " preprocessor_conf.ocr_blacklist_pattern = \".*\"\n", + " return config\n", + "\n", + " def to_dict(self):\n", + " return {\n", + " 'image_paths': list(map(str, self.image_paths)),\n", + " 'cache_dir': str(self.config.cache_dir)\n", + " }\n", + " def to_json(self):\n", + " return json.dumps(self.to_dict(), indent=2)\n", + " @classmethod\n", + " def from_json_data(cls, d: dict):\n", + " return cls(cls.get_config(Path(d['cache_dir'])), d['image_paths'])\n", + " @classmethod\n", + " def from_json_path(cls, path: Path):\n", + " return cls.from_json_data(json.loads(path.read_text()))\n", + "\n", + " \n", + " @functools.lru_cache()\n", + " def mocr(self, ocr_model: str, lang: str):\n", + " engine = self.engines[ocr_model]\n", + " ocr_processor = ocr.get_ocr_processor(True, engine)\n", + " proc = ocr_processor[lang2pcleaner(lang)]\n", + " if isinstance(proc, TesseractOcr):\n", + " proc.lang = lang2tesseract(lang)\n", + " return proc\n", + "\n", + " def ocr_box(self, result: ResultOCR, ocr_model: str, lang: str): \n", + " assert result.image is not None\n", + " text = self.mocr(ocr_model, lang)(result.image)\n", + " result.ocr = postprocess_ocr(text)\n", + " return result\n", + "\n", + " @property\n", + " def cache_dir(self): return self.config.get_cleaner_cache_dir()\n", + " image_cache_dir = ExperimentContext.subject_cache_dir\n", + "\n", + " @functools.lru_cache()\n", + " def _load_page_data(self, image_idx: int):\n", + " config = self.config\n", + " cache_dir = self.image_cache_dir(image_idx)\n", + " img_path = self.path_from_idx(image_idx)\n", + " image_name = img_path.stem\n", + " # read cached json\n", + " jsons = [_ for _ in cache_dir.glob(\"*#raw.json\") if image_name in _.stem]\n", + " assert len(jsons) <= 1\n", + " # generate text boxes if needed\n", + " if not jsons:\n", + " pfl = config.current_profile\n", + " gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + " model_path = config.get_model_path(gpu)\n", + " ctm.model2annotations(pfl.general, pfl.text_detector, model_path, [img_path], cache_dir)\n", + " # we don't need unique names for this tests, strip uuids\n", + " for p in cache_dir.glob(f\"*{image_name}*\"):\n", + " p.rename(strip_uuid(p))\n", + " jsons = [_ for _ in cache_dir.glob(\"*#raw.json\") if image_name in _.stem]\n", + "\n", + " # adapt paths to be relative to this notebook\n", + " this_path = self._root\n", + " json_file_path = jsons[0]\n", + " json_data = json.loads(json_file_path.read_text(encoding=\"utf-8\"))\n", + " json_data[\"image_path\"] = str(strip_uuid(json_data[\"image_path\"]).relative_to(this_path))\n", + " json_data[\"mask_path\"] = str(strip_uuid(json_data[\"mask_path\"]).relative_to(this_path))\n", + " json.dump(json_data, open(json_file_path, \"w\"), indent=2)\n", + " else:\n", + " json_file_path = jsons[0]\n", + " json_data = json.loads(json_file_path.read_text(encoding=\"utf-8\"))\n", + "\n", + " page_data = st.PageData(\n", + " json_data[\"image_path\"], json_data[\"mask_path\"], \n", + " json_data[\"original_path\"], json_data[\"scale\"], \n", + " [st.Box(*data[\"xyxy\"]) for data in json_data[\"blk_list\"]], \n", + " [], [], [])\n", + " # Merge boxes that have mutually overlapping centers.\n", + " page_data.resolve_total_overlaps()\n", + " return json_data, page_data\n", + "\n", + " def page_data(self, image_idx: int):\n", + " _, page_data = self._load_page_data(image_idx)\n", + " return page_data\n", + " def json_data(self, image_idx: int):\n", + " json_data, _ = self._load_page_data(image_idx)\n", + " return json_data\n", + "\n", + " def experiment_image(self, image_idx: ImgIdT | str | Path) -> ImageContext | None:\n", + " \"Cached image context.\"\n", + " return cast(ImageContext, self.experiment_subject(image_idx))\n", + "\n", + " def update_results(self, ocr_model: str, img_idx: ImgIdT, results: ResultSetDefault):\n", + " self._results[ocr_model][img_idx] = cast(ResultSet, results)\n", + " \n", + " \n", + " def _result_from(self, image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None):\n", + " img_ctx = ImageContext(self, image_idx)\n", + " extracted = method in _EXTRACTED_METHODS\n", + " result_cls = ResultOCRExtracted if extracted else ResultOCR\n", + " result = result_cls(int(box_idx), None, '', img_ctx.page_data, \n", + " img_ctx.gts, description=f\"{method.value}\")\n", + " if ocr is not None:\n", + " result.ocr = ocr\n", + " return result\n", + " \n", + " def result(self, \n", + " ocr_model: str,\n", + " image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, \n", + " ocr: bool=True, \n", + " rebuild: bool=False) -> ResultOCR | None:\n", + " img_ctx = ImageContext(self, image_idx)\n", + " result = self._results[ocr_model][image_idx][box_idx].get(method)\n", + " if not rebuild and result is not None:\n", + " return result\n", + " \n", + " result = self._result_from(image_idx, box_idx, method)\n", + " image, cropped_image, cropped_mask = result.image, None, None\n", + " base_image = img_ctx.base_image\n", + " box = img_ctx.boxes[box_idx]\n", + " if image is None and method in _IMAGE_METHODS:\n", + " image = crop_by_image(\n", + " method, box, base_image, self.config.current_profile.preprocessor)\n", + "\n", + " if image is None and method in _EXTRACTED_METHODS:\n", + " mask = img_ctx.mask\n", + " cropped_image_path = result.cache_image(cropped_image, \"cropped\")\n", + " cropped_mask_path = result.cache_image(cropped_mask, \"mask\")\n", + " if not cropped_image_path.exists() or not cropped_mask_path.exists():\n", + " image, cropped_image, cropped_mask = crop_by_extracted(\n", + " method, box, base_image, mask, \n", + " cropped_image_path, cropped_mask_path, img_ctx.dilated())\n", + " \n", + " assert image is not None\n", + " if result.image is None:\n", + " result.image = image\n", + " result.cache_image()\n", + " if cropped_image is not None:\n", + " result.cache_image(cropped_image, \"cropped\")\n", + " if cropped_mask is not None:\n", + " result.cache_image(cropped_mask, \"mask\")\n", + " \n", + " if ocr:\n", + " result = self.ocr_box(result, ocr_model, img_ctx.page_lang)\n", + " self._results[ocr_model][image_idx][box_idx][method] = result\n", + " return result\n", + "\n", + " def results(self, ocr_model: str | None = None, img_idx: ImgIdT | None = None):\n", + " if ocr_model is None: return self._results\n", + " if img_idx is None: return self._results[ocr_model]\n", + " return self._results[ocr_model][img_idx]\n", + " def model_results(self, ocr_model: str):\n", + " return cast(dict[ImgIdT, ResultSet], self.results(ocr_model))\n", + " def image_results(self, ocr_model: str, img_idx: ImgIdT):\n", + " return cast(ResultSet, self.results(ocr_model, img_idx))\n", + " def box_results(self, ocr_model: str, img_idx: ImgIdT, box_idx: BoxIdT):\n", + " return cast(ResultSet, self.results(ocr_model, img_idx))[box_idx]\n", + " def method_results(self, ocr_model: str, img_idx: ImgIdT, method: CropMethod):\n", + " image_results = self.image_results(ocr_model, img_idx)\n", + " return {i: box_results.get(method) for i,box_results in image_results.items()}\n", + "\n", + " def _reset_results(self):\n", + " results = defaultdict(lambda: defaultdict(lambda: ResultSetDefault(dict)))\n", + " self._results = cast(dict[str, dict[ImgIdT, ResultSet]], results)\n", + " def reset_results(self, \n", + " ocr_model: str | None = None, \n", + " image_idx: int | None = None, \n", + " box_idx: int | None = None, \n", + " method: CropMethod | None = None):\n", + " if ocr_model is None and image_idx is None and box_idx is None and method is None:\n", + " self._reset_results()\n", + " return\n", + " results = self._results\n", + " models = tuple(results.keys()) if ocr_model is None else [ocr_model] if ocr_model in results else []\n", + " for ocr_model in models:\n", + " img_nodes = results[ocr_model]\n", + " imgs = tuple(img_nodes.keys()) if image_idx is None else [image_idx] if image_idx in img_nodes else []\n", + " for img_idx in imgs:\n", + " box_nodes = img_nodes[img_idx]\n", + " boxes = tuple(box_nodes.keys()) if box_idx is None else [box_idx] if box_idx in box_nodes else []\n", + " for box_idx in boxes:\n", + " if method is None:\n", + " del box_nodes[box_idx]\n", + " else:\n", + " methods = box_nodes[box_idx]\n", + " if method in methods:\n", + " del methods[method]\n", + " if not box_nodes[box_idx]:\n", + " del box_nodes[box_idx]\n", + " if not img_nodes[img_idx]:\n", + " del img_nodes[img_idx]\n", + " if not results[ocr_model]:\n", + " del results[ocr_model]\n", + " def reset(self):\n", + " super().reset()\n", + " self.reset_results()\n", + " self._load_page_data.cache_clear()\n", + " self.mocr.cache_clear()\n", + "\n", + " def __init__(self, \n", + " config: cfg.Config | None, \n", + " image_paths: list[Path]\n", + " ):\n", + " super().__init__(list(map(lambda p: p.resolve(), image_paths)))\n", + " self.config = config or type(self).get_config()\n", + " self.image_paths = self._paths\n", + " self._reset_results()\n", + " self._images = self._subjects\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "@FC.patch_to(ImageContext)\n", + "def setup(self, exp: OCRExperimentContext, image_idx: ImgSpecT, page_lang: str | None = None):\n", + " super(type(self), self).setup(exp, image_idx)\n", + " self._mask_dilated1 = self._mask_dilated05 = self._mask_dilated02 = None\n", + " # if ocr_model not in exp.engines:\n", + " # raise ValueError(f\"OCR model {ocr_model} not supported.\")\n", + " # self.ocr_model = ocr_model\n", + " # self.idx = exp.normalize_idx(image_idx)\n", + " self.json_data, self.page_data = exp._load_page_data(self.idx)\n", + " self.setup_page_lang(page_lang)\n", + " self.mask = Image.open(self.page_data.mask_path)\n", + " self.base_image = Image.open(self.page_data.image_path)\n", + " self.setup_ground_truth()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "tirar = OCRExperimentContext(None, [])\n", + "test_eq(rr := tirar._results, {})\n", + "test_eq(rr['Tesseract'][0][0], {})\n", + "test_eq(rr, {'Tesseract': {0: {0: {}}}})\n", + "test_eq(rr['Tesseract'][0][0].get(CM.INITIAL_BOX), None)\n", + "rr['Tesseract'][0][0][CM.INITIAL_BOX] = 'a' # type: ignore\n", + "test_eq(rr, {'Tesseract': {0: {0: {CM.INITIAL_BOX: 'a'}}}})\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ContextVisor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ContextVisor:\n", + " ctx: Any\n", + " # control_names: list[str]\n", + " values: dict[str, Any]\n", + "\n", + " _css = ''\n", + "\n", + " _ctxs: dict[str, ContextVisor]\n", + " _hdlrs: dict[str, ContextVisor]\n", + "\n", + " @property\n", + " def w(self) -> W.DOMWidget:\n", + " if getattr(self, '_w', None) is None:\n", + " self._w = self.setup_ui()\n", + " return self._w\n", + " @property\n", + " def out(self) -> W.Output:\n", + " if getattr(self, '_out', None) is None:\n", + " self._out = W.Output()\n", + " self._out.clear_output(wait=True)\n", + " return self._out # type: ignore\n", + " @property\n", + " def controls(self) -> dict[str, W.ValueWidget | W.fixed]:\n", + " if getattr(self, '_controls', None) is None:\n", + " self._controls = self.setup_controls()\n", + " return self._controls\n", + " @property\n", + " def all_controls(self) -> dict[str, W.ValueWidget | W.fixed]:\n", + " if getattr(self, '_all_controls', None) is None:\n", + " controls = {}\n", + " for visor in self._ctxs.values():\n", + " controls.update(visor.all_controls)\n", + " controls.update(self.controls)\n", + " self._all_controls = controls\n", + " return self._all_controls\n", + " \n", + " @property\n", + " def all_values(self):\n", + " return {**{k:v.values for k,v in (self._ctxs | {'self': self}).items()}, **self.values}\n", + " \n", + " @property\n", + " def comps(self): return self._ctxs\n", + " def comp(self, k: str) -> ContextVisor | None:\n", + " return self._ctxs.get(k)\n", + " def handler(self, k: str) -> ContextVisor | None:\n", + " return self._hdlrs.get(k)\n", + " \n", + " @property\n", + " def styler(self) -> W.Output | None:\n", + " if (stl := self.setup_style()) is None: \n", + " return None\n", + " if getattr(self, '_style', None) is None:\n", + " self._style = W.Output(layout={'height': '0px'})\n", + " with self._style:\n", + " display(stl)\n", + " return self._style\n", + " def setup_style(self):\n", + " return HTML(f\"\") if self._css else None\n", + " \n", + " def update_output(self, **kwargs): \n", + " cprint(kwargs)\n", + " \n", + " def setup_controls(self) -> dict[str, W.ValueWidget | W.fixed]:\n", + " return {k: W.Label(value=k) for k,v in self.values.items()}\n", + " \n", + " def hide(self):\n", + " self.w.layout.visibility = 'hidden'\n", + " def show(self):\n", + " self.w.layout.visibility = 'visible'\n", + "\n", + " def setup_ui(self):\n", + " comps = []\n", + " for visor in self._ctxs.values():\n", + " comps.append(visor.w)\n", + " return W.HBox([*comps, *self.controls.values()])\n", + "\n", + " def setup_display(self): \n", + " if getattr(self, '_w', None) is None:\n", + " self._w = self.setup_ui()\n", + " \n", + "\n", + " def _output(self, **kwargs):\n", + " collator = defaultdict(dict)\n", + " show_inline_matplotlib_plots()\n", + " with self.out:\n", + " clear_output(wait=True)\n", + " for k,v in kwargs.items():\n", + " if (comp := self.handler(k)) is not None:\n", + " collator[comp][k] = v\n", + " else:\n", + " assert 0\n", + " # self.update_output(**{k: v})\n", + " for comp, kw in collator.items():\n", + " comp.update_output(**kw)\n", + " show_inline_matplotlib_plots()\n", + " def interactive_output(self):\n", + " controls = self.all_controls\n", + " controls2names = {v:k for k,v in controls.items()}\n", + " def observer(change):\n", + " control_name = controls2names[change['owner']]\n", + " kwargs = {control_name: change['new']}\n", + " updated = self._update(**kwargs)\n", + " self._output(**updated)\n", + " for w in controls.values():\n", + " w.observe(observer, 'value')\n", + " def display(self, **kwargs): \n", + " if getattr(self, '_w', None) is None:\n", + " self.setup_display()\n", + " self.interactive_output()\n", + " self._update(**(self.values | kwargs))\n", + " all_values= {}\n", + " for comp in list(self.comps.values()) + [self]: all_values.update(comp.values)\n", + " self._hdlrs = {k:self._hdlrs.get(k, self) for k in all_values}\n", + " self._output(**all_values)\n", + " display(self.styler, self.w, self.out) if self.styler else display(self.w, self.out)\n", + " else:\n", + " self.update(**kwargs)\n", + " def _ipython_display_(self): self.display()\n", + "\n", + " def _update(self, update_value: bool=True, **kwargs):\n", + " updated = {}\n", + " for visor in self.comps.values():\n", + " updated.update(visor._update(update_value=update_value, **kwargs))\n", + " values = self.values\n", + " my_vals = _pops_(kwargs, self.values.keys())\n", + " for k,v in my_vals.items():\n", + " if v is not None and v != values[k]:\n", + " if update_value: values[k] = v\n", + " updated[k] = v\n", + " return updated\n", + " def update(self, **kwargs):\n", + " updated = self._update(update_value=False, **kwargs)\n", + " controls = self.all_controls\n", + " for k in updated:\n", + " controls[k].value = updated[k]\n", + " # self._output(**updated)\n", + " \n", + " def __init__(self, \n", + " ctx: Any, \n", + " values: dict[str, Any], \n", + " out: W.Output | None = None,\n", + " ctxs: dict[str, ContextVisor] | None = None,\n", + " hdlrs: dict[str, ContextVisor] | None = None,\n", + " ):\n", + " self._ctxs = ctxs or {}\n", + " self._hdlrs = hdlrs or {}\n", + " self.ctx = ctx\n", + " self._out = out\n", + " self.values = values\n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "82c802235bf84f6eb36d87cd72607440", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(Label(value='a'),))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4f0809d6276b4bea9f0f992b337817a8", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('test_visor')\n", + "\n", + "test_visor = ContextVisor(None, {'a': 1})\n", + "test_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "test_eq(test_visor.values, {'a': 1})\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CONTEXT\n", + "> `CONTEXT` is an `OCRExperimentContext` object that contains the configuration and the list of image paths.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can get the configuration with `OCRExperimentContext.get_config()`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: cursor\n", + "Cache Directory: .\n", + "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", + "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
      cache_dir: Path('cleaner')\n",
+       "     model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
+       "         device: 'mps'\n",
+       "
\n" + ], + "text/plain": [ + " cache_dir: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'cleaner'\u001b[0m\u001b[1m)\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'mps'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CONFIG = OCRExperimentContext.get_config()\n", + "\n", + "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + "model_path = CONFIG.get_model_path(gpu)\n", + "device = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n", + "\n", + "CONFIG.show()\n", + "cprint(\n", + " f\"{'cache_dir':>15}: {repr(cache_dir)}\\n\"\n", + " f\"{'model_path':>15}: {repr(model_path)}\\n\"\n", + " f\"{'device':>15}: {repr(device)}\")\n", + "\n", + "test_eq(CONFIG.cache_dir, Path(\".\"))\n", + "test_eq(CONFIG.current_profile.preprocessor.ocr_enabled, True)\n", + "test_eq(CONFIG.current_profile.preprocessor.ocr_max_size, 10**10)\n", + "test_eq(CONFIG.current_profile.preprocessor.suspicious_box_min_size, 10**10)\n", + "test_eq(CONFIG.current_profile.preprocessor.ocr_blacklist_pattern, \".*\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT = OCRExperimentContext(CONFIG, IMAGE_PATHS)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ImageSelector" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ImageSelector(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + "\n", + " @property\n", + " def image_ctx(self):\n", + " return ImageContext(self.ctx, self.values['image_idx'])\n", + " \n", + " def setup_controls(self):\n", + " paths = self.ctx.image_paths\n", + " w = W.Dropdown(\n", + " options={_.stem:i for i,_ in enumerate(paths)}, \n", + " value=self.values['image_idx'],\n", + " layout={'width': 'fit-content'},\n", + " style={'description_width': 'initial'})\n", + " return {'image_idx': w}\n", + "\n", + " def update(self, image_idx: ImgSpecT | None = None, **kwargs):\n", + " if image_idx is None: return\n", + " idx = self.ctx.normalize_idx(image_idx)\n", + " if idx is None: return\n", + " super().update(image_idx=idx, **kwargs)\n", + "\n", + "\n", + " def __init__(self, \n", + " ctx: OCRExperimentContext, /, \n", + " image_idx: ImgSpecT = 0, *, \n", + " out: W.Output | None=None):\n", + " idx = ctx.normalize_idx(image_idx)\n", + " assert idx is not None, f\"Image {image_idx} not found in experiment context\"\n", + " super().__init__(ctx, {'image_idx': idx}, out)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c033b2c76629478f8d7702e1f3f8666a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(Dropdown(index=2, layout=Layout(width='fit-content'), options={'Action_Comics_1960-01-00_(262)'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d78cb5cf72c34bcab9274cfd77f585a5", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('image_selector')\n", + "\n", + "image_selector = ImageSelector(CONTEXT, 2)\n", + "image_selector\n" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "image_selector.update(13)\n", + "test_eq(image_selector.values['image_idx'], 13)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# OCRContextVisor" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "class OCRContextVisor(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + " \n", + " def update_output(self, /, image_idx: ImgIdT, **kwargs):\n", + " img_path = self.ctx.path_from_idx(image_idx)\n", + " display_image_grid([img_path], 1, 1)\n", + "\n", + " def update(self, image_idx: ImgSpecT | None = None, **kwargs):\n", + " if image_idx is None: return\n", + " idx = self.ctx.normalize_idx(image_idx)\n", + " if idx is None: return\n", + " super().update(image_idx=idx, **kwargs)\n", + " \n", + " def __init__(self, \n", + " ctx: OCRExperimentContext, /, \n", + " image_idx: ImgSpecT = 0, *, \n", + " out: W.Output | None=None):\n", + " super().__init__(ctx, {}, out, \n", + " ctxs={'image_idx': ImageSelector(ctx, image_idx, out=self.out)})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3b40f82e57564fbcae7913d7a76fbc32", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Dropdown(index=2, layout=Layout(width='fit-content'), options={'Action_Comics_19…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "174fbbc4b6ff42ac8013984946e787e4", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('ctx_visor')\n", + "\n", + "# ContextVisor(CONTEXT)\n", + "# ContextVisor(CONTEXT).display(3)\n", + "ctx_visor = OCRContextVisor(CONTEXT, 2)\n", + "ctx_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "ctx_visor.update('Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base image\n", + "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", + "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"0033\")\n", + "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"INOUE_KYOUMEN_002\")\n", + "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"Action_Comics_1960-01-00_(262)\")\n", + "\n", + "assert BASE_IMAGE_IDX is not None\n", + "img_path = Path(CONTEXT.image_paths[BASE_IMAGE_IDX])\n", + "assert img_path.exists()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Empty cache\n", + "> Clear the image cache used profusely throughout the examples below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "You will be warned before the cache is emptied." + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "# CONTEXT.empty_cache_warn()" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [], + "source": [ + "# CONTEXT.empty_cache_warn(BASE_IMAGE_IDX)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ImageContext of base image\n", + "> Creates the `ImageContext` for the base image.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If `PanelCleaner` page data is already cached, it is loaded from the cache.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT.reset()" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "page_lang = 'English'\n", + "# page_lang = 'Japanese'\n", + "# page_lang = 'Spanish'\n", + "# page_lang = 'French'\n", + "\n", + "IMAGE_CONTEXT = ImageContext(CONTEXT, BASE_IMAGE_IDX, page_lang=page_lang)\n", + "test_eq(IMAGE_CONTEXT.page_data is not None, True)\n", + "# cprint(IMAGE_CONTEXT.page_data.boxes)\n", + "RenderJSON(IMAGE_CONTEXT.json_data, 360, 2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [], + "source": [ + "test_is(IMAGE_CONTEXT, ImageContext(CONTEXT, BASE_IMAGE_IDX))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualize image" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Strange_Tales_172005.jpg - 1275x1888 px: 4.25x6.29\" @ 188.32 dpi
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "page_data = IMAGE_CONTEXT.page_data\n", + "display_image_grid([page_data.image_path, page_data.mask_path], 1, 2, caption=IMAGE_CONTEXT.image_name_rich)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "_, out_path = page_boxes(page_data)\n", + "display_image_grid([out_path], 1, 1)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ModelSelector\n" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class OCRModel(Enum):\n", + " TESSERACT = 0\n", + " IDEFICS = 1\n", + " @staticmethod\n", + " def __display_names__() -> dict[str, OCRModel]:\n", + " return dict(\n", + " zip(\"Tesseract, Idefics\".split(', '), \n", + " OCRModel))\n", + "\n", + "\n", + "class ModelSelector(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + " \n", + " def setup_controls(self):\n", + " options = self.models\n", + " w = W.Dropdown(\n", + " options=options, \n", + " value=self.values['model'],\n", + " layout={'width': 'fit-content'},\n", + " style={'description_width': 'initial'})\n", + " return {'model': w}\n", + "\n", + " def setup_ui(self):\n", + " ctls = self.controls\n", + " model_grp = W.HBox([ctls['model']])\n", + " model_grp.add_class('model_grp')\n", + " comps = []\n", + " for visor in self.comps.values():\n", + " comps.append(visor.setup_ui())\n", + " ui = W.HBox([*comps, model_grp])\n", + " return ui\n", + "\n", + " def __init__(self, \n", + " exp_ctx: OCRExperimentContext,\n", + " ocr_model: OCRModel | None=OCRModel.TESSERACT,\n", + " ocr_models: dict[str, OCRModel] | None = None,\n", + " out: W.Output | None = None\n", + " ):\n", + " self.models: dict[str, OCRModel] = ocr_models or OCRModel.__display_names__()\n", + " super().__init__(exp_ctx, \n", + " {'model': ocr_model or OCRModel.TESSERACT}, \n", + " out=out or self.out)#, ctxs=[exp_visor])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "413f66f1d43a4d849e43a79ca9b16502", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), options={'Tesseract': 30}: {w} x {h} pixels\\n\"\n", + " f\"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\\n\"\n", + " f\"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in\"\n", + " f\" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\\n\"\n", + " f\"Required DPI Modern Age format: {required_dpi:.3f} dpi \"\n", + " f\"({format[0]:.3f} x {format[1]:.3f} in)\")\n", + "\n", + "\n", + " def display_content(self, image_ctx: ImageContext, display_option: DisplayOptions):\n", + " page_data = image_ctx.page_data\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.PAGE_DATA):\n", + " self.image_info(image_ctx)\n", + " RenderJSON(image_ctx.json_data, 350, 2).display()\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.GROUND_TRUTH):\n", + " cprint(image_ctx.gts)\n", + " if display_option == DisplayOptions.IMAGE:\n", + " display_image_grid([page_data.image_path], 1, 1)\n", + " if display_option == DisplayOptions.MASK:\n", + " display_image_grid([page_data.mask_path], 1, 1)\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.IMAGE_MASK):\n", + " display_image_grid([page_data.image_path, page_data.mask_path], 1, 2)\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.BOXES):\n", + " _, out_path = page_boxes(page_data)\n", + " display_image_grid([out_path], 1, 1)\n", + "\n", + "\n", + " def setup_controls(self):\n", + " options = self.display_options or {**DisplayOptions.__display_names__()}\n", + " display_option_wdgt = W.Dropdown(\n", + " options=options, \n", + " value=self.values['display_option'],\n", + " layout={'width': '120px'},\n", + " style={'description_width': 'initial'})\n", + " return {'display_option': display_option_wdgt}\n", + "\n", + "\n", + " def setup_ui(self):\n", + " ctls = self.controls\n", + " display_option_grp = W.HBox([ctls['display_option']])\n", + " display_option_grp.add_class('display_option_grp')\n", + " comps = []\n", + " for visor in self.comps.values():\n", + " comps.append(visor.setup_ui())\n", + " ui = W.HBox([*comps, display_option_grp])\n", + " return ui\n", + "\n", + "\n", + " def __init__(self, \n", + " exp_ctx: OCRExperimentContext,\n", + " display_option: DisplayOptions | None=DisplayOptions.BOXES,\n", + " display_options: Mapping[str, DisplayOptions] | None = None,\n", + " out: W.Output | None = None\n", + " ):\n", + " self.display_options = display_options\n", + " super().__init__(exp_ctx, \n", + " {'display_option': display_option or DisplayOptions.BOXES}, \n", + " out=out or self.out)#, ctxs=[exp_visor])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "51b272e199e94fe69465b30306499d8a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Dropdown(index=2, layout=Layout(width='120px'), options={'Boxes': Width x Height: 1275 x 1888 pixels\n", + " PIL Info DPI: None\n", + " Print Size 300 DPI: 4.250 x 6.293 in / 10.795 x 15.985 cm\n", + "Required DPI Modern Age format: 188.324 dpi (6.625 x 10.250 in)\n", + "\n" + ], + "text/plain": [ + " Width x Height: \u001b[1;36m1275\u001b[0m x \u001b[1;36m1888\u001b[0m pixels\n", + " PIL Info DPI: \u001b[3;35mNone\u001b[0m\n", + " Print Size \u001b[1;36m300\u001b[0m DPI: \u001b[1;36m4.250\u001b[0m x \u001b[1;36m6.293\u001b[0m in \u001b[35m/\u001b[0m \u001b[1;36m10.795\u001b[0m x \u001b[1;36m15.985\u001b[0m cm\n", + "Required DPI Modern Age format: \u001b[1;36m188.324\u001b[0m dpi \u001b[1m(\u001b[0m\u001b[1;36m6.625\u001b[0m x \u001b[1;36m10.250\u001b[0m in\u001b[1m)\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "img = IMAGE_CONTEXT.base_image\n", + "w, h = img.size\n", + "\n", + "print_size_in = size(w, h, 'in', 300)\n", + "print_size_cm = size(w, h, 'cm', 300)\n", + "required_dpi = dpi(w, h, 'Modern Age')\n", + "format = PRINT_FORMATS['Modern Age']\n", + "cprint( f\"{'Width x Height':>30}: {w} x {h} pixels\\n\"\n", + " f\"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\\n\"\n", + " f\"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in\"\n", + " f\" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\\n\"\n", + " f\"Required DPI Modern Age format: {required_dpi:.3f} dpi ({format[0]:.3f} x {format[1]:.3f} in)\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "((1275, 1888),\n", + " (4.25, 6.293333333333333),\n", + " (10.795, 15.985066666666667),\n", + " 188.32397606994937)" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
                Width x Height: 804 x 1241 pixels\n",
+       "                  PIL Info DPI: None\n",
+       "            Print Size 300 DPI: 2.680 x 4.137 in / 6.807 x 10.507 cm\n",
+       "Required DPI Modern Age format: 121.216 dpi (6.625 x 10.250 in)\n",
+       "
\n" + ], + "text/plain": [ + " Width x Height: \u001b[1;36m804\u001b[0m x \u001b[1;36m1241\u001b[0m pixels\n", + " PIL Info DPI: \u001b[3;35mNone\u001b[0m\n", + " Print Size \u001b[1;36m300\u001b[0m DPI: \u001b[1;36m2.680\u001b[0m x \u001b[1;36m4.137\u001b[0m in \u001b[35m/\u001b[0m \u001b[1;36m6.807\u001b[0m x \u001b[1;36m10.507\u001b[0m cm\n", + "Required DPI Modern Age format: \u001b[1;36m121.216\u001b[0m dpi \u001b[1m(\u001b[0m\u001b[1;36m6.625\u001b[0m x \u001b[1;36m10.250\u001b[0m in\u001b[1m)\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display(IMAGE_CONTEXT.image_info)\n", + "img_visor.image_info()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Balloons and Captions Ground Truth\n", + "> The ground truth for the balloons and captions is read from a `.txt` file.\n", + "\n", + "The file is named `.gt.txt` and contains one entry per line, corresponding to each balloon or caption in the order found in PanelClenaer page data.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.',\n", + " 'The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home--',\n", + " 'And one in need of some help, it would appear.',\n", + " 'Bambu-- we have a guest.',\n", + " '--and tonight, he comes most urgently, slamming open the oaken front doors!',\n", + " 'Tell me, master-- how may Bambu serve?',\n", + " 'Some blankets to keep her warm, Bambu-- and perhaps some dry clothes',\n", + " \"The echo of the old man's footsteps fades down the hall as...\",\n", + " 'How curious the whims of fate. Had I not chanced to stroll along the river tonight--',\n", + " 'As quickly as I can, master',\n", + " '--the girl would most surely be dead by now.',\n", + " 'Ghede has been generous. the Death God has given the girl a second chance at--',\n", + " \"Easy, girl-- there's nothing to scream about anymore.\",\n", + " \"You're among friends now, you're safe!\",\n", + " 'Continued after next page']" + ] + }, + "execution_count": 63, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IMAGE_CONTEXT.gts\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Experiment\n", + "> Use `ExperimentOCR` to perform OCR on the page balloons given a `CropMethod` and a model (i.e., `'Tesseract'` or `'Idefics'`)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "def trimmed_mean(data, trim_percent):\n", + " sorted_data = np.sort(data)\n", + " n = len(data)\n", + " trim_count = int(trim_percent * n)\n", + " trimmed_data = sorted_data[trim_count:-trim_count]\n", + " return np.mean(trimmed_data)\n", + "\n", + "def mad_based_outlier(points, threshold=3.5):\n", + " median = np.median(points)\n", + " diff = np.abs(points - median)\n", + " mad = np.median(diff)\n", + " modified_z_score = 0.6745 * diff / mad\n", + " return points[modified_z_score < threshold]\n", + "\n", + "def iqr_outlier_removal(data):\n", + " q1 = np.percentile(data, 25)\n", + " q3 = np.percentile(data, 75)\n", + " iqr = q3 - q1\n", + " lower_bound = q1 - 1.5 * iqr\n", + " upper_bound = q3 + 1.5 * iqr\n", + " return data[(data >= lower_bound) & (data <= upper_bound)]\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "@dataclasses.dataclass\n", + "class Experiment:\n", + " ctx: ExperimentContext\n", + "\n", + "\n", + "@dataclasses.dataclass\n", + "class ExperimentOCR(Experiment):\n", + " ctx: ImageContext\n", + " ocr_model: str\n", + "\n", + " @property\n", + " def img_ctx(self): return self.ctx\n", + " @property\n", + " def ctxs(self):\n", + " img_ctx = self.img_ctx\n", + " return cast(OCRExperimentContext, img_ctx.exp), img_ctx\n", + "\n", + " @classmethod\n", + " def file_path_of(cls, page_data: st.PageData, ocr_model: str):\n", + " return f\"{Path(page_data.original_path).stem}_{ocr_model}.json\"\n", + " \n", + " def file_path(self):\n", + " img_ctx = self.img_ctx\n", + " return type(self).file_path_of(img_ctx.page_data, self.ocr_model)\n", + " \n", + " def to_dict(self):\n", + " \"JSON serializable dict of the experiment\"\n", + " img_ctx = self.img_ctx\n", + " img_idx = img_ctx.image_idx\n", + " results = results_to_dict(self.results())\n", + " return {\n", + " 'image_name': img_ctx.image_name,\n", + " 'ocr_model': self.ocr_model, \n", + " 'results': results,\n", + " }\n", + "\n", + " def to_json(self, out_dir: Path | None = None):\n", + " img_ctx = self.img_ctx\n", + " fp = (out_dir or img_ctx.cache_dir_image) / self.file_path()\n", + " data = self.to_dict()\n", + " with open(fp, 'w') as f:\n", + " json.dump(data, f, indent=2)\n", + " return fp, data\n", + "\n", + " @classmethod\n", + " def from_json(cls, experiment: OCRExperimentContext, json_path: Path) -> Self:\n", + " try:\n", + " with open(json_path, 'r') as f:\n", + " data = json.load(f)\n", + " except Exception as e:\n", + " logger.error(f\"Error loading {json_path}: {e}\")\n", + " raise e\n", + " ocr_model = data['ocr_model']\n", + " img_ctx = ImageContext(experiment, data['image_name'])\n", + " results: ResultSetDefault = dict_to_results(\n", + " img_ctx.image_idx, \n", + " data['results'], \n", + " result_factory=experiment._result_from)\n", + " experiment.update_results(ocr_model, img_ctx.image_idx, results)\n", + " return cls(img_ctx, ocr_model)\n", + "\n", + " @classmethod\n", + " def from_image(cls, \n", + " ctx: OCRExperimentContext, \n", + " ocr_model: str, \n", + " image_idx: ImgSpecT):\n", + " idx = cast(ImgIdT, ctx.normalize_idx(image_idx))\n", + " img_ctx = ImageContext(ctx, idx)\n", + " if img_ctx is None:\n", + " raise ValueError(f\"Image {image_idx} not found in experiment context\")\n", + " fp = img_ctx.cache_dir / cls.file_path_of(img_ctx.page_data, ocr_model)\n", + " if fp.exists(): \n", + " return cast(Self, cls.from_json(cast(OCRExperimentContext, img_ctx.exp), fp))\n", + " return cls(img_ctx, ocr_model)\n", + "\n", + " @classmethod\n", + " def from_method(cls, \n", + " ctx: OCRExperimentContext, \n", + " ocr_model: str, \n", + " image_idx: ImgIdT | str | Path, \n", + " method: CropMethod):\n", + " experiment = cls.from_image(ctx, ocr_model, image_idx)\n", + " if experiment is None:\n", + " return None\n", + " return experiment.method_experiment(method)\n", + "\n", + " @classmethod\n", + " def saved_experiment(cls, \n", + " ctx: OCRExperimentContext, ocr_model: str, image_idx: ImgIdT | str | Path):\n", + " idx = ctx.normalize_idx(image_idx)\n", + " if idx is None: \n", + " logger.warning(f\"Image {image_idx} not found in experiment context\")\n", + " return None\n", + " return cls.from_image(ctx, ocr_model, idx)\n", + "\n", + " @classmethod\n", + " def saved_experiments(cls, ctx: OCRExperimentContext, ocr_model: str) -> list[Self]:\n", + " return [exp for i in range(len(ctx.image_paths))\n", + " if (exp := cls.from_image(ctx, ocr_model, i)) is not None]\n", + " \n", + "\n", + " def result(self, box_idx: BoxIdT, method: CropMethod, ocr: bool=True, rebuild: bool=False):\n", + " ctx, img_ctx = self.ctxs\n", + " return ctx.result(self.ocr_model, img_ctx.image_idx, box_idx, method, ocr, rebuild)\n", + "\n", + " def results(self):\n", + " ctx, img_ctx = self.ctxs\n", + " return cast(ResultSet, ctx.results(self.ocr_model, img_ctx.image_idx))\n", + "\n", + " def has_run(self):\n", + " \"at least one method has run\"\n", + " img_ctx = self.img_ctx\n", + " return len(self.results()) == len(img_ctx.page_data.boxes)\n", + " \n", + " def best_results(self):\n", + " img_ctx = self.img_ctx\n", + " results = self.results()\n", + " if len(results) < len(img_ctx.page_data.boxes): # at least one method has run\n", + " return None\n", + " best = []\n", + " for box_idx in results:\n", + " methods = results[box_idx]\n", + " best_method = max(methods, key=lambda m: methods[m].acc) # type: ignore\n", + " best.append((best_method, methods[best_method]))\n", + " return best\n", + "\n", + " def save_results_as_ground_truth(self, overwrite=False):\n", + " img_ctx = self.img_ctx\n", + " gts_path = ground_truth_path(img_ctx.page_data)\n", + " if overwrite or not gts_path.exists():\n", + " best_results = self.best_results()\n", + " if best_results:\n", + " tt = [r.ocr for m,r in best_results]\n", + " gts_path.write_text('\\n'.join(tt), encoding=\"utf-8\")\n", + " img_ctx.setup_ground_truth()\n", + " logger.info(f\"Ground truth data saved successfully to {gts_path}\")\n", + " return True\n", + " else:\n", + " logger.info(\"No best results available to save.\")\n", + " return False\n", + " else:\n", + " return False\n", + "\n", + " @property\n", + " def experiments(self):\n", + " if not hasattr(self, '_experiments'):\n", + " self._experiments = {}\n", + " return self._experiments\n", + " def method_experiment(self, method: CropMethod) -> ExperimentOCRMethod:\n", + " if method not in self.experiments:\n", + " self.experiments[method] = ExperimentOCRMethod(self, method)\n", + " return self.experiments[method]\n", + " \n", + "\n", + " def to_dataframe(self):\n", + " \"Dataframe with crop methods as columns and box ids as rows\"\n", + " methods = list(CropMethod.__members__.values())\n", + " experiments = [self.method_experiment(m) for m in methods]\n", + " accuracies = [[result.acc for result in exp.results()] for exp in experiments]\n", + " # transpose accuracies\n", + " accuracies = list(zip(*accuracies))\n", + " return pd.DataFrame(accuracies, columns=CropMethod.__display_names__())\n", + "\n", + " def plot_accuracies(self, \n", + " methods: list[CropMethod] | None = None, \n", + " ):\n", + " \"Plots a horizontal bar chart of the accuracies for a list of method experiments.\"\n", + " methods = methods or list(CropMethod.__members__.values())\n", + " experiments = [self.method_experiment(m) for m in methods]\n", + " if not experiments: return\n", + "\n", + " ctx, img_ctx = self.ctxs\n", + " page_data = img_ctx.page_data\n", + " model = self.ocr_model\n", + " accuracies = [[result.acc for result in exp.results()] for exp in experiments]\n", + " accuracies = [np.mean(a) for a in accuracies]\n", + " # accuracies = [np.mean([result.acc for result in exp.results()]) for exp in experiments]\n", + "\n", + " _, ax = plt.subplots(figsize=(10, 5))\n", + " \n", + " # Normalize the accuracies for color mapping\n", + " norm = plt.Normalize(min(accuracies), max(accuracies))\n", + " # Color map from red to green\n", + " cmap = plt.get_cmap('RdYlGn')\n", + " colors = cmap(norm(accuracies))\n", + "\n", + " ax.barh([m.value for m in methods], accuracies, color=colors)\n", + "\n", + " ax.set_xscale('log') # Set the x-axis to a logarithmic scale\n", + " ax.set_xlabel('Average Accuracy (log scale)', fontsize=12, fontweight='bold')\n", + "\n", + " ax.set_ylabel('Method', fontsize=12, fontweight='bold')\n", + " ax.set_yticks(range(len(methods)))\n", + " ax.set_yticklabels([f'{method.value} ({acc:.2f})' \n", + " for method, acc in zip(methods, accuracies)], fontsize=12)\n", + " max_acc_index = np.argmax(accuracies)\n", + " ax.get_yticklabels()[max_acc_index].set(color='blue', fontweight='bold')\n", + "\n", + " title_text = (f\"{page_data.original_path} - OCR model: {model}\")\n", + " ax.set_title(title_text, fontsize=12, fontweight='bold')\n", + "\n", + " plt.tight_layout()\n", + " plt.show()\n", + "\n", + "\n", + " def summary_box(self, box_idx: int):\n", + " results: list[tuple[CropMethod, ResultOCR]] = []\n", + " pb = tqdm(CropMethod.__members__.values(), leave=False, desc=f\"Box #{box_idx+1}\")\n", + " for m in pb:\n", + " r = cast(ResultOCR, self.result(box_idx, m))\n", + " results.append((m, r))\n", + " methods, images, ocrs, accs = zip(\n", + " *map(\n", + " lambda t: (t[0].value, t[1].cache_image(), t[1].diff_tagged(), acc_as_html(t[1].acc)), \n", + " results))\n", + " display_columns([methods, images, accs, ocrs], \n", + " headers=[\"Method\", f\"Box #{box_idx+1}\", \"Accuracy\", \"OCR\"])\n", + "\n", + "\n", + " def summary_method(self, method: CropMethod):\n", + " results = self.method_experiment(method).results()\n", + " methods, images, ocrs, accs = zip(\n", + " *map(\n", + " lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), \n", + " results))\n", + " display_columns([methods, images, accs, ocrs], \n", + " headers=[\"Box #\", \"Box\", \"Accuracy\", f\"{method.value} OCR\"])\n", + "\n", + "\n", + " def display(self):\n", + " out = []\n", + " for method in CropMethod:\n", + " out.append(f\"---------- {method.value} ----------\")\n", + " results = self.method_experiment(method).results()\n", + " out.extend(results)\n", + " out.append('\\n')\n", + " cprint(*out, soft_wrap=True)\n", + "\n", + "\n", + " def reset(self, box_idx: int | None = None, method: CropMethod | None = None):\n", + " ctx, img_ctx = self.ctxs\n", + " ctx.reset_results(None, img_ctx.image_idx, box_idx, method)\n", + "\n", + " def perform_methods(self, \n", + " methods: CropMethod | list[CropMethod] | None = None, \n", + " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n", + " rebuild: bool = False,\n", + " plot_acc: bool = False\n", + " ):\n", + " if methods is None:\n", + " methods = [*CropMethod.__members__.values()]\n", + " elif isinstance(methods, CropMethod):\n", + " methods = [methods]\n", + " if rebuild:\n", + " _methods = tqdm(methods, desc=\"Methods\")\n", + " else:\n", + " _methods = methods\n", + " for method in _methods:\n", + " method_exp = self.method_experiment(method)\n", + " if method_exp: \n", + " if rebuild:\n", + " method_exp(box_idxs, rebuild=rebuild)\n", + " if plot_acc:\n", + " self.plot_accuracies()\n", + "\n", + " def __call__(self, \n", + " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n", + " methods: CropMethod | list[CropMethod] | None = None, \n", + " save: bool = True,\n", + " display=False, \n", + " rebuild: bool=False, \n", + " save_as_ground_truth=False):\n", + " self.perform_methods(methods, box_idxs, rebuild=rebuild)\n", + " if save_as_ground_truth:\n", + " self.save_results_as_ground_truth(overwrite=True)\n", + " if save:\n", + " self.to_json()\n", + " if display:\n", + " self.display()\n", + " \n", + "\n", + "@dataclasses.dataclass\n", + "class ExperimentOCRMethod:\n", + " ctx: ExperimentOCR\n", + " method: CropMethod\n", + "\n", + " @property\n", + " def exp_ctx(self): return self.ctx\n", + " @property\n", + " def img_ctx(self): return self.ctx.ctx\n", + " @property\n", + " def ctxs(self):\n", + " img_ctx = self.img_ctx\n", + " return cast(OCRExperimentContext, img_ctx.exp), img_ctx, self.ctx\n", + " \n", + " def result(self, box_idx: BoxIdT, ocr: bool=True, rebuild: bool=False) -> ResultOCR | None:\n", + " ctx, img_ctx, exp_ctx = self.ctxs\n", + " return ctx.result(exp_ctx.ocr_model, img_ctx.image_idx, box_idx, self.method, ocr, rebuild)\n", + "\n", + " def results(self, \n", + " box_idxs: BoxIdT | list[BoxIdT] | None = None, \n", + " ocr: bool=True, rebuild: bool=False) -> list[ResultOCR]:\n", + " ctx, img_ctx, exp_ctx = self.ctxs\n", + " if box_idxs is None:\n", + " box_idxs = list(range(len(img_ctx.boxes)))\n", + " elif isinstance(box_idxs, int):\n", + " box_idxs = [box_idxs]\n", + " model = exp_ctx.ocr_model\n", + " results = ctx.method_results(model, img_ctx.image_idx, self.method)\n", + " results = {i:results[i] if i in results else None for i in box_idxs}\n", + " pb = rebuild or not results or any(r is None for r in results.values())\n", + " if pb and len(results) > 2:\n", + " progress_bar = tqdm(list(results.keys()), desc=f\"{self.method.value} - {model}\")\n", + " else:\n", + " progress_bar = list(results.keys())\n", + " results = []\n", + " for i in progress_bar:\n", + " results.append(self.result(i, ocr, rebuild=rebuild))\n", + " return results\n", + "\n", + "\n", + " def get_results_html(self, \n", + " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n", + " max_image_width: int | None = None): \n", + " _, img_ctx, exp_ctx = self.ctxs\n", + " results: list[ResultOCR] = self.results(box_idxs)\n", + " accs = np.array([r.acc for r in results])\n", + " mean_accuracy = np.mean(accs)\n", + " mean_trimmed = trimmed_mean(accs, 0.1)\n", + " # filtered_data = mad_based_outlier(accs)\n", + " # mean_mad = np.mean(filtered_data)\n", + " # filtered_data = iqr_outlier_removal(accs)\n", + " # mean_iqr = np.mean(filtered_data)\n", + " \n", + " descriptions, images, ocrs, accs = zip(*map(\n", + " lambda r: (\n", + " r.block_idx+1, \n", + " r.cache_image(), \n", + " r.diff_tagged(), \n", + " acc_as_html(r.acc)\n", + " ), results))\n", + " non_breakin_space = u'\\u00A0'\n", + " tmpl = \"{}\"\n", + " padded_s = lambda s,n: tmpl.format(s.rjust(n))\n", + " acc_fmt = f\"{mean_accuracy:.2f}/{mean_trimmed:.2f}\"\n", + " w, h = img_ctx.base_image.size\n", + " dim, _dpi = size(w, h), dpi(w, h)\n", + " dim_fmt = f\"{w}x{h} px: {dim[0]:.2f} x {dim[1]:.2f} in @ {_dpi:.2f} dpi\"\n", + " return '\\n
\\n'.join([\n", + " (\"
\"\n", + " f\"{padded_s('Page', 24)}: {img_ctx.page_data.original_path}
\"\n", + " f\"{padded_s('Size', 24)}: {dim_fmt}
\"\n", + " f\"{padded_s('Model', 24)}: {exp_ctx.ocr_model}
\"\n", + " f\"{padded_s('Crop Method', 24)}: {self.method.value}
\"\n", + " f\"{padded_s('Accuracy Mean/Trimmed', 24)}: {acc_fmt}\"\n", + " \"
\"), \n", + " get_columns_html(\n", + " [descriptions, images, accs, ocrs], \n", + " max_image_width, \n", + " headers=[\"Box #\", \"Image\", \"Accuracy\", \"OCR\"]),\n", + " ])\n", + "\n", + " def display(self, \n", + " box_idxs: BoxIdT | list[BoxIdT] | None = None, max_image_width: int | None = None):\n", + " display(HTML(self.get_results_html(box_idxs, max_image_width)))\n", + "\n", + "\n", + " def summary(self):\n", + " results = self.results()\n", + " methods, images, ocrs, accs = zip(\n", + " *map(\n", + " lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), \n", + " results))\n", + " display_columns([methods, images, accs, ocrs], \n", + " headers=[\"Box #\", \"Box\", \"Accuracy\", f\"{self.method.value} OCR\"])\n", + "\n", + "\n", + " def reset(self):\n", + " _, _, exp_ctx = self.ctxs\n", + " exp_ctx.reset(method=self.method)\n", + " \n", + " def __call__(self, box_idxs: BoxIdT | list[BoxIdT] | None = None, display=False, rebuild=False):\n", + " if isinstance(box_idxs, int):\n", + " result = self.result(cast(BoxIdT, box_idxs), rebuild=rebuild)\n", + " if result is not None and display:\n", + " result.display()\n", + " else:\n", + " results = self.results(box_idxs, rebuild=rebuild)\n", + " if results and display:\n", + " self.display(box_idxs)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Box id\n", + "> change `BOX_IDX` to use any box to test crop methods" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "BOX_IDX = 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Crop methods testing" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT.reset()\n", + "test_eq(CONTEXT.results(), {})\n", + "\n", + "image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Tesseract')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Single box results\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### comics_text_detector initial boxes + padding" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Initial box" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[32m2024-05-10 20:25:26.385\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpcleaner.ocr.ocr_mangaocr\u001b[0m:\u001b[36m__new__\u001b[0m:\u001b[36m15\u001b[0m - \u001b[1mCreating the MangaOcr instance\u001b[0m\n" + ] + }, + { + "data": { + "text/html": [ + "
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
0.90
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.⎕⎕

Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method = CropMethod.INITIAL_BOX\n", + "\n", + "result = image_experiment.result(BOX_IDX, method, ocr=False)\n", + "assert result is not None\n", + "\n", + "image = result.image\n", + "assert image is not None\n", + "text = CONTEXT.mocr('Tesseract', page_lang)(image)\n", + "result.ocr = postprocess_ocr(text)\n", + "result\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### PanelCleaner default pad" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as
0.85
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orl⎕⎕⎕eans, kept tidy by a white-haired old man known only as Bambu.

Eneowered by great gnarled cypress jrfes, the ancient manor !⎕⎕⎕⎕⎕ alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired ao⎕⎕ han known only as⎕⎕⎕⎕⎕⎕⎕
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method = CropMethod.DEFAULT\n", + "\n", + "result = image_experiment.result(BOX_IDX, method, ocr=False)\n", + "assert result is not None\n", + "\n", + "CONTEXT.ocr_box(result, 'Tesseract', page_lang)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### PanelCleaner default pad, grey pad" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as
0.95
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as⎕⎕⎕⎕⎕⎕⎕
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method = CropMethod.DEFAULT_GREY_PAD\n", + "result = image_experiment.result(BOX_IDX, method)\n", + "result\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### padded, 4px" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as
0.88
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orl⎕⎕⎕eans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired aolo man known only as⎕⎕⎕⎕⎕⎕⎕
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PADDED_4)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### padded, 8px" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as
0.88
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired aolo man known omy as⎕⎕⎕⎕⎕⎕⎕
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PADDED_8)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Extracted text" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Extracted text, initial box\n", + "\n", + "Unfortunately, the `comic-text_detector` does not remove letter holes from the text mask, despite using OpenCV. This oversight likely impacts the accuracy of the OCR results." + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.92
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu⎕⎕.

Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a white-haire old man known only as bambi] .
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method = CropMethod.EXTRACTED_INIT_BOX\n", + "# results[method] = IMAGE_CONTEXT.result(BOX_IDX, method)\n", + "# image = results[method].image\n", + "# assert image is not None\n", + "# results[method].ocr = postprocess_ocr(IMAGE_CONTEXT.mocr(image))\n", + "# display_extracted_result(None, None, results[method], IMAGE_CONTEXT.gts[BOX_IDX])\n", + "image_experiment.result(BOX_IDX, method)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### padded 4, extracted" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.91
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonsred by great shale cypress trees, the anci⎕⎕⎕ manor stands alone on the [tskirts of new orleans, kept tidy by a white-haired old man known only as b8ambl .
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PADDED_4_EXTRACTED)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### padded 8, extracted" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.94
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu⎕⎕.

Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as 8ambli .
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PADDED_8_EXTRACTED)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### padded 8, dilation 1, extracted" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.61
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

O⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕utskirts of new orleans, kept tipy by a white-haired old man known only as sams .
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PADDED_8_DILATION_1)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### padded 8, dilation 0.5, extracted" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.94
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PAD_8_FRACT_0_5)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### padded 8, dilation 0.2, extracted" + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.94
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PAD_8_FRACT_0_2)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Summary\n", + "> Use `ImageContext.summary_box` to display the results of the crop methods for OCR of a given box index.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "2b5b75333766431bb85d2ae72ee47b50", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Box #1: 0%| | 0/11 [00:00MethodBox #1AccuracyOCRInitial box
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
Default
0.85
Eneowered by great gnarled cypress jrfes, the ancient manor !⎕⎕⎕⎕⎕ alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired ao⎕⎕ han known only as⎕⎕⎕⎕⎕⎕⎕
Default, grey pad
0.95
Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as⎕⎕⎕⎕⎕⎕⎕
Padded 4px
0.88
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired aolo man known only as⎕⎕⎕⎕⎕⎕⎕
Padded 8px
0.88
Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired aolo man known omy as⎕⎕⎕⎕⎕⎕⎕
Extracted, init box
0.92
Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a white-haire old man known only as bambi] .
Padded 4, extracted
0.91
Enbonsred by great shale cypress trees, the anci⎕⎕⎕ manor stands alone on the [tskirts of new orleans, kept tidy by a white-haired old man known only as b8ambl .
Padded 8, extracted
0.94
Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as 8ambli .
Padded 8, dilation 1
0.61
O⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕utskirts of new orleans, kept tipy by a white-haired old man known only as sams .
Pad 8, fract. 0.5
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
Pad 8, fract. 0.2
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# methods, images, ocrs, accs = zip(\n", + "# *map(lambda t: (t[0].value, t[1].cache_image(), t[1].diff_tagged(), acc_as_html(t[1].acc)), \n", + "# IMAGE_CONTEXT.results[BOX_IDX].items()))\n", + "# display_columns([methods, images, accs, ocrs], headers=[\"Method\", \"Box\", \"Accuracy\", \"OCR\"])\n", + "\n", + "image_experiment.summary_box(BOX_IDX)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Show result for any box # and any method" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Tonight, he comes host slamming open
0.61
\n", + "
\n", + "
--and tonight, he comes most urgently, slamming open the oaken front doors!

T⎕⎕⎕⎕⎕⎕onight, he comes host⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(4, CropMethod.PADDED_8)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.67
\n", + "
\n", + "
Bambu-- we have a guest.

⎕⎕⎕⎕⎕⎕ we have a i=s7t.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(3, CropMethod.EXTRACTED_INIT_BOX)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ResultVisor" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ResultVisor(ContextVisor):\n", + " ctx: ExperimentOCR\n", + " control_names: list[str] = ['all_boxes', 'box_idx', 'all_methods', 'method']\n", + "\n", + " _css = \"\"\"\n", + " .box_grp {\n", + " background-color: aliceblue;\n", + " }\n", + " .method_grp {\n", + " background-color: #ededed;\n", + " }\n", + " \"\"\"\n", + " \n", + " def best_results(self): \n", + " ll = self.ctx.best_results()\n", + " if ll:\n", + " cprint([(m.value, f\"{r.acc:.3f}\", r.ocr) for m,r in ll])\n", + "\n", + " def pd_to_html(self):\n", + " df = self.ctx.to_dataframe()\n", + " # set float precision\n", + " df = df.round(3)\n", + " # display floats with 3 decimal digits\n", + " df = df.applymap(lambda x: f\"{x:.3f}\")\n", + " # highlight max value in each row\n", + " stl = df.style.highlight_max(axis=0)\n", + " display(HTML(stl.to_html()))\n", + "\n", + " def update_output(self, **kwargs):\n", + " all_boxes: bool = self.values['all_boxes']\n", + " box_idx: int = self.values['box_idx']\n", + " all_methods: bool = self.values['all_methods']\n", + " method: CropMethod = self.values['method']\n", + "\n", + " # cprint(f\"all_boxes: {all_boxes}, box_idx: {box_idx}, all_methods: {all_methods}, method: {method}\")\n", + "\n", + " if all_boxes and all_methods:\n", + " self.ctx.plot_accuracies()\n", + " elif all_boxes:\n", + " self.ctx.summary_method(method)\n", + " elif all_methods:\n", + " self.ctx.summary_box(box_idx)\n", + " else:\n", + " result = self.ctx.result(box_idx, method)\n", + " if result is not None:\n", + " result.display()\n", + "\n", + " def setup_controls(self):\n", + " _, img_ctx = self.ctx.ctxs\n", + " values = self.values\n", + " box_wdgt = W.BoundedIntText(\n", + " value=values['box_idx'], min=0, max=len(img_ctx.boxes)-1, step=1,\n", + " disabled=values['all_boxes'],\n", + " layout={'width': '50px'},\n", + " style={'description_width': 'initial'})\n", + " methods_wdgt = W.Dropdown(\n", + " options=CropMethod.__display_names__(), \n", + " value=values['method'],\n", + " layout={'width': '150px'},\n", + " style={'description_width': 'initial'})\n", + " all_boxes_wdgt = W.Checkbox(label='All', value=values['all_boxes'], \n", + " description=\"all\", \n", + " layout={'width': 'initial'},\n", + " style={'description_width': '0px'})\n", + " all_methods_wdgt = W.Checkbox(label='All', value=values['all_methods'], \n", + " description=\"all\", \n", + " layout={'width': 'initial'},\n", + " style={'description_width': '0px'})\n", + " return {'all_boxes': all_boxes_wdgt, 'box_idx': box_wdgt, \n", + " 'all_methods': all_methods_wdgt, 'method': methods_wdgt}\n", + " \n", + " def setup_ui(self):\n", + " ctls = self.controls\n", + " _, img_ctx = self.ctx.ctxs\n", + " box_label = W.Label(\n", + " value=f\"Box # (of {len(img_ctx.boxes)}):\", \n", + " layout={'width': 'initial', 'padding': '0px 0px 0px 10px'})\n", + " method_label = W.Label(value='Method:', layout={'width': 'initial', 'padding': '0px 0px 0px 10px'})\n", + "\n", + " box_grp = W.HBox([box_label, ctls['all_boxes'], ctls['box_idx']])\n", + " box_grp.add_class('box_grp')\n", + " method_grp = W.HBox([method_label, ctls['all_methods'], ctls['method']])\n", + " method_grp.add_class('method_grp')\n", + " \n", + " return W.HBox([box_grp, method_grp])\n", + "\n", + " def __init__(self, \n", + " ctx: OCRExperimentContext | ExperimentOCR,\n", + " img_idx: int | str | Path | None = None,\n", + " all_boxes: bool = False,\n", + " box_idx: int = 0,\n", + " all_methods: bool = False,\n", + " method: CropMethod=CropMethod.INITIAL_BOX,\n", + " out: W.Output | None = None,\n", + " ):\n", + " if isinstance(ctx, OCRExperimentContext):\n", + " assert img_idx is not None, \"img_idx must be provided if ctx is an ExperimentContext\"\n", + " exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx)\n", + " if not exp:\n", + " raise ValueError(f\"Image {img_idx} not found in experiment context\")\n", + " ctx = exp\n", + " else:\n", + " if not isinstance(ctx, ExperimentOCR):\n", + " raise ValueError(\"ctx must be an ExperimentOCR or OCRExperimentContext\")\n", + " \n", + " super().__init__(ctx, {'all_boxes': all_boxes, 'box_idx': box_idx, \n", + " 'all_methods': all_methods, 'method': method}, out=out or self.out)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "400781b58e3e43cb868c0c278fd3ecd2", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output(layout=Layout(height='0px'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "2f2917080eb943acb8b665e1fa607c13", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Label(value='Box # (of 15):', layout=Layout(padding='0px 0px 0px 10px', width='i…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "81027eadfa3d40b6a81efcd991f2379a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('result_visor')\n", + "\n", + "result_visor = ResultVisor(image_experiment)\n", + "result_visor\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ExperimentVisor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ExperimentVisor(ContextVisor):\n", + " ctx: ExperimentOCR\n", + "\n", + " def update_output(self, \n", + " image_idx: int | None = None,\n", + " **kwargs):\n", + " exp_ctx, img_ctx = self.ctx.ctxs\n", + " if image_idx is not None and image_idx != img_ctx.image_idx:\n", + " ctx = ImageContext(exp_ctx, image_idx)\n", + " assert ctx is not None\n", + " self.ctx.ctx = ctx\n", + " result_visor = self.comp('result_visor')\n", + " if result_visor is not None:\n", + " result_visor.update_output(**kwargs)\n", + "\n", + " def __init__(self, \n", + " ctx: OCRExperimentContext | ExperimentOCR,\n", + " img_idx: int | str | Path | None = None,\n", + " all_boxes: bool = False,\n", + " box_idx: int = 0,\n", + " all_methods: bool = False,\n", + " method: CropMethod=CropMethod.INITIAL_BOX,\n", + " out: W.Output | None = None,\n", + " ):\n", + " if isinstance(ctx, OCRExperimentContext):\n", + " assert img_idx is not None, \"img_idx must be provided if ctx is an ExperimentContext\"\n", + " exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx)\n", + " if not exp:\n", + " raise ValueError(f\"Image {img_idx} not found in experiment context\")\n", + " ctx = exp\n", + " else:\n", + " if not issubclass(type(ctx), ExperimentOCR):\n", + " raise ValueError(\"ctx must be an ExperimentOCR or OCRExperimentContext\")\n", + " \n", + " exp_ctx, img_ctx = ctx.ctxs\n", + " out = out or self.out\n", + " image_selector = ImageSelector(exp_ctx, image_idx=img_ctx.image_idx, out=out)\n", + " result_visor = ResultVisor(ctx, out=out,\n", + " all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method)\n", + "\n", + " super().__init__(ctx, {}, out=out, \n", + " ctxs={'image_selector': image_selector, 'result_visor': result_visor},\n", + " hdlrs={'display_option': result_visor}\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "1e40a9f23a674b48abd50720e6523c2c", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5af1d96d5d9942fd8e895787ff50bbe5", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('exp_visor')\n", + "\n", + "exp_visor = ExperimentVisor(image_experiment)\n", + "exp_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": {}, + "outputs": [], + "source": [ + "exp_visor.update(box_idx=1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [], + "source": [ + "exp_visor.update(image_idx=0)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Method experiment\n", + "> perform method on one or more boxes" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT.reset()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [], + "source": [ + "image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Tesseract')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualize summary of crop methods on a given box\n" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "151bc83d198e447d8932fe48aa7ef2e6", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Box #2: 0%| | 0/11 [00:00MethodBox #2AccuracyOCRInitial box
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
Default
0.96
The house and the old man are alike in many ways; tall, proud, patient, contentel always to wait until their. master cones home ~~
Default, grey pad
0.96
The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their.⎕* master cones home⎕~-
Padded 4px
0.93
The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }
Padded 8px
0.99
The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home⎕⎕
Extracted, init box
0.93
Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~
Padded 4, extracted
0.98
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home--
Padded 8, extracted
0.98
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home--
Padded 8, dilation 1
0.88
The house and the old man are alike in many ways, tall, proud, ⎕⎕⎕⎕⎕nt, contented live⎕⎕⎕⎕ walt gtie their, master comes home-=
Pad 8, fract. 0.5
0.97
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~
Pad 8, fract. 0.2
0.97
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.summary_box(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Results for any crop method" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Box #BoxAccuracyPadded 4px OCR
1
0.88
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired aolo man known only as⎕⎕⎕⎕⎕⎕⎕
2
0.93
The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }
3
0.69
F and one in ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.77
" bambli- we have a gliest.
5
0.55
P⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ comes⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.57
Tel oe ⎕⎕⎕⎕er-- 5 ow a =⎕⎕⎕⎕ 7⎕⎕⎕⎕⎕
7
0.38
W⎕⎕e⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps c oe /⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
8
0.75
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall sra⎕⎕⎕⎕
9
0.92
How curious the a⎕whims of fate. - had i not chanced to stroll along the river yl⎕tonight~-
10
0.79
A⎕⎕⎕ulckly as t can, masrer.
11
0.92
<the girl wolld⎕- most surely be dead by now.
12
0.88
Ghede has been generous. the oeath gop has given -⎕the girl. a second chance ye,⎕alem
13
0.67
Soe⎕⎕ ⎕⎕⎕⎕⎕⎕⎕⎕⎕ereke othing to scream ay⎕⎕⎕ anymore.
14
0.94
"you're among friends now. you're safe!
15
1.00
Continued after next page
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.summary_method(CropMethod.PADDED_4)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can use method experiment directly" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
0.90
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.⎕⎕

Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method_experiment = cast(ExperimentOCRMethod, \n", + " ExperimentOCR.from_method(CONTEXT, 'Tesseract', IMAGE_CONTEXT.image_idx, CropMethod.INITIAL_BOX))\n", + "method_experiment(BOX_IDX, display=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "for all boxes" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Initial box
Accuracy Mean/Trimmed: 0.79/0.80
\n", + "
\n", + "
Box #ImageAccuracyOCR
1
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
3
0.70
“and one in ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.62
Re bambli-~ we have a⎕⎕⎕⎕⎕⎕⎕
5
0.70
T⎕⎕⎕⎕⎕⎕onight, he comes noost⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.82
Tell me naster. how may bambli serve 7
7
0.56
£7⎕⎕ »⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
8
0.81
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man'⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall as...⎕7
9
0.85
How curious the 4⎕fate.⎕whims of h⎕⎕⎕⎕⎕⎕ad t not chanced to stroll along the river yl⎕tonight ==
10
0.80
Fas oulckly as t ca, master.
11
0.91
<the girl would -⎕most slirely be dead by now.
12
0.47
A⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕th⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ the girl. a second chance ge⎕a ee yg adil
13
0.84
Ah⎕⎕⎕ girl--there's othing to scream nt⎕⎕t anymore.
14
0.93
You're among friends now. you're sale
15
1.00
Continued after next page
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method_experiment(display=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or selected boxes" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT.reset()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Initial box
Accuracy Mean/Trimmed: 0.80/nan
\n", + "
\n", + "
Box #ImageAccuracyOCR
1
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
7
0.56
£7⎕⎕ »⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
10
0.80
Fas oulckly as t ca, master.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method_experiment = cast(ExperimentOCRMethod, \n", + " ExperimentOCR.from_method(CONTEXT, 'Tesseract', IMAGE_CONTEXT.image_idx, CropMethod.INITIAL_BOX))\n", + "method_experiment([0, 1, 6, 9], display=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Full page results\n", + "> all methods on all boxes" + ] + }, + { + "cell_type": "code", + "execution_count": 97, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT.reset()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [], + "source": [ + "image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Tesseract')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 100, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Initial box
Accuracy Mean/Trimmed: 0.79/0.80
\n", + "
\n", + "
Box #ImageAccuracyOCR
1
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
3
0.70
“and one in ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.62
Re bambli-~ we have a⎕⎕⎕⎕⎕⎕⎕
5
0.70
T⎕⎕⎕⎕⎕⎕onight, he comes noost⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.82
Tell me naster. how may bambli serve 7
7
0.56
£7⎕⎕ »⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
8
0.81
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man'⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall as...⎕7
9
0.85
How curious the 4⎕fate.⎕whims of h⎕⎕⎕⎕⎕⎕ad t not chanced to stroll along the river yl⎕tonight ==
10
0.80
Fas oulckly as t ca, master.
11
0.91
<the girl would -⎕most slirely be dead by now.
12
0.47
A⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕th⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ the girl. a second chance ge⎕a ee yg adil
13
0.84
Ah⎕⎕⎕ girl--there's othing to scream nt⎕⎕t anymore.
14
0.93
You're among friends now. you're sale
15
1.00
Continued after next page
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method = CropMethod.INITIAL_BOX\n", + "# method = CropMethod.DEFAULT\n", + "# method = CropMethod.PADDED_4\n", + "# method = CropMethod.PADDED_8\n", + "# method = CropMethod.EXTRACTED_INIT_BOX\n", + "# method = CropMethod.PAD_8_FRACT_0_5\n", + "# method = CropMethod.PAD_8_FRACT_0_2\n", + "\n", + "# image_experiment.method_experiment(CropMethod.INITIAL_BOX).results()\n", + "initial_box_exp = image_experiment.method_experiment(CropMethod.INITIAL_BOX)\n", + "initial_box_exp(display=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Other method" + ] + }, + { + "cell_type": "code", + "execution_count": 102, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as,\n", + " ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~,\n", + " ResultOCR#block 02: 0.74||And one in ee would appear.,\n", + " ResultOCR#block 03: 0.41||Rir guest.,\n", + " ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo,\n", + " ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _,\n", + " ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps,\n", + " ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00,\n", + " ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >,\n", + " ResultOCR#block 09: 0.50||Aulckly “master as t can,,\n", + " ResultOCR#block 10: 0.94||" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.perform_methods(plot_acc=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 101, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
---------- Initial box ----------\n",
+       "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
+       "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
+       "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
+       "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
+       "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
+       "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
+       "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes... 7 /\n",
+       "ResultOCR#block 07: 0.81||The the old man's fades down the hall as... 7\n",
+       "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
+       "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
+       "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
+       "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
+       "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
+       "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Default ----------\n",
+       "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
+       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
+       "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
+       "ResultOCR#block 03: 0.41||Rir guest.\n",
+       "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
+       "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
+       "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
+       "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
+       "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
+       "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
+       "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
+       "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
+       "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
+       "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Default, grey pad ----------\n",
+       "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
+       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
+       "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
+       "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
+       "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
+       "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+       "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7 /.\n",
+       "ResultOCR#block 07: 0.06||As.\n",
+       "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
+       "ResultOCR#block 09: 0.55||Ickl as t can\n",
+       "ResultOCR#block 10: 0.00||\n",
+       "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
+       "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
+       "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 0.54||“continued a\n",
+       "\n",
+       " ---------- Padded 4px ----------\n",
+       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
+       "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
+       "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
+       "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
+       "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
+       "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
+       "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
+       "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
+       "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
+       "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
+       "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
+       "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
+       "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
+       "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Padded 8px ----------\n",
+       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
+       "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
+       "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
+       "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
+       "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
+       "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
+       "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
+       "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
+       "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
+       "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
+       "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
+       "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
+       "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
+       "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 0.94||“continued after next page\n",
+       "\n",
+       " ---------- Extracted, init box ----------\n",
+       "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
+       "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
+       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+       "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
+       "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
+       "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
+       "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
+       "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
+       "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
+       "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
+       "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
+       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+       "\n",
+       " ---------- Padded 4, extracted ----------\n",
+       "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
+       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+       "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
+       "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
+       "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
+       "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
+       "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
+       "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+       "\n",
+       " ---------- Padded 8, extracted ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
+       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
+       "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
+       "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
+       "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Padded 8, dilation 1 ----------\n",
+       "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
+       "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
+       "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
+       "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
+       "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
+       "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
+       "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
+       "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
+       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
+       "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
+       "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Pad 8, fract. 0.5 ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
+       "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
+       "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Pad 8, fract. 0.2 ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
+       "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
+       "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + "---------- Initial box ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n", + "\n", + " ---------- Padded 4px ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m||" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.plot_accuracies()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 103, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "RenderJSON(image_experiment.to_dict(), 400, 2)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "best results" + ] + }, + { + "cell_type": "code", + "execution_count": 104, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n",
+       "    (\n",
+       "        'Default, grey pad',\n",
+       "        '0.953',\n",
+       "        'Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of \n",
+       "new orleans, kept tipy by a white-haired old man known only as'\n",
+       "    ),\n",
+       "    (\n",
+       "        'Padded 8px',\n",
+       "        '0.988',\n",
+       "        'The house and the old man are alike in many ways; tall, proud, patient, contented always to \n",
+       "wait until their. master comes home'\n",
+       "    ),\n",
+       "    ('Padded 8, dilation 1', '0.968', 'And one in need of some help, it wolld appear .'),\n",
+       "    ('Default, grey pad', '0.880', '\" bambl-- we have a guest.'),\n",
+       "    ('Padded 8, dilation 1', '0.794', '=and tonight, he comes most slamming open the front'),\n",
+       "    ('Default, grey pad', '0.857', 'Tell me, master: how may bambli serve 7'),\n",
+       "    (\n",
+       "        'Pad 8, fract. 0.5',\n",
+       "        '0.935',\n",
+       "        'Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes'\n",
+       "    ),\n",
+       "    ('Initial box', '0.811', \"The the old man's fades down the hall as... 7\"),\n",
+       "    (\n",
+       "        'Padded 8, extracted',\n",
+       "        '0.959',\n",
+       "        'How curious the whims of fate . had i not chanced to stroll along the river tonight-~'\n",
+       "    ),\n",
+       "    ('Extracted, init box', '0.846', 'Aulckly as t can, master,'),\n",
+       "    ('Extracted, init box', '1.000', '--the girl would most surely be dead by now.'),\n",
+       "    (\n",
+       "        'Padded 8, extracted',\n",
+       "        '0.935',\n",
+       "        'Ghede has been generous. the peath god has given the girl a second chance po'\n",
+       "    ),\n",
+       "    ('Default, grey pad', '0.953', \"Easy, girl--there's | nothing to scream about anyaore.\"),\n",
+       "    ('Default, grey pad', '0.974', \"You're among friends now. you're safe!\"),\n",
+       "    ('Initial box', '1.000', 'Continued after next page')\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1m(\u001b[0m\n", + " \u001b[32m'Default, grey pad'\u001b[0m,\n", + " \u001b[32m'0.953'\u001b[0m,\n", + " \u001b[32m'Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of \u001b[0m\n", + "\u001b[32mnew orleans, kept tipy by a white-haired old man known only as'\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\n", + " \u001b[32m'Padded 8px'\u001b[0m,\n", + " \u001b[32m'0.988'\u001b[0m,\n", + " \u001b[32m'The house and the old man are alike in many ways; tall, proud, patient, contented always to \u001b[0m\n", + "\u001b[32mwait until their. master comes home'\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Padded 8, dilation 1'\u001b[0m, \u001b[32m'0.968'\u001b[0m, \u001b[32m'And one in need of some help, it wolld appear .'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.880'\u001b[0m, \u001b[32m'\" bambl-- we have a guest.'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Padded 8, dilation 1'\u001b[0m, \u001b[32m'0.794'\u001b[0m, \u001b[32m'=and tonight, he comes most slamming open the front'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.857'\u001b[0m, \u001b[32m'Tell me, master: how may bambli serve 7'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\n", + " \u001b[32m'Pad 8, fract. 0.5'\u001b[0m,\n", + " \u001b[32m'0.935'\u001b[0m,\n", + " \u001b[32m'Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes'\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Initial box'\u001b[0m, \u001b[32m'0.811'\u001b[0m, \u001b[32m\"The the old man's fades down the hall as... 7\"\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\n", + " \u001b[32m'Padded 8, extracted'\u001b[0m,\n", + " \u001b[32m'0.959'\u001b[0m,\n", + " \u001b[32m'How curious the whims of fate . had i not chanced to stroll along the river tonight-~'\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Extracted, init box'\u001b[0m, \u001b[32m'0.846'\u001b[0m, \u001b[32m'Aulckly as t can, master,'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Extracted, init box'\u001b[0m, \u001b[32m'1.000'\u001b[0m, \u001b[32m'--the girl would most surely be dead by now.'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\n", + " \u001b[32m'Padded 8, extracted'\u001b[0m,\n", + " \u001b[32m'0.935'\u001b[0m,\n", + " \u001b[32m'Ghede has been generous. the peath god has given the girl a second chance po'\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.953'\u001b[0m, \u001b[32m\"Easy, girl--there's | nothing to scream about anyaore.\"\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.974'\u001b[0m, \u001b[32m\"You're among friends now. you're safe!\"\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1m(\u001b[0m\u001b[32m'Initial box'\u001b[0m, \u001b[32m'1.000'\u001b[0m, \u001b[32m'Continued after next page'\u001b[0m\u001b[1m)\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ll = image_experiment.best_results()\n", + "if ll:\n", + " cprint([(m.value, f\"{r.acc:.3f}\", r.ocr) for m,r in ll])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perfom experiments given a list of `CropMethod`s\n" + ] + }, + { + "cell_type": "code", + "execution_count": 105, + "metadata": {}, + "outputs": [], + "source": [ + "# methods = [*CropMethod.__members__.values()]\n", + "methods = [CropMethod.INITIAL_BOX, CropMethod.DEFAULT]\n", + "image_experiment.perform_methods(methods)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Plot the perfomance of the experiments" + ] + }, + { + "cell_type": "code", + "execution_count": 106, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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lagPAP9A7qMs7n/Jb9CggVU+adIkq7xkyZJGkgkODrbKmjRpkuVfwiWZGjVqGGOMef/9962yzp07e7SlcePG1rrLjXSnpaWZ0aNHm/r165uIiAivIzM//vijVX/69OlGkhk7dmyG12Dq1Knmxhtv9LqPiIgI88cff1h1Bw8enOVf+N1HuteuXZth/V9//WX69+9vqlatao18uj9CQkKsuu6jgh07drTKt23bZpW3bt3aGGPMjh07PEY/3Eeunn/++QwjIStWrLjseybJzJ07N8MxXE5Wo0k5Pf6ctts10hQUFGQefPBB8+6775ply5aZkydPZvu43GVnpDs5Odn63Pj5+Zldu3ZlWf/w4cMeI1UvvfSSx/rKlStb69xPe01LS/N4Df7880+zbt066+fSpUt77OfDDz+01rVp08YqnzZtmpk9e7Y5ePCgOXfunPn5559N3bp1rbruo+5Z8dYH3N/T//u///Oo7/75X7hwoUlKSjJ+fn5Gco40ur9nEydOtOraMdLtPiL89NNPe63z1FNPWXXatm1rjDFm5MiRVlmtWrV8ei737+BLH8WKFTMfffSRT/tx/9w1bNjQKp8wYYJVftNNN1nlgwYNssr/85//GGM8+4T7d44xxnTo0MFa52qTq19LMtu2bbPqLlu2zCp3jVKfO3fOBAQEXPaz+/jjjxtjsh7pzqnMvpvs+l6pXbu29Xvk8ccfNxMnTjSrVq0yZ86csers2rXLp+cePXp0hmOoWLGi18ui1q5da9q3b28iIyO9jt4/8sgjxhhjvv76a6usQoUKHr83LnW5332AN8xeDgBeVKxY0VoODQ21lsuVK2ctu0ZuXH8Zl7yPkl3KNULgPnJ66WhIdHS0fvjhB5/a+vTTT1sj5plxjSxK0pw5cyTJ6+hmz5491bNnTx0/flw//PCDFi9erGnTpiktLU0JCQn66quv1K9fP5/a5a5evXoeP1+4cEEtW7bU1q1bM90ms1sQuU/oFhYWlqG+++taunRp+fv7Wz97m/jKl/fs0v1eqSs5fpfstvvtt99WXFycvvvuO3344YfW+sDAQD3xxBMaM2aMT/u7EjNnztSff/4pSerQoYPH5+xS27dv1x133GGNtA4bNkwvvfSSR50SJUro999/lySPszlcI46S8/gKFy7scZaDe91L65coUcJa7tGjh0e9unXr6t1331XTpk0lSevWrcu0/dkRHR2d4WfX5//48eM6efKkLly4IMk5Ku8+Up+d25BNnTrVGuVzad68uddbvXlr2969e73WcS931Xcf/d69e7dSUlJyPNotOb9nczI5Vna+y6WLnzv3z9el74/7a+6ql9n3+aXbSrLOmric3D67xhd2fa98/PHH6tWrl7Zu3erx+yo0NFTDhg3TM888c0XfxXXq1LHuUuCyfv163XLLLTp//nym+3L9bnR9L0lS9erVPX5vALmB08sBwIvMTtm83Kmc7v9h/+GHH7zOeOw6dbxo0aJW3UOHDnnsx3WKpi9mzJhhLc+bN08pKSkyxni9rU5iYqKWL1+uhg0bqmzZsh7rEhISrOXixYurQ4cO+vDDDz1uExYfH28tZ+dervny5fP4edu2bVbgLFGihLZt26b09HSPNmQmMDAwyzYUK1bMWj5y5IgVViTPU15d3N+z1q1be33PXDNb55YrOf6ctjs6Olrffvutjh07ppUrV+rDDz9UgwYNlJaWprFjx+rHH3/MtePLzFtvvWUtP/vss5nWW7t2rZo2baqDBw8qMDBQn3zySYbALUmNGjWylt1POXW/tVWdOnUUGBio8uXLq3jx4pKcs6C7f8bc6zds2FCSPPpNZi79T35OXfp5d/+5ePHiKlSokBUCTp8+7dFPvPXp3HTHHXdYy0uXLtXRo0c91h8+fFjLli2zfm7Tpo0kqWXLltYfxc6ePat3333X6/4zC5+DBw9WamqqFi1apHz58ikhIUFPPvmkxyUYvsiN7/JL3x/3Wehd9TL7Pvf2XV6kSBHr+cPDw63v7Esfn376aZZttINd3yt16tTRli1bdOjQIS1btkzjx49XlSpVdO7cOQ0YMEBHjhzxeO6qVat6fW5jjHWJlrtLf8dIzlP0XYG7W7duiouLkzHGa18sWbKktfzbb79l+fnnPubICUI3AOSijh07WsuPPfaYfv75Z6WkpCg+Pl5ffvmlunTpohEjRkiSbrvtNuuX96JFi7R48WKdOXNG06ZN83mUW/L8z2N4eLjS09M1adIkj3sRuyxevFjJycnWdYMu6enpKlu2rJ588kl98803OnnypNLS0rR161atXbvWqnfDDTdYy+7X4v73v//1aeTGW5v9/f2VP39+nT592uO68pyqVKmSNRJ1/Phxvf7669Z1eR999FGG+k2aNLGC+vLlyzV69GjFx8crJSVFO3bs0MiRI7Mckc2J3Dj+7Lb7zTff1MyZM5WQkKBGjRrp3nvv9bjdl/u1u5dz9uxZxcXFKS4uzuN9P336tFV+qeXLl1vBuGHDhmrSpInXfc+ePVutWrXSyZMnVaBAAS1dulQPPPCA17q9evWywuiECRO0adMmHTlyxOOaywcffNBa7tOnj7U8cOBAxcXFaeXKldbZHxEREbrvvvskOV+PBg0aaPr06Tpy5IhSUlK0adMmPfXUU9Y+mjdv7tEeh8Mhh8ORrdFnSdY9qC/9/IeGhqpp06bKly+fNbpujNHAgQN18uRJbdu2TaNGjfL5eXr16pUhwGQ1yi1J7du3t655TklJUefOnbVlyxalpaVpy5Yt6ty5s1JTUyVJ9evXV/v27SU5r5t/+eWXrf28/PLLGjVqlI4ePaq0tDTt2bNHY8eOtep7ExgYqDvvvFOvv/66VfbUU095nF1klzZt2igoKEiS83vziy++UFJSkubPn29dax0UFKTWrVtLklq1amVt+8ILL+jYsWM6ePCgR190CQkJsf44kZiYaF0/nJaWpkOHDmnatGlq0qSJx3dvZlx9LreCoF3fKy+++KLmz5+v9PR0NWvWTPfee6+1H2OM/vjjD1WsWFE1atSQJO3YsUMDBgyw+svevXs1YcIE1apVy+c/Srt/z4aEhCg0NFRbtmzRO++84/W4XX+U2717tx5++GEdPHhQSUlJWr9+vSZNmmTVvZLffbiO2XjqOgDkKZndpst9NnL3cvdrll2Sk5NNixYtsrwezX1W3sxmL3efcfdy13Q/8sgjGbbPly+fKV26dIZ9dOzY0Uiet0syJuM1sN4ejRs39rjOzf1WOO4P121YvL0+Lunp6aZGjRoZtnW/Rtd9u8xm787sWsfMZi93n0nY/RZTCxcuNEFBQVkef05kdt1kbh1/dtrdsmXLTOuEh4ebI0eO+Hxc7tc0+vp6tWrVylo3Z86cTPft3m982ffw4cMzrXfnnXd6XOd55swZU6dOHa91/fz8rOt5jfHsW5l9Ri+dwdzbe51Zuft76t4v3R/ut9lav36915mV3bft1atXlu9bTh06dMjUrFkzy9ejZs2a1t0Q3D377LNZbhcbG2vVzWz28tTUVFOpUiVr3ahRo7Js76W3knJxf83dyzO7Rvdydxhw3XLRmMxnL3f/Lnf/jtq7d2+m77vr4fre/rtnL7fje6VChQqZ1itdurQ5d+6cMcY5e3lERESWz+36HZPZ++yybt06ay4E94f796z7dr7MXm7M5X/3Ad4w0g0AuSg4OFgrVqzQe++9p8aNGysiIkJBQUEqXbq0mjVrpmHDhnmcrv32229r2LBhKlOmjIKCglSjRg3NnDnTminVF2PGjFH//v0VFRWlkJAQNW7cWCtWrPC4plKSkpKStHTpUtWvXz/DdYYBAQH65JNP1KdPH9WsWVPFixdXQECAwsLCFBsbqyFDhmj58uUe17nVq1dPEyZMUKVKlawRIV/5+/tr0aJFuvvuu1WoUCFFRESoc+fO+uabb7K1n8x07NhR8+fPV2xsrIKCglS2bFkNHTrUY+Zr99NB27dvr59//lk9evRQ2bJlFRgYqAIFCqhatWrq0aOHZs2alSvtcsmt489Ou3v16qW77rpL0dHRCgsLk7+/vyIjI9W5c2d9++23ioyMzNVjdPfrr79q+fLlkpzX0rqfEXKlXnjhBc2bN0/NmjVT/vz5FRISopo1a2rUqFGaN2+exyngYWFhWrNmjV566SWr3xYsWFBt2rTRqlWr1LVrV6tuyZIl9c4776ht27aKiYlRaGioQkJCVKVKFfXv319bt25VlSpVLts+91GwzD4n/fr108SJE1W5cmUFBQWpYsWKGj9+vJ5//nmrToMGDfT111+rcePGCg4OVokSJfT00097jAK79+ncVLp0aW3YsEHjxo1T8+bNVbhwYQUEBKhw4cJq1qyZ3nvvPW3YsMG6G4K70aNHa/369erdu7cqVKig0NBQhYWFqVKlSurevbvefPPNyz5/YGCgR73XX3/9b7neuX///lqxYoXatWunokWLyt/fX0WKFFHbtm21fPlyj7Meypcvr2+//Va33367QkNDVahQIT3wwAOZng5frlw5/fLLLxo4cKCqV69ujcSWL19e7du318SJE71eIvR3sON75YknnlDr1q1VunRphYSEKDAwUGXKlFHPnj21du1ahYSESHKeLbF161Y9+uijqlixooKDg5U/f35VqlRJXbp00dSpUxUVFeXTcTRu3Fhz5sxRrVq1FBISoujoaA0fPlyDBg3yWr9t27bavHmzevfurZiYGAUFBSk8PFyxsbEeZzJcye8+XL8cxvzvnioAgGva7Nmzdd9992nkyJEet9q6FiUm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A491P/30k+666y4VLlxYISEhqlOnjmbPnm2tHzJkiEqXLi1Jev755+VwOKzTv3fv3q3evXurUqVKypcvn0qVKqX27dtr27ZtHs/hOvV9//79HuWrV6+Ww+HQ6tWrM227w+FQUlKSpk2bZp2i3aJFiyyPd+LEiSpZsqRuv/12j/L58+fr1ltvtQK3JEVERKhTp05atGiR0tPTs9zvpRITEzVnzhw1b95cFStWzNa27h544AH9/vvvWrVqVY73AQAAAABXitB9Bdq2bSt/f3+tXbvWKlu1apWaNGmiU6dO6f3339eCBQtUu3Zt3XfffZo6daokqV+/fpo3b54k6YknntAPP/yg+fPnS3KOgBcpUkRvvPGGli5dqvHjxysgIEANGzbUzp07c6XdP/zwg0JDQ9W2bVv98MMP+uGHHzRhwoQst1myZImaNWsmP7+LXebcuXPas2ePatWqlaF+rVq1dO7cOe3duzdbbfvss8+UlJSkfv36eV3/6aefKjQ0VMHBwapXr56mTJnitV69evWUP39+LVmyJNPnSklJUUJCgscDAAAAAHITp5dfgbCwMBUtWlRHjhyxyh599FHdcMMN+uabbxQQ4Hx5W7durbi4OL344ovq0aOHSpcubY0Aly1b1uN06WbNmqlZs2bWz+fPn1e7du10ww036IMPPtDYsWOvuN2NGjWSn5+fihUrdtlTtSXp+PHj2rt3rx566CGP8pMnT8oYo8KFC2fYxlUWHx+frbZNnjxZBQsWVOfOnTOsu//++9WuXTuVKVNGx48f1+TJk9WnTx/t3btXQ4cO9ajr7++v2NhYff/995k+14gRI/Tqq69mq30AAAAAkB2MdF8hY4y1vHv3bu3YsUPdunWTJKWnp1uPtm3b6ujRo5cdrU5PT9fw4cNVvXp1BQUFKSAgQEFBQdq1a5d+++03W48lM64/KhQvXtzr+qyumc7O9dS//vqr1q9fr27duikkJCTD+pkzZ+r+++/XzTffrM6dO+vLL7/UnXfeqTfeeEN//fVXhvrFixfX4cOHM32+F154QadPn7Yehw4d8rmtAAAAAOALQvcVSEpKUnx8vKKioiRJx44dk+ScPTswMNDj8eijj0qS4uListznM888o3//+9+6++67tWjRIq1fv14bN25UbGyszp07Z+8BZcL1vJcG4UKFCsnhcHgdzT5x4oQkeR0F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adOmqUmTJj7fRssV4CVZszbv2bNHw4YNy1C3UqVK1ojk8ePH9frrr1vXFn/00UcZ6jdp0sQKWsuXL9fo0aMVHx+vlJQU7dixQyNHjlTFihWzbF9OXssmTZqoePHikqTdu3fr4Ycf1sGDB5WUlKT169dr0qRJkqQ77rjDCtSrVq3SK6+8omPHjikhIUGrVq3SrFmzJDkDlaver7/+qn379un8+fN66aWXshytzoz7ax4SEqLQ0FBt2bJF77zzToa6vh6LyzPPPCM/Pz8ZY7R69WpJUteuXVWwYMHLtqt06dLWdc6//PKLT8dy1113WctvvfWWfvnlFyUkJOjf//63NcpdvXp1VahQIdv9JzNr1qzR8OHD9euvvyomJkZ333237r77bmv9wYMHJckjNI8aNUqfffaZEhISdPz4cX366afW/bHd34/8+fPL4XBowYIFXudFyEzHjh0lOf/407NnT/32229KS0vTn3/+qblz56pNmzbWmSsumzZtspYbNWrk83MBuI79XeexAwDwT/fJJ59Y12rWqVMnw3r32colmdWrV1vrXnzxRY/rQGNiYjJcE7x3797LXkO6atUqY0zW1yO79pUvX74M21euXNnrdpnNPu3eHvfrZxcuXOj1OnH3hx2vZW7OXm6MMQ8++KBV7u/vb/Lly2cCAgI8js3F/Zpu1wzx7tatW+f1Od1fc/ftfD0Wl86dO3vUWb9+fZavsTvXcfr7+5sTJ054rMts9vJOnTpl+t7my5fPfP/999Y+stt/vJk+fXqW/em9996z6vbo0SPTeq7Zy994440M6/z8/EyFChWsn6dMmWLt01V26ezlN9xwQ5btct+HMcY8+eST1nMdPHjQ5/cIwPWLkW4AAP7H/ZRx17XY7vz9/T1O93U/ffrBBx/0uNazX79+Ga4JLleunH755RcNHDhQ1atXt0ZLy5cvr/bt22vixIkeMyNnpVy5cvryyy/VqFEj5cuXT5GRkRowYIDXU50l54je/PnzFRsbq6CgIJUtW1ZDhw7V448/btUpWrSotdy+fXv9/PPP6tGjh8qWLavAwEAVKFBA1apVU48ePazR5Mzk9LVs27atNm/erN69eysmJkZBQUEKDw9XbGysWrVqZdV/8MEHtW7dOt13330qVaqUAgMDVbBgQTVo0EBNmza16o0dO1YPP/ywIiMjFRQUpPr16+ubb77xOCXbV40bN9acOXNUq1YthYSEKDo6WsOHD9egQYO81vf1WFzcr0+uU6eOGjRo4HPbXPduP3/+/GXfG8l5OvWcOXP0/vvvq1GjRgoPD1dAQIDKlCmjnj17avPmzbrpppus+tntP97Uq1dP/fr1U82aNVW4cGH5+/srPDxcjRo10qRJkzz2NW3aNH366adq2bKlChcurICAABUvXly33367dZbFgAED9NprrykmJkbBwcGKjY3V/PnzPd7/yylcuLDWr1+voUOHqk6dOgoLC1NwcLCio6N1++23a8yYMbrjjjus+ufPn7fuTHDXXXepTJkyPj8XgOuXw5hLZhYBAADXnMTERG3YsEHNmjVTYGCgJGn79u1q166d9u/fLz8/P23fvl1VqlS5yi29fs2fP986tfrjjz+2bkXmqzvvvFNLlixRbGysNm/enKsTftF/nObMmaN7771XDodD69evV/369a92kwDkAYRuAACuA/v371e5cuUUGBio4sWLKzk52bp2V5JeffVVvfLKK1exhdevF154QbNnz9a+fftkjFHVqlW1bds2j2uWfbFr1y7VqFFDqampmjt3rjp37pxrbaT/OK/7jo2N1bZt29S7d299/PHHV7tJAPIIbhkGAMB1oGDBgurevbt++OEH/fnnn0pNTVVUVJQaNmyoRx55xOvpzvh7HD16VHv37lV4eLiaNm2q8ePHZztwS84J81JSUmxoIf1Hcp6Sv3Xr1qvdDAB5ECPdAAAAAADYhInUAAAAAACwCaEbAAAAAACbELoBAAAAALAJoRsAAAAAAJsQugEAAAAAsAmhGwAAAAAAmxC6AQAAAACwCaEbAAAAAACbELoBAAAAALDJ/wPycqSMHEO5YQAAAABJRU5ErkJggg==", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# image_experiment.plot_accuracies(exps, IMAGE_CONTEXT)\n", + "image_experiment.plot_accuracies(methods)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Save the results to a file\n" + ] + }, + { + "cell_type": "code", + "execution_count": 107, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
cleaner/Strange_Tales_172005/Strange_Tales_172005_Tesseract.json\n",
+       "
\n" + ], + "text/plain": [ + "cleaner/Strange_Tales_172005/Strange_Tales_172005_Tesseract.json\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fp, json_results = image_experiment.to_json()\n", + "cprint(fp)\n", + "RenderJSON(json_results, 300, 2)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Load the results from a file\n" + ] + }, + { + "cell_type": "code", + "execution_count": 108, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
---------- Initial box ----------\n",
+       "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
+       "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
+       "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
+       "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
+       "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
+       "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
+       "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes... 7 /\n",
+       "ResultOCR#block 07: 0.81||The the old man's fades down the hall as... 7\n",
+       "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
+       "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
+       "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
+       "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
+       "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
+       "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Default ----------\n",
+       "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
+       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
+       "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
+       "ResultOCR#block 03: 0.41||Rir guest.\n",
+       "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
+       "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
+       "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
+       "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
+       "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
+       "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
+       "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
+       "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
+       "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
+       "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Default, grey pad ----------\n",
+       "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
+       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
+       "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
+       "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
+       "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
+       "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+       "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7 /.\n",
+       "ResultOCR#block 07: 0.06||As.\n",
+       "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
+       "ResultOCR#block 09: 0.55||Ickl as t can\n",
+       "ResultOCR#block 10: 0.00||\n",
+       "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
+       "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
+       "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 0.54||“continued a\n",
+       "\n",
+       " ---------- Padded 4px ----------\n",
+       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
+       "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
+       "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
+       "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
+       "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
+       "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
+       "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
+       "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
+       "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
+       "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
+       "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
+       "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
+       "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
+       "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Padded 8px ----------\n",
+       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
+       "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
+       "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
+       "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
+       "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
+       "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
+       "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
+       "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
+       "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
+       "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
+       "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
+       "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
+       "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
+       "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 0.94||“continued after next page\n",
+       "\n",
+       " ---------- Extracted, init box ----------\n",
+       "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
+       "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
+       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+       "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
+       "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
+       "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
+       "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
+       "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
+       "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
+       "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
+       "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
+       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+       "\n",
+       " ---------- Padded 4, extracted ----------\n",
+       "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
+       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+       "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
+       "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
+       "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
+       "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
+       "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
+       "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+       "\n",
+       " ---------- Padded 8, extracted ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
+       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
+       "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
+       "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
+       "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Padded 8, dilation 1 ----------\n",
+       "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
+       "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
+       "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
+       "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
+       "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
+       "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
+       "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
+       "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
+       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
+       "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
+       "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Pad 8, fract. 0.5 ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
+       "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
+       "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Pad 8, fract. 0.2 ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
+       "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
+       "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + "---------- Initial box ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n", + "\n", + " ---------- Padded 4px ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m|| Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Pad 8, fract. 0.2
Accuracy Mean/Trimmed: 0.85/0.86
\n", + "
\n", + "
Box #ImageAccuracyOCR
1
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
2
0.97
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~
3
0.77
And one in eet⎕⎕⎕ sve⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.86
Bambl ~~ we have a guest.
5
0.64
=~and tonight, he comes ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕slamming open urg⎕⎕⎕⎕en⎕⎕⎕⎕⎕tly,⎕⎕⎕⎕
6
0.82
Tell me master... how may bambli serve'7
7
0.94
Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes
8
0.75
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall sere
9
0.96
How curious the whims of fate. had i not chanced to stroll along the river tonight-~
10
0.81
A⎕⎕⎕ulckry as t can, master.
11
0.95
~<the girl would most surely be dead by now.
12
0.94
Ghede has been generous. the ceath god has given the girl a second chance po⎕⎕
13
0.67
Yi⎕⎕⎕ ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕renee othing to scream sea⎕⎕⎕t anhore.
14
0.93
Youre among eriends now. you're safe!
15
0.83
| continued af⎕⎕⎕ ext page
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "saved_exp = ExperimentOCR.saved_experiment(CONTEXT, 'Tesseract', IMAGE_CONTEXT.image_idx)\n", + "# saved_exp = ExperimentOCR.saved_experiment(IMAGE_CONTEXT, 'Tesseract', 'Action_Comics_1960-01-00_(262).JPG')\n", + "if saved_exp:\n", + " saved_exp.method_experiment(CropMethod.PAD_8_FRACT_0_2).display()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Perform experiments for selected boxes y methods" + ] + }, + { + "cell_type": "code", + "execution_count": 110, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
---------- Initial box ----------\n",
+       "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
+       "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
+       "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
+       "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
+       "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
+       "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
+       "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes... 7 /\n",
+       "ResultOCR#block 07: 0.81||The the old man's fades down the hall as... 7\n",
+       "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
+       "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
+       "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
+       "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
+       "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
+       "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Default ----------\n",
+       "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
+       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
+       "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
+       "ResultOCR#block 03: 0.41||Rir guest.\n",
+       "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
+       "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
+       "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
+       "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
+       "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
+       "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
+       "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
+       "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
+       "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
+       "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Default, grey pad ----------\n",
+       "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
+       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
+       "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
+       "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
+       "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
+       "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+       "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7 /.\n",
+       "ResultOCR#block 07: 0.06||As.\n",
+       "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
+       "ResultOCR#block 09: 0.55||Ickl as t can\n",
+       "ResultOCR#block 10: 0.00||\n",
+       "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
+       "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
+       "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 0.54||“continued a\n",
+       "\n",
+       " ---------- Padded 4px ----------\n",
+       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
+       "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
+       "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
+       "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
+       "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
+       "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
+       "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
+       "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
+       "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
+       "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
+       "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
+       "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
+       "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
+       "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 1.00||Continued after next page\n",
+       "\n",
+       " ---------- Padded 8px ----------\n",
+       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
+       "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
+       "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
+       "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
+       "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
+       "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
+       "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
+       "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
+       "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
+       "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
+       "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
+       "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
+       "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
+       "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
+       "ResultOCR#block 14: 0.94||“continued after next page\n",
+       "\n",
+       " ---------- Extracted, init box ----------\n",
+       "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
+       "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
+       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+       "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
+       "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
+       "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
+       "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
+       "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
+       "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
+       "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
+       "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
+       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+       "\n",
+       " ---------- Padded 4, extracted ----------\n",
+       "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
+       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
+       "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
+       "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
+       "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
+       "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
+       "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
+       "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
+       "\n",
+       " ---------- Padded 8, extracted ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
+       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
+       "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
+       "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
+       "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Padded 8, dilation 1 ----------\n",
+       "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
+       "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
+       "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
+       "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
+       "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
+       "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
+       "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
+       "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
+       "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
+       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
+       "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
+       "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Pad 8, fract. 0.5 ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
+       "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
+       "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       " ---------- Pad 8, fract. 0.2 ----------\n",
+       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
+       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
+       "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
+       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
+       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
+       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
+       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
+       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
+       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
+       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
+       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
+       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
+       "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
+       "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
+       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
+       "\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + "---------- Initial box ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n", + "\n", + " ---------- Padded 4px ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m||---------- Initial box ----------\n", + "ResultOCR#block 00: 0.90||Suddenly.\n", + "ResultOCR#block 01: 0.81||>gasp!z everything's w- whirling around me!t can't stand sr rea\n", + "ResultOCR#block 02: 0.81||Clark!i'm falling' “help! help! —\n", + "ResultOCR#block 03: 0.67||I-i'm bs \"passing ohhh\n", + "ResultOCR#block 04: 0.92||Action comics\n", + "ResultOCR#block 05: 1.00||Then, seconds later...\n", + "ResultOCR#block 06: 0.89||Great caesars ghost! { this /s black magic! we've been transportel to the weirdest world, tit ever saw!\n", + "ResultOCR#block 07: 0.91||...|t certainly isn't our earth, perry. look at the size of those bees.\n", + "ResultOCR#block 08: 0.88||Watch out, clark!\n", + "ResultOCR#block 09: 0.73||Owwww.\n", + "ResultOCR#block 10: 0.85||Yet the bee's stinger went ws. right through my uniform and penetrated my skin! that means. the fabric of pe ay costume has become dj} satie fued 1,\n", + "ResultOCR#block 11: 0.87||Hurry. let's beat it before we get stung, foo = aii\n", + "ResultOCR#block 12: 0.86||Ggreat guns!...2g, .pa/n i feel n pain! as superman, i should be > invulnerable! 1 have unbreakabl ‘skin! under my clark kent clothes, im wearing an woestructisle superman uniform ! =\n", + "ResultOCR#block 13: 1.00||Abruptly...\n", + "ResultOCR#block 14: 0.77||Great caesar's ghost. he's spinning a web of g/ant, sr strands --\n", + "ResultOCR#block 15: 0.89||I-i feel the heat of the sun...the pain of the bee-sting ... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers! i've become an ordinary mortal in this world. /\n", + "ResultOCR#block 16: 0.84||Enormous spider- like creature is going berserk, as if the sight of us excited him (into mad spinning get back! that 2\n", + "\n", + " ---------- Default ----------\n", + "ResultOCR#block 00: 1.00||Suddenly...\n", + "ResultOCR#block 01: 0.80||Gasp! everything's w- whi rns atound me!i can't stand we a\n", + "ResultOCR#block 02: 0.87||Clark!i'm falling! help! help\n", + "ResultOCR#block 03: 0.45||I-i'm se ou\n", + "ResultOCR#block 04: 0.92||Action comics\n", + "ResultOCR#block 05: 0.95||Then, seconds later.\n", + "ResultOCR#block 06: 0.92||Great caesar's ghost! this /s black magic! we've been transported, to the weirdest world, i ever saw!\n", + "ResultOCR#block 07: 0.93||...|t certainly isn't our earth, perry look at the size of those bees!\n", + "ResultOCR#block 08: 0.88||Watch out, clark)\n", + "ResultOCR#block 09: 0.67||Owwww.,\n", + "ResultOCR#block 10: 0.97||Yet the bee's stinger went = right through my uniform ando penetrated my skin! that mean the fabric of my superman costume has become ordinary, cloth! £\n", + "ResultOCR#block 11: 0.89||Hurry. let's beat it before we get stung, tod yi\n", + "ResultOCR#block 12: 0.88||Ggreat guns!...2gasp/z...pain i feel n fan! as superman, i should be invulnerable! 1 have unbreakable skin! under my clark kent clothes, i'm wearing an /noestruct/ele superman uniform !\n", + "ResultOCR#block 13: 1.00||Abruptly...\n", + "ResultOCR#block 14: 0.76||Great caesars ° ghost! he's spinning & web of g/a, silk strands\n", + "ResultOCR#block 15: 0.89||I-i feel the heat of the sum...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all my super -powersx ve become an ordinary mortal in this world! j\n", + "ResultOCR#block 16: 0.70||Like creature is going berserk, as if the sight of us excited him into mad spinning, get back! that \\ enormous spider-\n", + "\n", + " ---------- Default, grey pad ----------\n", + "ResultOCR#block 00: 0.78||Sudden.\n", + "ResultOCR#block 01: 0.82||5gasp!z everything's | w- whirling around] me!t can't stand ue a\n", + "ResultOCR#block 02: 0.57||Ark!i'm falling\n", + "ResultOCR#block 03: 0.85||I-t'm eq \"passing out... ohhh.\n", + "ResultOCR#block 04: 0.92||Action comics\n", + "ResultOCR#block 05: 0.00||\n", + "ResultOCR#block 06: 0.88||‘great caesar's ghost! || this /§ black magic! we've been transportel to the weirdest world, i ever saw.\n", + "ResultOCR#block 07: 0.87||\"...it certainly isn't our | earth, perry look at the| \\s|ze of those bees.\n", + "ResultOCR#block 08: 0.88||Watch out, clark!\n", + "ResultOCR#block 09: 0.73||Owwww.\n", + "ResultOCR#block 10: 0.90||Yet the bee's stinger went ~ right through my uniform and penetrated my skin! that means. the fabric of sera ry costume vis become din a s clots! a\n", + "ResultOCR#block 11: 0.80||Hurry. let's ) beat it before] we get stung, k 00! __j\n", + "ResultOCR#block 12: 0.86||Ggreat guns!...3gasp/=... rain t feel fan! as superman, i should be invulnerable® 1 have unbreakabli skin! under my clark kent clothes, ia wearing an /noestryct/iele supe iperman uniform !\n", + "ResultOCR#block 13: 0.90||Abruptly.\n", + "ResultOCR#block 14: 0.92||Great caesar's | ghost! he's spinning k web of giant, silk strands -- as tough as steel! ne]\n", + "ResultOCR#block 15: 0.89||\\i-t feel the heat of the sun...the pain of the bee-sting... the heavy weight of my & pack! every human discomfort... good grief! i've lost all my super-powers i've become an ordinary mortal in this world. /.\n", + "ResultOCR#block 16: 0.94||(get back! that enormous spider- like creature 1 § going berserk, as if the sight of us excited him into mad spinning]\n", + "\n", + " ---------- Padded 4px ----------\n", + "ResultOCR#block 00: 0.90||Suddenly.\n", + "ResultOCR#block 01: 0.83||Fgasp/= everything's whirling around me!i can't stand ea\n", + "ResultOCR#block 02: 0.68||Ie lottie eto clark!i'm falling help! help!\n", + "ResultOCR#block 03: 0.55||I-i'm yr a ohh hh.\n", + "ResultOCR#block 04: 0.92||Action comics\n", + "ResultOCR#block 05: 0.74||Then, seconds\n", + "ResultOCR#block 06: 0.62||Great caesar's ghost! \\ this /§ black magic! i ever saw!\n", + "ResultOCR#block 07: 0.87||T certainly isn't our earth, perry! look at the \\s|ze of those bees.\n", + "ResultOCR#block 08: 0.76||#3 watch out, clark!\n", + "ResultOCR#block 09: 0.73||Owwww.\n", + "ResultOCR#block 10: 0.95||\"yet the bee's stinger went ~~ right through my uniform and enetrated my skin! that means. the fabric of my superman costume has become ordinary, clot! &\n", + "ResultOCR#block 11: 0.86||Hurry! let's beat it b=fore we get stung, ¢ tool: puma\n", + "ResultOCR#block 12: 0.86||‘ggreat guns!...3gasp/5... pain i feel pain? as superman, i should be invilnerable | t ne unbreakasle gkin! under my clark kent clothes, tih wearing an indestructible superman uniform\n", + "ResultOCR#block 13: 1.00||Abruptly...\n", + "ResultOCR#block 14: 0.91||Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!\n", + "ResultOCR#block 15: 0.89||I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all \\my super-powersx ve become an ordinary mortal in this world.\n", + "ResultOCR#block 16: 0.81||(get back! that enormous spider- as if the sight of us excited him [into mad spinning\n", + "\n", + " ---------- Padded 8px ----------\n", + "ResultOCR#block 00: 0.00||\n", + "ResultOCR#block 01: 0.76||Ega5p/% everything s\\ w- whirling around me! t can't stand ue... slee\n", + "ResultOCR#block 02: 0.41||\\ help! help’\n", + "ResultOCR#block 03: 0.86||-i'm passing qut... ohh hh.\n", + "ResultOCR#block 04: 0.92||Action comics\n", + "ResultOCR#block 05: 0.00||\n", + "ResultOCR#block 06: 0.18||I ever saw/\n", + "ResultOCR#block 07: 0.86||It certainly isn't our earth, perry! poor a the size of thos!\n", + "ResultOCR#block 08: 0.62||“watch out” ial ae clark!\n", + "ResultOCR#block 09: 0.73||Owwww.\n", + "ResultOCR#block 10: 0.98||Yet the bee's stinger went right through my uniform and \\penetrated my skin! that means. the fabric of my superman costume has become ordinar! cloth!\n", + "ResultOCR#block 11: 0.93||Hurry. let's beat it before we get stung, too!\n", + "ResultOCR#block 12: 0.88||Ggreat guns!...2gasp/z...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ele $ superman uniform ! &\n", + "ResultOCR#block 13: 0.00||\n", + "ResultOCR#block 14: 0.91||Great caesai ghost. he's spinning a web of g/ant, silk strands -- as tough as steel!\n", + "ResultOCR#block 15: 0.88||I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my ! every human discomfort... good grief! i've lost all \\my super-powers! ‘ve become an ordinary mortal in this world. x\n", + "ResultOCR#block 16: 0.60||As if the sight of us excited him {into mad spinning\n", + "\n", + " ---------- Extracted, init box ----------\n", + "ResultOCRExtracted#block 00: 0.90||Suddenly.\n", + "ResultOCRExtracted#block 01: 0.83||Fgasp!z everything § w- whirling around me!i can't stand ue.\n", + "ResultOCRExtracted#block 02: 0.89||Clark!i'm falling! help! help!\n", + "ResultOCRExtracted#block 03: 0.71||I-i'm passing ohhh?\n", + "ResultOCRExtracted#block 04: 0.92||Action comics\n", + "ResultOCRExtracted#block 05: 0.98||Then, seconds later..\n", + "ResultOCRExtracted#block 06: 0.91||Great caesar's ghost! this /s black magic! we've been transportel to the weirdest world tit ever saw.\n", + "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n", + "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", + "ResultOCRExtracted#block 09: 0.62||Oowwwww.\n", + "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block 11: 0.93||Hurry. let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block 12: 0.88||Ggreat guns!...2g/ pain t feel pain? as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform *\n", + "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n", + "ResultOCRExtracted#block 14: 0.80||Great caesar's ghost. he's spinning a web of g/ant, silk strands --\n", + "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal im this world.\n", + "ResultOCRExtracted#block 16: 0.97||Get back. that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning\n", + "\n", + " ---------- Padded 4, extracted ----------\n", + "ResultOCRExtracted#block 00: 1.00||Suddenly...\n", + "ResultOCRExtracted#block 01: 0.83||Sgasp/z everything s w- whirling around me!i can't stand ue.\n", + "ResultOCRExtracted#block 02: 0.87||Clark! i'm falling’ help! help!\n", + "ResultOCRExtracted#block 03: 0.78||I-i'm passing ohhhh.\n", + "ResultOCRExtracted#block 04: 0.92||Action comics\n", + "ResultOCRExtracted#block 05: 0.98||Then, seconds later..\n", + "ResultOCRExtracted#block 06: 0.93||Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw!\n", + "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n", + "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", + "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", + "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block 12: 0.89||Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !\n", + "ResultOCRExtracted#block 13: 1.00||Abruptly...\n", + "ResultOCRExtracted#block 14: 0.94||Great caesar's ghost! he's spinning a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block 16: 0.97||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning\n", + "\n", + " ---------- Padded 8, extracted ----------\n", + "ResultOCRExtracted#block 00: 0.91||Suddemly...\n", + "ResultOCRExtracted#block 01: 0.85||Sgasp/z everything s w- whirling around me!i can't stand up.\n", + "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n", + "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n", + "ResultOCRExtracted#block 04: 0.92||Action comics\n", + "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n", + "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw.\n", + "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n", + "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", + "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", + "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block 12: 0.89||Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !\n", + "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n", + "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block 15: 0.89||I-t feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block 16: 0.95||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [\n", + "\n", + " ---------- Padded 8, dilation 1 ----------\n", + "ResultOCRExtracted#block 00: 1.00||Suddenly...\n", + "ResultOCRExtracted#block 01: 0.83||Gasp! everything s w-whirling around wel] i can't stand\n", + "ResultOCRExtracted#block 02: 0.86||Clark!i'm falling! . help! help!\n", + "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n", + "ResultOCRExtracted#block 04: 0.92||Action comics\n", + "ResultOCRExtracted#block 05: 0.95||Then, seconds later.\n", + "ResultOCRExtracted#block 06: 0.91||Great caesar's ghost! e this /5 black magic! we've been transported to the weirdest world i ever saw/\n", + "ResultOCRExtracted#block 07: 0.91||...|it certainly isnt our earth, perry” look at the size of those bees!\n", + "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", + "ResultOCRExtracted#block 09: 0.73||Owwww.\n", + "ResultOCRExtracted#block 10: 0.94||Yet the bee's stinger we right through my tform and penetrated my skin! that means. the fabric of my superman othe has become ordinary clot?\n", + "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block 12: 0.82||Fain! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", + "ResultOCRExtracted#block 13: 0.00||\n", + "ResultOCRExtracted#block 14: 0.67||Great caesars ghost! he's spinning _ a web of g/ant,\n", + "ResultOCRExtracted#block 15: 0.86||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve ie an ordinary mortal in this world.\n", + "ResultOCRExtracted#block 16: 0.96||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning’ g [\n", + "\n", + " ---------- Pad 8, fract. 0.5 ----------\n", + "ResultOCRExtracted#block 00: 0.91||Suddemly...\n", + "ResultOCRExtracted#block 01: 0.87||Gasp/z everything s w- whirling around me!i can't stand up.\n", + "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n", + "ResultOCRExtracted#block 03: 0.78||I-i'm passing ohhhh.\n", + "ResultOCRExtracted#block 04: 0.92||Action comics\n", + "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n", + "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw.\n", + "ResultOCRExtracted#block 07: 0.92||...it certainly isnt our earth, perry! look at the size of those bees.\n", + "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", + "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", + "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block 12: 0.90||Ggreat guns!...2gasp/:...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /nodestruct/ible superman uniform !\n", + "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n", + "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block 16: 0.95||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [\n", + "\n", + " ---------- Pad 8, fract. 0.2 ----------\n", + "ResultOCRExtracted#block 00: 1.00||Suddenly...\n", + "ResultOCRExtracted#block 01: 0.87||Gasp/z everything s w- whirling around me!i can't stand up.\n", + "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n", + "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n", + "ResultOCRExtracted#block 04: 0.92||Action comics\n", + "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n", + "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw!\n", + "ResultOCRExtracted#block 07: 0.92||...it certainly isnt our earth, perry! look at the size of those bees.\n", + "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", + "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", + "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block 12: 0.91||Ggreat guns!...2gasp/:... pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", + "ResultOCRExtracted#block 13: 0.96||Abruptly....\n", + "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block 16: 0.96||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning gs [\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "---------- Initial box ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.81\u001b[0m||>gasp!z everything's w- whirling around me!t can't stand sr rea\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.81\u001b[0m||Clark!i'm falling' “help! help! —\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.67\u001b[0m||I-i'm bs \"passing ohhh\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.89\u001b[0m||Great caesars ghost! \u001b[1m{\u001b[0m this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transportel to the weirdest world, tit ever saw!\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.91\u001b[0m||\u001b[33m...\u001b[0m|t certainly isn't our earth, perry. look at the size of those bees.\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.85\u001b[0m||Yet the bee's stinger went ws. right through my uniform and penetrated my skin! that means. the fabric of pe ay costume has become dj\u001b[1m}\u001b[0m satie fued \u001b[1;36m1\u001b[0m,\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.87\u001b[0m||Hurry. let's beat it before we get stung, foo = aii\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2g, .pa/n i feel n pain! as superman, i should be > invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl ‘skin! under my clark kent clothes, im wearing an woestructisle superman uniform ! =\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.77\u001b[0m||Great caesar's ghost. he's spinning a web of g/ant, sr strands --\n", + "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting \u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers! i've become an ordinary mortal in this world. \u001b[35m/\u001b[0m\n", + "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.84\u001b[0m||Enormous spider- like creature is going berserk, as if the sight of us excited him \u001b[1m(\u001b[0minto mad spinning get back! that \u001b[1;36m2\u001b[0m\n", + "\n", + " ---------- Default ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.80\u001b[0m||Gasp! everything's w- whi rns atound me!i can't stand we a\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.87\u001b[0m||Clark!i'm falling! help! help\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.45\u001b[0m||I-i'm se ou\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.95\u001b[0m||Then, seconds later.\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.92\u001b[0m||Great caesar's ghost! this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transported, to the weirdest world, i ever saw!\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.93\u001b[0m||\u001b[33m...\u001b[0m|t certainly isn't our earth, perry look at the size of those bees!\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark\u001b[1m)\u001b[0m\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.97\u001b[0m||Yet the bee's stinger went = right through my uniform ando penetrated my skin! that mean the fabric of my superman costume has become ordinary, cloth! £\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.89\u001b[0m||Hurry. let's beat it before we get stung, tod yi\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/z\u001b[33m...\u001b[0mpain i feel n fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakable skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mele\u001b[0m superman uniform !\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.76\u001b[0m||Great caesars ° ghost! he's spinning & web of g/a, silk strands\n", + "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sum\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my \u001b[1m{\u001b[0m pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super -powersx ve become an ordinary mortal in this world! j\n", + "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.70\u001b[0m||Like creature is going berserk, as if the sight of us excited him into mad spinning, get back! that \\ enormous spider-\n", + "\n", + " ---------- Default, grey pad ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.78\u001b[0m||Sudden.\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.82\u001b[0m||5gasp!z everything's | w- whirling around\u001b[1m]\u001b[0m me!t can't stand ue a\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.57\u001b[0m||Ark!i'm falling\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.85\u001b[0m||I-t'm eq \"passing out\u001b[33m...\u001b[0m ohhh.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.88\u001b[0m||‘great caesar's ghost! || this \u001b[35m/\u001b[0m§ black magic! we've been transportel to the weirdest world, i ever saw.\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.87\u001b[0m||\"\u001b[33m...\u001b[0mit certainly isn't our | earth, perry look at the| \\s|ze of those bees.\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.90\u001b[0m||Yet the bee's stinger went ~ right through my uniform and penetrated my skin! that means. the fabric of sera ry costume vis become din a s clots! a\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.80\u001b[0m||Hurry. let's \u001b[1m)\u001b[0m beat it before\u001b[1m]\u001b[0m we get stung, k \u001b[1;36m00\u001b[0m! __j\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m3gasp/=\u001b[33m...\u001b[0m rain t feel fan! as superman, i should be invulnerable® \u001b[1;36m1\u001b[0m have unbreakabli skin! under my clark kent clothes, ia wearing an \u001b[35m/noestryct/\u001b[0m\u001b[95miele\u001b[0m supe iperman uniform !\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.90\u001b[0m||Abruptly.\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.92\u001b[0m||Great caesar's | ghost! he's spinning k web of giant, silk strands -- as tough as steel! ne\u001b[1m]\u001b[0m\n", + "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||\\i-t feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my & pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers i've become an ordinary mortal in this world. \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", + "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.94\u001b[0m||\u001b[1m(\u001b[0mget back! that enormous spider- like creature \u001b[1;36m1\u001b[0m § going berserk, as if the sight of us excited him into mad spinning\u001b[1m]\u001b[0m\n", + "\n", + " ---------- Padded 4px ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Fgasp/= everything's whirling around me!i can't stand ea\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.68\u001b[0m||Ie lottie eto clark!i'm falling help! help!\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.55\u001b[0m||I-i'm yr a ohh hh.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.74\u001b[0m||Then, seconds\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.62\u001b[0m||Great caesar's ghost! \\ this \u001b[35m/\u001b[0m§ black magic! i ever saw!\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.87\u001b[0m||T certainly isn't our earth, perry! look at the \\s|ze of those bees.\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.76\u001b[0m||#\u001b[1;36m3\u001b[0m watch out, clark!\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.95\u001b[0m||\"yet the bee's stinger went ~~ right through my uniform and enetrated my skin! that means. the fabric of my superman costume has become ordinary, clot! &\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.86\u001b[0m||Hurry! let's beat it \u001b[33mb\u001b[0m=\u001b[35mfore\u001b[0m we get stung, ¢ tool: puma\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||‘ggreat guns!\u001b[33m...\u001b[0m3gasp/\u001b[1;36m5\u001b[0m\u001b[33m...\u001b[0m pain i feel pain? as superman, i should be invilnerable | t ne unbreakasle gkin! under my clark kent clothes, tih wearing an indestructible superman uniform\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!\n", + "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my \u001b[1m{\u001b[0m pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all \\my super-powersx ve become an ordinary mortal in this world.\n", + "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.81\u001b[0m||\u001b[1m(\u001b[0mget back! that enormous spider- as if the sight of us excited him \u001b[1m[\u001b[0minto mad spinning\n", + "\n", + " ---------- Padded 8px ----------\n", + "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.76\u001b[0m||Ega5p/% everything s\\ w- whirling around me! t can't stand ue\u001b[33m...\u001b[0m slee\n", + "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.41\u001b[0m||\\ help! help’\n", + "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.86\u001b[0m||-i'm passing qut\u001b[33m...\u001b[0m ohh hh.\n", + "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.18\u001b[0m||I ever saw/\n", + "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.86\u001b[0m||It certainly isn't our earth, perry! poor a the size of thos!\n", + "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.62\u001b[0m||“watch out” ial ae clark!\n", + "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", + "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.98\u001b[0m||Yet the bee's stinger went right through my uniform and \\penetrated my skin! that means. the fabric of my superman costume has become ordinar! cloth!\n", + "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.93\u001b[0m||Hurry. let's beat it before we get stung, too!\n", + "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/z\u001b[33m...\u001b[0mpain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mele\u001b[0m $ superman uniform ! &\n", + "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesai ghost. he's spinning a web of g/ant, silk strands -- as tough as steel!\n", + "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.88\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my ! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all \\my super-powers! ‘ve become an ordinary mortal in this world. x\n", + "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.60\u001b[0m||As if the sight of us excited him \u001b[1m{\u001b[0minto mad spinning\n", + "\n", + " ---------- Extracted, init box ----------\n", + "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n", + "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Fgasp!z everything § w- whirling around me!i can't stand ue.\n", + "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.89\u001b[0m||Clark!i'm falling! help! help!\n", + "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.71\u001b[0m||I-i'm passing ohhh?\n", + "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.98\u001b[0m||Then, seconds later..\n", + "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesar's ghost! this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transportel to the weirdest world tit ever saw.\n", + "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n", + "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.62\u001b[0m||Oowwwww.\n", + "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.93\u001b[0m||Hurry. let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2g/ pain t feel pain? as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform *\n", + "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n", + "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.80\u001b[0m||Great caesar's ghost. he's spinning a web of g/ant, silk strands --\n", + "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal im this world.\n", + "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.97\u001b[0m||Get back. that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning\n", + "\n", + " ---------- Padded \u001b[1;36m4\u001b[0m, extracted ----------\n", + "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Sgasp/z everything s w- whirling around me!i can't stand ue.\n", + "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.87\u001b[0m||Clark! i'm falling’ help! help!\n", + "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.78\u001b[0m||I-i'm passing ohhhh.\n", + "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.98\u001b[0m||Then, seconds later..\n", + "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw!\n", + "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n", + "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", + "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.89\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain t feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform !\n", + "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.94\u001b[0m||Great caesar's ghost! he's spinning a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.97\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning\n", + "\n", + " ---------- Padded \u001b[1;36m8\u001b[0m, extracted ----------\n", + "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.91\u001b[0m||Suddemly\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.85\u001b[0m||Sgasp/z everything s w- whirling around me!i can't stand up.\n", + "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n", + "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n", + "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw.\n", + "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n", + "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", + "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.89\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain t feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform !\n", + "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n", + "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-t feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.95\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning g \u001b[1m[\u001b[0m\n", + "\n", + " ---------- Padded \u001b[1;36m8\u001b[0m, dilation \u001b[1;36m1\u001b[0m ----------\n", + "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Gasp! everything s w-whirling around wel\u001b[1m]\u001b[0m i can't stand\n", + "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.86\u001b[0m||Clark!i'm falling! . help! help!\n", + "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n", + "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.95\u001b[0m||Then, seconds later.\n", + "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesar's ghost! e this \u001b[35m/\u001b[0m\u001b[95m5\u001b[0m black magic! we've been transported to the weirdest world i ever saw/\n", + "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.91\u001b[0m||\u001b[33m...\u001b[0m|it certainly isnt our earth, perry” look at the size of those bees!\n", + "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", + "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m||Yet the bee's stinger we right through my tform and penetrated my skin! that means. the fabric of my superman othe has become ordinary clot?\n", + "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.82\u001b[0m||Fain! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", + "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", + "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.67\u001b[0m||Great caesars ghost! he's spinning _ a web of g/ant,\n", + "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.86\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve ie an ordinary mortal in this world.\n", + "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.96\u001b[0m||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning’ g \u001b[1m[\u001b[0m\n", + "\n", + " ---------- Pad \u001b[1;36m8\u001b[0m, fract. \u001b[1;36m0.5\u001b[0m ----------\n", + "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.91\u001b[0m||Suddemly\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.87\u001b[0m||Gasp/z everything s w- whirling around me!i can't stand up.\n", + "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n", + "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.78\u001b[0m||I-i'm passing ohhhh.\n", + "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw.\n", + "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.92\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry! look at the size of those bees.\n", + "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", + "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.90\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0mpain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/nodestruct/\u001b[0m\u001b[95mible\u001b[0m superman uniform !\n", + "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n", + "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.95\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning g \u001b[1m[\u001b[0m\n", + "\n", + " ---------- Pad \u001b[1;36m8\u001b[0m, fract. \u001b[1;36m0.2\u001b[0m ----------\n", + "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.87\u001b[0m||Gasp/z everything s w- whirling around me!i can't stand up.\n", + "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n", + "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n", + "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", + "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", + "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw!\n", + "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.92\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry! look at the size of those bees.\n", + "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", + "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", + "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", + "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", + "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.91\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", + "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly\u001b[33m...\u001b[0m.\n", + "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", + "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", + "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.96\u001b[0m||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning gs \u001b[1m[\u001b[0m\n", + "\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_action_experiment: ExperimentOCR = cast(ExperimentOCR, ExperimentOCR.from_image(\n", + " CONTEXT, 'Tesseract', 'Action_Comics_1960-01-00_(262).JPG'))\n", + "image_action_experiment.display()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAHqCAYAAAAZLi26AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8fJSN1AAAACXBIWXMAAA9hAAAPYQGoP6dpAADmy0lEQVR4nOzdd1gUx/8H8Pchx9GbCAgqqFiwN1TEgmDvYu9YY++9IIpdkmisUVGwl2BJrBFENEaixtij+Vow9oICIkXB/f2xv1vuuAMOhGB5v57nHu/mZmdmd8/jPjuzMzJBEAQQERERERERUZ7TK+gGEBEREREREX2pGHQTERERERER5RMG3URERERERET5hEE3ERERERERUT5h0E1ERERERESUTxh0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE8YdBMRfSJ8fX0hk8kgk8lw8uRJKV2Z5uzs/NF1BAUFQSaTYcWKFWrpiYmJMDc3l+rS09NDdHT0R9W1bNky+Pv7w9/fX+O9kydPSnX5+vp+VD354fz58xg4cCDKli0LExMTmJqaoly5cujbty+OHz9eoG1zdnaWjl1BOn78OHr37o2yZctCT09P62dX1ZMnTzB8+HA4OzvDwMAARYoUQceOHXHx4sVM6zhy5Ahat24NW1tbGBgYwNbWFg0bNsSuXbs08u7btw+NGjWCubk5jIyMUKVKFXz77bd4//59jvbr+fPnGD16NJydnaFQKGBra4suXbrgypUrH30MspKQkICZM2eiXLlyMDQ0hLW1NVq1aoXTp09rzX/58mV07twZtra2UCgUcHZ2xujRo/HixYsc1w0A79+/R7ly5SCTyTBq1Cgp/erVqxg/fjzq1KkDBwcHKBQKFCtWDE2aNMHBgwczLU+XcxcTE4M5c+agSZMmcHJygrGxMWxsbODm5oaVK1ciJSVFrcylS5dCJpPBxsYGr1+/1nnfVL9bVb+P/P39pXTVh7m5Odzd3bF27Vp8+PBBo7zk5GSsX78eLVq0QNGiRaFQKGBlZYVy5crBx8cH69atw9u3b3VuX07FxcVh0aJFcHd3h5WVFQwMDGBnZ4cWLVpgy5YtSEtLy3TbsLAw9OjRAyVLloSRkREsLS1RsWJFDB06FH/88YeUz9PTU+O4KBQKODk5oW/fvvjnn3/ybf/yS1783cmLMoKDg7V+7rQ98uLv/pds//790u+Mj/3Nku8EIiL6JPTr108AIAAQIiIipHRlmpOT00fX0aJFC0EmkwmPHj1SS9+8ebNUj/Lh7+//UXU5OTlJZWUUEREhvdevX7+PqievTZw4UZDJZBrHQ/moWrVqgbYvq+P6XxozZozW46P62VW6d++eYG9vrzW/QqEQjh07prHNxIkTMz0HAwcOVMu7YMGCTPO2adNGSEtL02mfHj9+LDg7O2stx8jISDh58mSuj0FWEhIShOrVq2stS09PT9ixY4da/vDwcMHQ0FBr/lKlSglPnz7NUf2CIAiBgYHS+Xj48KGUvnDhwkyPLQBhxowZGmXpeu7Onj2bZdkNGzYUUlNTpfxv374VihQpIgAQRo4cqfO+qX63zp49W0qfPXt2lvUDELp3765W1s2bN4Xy5ctnu9358+d1bl9OXLlyRShRokSWdTdq1EiIi4tT2y4lJUXo2bNnltu1b99eyt+oUaMs81pZWQkPHjzIl33ML3nxdycvyti0aVO2nx/lIy/+7n/JMvvd9CliTzcR0SdOEAQIgvDRV3FjY2MRHh6OevXqwcHBQe294OBg6bmyBzUkJASCIHxUnZnx9PSU9ku17oK2cOFCBAYGQhAEyOVyLFq0CI8ePUJKSgpu376N7777TuPY/deio6OlY1eQatasiYCAABw7dgxVq1bNMu/UqVPx9OlTAMCkSZPw5s0bHDx4EDKZDCkpKejfvz/evXsn5d+9ezcCAwMBABUqVEBYWBji4+Px/Plz/Prrr2jVqpWU9/r165g1axYAwNbWFn/++ScePXqEBg0aAAAOHjyIjRs36rRP48aNk/6fjR07FjExMdi+fTv09PSQlJSEfv36ITU1NVfHICsBAQH466+/AABdu3bF8+fPERYWBmNjY3z48AHffPMNXr16BUDskfb19UVycjL09PSwbds2xMTEYNy4cQCAu3fvYsKECTmq/927d1i6dCkAoH379nB0dJTek8lkaNKkCfbt24fY2Fi8ePECI0eOlN5ftGgRXr58Kb3OybkDgPLly2Pt2rV4+PAh3rx5g02bNqFQoUIAgFOnTuGXX36R8hobG6Nv374AgPXr1+e6V1+bfv36QRAEJCUlYcOGDVL6zp078dtvvwEQv0ObNm2KmzdvAgCqVKmCQ4cOIS4uDikpKbhz5w6Cg4PRrFmzfBmJ8vbtW7Rp0wb//vsvAKBVq1b4559/kJKSglOnTqF06dIAgMjISAwcOFBt21GjRmH79u0AAFNTU/z444948eIFUlJScP36dcyZMweWlpZa6920aRM+fPiAq1evonjx4gCA169fY/PmzXm+j18DX19f6TtcEARs2rRJeq9Ro0Zq733yvbc6SEpKKugmfBoKINAnIvpkqF4l3bdvnzBw4EDB0tJSsLS0FAYNGiTEx8cLf//9t9C8eXPBxMREcHJyEqZNmya8e/dOrZx3794J33//veDm5iaYmpoKBgYGQtmyZYUpU6Zo9DikpaUJ8+bNE5ycnASFQiFUrVpV+Omnn3LU0/348WOhZ8+eQoUKFQRra2tBX19fMDMzE2rWrCl8++23wvv37zX2NTg4WAAgLFu2TC39/v37gp6engBAKFmypNC8eXOpzow9e0o7duwQmjRpIhQuXFiQy+WCnZ2d0KxZM+Hq1avZXsUXhKx7C/73v/8JAwYMEJycnAS5XC6YmZkJ7u7uwrp164QPHz5I+e7du6fWs3P06FGhbt26gqGhYabnKSuvX78WTExMpDIXLVqkNV/GY/vnn38K3bp1ExwcHAS5XC5YWVkJXl5ewk8//aSWL+M+b9iwQShTpoxgaGgo1K1bVzh79qyQnJwsTJ06VbC3txcsLS2FFi1aCLdv31YrJ7Oe7tTUVGHNmjWCh4eHYGFhIcjlcsHBwUFo166d8PjxY0EQxM/ptGnThPLlywuGhoaCQqEQHBwcBC8vL+GHH37Q+VhlVKdOnSx7G6ysrKT3VXthq1WrJqXv379fSq9ataoAQJDJZMI///yTZd2qvaqqozNOnjwppdeuXTvbfXj9+rWgr68vABAMDQ2FpKQk6T1PT0+prMOHD+fqGGTmw4cPUu8tACE6Olp6z9fXV0pfvXq1IAiCcPDgQSnN09NTypuUlCT1fsvlciE2NlbnNmzfvl0q8+eff1Z7L+P3lyCI32FmZmbSNmfPnpXey8m5e/v2rVpPtlKrVq2kshcuXKj23sWLFzN9LzO69HRn/B6qVKmS9N7SpUsFQRCEmTNnqn0f5+QY54Vly5ZJ9RcpUkRITExUez8qKkrtu/bSpUuCIIi986qjd3bu3Km1fNXvNtWe7k2bNknp48aNk9KHDBmSbZtV/x74+fkJCxcuFIoXLy4YGRkJTZo0EW7duiXExsYKQ4YMEaytrQUbGxuha9euwrNnzzTK+umnnwRvb2/ByspKkMvlQtGiRYWuXbsKf/75p0beU6dOCe7u7oKhoaFgb28vjB8/Xjh06FCm5/vu3bvCkCFDhJIlSwoGBgaCmZmZ0KBBA2H37t1q+TL726X69yinvdOqx6hRo0Ya70dGRgodOnQQ7OzsBLlcLhQpUkTw8fERLly4oJYvNjZWGD58uLQPRkZGQvHixYUWLVoI27Ztk/I9fPhQ6Nu3r1CsWDFBLpcLJiYmQsmSJYX27dtrjDq6dOmS0LNnT8HR0VH6+9a8eXMhLCws033w8/MTFi9eLJQuXVooVKiQ9PkZM2aM4ObmJtja2krtK1u2rDBmzBjhxYsXGvsdFRUldOvWTa3u2rVrC3v27FE73toen2KvN4NuIvqqqf4YU/3hq3x4e3sLhQsX1khfsGCBVEZycnKWQ/FcXV2FV69eSflHjRqlNZ+Dg4POQfdff/2V5R8cbT+GWrduLchkMo0hgXPnzpW2mzp1qhAUFCS99vX11SinT58+mda7b9++jwq6z549K5iamma6bZcuXaTAW/WPrrm5uXThILPzlJ09e/ZI2xkbGwvJycnZbrN3715BLpdn2t6JEydKeVX3WdtnzdzcXGjRooXWz49qYKIt6E5JSRGaNGmSaTv++usvQRAEYezYsZnm8fDw0PlYZZRdwKlQKKT3VYNuZYAGpA9Tfv78uZTm6OgojBgxQihRooRgYGAglCtXTliyZIna8WjQoIGUPzQ0VEqPiYmR0vX19bO9ABMeHi7lr1y5stp7qv9n/fz8cnUMMnPnzh1pOzMzM7X3vv32W+m9vn37CoIgCLNmzZLSRo0apZa/cuXK0nsnTpzQuQ29evUSADFQ1iWQTExMFIyNjaVtlN8pOT13mVG9yKEaLAiCeJHC0tJSACDUr19fp/3LTdBdsWJF6T1l0K0aiGd2US4/qV4QHTNmjNY8qp+BxYsXC4IgCEuXLpXSSpcurVNdmQXdqt8hM2fOzLYc1b8H2r73nJychLp162qkN2vWTK2cCRMmZPrdJZfLhX379kl5f//9d8HAwEAjn6Ojo9bzfe7cObWLSBkfU6dOlfL+10H36tWrM73dSS6XC7/88ouUt0OHDpnuQ69evaR8qhc7Mz5Ubxc5cOBApn/fZDKZsGbNGq37YGNjo5ZX+fmxsLDItN6KFSuqfUevW7dO69905Wf/cwy6ObyciOj/WVpa4tatW/jf//4HU1NTAEB4eDjs7e0RHR2NM2fOqA29Vlq5ciUiIyMBANOmTUNMTAzevn2LxYsXAwD+/vtvLFiwAABw584drFy5EgBgYGCAn3/+GW/evEFwcDAeP36sc1sdHBwQGhqK+/fv4+3bt0hJScGVK1dQrFgxAOKEabGxsVL++Ph4HD9+HHXr1pXyKKkOEezWrRs6duwIuVwOAPjpp5/UJgTau3cvtmzZAgAwMTHB1q1bERsbiydPniAkJASOjo7S0DknJydpO0FluFxWBg4ciISEBOlYxsbG4s8//5SGNO7Zswc//fSTxnbx8fEYN24cXr16hf3790vpqucpO/fu3ZOely5dGgqFIsv8SUlJGDJkiDRR16pVqxAfH48TJ07A3NwcABAYGIjz589rbPvixQts2bIF8fHx6NChg7QPx44dQ2hoKF69eoVatWoBED8/2spQtXLlSoSFhQEA7O3tcfDgQbx58wb//vsvVqxYAQsLCwDi5xkASpYsiYcPHyI5ORnR0dH46aef0KlTp+wOUa5Vr15dev7tt98iISEBhw8fVpucTDlUWHU45aNHj7Bq1Sr8+++/ePfuHW7duoXJkyerDZ199uyZ9Fx1eKxynwEgNTUVMTExWbYxs3IylqWaLy/ktN78aGdUVBQAcZI+1TIyM2PGDCQmJgIAOnToIH2n5PTcafPzzz9LE9E5OjpK/z+UZDIZqlWrBgA4d+5cnt9mkZycjA0bNuD69etSmru7OwBx6L5SlSpVpOdhYWEaE2B17949T9sFQBpWDgClSpXSmkc5xBwA7t+/D0D9u61ChQq5qlsQBFy/fh2hoaEAAH19/Rzv45s3b3Ds2DG8fv0atWvXltp49epVREZG4smTJ9J3/a+//irdknL+/Hl8++23AMTP/IkTJxAfHy9NCPr+/XsMHjxYGsY8depU6XaVQYMG4dWrV7h27RqMjY21tmvAgAF48+YNLC0tERYWhuTkZPz777/SLSqLFy/GtWvXcrSveeHRo0cYN24cBEFAjRo18PfffyMlJQUXLlxAkSJF8P79ewwZMkS65UX5/e7u7o6XL18iKSkJd+7cwZYtW+Dt7Q0AePXqFS5dugQA6NSpE+Li4pCQkICbN29i3bp10t+dpKQkDBo0CO/fv4ezszPOnz+PlJQU3Lp1C+XKlYMgCBg/frzarSVKL1++xNKlS/Hq1Ss8efIETZs2BQCsWbMGN2/eRGxsLN6/f4+HDx+iRYsWAMTbhI4ePQoAePz4MUaPHi1NYjh9+nQ8efIEsbGx+PXXX+Hu7g5nZ2cIgoB+/fpJ9UZEREi/Mzw9PfP4bHw8Bt1ERP9v/PjxKFu2LFxcXNR+mIwZMwZOTk6oV68e7OzsAKj/uNy3b5/0fOHChShcuDBMTEwwZcoUKV35xyQsLEz6kdi2bVu0bdsWpqam6Nevn/TDThfW1ta4d+8eOnfujKJFi8LQ0BBVqlTBw4cPAQBpaWm4deuWlP/nn3/Gu3fv0KVLF7VyTp8+jdu3bwMAypYti2rVqsHKykr6I5mQkKAW5Kru66RJk9CrVy9YWFjA3t4effv2hZubm877kNHt27dx48YNAICNjQ0CAgJgYWGBGjVqYPz48Wr7klGRIkWwaNEiWFlZoX379ihcuDAA5Oh+ONUf77rcj3nmzBnpB0f16tUxfPhwmJmZoXHjxujfv3+W7a1Tpw569+4NMzMzNGvWTEp3d3eHj48PrKys0KRJEyk9u/1QPS+LFi1C69atYWpqiuLFi2PkyJEoWbIkgPQf5I8ePcKcOXOwbt063Lp1C97e3tI9wflh/vz50NfXByDOQG1mZobWrVurHXMDAwMA0Jht3NfXF3FxcYiKioKJiQkA8WLK1atXNepRLS9jMJaTe2wzbpvTz0Zu5bTevGrnkydPAIj/j7Jr35QpU/D9998DACpXroygoCDp/Y85dwAQGhqKbt26ARAvIBw4cEBroKRs57t377K9mKKrkJAQyGQyGBkZYfDgwVJ6165d4eHhoZE/OTk5T+rNCV0uMGjL87Gf3/79+0NPTw+VKlXCgwcP4OTkhL1796JixYo5Kqd9+/Zo1qwZLC0t1YKi9u3bo2HDhrC3t1c71srvvQMHDqi1pXHjxjAzM8PIkSOluRRevnyJ33//HYmJiThz5oy0r99++y2srKxQsWJFTJw4UaNNt2/flgLq2NhYNGnSBIaGhihRooS0coAgCDh27FiW+6YMAoU8vA/7yJEj0gz+Fy9ehKurKxQKBWrVqiVdpHzy5AkuX74MIP37/fr16/D390dwcDD+/fdfdOzYUfqbZGlpCWtrawDi37C5c+di586diImJQd++faWLXGfOnFG7EOrm5gaFQoFy5cpJvy2SkpKkDgdVXl5emDhxIqysrGBvby/NEWFkZISRI0fCxcUFhoaGKFasmPTbCID09//IkSPS/y9PT0/Mnz8f9vb2sLCwQNOmTaXviM8Ng24iov/n4uIiPTcyMpKeKwMWAFLvp+pSNrr0KCmDM9Wrwsor+kqqPcPZGTduHCZOnIjz588jPj5e6w8t1clL9uzZAwAavZmqk5i5u7vj0qVLuHTpEmrUqKE1j7LnARB/cOcl1eNYrFgxaTIlAGrLpmg73mXKlJGCOgDSD/yMSw5lRbWH6Pbt29luq9qOjOcuu/bm5LMGZP8DX9fzsmzZMtSvXx/v3r3D+vXrMXr0aDRv3hy2trY5nnwrJ7y8vHDixAk0adIEJiYmsLCwgLe3Nzp27CjlUR7DjIHf2LFjYW5ujjp16kgXgwBIS40pL4QBUBvdERcXJz2Xy+WwtrZGdHS01mV5sionY1mq+XJCW73R0dE5rje/25mZd+/eoXfv3liyZAkAoG7duoiIiICVlZWUJ6fnTtUPP/yArl27Ijk5GXZ2djhx4gRq1qyZp/ugK1NTU9SuXRsrVqyQJh8D1HuXlQECADRp0kRjQqzsaFuuLLslqFS/Z1R73VWppivzq363qfbg51ZSUlKOvluVcvu9l5Pv2tevX0tLpllYWEijjrRtm7HsrGjr0c1vOW3bxo0bUaVKFcTHx2PlypUYNmwYGjdujCJFiuC7774DAOjp6WHnzp0oVaoUnj59im+//RaDBg2Ch4cH7O3tsXPnzlzVrUrb/9uffvoJHTt2RFhYGF6+fKl1WTvlb5b8/J1RkBh0ExH9P9WgTZd0JdUft2fPnlUbSq18KIeO29jYSHkfPHigVo5yKKAutm7dKj3fu3cvUlJSpCFoGb158wa//vor6tSpgxIlSkjpiYmJUjAOiD091atXR/Xq1TFv3jwpPTIyUrpyb29vL6VnN9wupz0qqsfx4cOHan+UVXsOtAUTyuHwua0bALy9vaVgPTExET/88IPWfMqhfKrtyHjusmtvbj9rmdH1vDg5OeH06dN49uwZwsPDsX79etSuXRvv37/Hd999Jw0zzg8NGjTA8ePHkZCQgNjYWBw/fhzPnz+X3lcGZaVLl1YL5FSpXlxS9oDWrVtXSlPdd9Xe1OrVq2t8RjKqWbOmlOf27dtqFzpUy6pTp06W5eRUqVKlYGtrC0AcWaL6WdJWb2b7m5ycLI1akcvlWr8LMlO0aFEAyHQ28Li4OLRo0UIKQDt27IgTJ05II0qUcnrulOmTJk3CmDFj8OHDB5QvXx5RUVFZtl/ZTrlcrtGG3FLOXi4IAt68eYM//vgDI0eOVLv41759e+n5ypUr8ebNmzypW1ctW7aUnu/YsUPjYtz58+fVPjPNmzcHALRp0wZ6euJP/jt37qh976tSnZlf1aZNm5CcnIygoCDo6enh+fPn6NGjhzTjvq7y4m9sdt+1VlZW0r7GxcUhPj4+020zll2+fHmtf78FQZBuEfsvqbbtm2++0dquDx8+SOe5evXquHz5Mh48eIBjx45h1apVKFeuHJKSkjBx4kTpd0jTpk1x584d3L59G4cOHcJ3330He3t7xMbGYtCgQUhLS1Oru3nz5pnW/c0332i0W9volG3btknPJ02aJHUWqI5iU8rP3xkFiUE3EdFHUu2tGzFiBP7880+kpKQgJiYGhw8fRpcuXbBw4UIAYo+I8o/EL7/8goMHDyIhIQEhISE4e/asznWq/kgxMzNDamoq1q1bp/VH0MGDB5GcnKwxtDw0NFSnH42CIEj3Rvv4+EjpS5cuxc6dO6XlgLZv365277Hqj2HlPWRZcXFxgaurKwDx6vns2bMRFxeHS5cuScNZAaBdu3bZlpUblpaWmDlzpvR65syZWLp0KZ48eYL379/jzp07+O6779C2bVsAQL169aR9/Ouvv7B27VokJCQgMjJSbXSAMn9+Uj0vU6dOxZEjR5CQkIBHjx5hzZo10j2dS5YswbZt2xAfH4+6deuia9euaktdqd4zmp3ExES8fPkSL1++VPuxHhcXJ6UrPXr0CMHBwXjw4IG0/NrAgQOlYaCtWrWS2qGnp6fW47ds2TLEx8fj3Llz0n3rCoUCDRs2BCAOYVYGRqtXr8bFixfx+PFjzJ49WypDOVxYdQhoxnkGLCwspJEgycnJmDZtGl6/fo2dO3dKw0ydnJzUemxzcgy01avspRswYICUb/LkyXj58iXCw8Ol4Mjc3FwaUtm0aVNplMypU6ewY8cOvH79GtOnT5eCsK5du6r18GVHGdBHR0dr9J4/fPgQ9evXR0REBADxdpuffvpJradSKafnLiUlBT169JCWGGvYsCF+//13td7LjARBkL5Pateurfaj29PTU20UQV4bP368NFT26dOnaNq0KU6ePImkpCS8ffs2R3X6+/trfB6yWz5x0KBB0oXT58+fo2vXrrh9+zbev3+P3377Db169ZLydurUSfo/Va5cObUh84MGDcKGDRsQExODd+/e4caNG5gzZw4GDRqUad0KhQIDBgzAqFGjAIgBuurScflJ9Ts/ODgYkZGRSEhIwOrVq6Wh1TY2NqhXrx6MjY1Rv359AOJnZeLEiXj9+jVu3Lghfc5Uubi4oFKlSgCAmzdvYuLEidJ3/t27d7F69WpUqVIl24viqqNosvr85kTLli2lnv9NmzZh8+bNiIuLQ1JSEi5duoSZM2eiXr16Uv7p06dj3759SE1NRcOGDdG1a1dpdIEgCNLtZyNGjMDRo0dhYGCAJk2aoFu3btJSmG/fvkVMTAw8PDykkSu//vorAgMDERMTg5SUFNy8eROLFy9WG7mQHdXfLMbGxpDL5Th9+rTWeVdatmwJQ0NDAOJ92n5+fnj27Bni4+MRERGBXbt2SXlVf2dcuXJFug/8k5Sr6deIiL4QmS3TpTpzq2q6tpmjk5OT1Wbb1fZQnTE3s9nLVWd2zW728qFDh2psb2xsLBQrVkyjjI4dOwqA+lJEgiAIXl5eUt7ly5drHJsjR45I75csWVKaNbxv376Z7qfqDLLa9lM5M2tmM8CeOXNGmhVZ28PHx0fr7OUZZ3zNbFktXWQ1Sy4AoWrVqlLen376SVpmSttj7NixUt7M9ll11lfVdNWZlVVnD/6Y2cu9vb0zzWNmZiYtLaYL1fZl9lDKarb9ihUrqs1oLgjiMlWqszBnfGRc9m7BggWZ5m3Tpo2Qlpam0z49fvxYcHZ21lqOkZGRxhJ6OTkGWUlISBCqV6+udXs9PT1hx44davnDw8Ol5cEyPkqWLKlxPLOzbds2afuMS4bpso+qn8+cnDvV/xOZPTLOKq66ZFjG1QlUv7fv3bsnpauuuDBnzhyt+5axnsxcu3ZNKF26dLbt7tatm07l5dSVK1eEEiVKZFl3o0aNNJZ6e/fundCjR48st2vfvr2UP7PZy1+9eiVYW1tL7+3ZsyfL9qp+v2U2c7xqemZ/k7NaeUFfX19ticbMZi9X/RubcfZyc3PzLI+N8vP0X89evmbNmkxnL89YV1afy2LFiknLIBYqVCjTfDVr1pTK+/nnn7UeR23fb5mdZ6WdO3dq3b5s2bJat8tu9nKl0NDQLNv1KWFPNxHRR1IoFDh+/DhWrFgBd3d3mJubw8DAAMWKFUPDhg0xb948tRk2ly1bhnnz5qF48eIwMDBApUqVsG3bNrRq1UrnOr/99luMHTsWDg4OMDQ0hLu7O44fP6527x4gXrU+evQo3Nzc1O5ne/DggTRDsIGBgVoPiVKzZs2kHrV79+7h1KlTAMRh6Nu3b4e3tzesra2hr68PW1tbNG3aVO3Kt7+/P3r16gU7Ozudh4DVq1cPf/31F3x9fVG8eHHI5XKYmpqiTp06WLNmDfbs2ZPvw8kCAwPxxx9/oH///ihdujSMjIxgYmKCMmXKqN3TCoi9SWfPnkWXLl1gb28PfX19WFhYwNPTEzt37lTroc9PBgYGOHr0KFavXg0PDw9YWFhALpejaNGiaNu2rTRU0NfXF+3atYOTkxNMTExQqFAhFC1aFJ06dcLp06elYcZ5zc7ODh07dkSJEiVgaGgIY2NjVK1aFfPnz0dUVJTGEHxzc3OcPn0akydPRunSpSGXy2Fubg5vb28cPnwYY8aMUcs/bdo07N27Fw0bNoSpqSkMDQ1RuXJlLF26FHv37pWGm2anaNGi0rBiJycnyOVy2NjYoFOnToiKikKjRo3y7JioMjExQWRkJGbMmIEyZcrAwMAAlpaWaNGiBSIiIjRmifby8kJUVBQ6deoEGxsbyOVyODk5YdSoUfjjjz9yfD93586dpSHuqsNAcyOn5y6nlO0zMDDIdiZ0pb///lt6/rHD0StWrIjLly/jhx9+gKenJwoXLgx9fX0UKVIElStXRrdu3bB161asXbv2o+rJTOXKlXHlyhUsWLAAderUgbm5uVR/s2bNEBISgvDwcI2RDnK5HNu3b8evv/6K7t27o0SJElAoFDA3N4erqyuGDBmCqVOnZlu/lZUVZs2aJb2eMmWKNFN4fvr++++xa9cuNG7cGJaWltDX14e9vT06d+6M33//XW2+EuXfw7p160KhUMDW1hYjR45Um/RPlZubG65cuYLhw4fDxcUFCoUCpqamKFOmDLp06YLg4GCpJ/i/NnToUJw+fVqaNFVfXx/W1taoXLkyhg4dinXr1kl5R40ahebNm6NYsWIwNDSEXC5H8eLF0a9fP5w6dUrqPZ42bRo8PT1RtGhRGBgYwMDAAKVLl5Z6wJXatm2LP//8E3379kWJEiUgl8thYWEBV1dX9O3bV63HOTvdunXD2rVrUbZsWWlCtvXr16NHjx5a8w8ePBi///47unXrBkdHR8jlclhaWqJ27drSSAZAHOU1e/ZsODs75/r2rP+KTBDyeK0FIiL6ZOzevRvdunXD4sWLMXny5IJuDhF9ogIDAzFp0iQYGhri7t27+XYB5mMkJibC2dkZL168wMiRI6Ulo7RJTU3F4cOHceTIEbUA+MqVK1/U5ExE9Hlg0E1ERET0lXv//j0qVaqEf/75J9uAtqAoLwwULlwY//zzj7T0kTaxsbEak7oNHjxYrWeQiOi/wuHlRET0xVOdYEnbI7uler4mzs7OWR4rf3//gm4i6Sgnn3u5XI5bt25BEIRPMuAGgIkTJ0IQBLx8+TLLgFtJJpPB3NwcHh4eWL9+PX788cf/oJVERJo+7cHvREREREQ5ZGlp+WnPZExEXxUOLyciIiIiIiLKJxxeTkRERERERJRPGHQTERERERER5RPe001En4QPHz7g8ePHMDMzy/d1mImIiIiIPpYgCHjz5g0cHBygp5d5fzaDbiL6JDx+/BjFixcv6GYQEREREeXIgwcPUKxYsUzfZ9BNRJ8EMzMzAOKXlrm5eQG3hoiIiIgoa/Hx8ShevLj0OzYzDLqJ6JOgHFJubm7OoJuIiIiIPhvZ3RrJidSIiIiIiIiI8gmDbiIiIiIiIqJ8wqCbiIiIiIiIKJ8w6CYiIiIiIiLKJwy6iYiIiIiIiPIJg24iIiIiIiKifMKgm4iIiIiIiCifMOgmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoJuIiIiIiIgonzDoJiIiIiIiIsonDLqJiIiIiIiI8gmDbiIiIiIiIqJ8wqCbiIiIiIiIKJ8w6CYiIiIiIiLKJ/oF3QAiIlVWk5tCpuBXExERERGlS11+pqCbkGvs6SYiIiIiIiLKJwy6iYiIiIiIiPIJg24iIiIiIiKifMKgm4iIiIiIiCifMOgmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoLuABQcHQyaTSQ99fX0UK1YM/fv3x6NHj/KsHmdnZ/j6+mabLz4+HjNmzEDZsmVhbGwMR0dHdOnSBdevX8913e/evcPQoUNRtGhRFCpUCNWqVct1Wbmxfft2LFu27KPLef78OXx9fWFjYwNjY2O4u7sjPDxcp203bNiADh06wNnZGUZGRnBxccGwYcPw5MkTnet///49ypcvj0WLFqmlJyQkYOzYsXBwcIChoSGqVauGnTt36lzusWPH4OHhASMjI1hYWKBt27aZnu+wsDC4u7vD2NgYNjY28PX1xfPnz9XyhIeHw9TUNE8/v0REREREnysG3Z+ITZs24ezZszh+/DgGDx6MHTt2oEGDBnj79u1/2o62bdti2bJlGDx4MA4dOoRFixbh0qVLcHd3x/3793NV5po1a/Djjz9ixowZ+O2337Bly5Y8bnXW8iLoTklJgbe3N8LDw7F8+XIcOHAAdnZ2aNGiBSIjI7Pdfvbs2TA1NcWCBQtw9OhRTJ48GQcPHkTNmjXx7NkzndqwevVqvH79GqNGjVJL9/HxQUhICGbPno0jR47Azc0NPXr0wPbt27Mt88CBA2jZsiVsbW0RGhqKtWvX4n//+x8aNGiAO3fuqOWNjIxEy5YtYWdnhwMHDmD58uUICwuDt7c3UlJSpHze3t6oXbs2pk+frtN+ERERERF9yfQLugEkqlSpEmrVqgUAaNy4MdLS0hAQEID9+/ejV69e/0kbbt++jVOnTmHmzJmYNGmSlO7i4oJ69eph7969GDduXI7LvXbtGoyMjDBy5Mgs8wmCgOTkZBgZGeW4jvwWFBSEa9eu4ffff4e7uzsA8TxVrVoVkydPxh9//JHl9n/99RdsbW2l140aNUKNGjXg5uaG9evXY+bMmVlun5qaiqVLl2LAgAEwMTGR0g8fPozjx49j+/bt6NGjh9Su+/fvY9KkSejWrRsKFSqUablTpkxB5cqVsXfvXshkMgBAvXr1ULZsWfj5+WHbtm1S3kmTJqFs2bL46aefoK8vfnWULFkSHh4e2LhxI4YNGyblHTFiBLp164Z58+ahePHiWe4bEREREdGXjD3dn6i6desCgNS7PGfOHNSpUwfW1tYwNzdHjRo1EBQUBEEQ1LZ7//49Jk+eDHt7exgbG6N+/fo4d+6cTnXK5XIAgIWFhVq6paUlAMDQ0DDH+yGTybBhwwYkJSVJQ+iDg4Ol90aOHIm1a9fC1dUVCoUCISEhOdpfQOzJdnd3h6mpKUxNTVGtWjUEBQUBADw9PXHo0CHcv39fbRh/Tu3btw/lypWTAm4A0NfXR+/evXHu3Llsh1KrBtxKNWvWRKFChfDgwYNs6//555/x6NEj9OnTR6Ndpqam6NKli1p6//798fjx4ywvBsTExODWrVto2bKl2jFxcnJCpUqVsH//fqSlpQEAHj16hPPnz6NPnz5SwA2kB+j79u1TK7tt27YwNTXF+vXrs903IiIiIqIvGXu6P1G3b98GABQpUgQAEB0djW+++QYlSpQAAERFRWHUqFF49OgR/Pz8pO0GDx6MzZs3Y+LEiWjatCmuXbsGHx8fvHnzJts6nZyc0L59e3z//feoWbMm3Nzc8PDhQ4wePRolSpRA9+7dc7wfZ8+eRUBAACIiInDixAkAQOnSpaX39+/fj9OnT8PPzw/29vZScKrr/vr5+SEgIAA+Pj6YMGECLCwscO3aNelixerVqzFkyBDcuXNHIzDMiWvXrqFBgwYa6VWqVAEAXL9+HY6OjjkqMzIyEmlpaahYsWK2eQ8dOgRbW1tUqFBBo12urq5qgbBqu65du4Z69eppLfPdu3cAAIVCofGeQqFAYmIi7ty5g7Jly+LatWtq5Was68yZM2ppBgYGqFevHg4dOoS5c+dqrT8lJUVtWHp8fLzWfEREREREnzMG3Z+ItLQ0pKamIjk5GZGRkZg3bx7MzMzQrl07AOI930ofPnyAp6cnBEHA8uXLMWvWLMhkMty8eRMhISEYN24clixZAgBo2rQp7OzsdB6ivmfPHowYMQJeXl5SWpUqVRAZGQkrK6sc71fdunVRpEgR6OnpSb33qhISEnD16lWNsnXZ33v37mHBggXo1asXtm7dKuVv2rSp9LxChQqwtLSEQqHQWr+uYmJiYG1trZGuTIuJiclReW/evMHw4cNRvHhxDBgwINv8Z8+eRY0aNbS2q1SpUrlql52dHaytrTUC5tjYWCnIVm6v/DezY6Ctnho1amDhwoV4+/at2pB4pYULF2LOnDmZto+IiIiI6EvA4eWfiLp160Iul8PMzAxt2rSBvb09jhw5Ajs7OwDAiRMn0KRJE1hYWKBQoUKQy+Xw8/NDTEyMNHt0REQEAGgE2F27dtXoCc3MsGHDEBoaiu+//x6RkZHYtWsXDAwM4OXlleuJ1LLi5eWlNZjXZX+PHz+OtLQ0jBgxIs/bpU1Ww9JzMmQ9OTkZPj4+uH//Pvbs2QNTU9Nst3n8+LHWIeof0y49PT2MGDEC4eHhCAgIwPPnz3H79m307t0biYmJUh5dytOWbmtriw8fPuDp06dat5k2bRri4uKkhy7D7ImIiIiIPjfs6f5EbN68WRombGdnh6JFi0rvnTt3Ds2aNYOnpyfWr1+PYsWKwcDAAPv378f8+fORlJQEIL030t7eXq1sfX19FC5cONs2HD16FEFBQdizZw86d+4spTdr1gzOzs7w9/dX64HOC6r7qaTr/r548QIAUKxYsTxtkzaFCxfW2pv76tUrANp7gLVJSUlBx44d8dtvv+HgwYOoU6eOTtslJSVpvaf+Y9vl5+eHhIQEzJs3Txq237p1a/Tv3x8bNmyQhswrPz+Z1aWtHmV7lecrI4VCoXVoOxERERHRl4RB9yfC1dVVmr08o507d0Iul+PgwYNqgdf+/fvV8ikDo6dPn6rdX5yamqrT8OdLly4BANzc3NTSLS0t4eLiIg05zkvaekh13V/l/e4PHz7M9xmyK1eujKtXr2qkK9MqVaqUbRkpKSno0KEDIiIicODAAXh7e+tcv42NjRRIZ2zXjh07kJqaqjaaQdd26evr47vvvsPcuXNx79492NjYoGjRomjevDlKliwpXdBQlnP16lW0atVKrYyrV69qrUfZXhsbG533k4iIiIjoS8Ph5Z8BmUwGfX19taWfkpKSNNa79vT0BAC1ZZ4AYPfu3UhNTc22HgcHBwDipGWqYmJi8M8///wnPcqA7vvbrFkzFCpUCGvWrMmyPIVCkWlvq646duyImzdvqs0Gnpqaiq1bt6JOnTrSscuMsof7xIkTCA0NRfPmzXNUf/ny5TXWzVa2KyEhAaGhoWrpISEhcHBw0Lkn3dTUFJUrV0bRokVx8eJFhIeHY8yYMdL7jo6OqF27NrZu3SrNaA6In5Vbt27Bx8dHo8y7d++icOHC0i0SRERERERfI/Z0fwZat26N7777Dj179sSQIUMQExODwMBAjaG5rq6u6N27N5YtWwa5XI4mTZrg2rVrCAwMhLm5ebb1+Pj4wM/PD8OGDcPDhw9Ro0YNPHnyBEuXLkViYqJaEAaIwXGjRo1w8uTJvNxdnffX2dkZ06dPR0BAAJKSktCjRw9YWFjgxo0bePnypTRJl3Id6jVr1qBmzZrQ09OTRhW4uLgASJ8tPjMDBgzAqlWr0KVLFyxatAi2trZYvXo1bt26hbCwMLW83t7eiIyMVLvQ0blzZxw5cgQzZsxA4cKF1S5smJuba8xKnpGnpyfmzp2LxMREGBsbS+ktW7ZE06ZNMWzYMMTHx8PFxQU7duzA0aNHsXXrVrULFwMHDkRISAju3LkDJycnAMDJkydx/vx5VKlSBYIg4Ny5c1i8eDFatGihsa764sWL0bRpU3Tp0gXDhw/H8+fPMXXqVFSqVAn9+/fXaHNUVBQaNWqUqyXaiIiIiIi+FAy6PwNeXl7YuHEjFi9ejLZt28LR0RGDBw+Gra0tBg4cqJY3KCgIdnZ2CA4Oxg8//IBq1aohNDRUp+W+TE1NERUVhfnz52Pt2rV4+PAhrK2tUb16daxZs0Zt9u+EhAQA2u/J/lg52d+5c+eiTJkyWLFiBXr16gV9fX2UKVMGo0ePlvKMGTMG169fx/Tp0xEXFwdBEKT1vnUZAQCIveXh4eGYPHkyRo0ahcTERFSrVg1HjhxBo0aN1PKmpaWp9QYDwMGDBwEA8+fPx/z589Xe0+XCRc+ePTF79mwcOnRIY03uvXv3YsaMGfDz88OrV69Qvnx57NixQ+OcK9uluta5gYEBQkNDMW/ePKSkpKBMmTKYO3cuRo8erRawA2Lgf/jwYfj5+aFt27YwNjZGmzZtsHTpUo0LInfu3MHVq1fh7++f5X4REREREX3pZILqL3AiHR0+fBht2rTB5cuXUbly5YJuzlehbdu2SE1NxZEjRwq6KdmaNWsWNm/ejDt37ug8c358fDwsLCyg901tyBS8HkhERERE6VKXn8k+039M+fs1Li4uy5HFvKebciUiIgLdu3dnwP0fWrhwIcLCwnD+/PmCbkqWYmNjsWrVKixYsEDngJuIiIiI6EvFX8SUK0uXLi3oJnx1KlWqhE2bNmW67vWn4t69e5g2bRp69uxZ0E0hIiIiIipwDLqJPiO9e/cu6CZkq3r16qhevXpBN4OIiIiI6JPA4eVERERERERE+YRBNxEREREREVE+YdBNRERERERElE94TzcRfVJeLzme5ZILRERERESfE/Z0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE8YdBMRERERERHlEwbdRERERERERPmES4YR0SelyKyWkCn41URERET0NUleElnQTcg37OkmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoJuIiIiIiIgonzDoJiIiIiIiIsonDLqJiIiIiIiI8gmDbiIiIiIiIqJ8wqC7gAUHB0Mmk0kPfX19FCtWDP3798ejR4/yrB5nZ2f4+vpmmy8+Ph4zZsxA2bJlYWxsDEdHR3Tp0gXXr1/Pdd3v3r3D0KFDUbRoURQqVAjVqlXLdVm5sX37dixbtuyjy3n+/Dl8fX1hY2MDY2NjuLu7Izw8XKdt/f391c6z8mFoaKhz/e/fv0f58uWxaNEitfSEhASMHTsWDg4OMDQ0RLVq1bBz506dyz127Bg8PDxgZGQECwsLtG3bNtPzHRYWBnd3dxgbG8PGxga+vr54/vy5Wp7w8HCYmprm6eeXiIiIiOhzpV/QDSDRpk2bUL58eSQlJeHUqVNYuHAhIiMjcfXqVZiYmPxn7Wjbti0uXLgAf39/1KpVCw8fPsTcuXPh7u6Oq1evwsnJKcdlrlmzBj/++CNWrFiBmjVrwtTUNB9anrnt27fj2rVrGDt2bK7LSElJgbe3N2JjY7F8+XLY2tpi1apVaNGiBcLCwtCoUSOdyjl69CgsLCyk13p6ul/3Wr16NV6/fo1Ro0appfv4+OD8+fNYtGgRypYti+3bt6NHjx748OEDevbsmWWZBw4cQMeOHdG+fXuEhoYiLi4Oc+bMQYMGDXD+/HmULl1ayhsZGYmWLVuidevWOHDgAJ4/f44pU6bA29sbFy5cgEKhAAB4e3ujdu3amD59OkJCQnTePyIiIiKiLxGD7k9EpUqVUKtWLQBA48aNkZaWhoCAAOzfvx+9evX6T9pw+/ZtnDp1CjNnzsSkSZOkdBcXF9SrVw979+7FuHHjclzutWvXYGRkhJEjR2aZTxAEJCcnw8jIKMd15LegoCBcu3YNv//+O9zd3QGI56lq1aqYPHky/vjjD53KqVmzJmxsbHJcf2pqKpYuXYoBAwaoXYQ5fPgwjh8/LgXaynbdv38fkyZNQrdu3VCoUKFMy50yZQoqV66MvXv3QiaTAQDq1auHsmXLws/PD9u2bZPyTpo0CWXLlsVPP/0EfX3xq6NkyZLw8PDAxo0bMWzYMCnviBEj0K1bN8ybNw/FixfP8f4SEREREX0pOLz8E1W3bl0AwP379wEAc+bMQZ06dWBtbQ1zc3PUqFEDQUFBEARBbbv3799j8uTJsLe3h7GxMerXr49z587pVKdcLgcAtZ5YALC0tASAHA2FVpLJZNiwYQOSkpKkIdXBwcHSeyNHjsTatWvh6uoKhUIh9Yzqur+A2JPt7u4OU1NTmJqaolq1aggKCgIAeHp64tChQ7h//77asO6c2rdvH8qVKycF3ACgr6+P3r1749y5c/k+lPrnn3/Go0eP0KdPH412mZqaokuXLmrp/fv3x+PHj7O8GBATE4Nbt26hZcuWasfEyckJlSpVwv79+5GWlgYAePToEc6fP48+ffpIATeQHqDv27dPrey2bdvC1NQU69evz/U+ExERERF9CdjT/Ym6ffs2AKBIkSIAgOjoaHzzzTcoUaIEACAqKgqjRo3Co0eP4OfnJ203ePBgbN68GRMnTkTTpk1x7do1+Pj44M2bN9nW6eTkhPbt2+P7779HzZo14ebmhocPH2L06NEoUaIEunfvnuP9OHv2LAICAhAREYETJ04AgNqQ5f379+P06dPw8/ODvb09bG1tc7S/fn5+CAgIgI+PDyZMmAALCwtcu3ZNulixevVqDBkyBHfu3NEIDHPi2rVraNCggUZ6lSpVAADXr1+Ho6NjtuVUrlwZz58/h42NDZo3b4558+ZJ+5iVQ4cOwdbWFhUqVNBol6urq1ogrNqua9euoV69elrLfPfuHQBIw8JVKRQKJCYm4s6dOyhbtiyuXbumVm7Gus6cOaOWZmBggHr16uHQoUOYO3eu1vpTUlKQkpIivY6Pj9eaj4iIiIjoc8ag+xORlpaG1NRUJCcnIzIyEvPmzYOZmRnatWsHQLznW+nDhw/w9PSEIAhYvnw5Zs2aBZlMhps3byIkJATjxo3DkiVLAABNmzaFnZ2dzkPU9+zZgxEjRsDLy0tKq1KlCiIjI2FlZZXj/apbty6KFCkCPT09qfdeVUJCAq5evapRti77e+/ePSxYsAC9evXC1q1bpfxNmzaVnleoUAGWlpZQKBRa69dVTEwMrK2tNdKVaTExMVluX7p0acyfPx/Vq1eHoaEhzp07hyVLluDXX3/Fn3/+mW3AfvbsWdSoUUNru0qVKpWrdtnZ2cHa2lojYI6NjZWCbOX2yn8zOwba6qlRowYWLlyIt2/fap2XYOHChZgzZ06m7SMiIiIi+hJwePknom7dupDL5TAzM0ObNm1gb2+PI0eOwM7ODgBw4sQJNGnSBBYWFihUqBDkcjn8/PwQExMjzR4dEREBABoBdteuXTV6QjMzbNgwhIaG4vvvv0dkZCR27doFAwMDeHl5Sb3HecnLy0trMK/L/h4/fhxpaWkYMWJEnrdLm6yGpWc3ZL1Pnz6YPn06WrZsicaNG2PKlCk4cuQIXrx4IV0gycrjx4+lUQB51S49PT2MGDEC4eHhCAgIwPPnz3H79m307t0biYmJUh5dytOWbmtriw8fPuDp06dat5k2bRri4uKkx4MHDzJtKxERERHR54pB9ydi8+bNOH/+PP766y88fvwYV65cgYeHBwDg3LlzaNasGQBg/fr1OHPmDM6fP48ZM2YAAJKSkgCk90ba29urla2vr4/ChQtn24ajR48iKCgIP/74I8aOHYuGDRuia9euOH78OF69egV/f/+82l1J0aJFNdJ03d8XL14AAIoVK5bn7cqocOHCWntzX716BUB7D3B2ateujbJlyyIqKirbvElJSVrvqf/Ydvn5+WHcuHGYN28e7OzsUKZMGQDiPeEApB545ecns7q01aNsr/J8ZaRQKGBubq72ICIiIiL60nB4+SfC1dVVmr08o507d0Iul+PgwYNqgdf+/fvV8ikDo6dPn6oNV05NTc12+DMAXLp0CQDg5uamlm5paQkXFxdpyHFe0tZDquv+Ku93f/jwYb7PkF25cmVcvXpVI12ZVqlSpVyVKwiCTsuG2djYSIF0xnbt2LEDqampaqMZdG2Xvr4+vvvuO8ydOxf37t2DjY0NihYtiubNm6NkyZLSBQ1lOVevXkWrVq3Uyrh69arWepTtzc1s7UREREREXwr2dH8GZDIZ9PX11ZZ+SkpKwpYtW9TyeXp6AoDaMk8AsHv3bqSmpmZbj4ODAwBo9LzGxMTgn3/++U96lAHd97dZs2YoVKgQ1qxZk2V5CoUi095WXXXs2BE3b95Umw08NTUVW7duRZ06daRjlxNRUVH43//+p9O95uXLl8edO3e0tishIQGhoaFq6SEhIXBwcECdOnV0aoupqSkqV66MokWL4uLFiwgPD8eYMWOk9x0dHVG7dm1s3bpVmtFcuQ+3bt2Cj4+PRpl3795F4cKFpVskiIiIiIi+Ruzp/gy0bt0a3333HXr27IkhQ4YgJiYGgYGBGrNOu7q6onfv3li2bBnkcjmaNGmCa9euITAwUKehuz4+PvDz88OwYcPw8OFD1KhRA0+ePMHSpUuRmJioFoQBYnDcqFEjnDx5Mi93V+f9dXZ2xvTp0xEQEICkpCT06NEDFhYWuHHjBl6+fClN0qVch3rNmjWoWbMm9PT0pFEFLi4uANJni8/MgAEDsGrVKnTp0gWLFi2Cra0tVq9ejVu3biEsLEwtr7e3NyIjI9UudFStWhW9e/eGq6urNJHa0qVLYW9vj8mTJ2d7TDw9PTF37lwkJibC2NhYSm/ZsiWaNm2KYcOGIT4+Hi4uLtixYweOHj2KrVu3ql24GDhwIEJCQnDnzh04OTkBAE6ePInz58+jSpUqEAQB586dw+LFi9GiRQuNddUXL16Mpk2bokuXLhg+fDieP3+OqVOnolKlStJwdFVRUVFo1KhRrpZoIyIiIiL6UjDo/gx4eXlh48aNWLx4Mdq2bQtHR0cMHjwYtra2GDhwoFreoKAg2NnZITg4GD/88AOqVauG0NBQnZb7MjU1RVRUFObPn4+1a9fi4cOHsLa2RvXq1bFmzRq1HtmEhAQA2u/J/lg52d+5c+eiTJkyWLFiBXr16gV9fX2UKVMGo0ePlvKMGTMG169fx/Tp0xEXFwdBEKT1vnUZAQCIveXh4eGYPHkyRo0ahcTERFSrVg1HjhxBo0aN1PKmpaWp9QYD4izq69atw5MnT/Du3Ts4ODige/fu8PPz0+kY9uzZE7Nnz8ahQ4c01uTeu3cvZsyYAT8/P7x69Qrly5fHjh07NM65sl2qa50bGBggNDQU8+bNQ0pKCsqUKYO5c+di9OjRagE7IAb+hw8fhp+fH9q2bQtjY2O0adMGS5cu1bggcufOHVy9ejVf5gEgIiIiIvqcyATVX+BEOjp8+DDatGmDy5cvo3LlygXdnK9C27ZtkZqaiiNHjhR0U7I1a9YsbN68GXfu3NF55vz4+HhYWFjAYHQ9yBS8HkhERET0NUleElnQTcgx5e/XuLi4LEcW855uypWIiAh0796dAfd/aOHChQgLC8P58+cLuilZio2NxapVq7BgwQKdA24iIiIioi8VfxFTrixdurSgm/DVqVSpEjZt2pTputefinv37mHatGno2bNnQTeFiIiIiKjAMegm+oz07t27oJuQrerVq6N69eoF3QwiIiIiok8Ch5cTERERERER5RMG3URERERERET5hEE3ERERERERUT7hPd1E9El5EXAkyyUXiIiIiIg+J+zpJiIiIiIiIsonDLqJiIiIiIiI8gmDbiIiIiIiIqJ8wqCbiIiIiIiIKJ8w6CYiIiIiIiLKJ5y9nIg+Kbv/NwHGpgYF3QwiIiLKRs9yqwq6CUSfBfZ0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE8YdBMRERERERHlEwbdRERERERERPmEQTcRERERERFRPmHQTURERERERJRPvtqgOzg4GDKZTHro6+ujWLFi6N+/Px49epRn9Tg7O8PX11fn9kRHR+dZ3b6+vnB2ds42nyAIWL9+PWrWrAlzc3MULlwYjRo1wqFDh/KsLVm1SSaTwd/fX3p98uRJyGQynDx5Msfl37hxA/7+/lqPo67HIz9s3rwZ3bt3R7ly5aCnp5erdpw+fRoKhQL3799XS7948SKaNGkCU1NTWFpawsfHB3fv3tWpzJSUFCxduhSVKlWCiYkJ7Ozs0LJlS/z+++9q+f7880+MGDEClStXhpmZGezs7NCkSROcOHFCo8w+ffqgQ4cOOd4/IiIiIqIv0VcbdCtt2rQJZ8+exfHjxzF48GDs2LEDDRo0wNu3bwu6af+Z2bNnY8iQIahduzZCQ0MRHBwMhUKBNm3aYO/evfle/9mzZzFo0KA8KevGjRuYM2eO1qB71qxZ2LdvX57Uk1NbtmzB9evXUbt2bZQuXTrH2wuCgLFjx2Lw4MFwcnKS0m/evAlPT0+8e/cOu3fvxsaNG/HPP/+gQYMGePHiRbblDh48GFOnTkWHDh3wyy+/YNWqVXjx4gUaNWqEc+fOSfl27NiBc+fOYcCAAThw4AA2bNgAhUIBb29vbN68Wa1Mf39/HDp0SGtATkRERET0tdEv6AYUtEqVKqFWrVoAgMaNGyMtLQ0BAQHYv38/evXqVcCt+29s3LgR9evXx5o1a6S0pk2bwt7eHiEhIfDx8cnX+uvWrZuv5SvlJtjNK8eOHYOenniNq02bNrh27VqOtj969CguXryI7du3q6X7+flBoVDg4MGDMDc3BwDUrFkTZcqUQWBgIBYvXpxpmSkpKdi+fTt69uyJefPmSekeHh5wcHDAtm3bULt2bQDA5MmTERgYqLZ9q1atUKNGDcydOxd9+/aV0kuXLo0WLVpg0aJF8PLyytF+EhERERF9ab76nu6MlAGgcgjvnDlzUKdOHVhbW8Pc3Bw1atRAUFAQBEFQ2+79+/eYPHky7O3tYWxsjPr166v1FKqKioqCh4cHDA0N4eDggGnTpuH9+/da8+7atQvu7u4wMTGBqakpmjdvjr/++ksjX3BwMMqVKweFQgFXV1eN3sesyOVyWFhYqKUZGhpKj9zStU0Zh5drc+HCBXTv3h3Ozs4wMjKCs7MzevTooTbUOjg4GF26dAEgXkBR3joQHBwMQPvw8uTkZEybNg0lS5aEgYEBHB0dMWLECMTGxqrlc3Z2Rps2bXD06FHUqFEDRkZGKF++PDZu3KjTsVAG3Lm1Zs0auLm5oVy5clJaamoqDh48iE6dOkkBNwA4OTmhcePG2fbq6+npQU9PT+Pcm5ubQ09PT+3c29raamxfqFAh1KxZEw8ePNB4r0+fPggLC8OdO3d03kciIiIioi8Rg+4Mbt++DQAoUqQIACA6OhrffPMNdu/ejb1798LHxwejRo1CQECA2naDBw9GYGAg+vbtiwMHDqBTp07w8fHB69ev1fLduHED3t7eiI2NRXBwMNauXYu//vpLradRacGCBejRowcqVKiA3bt3Y8uWLXjz5g0aNGiAGzduSPmCg4PRv39/uLq6IjQ0FDNnzkRAQIDOw3vHjBmDo0ePIigoCK9fv8aTJ08wfvx4xMXFYfTo0Tk6fnnVpoyio6NRrlw5LFu2DMeOHcPixYvx5MkTuLm54eXLlwCA1q1bY8GCBQCAVatW4ezZszh79ixat26ttUxBENChQwcEBgaiT58+OHToEMaPH4+QkBB4eXkhJSVFLf/ly5cxYcIEjBs3DgcOHECVKlUwcOBAnDp1Klf7pKt3794hLCwMjRs3Vku/c+cOkpKSUKVKFY1tqlSpgtu3byM5OTnTcuVyOYYPH46QkBDs378f8fHxiI6OxuDBg2FhYYHBgwdn2a7U1FScPn0aFStW1HjP09MTgiDg8OHDmW6fkpKC+Ph4tQcRERER0Zfmqx9enpaWhtTUVCQnJyMyMhLz5s2DmZkZ2rVrB0C851vpw4cPUjCxfPlyzJo1CzKZDDdv3kRISAjGjRuHJUuWABCHZ9vZ2WkMUZ87dy4EQcCJEydgZ2cHQAwWK1WqpJbvwYMHmD17NkaOHIkffvhBSm/atCnKlCmDOXPmYNeuXfjw4QNmzJiBGjVqYN++fZDJZACA+vXro0yZMnBwcMj2GIwdOxZGRkYYMWKEdG+1tbU1fvnlF3h4eOT0kOZJmzLq3LkzOnfuLL1OS0tDmzZtYGdnh+3bt2P06NEoUqQIypQpAwCoUKFCtsPWf/31Vxw7dgxLlizBpEmTAIjHt3jx4ujWrRs2b96sFni+fPkSZ86cQYkSJQAADRs2RHh4OLZv346GDRvmeJ90denSJSQlJaFGjRpq6TExMQDEc5WRtbU1BEHA69evUbRo0UzL/v7772FhYYFOnTrhw4cPAIASJUrgxIkTcHFxybJd/v7+uH37Nvbv36/xnq2tLRwdHXHmzBmMGjVK6/YLFy7EnDlzsqyDiIiIiOhz99X3dNetWxdyuRxmZmZo06YN7O3tceTIESkgPnHiBJo0aQILCwsUKlQIcrkcfn5+iImJwfPnzwEAERERAKARYHft2hX6+urXNSIiIuDt7S2VD4jDdLt166aW79ixY0hNTUXfvn2RmpoqPQwNDdGoUSNpZu9bt27h8ePH6NmzpxTcAuIQ43r16ul0DDZt2oQxY8Zg5MiRCAsLw+HDh9GsWTO0b98ex44d06kMVXnRpowSEhIwZcoUuLi4QF9fH/r6+jA1NcXbt2/x999/56pMZa97xtnlu3TpAhMTE4SHh6ulV6tWTQq4AXEIftmyZTVmE89rjx8/BqB9iDcAtWOck/cAYP78+QgMDIS/vz8iIiJw4MABlCtXDk2bNtV6G4PShg0bMH/+fEyYMAHt27fXmsfW1jbLlQCmTZuGuLg46aFtmDoRERER0efuq+/p3rx5M1xdXaGvrw87Ozu1XsFz586hWbNm8PT0xPr161GsWDEYGBhg//79mD9/PpKSkgCk9zja29urla2vr4/ChQurpcXExGjk07bts2fPAABubm5a2628RzizupVp2S1B9vr1a6mHW3WirJYtW8LT0xNDhw7FvXv3siwjo49tkzY9e/ZEeHg4Zs2aBTc3N5ibm0Mmk6FVq1bSecipmJgY6OvrS7cSKMlkMtjb20v7oZTxXAKAQqHIdf26Upaf8f56ZXsythMAXr16BZlMBktLy0zL/fvvv+Hn54clS5Zg4sSJUnrLli1RoUIFjB8/XrqgpGrTpk345ptvMGTIECxdujTT8g0NDbM8NgqFAgqFItP3iYiIiIi+BF990O3q6irNXp7Rzp07IZfLcfDgQbWAJ+NwWmXw8/TpUzg6OkrpqampWgO3p0+fatSVMc3GxgYA8NNPP6ktEZWRat3ZlanNrVu3kJSUpDW4r1WrFiIjI5GQkABTU9Nsy8qrNmUUFxeHgwcPYvbs2Zg6daqUnpKSglevXuW4PNV2pqam4sWLF2qBtyAIePr0aaYXPP5rys9Cxn0tXbo0jIyMcPXqVY1trl69ChcXlywnwrt8+TIEQdDYT7lcjqpVqyIyMlJjm02bNmHQoEHo168f1q5dm2VP+qtXrwpsXXQiIiIiok/FVz+8PCsymQz6+vooVKiQlJaUlIQtW7ao5fP09AQAbNu2TS199+7dSE1NVUtr3LgxwsPDpZ5sQLw/edeuXWr5mjdvDn19fdy5cwe1atXS+gCAcuXKoWjRotixY4fajOr379/H77//nu0+Ku+vjoqKUksXBAFRUVGwsrKCiYlJtuWo+tg2ZSSTySAIgkav6IYNG5CWlqaWpsyjS++zt7c3AGDr1q1q6aGhoXj79q30fkFzdXUFAI2ZwPX19dG2bVvs3bsXb968kdL//fdfREREZLvUW2bnPiUlBRcvXkSxYsXU0oODgzFo0CD07t0bGzZsyDLgTk1NxYMHD1ChQoXsd5CIiIiI6Av21fd0Z6V169b47rvv0LNnTwwZMgQxMTEIDAzUCP5cXV3Ru3dvLFu2DHK5HE2aNMG1a9cQGBiotpQTAMycORM///wzvLy84OfnB2NjY6xatQpv375Vy+fs7Iy5c+dixowZuHv3Llq0aAErKys8e/YM586dg4mJCebMmQM9PT0EBARg0KBB6NixIwYPHozY2Fj4+/trHd6dUYkSJeDj44N169ZBoVCgVatWSElJQUhICM6cOYOAgAC14MrT0xORkZEaS6ap+tg2ZWRubo6GDRti6dKlsLGxgbOzMyIjIxEUFKQxfFo5Id26detgZmYGQ0NDlCxZUuvQ8KZNm6J58+aYMmUK4uPj4eHhgStXrmD27NmoXr06+vTpk+O2ZubGjRvSjPNPnz5FYmIifvrpJwDipG9ZBafFihVDqVKlEBUVpTGb/Jw5c+Dm5oY2bdpg6tSpSE5Ohp+fH2xsbDBhwgS1vPr6+mjUqJF0r3r9+vXh5uYGf39/JCYmomHDhoiLi8OKFStw7949tYtLe/bswcCBA1GtWjV88803GsvhVa9eXe3/xZUrV5CYmKgx4zoRERER0deGQXcWvLy8sHHjRixevBht27aFo6MjBg8eDFtbWwwcOFAtb1BQEOzs7BAcHIwffvgB1apVQ2hoKLp3766Wr1KlSggLC8OECRPQr18/WFlZoU+fPujUqROGDBmilnfatGmoUKECli9fjh07diAlJQX29vZwc3PD0KFDpXzKtixevBg+Pj5wdnbG9OnTERkZKU24lpVt27Zh5cqV2LJlCzZu3Ai5XI6yZcti69at6Nmzp1rehIQEnQLnj21TRtu3b8eYMWMwefJkpKamwsPDA8ePH9dYDqxkyZJYtmwZli9fDk9PT6SlpWHTpk0ak6UBYg/6/v374e/vj02bNmH+/PmwsbFBnz59sGDBgjy933j37t0aM3Ur1xSfPXt2tuuU9+rVCytXrkRKSopau8qXL4+TJ09iypQp6Ny5M/T19eHl5YXAwECNe9XT0tLURgbo6enh+PHjWLp0Kfbs2YPAwECYmpqiQoUKOHz4MFq2bCnlPXToED58+ICLFy9qndH+3r17akPJ9+/fDxsbGzRr1izbY0NERERE9CWTCVl1WRKpePPmDaytrbFs2TKMGDGioJvzVXn8+DFKliyJzZs3a8x0/6lJS0uDi4sLevbsifnz5+u8XXx8PCwsLLD+wiAYmxrkYwuJiIgoL/Qst6qgm0BUoJS/X+Pi4jRGOKviPd2ks1OnTkm9/fTfcnBwwNixYzF//nxpPe1P1datW5GQkCCtfU5ERERE9DXj8HLSWevWrTWGc9N/Z+bMmTA2NsajR49QvHjxgm5Opj58+IBt27ZluVwZEREREdHXgkE30WfCzMwMs2fPLuhmZKt///4F3QQiIiIiok8Gh5cTERERERER5RMG3URERERERET5hEE3ERERERERUT7hPd1E9EnpWubbLJdcICIiIiL6nLCnm4iIiIiIiCifMOgmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoJuIiIiIiIgon3D2ciL6pBSd3xYyBb+aiIiIiL4UCXPDC7oJBYo93URERERERET5hEE3ERERERERUT5h0E1ERERERESUTxh0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE++uqA7ODgYMplMeujr66NYsWLo378/Hj16lGf1ODs7w9fXV+f2REdH51ndvr6+cHZ2zjafIAhYv349atasCXNzcxQuXBiNGjXCoUOH8qwtH2v79u1YtmxZgbZh9erVCA4OzpeyZTIZ/P39dcp7+vRpKBQK3L9/Xy394sWLaNKkCUxNTWFpaQkfHx/cvXtXpzJTUlKwdOlSVKpUCSYm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Pj44evQonj17Bjs7O7Ro0QKOjo552T4iIiIiIiKiz1aug24AcHR0xMCBA/OqLURERERERERflFwH3QkJCTh8+DCio6ORnJys8b6fn99HNYyIiIiIiIjoc5eroPvixYto2bIlXr58mWkeBt1ERERERET0tcv17OUvXrzI9H2ZTJbrBhERERERERF9KXI1e/mlS5cgk8ng6emJFStWYOPGjdi0aZP02LhxY16385MQHBwMmUyW6ePkyZM5Ki8xMRH+/v453i4vPX78GP7+/rh06VKel608XtHR0TneNjo6GjKZDMHBwbmq29nZGb6+vtLrnO6nsu0XLlzIVf35ITY2FjY2Nti5c6da+vPnz+Hr6wsbGxsYGxvD3d0d4eHhOpcbGhoKDw8PWFtbw9LSErVr18aWLVs08sXHx2PGjBkoW7YsjI2N4ejoiC5duuD69etq+YKCguDo6Ii3b9/mbkeJiIiIiL4guerpNjMzw9u3bxEaGgorK6u8btMnb9OmTShfvrxGeoUKFXJUTmJiIubMmQMA8PT0zIum5djjx48xZ84cODs7o1q1agXSBm2KFi2Ks2fPonTp0rnaft++fTA3N5def6r7mRNz5syBg4MDunXrJqWlpKTA29sbsbGxWL58OWxtbbFq1Sq0aNECYWFhaNSoUZZlbty4EQMHDkSnTp0wc+ZMyGQyhISEoG/fvnj58iXGjRsn5W3bti0uXLgAf39/1KpVCw8fPsTcuXPh7u6Oq1evwsnJCQDQr18/LF68GEuWLJE+30REREREX6tcBd29e/dGYGAg7t2791UG3ZUqVUKtWrX+83oTExNhbGz8n9dbEBQKBerWrZvr7atXr56HrSl4r169wo8//ojvv/9e7faNoKAgXLt2Db///jvc3d0BAI0bN0bVqlUxefJk/PHHH1mWu3HjRjg5OWH37t3Q0xMHvjRv3hyXLl1CcHCwFHTfvn0bp06dwsyZMzFp0iRpexcXF9SrVw979+6V8urr6+Obb75BQEAApkyZ8tV8ZomIiIiItNF5ePmpU6ekh6enJ+zs7NChQwesXLkS4eHhau+fOnUqP9v8ydu5cydkMhlWrlyplj579mwUKlQIx48fR3R0NIoUKQJA7MFUDlFXDon29/eHTCbDxYsX0blzZ1hZWUm9vhcuXED37t3h7OwMIyMjODs7o0ePHrh//75GWx49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SBOoAUDx4sURGRmJPXv25GkjiYiIiIiIiD5HuRpeHhAQgISEBBgYGODdu3dSeo8ePbBixQpERkbmWQOJ6Oty+5udWd4TQ0RERET0OclVT3d4eDhkMhmOHDmill65cmUAwIMHDz6+ZURERERERESfuVwF3cplnzIuCSSTyQAAr1+//shmEREREREREX3+chV0K4d+Pn36VC1duYSYlZXVRzaLiIiIiIiI6POXq6C7Zs2aAIChQ4dKaUuWLEHfvn0hk8ng5uaWN60jIiL6v/buOyyK630b+L3u0kEElC5gx44o9gIidjRi76DYjb1EVCwo2GKJvSBg76LEFnsFxdhj7PVrI4IKIiJl3j94d36MuxSNGwTvz3XtdbFnnjnzzLCb+HDOnCEiIiLKx76q6B48eDAEQcDBgwfFKeUTJkwQp5UPHjz422VIRERERERElE99VdHdtm1bjBs3TnxcWObHhv3yyy9o0aLFN02SiIiIiIiIKD+SCcpq+StcvHgRe/bswatXr2BhYYGffvpJnHpORPQl4uPjYWxsjNUoBX3I8ySHbsLtPDkuEREREeU/yn+/vnv3LttH3ub6Od2Zn8etVKVKFVSpUkVtnLa2dm67JiIiIiIiIiqQcl106+np5bpTmUyG1NTUr0qIiIiIiIiIqKDIddH9L2ahExEREREREf2QvmghNZlMJq5WTkRERERERETZ+6KiWznaXbJkScybNw9v3rxBenq6yistLU0jyRIRERERERHlJ7kuus+fP49u3bpBS0sLDx48wNixY1G8eHEMGjQIf/31lyZzJCIiIiIiIsqXcl10u7i4YMOGDXjy5AmmTp0KS0tLvH//HqtWrUKVKlXg7u6Oo0ePajJXIiIiIiIionzli6aXA4C5uTn8/f3x+PFjbNy4EaamphAEASdOnMDSpUs1kSP9R0JDQ8X79mUyGRQKBWxtbeHj44Nnz559s+M4ODjA29s71/k8evTomx3b29sbDg4OOcYJgoDVq1ejevXqKFy4MMzMzNCoUSPs27fvm+XyNaZPn44KFSogPT1d0r5lyxY4OTlBV1cX1tbWGDFiBN6/f5/rfh8/fow+ffrA2toaOjo6sLGxQbt27SQxu3btQteuXVG6dGno6enBwcEB3bt3x927dyVxKSkpKFWqFBYuXPjV50lEREREVFB8cdENZDwEfMmSJfD390dc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tvDx8cGzZ8++2XEcHBzg7e2d63wePXr0zY7t7e0NBweHL9pHEAQ0bNgQMpkMQ4cO/Wa5fI3p06ejQoUKSE9Pl7Rv2bIFTk5O0NXVhbW1NUaMGIH379/nqs+XL19i6NChKFmyJPT09GBvb4++ffviyZMnkrhdu3aha9euKF26NPT09ODg4IDu3bvj7t27kriUlBSUKlUKCxcu/FfnSkRERERUELDoJhUhISGIjIzE4cOH0a9fP2zevBkNGjRAYmJiXqeWJ5YuXYp79+7ldRp4/vw55syZg+nTp6NQof/76m7cuBFdu3aFi4sLDhw4gClTpiA0NBReXl459pmcnIyGDRti69atGDNmDA4cOAA/Pz/s27cPdevWRUJCghg7e/ZsfPjwARMnTsTBgwcxY8YMXL58Gc7Ozvjrr7/EOC0tLfj7+2P69OmIjY39theBiIiIiCifUeR1AvT9qVSpEmrUqAEAcHNzQ1paGgICAhAeHo7u3bvncXb/rUePHmHChAlYt25dropYTVq0aBGKFCkiySMtLQ1jx45F06ZNsXr1agAZvzMjIyN0794dBw4cQIsWLbLs8/Tp07h79y7WrFmDvn37AgBcXV1RuHBhdOvWDUeOHEG7du0AABERETA3N5fs37hxYzg4OGDBggVYs2aN2N61a1eMGjUKK1euhJ+f3ze7BkRERERE+Q1HuilHtWvXBgA8fvwYADBt2jTUqlULpqamKFy4MJydnREcHAxBECT7paSkYNy4cbC0tIS+vj7q16+PCxcuqD1GVFQU6tWrJ06PnjBhAlJSUtTGbt26FXXq1IGBgQEMDQ3RrFkzXL58WSUuNDQU5cqVg46ODsqXL49169Z98bn3798fHh4eYuH5uRMnTkAmk2HDhg0YNWoULC0toaenh0aNGklyev36NYoXL466detKzuvmzZswMDBAz549s83j06dPCA4ORrdu3SSj3FFRUXjx4gV8fHwk8R07doShoSF2796dbb9aWloAAGNjY0l7kSJFAAC6urpi2+cFNwBYW1vD1tYWT58+lbRra2ujc+fOWLVqlcrngoiIiIjoR8Kim3KknFpdrFgxABmjvwMGDMC2bduwa9cueHl54eeff0ZAQIBkv379+mHevHno1asX9uzZg/bt28PLywtv3ryRxN28eRPu7u54+/YtQkNDsWLFCly+fBkzZsxQySUw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ZDKBD9Glf+HmzZuoWLEifv/991wV7597+PAhHB0dMWXKFPj5+X3z/K5du4aqVati6dKl4gh1TkJDQ+Hj44Po6GjUqFHjm+f0tX7++WccPXoUf/311xevSv5fCw4OxvDhw/H06dNcj3THx8fD2NgYkQ+nwNBIddE4IiKi/KyS2S95nQIRfWPKf7++e/cOhQsXzjKO93TTv3L8+HHUqVMnVwX31atX8csvv2Dv3r04ceIEVq5ciSZNmqBw4cIqz4X+t+7fv49jx46hf//+sLKyUjsKnt9MmjQJz549w86dO/M6lWylpqZi9uzZmDBhAqeWExEREdEPj0U3/StDhgzBuXPnchVrYGCAixcvom/fvvDw8MDEiRNRrVo1nDlzJsvHhn2tgIAAeHh44P3799i+fTv09fW/af95wcLCAhs3bvyuHgWnztOnT9GjRw+MHj06r1MhIiIiIspznF5ORN8FTi8nIqKCjNPLiQoeTi8nIiIiIiIiymMsuomIiIiIiIg0hEU3ERERERERkYbwOd1E9F2pYDoq23tiiIiIiIjyE450ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOgmIiIiIiIi0hA+MoyIviu+hwdBy0A7r9MgIiIiytLG5iF5nQLlIxzpJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3fbdCQ0Mhk8nEl66uLiwtLeHm5oagoCDExMT8q/6PHj2KGjVqwMDAADKZDOHh4d8m8c94e3vDwcFB0hYYGPjFx7t//z50dHQQGRkpaX/w4AG8vLxQpEgRGBoawsPDA5cuXcpVn4IgYPXq1ahevToKFy4MMzMzNGrUCPv27VOJzfy7yPyaNWuWJG7y5MlwdnZGenr6F50fEREREVFBxKKbvnshISGIjIzE4cOHsXTpUjg5OWH27NkoX748jhw58lV9CoKATp06QUtLC3v37kVkZCQaNWr0jTPP2tcU3WPGjIGHhwfq1Kkjtv3zzz9o0KAB7ty5g7Vr12Lbtm34+PEjXF1dcfv27Rz7nDJlCvr374+aNWti586dCA0NhY6ODlq3bo1du3apxHfo0AGRkZGSV69evVTyfPjwIcLC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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_action_experiment.plot_accuracies()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 115, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!
0.91
\n", + "
\n", + "
Great Caesar's Ghost! He's spinning a web of giant,⎕⎕ silk strands-- as tough as steel!

Great caesars ghost. he's spinning a web of g/ant,⎕| silk strands⎕⎕ as tough as steel!
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_action_experiment.result(14, CropMethod.PADDED_4)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 116, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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UKECli9fjh07diAlJQX29vZwc3PD0KFDpXzKtixevBg+Pj5wdnbG9OnTERkZKU24lpVt27Zh5cqV2LJlCzZu3Ai5XI6yZcti69at6Nmzp1rehIQEnQLnj21TRtu3b8eYMWMwefJkpKamwsPDA8ePH9dYDqxkyZJYtmwZli9fDk9PT6SlpWHTpk0ak6UBYg/6/v374e/vj02bNmH+/PmwsbFBnz59sGDBgjy933j37t0aM3Ur1xSfPXt2tuuU9+rVCytXrkRKSopau8qXL4+TJ09iypQp6Ny5M/T19eHl5YXAwECNe9XT0tLURgbo6enh+PHjWLp0Kfbs2YPAwECYmpqiQoUKOHz4MFq2bCnlPXToED58+ICLFy9qndH+3r17akPJ9+/fDxsbGzRr1izbY0NERERE9CWTCVl1WRKpePPmDaytrbFs2TKMGDGioJvzVXn8+DFKliyJzZs3a8x0/6lJS0uDi4sLevbsifnz5+u8XXx8PCwsLLD+wiAYmxrkYwuJiIgoL/Qst6qgm0BUoJS/X+Pi4jRGOKviPd2ks1OnTkm9/fTfcnBwwNixYzF//nxpPe1P1datW5GQkCCtfU5ERERE9DXj8HLSWevWrTWGc9N/Z+bMmTA2NsajR49QvHjxgm5Opj58+IBt27ZluVwZEREREdHXgkE30WfCzMwMs2fPLuhmZKt///4F3QQiIiIiok8Gh5cTERERERER5RMG3URERERERET5hEE3ERERERERUT7hPd1E9EnpWubbLJdcICIiIiL6nLCnm4iIiIiIiCifMOgmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoJuIiIiIiIgon3D2ciL6pBSd3xYyBb+aiIiIiL4UCXPDC7oJBYo93URERERERET5hEE3ERERERERUT5h0E1ERERERESUTxh0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE++uqA7ODgYMplMeujr66NYsWLo378/Hj16lGf1ODs7w9fXV+f2REdH51ndvr6+cHZ2zjafIAhYv349atasCXNzcxQuXBiNGjXCoUOH8qwtH2v79u1YtmxZgbZh9erVCA4OzpeyZTIZ/P39dcp7+vRpKBQK3L9/Xy394sWLaNKkCUxNTWFpaQkfHx/cvXtXpzJTUlKwdOlSVKpUCSYm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Pj44evQonj17Bjs7O7Ro0QKOjo552T4iIiIiIiKiz1aug24AcHR0xMCBA/OqLURERERERERflFwH3QkJCTh8+DCio6ORnJys8b6fn99HNYyIiIiIiIjoc5eroPvixYto2bIlXr58mWkeBt1ERERERET0tcv17OUvXrzI9H2ZTJbrBhERERERERF9KXI1e/mlS5cgk8ng6emJFStWYOPGjdi0aZP02LhxY16385MQHBwMmUyW6ePkyZM5Ki8xMRH+/v453i4vPX78GP7+/rh06VKel608XtHR0TneNjo6GjKZDMHBwbmq29nZGb6+vtLrnO6nsu0XLlzIVf35ITY2FjY2Nti5c6da+vPnz+Hr6wsbGxsYGxvD3d0d4eHhOpcbGhoKDw8PWFtbw9LSErVr18aWLVs08sXHx2PGjBkoW7YsjI2N4ejoiC5duuD69etq+YKCguDo6Ii3b9/mbkeJiIiIiL4guerpNjMzw9u3bxEaGgorK6u8btMnb9OmTShfvrxGeoUKFXJUTmJiIubMmQMA8PT0zIum5djjx48xZ84cODs7o1q1agXSBm2KFi2Ks2fPonTp0rnaft++fTA3N5def6r7mRNz5syBg4MDunXrJqWlpKTA29sbsbGxWL58OWxtbbFq1Sq0aNECYWFhaNSoUZZlbty4EQMHDkSnTp0wc+ZMyGQyhISEoG/fvnj58iXGjRsn5W3bti0uXLgAf39/1KpVCw8fPsTcuXPh7u6Oq1evwsnJCQDQr18/LF68GEuWLJE+30REREREX6tcBd29e/dGYGAg7t2791UG3ZUqVUKtWrX+83oTExNhbGz8n9dbEBQKBerWrZvr7atXr56HrSl4r169wo8//ojvv/9e7faNoKAgXLt2Db///jvc3d0BAI0bN0bVqlUxefJk/PHHH1mWu3HjRjg5OWH37t3Q0xMHvjRv3hyXLl1CcHCwFHTfvn0bp06dwsyZMzFp0iRpexcXF9SrVw979+6V8urr6+Obb75BQEAApkyZ8tV8ZomIiIiItNF5ePmpU6ekh6enJ+zs7NChQwesXLkS4eHhau+fOnUqP9v8ydu5cydkMhlWrlyplj579mwUKlQIx48fR3R0NIoUKQJA7MFUDlFXDon29/eHTCbDxYsX0blzZ1hZWUm9vhcuXED37t3h7OwMIyMjODs7o0ePHrh//75GWx49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SBOoAUDx4sURGRmJPXv25GkjiYiIiIiIiD5HuRpeHhAQgISEBBgYGODdu3dSeo8ePbBixQpERkbmWQOJ6Oty+5udWd4TQ0RERET0OclVT3d4eDhkMhmOHDmill65cmUAwIMHDz6+ZURERERERESfuVwF3cplnzIuCSSTyQAAr1+//shmEREREREREX3+chV0K4d+Pn36VC1duYSYlZXVRzaLiIiIiIiI6POXq6C7Zs2aAIChQ4dKaUuWLEHfvn0hk8ng5uaWN60jIiL6v/buOyyK630b+L3u0kEElC5gx44o9gIidjRi76DYjb1EVCwo2GKJvSBg76LEFnsFxdhj7PVrI4IKIiJl3j94d36MuxSNGwTvz3XtdbFnnjnzzLCb+HDOnCEiIiLKx76q6B48eDAEQcDBgwfFKeUTJkwQp5UPHjz422VIRERERERElE99VdHdtm1bjBs3TnxcWObHhv3yyy9o0aLFN02SiIiIiIiIKD+SCcpq+StcvHgRe/bswatXr2BhYYGffvpJnHpORPQl4uPjYWxsjNUoBX3I8ySHbsLtPDkuEREREeU/yn+/vnv3LttH3ub6Od2Zn8etVKVKFVSpUkVtnLa2dm67JiIiIiIiIiqQcl106+np5bpTmUyG1NTUr0qIiIiIiIiIqKDIddH9L2ahExEREREREf2QvmghNZlMJq5WTkRERERERETZ+6KiWznaXbJkScybNw9v3rxBenq6yistLU0jyRIRERERERHlJ7kuus+fP49u3bpBS0sLDx48wNixY1G8eHEMGjQIf/31lyZzJCIiIiIiIsqXcl10u7i4YMOGDXjy5AmmTp0KS0tLvH//HqtWrUKVKlXg7u6Oo0ePajJXIiIiIiIionzli6aXA4C5uTn8/f3x+PFjbNy4EaamphAEASdOnMDSpUs1kSP9R0JDQ8X79mUyGRQKBWxtbeHj44Nnz559s+M4ODjA29s71/k8evTomx3b29sbDg4OOcYJgoDVq1ejevXqKFy4MMzMzNCoUSPs27fvm+XyNaZPn44KFSogPT1d0r5lyxY4OTlBV1cX1tbWGDFiBN6/f5/rfh8/fow+ffrA2toaOjo6sLGxQbt27SQxu3btQteuXVG6dGno6enBwcEB3bt3x927dyVxKSkpKFWqFBYuXPjV50lEREREVFB8cdENZDwEfMmSJfD390dc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tvDx8cGzZ8++2XEcHBzg7e2d63wePXr0zY7t7e0NBweHL9pHEAQ0bNgQMpkMQ4cO/Wa5fI3p06ejQoUKSE9Pl7Rv2bIFTk5O0NXVhbW1NUaMGIH379/nqs+XL19i6NChKFmyJPT09GBvb4++ffviyZMnkrhdu3aha9euKF26NPT09ODg4IDu3bvj7t27kriUlBSUKlUKCxcu/FfnSkRERERUELDoJhUhISGIjIzE4cOH0a9fP2zevBkNGjRAYmJiXqeWJ5YuXYp79+7ldRp4/vw55syZg+nTp6NQof/76m7cuBFdu3aFi4sLDhw4gClTpiA0NBReXl459pmcnIyGDRti69atGDNmDA4cOAA/Pz/s27cPdevWRUJCghg7e/ZsfPjwARMnTsTBgwcxY8YMXL58Gc7Ozvjrr7/EOC0tLfj7+2P69OmIjY39theBiIiIiCifUeR1AvT9qVSpEmrUqAEAcHNzQ1paGgICAhAeHo7u3bvncXb/rUePHmHChAlYt25dropYTVq0aBGKFCkiySMtLQ1jx45F06ZNsXr1agAZvzMjIyN0794dBw4cQIsWLbLs8/Tp07h79y7WrFmDvn37AgBcXV1RuHBhdOvWDUeOHEG7du0AABERETA3N5fs37hxYzg4OGDBggVYs2aN2N61a1eMGjUKK1euhJ+f3ze7BkRERERE+Q1HuilHtWvXBgA8fvwYADBt2jTUqlULpqamKFy4MJydnREcHAxBECT7paSkYNy4cbC0tIS+vj7q16+PCxcuqD1GVFQU6tWrJ06PnjBhAlJSUtTGbt26FXXq1IGBgQEMDQ3RrFkzXL58WSUuNDQU5cqVg46ODsqXL49169Z98bn3798fHh4eYuH5uRMnTkAmk2HDhg0YNWoULC0toaenh0aNGklyev36NYoXL466detKzuvmzZswMDBAz549s83j06dPCA4ORrdu3SSj3FFRUXjx4gV8fHwk8R07doShoSF2796dbb9aWloAAGNjY0l7kSJFAAC6urpi2+cFNwBYW1vD1tYWT58+lbRra2ujc+fOWLVqlcrngoiIiIjoR8Kim3KknFpdrFgxABmjvwMGDMC2bduwa9cueHl54eeff0ZAQIBkv379+mHevHno1asX9uzZg/bt28PLywtv3ryRxN28eRPu7u54+/YtQkNDsWLFCly+fBkzZsxQySUw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ZDKBD9Glf+HmzZuoWLEifv/991wV7597+PAhHB0dMWXKFPj5+X3z/K5du4aqVati6dKl4gh1TkJDQ+Hj44Po6GjUqFHjm+f0tX7++WccPXoUf/311xevSv5fCw4OxvDhw/H06dNcj3THx8fD2NgYkQ+nwNBIddE4IiKi/KyS2S95nQIRfWPKf7++e/cOhQsXzjKO93TTv3L8+HHUqVMnVwX31atX8csvv2Dv3r04ceIEVq5ciSZNmqBw4cIqz4X+t+7fv49jx46hf//+sLKyUjsKnt9MmjQJz549w86dO/M6lWylpqZi9uzZmDBhAqeWExEREdEPj0U3/StDhgzBuXPnchVrYGCAixcvom/fvvDw8MDEiRNRrVo1nDlzJsvHhn2tgIAAeHh44P3799i+fTv09fW/af95wcLCAhs3bvyuHgWnztOnT9GjRw+MHj06r1MhIiIiIspznF5ORN8FTi8nIqKCjNPLiQoeTi8nIiIiIiIiymMsuomIiIiIiIg0hEU3ERERERERkYbwOd1E9F2pYDoq23tiiIiIiIjyE450ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOgmIiIiIiIi0hA+MoyIviu+hwdBy0A7r9MgIiIiytLG5iF5nQLlIxzpJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3fbdCQ0Mhk8nEl66uLiwtLeHm5oagoCDExMT8q/6PHj2KGjVqwMDAADKZDOHh4d8m8c94e3vDwcFB0hYYGPjFx7t//z50dHQQGRkpaX/w4AG8vLxQpEgRGBoawsPDA5cuXcpVn4IgYPXq1ahevToKFy4MMzMzNGrUCPv27VOJzfy7yPyaNWuWJG7y5MlwdnZGenr6F50fEREREVFBxKKbvnshISGIjIzE4cOHsXTpUjg5OWH27NkoX748jhw58lV9CoKATp06QUtLC3v37kVkZCQaNWr0jTPP2tcU3WPGjIGHhwfq1Kkjtv3zzz9o0KAB7ty5g7Vr12Lbtm34+PEjXF1dcfv27Rz7nDJlCvr374+aNWti586dCA0NhY6ODlq3bo1du3apxHfo0AGRkZGSV69evVTyfPjwIcLC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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_action_experiment.perform_methods(plot_acc=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Everything Everywhere All at Once\n" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT.reset()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ExperimentsVisor" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ExperimentsVisor(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + "\n", + " def update_output(self, \n", + " model: OCRModel | None = None,\n", + " image_idx: ImgIdT | None = None,\n", + " display_option: DisplayOptions | None = None, \n", + " **kwargs):\n", + " model_selector, image_selector, content_selector, result_visor = self._comps()\n", + " if model is not None:\n", + " exp_ctx = result_visor.ctx\n", + " exp_ctx.ocr_model = list(model_selector.models.keys())[model.value]\n", + " result_visor.ctx = exp_ctx\n", + " if image_idx is not None:\n", + " img_ctx = ImageContext(self.ctx, image_idx)\n", + " result_visor.ctx.ctx = img_ctx\n", + " display_option = content_selector.values['display_option']\n", + " if display_option is not None and display_option != DisplayOptions.RESULTS:\n", + " result_visor.hide()\n", + " if display_option == DisplayOptions.BEST_RESULTS:\n", + " result_visor.best_results()\n", + " elif display_option == DisplayOptions.DATAFRAME:\n", + " result_visor.pd_to_html()\n", + " else:\n", + " content_selector.display_content(image_selector.image_ctx, display_option)\n", + " else:\n", + " result_visor.show()\n", + " result_visor.update_output(**kwargs)\n", + "\n", + " def _comps(self):\n", + " cc = self.comps\n", + " msel: ModelSelector = cc['model_selector'] # type: ignore\n", + " isel: ImageSelector = cc['image_selector'] # type: ignore\n", + " cs: ContentSelector = cc['content_selector'] # type: ignore\n", + " rv: ResultVisor = cc['result_visor'] # type: ignore\n", + " return msel, isel, cs, rv\n", + "\n", + " def setup_ui(self):\n", + " ctls = self.controls.values()\n", + " msw, isw, csw, rvw = [_.w for _ in self._comps()]\n", + " return W.VBox([W.HBox([msw, isw, csw, *ctls]), rvw,])\n", + "\n", + " def __init__(self, \n", + " ctx: OCRExperimentContext,\n", + " image_idx: ImgIdT | str | Path = 0,\n", + " ocr_model: OCRModel = OCRModel.TESSERACT,\n", + " display_option: DisplayOptions = DisplayOptions.RESULTS,\n", + " all_boxes: bool = False,\n", + " box_idx: int = 0,\n", + " all_methods: bool = False,\n", + " method: CropMethod=CropMethod.INITIAL_BOX,\n", + " ocr_models: dict[str, OCRModel] = {'Tesseract': OCRModel.TESSERACT},\n", + " out: W.Output | None = None,\n", + " ):\n", + " if not isinstance(ctx, OCRExperimentContext):\n", + " raise ValueError(\"ctx must be an OCRExperimentContext\")\n", + " exp = ExperimentOCR.from_image(ctx, 'Tesseract', image_idx)\n", + " if not exp:\n", + " raise ValueError(f\"Image {image_idx} not found in experiment context\")\n", + " \n", + " out = out or self.out\n", + " model_selector = ModelSelector(ctx, ocr_model=ocr_model, \n", + " ocr_models=ocr_models, out=out)\n", + " image_selector = ImageSelector(ctx, image_idx=image_idx, out=out)\n", + " content_selector = ContentSelector(ctx, display_option=display_option, out=out)\n", + " result_visor = ResultVisor(exp, out=out,\n", + " all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method)\n", + "\n", + " super().__init__(ctx, {}, out=out, \n", + " ctxs={'model_selector': model_selector, 'image_selector': image_selector, 'content_selector': content_selector, \n", + " 'result_visor': result_visor}\n", + " )\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualize all" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c722001cdbcf444da9b56a366c6723e1", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), optio…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8a95135fcb03495f94fb726416f3df54", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# tesseract_experiment = ExperimentsVisor(CONTEXT)\n", + "tesseract_experiment = ExperimentsVisor(CONTEXT, BASE_IMAGE_IDX)\n", + "\n", + "test_eq(tesseract_experiment.all_values, {\n", + " 'image_selector': {'image_idx': 20},\n", + " 'content_selector': {'display_option': DisplayOptions.RESULTS},\n", + " 'result_visor': {\n", + " 'all_boxes': False,\n", + " 'box_idx': 0,\n", + " 'all_methods': False,\n", + " 'method': CropMethod.INITIAL_BOX,\n", + " },\n", + " 'model_selector': {'model': OCRModel.TESSERACT},\n", + " 'self': {}\n", + "})\n", + "\n", + "tesseract_experiment\n" + ] + }, + { + "cell_type": "code", + "execution_count": 121, + "metadata": {}, + "outputs": [], + "source": [ + "tesseract_experiment.update(display_option=DisplayOptions.BOXES)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Colophon\n", + "----\n" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "from nbdev.export import nb_export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_NOTEBOOK:\n", + " nb_export('experiments.ipynb', '.')\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/_testbed/experiments.py b/_testbed/experiments.py new file mode 100644 index 00000000..27d56ba6 --- /dev/null +++ b/_testbed/experiments.py @@ -0,0 +1,1995 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: experiments.ipynb. + +# %% experiments.ipynb 7 +from __future__ import annotations + +import dataclasses +import difflib +import functools +import json +import shutil +from collections import defaultdict +from enum import Enum +from pathlib import Path +from typing import Any +from typing import Callable +from typing import cast +from typing import Mapping +from typing import Self +from typing import TypeAlias + +import fastcore.all as FC +import ipywidgets as W +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import pcleaner.config as cfg +import pcleaner.ctd_interface as ctm +import pcleaner.image_ops as ops +import pcleaner.ocr.ocr as ocr +import pcleaner.structures as st +import torch +from IPython.display import clear_output +from IPython.display import display +from IPython.display import HTML +from ipywidgets.widgets.interaction import show_inline_matplotlib_plots +from loguru import logger +from pcleaner.ocr.ocr_tesseract import TesseractOcr +from PIL import Image +from PIL import ImageFilter +from rich.console import Console +from tqdm.notebook import tqdm + + +# %% auto 0 +__all__ = ['CM', 'SubjIdT', 'ImgIdT', 'BoxIdT', 'ImgSpecT', 'remove_multiple_whitespaces', 'postprocess_ocr', + 'accuracy_ocr_naive', 'accuracy_ocr_difflib', 'ground_truth_path', 'read_ground_truth', + 'dilate_by_fractional_pixel', 'extract_text', 'lang2pcleaner', 'lang2tesseract', 'ResultOCR', + 'ResultOCRExtracted', 'CropMethod', 'crop_by_image', 'crop_by_extracted', 'ResultSet', 'ResultSetDefault', + 'results_to_dict', 'dict_to_results', 'ExperimentSubject', 'ExperimentContext', 'ImageContext', + 'OCRExperimentContext', 'ContextVisor', 'ImageSelector', 'OCRContextVisor', 'OCRModel', 'ModelSelector', + 'DisplayOptions', 'ContentSelector', 'ImageContextVisor', 'Experiment', 'ExperimentOCR', + 'ExperimentOCRMethod', 'ResultVisor', 'ExperimentVisor', 'ExperimentsVisor'] + +# %% experiments.ipynb 8 +from helpers import * +from ocr_metric import * + + +# %% experiments.ipynb 12 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% experiments.ipynb 20 +def remove_multiple_whitespaces(text): + return ' '.join(text.split()) + + +def postprocess_ocr(text): + "Basic postprocessing for English Tesseract OCR results." + return ' '.join(remove_multiple_whitespaces(text).splitlines()).capitalize() + +def accuracy_ocr_naive(text, ground_truth): + return sum(1 for a, b in zip(text, ground_truth) if a == b) / len(text) + + +def accuracy_ocr_difflib(text, ground_truth): + """ + Calculates the OCR accuracy based on the similarity between the OCR text and the ground truth text, + using difflib's SequenceMatcher to account for differences in a manner similar to git diffs. + + :param text: The OCR-generated text. + :param ground_truth: The ground truth text. + :return: A float representing the similarity ratio between the OCR text and the ground truth, + where 1.0 is identical. + """ + # Initialize the SequenceMatcher with the OCR text and the ground truth + matcher = difflib.SequenceMatcher(None, text, ground_truth) + + # Get the similarity ratio + similarity_ratio = matcher.ratio() + + return similarity_ratio + +# %% experiments.ipynb 22 +def ground_truth_path(page_data: st.PageData): + path = Path(page_data.original_path) + return path.with_stem(path.stem + '_gt').with_suffix('.txt') + + +def read_ground_truth(page_data: st.PageData): + gts_path = ground_truth_path(page_data) + if gts_path.exists(): + gts = gts_path.read_text(encoding="utf-8").splitlines() + else: + gts = ["" for _ in range(len(page_data.boxes))] + return gts + + +# %% experiments.ipynb 24 +def dilate_by_fractional_pixel(image, dilation_fraction, filter_base_size=3): + """ + Dilates an image by a specified fractional pixel amount. The function calculates + the necessary scaling factor and filter size based on the desired dilation fraction. + + :param image: A PIL Image object (1-bit mode). + :param dilation_fraction: The desired fractional pixel amount for dilation (e.g., 0.2). + :param filter_base_size: The base size of the dilation filter to apply on the scaled image. + This size is adjusted based on the scaling factor to achieve the + desired dilation effect. + :return: A PIL Image object after dilation, converted back to grayscale. + """ + # Calculate the scale factor based on the desired dilation fraction + scale_factor = int(1 / dilation_fraction) + + # Adjust the filter size based on the scale factor + # This ensures the dilation effect is proportional to the desired fraction + filter_size = max(1, filter_base_size * scale_factor // 5) + + # Convert the image to grayscale for more nuanced intermediate values + image_gray = image.convert("L") + + # Resize the image to a larger size using bicubic interpolation + larger_size = (int(image.width * scale_factor), int(image.height * scale_factor)) + image_resized = image_gray.resize(larger_size, Image.BICUBIC) + + # Apply the dilation filter to the resized image + dilated_image = image_resized.filter(ImageFilter.MaxFilter(filter_size)) + + # Resize the image back to its original size using bicubic interpolation + image_dilated_fractional_pixel = dilated_image.resize(image.size, Image.BICUBIC) + + return image_dilated_fractional_pixel + + +# %% experiments.ipynb 25 +def extract_text(image, text_mask, box): + cropped_image = crop_box(box, image) + cropped_mask = crop_box(box, text_mask) + extracted = ops.extract_text(cropped_image, cropped_mask) + return cropped_image, cropped_mask, extracted + + +# %% experiments.ipynb 27 +_lang2pcleaner = {'English': st.DetectedLang.ENG, 'Japanese': st.DetectedLang.JA, 'Spanish': st.DetectedLang.ENG, + 'French':st.DetectedLang.ENG} +# _lang2tesseract = {'English': 'eng', 'Japanese': 'jpn'} +_lang2tesseract = {'English': 'eng', 'Japanese': 'jpn_vert', 'Spanish': 'spa', 'French': 'fra'} + + +# %% experiments.ipynb 28 +def lang2pcleaner(lang: str): + return _lang2pcleaner[lang] + +def lang2tesseract(lang: str): + return _lang2tesseract[lang] + + +# %% experiments.ipynb 35 +@dataclasses.dataclass +class ResultOCR: + block_idx: int + image: Image.Image | None + ocr: str + page_data: st.PageData + gts: list[str] + description: str = dataclasses.field(default='', kw_only=True) + + def __post_init__(self): + if self.image is None: + cache_path = self.cache_path() + if cache_path.exists(): + self.image = Image.open(cache_path) + + @property + def acc(self): + self._acc = accuracy_ocr_difflib(self.ocr, self.gts[self.block_idx]) + return self._acc + @property + def suffix(self): return f"{self.block_idx}_{self.description}" + + def diff_tagged(self): + _, html2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr, False) + return f"{html2}" + + def cache_path(self, suffix: str | None = None): + suffix = self.suffix + (('_'+suffix) if suffix else '') + parent = Path(self.page_data.image_path).parent + img_name = Path(self.page_data.original_path).stem + box_image_path = parent / f"{img_name}_{suffix}.png" + return box_image_path + + def cache_image(self, image: Image.Image | None = None, suffix: str | None = None): + image = image or (self.image if not suffix else None) + box_image_path = self.cache_path(suffix) + if image and not box_image_path.exists(): + image.save(box_image_path) + return box_image_path + + + def as_html(self): + acc_html = f"
{self.acc:.2f}" + box_image_path = self.cache_image() + html1 = get_columns_html([[box_image_path], [self.ocr + acc_html]]) + html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr) + html2 = f"
{html_str1}
{html_str2}
" + return html1 + '\n
\n' + html2 + + def __repr__(self): + return f"{type(self).__name__}#block {self.block_idx:02}: {self.acc:.2f}||{self.ocr}" + + def display(self): display(HTML(self.as_html())) + + def _ipython_display_(self): self.display() + + def to_dict(self): + d = dataclasses.asdict(self) + d['image'] = d['page_data'] = d['gts'] = None + return d + + # @classmethod + # def from_dict(cls, d: dict, page_data: st.PageData, gts: list[str]): + # return cls(**(d | {'page_data':page_data, 'gts':gts})) + + +@dataclasses.dataclass +class ResultOCRExtracted(ResultOCR): + + def __repr__(self): return super().__repr__() + def as_html(self): + html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr) + diff_html = f"
{html_str1}
{html_str2}
" + cropped_image_path = self.cache_image(None, "cropped") + cropped_mask_path = self.cache_image(None, "mask") + result_path = self.cache_image() + return '\n
\n'.join([ + get_image_grid_html([cropped_image_path, cropped_mask_path, result_path], 1, 3), + acc_as_html(self.acc), + diff_html + ]) + + +# %% experiments.ipynb 37 +class CropMethod(Enum): + INITIAL_BOX = 'Initial box' + DEFAULT = 'Default' + DEFAULT_GREY_PAD = 'Default, grey pad' + PADDED_4 = 'Padded 4px' + PADDED_8 = 'Padded 8px' + EXTRACTED_INIT_BOX = 'Extracted, init box' + PADDED_4_EXTRACTED = 'Padded 4, extracted' + PADDED_8_EXTRACTED = 'Padded 8, extracted' + PADDED_8_DILATION_1 = 'Padded 8, dilation 1' + PAD_8_FRACT_0_5 = 'Pad 8, fract. 0.5' + PAD_8_FRACT_0_2 = 'Pad 8, fract. 0.2' + + @classmethod + def __display_names__(cls): + return dict( + zip([_.value for _ in cls], + cls)) + + +CM = CropMethod + +_IMAGE_METHODS = [CM.INITIAL_BOX, CM.DEFAULT, CM.DEFAULT_GREY_PAD, + CM.PADDED_4, CM.PADDED_8] +_EXTRACTED_METHODS = [CM.EXTRACTED_INIT_BOX, CM.PADDED_4_EXTRACTED, + CM.PADDED_8_EXTRACTED, CM.PADDED_8_DILATION_1, + CM.PAD_8_FRACT_0_5, CM.PAD_8_FRACT_0_2] + + +def crop_by_image(method: CM, + box: st.Box, + base: Image.Image, + preproc: cfg.PreprocessorConfig, + ): + image = None + match method: + case CM.INITIAL_BOX : + image = crop_box(box, base) + case CM.DEFAULT: + padded2_4 = ( + box.pad(preproc.box_padding_initial, base.size).right_pad( + preproc.box_right_padding_initial, base.size)) + image = crop_box(padded2_4, base) + case CM.DEFAULT_GREY_PAD: + image = crop_box(box, base) + image = ops.pad_image(image, 8, fill_color=(128, 128, 128)) + case CM.PADDED_4: + padded4 = box.pad(4, base.size) + image = crop_box(padded4, base) + case CM.PADDED_8: + padded4 = box.pad(8, base.size) + image = crop_box(padded4, base) + case _: pass + return image + + +def crop_by_extracted(method: CM, + box: st.Box, + base: Image.Image, + mask: Image.Image, + cropped_image_path: Path, + cropped_mask_path: Path, + dilated: dict[float, Image.Image] + ): + cropped_image, cropped_mask, image = None, None, None + if method in _EXTRACTED_METHODS: + if not cropped_image_path.exists() or not cropped_mask_path.exists(): + match method: + case CM.EXTRACTED_INIT_BOX: + cropped_image, cropped_mask, image = extract_text(base, mask, box) + case CM.PADDED_4_EXTRACTED: + padded4 = box.pad(4, base.size) + cropped_image, cropped_mask, image = extract_text(base, mask, padded4) + case CM.PADDED_8_EXTRACTED: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text(base, mask, padded8) + case CM.PADDED_8_DILATION_1: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text( + base, dilated[1], padded8) + case CM.PAD_8_FRACT_0_5: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text( + base, dilated[0.5], padded8) + case CM.PAD_8_FRACT_0_2: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text( + base, dilated[0.2], padded8) + case _: pass + + return image, cropped_image, cropped_mask + + + +# %% experiments.ipynb 39 +SubjIdT: TypeAlias = int +ImgIdT = SubjIdT +BoxIdT: TypeAlias = int + +class ResultSet(dict[BoxIdT, dict[CropMethod, ResultOCR]]): ... + +class ResultSetDefault(defaultdict[BoxIdT, dict[CropMethod, ResultOCR]]): ... + +def results_to_dict(results: ResultSet) -> dict[BoxIdT, dict[str, str]]: + d = {} + for box, box_methods in results.items(): + for method, result in box_methods.items(): + if box not in d: + d[box] = {} + d[box][method.name] = result.ocr + return d + +def dict_to_results( + image_idx: ImgIdT, + results_dict: dict[BoxIdT, dict[str, str]], + result_factory: Callable + ) -> ResultSetDefault: + results = ResultSetDefault(dict[CropMethod, ResultOCR]) + for box_idx, box_methods in results_dict.items(): + box_idx = int(box_idx) + for method, ocr in box_methods.items(): + m = CM[method] + results[box_idx][m] = result_factory(image_idx, box_idx, m, ocr) + return results + + + +# %% experiments.ipynb 41 +# class ExperimentSubject(Protocol): +# @property +# def exp(self) -> 'ExperimentContext': ... +# @property +# def idx(self) -> SubjIdT: ... +# def setup(self, +# exp: 'ExperimentContext', +# idx: Any, +# *args, **kwargs +# ): ... + + +# class ExperimentContext(Protocol): +# def subject_factory(self) -> Callable[..., ExperimentSubject]: ... +# def normalize_idx(self, idx: Any) -> SubjIdT: ... +# def experiment_subject(self, idx: Any, /, +# create: bool = False, *args, **kwargs) -> ExperimentSubject | None: +# """Get or create an `ExperimentSubject` for the given identifier. +# Returns `None` if `idx` is out of domain range. +# """ +# ... + + +# %% experiments.ipynb 42 +class ExperimentSubject: + exp: ExperimentContext + idx: SubjIdT + + def setup(self, exp: ExperimentContext, idx: Any, *args, **kwargs): + self.exp = exp + self.idx = cast(SubjIdT, exp.normalize_idx(idx)) + return self + + def __new__(cls, + exp: ExperimentContext, + idx: Any, + *args, **kwargs): + self = exp.experiment_subject(idx) + if self is None: + self = super().__new__(cls) + self = exp.experiment_subject(idx, new_subject=self, *args, **kwargs) + if self is None: + raise ValueError(f"Can't create new subject with idx: {idx}: out of range") + return self + + +class ExperimentContext: + "Class to maintain shared state across all file-based experiments within the experiment domain." + + subject_cls: Callable[..., ExperimentSubject] + def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls + + def normalize_idx(self, idx: int | str | Path) -> SubjIdT | None: + nidx = None + if isinstance(idx, int) and idx < len(self._paths): + nidx = idx + elif isinstance(idx, str): + try: + nidx = [_.name for _ in self._paths].index(idx) + except Exception: + pass + elif isinstance(idx, Path): + idx = idx.resolve() + if idx in self._paths: + nidx = self._paths.index(idx) + return nidx + + def path_from_idx(self, idx: int | str | Path): + _idx = self.normalize_idx(idx) + if _idx is None: + raise ValueError(f"{_idx} not found in context.") + path = Path(self._paths[_idx]) + if not path.exists(): + raise ValueError(f"{path} not found in context.") + return path + + @property + def count(self): return len(self._paths) + @property + def cache_dir(self): return Path(".cache/") + @functools.lru_cache() + def _cache_dir(self, idx: SubjIdT): + # create one folder for each image to cache and save results + path = self.path_from_idx(idx) + cache_dir = self.cache_dir / path.stem + cache_dir.mkdir(parents=True, exist_ok=True) + return cache_dir + def subject_cache_dir(self, idx: int | str | Path): + return self._cache_dir(idx) + + def empty_cache(self, idx: SubjIdT | None = None): + cache_dir = self.cache_dir + if idx is None: + shutil.rmtree(cache_dir, ignore_errors=True) + cache_dir.mkdir(parents=True, exist_ok=True) + else: + path = Path(self._paths[idx]) + cache_dir = cache_dir / path.stem + for p in cache_dir.glob("*"): + p.unlink(missing_ok=True) + if not any(cache_dir.iterdir()): + cache_dir.rmdir() + + def empty_cache_warn(self, idx: SubjIdT | None=None, *, warn: bool=True, out: W.Output | None=None): + def on_confirm_clicked(b): + try: + self.empty_cache(idx) + print("Cache cleared successfully.") + except Exception as e: + print(f"Failed to clear cache: {e}") + finally: + for widget in confirmation_box.children: + widget.close() + + def on_cancel_clicked(b): + print("Cache clear cancelled.") + for widget in confirmation_box.children: + widget.close() + + if out is None: + out = W.Output() + with out: + if FC.IN_NOTEBOOK: + confirm_button = W.Button(description="Confirm") + cancel_button = W.Button(description="Cancel") + confirm_button.on_click(on_confirm_clicked) + cancel_button.on_click(on_cancel_clicked) + label = W.Label('Are you sure you want to clear the cache? This action cannot be undone.') + confirmation_box = W.VBox([label, W.HBox([confirm_button, cancel_button])]) + display(confirmation_box) + else: + on_confirm_clicked(None) + + def experiment_subject(self, idx: SubjIdT | str | Path, /, + new_subject: ExperimentSubject | None = None, *args, **kwargs) -> ExperimentSubject | None: + "Cached subject. If provided, `new_subject` replaces value at the index." + if (nidx := self.normalize_idx(idx)) is None: + return None + if new_subject is None: + subject = self._subjects.get(nidx) + else: + new_subject.setup(self, nidx, *args, **kwargs) + self._subjects[nidx] = subject = new_subject + return subject + + def reset(self): + self._subjects.clear() + self._cache_dir.cache_clear() + + def __init__(self, paths: list[Path], root: Path | None = None): + self._root = (root or Path('.')).resolve() + self._paths = [p.resolve().relative_to(self._root) for p in paths] + self._subjects: dict[SubjIdT, ExperimentSubject] = {} + + +# %% experiments.ipynb 48 +ImgSpecT: TypeAlias = ImgIdT | str | Path + +class ImageContext(ExperimentSubject): + """ + A utility class to maintain image state for a ExperimentContext. + This class encapsulates state necessary for conducting OCR experiments. + + Attributes: + json_data (dict): JSON data loaded from cached files. + page_data (st.PageData): PanelClaner page data. + base_image (Image.Image): The base image loaded from the page data. + mask (Image.Image): The mask image used for text detection. + gts (list[str]): Ground truth data for the text in the images. + ocr_model (str): Name or identifier of the OCR model used. + mocr (ocr.OCRModel): OCR model configured for the experiment. + mask_dilated1 (Image.Image): Image mask dilated by 1 pixel. + mask_dilated05 (Image.Image): Image mask dilated by 0.5 pixels. + mask_dilated02 (Image.Image): Image mask dilated by 0.2 pixels. + + Methods: + init(config: cfg.Config, img_path: Path, cache_dir: Path, ocr_model: str): + Initializes the experiment context. It also handles the generation of text boxes + if they are not already present. + + setup_ground_truth(): + Loads or initializes ground truth data for the experiment based on the page data. + + setup_crop_masks(): + Prepares various dilated versions of the mask image to be used in different cropping + strategies during the experiments. + """ + exp: ExperimentContext + idx: ImgIdT + base_image: Image.Image + mask: Image.Image + json_data: dict | None + page_data: st.PageData + # ocr_model: str + # mocr: ocr.OCRModel + # postprocess_ocr: Callable[..., str] + _page_lang: str + _gts: list[str] + _mask_dilated1: Image.Image | None + _mask_dilated05: Image.Image | None + _mask_dilated02: Image.Image | None + + + # # this methods will be set downstream, declared here to make the type checker happy + # def result(self: Self, + # box_idx: int, method: CropMethod, ocr: bool = True, reset: bool=False) -> ResultOCR: ... + # def summary_box(self: Self, box_idx: int): ... + + def to_dict(self): + return { + 'image_idx': self.idx, + 'page_lang': self.page_lang, + } + + @property + def image_idx(self): return self.idx + @property + def cache_dir(self): + return self.exp.subject_cache_dir(self.idx) + cache_dir_image = cache_dir + + @property + def image_info(self): + img = self.base_image + w, h = img.size + print_size_in = size(w, h, 'in', 300) + print_size_cm = size(w, h, 'cm', 300) + required_dpi = dpi(w, h, 'Modern Age') + return (w, h), print_size_in, print_size_cm, required_dpi + + @property + def original_image_path(self): return Path(self.page_data.original_path) + @property + def image_path(self): return Path(self.page_data.image_path) + @property + def image_name(self): return self.original_image_path.name + @property + def image_size(self): return self.base_image.size + @property + def image_dim(self):return size(*self.image_size) + @property + def image_dpi(self): return dpi(*self.image_size) + @property + def image_print(self): + return self.image_size, self.image_dim, self.image_dpi + @property + def image_name_rich(self): + siz, dim, res = self.image_print + return f"{self.image_name} - {siz[0]}x{siz[1]} px: {dim[0]:.2f}x{dim[1]:.2f}\" @ {res:.2f} dpi" + + def setup_page_lang(self, page_lang: str | None = None): + path = Path(self.page_data.original_path).with_suffix('.json') + metadata = json.load(open(path)) if path.exists() else {} + if 'lang' in metadata and (page_lang == metadata['lang'] or page_lang is None): + self._page_lang = metadata['lang'] + return + self._page_lang = metadata['lang'] = page_lang or 'English' + json.dump(metadata, open(path, 'w'), indent=2) + @property + def page_lang(self): + if self._page_lang == None: + self.setup_page_lang() + return self._page_lang + + @property + def boxes(self): return self.page_data.boxes + + def setup_ground_truth(self): + self._gts = read_ground_truth(self.page_data) + @property + def gts(self): + if self._gts is None: + self.setup_ground_truth() + return self._gts + + @functools.lru_cache(typed=True) + def dilated_mask(self, fraction: float): + return dilate_by_fractional_pixel(self.mask, fraction) + + def mask_dilated1(self): + if self._mask_dilated1 is None: + self._mask_dilated1 = self.mask.filter(ImageFilter.MaxFilter(3)) + return self._mask_dilated1 + + def mask_dilated05(self): + if self._mask_dilated05 is None: + self._mask_dilated05 = self.dilated_mask(0.5) + return self._mask_dilated05 + + def mask_dilated02(self): + if self._mask_dilated02 is None: + self._mask_dilated02 = self.dilated_mask(0.2) + return self._mask_dilated02 + + def dilated(self): + return {1: self.mask_dilated1(), + 0.5: self.mask_dilated05(), + 0.2: self.mask_dilated02(),} + + def __new__(cls, + exp: ExperimentContext, + idx: ImgSpecT, + *args, **kwargs) -> Self: + return super().__new__(cls, exp, idx, *args, **kwargs) # type: ignore + + +# %% experiments.ipynb 50 +class OCRExperimentContext(ExperimentContext): + """ + A utility class to maintain shared state across all experiments within OCR domain. + This class encapsulates state necessary for conducting PanelCleaner OCR experiments. + """ + + config: cfg.Config + image_paths: list[Path] + # OCR engine -> Image index -> Box index -> Crop method -> Result + _results: dict[str, dict[ImgIdT, ResultSet]] + + + engines = { + 'Tesseract': cfg.OCREngine.TESSERACT, + 'Idefics': None, + 'manga-ocr': cfg.OCREngine.MANGAOCR} + + # subject_cls: ImageContext + # def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls + + @classmethod + def get_config(cls, cache_dir: Path | None = None) -> cfg.Config: + config = cfg.load_config() + config.cache_dir = cache_dir or Path(".") + profile = config.current_profile + preprocessor_conf = profile.preprocessor + # Modify the profile to OCR all boxes. + # Make sure OCR is enabled. + preprocessor_conf.ocr_enabled = True + # Make sure the max size is infinite, so no boxes are skipped in the OCR process. + preprocessor_conf.ocr_max_size = 10**10 + # Make sure the sus box min size is infinite, so all boxes with "unknown" language are skipped. + preprocessor_conf.suspicious_box_min_size = 10**10 + # Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics. + preprocessor_conf.ocr_blacklist_pattern = ".*" + return config + + def to_dict(self): + return { + 'image_paths': list(map(str, self.image_paths)), + 'cache_dir': str(self.config.cache_dir) + } + def to_json(self): + return json.dumps(self.to_dict(), indent=2) + @classmethod + def from_json_data(cls, d: dict): + return cls(cls.get_config(Path(d['cache_dir'])), d['image_paths']) + @classmethod + def from_json_path(cls, path: Path): + return cls.from_json_data(json.loads(path.read_text())) + + + @functools.lru_cache() + def mocr(self, ocr_model: str, lang: str): + engine = self.engines[ocr_model] + ocr_processor = ocr.get_ocr_processor(True, engine) + proc = ocr_processor[lang2pcleaner(lang)] + if isinstance(proc, TesseractOcr): + proc.lang = lang2tesseract(lang) + return proc + + def ocr_box(self, result: ResultOCR, ocr_model: str, lang: str): + assert result.image is not None + text = self.mocr(ocr_model, lang)(result.image) + result.ocr = postprocess_ocr(text) + return result + + @property + def cache_dir(self): return self.config.get_cleaner_cache_dir() + image_cache_dir = ExperimentContext.subject_cache_dir + + @functools.lru_cache() + def _load_page_data(self, image_idx: int): + config = self.config + cache_dir = self.image_cache_dir(image_idx) + img_path = self.path_from_idx(image_idx) + image_name = img_path.stem + # read cached json + jsons = [_ for _ in cache_dir.glob("*#raw.json") if image_name in _.stem] + assert len(jsons) <= 1 + # generate text boxes if needed + if not jsons: + pfl = config.current_profile + gpu = torch.cuda.is_available() or torch.backends.mps.is_available() + model_path = config.get_model_path(gpu) + ctm.model2annotations(pfl.general, pfl.text_detector, model_path, [img_path], cache_dir) + # we don't need unique names for this tests, strip uuids + for p in cache_dir.glob(f"*{image_name}*"): + p.rename(strip_uuid(p)) + jsons = [_ for _ in cache_dir.glob("*#raw.json") if image_name in _.stem] + + # adapt paths to be relative to this notebook + this_path = self._root + json_file_path = jsons[0] + json_data = json.loads(json_file_path.read_text(encoding="utf-8")) + json_data["image_path"] = str(strip_uuid(json_data["image_path"]).relative_to(this_path)) + json_data["mask_path"] = str(strip_uuid(json_data["mask_path"]).relative_to(this_path)) + json.dump(json_data, open(json_file_path, "w"), indent=2) + else: + json_file_path = jsons[0] + json_data = json.loads(json_file_path.read_text(encoding="utf-8")) + + page_data = st.PageData( + json_data["image_path"], json_data["mask_path"], + json_data["original_path"], json_data["scale"], + [st.Box(*data["xyxy"]) for data in json_data["blk_list"]], + [], [], []) + # Merge boxes that have mutually overlapping centers. + page_data.resolve_total_overlaps() + return json_data, page_data + + def page_data(self, image_idx: int): + _, page_data = self._load_page_data(image_idx) + return page_data + def json_data(self, image_idx: int): + json_data, _ = self._load_page_data(image_idx) + return json_data + + def experiment_image(self, image_idx: ImgIdT | str | Path) -> ImageContext | None: + "Cached image context." + return cast(ImageContext, self.experiment_subject(image_idx)) + + def update_results(self, ocr_model: str, img_idx: ImgIdT, results: ResultSetDefault): + self._results[ocr_model][img_idx] = cast(ResultSet, results) + + + def _result_from(self, image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None): + img_ctx = ImageContext(self, image_idx) + extracted = method in _EXTRACTED_METHODS + result_cls = ResultOCRExtracted if extracted else ResultOCR + result = result_cls(int(box_idx), None, '', img_ctx.page_data, + img_ctx.gts, description=f"{method.value}") + if ocr is not None: + result.ocr = ocr + return result + + def result(self, + ocr_model: str, + image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, + ocr: bool=True, + rebuild: bool=False) -> ResultOCR | None: + img_ctx = ImageContext(self, image_idx) + result = self._results[ocr_model][image_idx][box_idx].get(method) + if not rebuild and result is not None: + return result + + result = self._result_from(image_idx, box_idx, method) + image, cropped_image, cropped_mask = result.image, None, None + base_image = img_ctx.base_image + box = img_ctx.boxes[box_idx] + if image is None and method in _IMAGE_METHODS: + image = crop_by_image( + method, box, base_image, self.config.current_profile.preprocessor) + + if image is None and method in _EXTRACTED_METHODS: + mask = img_ctx.mask + cropped_image_path = result.cache_image(cropped_image, "cropped") + cropped_mask_path = result.cache_image(cropped_mask, "mask") + if not cropped_image_path.exists() or not cropped_mask_path.exists(): + image, cropped_image, cropped_mask = crop_by_extracted( + method, box, base_image, mask, + cropped_image_path, cropped_mask_path, img_ctx.dilated()) + + assert image is not None + if result.image is None: + result.image = image + result.cache_image() + if cropped_image is not None: + result.cache_image(cropped_image, "cropped") + if cropped_mask is not None: + result.cache_image(cropped_mask, "mask") + + if ocr: + result = self.ocr_box(result, ocr_model, img_ctx.page_lang) + self._results[ocr_model][image_idx][box_idx][method] = result + return result + + def results(self, ocr_model: str | None = None, img_idx: ImgIdT | None = None): + if ocr_model is None: return self._results + if img_idx is None: return self._results[ocr_model] + return self._results[ocr_model][img_idx] + def model_results(self, ocr_model: str): + return cast(dict[ImgIdT, ResultSet], self.results(ocr_model)) + def image_results(self, ocr_model: str, img_idx: ImgIdT): + return cast(ResultSet, self.results(ocr_model, img_idx)) + def box_results(self, ocr_model: str, img_idx: ImgIdT, box_idx: BoxIdT): + return cast(ResultSet, self.results(ocr_model, img_idx))[box_idx] + def method_results(self, ocr_model: str, img_idx: ImgIdT, method: CropMethod): + image_results = self.image_results(ocr_model, img_idx) + return {i: box_results.get(method) for i,box_results in image_results.items()} + + def _reset_results(self): + results = defaultdict(lambda: defaultdict(lambda: ResultSetDefault(dict))) + self._results = cast(dict[str, dict[ImgIdT, ResultSet]], results) + def reset_results(self, + ocr_model: str | None = None, + image_idx: int | None = None, + box_idx: int | None = None, + method: CropMethod | None = None): + if ocr_model is None and image_idx is None and box_idx is None and method is None: + self._reset_results() + return + results = self._results + models = tuple(results.keys()) if ocr_model is None else [ocr_model] if ocr_model in results else [] + for ocr_model in models: + img_nodes = results[ocr_model] + imgs = tuple(img_nodes.keys()) if image_idx is None else [image_idx] if image_idx in img_nodes else [] + for img_idx in imgs: + box_nodes = img_nodes[img_idx] + boxes = tuple(box_nodes.keys()) if box_idx is None else [box_idx] if box_idx in box_nodes else [] + for box_idx in boxes: + if method is None: + del box_nodes[box_idx] + else: + methods = box_nodes[box_idx] + if method in methods: + del methods[method] + if not box_nodes[box_idx]: + del box_nodes[box_idx] + if not img_nodes[img_idx]: + del img_nodes[img_idx] + if not results[ocr_model]: + del results[ocr_model] + def reset(self): + super().reset() + self.reset_results() + self._load_page_data.cache_clear() + self.mocr.cache_clear() + + def __init__(self, + config: cfg.Config | None, + image_paths: list[Path] + ): + super().__init__(list(map(lambda p: p.resolve(), image_paths))) + self.config = config or type(self).get_config() + self.image_paths = self._paths + self._reset_results() + self._images = self._subjects + + +# %% experiments.ipynb 51 +@FC.patch_to(ImageContext) +def setup(self, exp: OCRExperimentContext, image_idx: ImgSpecT, page_lang: str | None = None): + super(type(self), self).setup(exp, image_idx) + self._mask_dilated1 = self._mask_dilated05 = self._mask_dilated02 = None + # if ocr_model not in exp.engines: + # raise ValueError(f"OCR model {ocr_model} not supported.") + # self.ocr_model = ocr_model + # self.idx = exp.normalize_idx(image_idx) + self.json_data, self.page_data = exp._load_page_data(self.idx) + self.setup_page_lang(page_lang) + self.mask = Image.open(self.page_data.mask_path) + self.base_image = Image.open(self.page_data.image_path) + self.setup_ground_truth() + + + +# %% experiments.ipynb 54 +class ContextVisor: + ctx: Any + # control_names: list[str] + values: dict[str, Any] + + _css = '' + + _ctxs: dict[str, ContextVisor] + _hdlrs: dict[str, ContextVisor] + + @property + def w(self) -> W.DOMWidget: + if getattr(self, '_w', None) is None: + self._w = self.setup_ui() + return self._w + @property + def out(self) -> W.Output: + if getattr(self, '_out', None) is None: + self._out = W.Output() + self._out.clear_output(wait=True) + return self._out # type: ignore + @property + def controls(self) -> dict[str, W.ValueWidget | W.fixed]: + if getattr(self, '_controls', None) is None: + self._controls = self.setup_controls() + return self._controls + @property + def all_controls(self) -> dict[str, W.ValueWidget | W.fixed]: + if getattr(self, '_all_controls', None) is None: + controls = {} + for visor in self._ctxs.values(): + controls.update(visor.all_controls) + controls.update(self.controls) + self._all_controls = controls + return self._all_controls + + @property + def all_values(self): + return {**{k:v.values for k,v in (self._ctxs | {'self': self}).items()}, **self.values} + + @property + def comps(self): return self._ctxs + def comp(self, k: str) -> ContextVisor | None: + return self._ctxs.get(k) + def handler(self, k: str) -> ContextVisor | None: + return self._hdlrs.get(k) + + @property + def styler(self) -> W.Output | None: + if (stl := self.setup_style()) is None: + return None + if getattr(self, '_style', None) is None: + self._style = W.Output(layout={'height': '0px'}) + with self._style: + display(stl) + return self._style + def setup_style(self): + return HTML(f"") if self._css else None + + def update_output(self, **kwargs): + cprint(kwargs) + + def setup_controls(self) -> dict[str, W.ValueWidget | W.fixed]: + return {k: W.Label(value=k) for k,v in self.values.items()} + + def hide(self): + self.w.layout.visibility = 'hidden' + def show(self): + self.w.layout.visibility = 'visible' + + def setup_ui(self): + comps = [] + for visor in self._ctxs.values(): + comps.append(visor.w) + return W.HBox([*comps, *self.controls.values()]) + + def setup_display(self): + if getattr(self, '_w', None) is None: + self._w = self.setup_ui() + + + def _output(self, **kwargs): + collator = defaultdict(dict) + show_inline_matplotlib_plots() + with self.out: + clear_output(wait=True) + for k,v in kwargs.items(): + if (comp := self.handler(k)) is not None: + collator[comp][k] = v + else: + assert 0 + # self.update_output(**{k: v}) + for comp, kw in collator.items(): + comp.update_output(**kw) + show_inline_matplotlib_plots() + def interactive_output(self): + controls = self.all_controls + controls2names = {v:k for k,v in controls.items()} + def observer(change): + control_name = controls2names[change['owner']] + kwargs = {control_name: change['new']} + updated = self._update(**kwargs) + self._output(**updated) + for w in controls.values(): + w.observe(observer, 'value') + def display(self, **kwargs): + if getattr(self, '_w', None) is None: + self.setup_display() + self.interactive_output() + self._update(**(self.values | kwargs)) + all_values= {} + for comp in list(self.comps.values()) + [self]: all_values.update(comp.values) + self._hdlrs = {k:self._hdlrs.get(k, self) for k in all_values} + self._output(**all_values) + display(self.styler, self.w, self.out) if self.styler else display(self.w, self.out) + else: + self.update(**kwargs) + def _ipython_display_(self): self.display() + + def _update(self, update_value: bool=True, **kwargs): + updated = {} + for visor in self.comps.values(): + updated.update(visor._update(update_value=update_value, **kwargs)) + values = self.values + my_vals = _pops_(kwargs, self.values.keys()) + for k,v in my_vals.items(): + if v is not None and v != values[k]: + if update_value: values[k] = v + updated[k] = v + return updated + def update(self, **kwargs): + updated = self._update(update_value=False, **kwargs) + controls = self.all_controls + for k in updated: + controls[k].value = updated[k] + # self._output(**updated) + + def __init__(self, + ctx: Any, + values: dict[str, Any], + out: W.Output | None = None, + ctxs: dict[str, ContextVisor] | None = None, + hdlrs: dict[str, ContextVisor] | None = None, + ): + self._ctxs = ctxs or {} + self._hdlrs = hdlrs or {} + self.ctx = ctx + self._out = out + self.values = values + + + +# %% experiments.ipynb 62 +class ImageSelector(ContextVisor): + ctx: OCRExperimentContext + + @property + def image_ctx(self): + return ImageContext(self.ctx, self.values['image_idx']) + + def setup_controls(self): + paths = self.ctx.image_paths + w = W.Dropdown( + options={_.stem:i for i,_ in enumerate(paths)}, + value=self.values['image_idx'], + layout={'width': 'fit-content'}, + style={'description_width': 'initial'}) + return {'image_idx': w} + + def update(self, image_idx: ImgSpecT | None = None, **kwargs): + if image_idx is None: return + idx = self.ctx.normalize_idx(image_idx) + if idx is None: return + super().update(image_idx=idx, **kwargs) + + + def __init__(self, + ctx: OCRExperimentContext, /, + image_idx: ImgSpecT = 0, *, + out: W.Output | None=None): + idx = ctx.normalize_idx(image_idx) + assert idx is not None, f"Image {image_idx} not found in experiment context" + super().__init__(ctx, {'image_idx': idx}, out) + + +# %% experiments.ipynb 66 +class OCRContextVisor(ContextVisor): + ctx: OCRExperimentContext + + def update_output(self, /, image_idx: ImgIdT, **kwargs): + img_path = self.ctx.path_from_idx(image_idx) + display_image_grid([img_path], 1, 1) + + def update(self, image_idx: ImgSpecT | None = None, **kwargs): + if image_idx is None: return + idx = self.ctx.normalize_idx(image_idx) + if idx is None: return + super().update(image_idx=idx, **kwargs) + + def __init__(self, + ctx: OCRExperimentContext, /, + image_idx: ImgSpecT = 0, *, + out: W.Output | None=None): + super().__init__(ctx, {}, out, + ctxs={'image_idx': ImageSelector(ctx, image_idx, out=self.out)}) + + +# %% experiments.ipynb 84 +class OCRModel(Enum): + TESSERACT = 0 + IDEFICS = 1 + @staticmethod + def __display_names__() -> dict[str, OCRModel]: + return dict( + zip("Tesseract, Idefics".split(', '), + OCRModel)) + + +class ModelSelector(ContextVisor): + ctx: OCRExperimentContext + + def setup_controls(self): + options = self.models + w = W.Dropdown( + options=options, + value=self.values['model'], + layout={'width': 'fit-content'}, + style={'description_width': 'initial'}) + return {'model': w} + + def setup_ui(self): + ctls = self.controls + model_grp = W.HBox([ctls['model']]) + model_grp.add_class('model_grp') + comps = [] + for visor in self.comps.values(): + comps.append(visor.setup_ui()) + ui = W.HBox([*comps, model_grp]) + return ui + + def __init__(self, + exp_ctx: OCRExperimentContext, + ocr_model: OCRModel | None=OCRModel.TESSERACT, + ocr_models: dict[str, OCRModel] | None = None, + out: W.Output | None = None + ): + self.models: dict[str, OCRModel] = ocr_models or OCRModel.__display_names__() + super().__init__(exp_ctx, + {'model': ocr_model or OCRModel.TESSERACT}, + out=out or self.out)#, ctxs=[exp_visor]) + + +# %% experiments.ipynb 87 +class DisplayOptions(Enum): + BOXES = 0 + IMAGE = 1 + MASK = 2 + IMAGE_MASK = 3 + PAGE_DATA = 4 + GROUND_TRUTH = 5 + ALL = 6 + RESULTS = 7 + BEST_RESULTS = 8 + DATAFRAME = 9 + + @staticmethod + def __display_names__(): + return dict( + zip("Boxes, Image, Mask, Image & Mask, Page data, Ground truth, All, Results, " + "Best results, Dataframe".split(', '), + DisplayOptions)) + + +class ContentSelector(ContextVisor): + ctx: OCRExperimentContext + + def image_info(self, image_ctx: ImageContext): + img = image_ctx.base_image + (w, h), print_size_in, print_size_cm, required_dpi = image_ctx.image_info + format = PRINT_FORMATS['Modern Age'] + cprint( f"{'Width x Height':>30}: {w} x {h} pixels\n" + f"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\n" + f"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in" + f" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\n" + f"Required DPI Modern Age format: {required_dpi:.3f} dpi " + f"({format[0]:.3f} x {format[1]:.3f} in)") + + + def display_content(self, image_ctx: ImageContext, display_option: DisplayOptions): + page_data = image_ctx.page_data + if display_option in (DisplayOptions.ALL, DisplayOptions.PAGE_DATA): + self.image_info(image_ctx) + RenderJSON(image_ctx.json_data, 350, 2).display() + if display_option in (DisplayOptions.ALL, DisplayOptions.GROUND_TRUTH): + cprint(image_ctx.gts) + if display_option == DisplayOptions.IMAGE: + display_image_grid([page_data.image_path], 1, 1) + if display_option == DisplayOptions.MASK: + display_image_grid([page_data.mask_path], 1, 1) + if display_option in (DisplayOptions.ALL, DisplayOptions.IMAGE_MASK): + display_image_grid([page_data.image_path, page_data.mask_path], 1, 2) + if display_option in (DisplayOptions.ALL, DisplayOptions.BOXES): + _, out_path = page_boxes(page_data) + display_image_grid([out_path], 1, 1) + + + def setup_controls(self): + options = self.display_options or {**DisplayOptions.__display_names__()} + display_option_wdgt = W.Dropdown( + options=options, + value=self.values['display_option'], + layout={'width': '120px'}, + style={'description_width': 'initial'}) + return {'display_option': display_option_wdgt} + + + def setup_ui(self): + ctls = self.controls + display_option_grp = W.HBox([ctls['display_option']]) + display_option_grp.add_class('display_option_grp') + comps = [] + for visor in self.comps.values(): + comps.append(visor.setup_ui()) + ui = W.HBox([*comps, display_option_grp]) + return ui + + + def __init__(self, + exp_ctx: OCRExperimentContext, + display_option: DisplayOptions | None=DisplayOptions.BOXES, + display_options: Mapping[str, DisplayOptions] | None = None, + out: W.Output | None = None + ): + self.display_options = display_options + super().__init__(exp_ctx, + {'display_option': display_option or DisplayOptions.BOXES}, + out=out or self.out)#, ctxs=[exp_visor]) + + +# %% experiments.ipynb 91 +class ImageContextVisor(ContextVisor): + ctx: ImageContext + # control_names: list[str] = ['display_option'] + + _css = """ + .display_option_grp { + background-color: lightblue; + } + """ + + def image_info(self): + content_selector = cast(ContentSelector, self.comp('display_option')) + content_selector.image_info(self.ctx) + + def update_output(self, + display_option: DisplayOptions | None = None, + image_idx: ImgIdT | None = None, + **kwargs): + content_selector = cast(ContentSelector, self.comp('display_option')) + if image_idx is not None and image_idx != self.ctx.image_idx: + ctx = ImageContext(self.ctx.exp, image_idx) + assert ctx is not None + self.ctx = ctx + display_option = content_selector.values['display_option'] + if display_option is None: + return + content_selector.display_content(self.ctx, display_option) + + def update(self, + display_option: DisplayOptions | None=None, + image_idx: ImgSpecT | None=None, + **kwargs): + if image_idx is not None: + if (idx := self.ctx.exp.normalize_idx(image_idx)) is not None: + kwargs['image_idx'] = idx + super().update(display_option=display_option, **kwargs) + + def __init__(self, + exp_ctx: OCRExperimentContext, + img_idx: ImgIdT | str | Path | ImageContext, + display_option: DisplayOptions=DisplayOptions.BOXES, + display_options: Mapping[str, DisplayOptions] | None = None, + out: W.Output | None = None + ): + if isinstance(img_idx, ImageContext): + ctx = img_idx + else: + assert exp_ctx is not None, "exp_ctx must be provided if img_idx is not an ImageContext" + ctx = ImageContext(exp_ctx, img_idx) + assert ctx is not None, f"Image {img_idx} not found in experiment context" + if display_options is None: + display_options = {**DisplayOptions.__display_names__()} + del display_options['Results'] + out = out or self.out + content_selector = ContentSelector(exp_ctx, + display_option=display_option, display_options=display_options, out=out) + image_selector = ImageSelector(exp_ctx, ctx.image_idx, out=out) + super().__init__(ctx, {}, out=out, + ctxs={'image_idx': image_selector, 'display_option': content_selector}) + + +# %% experiments.ipynb 104 +def trimmed_mean(data, trim_percent): + sorted_data = np.sort(data) + n = len(data) + trim_count = int(trim_percent * n) + trimmed_data = sorted_data[trim_count:-trim_count] + return np.mean(trimmed_data) + +def mad_based_outlier(points, threshold=3.5): + median = np.median(points) + diff = np.abs(points - median) + mad = np.median(diff) + modified_z_score = 0.6745 * diff / mad + return points[modified_z_score < threshold] + +def iqr_outlier_removal(data): + q1 = np.percentile(data, 25) + q3 = np.percentile(data, 75) + iqr = q3 - q1 + lower_bound = q1 - 1.5 * iqr + upper_bound = q3 + 1.5 * iqr + return data[(data >= lower_bound) & (data <= upper_bound)] + + +# %% experiments.ipynb 105 +@dataclasses.dataclass +class Experiment: + ctx: ExperimentContext + + +@dataclasses.dataclass +class ExperimentOCR(Experiment): + ctx: ImageContext + ocr_model: str + + @property + def img_ctx(self): return self.ctx + @property + def ctxs(self): + img_ctx = self.img_ctx + return cast(OCRExperimentContext, img_ctx.exp), img_ctx + + @classmethod + def file_path_of(cls, page_data: st.PageData, ocr_model: str): + return f"{Path(page_data.original_path).stem}_{ocr_model}.json" + + def file_path(self): + img_ctx = self.img_ctx + return type(self).file_path_of(img_ctx.page_data, self.ocr_model) + + def to_dict(self): + "JSON serializable dict of the experiment" + img_ctx = self.img_ctx + img_idx = img_ctx.image_idx + results = results_to_dict(self.results()) + return { + 'image_name': img_ctx.image_name, + 'ocr_model': self.ocr_model, + 'results': results, + } + + def to_json(self, out_dir: Path | None = None): + img_ctx = self.img_ctx + fp = (out_dir or img_ctx.cache_dir_image) / self.file_path() + data = self.to_dict() + with open(fp, 'w') as f: + json.dump(data, f, indent=2) + return fp, data + + @classmethod + def from_json(cls, experiment: OCRExperimentContext, json_path: Path) -> Self: + try: + with open(json_path, 'r') as f: + data = json.load(f) + except Exception as e: + logger.error(f"Error loading {json_path}: {e}") + raise e + ocr_model = data['ocr_model'] + img_ctx = ImageContext(experiment, data['image_name']) + results: ResultSetDefault = dict_to_results( + img_ctx.image_idx, + data['results'], + result_factory=experiment._result_from) + experiment.update_results(ocr_model, img_ctx.image_idx, results) + return cls(img_ctx, ocr_model) + + @classmethod + def from_image(cls, + ctx: OCRExperimentContext, + ocr_model: str, + image_idx: ImgSpecT): + idx = cast(ImgIdT, ctx.normalize_idx(image_idx)) + img_ctx = ImageContext(ctx, idx) + if img_ctx is None: + raise ValueError(f"Image {image_idx} not found in experiment context") + fp = img_ctx.cache_dir / cls.file_path_of(img_ctx.page_data, ocr_model) + if fp.exists(): + return cast(Self, cls.from_json(cast(OCRExperimentContext, img_ctx.exp), fp)) + return cls(img_ctx, ocr_model) + + @classmethod + def from_method(cls, + ctx: OCRExperimentContext, + ocr_model: str, + image_idx: ImgIdT | str | Path, + method: CropMethod): + experiment = cls.from_image(ctx, ocr_model, image_idx) + if experiment is None: + return None + return experiment.method_experiment(method) + + @classmethod + def saved_experiment(cls, + ctx: OCRExperimentContext, ocr_model: str, image_idx: ImgIdT | str | Path): + idx = ctx.normalize_idx(image_idx) + if idx is None: + logger.warning(f"Image {image_idx} not found in experiment context") + return None + return cls.from_image(ctx, ocr_model, idx) + + @classmethod + def saved_experiments(cls, ctx: OCRExperimentContext, ocr_model: str) -> list[Self]: + return [exp for i in range(len(ctx.image_paths)) + if (exp := cls.from_image(ctx, ocr_model, i)) is not None] + + + def result(self, box_idx: BoxIdT, method: CropMethod, ocr: bool=True, rebuild: bool=False): + ctx, img_ctx = self.ctxs + return ctx.result(self.ocr_model, img_ctx.image_idx, box_idx, method, ocr, rebuild) + + def results(self): + ctx, img_ctx = self.ctxs + return cast(ResultSet, ctx.results(self.ocr_model, img_ctx.image_idx)) + + def has_run(self): + "at least one method has run" + img_ctx = self.img_ctx + return len(self.results()) == len(img_ctx.page_data.boxes) + + def best_results(self): + img_ctx = self.img_ctx + results = self.results() + if len(results) < len(img_ctx.page_data.boxes): # at least one method has run + return None + best = [] + for box_idx in results: + methods = results[box_idx] + best_method = max(methods, key=lambda m: methods[m].acc) # type: ignore + best.append((best_method, methods[best_method])) + return best + + def save_results_as_ground_truth(self, overwrite=False): + img_ctx = self.img_ctx + gts_path = ground_truth_path(img_ctx.page_data) + if overwrite or not gts_path.exists(): + best_results = self.best_results() + if best_results: + tt = [r.ocr for m,r in best_results] + gts_path.write_text('\n'.join(tt), encoding="utf-8") + img_ctx.setup_ground_truth() + logger.info(f"Ground truth data saved successfully to {gts_path}") + return True + else: + logger.info("No best results available to save.") + return False + else: + return False + + @property + def experiments(self): + if not hasattr(self, '_experiments'): + self._experiments = {} + return self._experiments + def method_experiment(self, method: CropMethod) -> ExperimentOCRMethod: + if method not in self.experiments: + self.experiments[method] = ExperimentOCRMethod(self, method) + return self.experiments[method] + + + def to_dataframe(self): + "Dataframe with crop methods as columns and box ids as rows" + methods = list(CropMethod.__members__.values()) + experiments = [self.method_experiment(m) for m in methods] + accuracies = [[result.acc for result in exp.results()] for exp in experiments] + # transpose accuracies + accuracies = list(zip(*accuracies)) + return pd.DataFrame(accuracies, columns=CropMethod.__display_names__()) + + def plot_accuracies(self, + methods: list[CropMethod] | None = None, + ): + "Plots a horizontal bar chart of the accuracies for a list of method experiments." + methods = methods or list(CropMethod.__members__.values()) + experiments = [self.method_experiment(m) for m in methods] + if not experiments: return + + ctx, img_ctx = self.ctxs + page_data = img_ctx.page_data + model = self.ocr_model + accuracies = [[result.acc for result in exp.results()] for exp in experiments] + accuracies = [np.mean(a) for a in accuracies] + # accuracies = [np.mean([result.acc for result in exp.results()]) for exp in experiments] + + _, ax = plt.subplots(figsize=(10, 5)) + + # Normalize the accuracies for color mapping + norm = plt.Normalize(min(accuracies), max(accuracies)) + # Color map from red to green + cmap = plt.get_cmap('RdYlGn') + colors = cmap(norm(accuracies)) + + ax.barh([m.value for m in methods], accuracies, color=colors) + + ax.set_xscale('log') # Set the x-axis to a logarithmic scale + ax.set_xlabel('Average Accuracy (log scale)', fontsize=12, fontweight='bold') + + ax.set_ylabel('Method', fontsize=12, fontweight='bold') + ax.set_yticks(range(len(methods))) + ax.set_yticklabels([f'{method.value} ({acc:.2f})' + for method, acc in zip(methods, accuracies)], fontsize=12) + max_acc_index = np.argmax(accuracies) + ax.get_yticklabels()[max_acc_index].set(color='blue', fontweight='bold') + + title_text = (f"{page_data.original_path} - OCR model: {model}") + ax.set_title(title_text, fontsize=12, fontweight='bold') + + plt.tight_layout() + plt.show() + + + def summary_box(self, box_idx: int): + results: list[tuple[CropMethod, ResultOCR]] = [] + pb = tqdm(CropMethod.__members__.values(), leave=False, desc=f"Box #{box_idx+1}") + for m in pb: + r = cast(ResultOCR, self.result(box_idx, m)) + results.append((m, r)) + methods, images, ocrs, accs = zip( + *map( + lambda t: (t[0].value, t[1].cache_image(), t[1].diff_tagged(), acc_as_html(t[1].acc)), + results)) + display_columns([methods, images, accs, ocrs], + headers=["Method", f"Box #{box_idx+1}", "Accuracy", "OCR"]) + + + def summary_method(self, method: CropMethod): + results = self.method_experiment(method).results() + methods, images, ocrs, accs = zip( + *map( + lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), + results)) + display_columns([methods, images, accs, ocrs], + headers=["Box #", "Box", "Accuracy", f"{method.value} OCR"]) + + + def display(self): + out = [] + for method in CropMethod: + out.append(f"---------- {method.value} ----------") + results = self.method_experiment(method).results() + out.extend(results) + out.append('\n') + cprint(*out, soft_wrap=True) + + + def reset(self, box_idx: int | None = None, method: CropMethod | None = None): + ctx, img_ctx = self.ctxs + ctx.reset_results(None, img_ctx.image_idx, box_idx, method) + + def perform_methods(self, + methods: CropMethod | list[CropMethod] | None = None, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + rebuild: bool = False, + plot_acc: bool = False + ): + if methods is None: + methods = [*CropMethod.__members__.values()] + elif isinstance(methods, CropMethod): + methods = [methods] + if rebuild: + _methods = tqdm(methods, desc="Methods") + else: + _methods = methods + for method in _methods: + method_exp = self.method_experiment(method) + if method_exp: + if rebuild: + method_exp(box_idxs, rebuild=rebuild) + if plot_acc: + self.plot_accuracies() + + def __call__(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + methods: CropMethod | list[CropMethod] | None = None, + save: bool = True, + display=False, + rebuild: bool=False, + save_as_ground_truth=False): + self.perform_methods(methods, box_idxs, rebuild=rebuild) + if save_as_ground_truth: + self.save_results_as_ground_truth(overwrite=True) + if save: + self.to_json() + if display: + self.display() + + +@dataclasses.dataclass +class ExperimentOCRMethod: + ctx: ExperimentOCR + method: CropMethod + + @property + def exp_ctx(self): return self.ctx + @property + def img_ctx(self): return self.ctx.ctx + @property + def ctxs(self): + img_ctx = self.img_ctx + return cast(OCRExperimentContext, img_ctx.exp), img_ctx, self.ctx + + def result(self, box_idx: BoxIdT, ocr: bool=True, rebuild: bool=False) -> ResultOCR | None: + ctx, img_ctx, exp_ctx = self.ctxs + return ctx.result(exp_ctx.ocr_model, img_ctx.image_idx, box_idx, self.method, ocr, rebuild) + + def results(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + ocr: bool=True, rebuild: bool=False) -> list[ResultOCR]: + ctx, img_ctx, exp_ctx = self.ctxs + if box_idxs is None: + box_idxs = list(range(len(img_ctx.boxes))) + elif isinstance(box_idxs, int): + box_idxs = [box_idxs] + model = exp_ctx.ocr_model + results = ctx.method_results(model, img_ctx.image_idx, self.method) + results = {i:results[i] if i in results else None for i in box_idxs} + pb = rebuild or not results or any(r is None for r in results.values()) + if pb and len(results) > 2: + progress_bar = tqdm(list(results.keys()), desc=f"{self.method.value} - {model}") + else: + progress_bar = list(results.keys()) + results = [] + for i in progress_bar: + results.append(self.result(i, ocr, rebuild=rebuild)) + return results + + + def get_results_html(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + max_image_width: int | None = None): + _, img_ctx, exp_ctx = self.ctxs + results: list[ResultOCR] = self.results(box_idxs) + accs = np.array([r.acc for r in results]) + mean_accuracy = np.mean(accs) + mean_trimmed = trimmed_mean(accs, 0.1) + # filtered_data = mad_based_outlier(accs) + # mean_mad = np.mean(filtered_data) + # filtered_data = iqr_outlier_removal(accs) + # mean_iqr = np.mean(filtered_data) + + descriptions, images, ocrs, accs = zip(*map( + lambda r: ( + r.block_idx+1, + r.cache_image(), + r.diff_tagged(), + acc_as_html(r.acc) + ), results)) + non_breakin_space = u'\u00A0' + tmpl = "{}" + padded_s = lambda s,n: tmpl.format(s.rjust(n)) + acc_fmt = f"{mean_accuracy:.2f}/{mean_trimmed:.2f}" + w, h = img_ctx.base_image.size + dim, _dpi = size(w, h), dpi(w, h) + dim_fmt = f"{w}x{h} px: {dim[0]:.2f} x {dim[1]:.2f} in @ {_dpi:.2f} dpi" + return '\n
\n'.join([ + ("
" + f"{padded_s('Page', 24)}: {img_ctx.page_data.original_path}
" + f"{padded_s('Size', 24)}: {dim_fmt}
" + f"{padded_s('Model', 24)}: {exp_ctx.ocr_model}
" + f"{padded_s('Crop Method', 24)}: {self.method.value}
" + f"{padded_s('Accuracy Mean/Trimmed', 24)}: {acc_fmt}" + "
"), + get_columns_html( + [descriptions, images, accs, ocrs], + max_image_width, + headers=["Box #", "Image", "Accuracy", "OCR"]), + ]) + + def display(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, max_image_width: int | None = None): + display(HTML(self.get_results_html(box_idxs, max_image_width))) + + + def summary(self): + results = self.results() + methods, images, ocrs, accs = zip( + *map( + lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), + results)) + display_columns([methods, images, accs, ocrs], + headers=["Box #", "Box", "Accuracy", f"{self.method.value} OCR"]) + + + def reset(self): + _, _, exp_ctx = self.ctxs + exp_ctx.reset(method=self.method) + + def __call__(self, box_idxs: BoxIdT | list[BoxIdT] | None = None, display=False, rebuild=False): + if isinstance(box_idxs, int): + result = self.result(cast(BoxIdT, box_idxs), rebuild=rebuild) + if result is not None and display: + result.display() + else: + results = self.results(box_idxs, rebuild=rebuild) + if results and display: + self.display(box_idxs) + + +# %% experiments.ipynb 141 +class ResultVisor(ContextVisor): + ctx: ExperimentOCR + control_names: list[str] = ['all_boxes', 'box_idx', 'all_methods', 'method'] + + _css = """ + .box_grp { + background-color: aliceblue; + } + .method_grp { + background-color: #ededed; + } + """ + + def best_results(self): + ll = self.ctx.best_results() + if ll: + cprint([(m.value, f"{r.acc:.3f}", r.ocr) for m,r in ll]) + + def pd_to_html(self): + df = self.ctx.to_dataframe() + # set float precision + df = df.round(3) + # display floats with 3 decimal digits + df = df.applymap(lambda x: f"{x:.3f}") + # highlight max value in each row + stl = df.style.highlight_max(axis=0) + display(HTML(stl.to_html())) + + def update_output(self, **kwargs): + all_boxes: bool = self.values['all_boxes'] + box_idx: int = self.values['box_idx'] + all_methods: bool = self.values['all_methods'] + method: CropMethod = self.values['method'] + + # cprint(f"all_boxes: {all_boxes}, box_idx: {box_idx}, all_methods: {all_methods}, method: {method}") + + if all_boxes and all_methods: + self.ctx.plot_accuracies() + elif all_boxes: + self.ctx.summary_method(method) + elif all_methods: + self.ctx.summary_box(box_idx) + else: + result = self.ctx.result(box_idx, method) + if result is not None: + result.display() + + def setup_controls(self): + _, img_ctx = self.ctx.ctxs + values = self.values + box_wdgt = W.BoundedIntText( + value=values['box_idx'], min=0, max=len(img_ctx.boxes)-1, step=1, + disabled=values['all_boxes'], + layout={'width': '50px'}, + style={'description_width': 'initial'}) + methods_wdgt = W.Dropdown( + options=CropMethod.__display_names__(), + value=values['method'], + layout={'width': '150px'}, + style={'description_width': 'initial'}) + all_boxes_wdgt = W.Checkbox(label='All', value=values['all_boxes'], + description="all", + layout={'width': 'initial'}, + style={'description_width': '0px'}) + all_methods_wdgt = W.Checkbox(label='All', value=values['all_methods'], + description="all", + layout={'width': 'initial'}, + style={'description_width': '0px'}) + return {'all_boxes': all_boxes_wdgt, 'box_idx': box_wdgt, + 'all_methods': all_methods_wdgt, 'method': methods_wdgt} + + def setup_ui(self): + ctls = self.controls + _, img_ctx = self.ctx.ctxs + box_label = W.Label( + value=f"Box # (of {len(img_ctx.boxes)}):", + layout={'width': 'initial', 'padding': '0px 0px 0px 10px'}) + method_label = W.Label(value='Method:', layout={'width': 'initial', 'padding': '0px 0px 0px 10px'}) + + box_grp = W.HBox([box_label, ctls['all_boxes'], ctls['box_idx']]) + box_grp.add_class('box_grp') + method_grp = W.HBox([method_label, ctls['all_methods'], ctls['method']]) + method_grp.add_class('method_grp') + + return W.HBox([box_grp, method_grp]) + + def __init__(self, + ctx: OCRExperimentContext | ExperimentOCR, + img_idx: int | str | Path | None = None, + all_boxes: bool = False, + box_idx: int = 0, + all_methods: bool = False, + method: CropMethod=CropMethod.INITIAL_BOX, + out: W.Output | None = None, + ): + if isinstance(ctx, OCRExperimentContext): + assert img_idx is not None, "img_idx must be provided if ctx is an ExperimentContext" + exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx) + if not exp: + raise ValueError(f"Image {img_idx} not found in experiment context") + ctx = exp + else: + if not isinstance(ctx, ExperimentOCR): + raise ValueError("ctx must be an ExperimentOCR or OCRExperimentContext") + + super().__init__(ctx, {'all_boxes': all_boxes, 'box_idx': box_idx, + 'all_methods': all_methods, 'method': method}, out=out or self.out) + + +# %% experiments.ipynb 144 +class ExperimentVisor(ContextVisor): + ctx: ExperimentOCR + + def update_output(self, + image_idx: int | None = None, + **kwargs): + exp_ctx, img_ctx = self.ctx.ctxs + if image_idx is not None and image_idx != img_ctx.image_idx: + ctx = ImageContext(exp_ctx, image_idx) + assert ctx is not None + self.ctx.ctx = ctx + result_visor = self.comp('result_visor') + if result_visor is not None: + result_visor.update_output(**kwargs) + + def __init__(self, + ctx: OCRExperimentContext | ExperimentOCR, + img_idx: int | str | Path | None = None, + all_boxes: bool = False, + box_idx: int = 0, + all_methods: bool = False, + method: CropMethod=CropMethod.INITIAL_BOX, + out: W.Output | None = None, + ): + if isinstance(ctx, OCRExperimentContext): + assert img_idx is not None, "img_idx must be provided if ctx is an ExperimentContext" + exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx) + if not exp: + raise ValueError(f"Image {img_idx} not found in experiment context") + ctx = exp + else: + if not issubclass(type(ctx), ExperimentOCR): + raise ValueError("ctx must be an ExperimentOCR or OCRExperimentContext") + + exp_ctx, img_ctx = ctx.ctxs + out = out or self.out + image_selector = ImageSelector(exp_ctx, image_idx=img_ctx.image_idx, out=out) + result_visor = ResultVisor(ctx, out=out, + all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method) + + super().__init__(ctx, {}, out=out, + ctxs={'image_selector': image_selector, 'result_visor': result_visor}, + hdlrs={'display_option': result_visor} + ) + + +# %% experiments.ipynb 198 +class ExperimentsVisor(ContextVisor): + ctx: OCRExperimentContext + + def update_output(self, + model: OCRModel | None = None, + image_idx: ImgIdT | None = None, + display_option: DisplayOptions | None = None, + **kwargs): + model_selector, image_selector, content_selector, result_visor = self._comps() + if model is not None: + exp_ctx = result_visor.ctx + exp_ctx.ocr_model = list(model_selector.models.keys())[model.value] + result_visor.ctx = exp_ctx + if image_idx is not None: + img_ctx = ImageContext(self.ctx, image_idx) + result_visor.ctx.ctx = img_ctx + display_option = content_selector.values['display_option'] + if display_option is not None and display_option != DisplayOptions.RESULTS: + result_visor.hide() + if display_option == DisplayOptions.BEST_RESULTS: + result_visor.best_results() + elif display_option == DisplayOptions.DATAFRAME: + result_visor.pd_to_html() + else: + content_selector.display_content(image_selector.image_ctx, display_option) + else: + result_visor.show() + result_visor.update_output(**kwargs) + + def _comps(self): + cc = self.comps + msel: ModelSelector = cc['model_selector'] # type: ignore + isel: ImageSelector = cc['image_selector'] # type: ignore + cs: ContentSelector = cc['content_selector'] # type: ignore + rv: ResultVisor = cc['result_visor'] # type: ignore + return msel, isel, cs, rv + + def setup_ui(self): + ctls = self.controls.values() + msw, isw, csw, rvw = [_.w for _ in self._comps()] + return W.VBox([W.HBox([msw, isw, csw, *ctls]), rvw,]) + + def __init__(self, + ctx: OCRExperimentContext, + image_idx: ImgIdT | str | Path = 0, + ocr_model: OCRModel = OCRModel.TESSERACT, + display_option: DisplayOptions = DisplayOptions.RESULTS, + all_boxes: bool = False, + box_idx: int = 0, + all_methods: bool = False, + method: CropMethod=CropMethod.INITIAL_BOX, + ocr_models: dict[str, OCRModel] = {'Tesseract': OCRModel.TESSERACT}, + out: W.Output | None = None, + ): + if not isinstance(ctx, OCRExperimentContext): + raise ValueError("ctx must be an OCRExperimentContext") + exp = ExperimentOCR.from_image(ctx, 'Tesseract', image_idx) + if not exp: + raise ValueError(f"Image {image_idx} not found in experiment context") + + out = out or self.out + model_selector = ModelSelector(ctx, ocr_model=ocr_model, + ocr_models=ocr_models, out=out) + image_selector = ImageSelector(ctx, image_idx=image_idx, out=out) + content_selector = ContentSelector(ctx, display_option=display_option, out=out) + result_visor = ResultVisor(exp, out=out, + all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method) + + super().__init__(ctx, {}, out=out, + ctxs={'model_selector': model_selector, 'image_selector': image_selector, 'content_selector': content_selector, + 'result_visor': result_visor} + ) + diff --git a/_testbed/helpers.ipynb b/_testbed/helpers.ipynb new file mode 100644 index 00000000..32a6fa6d --- /dev/null +++ b/_testbed/helpers.ipynb @@ -0,0 +1,835 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#| default_exp helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "# %reload_ext autoreload\n", + "# %autoreload 0\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# try: \n", + "# import fastcore as FC\n", + "# except ImportError: \n", + "# !pip install -q fastcore\n", + "# try:\n", + "# import rich\n", + "# except ImportError:\n", + "# !pip install -q rich\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@basic-tesseract" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `Tesseract` OCR for Comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "from __future__ import annotations\n", + "\n", + "import base64\n", + "import json\n", + "import re\n", + "import sys\n", + "import uuid\n", + "from importlib import resources\n", + "from io import BytesIO\n", + "from pathlib import Path\n", + "from typing import Any\n", + "from typing import Iterable\n", + "from typing import Mapping\n", + "from typing import Sequence\n", + "\n", + "import pcleaner.data\n", + "import pcleaner.structures as st\n", + "from IPython.display import clear_output\n", + "from IPython.display import display\n", + "from IPython.display import HTML\n", + "from PIL import Image\n", + "from PIL import ImageDraw\n", + "from PIL import ImageFont\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import defaultdict\n", + "\n", + "import fastcore.xtras # patch Path with some utils\n", + "import ipywidgets as W\n", + "import rich\n", + "from fastcore.test import * # type: ignore\n", + "from rich.console import Console\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# pretty print by default\n", + "# %load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "console = Console(width=104, tab_size=4, force_jupyter=True)\n", + "cprint = console.print\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## dict helpers: _pops_\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "_all_ = ['_pops_', '_pops_values_', '_gets_']\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "def _pops_(d: dict, ks: Iterable) -> dict: \n", + " \"Pops `ks` keys from `d` and returns them in a dict. Note: `d` is changed in-place.\"\n", + " return {k:d.pop(k) for k in ks if k in d}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "test_eq(_pops_({'a': 1, 'b': 2, 'c': 3}, ['a', 'b']), {'a': 1, 'b': 2})\n", + "test_eq(_pops_({'a': 1, 'b': 2, 'c': 3}, ['d']), {})\n", + "test_eq(_pops_({'a': 1, 'b': 2, 'c': 3}, ['a', 'c', 'd']), {'a': 1, 'c': 3})\n", + "test_eq(_pops_({}, ['a']), {})\n", + "test_eq(_pops_({'a': 1}, ['a', 'a']), {'a': 1})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "def _pops_values_(d: dict, ks: Iterable) -> tuple:\n", + " \"Pops `ks` keys from `d` and returns them as a tuple. Note: `d` is changed in-place.\"\n", + " return tuple(d.pop(k, None) for k in ks)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "test_eq(_pops_values_({'a': 1, 'b': 2, 'c': 3}, ['a', 'b']), (1, 2))\n", + "test_eq(_pops_values_({'a': 1, 'b': 2, 'c': 3}, ['d']), (None,))\n", + "test_eq(_pops_values_({'a': 1, 'b': 2, 'c': 3}, ['a', 'c', 'd']), (1, 3, None))\n", + "test_eq(_pops_values_({}, ['a']), (None,))\n", + "test_eq(_pops_values_({'a': 1}, ['a', 'a']), (1, None))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "def _gets_(d: Mapping[str, Any], ks: Iterable):\n", + " \"Fetches values from a mapping for a given list of keys, returning `None` for missing keys.\"\n", + " return (d.get(k, None) for k in ks)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "test_eq(_gets_({'a': 1, 'b': 2}, ('a', 'c', 'b')), [1, None, 2])\n", + "test_eq(_gets_({'a': 1, 'b': 2}, ()), [])\n", + "a, b = _gets_({'a': 1, 'b': 2}, ('b', 'a'))\n", + "test_eq((a, b), (2, 1))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## cleanupwidget\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "def _get_globals(mod: str):\n", + " if hasattr(sys, '_getframe'):\n", + " glb = sys._getframe(2).f_globals\n", + " else:\n", + " glb = sys.modules[mod].__dict__\n", + " return glb\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# _all_ = ['_get_globals']\n", + "def _gtest():\n", + " return _get_globals(__name__)\n", + "g1 = _gtest()\n", + "g2 = globals()\n", + "test_eq(g1, g2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "def cleanupwidgets(*ws, mod: str|None=None, clear=True):\n", + " glb = _get_globals(mod or __name__)\n", + " if clear: clear_output(wait=True)\n", + " for w in ws:\n", + " _w = glb.get(w) if isinstance(w, str) else w\n", + " if _w:\n", + " try: _w.close() # type: ignore\n", + " except: pass\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "_b = W.Button()\n", + "test_ne(_b.comm, None)\n", + "cleanupwidgets('_b')\n", + "test_is(_b.comm, None)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Collapsable JSON in a notebook cell" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "class RenderJSON(object):\n", + " def __init__(self, json_data, max_height=200, init_level=0):\n", + " if isinstance(json_data, (Sequence, Mapping)):\n", + " s = json.dumps(json_data)\n", + " elif hasattr(json_data, 'to_dict'):\n", + " s = json.dumps(json_data.to_dict())\n", + " elif hasattr(json_data, 'to_json'):\n", + " s = json_data.to_json()\n", + " else:\n", + " s = json_data\n", + " self.json_str = s\n", + " self.uuid = str(uuid.uuid4())\n", + " self.max_height = max_height\n", + " self.init_level = init_level\n", + "\n", + " def display(self):\n", + " html_content = f\"\"\"\n", + "
\n", + "
\n", + " \n", + "
\n", + " \"\"\"\n", + " display(HTML(html_content))\n", + "\n", + " def _ipython_display_(self):\n", + " self.display()" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "json_data = {\n", + " \"name\": \"Petronila\",\n", + " \"age\": 28,\n", + " \"interests\": [\"reading\", \"cycling\", \"technology\"],\n", + " \"education\": {\n", + " \"bachelor\": \"Computer Science\",\n", + " \"master\": \"Data Science\",\n", + " \"phd\": \"Not enrolled\"\n", + " }\n", + "}\n", + "\n", + "RenderJSON(json_data, init_level=1).display()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize boxes on the page image\n", + "> adapted from `PageData.visualize` but returns the image instead of saving it." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def page_boxes(self: st.PageData, out_dir: Path | None = None) -> tuple[Image.Image, Path]:\n", + " \"\"\"\n", + " Visualize the boxes on an image.\n", + " Typically, this would be used to check where on the original image the\n", + " boxes are located.\n", + "\n", + " :param image_path: The path to the image to visualize the boxes on.\n", + " \"\"\"\n", + " image_path = Path(self.image_path)\n", + " image = Image.open(image_path)\n", + " draw = ImageDraw.Draw(image)\n", + " data_path = resources.files(pcleaner.data)\n", + " font_path = str(data_path / \"LiberationSans-Regular.ttf\")\n", + " # Figure out the optimal font size based on the image size. E.g. 30 for a 1600px image.\n", + " font_size = int(image.size[0] / 50) + 5\n", + "\n", + " for index, box in enumerate(self.boxes):\n", + " draw.rectangle(box.as_tuple, outline=\"green\")\n", + " # Draw the box number, with a white background, respecting font size.\n", + " draw.text(\n", + " (box.x1 + 4, box.y1),\n", + " str(index + 1),\n", + " fill=\"green\",\n", + " font=ImageFont.truetype(font_path, font_size),\n", + " stroke_fill=\"white\",\n", + " stroke_width=3,\n", + " )\n", + "\n", + " for box in self.extended_boxes:\n", + " draw.rectangle(box.as_tuple, outline=\"red\")\n", + " for box in self.merged_extended_boxes:\n", + " draw.rectangle(box.as_tuple, outline=\"purple\")\n", + " for box in self.reference_boxes:\n", + " draw.rectangle(box.as_tuple, outline=\"blue\")\n", + "\n", + " # Save the image.\n", + " extension = \"_boxes\"\n", + " out_path = image_path.with_stem(image_path.stem + extension)\n", + " if out_dir is not None:\n", + " out_dir.mkdir(parents=True, exist_ok=True)\n", + " out_path = out_dir / image_path.name\n", + " image.save(out_path)\n", + "\n", + " return image, out_path" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simple crop" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def crop_box(box: st.Box, image: Image.Image) -> Image.Image:\n", + " return image.crop(box.as_tuple)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Print size & resolution" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "PRINT_FORMATS = {\n", + " 'Golden Age': (7.75, 10.5), # (1930s-40s) \n", + " 'Siver Age': (7, 10.375), # (1950s-60s)\n", + " 'Modern Age': (6.625,10.25), # North American comic books\n", + " 'Magazine': (8.5, 11), \n", + " 'Digest': (5.5, 8.5), \n", + " 'Manga': (5.0, 7.5),\n", + "}\n", + "\n", + "\n", + "def size(w: int, h: int, unit: str = 'in', dpi: float = 300.) -> tuple:\n", + " \"\"\"\n", + " Calculate the print size of an image in inches or centimeters.\n", + "\n", + " Args:\n", + " w (int): Width of the image in pixels.\n", + " h (int): Height of the image in pixels.\n", + " unit (str): Unit of measurement ('in' for inches, 'cm' for centimeters).\n", + " dpi (float): Dots per inch (resolution).\n", + "\n", + " Returns:\n", + " tuple: Width and height of the image in the specified unit.\n", + " \"\"\"\n", + " if unit == 'cm':\n", + " return (w / dpi * 2.54, h / dpi * 2.54)\n", + " else: # default to inches\n", + " return (w / dpi, h / dpi)\n", + "\n", + "\n", + "def dpi(w: int, h: int, print_format: str = 'Modern Age') -> float:\n", + " \"\"\"\n", + " Calculate the dpi (dots per inch) needed to print an image at a specified format size.\n", + "\n", + " Args:\n", + " w (int): Width of the image in pixels.\n", + " h (int): Height of the image in pixels.\n", + " print_format (str): Print format as defined in the formats dictionary.\n", + "\n", + " Returns:\n", + " float: Required dpi to achieve the desired print format size.\n", + " \"\"\"\n", + " # Default to 'Modern Age' if format not found\n", + " format_size = PRINT_FORMATS.get(print_format, PRINT_FORMATS['Modern Age'])\n", + " width_inch, height_inch = format_size\n", + " dpi_w = w / width_inch\n", + " dpi_h = h / height_inch\n", + " return (dpi_w + dpi_h) / 2 # Average dpi for width and height\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Show images and texts on HTML tables" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def get_image_html(image: Image.Image | Path | str, max_width: int | None = None):\n", + " \"\"\"\n", + " Converts a PIL image to an HTML image tag containing the image as a base64 blob.\n", + "\n", + " :param image: A PIL Image object.\n", + " :param max_size: A PIL Image object.\n", + " :return: A string containing an HTML tag with the image.\n", + " \"\"\"\n", + " style = f' style=\"max-width: {max_width}px;\"' if max_width is not None else ''\n", + " if isinstance(image, (Path, str)):\n", + " return f''\n", + " else:\n", + " buffered = BytesIO()\n", + " image.save(buffered, format='PNG')\n", + " img_str = base64.b64encode(buffered.getvalue()).decode()\n", + " return f''\n", + "\n", + "\n", + "def get_columns_html(\n", + " columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None\n", + "):\n", + " if not all(len(col) == len(columns[0]) for col in columns):\n", + " raise ValueError(\"All columns must have the same length.\")\n", + "\n", + " # Calculate the maximum width of images in each column\n", + " max_widths = []\n", + " for col_index in range(len(columns)):\n", + " max_col_width = 0\n", + " for item in columns[col_index]:\n", + " if isinstance(item, (Image.Image, Path)):\n", + " if isinstance(item, (Path, str)):\n", + " item = Image.open(item)\n", + " width, _ = item.size\n", + " max_col_width = max(max_col_width, width)\n", + " if max_col_width > 0:\n", + " max_widths.append(\n", + " f\"{min(max_col_width, max_image_width)}px\"\n", + " if max_image_width is not None else \n", + " f\"{max_col_width}px\"\n", + " )\n", + " else:\n", + " max_widths.append('auto')\n", + "\n", + " html_str = \"\"\n", + "\n", + " # Apply calculated column widths using and elements\n", + " html_str += \"\"\n", + " for width in max_widths:\n", + " html_str += f\"\"\n", + " html_str += \"\"\n", + "\n", + " if headers:\n", + " if len(headers) != len(columns):\n", + " raise ValueError(\"Headers list must match the number of columns.\")\n", + " html_str += (\n", + " \"\"\n", + " + \"\".join(\n", + " f\"\"\n", + " for header in headers\n", + " )\n", + " + \"\"\n", + " )\n", + "\n", + " for row_items in zip(*columns):\n", + " html_str += \"\"\n", + " for i, item in enumerate(row_items):\n", + " if isinstance(item, (Image.Image, Path)):\n", + " img_html = get_image_html(item, max_width=max_image_width)\n", + " html_str += f\"\"\n", + " else: # Assume the item is a string\n", + " style = \"font-weight: bold;\" if i == 0 else \"\"\n", + " html_str += f\"\"\n", + " html_str += \"\"\n", + "\n", + " html_str += \"
{header}
{img_html}{item}
\"\n", + " return html_str\n", + "\n", + "\n", + "def display_columns(\n", + " columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None\n", + "):\n", + " \"\"\"\n", + " Displays a table with any combination of columns, which can be lists of strings or lists \n", + " of PIL Image objects, within a Jupyter notebook cell.\n", + "\n", + " :param columns: A list of lists, where each sublist represents a column in the table. \n", + " Each sublist can contain either strings or PIL Image objects.\n", + " :param max_image_width: The maximum size of the images in pixels. This controls the max-height \n", + " of the images.\n", + " :param headers: A list of header labels for the table. If None, no headers are displayed.\n", + " \"\"\"\n", + " return display(HTML(get_columns_html(columns, max_image_width, headers)))\n", + "\n", + "\n", + "def get_image_grid_html(\n", + " images: list[Image.Image | Path | str],\n", + " rows: int,\n", + " columns: int,\n", + " titles: list[str] | None = None,\n", + " max_image_width: int | None = None,\n", + " caption: str | None = None\n", + "):\n", + " if titles and len(titles) != len(images):\n", + " raise ValueError(\"Titles list must match the number of images if provided.\")\n", + "\n", + " html_str = \"\"\n", + "\n", + " if caption:\n", + " html_str += (f\"\")\n", + "\n", + " image_index = 0\n", + " for row in range(rows):\n", + " html_str += \"\"\n", + " for col in range(columns):\n", + " if image_index < len(images):\n", + " img_html = get_image_html(images[image_index], max_width=max_image_width)\n", + " title_html = (\n", + " f\"
{titles[image_index]}
\"\n", + " if titles\n", + " else \"\"\n", + " )\n", + " html_str += f\"\"\n", + " else:\n", + " html_str += \"\" # Empty cell if no more images\n", + " image_index += 1\n", + " html_str += \"\"\n", + "\n", + " html_str += \"
{caption}
{title_html}{img_html}
\"\n", + " return html_str\n", + "\n", + "\n", + "def display_image_grid(\n", + " images: list[Image.Image | Path | str],\n", + " rows: int,\n", + " columns: int,\n", + " titles: list[str] | None = None,\n", + " max_image_width: int | None = None,\n", + " caption: str | None = None,\n", + "):\n", + " \"\"\"\n", + " Displays a grid of images in a HTML table within a Jupyter notebook cell.\n", + "\n", + " :param images: A list of PIL Image objects to be displayed.\n", + " :param rows: The number of rows in the grid.\n", + " :param columns: The number of columns in the grid.\n", + " :param titles: An optional list of titles for each image. If provided, it must match the length \n", + " of the images list.\n", + " :param max_image_width: The maximum width of the images in pixels.\n", + " \"\"\"\n", + " display(HTML(get_image_grid_html(images, rows, columns, titles, max_image_width, caption)))\n", + "\n", + "\n", + "def acc_as_html(acc):\n", + " return f\"
{acc:.2f}
\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## UUIDs" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def strip_uuid(p: Path | str):\n", + " _p: Path = p if isinstance(p, Path) else Path(p)\n", + " new_stem = re.sub(r'(?i)[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}', '', _p.stem).strip('_')\n", + " return _p.with_stem(new_stem)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Path('a/b/c/Strange Tales 172_boxes.png')" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "strip_uuid(Path(\"a/b/c/ac265dc1-51a0-46ca-9101-7195cbad33f2_Strange Tales 172_boxes.png\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Other" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "# Deep copy a defaultdict of defaultdicts to a dict of dicts if it is not already a dict\n", + "def defaultdict_to_dict(d) -> dict:\n", + " if not isinstance(d, defaultdict):\n", + " return d\n", + " return {k: defaultdict_to_dict(v) for k, v in d.items()}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "aaa\n" + ] + } + ], + "source": [ + "print('aaa')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Colophon\n", + "----\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "from nbdev.export import nb_export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_NOTEBOOK:\n", + " nb_export('helpers.ipynb', '.')\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/_testbed/helpers.py b/_testbed/helpers.py new file mode 100644 index 00000000..a7095701 --- /dev/null +++ b/_testbed/helpers.py @@ -0,0 +1,372 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: helpers.ipynb. + +# %% helpers.ipynb 7 +from __future__ import annotations + +import base64 +import json +import re +import sys +import uuid +from importlib import resources +from io import BytesIO +from pathlib import Path +from typing import Any +from typing import Iterable +from typing import Mapping +from typing import Sequence + +import pcleaner.data +import pcleaner.structures as st +from IPython.display import clear_output +from IPython.display import display +from IPython.display import HTML +from PIL import Image +from PIL import ImageDraw +from PIL import ImageFont + + +# %% auto 0 +__all__ = ['PRINT_FORMATS', 'cleanupwidgets', 'RenderJSON', 'page_boxes', 'crop_box', 'size', 'dpi', 'get_image_html', + 'get_columns_html', 'display_columns', 'get_image_grid_html', 'display_image_grid', 'acc_as_html', + 'strip_uuid', '_pops_', '_pops_values_', '_gets_'] + +# %% helpers.ipynb 13 +_all_ = ['_pops_', '_pops_values_', '_gets_'] + + +# %% helpers.ipynb 14 +def _pops_(d: dict, ks: Iterable) -> dict: + "Pops `ks` keys from `d` and returns them in a dict. Note: `d` is changed in-place." + return {k:d.pop(k) for k in ks if k in d} + + +# %% helpers.ipynb 16 +def _pops_values_(d: dict, ks: Iterable) -> tuple: + "Pops `ks` keys from `d` and returns them as a tuple. Note: `d` is changed in-place." + return tuple(d.pop(k, None) for k in ks) + + +# %% helpers.ipynb 18 +def _gets_(d: Mapping[str, Any], ks: Iterable): + "Fetches values from a mapping for a given list of keys, returning `None` for missing keys." + return (d.get(k, None) for k in ks) + + +# %% helpers.ipynb 21 +def _get_globals(mod: str): + if hasattr(sys, '_getframe'): + glb = sys._getframe(2).f_globals + else: + glb = sys.modules[mod].__dict__ + return glb + + +# %% helpers.ipynb 23 +def cleanupwidgets(*ws, mod: str|None=None, clear=True): + glb = _get_globals(mod or __name__) + if clear: clear_output(wait=True) + for w in ws: + _w = glb.get(w) if isinstance(w, str) else w + if _w: + try: _w.close() # type: ignore + except: pass + + +# %% helpers.ipynb 26 +class RenderJSON(object): + def __init__(self, json_data, max_height=200, init_level=0): + if isinstance(json_data, (Sequence, Mapping)): + s = json.dumps(json_data) + elif hasattr(json_data, 'to_dict'): + s = json.dumps(json_data.to_dict()) + elif hasattr(json_data, 'to_json'): + s = json_data.to_json() + else: + s = json_data + self.json_str = s + self.uuid = str(uuid.uuid4()) + self.max_height = max_height + self.init_level = init_level + + def display(self): + html_content = f""" +
+
+ +
+ """ + display(HTML(html_content)) + + def _ipython_display_(self): + self.display() + +# %% helpers.ipynb 29 +def page_boxes(self: st.PageData, out_dir: Path | None = None) -> tuple[Image.Image, Path]: + """ + Visualize the boxes on an image. + Typically, this would be used to check where on the original image the + boxes are located. + + :param image_path: The path to the image to visualize the boxes on. + """ + image_path = Path(self.image_path) + image = Image.open(image_path) + draw = ImageDraw.Draw(image) + data_path = resources.files(pcleaner.data) + font_path = str(data_path / "LiberationSans-Regular.ttf") + # Figure out the optimal font size based on the image size. E.g. 30 for a 1600px image. + font_size = int(image.size[0] / 50) + 5 + + for index, box in enumerate(self.boxes): + draw.rectangle(box.as_tuple, outline="green") + # Draw the box number, with a white background, respecting font size. + draw.text( + (box.x1 + 4, box.y1), + str(index + 1), + fill="green", + font=ImageFont.truetype(font_path, font_size), + stroke_fill="white", + stroke_width=3, + ) + + for box in self.extended_boxes: + draw.rectangle(box.as_tuple, outline="red") + for box in self.merged_extended_boxes: + draw.rectangle(box.as_tuple, outline="purple") + for box in self.reference_boxes: + draw.rectangle(box.as_tuple, outline="blue") + + # Save the image. + extension = "_boxes" + out_path = image_path.with_stem(image_path.stem + extension) + if out_dir is not None: + out_dir.mkdir(parents=True, exist_ok=True) + out_path = out_dir / image_path.name + image.save(out_path) + + return image, out_path + +# %% helpers.ipynb 31 +def crop_box(box: st.Box, image: Image.Image) -> Image.Image: + return image.crop(box.as_tuple) + +# %% helpers.ipynb 33 +PRINT_FORMATS = { + 'Golden Age': (7.75, 10.5), # (1930s-40s) + 'Siver Age': (7, 10.375), # (1950s-60s) + 'Modern Age': (6.625,10.25), # North American comic books + 'Magazine': (8.5, 11), + 'Digest': (5.5, 8.5), + 'Manga': (5.0, 7.5), +} + + +def size(w: int, h: int, unit: str = 'in', dpi: float = 300.) -> tuple: + """ + Calculate the print size of an image in inches or centimeters. + + Args: + w (int): Width of the image in pixels. + h (int): Height of the image in pixels. + unit (str): Unit of measurement ('in' for inches, 'cm' for centimeters). + dpi (float): Dots per inch (resolution). + + Returns: + tuple: Width and height of the image in the specified unit. + """ + if unit == 'cm': + return (w / dpi * 2.54, h / dpi * 2.54) + else: # default to inches + return (w / dpi, h / dpi) + + +def dpi(w: int, h: int, print_format: str = 'Modern Age') -> float: + """ + Calculate the dpi (dots per inch) needed to print an image at a specified format size. + + Args: + w (int): Width of the image in pixels. + h (int): Height of the image in pixels. + print_format (str): Print format as defined in the formats dictionary. + + Returns: + float: Required dpi to achieve the desired print format size. + """ + # Default to 'Modern Age' if format not found + format_size = PRINT_FORMATS.get(print_format, PRINT_FORMATS['Modern Age']) + width_inch, height_inch = format_size + dpi_w = w / width_inch + dpi_h = h / height_inch + return (dpi_w + dpi_h) / 2 # Average dpi for width and height + + +# %% helpers.ipynb 35 +def get_image_html(image: Image.Image | Path | str, max_width: int | None = None): + """ + Converts a PIL image to an HTML image tag containing the image as a base64 blob. + + :param image: A PIL Image object. + :param max_size: A PIL Image object. + :return: A string containing an HTML tag with the image. + """ + style = f' style="max-width: {max_width}px;"' if max_width is not None else '' + if isinstance(image, (Path, str)): + return f'' + else: + buffered = BytesIO() + image.save(buffered, format='PNG') + img_str = base64.b64encode(buffered.getvalue()).decode() + return f'' + + +def get_columns_html( + columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None +): + if not all(len(col) == len(columns[0]) for col in columns): + raise ValueError("All columns must have the same length.") + + # Calculate the maximum width of images in each column + max_widths = [] + for col_index in range(len(columns)): + max_col_width = 0 + for item in columns[col_index]: + if isinstance(item, (Image.Image, Path)): + if isinstance(item, (Path, str)): + item = Image.open(item) + width, _ = item.size + max_col_width = max(max_col_width, width) + if max_col_width > 0: + max_widths.append( + f"{min(max_col_width, max_image_width)}px" + if max_image_width is not None else + f"{max_col_width}px" + ) + else: + max_widths.append('auto') + + html_str = "" + + # Apply calculated column widths using and elements + html_str += "" + for width in max_widths: + html_str += f"" + html_str += "" + + if headers: + if len(headers) != len(columns): + raise ValueError("Headers list must match the number of columns.") + html_str += ( + "" + + "".join( + f"" + for header in headers + ) + + "" + ) + + for row_items in zip(*columns): + html_str += "" + for i, item in enumerate(row_items): + if isinstance(item, (Image.Image, Path)): + img_html = get_image_html(item, max_width=max_image_width) + html_str += f"" + else: # Assume the item is a string + style = "font-weight: bold;" if i == 0 else "" + html_str += f"" + html_str += "" + + html_str += "
{header}
{img_html}{item}
" + return html_str + + +def display_columns( + columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None +): + """ + Displays a table with any combination of columns, which can be lists of strings or lists + of PIL Image objects, within a Jupyter notebook cell. + + :param columns: A list of lists, where each sublist represents a column in the table. + Each sublist can contain either strings or PIL Image objects. + :param max_image_width: The maximum size of the images in pixels. This controls the max-height + of the images. + :param headers: A list of header labels for the table. If None, no headers are displayed. + """ + return display(HTML(get_columns_html(columns, max_image_width, headers))) + + +def get_image_grid_html( + images: list[Image.Image | Path | str], + rows: int, + columns: int, + titles: list[str] | None = None, + max_image_width: int | None = None, + caption: str | None = None +): + if titles and len(titles) != len(images): + raise ValueError("Titles list must match the number of images if provided.") + + html_str = "" + + if caption: + html_str += (f"") + + image_index = 0 + for row in range(rows): + html_str += "" + for col in range(columns): + if image_index < len(images): + img_html = get_image_html(images[image_index], max_width=max_image_width) + title_html = ( + f"
{titles[image_index]}
" + if titles + else "" + ) + html_str += f"" + else: + html_str += "" # Empty cell if no more images + image_index += 1 + html_str += "" + + html_str += "
{caption}
{title_html}{img_html}
" + return html_str + + +def display_image_grid( + images: list[Image.Image | Path | str], + rows: int, + columns: int, + titles: list[str] | None = None, + max_image_width: int | None = None, + caption: str | None = None, +): + """ + Displays a grid of images in a HTML table within a Jupyter notebook cell. + + :param images: A list of PIL Image objects to be displayed. + :param rows: The number of rows in the grid. + :param columns: The number of columns in the grid. + :param titles: An optional list of titles for each image. If provided, it must match the length + of the images list. + :param max_image_width: The maximum width of the images in pixels. + """ + display(HTML(get_image_grid_html(images, rows, columns, titles, max_image_width, caption))) + + +def acc_as_html(acc): + return f"
{acc:.2f}
" + + +# %% helpers.ipynb 37 +def strip_uuid(p: Path | str): + _p: Path = p if isinstance(p, Path) else Path(p) + new_stem = re.sub(r'(?i)[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}', '', _p.stem).strip('_') + return _p.with_stem(new_stem) + diff --git a/_testbed/ocr_idefics.py b/_testbed/ocr_idefics.py new file mode 100644 index 00000000..67a50c42 --- /dev/null +++ b/_testbed/ocr_idefics.py @@ -0,0 +1,184 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: test_idefics.ipynb. + +# %% test_idefics.ipynb 12 +from __future__ import annotations + +import functools +from pathlib import Path + +import pcleaner.ocr.ocr as ocr +import torch +import transformers +from pcleaner.ocr.ocr_tesseract import TesseractOcr +from PIL import Image +from rich.console import Console +from transformers import AutoProcessor +from transformers import Idefics2ForConditionalGeneration +from transformers import PreTrainedModel + + +# %% auto 0 +__all__ = ['IdeficsOCR', 'IdeficsExperimentContext'] + +# %% test_idefics.ipynb 17 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% test_idefics.ipynb 20 +from experiments import * +from helpers import * +from ocr_metric import * + + +# %% test_idefics.ipynb 21 +def load_image(img_or_path) -> Image.Image: + if isinstance(img_or_path, (str, Path)): + return Image.open(img_or_path) + elif isinstance(img_or_path, Image.Image): + return img_or_path + else: + raise ValueError(f"img_or_path must be a path or PIL.Image, got: {type(img_or_path)}") + + +# %% test_idefics.ipynb 36 +processor = AutoProcessor.from_pretrained("HuggingFaceM4/idefics2-8b") + +# %% test_idefics.ipynb 37 +device = "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu" + +model = Idefics2ForConditionalGeneration.from_pretrained( + "HuggingFaceM4/idefics2-8b", + torch_dtype=torch.bfloat16, + _attn_implementation="flash_attention_2", + ).to(device) # type: ignore + + +# %% test_idefics.ipynb 39 +prompt_text_tmpl = ( + "Please perform optical character recognition (OCR) on this image, which displays " + "speech balloons from a comic book. The text is in {}. Extract the text and " + "format it as follows: transcribe in standard sentence case, avoid using all capital " + "letters. Provide the transcribed text clearly and double check the sentence is not all capital letters.") + +# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " +# f"speech balloons from a manga comic. The text is in {}. Extract the text and " +# "format it without newlines. Provide the transcribed text clearly.") + +# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " +# "speech balloons from a comic book. The text is in {}. Extract the text and " +# "format it as follows: transcribe in standard sentence case (avoid using all capital " +# "letters) and use asterisks to denote any words that appear in bold within the image. " +# "Provide the transcribed text clearly.") + +# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " +# "speech balloons from a comic book. The text is in {}. Extract the text and " +# "format it as follows: transcribe in standard sentence case, capitalized. Avoid using " +# "all capital letters. In comics, it is common to use two hyphens '--' to interrupt a sentence. " +# "Retain any hyphens as they appear in the original text. Provide the transcribed text " +# "clearly, ensuring it is capitalized where appropriate, including proper nouns.") + +prompt_text_tmpl = ( + "Please perform optical character recognition (OCR) on this image, which displays " + "speech balloons from a comic book. The text is in {}. Extract the text and " + "format it as follows: transcribe in standard sentence case, capitalized. Avoid using " + "all capital letters, but ensure it is capitalized where appropriate, including proper nouns. " + "Provide the transcribed text clearly. Double check the text is not all capital letters.") + +default_prompt_text_tmpl = prompt_text_tmpl + +# %% test_idefics.ipynb 41 +class IdeficsOCR: + prompt_text_tmpl: str = default_prompt_text_tmpl + + def __init__(self, + lang: str | None = None, + prompt_text_tmpl: str|None = None, + device: str | None = None + ): + self.lang = lang + self.prompt_text_tmpl = prompt_text_tmpl or self.prompt_text_tmpl + self.device = (device or + "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu") + + @staticmethod + def is_idefics_available() -> bool: + return True + + def _generation_args(self, image: Image.Image, resulting_messages: list[dict]): + prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True) + inputs = processor(text=prompt, images=[image], return_tensors="pt") + inputs = {k: v.to(self.device) for k, v in inputs.items()} + + max_new_tokens = 512 + repetition_penalty = 1.2 + decoding_strategy = "Greedy" + temperature = 0.4 + top_p = 0.8 + + generation_args = { + "max_new_tokens": max_new_tokens, + "repetition_penalty": repetition_penalty, + } + + assert decoding_strategy in [ + "Greedy", + "Top P Sampling", + ] + + if decoding_strategy == "Greedy": + generation_args["do_sample"] = False + elif decoding_strategy == "Top P Sampling": + generation_args["temperature"] = temperature + generation_args["do_sample"] = True + generation_args["top_p"] = top_p + + generation_args.update(inputs) + return prompt, generation_args + + def __call__( + self, + img_or_path: Image.Image | Path | str, + prompt_text: str | None = None, + lang: str | None = None, + config: str | None = None, + show_prompt: bool = False, + **kwargs, + ) -> str: + if not self.is_idefics_available(): + raise RuntimeError("Idefics is not installed or not found.") + resulting_messages = [ + { + "role": "user", + "content": [{"type": "image"}] + [ + {"type": "text", "text": prompt_text or self.prompt_text_tmpl.format(lang or self.lang)} + ] + } + ] + image = load_image(img_or_path) + prompt, generation_args = self._generation_args(image, resulting_messages) + generated_ids = model.generate(**generation_args) + generated_texts = processor.batch_decode( + generated_ids[:, generation_args["input_ids"].size(1):], skip_special_tokens=True) + if show_prompt: + cprint("INPUT:", prompt, "|OUTPUT:", generated_texts) + return generated_texts[0]#.strip('"') + + def postprocess_ocr(self, text): + return ' '.join(remove_multiple_whitespaces(text).splitlines()) + + +# %% test_idefics.ipynb 43 +class IdeficsExperimentContext(OCRExperimentContext): + @functools.lru_cache() + def mocr(self, ocr_model: str, lang: str): + if ocr_model == 'Idefics': + proc = IdeficsOCR(lang) + else: + engine = self.engines[ocr_model] + ocr_processor = ocr.get_ocr_processor(True, engine) + proc = ocr_processor[lang2pcleaner(lang)] + if isinstance(proc, TesseractOcr): + proc.lang = lang2tesseract(lang) + return proc + diff --git a/_testbed/ocr_metric.ipynb b/_testbed/ocr_metric.ipynb new file mode 100644 index 00000000..41f2fad4 --- /dev/null +++ b/_testbed/ocr_metric.ipynb @@ -0,0 +1,276 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#| default_exp ocr_metric" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "# %reload_ext autoreload\n", + "# %autoreload 0\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# try: \n", + "# import fastcore as FC\n", + "# except ImportError: \n", + "# !pip install -q fastcore\n", + "# try:\n", + "# import rich\n", + "# except ImportError:\n", + "# !pip install -q rich\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Developing a metric for OCR of Comics/Manga texts\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "from __future__ import annotations\n", + "\n", + "import difflib\n", + "import html\n", + "\n", + "from IPython.display import display\n", + "from IPython.display import HTML\n", + "from rich.console import Console\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "import fastcore.xtras # patch Path with some utils\n", + "import rich\n", + "from fastcore.test import * # type: ignore\n", + "from loguru import logger\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# pretty print by default\n", + "# %load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "console = Console(width=104, tab_size=4, force_jupyter=True)\n", + "cprint = console.print\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OCR metric\n", + "> Some basic ways to compare OCR results" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def get_text_diffs_html(str1, str2, ignore_align: bool = False):\n", + " matcher = difflib.SequenceMatcher(None, str1, str2)\n", + " html_str1, html_str2 = \"\", \"\"\n", + " _ch ='⎕' # ▿\n", + " ch = f'&#x{ord(_ch):x};'\n", + " span1_g = lambda l: f\"{ch*l}\" if l > 0 else \"\"\n", + " span1_r = lambda l: f\"{ch*l}\" if l > 0 else \"\"\n", + " span2 = lambda s: f\"{html.escape(s)}\" if s else \"\"\n", + "\n", + " for opcode in matcher.get_opcodes():\n", + " tag, i1, i2, j1, j2 = opcode\n", + " if tag == \"equal\":\n", + " html_str1 += html.escape(str1[i1:i2])\n", + " html_str2 += html.escape(str2[j1:j2])\n", + " elif tag == \"replace\":\n", + " max_span = max(i2 - i1, j2 - j1)\n", + " # str1_segment = str1[i1:i2].ljust(max_span)\n", + " html_str1 += html.escape(str1[i1:i2]) + span1_g(max_span - (i2 - i1))\n", + " html_str2 += span2(str2[j1:j2]) + (span1_r(max_span - (j2 - j1)) if not ignore_align else '')\n", + " elif tag == \"delete\":\n", + " deleted_segment = str1[i1:i2]\n", + " html_str1 += html.escape(deleted_segment)\n", + " if not ignore_align: html_str2 += span1_r(len(deleted_segment))\n", + " elif tag == \"insert\":\n", + " inserted_segment = str2[j1:j2].replace(\" \", _ch)\n", + " html_str1 += span1_g(len(inserted_segment))\n", + " html_str2 += span2(inserted_segment)\n", + " html_str1 = f\"
{html_str1}
\"\n", + " html_str2 = f\"
{html_str2}
\"\n", + " return html_str1, html_str2\n", + "\n", + "def display_text_diffs(str1, str2):\n", + " \"\"\"\n", + " Displays two strings one above the other, with differing characters highlighted in red in the \n", + " second string only, using difflib.SequenceMatcher to align the strings and ensure matching \n", + " sequences are vertically aligned.\n", + "\n", + " :param str1: The first string to compare.\n", + " :param str2: The second string to compare.\n", + " \"\"\"\n", + " html_str1, html_str2 = get_text_diffs_html(str1, str2)\n", + " display(HTML(f\"
{html_str1}
{html_str2}
\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
This is an awesome_⎕⎕⎕ test string.This is an awesome_⎕⎕⎕ test string.This is an awesome_⎕⎕⎕ test string.This is an awesome_⎕⎕⎕ test string.

This was an a⎕⎕⎕⎕mazing test spring.This was an a⎕⎕⎕⎕mazing test spring.This was an a⎕⎕⎕⎕mazing test spring.This was an a⎕⎕⎕⎕mazing test spring.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "str1 = \"This is an awesome_ test string.\"*4\n", + "str2 = \"This was an amazing test▿ spring.\"*4\n", + "display_text_diffs(str1, str2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
I was in a bad mood, and Curt sensed it immediately...

I was in a bad mood, and Curt sensed it immediately...
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "str1 = \"I was in a bad mood, and Curt sensed it immediately...\"\n", + "str2 = \"I was in a bad mood, and Curt sensed it immediately ...\"\n", + "display_text_diffs(str1, str2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Colophon\n", + "----\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "from nbdev.export import nb_export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_NOTEBOOK:\n", + " nb_export('ocr_metric.ipynb', '.')\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/_testbed/ocr_metric.py b/_testbed/ocr_metric.py new file mode 100644 index 00000000..f81b9a5e --- /dev/null +++ b/_testbed/ocr_metric.py @@ -0,0 +1,64 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ocr_metric.ipynb. + +# %% ocr_metric.ipynb 6 +from __future__ import annotations + +import difflib +import html + +from IPython.display import display +from IPython.display import HTML +from rich.console import Console + + +# %% auto 0 +__all__ = ['get_text_diffs_html', 'display_text_diffs'] + +# %% ocr_metric.ipynb 10 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% ocr_metric.ipynb 12 +def get_text_diffs_html(str1, str2, ignore_align: bool = False): + matcher = difflib.SequenceMatcher(None, str1, str2) + html_str1, html_str2 = "", "" + _ch ='⎕' # ▿ + ch = f'&#x{ord(_ch):x};' + span1_g = lambda l: f"{ch*l}" if l > 0 else "" + span1_r = lambda l: f"{ch*l}" if l > 0 else "" + span2 = lambda s: f"{html.escape(s)}" if s else "" + + for opcode in matcher.get_opcodes(): + tag, i1, i2, j1, j2 = opcode + if tag == "equal": + html_str1 += html.escape(str1[i1:i2]) + html_str2 += html.escape(str2[j1:j2]) + elif tag == "replace": + max_span = max(i2 - i1, j2 - j1) + # str1_segment = str1[i1:i2].ljust(max_span) + html_str1 += html.escape(str1[i1:i2]) + span1_g(max_span - (i2 - i1)) + html_str2 += span2(str2[j1:j2]) + (span1_r(max_span - (j2 - j1)) if not ignore_align else '') + elif tag == "delete": + deleted_segment = str1[i1:i2] + html_str1 += html.escape(deleted_segment) + if not ignore_align: html_str2 += span1_r(len(deleted_segment)) + elif tag == "insert": + inserted_segment = str2[j1:j2].replace(" ", _ch) + html_str1 += span1_g(len(inserted_segment)) + html_str2 += span2(inserted_segment) + html_str1 = f"
{html_str1}
" + html_str2 = f"
{html_str2}
" + return html_str1, html_str2 + +def display_text_diffs(str1, str2): + """ + Displays two strings one above the other, with differing characters highlighted in red in the + second string only, using difflib.SequenceMatcher to align the strings and ensure matching + sequences are vertically aligned. + + :param str1: The first string to compare. + :param str2: The second string to compare. + """ + html_str1, html_str2 = get_text_diffs_html(str1, str2) + display(HTML(f"
{html_str1}
{html_str2}
")) diff --git a/_testbed/requirements.txt b/_testbed/requirements.txt new file mode 100644 index 00000000..4e3d1c68 --- /dev/null +++ b/_testbed/requirements.txt @@ -0,0 +1,5 @@ +matplotlib +rich +fastcore +nbdev +ipywidgets diff --git a/_testbed/test_idefics.ipynb b/_testbed/test_idefics.ipynb new file mode 100644 index 00000000..a8978d12 --- /dev/null +++ b/_testbed/test_idefics.ipynb @@ -0,0 +1,1497 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#| default_exp ocr_idefics" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "# %reload_ext autoreload\n", + "# %autoreload 0\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# try: \n", + "# import fastcore as FC\n", + "# except ImportError: \n", + "# !pip install -q fastcore\n", + "# try:\n", + "# import rich\n", + "# except ImportError:\n", + "# !pip install -q rich\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@basic-tesseract" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "need version >4.40 of transformers" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install git+https://github.com/huggingface/transformers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Fash attention doesn't support Metal [#412](https://github.com/Dao-AILab/flash-attention/issues/412) (but see [metal-flash-attention](https://github.com/philipturner/metal-flash-attention))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# %env FLASH_ATTENTION_SKIP_CUDA_BUILD=TRUE\n", + "# %pip install flash-attn --no-build-isolation" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "notebookRunGroups": { + "groupValue": "" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fri May 10 18:32:10 2024 \n", + "+---------------------------------------------------------------------------------------+\n", + "| NVIDIA-SMI 535.161.08 Driver Version: 535.161.08 CUDA Version: 12.2 |\n", + "|-----------------------------------------+----------------------+----------------------+\n", + "| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n", + "| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n", + "| | | MIG M. |\n", + "|=========================================+======================+======================|\n", + "| 0 NVIDIA GeForce RTX 3090 Ti On | 00000000:65:00.0 Off | Off |\n", + "| 0% 50C P8 33W / 480W | 1MiB / 24564MiB | 0% Default |\n", + "| | | N/A |\n", + "+-----------------------------------------+----------------------+----------------------+\n", + " \n", + "+---------------------------------------------------------------------------------------+\n", + "| Processes: |\n", + "| GPU GI CI PID Type Process name GPU Memory |\n", + "| ID ID Usage |\n", + "|=======================================================================================|\n", + "| No running processes found |\n", + "+---------------------------------------------------------------------------------------+\n" + ] + } + ], + "source": [ + "!nvidia-smi" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `Idefics` OCR for Comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "from __future__ import annotations\n", + "\n", + "import functools\n", + "from pathlib import Path\n", + "\n", + "import pcleaner.ocr.ocr as ocr\n", + "import torch\n", + "import transformers\n", + "from pcleaner.ocr.ocr_tesseract import TesseractOcr\n", + "from PIL import Image\n", + "from rich.console import Console\n", + "from transformers import AutoProcessor\n", + "from transformers import Idefics2ForConditionalGeneration\n", + "from transformers import PreTrainedModel\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "from typing import cast\n", + "\n", + "import fastcore.xtras # patch Path with some utils\n", + "import pcleaner.config as cfg\n", + "from fastcore.test import * # type: ignore\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "notebookRunGroups": { + "groupValue": "" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'4.41.0.dev0'" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "transformers.__version__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "notebookRunGroups": { + "groupValue": "" + } + }, + "outputs": [], + "source": [ + "# pretty print by default\n", + "# %load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "notebookRunGroups": { + "groupValue": "" + } + }, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "console = Console(width=104, tab_size=4, force_jupyter=True)\n", + "cprint = console.print\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Force reload of `experiments` module" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "if 'experiments' in sys.modules:\n", + " import importlib; importlib.reload(experiments) # type: ignore\n", + "else:\n", + " import experiments\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "from experiments import *\n", + "from helpers import *\n", + "from ocr_metric import *\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "def load_image(img_or_path) -> Image.Image:\n", + " if isinstance(img_or_path, (str, Path)):\n", + " return Image.open(img_or_path)\n", + " elif isinstance(img_or_path, Image.Image):\n", + " return img_or_path\n", + " else:\n", + " raise ValueError(f\"img_or_path must be a path or PIL.Image, got: {type(img_or_path)}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Idefics basic usage\n", + "\n", + "not working, cuda memory error" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# # Note that passing the image urls (instead of the actual pil images) to the processor is also possible\n", + "# # image1 = load_image(\"https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg\")\n", + "# # image2 = load_image(\"https://cdn.britannica.com/59/94459-050-DBA42467/Skyline-Chicago.jpg\")\n", + "# # image3 = load_image(\"https://cdn.britannica.com/68/170868-050-8DDE8263/Golden-Gate-Bridge-San-Francisco.jpg\")\n", + "\n", + "# image1 = Image.open(\"media/Statue-of-Liberty-Island-New-York-Bay.webp\")\n", + "# image2 = Image.open(\"media/Skyline-Chicago.webp\")\n", + "# image3 = Image.open(\"media/Golden-Gate-Bridge-San-Francisco.webp\")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# processor = AutoProcessor.from_pretrained(\"HuggingFaceM4/idefics2-8b\")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# model = Idefics2ForConditionalGeneration.from_pretrained(\n", + "# \"HuggingFaceM4/idefics2-8b\",\n", + "# torch_dtype=torch.bfloat16,\n", + "# #_attn_implementation=\"flash_attention_2\",\n", + "# )\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "# assert isinstance(model, PreTrainedModel)\n", + "# model.to(DEVICE)\n", + "# type(model), model.device\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Create inputs" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "# messages = [\n", + "# {\n", + "# \"role\": \"user\",\n", + "# \"content\": [\n", + "# {\"type\": \"image\"},\n", + "# {\"type\": \"text\", \"text\": \"What do we see in this image?\"},\n", + "# ]\n", + "# },\n", + "# {\n", + "# \"role\": \"assistant\",\n", + "# \"content\": [\n", + "# {\"type\": \"text\", \"text\": \"In this image, we can see the city of New York, and more specifically the Statue of Liberty.\"},\n", + "# ]\n", + "# },\n", + "# {\n", + "# \"role\": \"user\",\n", + "# \"content\": [\n", + "# {\"type\": \"image\"},\n", + "# {\"type\": \"text\", \"text\": \"And how about this image?\"},\n", + "# ]\n", + "# }, \n", + "# ]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "# prompt = processor.apply_chat_template(messages, add_generation_prompt=True)\n", + "# inputs = processor(text=prompt, images=[image1, image2], return_tensors=\"pt\")\n", + "# inputs = {k: v.to(DEVICE) for k, v in inputs.items()}\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Generate" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "# generated_ids = model.generate(**inputs, max_new_tokens=500)\n", + "# generated_texts = processor.batch_decode(generated_ids, skip_special_tokens=True)\n", + "\n", + "# print(generated_texts)\n", + "# # ['User: What do we see in this image? \\nAssistant: In this image, we can see the city of New York, and more specifically the Statue of Liberty. \\nUser: And how about this image? \\nAssistant: In this image we can see buildings, trees, lights, water and sky.']\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "# [\n", + "# 'User: What do we see in this image? '\n", + "# 'Assistant: In this image, we can see the city of New York, and more specifically the Statue of Liberty. '\n", + "# 'User: And how about this image? '\n", + "# 'Assistant: In this image we can see buildings, trees, lights, water and sky.'\n", + "# ]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Idefics experiments\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Idefics" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Idefics initialization" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n" + ] + } + ], + "source": [ + "#| exporti\n", + "\n", + "processor = AutoProcessor.from_pretrained(\"HuggingFaceM4/idefics2-8b\")" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "You are attempting to use Flash Attention 2.0 with a model not initialized on GPU. Make sure to move the model to GPU after initializing it on CPU with `model.to('cuda')`.\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5a21b61268674a159f210694841c2149", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Loading checkpoint shards: 0%| | 0/7 [00:00 bool:\n", + " return True\n", + "\n", + " def _generation_args(self, image: Image.Image, resulting_messages: list[dict]):\n", + " prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True)\n", + " inputs = processor(text=prompt, images=[image], return_tensors=\"pt\")\n", + " inputs = {k: v.to(self.device) for k, v in inputs.items()}\n", + " \n", + " max_new_tokens = 512\n", + " repetition_penalty = 1.2\n", + " decoding_strategy = \"Greedy\"\n", + " temperature = 0.4\n", + " top_p = 0.8\n", + "\n", + " generation_args = {\n", + " \"max_new_tokens\": max_new_tokens,\n", + " \"repetition_penalty\": repetition_penalty,\n", + " }\n", + "\n", + " assert decoding_strategy in [\n", + " \"Greedy\",\n", + " \"Top P Sampling\",\n", + " ]\n", + "\n", + " if decoding_strategy == \"Greedy\":\n", + " generation_args[\"do_sample\"] = False\n", + " elif decoding_strategy == \"Top P Sampling\":\n", + " generation_args[\"temperature\"] = temperature\n", + " generation_args[\"do_sample\"] = True\n", + " generation_args[\"top_p\"] = top_p\n", + "\n", + " generation_args.update(inputs)\n", + " return prompt, generation_args\n", + "\n", + " def __call__(\n", + " self,\n", + " img_or_path: Image.Image | Path | str,\n", + " prompt_text: str | None = None,\n", + " lang: str | None = None,\n", + " config: str | None = None,\n", + " show_prompt: bool = False,\n", + " **kwargs,\n", + " ) -> str:\n", + " if not self.is_idefics_available():\n", + " raise RuntimeError(\"Idefics is not installed or not found.\")\n", + " resulting_messages = [\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": [{\"type\": \"image\"}] + [\n", + " {\"type\": \"text\", \"text\": prompt_text or self.prompt_text_tmpl.format(lang or self.lang)}\n", + " ]\n", + " }\n", + " ]\n", + " image = load_image(img_or_path)\n", + " prompt, generation_args = self._generation_args(image, resulting_messages)\n", + " generated_ids = model.generate(**generation_args)\n", + " generated_texts = processor.batch_decode(\n", + " generated_ids[:, generation_args[\"input_ids\"].size(1):], skip_special_tokens=True)\n", + " if show_prompt:\n", + " cprint(\"INPUT:\", prompt, \"|OUTPUT:\", generated_texts)\n", + " return generated_texts[0]#.strip('\"')\n", + "\n", + " def postprocess_ocr(self, text):\n", + " return ' '.join(remove_multiple_whitespaces(text).splitlines())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## IdeficsExperimentContext" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class IdeficsExperimentContext(OCRExperimentContext):\n", + " @functools.lru_cache()\n", + " def mocr(self, ocr_model: str, lang: str):\n", + " if ocr_model == 'Idefics':\n", + " proc = IdeficsOCR(lang)\n", + " else:\n", + " engine = self.engines[ocr_model]\n", + " ocr_processor = ocr.get_ocr_processor(True, engine)\n", + " proc = ocr_processor[lang2pcleaner(lang)]\n", + " if isinstance(proc, TesseractOcr):\n", + " proc.lang = lang2tesseract(lang)\n", + " return proc\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PanelCleaner Configuration\n", + "> Adapt `PanelCleaner` `Config` current config to this notebook.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "config = cfg.load_config()\n", + "config.cache_dir = Path(\".\")\n", + "\n", + "cache_dir = config.get_cleaner_cache_dir()\n", + "\n", + "profile = config.current_profile\n", + "preprocessor_conf = profile.preprocessor\n", + "# Modify the profile to OCR all boxes.\n", + "# Make sure OCR is enabled.\n", + "preprocessor_conf.ocr_enabled = True\n", + "# Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", + "preprocessor_conf.ocr_max_size = 10**10\n", + "# Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", + "preprocessor_conf.suspicious_box_min_size = 10**10\n", + "# Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", + "preprocessor_conf.ocr_blacklist_pattern = \".*\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n", + "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "media_path = Path(\"media/\")\n", + "\n", + "IMAGE_PATHS = sorted(\n", + " [_ for _ in media_path.glob(\"*\") if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n", + "\n", + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CONTEXT\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /home/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- victmang: /home/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: System default\n", + "Cache Directory: .\n", + "Default Torch Model Path: /home/vic/.cache/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /home/vic/.cache/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /home/vic/.config/pcleaner/pcleanerrc\n", + "System default cache directory: /home/vic/.cache/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
      cache_dir: Path('cleaner')\n",
+       "     model_path: Path('/home/vic/.cache/pcleaner/model/comictextdetector.pt')\n",
+       "         device: 'cuda'\n",
+       "
\n" + ], + "text/plain": [ + " cache_dir: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'cleaner'\u001b[0m\u001b[1m)\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/home/vic/.cache/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'cuda'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CONTEXT = IdeficsExperimentContext(None, IMAGE_PATHS)\n", + "\n", + "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + "model_path = CONTEXT.config.get_model_path(gpu)\n", + "DEVICE = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n", + "\n", + "CONTEXT.config.show()\n", + "cprint(\n", + " f\"{'cache_dir':>15}: {repr(cache_dir)}\\n\"\n", + " f\"{'model_path':>15}: {repr(model_path)}\\n\"\n", + " f\"{'device':>15}: {repr(DEVICE)}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base image\n", + "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", + "assert CONTEXT.path_from_idx(BASE_IMAGE_IDX).exists()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualize images\n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "IMAGE_CONTEXT = ImageContext(CONTEXT, BASE_IMAGE_IDX)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "9c0379d4776a4e0f9facd7e0092c79f3", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output(layout=Layout(height='0px'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5f0ae88943a14ea38efb029c40183ffd", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "26c6ecdbae6f4952aab7ff3106400f04", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "img_visor = ImageContextVisor(CONTEXT, BASE_IMAGE_IDX)\n", + "img_visor\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Box id\n", + "> change `BOX_IDX` to use any box to test crop methods" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "BOX_IDX = 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Idefics inference" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "page_lang = IMAGE_CONTEXT.page_lang\n", + "\n", + "resulting_messages = [\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": [{\"type\": \"image\"}] + [\n", + " {\"type\": \"text\", \"text\": prompt_text_tmpl.format(page_lang)}\n", + " ]\n", + " }\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "def idefics_generation_args(image: Image.Image, resulting_messages: list[dict]):\n", + " prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True)\n", + " inputs = processor(text=prompt, images=[image], return_tensors=\"pt\")\n", + " inputs = {k: v.to(DEVICE) for k, v in inputs.items()}\n", + " \n", + " max_new_tokens = 512\n", + " repetition_penalty = 1.2\n", + " decoding_strategy = \"Greedy\"\n", + " temperature = 0.4\n", + " top_p = 0.8\n", + "\n", + " generation_args = {\n", + " \"max_new_tokens\": max_new_tokens,\n", + " \"repetition_penalty\": repetition_penalty,\n", + " }\n", + "\n", + " assert decoding_strategy in [\n", + " \"Greedy\",\n", + " \"Top P Sampling\",\n", + " ]\n", + "\n", + " if decoding_strategy == \"Greedy\":\n", + " generation_args[\"do_sample\"] = False\n", + " elif decoding_strategy == \"Top P Sampling\":\n", + " generation_args[\"temperature\"] = temperature\n", + " generation_args[\"do_sample\"] = True\n", + " generation_args[\"top_p\"] = top_p\n", + "\n", + " generation_args.update(inputs)\n", + " return prompt, generation_args\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Crop methods" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "# image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Idefics')\n", + "image_experiment = ExperimentOCR.from_image(CONTEXT, 'Idefics', IMAGE_CONTEXT.image_idx) # use cache\n" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [], + "source": [ + "method = CropMethod.INITIAL_BOX\n", + "\n", + "result = cast(ResultOCR, image_experiment.result(BOX_IDX, method, ocr=False))\n", + "image = cast(Image.Image, result.image)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "No chat template is set for this tokenizer, falling back to a default class-level template. This is very error-prone, because models are often trained with templates different from the class default! Default chat templates are a legacy feature and will be removed in Transformers v4.43, at which point any code depending on them will stop working. We recommend setting a valid chat template before then to ensure that this model continues working without issues.\n", + "The `seen_tokens` attribute is deprecated and will be removed in v4.41. Use the `cache_position` model input instead.\n" + ] + }, + { + "data": { + "text/html": [ + "
INPUT: User:<image>Please perform optical character recognition (OCR) on this image, which displays \n",
+       "speech balloons from a comic book. The text is in English. Extract the text and format it as follows: \n",
+       "transcribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \n",
+       "capitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \n",
+       "check the text is not all capital letters.<end_of_utterance>\n",
+       "Assistant: |OUTPUT:\n",
+       "[\n",
+       "    'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \n",
+       "Orleans, kept tidy by a white-haired old man known only as Bambu.'\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "INPUT: User:\u001b[1m<\u001b[0m\u001b[1;95mimage\u001b[0m\u001b[39m>Please perform optical character recognition \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mOCR\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m on this image, which displays \u001b[0m\n", + "\u001b[39mspeech balloons from a comic book. The text is in English. Extract the text and format it as follows: \u001b[0m\n", + "\u001b[39mtranscribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \u001b[0m\n", + "\u001b[39mcapitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \u001b[0m\n", + "\u001b[39mcheck the text is not all capital letters.\u001b[0m\n", + "Assistant: |OUTPUT:\n", + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \u001b[0m\n", + "\u001b[32mOrleans, kept tidy by a white-haired old man known only as Bambu.'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "prompt, generation_args = idefics_generation_args(image, resulting_messages)\n", + "generated_ids = model.generate(**generation_args)\n", + "\n", + "generated_texts = processor.batch_decode(\n", + " generated_ids[:, generation_args[\"input_ids\"].size(1):], skip_special_tokens=True)\n", + "cprint(\"INPUT:\", prompt, \"|OUTPUT:\", generated_texts)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
1.00
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "result.ocr = generated_texts[0]\n", + "result\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
INPUT: User:<image>Please perform optical character recognition (OCR) on this image, which displays \n",
+       "speech balloons from a comic book. The text is in English. Extract the text and format it as follows: \n",
+       "transcribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \n",
+       "capitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \n",
+       "check the text is not all capital letters.<end_of_utterance>\n",
+       "Assistant: |OUTPUT:\n",
+       "[\n",
+       "    'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \n",
+       "Orleans, kept tidy by a white-haired old man known only as Bambu.'\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "INPUT: User:\u001b[1m<\u001b[0m\u001b[1;95mimage\u001b[0m\u001b[39m>Please perform optical character recognition \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mOCR\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m on this image, which displays \u001b[0m\n", + "\u001b[39mspeech balloons from a comic book. The text is in English. Extract the text and format it as follows: \u001b[0m\n", + "\u001b[39mtranscribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \u001b[0m\n", + "\u001b[39mcapitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \u001b[0m\n", + "\u001b[39mcheck the text is not all capital letters.\u001b[0m\n", + "Assistant: |OUTPUT:\n", + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \u001b[0m\n", + "\u001b[32mOrleans, kept tidy by a white-haired old man known only as Bambu.'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
1.00
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "method = CropMethod.INITIAL_BOX\n", + "\n", + "result = cast(ResultOCR, image_experiment.result(BOX_IDX, method, ocr=False))\n", + "image = cast(Image.Image, result.image)\n", + "\n", + "mocr: IdeficsOCR = cast(IdeficsOCR, CONTEXT.mocr('Idefics', page_lang))\n", + "text = mocr(image, show_prompt=True)\n", + "result.ocr = mocr.postprocess_ocr(text)\n", + "result\n" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
0.98
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PADDED_4)" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
0.94
\n", + "
\n", + "
Embow⎕⎕ered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Encountered by great charles cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_experiment.result(BOX_IDX, CropMethod.PAD_8_FRACT_0_2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Visualize results" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "522220949ff540fdbd864dc8d8722cf0", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output(layout=Layout(height='0px'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "13a3ec1b0ea04630b339e5026e01eee2", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Label(value='Box # (of 15):', layout=Layout(padding='0px 0px 0px 10px', width='i…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "989b4acac70848f2a5da0a74f99bc181", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "result_visor = ResultVisor(image_experiment)\n", + "result_visor\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Visualize Experiment" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [], + "source": [ + "# p, d = image_experiment.to_json()" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bae922f0f53b47b5909334ca7f5d24fc", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "9c8a0db76d0a40eb9c3451129e803124", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "exp_visor = ExperimentVisor(image_experiment)\n", + "exp_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "# p, d = exp_visor.ctx.to_json()\n", + "# p" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# EEAaO" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d441a9415ca94481a85523a6d30eca92", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(HBox(children=(Dropdown(index=1, layout=Layout(width='fit-content'), options={'T…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4f568a40794a4cba951fb6652b5446dd", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "idefics_experiment = ExperimentsVisor(CONTEXT, BASE_IMAGE_IDX, \n", + " box_idx=13, method=CropMethod.DEFAULT_GREY_PAD,\n", + " ocr_model=OCRModel.IDEFICS, \n", + " ocr_models={'Tesseract': OCRModel.TESSERACT, 'Idefics': OCRModel.IDEFICS})\n", + "idefics_experiment\n" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "idefics_experiment.update(model=OCRModel.TESSERACT)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Colophon\n", + "----\n" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "from nbdev.export import nb_export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_NOTEBOOK:\n", + " nb_export('test_idefics.ipynb', '.')\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "panel-cleaner", + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/_testbed/test_tesseract.ipynb b/_testbed/test_tesseract.ipynb new file mode 100644 index 00000000..3cb1dc79 --- /dev/null +++ b/_testbed/test_tesseract.ipynb @@ -0,0 +1,638 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# try: \n", + "# import fastcore as FC\n", + "# except ImportError: \n", + "# !pip install -q fastcore\n", + "# try:\n", + "# import rich\n", + "# except ImportError:\n", + "# !pip install -q rich\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `Tesseract` OCR for Comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "from pathlib import Path\n", + "from typing import cast\n", + "\n", + "import pcleaner.config as cfg\n", + "import torch\n", + "from rich.console import Console\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from experiments import *\n", + "from helpers import *\n", + "from ocr_metric import *\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.xtras # patch Path with some utils\n", + "from fastcore.test import * # type: ignore\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# pretty print by default\n", + "# %load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "console = Console(width=104, tab_size=4, force_jupyter=True)\n", + "cprint = console.print\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tesseract installation" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['tesseract 5.3.4',\n", + " ' leptonica-1.84.1',\n", + " ' libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp 1.4.0 : libopenjp2 2.5.2',\n", + " ' Found NEON',\n", + " ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n", + " ' Found libcurl/8.4.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.11 nghttp2/1.51.0']" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out = !tesseract --version\n", + "out\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install jpn_vert tesserac lang\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "```bash\n", + "cd model\n", + "sudo ln -s jpn_vert_tessdata_best.traineddata /usr/share/tesseract-ocr/5/tessdata/jpn_vert.traineddata\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(Path('/opt/homebrew/share/tessdata'),\n", + " ['afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n", + " 'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n", + " 'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n", + " 'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n", + " 'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n", + " 'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n", + " 'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n", + " 'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, script/Kannada, script/Khmer',\n", + " 'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n", + " 'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n", + " 'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'])" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "out = !tesseract --list-langs\n", + "tessdata = Path(out[0].split('\"')[1])\n", + "tessdata, [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n",
+       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'),\n",
+       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'),\n",
+       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata')\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "langs = tessdata.ls()\n", + "cprint([p.resolve() for p in langs if 'eng' in p.name] + [p.resolve() for p in langs if 'jpn' in p.name])\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Tesseract experiments" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PanelCleaner Configuration\n", + "> Adapt `PanelCleaner` `Config` current config to this notebook.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "config = cfg.load_config()\n", + "config.cache_dir = Path(\".\")\n", + "\n", + "cache_dir = config.get_cleaner_cache_dir()\n", + "\n", + "profile = config.current_profile\n", + "preprocessor_conf = profile.preprocessor\n", + "# Modify the profile to OCR all boxes.\n", + "# Make sure OCR is enabled.\n", + "preprocessor_conf.ocr_enabled = True\n", + "# Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", + "preprocessor_conf.ocr_max_size = 10**10\n", + "# Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", + "preprocessor_conf.suspicious_box_min_size = 10**10\n", + "# Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", + "preprocessor_conf.ocr_blacklist_pattern = \".*\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n", + "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "media_path = Path(\"media/\")\n", + "\n", + "IMAGE_PATHS = sorted(\n", + " [_ for _ in media_path.glob(\"*\") if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n", + "\n", + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CONTEXT\n", + "> `CONTEXT` is an `OCRExperimentContext` object that contains the configuration and the list of image paths.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can get the configuration with `OCRExperimentContext.get_config()`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: cursor\n", + "Cache Directory: .\n", + "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", + "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
      cache_dir: Path('cleaner')\n",
+       "     model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
+       "         device: 'mps'\n",
+       "
\n" + ], + "text/plain": [ + " cache_dir: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'cleaner'\u001b[0m\u001b[1m)\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'mps'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CONTEXT = OCRExperimentContext(None, IMAGE_PATHS)\n", + "\n", + "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + "model_path = CONTEXT.config.get_model_path(gpu)\n", + "DEVICE = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n", + "\n", + "CONTEXT.config.show()\n", + "cprint(\n", + " f\"{'cache_dir':>15}: {repr(cache_dir)}\\n\"\n", + " f\"{'model_path':>15}: {repr(model_path)}\\n\"\n", + " f\"{'device':>15}: {repr(DEVICE)}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base image\n", + "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", + "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"0033\")\n", + "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"INOUE_KYOUMEN_002\")\n", + "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"Action_Comics_1960-01-00_(262)\")\n", + "\n", + "assert BASE_IMAGE_IDX is not None\n", + "img_path = Path(CONTEXT.image_paths[BASE_IMAGE_IDX])\n", + "assert img_path.exists()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Empty cache\n", + "> Clear the image cache used profusely throughout the examples below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "You will be warned before the cache is emptied." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# CONTEXT.empty_cache_warn()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# CONTEXT.empty_cache_warn(BASE_IMAGE_IDX)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base image\n", + "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", + "assert CONTEXT.path_from_idx(BASE_IMAGE_IDX).exists()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Visualize images\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "3de3bd90585a452ab7bd9f5dce716e4e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output(layout=Layout(height='0px'))" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6ab61afc65d84115b81c248ed1d0ab03", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8c79a1393b5a4feaaa8c6d7cf2b458bc", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "img_visor = ImageContextVisor(CONTEXT, BASE_IMAGE_IDX)\n", + "img_visor\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tesseract experiments\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d65bd435e6774637ac667defde594c4d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "HBox(children=(HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), options={'Tesseract'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "f2ca36a4d81144d59ba835c40b990d34", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Output()" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# tesseract_experiment = ExperimentsVisor(CONTEXT)\n", + "tesseract_experiment = ExperimentsVisor(CONTEXT, BASE_IMAGE_IDX)\n", + "\n", + "test_eq(tesseract_experiment.all_values, {\n", + " 'image_selector': {'image_idx': 20},\n", + " 'content_selector': {'display_option': DisplayOptions.RESULTS},\n", + " 'result_visor': {\n", + " 'all_boxes': False,\n", + " 'box_idx': 0,\n", + " 'all_methods': False,\n", + " 'method': CropMethod.INITIAL_BOX,\n", + " },\n", + " 'model_selector': {'model': OCRModel.TESSERACT},\n", + " 'self': {}\n", + "})\n", + "\n", + "tesseract_experiment\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 3ab93d9b65c8efd750d6b6ef232599afa3cf0eef Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 10 May 2024 20:50:13 +0200 Subject: [PATCH 02/27] Add .gitkeep files --- _testbed/cleaner/.gitkeep | 0 _testbed/media/.gitkeep | 0 _testbed/model/.gitkeep | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 _testbed/cleaner/.gitkeep create mode 100644 _testbed/media/.gitkeep create mode 100644 _testbed/model/.gitkeep diff --git a/_testbed/cleaner/.gitkeep b/_testbed/cleaner/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/_testbed/media/.gitkeep b/_testbed/media/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/_testbed/model/.gitkeep b/_testbed/model/.gitkeep new file mode 100644 index 00000000..e69de29b From fba9f88c25e895f2f8b36be9177f63d750c821fa Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 10 May 2024 21:21:00 +0200 Subject: [PATCH 03/27] fix GDrive links --- .gitignore | 3 +++ _testbed/README.md | 2 +- _testbed/experiments.ipynb | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 8fc7b143..6bf84825 100644 --- a/.gitignore +++ b/.gitignore @@ -169,6 +169,9 @@ cython_debug/ *.sh .DS_Store + _testbed/media/** _testbed/cleaner/** _testbed/model/** + +!.gitkeep \ No newline at end of file diff --git a/_testbed/README.md b/_testbed/README.md index 702df030..5c782408 100644 --- a/_testbed/README.md +++ b/_testbed/README.md @@ -24,7 +24,7 @@ Instructions to use Google Colab are included in the notebooks (TBD). ## Install Test Images The test images are not included in the repository but can be downloaded from the following link: -- [Test images](https://drive.google.com/drive/folders/101_1_20240229) +- [Test images](https://drive.google.com/drive/folders/0BzW8DiWVVMiMN2JaZkg4cHN0NFU?resourcekey=0-ddnFRuwaLHH4FH5bPVa1SA&usp=drive_link) After downloading, place the test images in the [media](media) directory. If you want to use your own, each image should have a corresponding text file with the same name, but with the extension `.txt`, which contains the ground truth data, one line per box (as calculated by PanelCleaner). Optionally, you can also include a `.json` file with the same name, specifying the language of the page: ```json diff --git a/_testbed/experiments.ipynb b/_testbed/experiments.ipynb index 6c8d3c81..15cb4f85 100644 --- a/_testbed/experiments.ipynb +++ b/_testbed/experiments.ipynb @@ -227,7 +227,7 @@ "\n", "Note: I've not play much with this one, `managa-ocr` is surely a much better fit, but it can be educational to compare.\n", "\n", - "I have copied models in my GDrive, and installed (in my Ubuntu, similar in Mac):\n", + "I have copied models in my [drive](https://drive.google.com/drive/folders/0BzW8DiWVVMiMN2JaZkg4cHN0NFU?resourcekey=0-ddnFRuwaLHH4FH5bPVa1SA&usp=drive_link), and installed (in my Ubuntu, similar in Mac):\n", "```bash\n", "cd model\n", "ln -s jpn_vert_tessdata_best.traineddata /usr/share/tesseract-ocr/5/tessdata/jpn_vert.traineddata\n", From 88fd30b6009dedab8b46155dc2b6f5dd42014a01 Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 24 May 2024 19:24:07 +0200 Subject: [PATCH 04/27] Moved to pclaner/ --- .gitignore | 7 +- _testbed/README.md | 55 - _testbed/cleaner/.gitkeep | 0 _testbed/experiments.ipynb | 6810 --------------------------------- _testbed/experiments.py | 1995 ---------- _testbed/helpers.ipynb | 835 ---- _testbed/helpers.py | 372 -- _testbed/media/.gitkeep | 0 _testbed/model/.gitkeep | 0 _testbed/ocr_idefics.py | 184 - _testbed/ocr_metric.ipynb | 276 -- _testbed/ocr_metric.py | 64 - _testbed/requirements.txt | 5 - _testbed/test_idefics.ipynb | 1497 -------- _testbed/test_tesseract.ipynb | 638 --- 15 files changed, 3 insertions(+), 12735 deletions(-) delete mode 100644 _testbed/README.md delete mode 100644 _testbed/cleaner/.gitkeep delete mode 100644 _testbed/experiments.ipynb delete mode 100644 _testbed/experiments.py delete mode 100644 _testbed/helpers.ipynb delete mode 100644 _testbed/helpers.py delete mode 100644 _testbed/media/.gitkeep delete mode 100644 _testbed/model/.gitkeep delete mode 100644 _testbed/ocr_idefics.py delete mode 100644 _testbed/ocr_metric.ipynb delete mode 100644 _testbed/ocr_metric.py delete mode 100644 _testbed/requirements.txt delete mode 100644 _testbed/test_idefics.ipynb delete mode 100644 _testbed/test_tesseract.ipynb diff --git a/.gitignore b/.gitignore index 6bf84825..ce5d862b 100644 --- a/.gitignore +++ b/.gitignore @@ -170,8 +170,7 @@ cython_debug/ .DS_Store -_testbed/media/** -_testbed/cleaner/** -_testbed/model/** +*/_testbed/experiment/cache/** +*/_testbed/experiment/source/** -!.gitkeep \ No newline at end of file +!.gitkeep diff --git a/_testbed/README.md b/_testbed/README.md deleted file mode 100644 index 5c782408..00000000 --- a/_testbed/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# PanelCleaner Testbed - -## Overview -The **PanelCleaner** testbed serves as a dedicated area for experimenting and testing new ideas with *PanelCleaner* using Jupyter Notebooks. Currently, it focuses on **OCR** technologies, primarily using **Tesseract** and **IDefics** models. The testbed also begins the development of an evaluation framework to support future experiments. This project utilizes the `nbdev` literate programming environment. - -## Installation -To get started with the notebooks, you'll need Jupyter Lab/Notebook or any Python IDE that supports Jupyter notebooks like *VSCode* or *Google Colab*. -The setup mostly shares the same requirements as PanelCleaner and its CLI, with a few additional dependencies. -Here’s how to set up your environment: -1. Activate a virtual environment. -2. Navigate to the `_testbed` directory: - ```bash - cd _testbed - ``` -3. Install the required dependencies: - ```bash - pip install -r requirements.txt - ``` -Note: Each notebook may require the installation of additional dependencies. - -## Google Colab Support -The notebooks are ready to use on Google Colab, allowing you to run them directly on the platform without any extra setup or local GPU rigs. -Instructions to use Google Colab are included in the notebooks (TBD). - -## Install Test Images -The test images are not included in the repository but can be downloaded from the following link: -- [Test images](https://drive.google.com/drive/folders/0BzW8DiWVVMiMN2JaZkg4cHN0NFU?resourcekey=0-ddnFRuwaLHH4FH5bPVa1SA&usp=drive_link) - -After downloading, place the test images in the [media](media) directory. If you want to use your own, each image should have a corresponding text file with the same name, but with the extension `.txt`, which contains the ground truth data, one line per box (as calculated by PanelCleaner). Optionally, you can also include a `.json` file with the same name, specifying the language of the page: -```json -{ - "lang": "Spanish" -} -``` -If no language file is found, English will be used by default. In the near future, language detection will be automated. - -## Introduction to nbdev -[nbdev](https://nbdev.fast.ai/) is a **literate programming** environment that allows you to develop a Python library in Jupyter Notebooks, integrating exploratory programming, code, tests, and documentation into a single cohesive workflow. Inspired by **Donald Knuth**'s concept of literate programming, this approach not only makes the development process more intuitive but also eases the maintenance and understanding of the codebase. - -## Notebooks (WIP) - -#### [helpers.ipynb](helpers.ipynb) -This notebook includes utility functions and helpers that support the experiments in other notebooks, streamlining repetitive tasks and data manipulation. - -#### [ocr_metric.ipynb](ocr_metric.ipynb) -This notebook focuses on defining and implementing metrics to evaluate the performance and accuracy of OCR engines, crucial for assessing the effectiveness of OCR technologies in various scenarios. It currently develops a basic metric for evaluating OCR models. In the near future, additional metrics will be added, such as precision and recall using Levenshtein distance (edit distance). More importantly, it will introduce a metric tailored to the unique characteristics of Comics/Manga OCR, a topic currently unexplored in technical literature. - -#### [experiments.ipynb](experiments.ipynb) -This notebook details the development of the evaluation framework used in other notebooks, with Tesseract as a case study to illustrate the evaluation process. It's a work in progress, and will be updated continuously. If you're only interested in visualizing the results of the experiments, go directly to `Test_tesseract.ipynb` or `Test_idefics.ipynb`, which are much shorter and more to the point. - -#### [test_tesseract.ipynb](test_tesseract.ipynb) -This notebook is dedicated to testing the Tesseract OCR engine, offering insights into its capabilities and limitations through hands-on experiments. - -#### [test_idefics.ipynb](test_idefics.ipynb) -Similar to `test_tesseract.ipynb`, this notebook focuses on the IDefics LVM model, evaluating its performance and accuracy under different conditions. Here you can compare the results of the Tesseract OCR engine with the IDefics LVM model to see how the two compare in terms of accuracy and performance. diff --git a/_testbed/cleaner/.gitkeep b/_testbed/cleaner/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/_testbed/experiments.ipynb b/_testbed/experiments.ipynb deleted file mode 100644 index 15cb4f85..00000000 --- a/_testbed/experiments.ipynb +++ /dev/null @@ -1,6810 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#| default_exp experiments" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "# %reload_ext autoreload\n", - "# %autoreload 0\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# install (Colab)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# try: \n", - "# import fastcore as FC\n", - "# except ImportError: \n", - "# !pip install -q fastcore\n", - "# try:\n", - "# import rich\n", - "# except ImportError:\n", - "# !pip install -q rich\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Note: we're using the `testbed` branch of PanelCleaner.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Testing `Tesseract` OCR for Comics\n", - "> Accuracy Enhancements for OCR in `PanelCleaner`\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prologue" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "from __future__ import annotations\n", - "\n", - "import dataclasses\n", - "import difflib\n", - "import functools\n", - "import json\n", - "import shutil\n", - "from collections import defaultdict\n", - "from enum import Enum\n", - "from pathlib import Path\n", - "from typing import Any\n", - "from typing import Callable\n", - "from typing import cast\n", - "from typing import Mapping\n", - "from typing import Self\n", - "from typing import TypeAlias\n", - "\n", - "import fastcore.all as FC\n", - "import ipywidgets as W\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd\n", - "import pcleaner.config as cfg\n", - "import pcleaner.ctd_interface as ctm\n", - "import pcleaner.image_ops as ops\n", - "import pcleaner.ocr.ocr as ocr\n", - "import pcleaner.structures as st\n", - "import torch\n", - "from IPython.display import clear_output\n", - "from IPython.display import display\n", - "from IPython.display import HTML\n", - "from ipywidgets.widgets.interaction import show_inline_matplotlib_plots\n", - "from loguru import logger\n", - "from pcleaner.ocr.ocr_tesseract import TesseractOcr\n", - "from PIL import Image\n", - "from PIL import ImageFilter\n", - "from rich.console import Console\n", - "from tqdm.notebook import tqdm\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "from helpers import *\n", - "from ocr_metric import *\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "import copy\n", - "\n", - "import fastcore.xtras # patch Path with some utils\n", - "import pcleaner.cli_utils as cli\n", - "import pcleaner.preprocessor as pp\n", - "import rich\n", - "from fastcore.test import * # type: ignore\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Helpers" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# pretty print by default\n", - "# %load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "console = Console(width=104, tab_size=4, force_jupyter=True)\n", - "cprint = console.print\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tesseract installation" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['tesseract 5.3.4',\n", - " ' leptonica-1.84.1',\n", - " ' libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp 1.4.0 : libopenjp2 2.5.2',\n", - " ' Found NEON',\n", - " ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n", - " ' Found libcurl/8.4.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.11 nghttp2/1.51.0']" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "out = !tesseract --version\n", - "out\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Install jpn_vert tesserac lang\n", - "> It has much better results than the default `jpn` language model.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best), or from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) trained for vertical Japanese text as found in manga.\n", - "\n", - "Note: I've not play much with this one, `managa-ocr` is surely a much better fit, but it can be educational to compare.\n", - "\n", - "I have copied models in my [drive](https://drive.google.com/drive/folders/0BzW8DiWVVMiMN2JaZkg4cHN0NFU?resourcekey=0-ddnFRuwaLHH4FH5bPVa1SA&usp=drive_link), and installed (in my Ubuntu, similar in Mac):\n", - "```bash\n", - "cd model\n", - "ln -s jpn_vert_tessdata_best.traineddata /usr/share/tesseract-ocr/5/tessdata/jpn_vert.traineddata\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(Path('/opt/homebrew/share/tessdata'),\n", - " ['afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n", - " 'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n", - " 'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n", - " 'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n", - " 'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n", - " 'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n", - " 'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n", - " 'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, script/Kannada, script/Khmer',\n", - " 'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n", - " 'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n", - " 'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'])" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "out = !tesseract --list-langs\n", - "tessdata = Path(out[0].split('\"')[1])\n", - "tessdata, [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
[\n",
-       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'),\n",
-       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'),\n",
-       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata')\n",
-       "]\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1m[\u001b[0m\n", - " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n", - "\u001b[1m]\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "langs = tessdata.ls()\n", - "cprint([p.resolve() for p in langs if 'eng' in p.name] + [p.resolve() for p in langs if 'jpn' in p.name])\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## OCR results clean-up" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def remove_multiple_whitespaces(text):\n", - " return ' '.join(text.split())\n", - "\n", - " \n", - "def postprocess_ocr(text):\n", - " \"Basic postprocessing for English Tesseract OCR results.\"\n", - " return ' '.join(remove_multiple_whitespaces(text).splitlines()).capitalize()\n", - "\n", - "def accuracy_ocr_naive(text, ground_truth):\n", - " return sum(1 for a, b in zip(text, ground_truth) if a == b) / len(text)\n", - "\n", - "\n", - "def accuracy_ocr_difflib(text, ground_truth):\n", - " \"\"\"\n", - " Calculates the OCR accuracy based on the similarity between the OCR text and the ground truth text,\n", - " using difflib's SequenceMatcher to account for differences in a manner similar to git diffs.\n", - "\n", - " :param text: The OCR-generated text.\n", - " :param ground_truth: The ground truth text.\n", - " :return: A float representing the similarity ratio between the OCR text and the ground truth, \n", - " where 1.0 is identical.\n", - " \"\"\"\n", - " # Initialize the SequenceMatcher with the OCR text and the ground truth\n", - " matcher = difflib.SequenceMatcher(None, text, ground_truth)\n", - " \n", - " # Get the similarity ratio\n", - " similarity_ratio = matcher.ratio()\n", - " \n", - " return similarity_ratio" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Ground truth" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def ground_truth_path(page_data: st.PageData):\n", - " path = Path(page_data.original_path)\n", - " return path.with_stem(path.stem + '_gt').with_suffix('.txt')\n", - "\n", - "\n", - "def read_ground_truth(page_data: st.PageData):\n", - " gts_path = ground_truth_path(page_data)\n", - " if gts_path.exists():\n", - " gts = gts_path.read_text(encoding=\"utf-8\").splitlines()\n", - " else:\n", - " gts = [\"\" for _ in range(len(page_data.boxes))]\n", - " return gts\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cropping" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def dilate_by_fractional_pixel(image, dilation_fraction, filter_base_size=3):\n", - " \"\"\"\n", - " Dilates an image by a specified fractional pixel amount. The function calculates \n", - " the necessary scaling factor and filter size based on the desired dilation fraction.\n", - "\n", - " :param image: A PIL Image object (1-bit mode).\n", - " :param dilation_fraction: The desired fractional pixel amount for dilation (e.g., 0.2).\n", - " :param filter_base_size: The base size of the dilation filter to apply on the scaled image.\n", - " This size is adjusted based on the scaling factor to achieve the\n", - " desired dilation effect.\n", - " :return: A PIL Image object after dilation, converted back to grayscale.\n", - " \"\"\"\n", - " # Calculate the scale factor based on the desired dilation fraction\n", - " scale_factor = int(1 / dilation_fraction)\n", - " \n", - " # Adjust the filter size based on the scale factor\n", - " # This ensures the dilation effect is proportional to the desired fraction\n", - " filter_size = max(1, filter_base_size * scale_factor // 5)\n", - "\n", - " # Convert the image to grayscale for more nuanced intermediate values\n", - " image_gray = image.convert(\"L\")\n", - "\n", - " # Resize the image to a larger size using bicubic interpolation\n", - " larger_size = (int(image.width * scale_factor), int(image.height * scale_factor))\n", - " image_resized = image_gray.resize(larger_size, Image.BICUBIC)\n", - "\n", - " # Apply the dilation filter to the resized image\n", - " dilated_image = image_resized.filter(ImageFilter.MaxFilter(filter_size))\n", - "\n", - " # Resize the image back to its original size using bicubic interpolation\n", - " image_dilated_fractional_pixel = dilated_image.resize(image.size, Image.BICUBIC)\n", - "\n", - " return image_dilated_fractional_pixel\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def extract_text(image, text_mask, box):\n", - " cropped_image = crop_box(box, image)\n", - " cropped_mask = crop_box(box, text_mask)\n", - " extracted = ops.extract_text(cropped_image, cropped_mask)\n", - " return cropped_image, cropped_mask, extracted\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Lang\n", - "> language name to a language code \n", - "> every one has language codes: tesseract, comic-text-detector, earthlings...\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "_lang2pcleaner = {'English': st.DetectedLang.ENG, 'Japanese': st.DetectedLang.JA, 'Spanish': st.DetectedLang.ENG,\n", - " 'French':st.DetectedLang.ENG}\n", - "# _lang2tesseract = {'English': 'eng', 'Japanese': 'jpn'}\n", - "_lang2tesseract = {'English': 'eng', 'Japanese': 'jpn_vert', 'Spanish': 'spa', 'French': 'fra'}\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def lang2pcleaner(lang: str):\n", - " return _lang2pcleaner[lang]\n", - "\n", - "def lang2tesseract(lang: str):\n", - " return _lang2tesseract[lang]\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "# Tesseract experiments" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# PanelCleaner Configuration\n", - "> Adapt `PanelCleaner` `Config` current config to this notebook.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "config = cfg.load_config()\n", - "config.cache_dir = Path(\".\")\n", - "\n", - "cache_dir = config.get_cleaner_cache_dir()\n", - "\n", - "profile = config.current_profile\n", - "preprocessor_conf = profile.preprocessor\n", - "# Modify the profile to OCR all boxes.\n", - "# Make sure OCR is enabled.\n", - "preprocessor_conf.ocr_enabled = True\n", - "# Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", - "preprocessor_conf.ocr_max_size = 10**10\n", - "# Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", - "preprocessor_conf.suspicious_box_min_size = 10**10\n", - "# Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", - "preprocessor_conf.ocr_blacklist_pattern = \".*\"\n", - "\n", - "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", - "model_path = config.get_model_path(gpu)\n", - "device = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Test images\n", - "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['00: Action_Comics_1960-01-00_(262).JPG',\n", - " '01: Adolf_Cap_01_008.jpg',\n", - " '02: Barnaby_v1-028.png',\n", - " '03: Barnaby_v1-029.png',\n", - " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", - " '05: Cannon-292.jpg',\n", - " '06: Contrato_con_Dios_028.jpg',\n", - " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", - " '08: FOX_CHILLINTALES_T17_012.jpg',\n", - " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", - " '10: Galactus_12.jpg',\n", - " '11: INOUE_KYOUMEN_002.png',\n", - " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", - " '13: MCCAY_LITTLENEMO_090.jpg',\n", - " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", - " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", - " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", - " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", - " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", - " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", - " '20: Strange_Tales_172005.jpg',\n", - " '21: Strange_Tales_172021.jpg',\n", - " '22: Tarzan_014-21.JPG',\n", - " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", - " '24: Transformers_-_Unicron_000-004.jpg',\n", - " '25: Transformers_-_Unicron_000-016.jpg',\n", - " '26: WARE_ACME_024.jpg',\n", - " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", - " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", - " '29: manga_0033.jpg',\n", - " '30: ronson-031.jpg',\n", - " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "media_path = Path(\"media/\")\n", - "\n", - "IMAGE_PATHS = sorted(\n", - " [_ for _ in media_path.glob(\"*\") if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n", - "\n", - "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Results helper\n", - "> Dataclass helper to store and display results\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "@dataclasses.dataclass\n", - "class ResultOCR:\n", - " block_idx: int\n", - " image: Image.Image | None\n", - " ocr: str\n", - " page_data: st.PageData\n", - " gts: list[str]\n", - " description: str = dataclasses.field(default='', kw_only=True)\n", - "\n", - " def __post_init__(self): \n", - " if self.image is None:\n", - " cache_path = self.cache_path()\n", - " if cache_path.exists():\n", - " self.image = Image.open(cache_path)\n", - "\n", - " @property\n", - " def acc(self):\n", - " self._acc = accuracy_ocr_difflib(self.ocr, self.gts[self.block_idx])\n", - " return self._acc\n", - " @property\n", - " def suffix(self): return f\"{self.block_idx}_{self.description}\"\n", - "\n", - " def diff_tagged(self):\n", - " _, html2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr, False)\n", - " return f\"{html2}\"\n", - " \n", - " def cache_path(self, suffix: str | None = None):\n", - " suffix = self.suffix + (('_'+suffix) if suffix else '')\n", - " parent = Path(self.page_data.image_path).parent\n", - " img_name = Path(self.page_data.original_path).stem\n", - " box_image_path = parent / f\"{img_name}_{suffix}.png\"\n", - " return box_image_path\n", - " \n", - " def cache_image(self, image: Image.Image | None = None, suffix: str | None = None):\n", - " image = image or (self.image if not suffix else None)\n", - " box_image_path = self.cache_path(suffix)\n", - " if image and not box_image_path.exists():\n", - " image.save(box_image_path)\n", - " return box_image_path\n", - "\n", - "\n", - " def as_html(self):\n", - " acc_html = f\"
{self.acc:.2f}\"\n", - " box_image_path = self.cache_image()\n", - " html1 = get_columns_html([[box_image_path], [self.ocr + acc_html]])\n", - " html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr)\n", - " html2 = f\"
{html_str1}
{html_str2}
\"\n", - " return html1 + '\\n
\\n' + html2\n", - "\n", - " def __repr__(self): \n", - " return f\"{type(self).__name__}#block {self.block_idx:02}: {self.acc:.2f}||{self.ocr}\"\n", - " \n", - " def display(self): display(HTML(self.as_html()))\n", - " \n", - " def _ipython_display_(self): self.display()\n", - "\n", - " def to_dict(self):\n", - " d = dataclasses.asdict(self)\n", - " d['image'] = d['page_data'] = d['gts'] = None\n", - " return d\n", - "\n", - " # @classmethod\n", - " # def from_dict(cls, d: dict, page_data: st.PageData, gts: list[str]):\n", - " # return cls(**(d | {'page_data':page_data, 'gts':gts}))\n", - "\n", - "\n", - "@dataclasses.dataclass\n", - "class ResultOCRExtracted(ResultOCR):\n", - "\n", - " def __repr__(self): return super().__repr__()\n", - " def as_html(self):\n", - " html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr)\n", - " diff_html = f\"
{html_str1}
{html_str2}
\"\n", - " cropped_image_path = self.cache_image(None, \"cropped\")\n", - " cropped_mask_path = self.cache_image(None, \"mask\")\n", - " result_path = self.cache_image()\n", - " return '\\n
\\n'.join([\n", - " get_image_grid_html([cropped_image_path, cropped_mask_path, result_path], 1, 3), \n", - " acc_as_html(self.acc), \n", - " diff_html\n", - " ])\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# CropMethod\n", - "> Box cropping methods.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class CropMethod(Enum):\n", - " INITIAL_BOX = 'Initial box'\n", - " DEFAULT = 'Default'\n", - " DEFAULT_GREY_PAD = 'Default, grey pad'\n", - " PADDED_4 = 'Padded 4px'\n", - " PADDED_8 = 'Padded 8px'\n", - " EXTRACTED_INIT_BOX = 'Extracted, init box'\n", - " PADDED_4_EXTRACTED = 'Padded 4, extracted'\n", - " PADDED_8_EXTRACTED = 'Padded 8, extracted'\n", - " PADDED_8_DILATION_1 = 'Padded 8, dilation 1'\n", - " PAD_8_FRACT_0_5 = 'Pad 8, fract. 0.5'\n", - " PAD_8_FRACT_0_2 = 'Pad 8, fract. 0.2'\n", - "\n", - " @classmethod\n", - " def __display_names__(cls):\n", - " return dict(\n", - " zip([_.value for _ in cls], \n", - " cls))\n", - "\n", - "\n", - "CM = CropMethod\n", - "\n", - "_IMAGE_METHODS = [CM.INITIAL_BOX, CM.DEFAULT, CM.DEFAULT_GREY_PAD, \n", - " CM.PADDED_4, CM.PADDED_8]\n", - "_EXTRACTED_METHODS = [CM.EXTRACTED_INIT_BOX, CM.PADDED_4_EXTRACTED, \n", - " CM.PADDED_8_EXTRACTED, CM.PADDED_8_DILATION_1, \n", - " CM.PAD_8_FRACT_0_5, CM.PAD_8_FRACT_0_2]\n", - "\n", - "\n", - "def crop_by_image(method: CM, \n", - " box: st.Box, \n", - " base: Image.Image, \n", - " preproc: cfg.PreprocessorConfig,\n", - " ):\n", - " image = None\n", - " match method:\n", - " case CM.INITIAL_BOX :\n", - " image = crop_box(box, base)\n", - " case CM.DEFAULT:\n", - " padded2_4 = (\n", - " box.pad(preproc.box_padding_initial, base.size).right_pad(\n", - " preproc.box_right_padding_initial, base.size))\n", - " image = crop_box(padded2_4, base)\n", - " case CM.DEFAULT_GREY_PAD:\n", - " image = crop_box(box, base)\n", - " image = ops.pad_image(image, 8, fill_color=(128, 128, 128))\n", - " case CM.PADDED_4:\n", - " padded4 = box.pad(4, base.size)\n", - " image = crop_box(padded4, base)\n", - " case CM.PADDED_8:\n", - " padded4 = box.pad(8, base.size)\n", - " image = crop_box(padded4, base)\n", - " case _: pass\n", - " return image\n", - "\n", - "\n", - "def crop_by_extracted(method: CM, \n", - " box: st.Box, \n", - " base: Image.Image, \n", - " mask: Image.Image,\n", - " cropped_image_path: Path,\n", - " cropped_mask_path: Path,\n", - " dilated: dict[float, Image.Image]\n", - " ):\n", - " cropped_image, cropped_mask, image = None, None, None\n", - " if method in _EXTRACTED_METHODS:\n", - " if not cropped_image_path.exists() or not cropped_mask_path.exists():\n", - " match method:\n", - " case CM.EXTRACTED_INIT_BOX:\n", - " cropped_image, cropped_mask, image = extract_text(base, mask, box)\n", - " case CM.PADDED_4_EXTRACTED:\n", - " padded4 = box.pad(4, base.size)\n", - " cropped_image, cropped_mask, image = extract_text(base, mask, padded4)\n", - " case CM.PADDED_8_EXTRACTED:\n", - " padded8 = box.pad(8, base.size)\n", - " cropped_image, cropped_mask, image = extract_text(base, mask, padded8)\n", - " case CM.PADDED_8_DILATION_1:\n", - " padded8 = box.pad(8, base.size)\n", - " cropped_image, cropped_mask, image = extract_text(\n", - " base, dilated[1], padded8)\n", - " case CM.PAD_8_FRACT_0_5:\n", - " padded8 = box.pad(8, base.size)\n", - " cropped_image, cropped_mask, image = extract_text(\n", - " base, dilated[0.5], padded8)\n", - " case CM.PAD_8_FRACT_0_2:\n", - " padded8 = box.pad(8, base.size)\n", - " cropped_image, cropped_mask, image = extract_text(\n", - " base, dilated[0.2], padded8)\n", - " case _: pass\n", - "\n", - " return image, cropped_image, cropped_mask\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ResultSet\n", - "> tagged nested dict to store image results keyed by box, and crop method\n" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "SubjIdT: TypeAlias = int\n", - "ImgIdT = SubjIdT\n", - "BoxIdT: TypeAlias = int\n", - "\n", - "class ResultSet(dict[BoxIdT, dict[CropMethod, ResultOCR]]): ...\n", - "\n", - "class ResultSetDefault(defaultdict[BoxIdT, dict[CropMethod, ResultOCR]]): ...\n", - "\n", - "def results_to_dict(results: ResultSet) -> dict[BoxIdT, dict[str, str]]:\n", - " d = {}\n", - " for box, box_methods in results.items():\n", - " for method, result in box_methods.items():\n", - " if box not in d:\n", - " d[box] = {}\n", - " d[box][method.name] = result.ocr\n", - " return d\n", - "\n", - "def dict_to_results(\n", - " image_idx: ImgIdT, \n", - " results_dict: dict[BoxIdT, dict[str, str]],\n", - " result_factory: Callable\n", - " ) -> ResultSetDefault:\n", - " results = ResultSetDefault(dict[CropMethod, ResultOCR])\n", - " for box_idx, box_methods in results_dict.items():\n", - " box_idx = int(box_idx)\n", - " for method, ocr in box_methods.items():\n", - " m = CM[method]\n", - " results[box_idx][m] = result_factory(image_idx, box_idx, m, ocr)\n", - " return results\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ExperimentContext\n", - "> Utility class to maintain shared state across all experiments.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "# class ExperimentSubject(Protocol):\n", - "# @property\n", - "# def exp(self) -> 'ExperimentContext': ...\n", - "# @property\n", - "# def idx(self) -> SubjIdT: ...\n", - "# def setup(self,\n", - "# exp: 'ExperimentContext',\n", - "# idx: Any,\n", - "# *args, **kwargs\n", - "# ): ...\n", - "\n", - "\n", - "# class ExperimentContext(Protocol):\n", - "# def subject_factory(self) -> Callable[..., ExperimentSubject]: ...\n", - "# def normalize_idx(self, idx: Any) -> SubjIdT: ...\n", - "# def experiment_subject(self, idx: Any, /, \n", - "# create: bool = False, *args, **kwargs) -> ExperimentSubject | None: \n", - "# \"\"\"Get or create an `ExperimentSubject` for the given identifier. \n", - "# Returns `None` if `idx` is out of domain range.\n", - "# \"\"\"\n", - "# ...\n" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class ExperimentSubject:\n", - " exp: ExperimentContext\n", - " idx: SubjIdT\n", - "\n", - " def setup(self, exp: ExperimentContext, idx: Any, *args, **kwargs): \n", - " self.exp = exp\n", - " self.idx = cast(SubjIdT, exp.normalize_idx(idx))\n", - " return self\n", - "\n", - " def __new__(cls,\n", - " exp: ExperimentContext,\n", - " idx: Any,\n", - " *args, **kwargs):\n", - " self = exp.experiment_subject(idx)\n", - " if self is None:\n", - " self = super().__new__(cls)\n", - " self = exp.experiment_subject(idx, new_subject=self, *args, **kwargs)\n", - " if self is None:\n", - " raise ValueError(f\"Can't create new subject with idx: {idx}: out of range\")\n", - " return self\n", - "\n", - "\n", - "class ExperimentContext:\n", - " \"Class to maintain shared state across all file-based experiments within the experiment domain.\"\n", - "\n", - " subject_cls: Callable[..., ExperimentSubject]\n", - " def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls\n", - "\n", - " def normalize_idx(self, idx: int | str | Path) -> SubjIdT | None:\n", - " nidx = None\n", - " if isinstance(idx, int) and idx < len(self._paths):\n", - " nidx = idx\n", - " elif isinstance(idx, str):\n", - " try:\n", - " nidx = [_.name for _ in self._paths].index(idx)\n", - " except Exception:\n", - " pass\n", - " elif isinstance(idx, Path):\n", - " idx = idx.resolve()\n", - " if idx in self._paths:\n", - " nidx = self._paths.index(idx)\n", - " return nidx\n", - " \n", - " def path_from_idx(self, idx: int | str | Path):\n", - " _idx = self.normalize_idx(idx)\n", - " if _idx is None:\n", - " raise ValueError(f\"{_idx} not found in context.\")\n", - " path = Path(self._paths[_idx])\n", - " if not path.exists():\n", - " raise ValueError(f\"{path} not found in context.\")\n", - " return path\n", - " \n", - " @property\n", - " def count(self): return len(self._paths)\n", - " @property\n", - " def cache_dir(self): return Path(\".cache/\")\n", - " @functools.lru_cache()\n", - " def _cache_dir(self, idx: SubjIdT):\n", - " # create one folder for each image to cache and save results\n", - " path = self.path_from_idx(idx)\n", - " cache_dir = self.cache_dir / path.stem\n", - " cache_dir.mkdir(parents=True, exist_ok=True)\n", - " return cache_dir\n", - " def subject_cache_dir(self, idx: int | str | Path):\n", - " return self._cache_dir(idx)\n", - "\n", - " def empty_cache(self, idx: SubjIdT | None = None):\n", - " cache_dir = self.cache_dir\n", - " if idx is None:\n", - " shutil.rmtree(cache_dir, ignore_errors=True)\n", - " cache_dir.mkdir(parents=True, exist_ok=True)\n", - " else:\n", - " path = Path(self._paths[idx])\n", - " cache_dir = cache_dir / path.stem\n", - " for p in cache_dir.glob(\"*\"):\n", - " p.unlink(missing_ok=True)\n", - " if not any(cache_dir.iterdir()):\n", - " cache_dir.rmdir()\n", - "\n", - " def empty_cache_warn(self, idx: SubjIdT | None=None, *, warn: bool=True, out: W.Output | None=None):\n", - " def on_confirm_clicked(b):\n", - " try:\n", - " self.empty_cache(idx)\n", - " print(\"Cache cleared successfully.\")\n", - " except Exception as e:\n", - " print(f\"Failed to clear cache: {e}\")\n", - " finally:\n", - " for widget in confirmation_box.children:\n", - " widget.close()\n", - "\n", - " def on_cancel_clicked(b):\n", - " print(\"Cache clear cancelled.\")\n", - " for widget in confirmation_box.children:\n", - " widget.close()\n", - "\n", - " if out is None:\n", - " out = W.Output()\n", - " with out:\n", - " if FC.IN_NOTEBOOK:\n", - " confirm_button = W.Button(description=\"Confirm\")\n", - " cancel_button = W.Button(description=\"Cancel\")\n", - " confirm_button.on_click(on_confirm_clicked)\n", - " cancel_button.on_click(on_cancel_clicked)\n", - " label = W.Label('Are you sure you want to clear the cache? This action cannot be undone.')\n", - " confirmation_box = W.VBox([label, W.HBox([confirm_button, cancel_button])])\n", - " display(confirmation_box)\n", - " else:\n", - " on_confirm_clicked(None)\n", - "\n", - " def experiment_subject(self, idx: SubjIdT | str | Path, /, \n", - " new_subject: ExperimentSubject | None = None, *args, **kwargs) -> ExperimentSubject | None:\n", - " \"Cached subject. If provided, `new_subject` replaces value at the index.\"\n", - " if (nidx := self.normalize_idx(idx)) is None:\n", - " return None\n", - " if new_subject is None:\n", - " subject = self._subjects.get(nidx)\n", - " else:\n", - " new_subject.setup(self, nidx, *args, **kwargs)\n", - " self._subjects[nidx] = subject = new_subject\n", - " return subject\n", - "\n", - " def reset(self):\n", - " self._subjects.clear()\n", - " self._cache_dir.cache_clear()\n", - " \n", - " def __init__(self, paths: list[Path], root: Path | None = None):\n", - " self._root = (root or Path('.')).resolve()\n", - " self._paths = [p.resolve().relative_to(self._root) for p in paths]\n", - " self._subjects: dict[SubjIdT, ExperimentSubject] = {}\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "`ExperimentSubject`s are singletons" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "exp = ExperimentContext([Path('a'), Path('b')])\n", - "subj = exp.experiment_subject(5)\n", - "test_eq(subj, None)\n", - "\n", - "_ = exp.experiment_subject(1)\n", - "test_is(_, None)\n", - "\n", - "subj1 = ExperimentSubject(exp, 1)\n", - "_ = exp.experiment_subject(1)\n", - "test_eq(_ is not None, True)\n", - "test_is(_, subj1)\n", - "test_is(subj1, ExperimentSubject(exp, 1))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can't create `ExperimentSubject`s beyond `ExperimentContext` domain." - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], - "source": [ - "test_fail(lambda:ExperimentSubject(exp, 2), 'out of range')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ImageContext\n", - "> A utility class to maintain image state for a `OCRExperimentContext`.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "ImgSpecT: TypeAlias = ImgIdT | str | Path\n", - "\n", - "class ImageContext(ExperimentSubject):\n", - " \"\"\"\n", - " A utility class to maintain image state for a ExperimentContext.\n", - " This class encapsulates state necessary for conducting OCR experiments.\n", - "\n", - " Attributes:\n", - " json_data (dict): JSON data loaded from cached files.\n", - " page_data (st.PageData): PanelClaner page data.\n", - " base_image (Image.Image): The base image loaded from the page data.\n", - " mask (Image.Image): The mask image used for text detection.\n", - " gts (list[str]): Ground truth data for the text in the images.\n", - " ocr_model (str): Name or identifier of the OCR model used.\n", - " mocr (ocr.OCRModel): OCR model configured for the experiment.\n", - " mask_dilated1 (Image.Image): Image mask dilated by 1 pixel.\n", - " mask_dilated05 (Image.Image): Image mask dilated by 0.5 pixels.\n", - " mask_dilated02 (Image.Image): Image mask dilated by 0.2 pixels.\n", - "\n", - " Methods:\n", - " init(config: cfg.Config, img_path: Path, cache_dir: Path, ocr_model: str):\n", - " Initializes the experiment context. It also handles the generation of text boxes \n", - " if they are not already present.\n", - "\n", - " setup_ground_truth():\n", - " Loads or initializes ground truth data for the experiment based on the page data.\n", - "\n", - " setup_crop_masks():\n", - " Prepares various dilated versions of the mask image to be used in different cropping \n", - " strategies during the experiments.\n", - " \"\"\"\n", - " exp: ExperimentContext\n", - " idx: ImgIdT\n", - " base_image: Image.Image\n", - " mask: Image.Image\n", - " json_data: dict | None\n", - " page_data: st.PageData\n", - " # ocr_model: str\n", - " # mocr: ocr.OCRModel\n", - " # postprocess_ocr: Callable[..., str]\n", - " _page_lang: str\n", - " _gts: list[str]\n", - " _mask_dilated1: Image.Image | None\n", - " _mask_dilated05: Image.Image | None\n", - " _mask_dilated02: Image.Image | None\n", - " \n", - "\n", - " # # this methods will be set downstream, declared here to make the type checker happy\n", - " # def result(self: Self, \n", - " # box_idx: int, method: CropMethod, ocr: bool = True, reset: bool=False) -> ResultOCR: ...\n", - " # def summary_box(self: Self, box_idx: int): ...\n", - "\n", - " def to_dict(self):\n", - " return {\n", - " 'image_idx': self.idx,\n", - " 'page_lang': self.page_lang,\n", - " }\n", - " \n", - " @property\n", - " def image_idx(self): return self.idx\n", - " @property\n", - " def cache_dir(self): \n", - " return self.exp.subject_cache_dir(self.idx)\n", - " cache_dir_image = cache_dir\n", - " \n", - " @property\n", - " def image_info(self): \n", - " img = self.base_image\n", - " w, h = img.size\n", - " print_size_in = size(w, h, 'in', 300)\n", - " print_size_cm = size(w, h, 'cm', 300)\n", - " required_dpi = dpi(w, h, 'Modern Age')\n", - " return (w, h), print_size_in, print_size_cm, required_dpi\n", - "\n", - " @property\n", - " def original_image_path(self): return Path(self.page_data.original_path)\n", - " @property\n", - " def image_path(self): return Path(self.page_data.image_path)\n", - " @property\n", - " def image_name(self): return self.original_image_path.name\n", - " @property\n", - " def image_size(self): return self.base_image.size\n", - " @property\n", - " def image_dim(self):return size(*self.image_size)\n", - " @property\n", - " def image_dpi(self): return dpi(*self.image_size)\n", - " @property\n", - " def image_print(self):\n", - " return self.image_size, self.image_dim, self.image_dpi\n", - " @property\n", - " def image_name_rich(self):\n", - " siz, dim, res = self.image_print\n", - " return f\"{self.image_name} - {siz[0]}x{siz[1]} px: {dim[0]:.2f}x{dim[1]:.2f}\\\" @ {res:.2f} dpi\"\n", - " \n", - " def setup_page_lang(self, page_lang: str | None = None):\n", - " path = Path(self.page_data.original_path).with_suffix('.json')\n", - " metadata = json.load(open(path)) if path.exists() else {}\n", - " if 'lang' in metadata and (page_lang == metadata['lang'] or page_lang is None):\n", - " self._page_lang = metadata['lang']\n", - " return\n", - " self._page_lang = metadata['lang'] = page_lang or 'English'\n", - " json.dump(metadata, open(path, 'w'), indent=2)\n", - " @property\n", - " def page_lang(self):\n", - " if self._page_lang == None:\n", - " self.setup_page_lang()\n", - " return self._page_lang\n", - " \n", - " @property\n", - " def boxes(self): return self.page_data.boxes\n", - " \n", - " def setup_ground_truth(self):\n", - " self._gts = read_ground_truth(self.page_data)\n", - " @property\n", - " def gts(self): \n", - " if self._gts is None:\n", - " self.setup_ground_truth()\n", - " return self._gts\n", - " \n", - " @functools.lru_cache(typed=True)\n", - " def dilated_mask(self, fraction: float):\n", - " return dilate_by_fractional_pixel(self.mask, fraction)\n", - " \n", - " def mask_dilated1(self): \n", - " if self._mask_dilated1 is None:\n", - " self._mask_dilated1 = self.mask.filter(ImageFilter.MaxFilter(3))\n", - " return self._mask_dilated1\n", - " \n", - " def mask_dilated05(self): \n", - " if self._mask_dilated05 is None:\n", - " self._mask_dilated05 = self.dilated_mask(0.5)\n", - " return self._mask_dilated05\n", - " \n", - " def mask_dilated02(self): \n", - " if self._mask_dilated02 is None:\n", - " self._mask_dilated02 = self.dilated_mask(0.2)\n", - " return self._mask_dilated02\n", - " \n", - " def dilated(self):\n", - " return {1: self.mask_dilated1(),\n", - " 0.5: self.mask_dilated05(),\n", - " 0.2: self.mask_dilated02(),}\n", - "\n", - " def __new__(cls,\n", - " exp: ExperimentContext,\n", - " idx: ImgSpecT,\n", - " *args, **kwargs) -> Self:\n", - " return super().__new__(cls, exp, idx, *args, **kwargs) # type: ignore\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# OCRExperimentContext" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class OCRExperimentContext(ExperimentContext):\n", - " \"\"\"\n", - " A utility class to maintain shared state across all experiments within OCR domain.\n", - " This class encapsulates state necessary for conducting PanelCleaner OCR experiments.\n", - " \"\"\"\n", - "\n", - " config: cfg.Config\n", - " image_paths: list[Path]\n", - " # OCR engine -> Image index -> Box index -> Crop method -> Result\n", - " _results: dict[str, dict[ImgIdT, ResultSet]]\n", - "\n", - " \n", - " engines = {\n", - " 'Tesseract': cfg.OCREngine.TESSERACT, \n", - " 'Idefics': None, \n", - " 'manga-ocr': cfg.OCREngine.MANGAOCR}\n", - "\n", - " # subject_cls: ImageContext\n", - " # def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls\n", - "\n", - " @classmethod\n", - " def get_config(cls, cache_dir: Path | None = None) -> cfg.Config:\n", - " config = cfg.load_config()\n", - " config.cache_dir = cache_dir or Path(\".\")\n", - " profile = config.current_profile\n", - " preprocessor_conf = profile.preprocessor\n", - " # Modify the profile to OCR all boxes.\n", - " # Make sure OCR is enabled.\n", - " preprocessor_conf.ocr_enabled = True\n", - " # Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", - " preprocessor_conf.ocr_max_size = 10**10\n", - " # Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", - " preprocessor_conf.suspicious_box_min_size = 10**10\n", - " # Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", - " preprocessor_conf.ocr_blacklist_pattern = \".*\"\n", - " return config\n", - "\n", - " def to_dict(self):\n", - " return {\n", - " 'image_paths': list(map(str, self.image_paths)),\n", - " 'cache_dir': str(self.config.cache_dir)\n", - " }\n", - " def to_json(self):\n", - " return json.dumps(self.to_dict(), indent=2)\n", - " @classmethod\n", - " def from_json_data(cls, d: dict):\n", - " return cls(cls.get_config(Path(d['cache_dir'])), d['image_paths'])\n", - " @classmethod\n", - " def from_json_path(cls, path: Path):\n", - " return cls.from_json_data(json.loads(path.read_text()))\n", - "\n", - " \n", - " @functools.lru_cache()\n", - " def mocr(self, ocr_model: str, lang: str):\n", - " engine = self.engines[ocr_model]\n", - " ocr_processor = ocr.get_ocr_processor(True, engine)\n", - " proc = ocr_processor[lang2pcleaner(lang)]\n", - " if isinstance(proc, TesseractOcr):\n", - " proc.lang = lang2tesseract(lang)\n", - " return proc\n", - "\n", - " def ocr_box(self, result: ResultOCR, ocr_model: str, lang: str): \n", - " assert result.image is not None\n", - " text = self.mocr(ocr_model, lang)(result.image)\n", - " result.ocr = postprocess_ocr(text)\n", - " return result\n", - "\n", - " @property\n", - " def cache_dir(self): return self.config.get_cleaner_cache_dir()\n", - " image_cache_dir = ExperimentContext.subject_cache_dir\n", - "\n", - " @functools.lru_cache()\n", - " def _load_page_data(self, image_idx: int):\n", - " config = self.config\n", - " cache_dir = self.image_cache_dir(image_idx)\n", - " img_path = self.path_from_idx(image_idx)\n", - " image_name = img_path.stem\n", - " # read cached json\n", - " jsons = [_ for _ in cache_dir.glob(\"*#raw.json\") if image_name in _.stem]\n", - " assert len(jsons) <= 1\n", - " # generate text boxes if needed\n", - " if not jsons:\n", - " pfl = config.current_profile\n", - " gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", - " model_path = config.get_model_path(gpu)\n", - " ctm.model2annotations(pfl.general, pfl.text_detector, model_path, [img_path], cache_dir)\n", - " # we don't need unique names for this tests, strip uuids\n", - " for p in cache_dir.glob(f\"*{image_name}*\"):\n", - " p.rename(strip_uuid(p))\n", - " jsons = [_ for _ in cache_dir.glob(\"*#raw.json\") if image_name in _.stem]\n", - "\n", - " # adapt paths to be relative to this notebook\n", - " this_path = self._root\n", - " json_file_path = jsons[0]\n", - " json_data = json.loads(json_file_path.read_text(encoding=\"utf-8\"))\n", - " json_data[\"image_path\"] = str(strip_uuid(json_data[\"image_path\"]).relative_to(this_path))\n", - " json_data[\"mask_path\"] = str(strip_uuid(json_data[\"mask_path\"]).relative_to(this_path))\n", - " json.dump(json_data, open(json_file_path, \"w\"), indent=2)\n", - " else:\n", - " json_file_path = jsons[0]\n", - " json_data = json.loads(json_file_path.read_text(encoding=\"utf-8\"))\n", - "\n", - " page_data = st.PageData(\n", - " json_data[\"image_path\"], json_data[\"mask_path\"], \n", - " json_data[\"original_path\"], json_data[\"scale\"], \n", - " [st.Box(*data[\"xyxy\"]) for data in json_data[\"blk_list\"]], \n", - " [], [], [])\n", - " # Merge boxes that have mutually overlapping centers.\n", - " page_data.resolve_total_overlaps()\n", - " return json_data, page_data\n", - "\n", - " def page_data(self, image_idx: int):\n", - " _, page_data = self._load_page_data(image_idx)\n", - " return page_data\n", - " def json_data(self, image_idx: int):\n", - " json_data, _ = self._load_page_data(image_idx)\n", - " return json_data\n", - "\n", - " def experiment_image(self, image_idx: ImgIdT | str | Path) -> ImageContext | None:\n", - " \"Cached image context.\"\n", - " return cast(ImageContext, self.experiment_subject(image_idx))\n", - "\n", - " def update_results(self, ocr_model: str, img_idx: ImgIdT, results: ResultSetDefault):\n", - " self._results[ocr_model][img_idx] = cast(ResultSet, results)\n", - " \n", - " \n", - " def _result_from(self, image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None):\n", - " img_ctx = ImageContext(self, image_idx)\n", - " extracted = method in _EXTRACTED_METHODS\n", - " result_cls = ResultOCRExtracted if extracted else ResultOCR\n", - " result = result_cls(int(box_idx), None, '', img_ctx.page_data, \n", - " img_ctx.gts, description=f\"{method.value}\")\n", - " if ocr is not None:\n", - " result.ocr = ocr\n", - " return result\n", - " \n", - " def result(self, \n", - " ocr_model: str,\n", - " image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, \n", - " ocr: bool=True, \n", - " rebuild: bool=False) -> ResultOCR | None:\n", - " img_ctx = ImageContext(self, image_idx)\n", - " result = self._results[ocr_model][image_idx][box_idx].get(method)\n", - " if not rebuild and result is not None:\n", - " return result\n", - " \n", - " result = self._result_from(image_idx, box_idx, method)\n", - " image, cropped_image, cropped_mask = result.image, None, None\n", - " base_image = img_ctx.base_image\n", - " box = img_ctx.boxes[box_idx]\n", - " if image is None and method in _IMAGE_METHODS:\n", - " image = crop_by_image(\n", - " method, box, base_image, self.config.current_profile.preprocessor)\n", - "\n", - " if image is None and method in _EXTRACTED_METHODS:\n", - " mask = img_ctx.mask\n", - " cropped_image_path = result.cache_image(cropped_image, \"cropped\")\n", - " cropped_mask_path = result.cache_image(cropped_mask, \"mask\")\n", - " if not cropped_image_path.exists() or not cropped_mask_path.exists():\n", - " image, cropped_image, cropped_mask = crop_by_extracted(\n", - " method, box, base_image, mask, \n", - " cropped_image_path, cropped_mask_path, img_ctx.dilated())\n", - " \n", - " assert image is not None\n", - " if result.image is None:\n", - " result.image = image\n", - " result.cache_image()\n", - " if cropped_image is not None:\n", - " result.cache_image(cropped_image, \"cropped\")\n", - " if cropped_mask is not None:\n", - " result.cache_image(cropped_mask, \"mask\")\n", - " \n", - " if ocr:\n", - " result = self.ocr_box(result, ocr_model, img_ctx.page_lang)\n", - " self._results[ocr_model][image_idx][box_idx][method] = result\n", - " return result\n", - "\n", - " def results(self, ocr_model: str | None = None, img_idx: ImgIdT | None = None):\n", - " if ocr_model is None: return self._results\n", - " if img_idx is None: return self._results[ocr_model]\n", - " return self._results[ocr_model][img_idx]\n", - " def model_results(self, ocr_model: str):\n", - " return cast(dict[ImgIdT, ResultSet], self.results(ocr_model))\n", - " def image_results(self, ocr_model: str, img_idx: ImgIdT):\n", - " return cast(ResultSet, self.results(ocr_model, img_idx))\n", - " def box_results(self, ocr_model: str, img_idx: ImgIdT, box_idx: BoxIdT):\n", - " return cast(ResultSet, self.results(ocr_model, img_idx))[box_idx]\n", - " def method_results(self, ocr_model: str, img_idx: ImgIdT, method: CropMethod):\n", - " image_results = self.image_results(ocr_model, img_idx)\n", - " return {i: box_results.get(method) for i,box_results in image_results.items()}\n", - "\n", - " def _reset_results(self):\n", - " results = defaultdict(lambda: defaultdict(lambda: ResultSetDefault(dict)))\n", - " self._results = cast(dict[str, dict[ImgIdT, ResultSet]], results)\n", - " def reset_results(self, \n", - " ocr_model: str | None = None, \n", - " image_idx: int | None = None, \n", - " box_idx: int | None = None, \n", - " method: CropMethod | None = None):\n", - " if ocr_model is None and image_idx is None and box_idx is None and method is None:\n", - " self._reset_results()\n", - " return\n", - " results = self._results\n", - " models = tuple(results.keys()) if ocr_model is None else [ocr_model] if ocr_model in results else []\n", - " for ocr_model in models:\n", - " img_nodes = results[ocr_model]\n", - " imgs = tuple(img_nodes.keys()) if image_idx is None else [image_idx] if image_idx in img_nodes else []\n", - " for img_idx in imgs:\n", - " box_nodes = img_nodes[img_idx]\n", - " boxes = tuple(box_nodes.keys()) if box_idx is None else [box_idx] if box_idx in box_nodes else []\n", - " for box_idx in boxes:\n", - " if method is None:\n", - " del box_nodes[box_idx]\n", - " else:\n", - " methods = box_nodes[box_idx]\n", - " if method in methods:\n", - " del methods[method]\n", - " if not box_nodes[box_idx]:\n", - " del box_nodes[box_idx]\n", - " if not img_nodes[img_idx]:\n", - " del img_nodes[img_idx]\n", - " if not results[ocr_model]:\n", - " del results[ocr_model]\n", - " def reset(self):\n", - " super().reset()\n", - " self.reset_results()\n", - " self._load_page_data.cache_clear()\n", - " self.mocr.cache_clear()\n", - "\n", - " def __init__(self, \n", - " config: cfg.Config | None, \n", - " image_paths: list[Path]\n", - " ):\n", - " super().__init__(list(map(lambda p: p.resolve(), image_paths)))\n", - " self.config = config or type(self).get_config()\n", - " self.image_paths = self._paths\n", - " self._reset_results()\n", - " self._images = self._subjects\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "\n", - "@FC.patch_to(ImageContext)\n", - "def setup(self, exp: OCRExperimentContext, image_idx: ImgSpecT, page_lang: str | None = None):\n", - " super(type(self), self).setup(exp, image_idx)\n", - " self._mask_dilated1 = self._mask_dilated05 = self._mask_dilated02 = None\n", - " # if ocr_model not in exp.engines:\n", - " # raise ValueError(f\"OCR model {ocr_model} not supported.\")\n", - " # self.ocr_model = ocr_model\n", - " # self.idx = exp.normalize_idx(image_idx)\n", - " self.json_data, self.page_data = exp._load_page_data(self.idx)\n", - " self.setup_page_lang(page_lang)\n", - " self.mask = Image.open(self.page_data.mask_path)\n", - " self.base_image = Image.open(self.page_data.image_path)\n", - " self.setup_ground_truth()\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "tirar = OCRExperimentContext(None, [])\n", - "test_eq(rr := tirar._results, {})\n", - "test_eq(rr['Tesseract'][0][0], {})\n", - "test_eq(rr, {'Tesseract': {0: {0: {}}}})\n", - "test_eq(rr['Tesseract'][0][0].get(CM.INITIAL_BOX), None)\n", - "rr['Tesseract'][0][0][CM.INITIAL_BOX] = 'a' # type: ignore\n", - "test_eq(rr, {'Tesseract': {0: {0: {CM.INITIAL_BOX: 'a'}}}})\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ContextVisor\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class ContextVisor:\n", - " ctx: Any\n", - " # control_names: list[str]\n", - " values: dict[str, Any]\n", - "\n", - " _css = ''\n", - "\n", - " _ctxs: dict[str, ContextVisor]\n", - " _hdlrs: dict[str, ContextVisor]\n", - "\n", - " @property\n", - " def w(self) -> W.DOMWidget:\n", - " if getattr(self, '_w', None) is None:\n", - " self._w = self.setup_ui()\n", - " return self._w\n", - " @property\n", - " def out(self) -> W.Output:\n", - " if getattr(self, '_out', None) is None:\n", - " self._out = W.Output()\n", - " self._out.clear_output(wait=True)\n", - " return self._out # type: ignore\n", - " @property\n", - " def controls(self) -> dict[str, W.ValueWidget | W.fixed]:\n", - " if getattr(self, '_controls', None) is None:\n", - " self._controls = self.setup_controls()\n", - " return self._controls\n", - " @property\n", - " def all_controls(self) -> dict[str, W.ValueWidget | W.fixed]:\n", - " if getattr(self, '_all_controls', None) is None:\n", - " controls = {}\n", - " for visor in self._ctxs.values():\n", - " controls.update(visor.all_controls)\n", - " controls.update(self.controls)\n", - " self._all_controls = controls\n", - " return self._all_controls\n", - " \n", - " @property\n", - " def all_values(self):\n", - " return {**{k:v.values for k,v in (self._ctxs | {'self': self}).items()}, **self.values}\n", - " \n", - " @property\n", - " def comps(self): return self._ctxs\n", - " def comp(self, k: str) -> ContextVisor | None:\n", - " return self._ctxs.get(k)\n", - " def handler(self, k: str) -> ContextVisor | None:\n", - " return self._hdlrs.get(k)\n", - " \n", - " @property\n", - " def styler(self) -> W.Output | None:\n", - " if (stl := self.setup_style()) is None: \n", - " return None\n", - " if getattr(self, '_style', None) is None:\n", - " self._style = W.Output(layout={'height': '0px'})\n", - " with self._style:\n", - " display(stl)\n", - " return self._style\n", - " def setup_style(self):\n", - " return HTML(f\"\") if self._css else None\n", - " \n", - " def update_output(self, **kwargs): \n", - " cprint(kwargs)\n", - " \n", - " def setup_controls(self) -> dict[str, W.ValueWidget | W.fixed]:\n", - " return {k: W.Label(value=k) for k,v in self.values.items()}\n", - " \n", - " def hide(self):\n", - " self.w.layout.visibility = 'hidden'\n", - " def show(self):\n", - " self.w.layout.visibility = 'visible'\n", - "\n", - " def setup_ui(self):\n", - " comps = []\n", - " for visor in self._ctxs.values():\n", - " comps.append(visor.w)\n", - " return W.HBox([*comps, *self.controls.values()])\n", - "\n", - " def setup_display(self): \n", - " if getattr(self, '_w', None) is None:\n", - " self._w = self.setup_ui()\n", - " \n", - "\n", - " def _output(self, **kwargs):\n", - " collator = defaultdict(dict)\n", - " show_inline_matplotlib_plots()\n", - " with self.out:\n", - " clear_output(wait=True)\n", - " for k,v in kwargs.items():\n", - " if (comp := self.handler(k)) is not None:\n", - " collator[comp][k] = v\n", - " else:\n", - " assert 0\n", - " # self.update_output(**{k: v})\n", - " for comp, kw in collator.items():\n", - " comp.update_output(**kw)\n", - " show_inline_matplotlib_plots()\n", - " def interactive_output(self):\n", - " controls = self.all_controls\n", - " controls2names = {v:k for k,v in controls.items()}\n", - " def observer(change):\n", - " control_name = controls2names[change['owner']]\n", - " kwargs = {control_name: change['new']}\n", - " updated = self._update(**kwargs)\n", - " self._output(**updated)\n", - " for w in controls.values():\n", - " w.observe(observer, 'value')\n", - " def display(self, **kwargs): \n", - " if getattr(self, '_w', None) is None:\n", - " self.setup_display()\n", - " self.interactive_output()\n", - " self._update(**(self.values | kwargs))\n", - " all_values= {}\n", - " for comp in list(self.comps.values()) + [self]: all_values.update(comp.values)\n", - " self._hdlrs = {k:self._hdlrs.get(k, self) for k in all_values}\n", - " self._output(**all_values)\n", - " display(self.styler, self.w, self.out) if self.styler else display(self.w, self.out)\n", - " else:\n", - " self.update(**kwargs)\n", - " def _ipython_display_(self): self.display()\n", - "\n", - " def _update(self, update_value: bool=True, **kwargs):\n", - " updated = {}\n", - " for visor in self.comps.values():\n", - " updated.update(visor._update(update_value=update_value, **kwargs))\n", - " values = self.values\n", - " my_vals = _pops_(kwargs, self.values.keys())\n", - " for k,v in my_vals.items():\n", - " if v is not None and v != values[k]:\n", - " if update_value: values[k] = v\n", - " updated[k] = v\n", - " return updated\n", - " def update(self, **kwargs):\n", - " updated = self._update(update_value=False, **kwargs)\n", - " controls = self.all_controls\n", - " for k in updated:\n", - " controls[k].value = updated[k]\n", - " # self._output(**updated)\n", - " \n", - " def __init__(self, \n", - " ctx: Any, \n", - " values: dict[str, Any], \n", - " out: W.Output | None = None,\n", - " ctxs: dict[str, ContextVisor] | None = None,\n", - " hdlrs: dict[str, ContextVisor] | None = None,\n", - " ):\n", - " self._ctxs = ctxs or {}\n", - " self._hdlrs = hdlrs or {}\n", - " self.ctx = ctx\n", - " self._out = out\n", - " self.values = values\n", - " \n" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "82c802235bf84f6eb36d87cd72607440", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(Label(value='a'),))" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4f0809d6276b4bea9f0f992b337817a8", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "cleanupwidgets('test_visor')\n", - "\n", - "test_visor = ContextVisor(None, {'a': 1})\n", - "test_visor\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "test_eq(test_visor.values, {'a': 1})\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# CONTEXT\n", - "> `CONTEXT` is an `OCRExperimentContext` object that contains the configuration and the list of image paths.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can get the configuration with `OCRExperimentContext.get_config()`.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current Configuration:\n", - "\n", - "Locale: System default\n", - "Default Profile: Built-in\n", - "Saved Profiles:\n", - "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", - "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", - "\n", - "Profile Editor: cursor\n", - "Cache Directory: .\n", - "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", - "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", - "GUI Theme: System default\n", - "\n", - "--------------------\n", - "\n", - "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", - "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" - ] - }, - { - "data": { - "text/html": [ - "
      cache_dir: Path('cleaner')\n",
-       "     model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
-       "         device: 'mps'\n",
-       "
\n" - ], - "text/plain": [ - " cache_dir: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'cleaner'\u001b[0m\u001b[1m)\u001b[0m\n", - " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", - " device: \u001b[32m'mps'\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "CONFIG = OCRExperimentContext.get_config()\n", - "\n", - "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", - "model_path = CONFIG.get_model_path(gpu)\n", - "device = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n", - "\n", - "CONFIG.show()\n", - "cprint(\n", - " f\"{'cache_dir':>15}: {repr(cache_dir)}\\n\"\n", - " f\"{'model_path':>15}: {repr(model_path)}\\n\"\n", - " f\"{'device':>15}: {repr(device)}\")\n", - "\n", - "test_eq(CONFIG.cache_dir, Path(\".\"))\n", - "test_eq(CONFIG.current_profile.preprocessor.ocr_enabled, True)\n", - "test_eq(CONFIG.current_profile.preprocessor.ocr_max_size, 10**10)\n", - "test_eq(CONFIG.current_profile.preprocessor.suspicious_box_min_size, 10**10)\n", - "test_eq(CONFIG.current_profile.preprocessor.ocr_blacklist_pattern, \".*\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "CONTEXT = OCRExperimentContext(CONFIG, IMAGE_PATHS)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ImageSelector" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class ImageSelector(ContextVisor):\n", - " ctx: OCRExperimentContext\n", - "\n", - " @property\n", - " def image_ctx(self):\n", - " return ImageContext(self.ctx, self.values['image_idx'])\n", - " \n", - " def setup_controls(self):\n", - " paths = self.ctx.image_paths\n", - " w = W.Dropdown(\n", - " options={_.stem:i for i,_ in enumerate(paths)}, \n", - " value=self.values['image_idx'],\n", - " layout={'width': 'fit-content'},\n", - " style={'description_width': 'initial'})\n", - " return {'image_idx': w}\n", - "\n", - " def update(self, image_idx: ImgSpecT | None = None, **kwargs):\n", - " if image_idx is None: return\n", - " idx = self.ctx.normalize_idx(image_idx)\n", - " if idx is None: return\n", - " super().update(image_idx=idx, **kwargs)\n", - "\n", - "\n", - " def __init__(self, \n", - " ctx: OCRExperimentContext, /, \n", - " image_idx: ImgSpecT = 0, *, \n", - " out: W.Output | None=None):\n", - " idx = ctx.normalize_idx(image_idx)\n", - " assert idx is not None, f\"Image {image_idx} not found in experiment context\"\n", - " super().__init__(ctx, {'image_idx': idx}, out)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "c033b2c76629478f8d7702e1f3f8666a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(Dropdown(index=2, layout=Layout(width='fit-content'), options={'Action_Comics_1960-01-00_(262)'…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d78cb5cf72c34bcab9274cfd77f585a5", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "cleanupwidgets('image_selector')\n", - "\n", - "image_selector = ImageSelector(CONTEXT, 2)\n", - "image_selector\n" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "image_selector.update(13)\n", - "test_eq(image_selector.values['image_idx'], 13)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# OCRContextVisor" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "class OCRContextVisor(ContextVisor):\n", - " ctx: OCRExperimentContext\n", - " \n", - " def update_output(self, /, image_idx: ImgIdT, **kwargs):\n", - " img_path = self.ctx.path_from_idx(image_idx)\n", - " display_image_grid([img_path], 1, 1)\n", - "\n", - " def update(self, image_idx: ImgSpecT | None = None, **kwargs):\n", - " if image_idx is None: return\n", - " idx = self.ctx.normalize_idx(image_idx)\n", - " if idx is None: return\n", - " super().update(image_idx=idx, **kwargs)\n", - " \n", - " def __init__(self, \n", - " ctx: OCRExperimentContext, /, \n", - " image_idx: ImgSpecT = 0, *, \n", - " out: W.Output | None=None):\n", - " super().__init__(ctx, {}, out, \n", - " ctxs={'image_idx': ImageSelector(ctx, image_idx, out=self.out)})\n" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "3b40f82e57564fbcae7913d7a76fbc32", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Dropdown(index=2, layout=Layout(width='fit-content'), options={'Action_Comics_19…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "174fbbc4b6ff42ac8013984946e787e4", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "cleanupwidgets('ctx_visor')\n", - "\n", - "# ContextVisor(CONTEXT)\n", - "# ContextVisor(CONTEXT).display(3)\n", - "ctx_visor = OCRContextVisor(CONTEXT, 2)\n", - "ctx_visor\n" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [], - "source": [ - "ctx_visor.update('Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Base image\n", - "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below." - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [], - "source": [ - "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", - "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"0033\")\n", - "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"INOUE_KYOUMEN_002\")\n", - "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"Action_Comics_1960-01-00_(262)\")\n", - "\n", - "assert BASE_IMAGE_IDX is not None\n", - "img_path = Path(CONTEXT.image_paths[BASE_IMAGE_IDX])\n", - "assert img_path.exists()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Empty cache\n", - "> Clear the image cache used profusely throughout the examples below." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "You will be warned before the cache is emptied." - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [], - "source": [ - "# CONTEXT.empty_cache_warn()" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [], - "source": [ - "# CONTEXT.empty_cache_warn(BASE_IMAGE_IDX)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ImageContext of base image\n", - "> Creates the `ImageContext` for the base image.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If `PanelCleaner` page data is already cached, it is loaded from the cache.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [], - "source": [ - "CONTEXT.reset()" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "page_lang = 'English'\n", - "# page_lang = 'Japanese'\n", - "# page_lang = 'Spanish'\n", - "# page_lang = 'French'\n", - "\n", - "IMAGE_CONTEXT = ImageContext(CONTEXT, BASE_IMAGE_IDX, page_lang=page_lang)\n", - "test_eq(IMAGE_CONTEXT.page_data is not None, True)\n", - "# cprint(IMAGE_CONTEXT.page_data.boxes)\n", - "RenderJSON(IMAGE_CONTEXT.json_data, 360, 2)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [], - "source": [ - "test_is(IMAGE_CONTEXT, ImageContext(CONTEXT, BASE_IMAGE_IDX))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Visualize image" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Strange_Tales_172005.jpg - 1275x1888 px: 4.25x6.29\" @ 188.32 dpi
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "page_data = IMAGE_CONTEXT.page_data\n", - "display_image_grid([page_data.image_path, page_data.mask_path], 1, 2, caption=IMAGE_CONTEXT.image_name_rich)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "_, out_path = page_boxes(page_data)\n", - "display_image_grid([out_path], 1, 1)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ModelSelector\n" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class OCRModel(Enum):\n", - " TESSERACT = 0\n", - " IDEFICS = 1\n", - " @staticmethod\n", - " def __display_names__() -> dict[str, OCRModel]:\n", - " return dict(\n", - " zip(\"Tesseract, Idefics\".split(', '), \n", - " OCRModel))\n", - "\n", - "\n", - "class ModelSelector(ContextVisor):\n", - " ctx: OCRExperimentContext\n", - " \n", - " def setup_controls(self):\n", - " options = self.models\n", - " w = W.Dropdown(\n", - " options=options, \n", - " value=self.values['model'],\n", - " layout={'width': 'fit-content'},\n", - " style={'description_width': 'initial'})\n", - " return {'model': w}\n", - "\n", - " def setup_ui(self):\n", - " ctls = self.controls\n", - " model_grp = W.HBox([ctls['model']])\n", - " model_grp.add_class('model_grp')\n", - " comps = []\n", - " for visor in self.comps.values():\n", - " comps.append(visor.setup_ui())\n", - " ui = W.HBox([*comps, model_grp])\n", - " return ui\n", - "\n", - " def __init__(self, \n", - " exp_ctx: OCRExperimentContext,\n", - " ocr_model: OCRModel | None=OCRModel.TESSERACT,\n", - " ocr_models: dict[str, OCRModel] | None = None,\n", - " out: W.Output | None = None\n", - " ):\n", - " self.models: dict[str, OCRModel] = ocr_models or OCRModel.__display_names__()\n", - " super().__init__(exp_ctx, \n", - " {'model': ocr_model or OCRModel.TESSERACT}, \n", - " out=out or self.out)#, ctxs=[exp_visor])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "413f66f1d43a4d849e43a79ca9b16502", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), options={'Tesseract': 30}: {w} x {h} pixels\\n\"\n", - " f\"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\\n\"\n", - " f\"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in\"\n", - " f\" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\\n\"\n", - " f\"Required DPI Modern Age format: {required_dpi:.3f} dpi \"\n", - " f\"({format[0]:.3f} x {format[1]:.3f} in)\")\n", - "\n", - "\n", - " def display_content(self, image_ctx: ImageContext, display_option: DisplayOptions):\n", - " page_data = image_ctx.page_data\n", - " if display_option in (DisplayOptions.ALL, DisplayOptions.PAGE_DATA):\n", - " self.image_info(image_ctx)\n", - " RenderJSON(image_ctx.json_data, 350, 2).display()\n", - " if display_option in (DisplayOptions.ALL, DisplayOptions.GROUND_TRUTH):\n", - " cprint(image_ctx.gts)\n", - " if display_option == DisplayOptions.IMAGE:\n", - " display_image_grid([page_data.image_path], 1, 1)\n", - " if display_option == DisplayOptions.MASK:\n", - " display_image_grid([page_data.mask_path], 1, 1)\n", - " if display_option in (DisplayOptions.ALL, DisplayOptions.IMAGE_MASK):\n", - " display_image_grid([page_data.image_path, page_data.mask_path], 1, 2)\n", - " if display_option in (DisplayOptions.ALL, DisplayOptions.BOXES):\n", - " _, out_path = page_boxes(page_data)\n", - " display_image_grid([out_path], 1, 1)\n", - "\n", - "\n", - " def setup_controls(self):\n", - " options = self.display_options or {**DisplayOptions.__display_names__()}\n", - " display_option_wdgt = W.Dropdown(\n", - " options=options, \n", - " value=self.values['display_option'],\n", - " layout={'width': '120px'},\n", - " style={'description_width': 'initial'})\n", - " return {'display_option': display_option_wdgt}\n", - "\n", - "\n", - " def setup_ui(self):\n", - " ctls = self.controls\n", - " display_option_grp = W.HBox([ctls['display_option']])\n", - " display_option_grp.add_class('display_option_grp')\n", - " comps = []\n", - " for visor in self.comps.values():\n", - " comps.append(visor.setup_ui())\n", - " ui = W.HBox([*comps, display_option_grp])\n", - " return ui\n", - "\n", - "\n", - " def __init__(self, \n", - " exp_ctx: OCRExperimentContext,\n", - " display_option: DisplayOptions | None=DisplayOptions.BOXES,\n", - " display_options: Mapping[str, DisplayOptions] | None = None,\n", - " out: W.Output | None = None\n", - " ):\n", - " self.display_options = display_options\n", - " super().__init__(exp_ctx, \n", - " {'display_option': display_option or DisplayOptions.BOXES}, \n", - " out=out or self.out)#, ctxs=[exp_visor])\n" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "51b272e199e94fe69465b30306499d8a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Dropdown(index=2, layout=Layout(width='120px'), options={'Boxes': Width x Height: 1275 x 1888 pixels\n", - " PIL Info DPI: None\n", - " Print Size 300 DPI: 4.250 x 6.293 in / 10.795 x 15.985 cm\n", - "Required DPI Modern Age format: 188.324 dpi (6.625 x 10.250 in)\n", - "\n" - ], - "text/plain": [ - " Width x Height: \u001b[1;36m1275\u001b[0m x \u001b[1;36m1888\u001b[0m pixels\n", - " PIL Info DPI: \u001b[3;35mNone\u001b[0m\n", - " Print Size \u001b[1;36m300\u001b[0m DPI: \u001b[1;36m4.250\u001b[0m x \u001b[1;36m6.293\u001b[0m in \u001b[35m/\u001b[0m \u001b[1;36m10.795\u001b[0m x \u001b[1;36m15.985\u001b[0m cm\n", - "Required DPI Modern Age format: \u001b[1;36m188.324\u001b[0m dpi \u001b[1m(\u001b[0m\u001b[1;36m6.625\u001b[0m x \u001b[1;36m10.250\u001b[0m in\u001b[1m)\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "img = IMAGE_CONTEXT.base_image\n", - "w, h = img.size\n", - "\n", - "print_size_in = size(w, h, 'in', 300)\n", - "print_size_cm = size(w, h, 'cm', 300)\n", - "required_dpi = dpi(w, h, 'Modern Age')\n", - "format = PRINT_FORMATS['Modern Age']\n", - "cprint( f\"{'Width x Height':>30}: {w} x {h} pixels\\n\"\n", - " f\"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\\n\"\n", - " f\"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in\"\n", - " f\" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\\n\"\n", - " f\"Required DPI Modern Age format: {required_dpi:.3f} dpi ({format[0]:.3f} x {format[1]:.3f} in)\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "((1275, 1888),\n", - " (4.25, 6.293333333333333),\n", - " (10.795, 15.985066666666667),\n", - " 188.32397606994937)" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
                Width x Height: 804 x 1241 pixels\n",
-       "                  PIL Info DPI: None\n",
-       "            Print Size 300 DPI: 2.680 x 4.137 in / 6.807 x 10.507 cm\n",
-       "Required DPI Modern Age format: 121.216 dpi (6.625 x 10.250 in)\n",
-       "
\n" - ], - "text/plain": [ - " Width x Height: \u001b[1;36m804\u001b[0m x \u001b[1;36m1241\u001b[0m pixels\n", - " PIL Info DPI: \u001b[3;35mNone\u001b[0m\n", - " Print Size \u001b[1;36m300\u001b[0m DPI: \u001b[1;36m2.680\u001b[0m x \u001b[1;36m4.137\u001b[0m in \u001b[35m/\u001b[0m \u001b[1;36m6.807\u001b[0m x \u001b[1;36m10.507\u001b[0m cm\n", - "Required DPI Modern Age format: \u001b[1;36m121.216\u001b[0m dpi \u001b[1m(\u001b[0m\u001b[1;36m6.625\u001b[0m x \u001b[1;36m10.250\u001b[0m in\u001b[1m)\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "display(IMAGE_CONTEXT.image_info)\n", - "img_visor.image_info()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Balloons and Captions Ground Truth\n", - "> The ground truth for the balloons and captions is read from a `.txt` file.\n", - "\n", - "The file is named `.gt.txt` and contains one entry per line, corresponding to each balloon or caption in the order found in PanelClenaer page data.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.',\n", - " 'The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home--',\n", - " 'And one in need of some help, it would appear.',\n", - " 'Bambu-- we have a guest.',\n", - " '--and tonight, he comes most urgently, slamming open the oaken front doors!',\n", - " 'Tell me, master-- how may Bambu serve?',\n", - " 'Some blankets to keep her warm, Bambu-- and perhaps some dry clothes',\n", - " \"The echo of the old man's footsteps fades down the hall as...\",\n", - " 'How curious the whims of fate. Had I not chanced to stroll along the river tonight--',\n", - " 'As quickly as I can, master',\n", - " '--the girl would most surely be dead by now.',\n", - " 'Ghede has been generous. the Death God has given the girl a second chance at--',\n", - " \"Easy, girl-- there's nothing to scream about anymore.\",\n", - " \"You're among friends now, you're safe!\",\n", - " 'Continued after next page']" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "IMAGE_CONTEXT.gts\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Experiment\n", - "> Use `ExperimentOCR` to perform OCR on the page balloons given a `CropMethod` and a model (i.e., `'Tesseract'` or `'Idefics'`)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "\n", - "def trimmed_mean(data, trim_percent):\n", - " sorted_data = np.sort(data)\n", - " n = len(data)\n", - " trim_count = int(trim_percent * n)\n", - " trimmed_data = sorted_data[trim_count:-trim_count]\n", - " return np.mean(trimmed_data)\n", - "\n", - "def mad_based_outlier(points, threshold=3.5):\n", - " median = np.median(points)\n", - " diff = np.abs(points - median)\n", - " mad = np.median(diff)\n", - " modified_z_score = 0.6745 * diff / mad\n", - " return points[modified_z_score < threshold]\n", - "\n", - "def iqr_outlier_removal(data):\n", - " q1 = np.percentile(data, 25)\n", - " q3 = np.percentile(data, 75)\n", - " iqr = q3 - q1\n", - " lower_bound = q1 - 1.5 * iqr\n", - " upper_bound = q3 + 1.5 * iqr\n", - " return data[(data >= lower_bound) & (data <= upper_bound)]\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "@dataclasses.dataclass\n", - "class Experiment:\n", - " ctx: ExperimentContext\n", - "\n", - "\n", - "@dataclasses.dataclass\n", - "class ExperimentOCR(Experiment):\n", - " ctx: ImageContext\n", - " ocr_model: str\n", - "\n", - " @property\n", - " def img_ctx(self): return self.ctx\n", - " @property\n", - " def ctxs(self):\n", - " img_ctx = self.img_ctx\n", - " return cast(OCRExperimentContext, img_ctx.exp), img_ctx\n", - "\n", - " @classmethod\n", - " def file_path_of(cls, page_data: st.PageData, ocr_model: str):\n", - " return f\"{Path(page_data.original_path).stem}_{ocr_model}.json\"\n", - " \n", - " def file_path(self):\n", - " img_ctx = self.img_ctx\n", - " return type(self).file_path_of(img_ctx.page_data, self.ocr_model)\n", - " \n", - " def to_dict(self):\n", - " \"JSON serializable dict of the experiment\"\n", - " img_ctx = self.img_ctx\n", - " img_idx = img_ctx.image_idx\n", - " results = results_to_dict(self.results())\n", - " return {\n", - " 'image_name': img_ctx.image_name,\n", - " 'ocr_model': self.ocr_model, \n", - " 'results': results,\n", - " }\n", - "\n", - " def to_json(self, out_dir: Path | None = None):\n", - " img_ctx = self.img_ctx\n", - " fp = (out_dir or img_ctx.cache_dir_image) / self.file_path()\n", - " data = self.to_dict()\n", - " with open(fp, 'w') as f:\n", - " json.dump(data, f, indent=2)\n", - " return fp, data\n", - "\n", - " @classmethod\n", - " def from_json(cls, experiment: OCRExperimentContext, json_path: Path) -> Self:\n", - " try:\n", - " with open(json_path, 'r') as f:\n", - " data = json.load(f)\n", - " except Exception as e:\n", - " logger.error(f\"Error loading {json_path}: {e}\")\n", - " raise e\n", - " ocr_model = data['ocr_model']\n", - " img_ctx = ImageContext(experiment, data['image_name'])\n", - " results: ResultSetDefault = dict_to_results(\n", - " img_ctx.image_idx, \n", - " data['results'], \n", - " result_factory=experiment._result_from)\n", - " experiment.update_results(ocr_model, img_ctx.image_idx, results)\n", - " return cls(img_ctx, ocr_model)\n", - "\n", - " @classmethod\n", - " def from_image(cls, \n", - " ctx: OCRExperimentContext, \n", - " ocr_model: str, \n", - " image_idx: ImgSpecT):\n", - " idx = cast(ImgIdT, ctx.normalize_idx(image_idx))\n", - " img_ctx = ImageContext(ctx, idx)\n", - " if img_ctx is None:\n", - " raise ValueError(f\"Image {image_idx} not found in experiment context\")\n", - " fp = img_ctx.cache_dir / cls.file_path_of(img_ctx.page_data, ocr_model)\n", - " if fp.exists(): \n", - " return cast(Self, cls.from_json(cast(OCRExperimentContext, img_ctx.exp), fp))\n", - " return cls(img_ctx, ocr_model)\n", - "\n", - " @classmethod\n", - " def from_method(cls, \n", - " ctx: OCRExperimentContext, \n", - " ocr_model: str, \n", - " image_idx: ImgIdT | str | Path, \n", - " method: CropMethod):\n", - " experiment = cls.from_image(ctx, ocr_model, image_idx)\n", - " if experiment is None:\n", - " return None\n", - " return experiment.method_experiment(method)\n", - "\n", - " @classmethod\n", - " def saved_experiment(cls, \n", - " ctx: OCRExperimentContext, ocr_model: str, image_idx: ImgIdT | str | Path):\n", - " idx = ctx.normalize_idx(image_idx)\n", - " if idx is None: \n", - " logger.warning(f\"Image {image_idx} not found in experiment context\")\n", - " return None\n", - " return cls.from_image(ctx, ocr_model, idx)\n", - "\n", - " @classmethod\n", - " def saved_experiments(cls, ctx: OCRExperimentContext, ocr_model: str) -> list[Self]:\n", - " return [exp for i in range(len(ctx.image_paths))\n", - " if (exp := cls.from_image(ctx, ocr_model, i)) is not None]\n", - " \n", - "\n", - " def result(self, box_idx: BoxIdT, method: CropMethod, ocr: bool=True, rebuild: bool=False):\n", - " ctx, img_ctx = self.ctxs\n", - " return ctx.result(self.ocr_model, img_ctx.image_idx, box_idx, method, ocr, rebuild)\n", - "\n", - " def results(self):\n", - " ctx, img_ctx = self.ctxs\n", - " return cast(ResultSet, ctx.results(self.ocr_model, img_ctx.image_idx))\n", - "\n", - " def has_run(self):\n", - " \"at least one method has run\"\n", - " img_ctx = self.img_ctx\n", - " return len(self.results()) == len(img_ctx.page_data.boxes)\n", - " \n", - " def best_results(self):\n", - " img_ctx = self.img_ctx\n", - " results = self.results()\n", - " if len(results) < len(img_ctx.page_data.boxes): # at least one method has run\n", - " return None\n", - " best = []\n", - " for box_idx in results:\n", - " methods = results[box_idx]\n", - " best_method = max(methods, key=lambda m: methods[m].acc) # type: ignore\n", - " best.append((best_method, methods[best_method]))\n", - " return best\n", - "\n", - " def save_results_as_ground_truth(self, overwrite=False):\n", - " img_ctx = self.img_ctx\n", - " gts_path = ground_truth_path(img_ctx.page_data)\n", - " if overwrite or not gts_path.exists():\n", - " best_results = self.best_results()\n", - " if best_results:\n", - " tt = [r.ocr for m,r in best_results]\n", - " gts_path.write_text('\\n'.join(tt), encoding=\"utf-8\")\n", - " img_ctx.setup_ground_truth()\n", - " logger.info(f\"Ground truth data saved successfully to {gts_path}\")\n", - " return True\n", - " else:\n", - " logger.info(\"No best results available to save.\")\n", - " return False\n", - " else:\n", - " return False\n", - "\n", - " @property\n", - " def experiments(self):\n", - " if not hasattr(self, '_experiments'):\n", - " self._experiments = {}\n", - " return self._experiments\n", - " def method_experiment(self, method: CropMethod) -> ExperimentOCRMethod:\n", - " if method not in self.experiments:\n", - " self.experiments[method] = ExperimentOCRMethod(self, method)\n", - " return self.experiments[method]\n", - " \n", - "\n", - " def to_dataframe(self):\n", - " \"Dataframe with crop methods as columns and box ids as rows\"\n", - " methods = list(CropMethod.__members__.values())\n", - " experiments = [self.method_experiment(m) for m in methods]\n", - " accuracies = [[result.acc for result in exp.results()] for exp in experiments]\n", - " # transpose accuracies\n", - " accuracies = list(zip(*accuracies))\n", - " return pd.DataFrame(accuracies, columns=CropMethod.__display_names__())\n", - "\n", - " def plot_accuracies(self, \n", - " methods: list[CropMethod] | None = None, \n", - " ):\n", - " \"Plots a horizontal bar chart of the accuracies for a list of method experiments.\"\n", - " methods = methods or list(CropMethod.__members__.values())\n", - " experiments = [self.method_experiment(m) for m in methods]\n", - " if not experiments: return\n", - "\n", - " ctx, img_ctx = self.ctxs\n", - " page_data = img_ctx.page_data\n", - " model = self.ocr_model\n", - " accuracies = [[result.acc for result in exp.results()] for exp in experiments]\n", - " accuracies = [np.mean(a) for a in accuracies]\n", - " # accuracies = [np.mean([result.acc for result in exp.results()]) for exp in experiments]\n", - "\n", - " _, ax = plt.subplots(figsize=(10, 5))\n", - " \n", - " # Normalize the accuracies for color mapping\n", - " norm = plt.Normalize(min(accuracies), max(accuracies))\n", - " # Color map from red to green\n", - " cmap = plt.get_cmap('RdYlGn')\n", - " colors = cmap(norm(accuracies))\n", - "\n", - " ax.barh([m.value for m in methods], accuracies, color=colors)\n", - "\n", - " ax.set_xscale('log') # Set the x-axis to a logarithmic scale\n", - " ax.set_xlabel('Average Accuracy (log scale)', fontsize=12, fontweight='bold')\n", - "\n", - " ax.set_ylabel('Method', fontsize=12, fontweight='bold')\n", - " ax.set_yticks(range(len(methods)))\n", - " ax.set_yticklabels([f'{method.value} ({acc:.2f})' \n", - " for method, acc in zip(methods, accuracies)], fontsize=12)\n", - " max_acc_index = np.argmax(accuracies)\n", - " ax.get_yticklabels()[max_acc_index].set(color='blue', fontweight='bold')\n", - "\n", - " title_text = (f\"{page_data.original_path} - OCR model: {model}\")\n", - " ax.set_title(title_text, fontsize=12, fontweight='bold')\n", - "\n", - " plt.tight_layout()\n", - " plt.show()\n", - "\n", - "\n", - " def summary_box(self, box_idx: int):\n", - " results: list[tuple[CropMethod, ResultOCR]] = []\n", - " pb = tqdm(CropMethod.__members__.values(), leave=False, desc=f\"Box #{box_idx+1}\")\n", - " for m in pb:\n", - " r = cast(ResultOCR, self.result(box_idx, m))\n", - " results.append((m, r))\n", - " methods, images, ocrs, accs = zip(\n", - " *map(\n", - " lambda t: (t[0].value, t[1].cache_image(), t[1].diff_tagged(), acc_as_html(t[1].acc)), \n", - " results))\n", - " display_columns([methods, images, accs, ocrs], \n", - " headers=[\"Method\", f\"Box #{box_idx+1}\", \"Accuracy\", \"OCR\"])\n", - "\n", - "\n", - " def summary_method(self, method: CropMethod):\n", - " results = self.method_experiment(method).results()\n", - " methods, images, ocrs, accs = zip(\n", - " *map(\n", - " lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), \n", - " results))\n", - " display_columns([methods, images, accs, ocrs], \n", - " headers=[\"Box #\", \"Box\", \"Accuracy\", f\"{method.value} OCR\"])\n", - "\n", - "\n", - " def display(self):\n", - " out = []\n", - " for method in CropMethod:\n", - " out.append(f\"---------- {method.value} ----------\")\n", - " results = self.method_experiment(method).results()\n", - " out.extend(results)\n", - " out.append('\\n')\n", - " cprint(*out, soft_wrap=True)\n", - "\n", - "\n", - " def reset(self, box_idx: int | None = None, method: CropMethod | None = None):\n", - " ctx, img_ctx = self.ctxs\n", - " ctx.reset_results(None, img_ctx.image_idx, box_idx, method)\n", - "\n", - " def perform_methods(self, \n", - " methods: CropMethod | list[CropMethod] | None = None, \n", - " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n", - " rebuild: bool = False,\n", - " plot_acc: bool = False\n", - " ):\n", - " if methods is None:\n", - " methods = [*CropMethod.__members__.values()]\n", - " elif isinstance(methods, CropMethod):\n", - " methods = [methods]\n", - " if rebuild:\n", - " _methods = tqdm(methods, desc=\"Methods\")\n", - " else:\n", - " _methods = methods\n", - " for method in _methods:\n", - " method_exp = self.method_experiment(method)\n", - " if method_exp: \n", - " if rebuild:\n", - " method_exp(box_idxs, rebuild=rebuild)\n", - " if plot_acc:\n", - " self.plot_accuracies()\n", - "\n", - " def __call__(self, \n", - " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n", - " methods: CropMethod | list[CropMethod] | None = None, \n", - " save: bool = True,\n", - " display=False, \n", - " rebuild: bool=False, \n", - " save_as_ground_truth=False):\n", - " self.perform_methods(methods, box_idxs, rebuild=rebuild)\n", - " if save_as_ground_truth:\n", - " self.save_results_as_ground_truth(overwrite=True)\n", - " if save:\n", - " self.to_json()\n", - " if display:\n", - " self.display()\n", - " \n", - "\n", - "@dataclasses.dataclass\n", - "class ExperimentOCRMethod:\n", - " ctx: ExperimentOCR\n", - " method: CropMethod\n", - "\n", - " @property\n", - " def exp_ctx(self): return self.ctx\n", - " @property\n", - " def img_ctx(self): return self.ctx.ctx\n", - " @property\n", - " def ctxs(self):\n", - " img_ctx = self.img_ctx\n", - " return cast(OCRExperimentContext, img_ctx.exp), img_ctx, self.ctx\n", - " \n", - " def result(self, box_idx: BoxIdT, ocr: bool=True, rebuild: bool=False) -> ResultOCR | None:\n", - " ctx, img_ctx, exp_ctx = self.ctxs\n", - " return ctx.result(exp_ctx.ocr_model, img_ctx.image_idx, box_idx, self.method, ocr, rebuild)\n", - "\n", - " def results(self, \n", - " box_idxs: BoxIdT | list[BoxIdT] | None = None, \n", - " ocr: bool=True, rebuild: bool=False) -> list[ResultOCR]:\n", - " ctx, img_ctx, exp_ctx = self.ctxs\n", - " if box_idxs is None:\n", - " box_idxs = list(range(len(img_ctx.boxes)))\n", - " elif isinstance(box_idxs, int):\n", - " box_idxs = [box_idxs]\n", - " model = exp_ctx.ocr_model\n", - " results = ctx.method_results(model, img_ctx.image_idx, self.method)\n", - " results = {i:results[i] if i in results else None for i in box_idxs}\n", - " pb = rebuild or not results or any(r is None for r in results.values())\n", - " if pb and len(results) > 2:\n", - " progress_bar = tqdm(list(results.keys()), desc=f\"{self.method.value} - {model}\")\n", - " else:\n", - " progress_bar = list(results.keys())\n", - " results = []\n", - " for i in progress_bar:\n", - " results.append(self.result(i, ocr, rebuild=rebuild))\n", - " return results\n", - "\n", - "\n", - " def get_results_html(self, \n", - " box_idxs: BoxIdT | list[BoxIdT] | None = None,\n", - " max_image_width: int | None = None): \n", - " _, img_ctx, exp_ctx = self.ctxs\n", - " results: list[ResultOCR] = self.results(box_idxs)\n", - " accs = np.array([r.acc for r in results])\n", - " mean_accuracy = np.mean(accs)\n", - " mean_trimmed = trimmed_mean(accs, 0.1)\n", - " # filtered_data = mad_based_outlier(accs)\n", - " # mean_mad = np.mean(filtered_data)\n", - " # filtered_data = iqr_outlier_removal(accs)\n", - " # mean_iqr = np.mean(filtered_data)\n", - " \n", - " descriptions, images, ocrs, accs = zip(*map(\n", - " lambda r: (\n", - " r.block_idx+1, \n", - " r.cache_image(), \n", - " r.diff_tagged(), \n", - " acc_as_html(r.acc)\n", - " ), results))\n", - " non_breakin_space = u'\\u00A0'\n", - " tmpl = \"{}\"\n", - " padded_s = lambda s,n: tmpl.format(s.rjust(n))\n", - " acc_fmt = f\"{mean_accuracy:.2f}/{mean_trimmed:.2f}\"\n", - " w, h = img_ctx.base_image.size\n", - " dim, _dpi = size(w, h), dpi(w, h)\n", - " dim_fmt = f\"{w}x{h} px: {dim[0]:.2f} x {dim[1]:.2f} in @ {_dpi:.2f} dpi\"\n", - " return '\\n
\\n'.join([\n", - " (\"
\"\n", - " f\"{padded_s('Page', 24)}: {img_ctx.page_data.original_path}
\"\n", - " f\"{padded_s('Size', 24)}: {dim_fmt}
\"\n", - " f\"{padded_s('Model', 24)}: {exp_ctx.ocr_model}
\"\n", - " f\"{padded_s('Crop Method', 24)}: {self.method.value}
\"\n", - " f\"{padded_s('Accuracy Mean/Trimmed', 24)}: {acc_fmt}\"\n", - " \"
\"), \n", - " get_columns_html(\n", - " [descriptions, images, accs, ocrs], \n", - " max_image_width, \n", - " headers=[\"Box #\", \"Image\", \"Accuracy\", \"OCR\"]),\n", - " ])\n", - "\n", - " def display(self, \n", - " box_idxs: BoxIdT | list[BoxIdT] | None = None, max_image_width: int | None = None):\n", - " display(HTML(self.get_results_html(box_idxs, max_image_width)))\n", - "\n", - "\n", - " def summary(self):\n", - " results = self.results()\n", - " methods, images, ocrs, accs = zip(\n", - " *map(\n", - " lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), \n", - " results))\n", - " display_columns([methods, images, accs, ocrs], \n", - " headers=[\"Box #\", \"Box\", \"Accuracy\", f\"{self.method.value} OCR\"])\n", - "\n", - "\n", - " def reset(self):\n", - " _, _, exp_ctx = self.ctxs\n", - " exp_ctx.reset(method=self.method)\n", - " \n", - " def __call__(self, box_idxs: BoxIdT | list[BoxIdT] | None = None, display=False, rebuild=False):\n", - " if isinstance(box_idxs, int):\n", - " result = self.result(cast(BoxIdT, box_idxs), rebuild=rebuild)\n", - " if result is not None and display:\n", - " result.display()\n", - " else:\n", - " results = self.results(box_idxs, rebuild=rebuild)\n", - " if results and display:\n", - " self.display(box_idxs)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Box id\n", - "> change `BOX_IDX` to use any box to test crop methods" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [], - "source": [ - "BOX_IDX = 0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Crop methods testing" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [], - "source": [ - "CONTEXT.reset()\n", - "test_eq(CONTEXT.results(), {})\n", - "\n", - "image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Tesseract')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Single box results\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### comics_text_detector initial boxes + padding" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Initial box" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m2024-05-10 20:25:26.385\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mpcleaner.ocr.ocr_mangaocr\u001b[0m:\u001b[36m__new__\u001b[0m:\u001b[36m15\u001b[0m - \u001b[1mCreating the MangaOcr instance\u001b[0m\n" - ] - }, - { - "data": { - "text/html": [ - "
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
0.90
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.⎕⎕

Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method = CropMethod.INITIAL_BOX\n", - "\n", - "result = image_experiment.result(BOX_IDX, method, ocr=False)\n", - "assert result is not None\n", - "\n", - "image = result.image\n", - "assert image is not None\n", - "text = CONTEXT.mocr('Tesseract', page_lang)(image)\n", - "result.ocr = postprocess_ocr(text)\n", - "result\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### PanelCleaner default pad" - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as
0.85
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orl⎕⎕⎕eans, kept tidy by a white-haired old man known only as Bambu.

Eneowered by great gnarled cypress jrfes, the ancient manor !⎕⎕⎕⎕⎕ alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired ao⎕⎕ han known only as⎕⎕⎕⎕⎕⎕⎕
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method = CropMethod.DEFAULT\n", - "\n", - "result = image_experiment.result(BOX_IDX, method, ocr=False)\n", - "assert result is not None\n", - "\n", - "CONTEXT.ocr_box(result, 'Tesseract', page_lang)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### PanelCleaner default pad, grey pad" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as
0.95
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as⎕⎕⎕⎕⎕⎕⎕
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method = CropMethod.DEFAULT_GREY_PAD\n", - "result = image_experiment.result(BOX_IDX, method)\n", - "result\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### padded, 4px" - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as
0.88
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orl⎕⎕⎕eans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired aolo man known only as⎕⎕⎕⎕⎕⎕⎕
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PADDED_4)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### padded, 8px" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as
0.88
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired aolo man known omy as⎕⎕⎕⎕⎕⎕⎕
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PADDED_8)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Extracted text" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Extracted text, initial box\n", - "\n", - "Unfortunately, the `comic-text_detector` does not remove letter holes from the text mask, despite using OpenCV. This oversight likely impacts the accuracy of the OCR results." - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.92
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu⎕⎕.

Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a white-haire old man known only as bambi] .
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method = CropMethod.EXTRACTED_INIT_BOX\n", - "# results[method] = IMAGE_CONTEXT.result(BOX_IDX, method)\n", - "# image = results[method].image\n", - "# assert image is not None\n", - "# results[method].ocr = postprocess_ocr(IMAGE_CONTEXT.mocr(image))\n", - "# display_extracted_result(None, None, results[method], IMAGE_CONTEXT.gts[BOX_IDX])\n", - "image_experiment.result(BOX_IDX, method)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### padded 4, extracted" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.91
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonsred by great shale cypress trees, the anci⎕⎕⎕ manor stands alone on the [tskirts of new orleans, kept tidy by a white-haired old man known only as b8ambl .
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PADDED_4_EXTRACTED)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### padded 8, extracted" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.94
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu⎕⎕.

Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as 8ambli .
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PADDED_8_EXTRACTED)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### padded 8, dilation 1, extracted" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.61
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

O⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕utskirts of new orleans, kept tipy by a white-haired old man known only as sams .
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PADDED_8_DILATION_1)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### padded 8, dilation 0.5, extracted" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.94
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PAD_8_FRACT_0_5)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### padded 8, dilation 0.2, extracted" - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.94
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PAD_8_FRACT_0_2)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Summary\n", - "> Use `ImageContext.summary_box` to display the results of the crop methods for OCR of a given box index.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "2b5b75333766431bb85d2ae72ee47b50", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Box #1: 0%| | 0/11 [00:00MethodBox #1AccuracyOCRInitial box
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
Default
0.85
Eneowered by great gnarled cypress jrfes, the ancient manor !⎕⎕⎕⎕⎕ alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired ao⎕⎕ han known only as⎕⎕⎕⎕⎕⎕⎕
Default, grey pad
0.95
Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as⎕⎕⎕⎕⎕⎕⎕
Padded 4px
0.88
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired aolo man known only as⎕⎕⎕⎕⎕⎕⎕
Padded 8px
0.88
Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired aolo man known omy as⎕⎕⎕⎕⎕⎕⎕
Extracted, init box
0.92
Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a white-haire old man known only as bambi] .
Padded 4, extracted
0.91
Enbonsred by great shale cypress trees, the anci⎕⎕⎕ manor stands alone on the [tskirts of new orleans, kept tidy by a white-haired old man known only as b8ambl .
Padded 8, extracted
0.94
Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as 8ambli .
Padded 8, dilation 1
0.61
O⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕utskirts of new orleans, kept tipy by a white-haired old man known only as sams .
Pad 8, fract. 0.5
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
Pad 8, fract. 0.2
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# methods, images, ocrs, accs = zip(\n", - "# *map(lambda t: (t[0].value, t[1].cache_image(), t[1].diff_tagged(), acc_as_html(t[1].acc)), \n", - "# IMAGE_CONTEXT.results[BOX_IDX].items()))\n", - "# display_columns([methods, images, accs, ocrs], headers=[\"Method\", \"Box\", \"Accuracy\", \"OCR\"])\n", - "\n", - "image_experiment.summary_box(BOX_IDX)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Show result for any box # and any method" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Tonight, he comes host slamming open
0.61
\n", - "
\n", - "
--and tonight, he comes most urgently, slamming open the oaken front doors!

T⎕⎕⎕⎕⎕⎕onight, he comes host⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(4, CropMethod.PADDED_8)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.67
\n", - "
\n", - "
Bambu-- we have a guest.

⎕⎕⎕⎕⎕⎕ we have a i=s7t.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(3, CropMethod.EXTRACTED_INIT_BOX)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ResultVisor" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class ResultVisor(ContextVisor):\n", - " ctx: ExperimentOCR\n", - " control_names: list[str] = ['all_boxes', 'box_idx', 'all_methods', 'method']\n", - "\n", - " _css = \"\"\"\n", - " .box_grp {\n", - " background-color: aliceblue;\n", - " }\n", - " .method_grp {\n", - " background-color: #ededed;\n", - " }\n", - " \"\"\"\n", - " \n", - " def best_results(self): \n", - " ll = self.ctx.best_results()\n", - " if ll:\n", - " cprint([(m.value, f\"{r.acc:.3f}\", r.ocr) for m,r in ll])\n", - "\n", - " def pd_to_html(self):\n", - " df = self.ctx.to_dataframe()\n", - " # set float precision\n", - " df = df.round(3)\n", - " # display floats with 3 decimal digits\n", - " df = df.applymap(lambda x: f\"{x:.3f}\")\n", - " # highlight max value in each row\n", - " stl = df.style.highlight_max(axis=0)\n", - " display(HTML(stl.to_html()))\n", - "\n", - " def update_output(self, **kwargs):\n", - " all_boxes: bool = self.values['all_boxes']\n", - " box_idx: int = self.values['box_idx']\n", - " all_methods: bool = self.values['all_methods']\n", - " method: CropMethod = self.values['method']\n", - "\n", - " # cprint(f\"all_boxes: {all_boxes}, box_idx: {box_idx}, all_methods: {all_methods}, method: {method}\")\n", - "\n", - " if all_boxes and all_methods:\n", - " self.ctx.plot_accuracies()\n", - " elif all_boxes:\n", - " self.ctx.summary_method(method)\n", - " elif all_methods:\n", - " self.ctx.summary_box(box_idx)\n", - " else:\n", - " result = self.ctx.result(box_idx, method)\n", - " if result is not None:\n", - " result.display()\n", - "\n", - " def setup_controls(self):\n", - " _, img_ctx = self.ctx.ctxs\n", - " values = self.values\n", - " box_wdgt = W.BoundedIntText(\n", - " value=values['box_idx'], min=0, max=len(img_ctx.boxes)-1, step=1,\n", - " disabled=values['all_boxes'],\n", - " layout={'width': '50px'},\n", - " style={'description_width': 'initial'})\n", - " methods_wdgt = W.Dropdown(\n", - " options=CropMethod.__display_names__(), \n", - " value=values['method'],\n", - " layout={'width': '150px'},\n", - " style={'description_width': 'initial'})\n", - " all_boxes_wdgt = W.Checkbox(label='All', value=values['all_boxes'], \n", - " description=\"all\", \n", - " layout={'width': 'initial'},\n", - " style={'description_width': '0px'})\n", - " all_methods_wdgt = W.Checkbox(label='All', value=values['all_methods'], \n", - " description=\"all\", \n", - " layout={'width': 'initial'},\n", - " style={'description_width': '0px'})\n", - " return {'all_boxes': all_boxes_wdgt, 'box_idx': box_wdgt, \n", - " 'all_methods': all_methods_wdgt, 'method': methods_wdgt}\n", - " \n", - " def setup_ui(self):\n", - " ctls = self.controls\n", - " _, img_ctx = self.ctx.ctxs\n", - " box_label = W.Label(\n", - " value=f\"Box # (of {len(img_ctx.boxes)}):\", \n", - " layout={'width': 'initial', 'padding': '0px 0px 0px 10px'})\n", - " method_label = W.Label(value='Method:', layout={'width': 'initial', 'padding': '0px 0px 0px 10px'})\n", - "\n", - " box_grp = W.HBox([box_label, ctls['all_boxes'], ctls['box_idx']])\n", - " box_grp.add_class('box_grp')\n", - " method_grp = W.HBox([method_label, ctls['all_methods'], ctls['method']])\n", - " method_grp.add_class('method_grp')\n", - " \n", - " return W.HBox([box_grp, method_grp])\n", - "\n", - " def __init__(self, \n", - " ctx: OCRExperimentContext | ExperimentOCR,\n", - " img_idx: int | str | Path | None = None,\n", - " all_boxes: bool = False,\n", - " box_idx: int = 0,\n", - " all_methods: bool = False,\n", - " method: CropMethod=CropMethod.INITIAL_BOX,\n", - " out: W.Output | None = None,\n", - " ):\n", - " if isinstance(ctx, OCRExperimentContext):\n", - " assert img_idx is not None, \"img_idx must be provided if ctx is an ExperimentContext\"\n", - " exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx)\n", - " if not exp:\n", - " raise ValueError(f\"Image {img_idx} not found in experiment context\")\n", - " ctx = exp\n", - " else:\n", - " if not isinstance(ctx, ExperimentOCR):\n", - " raise ValueError(\"ctx must be an ExperimentOCR or OCRExperimentContext\")\n", - " \n", - " super().__init__(ctx, {'all_boxes': all_boxes, 'box_idx': box_idx, \n", - " 'all_methods': all_methods, 'method': method}, out=out or self.out)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "400781b58e3e43cb868c0c278fd3ecd2", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output(layout=Layout(height='0px'))" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "2f2917080eb943acb8b665e1fa607c13", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Label(value='Box # (of 15):', layout=Layout(padding='0px 0px 0px 10px', width='i…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "81027eadfa3d40b6a81efcd991f2379a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "cleanupwidgets('result_visor')\n", - "\n", - "result_visor = ResultVisor(image_experiment)\n", - "result_visor\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# ExperimentVisor\n" - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class ExperimentVisor(ContextVisor):\n", - " ctx: ExperimentOCR\n", - "\n", - " def update_output(self, \n", - " image_idx: int | None = None,\n", - " **kwargs):\n", - " exp_ctx, img_ctx = self.ctx.ctxs\n", - " if image_idx is not None and image_idx != img_ctx.image_idx:\n", - " ctx = ImageContext(exp_ctx, image_idx)\n", - " assert ctx is not None\n", - " self.ctx.ctx = ctx\n", - " result_visor = self.comp('result_visor')\n", - " if result_visor is not None:\n", - " result_visor.update_output(**kwargs)\n", - "\n", - " def __init__(self, \n", - " ctx: OCRExperimentContext | ExperimentOCR,\n", - " img_idx: int | str | Path | None = None,\n", - " all_boxes: bool = False,\n", - " box_idx: int = 0,\n", - " all_methods: bool = False,\n", - " method: CropMethod=CropMethod.INITIAL_BOX,\n", - " out: W.Output | None = None,\n", - " ):\n", - " if isinstance(ctx, OCRExperimentContext):\n", - " assert img_idx is not None, \"img_idx must be provided if ctx is an ExperimentContext\"\n", - " exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx)\n", - " if not exp:\n", - " raise ValueError(f\"Image {img_idx} not found in experiment context\")\n", - " ctx = exp\n", - " else:\n", - " if not issubclass(type(ctx), ExperimentOCR):\n", - " raise ValueError(\"ctx must be an ExperimentOCR or OCRExperimentContext\")\n", - " \n", - " exp_ctx, img_ctx = ctx.ctxs\n", - " out = out or self.out\n", - " image_selector = ImageSelector(exp_ctx, image_idx=img_ctx.image_idx, out=out)\n", - " result_visor = ResultVisor(ctx, out=out,\n", - " all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method)\n", - "\n", - " super().__init__(ctx, {}, out=out, \n", - " ctxs={'image_selector': image_selector, 'result_visor': result_visor},\n", - " hdlrs={'display_option': result_visor}\n", - " )\n" - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "1e40a9f23a674b48abd50720e6523c2c", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "5af1d96d5d9942fd8e895787ff50bbe5", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "cleanupwidgets('exp_visor')\n", - "\n", - "exp_visor = ExperimentVisor(image_experiment)\n", - "exp_visor\n" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [], - "source": [ - "exp_visor.update(box_idx=1)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "metadata": {}, - "outputs": [], - "source": [ - "exp_visor.update(image_idx=0)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Method experiment\n", - "> perform method on one or more boxes" - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [], - "source": [ - "CONTEXT.reset()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [], - "source": [ - "image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Tesseract')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Visualize summary of crop methods on a given box\n" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "151bc83d198e447d8932fe48aa7ef2e6", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Box #2: 0%| | 0/11 [00:00MethodBox #2AccuracyOCRInitial box
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
Default
0.96
The house and the old man are alike in many ways; tall, proud, patient, contentel always to wait until their. master cones home ~~
Default, grey pad
0.96
The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their.⎕* master cones home⎕~-
Padded 4px
0.93
The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }
Padded 8px
0.99
The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home⎕⎕
Extracted, init box
0.93
Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~
Padded 4, extracted
0.98
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home--
Padded 8, extracted
0.98
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home--
Padded 8, dilation 1
0.88
The house and the old man are alike in many ways, tall, proud, ⎕⎕⎕⎕⎕nt, contented live⎕⎕⎕⎕ walt gtie their, master comes home-=
Pad 8, fract. 0.5
0.97
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~
Pad 8, fract. 0.2
0.97
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.summary_box(1)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Results for any crop method" - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Box #BoxAccuracyPadded 4px OCR
1
0.88
Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit⎕⎕⎕⎕⎕⎕ of mew rce: eans, kept tipy by a white-haired aolo man known only as⎕⎕⎕⎕⎕⎕⎕
2
0.93
The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }
3
0.69
F and one in ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.77
" bambli- we have a gliest.
5
0.55
P⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ comes⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.57
Tel oe ⎕⎕⎕⎕er-- 5 ow a =⎕⎕⎕⎕ 7⎕⎕⎕⎕⎕
7
0.38
W⎕⎕e⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps c oe /⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
8
0.75
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall sra⎕⎕⎕⎕
9
0.92
How curious the a⎕whims of fate. - had i not chanced to stroll along the river yl⎕tonight~-
10
0.79
A⎕⎕⎕ulckly as t can, masrer.
11
0.92
<the girl wolld⎕- most surely be dead by now.
12
0.88
Ghede has been generous. the oeath gop has given -⎕the girl. a second chance ye,⎕alem
13
0.67
Soe⎕⎕ ⎕⎕⎕⎕⎕⎕⎕⎕⎕ereke othing to scream ay⎕⎕⎕ anymore.
14
0.94
"you're among friends now. you're safe!
15
1.00
Continued after next page
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.summary_method(CropMethod.PADDED_4)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can use method experiment directly" - ] - }, - { - "cell_type": "code", - "execution_count": 93, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
0.90
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.⎕⎕

Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method_experiment = cast(ExperimentOCRMethod, \n", - " ExperimentOCR.from_method(CONTEXT, 'Tesseract', IMAGE_CONTEXT.image_idx, CropMethod.INITIAL_BOX))\n", - "method_experiment(BOX_IDX, display=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "for all boxes" - ] - }, - { - "cell_type": "code", - "execution_count": 94, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Initial box
Accuracy Mean/Trimmed: 0.79/0.80
\n", - "
\n", - "
Box #ImageAccuracyOCR
1
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
3
0.70
“and one in ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.62
Re bambli-~ we have a⎕⎕⎕⎕⎕⎕⎕
5
0.70
T⎕⎕⎕⎕⎕⎕onight, he comes noost⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.82
Tell me naster. how may bambli serve 7
7
0.56
£7⎕⎕ »⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
8
0.81
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man'⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall as...⎕7
9
0.85
How curious the 4⎕fate.⎕whims of h⎕⎕⎕⎕⎕⎕ad t not chanced to stroll along the river yl⎕tonight ==
10
0.80
Fas oulckly as t ca, master.
11
0.91
<the girl would -⎕most slirely be dead by now.
12
0.47
A⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕th⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ the girl. a second chance ge⎕a ee yg adil
13
0.84
Ah⎕⎕⎕ girl--there's othing to scream nt⎕⎕t anymore.
14
0.93
You're among friends now. you're sale
15
1.00
Continued after next page
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method_experiment(display=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "or selected boxes" - ] - }, - { - "cell_type": "code", - "execution_count": 95, - "metadata": {}, - "outputs": [], - "source": [ - "CONTEXT.reset()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 96, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Initial box
Accuracy Mean/Trimmed: 0.80/nan
\n", - "
\n", - "
Box #ImageAccuracyOCR
1
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
7
0.56
£7⎕⎕ »⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
10
0.80
Fas oulckly as t ca, master.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method_experiment = cast(ExperimentOCRMethod, \n", - " ExperimentOCR.from_method(CONTEXT, 'Tesseract', IMAGE_CONTEXT.image_idx, CropMethod.INITIAL_BOX))\n", - "method_experiment([0, 1, 6, 9], display=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Full page results\n", - "> all methods on all boxes" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [], - "source": [ - "CONTEXT.reset()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 98, - "metadata": {}, - "outputs": [], - "source": [ - "image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Tesseract')\n" - ] - }, - { - "cell_type": "code", - "execution_count": 100, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Initial box
Accuracy Mean/Trimmed: 0.79/0.80
\n", - "
\n", - "
Box #ImageAccuracyOCR
1
0.90
Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3
2
0.93
The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~
3
0.70
“and one in ee⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.62
Re bambli-~ we have a⎕⎕⎕⎕⎕⎕⎕
5
0.70
T⎕⎕⎕⎕⎕⎕onight, he comes noost⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ slamming open the caken⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕
6
0.82
Tell me naster. how may bambli serve 7
7
0.56
£7⎕⎕ »⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ and perhaps some dry clothes...⎕7⎕/
8
0.81
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man'⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall as...⎕7
9
0.85
How curious the 4⎕fate.⎕whims of h⎕⎕⎕⎕⎕⎕ad t not chanced to stroll along the river yl⎕tonight ==
10
0.80
Fas oulckly as t ca, master.
11
0.91
<the girl would -⎕most slirely be dead by now.
12
0.47
A⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕th⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕ the girl. a second chance ge⎕a ee yg adil
13
0.84
Ah⎕⎕⎕ girl--there's othing to scream nt⎕⎕t anymore.
14
0.93
You're among friends now. you're sale
15
1.00
Continued after next page
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method = CropMethod.INITIAL_BOX\n", - "# method = CropMethod.DEFAULT\n", - "# method = CropMethod.PADDED_4\n", - "# method = CropMethod.PADDED_8\n", - "# method = CropMethod.EXTRACTED_INIT_BOX\n", - "# method = CropMethod.PAD_8_FRACT_0_5\n", - "# method = CropMethod.PAD_8_FRACT_0_2\n", - "\n", - "# image_experiment.method_experiment(CropMethod.INITIAL_BOX).results()\n", - "initial_box_exp = image_experiment.method_experiment(CropMethod.INITIAL_BOX)\n", - "initial_box_exp(display=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Other method" - ] - }, - { - "cell_type": "code", - "execution_count": 102, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as,\n", - " ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~,\n", - " ResultOCR#block 02: 0.74||And one in ee would appear.,\n", - " ResultOCR#block 03: 0.41||Rir guest.,\n", - " ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo,\n", - " ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _,\n", - " ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps,\n", - " ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00,\n", - " ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >,\n", - " ResultOCR#block 09: 0.50||Aulckly “master as t can,,\n", - " ResultOCR#block 10: 0.94||" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.perform_methods(plot_acc=True)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
---------- Initial box ----------\n",
-       "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
-       "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
-       "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
-       "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
-       "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
-       "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
-       "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes... 7 /\n",
-       "ResultOCR#block 07: 0.81||The the old man's fades down the hall as... 7\n",
-       "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
-       "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
-       "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
-       "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
-       "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
-       "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Default ----------\n",
-       "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
-       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
-       "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
-       "ResultOCR#block 03: 0.41||Rir guest.\n",
-       "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
-       "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
-       "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
-       "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
-       "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
-       "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
-       "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
-       "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
-       "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
-       "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Default, grey pad ----------\n",
-       "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
-       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
-       "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
-       "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
-       "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
-       "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
-       "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7 /.\n",
-       "ResultOCR#block 07: 0.06||As.\n",
-       "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
-       "ResultOCR#block 09: 0.55||Ickl as t can\n",
-       "ResultOCR#block 10: 0.00||\n",
-       "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
-       "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
-       "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 0.54||“continued a\n",
-       "\n",
-       " ---------- Padded 4px ----------\n",
-       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
-       "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
-       "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
-       "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
-       "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
-       "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
-       "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
-       "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
-       "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
-       "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
-       "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
-       "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
-       "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
-       "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Padded 8px ----------\n",
-       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
-       "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
-       "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
-       "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
-       "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
-       "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
-       "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
-       "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
-       "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
-       "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
-       "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
-       "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
-       "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
-       "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 0.94||“continued after next page\n",
-       "\n",
-       " ---------- Extracted, init box ----------\n",
-       "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
-       "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
-       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
-       "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
-       "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
-       "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
-       "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
-       "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
-       "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
-       "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
-       "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
-       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
-       "\n",
-       " ---------- Padded 4, extracted ----------\n",
-       "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
-       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
-       "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
-       "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
-       "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
-       "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
-       "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
-       "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
-       "\n",
-       " ---------- Padded 8, extracted ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
-       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
-       "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
-       "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
-       "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Padded 8, dilation 1 ----------\n",
-       "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
-       "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
-       "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
-       "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
-       "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
-       "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
-       "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
-       "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
-       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
-       "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
-       "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Pad 8, fract. 0.5 ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
-       "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
-       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
-       "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Pad 8, fract. 0.2 ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
-       "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
-       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
-       "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       "\n",
-       "
\n" - ], - "text/plain": [ - "---------- Initial box ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n", - "\n", - " ---------- Padded 4px ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m||" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.plot_accuracies()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "RenderJSON(image_experiment.to_dict(), 400, 2)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "best results" - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
[\n",
-       "    (\n",
-       "        'Default, grey pad',\n",
-       "        '0.953',\n",
-       "        'Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of \n",
-       "new orleans, kept tipy by a white-haired old man known only as'\n",
-       "    ),\n",
-       "    (\n",
-       "        'Padded 8px',\n",
-       "        '0.988',\n",
-       "        'The house and the old man are alike in many ways; tall, proud, patient, contented always to \n",
-       "wait until their. master comes home'\n",
-       "    ),\n",
-       "    ('Padded 8, dilation 1', '0.968', 'And one in need of some help, it wolld appear .'),\n",
-       "    ('Default, grey pad', '0.880', '\" bambl-- we have a guest.'),\n",
-       "    ('Padded 8, dilation 1', '0.794', '=and tonight, he comes most slamming open the front'),\n",
-       "    ('Default, grey pad', '0.857', 'Tell me, master: how may bambli serve 7'),\n",
-       "    (\n",
-       "        'Pad 8, fract. 0.5',\n",
-       "        '0.935',\n",
-       "        'Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes'\n",
-       "    ),\n",
-       "    ('Initial box', '0.811', \"The the old man's fades down the hall as... 7\"),\n",
-       "    (\n",
-       "        'Padded 8, extracted',\n",
-       "        '0.959',\n",
-       "        'How curious the whims of fate . had i not chanced to stroll along the river tonight-~'\n",
-       "    ),\n",
-       "    ('Extracted, init box', '0.846', 'Aulckly as t can, master,'),\n",
-       "    ('Extracted, init box', '1.000', '--the girl would most surely be dead by now.'),\n",
-       "    (\n",
-       "        'Padded 8, extracted',\n",
-       "        '0.935',\n",
-       "        'Ghede has been generous. the peath god has given the girl a second chance po'\n",
-       "    ),\n",
-       "    ('Default, grey pad', '0.953', \"Easy, girl--there's | nothing to scream about anyaore.\"),\n",
-       "    ('Default, grey pad', '0.974', \"You're among friends now. you're safe!\"),\n",
-       "    ('Initial box', '1.000', 'Continued after next page')\n",
-       "]\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1m[\u001b[0m\n", - " \u001b[1m(\u001b[0m\n", - " \u001b[32m'Default, grey pad'\u001b[0m,\n", - " \u001b[32m'0.953'\u001b[0m,\n", - " \u001b[32m'Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of \u001b[0m\n", - "\u001b[32mnew orleans, kept tipy by a white-haired old man known only as'\u001b[0m\n", - " \u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\n", - " \u001b[32m'Padded 8px'\u001b[0m,\n", - " \u001b[32m'0.988'\u001b[0m,\n", - " \u001b[32m'The house and the old man are alike in many ways; tall, proud, patient, contented always to \u001b[0m\n", - "\u001b[32mwait until their. master comes home'\u001b[0m\n", - " \u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Padded 8, dilation 1'\u001b[0m, \u001b[32m'0.968'\u001b[0m, \u001b[32m'And one in need of some help, it wolld appear .'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.880'\u001b[0m, \u001b[32m'\" bambl-- we have a guest.'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Padded 8, dilation 1'\u001b[0m, \u001b[32m'0.794'\u001b[0m, \u001b[32m'=and tonight, he comes most slamming open the front'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.857'\u001b[0m, \u001b[32m'Tell me, master: how may bambli serve 7'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\n", - " \u001b[32m'Pad 8, fract. 0.5'\u001b[0m,\n", - " \u001b[32m'0.935'\u001b[0m,\n", - " \u001b[32m'Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes'\u001b[0m\n", - " \u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Initial box'\u001b[0m, \u001b[32m'0.811'\u001b[0m, \u001b[32m\"The the old man's fades down the hall as... 7\"\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\n", - " \u001b[32m'Padded 8, extracted'\u001b[0m,\n", - " \u001b[32m'0.959'\u001b[0m,\n", - " \u001b[32m'How curious the whims of fate . had i not chanced to stroll along the river tonight-~'\u001b[0m\n", - " \u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Extracted, init box'\u001b[0m, \u001b[32m'0.846'\u001b[0m, \u001b[32m'Aulckly as t can, master,'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Extracted, init box'\u001b[0m, \u001b[32m'1.000'\u001b[0m, \u001b[32m'--the girl would most surely be dead by now.'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\n", - " \u001b[32m'Padded 8, extracted'\u001b[0m,\n", - " \u001b[32m'0.935'\u001b[0m,\n", - " \u001b[32m'Ghede has been generous. the peath god has given the girl a second chance po'\u001b[0m\n", - " \u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.953'\u001b[0m, \u001b[32m\"Easy, girl--there's | nothing to scream about anyaore.\"\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Default, grey pad'\u001b[0m, \u001b[32m'0.974'\u001b[0m, \u001b[32m\"You're among friends now. you're safe!\"\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1m(\u001b[0m\u001b[32m'Initial box'\u001b[0m, \u001b[32m'1.000'\u001b[0m, \u001b[32m'Continued after next page'\u001b[0m\u001b[1m)\u001b[0m\n", - "\u001b[1m]\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "ll = image_experiment.best_results()\n", - "if ll:\n", - " cprint([(m.value, f\"{r.acc:.3f}\", r.ocr) for m,r in ll])\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perfom experiments given a list of `CropMethod`s\n" - ] - }, - { - "cell_type": "code", - "execution_count": 105, - "metadata": {}, - "outputs": [], - "source": [ - "# methods = [*CropMethod.__members__.values()]\n", - "methods = [CropMethod.INITIAL_BOX, CropMethod.DEFAULT]\n", - "image_experiment.perform_methods(methods)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Plot the perfomance of the experiments" - ] - }, - { - "cell_type": "code", - "execution_count": 106, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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lagPAP9A7qMs7n/Jb9CggVU+adIkq7xkyZJGkgkODrbKmjRpkuVfwiWZGjVqGGOMef/9962yzp07e7SlcePG1rrLjXSnpaWZ0aNHm/r165uIiAivIzM//vijVX/69OlGkhk7dmyG12Dq1Knmxhtv9LqPiIgI88cff1h1Bw8enOVf+N1HuteuXZth/V9//WX69+9vqlatao18uj9CQkKsuu6jgh07drTKt23bZpW3bt3aGGPMjh07PEY/3Eeunn/++QwjIStWrLjseybJzJ07N8MxXE5Wo0k5Pf6ctts10hQUFGQefPBB8+6775ply5aZkydPZvu43GVnpDs5Odn63Pj5+Zldu3ZlWf/w4cMeI1UvvfSSx/rKlStb69xPe01LS/N4Df7880+zbt066+fSpUt77OfDDz+01rVp08YqnzZtmpk9e7Y5ePCgOXfunPn5559N3bp1rbruo+5Z8dYH3N/T//u///Oo7/75X7hwoUlKSjJ+fn5Gco40ur9nEydOtOraMdLtPiL89NNPe63z1FNPWXXatm1rjDFm5MiRVlmtWrV8ei737+BLH8WKFTMfffSRT/tx/9w1bNjQKp8wYYJVftNNN1nlgwYNssr/85//GGM8+4T7d44xxnTo0MFa52qTq19LMtu2bbPqLlu2zCp3jVKfO3fOBAQEXPaz+/jjjxtjsh7pzqnMvpvs+l6pXbu29Xvk8ccfNxMnTjSrVq0yZ86csers2rXLp+cePXp0hmOoWLGi18ui1q5da9q3b28iIyO9jt4/8sgjxhhjvv76a6usQoUKHr83LnW5332AN8xeDgBeVKxY0VoODQ21lsuVK2ctu0ZuXH8Zl7yPkl3KNULgPnJ66WhIdHS0fvjhB5/a+vTTT1sj5plxjSxK0pw5cyTJ6+hmz5491bNnTx0/flw//PCDFi9erGnTpiktLU0JCQn66quv1K9fP5/a5a5evXoeP1+4cEEtW7bU1q1bM90ms1sQuU/oFhYWlqG+++taunRp+fv7Wz97m/jKl/fs0v1eqSs5fpfstvvtt99WXFycvvvuO3344YfW+sDAQD3xxBMaM2aMT/u7EjNnztSff/4pSerQoYPH5+xS27dv1x133GGNtA4bNkwvvfSSR50SJUro999/lySPszlcI46S8/gKFy7scZaDe91L65coUcJa7tGjh0e9unXr6t1331XTpk0lSevWrcu0/dkRHR2d4WfX5//48eM6efKkLly4IMk5Ku8+Up+d25BNnTrVGuVzad68uddbvXlr2969e73WcS931Xcf/d69e7dSUlJyPNotOb9nczI5Vna+y6WLnzv3z9el74/7a+6ql9n3+aXbSrLOmric3D67xhd2fa98/PHH6tWrl7Zu3erx+yo0NFTDhg3TM888c0XfxXXq1LHuUuCyfv163XLLLTp//nym+3L9bnR9L0lS9erVPX5vALmB08sBwIvMTtm83Kmc7v9h/+GHH7zOeOw6dbxo0aJW3UOHDnnsx3WKpi9mzJhhLc+bN08pKSkyxni9rU5iYqKWL1+uhg0bqmzZsh7rEhISrOXixYurQ4cO+vDDDz1uExYfH28tZ+dervny5fP4edu2bVbgLFGihLZt26b09HSPNmQmMDAwyzYUK1bMWj5y5IgVViTPU15d3N+z1q1be33PXDNb55YrOf6ctjs6Olrffvutjh07ppUrV+rDDz9UgwYNlJaWprFjx+rHH3/MtePLzFtvvWUtP/vss5nWW7t2rZo2baqDBw8qMDBQn3zySYbALUmNGjWylt1POXW/tVWdOnUUGBio8uXLq3jx4pKcs6C7f8bc6zds2FCSPPpNZi79T35OXfp5d/+5ePHiKlSokBUCTp8+7dFPvPXp3HTHHXdYy0uXLtXRo0c91h8+fFjLli2zfm7Tpo0kqWXLltYfxc6ePat3333X6/4zC5+DBw9WamqqFi1apHz58ikhIUFPPvmkxyUYvsiN7/JL3x/3Wehd9TL7Pvf2XV6kSBHr+cPDw63v7Esfn376aZZttINd3yt16tTRli1bdOjQIS1btkzjx49XlSpVdO7cOQ0YMEBHjhzxeO6qVat6fW5jjHWJlrtLf8dIzlP0XYG7W7duiouLkzHGa18sWbKktfzbb79l+fnnPubICUI3AOSijh07WsuPPfaYfv75Z6WkpCg+Pl5ffvmlunTpohEjRkiSbrvtNuuX96JFi7R48WKdOXNG06ZN83mUW/L8z2N4eLjS09M1adIkj3sRuyxevFjJycnWdYMu6enpKlu2rJ588kl98803OnnypNLS0rR161atXbvWqnfDDTdYy+7X4v73v//1aeTGW5v9/f2VP39+nT592uO68pyqVKmSNRJ1/Phxvf7669Z1eR999FGG+k2aNLGC+vLlyzV69GjFx8crJSVFO3bs0MiRI7Mckc2J3Dj+7Lb7zTff1MyZM5WQkKBGjRrp3nvv9bjdl/u1u5dz9uxZxcXFKS4uzuN9P336tFV+qeXLl1vBuGHDhmrSpInXfc+ePVutWrXSyZMnVaBAAS1dulQPPPCA17q9evWywuiECRO0adMmHTlyxOOaywcffNBa7tOnj7U8cOBAxcXFaeXKldbZHxEREbrvvvskOV+PBg0aaPr06Tpy5IhSUlK0adMmPfXUU9Y+mjdv7tEeh8Mhh8ORrdFnSdY9qC/9/IeGhqpp06bKly+fNbpujNHAgQN18uRJbdu2TaNGjfL5eXr16pUhwGQ1yi1J7du3t655TklJUefOnbVlyxalpaVpy5Yt6ty5s1JTUyVJ9evXV/v27SU5r5t/+eWXrf28/PLLGjVqlI4ePaq0tDTt2bNHY8eOtep7ExgYqDvvvFOvv/66VfbUU095nF1klzZt2igoKEiS83vziy++UFJSkubPn29dax0UFKTWrVtLklq1amVt+8ILL+jYsWM6ePCgR190CQkJsf44kZiYaF0/nJaWpkOHDmnatGlq0qSJx3dvZlx9LreCoF3fKy+++KLmz5+v9PR0NWvWTPfee6+1H2OM/vjjD1WsWFE1atSQJO3YsUMDBgyw+svevXs1YcIE1apVy+c/Srt/z4aEhCg0NFRbtmzRO++84/W4XX+U2717tx5++GEdPHhQSUlJWr9+vSZNmmTVvZLffbiO2XjqOgDkKZndpst9NnL3cvdrll2Sk5NNixYtsrwezX1W3sxmL3efcfdy13Q/8sgjGbbPly+fKV26dIZ9dOzY0Uiet0syJuM1sN4ejRs39rjOzf1WOO4P121YvL0+Lunp6aZGjRoZtnW/Rtd9u8xm787sWsfMZi93n0nY/RZTCxcuNEFBQVkef05kdt1kbh1/dtrdsmXLTOuEh4ebI0eO+Hxc7tc0+vp6tWrVylo3Z86cTPft3m982ffw4cMzrXfnnXd6XOd55swZU6dOHa91/fz8rOt5jfHsW5l9Ri+dwdzbe51Zuft76t4v3R/ut9lav36915mV3bft1atXlu9bTh06dMjUrFkzy9ejZs2a1t0Q3D377LNZbhcbG2vVzWz28tTUVFOpUiVr3ahRo7Js76W3knJxf83dyzO7Rvdydxhw3XLRmMxnL3f/Lnf/jtq7d2+m77vr4fre/rtnL7fje6VChQqZ1itdurQ5d+6cMcY5e3lERESWz+36HZPZ++yybt06ay4E94f796z7dr7MXm7M5X/3Ad4w0g0AuSg4OFgrVqzQe++9p8aNGysiIkJBQUEqXbq0mjVrpmHDhnmcrv32229r2LBhKlOmjIKCglSjRg3NnDnTminVF2PGjFH//v0VFRWlkJAQNW7cWCtWrPC4plKSkpKStHTpUtWvXz/DdYYBAQH65JNP1KdPH9WsWVPFixdXQECAwsLCFBsbqyFDhmj58uUe17nVq1dPEyZMUKVKlawRIV/5+/tr0aJFuvvuu1WoUCFFRESoc+fO+uabb7K1n8x07NhR8+fPV2xsrIKCglS2bFkNHTrUY+Zr99NB27dvr59//lk9evRQ2bJlFRgYqAIFCqhatWrq0aOHZs2alSvtcsmt489Ou3v16qW77rpL0dHRCgsLk7+/vyIjI9W5c2d9++23ioyMzNVjdPfrr79q+fLlkpzX0rqfEXKlXnjhBc2bN0/NmjVT/vz5FRISopo1a2rUqFGaN2+exyngYWFhWrNmjV566SWr3xYsWFBt2rTRqlWr1LVrV6tuyZIl9c4776ht27aKiYlRaGioQkJCVKVKFfXv319bt25VlSpVLts+91GwzD4n/fr108SJE1W5cmUFBQWpYsWKGj9+vJ5//nmrToMGDfT111+rcePGCg4OVokSJfT00097jAK79+ncVLp0aW3YsEHjxo1T8+bNVbhwYQUEBKhw4cJq1qyZ3nvvPW3YsMG6G4K70aNHa/369erdu7cqVKig0NBQhYWFqVKlSurevbvefPPNyz5/YGCgR73XX3/9b7neuX///lqxYoXatWunokWLyt/fX0WKFFHbtm21fPlyj7Meypcvr2+//Va33367QkNDVahQIT3wwAOZng5frlw5/fLLLxo4cKCqV69ujcSWL19e7du318SJE71eIvR3sON75YknnlDr1q1VunRphYSEKDAwUGXKlFHPnj21du1ahYSESHKeLbF161Y9+uijqlixooKDg5U/f35VqlRJXbp00dSpUxUVFeXTcTRu3Fhz5sxRrVq1FBISoujoaA0fPlyDBg3yWr9t27bavHmzevfurZiYGAUFBSk8PFyxsbEeZzJcye8+XL8cxvzvnioAgGva7Nmzdd9992nkyJEet9q6FiUm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A491P/30k+666y4VLlxYISEhqlOnjmbPnm2tHzJkiEqXLi1Jev755+VwOKzTv3fv3q3evXurUqVKypcvn0qVKqX27dtr27ZtHs/hOvV9//79HuWrV6+Ww+HQ6tWrM227w+FQUlKSpk2bZp2i3aJFiyyPd+LEiSpZsqRuv/12j/L58+fr1ltvtQK3JEVERKhTp05atGiR0tPTs9zvpRITEzVnzhw1b95cFStWzNa27h544AH9/vvvWrVqVY73AQAAAABXitB9Bdq2bSt/f3+tXbvWKlu1apWaNGmiU6dO6f3339eCBQtUu3Zt3XfffZo6daokqV+/fpo3b54k6YknntAPP/yg+fPnS3KOgBcpUkRvvPGGli5dqvHjxysgIEANGzbUzp07c6XdP/zwg0JDQ9W2bVv98MMP+uGHHzRhwoQst1myZImaNWsmP7+LXebcuXPas2ePatWqlaF+rVq1dO7cOe3duzdbbfvss8+UlJSkfv36eV3/6aefKjQ0VMHBwapXr56mTJnitV69evWUP39+LVmyJNPnSklJUUJCgscDAAAAAHITp5dfgbCwMBUtWlRHjhyxyh599FHdcMMN+uabbxQQ4Hx5W7durbi4OL344ovq0aOHSpcubY0Aly1b1uN06WbNmqlZs2bWz+fPn1e7du10ww036IMPPtDYsWOvuN2NGjWSn5+fihUrdtlTtSXp+PHj2rt3rx566CGP8pMnT8oYo8KFC2fYxlUWHx+frbZNnjxZBQsWVOfOnTOsu//++9WuXTuVKVNGx48f1+TJk9WnTx/t3btXQ4cO9ajr7++v2NhYff/995k+14gRI/Tqq69mq30AAAAAkB2MdF8hY4y1vHv3bu3YsUPdunWTJKWnp1uPtm3b6ujRo5cdrU5PT9fw4cNVvXp1BQUFKSAgQEFBQdq1a5d+++03W48lM64/KhQvXtzr+qyumc7O9dS//vqr1q9fr27duikkJCTD+pkzZ+r+++/XzTffrM6dO+vLL7/UnXfeqTfeeEN//fVXhvrFixfX4cOHM32+F154QadPn7Yehw4d8rmtAAAAAOALQvcVSEpKUnx8vKKioiRJx44dk+ScPTswMNDj8eijj0qS4uListznM888o3//+9+6++67tWjRIq1fv14bN25UbGyszp07Z+8BZcL1vJcG4UKFCsnhcHgdzT5x4oQkeR0F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adOmqUmTJj7fRssV4CVZszbv2bNHw4YNy1C3UqVK1ojk8ePH9frrr1vXFn/00UcZ6jdp0sQKWsuXL9fo0aMVHx+vlJQU7dixQyNHjlTFihWzbF9OXssmTZqoePHikqTdu3fr4Ycf1sGDB5WUlKT169dr0qRJkqQ77rjDCtSrVq3SK6+8omPHjikhIUGrVq3SrFmzJDkDlaver7/+qn379un8+fN66aWXshytzoz7ax4SEqLQ0FBt2bJF77zzToa6vh6LyzPPPCM/Pz8ZY7R69WpJUteuXVWwYMHLtqt06dLWdc6//PKLT8dy1113WctvvfWWfvnlFyUkJOjf//63NcpdvXp1VahQIdv9JzNr1qzR8OHD9euvvyomJkZ333237r77bmv9wYMHJckjNI8aNUqfffaZEhISdPz4cX366afW/bHd34/8+fPL4XBowYIFXudFyEzHjh0lOf/407NnT/32229KS0vTn3/+qblz56pNmzbWmSsumzZtspYbNWrk83MBuI79XeexAwDwT/fJJ59Y12rWqVMnw3r32colmdWrV1vrXnzxRY/rQGNiYjJcE7x3797LXkO6atUqY0zW1yO79pUvX74M21euXNnrdpnNPu3eHvfrZxcuXOj1OnH3hx2vZW7OXm6MMQ8++KBV7u/vb/Lly2cCAgI8js3F/Zpu1wzx7tatW+f1Od1fc/ftfD0Wl86dO3vUWb9+fZavsTvXcfr7+5sTJ054rMts9vJOnTpl+t7my5fPfP/999Y+stt/vJk+fXqW/em9996z6vbo0SPTeq7Zy994440M6/z8/EyFChWsn6dMmWLt01V26ezlN9xwQ5btct+HMcY8+eST1nMdPHjQ5/cIwPWLkW4AAP7H/ZRx17XY7vz9/T1O93U/ffrBBx/0uNazX79+Ga4JLleunH755RcNHDhQ1atXt0ZLy5cvr/bt22vixIkeMyNnpVy5cvryyy/VqFEj5cuXT5GRkRowYIDXU50l54je/PnzFRsbq6CgIJUtW1ZDhw7V448/btUpWrSotdy+fXv9/PPP6tGjh8qWLavAwEAVKFBA1apVU48ePazR5Mzk9LVs27atNm/erN69eysmJkZBQUEKDw9XbGysWrVqZdV/8MEHtW7dOt13330qVaqUAgMDVbBgQTVo0EBNmza16o0dO1YPP/ywIiMjFRQUpPr16+ubb77xOCXbV40bN9acOXNUq1YthYSEKDo6WsOHD9egQYO81vf1WFzcr0+uU6eOGjRo4HPbXPduP3/+/GXfG8l5OvWcOXP0/vvvq1GjRgoPD1dAQIDKlCmjnj17avPmzbrpppus+tntP97Uq1dP/fr1U82aNVW4cGH5+/srPDxcjRo10qRJkzz2NW3aNH366adq2bKlChcurICAABUvXly33367dZbFgAED9NprrykmJkbBwcGKjY3V/PnzPd7/yylcuLDWr1+voUOHqk6dOgoLC1NwcLCio6N1++23a8yYMbrjjjus+ufPn7fuTHDXXXepTJkyPj8XgOuXw5hLZhYBAADXnMTERG3YsEHNmjVTYGCgJGn79u1q166d9u/fLz8/P23fvl1VqlS5yi29fs2fP986tfrjjz+2bkXmqzvvvFNLlixRbGysNm/enKsTftF/nObMmaN7771XDodD69evV/369a92kwDkAYRuAACuA/v371e5cuUUGBio4sWLKzk52bp2V5JeffVVvfLKK1exhdevF154QbNnz9a+fftkjFHVqlW1bds2j2uWfbFr1y7VqFFDqampmjt3rjp37pxrbaT/OK/7jo2N1bZt29S7d299/PHHV7tJAPIIbhkGAMB1oGDBgurevbt++OEH/fnnn0pNTVVUVJQaNmyoRx55xOvpzvh7HD16VHv37lV4eLiaNm2q8ePHZztwS84J81JSUmxoIf1Hcp6Sv3Xr1qvdDAB5ECPdAAAAAADYhInUAAAAAACwCaEbAAAAAACbELoBAAAAALAJoRsAAAAAAJsQugEAAAAAsAmhGwAAAAAAmxC6AQAAAACwCaEbAAAAAACbELoBAAAAALDJ/wPycqSMHEO5YQAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# image_experiment.plot_accuracies(exps, IMAGE_CONTEXT)\n", - "image_experiment.plot_accuracies(methods)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Save the results to a file\n" - ] - }, - { - "cell_type": "code", - "execution_count": 107, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
cleaner/Strange_Tales_172005/Strange_Tales_172005_Tesseract.json\n",
-       "
\n" - ], - "text/plain": [ - "cleaner/Strange_Tales_172005/Strange_Tales_172005_Tesseract.json\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fp, json_results = image_experiment.to_json()\n", - "cprint(fp)\n", - "RenderJSON(json_results, 300, 2)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Load the results from a file\n" - ] - }, - { - "cell_type": "code", - "execution_count": 108, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
---------- Initial box ----------\n",
-       "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
-       "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
-       "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
-       "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
-       "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
-       "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
-       "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes... 7 /\n",
-       "ResultOCR#block 07: 0.81||The the old man's fades down the hall as... 7\n",
-       "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
-       "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
-       "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
-       "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
-       "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
-       "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Default ----------\n",
-       "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
-       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
-       "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
-       "ResultOCR#block 03: 0.41||Rir guest.\n",
-       "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
-       "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
-       "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
-       "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
-       "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
-       "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
-       "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
-       "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
-       "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
-       "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Default, grey pad ----------\n",
-       "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
-       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
-       "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
-       "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
-       "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
-       "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
-       "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7 /.\n",
-       "ResultOCR#block 07: 0.06||As.\n",
-       "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
-       "ResultOCR#block 09: 0.55||Ickl as t can\n",
-       "ResultOCR#block 10: 0.00||\n",
-       "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
-       "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
-       "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 0.54||“continued a\n",
-       "\n",
-       " ---------- Padded 4px ----------\n",
-       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
-       "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
-       "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
-       "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
-       "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
-       "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
-       "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
-       "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
-       "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
-       "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
-       "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
-       "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
-       "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
-       "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Padded 8px ----------\n",
-       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
-       "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
-       "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
-       "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
-       "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
-       "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
-       "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
-       "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
-       "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
-       "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
-       "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
-       "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
-       "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
-       "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 0.94||“continued after next page\n",
-       "\n",
-       " ---------- Extracted, init box ----------\n",
-       "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
-       "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
-       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
-       "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
-       "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
-       "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
-       "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
-       "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
-       "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
-       "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
-       "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
-       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
-       "\n",
-       " ---------- Padded 4, extracted ----------\n",
-       "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
-       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
-       "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
-       "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
-       "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
-       "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
-       "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
-       "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
-       "\n",
-       " ---------- Padded 8, extracted ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
-       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
-       "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
-       "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
-       "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Padded 8, dilation 1 ----------\n",
-       "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
-       "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
-       "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
-       "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
-       "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
-       "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
-       "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
-       "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
-       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
-       "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
-       "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Pad 8, fract. 0.5 ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
-       "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
-       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
-       "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Pad 8, fract. 0.2 ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
-       "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
-       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
-       "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       "\n",
-       "
\n" - ], - "text/plain": [ - "---------- Initial box ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n", - "\n", - " ---------- Padded 4px ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m|| Page: media/Strange_Tales_172005.jpg
Size: 1275x1888 px: 4.25 x 6.29 in @ 188.32 dpi
Model: Tesseract
Crop Method: Pad 8, fract. 0.2
Accuracy Mean/Trimmed: 0.85/0.86
\n", - "
\n", - "
Box #ImageAccuracyOCR
1
0.94
Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as b8ambl .
2
0.97
The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~
3
0.77
And one in eet⎕⎕⎕ sve⎕⎕⎕⎕⎕⎕⎕⎕⎕ would appear.
4
0.86
Bambl ~~ we have a guest.
5
0.64
=~and tonight, he comes ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕slamming open urg⎕⎕⎕⎕en⎕⎕⎕⎕⎕tly,⎕⎕⎕⎕
6
0.82
Tell me master... how may bambli serve'7
7
0.94
Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes
8
0.75
The⎕⎕⎕⎕⎕⎕⎕⎕ the old man⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕s fades down the hall sere
9
0.96
How curious the whims of fate. had i not chanced to stroll along the river tonight-~
10
0.81
A⎕⎕⎕ulckry as t can, master.
11
0.95
~<the girl would most surely be dead by now.
12
0.94
Ghede has been generous. the ceath god has given the girl a second chance po⎕⎕
13
0.67
Yi⎕⎕⎕ ⎕⎕⎕⎕⎕⎕⎕⎕⎕⎕renee othing to scream sea⎕⎕⎕t anhore.
14
0.93
Youre among eriends now. you're safe!
15
0.83
| continued af⎕⎕⎕ ext page
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "saved_exp = ExperimentOCR.saved_experiment(CONTEXT, 'Tesseract', IMAGE_CONTEXT.image_idx)\n", - "# saved_exp = ExperimentOCR.saved_experiment(IMAGE_CONTEXT, 'Tesseract', 'Action_Comics_1960-01-00_(262).JPG')\n", - "if saved_exp:\n", - " saved_exp.method_experiment(CropMethod.PAD_8_FRACT_0_2).display()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Perform experiments for selected boxes y methods" - ] - }, - { - "cell_type": "code", - "execution_count": 110, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
---------- Initial box ----------\n",
-       "ResultOCR#block 00: 0.90||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3\n",
-       "ResultOCR#block 01: 0.93||The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~\n",
-       "ResultOCR#block 02: 0.70||“and one in ee would appear.\n",
-       "ResultOCR#block 03: 0.62||Re bambli-~ we have a\n",
-       "ResultOCR#block 04: 0.70||Tonight, he comes noost slamming open the caken\n",
-       "ResultOCR#block 05: 0.82||Tell me naster. how may bambli serve 7\n",
-       "ResultOCR#block 06: 0.56||£7 » and perhaps some dry clothes... 7 /\n",
-       "ResultOCR#block 07: 0.81||The the old man's fades down the hall as... 7\n",
-       "ResultOCR#block 08: 0.85||How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==\n",
-       "ResultOCR#block 09: 0.80||Fas oulckly as t ca, master.\n",
-       "ResultOCR#block 10: 0.91||<the girl would - most slirely be dead by now.\n",
-       "ResultOCR#block 11: 0.47||Ath the girl. a second chance ge a ee yg adil\n",
-       "ResultOCR#block 12: 0.84||Ah girl--there's othing to scream ntt anymore .\n",
-       "ResultOCR#block 13: 0.93||You're among friends now. you're sale\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Default ----------\n",
-       "ResultOCR#block 00: 0.85||Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as\n",
-       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~\n",
-       "ResultOCR#block 02: 0.74||And one in ee would appear.\n",
-       "ResultOCR#block 03: 0.41||Rir guest.\n",
-       "ResultOCR#block 04: 0.59||=~and tonight, he comes host sane oo\n",
-       "ResultOCR#block 05: 0.78||Tell me masts - how may bambli . serve 7 _\n",
-       "ResultOCR#block 06: 0.48||R warm, bambli-~ and perhaps\n",
-       "ResultOCR#block 07: 0.76||The the old mans fades down the hall s.00\n",
-       "ResultOCR#block 08: 0.92||How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >\n",
-       "ResultOCR#block 09: 0.50||Aulckly “master as t can,\n",
-       "ResultOCR#block 10: 0.94||<the girl would - most surely be dead by now.\n",
-       "ResultOCR#block 11: 0.50||Ath - the girl. a second chance ee oo tr tt\n",
-       "ResultOCR#block 12: 0.84||Oe girl--there's othing to scream nt anymore. 4\n",
-       "ResultOCR#block 13: 0.96||You're among friends now. youre safe!\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Default, grey pad ----------\n",
-       "ResultOCR#block 00: 0.95||Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as\n",
-       "ResultOCR#block 01: 0.96||The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-\n",
-       "ResultOCR#block 02: 0.94||“and one in > need of some help, it would appear .\n",
-       "ResultOCR#block 03: 0.88||\" bambl-- we have a guest.\n",
-       "ResultOCR#block 04: 0.72||~~and tonight, he comes urgently, slanming open\n",
-       "ResultOCR#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
-       "ResultOCR#block 06: 0.90||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7 /.\n",
-       "ResultOCR#block 07: 0.06||As.\n",
-       "ResultOCR#block 08: 0.91||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n",
-       "ResultOCR#block 09: 0.55||Ickl as t can\n",
-       "ResultOCR#block 10: 0.00||\n",
-       "ResultOCR#block 11: 0.85||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n",
-       "ResultOCR#block 12: 0.95||Easy, girl--there's | nothing to scream about anyaore.\n",
-       "ResultOCR#block 13: 0.97||You're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 0.54||“continued a\n",
-       "\n",
-       " ---------- Padded 4px ----------\n",
-       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n",
-       "ResultOCR#block 01: 0.93||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }\n",
-       "ResultOCR#block 02: 0.69||F and one in ee would appear.\n",
-       "ResultOCR#block 03: 0.77||\" bambli-— we have a gliest.\n",
-       "ResultOCR#block 04: 0.55||P comes slamming open the caken\n",
-       "ResultOCR#block 05: 0.57||Tel oe er-- 5 ow a = 7\n",
-       "ResultOCR#block 06: 0.38||We and perhaps c oe /\n",
-       "ResultOCR#block 07: 0.75||The the old mans fades down the hall sra\n",
-       "ResultOCR#block 08: 0.92||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n",
-       "ResultOCR#block 09: 0.79||Aulckly as t can, ‘masrer.\n",
-       "ResultOCR#block 10: 0.92||<the girl wolld - most surely be dead by now.\n",
-       "ResultOCR#block 11: 0.88||Ghede has been generous. the oeath gop has given - the girl. a second chance ye, alem\n",
-       "ResultOCR#block 12: 0.67||Soe er eke othing to scream ay anymore.\n",
-       "ResultOCR#block 13: 0.94||\"you're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 1.00||Continued after next page\n",
-       "\n",
-       " ---------- Padded 8px ----------\n",
-       "ResultOCR#block 00: 0.88||Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as\n",
-       "ResultOCR#block 01: 0.99||The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home\n",
-       "ResultOCR#block 02: 0.67||7 and one in ee would appear,\n",
-       "ResultOCR#block 03: 0.76||Zf mbl == we have a guest.\n",
-       "ResultOCR#block 04: 0.61||Tonight, he comes host slamming open\n",
-       "ResultOCR#block 05: 0.75||Yy i tell me master - how may bambli serve 7 _,\n",
-       "ResultOCR#block 06: 0.89||Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s\n",
-       "ResultOCR#block 07: 0.72||The the old mans fades down the hal. srl see\n",
-       "ResultOCR#block 08: 0.88||* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~\n",
-       "ResultOCR#block 09: 0.65||Tiie as t can, \\ master ,\n",
-       "ResultOCR#block 10: 0.86||The girl wolld - most slirely be - dead by now.\n",
-       "ResultOCR#block 11: 0.62||Ghede has been generous. : the crn son ue;\n",
-       "ResultOCR#block 12: 0.62||Soe er eke othing to scream hbolt anhore hr\n",
-       "ResultOCR#block 13: 0.92||” you're among friends now. you're safe!\n",
-       "ResultOCR#block 14: 0.94||“continued after next page\n",
-       "\n",
-       " ---------- Extracted, init box ----------\n",
-       "ResultOCRExtracted#block 00: 0.92||Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .\n",
-       "ResultOCRExtracted#block 01: 0.93||Ee house and the old man por alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home ~~\n",
-       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
-       "ResultOCRExtracted#block 03: 0.67||— we have a i=s7t.\n",
-       "ResultOCRExtracted#block 04: 0.74||~and tonight, he comes urgently, slamming open\n",
-       "ResultOCRExtracted#block 05: 0.85||Tell me master how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.93||Some blankets to keep her warm, banbli-- and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.77||The the old man's fades down the hall s.,00\n",
-       "ResultOCRExtracted#block 08: 0.77||Hin ef fare” had i not chanced to stroll along the river. tonigmt=~\n",
-       "ResultOCRExtracted#block 09: 0.85||Aulckly as t can, master,\n",
-       "ResultOCRExtracted#block 10: 1.00||--the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.51||Ath the girl a second chance ro\n",
-       "ResultOCRExtracted#block 12: 0.56||Cas ee, othing to scream pls aa .\n",
-       "ResultOCRExtracted#block 13: 0.95||You're among friends now. you're sale!\n",
-       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
-       "\n",
-       " ---------- Padded 4, extracted ----------\n",
-       "ResultOCRExtracted#block 00: 0.91||Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master cones home --\n",
-       "ResultOCRExtracted#block 02: 0.73||And one in fee would appear.\n",
-       "ResultOCRExtracted#block 03: 0.83||Bambli we have a gliest.\n",
-       "ResultOCRExtracted#block 04: 0.74||=~and tonight, he comes urgently, slamming open\n",
-       "ResultOCRExtracted#block 05: 0.84||Tell me master. how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.53||Warm, bambli-- and perhaps. som\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sra\n",
-       "ResultOCRExtracted#block 08: 0.76||We sea had i not chanced to stroll along the river. tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.76||Alley as t can, master,\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.92||Chepe has been generous. the peath god has given the girl a second chance amr\n",
-       "ResultOCRExtracted#block 12: 0.73||Cas gr theres othing to scream pissy tore .\n",
-       "ResultOCRExtracted#block 13: 0.95||You're among eriends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.91||Continued af ext page\n",
-       "\n",
-       " ---------- Padded 8, extracted ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .\n",
-       "ResultOCRExtracted#block 01: 0.98||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home --\n",
-       "ResultOCRExtracted#block 02: 0.70||And one in fee wolld appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve't\n",
-       "ResultOCRExtracted#block 06: 0.91||Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sire\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.77||Allckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the peath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.74||Cas gr theres othing to scream pps hore .\n",
-       "ResultOCRExtracted#block 13: 0.42||You're safe § r\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Padded 8, dilation 1 ----------\n",
-       "ResultOCRExtracted#block 00: 0.61||Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .\n",
-       "ResultOCRExtracted#block 01: 0.88||The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=\n",
-       "ResultOCRExtracted#block 02: 0.97||And one in need of some help, it wolld appear .\n",
-       "ResultOCRExtracted#block 03: 0.78||Bambli ~~ we have a gliest.\n",
-       "ResultOCRExtracted#block 04: 0.79||=and tonight, he comes most slamming open the front\n",
-       "ResultOCRExtracted#block 05: 0.86||Tell me, master: how may bambli serve 7\n",
-       "ResultOCRExtracted#block 06: 0.85||Gone blankets to keep her. warm, bambli-~ and perhaps some dry\n",
-       "ResultOCRExtracted#block 07: 0.73||The old man's footsteps the hall as.re\n",
-       "ResultOCRExtracted#block 08: 0.94||How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.68||Aulckly as t can,\n",
-       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.75||Ee lh boe ene. the death gop has the girl. a second chance\n",
-       "ResultOCRExtracted#block 12: 0.92||Easy, girl--there's nothing to scream abolit anymo!\n",
-       "ResultOCRExtracted#block 13: 0.97||You're among friends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Pad 8, fract. 0.5 ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until. their. master comes home ~~\n",
-       "ResultOCRExtracted#block 02: 0.78||And one in eee pe would appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
-       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.73||The the old mans fades donn the hall sire\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.98||~-the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.92||Ghede hag been generous. the peath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.76||Cas srl theres othing to scream seoit hore .\n",
-       "ResultOCRExtracted#block 13: 0.42||You're safe 4 ’\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       " ---------- Pad 8, fract. 0.2 ----------\n",
-       "ResultOCRExtracted#block 00: 0.94||Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .\n",
-       "ResultOCRExtracted#block 01: 0.97||The house and the old man are alike in many ways; tall, proud, patient, contented always t° wait until their. master comes home ~~\n",
-       "ResultOCRExtracted#block 02: 0.77||And one in eet sve would appear.\n",
-       "ResultOCRExtracted#block 03: 0.86||Bambl ~~ we have a guest.\n",
-       "ResultOCRExtracted#block 04: 0.64||=~and tonight, he comes slamming open urgently,\n",
-       "ResultOCRExtracted#block 05: 0.82||Tell me master... how may bambli serve'7\n",
-       "ResultOCRExtracted#block 06: 0.94||Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes\n",
-       "ResultOCRExtracted#block 07: 0.75||The the old mans fades down the hall sere\n",
-       "ResultOCRExtracted#block 08: 0.96||How curious the whims of fate . had i not chanced to stroll along the river tonight-~\n",
-       "ResultOCRExtracted#block 09: 0.81||Aulckry as t can, master.\n",
-       "ResultOCRExtracted#block 10: 0.95||~<the girl would most surely be dead by now.\n",
-       "ResultOCRExtracted#block 11: 0.94||Ghede has been generous. the ceath god has given the girl a second chance po\n",
-       "ResultOCRExtracted#block 12: 0.67||Yi renee othing to scream seat anhore .\n",
-       "ResultOCRExtracted#block 13: 0.93||Youre among eriends now. you're safe!\n",
-       "ResultOCRExtracted#block 14: 0.83||| continued af ext page\n",
-       "\n",
-       "\n",
-       "
\n" - ], - "text/plain": [ - "---------- Initial box ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski\u001b[1m)\u001b[0m \u001b[1;36m2\u001b[0m of mew ce eans, kept tidy by a white-haired old man known only as bambs, \u001b[1;36m3\u001b[0m\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the old man are alike in many ways; tall, prolid, patient, contented always \u001b[1;36m0\u001b[0m wait until. their. master cones mome ~~\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.70\u001b[0m||“and one in ee would appear.\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.62\u001b[0m||Re bambli-~ we have a\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.70\u001b[0m||Tonight, he comes noost slamming open the caken\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.82\u001b[0m||Tell me naster. how may bambli serve \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.56\u001b[0m||£\u001b[1;36m7\u001b[0m » and perhaps some dry clothes\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m \u001b[35m/\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.81\u001b[0m||The the old man's fades down the hall as\u001b[33m...\u001b[0m \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.85\u001b[0m||How curious the \u001b[1;36m4\u001b[0m fate. whims of had t not chanced to stroll along the river yl tonight ==\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.80\u001b[0m||Fas oulckly as t ca, master.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.91\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.50\u001b[0m||Aulckly “master as t can,\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m|| need of some help, it would appear .\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.88\u001b[0m||\" bambl-- we have a guest.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.72\u001b[0m||~~and tonight, he comes urgently, slanming open\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.86\u001b[0m||Tell me, master: how may bambli serve \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes-\u001b[1;36m-7\u001b[0m \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.06\u001b[0m||As.\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.91\u001b[0m||How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.55\u001b[0m||Ickl as t can\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.85\u001b[0m||Ghede has been generous. the death god has gen + the girl. a second chance te oe ato\" pd ate\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.95\u001b[0m||Easy, girl--there's | nothing to scream about anyaore.\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.97\u001b[0m||You're among friends now. you're safe!\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.54\u001b[0m||“continued a\n", - "\n", - " ---------- Padded 4px ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.88\u001b[0m||Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.93\u001b[0m||The house and the oldman are alike in many ways; tall, proud, patient, contented a ways \u001b[1;36m0\u001b[0m wait until their. aster comes home ~~ | \u001b[1m}\u001b[0m\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.69\u001b[0m||F and one in ee would appear.\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.77\u001b[0m||\" bambli-— we have a gliest.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.55\u001b[0m||P comes slamming open the caken\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.57\u001b[0m||Tel oe er-- \u001b[1;36m5\u001b[0m ow a = \u001b[1;36m7\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.38\u001b[0m||We and perhaps c oe \u001b[35m/\u001b[0m\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.75\u001b[0m||The the old mans fades down the hall sra\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.92\u001b[0m||How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.79\u001b[0m||Aulckly as t can, ‘masrer.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.92\u001b[0m||---------- Initial box ----------\n", - "ResultOCR#block 00: 0.90||Suddenly.\n", - "ResultOCR#block 01: 0.81||>gasp!z everything's w- whirling around me!t can't stand sr rea\n", - "ResultOCR#block 02: 0.81||Clark!i'm falling' “help! help! —\n", - "ResultOCR#block 03: 0.67||I-i'm bs \"passing ohhh\n", - "ResultOCR#block 04: 0.92||Action comics\n", - "ResultOCR#block 05: 1.00||Then, seconds later...\n", - "ResultOCR#block 06: 0.89||Great caesars ghost! { this /s black magic! we've been transportel to the weirdest world, tit ever saw!\n", - "ResultOCR#block 07: 0.91||...|t certainly isn't our earth, perry. look at the size of those bees.\n", - "ResultOCR#block 08: 0.88||Watch out, clark!\n", - "ResultOCR#block 09: 0.73||Owwww.\n", - "ResultOCR#block 10: 0.85||Yet the bee's stinger went ws. right through my uniform and penetrated my skin! that means. the fabric of pe ay costume has become dj} satie fued 1,\n", - "ResultOCR#block 11: 0.87||Hurry. let's beat it before we get stung, foo = aii\n", - "ResultOCR#block 12: 0.86||Ggreat guns!...2g, .pa/n i feel n pain! as superman, i should be > invulnerable! 1 have unbreakabl ‘skin! under my clark kent clothes, im wearing an woestructisle superman uniform ! =\n", - "ResultOCR#block 13: 1.00||Abruptly...\n", - "ResultOCR#block 14: 0.77||Great caesar's ghost. he's spinning a web of g/ant, sr strands --\n", - "ResultOCR#block 15: 0.89||I-i feel the heat of the sun...the pain of the bee-sting ... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers! i've become an ordinary mortal in this world. /\n", - "ResultOCR#block 16: 0.84||Enormous spider- like creature is going berserk, as if the sight of us excited him (into mad spinning get back! that 2\n", - "\n", - " ---------- Default ----------\n", - "ResultOCR#block 00: 1.00||Suddenly...\n", - "ResultOCR#block 01: 0.80||Gasp! everything's w- whi rns atound me!i can't stand we a\n", - "ResultOCR#block 02: 0.87||Clark!i'm falling! help! help\n", - "ResultOCR#block 03: 0.45||I-i'm se ou\n", - "ResultOCR#block 04: 0.92||Action comics\n", - "ResultOCR#block 05: 0.95||Then, seconds later.\n", - "ResultOCR#block 06: 0.92||Great caesar's ghost! this /s black magic! we've been transported, to the weirdest world, i ever saw!\n", - "ResultOCR#block 07: 0.93||...|t certainly isn't our earth, perry look at the size of those bees!\n", - "ResultOCR#block 08: 0.88||Watch out, clark)\n", - "ResultOCR#block 09: 0.67||Owwww.,\n", - "ResultOCR#block 10: 0.97||Yet the bee's stinger went = right through my uniform ando penetrated my skin! that mean the fabric of my superman costume has become ordinary, cloth! £\n", - "ResultOCR#block 11: 0.89||Hurry. let's beat it before we get stung, tod yi\n", - "ResultOCR#block 12: 0.88||Ggreat guns!...2gasp/z...pain i feel n fan! as superman, i should be invulnerable! 1 have unbreakable skin! under my clark kent clothes, i'm wearing an /noestruct/ele superman uniform !\n", - "ResultOCR#block 13: 1.00||Abruptly...\n", - "ResultOCR#block 14: 0.76||Great caesars ° ghost! he's spinning & web of g/a, silk strands\n", - "ResultOCR#block 15: 0.89||I-i feel the heat of the sum...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all my super -powersx ve become an ordinary mortal in this world! j\n", - "ResultOCR#block 16: 0.70||Like creature is going berserk, as if the sight of us excited him into mad spinning, get back! that \\ enormous spider-\n", - "\n", - " ---------- Default, grey pad ----------\n", - "ResultOCR#block 00: 0.78||Sudden.\n", - "ResultOCR#block 01: 0.82||5gasp!z everything's | w- whirling around] me!t can't stand ue a\n", - "ResultOCR#block 02: 0.57||Ark!i'm falling\n", - "ResultOCR#block 03: 0.85||I-t'm eq \"passing out... ohhh.\n", - "ResultOCR#block 04: 0.92||Action comics\n", - "ResultOCR#block 05: 0.00||\n", - "ResultOCR#block 06: 0.88||‘great caesar's ghost! || this /§ black magic! we've been transportel to the weirdest world, i ever saw.\n", - "ResultOCR#block 07: 0.87||\"...it certainly isn't our | earth, perry look at the| \\s|ze of those bees.\n", - "ResultOCR#block 08: 0.88||Watch out, clark!\n", - "ResultOCR#block 09: 0.73||Owwww.\n", - "ResultOCR#block 10: 0.90||Yet the bee's stinger went ~ right through my uniform and penetrated my skin! that means. the fabric of sera ry costume vis become din a s clots! a\n", - "ResultOCR#block 11: 0.80||Hurry. let's ) beat it before] we get stung, k 00! __j\n", - "ResultOCR#block 12: 0.86||Ggreat guns!...3gasp/=... rain t feel fan! as superman, i should be invulnerable® 1 have unbreakabli skin! under my clark kent clothes, ia wearing an /noestryct/iele supe iperman uniform !\n", - "ResultOCR#block 13: 0.90||Abruptly.\n", - "ResultOCR#block 14: 0.92||Great caesar's | ghost! he's spinning k web of giant, silk strands -- as tough as steel! ne]\n", - "ResultOCR#block 15: 0.89||\\i-t feel the heat of the sun...the pain of the bee-sting... the heavy weight of my & pack! every human discomfort... good grief! i've lost all my super-powers i've become an ordinary mortal in this world. /.\n", - "ResultOCR#block 16: 0.94||(get back! that enormous spider- like creature 1 § going berserk, as if the sight of us excited him into mad spinning]\n", - "\n", - " ---------- Padded 4px ----------\n", - "ResultOCR#block 00: 0.90||Suddenly.\n", - "ResultOCR#block 01: 0.83||Fgasp/= everything's whirling around me!i can't stand ea\n", - "ResultOCR#block 02: 0.68||Ie lottie eto clark!i'm falling help! help!\n", - "ResultOCR#block 03: 0.55||I-i'm yr a ohh hh.\n", - "ResultOCR#block 04: 0.92||Action comics\n", - "ResultOCR#block 05: 0.74||Then, seconds\n", - "ResultOCR#block 06: 0.62||Great caesar's ghost! \\ this /§ black magic! i ever saw!\n", - "ResultOCR#block 07: 0.87||T certainly isn't our earth, perry! look at the \\s|ze of those bees.\n", - "ResultOCR#block 08: 0.76||#3 watch out, clark!\n", - "ResultOCR#block 09: 0.73||Owwww.\n", - "ResultOCR#block 10: 0.95||\"yet the bee's stinger went ~~ right through my uniform and enetrated my skin! that means. the fabric of my superman costume has become ordinary, clot! &\n", - "ResultOCR#block 11: 0.86||Hurry! let's beat it b=fore we get stung, ¢ tool: puma\n", - "ResultOCR#block 12: 0.86||‘ggreat guns!...3gasp/5... pain i feel pain? as superman, i should be invilnerable | t ne unbreakasle gkin! under my clark kent clothes, tih wearing an indestructible superman uniform\n", - "ResultOCR#block 13: 1.00||Abruptly...\n", - "ResultOCR#block 14: 0.91||Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!\n", - "ResultOCR#block 15: 0.89||I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all \\my super-powersx ve become an ordinary mortal in this world.\n", - "ResultOCR#block 16: 0.81||(get back! that enormous spider- as if the sight of us excited him [into mad spinning\n", - "\n", - " ---------- Padded 8px ----------\n", - "ResultOCR#block 00: 0.00||\n", - "ResultOCR#block 01: 0.76||Ega5p/% everything s\\ w- whirling around me! t can't stand ue... slee\n", - "ResultOCR#block 02: 0.41||\\ help! help’\n", - "ResultOCR#block 03: 0.86||-i'm passing qut... ohh hh.\n", - "ResultOCR#block 04: 0.92||Action comics\n", - "ResultOCR#block 05: 0.00||\n", - "ResultOCR#block 06: 0.18||I ever saw/\n", - "ResultOCR#block 07: 0.86||It certainly isn't our earth, perry! poor a the size of thos!\n", - "ResultOCR#block 08: 0.62||“watch out” ial ae clark!\n", - "ResultOCR#block 09: 0.73||Owwww.\n", - "ResultOCR#block 10: 0.98||Yet the bee's stinger went right through my uniform and \\penetrated my skin! that means. the fabric of my superman costume has become ordinar! cloth!\n", - "ResultOCR#block 11: 0.93||Hurry. let's beat it before we get stung, too!\n", - "ResultOCR#block 12: 0.88||Ggreat guns!...2gasp/z...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ele $ superman uniform ! &\n", - "ResultOCR#block 13: 0.00||\n", - "ResultOCR#block 14: 0.91||Great caesai ghost. he's spinning a web of g/ant, silk strands -- as tough as steel!\n", - "ResultOCR#block 15: 0.88||I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my ! every human discomfort... good grief! i've lost all \\my super-powers! ‘ve become an ordinary mortal in this world. x\n", - "ResultOCR#block 16: 0.60||As if the sight of us excited him {into mad spinning\n", - "\n", - " ---------- Extracted, init box ----------\n", - "ResultOCRExtracted#block 00: 0.90||Suddenly.\n", - "ResultOCRExtracted#block 01: 0.83||Fgasp!z everything § w- whirling around me!i can't stand ue.\n", - "ResultOCRExtracted#block 02: 0.89||Clark!i'm falling! help! help!\n", - "ResultOCRExtracted#block 03: 0.71||I-i'm passing ohhh?\n", - "ResultOCRExtracted#block 04: 0.92||Action comics\n", - "ResultOCRExtracted#block 05: 0.98||Then, seconds later..\n", - "ResultOCRExtracted#block 06: 0.91||Great caesar's ghost! this /s black magic! we've been transportel to the weirdest world tit ever saw.\n", - "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n", - "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", - "ResultOCRExtracted#block 09: 0.62||Oowwwww.\n", - "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block 11: 0.93||Hurry. let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block 12: 0.88||Ggreat guns!...2g/ pain t feel pain? as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform *\n", - "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n", - "ResultOCRExtracted#block 14: 0.80||Great caesar's ghost. he's spinning a web of g/ant, silk strands --\n", - "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal im this world.\n", - "ResultOCRExtracted#block 16: 0.97||Get back. that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning\n", - "\n", - " ---------- Padded 4, extracted ----------\n", - "ResultOCRExtracted#block 00: 1.00||Suddenly...\n", - "ResultOCRExtracted#block 01: 0.83||Sgasp/z everything s w- whirling around me!i can't stand ue.\n", - "ResultOCRExtracted#block 02: 0.87||Clark! i'm falling’ help! help!\n", - "ResultOCRExtracted#block 03: 0.78||I-i'm passing ohhhh.\n", - "ResultOCRExtracted#block 04: 0.92||Action comics\n", - "ResultOCRExtracted#block 05: 0.98||Then, seconds later..\n", - "ResultOCRExtracted#block 06: 0.93||Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw!\n", - "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n", - "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", - "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", - "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block 12: 0.89||Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !\n", - "ResultOCRExtracted#block 13: 1.00||Abruptly...\n", - "ResultOCRExtracted#block 14: 0.94||Great caesar's ghost! he's spinning a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block 16: 0.97||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning\n", - "\n", - " ---------- Padded 8, extracted ----------\n", - "ResultOCRExtracted#block 00: 0.91||Suddemly...\n", - "ResultOCRExtracted#block 01: 0.85||Sgasp/z everything s w- whirling around me!i can't stand up.\n", - "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n", - "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n", - "ResultOCRExtracted#block 04: 0.92||Action comics\n", - "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n", - "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw.\n", - "ResultOCRExtracted#block 07: 0.90||...it certainly isnt our earth, perry. look at the size of those bees.\n", - "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", - "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", - "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block 12: 0.89||Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !\n", - "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n", - "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block 15: 0.89||I-t feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block 16: 0.95||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [\n", - "\n", - " ---------- Padded 8, dilation 1 ----------\n", - "ResultOCRExtracted#block 00: 1.00||Suddenly...\n", - "ResultOCRExtracted#block 01: 0.83||Gasp! everything s w-whirling around wel] i can't stand\n", - "ResultOCRExtracted#block 02: 0.86||Clark!i'm falling! . help! help!\n", - "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n", - "ResultOCRExtracted#block 04: 0.92||Action comics\n", - "ResultOCRExtracted#block 05: 0.95||Then, seconds later.\n", - "ResultOCRExtracted#block 06: 0.91||Great caesar's ghost! e this /5 black magic! we've been transported to the weirdest world i ever saw/\n", - "ResultOCRExtracted#block 07: 0.91||...|it certainly isnt our earth, perry” look at the size of those bees!\n", - "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", - "ResultOCRExtracted#block 09: 0.73||Owwww.\n", - "ResultOCRExtracted#block 10: 0.94||Yet the bee's stinger we right through my tform and penetrated my skin! that means. the fabric of my superman othe has become ordinary clot?\n", - "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block 12: 0.82||Fain! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", - "ResultOCRExtracted#block 13: 0.00||\n", - "ResultOCRExtracted#block 14: 0.67||Great caesars ghost! he's spinning _ a web of g/ant,\n", - "ResultOCRExtracted#block 15: 0.86||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve ie an ordinary mortal in this world.\n", - "ResultOCRExtracted#block 16: 0.96||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning’ g [\n", - "\n", - " ---------- Pad 8, fract. 0.5 ----------\n", - "ResultOCRExtracted#block 00: 0.91||Suddemly...\n", - "ResultOCRExtracted#block 01: 0.87||Gasp/z everything s w- whirling around me!i can't stand up.\n", - "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n", - "ResultOCRExtracted#block 03: 0.78||I-i'm passing ohhhh.\n", - "ResultOCRExtracted#block 04: 0.92||Action comics\n", - "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n", - "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw.\n", - "ResultOCRExtracted#block 07: 0.92||...it certainly isnt our earth, perry! look at the size of those bees.\n", - "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", - "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", - "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block 12: 0.90||Ggreat guns!...2gasp/:...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /nodestruct/ible superman uniform !\n", - "ResultOCRExtracted#block 13: 0.96||Abruptly. ..\n", - "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block 16: 0.95||Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [\n", - "\n", - " ---------- Pad 8, fract. 0.2 ----------\n", - "ResultOCRExtracted#block 00: 1.00||Suddenly...\n", - "ResultOCRExtracted#block 01: 0.87||Gasp/z everything s w- whirling around me!i can't stand up.\n", - "ResultOCRExtracted#block 02: 0.84||Clark! i'm falling’ _ help! help!\n", - "ResultOCRExtracted#block 03: 0.73||I-i'm passing ohhha.\n", - "ResultOCRExtracted#block 04: 0.92||Action comics\n", - "ResultOCRExtracted#block 05: 1.00||Then, seconds later...\n", - "ResultOCRExtracted#block 06: 0.90||Great caesar's ghost! f this /§ black magic! : we've been transported to the weirdest world i ever saw!\n", - "ResultOCRExtracted#block 07: 0.92||...it certainly isnt our earth, perry! look at the size of those bees.\n", - "ResultOCRExtracted#block 08: 0.88||Watch out, clark!\n", - "ResultOCRExtracted#block 09: 0.67||Owwww.,\n", - "ResultOCRExtracted#block 10: 0.99||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block 11: 0.96||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block 12: 0.91||Ggreat guns!...2gasp/:... pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", - "ResultOCRExtracted#block 13: 0.96||Abruptly....\n", - "ResultOCRExtracted#block 14: 0.93||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block 15: 0.89||I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block 16: 0.96||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning gs [\n", - "\n", - "\n", - "\n" - ], - "text/plain": [ - "---------- Initial box ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.81\u001b[0m||>gasp!z everything's w- whirling around me!t can't stand sr rea\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.81\u001b[0m||Clark!i'm falling' “help! help! —\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.67\u001b[0m||I-i'm bs \"passing ohhh\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.89\u001b[0m||Great caesars ghost! \u001b[1m{\u001b[0m this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transportel to the weirdest world, tit ever saw!\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.91\u001b[0m||\u001b[33m...\u001b[0m|t certainly isn't our earth, perry. look at the size of those bees.\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.85\u001b[0m||Yet the bee's stinger went ws. right through my uniform and penetrated my skin! that means. the fabric of pe ay costume has become dj\u001b[1m}\u001b[0m satie fued \u001b[1;36m1\u001b[0m,\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.87\u001b[0m||Hurry. let's beat it before we get stung, foo = aii\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2g, .pa/n i feel n pain! as superman, i should be > invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl ‘skin! under my clark kent clothes, im wearing an woestructisle superman uniform ! =\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.77\u001b[0m||Great caesar's ghost. he's spinning a web of g/ant, sr strands --\n", - "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting \u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers! i've become an ordinary mortal in this world. \u001b[35m/\u001b[0m\n", - "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.84\u001b[0m||Enormous spider- like creature is going berserk, as if the sight of us excited him \u001b[1m(\u001b[0minto mad spinning get back! that \u001b[1;36m2\u001b[0m\n", - "\n", - " ---------- Default ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.80\u001b[0m||Gasp! everything's w- whi rns atound me!i can't stand we a\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.87\u001b[0m||Clark!i'm falling! help! help\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.45\u001b[0m||I-i'm se ou\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.95\u001b[0m||Then, seconds later.\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.92\u001b[0m||Great caesar's ghost! this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transported, to the weirdest world, i ever saw!\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.93\u001b[0m||\u001b[33m...\u001b[0m|t certainly isn't our earth, perry look at the size of those bees!\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark\u001b[1m)\u001b[0m\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.97\u001b[0m||Yet the bee's stinger went = right through my uniform ando penetrated my skin! that mean the fabric of my superman costume has become ordinary, cloth! £\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.89\u001b[0m||Hurry. let's beat it before we get stung, tod yi\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/z\u001b[33m...\u001b[0mpain i feel n fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakable skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mele\u001b[0m superman uniform !\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.76\u001b[0m||Great caesars ° ghost! he's spinning & web of g/a, silk strands\n", - "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sum\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my \u001b[1m{\u001b[0m pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super -powersx ve become an ordinary mortal in this world! j\n", - "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.70\u001b[0m||Like creature is going berserk, as if the sight of us excited him into mad spinning, get back! that \\ enormous spider-\n", - "\n", - " ---------- Default, grey pad ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.78\u001b[0m||Sudden.\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.82\u001b[0m||5gasp!z everything's | w- whirling around\u001b[1m]\u001b[0m me!t can't stand ue a\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.57\u001b[0m||Ark!i'm falling\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.85\u001b[0m||I-t'm eq \"passing out\u001b[33m...\u001b[0m ohhh.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.88\u001b[0m||‘great caesar's ghost! || this \u001b[35m/\u001b[0m§ black magic! we've been transportel to the weirdest world, i ever saw.\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.87\u001b[0m||\"\u001b[33m...\u001b[0mit certainly isn't our | earth, perry look at the| \\s|ze of those bees.\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.90\u001b[0m||Yet the bee's stinger went ~ right through my uniform and penetrated my skin! that means. the fabric of sera ry costume vis become din a s clots! a\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.80\u001b[0m||Hurry. let's \u001b[1m)\u001b[0m beat it before\u001b[1m]\u001b[0m we get stung, k \u001b[1;36m00\u001b[0m! __j\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m3gasp/=\u001b[33m...\u001b[0m rain t feel fan! as superman, i should be invulnerable® \u001b[1;36m1\u001b[0m have unbreakabli skin! under my clark kent clothes, ia wearing an \u001b[35m/noestryct/\u001b[0m\u001b[95miele\u001b[0m supe iperman uniform !\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.90\u001b[0m||Abruptly.\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.92\u001b[0m||Great caesar's | ghost! he's spinning k web of giant, silk strands -- as tough as steel! ne\u001b[1m]\u001b[0m\n", - "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||\\i-t feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my & pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers i've become an ordinary mortal in this world. \u001b[35m/\u001b[0m\u001b[95m.\u001b[0m\n", - "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.94\u001b[0m||\u001b[1m(\u001b[0mget back! that enormous spider- like creature \u001b[1;36m1\u001b[0m § going berserk, as if the sight of us excited him into mad spinning\u001b[1m]\u001b[0m\n", - "\n", - " ---------- Padded 4px ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Fgasp/= everything's whirling around me!i can't stand ea\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.68\u001b[0m||Ie lottie eto clark!i'm falling help! help!\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.55\u001b[0m||I-i'm yr a ohh hh.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.74\u001b[0m||Then, seconds\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.62\u001b[0m||Great caesar's ghost! \\ this \u001b[35m/\u001b[0m§ black magic! i ever saw!\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.87\u001b[0m||T certainly isn't our earth, perry! look at the \\s|ze of those bees.\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.76\u001b[0m||#\u001b[1;36m3\u001b[0m watch out, clark!\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.95\u001b[0m||\"yet the bee's stinger went ~~ right through my uniform and enetrated my skin! that means. the fabric of my superman costume has become ordinary, clot! &\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.86\u001b[0m||Hurry! let's beat it \u001b[33mb\u001b[0m=\u001b[35mfore\u001b[0m we get stung, ¢ tool: puma\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.86\u001b[0m||‘ggreat guns!\u001b[33m...\u001b[0m3gasp/\u001b[1;36m5\u001b[0m\u001b[33m...\u001b[0m pain i feel pain? as superman, i should be invilnerable | t ne unbreakasle gkin! under my clark kent clothes, tih wearing an indestructible superman uniform\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!\n", - "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my \u001b[1m{\u001b[0m pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all \\my super-powersx ve become an ordinary mortal in this world.\n", - "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.81\u001b[0m||\u001b[1m(\u001b[0mget back! that enormous spider- as if the sight of us excited him \u001b[1m[\u001b[0minto mad spinning\n", - "\n", - " ---------- Padded 8px ----------\n", - "ResultOCR#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.76\u001b[0m||Ega5p/% everything s\\ w- whirling around me! t can't stand ue\u001b[33m...\u001b[0m slee\n", - "ResultOCR#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.41\u001b[0m||\\ help! help’\n", - "ResultOCR#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.86\u001b[0m||-i'm passing qut\u001b[33m...\u001b[0m ohh hh.\n", - "ResultOCR#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCR#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.18\u001b[0m||I ever saw/\n", - "ResultOCR#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.86\u001b[0m||It certainly isn't our earth, perry! poor a the size of thos!\n", - "ResultOCR#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.62\u001b[0m||“watch out” ial ae clark!\n", - "ResultOCR#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", - "ResultOCR#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.98\u001b[0m||Yet the bee's stinger went right through my uniform and \\penetrated my skin! that means. the fabric of my superman costume has become ordinar! cloth!\n", - "ResultOCR#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.93\u001b[0m||Hurry. let's beat it before we get stung, too!\n", - "ResultOCR#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/z\u001b[33m...\u001b[0mpain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mele\u001b[0m $ superman uniform ! &\n", - "ResultOCR#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCR#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesai ghost. he's spinning a web of g/ant, silk strands -- as tough as steel!\n", - "ResultOCR#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.88\u001b[0m||I-i feel the heat of the sun\u001b[33m...\u001b[0mthe pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my ! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all \\my super-powers! ‘ve become an ordinary mortal in this world. x\n", - "ResultOCR#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.60\u001b[0m||As if the sight of us excited him \u001b[1m{\u001b[0minto mad spinning\n", - "\n", - " ---------- Extracted, init box ----------\n", - "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.90\u001b[0m||Suddenly.\n", - "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Fgasp!z everything § w- whirling around me!i can't stand ue.\n", - "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.89\u001b[0m||Clark!i'm falling! help! help!\n", - "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.71\u001b[0m||I-i'm passing ohhh?\n", - "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.98\u001b[0m||Then, seconds later..\n", - "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesar's ghost! this \u001b[35m/\u001b[0m\u001b[95ms\u001b[0m black magic! we've been transportel to the weirdest world tit ever saw.\n", - "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n", - "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.62\u001b[0m||Oowwwww.\n", - "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.93\u001b[0m||Hurry. let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.88\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2g/ pain t feel pain? as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform *\n", - "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n", - "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.80\u001b[0m||Great caesar's ghost. he's spinning a web of g/ant, silk strands --\n", - "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal im this world.\n", - "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.97\u001b[0m||Get back. that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning\n", - "\n", - " ---------- Padded \u001b[1;36m4\u001b[0m, extracted ----------\n", - "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Sgasp/z everything s w- whirling around me!i can't stand ue.\n", - "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.87\u001b[0m||Clark! i'm falling’ help! help!\n", - "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.78\u001b[0m||I-i'm passing ohhhh.\n", - "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.98\u001b[0m||Then, seconds later..\n", - "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw!\n", - "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n", - "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", - "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.89\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain t feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform !\n", - "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m1.00\u001b[0m||Abruptly\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.94\u001b[0m||Great caesar's ghost! he's spinning a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.97\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning\n", - "\n", - " ---------- Padded \u001b[1;36m8\u001b[0m, extracted ----------\n", - "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.91\u001b[0m||Suddemly\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.85\u001b[0m||Sgasp/z everything s w- whirling around me!i can't stand up.\n", - "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n", - "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n", - "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw.\n", - "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.90\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry. look at the size of those bees.\n", - "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", - "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.89\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain t feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/noestruct/\u001b[0m\u001b[95mble\u001b[0m superman uniform !\n", - "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n", - "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-t feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.95\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning g \u001b[1m[\u001b[0m\n", - "\n", - " ---------- Padded \u001b[1;36m8\u001b[0m, dilation \u001b[1;36m1\u001b[0m ----------\n", - "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.83\u001b[0m||Gasp! everything s w-whirling around wel\u001b[1m]\u001b[0m i can't stand\n", - "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.86\u001b[0m||Clark!i'm falling! . help! help!\n", - "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n", - "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m0.95\u001b[0m||Then, seconds later.\n", - "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.91\u001b[0m||Great caesar's ghost! e this \u001b[35m/\u001b[0m\u001b[95m5\u001b[0m black magic! we've been transported to the weirdest world i ever saw/\n", - "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.91\u001b[0m||\u001b[33m...\u001b[0m|it certainly isnt our earth, perry” look at the size of those bees!\n", - "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.73\u001b[0m||Owwww.\n", - "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.94\u001b[0m||Yet the bee's stinger we right through my tform and penetrated my skin! that means. the fabric of my superman othe has become ordinary clot?\n", - "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.82\u001b[0m||Fain! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", - "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.00\u001b[0m||\n", - "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.67\u001b[0m||Great caesars ghost! he's spinning _ a web of g/ant,\n", - "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.86\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve ie an ordinary mortal in this world.\n", - "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.96\u001b[0m||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning’ g \u001b[1m[\u001b[0m\n", - "\n", - " ---------- Pad \u001b[1;36m8\u001b[0m, fract. \u001b[1;36m0.5\u001b[0m ----------\n", - "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m0.91\u001b[0m||Suddemly\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.87\u001b[0m||Gasp/z everything s w- whirling around me!i can't stand up.\n", - "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n", - "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.78\u001b[0m||I-i'm passing ohhhh.\n", - "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw.\n", - "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.92\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry! look at the size of those bees.\n", - "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", - "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.90\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0mpain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an \u001b[35m/nodestruct/\u001b[0m\u001b[95mible\u001b[0m superman uniform !\n", - "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly. ..\n", - "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun. the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.95\u001b[0m||Get back! that enormous spider- like creature is going berserk, \u001b[1;36m25\u001b[0m if the sight of us excited him into mad spinning g \u001b[1m[\u001b[0m\n", - "\n", - " ---------- Pad \u001b[1;36m8\u001b[0m, fract. \u001b[1;36m0.2\u001b[0m ----------\n", - "ResultOCRExtracted#block \u001b[1;36m00\u001b[0m: \u001b[1;36m1.00\u001b[0m||Suddenly\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m01\u001b[0m: \u001b[1;36m0.87\u001b[0m||Gasp/z everything s w- whirling around me!i can't stand up.\n", - "ResultOCRExtracted#block \u001b[1;36m02\u001b[0m: \u001b[1;36m0.84\u001b[0m||Clark! i'm falling’ _ help! help!\n", - "ResultOCRExtracted#block \u001b[1;36m03\u001b[0m: \u001b[1;36m0.73\u001b[0m||I-i'm passing ohhha.\n", - "ResultOCRExtracted#block \u001b[1;36m04\u001b[0m: \u001b[1;36m0.92\u001b[0m||Action comics\n", - "ResultOCRExtracted#block \u001b[1;36m05\u001b[0m: \u001b[1;36m1.00\u001b[0m||Then, seconds later\u001b[33m...\u001b[0m\n", - "ResultOCRExtracted#block \u001b[1;36m06\u001b[0m: \u001b[1;36m0.90\u001b[0m||Great caesar's ghost! f this \u001b[35m/\u001b[0m§ black magic! : we've been transported to the weirdest world i ever saw!\n", - "ResultOCRExtracted#block \u001b[1;36m07\u001b[0m: \u001b[1;36m0.92\u001b[0m||\u001b[33m...\u001b[0mit certainly isnt our earth, perry! look at the size of those bees.\n", - "ResultOCRExtracted#block \u001b[1;36m08\u001b[0m: \u001b[1;36m0.88\u001b[0m||Watch out, clark!\n", - "ResultOCRExtracted#block \u001b[1;36m09\u001b[0m: \u001b[1;36m0.67\u001b[0m||Owwww.,\n", - "ResultOCRExtracted#block \u001b[1;36m10\u001b[0m: \u001b[1;36m0.99\u001b[0m||Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!\n", - "ResultOCRExtracted#block \u001b[1;36m11\u001b[0m: \u001b[1;36m0.96\u001b[0m||Hurry! let's beat it before we get stung, too!\n", - "ResultOCRExtracted#block \u001b[1;36m12\u001b[0m: \u001b[1;36m0.91\u001b[0m||Ggreat guns!\u001b[33m...\u001b[0m2gasp/:\u001b[33m...\u001b[0m pain i feel fan! as superman, i should be invulnerable! \u001b[1;36m1\u001b[0m have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !\n", - "ResultOCRExtracted#block \u001b[1;36m13\u001b[0m: \u001b[1;36m0.96\u001b[0m||Abruptly\u001b[33m...\u001b[0m.\n", - "ResultOCRExtracted#block \u001b[1;36m14\u001b[0m: \u001b[1;36m0.93\u001b[0m||Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!\n", - "ResultOCRExtracted#block \u001b[1;36m15\u001b[0m: \u001b[1;36m0.89\u001b[0m||I-i feel the heat of the sun., the pain of the bee-sting\u001b[33m...\u001b[0m the heavy weight of my pack! every human discomfort\u001b[33m...\u001b[0m good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.\n", - "ResultOCRExtracted#block \u001b[1;36m16\u001b[0m: \u001b[1;36m0.96\u001b[0m||Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning gs \u001b[1m[\u001b[0m\n", - "\n", - "\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_action_experiment: ExperimentOCR = cast(ExperimentOCR, ExperimentOCR.from_image(\n", - " CONTEXT, 'Tesseract', 'Action_Comics_1960-01-00_(262).JPG'))\n", - "image_action_experiment.display()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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UKECli9fjh07diAlJQX29vZwc3PD0KFDpXzKtixevBg+Pj5wdnbG9OnTERkZKU24lpVt27Zh5cqV2LJlCzZu3Ai5XI6yZcti69at6Nmzp1rehIQEnQLnj21TRtu3b8eYMWMwefJkpKamwsPDA8ePH9dYDqxkyZJYtmwZli9fDk9PT6SlpWHTpk0ak6UBYg/6/v374e/vj02bNmH+/PmwsbFBnz59sGDBgjy933j37t0aM3Ur1xSfPXt2tuuU9+rVCytXrkRKSopau8qXL4+TJ09iypQp6Ny5M/T19eHl5YXAwECNe9XT0tLURgbo6enh+PHjWLp0Kfbs2YPAwECYmpqiQoUKOHz4MFq2bCnlPXToED58+ICLFy9qndH+3r17akPJ9+/fDxsbGzRr1izbY0NERERE9CWTCVl1WRKpePPmDaytrbFs2TKMGDGioJvzVXn8+DFKliyJzZs3a8x0/6lJS0uDi4sLevbsifnz5+u8XXx8PCwsLLD+wiAYmxrkYwuJiIgoL/Qst6qgm0BUoJS/X+Pi4jRGOKviPd2ks1OnTkm9/fTfcnBwwNixYzF//nxpPe1P1datW5GQkCCtfU5ERERE9DXj8HLSWevWrTWGc9N/Z+bMmTA2NsajR49QvHjxgm5Opj58+IBt27ZluVwZEREREdHXgkE30WfCzMwMs2fPLuhmZKt///4F3QQiIiIiok8Gh5cTERERERER5RMG3URERERERET5hEE3ERERERERUT7hPd1E9EnpWubbLJdcICIiIiL6nLCnm4iIiIiIiCifMOgmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoJuIiIiIiIgon3D2ciL6pBSd3xYyBb+aiIiIiL4UCXPDC7oJBYo93URERERERET5hEE3ERERERERUT5h0E1ERERERESUTxh0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE++uqA7ODgYMplMeujr66NYsWLo378/Hj16lGf1ODs7w9fXV+f2REdH51ndvr6+cHZ2zjafIAhYv349atasCXNzcxQuXBiNGjXCoUOH8qwtH2v79u1YtmxZgbZh9erVCA4OzpeyZTIZ/P39dcp7+vRpKBQK3L9/Xy394sWLaNKkCUxNTWFpaQkfHx/cvXtXpzJTUlKwdOlSVKpUCSYm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Pj44evQonj17Bjs7O7Ro0QKOjo552T4iIiIiIiKiz1aug24AcHR0xMCBA/OqLURERERERERflFwH3QkJCTh8+DCio6ORnJys8b6fn99HNYyIiIiIiIjoc5eroPvixYto2bIlXr58mWkeBt1ERERERET0tcv17OUvXrzI9H2ZTJbrBhERERERERF9KXI1e/mlS5cgk8ng6emJFStWYOPGjdi0aZP02LhxY16385MQHBwMmUyW6ePkyZM5Ki8xMRH+/v453i4vPX78GP7+/rh06VKel608XtHR0TneNjo6GjKZDMHBwbmq29nZGb6+vtLrnO6nsu0XLlzIVf35ITY2FjY2Nti5c6da+vPnz+Hr6wsbGxsYGxvD3d0d4eHhOpcbGhoKDw8PWFtbw9LSErVr18aWLVs08sXHx2PGjBkoW7YsjI2N4ejoiC5duuD69etq+YKCguDo6Ii3b9/mbkeJiIiIiL4guerpNjMzw9u3bxEaGgorK6u8btMnb9OmTShfvrxGeoUKFXJUTmJiIubMmQMA8PT0zIum5djjx48xZ84cODs7o1q1agXSBm2KFi2Ks2fPonTp0rnaft++fTA3N5def6r7mRNz5syBg4MDunXrJqWlpKTA29sbsbGxWL58OWxtbbFq1Sq0aNECYWFhaNSoUZZlbty4EQMHDkSnTp0wc+ZMyGQyhISEoG/fvnj58iXGjRsn5W3bti0uXLgAf39/1KpVCw8fPsTcuXPh7u6Oq1evwsnJCQDQr18/LF68GEuWLJE+30REREREX6tcBd29e/dGYGAg7t2791UG3ZUqVUKtWrX+83oTExNhbGz8n9dbEBQKBerWrZvr7atXr56HrSl4r169wo8//ojvv/9e7faNoKAgXLt2Db///jvc3d0BAI0bN0bVqlUxefJk/PHHH1mWu3HjRjg5OWH37t3Q0xMHvjRv3hyXLl1CcHCwFHTfvn0bp06dwsyZMzFp0iRpexcXF9SrVw979+6V8urr6+Obb75BQEAApkyZ8tV8ZomIiIiItNF5ePmpU6ekh6enJ+zs7NChQwesXLkS4eHhau+fOnUqP9v8ydu5cydkMhlWrlyplj579mwUKlQIx48fR3R0NIoUKQJA7MFUDlFXDon29/eHTCbDxYsX0blzZ1hZWUm9vhcuXED37t3h7OwMIyMjODs7o0ePHrh//75GWx49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SBOoAUDx4sURGRmJPXv25GkjiYiIiIiIiD5HuRpeHhAQgISEBBgYGODdu3dSeo8ePbBixQpERkbmWQOJ6Oty+5udWd4TQ0RERET0OclVT3d4eDhkMhmOHDmill65cmUAwIMHDz6+ZURERERERESfuVwF3cplnzIuCSSTyQAAr1+//shmEREREREREX3+chV0K4d+Pn36VC1duYSYlZXVRzaLiIiIiIiI6POXq6C7Zs2aAIChQ4dKaUuWLEHfvn0hk8ng5uaWN60jIiL6v/buOyyK630b+L3u0kEElC5gx44o9gIidjRi76DYjb1EVCwo2GKJvSBg76LEFnsFxdhj7PVrI4IKIiJl3j94d36MuxSNGwTvz3XtdbFnnjnzzLCb+HDOnCEiIiLKx76q6B48eDAEQcDBgwfFKeUTJkwQp5UPHjz422VIRERERERElE99VdHdtm1bjBs3TnxcWObHhv3yyy9o0aLFN02SiIiIiIiIKD+SCcpq+StcvHgRe/bswatXr2BhYYGffvpJnHpORPQl4uPjYWxsjNUoBX3I8ySHbsLtPDkuEREREeU/yn+/vnv3LttH3ub6Od2Zn8etVKVKFVSpUkVtnLa2dm67JiIiIiIiIiqQcl106+np5bpTmUyG1NTUr0qIiIiIiIiIqKDIddH9L2ahExEREREREf2QvmghNZlMJq5WTkRERERERETZ+6KiWznaXbJkScybNw9v3rxBenq6yistLU0jyRIRERERERHlJ7kuus+fP49u3bpBS0sLDx48wNixY1G8eHEMGjQIf/31lyZzJCIiIiIiIsqXcl10u7i4YMOGDXjy5AmmTp0KS0tLvH//HqtWrUKVKlXg7u6Oo0ePajJXIiIiIiIionzli6aXA4C5uTn8/f3x+PFjbNy4EaamphAEASdOnMDSpUs1kSP9R0JDQ8X79mUyGRQKBWxtbeHj44Nnz559s+M4ODjA29s71/k8evTomx3b29sbDg4OOcYJgoDVq1ejevXqKFy4MMzMzNCoUSPs27fvm+XyNaZPn44KFSogPT1d0r5lyxY4OTlBV1cX1tbWGDFiBN6/f5/rfh8/fow+ffrA2toaOjo6sLGxQbt27SQxu3btQteuXVG6dGno6enBwcEB3bt3x927dyVxKSkpKFWqFBYuXPjV50lEREREVFB8cdENZDwEfMmSJfD390dc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tvDx8cGzZ8++2XEcHBzg7e2d63wePXr0zY7t7e0NBweHL9pHEAQ0bNgQMpkMQ4cO/Wa5fI3p06ejQoUKSE9Pl7Rv2bIFTk5O0NXVhbW1NUaMGIH379/nqs+XL19i6NChKFmyJPT09GBvb4++ffviyZMnkrhdu3aha9euKF26NPT09ODg4IDu3bvj7t27kriUlBSUKlUKCxcu/FfnSkRERERUELDoJhUhISGIjIzE4cOH0a9fP2zevBkNGjRAYmJiXqeWJ5YuXYp79+7ldRp4/vw55syZg+nTp6NQof/76m7cuBFdu3aFi4sLDhw4gClTpiA0NBReXl459pmcnIyGDRti69atGDNmDA4cOAA/Pz/s27cPdevWRUJCghg7e/ZsfPjwARMnTsTBgwcxY8YMXL58Gc7Ozvjrr7/EOC0tLfj7+2P69OmIjY39theBiIiIiCifUeR1AvT9qVSpEmrUqAEAcHNzQ1paGgICAhAeHo7u3bvncXb/rUePHmHChAlYt25dropYTVq0aBGKFCkiySMtLQ1jx45F06ZNsXr1agAZvzMjIyN0794dBw4cQIsWLbLs8/Tp07h79y7WrFmDvn37AgBcXV1RuHBhdOvWDUeOHEG7du0AABERETA3N5fs37hxYzg4OGDBggVYs2aN2N61a1eMGjUKK1euhJ+f3ze7BkRERERE+Q1HuilHtWvXBgA8fvwYADBt2jTUqlULpqamKFy4MJydnREcHAxBECT7paSkYNy4cbC0tIS+vj7q16+PCxcuqD1GVFQU6tWrJ06PnjBhAlJSUtTGbt26FXXq1IGBgQEMDQ3RrFkzXL58WSUuNDQU5cqVg46ODsqXL49169Z98bn3798fHh4eYuH5uRMnTkAmk2HDhg0YNWoULC0toaenh0aNGklyev36NYoXL466detKzuvmzZswMDBAz549s83j06dPCA4ORrdu3SSj3FFRUXjx4gV8fHwk8R07doShoSF2796dbb9aWloAAGNjY0l7kSJFAAC6urpi2+cFNwBYW1vD1tYWT58+lbRra2ujc+fOWLVqlcrngoiIiIjoR8Kim3KknFpdrFgxABmjvwMGDMC2bduwa9cueHl54eeff0ZAQIBkv379+mHevHno1asX9uzZg/bt28PLywtv3ryRxN28eRPu7u54+/YtQkNDsWLFCly+fBkzZsxQySUw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ZDKBD9Glf+HmzZuoWLEifv/991wV7597+PAhHB0dMWXKFPj5+X3z/K5du4aqVati6dKl4gh1TkJDQ+Hj44Po6GjUqFHjm+f0tX7++WccPXoUf/311xevSv5fCw4OxvDhw/H06dNcj3THx8fD2NgYkQ+nwNBIddE4IiKi/KyS2S95nQIRfWPKf7++e/cOhQsXzjKO93TTv3L8+HHUqVMnVwX31atX8csvv2Dv3r04ceIEVq5ciSZNmqBw4cIqz4X+t+7fv49jx46hf//+sLKyUjsKnt9MmjQJz549w86dO/M6lWylpqZi9uzZmDBhAqeWExEREdEPj0U3/StDhgzBuXPnchVrYGCAixcvom/fvvDw8MDEiRNRrVo1nDlzJsvHhn2tgIAAeHh44P3799i+fTv09fW/af95wcLCAhs3bvyuHgWnztOnT9GjRw+MHj06r1MhIiIiIspznF5ORN8FTi8nIqKCjNPLiQoeTi8nIiIiIiIiymMsuomIiIiIiIg0hEU3ERERERERkYbwOd1E9F2pYDoq23tiiIiIiIjyE450ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOgmIiIiIiIi0hA+MoyIviu+hwdBy0A7r9MgIiIiytLG5iF5nQLlIxzpJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3fbdCQ0Mhk8nEl66uLiwtLeHm5oagoCDExMT8q/6PHj2KGjVqwMDAADKZDOHh4d8m8c94e3vDwcFB0hYYGPjFx7t//z50dHQQGRkpaX/w4AG8vLxQpEgRGBoawsPDA5cuXcpVn4IgYPXq1ahevToKFy4MMzMzNGrUCPv27VOJzfy7yPyaNWuWJG7y5MlwdnZGenr6F50fEREREVFBxKKbvnshISGIjIzE4cOHsXTpUjg5OWH27NkoX748jhw58lV9CoKATp06QUtLC3v37kVkZCQaNWr0jTPP2tcU3WPGjIGHhwfq1Kkjtv3zzz9o0KAB7ty5g7Vr12Lbtm34+PEjXF1dcfv27Rz7nDJlCvr374+aNWti586dCA0NhY6ODlq3bo1du3apxHfo0AGRkZGSV69evVTyfPjwIcLC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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_action_experiment.plot_accuracies()\n" - ] - }, - { - "cell_type": "code", - "execution_count": 115, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!
0.91
\n", - "
\n", - "
Great Caesar's Ghost! He's spinning a web of giant,⎕⎕ silk strands-- as tough as steel!

Great caesars ghost. he's spinning a web of g/ant,⎕| silk strands⎕⎕ as tough as steel!
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_action_experiment.result(14, CropMethod.PADDED_4)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 116, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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UKECli9fjh07diAlJQX29vZwc3PD0KFDpXzKtixevBg+Pj5wdnbG9OnTERkZKU24lpVt27Zh5cqV2LJlCzZu3Ai5XI6yZcti69at6Nmzp1rehIQEnQLnj21TRtu3b8eYMWMwefJkpKamwsPDA8ePH9dYDqxkyZJYtmwZli9fDk9PT6SlpWHTpk0ak6UBYg/6/v374e/vj02bNmH+/PmwsbFBnz59sGDBgjy933j37t0aM3Ur1xSfPXt2tuuU9+rVCytXrkRKSopau8qXL4+TJ09iypQp6Ny5M/T19eHl5YXAwECNe9XT0tLURgbo6enh+PHjWLp0Kfbs2YPAwECYmpqiQoUKOHz4MFq2bCnlPXToED58+ICLFy9qndH+3r17akPJ9+/fDxsbGzRr1izbY0NERERE9CWTCVl1WRKpePPmDaytrbFs2TKMGDGioJvzVXn8+DFKliyJzZs3a8x0/6lJS0uDi4sLevbsifnz5+u8XXx8PCwsLLD+wiAYmxrkYwuJiIgoL/Qst6qgm0BUoJS/X+Pi4jRGOKviPd2ks1OnTkm9/fTfcnBwwNixYzF//nxpPe1P1datW5GQkCCtfU5ERERE9DXj8HLSWevWrTWGc9N/Z+bMmTA2NsajR49QvHjxgm5Opj58+IBt27ZluVwZEREREdHXgkE30WfCzMwMs2fPLuhmZKt///4F3QQiIiIiok8Gh5cTERERERER5RMG3URERERERET5hEE3ERERERERUT7hPd1E9EnpWubbLJdcICIiIiL6nLCnm4iIiIiIiCifMOgmIiIiIiIiyicMuomIiIiIiIjyCYNuIiIiIiIionzCoJuIiIiIiIgon3D2ciL6pBSd3xYyBb+aiIiIiL4UCXPDC7oJBYo93URERERERET5hEE3ERERERERUT5h0E1ERERERESUTxh0ExEREREREeUTBt1ERERERERE+YRBNxEREREREVE+YdBNRERERERElE++uqA7ODgYMplMeujr66NYsWLo378/Hj16lGf1ODs7w9fXV+f2REdH51ndvr6+cHZ2zjafIAhYv349atasCXNzcxQuXBiNGjXCoUOH8qwtH2v79u1YtmxZgbZh9erVCA4OzpeyZTIZ/P39dcp7+vRpKBQK3L9/Xy394sWLaNKkCUxNTWFpaQkfHx/cvXtXpzJTUlKwdOlSVKpUCSYm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Pj44evQonj17Bjs7O7Ro0QKOjo552T4iIiIiIiKiz1aug24AcHR0xMCBA/OqLURERERERERflFwH3QkJCTh8+DCio6ORnJys8b6fn99HNYyIiIiIiIjoc5eroPvixYto2bIlXr58mWkeBt1ERERERET0tcv17OUvXrzI9H2ZTJbrBhERERERERF9KXI1e/mlS5cgk8ng6emJFStWYOPGjdi0aZP02LhxY16385MQHBwMmUyW6ePkyZM5Ki8xMRH+/v453i4vPX78GP7+/rh06VKel608XtHR0TneNjo6GjKZDMHBwbmq29nZGb6+vtLrnO6nsu0XLlzIVf35ITY2FjY2Nti5c6da+vPnz+Hr6wsbGxsYGxvD3d0d4eHhOpcbGhoKDw8PWFtbw9LSErVr18aWLVs08sXHx2PGjBkoW7YsjI2N4ejoiC5duuD69etq+YKCguDo6Ii3b9/mbkeJiIiIiL4guerpNjMzw9u3bxEaGgorK6u8btMnb9OmTShfvrxGeoUKFXJUTmJiIubMmQMA8PT0zIum5djjx48xZ84cODs7o1q1agXSBm2KFi2Ks2fPonTp0rnaft++fTA3N5def6r7mRNz5syBg4MDunXrJqWlpKTA29sbsbGxWL58OWxtbbFq1Sq0aNECYWFhaNSoUZZlbty4EQMHDkSnTp0wc+ZMyGQyhISEoG/fvnj58iXGjRsn5W3bti0uXLgAf39/1KpVCw8fPsTcuXPh7u6Oq1evwsnJCQDQr18/LF68GEuWLJE+30REREREX6tcBd29e/dGYGAg7t2791UG3ZUqVUKtWrX+83oTExNhbGz8n9dbEBQKBerWrZvr7atXr56HrSl4r169wo8//ojvv/9e7faNoKAgXLt2Db///jvc3d0BAI0bN0bVqlUxefJk/PHHH1mWu3HjRjg5OWH37t3Q0xMHvjRv3hyXLl1CcHCwFHTfvn0bp06dwsyZMzFp0iRpexcXF9SrVw979+6V8urr6+Obb75BQEAApkyZ8tV8ZomIiIiItNF5ePmpU6ekh6enJ+zs7NChQwesXLkS4eHhau+fOnUqP9v8ydu5cydkMhlWrlyplj579mwUKlQIx48fR3R0NIoUKQJA7MFUDlFXDon29/eHTCbDxYsX0blzZ1hZWUm9vhcuXED37t3h7OwMIyMjODs7o0ePHrh//75GWx49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SBOoAUDx4sURGRmJPXv25GkjiYiIiIiIiD5HuRpeHhAQgISEBBgYGODdu3dSeo8ePbBixQpERkbmWQOJ6Oty+5udWd4TQ0RERET0OclVT3d4eDhkMhmOHDmill65cmUAwIMHDz6+ZURERERERESfuVwF3cplnzIuCSSTyQAAr1+//shmEREREREREX3+chV0K4d+Pn36VC1duYSYlZXVRzaLiIiIiIiI6POXq6C7Zs2aAIChQ4dKaUuWLEHfvn0hk8ng5uaWN60jIiL6v/buOyyK630b+L3u0kEElC5gx44o9gIidjRi76DYjb1EVCwo2GKJvSBg76LEFnsFxdhj7PVrI4IKIiJl3j94d36MuxSNGwTvz3XtdbFnnjnzzLCb+HDOnCEiIiLKx76q6B48eDAEQcDBgwfFKeUTJkwQp5UPHjz422VIRERERERElE99VdHdtm1bjBs3TnxcWObHhv3yyy9o0aLFN02SiIiIiIiIKD+SCcpq+StcvHgRe/bswatXr2BhYYGffvpJnHpORPQl4uPjYWxsjNUoBX3I8ySHbsLtPDkuEREREeU/yn+/vnv3LttH3ub6Od2Zn8etVKVKFVSpUkVtnLa2dm67JiIiIiIiIiqQcl106+np5bpTmUyG1NTUr0qIiIiIiIiIqKDIddH9L2ahExEREREREf2QvmghNZlMJq5WTkRERERERETZ+6KiWznaXbJkScybNw9v3rxBenq6yistLU0jyRIRERERERHlJ7kuus+fP49u3bpBS0sLDx48wNixY1G8eHEMGjQIf/31lyZzJCIiIiIiIsqXcl10u7i4YMOGDXjy5AmmTp0KS0tLvH//HqtWrUKVKlXg7u6Oo0ePajJXIiIiIiIionzli6aXA4C5uTn8/f3x+PFjbNy4EaamphAEASdOnMDSpUs1kSP9R0JDQ8X79mUyGRQKBWxtbeHj44Nnz559s+M4ODjA29s71/k8evTomx3b29sbDg4OOcYJgoDVq1ejevXqKFy4MMzMzNCoUSPs27fvm+XyNaZPn44KFSogPT1d0r5lyxY4OTlBV1cX1tbWGDFiBN6/f5/rfh8/fow+ffrA2toaOjo6sLGxQbt27SQxu3btQteuXVG6dGno6enBwcEB3bt3x927dyVxKSkpKFWqFBYuXPjV50lEREREVFB8cdENZDwEfMmSJfD390dc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tvDx8cGzZ8++2XEcHBzg7e2d63wePXr0zY7t7e0NBweHL9pHEAQ0bNgQMpkMQ4cO/Wa5fI3p06ejQoUKSE9Pl7Rv2bIFTk5O0NXVhbW1NUaMGIH379/nqs+XL19i6NChKFmyJPT09GBvb4++ffviyZMnkrhdu3aha9euKF26NPT09ODg4IDu3bvj7t27kriUlBSUKlUKCxcu/FfnSkRERERUELDoJhUhISGIjIzE4cOH0a9fP2zevBkNGjRAYmJiXqeWJ5YuXYp79+7ldRp4/vw55syZg+nTp6NQof/76m7cuBFdu3aFi4sLDhw4gClTpiA0NBReXl459pmcnIyGDRti69atGDNmDA4cOAA/Pz/s27cPdevWRUJCghg7e/ZsfPjwARMnTsTBgwcxY8YMXL58Gc7Ozvjrr7/EOC0tLfj7+2P69OmIjY39theBiIiIiCifUeR1AvT9qVSpEmrUqAEAcHNzQ1paGgICAhAeHo7u3bvncXb/rUePHmHChAlYt25dropYTVq0aBGKFCkiySMtLQ1jx45F06ZNsXr1agAZvzMjIyN0794dBw4cQIsWLbLs8/Tp07h79y7WrFmDvn37AgBcXV1RuHBhdOvWDUeOHEG7du0AABERETA3N5fs37hxYzg4OGDBggVYs2aN2N61a1eMGjUKK1euhJ+f3ze7BkRERERE+Q1HuilHtWvXBgA8fvwYADBt2jTUqlULpqamKFy4MJydnREcHAxBECT7paSkYNy4cbC0tIS+vj7q16+PCxcuqD1GVFQU6tWrJ06PnjBhAlJSUtTGbt26FXXq1IGBgQEMDQ3RrFkzXL58WSUuNDQU5cqVg46ODsqXL49169Z98bn3798fHh4eYuH5uRMnTkAmk2HDhg0YNWoULC0toaenh0aNGklyev36NYoXL466detKzuvmzZswMDBAz549s83j06dPCA4ORrdu3SSj3FFRUXjx4gV8fHwk8R07doShoSF2796dbb9aWloAAGNjY0l7kSJFAAC6urpi2+cFNwBYW1vD1tYWT58+lbRra2ujc+fOWLVqlcrngoiIiIjoR8Kim3KknFpdrFgxABmjvwMGDMC2bduwa9cueHl54eeff0ZAQIBkv379+mHevHno1asX9uzZg/bt28PLywtv3ryRxN28eRPu7u54+/YtQkNDsWLFCly+fBkzZsxQySUw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ZDKBD9Glf+HmzZuoWLEifv/991wV7597+PAhHB0dMWXKFPj5+X3z/K5du4aqVati6dKl4gh1TkJDQ+Hj44Po6GjUqFHjm+f0tX7++WccPXoUf/311xevSv5fCw4OxvDhw/H06dNcj3THx8fD2NgYkQ+nwNBIddE4IiKi/KyS2S95nQIRfWPKf7++e/cOhQsXzjKO93TTv3L8+HHUqVMnVwX31atX8csvv2Dv3r04ceIEVq5ciSZNmqBw4cIqz4X+t+7fv49jx46hf//+sLKyUjsKnt9MmjQJz549w86dO/M6lWylpqZi9uzZmDBhAqeWExEREdEPj0U3/StDhgzBuXPnchVrYGCAixcvom/fvvDw8MDEiRNRrVo1nDlzJsvHhn2tgIAAeHh44P3799i+fTv09fW/af95wcLCAhs3bvyuHgWnztOnT9GjRw+MHj06r1MhIiIiIspznF5ORN8FTi8nIqKCjNPLiQoeTi8nIiIiIiIiymMsuomIiIiIiIg0hEU3ERERERERkYbwOd1E9F2pYDoq23tiiIiIiIjyE450ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOgmIiIiIiIi0hA+MoyIviu+hwdBy0A7r9MgIiIiytLG5iF5nQLlIxzpJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3fbdCQ0Mhk8nEl66uLiwtLeHm5oagoCDExMT8q/6PHj2KGjVqwMDAADKZDOHh4d8m8c94e3vDwcFB0hYYGPjFx7t//z50dHQQGRkpaX/w4AG8vLxQpEgRGBoawsPDA5cuXcpVn4IgYPXq1ahevToKFy4MMzMzNGrUCPv27VOJzfy7yPyaNWuWJG7y5MlwdnZGenr6F50fEREREVFBxKKbvnshISGIjIzE4cOHsXTpUjg5OWH27NkoX748jhw58lV9CoKATp06QUtLC3v37kVkZCQaNWr0jTPP2tcU3WPGjIGHhwfq1Kkjtv3zzz9o0KAB7ty5g7Vr12Lbtm34+PEjXF1dcfv27Rz7nDJlCvr374+aNWti586dCA0NhY6ODlq3bo1du3apxHfo0AGRkZGSV69evVTyfPjwIcLCwr7o/IiIiIiICiJFXidAlJNKlSqhRo0a4vv27dtj5MiRqF+/Pry8vHD37l1YWFh8UZ/Pnz9HXFwc2rVrB3d392+d8jf3999/Izw8HAcPHpS0z507F//88w/OnTsHe3t7AED9+vVRqlQp+Pv7Y+vWrdn2u3btWtSvXx/Lly8X2zw8PGBpaYmwsDB4eXlJ4i0sLFC7du1s+zQ2NkaPHj0wa9YseHt7QyaTfcmpEhEREREVKBzppnzJzs4Ov/76KxISErBy5UrJtosXL6JNmzYwNTWFrq4uqlWrhm3btonbp06dCltbWwDA+PHjIZPJxOnf9+7dg4+PD8qUKQN9fX3Y2NjA09MT169flxxDOfX90aNHkvYTJ05AJpPhxIkTWeYuk8mQmJiIsLAwcYq2q6trtue7fPlyWFpawsPDQ9K+e/duNG7cWCy4AaBw4cLw8vJCREQEUlNTs+1XS0sLxsbGkjZdXV3x9bV69uyJO3fu4Pjx41/dBxERERFRQcCim/Ktli1bQi6X49SpU2Lb8ePHUa9ePbx9+xYrVqzAnj174OTkhM6dOyM0NBQA4OvrK06d/vnnnxEZGYndu3cDyBgBNzMzw6xZs3Dw4EEsXboUCoUCtWrVytV07dyIjIyEnp4eWrZsKU7RXrZsWbb77Nu3Dw0bNkShQv/3lU1KSsL9+/dRpUoVlfgqVaogKSkJDx48yLbf4cOH4+DBgwgODsabN2/w4sULjBo1Cu/evcOwYcNU4jdt2gQ9PT3o6OigevXqCAkJUdtv9erVYWhoqPbecCIiIiKiHwmnl1O+ZWBggKJFi+L58+di2+DBg1GxYkUcO3YMCkXGx7tZs2Z4/fo1/Pz80KtXL9ja2oojwHZ2dpLp0g0bNkTDhg3F92lpaWjVqhUqVqyIlStXYv78+f8679q1a6NQoUIoVqxYjlO1ASAmJgYPHjxA//79Je1v3ryBIAgwNTVV2UfZFhsbm23fI0aMgJ6eHoYMGQJfX19x34iICNSrV08S261bN7Rq1QrFixdHTEwMgoOD0adPHzx48AABAQGSWLlcjqpVq+Ls2bNZHjs5ORnJycni+/j4+GxzJSIiIiLKjzjSTfmaIAjiz/fu3cOtW7fQvXt3AEBqaqr4atmyJV68eJHjaHVqaioCAwNRoUIFaGtrQ6FQQFtbG3fv3sXff/+t0XPJivKPCubm5mq3Z3fPdE73U4eEhGD48OEYOnQojhw5gv3796Np06Zo27YtDh06JInduHEjunXrhgYNGqB9+/bYv38/WrdujVmzZuGff/5R6dvc3BzPnj3L8thBQUEwNjYWX8WLF882VyIiIiKi/IhFN+VbiYmJiI2NhbW1NQDg1atXADJWz9bS0pK8Bg8eDAB4/fp1tn2OGjUKkydPxk8//YSIiAicP38e0dHRqFq1KpKSkjR7QllQHvfze6xNTEwgk8nUjmbHxcUBgNpRcKU3b96II9zz5s2Du7s7WrRogc2bN8PFxQUDBw7MMbcePXogNTUVFy9eVNmmq6ub7TWbMGEC3r17J76ePn2a4/GIiIiIiPIbTi+nfGvfvn1IS0sTFyErWrQogIxi7vNVt5XKlSuXbZ8bNmxAr169EBgYKGl//fo1ihQpIr5XFsCZp0cr47415XkpC2klPT09lC5dWmWRNwC4fv069PT0ULJkySz7vX37NpKSkuDi4qKyrUaNGjh58iTev38PQ0PDLPtQzjTIfK+5UlxcnJi7Ojo6OtDR0clyOxERERFRQcCRbsqXnjx5gjFjxsDY2BgDBgwAkFFQlylTBlevXkWNGjXUvoyMjLLtVyaTqRSC+/btU5kmrVzt/Nq1a5L2vXv35ip/HR2dXI+c29vbQ09PD/fv31fZ1q5dOxw7dkwySpyQkIBdu3ahTZs24n3t6ihnCERFRUnaBUFAVFQUTExMYGBgkG1u69evh5aWFqpXr66y7cGDB6hQoUK2+xMRERERFXQc6abv3o0bN8R7s2NiYnD69GmEhIRALpdj9+7dKFasmBi7cuVKtGjRAs2aNYO3tzdsbGwQFxeHv//+G5cuXcL27duzPVbr1q0RGhoKR0dHVKlSBX/++Sfmzp0rPmJMycXFBeXKlcOYMWOQmpoKExMT7N69G2fOnMnVOVWuXBknTpxAREQErKysYGRklOUovLa2NurUqaNSHAMZU+nXr1+PVq1aYfr06dDR0cGsWbPw8eNHTJ06VRJbunRpABn3vgMZi8h5eXlh1apV0NHRQcuWLZGcnIywsDCcPXsWAQEB4j3hc+fOxc2bN+Hu7g5bW1txIbU//vgDU6dOVRnRjo2Nxd27d/Hzzz/n6noQERERERVULLrpu+fj4wMgo/gsUqQIypcvj/Hjx8PX11dScAOAm5sbLly4gJkzZ2LEiBF48+YNzMzMUKFCBXTq1CnHYy1atAhaWloICgrC+/fv4ezsjF27dmHSpEmSOLlcjoiICAwdOhQDBw6Ejo4OunTpgiVLlqBVq1a5Os6QIUPQpUsXfPjwAY0aNcr22d7du3dH//798eLFC1hZWYntxYoVw+nTpzFmzBj07t0bqampqFOnDk6cOAFHR0dJH+qe2b1x40YsWbIE69evx9q1a6GlpYWyZctiw4YN6Natmxjn6OiIvXv3Yt++fXjz5g309PTg5OSEzZs3o0uXLir97tmzB1paWrm65kREREREBZlMyLz8MxF9lz5+/Ag7OzuMHj0a48ePz+t0ctSgQQPY2dlh48aNud4nPj4exsbG6LijG7QMtDWYHREREdG/s7F5SF6nQN8B5b9f3717h8KFC2cZx3u6ifIBXV1dTJs2DfPnz0diYmJep5OtU6dOITo6WuXZ3UREREREPyJOLyfKJ/r374+3b9/iwYMHqFy5cl6nk6XY2FisW7cu25XTiYiIiIh+FCy6ifIJuVyOCRMm5HUaOWrXrl1ep0BERERE9N3g9HIiIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIT3dBPRd2WNx/JsH7lARERERJSfcKSbiIiIiIiISENYdBMRERERERFpCItuIiIiIiIiIg1h0U1ERERERESkISy6iYiIiIiIiDSERTcRERERERGRhvCRYUT0XWkf0Q8Kfe28ToOIiIjomzrQbn1ep0B5hCPdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWkIi24iIiIiIiIiDWHRTURERERERKQhLLqJiIiIiIiINIRFNxEREREREZGGsOimbyY0NBQymQwXL178qv1lMhmmTp0qvr958yamTp2KR48eqcR6e3vDwcHhq46T231dXV1RqVKlrzqGpqxbtw7FihVDQkKCpP3IkSOoU6cO9PX1UbRoUXh7eyMmJiZXfcbHx2PixIkoW7Ys9PX1YWNjg44dO+Kvv/5SG3/mzBm0bNkSJiYm0NPTQ5kyZRAQECCJadiwIUaMGPFV50hEREREVJCw6KbvRmRkJHx9fcX3N2/exLRp09QW3ZMnT8bu3bv/w+zy3ocPH+Dn54fx48fDyMhIbD958iRatGgBCwsL7NmzB4sWLcKRI0fg7u6O5OTkHPv19PTEwoUL0a9fP+zbtw+zZs3ClStXUKdOHTx+/FgSu2nTJjRq1AjGxsZYt24d9u/fj/Hjx0MQBElcQEAAli1bhtu3b3+bkyciIiIiyqcUeZ0AkVLt2rVzHVuqVCkNZvJ9CgsLQ2xsrOQPEwAwduxYlC1bFjt27IBCkfGVLlGiBOrVq4e1a9di0KBBWfZ57949nDp1CpMmTcLYsWPF9tKlS6Nu3brYtWsXRo4cCQB49uwZ+vfvjwEDBmDZsmVirJubm0q/jRo1Qrly5fDrr79i1apV/+q8iYiIiIjyM450k0Z5e3vD0NAQ9+7dQ8uWLWFoaIjixYtj9OjRKqOwmaeXh4aGomPHjgAyijqZTAaZTIbQ0FCx38+niC9duhQNGzaEubk5DAwMULlyZcyZMwcpKSn/6hxOnz6N2rVrQ09PDzY2Npg8eTLS0tIkMXFxcRg8eDBsbGygra2NkiVLYuLEieI5fvz4EdWqVUPp0qXx7t07cb+XL1/C0tISrq6uKn1+bvny5fD09ESRIkXEtmfPniE6Oho9e/YUC24AqFu3LsqWLZvjbAAtLS0AgLGxsaRdeQxdXV2xbc2aNUhMTMT48eOz7VOpZ8+e2LRpk8pUeCIiIiKiHwmLbtK4lJQUtGnTBu7u7tizZw/69OmDBQsWYPbs2Vnu06pVKwQGBgLIKKYjIyMRGRmJVq1aZbnP/fv30a1bN6xfvx6///47+vbti7lz52LAgAFfnfvLly/RpUsXdO/eHXv27EGHDh0wY8YMDB8+XIz5+PEj3NzcsG7dOowaNQr79u1Djx49MGfOHHh5eQHIKF63bduGmJgY9OnTBwCQnp6O7t27QxAEbN68GXK5PMs8/ve//+H69esqo8o3btwAAFSpUkVlnypVqojbs2Jvb4+2bdtiwYIFOH78ON6/f49bt25h2LBhsLOzQ5cuXcTYU6dOwdTUFLdu3YKTkxMUCgXMzc0xcOBAxMfHq/Tt6uqKxMREnDhxQu2xk5OTER8fL3kRERERERU0nF5OGvfp0ydMmzZNHLl2d3fHxYsXsWnTJvj7+6vdp1ixYihTpgwAoEKFCrmaej5//nzx5/T0dDRo0ABmZmbw8fHBr7/+ChMTky/OPTY2Fnv27EGbNm0AAE2bNkVSUhKWL1+OcePGwc7ODmFhYbh27Rq2bdsmnqOHhwcMDQ0xfvx4HD58GB4eHihTpgzWrFmDzp07Y9GiRYiLi8OJEydw8OBBWFlZZZvHuXPnAADOzs4q+QGAqampyj6mpqbi9uxs374dQ4YMQePGjcW2KlWq4OTJk5Jr9uzZM3z48AEdO3bEhAkTsHDhQkRHR2PKlCm4ceMGTp8+DZlMJsZXq1YNMpkMZ8+ehaenp8pxg4KCMG3atBzzIyIiIiLKzzjSTRonk8lUiq4qVaqoLNL1b12+fBlt2rSBmZkZ5HI5tLS00KtXL6SlpeHOnTtf1aeRkZFYcCt169YN6enpOHXqFADg2LFjMDAwQIcOHSRx3t7eAICjR4+KbZ06dcKgQYMwduxYzJgxA35+fvDw8Mgxj+fPnwMAzM3N1W7PXOzmpj2zQYMGYefOnViwYAFOnjyJrVu3QltbG40bN5b8jtLT0/Hx40f4+flhwoQJcHV1xdixYxEUFISzZ89KzhPImLpepEgRPHv2TO1xJ0yYgHfv3omvp0+f5pgrEREREVF+w6KbNE5fX19ybzAA6Ojo4OPHj9/sGE+ePEGDBg3w7NkzLFq0CKdPn0Z0dDSWLl0KAEhKSvqqfi0sLFTaLC0tAfzfKHNsbCwsLS1VClxzc3MoFAqV0eY+ffogJSUFCoUCw4YNy1Ueyvw/v45mZmaSXDKLi4tTOwKe2cGDBxEcHIyVK1dixIgRaNiwITp16oTDhw8jLi5O8gg35bGaNWsm6aNFixYAgEuXLqn0r6urm+W119HRQeHChSUvIiIiIqKChkU3FQjh4eFITEzErl270KNHD9SvXx81atSAtrb2v+r31atXKm0vX74E8H9FqJmZGV69eqXy2KyYmBikpqaiaNGiYltiYiJ69uyJsmXLQk9PT2Ul8qwo+4iLi5O0K58jfv36dZV9rl+/nuNzxq9cuQIAcHFxkbQXKVIEpUuXltwTru6+cQDieRcqpPqfkzdv3kjOn4iIiIjoR8Oim75bOjo6AHI3Sq0cZVbuA2QUg6tXr/5XOSQkJGDv3r2Stk2bNqFQoUJo2LAhgIx71N+/f4/w8HBJ3Lp168TtSgMHDsSTJ0+wa9cuBAcHY+/evViwYEGOeTg6OgLIWCwuMxsbG9SsWRMbNmyQrH4eFRWF27dviwu5ZcXa2lqMzyw2NhZ37tyBra2t2Na+fXsAwIEDBySx+/fvB6D6yLfnz5/j48ePqFChQo7nR0RERERUUHEhNfpuKUdpV61aBSMjI+jq6qJEiRLiCHNmHh4e0NbWRteuXTFu3Dh8/PgRy5cvx5s3b/5VDmZmZhg0aBCePHmCsmXLYv/+/Vi9ejUGDRoEOzs7AECvXr2wdOlS9O7dG48ePULlypVx5swZBAYGomXLlmjSpAmAjEdubdiwASEhIahYsSIqVqyIoUOHYvz48ahXrx5q1qyZZR61atWCnp4eoqKiVO4xnz17Njw8PNCxY0cMHjwYMTEx+OWXX1CpUiX4+PiIcY8fP0apUqXQu3dvBAcHAwC8vLzg7++PQYMG4X//+x+cnZ3x4sULzJ07Fx8+fJCs0t60aVN4enpi+vTpSE9PR+3atXHx4kVMmzYNrVu3Rv369SV5KQt5dc/xJiIiIiL6UXCkm75bJUqUwMKFC3H16lW4urrCxcUFERERamMdHR2xc+dOvHnzBl5eXvj555/h5OSE33777V/lYGlpiU2bNiEsLAxt2rTBtm3b4OfnJ+lXV1cXx48fR/fu3TF37ly0aNECoaGhGDNmDHbt2gUgY6r3sGHD0Lt3b3GBNQCYN28eqlSpgs6dO+Pt27dZ5qGtrY0OHTpgz549KttcXV2xf/9+vHjxAp6envj555/h5uaGo0ePqoz8p6WlSUbEDQ0NERUVhe7du2PFihVo2bIlxo4dCxsbG5w5cwaurq6SY23duhUjRozAqlWr0KJFCyxfvhwjR47Ejh07VPIKDw9H5cqVUbly5ZwuMxERERFRgSUTPr8RlYi+SxcvXoSLiwuioqJQq1atvE4nW/Hx8bC2tsaCBQvQr1+/XO9jbGyMJhs6QaH/7+7FJyIiIvreHGi3Pq9ToG9M+e/Xd+/eZbsoMEe6ifKJGjVqoFOnTggICMjrVHK0YMEC2NnZSaa3ExERERH9iFh0E+Ujv/76K1xcXJCQkJDXqWSrcOHCCA0NhULBZSOIiIiI6MfG6eVE9F3g9HIiIiIqyDi9vODh9HIiIiIiIiKiPMaim4iIiIiIiEhDWHQTERERERERaQhXOSKi78pOz9XZ3hNDRERERJSfcKSbiIiIiIiISENYdBMRERERERFpCItuIiIiIiIiIg1h0U1ERERERESkISy6iYiIiIiIiDSERTcRERERERGRhrDoJiIiIiIiItIQFt1EREREREREGsKim4iIiIiIiEhDWHQTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBqiyOsEiIgAQBAEAEB8fHweZ0JERERElDPlv1uV/47NCotuIvouJCQkAACKFy+ex5kQEREREeVeQkICjI2Ns9wuE3Iqy4mI/gPp6el4/vw5jIyMIJPJ8jodIsqCi4sLoqOj8zoNogKP3zX60eWH74AgCEhISIC1tTUKFcr6zm2OdBPRd6FQoUKwtbXN6zSIKAdyuRyFCxfO6zSICjx+1+hHl1++A9mNcCtxITUiIiLKtSFDhuR1CkQ/BH7X6EdXkL4DnF5OREREREREpCEc6SYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWkIi24iIiL6brRr1w4mJibo0KFDXqdCVKDxu0Y/uv/yO8Cim4iIiL4bw4YNw7p16/I6DaICj981+tH9l98BFt1ERET03XBzc4ORkVFep0FU4PG7Rj+6//I7wKKbiIgon3NwcIBMJlN5DRky5Jsd49SpU/D09IS1tTVkMhnCw8PVxi1btgwlSpSArq4uqlevjtOnT3+zHIjyWmpqKiZNmoQSJUpAT08PJUuWxPTp05Genv7NjsHvGn3PEhISMGLECNjb20NPTw9169ZFdHT0Nz1GQfwOsOgmIiLK56Kjo/HixQvxdfjwYQBAx44d1cafPXsWKSkpKu23bt3Cy5cv1e6TmJiIqlWrYsmSJVnmsXXrVowYMQITJ07E5cuX0aBBA7Ro0QJPnjwRY6pXr45KlSqpvJ4/f/4lp0yUJ2bPno0VK1ZgyZIl+PvvvzFnzhzMnTsXixcvVhvP7xoVNL6+vjh8+DDWr1+P69evo2nTpmjSpAmePXumNp7fgf9PICIiogJl+PDhQqlSpYT09HSVbWlpaULVqlWFDh06CKmpqWL77du3BUtLS2H27Nk59g9A2L17t0p7zZo1hYEDB0raHB0dhV9++eWL8j9+/LjQvn37L9qH6L/QqlUroU+fPpI2Ly8voUePHiqx/K5RQfPhwwdBLpcLv//+u6S9atWqwsSJE1Xi+R34PxzpJiIiKkA+ffqEDRs2oE+fPpDJZCrbCxUqhP379+Py5cvo1asX0tPTcf/+fTRu3Bht2rTBuHHjvvq4f/75J5o2bSppb9q0Kc6dO/dVfRJ9b+rXr4+jR4/izp07AICrV6/izJkzaNmypUosv2tU0KSmpiItLQ26urqSdj09PZw5c0Ylnt+B/6PI6wSIiIjo2wkPD8fbt2/h7e2dZYy1tTWOHTuGhg0bolu3boiMjIS7uztWrFjx1cd9/fo10tLSYGFhIWm3sLDIcgqhOs2aNcOlS5eQmJgIW1tb7N69Gy4uLl+dF9G3NH78eLx79w6Ojo6Qy+VIS0vDzJkz0bVrV7Xx/K5RQWJkZIQ6deogICAA5cuXh4WFBTZv3ozz58+jTJkyavfhdyADi24iIqICJDg4GC1atIC1tXW2cXZ2dli3bh0aNWqEkiVLIjg4WO3I+Jf6vA9BEL6o30OHDv3rHIg0ZevWrdiwYQM2bdqEihUr4sqVKxgxYgSsra3Ru3dvtfvwu0YFyfr169GnTx/Y2NhALpfD2dkZ3bp1w6VLl7Lch98BLqRGRERUYDx+/BhHjhyBr69vjrGvXr1C//794enpiQ8fPmDkyJH/6thFixaFXC5XGWWIiYlRGY0gyq/Gjh2LX375BV26dEHlypXRs2dPjBw5EkFBQVnuw+8aFSSlSpXCyZMn8f79ezx9+hQXLlxASkoKSpQokeU+/A6w6CYiIiowQkJCYG5ujlatWmUb9/r1a7i7u6N8+fLYtWsXjh07hm3btmHMmDFffWxtbW1Ur15dXDld6fDhw6hbt+5X90v0Pfnw4QMKFZL+81kul2f5yDB+16igMjAwgJWVFd68eYNDhw6hbdu2auP4HcjA6eVEREQFQHp6OkJCQtC7d28oFFn/7z09PR3NmzeHvb09tm7dCoVCgfLly+PIkSNwc3ODjY2N2lGI9+/f4969e+L7hw8f4sqVKzA1NYWdnR0AYNSoUejZsydq1KiBOnXqYNWqVXjy5AkGDhz47U+YKA94enpi5syZsLOzQ8WKFXH58mXMnz8fffr0UYnld40KokOHDkEQBJQrVw737t3D2LFjUa5cOfj4+KjE8juQicbXRyciIiKNO3TokABAuH37do6xf/zxh5CUlKTSfvnyZeHJkydq9zl+/LgAQOXVu3dvSdzSpUsFe3t7QVtbW3B2dhZOnjz5VedD9D2Kj48Xhg8fLtjZ2Qm6urpCyZIlhYkTJwrJyclq4/ldo4Jm69atQsmSJQVtbW3B0tJSGDJkiPD27dss4/kdyCATBEH470t9IiIiIiIiooKP93QTERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWkIi24iIqICqm/fvpDJZOJr2rRpeZ1SvsVrqXl3796Fjo4OZDIZdu7cKba7urqK1/3Ro0d5l2AeU14DBweHr9pfEARUrlwZMpkMffr0+bbJEVG2WHQTEREVQB8+fMD27dslbWFhYRAEIY8yyr94Lf8bo0aNwqdPn1C5cmV4eXnldToFjkwmg7+/PwAgNDQU0dHReZwR0Y+DRTcREVEBtHPnTiQkJADI+Mc2ADx8+BCnTp3Ky7QAZBSx+cn3fC1z63u/5levXsXvv/8OABg0aJB4nenb8vLygoWFBQRBQFBQUF6nQ/TDYNFNRERUAIWGhoo/Dxw4UG373r17xSmr/fv3l+x/9uxZcVuHDh3E9piYGIwePRqOjo7Q09ODgYEBXFxcsHLlSsnI76NHj8T9XV1d8fvvv6NGjRrQ1dXF4MGDAQCrVq2Cu7s7bG1tYWBgAG1tbdja2qJLly64du2ayjnt3bsXTk5O0NXVRYkSJTBr1iysXbtWPM7UqVMl8VevXkX37t1ha2sLbW1tmJqaonnz5jh69Og3v5aZ/f333+jbty9KlCgBHR0dGBsbw8nJCcuWLZPEnT9/Hl26dJHkV6tWLezYsUPtNczMwcFB3KZ04sQJsc3b2xshISGoVKkStLW1MWfOHADAzJkz0aBBA1hbW0NPTw+6urooWbIk+vbtq3bqdnbnkp6ejjJlykAmk0FfXx9xcXGSfatUqQKZTAYdHR38888/2V5j5bVRKBTo0qVLtrFKgiBgzZo1qFevHoyNjaGtrQ17e3v06dMH9+7dU4n/0s+POr///jsaNWoEExMTKBQKmJmZwcnJCX379sWbN28ksVu2bIGHhweKFi0KbW1tWFpaolmzZrhx4wYA4OPHj/Dx8YGTkxOKFSsGbW1tGBgYoEqVKvD390diYmKursP79+8xbdo0VKlSBQYGBtDT00PlypUxa9YsfPr0SRIrl8vRuXNn8Xo8e/YsV8cgon9JICIiogLl8ePHQqFChQQAgrW1tRAfHy/o6ekJAARDQ0Ph/fv3giAIQmpqqmBjYyMAEIoUKSJ8/PhR7GPAgAECAAGAcOjQIUEQBOH+/fuClZWV2P75q0uXLuL+Dx8+FNtNTEzEfAAIvXv3FgRBENq2bZtlX4aGhsKdO3fE/nbt2iXIZDKVuOLFi4s/T5kyRYzfs2ePoKWlpbZvmUwmLF++/JteS6V9+/YJOjo6ao/btm1bMW7VqlWSa5L5NXz4cJVr2KhRI8lx7O3txW1Kx48fF9uKFi0q6VN5bapWrZrlNbeyshJiY2O/6FyWLVsmts2ePVvc99q1a2o/F1mxtbUVAAjOzs4q2xo1aiT29fDhQ0EQBCE9PV3o2LFjtp+fqKgosY8v/fyoc/HiRUGhUGR5zLt374qxPXv2zDJu9+7dgiAIwps3b7KMASA0bdpUcnxlu729vdgWGxsrVKhQIcs+GjZsKCQnJ0v62bVrl7h9zZo1Of5uiOjf40g3ERFRARMWFob09HQAQMeOHWFkZISWLVsCyBgVU46kyuVycUGlt2/fIiIiAgDw6dMnbNu2DQBQokQJeHh4AACGDx+OFy9eQKFQYPv27fjw4QNevXqFjh07AsgY2du3b59KPm/evEHHjh3x9OlTxMfHw8/PDwAwePBgXLx4Ea9fv0ZKSgpiY2MxadIkMc8VK1YAyBjRHDlypDiS7ufnh7dv3+L06dNqRwOTkpLg6+uLlJQUODg4IDo6GsnJybh9+zbKlSsHQRAwatQovH79+ptdS+D/Ri6Tk5MBAH369MGjR4+QkJCAM2fOiPs9f/4cw4YNE/v18/PDixcv8PbtW/zxxx+oU6dOjnnl5PXr1xgxYgRevXqF2NhY9O7dGwAwdepUXLt2DXFxcUhJScGrV6/g4+MDAHjx4gU2btz4Refi7e2NYsWKAQCWL18untOGDRvEXDLPDlDnf//7H/73v/8BAKpWrZqr89uxY4d4n729vT3+/PNPvH37FuPHjweQ8bvp27cvgC///GTl5MmTSE1NBQBs3boVnz59QkxMDM6dOwd/f38YGhoCAHbt2oX169cDAAwMDLBhwwa8ffsWL168QFhYGGxsbAAAenp62LhxI+7fv4+EhAR8+vQJ9+7dg5OTEwDgjz/+wPXr17PNacqUKbh58yYAYMmSJYiPj8fbt28xbNgwAMCpU6ewevVqyT7Ozs7iz1FRUbk+fyL6F/K05CciIqJvrnTp0uJI1rlz5wRBEIRt27aJba6urmJs5pFcT09PQRAEYceOHWLszJkzBUEQhKSkpGxH+ZSvoUOHCoIgHaUtXLiwyoiwIAjC1atXhS5dugjFixcXtLW1Vfpq3ry5IAiCcOvWLckIbmpqqtjH+PHjVUYqDx8+nGOeAIQdO3Z802t55MgRsb1UqVKSPDNbs2aN2v0/929GukuXLi2kpaWp9Hnq1CnB09NTsLKyUjsTYODAgV90LoIgCFOnThVj9+zZI6Snp4sjyOXLl89yP6ULFy6I+48bN05lu7qR7u7du4ttixYtEmNTUlIEMzMzcdu9e/e++POTlfDwcMkIckBAgLBt2zbJjAxBEIQePXqIcVOnTs22z+DgYKF+/foqs0GUry1btoixyrbMI93KmSrZvVq3bi05ZmJioritVatW2eZHRN+GItfVOREREX33Tp8+Ld7PamJiAl1dXVy5cgU2NjZQKBRITU3FyZMn8ejRIzg4OMDOzg7NmjXDgQMHcPDgQbx+/VocpVMoFOJIeGxsrDjKlx11o8flypWDgYGBpO3x48eoW7dutiONSUlJKn3a2tpCLpeL79U9PunVq1c55plVrpl96bV8+fKluG+FChUkeWaWOa5y5cq5ylX4bKX0nH4X1apVQ6FC0gmN58+fh5ubG9LS0rLcT3nNc3suADBkyBDMnj0bSUlJWLJkCQoXLoynT58CAAYMGJBtnl8r8+/Y3t5e/FmhUMDW1haxsbFiXOZrl5vPT1batm2L0aNHY/ny5Th16pRkIT1nZ2dERETA2to617/fX3/9FWPGjMn2mMrfR1Zy81n//HPOReqI/nucXk5ERFSAZF7c682bN3B2dka1atVQr149sVATBAFhYWFiXL9+/QAAKSkpWLp0Kfbv3w8AaNOmDSwtLQEAZmZmUCgy/lZvZGSE5ORkCIKg8tq0aZNKTvr6+ipt4eHhYsHduHFjPHv2DIIgYO/evSqxyunLQMbUbOUUZiBjFfHPWVhYiD83a9ZMbZ7p6ek5FoRfei2V1wrIWIAsc56ZZY5TLqqljq6urvhz5tXH379/Lyns1FF3zbds2SIW3N27d8fr168hCAJ+++23bHPM7lwAoGjRovD29gYAHDlyRHyGuZ6enjitPTtWVlbizzktuKaU+Xf8+PFj8ee0tDRxqroy7ks/P9mZN28e4uLiEB0djW3btmHIkCEAgEuXLmH69OkAcv/7zTwFf9GiRfjw4QMEQfiix6Upr4NMJsPz58/VftbPnTsn2ScmJkb8OXOuRKQ5LLqJiIgKCHXPk85K5udMe3p6ioXPjBkzkJKSAgCSFc11dXXRvHlzAEBCQoJ4j29KSgqePn2KsLAw1KtXL9eP0VIW8ADEVZvv37+PGTNmqMSWKVNGHJGMiYnBzJkzxXuL16xZoxJfr149sdD6448/MG/ePMTGxiI5ORm3bt3C7NmzUbp06Wzz+5prWa9ePZibmwMA7t27hwEDBuDJkydITEzE+fPnsWrVKgBAixYtxIL6+PHj8Pf3x6tXrxAfH4/jx49j69atADIKKmXcX3/9hYcPHyItLQ0TJ07MdrQ6K5mvua6uLvT09HD16lUsWrRIJTa356I0atQoFCpUCIIg4MSJEwCALl26oEiRIjnmZWtrK97nfOXKlVydS5s2bcSfFyxYgCtXriA+Ph6TJ08WR7krVKiAUqVKffHnJysnT55EYGAg/vrrLzg4OOCnn37CTz/9JG5/8uQJAEiK5rlz52LLli2Ij49HTEwMNm3aJD4fO/Pvw9DQEDKZDHv27FG7LkJW2rVrByDjjz+9e/fG33//jZSUFLx8+RI7duxA8+bNxZkrSpcuXRJ/rl27dq6PRUT/wn81j52IiIg0a926deK9mtWqVVPZnnm1cgDCiRMnxG1+fn6S+0AdHBxU7gl+8OBBjveQHj9+XBCE7O9HVvalr6+vsn/ZsmXV7pfV6tOZ88l8/+zevXvV3iee+aWJa/ktVy8XBEHo16+f2C6XywV9fX1BoVBIzk0p8z3dyhXiMzt37pzaY2a+5pn3y+25KLVv314Sc/78+WyvcWbK85TL5UJcXJxkW1arl3t5eWX5u9XX1xfOnj0r9vGlnx911q9fn+3nafHixWJsr169soxTrl4+a9YslW2FChUSSpUqJb4PCQkR+1S2fb56ecWKFbPNK3MfgiAIw4YNE4/15MmTXP+OiOjrcaSbiIiogMg8ZVx5L3ZmcrlcMt038/Tpfv36Se719PX1VbknuESJErhy5QrGjRuHChUqiKOlJUuWhKenJ5YvXy5ZGTk7JUqUwP79+1G7dm3o6+vDysoKY8aMUTvVGcgY0du9ezeqVq0KbW1t2NnZISAgAEOHDhVjihYtKv7s6emJP//8E7169YKdnR20tLRgbGyM8uXLo1evXuJocla+9lq2bNkSly9fho+PDxwcHKCtrQ0jIyNUrVoVTZs2FeP79euHc+fOoXPnzrCxsYGWlhaKFCmCmjVron79+mLc/PnzMWDAAFhZWUFbWxsuLi44duyYZEp2btWpUwfbt29HlSpVoKurC3t7ewQGBuKXX35RG5/bc1HKfH9ytWrVULNmzVznpnx2e1paWo6/GyBjOvX27duxYsUK1K5dG0ZGRlAoFChevDh69+6Ny5cvo27dumL8l35+1KlevTp8fX1RuXJlmJqaQi6Xw8jICLVr18aqVaskfYWFhWHTpk1wd3eHqakpFAoFzM3N4eHhIc6yGDNmDKZPnw4HBwfo6OigatWq2L17t+T3nxNTU1OcP38eAQEBqFatGgwMDKCjowN7e3t4eHjg119/RYsWLcT4tLQ08ckEbdq0QfHixXN9LCL6ejJB+GxlDiIiIqLvTEJCAi5cuICGDRtCS0sLAHDz5k20atUKjx49QqFChXDz5k2UK1cujzP9ce3evVucWr127VrxUWS51bp1a+zbtw9Vq1bF5cuXv+mCX/z8ZNi+fTs6deoEmUyG8+fPw8XFJa9TIvohsOgmIiKi796jR49QokQJaGlpwdzcHB8/fhTv3QWAadOmwd/fPw8z/HFNmDAB27Ztw8OHDyEIAhwdHXH9+nXJPcu5cffuXVSqVAmfPn3Cjh070L59+2+WIz8/Gfd9V61aFdevX4ePjw/Wrl2b1ykR/TD4yDAiIiL67hUpUgQ9evRAZGQkXr58iU+fPsHa2hq1atXCwIED1U53pv/Gixcv8ODBAxgZGaF+/fpYunTpFxfcQMaCecnJyRrIkJ8fIGNK/rVr1/I6DaIfEke6iYiIiIiIiDSEC6kRERERERERaQiLbiIiIiIiIiINYdFNREREREREpCEsuomIiIiIiIg0hEU3ERERERERkYaw6CYiIiIiIiLSEBbdRERERERERBrCopuIiIiIiIhIQ1h0ExEREREREWnI/wMd2zX/ZNR0/QAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_action_experiment.perform_methods(plot_acc=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Everything Everywhere All at Once\n" - ] - }, - { - "cell_type": "code", - "execution_count": 117, - "metadata": {}, - "outputs": [], - "source": [ - "CONTEXT.reset()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ExperimentsVisor" - ] - }, - { - "cell_type": "code", - "execution_count": 121, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class ExperimentsVisor(ContextVisor):\n", - " ctx: OCRExperimentContext\n", - "\n", - " def update_output(self, \n", - " model: OCRModel | None = None,\n", - " image_idx: ImgIdT | None = None,\n", - " display_option: DisplayOptions | None = None, \n", - " **kwargs):\n", - " model_selector, image_selector, content_selector, result_visor = self._comps()\n", - " if model is not None:\n", - " exp_ctx = result_visor.ctx\n", - " exp_ctx.ocr_model = list(model_selector.models.keys())[model.value]\n", - " result_visor.ctx = exp_ctx\n", - " if image_idx is not None:\n", - " img_ctx = ImageContext(self.ctx, image_idx)\n", - " result_visor.ctx.ctx = img_ctx\n", - " display_option = content_selector.values['display_option']\n", - " if display_option is not None and display_option != DisplayOptions.RESULTS:\n", - " result_visor.hide()\n", - " if display_option == DisplayOptions.BEST_RESULTS:\n", - " result_visor.best_results()\n", - " elif display_option == DisplayOptions.DATAFRAME:\n", - " result_visor.pd_to_html()\n", - " else:\n", - " content_selector.display_content(image_selector.image_ctx, display_option)\n", - " else:\n", - " result_visor.show()\n", - " result_visor.update_output(**kwargs)\n", - "\n", - " def _comps(self):\n", - " cc = self.comps\n", - " msel: ModelSelector = cc['model_selector'] # type: ignore\n", - " isel: ImageSelector = cc['image_selector'] # type: ignore\n", - " cs: ContentSelector = cc['content_selector'] # type: ignore\n", - " rv: ResultVisor = cc['result_visor'] # type: ignore\n", - " return msel, isel, cs, rv\n", - "\n", - " def setup_ui(self):\n", - " ctls = self.controls.values()\n", - " msw, isw, csw, rvw = [_.w for _ in self._comps()]\n", - " return W.VBox([W.HBox([msw, isw, csw, *ctls]), rvw,])\n", - "\n", - " def __init__(self, \n", - " ctx: OCRExperimentContext,\n", - " image_idx: ImgIdT | str | Path = 0,\n", - " ocr_model: OCRModel = OCRModel.TESSERACT,\n", - " display_option: DisplayOptions = DisplayOptions.RESULTS,\n", - " all_boxes: bool = False,\n", - " box_idx: int = 0,\n", - " all_methods: bool = False,\n", - " method: CropMethod=CropMethod.INITIAL_BOX,\n", - " ocr_models: dict[str, OCRModel] = {'Tesseract': OCRModel.TESSERACT},\n", - " out: W.Output | None = None,\n", - " ):\n", - " if not isinstance(ctx, OCRExperimentContext):\n", - " raise ValueError(\"ctx must be an OCRExperimentContext\")\n", - " exp = ExperimentOCR.from_image(ctx, 'Tesseract', image_idx)\n", - " if not exp:\n", - " raise ValueError(f\"Image {image_idx} not found in experiment context\")\n", - " \n", - " out = out or self.out\n", - " model_selector = ModelSelector(ctx, ocr_model=ocr_model, \n", - " ocr_models=ocr_models, out=out)\n", - " image_selector = ImageSelector(ctx, image_idx=image_idx, out=out)\n", - " content_selector = ContentSelector(ctx, display_option=display_option, out=out)\n", - " result_visor = ResultVisor(exp, out=out,\n", - " all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method)\n", - "\n", - " super().__init__(ctx, {}, out=out, \n", - " ctxs={'model_selector': model_selector, 'image_selector': image_selector, 'content_selector': content_selector, \n", - " 'result_visor': result_visor}\n", - " )\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Visualize all" - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "c722001cdbcf444da9b56a366c6723e1", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "VBox(children=(HBox(children=(HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), optio…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8a95135fcb03495f94fb726416f3df54", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# tesseract_experiment = ExperimentsVisor(CONTEXT)\n", - "tesseract_experiment = ExperimentsVisor(CONTEXT, BASE_IMAGE_IDX)\n", - "\n", - "test_eq(tesseract_experiment.all_values, {\n", - " 'image_selector': {'image_idx': 20},\n", - " 'content_selector': {'display_option': DisplayOptions.RESULTS},\n", - " 'result_visor': {\n", - " 'all_boxes': False,\n", - " 'box_idx': 0,\n", - " 'all_methods': False,\n", - " 'method': CropMethod.INITIAL_BOX,\n", - " },\n", - " 'model_selector': {'model': OCRModel.TESSERACT},\n", - " 'self': {}\n", - "})\n", - "\n", - "tesseract_experiment\n" - ] - }, - { - "cell_type": "code", - "execution_count": 121, - "metadata": {}, - "outputs": [], - "source": [ - "tesseract_experiment.update(display_option=DisplayOptions.BOXES)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Colophon\n", - "----\n" - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "metadata": {}, - "outputs": [], - "source": [ - "import fastcore.all as FC\n", - "from nbdev.export import nb_export\n" - ] - }, - { - "cell_type": "code", - "execution_count": 124, - "metadata": {}, - "outputs": [], - "source": [ - "if FC.IN_NOTEBOOK:\n", - " nb_export('experiments.ipynb', '.')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/_testbed/experiments.py b/_testbed/experiments.py deleted file mode 100644 index 27d56ba6..00000000 --- a/_testbed/experiments.py +++ /dev/null @@ -1,1995 +0,0 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: experiments.ipynb. - -# %% experiments.ipynb 7 -from __future__ import annotations - -import dataclasses -import difflib -import functools -import json -import shutil -from collections import defaultdict -from enum import Enum -from pathlib import Path -from typing import Any -from typing import Callable -from typing import cast -from typing import Mapping -from typing import Self -from typing import TypeAlias - -import fastcore.all as FC -import ipywidgets as W -import matplotlib.pyplot as plt -import numpy as np -import pandas as pd -import pcleaner.config as cfg -import pcleaner.ctd_interface as ctm -import pcleaner.image_ops as ops -import pcleaner.ocr.ocr as ocr -import pcleaner.structures as st -import torch -from IPython.display import clear_output -from IPython.display import display -from IPython.display import HTML -from ipywidgets.widgets.interaction import show_inline_matplotlib_plots -from loguru import logger -from pcleaner.ocr.ocr_tesseract import TesseractOcr -from PIL import Image -from PIL import ImageFilter -from rich.console import Console -from tqdm.notebook import tqdm - - -# %% auto 0 -__all__ = ['CM', 'SubjIdT', 'ImgIdT', 'BoxIdT', 'ImgSpecT', 'remove_multiple_whitespaces', 'postprocess_ocr', - 'accuracy_ocr_naive', 'accuracy_ocr_difflib', 'ground_truth_path', 'read_ground_truth', - 'dilate_by_fractional_pixel', 'extract_text', 'lang2pcleaner', 'lang2tesseract', 'ResultOCR', - 'ResultOCRExtracted', 'CropMethod', 'crop_by_image', 'crop_by_extracted', 'ResultSet', 'ResultSetDefault', - 'results_to_dict', 'dict_to_results', 'ExperimentSubject', 'ExperimentContext', 'ImageContext', - 'OCRExperimentContext', 'ContextVisor', 'ImageSelector', 'OCRContextVisor', 'OCRModel', 'ModelSelector', - 'DisplayOptions', 'ContentSelector', 'ImageContextVisor', 'Experiment', 'ExperimentOCR', - 'ExperimentOCRMethod', 'ResultVisor', 'ExperimentVisor', 'ExperimentsVisor'] - -# %% experiments.ipynb 8 -from helpers import * -from ocr_metric import * - - -# %% experiments.ipynb 12 -console = Console(width=104, tab_size=4, force_jupyter=True) -cprint = console.print - - -# %% experiments.ipynb 20 -def remove_multiple_whitespaces(text): - return ' '.join(text.split()) - - -def postprocess_ocr(text): - "Basic postprocessing for English Tesseract OCR results." - return ' '.join(remove_multiple_whitespaces(text).splitlines()).capitalize() - -def accuracy_ocr_naive(text, ground_truth): - return sum(1 for a, b in zip(text, ground_truth) if a == b) / len(text) - - -def accuracy_ocr_difflib(text, ground_truth): - """ - Calculates the OCR accuracy based on the similarity between the OCR text and the ground truth text, - using difflib's SequenceMatcher to account for differences in a manner similar to git diffs. - - :param text: The OCR-generated text. - :param ground_truth: The ground truth text. - :return: A float representing the similarity ratio between the OCR text and the ground truth, - where 1.0 is identical. - """ - # Initialize the SequenceMatcher with the OCR text and the ground truth - matcher = difflib.SequenceMatcher(None, text, ground_truth) - - # Get the similarity ratio - similarity_ratio = matcher.ratio() - - return similarity_ratio - -# %% experiments.ipynb 22 -def ground_truth_path(page_data: st.PageData): - path = Path(page_data.original_path) - return path.with_stem(path.stem + '_gt').with_suffix('.txt') - - -def read_ground_truth(page_data: st.PageData): - gts_path = ground_truth_path(page_data) - if gts_path.exists(): - gts = gts_path.read_text(encoding="utf-8").splitlines() - else: - gts = ["" for _ in range(len(page_data.boxes))] - return gts - - -# %% experiments.ipynb 24 -def dilate_by_fractional_pixel(image, dilation_fraction, filter_base_size=3): - """ - Dilates an image by a specified fractional pixel amount. The function calculates - the necessary scaling factor and filter size based on the desired dilation fraction. - - :param image: A PIL Image object (1-bit mode). - :param dilation_fraction: The desired fractional pixel amount for dilation (e.g., 0.2). - :param filter_base_size: The base size of the dilation filter to apply on the scaled image. - This size is adjusted based on the scaling factor to achieve the - desired dilation effect. - :return: A PIL Image object after dilation, converted back to grayscale. - """ - # Calculate the scale factor based on the desired dilation fraction - scale_factor = int(1 / dilation_fraction) - - # Adjust the filter size based on the scale factor - # This ensures the dilation effect is proportional to the desired fraction - filter_size = max(1, filter_base_size * scale_factor // 5) - - # Convert the image to grayscale for more nuanced intermediate values - image_gray = image.convert("L") - - # Resize the image to a larger size using bicubic interpolation - larger_size = (int(image.width * scale_factor), int(image.height * scale_factor)) - image_resized = image_gray.resize(larger_size, Image.BICUBIC) - - # Apply the dilation filter to the resized image - dilated_image = image_resized.filter(ImageFilter.MaxFilter(filter_size)) - - # Resize the image back to its original size using bicubic interpolation - image_dilated_fractional_pixel = dilated_image.resize(image.size, Image.BICUBIC) - - return image_dilated_fractional_pixel - - -# %% experiments.ipynb 25 -def extract_text(image, text_mask, box): - cropped_image = crop_box(box, image) - cropped_mask = crop_box(box, text_mask) - extracted = ops.extract_text(cropped_image, cropped_mask) - return cropped_image, cropped_mask, extracted - - -# %% experiments.ipynb 27 -_lang2pcleaner = {'English': st.DetectedLang.ENG, 'Japanese': st.DetectedLang.JA, 'Spanish': st.DetectedLang.ENG, - 'French':st.DetectedLang.ENG} -# _lang2tesseract = {'English': 'eng', 'Japanese': 'jpn'} -_lang2tesseract = {'English': 'eng', 'Japanese': 'jpn_vert', 'Spanish': 'spa', 'French': 'fra'} - - -# %% experiments.ipynb 28 -def lang2pcleaner(lang: str): - return _lang2pcleaner[lang] - -def lang2tesseract(lang: str): - return _lang2tesseract[lang] - - -# %% experiments.ipynb 35 -@dataclasses.dataclass -class ResultOCR: - block_idx: int - image: Image.Image | None - ocr: str - page_data: st.PageData - gts: list[str] - description: str = dataclasses.field(default='', kw_only=True) - - def __post_init__(self): - if self.image is None: - cache_path = self.cache_path() - if cache_path.exists(): - self.image = Image.open(cache_path) - - @property - def acc(self): - self._acc = accuracy_ocr_difflib(self.ocr, self.gts[self.block_idx]) - return self._acc - @property - def suffix(self): return f"{self.block_idx}_{self.description}" - - def diff_tagged(self): - _, html2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr, False) - return f"{html2}" - - def cache_path(self, suffix: str | None = None): - suffix = self.suffix + (('_'+suffix) if suffix else '') - parent = Path(self.page_data.image_path).parent - img_name = Path(self.page_data.original_path).stem - box_image_path = parent / f"{img_name}_{suffix}.png" - return box_image_path - - def cache_image(self, image: Image.Image | None = None, suffix: str | None = None): - image = image or (self.image if not suffix else None) - box_image_path = self.cache_path(suffix) - if image and not box_image_path.exists(): - image.save(box_image_path) - return box_image_path - - - def as_html(self): - acc_html = f"
{self.acc:.2f}" - box_image_path = self.cache_image() - html1 = get_columns_html([[box_image_path], [self.ocr + acc_html]]) - html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr) - html2 = f"
{html_str1}
{html_str2}
" - return html1 + '\n
\n' + html2 - - def __repr__(self): - return f"{type(self).__name__}#block {self.block_idx:02}: {self.acc:.2f}||{self.ocr}" - - def display(self): display(HTML(self.as_html())) - - def _ipython_display_(self): self.display() - - def to_dict(self): - d = dataclasses.asdict(self) - d['image'] = d['page_data'] = d['gts'] = None - return d - - # @classmethod - # def from_dict(cls, d: dict, page_data: st.PageData, gts: list[str]): - # return cls(**(d | {'page_data':page_data, 'gts':gts})) - - -@dataclasses.dataclass -class ResultOCRExtracted(ResultOCR): - - def __repr__(self): return super().__repr__() - def as_html(self): - html_str1, html_str2 = get_text_diffs_html(self.gts[self.block_idx], self.ocr) - diff_html = f"
{html_str1}
{html_str2}
" - cropped_image_path = self.cache_image(None, "cropped") - cropped_mask_path = self.cache_image(None, "mask") - result_path = self.cache_image() - return '\n
\n'.join([ - get_image_grid_html([cropped_image_path, cropped_mask_path, result_path], 1, 3), - acc_as_html(self.acc), - diff_html - ]) - - -# %% experiments.ipynb 37 -class CropMethod(Enum): - INITIAL_BOX = 'Initial box' - DEFAULT = 'Default' - DEFAULT_GREY_PAD = 'Default, grey pad' - PADDED_4 = 'Padded 4px' - PADDED_8 = 'Padded 8px' - EXTRACTED_INIT_BOX = 'Extracted, init box' - PADDED_4_EXTRACTED = 'Padded 4, extracted' - PADDED_8_EXTRACTED = 'Padded 8, extracted' - PADDED_8_DILATION_1 = 'Padded 8, dilation 1' - PAD_8_FRACT_0_5 = 'Pad 8, fract. 0.5' - PAD_8_FRACT_0_2 = 'Pad 8, fract. 0.2' - - @classmethod - def __display_names__(cls): - return dict( - zip([_.value for _ in cls], - cls)) - - -CM = CropMethod - -_IMAGE_METHODS = [CM.INITIAL_BOX, CM.DEFAULT, CM.DEFAULT_GREY_PAD, - CM.PADDED_4, CM.PADDED_8] -_EXTRACTED_METHODS = [CM.EXTRACTED_INIT_BOX, CM.PADDED_4_EXTRACTED, - CM.PADDED_8_EXTRACTED, CM.PADDED_8_DILATION_1, - CM.PAD_8_FRACT_0_5, CM.PAD_8_FRACT_0_2] - - -def crop_by_image(method: CM, - box: st.Box, - base: Image.Image, - preproc: cfg.PreprocessorConfig, - ): - image = None - match method: - case CM.INITIAL_BOX : - image = crop_box(box, base) - case CM.DEFAULT: - padded2_4 = ( - box.pad(preproc.box_padding_initial, base.size).right_pad( - preproc.box_right_padding_initial, base.size)) - image = crop_box(padded2_4, base) - case CM.DEFAULT_GREY_PAD: - image = crop_box(box, base) - image = ops.pad_image(image, 8, fill_color=(128, 128, 128)) - case CM.PADDED_4: - padded4 = box.pad(4, base.size) - image = crop_box(padded4, base) - case CM.PADDED_8: - padded4 = box.pad(8, base.size) - image = crop_box(padded4, base) - case _: pass - return image - - -def crop_by_extracted(method: CM, - box: st.Box, - base: Image.Image, - mask: Image.Image, - cropped_image_path: Path, - cropped_mask_path: Path, - dilated: dict[float, Image.Image] - ): - cropped_image, cropped_mask, image = None, None, None - if method in _EXTRACTED_METHODS: - if not cropped_image_path.exists() or not cropped_mask_path.exists(): - match method: - case CM.EXTRACTED_INIT_BOX: - cropped_image, cropped_mask, image = extract_text(base, mask, box) - case CM.PADDED_4_EXTRACTED: - padded4 = box.pad(4, base.size) - cropped_image, cropped_mask, image = extract_text(base, mask, padded4) - case CM.PADDED_8_EXTRACTED: - padded8 = box.pad(8, base.size) - cropped_image, cropped_mask, image = extract_text(base, mask, padded8) - case CM.PADDED_8_DILATION_1: - padded8 = box.pad(8, base.size) - cropped_image, cropped_mask, image = extract_text( - base, dilated[1], padded8) - case CM.PAD_8_FRACT_0_5: - padded8 = box.pad(8, base.size) - cropped_image, cropped_mask, image = extract_text( - base, dilated[0.5], padded8) - case CM.PAD_8_FRACT_0_2: - padded8 = box.pad(8, base.size) - cropped_image, cropped_mask, image = extract_text( - base, dilated[0.2], padded8) - case _: pass - - return image, cropped_image, cropped_mask - - - -# %% experiments.ipynb 39 -SubjIdT: TypeAlias = int -ImgIdT = SubjIdT -BoxIdT: TypeAlias = int - -class ResultSet(dict[BoxIdT, dict[CropMethod, ResultOCR]]): ... - -class ResultSetDefault(defaultdict[BoxIdT, dict[CropMethod, ResultOCR]]): ... - -def results_to_dict(results: ResultSet) -> dict[BoxIdT, dict[str, str]]: - d = {} - for box, box_methods in results.items(): - for method, result in box_methods.items(): - if box not in d: - d[box] = {} - d[box][method.name] = result.ocr - return d - -def dict_to_results( - image_idx: ImgIdT, - results_dict: dict[BoxIdT, dict[str, str]], - result_factory: Callable - ) -> ResultSetDefault: - results = ResultSetDefault(dict[CropMethod, ResultOCR]) - for box_idx, box_methods in results_dict.items(): - box_idx = int(box_idx) - for method, ocr in box_methods.items(): - m = CM[method] - results[box_idx][m] = result_factory(image_idx, box_idx, m, ocr) - return results - - - -# %% experiments.ipynb 41 -# class ExperimentSubject(Protocol): -# @property -# def exp(self) -> 'ExperimentContext': ... -# @property -# def idx(self) -> SubjIdT: ... -# def setup(self, -# exp: 'ExperimentContext', -# idx: Any, -# *args, **kwargs -# ): ... - - -# class ExperimentContext(Protocol): -# def subject_factory(self) -> Callable[..., ExperimentSubject]: ... -# def normalize_idx(self, idx: Any) -> SubjIdT: ... -# def experiment_subject(self, idx: Any, /, -# create: bool = False, *args, **kwargs) -> ExperimentSubject | None: -# """Get or create an `ExperimentSubject` for the given identifier. -# Returns `None` if `idx` is out of domain range. -# """ -# ... - - -# %% experiments.ipynb 42 -class ExperimentSubject: - exp: ExperimentContext - idx: SubjIdT - - def setup(self, exp: ExperimentContext, idx: Any, *args, **kwargs): - self.exp = exp - self.idx = cast(SubjIdT, exp.normalize_idx(idx)) - return self - - def __new__(cls, - exp: ExperimentContext, - idx: Any, - *args, **kwargs): - self = exp.experiment_subject(idx) - if self is None: - self = super().__new__(cls) - self = exp.experiment_subject(idx, new_subject=self, *args, **kwargs) - if self is None: - raise ValueError(f"Can't create new subject with idx: {idx}: out of range") - return self - - -class ExperimentContext: - "Class to maintain shared state across all file-based experiments within the experiment domain." - - subject_cls: Callable[..., ExperimentSubject] - def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls - - def normalize_idx(self, idx: int | str | Path) -> SubjIdT | None: - nidx = None - if isinstance(idx, int) and idx < len(self._paths): - nidx = idx - elif isinstance(idx, str): - try: - nidx = [_.name for _ in self._paths].index(idx) - except Exception: - pass - elif isinstance(idx, Path): - idx = idx.resolve() - if idx in self._paths: - nidx = self._paths.index(idx) - return nidx - - def path_from_idx(self, idx: int | str | Path): - _idx = self.normalize_idx(idx) - if _idx is None: - raise ValueError(f"{_idx} not found in context.") - path = Path(self._paths[_idx]) - if not path.exists(): - raise ValueError(f"{path} not found in context.") - return path - - @property - def count(self): return len(self._paths) - @property - def cache_dir(self): return Path(".cache/") - @functools.lru_cache() - def _cache_dir(self, idx: SubjIdT): - # create one folder for each image to cache and save results - path = self.path_from_idx(idx) - cache_dir = self.cache_dir / path.stem - cache_dir.mkdir(parents=True, exist_ok=True) - return cache_dir - def subject_cache_dir(self, idx: int | str | Path): - return self._cache_dir(idx) - - def empty_cache(self, idx: SubjIdT | None = None): - cache_dir = self.cache_dir - if idx is None: - shutil.rmtree(cache_dir, ignore_errors=True) - cache_dir.mkdir(parents=True, exist_ok=True) - else: - path = Path(self._paths[idx]) - cache_dir = cache_dir / path.stem - for p in cache_dir.glob("*"): - p.unlink(missing_ok=True) - if not any(cache_dir.iterdir()): - cache_dir.rmdir() - - def empty_cache_warn(self, idx: SubjIdT | None=None, *, warn: bool=True, out: W.Output | None=None): - def on_confirm_clicked(b): - try: - self.empty_cache(idx) - print("Cache cleared successfully.") - except Exception as e: - print(f"Failed to clear cache: {e}") - finally: - for widget in confirmation_box.children: - widget.close() - - def on_cancel_clicked(b): - print("Cache clear cancelled.") - for widget in confirmation_box.children: - widget.close() - - if out is None: - out = W.Output() - with out: - if FC.IN_NOTEBOOK: - confirm_button = W.Button(description="Confirm") - cancel_button = W.Button(description="Cancel") - confirm_button.on_click(on_confirm_clicked) - cancel_button.on_click(on_cancel_clicked) - label = W.Label('Are you sure you want to clear the cache? This action cannot be undone.') - confirmation_box = W.VBox([label, W.HBox([confirm_button, cancel_button])]) - display(confirmation_box) - else: - on_confirm_clicked(None) - - def experiment_subject(self, idx: SubjIdT | str | Path, /, - new_subject: ExperimentSubject | None = None, *args, **kwargs) -> ExperimentSubject | None: - "Cached subject. If provided, `new_subject` replaces value at the index." - if (nidx := self.normalize_idx(idx)) is None: - return None - if new_subject is None: - subject = self._subjects.get(nidx) - else: - new_subject.setup(self, nidx, *args, **kwargs) - self._subjects[nidx] = subject = new_subject - return subject - - def reset(self): - self._subjects.clear() - self._cache_dir.cache_clear() - - def __init__(self, paths: list[Path], root: Path | None = None): - self._root = (root or Path('.')).resolve() - self._paths = [p.resolve().relative_to(self._root) for p in paths] - self._subjects: dict[SubjIdT, ExperimentSubject] = {} - - -# %% experiments.ipynb 48 -ImgSpecT: TypeAlias = ImgIdT | str | Path - -class ImageContext(ExperimentSubject): - """ - A utility class to maintain image state for a ExperimentContext. - This class encapsulates state necessary for conducting OCR experiments. - - Attributes: - json_data (dict): JSON data loaded from cached files. - page_data (st.PageData): PanelClaner page data. - base_image (Image.Image): The base image loaded from the page data. - mask (Image.Image): The mask image used for text detection. - gts (list[str]): Ground truth data for the text in the images. - ocr_model (str): Name or identifier of the OCR model used. - mocr (ocr.OCRModel): OCR model configured for the experiment. - mask_dilated1 (Image.Image): Image mask dilated by 1 pixel. - mask_dilated05 (Image.Image): Image mask dilated by 0.5 pixels. - mask_dilated02 (Image.Image): Image mask dilated by 0.2 pixels. - - Methods: - init(config: cfg.Config, img_path: Path, cache_dir: Path, ocr_model: str): - Initializes the experiment context. It also handles the generation of text boxes - if they are not already present. - - setup_ground_truth(): - Loads or initializes ground truth data for the experiment based on the page data. - - setup_crop_masks(): - Prepares various dilated versions of the mask image to be used in different cropping - strategies during the experiments. - """ - exp: ExperimentContext - idx: ImgIdT - base_image: Image.Image - mask: Image.Image - json_data: dict | None - page_data: st.PageData - # ocr_model: str - # mocr: ocr.OCRModel - # postprocess_ocr: Callable[..., str] - _page_lang: str - _gts: list[str] - _mask_dilated1: Image.Image | None - _mask_dilated05: Image.Image | None - _mask_dilated02: Image.Image | None - - - # # this methods will be set downstream, declared here to make the type checker happy - # def result(self: Self, - # box_idx: int, method: CropMethod, ocr: bool = True, reset: bool=False) -> ResultOCR: ... - # def summary_box(self: Self, box_idx: int): ... - - def to_dict(self): - return { - 'image_idx': self.idx, - 'page_lang': self.page_lang, - } - - @property - def image_idx(self): return self.idx - @property - def cache_dir(self): - return self.exp.subject_cache_dir(self.idx) - cache_dir_image = cache_dir - - @property - def image_info(self): - img = self.base_image - w, h = img.size - print_size_in = size(w, h, 'in', 300) - print_size_cm = size(w, h, 'cm', 300) - required_dpi = dpi(w, h, 'Modern Age') - return (w, h), print_size_in, print_size_cm, required_dpi - - @property - def original_image_path(self): return Path(self.page_data.original_path) - @property - def image_path(self): return Path(self.page_data.image_path) - @property - def image_name(self): return self.original_image_path.name - @property - def image_size(self): return self.base_image.size - @property - def image_dim(self):return size(*self.image_size) - @property - def image_dpi(self): return dpi(*self.image_size) - @property - def image_print(self): - return self.image_size, self.image_dim, self.image_dpi - @property - def image_name_rich(self): - siz, dim, res = self.image_print - return f"{self.image_name} - {siz[0]}x{siz[1]} px: {dim[0]:.2f}x{dim[1]:.2f}\" @ {res:.2f} dpi" - - def setup_page_lang(self, page_lang: str | None = None): - path = Path(self.page_data.original_path).with_suffix('.json') - metadata = json.load(open(path)) if path.exists() else {} - if 'lang' in metadata and (page_lang == metadata['lang'] or page_lang is None): - self._page_lang = metadata['lang'] - return - self._page_lang = metadata['lang'] = page_lang or 'English' - json.dump(metadata, open(path, 'w'), indent=2) - @property - def page_lang(self): - if self._page_lang == None: - self.setup_page_lang() - return self._page_lang - - @property - def boxes(self): return self.page_data.boxes - - def setup_ground_truth(self): - self._gts = read_ground_truth(self.page_data) - @property - def gts(self): - if self._gts is None: - self.setup_ground_truth() - return self._gts - - @functools.lru_cache(typed=True) - def dilated_mask(self, fraction: float): - return dilate_by_fractional_pixel(self.mask, fraction) - - def mask_dilated1(self): - if self._mask_dilated1 is None: - self._mask_dilated1 = self.mask.filter(ImageFilter.MaxFilter(3)) - return self._mask_dilated1 - - def mask_dilated05(self): - if self._mask_dilated05 is None: - self._mask_dilated05 = self.dilated_mask(0.5) - return self._mask_dilated05 - - def mask_dilated02(self): - if self._mask_dilated02 is None: - self._mask_dilated02 = self.dilated_mask(0.2) - return self._mask_dilated02 - - def dilated(self): - return {1: self.mask_dilated1(), - 0.5: self.mask_dilated05(), - 0.2: self.mask_dilated02(),} - - def __new__(cls, - exp: ExperimentContext, - idx: ImgSpecT, - *args, **kwargs) -> Self: - return super().__new__(cls, exp, idx, *args, **kwargs) # type: ignore - - -# %% experiments.ipynb 50 -class OCRExperimentContext(ExperimentContext): - """ - A utility class to maintain shared state across all experiments within OCR domain. - This class encapsulates state necessary for conducting PanelCleaner OCR experiments. - """ - - config: cfg.Config - image_paths: list[Path] - # OCR engine -> Image index -> Box index -> Crop method -> Result - _results: dict[str, dict[ImgIdT, ResultSet]] - - - engines = { - 'Tesseract': cfg.OCREngine.TESSERACT, - 'Idefics': None, - 'manga-ocr': cfg.OCREngine.MANGAOCR} - - # subject_cls: ImageContext - # def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls - - @classmethod - def get_config(cls, cache_dir: Path | None = None) -> cfg.Config: - config = cfg.load_config() - config.cache_dir = cache_dir or Path(".") - profile = config.current_profile - preprocessor_conf = profile.preprocessor - # Modify the profile to OCR all boxes. - # Make sure OCR is enabled. - preprocessor_conf.ocr_enabled = True - # Make sure the max size is infinite, so no boxes are skipped in the OCR process. - preprocessor_conf.ocr_max_size = 10**10 - # Make sure the sus box min size is infinite, so all boxes with "unknown" language are skipped. - preprocessor_conf.suspicious_box_min_size = 10**10 - # Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics. - preprocessor_conf.ocr_blacklist_pattern = ".*" - return config - - def to_dict(self): - return { - 'image_paths': list(map(str, self.image_paths)), - 'cache_dir': str(self.config.cache_dir) - } - def to_json(self): - return json.dumps(self.to_dict(), indent=2) - @classmethod - def from_json_data(cls, d: dict): - return cls(cls.get_config(Path(d['cache_dir'])), d['image_paths']) - @classmethod - def from_json_path(cls, path: Path): - return cls.from_json_data(json.loads(path.read_text())) - - - @functools.lru_cache() - def mocr(self, ocr_model: str, lang: str): - engine = self.engines[ocr_model] - ocr_processor = ocr.get_ocr_processor(True, engine) - proc = ocr_processor[lang2pcleaner(lang)] - if isinstance(proc, TesseractOcr): - proc.lang = lang2tesseract(lang) - return proc - - def ocr_box(self, result: ResultOCR, ocr_model: str, lang: str): - assert result.image is not None - text = self.mocr(ocr_model, lang)(result.image) - result.ocr = postprocess_ocr(text) - return result - - @property - def cache_dir(self): return self.config.get_cleaner_cache_dir() - image_cache_dir = ExperimentContext.subject_cache_dir - - @functools.lru_cache() - def _load_page_data(self, image_idx: int): - config = self.config - cache_dir = self.image_cache_dir(image_idx) - img_path = self.path_from_idx(image_idx) - image_name = img_path.stem - # read cached json - jsons = [_ for _ in cache_dir.glob("*#raw.json") if image_name in _.stem] - assert len(jsons) <= 1 - # generate text boxes if needed - if not jsons: - pfl = config.current_profile - gpu = torch.cuda.is_available() or torch.backends.mps.is_available() - model_path = config.get_model_path(gpu) - ctm.model2annotations(pfl.general, pfl.text_detector, model_path, [img_path], cache_dir) - # we don't need unique names for this tests, strip uuids - for p in cache_dir.glob(f"*{image_name}*"): - p.rename(strip_uuid(p)) - jsons = [_ for _ in cache_dir.glob("*#raw.json") if image_name in _.stem] - - # adapt paths to be relative to this notebook - this_path = self._root - json_file_path = jsons[0] - json_data = json.loads(json_file_path.read_text(encoding="utf-8")) - json_data["image_path"] = str(strip_uuid(json_data["image_path"]).relative_to(this_path)) - json_data["mask_path"] = str(strip_uuid(json_data["mask_path"]).relative_to(this_path)) - json.dump(json_data, open(json_file_path, "w"), indent=2) - else: - json_file_path = jsons[0] - json_data = json.loads(json_file_path.read_text(encoding="utf-8")) - - page_data = st.PageData( - json_data["image_path"], json_data["mask_path"], - json_data["original_path"], json_data["scale"], - [st.Box(*data["xyxy"]) for data in json_data["blk_list"]], - [], [], []) - # Merge boxes that have mutually overlapping centers. - page_data.resolve_total_overlaps() - return json_data, page_data - - def page_data(self, image_idx: int): - _, page_data = self._load_page_data(image_idx) - return page_data - def json_data(self, image_idx: int): - json_data, _ = self._load_page_data(image_idx) - return json_data - - def experiment_image(self, image_idx: ImgIdT | str | Path) -> ImageContext | None: - "Cached image context." - return cast(ImageContext, self.experiment_subject(image_idx)) - - def update_results(self, ocr_model: str, img_idx: ImgIdT, results: ResultSetDefault): - self._results[ocr_model][img_idx] = cast(ResultSet, results) - - - def _result_from(self, image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None): - img_ctx = ImageContext(self, image_idx) - extracted = method in _EXTRACTED_METHODS - result_cls = ResultOCRExtracted if extracted else ResultOCR - result = result_cls(int(box_idx), None, '', img_ctx.page_data, - img_ctx.gts, description=f"{method.value}") - if ocr is not None: - result.ocr = ocr - return result - - def result(self, - ocr_model: str, - image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, - ocr: bool=True, - rebuild: bool=False) -> ResultOCR | None: - img_ctx = ImageContext(self, image_idx) - result = self._results[ocr_model][image_idx][box_idx].get(method) - if not rebuild and result is not None: - return result - - result = self._result_from(image_idx, box_idx, method) - image, cropped_image, cropped_mask = result.image, None, None - base_image = img_ctx.base_image - box = img_ctx.boxes[box_idx] - if image is None and method in _IMAGE_METHODS: - image = crop_by_image( - method, box, base_image, self.config.current_profile.preprocessor) - - if image is None and method in _EXTRACTED_METHODS: - mask = img_ctx.mask - cropped_image_path = result.cache_image(cropped_image, "cropped") - cropped_mask_path = result.cache_image(cropped_mask, "mask") - if not cropped_image_path.exists() or not cropped_mask_path.exists(): - image, cropped_image, cropped_mask = crop_by_extracted( - method, box, base_image, mask, - cropped_image_path, cropped_mask_path, img_ctx.dilated()) - - assert image is not None - if result.image is None: - result.image = image - result.cache_image() - if cropped_image is not None: - result.cache_image(cropped_image, "cropped") - if cropped_mask is not None: - result.cache_image(cropped_mask, "mask") - - if ocr: - result = self.ocr_box(result, ocr_model, img_ctx.page_lang) - self._results[ocr_model][image_idx][box_idx][method] = result - return result - - def results(self, ocr_model: str | None = None, img_idx: ImgIdT | None = None): - if ocr_model is None: return self._results - if img_idx is None: return self._results[ocr_model] - return self._results[ocr_model][img_idx] - def model_results(self, ocr_model: str): - return cast(dict[ImgIdT, ResultSet], self.results(ocr_model)) - def image_results(self, ocr_model: str, img_idx: ImgIdT): - return cast(ResultSet, self.results(ocr_model, img_idx)) - def box_results(self, ocr_model: str, img_idx: ImgIdT, box_idx: BoxIdT): - return cast(ResultSet, self.results(ocr_model, img_idx))[box_idx] - def method_results(self, ocr_model: str, img_idx: ImgIdT, method: CropMethod): - image_results = self.image_results(ocr_model, img_idx) - return {i: box_results.get(method) for i,box_results in image_results.items()} - - def _reset_results(self): - results = defaultdict(lambda: defaultdict(lambda: ResultSetDefault(dict))) - self._results = cast(dict[str, dict[ImgIdT, ResultSet]], results) - def reset_results(self, - ocr_model: str | None = None, - image_idx: int | None = None, - box_idx: int | None = None, - method: CropMethod | None = None): - if ocr_model is None and image_idx is None and box_idx is None and method is None: - self._reset_results() - return - results = self._results - models = tuple(results.keys()) if ocr_model is None else [ocr_model] if ocr_model in results else [] - for ocr_model in models: - img_nodes = results[ocr_model] - imgs = tuple(img_nodes.keys()) if image_idx is None else [image_idx] if image_idx in img_nodes else [] - for img_idx in imgs: - box_nodes = img_nodes[img_idx] - boxes = tuple(box_nodes.keys()) if box_idx is None else [box_idx] if box_idx in box_nodes else [] - for box_idx in boxes: - if method is None: - del box_nodes[box_idx] - else: - methods = box_nodes[box_idx] - if method in methods: - del methods[method] - if not box_nodes[box_idx]: - del box_nodes[box_idx] - if not img_nodes[img_idx]: - del img_nodes[img_idx] - if not results[ocr_model]: - del results[ocr_model] - def reset(self): - super().reset() - self.reset_results() - self._load_page_data.cache_clear() - self.mocr.cache_clear() - - def __init__(self, - config: cfg.Config | None, - image_paths: list[Path] - ): - super().__init__(list(map(lambda p: p.resolve(), image_paths))) - self.config = config or type(self).get_config() - self.image_paths = self._paths - self._reset_results() - self._images = self._subjects - - -# %% experiments.ipynb 51 -@FC.patch_to(ImageContext) -def setup(self, exp: OCRExperimentContext, image_idx: ImgSpecT, page_lang: str | None = None): - super(type(self), self).setup(exp, image_idx) - self._mask_dilated1 = self._mask_dilated05 = self._mask_dilated02 = None - # if ocr_model not in exp.engines: - # raise ValueError(f"OCR model {ocr_model} not supported.") - # self.ocr_model = ocr_model - # self.idx = exp.normalize_idx(image_idx) - self.json_data, self.page_data = exp._load_page_data(self.idx) - self.setup_page_lang(page_lang) - self.mask = Image.open(self.page_data.mask_path) - self.base_image = Image.open(self.page_data.image_path) - self.setup_ground_truth() - - - -# %% experiments.ipynb 54 -class ContextVisor: - ctx: Any - # control_names: list[str] - values: dict[str, Any] - - _css = '' - - _ctxs: dict[str, ContextVisor] - _hdlrs: dict[str, ContextVisor] - - @property - def w(self) -> W.DOMWidget: - if getattr(self, '_w', None) is None: - self._w = self.setup_ui() - return self._w - @property - def out(self) -> W.Output: - if getattr(self, '_out', None) is None: - self._out = W.Output() - self._out.clear_output(wait=True) - return self._out # type: ignore - @property - def controls(self) -> dict[str, W.ValueWidget | W.fixed]: - if getattr(self, '_controls', None) is None: - self._controls = self.setup_controls() - return self._controls - @property - def all_controls(self) -> dict[str, W.ValueWidget | W.fixed]: - if getattr(self, '_all_controls', None) is None: - controls = {} - for visor in self._ctxs.values(): - controls.update(visor.all_controls) - controls.update(self.controls) - self._all_controls = controls - return self._all_controls - - @property - def all_values(self): - return {**{k:v.values for k,v in (self._ctxs | {'self': self}).items()}, **self.values} - - @property - def comps(self): return self._ctxs - def comp(self, k: str) -> ContextVisor | None: - return self._ctxs.get(k) - def handler(self, k: str) -> ContextVisor | None: - return self._hdlrs.get(k) - - @property - def styler(self) -> W.Output | None: - if (stl := self.setup_style()) is None: - return None - if getattr(self, '_style', None) is None: - self._style = W.Output(layout={'height': '0px'}) - with self._style: - display(stl) - return self._style - def setup_style(self): - return HTML(f"") if self._css else None - - def update_output(self, **kwargs): - cprint(kwargs) - - def setup_controls(self) -> dict[str, W.ValueWidget | W.fixed]: - return {k: W.Label(value=k) for k,v in self.values.items()} - - def hide(self): - self.w.layout.visibility = 'hidden' - def show(self): - self.w.layout.visibility = 'visible' - - def setup_ui(self): - comps = [] - for visor in self._ctxs.values(): - comps.append(visor.w) - return W.HBox([*comps, *self.controls.values()]) - - def setup_display(self): - if getattr(self, '_w', None) is None: - self._w = self.setup_ui() - - - def _output(self, **kwargs): - collator = defaultdict(dict) - show_inline_matplotlib_plots() - with self.out: - clear_output(wait=True) - for k,v in kwargs.items(): - if (comp := self.handler(k)) is not None: - collator[comp][k] = v - else: - assert 0 - # self.update_output(**{k: v}) - for comp, kw in collator.items(): - comp.update_output(**kw) - show_inline_matplotlib_plots() - def interactive_output(self): - controls = self.all_controls - controls2names = {v:k for k,v in controls.items()} - def observer(change): - control_name = controls2names[change['owner']] - kwargs = {control_name: change['new']} - updated = self._update(**kwargs) - self._output(**updated) - for w in controls.values(): - w.observe(observer, 'value') - def display(self, **kwargs): - if getattr(self, '_w', None) is None: - self.setup_display() - self.interactive_output() - self._update(**(self.values | kwargs)) - all_values= {} - for comp in list(self.comps.values()) + [self]: all_values.update(comp.values) - self._hdlrs = {k:self._hdlrs.get(k, self) for k in all_values} - self._output(**all_values) - display(self.styler, self.w, self.out) if self.styler else display(self.w, self.out) - else: - self.update(**kwargs) - def _ipython_display_(self): self.display() - - def _update(self, update_value: bool=True, **kwargs): - updated = {} - for visor in self.comps.values(): - updated.update(visor._update(update_value=update_value, **kwargs)) - values = self.values - my_vals = _pops_(kwargs, self.values.keys()) - for k,v in my_vals.items(): - if v is not None and v != values[k]: - if update_value: values[k] = v - updated[k] = v - return updated - def update(self, **kwargs): - updated = self._update(update_value=False, **kwargs) - controls = self.all_controls - for k in updated: - controls[k].value = updated[k] - # self._output(**updated) - - def __init__(self, - ctx: Any, - values: dict[str, Any], - out: W.Output | None = None, - ctxs: dict[str, ContextVisor] | None = None, - hdlrs: dict[str, ContextVisor] | None = None, - ): - self._ctxs = ctxs or {} - self._hdlrs = hdlrs or {} - self.ctx = ctx - self._out = out - self.values = values - - - -# %% experiments.ipynb 62 -class ImageSelector(ContextVisor): - ctx: OCRExperimentContext - - @property - def image_ctx(self): - return ImageContext(self.ctx, self.values['image_idx']) - - def setup_controls(self): - paths = self.ctx.image_paths - w = W.Dropdown( - options={_.stem:i for i,_ in enumerate(paths)}, - value=self.values['image_idx'], - layout={'width': 'fit-content'}, - style={'description_width': 'initial'}) - return {'image_idx': w} - - def update(self, image_idx: ImgSpecT | None = None, **kwargs): - if image_idx is None: return - idx = self.ctx.normalize_idx(image_idx) - if idx is None: return - super().update(image_idx=idx, **kwargs) - - - def __init__(self, - ctx: OCRExperimentContext, /, - image_idx: ImgSpecT = 0, *, - out: W.Output | None=None): - idx = ctx.normalize_idx(image_idx) - assert idx is not None, f"Image {image_idx} not found in experiment context" - super().__init__(ctx, {'image_idx': idx}, out) - - -# %% experiments.ipynb 66 -class OCRContextVisor(ContextVisor): - ctx: OCRExperimentContext - - def update_output(self, /, image_idx: ImgIdT, **kwargs): - img_path = self.ctx.path_from_idx(image_idx) - display_image_grid([img_path], 1, 1) - - def update(self, image_idx: ImgSpecT | None = None, **kwargs): - if image_idx is None: return - idx = self.ctx.normalize_idx(image_idx) - if idx is None: return - super().update(image_idx=idx, **kwargs) - - def __init__(self, - ctx: OCRExperimentContext, /, - image_idx: ImgSpecT = 0, *, - out: W.Output | None=None): - super().__init__(ctx, {}, out, - ctxs={'image_idx': ImageSelector(ctx, image_idx, out=self.out)}) - - -# %% experiments.ipynb 84 -class OCRModel(Enum): - TESSERACT = 0 - IDEFICS = 1 - @staticmethod - def __display_names__() -> dict[str, OCRModel]: - return dict( - zip("Tesseract, Idefics".split(', '), - OCRModel)) - - -class ModelSelector(ContextVisor): - ctx: OCRExperimentContext - - def setup_controls(self): - options = self.models - w = W.Dropdown( - options=options, - value=self.values['model'], - layout={'width': 'fit-content'}, - style={'description_width': 'initial'}) - return {'model': w} - - def setup_ui(self): - ctls = self.controls - model_grp = W.HBox([ctls['model']]) - model_grp.add_class('model_grp') - comps = [] - for visor in self.comps.values(): - comps.append(visor.setup_ui()) - ui = W.HBox([*comps, model_grp]) - return ui - - def __init__(self, - exp_ctx: OCRExperimentContext, - ocr_model: OCRModel | None=OCRModel.TESSERACT, - ocr_models: dict[str, OCRModel] | None = None, - out: W.Output | None = None - ): - self.models: dict[str, OCRModel] = ocr_models or OCRModel.__display_names__() - super().__init__(exp_ctx, - {'model': ocr_model or OCRModel.TESSERACT}, - out=out or self.out)#, ctxs=[exp_visor]) - - -# %% experiments.ipynb 87 -class DisplayOptions(Enum): - BOXES = 0 - IMAGE = 1 - MASK = 2 - IMAGE_MASK = 3 - PAGE_DATA = 4 - GROUND_TRUTH = 5 - ALL = 6 - RESULTS = 7 - BEST_RESULTS = 8 - DATAFRAME = 9 - - @staticmethod - def __display_names__(): - return dict( - zip("Boxes, Image, Mask, Image & Mask, Page data, Ground truth, All, Results, " - "Best results, Dataframe".split(', '), - DisplayOptions)) - - -class ContentSelector(ContextVisor): - ctx: OCRExperimentContext - - def image_info(self, image_ctx: ImageContext): - img = image_ctx.base_image - (w, h), print_size_in, print_size_cm, required_dpi = image_ctx.image_info - format = PRINT_FORMATS['Modern Age'] - cprint( f"{'Width x Height':>30}: {w} x {h} pixels\n" - f"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\n" - f"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in" - f" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\n" - f"Required DPI Modern Age format: {required_dpi:.3f} dpi " - f"({format[0]:.3f} x {format[1]:.3f} in)") - - - def display_content(self, image_ctx: ImageContext, display_option: DisplayOptions): - page_data = image_ctx.page_data - if display_option in (DisplayOptions.ALL, DisplayOptions.PAGE_DATA): - self.image_info(image_ctx) - RenderJSON(image_ctx.json_data, 350, 2).display() - if display_option in (DisplayOptions.ALL, DisplayOptions.GROUND_TRUTH): - cprint(image_ctx.gts) - if display_option == DisplayOptions.IMAGE: - display_image_grid([page_data.image_path], 1, 1) - if display_option == DisplayOptions.MASK: - display_image_grid([page_data.mask_path], 1, 1) - if display_option in (DisplayOptions.ALL, DisplayOptions.IMAGE_MASK): - display_image_grid([page_data.image_path, page_data.mask_path], 1, 2) - if display_option in (DisplayOptions.ALL, DisplayOptions.BOXES): - _, out_path = page_boxes(page_data) - display_image_grid([out_path], 1, 1) - - - def setup_controls(self): - options = self.display_options or {**DisplayOptions.__display_names__()} - display_option_wdgt = W.Dropdown( - options=options, - value=self.values['display_option'], - layout={'width': '120px'}, - style={'description_width': 'initial'}) - return {'display_option': display_option_wdgt} - - - def setup_ui(self): - ctls = self.controls - display_option_grp = W.HBox([ctls['display_option']]) - display_option_grp.add_class('display_option_grp') - comps = [] - for visor in self.comps.values(): - comps.append(visor.setup_ui()) - ui = W.HBox([*comps, display_option_grp]) - return ui - - - def __init__(self, - exp_ctx: OCRExperimentContext, - display_option: DisplayOptions | None=DisplayOptions.BOXES, - display_options: Mapping[str, DisplayOptions] | None = None, - out: W.Output | None = None - ): - self.display_options = display_options - super().__init__(exp_ctx, - {'display_option': display_option or DisplayOptions.BOXES}, - out=out or self.out)#, ctxs=[exp_visor]) - - -# %% experiments.ipynb 91 -class ImageContextVisor(ContextVisor): - ctx: ImageContext - # control_names: list[str] = ['display_option'] - - _css = """ - .display_option_grp { - background-color: lightblue; - } - """ - - def image_info(self): - content_selector = cast(ContentSelector, self.comp('display_option')) - content_selector.image_info(self.ctx) - - def update_output(self, - display_option: DisplayOptions | None = None, - image_idx: ImgIdT | None = None, - **kwargs): - content_selector = cast(ContentSelector, self.comp('display_option')) - if image_idx is not None and image_idx != self.ctx.image_idx: - ctx = ImageContext(self.ctx.exp, image_idx) - assert ctx is not None - self.ctx = ctx - display_option = content_selector.values['display_option'] - if display_option is None: - return - content_selector.display_content(self.ctx, display_option) - - def update(self, - display_option: DisplayOptions | None=None, - image_idx: ImgSpecT | None=None, - **kwargs): - if image_idx is not None: - if (idx := self.ctx.exp.normalize_idx(image_idx)) is not None: - kwargs['image_idx'] = idx - super().update(display_option=display_option, **kwargs) - - def __init__(self, - exp_ctx: OCRExperimentContext, - img_idx: ImgIdT | str | Path | ImageContext, - display_option: DisplayOptions=DisplayOptions.BOXES, - display_options: Mapping[str, DisplayOptions] | None = None, - out: W.Output | None = None - ): - if isinstance(img_idx, ImageContext): - ctx = img_idx - else: - assert exp_ctx is not None, "exp_ctx must be provided if img_idx is not an ImageContext" - ctx = ImageContext(exp_ctx, img_idx) - assert ctx is not None, f"Image {img_idx} not found in experiment context" - if display_options is None: - display_options = {**DisplayOptions.__display_names__()} - del display_options['Results'] - out = out or self.out - content_selector = ContentSelector(exp_ctx, - display_option=display_option, display_options=display_options, out=out) - image_selector = ImageSelector(exp_ctx, ctx.image_idx, out=out) - super().__init__(ctx, {}, out=out, - ctxs={'image_idx': image_selector, 'display_option': content_selector}) - - -# %% experiments.ipynb 104 -def trimmed_mean(data, trim_percent): - sorted_data = np.sort(data) - n = len(data) - trim_count = int(trim_percent * n) - trimmed_data = sorted_data[trim_count:-trim_count] - return np.mean(trimmed_data) - -def mad_based_outlier(points, threshold=3.5): - median = np.median(points) - diff = np.abs(points - median) - mad = np.median(diff) - modified_z_score = 0.6745 * diff / mad - return points[modified_z_score < threshold] - -def iqr_outlier_removal(data): - q1 = np.percentile(data, 25) - q3 = np.percentile(data, 75) - iqr = q3 - q1 - lower_bound = q1 - 1.5 * iqr - upper_bound = q3 + 1.5 * iqr - return data[(data >= lower_bound) & (data <= upper_bound)] - - -# %% experiments.ipynb 105 -@dataclasses.dataclass -class Experiment: - ctx: ExperimentContext - - -@dataclasses.dataclass -class ExperimentOCR(Experiment): - ctx: ImageContext - ocr_model: str - - @property - def img_ctx(self): return self.ctx - @property - def ctxs(self): - img_ctx = self.img_ctx - return cast(OCRExperimentContext, img_ctx.exp), img_ctx - - @classmethod - def file_path_of(cls, page_data: st.PageData, ocr_model: str): - return f"{Path(page_data.original_path).stem}_{ocr_model}.json" - - def file_path(self): - img_ctx = self.img_ctx - return type(self).file_path_of(img_ctx.page_data, self.ocr_model) - - def to_dict(self): - "JSON serializable dict of the experiment" - img_ctx = self.img_ctx - img_idx = img_ctx.image_idx - results = results_to_dict(self.results()) - return { - 'image_name': img_ctx.image_name, - 'ocr_model': self.ocr_model, - 'results': results, - } - - def to_json(self, out_dir: Path | None = None): - img_ctx = self.img_ctx - fp = (out_dir or img_ctx.cache_dir_image) / self.file_path() - data = self.to_dict() - with open(fp, 'w') as f: - json.dump(data, f, indent=2) - return fp, data - - @classmethod - def from_json(cls, experiment: OCRExperimentContext, json_path: Path) -> Self: - try: - with open(json_path, 'r') as f: - data = json.load(f) - except Exception as e: - logger.error(f"Error loading {json_path}: {e}") - raise e - ocr_model = data['ocr_model'] - img_ctx = ImageContext(experiment, data['image_name']) - results: ResultSetDefault = dict_to_results( - img_ctx.image_idx, - data['results'], - result_factory=experiment._result_from) - experiment.update_results(ocr_model, img_ctx.image_idx, results) - return cls(img_ctx, ocr_model) - - @classmethod - def from_image(cls, - ctx: OCRExperimentContext, - ocr_model: str, - image_idx: ImgSpecT): - idx = cast(ImgIdT, ctx.normalize_idx(image_idx)) - img_ctx = ImageContext(ctx, idx) - if img_ctx is None: - raise ValueError(f"Image {image_idx} not found in experiment context") - fp = img_ctx.cache_dir / cls.file_path_of(img_ctx.page_data, ocr_model) - if fp.exists(): - return cast(Self, cls.from_json(cast(OCRExperimentContext, img_ctx.exp), fp)) - return cls(img_ctx, ocr_model) - - @classmethod - def from_method(cls, - ctx: OCRExperimentContext, - ocr_model: str, - image_idx: ImgIdT | str | Path, - method: CropMethod): - experiment = cls.from_image(ctx, ocr_model, image_idx) - if experiment is None: - return None - return experiment.method_experiment(method) - - @classmethod - def saved_experiment(cls, - ctx: OCRExperimentContext, ocr_model: str, image_idx: ImgIdT | str | Path): - idx = ctx.normalize_idx(image_idx) - if idx is None: - logger.warning(f"Image {image_idx} not found in experiment context") - return None - return cls.from_image(ctx, ocr_model, idx) - - @classmethod - def saved_experiments(cls, ctx: OCRExperimentContext, ocr_model: str) -> list[Self]: - return [exp for i in range(len(ctx.image_paths)) - if (exp := cls.from_image(ctx, ocr_model, i)) is not None] - - - def result(self, box_idx: BoxIdT, method: CropMethod, ocr: bool=True, rebuild: bool=False): - ctx, img_ctx = self.ctxs - return ctx.result(self.ocr_model, img_ctx.image_idx, box_idx, method, ocr, rebuild) - - def results(self): - ctx, img_ctx = self.ctxs - return cast(ResultSet, ctx.results(self.ocr_model, img_ctx.image_idx)) - - def has_run(self): - "at least one method has run" - img_ctx = self.img_ctx - return len(self.results()) == len(img_ctx.page_data.boxes) - - def best_results(self): - img_ctx = self.img_ctx - results = self.results() - if len(results) < len(img_ctx.page_data.boxes): # at least one method has run - return None - best = [] - for box_idx in results: - methods = results[box_idx] - best_method = max(methods, key=lambda m: methods[m].acc) # type: ignore - best.append((best_method, methods[best_method])) - return best - - def save_results_as_ground_truth(self, overwrite=False): - img_ctx = self.img_ctx - gts_path = ground_truth_path(img_ctx.page_data) - if overwrite or not gts_path.exists(): - best_results = self.best_results() - if best_results: - tt = [r.ocr for m,r in best_results] - gts_path.write_text('\n'.join(tt), encoding="utf-8") - img_ctx.setup_ground_truth() - logger.info(f"Ground truth data saved successfully to {gts_path}") - return True - else: - logger.info("No best results available to save.") - return False - else: - return False - - @property - def experiments(self): - if not hasattr(self, '_experiments'): - self._experiments = {} - return self._experiments - def method_experiment(self, method: CropMethod) -> ExperimentOCRMethod: - if method not in self.experiments: - self.experiments[method] = ExperimentOCRMethod(self, method) - return self.experiments[method] - - - def to_dataframe(self): - "Dataframe with crop methods as columns and box ids as rows" - methods = list(CropMethod.__members__.values()) - experiments = [self.method_experiment(m) for m in methods] - accuracies = [[result.acc for result in exp.results()] for exp in experiments] - # transpose accuracies - accuracies = list(zip(*accuracies)) - return pd.DataFrame(accuracies, columns=CropMethod.__display_names__()) - - def plot_accuracies(self, - methods: list[CropMethod] | None = None, - ): - "Plots a horizontal bar chart of the accuracies for a list of method experiments." - methods = methods or list(CropMethod.__members__.values()) - experiments = [self.method_experiment(m) for m in methods] - if not experiments: return - - ctx, img_ctx = self.ctxs - page_data = img_ctx.page_data - model = self.ocr_model - accuracies = [[result.acc for result in exp.results()] for exp in experiments] - accuracies = [np.mean(a) for a in accuracies] - # accuracies = [np.mean([result.acc for result in exp.results()]) for exp in experiments] - - _, ax = plt.subplots(figsize=(10, 5)) - - # Normalize the accuracies for color mapping - norm = plt.Normalize(min(accuracies), max(accuracies)) - # Color map from red to green - cmap = plt.get_cmap('RdYlGn') - colors = cmap(norm(accuracies)) - - ax.barh([m.value for m in methods], accuracies, color=colors) - - ax.set_xscale('log') # Set the x-axis to a logarithmic scale - ax.set_xlabel('Average Accuracy (log scale)', fontsize=12, fontweight='bold') - - ax.set_ylabel('Method', fontsize=12, fontweight='bold') - ax.set_yticks(range(len(methods))) - ax.set_yticklabels([f'{method.value} ({acc:.2f})' - for method, acc in zip(methods, accuracies)], fontsize=12) - max_acc_index = np.argmax(accuracies) - ax.get_yticklabels()[max_acc_index].set(color='blue', fontweight='bold') - - title_text = (f"{page_data.original_path} - OCR model: {model}") - ax.set_title(title_text, fontsize=12, fontweight='bold') - - plt.tight_layout() - plt.show() - - - def summary_box(self, box_idx: int): - results: list[tuple[CropMethod, ResultOCR]] = [] - pb = tqdm(CropMethod.__members__.values(), leave=False, desc=f"Box #{box_idx+1}") - for m in pb: - r = cast(ResultOCR, self.result(box_idx, m)) - results.append((m, r)) - methods, images, ocrs, accs = zip( - *map( - lambda t: (t[0].value, t[1].cache_image(), t[1].diff_tagged(), acc_as_html(t[1].acc)), - results)) - display_columns([methods, images, accs, ocrs], - headers=["Method", f"Box #{box_idx+1}", "Accuracy", "OCR"]) - - - def summary_method(self, method: CropMethod): - results = self.method_experiment(method).results() - methods, images, ocrs, accs = zip( - *map( - lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), - results)) - display_columns([methods, images, accs, ocrs], - headers=["Box #", "Box", "Accuracy", f"{method.value} OCR"]) - - - def display(self): - out = [] - for method in CropMethod: - out.append(f"---------- {method.value} ----------") - results = self.method_experiment(method).results() - out.extend(results) - out.append('\n') - cprint(*out, soft_wrap=True) - - - def reset(self, box_idx: int | None = None, method: CropMethod | None = None): - ctx, img_ctx = self.ctxs - ctx.reset_results(None, img_ctx.image_idx, box_idx, method) - - def perform_methods(self, - methods: CropMethod | list[CropMethod] | None = None, - box_idxs: BoxIdT | list[BoxIdT] | None = None, - rebuild: bool = False, - plot_acc: bool = False - ): - if methods is None: - methods = [*CropMethod.__members__.values()] - elif isinstance(methods, CropMethod): - methods = [methods] - if rebuild: - _methods = tqdm(methods, desc="Methods") - else: - _methods = methods - for method in _methods: - method_exp = self.method_experiment(method) - if method_exp: - if rebuild: - method_exp(box_idxs, rebuild=rebuild) - if plot_acc: - self.plot_accuracies() - - def __call__(self, - box_idxs: BoxIdT | list[BoxIdT] | None = None, - methods: CropMethod | list[CropMethod] | None = None, - save: bool = True, - display=False, - rebuild: bool=False, - save_as_ground_truth=False): - self.perform_methods(methods, box_idxs, rebuild=rebuild) - if save_as_ground_truth: - self.save_results_as_ground_truth(overwrite=True) - if save: - self.to_json() - if display: - self.display() - - -@dataclasses.dataclass -class ExperimentOCRMethod: - ctx: ExperimentOCR - method: CropMethod - - @property - def exp_ctx(self): return self.ctx - @property - def img_ctx(self): return self.ctx.ctx - @property - def ctxs(self): - img_ctx = self.img_ctx - return cast(OCRExperimentContext, img_ctx.exp), img_ctx, self.ctx - - def result(self, box_idx: BoxIdT, ocr: bool=True, rebuild: bool=False) -> ResultOCR | None: - ctx, img_ctx, exp_ctx = self.ctxs - return ctx.result(exp_ctx.ocr_model, img_ctx.image_idx, box_idx, self.method, ocr, rebuild) - - def results(self, - box_idxs: BoxIdT | list[BoxIdT] | None = None, - ocr: bool=True, rebuild: bool=False) -> list[ResultOCR]: - ctx, img_ctx, exp_ctx = self.ctxs - if box_idxs is None: - box_idxs = list(range(len(img_ctx.boxes))) - elif isinstance(box_idxs, int): - box_idxs = [box_idxs] - model = exp_ctx.ocr_model - results = ctx.method_results(model, img_ctx.image_idx, self.method) - results = {i:results[i] if i in results else None for i in box_idxs} - pb = rebuild or not results or any(r is None for r in results.values()) - if pb and len(results) > 2: - progress_bar = tqdm(list(results.keys()), desc=f"{self.method.value} - {model}") - else: - progress_bar = list(results.keys()) - results = [] - for i in progress_bar: - results.append(self.result(i, ocr, rebuild=rebuild)) - return results - - - def get_results_html(self, - box_idxs: BoxIdT | list[BoxIdT] | None = None, - max_image_width: int | None = None): - _, img_ctx, exp_ctx = self.ctxs - results: list[ResultOCR] = self.results(box_idxs) - accs = np.array([r.acc for r in results]) - mean_accuracy = np.mean(accs) - mean_trimmed = trimmed_mean(accs, 0.1) - # filtered_data = mad_based_outlier(accs) - # mean_mad = np.mean(filtered_data) - # filtered_data = iqr_outlier_removal(accs) - # mean_iqr = np.mean(filtered_data) - - descriptions, images, ocrs, accs = zip(*map( - lambda r: ( - r.block_idx+1, - r.cache_image(), - r.diff_tagged(), - acc_as_html(r.acc) - ), results)) - non_breakin_space = u'\u00A0' - tmpl = "{}" - padded_s = lambda s,n: tmpl.format(s.rjust(n)) - acc_fmt = f"{mean_accuracy:.2f}/{mean_trimmed:.2f}" - w, h = img_ctx.base_image.size - dim, _dpi = size(w, h), dpi(w, h) - dim_fmt = f"{w}x{h} px: {dim[0]:.2f} x {dim[1]:.2f} in @ {_dpi:.2f} dpi" - return '\n
\n'.join([ - ("
" - f"{padded_s('Page', 24)}: {img_ctx.page_data.original_path}
" - f"{padded_s('Size', 24)}: {dim_fmt}
" - f"{padded_s('Model', 24)}: {exp_ctx.ocr_model}
" - f"{padded_s('Crop Method', 24)}: {self.method.value}
" - f"{padded_s('Accuracy Mean/Trimmed', 24)}: {acc_fmt}" - "
"), - get_columns_html( - [descriptions, images, accs, ocrs], - max_image_width, - headers=["Box #", "Image", "Accuracy", "OCR"]), - ]) - - def display(self, - box_idxs: BoxIdT | list[BoxIdT] | None = None, max_image_width: int | None = None): - display(HTML(self.get_results_html(box_idxs, max_image_width))) - - - def summary(self): - results = self.results() - methods, images, ocrs, accs = zip( - *map( - lambda r: (r.block_idx+1, r.cache_image(), r.diff_tagged(), acc_as_html(r.acc)), - results)) - display_columns([methods, images, accs, ocrs], - headers=["Box #", "Box", "Accuracy", f"{self.method.value} OCR"]) - - - def reset(self): - _, _, exp_ctx = self.ctxs - exp_ctx.reset(method=self.method) - - def __call__(self, box_idxs: BoxIdT | list[BoxIdT] | None = None, display=False, rebuild=False): - if isinstance(box_idxs, int): - result = self.result(cast(BoxIdT, box_idxs), rebuild=rebuild) - if result is not None and display: - result.display() - else: - results = self.results(box_idxs, rebuild=rebuild) - if results and display: - self.display(box_idxs) - - -# %% experiments.ipynb 141 -class ResultVisor(ContextVisor): - ctx: ExperimentOCR - control_names: list[str] = ['all_boxes', 'box_idx', 'all_methods', 'method'] - - _css = """ - .box_grp { - background-color: aliceblue; - } - .method_grp { - background-color: #ededed; - } - """ - - def best_results(self): - ll = self.ctx.best_results() - if ll: - cprint([(m.value, f"{r.acc:.3f}", r.ocr) for m,r in ll]) - - def pd_to_html(self): - df = self.ctx.to_dataframe() - # set float precision - df = df.round(3) - # display floats with 3 decimal digits - df = df.applymap(lambda x: f"{x:.3f}") - # highlight max value in each row - stl = df.style.highlight_max(axis=0) - display(HTML(stl.to_html())) - - def update_output(self, **kwargs): - all_boxes: bool = self.values['all_boxes'] - box_idx: int = self.values['box_idx'] - all_methods: bool = self.values['all_methods'] - method: CropMethod = self.values['method'] - - # cprint(f"all_boxes: {all_boxes}, box_idx: {box_idx}, all_methods: {all_methods}, method: {method}") - - if all_boxes and all_methods: - self.ctx.plot_accuracies() - elif all_boxes: - self.ctx.summary_method(method) - elif all_methods: - self.ctx.summary_box(box_idx) - else: - result = self.ctx.result(box_idx, method) - if result is not None: - result.display() - - def setup_controls(self): - _, img_ctx = self.ctx.ctxs - values = self.values - box_wdgt = W.BoundedIntText( - value=values['box_idx'], min=0, max=len(img_ctx.boxes)-1, step=1, - disabled=values['all_boxes'], - layout={'width': '50px'}, - style={'description_width': 'initial'}) - methods_wdgt = W.Dropdown( - options=CropMethod.__display_names__(), - value=values['method'], - layout={'width': '150px'}, - style={'description_width': 'initial'}) - all_boxes_wdgt = W.Checkbox(label='All', value=values['all_boxes'], - description="all", - layout={'width': 'initial'}, - style={'description_width': '0px'}) - all_methods_wdgt = W.Checkbox(label='All', value=values['all_methods'], - description="all", - layout={'width': 'initial'}, - style={'description_width': '0px'}) - return {'all_boxes': all_boxes_wdgt, 'box_idx': box_wdgt, - 'all_methods': all_methods_wdgt, 'method': methods_wdgt} - - def setup_ui(self): - ctls = self.controls - _, img_ctx = self.ctx.ctxs - box_label = W.Label( - value=f"Box # (of {len(img_ctx.boxes)}):", - layout={'width': 'initial', 'padding': '0px 0px 0px 10px'}) - method_label = W.Label(value='Method:', layout={'width': 'initial', 'padding': '0px 0px 0px 10px'}) - - box_grp = W.HBox([box_label, ctls['all_boxes'], ctls['box_idx']]) - box_grp.add_class('box_grp') - method_grp = W.HBox([method_label, ctls['all_methods'], ctls['method']]) - method_grp.add_class('method_grp') - - return W.HBox([box_grp, method_grp]) - - def __init__(self, - ctx: OCRExperimentContext | ExperimentOCR, - img_idx: int | str | Path | None = None, - all_boxes: bool = False, - box_idx: int = 0, - all_methods: bool = False, - method: CropMethod=CropMethod.INITIAL_BOX, - out: W.Output | None = None, - ): - if isinstance(ctx, OCRExperimentContext): - assert img_idx is not None, "img_idx must be provided if ctx is an ExperimentContext" - exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx) - if not exp: - raise ValueError(f"Image {img_idx} not found in experiment context") - ctx = exp - else: - if not isinstance(ctx, ExperimentOCR): - raise ValueError("ctx must be an ExperimentOCR or OCRExperimentContext") - - super().__init__(ctx, {'all_boxes': all_boxes, 'box_idx': box_idx, - 'all_methods': all_methods, 'method': method}, out=out or self.out) - - -# %% experiments.ipynb 144 -class ExperimentVisor(ContextVisor): - ctx: ExperimentOCR - - def update_output(self, - image_idx: int | None = None, - **kwargs): - exp_ctx, img_ctx = self.ctx.ctxs - if image_idx is not None and image_idx != img_ctx.image_idx: - ctx = ImageContext(exp_ctx, image_idx) - assert ctx is not None - self.ctx.ctx = ctx - result_visor = self.comp('result_visor') - if result_visor is not None: - result_visor.update_output(**kwargs) - - def __init__(self, - ctx: OCRExperimentContext | ExperimentOCR, - img_idx: int | str | Path | None = None, - all_boxes: bool = False, - box_idx: int = 0, - all_methods: bool = False, - method: CropMethod=CropMethod.INITIAL_BOX, - out: W.Output | None = None, - ): - if isinstance(ctx, OCRExperimentContext): - assert img_idx is not None, "img_idx must be provided if ctx is an ExperimentContext" - exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx) - if not exp: - raise ValueError(f"Image {img_idx} not found in experiment context") - ctx = exp - else: - if not issubclass(type(ctx), ExperimentOCR): - raise ValueError("ctx must be an ExperimentOCR or OCRExperimentContext") - - exp_ctx, img_ctx = ctx.ctxs - out = out or self.out - image_selector = ImageSelector(exp_ctx, image_idx=img_ctx.image_idx, out=out) - result_visor = ResultVisor(ctx, out=out, - all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method) - - super().__init__(ctx, {}, out=out, - ctxs={'image_selector': image_selector, 'result_visor': result_visor}, - hdlrs={'display_option': result_visor} - ) - - -# %% experiments.ipynb 198 -class ExperimentsVisor(ContextVisor): - ctx: OCRExperimentContext - - def update_output(self, - model: OCRModel | None = None, - image_idx: ImgIdT | None = None, - display_option: DisplayOptions | None = None, - **kwargs): - model_selector, image_selector, content_selector, result_visor = self._comps() - if model is not None: - exp_ctx = result_visor.ctx - exp_ctx.ocr_model = list(model_selector.models.keys())[model.value] - result_visor.ctx = exp_ctx - if image_idx is not None: - img_ctx = ImageContext(self.ctx, image_idx) - result_visor.ctx.ctx = img_ctx - display_option = content_selector.values['display_option'] - if display_option is not None and display_option != DisplayOptions.RESULTS: - result_visor.hide() - if display_option == DisplayOptions.BEST_RESULTS: - result_visor.best_results() - elif display_option == DisplayOptions.DATAFRAME: - result_visor.pd_to_html() - else: - content_selector.display_content(image_selector.image_ctx, display_option) - else: - result_visor.show() - result_visor.update_output(**kwargs) - - def _comps(self): - cc = self.comps - msel: ModelSelector = cc['model_selector'] # type: ignore - isel: ImageSelector = cc['image_selector'] # type: ignore - cs: ContentSelector = cc['content_selector'] # type: ignore - rv: ResultVisor = cc['result_visor'] # type: ignore - return msel, isel, cs, rv - - def setup_ui(self): - ctls = self.controls.values() - msw, isw, csw, rvw = [_.w for _ in self._comps()] - return W.VBox([W.HBox([msw, isw, csw, *ctls]), rvw,]) - - def __init__(self, - ctx: OCRExperimentContext, - image_idx: ImgIdT | str | Path = 0, - ocr_model: OCRModel = OCRModel.TESSERACT, - display_option: DisplayOptions = DisplayOptions.RESULTS, - all_boxes: bool = False, - box_idx: int = 0, - all_methods: bool = False, - method: CropMethod=CropMethod.INITIAL_BOX, - ocr_models: dict[str, OCRModel] = {'Tesseract': OCRModel.TESSERACT}, - out: W.Output | None = None, - ): - if not isinstance(ctx, OCRExperimentContext): - raise ValueError("ctx must be an OCRExperimentContext") - exp = ExperimentOCR.from_image(ctx, 'Tesseract', image_idx) - if not exp: - raise ValueError(f"Image {image_idx} not found in experiment context") - - out = out or self.out - model_selector = ModelSelector(ctx, ocr_model=ocr_model, - ocr_models=ocr_models, out=out) - image_selector = ImageSelector(ctx, image_idx=image_idx, out=out) - content_selector = ContentSelector(ctx, display_option=display_option, out=out) - result_visor = ResultVisor(exp, out=out, - all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method) - - super().__init__(ctx, {}, out=out, - ctxs={'model_selector': model_selector, 'image_selector': image_selector, 'content_selector': content_selector, - 'result_visor': result_visor} - ) - diff --git a/_testbed/helpers.ipynb b/_testbed/helpers.ipynb deleted file mode 100644 index 32a6fa6d..00000000 --- a/_testbed/helpers.ipynb +++ /dev/null @@ -1,835 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#| default_exp helpers" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "# %reload_ext autoreload\n", - "# %autoreload 0\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# install (Colab)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# try: \n", - "# import fastcore as FC\n", - "# except ImportError: \n", - "# !pip install -q fastcore\n", - "# try:\n", - "# import rich\n", - "# except ImportError:\n", - "# !pip install -q rich\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@basic-tesseract" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Testing `Tesseract` OCR for Comics\n", - "> Accuracy Enhancements for OCR in `PanelCleaner`\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prologue" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "from __future__ import annotations\n", - "\n", - "import base64\n", - "import json\n", - "import re\n", - "import sys\n", - "import uuid\n", - "from importlib import resources\n", - "from io import BytesIO\n", - "from pathlib import Path\n", - "from typing import Any\n", - "from typing import Iterable\n", - "from typing import Mapping\n", - "from typing import Sequence\n", - "\n", - "import pcleaner.data\n", - "import pcleaner.structures as st\n", - "from IPython.display import clear_output\n", - "from IPython.display import display\n", - "from IPython.display import HTML\n", - "from PIL import Image\n", - "from PIL import ImageDraw\n", - "from PIL import ImageFont\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "from collections import defaultdict\n", - "\n", - "import fastcore.xtras # patch Path with some utils\n", - "import ipywidgets as W\n", - "import rich\n", - "from fastcore.test import * # type: ignore\n", - "from rich.console import Console\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Helpers" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# pretty print by default\n", - "# %load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "console = Console(width=104, tab_size=4, force_jupyter=True)\n", - "cprint = console.print\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## dict helpers: _pops_\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "_all_ = ['_pops_', '_pops_values_', '_gets_']\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def _pops_(d: dict, ks: Iterable) -> dict: \n", - " \"Pops `ks` keys from `d` and returns them in a dict. Note: `d` is changed in-place.\"\n", - " return {k:d.pop(k) for k in ks if k in d}\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "test_eq(_pops_({'a': 1, 'b': 2, 'c': 3}, ['a', 'b']), {'a': 1, 'b': 2})\n", - "test_eq(_pops_({'a': 1, 'b': 2, 'c': 3}, ['d']), {})\n", - "test_eq(_pops_({'a': 1, 'b': 2, 'c': 3}, ['a', 'c', 'd']), {'a': 1, 'c': 3})\n", - "test_eq(_pops_({}, ['a']), {})\n", - "test_eq(_pops_({'a': 1}, ['a', 'a']), {'a': 1})\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def _pops_values_(d: dict, ks: Iterable) -> tuple:\n", - " \"Pops `ks` keys from `d` and returns them as a tuple. Note: `d` is changed in-place.\"\n", - " return tuple(d.pop(k, None) for k in ks)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "test_eq(_pops_values_({'a': 1, 'b': 2, 'c': 3}, ['a', 'b']), (1, 2))\n", - "test_eq(_pops_values_({'a': 1, 'b': 2, 'c': 3}, ['d']), (None,))\n", - "test_eq(_pops_values_({'a': 1, 'b': 2, 'c': 3}, ['a', 'c', 'd']), (1, 3, None))\n", - "test_eq(_pops_values_({}, ['a']), (None,))\n", - "test_eq(_pops_values_({'a': 1}, ['a', 'a']), (1, None))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def _gets_(d: Mapping[str, Any], ks: Iterable):\n", - " \"Fetches values from a mapping for a given list of keys, returning `None` for missing keys.\"\n", - " return (d.get(k, None) for k in ks)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "test_eq(_gets_({'a': 1, 'b': 2}, ('a', 'c', 'b')), [1, None, 2])\n", - "test_eq(_gets_({'a': 1, 'b': 2}, ()), [])\n", - "a, b = _gets_({'a': 1, 'b': 2}, ('b', 'a'))\n", - "test_eq((a, b), (2, 1))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## cleanupwidget\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "def _get_globals(mod: str):\n", - " if hasattr(sys, '_getframe'):\n", - " glb = sys._getframe(2).f_globals\n", - " else:\n", - " glb = sys.modules[mod].__dict__\n", - " return glb\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# _all_ = ['_get_globals']\n", - "def _gtest():\n", - " return _get_globals(__name__)\n", - "g1 = _gtest()\n", - "g2 = globals()\n", - "test_eq(g1, g2)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "def cleanupwidgets(*ws, mod: str|None=None, clear=True):\n", - " glb = _get_globals(mod or __name__)\n", - " if clear: clear_output(wait=True)\n", - " for w in ws:\n", - " _w = glb.get(w) if isinstance(w, str) else w\n", - " if _w:\n", - " try: _w.close() # type: ignore\n", - " except: pass\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "_b = W.Button()\n", - "test_ne(_b.comm, None)\n", - "cleanupwidgets('_b')\n", - "test_is(_b.comm, None)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Collapsable JSON in a notebook cell" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "class RenderJSON(object):\n", - " def __init__(self, json_data, max_height=200, init_level=0):\n", - " if isinstance(json_data, (Sequence, Mapping)):\n", - " s = json.dumps(json_data)\n", - " elif hasattr(json_data, 'to_dict'):\n", - " s = json.dumps(json_data.to_dict())\n", - " elif hasattr(json_data, 'to_json'):\n", - " s = json_data.to_json()\n", - " else:\n", - " s = json_data\n", - " self.json_str = s\n", - " self.uuid = str(uuid.uuid4())\n", - " self.max_height = max_height\n", - " self.init_level = init_level\n", - "\n", - " def display(self):\n", - " html_content = f\"\"\"\n", - "
\n", - "
\n", - " \n", - "
\n", - " \"\"\"\n", - " display(HTML(html_content))\n", - "\n", - " def _ipython_display_(self):\n", - " self.display()" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "json_data = {\n", - " \"name\": \"Petronila\",\n", - " \"age\": 28,\n", - " \"interests\": [\"reading\", \"cycling\", \"technology\"],\n", - " \"education\": {\n", - " \"bachelor\": \"Computer Science\",\n", - " \"master\": \"Data Science\",\n", - " \"phd\": \"Not enrolled\"\n", - " }\n", - "}\n", - "\n", - "RenderJSON(json_data, init_level=1).display()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Visualize boxes on the page image\n", - "> adapted from `PageData.visualize` but returns the image instead of saving it." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def page_boxes(self: st.PageData, out_dir: Path | None = None) -> tuple[Image.Image, Path]:\n", - " \"\"\"\n", - " Visualize the boxes on an image.\n", - " Typically, this would be used to check where on the original image the\n", - " boxes are located.\n", - "\n", - " :param image_path: The path to the image to visualize the boxes on.\n", - " \"\"\"\n", - " image_path = Path(self.image_path)\n", - " image = Image.open(image_path)\n", - " draw = ImageDraw.Draw(image)\n", - " data_path = resources.files(pcleaner.data)\n", - " font_path = str(data_path / \"LiberationSans-Regular.ttf\")\n", - " # Figure out the optimal font size based on the image size. E.g. 30 for a 1600px image.\n", - " font_size = int(image.size[0] / 50) + 5\n", - "\n", - " for index, box in enumerate(self.boxes):\n", - " draw.rectangle(box.as_tuple, outline=\"green\")\n", - " # Draw the box number, with a white background, respecting font size.\n", - " draw.text(\n", - " (box.x1 + 4, box.y1),\n", - " str(index + 1),\n", - " fill=\"green\",\n", - " font=ImageFont.truetype(font_path, font_size),\n", - " stroke_fill=\"white\",\n", - " stroke_width=3,\n", - " )\n", - "\n", - " for box in self.extended_boxes:\n", - " draw.rectangle(box.as_tuple, outline=\"red\")\n", - " for box in self.merged_extended_boxes:\n", - " draw.rectangle(box.as_tuple, outline=\"purple\")\n", - " for box in self.reference_boxes:\n", - " draw.rectangle(box.as_tuple, outline=\"blue\")\n", - "\n", - " # Save the image.\n", - " extension = \"_boxes\"\n", - " out_path = image_path.with_stem(image_path.stem + extension)\n", - " if out_dir is not None:\n", - " out_dir.mkdir(parents=True, exist_ok=True)\n", - " out_path = out_dir / image_path.name\n", - " image.save(out_path)\n", - "\n", - " return image, out_path" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Simple crop" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def crop_box(box: st.Box, image: Image.Image) -> Image.Image:\n", - " return image.crop(box.as_tuple)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Print size & resolution" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "PRINT_FORMATS = {\n", - " 'Golden Age': (7.75, 10.5), # (1930s-40s) \n", - " 'Siver Age': (7, 10.375), # (1950s-60s)\n", - " 'Modern Age': (6.625,10.25), # North American comic books\n", - " 'Magazine': (8.5, 11), \n", - " 'Digest': (5.5, 8.5), \n", - " 'Manga': (5.0, 7.5),\n", - "}\n", - "\n", - "\n", - "def size(w: int, h: int, unit: str = 'in', dpi: float = 300.) -> tuple:\n", - " \"\"\"\n", - " Calculate the print size of an image in inches or centimeters.\n", - "\n", - " Args:\n", - " w (int): Width of the image in pixels.\n", - " h (int): Height of the image in pixels.\n", - " unit (str): Unit of measurement ('in' for inches, 'cm' for centimeters).\n", - " dpi (float): Dots per inch (resolution).\n", - "\n", - " Returns:\n", - " tuple: Width and height of the image in the specified unit.\n", - " \"\"\"\n", - " if unit == 'cm':\n", - " return (w / dpi * 2.54, h / dpi * 2.54)\n", - " else: # default to inches\n", - " return (w / dpi, h / dpi)\n", - "\n", - "\n", - "def dpi(w: int, h: int, print_format: str = 'Modern Age') -> float:\n", - " \"\"\"\n", - " Calculate the dpi (dots per inch) needed to print an image at a specified format size.\n", - "\n", - " Args:\n", - " w (int): Width of the image in pixels.\n", - " h (int): Height of the image in pixels.\n", - " print_format (str): Print format as defined in the formats dictionary.\n", - "\n", - " Returns:\n", - " float: Required dpi to achieve the desired print format size.\n", - " \"\"\"\n", - " # Default to 'Modern Age' if format not found\n", - " format_size = PRINT_FORMATS.get(print_format, PRINT_FORMATS['Modern Age'])\n", - " width_inch, height_inch = format_size\n", - " dpi_w = w / width_inch\n", - " dpi_h = h / height_inch\n", - " return (dpi_w + dpi_h) / 2 # Average dpi for width and height\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Show images and texts on HTML tables" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def get_image_html(image: Image.Image | Path | str, max_width: int | None = None):\n", - " \"\"\"\n", - " Converts a PIL image to an HTML image tag containing the image as a base64 blob.\n", - "\n", - " :param image: A PIL Image object.\n", - " :param max_size: A PIL Image object.\n", - " :return: A string containing an HTML tag with the image.\n", - " \"\"\"\n", - " style = f' style=\"max-width: {max_width}px;\"' if max_width is not None else ''\n", - " if isinstance(image, (Path, str)):\n", - " return f''\n", - " else:\n", - " buffered = BytesIO()\n", - " image.save(buffered, format='PNG')\n", - " img_str = base64.b64encode(buffered.getvalue()).decode()\n", - " return f''\n", - "\n", - "\n", - "def get_columns_html(\n", - " columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None\n", - "):\n", - " if not all(len(col) == len(columns[0]) for col in columns):\n", - " raise ValueError(\"All columns must have the same length.\")\n", - "\n", - " # Calculate the maximum width of images in each column\n", - " max_widths = []\n", - " for col_index in range(len(columns)):\n", - " max_col_width = 0\n", - " for item in columns[col_index]:\n", - " if isinstance(item, (Image.Image, Path)):\n", - " if isinstance(item, (Path, str)):\n", - " item = Image.open(item)\n", - " width, _ = item.size\n", - " max_col_width = max(max_col_width, width)\n", - " if max_col_width > 0:\n", - " max_widths.append(\n", - " f\"{min(max_col_width, max_image_width)}px\"\n", - " if max_image_width is not None else \n", - " f\"{max_col_width}px\"\n", - " )\n", - " else:\n", - " max_widths.append('auto')\n", - "\n", - " html_str = \"\"\n", - "\n", - " # Apply calculated column widths using and elements\n", - " html_str += \"\"\n", - " for width in max_widths:\n", - " html_str += f\"\"\n", - " html_str += \"\"\n", - "\n", - " if headers:\n", - " if len(headers) != len(columns):\n", - " raise ValueError(\"Headers list must match the number of columns.\")\n", - " html_str += (\n", - " \"\"\n", - " + \"\".join(\n", - " f\"\"\n", - " for header in headers\n", - " )\n", - " + \"\"\n", - " )\n", - "\n", - " for row_items in zip(*columns):\n", - " html_str += \"\"\n", - " for i, item in enumerate(row_items):\n", - " if isinstance(item, (Image.Image, Path)):\n", - " img_html = get_image_html(item, max_width=max_image_width)\n", - " html_str += f\"\"\n", - " else: # Assume the item is a string\n", - " style = \"font-weight: bold;\" if i == 0 else \"\"\n", - " html_str += f\"\"\n", - " html_str += \"\"\n", - "\n", - " html_str += \"
{header}
{img_html}{item}
\"\n", - " return html_str\n", - "\n", - "\n", - "def display_columns(\n", - " columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None\n", - "):\n", - " \"\"\"\n", - " Displays a table with any combination of columns, which can be lists of strings or lists \n", - " of PIL Image objects, within a Jupyter notebook cell.\n", - "\n", - " :param columns: A list of lists, where each sublist represents a column in the table. \n", - " Each sublist can contain either strings or PIL Image objects.\n", - " :param max_image_width: The maximum size of the images in pixels. This controls the max-height \n", - " of the images.\n", - " :param headers: A list of header labels for the table. If None, no headers are displayed.\n", - " \"\"\"\n", - " return display(HTML(get_columns_html(columns, max_image_width, headers)))\n", - "\n", - "\n", - "def get_image_grid_html(\n", - " images: list[Image.Image | Path | str],\n", - " rows: int,\n", - " columns: int,\n", - " titles: list[str] | None = None,\n", - " max_image_width: int | None = None,\n", - " caption: str | None = None\n", - "):\n", - " if titles and len(titles) != len(images):\n", - " raise ValueError(\"Titles list must match the number of images if provided.\")\n", - "\n", - " html_str = \"\"\n", - "\n", - " if caption:\n", - " html_str += (f\"\")\n", - "\n", - " image_index = 0\n", - " for row in range(rows):\n", - " html_str += \"\"\n", - " for col in range(columns):\n", - " if image_index < len(images):\n", - " img_html = get_image_html(images[image_index], max_width=max_image_width)\n", - " title_html = (\n", - " f\"
{titles[image_index]}
\"\n", - " if titles\n", - " else \"\"\n", - " )\n", - " html_str += f\"\"\n", - " else:\n", - " html_str += \"\" # Empty cell if no more images\n", - " image_index += 1\n", - " html_str += \"\"\n", - "\n", - " html_str += \"
{caption}
{title_html}{img_html}
\"\n", - " return html_str\n", - "\n", - "\n", - "def display_image_grid(\n", - " images: list[Image.Image | Path | str],\n", - " rows: int,\n", - " columns: int,\n", - " titles: list[str] | None = None,\n", - " max_image_width: int | None = None,\n", - " caption: str | None = None,\n", - "):\n", - " \"\"\"\n", - " Displays a grid of images in a HTML table within a Jupyter notebook cell.\n", - "\n", - " :param images: A list of PIL Image objects to be displayed.\n", - " :param rows: The number of rows in the grid.\n", - " :param columns: The number of columns in the grid.\n", - " :param titles: An optional list of titles for each image. If provided, it must match the length \n", - " of the images list.\n", - " :param max_image_width: The maximum width of the images in pixels.\n", - " \"\"\"\n", - " display(HTML(get_image_grid_html(images, rows, columns, titles, max_image_width, caption)))\n", - "\n", - "\n", - "def acc_as_html(acc):\n", - " return f\"
{acc:.2f}
\"\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## UUIDs" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def strip_uuid(p: Path | str):\n", - " _p: Path = p if isinstance(p, Path) else Path(p)\n", - " new_stem = re.sub(r'(?i)[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}', '', _p.stem).strip('_')\n", - " return _p.with_stem(new_stem)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Path('a/b/c/Strange Tales 172_boxes.png')" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "strip_uuid(Path(\"a/b/c/ac265dc1-51a0-46ca-9101-7195cbad33f2_Strange Tales 172_boxes.png\"))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Other" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "# Deep copy a defaultdict of defaultdicts to a dict of dicts if it is not already a dict\n", - "def defaultdict_to_dict(d) -> dict:\n", - " if not isinstance(d, defaultdict):\n", - " return d\n", - " return {k: defaultdict_to_dict(v) for k, v in d.items()}\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "aaa\n" - ] - } - ], - "source": [ - "print('aaa')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Colophon\n", - "----\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "import fastcore.all as FC\n", - "from nbdev.export import nb_export\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], - "source": [ - "if FC.IN_NOTEBOOK:\n", - " nb_export('helpers.ipynb', '.')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/_testbed/helpers.py b/_testbed/helpers.py deleted file mode 100644 index a7095701..00000000 --- a/_testbed/helpers.py +++ /dev/null @@ -1,372 +0,0 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: helpers.ipynb. - -# %% helpers.ipynb 7 -from __future__ import annotations - -import base64 -import json -import re -import sys -import uuid -from importlib import resources -from io import BytesIO -from pathlib import Path -from typing import Any -from typing import Iterable -from typing import Mapping -from typing import Sequence - -import pcleaner.data -import pcleaner.structures as st -from IPython.display import clear_output -from IPython.display import display -from IPython.display import HTML -from PIL import Image -from PIL import ImageDraw -from PIL import ImageFont - - -# %% auto 0 -__all__ = ['PRINT_FORMATS', 'cleanupwidgets', 'RenderJSON', 'page_boxes', 'crop_box', 'size', 'dpi', 'get_image_html', - 'get_columns_html', 'display_columns', 'get_image_grid_html', 'display_image_grid', 'acc_as_html', - 'strip_uuid', '_pops_', '_pops_values_', '_gets_'] - -# %% helpers.ipynb 13 -_all_ = ['_pops_', '_pops_values_', '_gets_'] - - -# %% helpers.ipynb 14 -def _pops_(d: dict, ks: Iterable) -> dict: - "Pops `ks` keys from `d` and returns them in a dict. Note: `d` is changed in-place." - return {k:d.pop(k) for k in ks if k in d} - - -# %% helpers.ipynb 16 -def _pops_values_(d: dict, ks: Iterable) -> tuple: - "Pops `ks` keys from `d` and returns them as a tuple. Note: `d` is changed in-place." - return tuple(d.pop(k, None) for k in ks) - - -# %% helpers.ipynb 18 -def _gets_(d: Mapping[str, Any], ks: Iterable): - "Fetches values from a mapping for a given list of keys, returning `None` for missing keys." - return (d.get(k, None) for k in ks) - - -# %% helpers.ipynb 21 -def _get_globals(mod: str): - if hasattr(sys, '_getframe'): - glb = sys._getframe(2).f_globals - else: - glb = sys.modules[mod].__dict__ - return glb - - -# %% helpers.ipynb 23 -def cleanupwidgets(*ws, mod: str|None=None, clear=True): - glb = _get_globals(mod or __name__) - if clear: clear_output(wait=True) - for w in ws: - _w = glb.get(w) if isinstance(w, str) else w - if _w: - try: _w.close() # type: ignore - except: pass - - -# %% helpers.ipynb 26 -class RenderJSON(object): - def __init__(self, json_data, max_height=200, init_level=0): - if isinstance(json_data, (Sequence, Mapping)): - s = json.dumps(json_data) - elif hasattr(json_data, 'to_dict'): - s = json.dumps(json_data.to_dict()) - elif hasattr(json_data, 'to_json'): - s = json_data.to_json() - else: - s = json_data - self.json_str = s - self.uuid = str(uuid.uuid4()) - self.max_height = max_height - self.init_level = init_level - - def display(self): - html_content = f""" -
-
- -
- """ - display(HTML(html_content)) - - def _ipython_display_(self): - self.display() - -# %% helpers.ipynb 29 -def page_boxes(self: st.PageData, out_dir: Path | None = None) -> tuple[Image.Image, Path]: - """ - Visualize the boxes on an image. - Typically, this would be used to check where on the original image the - boxes are located. - - :param image_path: The path to the image to visualize the boxes on. - """ - image_path = Path(self.image_path) - image = Image.open(image_path) - draw = ImageDraw.Draw(image) - data_path = resources.files(pcleaner.data) - font_path = str(data_path / "LiberationSans-Regular.ttf") - # Figure out the optimal font size based on the image size. E.g. 30 for a 1600px image. - font_size = int(image.size[0] / 50) + 5 - - for index, box in enumerate(self.boxes): - draw.rectangle(box.as_tuple, outline="green") - # Draw the box number, with a white background, respecting font size. - draw.text( - (box.x1 + 4, box.y1), - str(index + 1), - fill="green", - font=ImageFont.truetype(font_path, font_size), - stroke_fill="white", - stroke_width=3, - ) - - for box in self.extended_boxes: - draw.rectangle(box.as_tuple, outline="red") - for box in self.merged_extended_boxes: - draw.rectangle(box.as_tuple, outline="purple") - for box in self.reference_boxes: - draw.rectangle(box.as_tuple, outline="blue") - - # Save the image. - extension = "_boxes" - out_path = image_path.with_stem(image_path.stem + extension) - if out_dir is not None: - out_dir.mkdir(parents=True, exist_ok=True) - out_path = out_dir / image_path.name - image.save(out_path) - - return image, out_path - -# %% helpers.ipynb 31 -def crop_box(box: st.Box, image: Image.Image) -> Image.Image: - return image.crop(box.as_tuple) - -# %% helpers.ipynb 33 -PRINT_FORMATS = { - 'Golden Age': (7.75, 10.5), # (1930s-40s) - 'Siver Age': (7, 10.375), # (1950s-60s) - 'Modern Age': (6.625,10.25), # North American comic books - 'Magazine': (8.5, 11), - 'Digest': (5.5, 8.5), - 'Manga': (5.0, 7.5), -} - - -def size(w: int, h: int, unit: str = 'in', dpi: float = 300.) -> tuple: - """ - Calculate the print size of an image in inches or centimeters. - - Args: - w (int): Width of the image in pixels. - h (int): Height of the image in pixels. - unit (str): Unit of measurement ('in' for inches, 'cm' for centimeters). - dpi (float): Dots per inch (resolution). - - Returns: - tuple: Width and height of the image in the specified unit. - """ - if unit == 'cm': - return (w / dpi * 2.54, h / dpi * 2.54) - else: # default to inches - return (w / dpi, h / dpi) - - -def dpi(w: int, h: int, print_format: str = 'Modern Age') -> float: - """ - Calculate the dpi (dots per inch) needed to print an image at a specified format size. - - Args: - w (int): Width of the image in pixels. - h (int): Height of the image in pixels. - print_format (str): Print format as defined in the formats dictionary. - - Returns: - float: Required dpi to achieve the desired print format size. - """ - # Default to 'Modern Age' if format not found - format_size = PRINT_FORMATS.get(print_format, PRINT_FORMATS['Modern Age']) - width_inch, height_inch = format_size - dpi_w = w / width_inch - dpi_h = h / height_inch - return (dpi_w + dpi_h) / 2 # Average dpi for width and height - - -# %% helpers.ipynb 35 -def get_image_html(image: Image.Image | Path | str, max_width: int | None = None): - """ - Converts a PIL image to an HTML image tag containing the image as a base64 blob. - - :param image: A PIL Image object. - :param max_size: A PIL Image object. - :return: A string containing an HTML tag with the image. - """ - style = f' style="max-width: {max_width}px;"' if max_width is not None else '' - if isinstance(image, (Path, str)): - return f'' - else: - buffered = BytesIO() - image.save(buffered, format='PNG') - img_str = base64.b64encode(buffered.getvalue()).decode() - return f'' - - -def get_columns_html( - columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None -): - if not all(len(col) == len(columns[0]) for col in columns): - raise ValueError("All columns must have the same length.") - - # Calculate the maximum width of images in each column - max_widths = [] - for col_index in range(len(columns)): - max_col_width = 0 - for item in columns[col_index]: - if isinstance(item, (Image.Image, Path)): - if isinstance(item, (Path, str)): - item = Image.open(item) - width, _ = item.size - max_col_width = max(max_col_width, width) - if max_col_width > 0: - max_widths.append( - f"{min(max_col_width, max_image_width)}px" - if max_image_width is not None else - f"{max_col_width}px" - ) - else: - max_widths.append('auto') - - html_str = "" - - # Apply calculated column widths using and elements - html_str += "" - for width in max_widths: - html_str += f"" - html_str += "" - - if headers: - if len(headers) != len(columns): - raise ValueError("Headers list must match the number of columns.") - html_str += ( - "" - + "".join( - f"" - for header in headers - ) - + "" - ) - - for row_items in zip(*columns): - html_str += "" - for i, item in enumerate(row_items): - if isinstance(item, (Image.Image, Path)): - img_html = get_image_html(item, max_width=max_image_width) - html_str += f"" - else: # Assume the item is a string - style = "font-weight: bold;" if i == 0 else "" - html_str += f"" - html_str += "" - - html_str += "
{header}
{img_html}{item}
" - return html_str - - -def display_columns( - columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None -): - """ - Displays a table with any combination of columns, which can be lists of strings or lists - of PIL Image objects, within a Jupyter notebook cell. - - :param columns: A list of lists, where each sublist represents a column in the table. - Each sublist can contain either strings or PIL Image objects. - :param max_image_width: The maximum size of the images in pixels. This controls the max-height - of the images. - :param headers: A list of header labels for the table. If None, no headers are displayed. - """ - return display(HTML(get_columns_html(columns, max_image_width, headers))) - - -def get_image_grid_html( - images: list[Image.Image | Path | str], - rows: int, - columns: int, - titles: list[str] | None = None, - max_image_width: int | None = None, - caption: str | None = None -): - if titles and len(titles) != len(images): - raise ValueError("Titles list must match the number of images if provided.") - - html_str = "" - - if caption: - html_str += (f"") - - image_index = 0 - for row in range(rows): - html_str += "" - for col in range(columns): - if image_index < len(images): - img_html = get_image_html(images[image_index], max_width=max_image_width) - title_html = ( - f"
{titles[image_index]}
" - if titles - else "" - ) - html_str += f"" - else: - html_str += "" # Empty cell if no more images - image_index += 1 - html_str += "" - - html_str += "
{caption}
{title_html}{img_html}
" - return html_str - - -def display_image_grid( - images: list[Image.Image | Path | str], - rows: int, - columns: int, - titles: list[str] | None = None, - max_image_width: int | None = None, - caption: str | None = None, -): - """ - Displays a grid of images in a HTML table within a Jupyter notebook cell. - - :param images: A list of PIL Image objects to be displayed. - :param rows: The number of rows in the grid. - :param columns: The number of columns in the grid. - :param titles: An optional list of titles for each image. If provided, it must match the length - of the images list. - :param max_image_width: The maximum width of the images in pixels. - """ - display(HTML(get_image_grid_html(images, rows, columns, titles, max_image_width, caption))) - - -def acc_as_html(acc): - return f"
{acc:.2f}
" - - -# %% helpers.ipynb 37 -def strip_uuid(p: Path | str): - _p: Path = p if isinstance(p, Path) else Path(p) - new_stem = re.sub(r'(?i)[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}', '', _p.stem).strip('_') - return _p.with_stem(new_stem) - diff --git a/_testbed/media/.gitkeep b/_testbed/media/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/_testbed/model/.gitkeep b/_testbed/model/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/_testbed/ocr_idefics.py b/_testbed/ocr_idefics.py deleted file mode 100644 index 67a50c42..00000000 --- a/_testbed/ocr_idefics.py +++ /dev/null @@ -1,184 +0,0 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: test_idefics.ipynb. - -# %% test_idefics.ipynb 12 -from __future__ import annotations - -import functools -from pathlib import Path - -import pcleaner.ocr.ocr as ocr -import torch -import transformers -from pcleaner.ocr.ocr_tesseract import TesseractOcr -from PIL import Image -from rich.console import Console -from transformers import AutoProcessor -from transformers import Idefics2ForConditionalGeneration -from transformers import PreTrainedModel - - -# %% auto 0 -__all__ = ['IdeficsOCR', 'IdeficsExperimentContext'] - -# %% test_idefics.ipynb 17 -console = Console(width=104, tab_size=4, force_jupyter=True) -cprint = console.print - - -# %% test_idefics.ipynb 20 -from experiments import * -from helpers import * -from ocr_metric import * - - -# %% test_idefics.ipynb 21 -def load_image(img_or_path) -> Image.Image: - if isinstance(img_or_path, (str, Path)): - return Image.open(img_or_path) - elif isinstance(img_or_path, Image.Image): - return img_or_path - else: - raise ValueError(f"img_or_path must be a path or PIL.Image, got: {type(img_or_path)}") - - -# %% test_idefics.ipynb 36 -processor = AutoProcessor.from_pretrained("HuggingFaceM4/idefics2-8b") - -# %% test_idefics.ipynb 37 -device = "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu" - -model = Idefics2ForConditionalGeneration.from_pretrained( - "HuggingFaceM4/idefics2-8b", - torch_dtype=torch.bfloat16, - _attn_implementation="flash_attention_2", - ).to(device) # type: ignore - - -# %% test_idefics.ipynb 39 -prompt_text_tmpl = ( - "Please perform optical character recognition (OCR) on this image, which displays " - "speech balloons from a comic book. The text is in {}. Extract the text and " - "format it as follows: transcribe in standard sentence case, avoid using all capital " - "letters. Provide the transcribed text clearly and double check the sentence is not all capital letters.") - -# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " -# f"speech balloons from a manga comic. The text is in {}. Extract the text and " -# "format it without newlines. Provide the transcribed text clearly.") - -# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " -# "speech balloons from a comic book. The text is in {}. Extract the text and " -# "format it as follows: transcribe in standard sentence case (avoid using all capital " -# "letters) and use asterisks to denote any words that appear in bold within the image. " -# "Provide the transcribed text clearly.") - -# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " -# "speech balloons from a comic book. The text is in {}. Extract the text and " -# "format it as follows: transcribe in standard sentence case, capitalized. Avoid using " -# "all capital letters. In comics, it is common to use two hyphens '--' to interrupt a sentence. " -# "Retain any hyphens as they appear in the original text. Provide the transcribed text " -# "clearly, ensuring it is capitalized where appropriate, including proper nouns.") - -prompt_text_tmpl = ( - "Please perform optical character recognition (OCR) on this image, which displays " - "speech balloons from a comic book. The text is in {}. Extract the text and " - "format it as follows: transcribe in standard sentence case, capitalized. Avoid using " - "all capital letters, but ensure it is capitalized where appropriate, including proper nouns. " - "Provide the transcribed text clearly. Double check the text is not all capital letters.") - -default_prompt_text_tmpl = prompt_text_tmpl - -# %% test_idefics.ipynb 41 -class IdeficsOCR: - prompt_text_tmpl: str = default_prompt_text_tmpl - - def __init__(self, - lang: str | None = None, - prompt_text_tmpl: str|None = None, - device: str | None = None - ): - self.lang = lang - self.prompt_text_tmpl = prompt_text_tmpl or self.prompt_text_tmpl - self.device = (device or - "mps" if torch.backends.mps.is_available() else "cuda" if torch.cuda.is_available() else "cpu") - - @staticmethod - def is_idefics_available() -> bool: - return True - - def _generation_args(self, image: Image.Image, resulting_messages: list[dict]): - prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True) - inputs = processor(text=prompt, images=[image], return_tensors="pt") - inputs = {k: v.to(self.device) for k, v in inputs.items()} - - max_new_tokens = 512 - repetition_penalty = 1.2 - decoding_strategy = "Greedy" - temperature = 0.4 - top_p = 0.8 - - generation_args = { - "max_new_tokens": max_new_tokens, - "repetition_penalty": repetition_penalty, - } - - assert decoding_strategy in [ - "Greedy", - "Top P Sampling", - ] - - if decoding_strategy == "Greedy": - generation_args["do_sample"] = False - elif decoding_strategy == "Top P Sampling": - generation_args["temperature"] = temperature - generation_args["do_sample"] = True - generation_args["top_p"] = top_p - - generation_args.update(inputs) - return prompt, generation_args - - def __call__( - self, - img_or_path: Image.Image | Path | str, - prompt_text: str | None = None, - lang: str | None = None, - config: str | None = None, - show_prompt: bool = False, - **kwargs, - ) -> str: - if not self.is_idefics_available(): - raise RuntimeError("Idefics is not installed or not found.") - resulting_messages = [ - { - "role": "user", - "content": [{"type": "image"}] + [ - {"type": "text", "text": prompt_text or self.prompt_text_tmpl.format(lang or self.lang)} - ] - } - ] - image = load_image(img_or_path) - prompt, generation_args = self._generation_args(image, resulting_messages) - generated_ids = model.generate(**generation_args) - generated_texts = processor.batch_decode( - generated_ids[:, generation_args["input_ids"].size(1):], skip_special_tokens=True) - if show_prompt: - cprint("INPUT:", prompt, "|OUTPUT:", generated_texts) - return generated_texts[0]#.strip('"') - - def postprocess_ocr(self, text): - return ' '.join(remove_multiple_whitespaces(text).splitlines()) - - -# %% test_idefics.ipynb 43 -class IdeficsExperimentContext(OCRExperimentContext): - @functools.lru_cache() - def mocr(self, ocr_model: str, lang: str): - if ocr_model == 'Idefics': - proc = IdeficsOCR(lang) - else: - engine = self.engines[ocr_model] - ocr_processor = ocr.get_ocr_processor(True, engine) - proc = ocr_processor[lang2pcleaner(lang)] - if isinstance(proc, TesseractOcr): - proc.lang = lang2tesseract(lang) - return proc - diff --git a/_testbed/ocr_metric.ipynb b/_testbed/ocr_metric.ipynb deleted file mode 100644 index 41f2fad4..00000000 --- a/_testbed/ocr_metric.ipynb +++ /dev/null @@ -1,276 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#| default_exp ocr_metric" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "# %reload_ext autoreload\n", - "# %autoreload 0\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# install (Colab)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# try: \n", - "# import fastcore as FC\n", - "# except ImportError: \n", - "# !pip install -q fastcore\n", - "# try:\n", - "# import rich\n", - "# except ImportError:\n", - "# !pip install -q rich\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Developing a metric for OCR of Comics/Manga texts\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prologue" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "from __future__ import annotations\n", - "\n", - "import difflib\n", - "import html\n", - "\n", - "from IPython.display import display\n", - "from IPython.display import HTML\n", - "from rich.console import Console\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import fastcore.all as FC\n", - "import fastcore.xtras # patch Path with some utils\n", - "import rich\n", - "from fastcore.test import * # type: ignore\n", - "from loguru import logger\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Helpers" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# pretty print by default\n", - "# %load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "console = Console(width=104, tab_size=4, force_jupyter=True)\n", - "cprint = console.print\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## OCR metric\n", - "> Some basic ways to compare OCR results" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "def get_text_diffs_html(str1, str2, ignore_align: bool = False):\n", - " matcher = difflib.SequenceMatcher(None, str1, str2)\n", - " html_str1, html_str2 = \"\", \"\"\n", - " _ch ='⎕' # ▿\n", - " ch = f'&#x{ord(_ch):x};'\n", - " span1_g = lambda l: f\"{ch*l}\" if l > 0 else \"\"\n", - " span1_r = lambda l: f\"{ch*l}\" if l > 0 else \"\"\n", - " span2 = lambda s: f\"{html.escape(s)}\" if s else \"\"\n", - "\n", - " for opcode in matcher.get_opcodes():\n", - " tag, i1, i2, j1, j2 = opcode\n", - " if tag == \"equal\":\n", - " html_str1 += html.escape(str1[i1:i2])\n", - " html_str2 += html.escape(str2[j1:j2])\n", - " elif tag == \"replace\":\n", - " max_span = max(i2 - i1, j2 - j1)\n", - " # str1_segment = str1[i1:i2].ljust(max_span)\n", - " html_str1 += html.escape(str1[i1:i2]) + span1_g(max_span - (i2 - i1))\n", - " html_str2 += span2(str2[j1:j2]) + (span1_r(max_span - (j2 - j1)) if not ignore_align else '')\n", - " elif tag == \"delete\":\n", - " deleted_segment = str1[i1:i2]\n", - " html_str1 += html.escape(deleted_segment)\n", - " if not ignore_align: html_str2 += span1_r(len(deleted_segment))\n", - " elif tag == \"insert\":\n", - " inserted_segment = str2[j1:j2].replace(\" \", _ch)\n", - " html_str1 += span1_g(len(inserted_segment))\n", - " html_str2 += span2(inserted_segment)\n", - " html_str1 = f\"
{html_str1}
\"\n", - " html_str2 = f\"
{html_str2}
\"\n", - " return html_str1, html_str2\n", - "\n", - "def display_text_diffs(str1, str2):\n", - " \"\"\"\n", - " Displays two strings one above the other, with differing characters highlighted in red in the \n", - " second string only, using difflib.SequenceMatcher to align the strings and ensure matching \n", - " sequences are vertically aligned.\n", - "\n", - " :param str1: The first string to compare.\n", - " :param str2: The second string to compare.\n", - " \"\"\"\n", - " html_str1, html_str2 = get_text_diffs_html(str1, str2)\n", - " display(HTML(f\"
{html_str1}
{html_str2}
\"))" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
This is an awesome_⎕⎕⎕ test string.This is an awesome_⎕⎕⎕ test string.This is an awesome_⎕⎕⎕ test string.This is an awesome_⎕⎕⎕ test string.

This was an a⎕⎕⎕⎕mazing test spring.This was an a⎕⎕⎕⎕mazing test spring.This was an a⎕⎕⎕⎕mazing test spring.This was an a⎕⎕⎕⎕mazing test spring.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "str1 = \"This is an awesome_ test string.\"*4\n", - "str2 = \"This was an amazing test▿ spring.\"*4\n", - "display_text_diffs(str1, str2)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
I was in a bad mood, and Curt sensed it immediately...

I was in a bad mood, and Curt sensed it immediately...
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "str1 = \"I was in a bad mood, and Curt sensed it immediately...\"\n", - "str2 = \"I was in a bad mood, and Curt sensed it immediately ...\"\n", - "display_text_diffs(str1, str2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Colophon\n", - "----\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import fastcore.all as FC\n", - "from nbdev.export import nb_export\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [], - "source": [ - "if FC.IN_NOTEBOOK:\n", - " nb_export('ocr_metric.ipynb', '.')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/_testbed/ocr_metric.py b/_testbed/ocr_metric.py deleted file mode 100644 index f81b9a5e..00000000 --- a/_testbed/ocr_metric.py +++ /dev/null @@ -1,64 +0,0 @@ -# AUTOGENERATED! DO NOT EDIT! File to edit: ocr_metric.ipynb. - -# %% ocr_metric.ipynb 6 -from __future__ import annotations - -import difflib -import html - -from IPython.display import display -from IPython.display import HTML -from rich.console import Console - - -# %% auto 0 -__all__ = ['get_text_diffs_html', 'display_text_diffs'] - -# %% ocr_metric.ipynb 10 -console = Console(width=104, tab_size=4, force_jupyter=True) -cprint = console.print - - -# %% ocr_metric.ipynb 12 -def get_text_diffs_html(str1, str2, ignore_align: bool = False): - matcher = difflib.SequenceMatcher(None, str1, str2) - html_str1, html_str2 = "", "" - _ch ='⎕' # ▿ - ch = f'&#x{ord(_ch):x};' - span1_g = lambda l: f"{ch*l}" if l > 0 else "" - span1_r = lambda l: f"{ch*l}" if l > 0 else "" - span2 = lambda s: f"{html.escape(s)}" if s else "" - - for opcode in matcher.get_opcodes(): - tag, i1, i2, j1, j2 = opcode - if tag == "equal": - html_str1 += html.escape(str1[i1:i2]) - html_str2 += html.escape(str2[j1:j2]) - elif tag == "replace": - max_span = max(i2 - i1, j2 - j1) - # str1_segment = str1[i1:i2].ljust(max_span) - html_str1 += html.escape(str1[i1:i2]) + span1_g(max_span - (i2 - i1)) - html_str2 += span2(str2[j1:j2]) + (span1_r(max_span - (j2 - j1)) if not ignore_align else '') - elif tag == "delete": - deleted_segment = str1[i1:i2] - html_str1 += html.escape(deleted_segment) - if not ignore_align: html_str2 += span1_r(len(deleted_segment)) - elif tag == "insert": - inserted_segment = str2[j1:j2].replace(" ", _ch) - html_str1 += span1_g(len(inserted_segment)) - html_str2 += span2(inserted_segment) - html_str1 = f"
{html_str1}
" - html_str2 = f"
{html_str2}
" - return html_str1, html_str2 - -def display_text_diffs(str1, str2): - """ - Displays two strings one above the other, with differing characters highlighted in red in the - second string only, using difflib.SequenceMatcher to align the strings and ensure matching - sequences are vertically aligned. - - :param str1: The first string to compare. - :param str2: The second string to compare. - """ - html_str1, html_str2 = get_text_diffs_html(str1, str2) - display(HTML(f"
{html_str1}
{html_str2}
")) diff --git a/_testbed/requirements.txt b/_testbed/requirements.txt deleted file mode 100644 index 4e3d1c68..00000000 --- a/_testbed/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -matplotlib -rich -fastcore -nbdev -ipywidgets diff --git a/_testbed/test_idefics.ipynb b/_testbed/test_idefics.ipynb deleted file mode 100644 index a8978d12..00000000 --- a/_testbed/test_idefics.ipynb +++ /dev/null @@ -1,1497 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "#| default_exp ocr_idefics" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "#| hide\n", - "# %reload_ext autoreload\n", - "# %autoreload 0\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# install (Colab)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# try: \n", - "# import fastcore as FC\n", - "# except ImportError: \n", - "# !pip install -q fastcore\n", - "# try:\n", - "# import rich\n", - "# except ImportError:\n", - "# !pip install -q rich\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@basic-tesseract" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "need version >4.40 of transformers" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# %pip install git+https://github.com/huggingface/transformers" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Fash attention doesn't support Metal [#412](https://github.com/Dao-AILab/flash-attention/issues/412) (but see [metal-flash-attention](https://github.com/philipturner/metal-flash-attention))\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# %env FLASH_ATTENTION_SKIP_CUDA_BUILD=TRUE\n", - "# %pip install flash-attn --no-build-isolation" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "notebookRunGroups": { - "groupValue": "" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Fri May 10 18:32:10 2024 \n", - "+---------------------------------------------------------------------------------------+\n", - "| NVIDIA-SMI 535.161.08 Driver Version: 535.161.08 CUDA Version: 12.2 |\n", - "|-----------------------------------------+----------------------+----------------------+\n", - "| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |\n", - "| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |\n", - "| | | MIG M. |\n", - "|=========================================+======================+======================|\n", - "| 0 NVIDIA GeForce RTX 3090 Ti On | 00000000:65:00.0 Off | Off |\n", - "| 0% 50C P8 33W / 480W | 1MiB / 24564MiB | 0% Default |\n", - "| | | N/A |\n", - "+-----------------------------------------+----------------------+----------------------+\n", - " \n", - "+---------------------------------------------------------------------------------------+\n", - "| Processes: |\n", - "| GPU GI CI PID Type Process name GPU Memory |\n", - "| ID ID Usage |\n", - "|=======================================================================================|\n", - "| No running processes found |\n", - "+---------------------------------------------------------------------------------------+\n" - ] - } - ], - "source": [ - "!nvidia-smi" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Testing `Idefics` OCR for Comics\n", - "> Accuracy Enhancements for OCR in `PanelCleaner`\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prologue" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "from __future__ import annotations\n", - "\n", - "import functools\n", - "from pathlib import Path\n", - "\n", - "import pcleaner.ocr.ocr as ocr\n", - "import torch\n", - "import transformers\n", - "from pcleaner.ocr.ocr_tesseract import TesseractOcr\n", - "from PIL import Image\n", - "from rich.console import Console\n", - "from transformers import AutoProcessor\n", - "from transformers import Idefics2ForConditionalGeneration\n", - "from transformers import PreTrainedModel\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "from typing import cast\n", - "\n", - "import fastcore.xtras # patch Path with some utils\n", - "import pcleaner.config as cfg\n", - "from fastcore.test import * # type: ignore\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "notebookRunGroups": { - "groupValue": "" - } - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'4.41.0.dev0'" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "transformers.__version__" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Helpers" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "notebookRunGroups": { - "groupValue": "" - } - }, - "outputs": [], - "source": [ - "# pretty print by default\n", - "# %load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "notebookRunGroups": { - "groupValue": "" - } - }, - "outputs": [], - "source": [ - "#| exporti\n", - "\n", - "console = Console(width=104, tab_size=4, force_jupyter=True)\n", - "cprint = console.print\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Force reload of `experiments` module" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [], - "source": [ - "if 'experiments' in sys.modules:\n", - " import importlib; importlib.reload(experiments) # type: ignore\n", - "else:\n", - " import experiments\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "from experiments import *\n", - "from helpers import *\n", - "from ocr_metric import *\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "\n", - "def load_image(img_or_path) -> Image.Image:\n", - " if isinstance(img_or_path, (str, Path)):\n", - " return Image.open(img_or_path)\n", - " elif isinstance(img_or_path, Image.Image):\n", - " return img_or_path\n", - " else:\n", - " raise ValueError(f\"img_or_path must be a path or PIL.Image, got: {type(img_or_path)}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "# Idefics basic usage\n", - "\n", - "not working, cuda memory error" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# # Note that passing the image urls (instead of the actual pil images) to the processor is also possible\n", - "# # image1 = load_image(\"https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg\")\n", - "# # image2 = load_image(\"https://cdn.britannica.com/59/94459-050-DBA42467/Skyline-Chicago.jpg\")\n", - "# # image3 = load_image(\"https://cdn.britannica.com/68/170868-050-8DDE8263/Golden-Gate-Bridge-San-Francisco.jpg\")\n", - "\n", - "# image1 = Image.open(\"media/Statue-of-Liberty-Island-New-York-Bay.webp\")\n", - "# image2 = Image.open(\"media/Skyline-Chicago.webp\")\n", - "# image3 = Image.open(\"media/Golden-Gate-Bridge-San-Francisco.webp\")" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# processor = AutoProcessor.from_pretrained(\"HuggingFaceM4/idefics2-8b\")" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "# model = Idefics2ForConditionalGeneration.from_pretrained(\n", - "# \"HuggingFaceM4/idefics2-8b\",\n", - "# torch_dtype=torch.bfloat16,\n", - "# #_attn_implementation=\"flash_attention_2\",\n", - "# )\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "# assert isinstance(model, PreTrainedModel)\n", - "# model.to(DEVICE)\n", - "# type(model), model.device\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create inputs" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], - "source": [ - "# messages = [\n", - "# {\n", - "# \"role\": \"user\",\n", - "# \"content\": [\n", - "# {\"type\": \"image\"},\n", - "# {\"type\": \"text\", \"text\": \"What do we see in this image?\"},\n", - "# ]\n", - "# },\n", - "# {\n", - "# \"role\": \"assistant\",\n", - "# \"content\": [\n", - "# {\"type\": \"text\", \"text\": \"In this image, we can see the city of New York, and more specifically the Statue of Liberty.\"},\n", - "# ]\n", - "# },\n", - "# {\n", - "# \"role\": \"user\",\n", - "# \"content\": [\n", - "# {\"type\": \"image\"},\n", - "# {\"type\": \"text\", \"text\": \"And how about this image?\"},\n", - "# ]\n", - "# }, \n", - "# ]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "# prompt = processor.apply_chat_template(messages, add_generation_prompt=True)\n", - "# inputs = processor(text=prompt, images=[image1, image2], return_tensors=\"pt\")\n", - "# inputs = {k: v.to(DEVICE) for k, v in inputs.items()}\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Generate" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], - "source": [ - "# generated_ids = model.generate(**inputs, max_new_tokens=500)\n", - "# generated_texts = processor.batch_decode(generated_ids, skip_special_tokens=True)\n", - "\n", - "# print(generated_texts)\n", - "# # ['User: What do we see in this image? \\nAssistant: In this image, we can see the city of New York, and more specifically the Statue of Liberty. \\nUser: And how about this image? \\nAssistant: In this image we can see buildings, trees, lights, water and sky.']\n" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [], - "source": [ - "# [\n", - "# 'User: What do we see in this image? '\n", - "# 'Assistant: In this image, we can see the city of New York, and more specifically the Statue of Liberty. '\n", - "# 'User: And how about this image? '\n", - "# 'Assistant: In this image we can see buildings, trees, lights, water and sky.'\n", - "# ]" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "# Idefics experiments\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Idefics" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Idefics initialization" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n" - ] - } - ], - "source": [ - "#| exporti\n", - "\n", - "processor = AutoProcessor.from_pretrained(\"HuggingFaceM4/idefics2-8b\")" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "You are attempting to use Flash Attention 2.0 with a model not initialized on GPU. Make sure to move the model to GPU after initializing it on CPU with `model.to('cuda')`.\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "5a21b61268674a159f210694841c2149", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Loading checkpoint shards: 0%| | 0/7 [00:00 bool:\n", - " return True\n", - "\n", - " def _generation_args(self, image: Image.Image, resulting_messages: list[dict]):\n", - " prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True)\n", - " inputs = processor(text=prompt, images=[image], return_tensors=\"pt\")\n", - " inputs = {k: v.to(self.device) for k, v in inputs.items()}\n", - " \n", - " max_new_tokens = 512\n", - " repetition_penalty = 1.2\n", - " decoding_strategy = \"Greedy\"\n", - " temperature = 0.4\n", - " top_p = 0.8\n", - "\n", - " generation_args = {\n", - " \"max_new_tokens\": max_new_tokens,\n", - " \"repetition_penalty\": repetition_penalty,\n", - " }\n", - "\n", - " assert decoding_strategy in [\n", - " \"Greedy\",\n", - " \"Top P Sampling\",\n", - " ]\n", - "\n", - " if decoding_strategy == \"Greedy\":\n", - " generation_args[\"do_sample\"] = False\n", - " elif decoding_strategy == \"Top P Sampling\":\n", - " generation_args[\"temperature\"] = temperature\n", - " generation_args[\"do_sample\"] = True\n", - " generation_args[\"top_p\"] = top_p\n", - "\n", - " generation_args.update(inputs)\n", - " return prompt, generation_args\n", - "\n", - " def __call__(\n", - " self,\n", - " img_or_path: Image.Image | Path | str,\n", - " prompt_text: str | None = None,\n", - " lang: str | None = None,\n", - " config: str | None = None,\n", - " show_prompt: bool = False,\n", - " **kwargs,\n", - " ) -> str:\n", - " if not self.is_idefics_available():\n", - " raise RuntimeError(\"Idefics is not installed or not found.\")\n", - " resulting_messages = [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": [{\"type\": \"image\"}] + [\n", - " {\"type\": \"text\", \"text\": prompt_text or self.prompt_text_tmpl.format(lang or self.lang)}\n", - " ]\n", - " }\n", - " ]\n", - " image = load_image(img_or_path)\n", - " prompt, generation_args = self._generation_args(image, resulting_messages)\n", - " generated_ids = model.generate(**generation_args)\n", - " generated_texts = processor.batch_decode(\n", - " generated_ids[:, generation_args[\"input_ids\"].size(1):], skip_special_tokens=True)\n", - " if show_prompt:\n", - " cprint(\"INPUT:\", prompt, \"|OUTPUT:\", generated_texts)\n", - " return generated_texts[0]#.strip('\"')\n", - "\n", - " def postprocess_ocr(self, text):\n", - " return ' '.join(remove_multiple_whitespaces(text).splitlines())\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## IdeficsExperimentContext" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "#| export\n", - "\n", - "class IdeficsExperimentContext(OCRExperimentContext):\n", - " @functools.lru_cache()\n", - " def mocr(self, ocr_model: str, lang: str):\n", - " if ocr_model == 'Idefics':\n", - " proc = IdeficsOCR(lang)\n", - " else:\n", - " engine = self.engines[ocr_model]\n", - " ocr_processor = ocr.get_ocr_processor(True, engine)\n", - " proc = ocr_processor[lang2pcleaner(lang)]\n", - " if isinstance(proc, TesseractOcr):\n", - " proc.lang = lang2tesseract(lang)\n", - " return proc\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# PanelCleaner Configuration\n", - "> Adapt `PanelCleaner` `Config` current config to this notebook.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], - "source": [ - "config = cfg.load_config()\n", - "config.cache_dir = Path(\".\")\n", - "\n", - "cache_dir = config.get_cleaner_cache_dir()\n", - "\n", - "profile = config.current_profile\n", - "preprocessor_conf = profile.preprocessor\n", - "# Modify the profile to OCR all boxes.\n", - "# Make sure OCR is enabled.\n", - "preprocessor_conf.ocr_enabled = True\n", - "# Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", - "preprocessor_conf.ocr_max_size = 10**10\n", - "# Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", - "preprocessor_conf.suspicious_box_min_size = 10**10\n", - "# Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", - "preprocessor_conf.ocr_blacklist_pattern = \".*\"\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Test images\n", - "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods." - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['00: Action_Comics_1960-01-00_(262).JPG',\n", - " '01: Adolf_Cap_01_008.jpg',\n", - " '02: Barnaby_v1-028.png',\n", - " '03: Barnaby_v1-029.png',\n", - " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", - " '05: Cannon-292.jpg',\n", - " '06: Contrato_con_Dios_028.jpg',\n", - " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", - " '08: FOX_CHILLINTALES_T17_012.jpg',\n", - " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", - " '10: Galactus_12.jpg',\n", - " '11: INOUE_KYOUMEN_002.png',\n", - " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", - " '13: MCCAY_LITTLENEMO_090.jpg',\n", - " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", - " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", - " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", - " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", - " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", - " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", - " '20: Strange_Tales_172005.jpg',\n", - " '21: Strange_Tales_172021.jpg',\n", - " '22: Tarzan_014-21.JPG',\n", - " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", - " '24: Transformers_-_Unicron_000-004.jpg',\n", - " '25: Transformers_-_Unicron_000-016.jpg',\n", - " '26: WARE_ACME_024.jpg',\n", - " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", - " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", - " '29: manga_0033.jpg',\n", - " '30: ronson-031.jpg',\n", - " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "media_path = Path(\"media/\")\n", - "\n", - "IMAGE_PATHS = sorted(\n", - " [_ for _ in media_path.glob(\"*\") if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n", - "\n", - "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# CONTEXT\n" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current Configuration:\n", - "\n", - "Locale: System default\n", - "Default Profile: Built-in\n", - "Saved Profiles:\n", - "- victess: /home/vic/dev/repo/DL-mac/cleaned/victess.conf\n", - "- victmang: /home/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", - "\n", - "Profile Editor: System default\n", - "Cache Directory: .\n", - "Default Torch Model Path: /home/vic/.cache/pcleaner/model/comictextdetector.pt\n", - "Default CV2 Model Path: /home/vic/.cache/pcleaner/model/comictextdetector.pt.onnx\n", - "GUI Theme: System default\n", - "\n", - "--------------------\n", - "\n", - "Config file located at: /home/vic/.config/pcleaner/pcleanerrc\n", - "System default cache directory: /home/vic/.cache/pcleaner\n" - ] - }, - { - "data": { - "text/html": [ - "
      cache_dir: Path('cleaner')\n",
-       "     model_path: Path('/home/vic/.cache/pcleaner/model/comictextdetector.pt')\n",
-       "         device: 'cuda'\n",
-       "
\n" - ], - "text/plain": [ - " cache_dir: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'cleaner'\u001b[0m\u001b[1m)\u001b[0m\n", - " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/home/vic/.cache/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", - " device: \u001b[32m'cuda'\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "CONTEXT = IdeficsExperimentContext(None, IMAGE_PATHS)\n", - "\n", - "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", - "model_path = CONTEXT.config.get_model_path(gpu)\n", - "DEVICE = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n", - "\n", - "CONTEXT.config.show()\n", - "cprint(\n", - " f\"{'cache_dir':>15}: {repr(cache_dir)}\\n\"\n", - " f\"{'model_path':>15}: {repr(model_path)}\\n\"\n", - " f\"{'device':>15}: {repr(DEVICE)}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Base image\n", - "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", - "assert CONTEXT.path_from_idx(BASE_IMAGE_IDX).exists()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Visualize images\n" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "IMAGE_CONTEXT = ImageContext(CONTEXT, BASE_IMAGE_IDX)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "9c0379d4776a4e0f9facd7e0092c79f3", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output(layout=Layout(height='0px'))" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "5f0ae88943a14ea38efb029c40183ffd", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "26c6ecdbae6f4952aab7ff3106400f04", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "img_visor = ImageContextVisor(CONTEXT, BASE_IMAGE_IDX)\n", - "img_visor\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Box id\n", - "> change `BOX_IDX` to use any box to test crop methods" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "BOX_IDX = 0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Idefics inference" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, - "outputs": [], - "source": [ - "page_lang = IMAGE_CONTEXT.page_lang\n", - "\n", - "resulting_messages = [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": [{\"type\": \"image\"}] + [\n", - " {\"type\": \"text\", \"text\": prompt_text_tmpl.format(page_lang)}\n", - " ]\n", - " }\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [], - "source": [ - "def idefics_generation_args(image: Image.Image, resulting_messages: list[dict]):\n", - " prompt = processor.apply_chat_template(resulting_messages, add_generation_prompt=True)\n", - " inputs = processor(text=prompt, images=[image], return_tensors=\"pt\")\n", - " inputs = {k: v.to(DEVICE) for k, v in inputs.items()}\n", - " \n", - " max_new_tokens = 512\n", - " repetition_penalty = 1.2\n", - " decoding_strategy = \"Greedy\"\n", - " temperature = 0.4\n", - " top_p = 0.8\n", - "\n", - " generation_args = {\n", - " \"max_new_tokens\": max_new_tokens,\n", - " \"repetition_penalty\": repetition_penalty,\n", - " }\n", - "\n", - " assert decoding_strategy in [\n", - " \"Greedy\",\n", - " \"Top P Sampling\",\n", - " ]\n", - "\n", - " if decoding_strategy == \"Greedy\":\n", - " generation_args[\"do_sample\"] = False\n", - " elif decoding_strategy == \"Top P Sampling\":\n", - " generation_args[\"temperature\"] = temperature\n", - " generation_args[\"do_sample\"] = True\n", - " generation_args[\"top_p\"] = top_p\n", - "\n", - " generation_args.update(inputs)\n", - " return prompt, generation_args\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Crop methods" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], - "source": [ - "# image_experiment = ExperimentOCR(IMAGE_CONTEXT, 'Idefics')\n", - "image_experiment = ExperimentOCR.from_image(CONTEXT, 'Idefics', IMAGE_CONTEXT.image_idx) # use cache\n" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [], - "source": [ - "method = CropMethod.INITIAL_BOX\n", - "\n", - "result = cast(ResultOCR, image_experiment.result(BOX_IDX, method, ocr=False))\n", - "image = cast(Image.Image, result.image)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "No chat template is set for this tokenizer, falling back to a default class-level template. This is very error-prone, because models are often trained with templates different from the class default! Default chat templates are a legacy feature and will be removed in Transformers v4.43, at which point any code depending on them will stop working. We recommend setting a valid chat template before then to ensure that this model continues working without issues.\n", - "The `seen_tokens` attribute is deprecated and will be removed in v4.41. Use the `cache_position` model input instead.\n" - ] - }, - { - "data": { - "text/html": [ - "
INPUT: User:<image>Please perform optical character recognition (OCR) on this image, which displays \n",
-       "speech balloons from a comic book. The text is in English. Extract the text and format it as follows: \n",
-       "transcribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \n",
-       "capitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \n",
-       "check the text is not all capital letters.<end_of_utterance>\n",
-       "Assistant: |OUTPUT:\n",
-       "[\n",
-       "    'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \n",
-       "Orleans, kept tidy by a white-haired old man known only as Bambu.'\n",
-       "]\n",
-       "
\n" - ], - "text/plain": [ - "INPUT: User:\u001b[1m<\u001b[0m\u001b[1;95mimage\u001b[0m\u001b[39m>Please perform optical character recognition \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mOCR\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m on this image, which displays \u001b[0m\n", - "\u001b[39mspeech balloons from a comic book. The text is in English. Extract the text and format it as follows: \u001b[0m\n", - "\u001b[39mtranscribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \u001b[0m\n", - "\u001b[39mcapitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \u001b[0m\n", - "\u001b[39mcheck the text is not all capital letters.\u001b[0m\n", - "Assistant: |OUTPUT:\n", - "\u001b[1m[\u001b[0m\n", - " \u001b[32m'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \u001b[0m\n", - "\u001b[32mOrleans, kept tidy by a white-haired old man known only as Bambu.'\u001b[0m\n", - "\u001b[1m]\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "prompt, generation_args = idefics_generation_args(image, resulting_messages)\n", - "generated_ids = model.generate(**generation_args)\n", - "\n", - "generated_texts = processor.batch_decode(\n", - " generated_ids[:, generation_args[\"input_ids\"].size(1):], skip_special_tokens=True)\n", - "cprint(\"INPUT:\", prompt, \"|OUTPUT:\", generated_texts)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
1.00
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "result.ocr = generated_texts[0]\n", - "result\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
INPUT: User:<image>Please perform optical character recognition (OCR) on this image, which displays \n",
-       "speech balloons from a comic book. The text is in English. Extract the text and format it as follows: \n",
-       "transcribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \n",
-       "capitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \n",
-       "check the text is not all capital letters.<end_of_utterance>\n",
-       "Assistant: |OUTPUT:\n",
-       "[\n",
-       "    'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \n",
-       "Orleans, kept tidy by a white-haired old man known only as Bambu.'\n",
-       "]\n",
-       "
\n" - ], - "text/plain": [ - "INPUT: User:\u001b[1m<\u001b[0m\u001b[1;95mimage\u001b[0m\u001b[39m>Please perform optical character recognition \u001b[0m\u001b[1;39m(\u001b[0m\u001b[39mOCR\u001b[0m\u001b[1;39m)\u001b[0m\u001b[39m on this image, which displays \u001b[0m\n", - "\u001b[39mspeech balloons from a comic book. The text is in English. Extract the text and format it as follows: \u001b[0m\n", - "\u001b[39mtranscribe in standard sentence case, capitalized. Avoid using all capital letters, but ensure it is \u001b[0m\n", - "\u001b[39mcapitalized where appropriate, including proper nouns. Provide the transcribed text clearly. Double \u001b[0m\n", - "\u001b[39mcheck the text is not all capital letters.\u001b[0m\n", - "Assistant: |OUTPUT:\n", - "\u001b[1m[\u001b[0m\n", - " \u001b[32m'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \u001b[0m\n", - "\u001b[32mOrleans, kept tidy by a white-haired old man known only as Bambu.'\u001b[0m\n", - "\u001b[1m]\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
1.00
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "method = CropMethod.INITIAL_BOX\n", - "\n", - "result = cast(ResultOCR, image_experiment.result(BOX_IDX, method, ocr=False))\n", - "image = cast(Image.Image, result.image)\n", - "\n", - "mocr: IdeficsOCR = cast(IdeficsOCR, CONTEXT.mocr('Idefics', page_lang))\n", - "text = mocr(image, show_prompt=True)\n", - "result.ocr = mocr.postprocess_ocr(text)\n", - "result\n" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
0.98
\n", - "
\n", - "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PADDED_4)" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "
\n", - "
0.94
\n", - "
\n", - "
Embow⎕⎕ered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Encountered by great charles cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "image_experiment.result(BOX_IDX, CropMethod.PAD_8_FRACT_0_2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "# Visualize results" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "522220949ff540fdbd864dc8d8722cf0", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output(layout=Layout(height='0px'))" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "13a3ec1b0ea04630b339e5026e01eee2", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Label(value='Box # (of 15):', layout=Layout(padding='0px 0px 0px 10px', width='i…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "989b4acac70848f2a5da0a74f99bc181", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "result_visor = ResultVisor(image_experiment)\n", - "result_visor\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "# Visualize Experiment" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [], - "source": [ - "# p, d = image_experiment.to_json()" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "bae922f0f53b47b5909334ca7f5d24fc", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "9c8a0db76d0a40eb9c3451129e803124", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "exp_visor = ExperimentVisor(image_experiment)\n", - "exp_visor\n" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [], - "source": [ - "# p, d = exp_visor.ctx.to_json()\n", - "# p" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "# EEAaO" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d441a9415ca94481a85523a6d30eca92", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(HBox(children=(Dropdown(index=1, layout=Layout(width='fit-content'), options={'T…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4f568a40794a4cba951fb6652b5446dd", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "idefics_experiment = ExperimentsVisor(CONTEXT, BASE_IMAGE_IDX, \n", - " box_idx=13, method=CropMethod.DEFAULT_GREY_PAD,\n", - " ocr_model=OCRModel.IDEFICS, \n", - " ocr_models={'Tesseract': OCRModel.TESSERACT, 'Idefics': OCRModel.IDEFICS})\n", - "idefics_experiment\n" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [], - "source": [ - "idefics_experiment.update(model=OCRModel.TESSERACT)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Colophon\n", - "----\n" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [], - "source": [ - "import fastcore.all as FC\n", - "from nbdev.export import nb_export\n" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [], - "source": [ - "if FC.IN_NOTEBOOK:\n", - " nb_export('test_idefics.ipynb', '.')\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "panel-cleaner", - "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.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/_testbed/test_tesseract.ipynb b/_testbed/test_tesseract.ipynb deleted file mode 100644 index 3cb1dc79..00000000 --- a/_testbed/test_tesseract.ipynb +++ /dev/null @@ -1,638 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# install (Colab)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "# try: \n", - "# import fastcore as FC\n", - "# except ImportError: \n", - "# !pip install -q fastcore\n", - "# try:\n", - "# import rich\n", - "# except ImportError:\n", - "# !pip install -q rich\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Testing `Tesseract` OCR for Comics\n", - "> Accuracy Enhancements for OCR in `PanelCleaner`\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Prologue" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "from pathlib import Path\n", - "from typing import cast\n", - "\n", - "import pcleaner.config as cfg\n", - "import torch\n", - "from rich.console import Console\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "from experiments import *\n", - "from helpers import *\n", - "from ocr_metric import *\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "import fastcore.xtras # patch Path with some utils\n", - "from fastcore.test import * # type: ignore\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Helpers" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "# pretty print by default\n", - "# %load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "console = Console(width=104, tab_size=4, force_jupyter=True)\n", - "cprint = console.print\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tesseract installation" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['tesseract 5.3.4',\n", - " ' leptonica-1.84.1',\n", - " ' libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp 1.4.0 : libopenjp2 2.5.2',\n", - " ' Found NEON',\n", - " ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n", - " ' Found libcurl/8.4.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.11 nghttp2/1.51.0']" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "out = !tesseract --version\n", - "out\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Install jpn_vert tesserac lang\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```bash\n", - "cd model\n", - "sudo ln -s jpn_vert_tessdata_best.traineddata /usr/share/tesseract-ocr/5/tessdata/jpn_vert.traineddata\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(Path('/opt/homebrew/share/tessdata'),\n", - " ['afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n", - " 'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n", - " 'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n", - " 'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n", - " 'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n", - " 'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n", - " 'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n", - " 'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, script/Kannada, script/Khmer',\n", - " 'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n", - " 'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n", - " 'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'])" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "out = !tesseract --list-langs\n", - "tessdata = Path(out[0].split('\"')[1])\n", - "tessdata, [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
[\n",
-       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'),\n",
-       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'),\n",
-       "    Path('/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata')\n",
-       "]\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[1m[\u001b[0m\n", - " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/eng_tessdata_best_410.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_vert_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", - " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/dev/repo/DL-mac/PanelCleaner/_testbed/model/jpn_tessdata_best.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n", - "\u001b[1m]\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "langs = tessdata.ls()\n", - "cprint([p.resolve() for p in langs if 'eng' in p.name] + [p.resolve() for p in langs if 'jpn' in p.name])\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "----\n", - "# Tesseract experiments" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# PanelCleaner Configuration\n", - "> Adapt `PanelCleaner` `Config` current config to this notebook.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "config = cfg.load_config()\n", - "config.cache_dir = Path(\".\")\n", - "\n", - "cache_dir = config.get_cleaner_cache_dir()\n", - "\n", - "profile = config.current_profile\n", - "preprocessor_conf = profile.preprocessor\n", - "# Modify the profile to OCR all boxes.\n", - "# Make sure OCR is enabled.\n", - "preprocessor_conf.ocr_enabled = True\n", - "# Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", - "preprocessor_conf.ocr_max_size = 10**10\n", - "# Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", - "preprocessor_conf.suspicious_box_min_size = 10**10\n", - "# Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", - "preprocessor_conf.ocr_blacklist_pattern = \".*\"\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Test images\n", - "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['00: Action_Comics_1960-01-00_(262).JPG',\n", - " '01: Adolf_Cap_01_008.jpg',\n", - " '02: Barnaby_v1-028.png',\n", - " '03: Barnaby_v1-029.png',\n", - " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", - " '05: Cannon-292.jpg',\n", - " '06: Contrato_con_Dios_028.jpg',\n", - " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", - " '08: FOX_CHILLINTALES_T17_012.jpg',\n", - " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", - " '10: Galactus_12.jpg',\n", - " '11: INOUE_KYOUMEN_002.png',\n", - " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", - " '13: MCCAY_LITTLENEMO_090.jpg',\n", - " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", - " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", - " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", - " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", - " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", - " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", - " '20: Strange_Tales_172005.jpg',\n", - " '21: Strange_Tales_172021.jpg',\n", - " '22: Tarzan_014-21.JPG',\n", - " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", - " '24: Transformers_-_Unicron_000-004.jpg',\n", - " '25: Transformers_-_Unicron_000-016.jpg',\n", - " '26: WARE_ACME_024.jpg',\n", - " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", - " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", - " '29: manga_0033.jpg',\n", - " '30: ronson-031.jpg',\n", - " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "media_path = Path(\"media/\")\n", - "\n", - "IMAGE_PATHS = sorted(\n", - " [_ for _ in media_path.glob(\"*\") if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n", - "\n", - "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# CONTEXT\n", - "> `CONTEXT` is an `OCRExperimentContext` object that contains the configuration and the list of image paths.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can get the configuration with `OCRExperimentContext.get_config()`.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current Configuration:\n", - "\n", - "Locale: System default\n", - "Default Profile: Built-in\n", - "Saved Profiles:\n", - "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", - "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", - "\n", - "Profile Editor: cursor\n", - "Cache Directory: .\n", - "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", - "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", - "GUI Theme: System default\n", - "\n", - "--------------------\n", - "\n", - "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", - "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" - ] - }, - { - "data": { - "text/html": [ - "
      cache_dir: Path('cleaner')\n",
-       "     model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
-       "         device: 'mps'\n",
-       "
\n" - ], - "text/plain": [ - " cache_dir: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'cleaner'\u001b[0m\u001b[1m)\u001b[0m\n", - " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", - " device: \u001b[32m'mps'\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "CONTEXT = OCRExperimentContext(None, IMAGE_PATHS)\n", - "\n", - "gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", - "model_path = CONTEXT.config.get_model_path(gpu)\n", - "DEVICE = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n", - "\n", - "CONTEXT.config.show()\n", - "cprint(\n", - " f\"{'cache_dir':>15}: {repr(cache_dir)}\\n\"\n", - " f\"{'model_path':>15}: {repr(model_path)}\\n\"\n", - " f\"{'device':>15}: {repr(DEVICE)}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Base image\n", - "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", - "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"0033\")\n", - "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"INOUE_KYOUMEN_002\")\n", - "# BASE_IMAGE_IDX = CONTEXT.normalize_idx(\"Action_Comics_1960-01-00_(262)\")\n", - "\n", - "assert BASE_IMAGE_IDX is not None\n", - "img_path = Path(CONTEXT.image_paths[BASE_IMAGE_IDX])\n", - "assert img_path.exists()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Empty cache\n", - "> Clear the image cache used profusely throughout the examples below." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "You will be warned before the cache is emptied." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# CONTEXT.empty_cache_warn()" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "# CONTEXT.empty_cache_warn(BASE_IMAGE_IDX)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Base image\n", - "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", - "assert CONTEXT.path_from_idx(BASE_IMAGE_IDX).exists()\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Visualize images\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "3de3bd90585a452ab7bd9f5dce716e4e", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output(layout=Layout(height='0px'))" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6ab61afc65d84115b81c248ed1d0ab03", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(Dropdown(index=20, layout=Layout(width='fit-content'), options={'Action_Comics_1…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8c79a1393b5a4feaaa8c6d7cf2b458bc", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "img_visor = ImageContextVisor(CONTEXT, BASE_IMAGE_IDX)\n", - "img_visor\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Tesseract experiments\n" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d65bd435e6774637ac667defde594c4d", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HBox(children=(HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), options={'Tesseract'…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "f2ca36a4d81144d59ba835c40b990d34", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Output()" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# tesseract_experiment = ExperimentsVisor(CONTEXT)\n", - "tesseract_experiment = ExperimentsVisor(CONTEXT, BASE_IMAGE_IDX)\n", - "\n", - "test_eq(tesseract_experiment.all_values, {\n", - " 'image_selector': {'image_idx': 20},\n", - " 'content_selector': {'display_option': DisplayOptions.RESULTS},\n", - " 'result_visor': {\n", - " 'all_boxes': False,\n", - " 'box_idx': 0,\n", - " 'all_methods': False,\n", - " 'method': CropMethod.INITIAL_BOX,\n", - " },\n", - " 'model_selector': {'model': OCRModel.TESSERACT},\n", - " 'self': {}\n", - "})\n", - "\n", - "tesseract_experiment\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} From 0b14d8a84f93c1be3790bd75d267c6b84cae445a Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 24 May 2024 19:24:24 +0200 Subject: [PATCH 05/27] Colab requirements --- setup-cli-gui.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup-cli-gui.cfg b/setup-cli-gui.cfg index b5c4642b..c00ba3fa 100644 --- a/setup-cli-gui.cfg +++ b/setup-cli-gui.cfg @@ -20,7 +20,7 @@ install_requires = opencv-python transformers manga_ocr - Pillow + Pillow == 9.4.0 # Colab torch torchvision tqdm From a3e0a6e80d45815973ad34b017c773a71ea76c4f Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 24 May 2024 19:26:05 +0200 Subject: [PATCH 06/27] Downgrade to Python 10 as Colab not yet support 11 --- pcleaner/config.py | 19 ++++++++++++------- pcleaner/gui/profile_parser.py | 2 +- pcleaner/preprocessor.py | 12 ++++++------ pcleaner/structures.py | 4 ++-- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/pcleaner/config.py b/pcleaner/config.py index 1a3066f3..4d4add4d 100644 --- a/pcleaner/config.py +++ b/pcleaner/config.py @@ -72,13 +72,17 @@ Percentage = NewType("Percentage", float) -class ReadingOrder(StrEnum): +class EnumStr_(Enum): + @classmethod + def display_names(cls) -> dict[str, 'EnumStr_']: + return {e.value: e for e in cls} + +class ReadingOrder(EnumStr_): AUTO = "auto" MANGA = "manga" COMIC = "comic" - -class OCREngine(StrEnum): +class OCREngine(EnumStr_): AUTO = "auto" MANGAOCR = "manga-ocr" TESSERACT = "tesseract" @@ -1309,13 +1313,14 @@ def try_to_load( return # check before: `StrEnum` is a `str` - elif isinstance(attr_type, type) and issubclass(attr_type, StrEnum): - if conf_data in attr_type.__members__.values(): - attr_value = conf_data + elif isinstance(attr_type, type) and issubclass(attr_type, EnumStr_): + names = attr_type.display_names() + if conf_data in names: # type: ignore + attr_value = names[conf_data] else: print( f"Option {attr_name} in section {section} should be a one " - f"of {', '.join(repr(str(_)) for _ in attr_type.__members__.values())}.\n" + f"of {', '.join(_.value for _ in attr_type)}.\n" f"Failed to parse '{conf_data}'" ) return diff --git a/pcleaner/gui/profile_parser.py b/pcleaner/gui/profile_parser.py index 4af9d5bb..9aaa48e2 100644 --- a/pcleaner/gui/profile_parser.py +++ b/pcleaner/gui/profile_parser.py @@ -206,7 +206,7 @@ def _get_text() -> str | None: enm = {EntryTypes.OCREngine: OCREngine, EntryTypes.ReadingOrder: ReadingOrder}[ entry_type ] - for member in enm.__members__.values(): + for member in enm: self._data_widget.addTextItemLinkedData(member.value, member) self._data_widget.setCurrentIndexByLinkedData(enm.AUTO) self._data_widget.currentIndexChanged.connect(self._value_changed) diff --git a/pcleaner/preprocessor.py b/pcleaner/preprocessor.py index 0f43ac3e..c15cd251 100644 --- a/pcleaner/preprocessor.py +++ b/pcleaner/preprocessor.py @@ -130,15 +130,15 @@ def prep_json_file( original_path: str = json_data["original_path"] scale: float = json_data["scale"] boxes: list[st.Box] = [] - page_langs: list[st.DetectedLang] = [] + page_langs: list[str] = [] # Define permitted languages based on strictness. # Since the OCR model is only trained to recognize Japanese, # we need to discard anything that isn't, and if strict, also # those that are unknown (likely a mix). - language_whitelist = [st.DetectedLang.JA, st.DetectedLang.ENG] + language_whitelist = [st.DetectedLang.JA.value, st.DetectedLang.ENG.value] if not preprocessor_conf.ocr_strict_language: - language_whitelist.append(st.DetectedLang.UNKNOWN) + language_whitelist.append(st.DetectedLang.UNKNOWN.value) for data in json_data["blk_list"]: # Check box language. @@ -155,9 +155,9 @@ def prep_json_file( page_langs.append(data["language"]) boxes.append(box) - page_lang: st.DetectedLang = ( - Counter(page_langs).most_common(1)[0][0] if boxes else st.DetectedLang.UNKNOWN - ) + page_lang: st.DetectedLang = st.DetectedLang.display_names()[( + Counter(page_langs).most_common(1)[0][0] if boxes else st.DetectedLang.UNKNOWN.value + )] logger.debug(f"Detected lang: {page_lang}") # reading_order = preprocessor_conf.reading_order diff --git a/pcleaner/structures.py b/pcleaner/structures.py index 02362bf1..8b3a1215 100644 --- a/pcleaner/structures.py +++ b/pcleaner/structures.py @@ -1,7 +1,7 @@ import json import re from enum import Enum -from enum import StrEnum +# from enum import StrEnum from importlib import resources from pathlib import Path from typing import Sequence @@ -15,7 +15,7 @@ import pcleaner.data -class DetectedLang(StrEnum): +class DetectedLang(cfg.EnumStr_): JA = "ja" ENG = "eng" UNKNOWN = "unknown" From 1c0a19bbd8de46cecc56df01bc94f209d80f852b Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 24 May 2024 19:27:26 +0200 Subject: [PATCH 07/27] fixes, refactor for Colab --- pcleaner/_testbed/README.md | 61 + pcleaner/_testbed/__init__.py | 0 pcleaner/_testbed/experiment/.gitkeep | 0 pcleaner/_testbed/experiment/Idefics.json | 3825 +++++++++ pcleaner/_testbed/experiment/Tesseract.json | 4062 ++++++++++ pcleaner/_testbed/experiment/cache/.gitkeep | 0 pcleaner/_testbed/experiment/source/.gitkeep | 0 pcleaner/_testbed/nbs/experiments.ipynb | 7640 ++++++++++++++++++ pcleaner/_testbed/nbs/helpers.ipynb | 821 ++ pcleaner/_testbed/nbs/ocr_idefics.ipynb | 1618 ++++ pcleaner/_testbed/nbs/ocr_metric.ipynb | 276 + pcleaner/_testbed/nbs/test_web_server.ipynb | 755 ++ pcleaner/_testbed/nbs/visor.ipynb | 1024 +++ pcleaner/_testbed/nbs/web_server.ipynb | 1 + pcleaner/_testbed/pcleaner.png | Bin 0 -> 17709 bytes pcleaner/_testbed/requirements-colab.txt | 7 + pcleaner/_testbed/requirements-idefics.txt | 4 + pcleaner/_testbed/requirements.txt | 8 + pcleaner/_testbed/test_idefics.ipynb | 1 + pcleaner/_testbed/test_tesseract.ipynb | 1 + pcleaner/_testbed/testbed/__init__.py | 0 pcleaner/_testbed/testbed/bottle.py | 4417 ++++++++++ pcleaner/_testbed/testbed/experiments.py | 2285 ++++++ pcleaner/_testbed/testbed/helpers.py | 381 + pcleaner/_testbed/testbed/ocr_idefics.py | 310 + pcleaner/_testbed/testbed/ocr_metric.py | 64 + pcleaner/_testbed/testbed/visor.py | 391 + pcleaner/_testbed/testbed/web_server.py | 330 + 28 files changed, 28282 insertions(+) create mode 100644 pcleaner/_testbed/README.md create mode 100644 pcleaner/_testbed/__init__.py create mode 100644 pcleaner/_testbed/experiment/.gitkeep create mode 100644 pcleaner/_testbed/experiment/Idefics.json create mode 100644 pcleaner/_testbed/experiment/Tesseract.json create mode 100644 pcleaner/_testbed/experiment/cache/.gitkeep create mode 100644 pcleaner/_testbed/experiment/source/.gitkeep create mode 100644 pcleaner/_testbed/nbs/experiments.ipynb create mode 100644 pcleaner/_testbed/nbs/helpers.ipynb create mode 100644 pcleaner/_testbed/nbs/ocr_idefics.ipynb create mode 100644 pcleaner/_testbed/nbs/ocr_metric.ipynb create mode 100644 pcleaner/_testbed/nbs/test_web_server.ipynb create mode 100644 pcleaner/_testbed/nbs/visor.ipynb create mode 100644 pcleaner/_testbed/nbs/web_server.ipynb create mode 100644 pcleaner/_testbed/pcleaner.png create mode 100644 pcleaner/_testbed/requirements-colab.txt create mode 100644 pcleaner/_testbed/requirements-idefics.txt create mode 100644 pcleaner/_testbed/requirements.txt create mode 100644 pcleaner/_testbed/test_idefics.ipynb create mode 100644 pcleaner/_testbed/test_tesseract.ipynb create mode 100644 pcleaner/_testbed/testbed/__init__.py create mode 100644 pcleaner/_testbed/testbed/bottle.py create mode 100644 pcleaner/_testbed/testbed/experiments.py create mode 100644 pcleaner/_testbed/testbed/helpers.py create mode 100644 pcleaner/_testbed/testbed/ocr_idefics.py create mode 100644 pcleaner/_testbed/testbed/ocr_metric.py create mode 100644 pcleaner/_testbed/testbed/visor.py create mode 100644 pcleaner/_testbed/testbed/web_server.py diff --git a/pcleaner/_testbed/README.md b/pcleaner/_testbed/README.md new file mode 100644 index 00000000..0bead663 --- /dev/null +++ b/pcleaner/_testbed/README.md @@ -0,0 +1,61 @@ +# PanelCleaner Testbed + +## Overview +The **PanelCleaner** testbed serves as a dedicated area for experimenting and testing new ideas with *PanelCleaner* using Jupyter Notebooks. Currently, it focuses on **OCR** technologies, primarily using **Tesseract** and **IDefics** models. The testbed also begins the development of an evaluation framework to support future experiments. This project utilizes the `nbdev` literate programming environment. + +## Installation +To get started with the notebooks, you'll need Jupyter Lab/Notebook or any Python IDE that supports Jupyter notebooks like *VSCode* or *Google Colab*. +The setup mostly shares the same requirements as PanelCleaner and its CLI, with a few additional dependencies. +Here’s how to set up your environment: +1. Activate a virtual environment. +2. Navigate to the `_testbed` directory: + ```bash + cd _testbed + ``` +3. Install the required dependencies: + ```bash + pip install -r requirements.txt + ``` +Note: Each notebook may require the installation of additional dependencies. + +## Google Colab Support +The notebooks are ready to use on Google Colab, allowing you to run them directly on the platform without any extra setup or local GPU rigs. +Instructions to use Google Colab are included in the notebooks. + +## Install Test Images +The test images are not included in the repository but can be downloaded from the following link: +- [Test images PCISet](https://drive.google.com/file/d/18TSXLCYAPxAlUsdHmgAe6FZM5d8K6gcT/view?usp=drive_link). The notebooks have also instructions and code to download directly the set + +After downloading, place the test images in the [source](source) directory. If you want to use your own, each image should have a corresponding text file with the same name, but with the extension `.txt`, which contains the ground truth data, one line per box (as calculated by PanelCleaner). Optionally, you can also include a `.json` file with the same name, specifying the language of the page: +```json +{ + "lang": "Spanish" +} +``` +If no language file is found, English will be used by default. In the near future, language detection will be automated. + +## Introduction to nbdev +[nbdev](https://nbdev.fast.ai/) is a **literate programming** environment that allows you to develop a Python library in Jupyter Notebooks, integrating exploratory programming, code, tests, and documentation into a single cohesive workflow. Inspired by **Donald Knuth**'s concept of literate programming, this approach not only makes the development process more intuitive but also eases the maintenance and understanding of the codebase. + +## Library Notebooks (WIP) + +#### [helpers.ipynb](helpers.ipynb) +This notebook includes utility functions and helpers that support the experiments in other notebooks, streamlining repetitive tasks and data manipulation. + +#### [ocr_metric.ipynb](ocr_metric.ipynb) +This notebook focuses on defining and implementing metrics to evaluate the performance and accuracy of OCR engines, crucial for assessing the effectiveness of OCR technologies in various scenarios. It currently develops a basic metric for evaluating OCR models. In the near future, additional metrics will be added, such as precision and recall using Levenshtein distance (edit distance). More importantly, it will introduce a metric tailored to the unique characteristics of Comics/Manga OCR, a topic currently unexplored in technical literature. + +#### [experiments.ipynb](experiments.ipynb) +This notebook details the development of the evaluation framework used in other notebooks, with Tesseract as a case study to illustrate the evaluation process. It's a work in progress, and will be updated continuously. If you're only interested in visualizing the results of the experiments, go directly to `Test_tesseract.ipynb` or `Test_idefics.ipynb`, which are much shorter and more to the point. + +#### [visor.ipynb](visor.ipynb) +Base infrastructure of experiments visualization. Simple composition of Jupyter widgets. + + +## Test Notebooks (WIP) + +#### [test_tesseract.ipynb](test_tesseract.ipynb) +This notebook is dedicated to testing the Tesseract OCR engine, offering insights into its capabilities and limitations through hands-on experiments. + +#### [test_idefics.ipynb](test_idefics.ipynb) +Similar to `test_tesseract.ipynb`, this notebook focuses on the IDefics LVM model, evaluating its performance and accuracy under different conditions. Here you can compare the results of the Tesseract OCR engine with the IDefics LVM model to see how the two stand in terms of accuracy and performance. diff --git a/pcleaner/_testbed/__init__.py b/pcleaner/_testbed/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/pcleaner/_testbed/experiment/.gitkeep b/pcleaner/_testbed/experiment/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/pcleaner/_testbed/experiment/Idefics.json b/pcleaner/_testbed/experiment/Idefics.json new file mode 100644 index 00000000..00a0f903 --- /dev/null +++ b/pcleaner/_testbed/experiment/Idefics.json @@ -0,0 +1,3825 @@ +{ + "ocr_model": "Idefics", + "runs": { + "Idefics-crop-post": { + "Strange_Tales_172005.jpg": { + "1": { + "DEFAULT_GREY_PAD": "The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home ...", + "INITIAL_BOX": "\"the house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home...\"", + "DEFAULT": "The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home ...", + "PADDED_4": "\"the house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home...\"", + "PADDED_8": "The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home ...", + "EXTRACTED_INIT_BOX": "The house and the old man are alike in many ways; tally-hoo! patient, contented always to wait until the master comes home ... \"", + "PADDED_4_EXTRACTED": "The house and the old man are alike in many ways; tally proud, patient, contented always to wait until they're naster comes home ...", + "PADDED_8_EXTRACTED": "The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until they master comes home ...", + "PADDED_8_DILATION_1": "The house and the old man are alike in many ways; \"tall, proud, patient, contented always to wait until their master comes home\" ...", + "PAD_8_FRACT_0_5": "The house and the old man are alike in many ways; tall, proud, patient, contented (they always to wait until they master comes home ...", + "PAD_8_FRACT_0_2": "The house and the old man are alike in many ways; tall, proud, patient, contented (they always to wait until their master comes home ..." + }, + "0": { + "DEFAULT_GREY_PAD": "Empowered by great charled cypress trees , the ancient manor stands alone on the outskirts of new orleans , kept tidy by a white-haired old man known only as bambu.", + "INITIAL_BOX": "Embodied by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.", + "DEFAULT": "Embodied by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.", + "PADDED_4": "Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.", + "PADDED_8": "Empowered by great charled cypress trees , the ancient manor stands alone on the outskirts of new orleans , kept tidy by a white-haired old man known only as bambu.", + "EXTRACTED_INIT_BOX": "Encountered by great charled express trees, the ancient manor stands alone on the quaint skirts of new orleans kept tidy by a white-haired old man known only as bannibull.", + "PADDED_4_EXTRACTED": "Enthroned by great charles cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-hired and man known only as bambu.", + "PADDED_8_EXTRACTED": "Enchanted by great charled cypress trees, the ancient manor stands alone on the outskirts of new orleans kept tidy by a white-haired and man known only as bambu.", + "PADDED_8_DILATION_1": "Engineered by great charled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-hairied old man known only as bambu.", + "PAD_8_FRACT_0_5": "Encountered by great charles cypress trees, the ancient manor stands alone on the outskirts of new orleans kept tidy by a white-haired red man known only as bambu.", + "PAD_8_FRACT_0_2": "Encountered by great charles cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu." + }, + "2": { + "DEFAULT_GREY_PAD": "And one in need of some help, it would appear.", + "INITIAL_BOX": "And one in need of some help, it would appear...", + "DEFAULT": "And one in need of some help, it would appear.", + "PADDED_4": "And one in need of some help, it would appear...", + "PADDED_8": "And one in need of some help, it would appear.", + "EXTRACTED_INIT_BOX": "And one in need of some help, it would appear...", + "PADDED_4_EXTRACTED": "And one in need of some help. it would appear...", + "PADDED_8_EXTRACTED": "And one in need of some help it would appear...", + "PADDED_8_DILATION_1": "And one in need of some help, it would appear.", + "PAD_8_FRACT_0_5": "And one in need of some help it would appear.", + "PAD_8_FRACT_0_2": "And one in need of some help, it would appear." + }, + "3": { + "DEFAULT_GREY_PAD": "Bambu - we have a guest.", + "INITIAL_BOX": "Bambi - we have a guest.", + "DEFAULT": "Bambu - we have a guest.", + "PADDED_4": "Bambi - we have a guest.", + "PADDED_8": "Bambu - we have a guest ...", + "EXTRACTED_INIT_BOX": "Banned by the law - we have a bluest.", + "PADDED_4_EXTRACTED": "Bam blam we have a guest.", + "PADDED_8_EXTRACTED": "Bambi - he have a guest.", + "PADDED_8_DILATION_1": "Bambi - we have a guest.", + "PAD_8_FRACT_0_5": "Bambi - we have a guest.", + "PAD_8_FRACT_0_2": "Bambi - we have a guest." + }, + "4": { + "DEFAULT_GREY_PAD": "\"and tonight, he comes most urgently, slamming open the oaken front doors!", + "INITIAL_BOX": "\"and tonight, he comes most urgently slamming open the oaken front doors!", + "DEFAULT": "And tonight, he comes most urgently, slamming open the oaken front doors!", + "PADDED_4": "And tonight, he comes most urgently, slamming open the oaken front doors!", + "PADDED_8": "And tonight, he comes most urgently, slamming open the oaken front doors!", + "EXTRACTED_INIT_BOX": "\"and tonight, he comes most largely slamming open the oaken front doors!", + "PADDED_4_EXTRACTED": "And tonight he comes most urgently, slamming open the oaken front doors!", + "PADDED_8_EXTRACTED": "And tonight, he comes most livelyly slamming open the oaken front doors!", + "PADDED_8_DILATION_1": "And tonight, he comes most urgently, slamming open the oaken front doors!", + "PAD_8_FRACT_0_5": "\"and tonight, he comes most lircently, slamming open the oaken front doors!", + "PAD_8_FRACT_0_2": "\"and to night, he comes most lircently, slamming open the oaken front doors!" + }, + "5": { + "DEFAULT_GREY_PAD": "Tell me master how may bambi serve?", + "INITIAL_BOX": "Tell me... master... how may bambi serve?", + "DEFAULT": "Tell me... master... how may bambu serve?", + "PADDED_4": "Tell me, master... how may bambi serve?", + "PADDED_8": "Tell me master how may bambi serve?", + "EXTRACTED_INIT_BOX": "Tell me master... how mary bambi serve?", + "PADDED_4_EXTRACTED": "Tell me master... how may bamouli serve?", + "PADDED_8_EXTRACTED": "Titell me master... how may bambi serve?", + "PADDED_8_DILATION_1": "Tell me master how may bamboli serve?", + "PAD_8_FRACT_0_5": "Tibell master... how may bambi serve?", + "PAD_8_FRACT_0_2": "Tell me master... how may bamoli serve?" + }, + "6": { + "DEFAULT_GREY_PAD": "Some blankets to keep her warm, bambi...and perhaps some dry clothes...?", + "INITIAL_BOX": "Some blankets to keep her warm, bambi- and perhaps some dry clothes?", + "DEFAULT": "Some blankets to keep her warm, bambi...and perhaps some dry clothes?", + "PADDED_4": "Some blankets to keep her warm, bambu- and perhaps some dry clothes?", + "PADDED_8": "Some blankets to keep her warm, bambi...and perhaps some dry clothes?", + "EXTRACTED_INIT_BOX": "Gome blankets to keep her warm, bambu-and perhaps some dry clothes", + "PADDED_4_EXTRACTED": "Gome blankets to keep her warm, bambu-and perhaps some dry clothes", + "PADDED_8_EXTRACTED": "Gone blankets to keep her warm, bamboo- and perhaps some dry clothes", + "PADDED_8_DILATION_1": "Some blankets to keep her warm, bambi- and perhaps some dry clothes", + "PAD_8_FRACT_0_5": "Some blankets to keep her warm, bambi- and perhaps some dry clothes", + "PAD_8_FRACT_0_2": "Some blankets to keep her warm, bambi- and perhaps some dry clothes" + }, + "7": { + "DEFAULT_GREY_PAD": "The echo of the old man's footsteps fades down the hall as...", + "INITIAL_BOX": "The echo of the old man's footsteps fades down the hall as...", + "DEFAULT": "The echo of the old man's footsteps fades down the hall as...", + "PADDED_4": "The echo of the old man's footsteps fades down the hall as...", + "PADDED_8": "The echo of the old man's footsteps fades down the hall as....", + "EXTRACTED_INIT_BOX": "The echo of the old man's footsteps fades down the hall ais...", + "PADDED_4_EXTRACTED": "The echo of the old man's footsteps fades down the hall aisw...", + "PADDED_8_EXTRACTED": "The echo of the old man's footsteps fades down the hall a6\"", + "PADDED_8_DILATION_1": "The echo of the old man's footsteps fades down the hall as", + "PAD_8_FRACT_0_5": "The echo of the old man's footsteps fades down the hall as", + "PAD_8_FRACT_0_2": "The echo of the old man's footsteps fades down the hall as..." + }, + "8": { + "DEFAULT_GREY_PAD": "How curious the whims of fate had i not chanced to stroll along the river tonight.", + "INITIAL_BOX": "How curious the whims of fate... had i not changed to stroll along the river tonight...", + "DEFAULT": "How curious the whims of fate... had i not changed to stroll along the river tonight...", + "PADDED_4": "How curious the whims of fate ... had i not changed to stroll along the river tonight ...", + "PADDED_8": "How curious the whims of fate... had i not changed to stroll along the river tonight...", + "EXTRACTED_INIT_BOX": "How curious the whims of fate! had i not changed to stroll along the river tonight ...", + "PADDED_4_EXTRACTED": "How curious the whims of fate ... had i not changed to stroll along the river tonight ... \"", + "PADDED_8_EXTRACTED": "How curious the whims of fate! had i not changed to stroll along the river tonight -?", + "PADDED_8_DILATION_1": "How curious the whims of fate. had i not changed to stroll along the river tonight--", + "PAD_8_FRACT_0_5": "How curious the whimings of fate! had i not chanced to stroll along the river tonight?", + "PAD_8_FRACT_0_2": "How curious the whims of fate! had i not chanced to stroll along the river tonight?" + }, + "9": { + "DEFAULT_GREY_PAD": "As quickly as i can, master.", + "INITIAL_BOX": "As quickly as i can master. \"", + "DEFAULT": "As quickly as i can, master.", + "PADDED_4": "As quickly as i can, master.", + "PADDED_8": "As quickly as i can, master.", + "EXTRACTED_INIT_BOX": "As quickly as i can, master.", + "PADDED_4_EXTRACTED": "As quickly as i can, master. \"", + "PADDED_8_EXTRACTED": "As quickly as i can, master!", + "PADDED_8_DILATION_1": "As quickly as i can, master.", + "PAD_8_FRACT_0_5": "As quickly as i can, master!", + "PAD_8_FRACT_0_2": "As quickly as i can, master!" + }, + "10": { + "DEFAULT_GREY_PAD": "\"the girl would most surely be dead by now.", + "INITIAL_BOX": "\"the girl would most surely be dead by now.", + "DEFAULT": "\"the girl would most surely be dead by now..\"", + "PADDED_4": "- the girl would most surely be dead by now...", + "PADDED_8": "\"the girl would most surely be dead by now.", + "EXTRACTED_INIT_BOX": "\"the girl would most surely be dead by now!", + "PADDED_4_EXTRACTED": "\"the girl would most surely be dead by now.", + "PADDED_8_EXTRACTED": "\"the girl, who'd most surely be dead by now...", + "PADDED_8_DILATION_1": "\"the girl would most surely be dead by now.", + "PAD_8_FRACT_0_5": "\"the girl would most surely be dead by now.", + "PAD_8_FRACT_0_2": "\"the girl would most surely be dead by now." + }, + "11": { + "DEFAULT_GREY_PAD": "Shede has been generous. the death god has given the girl a second chance at...\"", + "INITIAL_BOX": "Ghede has been generous. the death god has given the girl a second chance at...\"", + "DEFAULT": "Shede has been generous. the death god has given the girl a second chance at \"", + "PADDED_4": "Ghede has been generous. the death god has given the girl a second chance at...\"", + "PADDED_8": "Ghede has been generous...the death god has given the girl a second chance at...\"", + "EXTRACTED_INIT_BOX": "Chete has been gunned down the death god has given the girl a second chance at\"", + "PADDED_4_EXTRACTED": "Gwende has been generously the death (god has given the girl a second chance\" at--", + "PADDED_8_EXTRACTED": "One of his been generous the death; god has given the girl a second chance at\"", + "PADDED_8_DILATION_1": "Ghede has been generous. the death god has given the girl a second chance! at--", + "PAD_8_FRACT_0_5": "Cheers of has been generalizer the death; god has given the girl a second chance at\"", + "PAD_8_FRACT_0_2": "Chede has been generous the death god has given the girl a second chance at\"" + }, + "12": { + "DEFAULT_GREY_PAD": "Easy, girl-- there's nothing to scream about anymore.", + "INITIAL_BOX": "Easy, girl! \"\" there's nothing to scream about anymore.", + "DEFAULT": "Easy, girl--there's nothing to scream about anymore.", + "PADDED_4": "Easy, girl... there's nothing to scream about anymore.", + "PADDED_8": "Easy, girl-- there's nothing to scream about anymore.", + "EXTRACTED_INIT_BOX": "Easy, girl -- there's nothing to scream about anymore...", + "PADDED_4_EXTRACTED": "Easy, girl -- there's nothing to scream about anymore...", + "PADDED_8_EXTRACTED": "Easy, girl! there's nothing to scream about anymore.", + "PADDED_8_DILATION_1": "Easy, girl -- there's nothing to scream about anymore.", + "PAD_8_FRACT_0_5": "Easy, girl... there's nothing to scream about anymore.", + "PAD_8_FRACT_0_2": "Easy, girl...there's nothing to scream about anymore." + }, + "13": { + "DEFAULT_GREY_PAD": "You're among friends now. you're safe?", + "INITIAL_BOX": "You're among friends now. you're safe?", + "DEFAULT": "You're among friends now. you're safe?", + "PADDED_4": "You're among friends now. you're safe?", + "PADDED_8": "You're among friends now. you're safe?", + "EXTRACTED_INIT_BOX": "You're among friends now. you're safe!", + "PADDED_4_EXTRACTED": "You're among friends now! you're safe?", + "PADDED_8_EXTRACTED": "You're among friends now, you're safe!", + "PADDED_8_DILATION_1": "You're among friends now, you're safe!", + "PAD_8_FRACT_0_5": "You're among friends now, you're safe!", + "PAD_8_FRACT_0_2": "You're among friends now, you're safe!" + }, + "14": { + "DEFAULT_GREY_PAD": "Continued after next page", + "INITIAL_BOX": "Continued after next page", + "DEFAULT": "Continued after next page", + "PADDED_4": "Continued after next page", + "PADDED_8": "Continued after next page.", + "EXTRACTED_INIT_BOX": "Continued in the next issue! \" but it's", + "PADDED_4_EXTRACTED": "Cognitively tuned into everything", + "PADDED_8_EXTRACTED": "Continued on next page", + "PADDED_8_DILATION_1": "Continued... text page", + "PAD_8_FRACT_0_5": "Continued on next page.", + "PAD_8_FRACT_0_2": "Continued... text page." + } + }, + "Action_Comics_1960-01-00_(262).JPG": { + "1": { + "DEFAULT_GREY_PAD": ">gasp:: everything's w-whirling around me! i can't stand up...", + "INITIAL_BOX": "Gasp! everything's whirling around me! i can't stand up...", + "DEFAULT": "Gasp! everything's w-whirling around me! i can't stand up...", + "PADDED_4": "Gasp! everything's w-whirling around me! i can't stand up...", + "PADDED_8": "Gaspl; everything's w-whirling around me! i can't stand up...", + "EXTRACTED_INIT_BOX": "\" yeah... everything's all-whirlin 'round me! i can't stand up.", + "PADDED_4_EXTRACTED": "Figs? everything's w-whirling around me! i can't stand up?", + "PADDED_8_EXTRACTED": "\" i guess everything's well whirling around me! i can't stand up.", + "PADDED_8_DILATION_1": "%gasp% everything s w-whirling around me! i can't stand up.", + "PAD_8_FRACT_0_5": "\" gasp! everything's whirling around me! i can't stand up.", + "PAD_8_FRACT_0_2": "! gasps! everything's whirling around me! i can't stand up?" + }, + "0": { + "DEFAULT_GREY_PAD": "Suddenly...", + "INITIAL_BOX": "Suddenly...", + "DEFAULT": "Suddenly...", + "PADDED_4": "Suddenly...", + "PADDED_8": "Suddenly...", + "EXTRACTED_INIT_BOX": "Suddenly yours.", + "PADDED_4_EXTRACTED": "Suddenly... \"", + "PADDED_8_EXTRACTED": "Suddenly...", + "PADDED_8_DILATION_1": "Suddenly...", + "PAD_8_FRACT_0_5": "Suddenly...", + "PAD_8_FRACT_0_2": "Suddenly..." + }, + "2": { + "DEFAULT_GREY_PAD": "Clark! i'm falling! help?", + "INITIAL_BOX": "Clark! i'm falling! help?", + "DEFAULT": "Clark! i'm falling! help?", + "PADDED_4": "Clark! i'm falling! help?", + "PADDED_8": "Clark! i'm falling! help?", + "EXTRACTED_INIT_BOX": "\" clark, i'm falling! help? \"", + "PADDED_4_EXTRACTED": "\" clark, i'm falling! help? help? \"", + "PADDED_8_EXTRACTED": "' clark, i'm falling! help?", + "PADDED_8_DILATION_1": "Clark! i'm falling! help?", + "PAD_8_FRACT_0_5": "Clark! i'm falling! help?", + "PAD_8_FRACT_0_2": "Clark! i'm falling! help?" + }, + "3": { + "DEFAULT_GREY_PAD": "I-i'm passing out... ohhh...", + "INITIAL_BOX": "I'm passing out... ohhhh...", + "DEFAULT": "I-i'm passing out... ohhh...", + "PADDED_4": "I'm passing out... ohhhh...", + "PADDED_8": "I-i'm passing out... ohhh...", + "EXTRACTED_INIT_BOX": "I'm passing out... oh my god!", + "PADDED_4_EXTRACTED": "I'm passing out ohhhhmm...", + "PADDED_8_EXTRACTED": "I'm passing out... now?", + "PADDED_8_DILATION_1": "I-i'm passing out... ohhhh....", + "PAD_8_FRACT_0_5": "I'm passing out... original?", + "PAD_8_FRACT_0_2": "I'm passing out... oh no!" + }, + "4": { + "DEFAULT_GREY_PAD": "Action comics", + "INITIAL_BOX": "Action comics", + "DEFAULT": "Action comics", + "PADDED_4": "Action comics", + "PADDED_8": "Action comics", + "EXTRACTED_INIT_BOX": "Action comics", + "PADDED_4_EXTRACTED": "Action comics", + "PADDED_8_EXTRACTED": "Action comics", + "PADDED_8_DILATION_1": "Action comics", + "PAD_8_FRACT_0_5": "Action comics", + "PAD_8_FRACT_0_2": "Action comics" + }, + "5": { + "DEFAULT_GREY_PAD": "Then, seconds later...", + "INITIAL_BOX": "Then seconds later...", + "DEFAULT": "Then seconds later...", + "PADDED_4": "Then seconds later...", + "PADDED_8": "Then, seconds later...", + "EXTRACTED_INIT_BOX": "It was seconds later...", + "PADDED_4_EXTRACTED": "\"the next few seconds later...", + "PADDED_8_EXTRACTED": "Timeworn sectoids later...", + "PADDED_8_DILATION_1": "Then, seconds later...", + "PAD_8_FRACT_0_5": "Then seconds later...", + "PAD_8_FRACT_0_2": "Then seconds later..." + }, + "6": { + "DEFAULT_GREY_PAD": "Great caesar's ghost! this is black magic! we've been transported to the weirdest world i ever saw?", + "INITIAL_BOX": "Great caesar's ghost! this is black magic! we've been transported to the weirdest world i ever saw?", + "DEFAULT": "Great caesar's ghost! this /is black magic! we 've been transported to the weirdest world i ever saw?", + "PADDED_4": "Great caesar's ghost! this /5 black magic! we 've been transported to the weirdest world i ever saw?", + "PADDED_8": "Great caesar's ghost! this is black magic! we've been transported to the weirdest world i ever saw?", + "EXTRACTED_INIT_BOX": "Great caesar's ghost! this is black magic! we've been transported to the weirdest world i ever saw?", + "PADDED_4_EXTRACTED": "Great caesar's ghost! this is black magic! we've been transported to the weirdest world i ever saw?", + "PADDED_8_EXTRACTED": "Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw?", + "PADDED_8_DILATION_1": "Great caesar's ghost! this /s black magic! we 've been transported to the weirdest world i ever saw?", + "PAD_8_FRACT_0_5": "Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw?", + "PAD_8_FRACT_0_2": "Great caesar's ghost! this as black magic, we 've been transported to the weirdest world i ever saw?" + }, + "7": { + "DEFAULT_GREY_PAD": "... it certainly isn't our earth, perry! look at the size of those bees! '", + "INITIAL_BOX": "\"... it certainly isn't our earth, perry! look at the size of those bees!", + "DEFAULT": "... it certainly isn't our earth, perry! look at the size of those bees?", + "PADDED_4": "... it certainly isn't our earth, perry! look at the size of those bees?", + "PADDED_8": "... it certainly isn't our earth, perry! look at the size of those bees!", + "EXTRACTED_INIT_BOX": "... it certainly isn't on earth! perry look at the size- of those bees! '", + "PADDED_4_EXTRACTED": "... it certainly isn't okay, earth! peter look at the shee- of those beees?", + "PADDED_8_EXTRACTED": "... it certainly isn't our earth, perry! look at the size of those bees?", + "PADDED_8_DILATION_1": "\"... it certainly isn't our earth, perry! look at the size of those bees?", + "PAD_8_FRACT_0_5": "... it certainly isn't our earth, perry! look at the curse of those bees?", + "PAD_8_FRACT_0_2": "... it certainly isn't our earth, perry! look at the size of those bees?" + }, + "8": { + "DEFAULT_GREY_PAD": "Watch out, clark!", + "INITIAL_BOX": "Watch out, clark?", + "DEFAULT": "Watch out, clark!", + "PADDED_4": "Watch out, clark!", + "PADDED_8": "Watch out, clark!", + "EXTRACTED_INIT_BOX": "Watch out, clark?", + "PADDED_4_EXTRACTED": "Watch out, clark!", + "PADDED_8_EXTRACTED": "Watch out, clark?", + "PADDED_8_DILATION_1": "Watch out, clark!", + "PAD_8_FRACT_0_5": "Watch out, clark!", + "PAD_8_FRACT_0_2": "Watch out, clark!" + }, + "9": { + "DEFAULT_GREY_PAD": "Owww ww!?", + "INITIAL_BOX": "Ow! ww! w!?", + "DEFAULT": "Own nw nw!?", + "PADDED_4": "Own nwn!?", + "PADDED_8": "Owww!?", + "EXTRACTED_INIT_BOX": "\" ow! whoa? !", + "PADDED_4_EXTRACTED": "Owww wwww!?", + "PADDED_8_EXTRACTED": "Owww wwwhh?", + "PADDED_8_DILATION_1": "Oh ww!?", + "PAD_8_FRACT_0_5": "Owwwww!?", + "PAD_8_FRACT_0_2": "Owwwww!" + }, + "10": { + "DEFAULT_GREY_PAD": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means the fabric of my superman costume has become ordinary cloth!", + "INITIAL_BOX": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means: the fabric of my superman costume has become ordinary cloth!", + "DEFAULT": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means...the fabric of my superman costume has become ordinary cloth!", + "PADDED_4": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means...the fabric of my superman costume has become ordinary cloth!", + "PADDED_8": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means...the fabric of my superman costume has become ordinary cloth!", + "EXTRACTED_INIT_BOX": "Yet the bee's stinger worent mighty yithrough my uniform and penetrated my skin! that means, the fabric of my superman costume has become ordinary cloth! \"", + "PADDED_4_EXTRACTED": "Yet the bee's stinger went through my uniform and penetrated an skin! that means, the paired of my superhero suit has become ordinary cloth!", + "PADDED_8_EXTRACTED": "Yet the bee's stinger want high through my uniform, and penetrated an skin! that means, the fabric of my superhero costume has become ordinary cloth!", + "PADDED_8_DILATION_1": "Yet the bee's stinger went right through an uniform and penetrated an skin that means the fabric of an superman costume has become ordinary cloth!", + "PAD_8_FRACT_0_5": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means, the fabric of my superman costume has become ordinary cloth!!", + "PAD_8_FRACT_0_2": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means, the fabric of my superman costume has become ordinary cloth! \"" + }, + "11": { + "DEFAULT_GREY_PAD": "Hurry! let's beat it before we get stung, too?", + "INITIAL_BOX": "Hurry! let's beat it before we get stung, too?", + "DEFAULT": "Hurry! let's beat it before we get stung, too?", + "PADDED_4": "Hurry! let's beat it before we get stung, too?", + "PADDED_8": "Hurry! let's beat it before we get stung, too?", + "EXTRACTED_INIT_BOX": "Hurry! let's beat it before we get stung, too?", + "PADDED_4_EXTRACTED": "Hurry! let's beat it before we get stung, too?", + "PADDED_8_EXTRACTED": "Hurry! let's beat it before we get stung, too?", + "PADDED_8_DILATION_1": "Hurry! let's beat it before we get stung, too?", + "PAD_8_FRACT_0_5": "Hurry! let's beat it before we get stung, too?", + "PAD_8_FRACT_0_2": "Hurry! let's beat it before we get stung, too?" + }, + "12": { + "DEFAULT_GREY_PAD": "Ggreat guns! ... gasp... pain i feel pain! as superman, i should be invulnerable: i have unbreakable skin! under my clark kent clothes, i'm wearing an indestructible superman uniform!", + "INITIAL_BOX": "Great guns! ... gaspe... pain i feel pain! as superman, i should be invulnerable! i have breakable skin under my clark kent clothes. i'm wearing an indestructible superman uniform!", + "DEFAULT": "\" g-great guns! ... gaspe... pain i feel pain! as superman, i should be invulnerable! i have breakable skin under my clark kent clothes, wearing an indestructible superman uniform! \"", + "PADDED_4": "Great guns! ... gaspi... pain i feel pain! as superman, i should be invulnerable! i have breakable skin under my clark kent clothes, tim. wearing an indestructible superman uniform!", + "PADDED_8": "\"great guns! ... gasp... pain! i feel pain! as superman, i should be invulnerable: i have unbreakable skin! under my clark kent clothes, i'm wearing an indestructible superman uniform!", + "EXTRACTED_INIT_BOX": "Great guns! ... superman? ..... panic!!! i feel framed as superman; i should be amazingly awesome; i've undergone infinite hours of clark kent clothes, and undergoing an indestroctible superman uniform!!", + "PADDED_4_EXTRACTED": "Great guns ... good guys... pair it terf pants as superman, i should be able to wear them in clark kent clothes, the metamorphosis an inestigatable superhuman unknown! ?", + "PADDED_8_EXTRACTED": "\" great guns! ... you'll pay! i feel from this semi-barrage i should be able to understand how you managed to tie hinne injury with an indestructible suitsportman undronna !\"", + "PADDED_8_DILATION_1": "Great guns! ... gaspe... pain... i feel pain as superman! i should be invulnerable? i have unbreakable skin under my clark kent clothes; i'm wearing an indestructible superman uniform! ?", + "PAD_8_FRACT_0_5": "Great guns! ... yaffy pan! i feel fine as superman, y you should be involved newbie? i have unbreakable bon in under clark kent clothes, i'm wearing an indestroctible superman underwear! ?", + "PAD_8_FRACT_0_2": "Great guns! ... ygaspee! pain! i feel pain! as superman, i should be invulnerable! i have unbreakable skin under my clark kent clothes. i'm wearing an indestructible superman uniform!" + }, + "13": { + "DEFAULT_GREY_PAD": "Abruptly...", + "INITIAL_BOX": "Abruptly...", + "DEFAULT": "Abruptly...", + "PADDED_4": "Abruptly...", + "PADDED_8": "Abruptly...", + "EXTRACTED_INIT_BOX": "Absolutely! ...", + "PADDED_4_EXTRACTED": "Absolutely!", + "PADDED_8_EXTRACTED": "Absolutely...", + "PADDED_8_DILATION_1": "Abruptly...", + "PAD_8_FRACT_0_5": "Absolutely!", + "PAD_8_FRACT_0_2": "Absolutely..." + }, + "14": { + "DEFAULT_GREY_PAD": "Great caesar's ghost! he 's spinning a web of giant, silk strands ... as tough as steel!", + "INITIAL_BOX": "Great caesar's ghost! he's spinning a web of giant, silk strands ... as tough as steel!", + "DEFAULT": "Great caesar's ghost! he's spinning a web of giant, silk strands ... as tough as steel!", + "PADDED_4": "Great caesar's ghost! he's spinning a web of giant, silk strands ... as tough as steel!", + "PADDED_8": "Great caesar's ghost! he's spinning a web of giant, silk strands ... as tough as steel?", + "EXTRACTED_INIT_BOX": "Great caesar's ghost! he 's spinning a web of giant silk strands - as tough as steel?", + "PADDED_4_EXTRACTED": "Great caesar's ghost! he 's spinning a web of giant, silk strands - as tough as steel?", + "PADDED_8_EXTRACTED": "Great caesar's ghost! he 's spinning a web of giant, silk 5 strands - as tough as steel?", + "PADDED_8_DILATION_1": "Great caesar's ghost! he 's spinning a web of giant, silk strands ... as tough as steel?", + "PAD_8_FRACT_0_5": "Great caesar's ghost! he 's spinning a web of giant, silk strands ... as tough as steel?", + "PAD_8_FRACT_0_2": "Great caesar's ghost! he 's spinning a web of giant, silk strands ... as tough as steel?" + }, + "15": { + "DEFAULT_GREY_PAD": "I-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human discomfort...good grief! i've lost all my super-powers...i've become an ordinary mortal in this world?", + "INITIAL_BOX": "I-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human discomfort! good grief! i've lost all my super-powers! i've become an ordinary mortal in this world?", + "DEFAULT": "I-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human discomfort! good grief! i've lost all my super-powers! i've become an ordinary mortal in this world?", + "PADDED_4": "I-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human discomfort! good grief! i've lost all my super-powers! i've become an ordinary mortal in this world?", + "PADDED_8": "I-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human discomfort...good grief! i've lost all my super-powers. i've become an ordinary mortal in this world?", + "EXTRACTED_INIT_BOX": "It-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human recomfort...good grief! i've lost all my super-powers...and become an ordinary mortal...as this world?", + "PADDED_4_EXTRACTED": "I just feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! everything hillman discomfort...good grievier? i've lost all my super-powers and now i'm an electric monkey at this world!", + "PADDED_8_EXTRACTED": "I-i feel the heat of the gun...the pain of the bee-string...the heavy weight of my own mortality! humanity has become an organism mortal to tyris world?", + "PADDED_8_DILATION_1": "I...i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human discomfort! good grief! i've lost all my super-powers! have become an ordinary mortal in this world?", + "PAD_8_FRACT_0_5": "I-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human being good grief! i've lost all my super-powers. i've become an ordinary mortal on this world?", + "PAD_8_FRACT_0_2": "I-i feel the heat of the sun...the pain of the bee-sting...the heavy weight of my pack! every human discomfort...good grief! i've lost all my super-powers. i've become an ordinary mortal in this world?" + }, + "16": { + "DEFAULT_GREY_PAD": "Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning.", + "INITIAL_BOX": "Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning.", + "DEFAULT": "Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning!", + "PADDED_4": "Get back! that enormous spider- like creature is going berserk, as if the sight of him excited him into mad spinning.", + "PADDED_8": "Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning!", + "EXTRACTED_INIT_BOX": "Get back! that enormous spider-like creature is going berserk, as if the sight of us excited him into a frenzy of spinning.", + "PADDED_4_EXTRACTED": "Get back! that enormous spider- like creature is going berserk, as if the sight of him excited him into and spinning", + "PADDED_8_EXTRACTED": "Get back! that enormous spider-like creature is going to berserk, as if the sight of us excited him into mad spinning?", + "PADDED_8_DILATION_1": "Get back! that enormous spider-like creature is going berserk, as if the sight of his excited him into mad spinning. \"", + "PAD_8_FRACT_0_5": "Get back! that enormous spider-like creature is going berserk, as if the sight of us excited him into mad spinning.", + "PAD_8_FRACT_0_2": "Get back! that enormous spider-like creature is going berserk, as if the sight of us excited him into mad spinning." + } + }, + "Adolf_Cap_01_008.jpg": { + "1": { + "DEFAULT_GREY_PAD": "Fuerza de agua!", + "INITIAL_BOX": "Fuera de aqui!", + "DEFAULT": "Fuera de aqui!", + "PADDED_4": "Fuera de aqui!", + "PADDED_8": "Fueria de aguas!", + "EXTRACTED_INIT_BOX": "A fista de aguilas?", + "PADDED_4_EXTRACTED": "\u00bfqui\u00e9n es aqu\u00ed?", + "PADDED_8_EXTRACTED": "La rustia de agustin", + "PADDED_8_DILATION_1": "La fuera de agua?", + "PAD_8_FRACT_0_5": "Irustria de aguino?", + "PAD_8_FRACT_0_2": "Infierria de agua!" + }, + "0": { + "INITIAL_BOX": "Ya le dije - a mi padre que lo en- contrre en un aglue- ro en un arbol.", + "DEFAULT": "Ya le dije - a mi padre que lo en- contrre en un aglue- ro en un arbol.", + "DEFAULT_GREY_PAD": "Ya le dije - a mi padre que lo en- contrre en un aglue- ro en un arbol.", + "PADDED_4": "Ya le dice a mi padre que lo en- ctrre en un agujle- ro en una arbol.", + "PADDED_8": "Ya le dije - a mi padre que lo en- contrre en un aglje- ro en un arbol.", + "EXTRACTED_INIT_BOX": "Xia l.g. dijes a \"mi padre quie lo en- contrrete en un adulto en un arbol-.", + "PADDED_4_EXTRACTED": "Ya las pujes a mi paquer quie lo en- contrien un agente en una aglitte pro en un arrolo.", + "PADDED_8_EXTRACTED": "Ya le dice a mi favor quie lo-en contrieo en un agujilla-ro en uin arsol.", + "PADDED_8_DILATION_1": "Ya le dice a mi padre que lo envie contriere en un aguje- ro eno un arbol.", + "PAD_8_FRACT_0_5": "Xa le due a mi padre que lo en contrte en un agujer-o en un arbol.", + "PAD_8_FRACT_0_2": "Ya le due a mi padre que lo en contre en un aguje- ro en un arsol." + }, + "2": { + "INITIAL_BOX": "Te he pregunta que quien escribio este.", + "DEFAULT": "Te he pregunta que quien escribio este.", + "DEFAULT_GREY_PAD": "Te he pregunta que quien escribio este.", + "PADDED_4": "Te he pregunta que quien escribio este.", + "PADDED_8": "Te he pregunta que quien escribio este.", + "EXTRACTED_INIT_BOX": "El his friy gilnstado calle gulien escalibio esteo.", + "PADDED_4_EXTRACTED": "El his fry glin-tado cue guillen escribio esteo.", + "PADDED_8_EXTRACTED": "Tis his free glin-tado que alque enscidio esto.", + "PADDED_8_DILATION_1": "Te he pregunta que quien escribio este libro?", + "PAD_8_FRACT_0_5": "Te has encontrado al que quieres descubrirlo este.", + "PAD_8_FRACT_0_2": "Te has encontrado al que quieres escribir este." + }, + "3": { + "INITIAL_BOX": "Ino lo se! no quiero hablar mas deello.", + "DEFAULT": "Ino lo se/ no quiero hablar mas deello.", + "DEFAULT_GREY_PAD": "Ino lo se! no quiero hablar mas deello.", + "PADDED_4": "No lo se! no quiero hablar mas deello.", + "PADDED_8": "Ino lo sej no quiero hablar mas deello.", + "EXTRACTED_INIT_BOX": "No lo saque de la calle hablaor m\u00e1s, 175 eld20.", + "PADDED_4_EXTRACTED": "Uno lo sa que no quiero hablar mas de este e.u..", + "PADDED_8_EXTRACTED": "Uno lo sa que no quiero hablar mas de esto bueno.", + "PADDED_8_DILATION_1": "No lo se/ no quiero hablar mas de ello.", + "PAD_8_FRACT_0_5": "No lo seo, no quiero hablar mas deello.", + "PAD_8_FRACT_0_2": "No lo se/ no quiero hablar mas deello." + }, + "4": { + "INITIAL_BOX": "Adolf, lo que dice ese papel es completa- mente falso. es demagogia peligrosa.", + "DEFAULT": "Adolf, lo que dice ese papel es completa-mente falso. es demagogia pelegrosa.", + "DEFAULT_GREY_PAD": "Adolf, lo que dice ese papel es completa- mente falsa. es demagogia peligrosa.", + "PADDED_4": "Adolf, lo que dice ese papel es completa-mente falso. es demagogia peligrosa.", + "PADDED_8": "Adolf, lo que dice ese papel es completa- mente falso. es demagogia peligrosa.", + "EXTRACTED_INIT_BOX": "Ahora, lo que m\u00e1s me pase f\u00e1cil- es completo - mente italiano.", + "PADDED_4_EXTRACTED": "Ahora, lo que dice es que pafel bis completa ta- mi nte italso. as letrinos gregos, la filigrosa.", + "PADDED_8_EXTRACTED": "Ahora, lo que dice base pafel- es completa- mente italiano: es dih-magogia publica.", + "PADDED_8_DILATION_1": "Adulto , lo que dice ese papel es completa- mente falso. es demagogia peligrosa.", + "PAD_8_FRACT_0_5": "Ahora, lo que dice es que falta bs. completa - mente italso. es demagogia pablosra.", + "PAD_8_FRACT_0_2": "Adolf, lo que dice esa papafele bs completa - mente falso. es demagogia peligrosa." + }, + "5": { + "INITIAL_BOX": "Entonces,\" por que le preo- cupa tan to?", + "DEFAULT": "Entonces, \u00bfpor qu\u00e9 le preocupa cupa tan tanto?", + "DEFAULT_GREY_PAD": "Entonces,\" por que le preo- cupa tant\u00f3?", + "PADDED_4": "Entonces, \u00bfpor qu\u00e9 le preocupa cupa tan t\u00f3to?", + "PADDED_8": "Entonces, \u00bfpor qu\u00e9 le preocupa cupa tan tanto?", + "EXTRACTED_INIT_BOX": "Entonces cuesta dupor que los preco cupa tanto?", + "PADDED_4_EXTRACTED": "En tonto caso, antes de preocuparse por cuida tontot", + "PADDED_8_EXTRACTED": "Entonces ches\" uporr guie lee preco cupa tauntof", + "PADDED_8_DILATION_1": "Entonces, \u00bfpor que le preocupa cuya tanta?", + "PAD_8_FRACT_0_5": "Entonces, \u00bfpor que les preocupa cuanta tan top?", + "PAD_8_FRACT_0_2": "Entonces, \u00bfpor que les preocupa cuanta tan tontos?" + }, + "6": { + "INITIAL_BOX": "El consulado no permita la circulaci\u00f3n de ese tipo de rumores.", + "DEFAULT": "El consulado no permita la circulaci\u00f3n de ese tipo de rumores.", + "DEFAULT_GREY_PAD": "El consulado no permita la circulaci\u00f3n de ese tipo de rumores.", + "PADDED_4": "El consulado no permita la circulaci\u00f3n de ese tipo de rumores.", + "PADDED_8": "El consulado no permita la circulaci\u00f3n de ese tipo de rumores.", + "EXTRACTED_INIT_BOX": "El consulado no permite la circulacion del rosto tipo de trucos.", + "PADDED_4_EXTRACTED": "El con su amado no permiten la circulacion de este tipo de peligrosas.", + "PADDED_8_EXTRACTED": "El con su lenguaje no permitir\u00eda la circulaci\u00f3n de las razas tipo d'p3 krimmorges.", + "PADDED_8_DILATION_1": "El consulado no permita la circulacion de esos tipos de rumores.", + "PAD_8_FRACT_0_5": "El con su lago no pertenece la circulacion de ese tipo de rumores.", + "PAD_8_FRACT_0_2": "El con su lado no perwitte la circulacion de ese tipo de rumores." + }, + "7": { + "INITIAL_BOX": "Ino se nada!", + "DEFAULT": "Ino se nada!", + "DEFAULT_GREY_PAD": "Ino se nada!", + "PADDED_4": "Ino se nada!", + "PADDED_8": "Ino se nada!", + "EXTRACTED_INIT_BOX": "Kind of naive", + "PADDED_4_EXTRACTED": "No se rindan!", + "PADDED_8_EXTRACTED": "No se rindan!", + "PADDED_8_DILATION_1": "No se nadar!", + "PAD_8_FRACT_0_5": "No se nadar!", + "PAD_8_FRACT_0_2": "No se nadar!" + }, + "8": { + "INITIAL_BOX": "Tengo que silenciar, ciarlo, jentien-des?", + "DEFAULT": "Tengo que silenciar a carlos, jentien-des?", + "DEFAULT_GREY_PAD": "Tengo que silenciar, ciarlo, sent\u00eden-des?", + "PADDED_4": "Tengo que silenciar a ciarlo, \u00bfentienes- des?", + "PADDED_8": "Tengo que silenciar a ciarlo, dentien-des?", + "EXTRACTED_INIT_BOX": "Tango glue silen- claro de mentien- daisy?", + "PADDED_4_EXTRACTED": "Tango que salon- charlos. zentien- dusty?", + "PADDED_8_EXTRACTED": "Tengo que salvar a charles. sienten-dise?", + "PADDED_8_DILATION_1": "Tengo que silenciar- ciarlos, sentien- des?", + "PAD_8_FRACT_0_5": "Tengo que salvar a carlos, sentimiento-desesper?", + "PAD_8_FRACT_0_2": "Tengo que silenciar a carlos, cient\u00eden-des?" + }, + "9": { + "INITIAL_BOX": "Ahora, \u00bfhabla?", + "DEFAULT": "Ahora, \u00a1habla!", + "DEFAULT_GREY_PAD": "Ahora, \u00a1habla!", + "PADDED_4": "Ahora, \u00a1h\u00e1bla!", + "PADDED_8": "Ahora, \u00a1habla!", + "EXTRACTED_INIT_BOX": "Algunos de mis hablabs?", + "PADDED_4_EXTRACTED": "Ahira! hablas?", + "PADDED_8_EXTRACTED": "Ahora y habla!", + "PADDED_8_DILATION_1": "Ahora, ihablav", + "PAD_8_FRACT_0_5": "Ahora, nhablan", + "PAD_8_FRACT_0_2": "Ahora, hablamos!" + }, + "10": { + "INITIAL_BOX": "\u00bfc\u00f3mo est\u00e1s encu-briendo a alguien?", + "DEFAULT": "\u00bfest\u00e1s en cu- briendo a alguien?", + "DEFAULT_GREY_PAD": "\u00bfc\u00f3mo est\u00e1s encu- briendo a alguien?", + "PADDED_4": "\u00bfc\u00f3mo est\u00e1s enchu- briendo a alguien?", + "PADDED_8": "\u00bfest\u00e1s en cu- briendo a alguien?", + "EXTRACTED_INIT_BOX": "\u00bfqui\u00e9n es encuentro? es un alguien?", + "PADDED_4_EXTRACTED": "\u00bfqui\u00e9n es enrique? siempre lo llamo - aval - g\u00fcem\u00e9n?", + "PADDED_8_EXTRACTED": "Les tas enciu- bienido a al- guilen?", + "PADDED_8_DILATION_1": "\u00bfest\u00e1s encu-briendo a alguien?", + "PAD_8_FRACT_0_5": "Les tas enciu- briendo a al-quien?", + "PAD_8_FRACT_0_2": "\u00bfest\u00e1s en cu- briendo a alguien?" + } + }, + "Barnaby_v1-028.png": { + "1": { + "DEFAULT_GREY_PAD": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "INITIAL_BOX": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "DEFAULT": "We haven't any cattle and pop's victory garden is growing fine... and i don't think we've had much trouble with werewolves at all.", + "PADDED_4": "We haven't any cattle and pop's victory garden is growing fine... and i don't think we've had much trouble with werewolves at all.", + "PADDED_8": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "EXTRACTED_INIT_BOX": "We haven't any castle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all!", + "PADDED_4_EXTRACTED": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PADDED_8_EXTRACTED": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PADDED_8_DILATION_1": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PAD_8_FRACT_0_5": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PAD_8_FRACT_0_2": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all." + }, + "0": { + "INITIAL_BOX": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "DEFAULT": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "DEFAULT_GREY_PAD": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality. ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "PADDED_4": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality. ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "PADDED_8": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality. ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "EXTRACTED_INIT_BOX": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "PADDED_4_EXTRACTED": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality. ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "PADDED_8_EXTRACTED": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality. ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "PADDED_8_DILATION_1": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "PAD_8_FRACT_0_5": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality. ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ...", + "PAD_8_FRACT_0_2": "Barnaby, i should like to bestow a boon upon this household in return for its hospitality. ... shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? ..." + }, + "2": { + "INITIAL_BOX": "Then perhaps i can drive out snakes? or witch a well? ...", + "DEFAULT": "Then perhaps i can drive out snakes? or witch a well? ...", + "DEFAULT_GREY_PAD": "Then perhaps i can drive out snakes? or witch a well? ...", + "PADDED_4": "Then perhaps i can drive out snakes? or witch a well? ...", + "PADDED_8": "Then perhaps i can drive out snakes? or witch a well? ...", + "EXTRACTED_INIT_BOX": "Then perhaps i can drive out snakes? or switch a well? ...", + "PADDED_4_EXTRACTED": "Then perhaps i can drive out snakes? or switch a well? ...", + "PADDED_8_EXTRACTED": "Then perhaps i can drive out snakes? or witch a well? ...", + "PADDED_8_DILATION_1": "Then perhaps i can drive out snakes? or witch a well? ...", + "PAD_8_FRACT_0_5": "Then perhaps i can drive out snakes? or witch a well? ...", + "PAD_8_FRACT_0_2": "Then perhaps i can drive out snakes? or witch a well? ..." + }, + "3": { + "INITIAL_BOX": "Where the end of this dividing rod turns to the earth we'll find water.", + "DEFAULT": "Where the end of this dividing rod turns to the earth we'll find water.", + "DEFAULT_GREY_PAD": "Where the end of this divining rod turns to the earth we'll find water.", + "PADDED_4": "Where the end of this divining rod turns to the earth we'll find water.", + "PADDED_8": "Where the end of this divining rod turns to the earth we'll find water.", + "EXTRACTED_INIT_BOX": "Where are the ends of this diverging road leads to the earth we'll find water...", + "PADDED_4_EXTRACTED": "Where are the end of this dividing road turns to the earth we'll find water.", + "PADDED_8_EXTRACTED": "Where the end of this dividing rod turns to the earth we'll find water.", + "PADDED_8_DILATION_1": "Where the end of this dividing rod turns to the earth we'll find water.", + "PAD_8_FRACT_0_5": "Where the end of this dividing rod turns to the earth we'll find water.", + "PAD_8_FRACT_0_2": "Where the end of this dividing rod turns to the earth we'll find water." + }, + "4": { + "INITIAL_BOX": "Gosh... don't go to a lot of trouble, mr.. o'malley", + "DEFAULT": "Gosh... don't go to a lot of trouble, mr.. o'malley", + "DEFAULT_GREY_PAD": "Gosh. don't go to a lot of trouble, mr. o'malley.", + "PADDED_4": "Gosh. don't go to a lot of trouble, mr. o'malley ...", + "PADDED_8": "Gosh. don't go to a lot of trouble, mr. o'malley.", + "EXTRACTED_INIT_BOX": "Gosh... don't go too far of trouble, mr. o'malley.", + "PADDED_4_EXTRACTED": "Gosh... don't go too far a look of trouble, mr. o'malley...", + "PADDED_8_EXTRACTED": "Gosh... don't go to a lot of trouble, mr. o'malley.", + "PADDED_8_DILATION_1": "Gosh... don't go to a lot of trouble, mr. o'malley.", + "PAD_8_FRACT_0_5": "Gosh... don't go to a lot of trouble, mr. o'malley.", + "PAD_8_FRACT_0_2": "Gosh... don't go to a lot of trouble, mr. o'malley." + }, + "5": { + "INITIAL_BOX": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad.", + "DEFAULT": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad.", + "DEFAULT_GREY_PAD": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad.", + "PADDED_4": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad.", + "PADDED_8": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad.", + "EXTRACTED_INIT_BOX": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lord.", + "PADDED_4_EXTRACTED": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lord.", + "PADDED_8_EXTRACTED": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad.", + "PADDED_8_DILATION_1": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m'lad.", + "PAD_8_FRACT_0_5": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad.", + "PAD_8_FRACT_0_2": "When you grow to manhood and inherit this estate you 'll thank your fairy godfather for this well right in your cellar, m'lad." + }, + "6": { + "INITIAL_BOX": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fetch me a forked stick, m'boy.", + "DEFAULT": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... feych me a forked stick, m'boy.", + "DEFAULT_GREY_PAD": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fetch me a forked stick, m'boy.", + "PADDED_4": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fetch me a forked stick, m'boy.", + "PADDED_8": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fetch me a forked stick, m'boy.", + "EXTRACTED_INIT_BOX": "'ah, that's it! i shall bestow the blessing of a never-failing water supply upon this pilot of land ... feron me a forked stick, m'boy.", + "PADDED_4_EXTRACTED": "Ah, that's in it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... feron me a forked stick, m'boy.", + "PADDED_8_EXTRACTED": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fetch me a forked stick, m'boy.", + "PADDED_8_DILATION_1": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fehch me a forked stick, m'boy.", + "PAD_8_FRACT_0_5": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fetch me a forked stick, m'boy.", + "PAD_8_FRACT_0_2": "Ah, that's it! i shall bestow the blessing of a never-failing water supply upon this plot of land ... fetch me a forked stick, m'boy." + }, + "7": { + "INITIAL_BOX": "But we've got city water, mr. o'malley ...", + "DEFAULT": "But we've got city water, mr. o'malley.", + "DEFAULT_GREY_PAD": "But we've got city matter, mr. o'malley.", + "PADDED_4": "But we've got city writter, mr. o'malley.", + "PADDED_8": "But we've got city whisker, mr. o'malley.", + "EXTRACTED_INIT_BOX": "But we've got fifty wrestlers, mr. o'malley ...", + "PADDED_4_EXTRACTED": "But we've got city workers, mr.. o'malley.", + "PADDED_8_EXTRACTED": "But we've got city winter, mr. o'malley.", + "PADDED_8_DILATION_1": "But we've got city writter, mr. o'malley.", + "PAD_8_FRACT_0_5": "But we've got city weather, mr. o'malley.", + "PAD_8_FRACT_0_2": "But we've got city water, mr. o'malley." + }, + "8": { + "INITIAL_BOX": "Er ... is there any beer on ice, m'boy?", + "DEFAULT": "Er ... is there any beer on ice, mi'boy?", + "DEFAULT_GREY_PAD": "Er ... is there any beer on ice, mi'boy?", + "PADDED_4": "Er ... is there any beer on ice, mi'boy?", + "PADDED_8": "Er ... is there any beer on ice, mi'boy?", + "EXTRACTED_INIT_BOX": "Er ... is there any heavier ice, m'boy?", + "PADDED_4_EXTRACTED": "Ehr ... is there any heavier on ice, m'boy?", + "PADDED_8_EXTRACTED": "Er ... is there any beer on ice, m'boy?", + "PADDED_8_DILATION_1": "Br ... is there any beer on ice, m'boy?", + "PAD_8_FRACT_0_5": "Ehr ... is there any beer on ice, m'boy?", + "PAD_8_FRACT_0_2": "Er ... is there any beer on ice, m'boy?" + }, + "9": { + "INITIAL_BOX": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ....", + "DEFAULT": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirstily merely to describe it ....", + "DEFAULT_GREY_PAD": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ....", + "PADDED_4": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ....", + "PADDED_8": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ....", + "EXTRACTED_INIT_BOX": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ...", + "PADDED_4_EXTRACTED": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ...", + "PADDED_8_EXTRACTED": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ....", + "PADDED_8_DILATION_1": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ...", + "PAD_8_FRACT_0_5": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ....", + "PAD_8_FRACT_0_2": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth ... makes me thirsty merely to describe it ...." + }, + "10": { + "INITIAL_BOX": "The rockety johnson", + "DEFAULT": "The rockett johnson", + "DEFAULT_GREY_PAD": "Grockett johnson", + "PADDED_4": "Crockett johnson", + "PADDED_8": "Crockett johnson", + "EXTRACTED_INIT_BOX": "The rocky johnson family", + "PADDED_4_EXTRACTED": "G-rock: hey john! son!", + "PADDED_8_EXTRACTED": "E-roc mey john m son", + "PADDED_8_DILATION_1": "Grocket johnson", + "PAD_8_FRACT_0_5": "E rock me? john mason", + "PAD_8_FRACT_0_2": "G rocket? john mason" + }, + "11": { + "INITIAL_BOX": "We can really get along all right with the city water supply ...", + "DEFAULT": "We can really get along all right with the city water supply ....", + "DEFAULT_GREY_PAD": "We can really get along all right with the city water supply ....", + "PADDED_4": "We can really get along all right with the city water supply ...", + "PADDED_8": "We can really get along all right with the city water supply ....", + "EXTRACTED_INIT_BOX": "We can really get along all right with the city water supply ...", + "PADDED_4_EXTRACTED": "\"we can really get along all right within the city water supply ...", + "PADDED_8_EXTRACTED": "\"we can really get along all right with the city water supply ...", + "PADDED_8_DILATION_1": "We can really get along all right with the city water supply ...", + "PAD_8_FRACT_0_5": "\" we can really get along all right with the city water supply ...", + "PAD_8_FRACT_0_2": "\" we can really get along all right with the city water supply ..." + }, + "12": { + "INITIAL_BOX": "Hush, m'boy. this is a time of conservation.", + "DEFAULT": "Hush, m'boy. this is a time of conservation.", + "DEFAULT_GREY_PAD": "Hush, m'boy. this is a time of conservation..", + "PADDED_4": "Hush, m'boy. this is a time of conservation..", + "PADDED_8": "Hush, m'boy. this is a time of conservation..", + "EXTRACTED_INIT_BOX": "Hush, m'boy. this is a time of conservation...", + "PADDED_4_EXTRACTED": "Hush, m'boy. this is a time of conservation.", + "PADDED_8_EXTRACTED": "Mush, m'booy. this is a time of conservation.", + "PADDED_8_DILATION_1": "Hush, m'boy! this is a time of conservation.", + "PAD_8_FRACT_0_5": "Hush, m'booy. this is a time of conservation.", + "PAD_8_FRACT_0_2": "Hush, m'thoy. this is a time of conservation." + }, + "13": { + "INITIAL_BOX": "We're being patriotic.", + "DEFAULT": "We're being patriotic.", + "DEFAULT_GREY_PAD": "We're being patriotic.", + "PADDED_4": "We're being patriotic.", + "PADDED_8": "We're being patriotic -.", + "EXTRACTED_INIT_BOX": "We 're being patronizing --", + "PADDED_4_EXTRACTED": "We 're being patriotic --", + "PADDED_8_EXTRACTED": "We 're being patriotic.", + "PADDED_8_DILATION_1": "We 're leaving paradise -.", + "PAD_8_FRACT_0_5": "We're being patriotic.", + "PAD_8_FRACT_0_2": "We 're being patriotic." + }, + "14": { + "INITIAL_BOX": "Ah! here's the place! bring the pickaxe.", + "DEFAULT": "Ah! here's the place! bring the pickaxe.", + "DEFAULT_GREY_PAD": "Aha! here's the place! bring the pickaxe.", + "PADDED_4": "Ah! here's the place! bring the pickaxe.", + "PADDED_8": "Ah! here's the place! bring the pickaxe.", + "EXTRACTED_INIT_BOX": "Ah! here's the place! bringing the pickoxxe.", + "PADDED_4_EXTRACTED": "Aah! here's the place! bring the pickaxe.", + "PADDED_8_EXTRACTED": "Aha! here's the place! bring the pickaxe.", + "PADDED_8_DILATION_1": "Ah! here's the place! bring the pickaxe.", + "PAD_8_FRACT_0_5": "Aha! here's the place! bring the pickaxe.", + "PAD_8_FRACT_0_2": "Aha! here's the place! bring the pickaxe." + }, + "15": { + "INITIAL_BOX": "Crockett johnson", + "DEFAULT": "Crockett johnson", + "DEFAULT_GREY_PAD": "Crockett johnson", + "PADDED_4": "Crockett johnson", + "PADDED_8": "Crockett johnson", + "EXTRACTED_INIT_BOX": "Crockett johnson.", + "PADDED_4_EXTRACTED": "Crockett johnson", + "PADDED_8_EXTRACTED": "Crockett john sonei", + "PADDED_8_DILATION_1": "Crockett johnson", + "PAD_8_FRACT_0_5": "Crockett johnson", + "PAD_8_FRACT_0_2": "Crockett johnson" + } + }, + "Barnaby_v1-029.png": { + "1": { + "DEFAULT_GREY_PAD": "Maybe pop doesn't want a well.", + "INITIAL_BOX": "Maybe pop doesn't want a well.", + "DEFAULT": "Maybe pop doesn't want a well..", + "PADDED_4": "Maybe pop doesn't want a well.", + "PADDED_8": "Maybe pop doesn't want a well.", + "EXTRACTED_INIT_BOX": "Maybe pop doesn't want a wreath.", + "PADDED_4_EXTRACTED": "Maybobo pop doesn't want a woll?", + "PADDED_8_EXTRACTED": "A mayo-pop pop doesn't want a well-.", + "PADDED_8_DILATION_1": "Maybob pop doesn't want a woll.", + "PAD_8_FRACT_0_5": "Maybebob pop doesn't want a well.", + "PAD_8_FRACT_0_2": "Maybob pop doesn't want a well." + }, + "0": { + "INITIAL_BOX": "Trust your old fairy godfather to find the best spot in the cellar for a well. right handy to the stairs. bring the pick.", + "DEFAULT": "Trust your old fairy godfather to find the best spot in the cellar for a well. right handy to the stairs. bring the pick.", + "DEFAULT_GREY_PAD": "Trust your old fairy godfather to find the best spot in the cellar for a well. right handy to the stairs. bring the pick.", + "PADDED_4": "Trust your old fairy godfather to find the best spot in the cellar for a well... right handy to the stairs... bring the pick,.", + "PADDED_8": "Trust your old fairy godfather to find the best spot in the cellar for a well. right handy to the stairs. bring the pick.", + "EXTRACTED_INIT_BOX": "Trust your old fairy godfather to find the best spot in the cellar for a well. right handy to the stairs. bring the pick,.", + "PADDED_4_EXTRACTED": "Trust your old fairy godfather to find the best spot in the cellar for a well. right handy to the stairs, bring the pick,", + "PADDED_8_EXTRACTED": "Trust your old fairy godfathers to find the best sport in the collar for a well! right handy man with fine stains. bring the pick,", + "PADDED_8_DILATION_1": "Trust your old fairy godfather to find the best spot in the cellar for a well. right handy man to find the stain. bring the pick,", + "PAD_8_FRACT_0_5": "Trust your old fairy godfather to find the best spot in the collar for a well. right handy fella to find stains. bring the pick.", + "PAD_8_FRACT_0_2": "Trust your old fairy godfather to find the best spot in the collar for a well. right handy fella to find stains. bring the pick." + }, + "2": { + "INITIAL_BOX": "Nonsense, mi'boy. your whole family will be delighted.", + "DEFAULT": "Nonsense, mi'boy. your whole family will be delighted.", + "DEFAULT_GREY_PAD": "Nonsense, m'boy. your whole family will be delighted.", + "PADDED_4": "Nonsense, m'boy. your whole family will be delighted.", + "PADDED_8": "Nonsense, m'boy. your whole family will be delighted.", + "EXTRACTED_INIT_BOX": "Nonnenseo, m'boy. your whole family will be delighted.", + "PADDED_4_EXTRACTED": "Monsense, m'lord! your whole family will be delighted.", + "PADDED_8_EXTRACTED": "Nonsense, m'boy. your whole family will be delighted.", + "PADDED_8_DILATION_1": "Nonsense, m'boy. your whole family will be delighted.", + "PAD_8_FRACT_0_5": "Nonsense, m'boy. your whole family will be delighted.", + "PAD_8_FRACT_0_2": "Nonsense, m'boy. your whole family will be delighted." + }, + "3": { + "INITIAL_BOX": "That 's not water, mr. o'malley! did something go wrong?", + "DEFAULT": "That 's not water, mr. o'malley: did something go wrong?", + "DEFAULT_GREY_PAD": "That 's not water, mr. o'malley! did something go wrong?", + "PADDED_4": "That 's not water, mr. o'malley! did something go wrong?", + "PADDED_8": "That 's not water, mr. o'malley! did something go wrong?", + "EXTRACTED_INIT_BOX": "That 's not weather, mr. o'malley! did something go wrong?", + "PADDED_4_EXTRACTED": "That 's not water, mr. o'malley! did something go wrong?", + "PADDED_8_EXTRACTED": "\" that 's not water, mr. o'malley! did something go wrong?", + "PADDED_8_DILATION_1": "That's not water, mr. o'malley! did something go wrong?", + "PAD_8_FRACT_0_5": "That 's not water, mr. o'malley! did something go wrong?", + "PAD_8_FRACT_0_2": "That 's not water, mr. o'malley! did something go wrong?" + }, + "4": { + "INITIAL_BOX": "Cushlamochree?", + "DEFAULT": "Cushlamochree?", + "DEFAULT_GREY_PAD": "Cushlamochree?", + "PADDED_4": "Cushlamochree?", + "PADDED_8": "Cushlamochree!", + "EXTRACTED_INIT_BOX": "Crystal-ammo! charge?", + "PADDED_4_EXTRACTED": "Cushlie-larnum! oh dearie!", + "PADDED_8_EXTRACTED": "Cushlieannn@ch3ree?", + "PADDED_8_DILATION_1": "Cushlamoochree!", + "PAD_8_FRACT_0_5": "Cushla! oh ghreee?", + "PAD_8_FRACT_0_2": "Cushla! oh no?" + }, + "5": { + "INITIAL_BOX": "It does seem a bit brackish, doesn't it, m'boy. perhaps some ill-natured demon or?", + "DEFAULT": "It does seem a bit brackish, doesn't it, m'boy. perhaps some ill-natured demon ...?", + "DEFAULT_GREY_PAD": "It does seem a bit brackish, doesn't it, m'boy. perhaps some ill-natured demon or ...", + "PADDED_4": "It does seem a bit brackish, doesn't it, m'boy. perhaps some ill-natured demon ...?", + "PADDED_8": "It does seem a bit brackish, doesn't it, m'boy. perhaps some ill-natured demon ...?", + "EXTRACTED_INIT_BOX": "It does seem a bit brockish, doesn't it, milady. perhaps some ill-matured demon ...?", + "PADDED_4_EXTRACTED": "It does seem a bit backish, doesn't it, m'boy. perhaps some ill-natured demon? \"", + "PADDED_8_EXTRACTED": "It does seem a bit barbarickish, doesn't it, m'boy. perhaps some ill-natured demon ?", + "PADDED_8_DILATION_1": "It does seem a bit backassish, doesn't it, m'boy. perhaps some ill-natured demon ...? \"", + "PAD_8_FRACT_0_5": "It does seem a bit barbarickish, doesn't it, m'boy. perhaps some ill-natured demon so ...", + "PAD_8_FRACT_0_2": "It does seem a bit backackish, doesn't it, m'boy. perhaps some ill-natured demon so>" + }, + "6": { + "INITIAL_BOX": "May 22 - 23", + "DEFAULT": "May 22 - 23", + "DEFAULT_GREY_PAD": "May 22 - 23", + "PADDED_4": "May 22 - 23", + "PADDED_8": "May 22 - 23", + "EXTRACTED_INIT_BOX": "Molly - 22 - 23", + "PADDED_4_EXTRACTED": "J'mary 22 - 23", + "PADDED_8_EXTRACTED": "Myory 22 - 23", + "PADDED_8_DILATION_1": "May 22 - 23", + "PAD_8_FRACT_0_5": "Mary 22 - 23", + "PAD_8_FRACT_0_2": "Mary 22 - 23" + }, + "7": { + "INITIAL_BOX": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "DEFAULT": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "DEFAULT_GREY_PAD": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "PADDED_4": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "PADDED_8": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "EXTRACTED_INIT_BOX": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest water.", + "PADDED_4_EXTRACTED": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest water", + "PADDED_8_EXTRACTED": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "PADDED_8_DILATION_1": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "PAD_8_FRACT_0_5": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ...", + "PAD_8_FRACT_0_2": "This well will put the city's water supply to shame. a few blows of the pick will usher up the coolest, clearest ..." + }, + "8": { + "INITIAL_BOX": "Crockett johnson", + "DEFAULT": "Crocksby johnson", + "DEFAULT_GREY_PAD": "Crockett johnson", + "PADDED_4": "Crockett johnson", + "PADDED_8": "Crockett johnson", + "EXTRACTED_INIT_BOX": "Crooked by john sonney", + "PADDED_4_EXTRACTED": "Crosby johnson", + "PADDED_8_EXTRACTED": "Crockett johnson", + "PADDED_8_DILATION_1": "Grockit johnston", + "PAD_8_FRACT_0_5": "Crockett johnson", + "PAD_8_FRACT_0_2": "Crockett johnson" + }, + "9": { + "INITIAL_BOX": "Or could my divining rod have been short of the new regulation witching standards?", + "DEFAULT": "Or could my divining rod have been short of the new regulation water witching standards?", + "DEFAULT_GREY_PAD": "Or could my divining rod have been short of the new regulation witching standards?", + "PADDED_4": "Or could my divining rod have been short of the new regulation water witching standards?", + "PADDED_8": "Or could my divining rod have been short of the new regulation witching standards?", + "EXTRACTED_INIT_BOX": "Or could my dividing road have been short of the new regulation wichiting standards?", + "PADDED_4_EXTRACTED": "Or could my divining rod have been short of the new regulation whatever witching standards?", + "PADDED_8_EXTRACTED": "Or could my divining rod have been short of the new regulation width w/itching standards?", + "PADDED_8_DILATION_1": "Or could my divining rod have been short of the new regulation wattching standards?", + "PAD_8_FRACT_0_5": "Or could my divining rod have been short of the new regulation width witching standards?", + "PAD_8_FRACT_0_2": "Or could my divining rod have been short of the new regulation witching standards?" + }, + "10": { + "INITIAL_BOX": "Mr., o'malley!?", + "DEFAULT": "Mr., o'malley!?", + "DEFAULT_GREY_PAD": "Mr. o'malley!?", + "PADDED_4": "Mr. o'malley!?", + "PADDED_8": "Mr. o'malley!", + "EXTRACTED_INIT_BOX": "\" mr. o'malley!?", + "PADDED_4_EXTRACTED": "Mr. o'malletley!?", + "PADDED_8_EXTRACTED": "Mr. . o'malletley!?", + "PADDED_8_DILATION_1": "Mr. o'malley!?", + "PAD_8_FRACT_0_5": "Mr. o'maltley!?", + "PAD_8_FRACT_0_2": "Mr. o'maltley!?" + }, + "11": { + "INITIAL_BOX": "We've struck oil?", + "DEFAULT": "We've struck oil?", + "DEFAULT_GREY_PAD": "We've struck oil?", + "PADDED_4": "We've struck oil?", + "PADDED_8": "We've struck oil?", + "EXTRACTED_INIT_BOX": "How 've we been sherlock?", + "PADDED_4_EXTRACTED": "We 've struck oil?", + "PADDED_8_EXTRACTED": "We've struck oil?", + "PADDED_8_DILATION_1": "We've struck oil?", + "PAD_8_FRACT_0_5": "We've struck oil?", + "PAD_8_FRACT_0_2": "We've struck oil?" + }, + "12": { + "INITIAL_BOX": "Crockett johnson", + "DEFAULT": "Crockett johnson", + "DEFAULT_GREY_PAD": "Crockett johnson", + "PADDED_4": "Crockett johnson", + "PADDED_8": "Crockett johnson", + "EXTRACTED_INIT_BOX": "Crockett johnson", + "PADDED_4_EXTRACTED": "Chockett johnson", + "PADDED_8_EXTRACTED": "Chockett johnson", + "PADDED_8_DILATION_1": "Crockett johnson", + "PAD_8_FRACT_0_5": "Crockett johnson", + "PAD_8_FRACT_0_2": "Crockett johnson" + } + }, + "FOX_CHILLINTALES_T17_012.jpg": { + "1": { + "DEFAULT_GREY_PAD": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me ...", + "INITIAL_BOX": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me ...", + "DEFAULT": "At last the door swung open to reveal a gadaverous old man who peered out into the darkness at me ...", + "PADDED_4": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me ...", + "PADDED_8": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me ...", + "EXTRACTED_INIT_BOX": "At last the door swung open to reveal a canaverous old man who peered out into the darkness at me.", + "PADDED_4_EXTRACTED": "At last the door swung open to reveal a dastardly old man who peered out into the darkness at me.", + "PADDED_8_EXTRACTED": "At last the door swung open to reveal a dastardly old man who peered out into the darkness at me.", + "PADDED_8_DILATION_1": "At last the door swung open to reveal a gadabout old man who peered out into the darkness at me.", + "PAD_8_FRACT_0_5": "At last the door swung open to reveal a dastardly old man who peered out into the darkness at me.", + "PAD_8_FRACT_0_2": "At last the door swung open to reveal a dastardly old man who peered out into the darkness at me." + }, + "0": { + "INITIAL_BOX": "Who are you? what do you want?", + "DEFAULT": "Who are you? what do you want?", + "DEFAULT_GREY_PAD": "Who are you? what do you want?", + "PADDED_4": "Who are you? what do you want?", + "PADDED_8": "Who are you? what do you want?", + "EXTRACTED_INIT_BOX": "Who are you? what do you want?", + "PADDED_4_EXTRACTED": "Who are you? what do you want?", + "PADDED_8_EXTRACTED": "Who are you? what do you want?", + "PADDED_8_DILATION_1": "Who are you? what do you want?", + "PAD_8_FRACT_0_5": "Who are you? what do you want?", + "PAD_8_FRACT_0_2": "Who are you? what do you want?" + }, + "2": { + "INITIAL_BOX": "I want to see professor blutress. the agency sent me.", + "DEFAULT": "I want to see professor blutress. the agency sent me.", + "DEFAULT_GREY_PAD": "I want to see professor blutress. the agency sent me.", + "PADDED_4": "I want to see professor blutress . the agency sent me.", + "PADDED_8": "I want to see professor blutress. the agency sent me.", + "EXTRACTED_INIT_BOX": "I want to see professor blutress . the agency sent me.", + "PADDED_4_EXTRACTED": "I want to see professor blutress . the agency sent me.", + "PADDED_8_EXTRACTED": "I want to see professor blutress . the agency sent me.", + "PADDED_8_DILATION_1": "I want to see professor blutriss. the agency sent me.", + "PAD_8_FRACT_0_5": "I want to see professor blutress . the agency sent me.", + "PAD_8_FRACT_0_2": "I want to see professor blutress . the agency sent me." + }, + "3": { + "INITIAL_BOX": "Oh, yes. you must be the secretary i sent for. i'm professor blutress -- come in.", + "DEFAULT": "Oh, yes. you must be the secretary i sent for. i'm professor blutress--- come in. come in.", + "DEFAULT_GREY_PAD": "Oh, yes. you must be the secretary i sent for. i'm professor blutress -- come in. come in.", + "PADDED_4": "Oh, yes, you must be the secretary i sent for. i'm professor blutress -- come in. come in.", + "PADDED_8": "Oh, yes. you must be the secretary i sent for. i'm professor blutress -- come in. come in.", + "EXTRACTED_INIT_BOX": "Oh, yes, you must be the secretary i sent for. i'm professor blutress -- come in. come in.", + "PADDED_4_EXTRACTED": "Oh, yes, you must be the secretary i sent for. i'm professor blutress-- come in. come in.", + "PADDED_8_EXTRACTED": "Oh, yes, you must be the secretary i sent for. i'm professor blutress-- come in, come in.", + "PADDED_8_DILATION_1": "Oh, yes, you must be the secretary i sent for. i'm professor blutress -- come in, come in.", + "PAD_8_FRACT_0_5": "Oh, yes, you must be the secretary i sent for. i'm professor blutress-- come in, come in.", + "PAD_8_FRACT_0_2": "Oh, yes, you must be the secretary i sent for. i'm professor blutress-- come in, come in." + }, + "4": { + "INITIAL_BOX": "As we entered the pro- fessor's study an unearthly scream came from the dark recesses of the house ...", + "DEFAULT": "As we entered the pro- fessor's study an unearthly scream came from the dark recesses of the house ...", + "DEFAULT_GREY_PAD": "As we entered the pro- fessor's study an unearthly scream came from the dark recesses of the house ...", + "PADDED_4": "As we entered the pro- fessor's study an unearthly scream came from the dark recesses of the house ...", + "PADDED_8": "As we entered the pro- fessor's study an unearthly scream came from the dark recesses of the house ...", + "EXTRACTED_INIT_BOX": "We're ed ro's reunion of romark ecesses of the e house.", + "PADDED_4_EXTRACTED": "We ed ro's re form ark recesses of e house.", + "PADDED_8_EXTRACTED": "We ed ro's re rom ark excesses of e house.", + "PADDED_8_DILATION_1": "We ed ro's re rom ark ecgeses of e house.", + "PAD_8_FRACT_0_5": "We ed ro's re rom ark excesses of e house.", + "PAD_8_FRACT_0_2": "We ed ro's re rom e ark ecesses of e house." + }, + "5": { + "INITIAL_BOX": "Good lord! what was that? it sounded like a scream?", + "DEFAULT": "Good lord! what was that? it sounded like a scream?", + "DEFAULT_GREY_PAD": "Good lord! what was that? it sounded like a scream?", + "PADDED_4": "Good lord! what was that? it sounded like a scream?", + "PADDED_8": "Good lord! what was that? it sounded like a scream?", + "EXTRACTED_INIT_BOX": "Good lord! what was that? it sounded like a scream!", + "PADDED_4_EXTRACTED": "Good lord! what was that? it sounded like a scream?", + "PADDED_8_EXTRACTED": "Good lord! what was that? it sounded like a scream?", + "PADDED_8_DILATION_1": "Good lord! what was that? it sounded like a scream?", + "PAD_8_FRACT_0_5": "Good lord! what was that? it sounded like a scream?", + "PAD_8_FRACT_0_2": "Good lord! what was that? it sounded like a scream?" + }, + "6": { + "INITIAL_BOX": "A scream? i heard nothing, mr. howe.", + "DEFAULT": "A scream? i heard nothing, mr. howe.", + "DEFAULT_GREY_PAD": "A scream? i heard nothing, mr. howe.", + "PADDED_4": "A scream? i heard nothing, mr. howe.", + "PADDED_8": "A scream? i heard nothing, mr. howe.", + "EXTRACTED_INIT_BOX": "A scream? i heard nothing, mr. howe.", + "PADDED_4_EXTRACTED": "A scream? i heard nothing, mr. howe.", + "PADDED_8_EXTRACTED": "A scream? i heard nothing, mr. howe..", + "PADDED_8_DILATION_1": "A scream? i heard nothing, mr. howe.", + "PAD_8_FRACT_0_5": "A scream? i heard nothing, mr. howe..", + "PAD_8_FRACT_0_2": "A scream? i heard nothing, mr. howe." + }, + "7": { + "INITIAL_BOX": "I could have sworn - perhaps it was just my imagination.", + "DEFAULT": "I could have sworn ... perhaps it was just my imagination.", + "DEFAULT_GREY_PAD": "I could have sworn-- perhaps it was just my imagination.", + "PADDED_4": "I could have sworn ... perhaps it was just my imagination.", + "PADDED_8": "I could have sworn ... perhaps it was just my imagination.", + "EXTRACTED_INIT_BOX": "I could have sworn - perhaps it was just my imagination.", + "PADDED_4_EXTRACTED": "I could have sworn --- perhaps it was just my imagination.", + "PADDED_8_EXTRACTED": "I could have sworn -- perhaps it was just my imagination.", + "PADDED_8_DILATION_1": "I could've have sworn -- perhaps it was just my imagination.", + "PAD_8_FRACT_0_5": "I could have sworn-- perhaps it was just my imagination.", + "PAD_8_FRACT_0_2": "I could have sworn -- perhaps it was just my imagination." + }, + "8": { + "INITIAL_BOX": "\" you are tired. let me take you to your room. we 'll discuss your duties in the morning ... come ...", + "DEFAULT": "\" you are tired. let me take you to your room. we 'll discuss your duties in the morning ... come ...", + "DEFAULT_GREY_PAD": "\" you are tired. let me take you to your room. we 'll discuss your duties in the morning ... come ...", + "PADDED_4": "\" you are tired. let me take you to your room. we 'll discuss your duties in the morning ... come ...", + "PADDED_8": "\" you are tired. let me take you to your room. we 'll discuss your duties in the morning ... come ...", + "EXTRACTED_INIT_BOX": "--- you are tired. let me take you to your room. we'll discuss your duties in the morning ... come ...", + "PADDED_4_EXTRACTED": "\"you are tired. let me take you to your room. we'll discuss your duties in the morning ... come ...", + "PADDED_8_EXTRACTED": "\"you are tired. let me take you to your room. we'll discuss your duties in the morning... come...\".", + "PADDED_8_DILATION_1": "\" you are tired. just let me take you to your room. we 'll discuss your duties in the morning ... come ...", + "PAD_8_FRACT_0_5": "\" you are tired. just let me take you to your room. we 'll discuss your duties in the morning ... come ...", + "PAD_8_FRACT_0_2": "\" turn -- you are tired. just let me take you to your room. we 'll discuss your duties in the morning ... come ..." + }, + "9": { + "INITIAL_BOX": "\"the next morning i woke early and started downstairs. on the way down i passed a heavy barred door ...", + "DEFAULT": "\"the next morning i woke early and started downstairs, on the way down i passed a heavy barred door ...", + "DEFAULT_GREY_PAD": "He next morning i awoke early and started downstairs, on the way down i passed a heavy barred door ...", + "PADDED_4": "The next morning i woke early and started downstairs. on the way down i passed a heavy barred door ...", + "PADDED_8": "They next morning i woke early and started downstairs, on the way down i passed a heavy barred door ...", + "EXTRACTED_INIT_BOX": "Working early and started downstairs, on the way down i passed a heavy barred door", + "PADDED_4_EXTRACTED": "Morning - early and started downstairs. on the way down i passed a heavy # warred dogo", + "PADDED_8_EXTRACTED": "Morning - early and started com'stains. on the way down i passed a heavy barred door", + "PADDED_8_DILATION_1": "Morning! a few minutes ago i passed a heavy barred door", + "PAD_8_FRACT_0_5": "Morning - early and started c*ckwinstains. on the way down i passed a heavy barred door", + "PAD_8_FRACT_0_2": "Morning - early and started c'ownstairs. on the way down i passed a heavy barred door" + }, + "10": { + "INITIAL_BOX": "Ugh! it's awful...", + "DEFAULT": "Ugh! it's awful...", + "DEFAULT_GREY_PAD": "Ugh! it's awful...", + "PADDED_4": "Ugh! it's awful...", + "PADDED_8": "Ugh! it's awful...", + "EXTRACTED_INIT_BOX": "Ugh! it's awful...", + "PADDED_4_EXTRACTED": "Ugh! it's awful...", + "PADDED_8_EXTRACTED": "Ugh! it's awful...", + "PADDED_8_DILATION_1": "Ugh! it's awful...", + "PAD_8_FRACT_0_5": "Ugh! it's awful...", + "PAD_8_FRACT_0_2": "Ugh! it's awful..." + }, + "11": { + "INITIAL_BOX": "That 's strange; i wonder what's behind it? it 's thick enough to be a vault.", + "DEFAULT": "That's strange! i wonder what's behind it? it's thick enough to be a vault.", + "DEFAULT_GREY_PAD": "That 's strange! i wonder what's behind it? it 's thick enough to be a vault.", + "PADDED_4": "That 's strange! i wonder what's behind it? it 's thick enough to be a vault.", + "PADDED_8": "That's strange! i wonder what's behind it? it's thick enough to be a vault.", + "EXTRACTED_INIT_BOX": "That's... strange! i wonder what's behind it? it's thick enough to be a vault.", + "PADDED_4_EXTRACTED": "That's...strange! i wonder what's behind it? it's thick enough to be a vault.", + "PADDED_8_EXTRACTED": "That's...strange! i wonder what's behind it? it's thick enough to be a vault.", + "PADDED_8_DILATION_1": "That's... strange? i wonder what's behind it? it's thick enough to be a vault.", + "PAD_8_FRACT_0_5": "That's... strange! i wonder what's behind it? it's thick enough to be a vault.", + "PAD_8_FRACT_0_2": "That's... strange! i wonder what's behind it? it's thick enough to be a vault." + }, + "12": { + "INITIAL_BOX": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of rotting flesh...", + "DEFAULT": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of rotting flesh...", + "DEFAULT_GREY_PAD": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_4": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_8": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "EXTRACTED_INIT_BOX": "Suddenly i became aware of a frightful door that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_4_EXTRACTED": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decaying flesh...", + "PADDED_8_EXTRACTED": "Suddenly i became aware of a frightful door that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_8_DILATION_1": "Suddenly i became aware of a frightful odor that seemed to come from beneath the door. the house eating of its attendants decayed, rotting flesh...", + "PAD_8_FRACT_0_5": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PAD_8_FRACT_0_2": "Suddenly i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh..." + } + }, + "MCCALL_ROBINHOOD_T31_010.jpg": { + "1": { + "DEFAULT_GREY_PAD": "Seize them! cut them down! don't let them escape!", + "INITIAL_BOX": "Seize them! cut them down! don't let them escape?", + "DEFAULT": "Seize them! cut them down! don't let them escape?", + "PADDED_4": "Seize them! cut them down! don't let them escape?", + "PADDED_8": "Seize them! cut them down! don't let them escape?", + "EXTRACTED_INIT_BOX": "Seize them! cut them down! don't let them escape!", + "PADDED_4_EXTRACTED": "Seize them! cut them down! don't let them escape!", + "PADDED_8_EXTRACTED": "Seize them! / cut them down! don't let them escape!", + "PADDED_8_DILATION_1": "Squeeze them! cut them down! don't let them escape!", + "PAD_8_FRACT_0_5": "Seize them! cut them down! don't let them escape!", + "PAD_8_FRACT_0_2": "Seize them! cut them down! don't let them escape !" + }, + "0": { + "INITIAL_BOX": "Like a flash, robin and luthor john race for an exit, the guards close on their heels ...and at that moment, little john's feet slip on the wood strewn on the floor...", + "DEFAULT": "Like a flash, robin and little john race for an exit, the guards close on their heels ... and that moment, little john's feet slip on the food strewn on the floor...", + "DEFAULT_GREY_PAD": "Like a flash, robin and little john race for an exit. the guards close on their heels ...and at that moment, little-john's feet slip on the gooey stewen on the floor...", + "PADDED_4": "Like a flash, robin and little john race for an exit. the guards close on their heels ... and at that moment, little-john's feet slip on the good stewen on the floor...", + "PADDED_8": "Like a flash, robin and little john race for an exit. the guards close on their heels and at that moment, little-john's feet slip on the gooey stewen on the floor...", + "EXTRACTED_INIT_BOX": "Like a flash, robin and little john exit the guards close on their heels at that moment, little john's feet slip on the straw strewn on the floor.", + "PADDED_4_EXTRACTED": "I make a flash. robin and little john exit the race for an exit. the guards close on their heels and at that moment, little john's feet slip on the strewn straw on the floor.", + "PADDED_8_EXTRACTED": "I make a flash robin and little john race for an exit. the guards close on their heels and at that moment, little john's feet slip on the straw-laden floor...", + "PADDED_8_DILATION_1": "Like a flash, robin and little johnin race for the gin exit, but the guards close on their heels at that moment, little john's feet slip on the greasy floor on the third step down to the good room.", + "PAD_8_FRACT_0_5": "I make a flash, robin and little john race for an exit, the guards close on their heels and at that moment, 'little' john's feet slip on the straw strewn on the floor...", + "PAD_8_FRACT_0_2": "I make a flash, robin and little john race for an exit. the guards close on their heels and at that moment, little john's feet slip on the straw strewn on the floor..." + }, + "2": { + "INITIAL_BOX": "Whoops?", + "DEFAULT": "Whoops?", + "DEFAULT_GREY_PAD": "Whoo-0ops?", + "PADDED_4": "Whoo-ops?", + "PADDED_8": "Whoops?", + "EXTRACTED_INIT_BOX": "Whoops?", + "PADDED_4_EXTRACTED": "Whoops?", + "PADDED_8_EXTRACTED": "Whoops?", + "PADDED_8_DILATION_1": "Whoops?", + "PAD_8_FRACT_0_5": "Whoops?", + "PAD_8_FRACT_0_2": "Whoops?" + }, + "3": { + "INITIAL_BOX": "Go on! get away if you can! don't bother about me?", + "DEFAULT": "Go on! get away if you can! don't bother about me?", + "DEFAULT_GREY_PAD": "Go on! get away if you can! don't bother about me?", + "PADDED_4": "Go on! get away if you can! don't bother about me?", + "PADDED_8": "Go on! get away if you can! don't bother about me?", + "EXTRACTED_INIT_BOX": "Go on! get away if you can! don't bother about me?", + "PADDED_4_EXTRACTED": "Go on! get away if you can! don't bother about me?", + "PADDED_8_EXTRACTED": "Go on! get away if you can! don't bother about me?", + "PADDED_8_DILATION_1": "Go on! get away if you can! don't bother about me?", + "PAD_8_FRACT_0_5": "Go on! get away if you can! don't bother about me?", + "PAD_8_FRACT_0_2": "Go on! get away if you can! don't bother about me?" + }, + "4": { + "INITIAL_BOX": "\"the struggle is brief ... soon they are helpless prisoners... and the earl dancing in rage, is heaping abuse on them...\".", + "DEFAULT": "\"the struggle is brief ... soon they are helpless prisoners ... and the earl dancing in rage ... is heaping abuse on them ...\".", + "DEFAULT_GREY_PAD": "\"the struggle is brief... soon they are helpless prisoners... and the earl, dancing in rage ... is heaping abuse on them...\".", + "PADDED_4": "\"the struggle is brief.... soon they are helpless prisoners... and the earl dancing in rage..... he's heaping abuse on them...\".", + "PADDED_8": "\"the struggle is brief... soon they are helpless prisoners... and the earl dancing in rage... is heaping abuse on them...\".", + "EXTRACTED_INIT_BOX": "\"the struggle is brief... soon they are welded into prisoners. and the girl dancing in rage ... is resting. rise up on them!", + "PADDED_4_EXTRACTED": "\"the struggle is brief ... soon they are helpless prisoners. find the girl dancing in the ring. she is weeping. abuse them.\"", + "PADDED_8_EXTRACTED": "T he struggle is brief... soon they are helpless... prisoners... finding the end in unbridge... is respiring abuse on them...", + "PADDED_8_DILATION_1": "\"the struggle is brief... soon they are helpless prisoners.. and the earl dancing in, in rage .. is cheaping abuse on them...\".", + "PAD_8_FRACT_0_5": "\"the struggle is brief...\" soon they are helpless prisoners... and the final dance is unhinged violence... abuse on them...\"", + "PAD_8_FRACT_0_2": "\"the struggle is brief... soon they are helpless prisoners. and the final dancing in rage ... is cheating abuse on them...\"." + }, + "5": { + "INITIAL_BOX": "Fiercely the guards fall on the prone giant ... and robin, almost clear of the room, gallantly turns back to help his friend ...", + "DEFAULT": "Fiercely the guards fall on the prone giant...and robin, almost clear of the room, graciously turns back to help his friends...", + "DEFAULT_GREY_PAD": "Fiercely the guards fall on the prone giant...and robin, almost clear of the room, brilliantly turns back to help his friend...", + "PADDED_4": "Fiercely the guards fall on the prone giant ... and robin, almost clear of the room, grillantly turns back to help his friend ...", + "PADDED_8": "Fiercely the guards fall on the prone giant...and robin, almost clear of the room, brilliantly turns back to help his friend...", + "EXTRACTED_INIT_BOX": "Ferociously the guards fall on the poone giant... and robin, almost clear of the room, gallantly turns back to help his friend.", + "PADDED_4_EXTRACTED": "Prestow the cumaps fall on the probe giant...and robin, almost clear of the room, gallantly turns back to help his friends.", + "PADDED_8_EXTRACTED": "Friendly the guards fall on the prone giant...and robin, almost clear of the monolithically turning batcave to help his friend...\"", + "PADDED_8_DILATION_1": "Fiercely the guards fall on the prone giant...and robin, almost clear of the room gratefully turns back to help his friend... \"", + "PAD_8_FRACT_0_5": "Fiendly the guards fall on the prone giant...and robin, almost clear of the manor brilliantly turns back to help his friend. \"", + "PAD_8_FRACT_0_2": "Fiendly the guards fall on the prone giant...and robin, almost clear of the room grillantly turns back to help his friend: \"" + }, + "6": { + "INITIAL_BOX": "Wretches! doltz! assassins! you've made me the laughing stock of my friends! to the dungeons with them! on the morrow they suffer for this?", + "DEFAULT": "Wretches! doltz ! assassins! you've made me the laughing stock of my friends! to the dungeons with them! on the morrow they suffer for this?", + "DEFAULT_GREY_PAD": "Wretches! doltz! assassins! you've made me the laughing stock of my friends / to the dungeons with them / on the morrow they suffer for this!", + "PADDED_4": "Wretches! doltz! assassins! you've made me the laughing stock of my friends! to the dungeons with them! on to the morrow they suffer for this?", + "PADDED_8": "Wretches! doltz! assassins! you've made me the laughing stock of my friends / to the dungeons with them / on the morrow they suffer for this!", + "EXTRACTED_INIT_BOX": "Wretchies! / doltz! / assassining! // you've made me the laughing stock of any friends ! to the dungeon with them ! on the morrow they suffer for this!", + "PADDED_4_EXTRACTED": "Wretchnes! ! doltz! nassasinning! you've made me the laughing stock of my friends ! to the dungeons with them on the morrow they suffer for this?", + "PADDED_8_EXTRACTED": "Wretches! dolts! massacres! i've lived to make me the laughing stock of my friends / to the dungeoned with them ! on the morrow they suffer for this!", + "PADDED_8_DILATION_1": "Wrestlers ! dolts! resserins! / you've made me the laughing stock of mia' friends ! to the dungeons with them ! on the morrow they suffer for this!", + "PAD_8_FRACT_0_5": "Wretches! dolts! massacrings! i've made me the laughing stock of my friends ! to the dungeons with them ! on the morrow they suffer for this?", + "PAD_8_FRACT_0_2": "Wretches! dolts! massacringss! you've made me the laughing stock of my friends ! to the dungeons with them ! on the morrow they suffer for this?" + }, + "7": { + "INITIAL_BOX": "With fists lashing out right and left, the out- law chief hurls himself at the guards ... but he knows the odds are hopeless ...", + "DEFAULT": "With fists lashing out right and left, the out- law chief hurls himself at the guards ... but he knows the odds are hopeless ...", + "DEFAULT_GREY_PAD": "\" with fists lashing out right and left, the out- law chief hurls himself at the guards ... but he knows the odds are hopeless ...", + "PADDED_4": "With fists lashing out right and left, the out- law chief hurls himself at the guards ... but he knows the odds are hopeless ...", + "PADDED_8": "Cloth fists lashing out right and left, the out- law chief hurls himself at the guards ... but he knows the odds are hopeless ...", + "EXTRACTED_INIT_BOX": "Cyborg fists lashing out right and left, the out- law chief hurls himself in at the guards ... but he knows the odds are hopeless...", + "PADDED_4_EXTRACTED": "Sixth fists lashing out right and left, the out- law chief hurls himself at the guards ... but he knows the odds are hopeless...", + "PADDED_8_EXTRACTED": "Mouth fists lashing out right and left, the outline law chief hurls himself at the guards ... but he knows the odds are hopless ...", + "PADDED_8_DILATION_1": "\"young fists lashing out right and left, the cult- law chief hurls himself at the guards ... but he knows the odds are against himself...", + "PAD_8_FRACT_0_5": "Mouth fists lashing out right and left, the out- law chief hurls himself at the guards ... but he knows the odds are hopeless ...", + "PAD_8_FRACT_0_2": "Muth fists lashing out right and left, the oult- law chief hurls himself at the guards ... but he knows the oodds are hopeless..." + }, + "8": { + "INITIAL_BOX": "Roughly, they are hurled into a dungeon cell ...", + "DEFAULT": "Roughly, they are hurled into a dun-geon cell ...", + "DEFAULT_GREY_PAD": "Roughly, they are hurled into a din-geon cell ...", + "PADDED_4": "Roughly, they are hurled into a dun-geon cell ...", + "PADDED_8": "Roughly, they are hurled into a dun-geon cell ...", + "EXTRACTED_INIT_BOX": "Brougham, there's no time to hesitate! hurled into a dungeon cell...", + "PADDED_4_EXTRACTED": "Inough! they 've hurled into a din- owom cellar!", + "PADDED_8_EXTRACTED": "Roughly, they're hurled into a dungeon cell...", + "PADDED_8_DILATION_1": "Roughly, they're hurtled into a dun-geon cell ...", + "PAD_8_FRACT_0_5": "Roughly, they raced hurried into a dungeon cell...", + "PAD_8_FRACT_0_2": "Roughly, they're hurled into a dungeon cell ..." + }, + "9": { + "INITIAL_BOX": "'tis a pretty fix we're in, sir! what is the penalty for spilling soup on an earl?", + "DEFAULT": "'tis a pretty fix we're in, sir! what is the penalty for spilling soup on an earl?", + "DEFAULT_GREY_PAD": "'tis a pretty fix we're in, sir! what is the penalty for spilling soup on an ear?", + "PADDED_4": "'tis a pretty fix we're in, sir! what is the penalty for spilling soup on an ear?", + "PADDED_8": "'tis a pretty fix we're in, sir! what is the penalty for spilling soup on an ear?", + "EXTRACTED_INIT_BOX": "'tis a pretty fix we're in, sir! what if the penalty for spilling soup on an earl?", + "PADDED_4_EXTRACTED": "'tis a pretty fix we're in, sir! what is the penalty? for spilling soup on an earl?", + "PADDED_8_EXTRACTED": "'tis a pretty fix we're in; side! what is the penalty for spilling soup on an earl?", + "PADDED_8_DILATION_1": "'tis a pretty fix we're in, sir! what's the penalty for spilling soup on an earl?", + "PAD_8_FRACT_0_5": "'tis a pretty fix we're in, sir! what is the penalty for spilling soup on an earl?", + "PAD_8_FRACT_0_2": "'tis a pretty fix we're in, sir! what is the penalty for spilling soup on an earl?" + }, + "10": { + "INITIAL_BOX": "Dire tortures, i fear me, littlejohn/ rh, well, i came to see the earl's castle and see it did... even to the dungeon....", + "DEFAULT": "Dire tortures, i fear me, littlejohn! rh, well, i came to see the earl's castle and see it i did... even to the dungeon...", + "DEFAULT_GREY_PAD": "Dire tortures, i fear me, littlejohn/ rh, well, i came to see the earl's castle and see it i did... even to the dungeon....", + "PADDED_4": "Dire tortures, i fear me, littlejohn/ rh. well, i came to see the earl's castle and see it i did... even to the dungeon....", + "PADDED_8": "Dire tortures, i fear me, littlejohn/ rh, well... i came to see the earl's castle and see it i did... even to the dungeon....", + "EXTRACTED_INIT_BOX": "Dire tortures, i fear me, little john/yh, well! i came to see the earl's castle and see it stood... even to the dungeon....", + "PADDED_4_EXTRACTED": "Dire tortures, i fear me, little john/! rh. well: i come to see the earl's castle and see it did... even to the dungeon....", + "PADDED_8_EXTRACTED": "Dirte tortures, i fear me, littlejohn/ rh, well, i came to see the earl's castle and see it did... even to the dungeon....", + "PADDED_8_DILATION_1": "Dire tortures, i fear me, little john/oh, well! i came to see the earl's castle and see it did... even to the dungeon....", + "PAD_8_FRACT_0_5": "Dirte tortures, i fear me, littlejohn/ rh, well, i came to see the earl's castle and see it did... even to the dungeon....", + "PAD_8_FRACT_0_2": "Dare tortures, i fear me, little john/ rh, well, i come to see the earl's castle and see it did... even to the dungeon...." + }, + "11": { + "INITIAL_BOX": "Ruefully but undaunted they consider their plight.", + "DEFAULT": "Ruffianly disdained their considerate, dutiful.", + "DEFAULT_GREY_PAD": "Ruefully bit unenthusiastic they consider their plight...", + "PADDED_4": "Rifffully ruffled at undaunted they consider their plight.", + "PADDED_8": "Ruefully bit unenthusiastic they consider their plight...", + "EXTRACTED_INIT_BOX": "Sufficiently bet uncomplained they consider, their manners?", + "PADDED_4_EXTRACTED": "Correctly but undoubtedly they consider them valians. \"", + "PADDED_8_EXTRACTED": "Sufficiently bit uncounted they consider their actions.", + "PADDED_8_DILATION_1": "Kneefully, but undaunted they consider, their plight?", + "PAD_8_FRACT_0_5": "Awfully bit unmanly they consider their duties?", + "PAD_8_FRACT_0_2": "Awfully bit unaccounted they consider, their darlings?" + } + }, + "MCCAY_LITTLENEMO_090.jpg": { + "1": { + "DEFAULT_GREY_PAD": "Mon palais est tout pres juste une petite promenade dans la jungle.", + "INITIAL_BOX": "Mon palais est tout pres juste une petite promenade dans la jungle.", + "DEFAULT": "Mon palais est tout pres juste une petite promenade dans la jungle.", + "PADDED_4": "Mon palais est tout pres juste une petite promenade dans la jungle.", + "PADDED_8": "Mon palais est tout pres juste une petite promenade dans la jungle.", + "EXTRACTED_INIT_BOX": "Mon palais est tout fini juste une petite promenade j'ai pris la plage.", + "PADDED_4_EXTRACTED": "\"mon palais est tout pr\u00eat juste comme une petite promenade de jungle\"", + "PADDED_8_EXTRACTED": "Mon palais est tout fres juste avec petite promenade dambala jungle.", + "PADDED_8_DILATION_1": "\"mon palais est tout pr\u00eat juste une petite promenade dans la jungle.\".", + "PAD_8_FRACT_0_5": "\"mon palais est tout\" fres juste une petite fromenade jungle", + "PAD_8_FRACT_0_2": "\"mon palais est tout pres juste une petite promenade dans la jungle.\"." + }, + "2": { + "DEFAULT_GREY_PAD": "Vous allez avoir ce que vous cherchez chez et bien encore!", + "INITIAL_BOX": "\"vous allez avoir ce que vous cherchez - chez eux et bien encore\"", + "DEFAULT": "Vous allez avoidre ce que vous cherchez chez eux et bien encore", + "PADDED_4": "Vous allez avoirdre que vous cher-chez et bien encore", + "PADDED_8": "Vous allez avoirdre que vous cher- chez et bien encore", + "EXTRACTED_INIT_BOX": "\" well then i 'll just have to find another way of getting you outta here! \"", + "PADDED_4_EXTRACTED": "Us? we're us.", + "PADDED_8_EXTRACTED": "\" we 're here to help you. \"", + "PADDED_8_DILATION_1": "Us : \" re - us?", + "PAD_8_FRACT_0_5": "\" we 're here to help you. \"", + "PAD_8_FRACT_0_2": "\" we 're us! \"" + }, + "0": { + "DEFAULT_GREY_PAD": "Si vous tenez une rester en vie ... nevez approchez pas de moi!", + "INITIAL_BOX": "Si vous tenez une rester en vie ... nevez approchez pas de moi?", + "DEFAULT": "Si vous tenez une rester en vie ... nevez approchez pas de moi?", + "PADDED_4": "Sioux tenez a rester en vie... nevous approchez pas de moi?", + "PADDED_8": "Si vous tenez une rester en vie... nevez approchez pas de moi?", + "EXTRACTED_INIT_BOX": "Si vous tenez une rester en vie ... nous approchez pas de moi?", + "PADDED_4_EXTRACTED": "Si vous tenez un r\u00easter en vie ... nous approchez pas de moi?", + "PADDED_8_EXTRACTED": "Si vous tenez \u00e0 rester en vie... nous approchez pas de moi?", + "PADDED_8_DILATION_1": "Si vous tenez \u00e0 rester en vie ... ne vous approchez pas de moi!", + "PAD_8_FRACT_0_5": "Si vous tenez \u00e0 rester en vie... nous approchez pas de moi?", + "PAD_8_FRACT_0_2": "Si vous voulez tenez une rester en vie ... ne vous approchez pas de moi?" + }, + "3": { + "INITIAL_BOX": "Et maintenant, je veux parler de toi ! suivez-moi ?", + "DEFAULT": "And besides, i don't want to be alone! so?", + "DEFAULT_GREY_PAD": "Et mainte, vant par ic! suivez-moi?", + "PADDED_4": "And besides, i don't want to be alone! so?", + "PADDED_8": "And besides, i don't want to be alone! so what?", + "EXTRACTED_INIT_BOX": "Et maintenant je veux parler de toi ! suivez-moi ?", + "PADDED_4_EXTRACTED": "Et maintenant je veux parler de toi ! - suivez-moi?", + "PADDED_8_EXTRACTED": "Et maintenant je vant par ki! suivez-moi?", + "PADDED_8_DILATION_1": "Et mainte- nant par ic! suivez- moi?", + "PAD_8_FRACT_0_5": "Et maintenant je veux parler avec toi ! suivez-moi ?", + "PAD_8_FRACT_0_2": "Et maintenant n'want par ici ! suivez-moi?" + }, + "4": { + "INITIAL_BOX": "\"mon palais est moins bien que celui du roi mais il est joli fil'nest pas lun\"", + "DEFAULT": "Mon palais est moins bien que celui du roi mais il est joli l'n'est pas 1oin", + "DEFAULT_GREY_PAD": "\"mon palais est moins bien que celui du roi mais il est joli l'nest pas la vin\"", + "PADDED_4": "Mon palais est moins bien que celui du roi mais il est joli il n'est pas loin.", + "PADDED_8": "Mon palais est moins bien que celui du roi mais il est joli il n'est pas loin.", + "EXTRACTED_INIT_BOX": "Moon palace est maintenant bien que c'est du roi mais il est joli l'west pas long", + "PADDED_4_EXTRACTED": "Moon palais est mais bien que celui du roi 'monsieur il est joli l'nest pas un", + "PADDED_8_EXTRACTED": "\" mon palais bst moins bien que celui du roi ' monsieur il est joli l' nest pas un clin", + "PADDED_8_DILATION_1": "\"mon palais est moins bien que celui du roi\" \"mais il est joli l'nest pas qui\"", + "PAD_8_FRACT_0_5": "\"mon palais bst moins bien que celui du roi ' mus il est joli l' nbbt pas ' qui", + "PAD_8_FRACT_0_2": "\"mon palais bst moins bien que celui du roi 'mais il est joli l'nest pas 'quin\"" + }, + "5": { + "INITIAL_BOX": "Je croyais que les ma- rins dewaient nous accompa- gner? il s'en suivent?", + "DEFAULT": "Je crois que les ma- rins devaient nous accompagner sien? il s'en suiveit?", + "DEFAULT_GREY_PAD": "Je crois que les ma- rins devaient nous accompa gner? il s'en suive t?", + "PADDED_4": "Je crois que les ma- rins devaient nous accompagner sner? il s'en suiveit?", + "PADDED_8": "Je crois que les ma- rins devaient nous accompa gner? il s'en suiveit?", + "EXTRACTED_INIT_BOX": "Je crois que les mr king jeweler m'ont ?ils ne comprenent pas?", + "PADDED_4_EXTRACTED": "Je crois que les mi kings sont enfermer no ? / lesner?ils ne suivent pas?", + "PADDED_8_EXTRACTED": "Je crois que les murs riment j'en suis certain ?", + "PADDED_8_DILATION_1": "Je crois que les ma rins devaient nos s'enner pils no suivent?", + "PAD_8_FRACT_0_5": "Je crois que les mi kings power ni s ! super? il n'en suive pas ?", + "PAD_8_FRACT_0_2": "Je crois que les miens sont apr\u00e8s toi ! m's ? il s'en sortent?" + }, + "6": { + "INITIAL_BOX": "We regardez pas ces singes ou il sont toujours bombarder avee des noix de coco.", + "DEFAULT": "We regard these passages singes ou il s'avont vus bombarder avee des noix de coco.", + "DEFAULT_GREY_PAD": "\"ne regardez pas ces singes ou il sont vous bombarder avec des noix de coco\"", + "PADDED_4": "We regardez pas ces singes ou il sont vous bombarder avec des noix de coco.", + "PADDED_8": "\"ne regardez pas ces singes ou ils vont vous bombarder avec des noix de coco\"", + "EXTRACTED_INIT_BOX": "We recorded these cbs singes on 13/wont wave bombardier away das nox de coc", + "PADDED_4_EXTRACTED": "We regarder les cbs singes du riwont ving d'hommardier avec des noix de coco.", + "PADDED_8_EXTRACTED": "We regardz les ces singes d'ici wont ving bom barner avec des noix de coc", + "PADDED_8_DILATION_1": "Me regardez pas ces singes ou il sont tous bombarder avec des noia de codec", + "PAD_8_FRACT_0_5": "We regard these ces singers who won't vote for bombarier ainc as noix de coc.", + "PAD_8_FRACT_0_2": "We regret to inform you that your services are no longer required by bombardier aerospace." + }, + "7": { + "INITIAL_BOX": "Oui ! ouil! mais vous n'avez rien \u00e0 craindre et ne failles pas attention \u00e0 ce que vous pourriez voir?", + "DEFAULT": "Oui ! oui! mais vous n'avez rien \u00e0 craindre et ne failles pas attention \u00e7aque que vous pourriez voir?", + "DEFAULT_GREY_PAD": "Oui ! oui! mais vous n'avez rien \u00e0 craindre et ne faite pas attenter tion \u00e0 ce que vous pourriez voir !", + "PADDED_4": "Oui ! oui! mais vous n'avez rien \u00e0 craindre et ne faites pas attenter tion ace que vous pourriez voir?", + "PADDED_8": "Oui !!! mais vous n'avez rien \u00e0 craindre et ne faite pas attenter tion \u00e0 ce que vous pourriez voir ?", + "EXTRACTED_INIT_BOX": "' oui! oui ma'am, vous havaet rien a craindr de me futter in a knack age '.", + "PADDED_4_EXTRACTED": "\" oui' on ma hous n'avet rien a brager d'etre puttes en loage film\"", + "PADDED_8_EXTRACTED": "\" nou'ui ma 'nous n'avaz rien a brainor de participer a un age \" po", + "PADDED_8_DILATION_1": "\" oui\" oui ma , vous n'aviez rien a craindr b le faites pa a lion age po", + "PAD_8_FRACT_0_5": "\" oui\" oui mais n'avaz rien a ecraser d'une pantin faites pa how a long time ago!?", + "PAD_8_FRACT_0_2": "\" oui\" d'ou mais wus nyanzez rue a crainvor b he fantas fa a how a che po" + }, + "8": { + "INITIAL_BOX": "Non l'hai mai passato per ca flip! non?", + "DEFAULT": "Now i never fails pas ca flip! non?", + "DEFAULT_GREY_PAD": "Non! ne faites pas \u00e7a flip ! non?", + "PADDED_4": "Non l'ine faites pas \u00e7a flip ! non?", + "PADDED_8": "Non! n'ai faites pas \u00e7a flip ! non?", + "EXTRACTED_INIT_BOX": "Now i've failed as caflip! now?", + "PADDED_4_EXTRACTED": "Now i've failed as ga flip! now?", + "PADDED_8_EXTRACTED": "Now i we failtes pas sea flip! now?", + "PADDED_8_DILATION_1": "Now i'm never fatties pas sa flip! now?", + "PAD_8_FRACT_0_5": "Now i ne faites pas sa flip! now?", + "PAD_8_FRACT_0_2": "Now i see faites pas sa flip! now?" + }, + "9": { + "INITIAL_BOX": "\" oooh! arretez! arret\u00e9zei! \"", + "DEFAULT": "\" oooh! arretez arettez! oohh!", + "DEFAULT_GREY_PAD": "Oooh! arretez arretezi oooh?", + "PADDED_4": "Oooh! arretez! arretetez! oooh?", + "PADDED_8": "\" oooh! arretez aarretez! \"", + "EXTRACTED_INIT_BOX": "\" oh! arctez arcteus! do you think i'm stupid?", + "PADDED_4_EXTRACTED": "\" i 'll arrest you! \" arcturus shouted.", + "PADDED_8_EXTRACTED": "\" ha! arctez arreterei! \"", + "PADDED_8_DILATION_1": "\"000h! arrettez. arretetez! dooa hi\"", + "PAD_8_FRACT_0_5": "\"00h! arrettez! arrettezi !\"", + "PAD_8_FRACT_0_2": "\"000h! arretez! arretetez! 000h?" + }, + "10": { + "INITIAL_BOX": "Pourquoi donc nemo's agite-t-il tant la nuit? ce soir il ne faut que se retourner!", + "DEFAULT": "Pourquoi donc nemo's agite-t-il tant la nuit? ce soir il ne faut que se retourner!", + "DEFAULT_GREY_PAD": "Pourquoi donc nemo s'agite-t-il tant la nuit? ce soir il ne faut que se retourner!", + "PADDED_4": "Pourquoi donc memo s'agite-t-il tant la nuit? ce soir il ne faut que se retourner!", + "PADDED_8": "Pourquoi donc nemo s'agite-t-il tant la nuit? ce soir il ne faut que se retourner!", + "EXTRACTED_INIT_BOX": "Pourquoi dois-je m'humilier? - eh! tu veux que je te laisse tranquille? ce soir, il ne faut qu'que ses retours se terminent !", + "PADDED_4_EXTRACTED": "Pourquoi est-ce que je ne peux pas m'en aller?", + "PADDED_8_EXTRACTED": "Pourquoi dois-je m'humilier? -tu veux me agitter? -il faut la lune? ce soir, il ne fait qu'enfer! -retourner?", + "PADDED_8_DILATION_1": "Pourquoi done memo stagite-t il tanti la nutt? ce soir il ne part que se retourner!", + "PAD_8_FRACT_0_5": "Pourquoi dois-je m\u00e9mo sa git\u00e9-t-7 il t'ant la nuit? ce soir il ne faut que \u00e7a s'arr\u00eate!", + "PAD_8_FRACT_0_2": "Pouvons-nous diner avec ma s\u0153ur? -7 il vaut la peine de le dire! ce soir il ne faut que 5$ pour rouler !" + } + }, + "Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg": { + "0": { + "DEFAULT_GREY_PAD": "On stage" + } + }, + "PIKE_BOYLOVEGIRLS_T41_012.jpg": { + "0": { + "DEFAULT_GREY_PAD": "Curt! oh... i forgot we were going to play tennis!", + "INITIAL_BOX": "Curt! oh... i forgot we were going to play tennis?", + "DEFAULT": "Curt! oh... i forgot we were going to play tennis?", + "PADDED_4": "Curt! oh... i forgot we were going to play tennis!", + "PADDED_8": "Curt! oh... i forgot we were going to play tennis!", + "EXTRACTED_INIT_BOX": "Curt! oh... i forgot we were going to play tennis?", + "PADDED_4_EXTRACTED": "Gurt! oh... i forgot we were going to play tennis?", + "PADDED_8_EXTRACTED": "Curt! oh... i forgot we were going to play tennis?", + "PADDED_8_DILATION_1": "Curt! oh... i forgot we were going to play tennis?", + "PAD_8_FRACT_0_5": "Curt! oh... i forgot we were going to play tennis?", + "PAD_8_FRACT_0_2": "Curt! oh... i forgot we were going to play tennis?" + }, + "1": { + "INITIAL_BOX": "Well ... okay, honey! i 'd just as soon go for a drive, anyway?", + "DEFAULT": "Well ... okay, honey! i 'd just as soon go for a drive, anyway?", + "DEFAULT_GREY_PAD": "Well... okay, honey! i 'd just as soon go for a drive, anyway?", + "PADDED_4": "Well ... okay, honey! i 'd just as soon go for a drive, anyway !", + "PADDED_8": "Well... okay, honey! i 'd just as soon go for a drive, anyway?", + "EXTRACTED_INIT_BOX": "Well ... okay, honey! i 'd just as soon go for a drive, anyway?", + "PADDED_4_EXTRACTED": "Well ... okay, honey! i 'd just as soon go for a drive, anyway?", + "PADDED_8_EXTRACTED": "Well ... okay, honey! i 'd just as soon go for a drive, anyway?", + "PADDED_8_DILATION_1": "Well ... okay, honey! i 'd just as soon go for a drive anyway?", + "PAD_8_FRACT_0_5": "Well ... okay, honey! i 'd just as soon go for a drive, anyway?", + "PAD_8_FRACT_0_2": "Well ... okay, honey! i 'd just as soon go for a drive, anyway?" + }, + "2": { + "INITIAL_BOX": "I was in a bad mood, and curt sensed it immediately ...", + "DEFAULT": "I was in a bad mood, and curt sensed it immediately ...", + "DEFAULT_GREY_PAD": "I was in a bad mood, and curt sensed it immediately ...", + "PADDED_4": "I was in a bad mood, and curt sensed it immediately ...", + "PADDED_8": "I was in a bad mood, and curt sensed it immediately ...", + "EXTRACTED_INIT_BOX": "I was pa a bad wood, and court sensed \" immediately ......\"", + "PADDED_4_EXTRACTED": "I was in a bad mood, and curt sensed it immediately ...", + "PADDED_8_EXTRACTED": "I was at a bad mood, and curt sensed it immediately ...", + "PADDED_8_DILATION_1": "I was in a bad mood, and gurt seemed angry immediately ...", + "PAD_8_FRACT_0_5": "I was at a bad mood, and curt sensed it immediately ...", + "PAD_8_FRACT_0_2": "I was in a bad mood, and curt sensed it immediately ..." + }, + "3": { + "INITIAL_BOX": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy?", + "DEFAULT": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy?", + "DEFAULT_GREY_PAD": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy!", + "PADDED_4": "You've seemed so unhappy lately, cynthyl i wish there was something i could do i wish you 'd let me try and make you happy!", + "PADDED_8": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy!", + "EXTRACTED_INIT_BOX": "You've seemed so unhappy lately, cynthia! i wish there was something i could do! i wish you'd let me try and make you happy?", + "PADDED_4_EXTRACTED": "You've seemed so unhappy lately, cynthya! i wish there was something i could do to make you happy! i wish you'd let me try and make you happy?", + "PADDED_8_EXTRACTED": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy?", + "PADDED_8_DILATION_1": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy!", + "PAD_8_FRACT_0_5": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy?", + "PAD_8_FRACT_0_2": "You've seemed so unhappy lately, cynthya! i wish there was something i could do! i wish you'd let me try and make you happy?" + }, + "4": { + "INITIAL_BOX": "I knew what was coming, but i didn't want to give him an answer ... not then! i tried to change the mood!", + "DEFAULT": "I knew what was coming, but i didn't want to give him an answer ... not then! i tried to change the wood!", + "DEFAULT_GREY_PAD": "I knew what was coming, but i didn't want to give him an answer ... not then. i tried to change the mood.", + "PADDED_4": "I knew what was coming, but i didn't want to give him an answer ... not then. i tried to change the mood.", + "PADDED_8": "I knew what was coming, but i didn't want to give him an answer ... not then. i tried to change the mood.", + "EXTRACTED_INIT_BOX": "I knew what was coming, but i didn't want to give him an answer ... not theanswer i tried to change - the wood!", + "PADDED_4_EXTRACTED": "I knew what was coming, but i didn't want to give him an answer ... not then! i tried to change the wood,", + "PADDED_8_EXTRACTED": "I knew what was coming, but i didn't want to give him an answer ... not then! i tried to change the wood.", + "PADDED_8_DILATION_1": "I knew what was coming, but i didn't want to give him any answer ... not then! i tried to change the mood.", + "PAD_8_FRACT_0_5": "I knew what was coming, but i didn't want to give him an answer ... not then! i tried to change the wood.", + "PAD_8_FRACT_0_2": "I knew what was coming, but i didn't want to give him an answer ... not then! i tried to change the wood." + }, + "5": { + "INITIAL_BOX": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "DEFAULT": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "DEFAULT_GREY_PAD": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "PADDED_4": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "PADDED_8": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "EXTRACTED_INIT_BOX": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "PADDED_4_EXTRACTED": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "PADDED_8_EXTRACTED": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "PADDED_8_DILATION_1": "Goodness, curt, you worry about me too much! canon, let's go for a swim!", + "PAD_8_FRACT_0_5": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?", + "PAD_8_FRACT_0_2": "Goodness, curt, you worry about me too much! c'mon, let's go for a swim?" + }, + "6": { + "INITIAL_BOX": "I liked curt but i didn't love him, and i knew that marrying him would only be a surrender to my parents. i had to lick this problem myself - not give in to it later that evening, when we dropped in at gloria's. everybody gathered at gloria's -", + "DEFAULT": "I liked curt but i didn't love him, and i knew that marrying him would only be a surrender to my parents. i had to lick this problem myself - not give in to it later that evening, when we dropped in at gloria's. everybody gathered at gloria's...", + "DEFAULT_GREY_PAD": "I liked curt but i didn't love him, and i knew that marrying him would only be a surrender to my parents. i had to lick this problem myself not give in to it later that evening, we dropped in at gloria's everybody gathered at gloria's...", + "PADDED_4": "I liked curt but i didn't love him, and i knew that marrying him would only be a surrender to my parents. i had to lick this problem myself - not give in to it later that evening, when he dropped in at gloria's. everybody gathered at gloria's--", + "PADDED_8": "I liked curt but i didn't love him, and i knew that marrying him would only be a surrender to my parents. i had to lick this problem myself - not give in to it later that evening, when we dropped in at gloria's. everybody gathered at gloria's...", + "EXTRACTED_INIT_BOX": "I liked curt but i didn't love him, and i knew that marrying him would only be a surrender to my parents. i had to lick this problem myself not give in to it! later that evening, at gloria's everybody gathered at gloria's...", + "PADDED_4_EXTRACTED": "I liked curt but i didn't love him, and i knew that carrying his child would only be to surrender to my parents. i had to lick this problem myself. not give in to it! later that evening, at gloria's everybody gathered at gloria's - everyone except me.", + "PADDED_8_EXTRACTED": "I liked curt but i didn't love him, and i knew that warrying him would only be a surrender to my parents. i had to lick this problem myself not give in to it! later that evening, at 10 pm, in everybody's gloria's everybody gathered at gloria's...", + "PADDED_8_DILATION_1": "I liked curt but i didn't love him, and i knew that marrying him would only be to surrender to my parents. i had to lick this problem myself later that evening, in fact he dropped in at gloria's everybody gathered at gloria's--", + "PAD_8_FRACT_0_5": "I liked curt but i didn't love him, and i knew that warring his would only be a surrender to my parents. i had to lick this problem myself not give in to it! later that evening, we dropped in at gloria's everybody gazed at gloria's...", + "PAD_8_FRACT_0_2": "I liked curt but i didn't love him, and i knew that carrying his child would only be to surrender to my parents. i had to lick this problem myself. not give in to it! later that evening, at gloria's everybody gathered at gloria's..." + }, + "7": { + "INITIAL_BOX": "Hi, kids! what's up?", + "DEFAULT": "Hi, kids! what's up?", + "DEFAULT_GREY_PAD": "Hi, kids! what's up?", + "PADDED_4": "Hi, kids! what's up?", + "PADDED_8": "Hi, kids! what's up?", + "EXTRACTED_INIT_BOX": "Hi, kids! what's up?", + "PADDED_4_EXTRACTED": "Hi, kids! what's up?", + "PADDED_8_EXTRACTED": "Hi, kids! what's up?", + "PADDED_8_DILATION_1": "Hi, kids! what's up?", + "PAD_8_FRACT_0_5": "Hi, kids! what's up?", + "PAD_8_FRACT_0_2": "Hi, kids! what's up?" + }, + "8": { + "INITIAL_BOX": "Sparkling, wit... brilliant conversation... penetrating thought... what did you expect?", + "DEFAULT": "Sparkling, wit... brilliant conversation... penetrating thought... what did you expect?", + "DEFAULT_GREY_PAD": "Sparkling wit... brilliant conversation... penetrating thought... what did you expect?", + "PADDED_4": "Sparkling wit... brilliant conversation... penetrating thought... what did you expect?", + "PADDED_8": "Sparkling wit... brilliant conversation... penetrating thought... what did you expect?", + "EXTRACTED_INIT_BOX": "Sparkling...w.t....brilliant conversation.....penetrating thought....what did you expect?", + "PADDED_4_EXTRACTED": "Sparkling...wit...brilliant conversation....penetrating thought....what did you expect?", + "PADDED_8_EXTRACTED": "Sparkling...wit...brilliant conversation....penetrating thought....what did you expect?", + "PADDED_8_DILATION_1": "Sparkling wit ... brilliant ant conversation ... penetrating thought ... what did you expect?", + "PAD_8_FRACT_0_5": "Sparkling...wit...brilliant conversation....penetrating thought....what did you expect?", + "PAD_8_FRACT_0_2": "Sparkling wit ... brilliant conversation ... penetrating thought ... what did you expect?" + }, + "9": { + "INITIAL_BOX": "He means it 's the usual dull evening!", + "DEFAULT": "He means it 's the usual dull evening!", + "DEFAULT_GREY_PAD": "He means it 's the usual dull evening!", + "PADDED_4": "He means it 's the usual dull evening!", + "PADDED_8": "He means it's the usual dull evening!", + "EXTRACTED_INIT_BOX": "He means it 's the usual dull evening!", + "PADDED_4_EXTRACTED": "He means it 's the usual dull evening!", + "PADDED_8_EXTRACTED": "He means it 's the usual dull evening!", + "PADDED_8_DILATION_1": "He means it 's the usual dull evening!", + "PAD_8_FRACT_0_5": "He means it 's the usual dull evening!", + "PAD_8_FRACT_0_2": "He means it 's the usual dull evening!" + }, + "10": { + "INITIAL_BOX": "My old man says i'm going to have to take that advertising job in new york!", + "DEFAULT": "My old man says i'm going to have to take that advertising job in new york!", + "DEFAULT_GREY_PAD": "My old man says i'm going to have to take that advertising job in new york!", + "PADDED_4": "My old man says i'm going to have to take that advertising job in new york!", + "PADDED_8": "My old man says i'm going to have to take that advertising job in new york!", + "EXTRACTED_INIT_BOX": "My old man says i'm going to have to take that advertising job in new york!", + "PADDED_4_EXTRACTED": "Any old man says i'm going to have to take that advertising job in new york!", + "PADDED_8_EXTRACTED": "Any old man says i'm going to have to take that advertising job in new york!", + "PADDED_8_DILATION_1": "My old man says i'm going to have to take that advertising job in new york!", + "PAD_8_FRACT_0_5": "Any old man says i'm going to have to take that advertising job in new york!", + "PAD_8_FRACT_0_2": "My old man says i'm going to have to take that advertising job in new york!" + }, + "11": { + "INITIAL_BOX": "The conversation wandered aimlessly ...", + "DEFAULT": "The conversation wandered aimlessly ...", + "DEFAULT_GREY_PAD": "The conversation wandered aimlessly ...", + "PADDED_4": "The conversation wandered aimlessly ...", + "PADDED_8": "The conversation wandered aimlessly ...", + "EXTRACTED_INIT_BOX": "The colossus against whom he waged war was ordered on an angle essentially...", + "PADDED_4_EXTRACTED": "\" the conversations from mankind originated on an amorphously shaped planet.", + "PADDED_8_EXTRACTED": "\" the conversation was narrated on an ambulance bed \".", + "PADDED_8_DILATION_1": "\" the college examinations wangled on in a lessless? ...", + "PAD_8_FRACT_0_5": "The conversation wandered on amiable essy...", + "PAD_8_FRACT_0_2": "The conversation wandered on amiable essyl..." + }, + "12": { + "INITIAL_BOX": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncle's publishing house! did it ever", + "DEFAULT": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncle's publishing house! did it ever?", + "DEFAULT_GREY_PAD": "Yeah, me, too! he'll take me on at the bank, but i think i'd rather work in my uncle's publishing house! did it ever?", + "PADDED_4": "Yeah, me, too! he'll take me on at the bank, but i think i 'd rather work in my uncle's publishing house! did it ever new york?", + "PADDED_8": "Yeah, me, too! he'll take me on at the bank, but i think i 'd rather work in my uncle's publishing house?", + "EXTRACTED_INIT_BOX": "Yeah, me, too! he'll take me on at the bank, but i think i'd rather work in my uncle's publishing house! did it ever", + "PADDED_4_EXTRACTED": "Yeah, me, too! he'll take me on at the bank, but i think i 'd rather work in my uncle's publishing house! did it ever occur to you that he might be interested?", + "PADDED_8_EXTRACTED": "Yeah, me...100! he'll take me on at the bank, but i think i 'd rather work in my uncle's publishing house?", + "PADDED_8_DILATION_1": "Yeah, me too! he'll take me on at the bank, but i think i 'd rather work in my uncle's publishing house?", + "PAD_8_FRACT_0_5": "Yeah, me, too! he'll take me on at the bank, but i think i 'd rather work in my uncle's publishing house?", + "PAD_8_FRACT_0_2": "Yeah, me, too! he'll take me on at the bank, but i think i 'd rather work in my uncle's publishing house?" + }, + "13": { + "INITIAL_BOX": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "DEFAULT": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "DEFAULT_GREY_PAD": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "PADDED_4": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "PADDED_8": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "EXTRACTED_INIT_BOX": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "PADDED_4_EXTRACTED": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "PADDED_8_EXTRACTED": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "PADDED_8_DILATION_1": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "PAD_8_FRACT_0_5": "Lucky? my old man's got enough dough to support half this town! why should i want to work?", + "PAD_8_FRACT_0_2": "Lucky? my old man's got enough dough to support half this town! why should i want to work?" + }, + "14": { + "INITIAL_BOX": "If you don't know, i'm not going to tell you?", + "DEFAULT": "If you don't know, i'm not going to tell you?", + "DEFAULT_GREY_PAD": "If you don't know, i'm not going to tell you!", + "PADDED_4": "If you don't know, i'm not going to tell you!", + "PADDED_8": "If you don't know, i'm not going to tell you!", + "EXTRACTED_INIT_BOX": "If you don't know, i'm not going to tell you?", + "PADDED_4_EXTRACTED": "If you don't know, i'm not going to tell you?", + "PADDED_8_EXTRACTED": "If you don't know, i'm not going to tell you?", + "PADDED_8_DILATION_1": "If you don't know, i am not going to tell you?", + "PAD_8_FRACT_0_5": "If you don't know, i'm not going to tell you?", + "PAD_8_FRACT_0_2": "If you don't know, i'm not going to tell you?" + }, + "15": { + "INITIAL_BOX": "Are you speaking to me?", + "DEFAULT": "Are you speaking to me?", + "DEFAULT_GREY_PAD": "Are you speaking to me?", + "PADDED_4": "Are you speaking to me?", + "PADDED_8": "Are you speaking to me?", + "EXTRACTED_INIT_BOX": "Are you speaking to me?", + "PADDED_4_EXTRACTED": "Are you speaking to me?", + "PADDED_8_EXTRACTED": "Are you speaking to me?", + "PADDED_8_DILATION_1": "Are you speaking to me?", + "PAD_8_FRACT_0_5": "Are you speaking to me?", + "PAD_8_FRACT_0_2": "Are you speaking to me?" + }, + "16": { + "INITIAL_BOX": "Did it ever occur to you that you're lucky to get jobs?", + "DEFAULT": "Did it ever occur to you that you 're lucky to get jobs?", + "DEFAULT_GREY_PAD": "Did it ever occur to you that you 're lucky to get jobs?", + "PADDED_4": "Did it ever occur to you that you 're lucky to get jobs?", + "PADDED_8": "Did it ever occur to you that you 're lucky to get jobs?", + "EXTRACTED_INIT_BOX": "Did it ever occur to you that you 're lucky to get jobs?", + "PADDED_4_EXTRACTED": "Did it ever occur to you that you 're lucky to get jobs?", + "PADDED_8_EXTRACTED": "Did it ever occur to you that you 're lucky to get jobs?", + "PADDED_8_DILATION_1": "Did it ever occur to you that you 're lucky to get jobs?", + "PAD_8_FRACT_0_5": "Did it ever occur to you that you 're lucky to get jobs?", + "PAD_8_FRACT_0_2": "Did it ever occur to you that you 're lucky to get jobs?" + } + }, + "Strange_Tales_172021.jpg": { + "0": { + "DEFAULT_GREY_PAD": "A blur--only a blur at first, dark menacing...greets brother voodoo's eyes as he rises from the darkness......", + "INITIAL_BOX": "A blur -- only a blur at first, dark menacing...greets brother voodoo's eyes as he rises from the darkness....\"", + "DEFAULT": "A blur--only a blur at first, dark menacing...greets brother voodoo's eyes as he rises from the darkness...\"", + "PADDED_4": "A blur--only a blur at first, dark menacing...greets brother voodoo's eyes as he rises from the darkness......", + "PADDED_8": "A blur--only a blur at first, dark menacing...greets brother voodoo's eyes as he rises from the darkness......", + "EXTRACTED_INIT_BOX": "A billion -- only a billion at first, dark menacing--\" greets another voodoo's eyes as he rises from the darkness... \"", + "PADDED_4_EXTRACTED": "A blur -- only a blair at first, dark menacing--\" greets another / voodoo's eyes as he rodes from the darknesses... \"", + "PADDED_8_EXTRACTED": "A billion--only a blur at first, dark menacing...greets brother vodooodoo's eyes as he howls from the darkness......", + "PADDED_8_DILATION_1": "A blur -- only a blur at first, dark menacing greets brother voodoo's eyes as he rises from the darkness, ......", + "PAD_8_FRACT_0_5": "A blur -- only a blizz at first, dark menacing greys behind him. vooodoo is eyes as he nods from the darkness. ...", + "PAD_8_FRACT_0_2": "A blur -- only a blur at first, dark mannacing ... ghosts brother voodoo is eyes as he names from the darkness ... \"" + }, + "1": { + "INITIAL_BOX": "-\" but brother voodoo is not yet ready to sit at the table on the dead! \"", + "DEFAULT": "\" but brother voodoo is not yet ready to sit at the table on the dead! \"", + "DEFAULT_GREY_PAD": "\" but brother voodoo is not yet ready to sit at the table of the dead! \"", + "PADDED_4": "\" but brother voodoo is not yet ready to sit at the table of the dead! \"", + "PADDED_8": "\" but brother voodoo is not yet ready to sit at the table for the dead! \"", + "EXTRACTED_INIT_BOX": "\" but brother-in-law is not yet ready to sit at this table on the dead! \"", + "PADDED_4_EXTRACTED": "\" suit yourself wyatt is not ready to sit at the tables of the dead! \"", + "PADDED_8_EXTRACTED": "\" but brother wisedom is not yet ready to sit at the table of the dead! \"", + "PADDED_8_DILATION_1": "A - butt brother voodoo is not ready to sit at this table on the dead! \"", + "PAD_8_FRACT_0_5": "- but brother who'd have thought you were ready to sit at the tables of this dead! \"", + "PAD_8_FRACT_0_2": "-\" but brother whooosh! we're not ready to git at this trouble of this dead! \"" + }, + "2": { + "INITIAL_BOX": "--and immediately regrets it!?", + "DEFAULT": "--and immediately regrets it!?", + "DEFAULT_GREY_PAD": "--and immediately regrets it!?", + "PADDED_4": "--and immediately regrets it!?", + "PADDED_8": "--and immediately regrets it!?", + "EXTRACTED_INIT_BOX": "--and unleashed days!?!!?", + "PADDED_4_EXTRACTED": "--\"and unleash diversity defence-yes it!?", + "PADDED_8_EXTRACTED": "--and unleashed dynamicity begins it? !", + "PADDED_8_DILATION_1": "--and immediately regrets it!", + "PAD_8_FRACT_0_5": "--and unanswered diary entries!!?", + "PAD_8_FRACT_0_2": "--and immediately afterretes it! ?" + }, + "3": { + "INITIAL_BOX": "W-h-a? m-my throat! ?", + "DEFAULT": "W-h-a? m-my throat!?", + "DEFAULT_GREY_PAD": "W-h-a? m-my throat! ?", + "PADDED_4": "W-h-a? m-my throat!?", + "PADDED_8": "W-h-a? m-my throat!?", + "EXTRACTED_INIT_BOX": "W-w-what?!! my m-my throat! ?", + "PADDED_4_EXTRACTED": "What's that? my throat? !", + "PADDED_8_EXTRACTED": "What?!! my throat!?", + "PADDED_8_DILATION_1": "What? m-my throat?", + "PAD_8_FRACT_0_5": "What?!! my throat!?", + "PAD_8_FRACT_0_2": "Why-ha?--my throat!?" + }, + "4": { + "INITIAL_BOX": "\" the hooded men have not fled, \" thinks the still-dazed voodoo-lord: \" one, at least, has remained behind to deliver the final stroke...", + "DEFAULT": "\" the hooded men have not fled, \" thinks the still-dazed voodoo-lord: \" one, at least, has remained behind to deliver the final stroke...", + "DEFAULT_GREY_PAD": "\" the hooded men have not fled, \" thinks the still-dazed voodoo-lord: \" one, at least, has remained behind to deliver the final stroke...", + "PADDED_4": "\"the hooded men have not fled, \" thinks the still-dazed voodoo-lord? \" one, at least, has remained behind to deliver the final stroke...", + "PADDED_8": "\"the hooded men have not fled, \" thinks the still-dazed voodoo-lord? \" one, at least, has remained behind to deliver the final stroke--\"", + "EXTRACTED_INIT_BOX": "\" the hooded men have not fled, \" tinks the still-dazed woodman-lord. \" one, at least, has remained behind to another the final strike -", + "PADDED_4_EXTRACTED": "\" the hooded men have not fled, \" it thinks the still - dazed woodman lord. \" one, at least, has remained behind to deliver the final stroke-\"", + "PADDED_8_EXTRACTED": "\" the hooded men have not fled, \" i thinks the still- dazed woodman - lord? one, at least has remained behind to answer the final stroke -", + "PADDED_8_DILATION_1": "\" the hooded men have not fled, \" thinks the still-dazed voodoo-horror, \" one, at least, has remained behind to acheive the final stroke-", + "PAD_8_FRACT_0_5": "\" the hooded men have not fled, \" it thinks the still- dazed woodman lord, \" one, at least has remained behind to maneuver the final stroke.", + "PAD_8_FRACT_0_2": "\" the hooded men have not flinched, \" it thinks the still- dazed wood-lord, one, at least, has remained behind to face the final strokes." + }, + "5": { + "INITIAL_BOX": "Inspector tate? i ...", + "DEFAULT": "Inspector tate? i ...", + "DEFAULT_GREY_PAD": "Inspector tate? i ...", + "PADDED_4": "Inspector tate? i ...", + "PADDED_8": "Inspector tate? i ...", + "EXTRACTED_INIT_BOX": "Inspector tate? i'm...", + "PADDED_4_EXTRACTED": "Inspector tate? i...", + "PADDED_8_EXTRACTED": "Inspector tate? i ...", + "PADDED_8_DILATION_1": "Inspector tate? i...", + "PAD_8_FRACT_0_5": "Inspector tate? i ...", + "PAD_8_FRACT_0_2": "Inspector tate? i ..." + }, + "6": { + "INITIAL_BOX": "I can imagine what you thought, man!", + "DEFAULT": "I can imagine what you thought, man!", + "DEFAULT_GREY_PAD": "I can imagine what you thought, man?", + "PADDED_4": "I can imagine what you thought, man?", + "PADDED_8": "I can imagine what you thought, man?", + "EXTRACTED_INIT_BOX": "I can imagine what you thought, man! ?", + "PADDED_4_EXTRACTED": "I can imagine what you thought, man!", + "PADDED_8_EXTRACTED": "I can imagine what you thought, man!", + "PADDED_8_DILATION_1": "I can imagine what you thought, man!", + "PAD_8_FRACT_0_5": "I can imagine what you thought, man!", + "PAD_8_FRACT_0_2": "I can imagine what you thought, man!" + }, + "7": { + "INITIAL_BOX": "With this, the lord of the loa thrusts out a wise-like hand -", + "DEFAULT": "With this, the lord of the loa thrusts out a wise-like hand -", + "DEFAULT_GREY_PAD": "With this, the lord of the loa thrusts out a wise-like hand -", + "PADDED_4": "With this, the lord of the loa thrusts out a wise-like hand -", + "PADDED_8": "With this, the lord of the loa thrusts out a vise-like hand.", + "EXTRACTED_INIT_BOX": "With this, the lord of the loa thrusts out a wise-like hand...", + "PADDED_4_EXTRACTED": "With this, the lords of the loa thrust out a vice-like hand -", + "PADDED_8_EXTRACTED": "With this, the lord of the loa thrusts out a vice-like hand!", + "PADDED_8_DILATION_1": "With this, the lord of the loa thrusts out a wise-like hand ...", + "PAD_8_FRACT_0_5": "With this, the lord of the loa thrusts out a vice-like hand!", + "PAD_8_FRACT_0_2": "With this, the lord of the loa thrusts out a vice-like hand! \"" + }, + "8": { + "INITIAL_BOX": "\"forgive me, sir... but i thought...\".", + "DEFAULT": "Forgive me, sir... but i thought...", + "DEFAULT_GREY_PAD": "\"forgive me, sir... but i thought...\".", + "PADDED_4": "\"forgive me, sir... but i thought...\".", + "PADDED_8": "I forgive you.", + "EXTRACTED_INIT_BOX": "\"forgive me, sir... but i thought...\".", + "PADDED_4_EXTRACTED": "\"forgive me, sir... but i thought...\".", + "PADDED_8_EXTRACTED": "\"forgive me, sir - but i thought...\".", + "PADDED_8_DILATION_1": "\"forgive me, sir... but i thought...\".", + "PAD_8_FRACT_0_5": "\"forgive me, sir... but i thought...\".", + "PAD_8_FRACT_0_2": "\"forgive me, sir... but i thought...\"." + }, + "9": { + "INITIAL_BOX": "So's this one, sam... a little groggy -- but he'll survive.", + "DEFAULT": "So's this one, sam. a little groggy--but he'll survive.", + "DEFAULT_GREY_PAD": "So's this one, sam. a little groggy--but he'll survive.", + "PADDED_4": "So's this one, sam. a little groggy--but he'll survive.", + "PADDED_8": "So's this one, sam. a little groggy--but he'll survive.", + "EXTRACTED_INIT_BOX": "So's this one, sam, a little groogy-- but we'll survive.", + "PADDED_4_EXTRACTED": "90's this one, gam... a little groogy-- but he'll survive.", + "PADDED_8_EXTRACTED": "So's this one, sam. a little groogy--but we'll survive.", + "PADDED_8_DILATION_1": "So's this one, sam. a little groggy--but he'll survive.", + "PAD_8_FRACT_0_5": "So's this one, gam... a little groogy-- but he'll survive.", + "PAD_8_FRACT_0_2": "20's this one, sam... a little groogy-- but we'll survive." + }, + "10": { + "INITIAL_BOX": "And your name...", + "DEFAULT": "And your name?", + "DEFAULT_GREY_PAD": "And your name?", + "PADDED_4": "And your name?", + "PADDED_8": "And your name?", + "EXTRACTED_INIT_BOX": "And your name is...", + "PADDED_4_EXTRACTED": "And your name?", + "PADDED_8_EXTRACTED": "And your name is?", + "PADDED_8_DILATION_1": "And your name?", + "PAD_8_FRACT_0_5": "And your name?", + "PAD_8_FRACT_0_2": "And your name?" + }, + "11": { + "INITIAL_BOX": "Enough intro-ductions.", + "DEFAULT": "Enough intro-ductions.", + "DEFAULT_GREY_PAD": "Enough intro-ductions.", + "PADDED_4": "Enough intro-ductions.", + "PADDED_8": "Enough intro-ductions.", + "EXTRACTED_INIT_BOX": "Enough intro-actions.", + "PADDED_4_EXTRACTED": "Enough intro-auctions...", + "PADDED_8_EXTRACTED": "Enough intro-auctions.", + "PADDED_8_DILATION_1": "Enough intro-auctions.", + "PAD_8_FRACT_0_5": "Enough intro-auctions.", + "PAD_8_FRACT_0_2": "Enough intro-auctions." + }, + "12": { + "INITIAL_BOX": "I only bent down to see how you were...", + "DEFAULT": "I only bent down to see how you were...", + "DEFAULT_GREY_PAD": "I only bent down to see how you were...", + "PADDED_4": "I only bent down to see how you were...", + "PADDED_8": "I only bent down to see how you were...", + "EXTRACTED_INIT_BOX": "I only bent down to see how you were...", + "PADDED_4_EXTRACTED": "I only bent down to see how you were...", + "PADDED_8_EXTRACTED": "I only bent down to see how you were...", + "PADDED_8_DILATION_1": "I only bent down to see how you were...", + "PAD_8_FRACT_0_5": "I only bent down to see how you were...", + "PAD_8_FRACT_0_2": "I only bent down to see how you were..." + }, + "13": { + "INITIAL_BOX": "... but, judging by the bruises on my neck, i did say you're fine!", + "DEFAULT": "--- but, judging by the bruises on my neck, i'd say you're fine!", + "DEFAULT_GREY_PAD": "\"\" but, judging by the bruises on my neck, i did say you're fine! \"", + "PADDED_4": "--- but, judging by the bruises on my neck, i'd say you're fine!", + "PADDED_8": "\"\" but, judging by the bruises on my neck, i did say you're fine! \"", + "EXTRACTED_INIT_BOX": "--- but, judging by the bruises on my neck, i did say you're fine! \"", + "PADDED_4_EXTRACTED": "--- but, judging by the bruises on my neck, i say you're fine!", + "PADDED_8_EXTRACTED": "-\" but, judging by the bruises on my neck, i did say you're fine! \"", + "PADDED_8_DILATION_1": "--\" but, judging by the bruises on my neck, i'd say you're fine! \"", + "PAD_8_FRACT_0_5": "... but, judging by the bruises on my neck, i did say you're fine!", + "PAD_8_FRACT_0_2": "... but, judging by the bruises on my neck, i did say you're fine!" + }, + "14": { + "INITIAL_BOX": "We know who you are, mister: jericho drumm, psychologist - turned-voodoo quack -", + "DEFAULT": "We know who you are, mister: jericho drumm, psychologist - turned-voodoo quack ---", + "DEFAULT_GREY_PAD": "We know who you are, mister: jericho drumm, psychologist - turned-voodoo quick ---", + "PADDED_4": "We know who you are, mister : jericho drumm, psychologist - turned-voodoo quick ---", + "PADDED_8": "We know who you are, mister: jericho drumm, psychologist - turned-voodoo quick ---", + "EXTRACTED_INIT_BOX": "We know who you are, mister; jerkicho drummer, psychologist - turned-yokoddo quick! \"", + "PADDED_4_EXTRACTED": "We know who you are, mister : jerk/cho drummer, psychologist - turned- voodoo quick ---", + "PADDED_8_EXTRACTED": "We know who you are, mister : jericho drummer, psychologist - turned-voodoo shaman. \"", + "PADDED_8_DILATION_1": "We know who you are, mister: jericho drummm, psychologist- turned- voodoo quack! -", + "PAD_8_FRACT_0_5": "We know who you are, mister : jericho drummer, psychologist - turned- voodoo shaman. \"", + "PAD_8_FRACT_0_2": "We know who you are, mister; jericho drumman, psychologist - turned-voodoo shaman -\"" + }, + "15": { + "INITIAL_BOX": "Hawkins, detective first-class... but you can call me pete.", + "DEFAULT": "Hawkins, detective first-class... but you can call me pete...", + "DEFAULT_GREY_PAD": "Hawkins, detective first-class... but you can call me pete.", + "PADDED_4": "Hawkins, detective first-class... but you can call me pete...", + "PADDED_8": "Hawkins, detective first-class... but you can call me pete.", + "EXTRACTED_INIT_BOX": "Hawking, detective first-class-- but you can call me pete", + "PADDED_4_EXTRACTED": "Hawking, detective first-class-- but you call me pete", + "PADDED_8_EXTRACTED": "Hawking, detective first-class-- but you can call me pete", + "PADDED_8_DILATION_1": "Hawking, detective first-class-- but you can call me pete", + "PAD_8_FRACT_0_5": "Hawking, detective first-class... but you can call me pete?", + "PAD_8_FRACT_0_2": "Hawking, detective first-class... but you can call me pete?" + }, + "16": { + "INITIAL_BOX": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "DEFAULT": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "DEFAULT_GREY_PAD": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "PADDED_4": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "PADDED_8": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "EXTRACTED_INIT_BOX": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "PADDED_4_EXTRACTED": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt larry.", + "PADDED_8_EXTRACTED": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "PADDED_8_DILATION_1": "Easy, sam - the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "PAD_8_FRACT_0_5": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry.", + "PAD_8_FRACT_0_2": "Easy, sam--the man wouldn't have been crazy enough to call us here if he'd hurt lorry." + }, + "17": { + "INITIAL_BOX": "Very well then... pete?", + "DEFAULT": "Very well then... pete?", + "DEFAULT_GREY_PAD": "Very well then ... pete?", + "PADDED_4": "Very well then... pete!?", + "PADDED_8": "Very well then... pete!?", + "EXTRACTED_INIT_BOX": "Very well then... pete!", + "PADDED_4_EXTRACTED": "Very well then ... pete?", + "PADDED_8_EXTRACTED": "Very well then ... pete?", + "PADDED_8_DILATION_1": "Very well then ... pete!", + "PAD_8_FRACT_0_5": "Very well then ... pete!", + "PAD_8_FRACT_0_2": "Very well then ... pete!" + }, + "18": { + "INITIAL_BOX": "I ... wish i knew, inspector she was kidnapped shortly before you arrived -- by the same men who overpowered bambu and myself ---", + "DEFAULT": "I ... wish i knew, inspector she was kidnapped shortly before you arrived - by the same men who overpowered bambu and myself ....", + "DEFAULT_GREY_PAD": "I ... wish i knew, inspector she was kidnapped shortly before you arrived -- by the same men who overpowered bambu and myself ...", + "PADDED_4": "I ... wish i knew, inspector she was kidnapped shortly before you arrived ... by the same men who overpowered bambu and myself ...", + "PADDED_8": "I ... wish i knew, inspector she was kidnapped shortly before you arrived -- by the same men who overpowered bambu and myself ...", + "EXTRACTED_INIT_BOX": "\" ... i wish i knew, inspector\" she was kidnapped shortly before you arrived - by the same men who overpowered him and myself - \"", + "PADDED_4_EXTRACTED": "I ... wish i knew, inspector she was kidnapped shortly before you arrived - by the same men who overpowered symbol and myself ...", + "PADDED_8_EXTRACTED": "... i wish i knew, inspector she was kidnapped shortly before you arrived - by the same men who overpowered both you and myself ...", + "PADDED_8_DILATION_1": "I ... wish i knew, inspector she was kidnapped shortly before you arrived - by the same men who overpowered bambu and myself.", + "PAD_8_FRACT_0_5": "... wish i knew, inspector she was kidnapped shortly before you arrived - by the same men who overpowered sholou and myself...", + "PAD_8_FRACT_0_2": "\" i wish i knew, inspector she was kidnapped shortly before you arrived - by the same men who overpowered symbol and myself." + }, + "19": { + "INITIAL_BOX": "\"and i'm warning you now--if you've done anything to hurt my loralee, i'll...\"", + "DEFAULT": "\"and i'm warning you now--if you've done anything to hurt my lorelee, i'll...", + "DEFAULT_GREY_PAD": "\" and i'm warning you now-- if you've done anything to hurt my lorelee, i'll ...", + "PADDED_4": "\"and i'm warning you now--if you've done anything to hurt my coralee, i'll...\"", + "PADDED_8": "\"and i'm warning you now--if you've done anything to hurt my lorelee, i'll...\"", + "EXTRACTED_INIT_BOX": "And i'm warning you now-- if you've done anything to hurt ivan in any way, i'll...", + "PADDED_4_EXTRACTED": "And i'm warning you now--if you've done anything to hurt my daughter, i'll...", + "PADDED_8_EXTRACTED": "And i'm warning you now--if you've done anything to hurt my daughter, i'll...", + "PADDED_8_DILATION_1": "And i'm warning you now--if you've done anything to hurt my nagralee, i'll...", + "PAD_8_FRACT_0_5": "And i'm warning you now-- if you've done anything to hurt my grahlee, i'll ...", + "PAD_8_FRACT_0_2": "And i'm warning you now-- if you've done anything to hurt my graleee, i'll..." + }, + "20": { + "INITIAL_BOX": "Then where is she, drum?", + "DEFAULT": "Then where is she? drumm?", + "DEFAULT_GREY_PAD": "Then where is she, drum?", + "PADDED_4": "Then where is she, drum?", + "PADDED_8": "Then where is she, drum?", + "EXTRACTED_INIT_BOX": "Then where is she? drummer?", + "PADDED_4_EXTRACTED": "Then where is she, drummer?", + "PADDED_8_EXTRACTED": "Then where is she? drummer?", + "PADDED_8_DILATION_1": "Then where is she, drum?", + "PAD_8_FRACT_0_5": "Then where is she? drummer?", + "PAD_8_FRACT_0_2": "Then where is she? drummer?" + }, + "21": { + "INITIAL_BOX": "Men who claimed she was marked as sacrifice to the dark lord...", + "DEFAULT": "Men who claimed she was marked as sacrifice to the dark lord...", + "DEFAULT_GREY_PAD": "--men who claimed she was marked as sacrifice to the dark lord--", + "PADDED_4": "---men who claimed she was marked as sacrifice to the dark lord---", + "PADDED_8": "Men who claimed she was marked as sacrifice to the dark lord...", + "EXTRACTED_INIT_BOX": "--- men who claimed she was marked as sacrifice to the dark lord --\"", + "PADDED_4_EXTRACTED": "--- men who claimed she was marked as sacrifice to the dark lord --\"", + "PADDED_8_EXTRACTED": "---\"men who claimed she was marked as sacrifice to the dark lord\"----", + "PADDED_8_DILATION_1": "---men who claimed she was marked as sacrifice to the dark lord---\"", + "PAD_8_FRACT_0_5": "--- men who claimed she was marked as sacrifice to the dark lord --", + "PAD_8_FRACT_0_2": "--- men who claimed she was marked as sacrifice to the dark lord --" + }, + "22": { + "INITIAL_BOX": "Continued after next page.", + "DEFAULT": "Continued after next page", + "DEFAULT_GREY_PAD": "Continued after next page.", + "PADDED_4": "Continued after next page", + "PADDED_8": "Continued after next page.", + "EXTRACTED_INIT_BOX": "\" countdown to extinction was one of my favorite albums when i was growing up.", + "PADDED_4_EXTRACTED": "Continued as per exit", + "PADDED_8_EXTRACTED": "And he continued as if next", + "PADDED_8_DILATION_1": "Bounded configuration ap ... er exit", + "PAD_8_FRACT_0_5": "And i'm continued as next?", + "PAD_8_FRACT_0_2": "But now # configured ar_er exit?" + }, + "23": { + "INITIAL_BOX": "Marked by the sign of...the black rooster!?", + "DEFAULT": "Marked by the sign of...the black rooster!?", + "DEFAULT_GREY_PAD": "Marked by the sign of... the black rooster!?", + "PADDED_4": "Marked by the sign of...the black rooster!?", + "PADDED_8": "Marked by the sign of... the black rooster!?", + "EXTRACTED_INIT_BOX": "Marked by the sign of...the black rooster!?", + "PADDED_4_EXTRACTED": "Marked by the sign of... the black rooster!?", + "PADDED_8_EXTRACTED": "Marked by the sign of... the black rooster? !", + "PADDED_8_DILATION_1": "Marked by the sign of... the black rooster!?", + "PAD_8_FRACT_0_5": "Marked by the sign of the black rooster!", + "PAD_8_FRACT_0_2": "Marked by the sign of the black rooster!" + } + }, + "Tarzan_014-21.JPG": { + "0": { + "DEFAULT_GREY_PAD": "Toog? he is brave to come back here, after fighting with our leader...", + "INITIAL_BOX": "Toog? he is brave to come back here, after fighting with our leader...", + "DEFAULT": "Toog? he is brave to come back here, after fighting with our leader...", + "PADDED_4": "Toog? he is brave to come back here, after fighting with our leader.", + "PADDED_8": "Toog? he is brave to come back here, after fighting with our leader...", + "EXTRACTED_INIT_BOX": "Doog? me he is brave to come back here, after fighting with our leader.", + "PADDED_4_EXTRACTED": "Tyrog p? me is brave to come back here, after fighting with our leader.", + "PADDED_8_EXTRACTED": "Yiodog? me he is brave! to come back here, after fighting with our leader.", + "PADDED_8_DILATION_1": "Toodg p me is brave to come back here, after fighting with our leader.", + "PAD_8_FRACT_0_5": "Yodog p the is brave to come back again, after fighting with our leader.", + "PAD_8_FRACT_0_2": "Tyrog p the great braves to come back after fighting with our leader." + }, + "1": { + "INITIAL_BOX": "But the she will be a pretty one... when all her cuts heal... she will...", + "DEFAULT": "But the she will be a pretty one... when all her cuts heal... she will...", + "DEFAULT_GREY_PAD": "But the she will be a pretty one... when all her cuts heal... she will...", + "PADDED_4": "But she will be a pretty one... when all her cuts heal... she will...", + "PADDED_8": "But she will be a pretty one... when all her cuts heal... she will...", + "EXTRACTED_INIT_BOX": "But the gang will be a pretty one... when all her customs are gone... she will... \"", + "PADDED_4_EXTRACTED": "But time will be a pretty one... when all her cuts heal... same huh? ...hmmm....", + "PADDED_8_EXTRACTED": "But time will be a pretty one ... when all her cuts has healed ... she will ...", + "PADDED_8_DILATION_1": "But this she will be a pretty one... when all her cuts heal... she will...", + "PAD_8_FRACT_0_5": "But time will be a pretty one ... haimen all over cuts assail. one wills ...", + "PAD_8_FRACT_0_2": "Butt that game will be a pretty one... when all her cuts heal. some will ..." + }, + "2": { + "INITIAL_BOX": "Teeka will die before she will mate with toog--or with anyone but taung, of the tribe of merchants!", + "DEFAULT": "Teeka will die before she will mate with toog--or with anyone but taung, of the tribe of merchants!", + "DEFAULT_GREY_PAD": "Teeka will die before she will mate with toog--or with anyone but taung, of the tribe of merchak!?", + "PADDED_4": "Teeka will die before she will mate with toog--or with anyone but taung, of the tribe of merchants!", + "PADDED_8": "Teeka will die before she will mate with toog--or with anyone but taung, of the tribe of merchak!?", + "EXTRACTED_INIT_BOX": "Teefya will die before she will make with tooc--or with anyone buying of the virtue of miesmosmann!", + "PADDED_4_EXTRACTED": "Tiffanya will die before she will make with tobacco--or with anyone of the daughters of meroman!", + "PADDED_8_EXTRACTED": "Teeka will die before she will mate with troggs--or with anyone dying, of the property of aeronoman!", + "PADDED_8_DILATION_1": "Teeka will die before she will mate with toog--or with anyone but taung, of the tribe of meroman!?", + "PAD_8_FRACT_0_5": "Treesma will die before she makes it with troops -- or with anyone only dying of the poison of american!?", + "PAD_8_FRACT_0_2": "Teresa will die before she whines. matte with toots--or with anyone on the outside of her chain!" + }, + "3": { + "INITIAL_BOX": "Stay out of her reach, mangani! she is a fierce one!", + "DEFAULT": "Stay out of her reach, mangani! she is a fierce one!", + "DEFAULT_GREY_PAD": "Stay out of her reach, mangani! she is a fierce one!", + "PADDED_4": "Stay out of her reach! mangani! she is a fierce one!", + "PADDED_8": "Stay out of her reach, mangani! she is a fierce one!", + "EXTRACTED_INIT_BOX": "Stay out of her francis! marygani is she as a firebomb one?", + "PADDED_4_EXTRACTED": "Stay out of her business! mangamily she is a firebomb one!?", + "PADDED_8_EXTRACTED": "Stay out of her reach! manganiis! she is a fiend one! ?", + "PADDED_8_DILATION_1": "Stay out of her reach, manganelis! she is a fiend one!?", + "PAD_8_FRACT_0_5": "Stay out of her freaking business! manicanni? she is a firebot one! ?", + "PAD_8_FRACT_0_2": "Stay out of her freaking, mango-bannis! she is a fiend one! ?" + }, + "4": { + "INITIAL_BOX": "Just then...", + "DEFAULT": "Just then...", + "DEFAULT_GREY_PAD": "Just then...", + "PADDED_4": "Just then...", + "PADDED_8": "Just then...", + "EXTRACTED_INIT_BOX": "Just then...", + "PADDED_4_EXTRACTED": "\"just then\" he said.", + "PADDED_8_EXTRACTED": "Just then...", + "PADDED_8_DILATION_1": "Just then...", + "PAD_8_FRACT_0_5": "Just then...", + "PAD_8_FRACT_0_2": "Just then..." + }, + "5": { + "INITIAL_BOX": "Mangani! a pair of strange apes comes this way.", + "DEFAULT": "Mangani! a pair of strange apes comes this way.", + "DEFAULT_GREY_PAD": "Mangani! a pair of strange apes comes this way.", + "PADDED_4": "Mangani! a pair of strange apes comes this way.", + "PADDED_8": "Mangani! a pair of strange apes comes this way.", + "EXTRACTED_INIT_BOX": "Maggie ann! a pair of strange apes cries that's nutty?", + "PADDED_4_EXTRACTED": "Manning! a pair of strange apes comes this way?", + "PADDED_8_EXTRACTED": "Mapped ann! a pair of starranger apes monkeys this way?", + "PADDED_8_DILATION_1": "Mangani! a pair of strange apes comes this way.", + "PAD_8_FRACT_0_5": "Mappers ami! ? a pair of stranger apes comics this week.", + "PAD_8_FRACT_0_2": "Mapmaking game! a pair of stranger apes comics this way." + }, + "6": { + "INITIAL_BOX": "One is an ape...the other, a hairless monster.", + "DEFAULT": "One is an ape ... the other, a hairless monster.", + "DEFAULT_GREY_PAD": "One is an ape ... the other, a hairless monster.", + "PADDED_4": "One is an ape...the other, a hairless monster.", + "PADDED_8": "One is an ape ... the other, a hairless monster.", + "EXTRACTED_INIT_BOX": "One as an alpe --- the other, a miami egg monster.", + "PADDED_4_EXTRACTED": "Omif is an aide to the other, a hairless monster.", + "PADDED_8_EXTRACTED": "One as an ape -- the other, a hairless monster...", + "PADDED_8_DILATION_1": "One is an ape --- the other, a hairless monster.", + "PAD_8_FRACT_0_5": "One is an ape -- \"the other, \" a hairyless monster?", + "PAD_8_FRACT_0_2": "One is an ape -- \"the other, a hairless monster\"." + }, + "7": { + "INITIAL_BOX": "You hear, brothers? will you let strangers take toog's she away?", + "DEFAULT": "You hear, brothers? will you let strangers take toog's she away?", + "DEFAULT_GREY_PAD": "You hear, brothers? will you let strangers take toog's she away?", + "PADDED_4": "You hear, brothers? will you let strangers take todg's she away?", + "PADDED_8": "You hear, brothers? will you let strangers take toog's she away?", + "EXTRACTED_INIT_BOX": "You'll hear, brothers? will you live to see tomorrow morning for tom's bar away?", + "PADDED_4_EXTRACTED": "You hear, brothers? will you let strommebjer get twice todd's share away?", + "PADDED_8_EXTRACTED": "You mean, brothers? will you let cyborgers take todd's gun away?", + "PADDED_8_DILATION_1": "You hear, brothers? will you let strangers take todd's life away?", + "PAD_8_FRACT_0_5": "You hear, brothers? unveil you! let o'bannion take those frogs' car away?", + "PAD_8_FRACT_0_2": "You hear, brothers? will you let o'banioners take toodog's share away?" + }, + "8": { + "INITIAL_BOX": "Your she is no concern of ours--but we will not let any invade our part of the jungle.", + "DEFAULT": "Your she is no concern of ours--but we will not let any invade our part of the jungle.", + "DEFAULT_GREY_PAD": "Your she is no concern of ours--but we will not let any invade our part of the jungle.", + "PADDED_4": "Your she is no concern of ours--but we will not let any invade our part of the jungle.", + "PADDED_8": "Your she is no concern of ours--but we will not let any invade our part of the jungle.", + "EXTRACTED_INIT_BOX": "Your she is no conquest of ours --\" but he will not lift any invade our part of the jungle.", + "PADDED_4_EXTRACTED": "Your sister is no concern of ours--buy he will not let any invade our party of the jungle.", + "PADDED_8_EXTRACTED": "Nousr shie is no conversation of ours--buy we will not let any invaders on our part of the jungle", + "PADDED_8_DILATION_1": "Your ship is no concern of ours--but we will not let any invade our part of the jungle.", + "PAD_8_FRACT_0_5": "Your ship is no match for ours--but we will not let any invader take our part of the jungle!", + "PAD_8_FRACT_0_2": "Your ship is no connection of ours --\" but we will not let any invader cut our part of the jungle!" + }, + "9": { + "INITIAL_BOX": "Come ... and drag the she along! we will leap on them from hiding.", + "DEFAULT": "Come ... and drag the she along! we will leap on them from hiding.", + "DEFAULT_GREY_PAD": "Come ... and drag the she along! we will leap on them from hiding.", + "PADDED_4": "Come ... and drag the she along! we will leap on them from hiding.", + "PADDED_8": "Come ... and drag the she along! we will leap on them from hiding.", + "EXTRACTED_INIT_BOX": "\"come --\" and drag the she along! we will leap on them from hiding.", + "PADDED_4_EXTRACTED": "Coming -- and drag the she along! we will leap on them from hiding.", + "PADDED_8_EXTRACTED": "Coming --and dragging them she along! we will leap on them from hidings.", + "PADDED_8_DILATION_1": "Comes...and drag, the she along! we will leap on them from hiding.", + "PAD_8_FRACT_0_5": "Coming --and dragging the shit along! we will leap on them from hiding.", + "PAD_8_FRACT_0_2": "Coming --\"and drag the shit along! we will leap on them from hiding\"." + }, + "10": { + "INITIAL_BOX": "They are following toog's spoor!", + "DEFAULT": "They are following toog's spoor!", + "DEFAULT_GREY_PAD": "They are following toog's spoor!", + "PADDED_4": "They are following toog's spoor!", + "PADDED_8": "They are following toog's spoor!", + "EXTRACTED_INIT_BOX": "They are following toog's spoor!", + "PADDED_4_EXTRACTED": "They are following toog's smooor?", + "PADDED_8_EXTRACTED": "They are following toog's spoor!", + "PADDED_8_DILATION_1": "They are following toog's spoor!", + "PAD_8_FRACT_0_5": "They are following too's spoor?", + "PAD_8_FRACT_0_2": "They were following too's yooor?" + }, + "11": { + "INITIAL_BOX": "Teeka was here.", + "DEFAULT": "Teeka was here.", + "DEFAULT_GREY_PAD": "Teeka was here.", + "PADDED_4": "Teeka was here.", + "PADDED_8": "Teeka was here.", + "EXTRACTED_INIT_BOX": "Yeehaw was here.", + "PADDED_4_EXTRACTED": "Yeeka was here.", + "PADDED_8_EXTRACTED": "Yeeka was here.", + "PADDED_8_DILATION_1": "Yeeka was here.", + "PAD_8_FRACT_0_5": "Yeena was here.", + "PAD_8_FRACT_0_2": "Yeva was here." + }, + "12": { + "INITIAL_BOX": "Soon afterward, as tarzan and tug reach the selves same grove ...", + "DEFAULT": "Soon afterward, as tarzan and tang reach the selfsame grove ...", + "DEFAULT_GREY_PAD": "Soon afterward, as tarzan and tang reach the selfsame grove ...", + "PADDED_4": "Soon afterward, as tarzan and taj reach the selvesame grove ...", + "PADDED_8": "Soon afterward, as tarzan and tang reach the selfsame grove ...", + "EXTRACTED_INIT_BOX": "Soon afterworded as three-fourths of you reach the seaside once more ...", + "PADDED_4_EXTRACTED": "Soon afterwards, as thirty years ago, king george iii reached the age of...", + "PADDED_8_EXTRACTED": "Soon after that, as thirty-two and talking preach the selfsame song...", + "PADDED_8_DILATION_1": "Soon afterword, as tarkazan and takmes reach time selfsame grove ...", + "PAD_8_FRACT_0_5": "Soon after that, as tarazen and talus reach the shelter of same roof ...", + "PAD_8_FRACT_0_2": "Soon after shishimaro, as tarzan and tajun reach the selfsame grove ..." + }, + "13": { + "INITIAL_BOX": "Taugg! tarzan?", + "DEFAULT": "Taugg! tarzan?", + "DEFAULT_GREY_PAD": "Taug! tarzan?", + "PADDED_4": "Taug! tarzan?", + "PADDED_8": "Taug! tarzan?", + "EXTRACTED_INIT_BOX": "\" whoa!?", + "PADDED_4_EXTRACTED": "\"yahoo? darzan\"", + "PADDED_8_EXTRACTED": "Twug? darzany?", + "PADDED_8_DILATION_1": "Taug! tarzan", + "PAD_8_FRACT_0_5": "Yaz? darzan!", + "PAD_8_FRACT_0_2": "Tanug! tarzan" + }, + "14": { + "INITIAL_BOX": "Kretech4h?", + "DEFAULT": "Kretoah?", + "DEFAULT_GREY_PAD": "Kretegah?", + "PADDED_4": "Kre-o-ah?", + "PADDED_8": "Kretegah?", + "EXTRACTED_INIT_BOX": "Kre g'ah! *", + "PADDED_4_EXTRACTED": "Kreel: \"ah!", + "PADDED_8_EXTRACTED": "Kreel \"ah!", + "PADDED_8_DILATION_1": "Kreee-ahh?", + "PAD_8_FRACT_0_5": "Kreel \"ah!", + "PAD_8_FRACT_0_2": "Kre! o-ah?" + }, + "15": { + "INITIAL_BOX": "Toog will!?", + "DEFAULT": "Toog will!", + "DEFAULT_GREY_PAD": "Toog will!", + "PADDED_4": "Toog will!", + "PADDED_8": "Toog will!", + "EXTRACTED_INIT_BOX": "Toog will?", + "PADDED_4_EXTRACTED": "Toog will?", + "PADDED_8_EXTRACTED": "Toog will?", + "PADDED_8_DILATION_1": "Toog will!?", + "PAD_8_FRACT_0_5": "Tood hell?", + "PAD_8_FRACT_0_2": "Tood hymall?" + }, + "16": { + "INITIAL_BOX": "Yes! i smell her spoor...and the other's.", + "DEFAULT": "Yes! i smell her spoor...and the other's.", + "DEFAULT_GREY_PAD": "Yes! i smell her spoor...and the other's.", + "PADDED_4": "Yes! i smell her spoor...and the other's.", + "PADDED_8": "Yes! i smell her spoor...and the other's.", + "EXTRACTED_INIT_BOX": "Yes! i smell merr spook and me o'the", + "PADDED_4_EXTRACTED": "This! i smell mer spoor and he's out of time.", + "PADDED_8_EXTRACTED": "Yipes! i smell her spor and me odyne", + "PADDED_8_DILATION_1": "Yes! i smell her spoor and he othe", + "PAD_8_FRACT_0_5": "Yep! i smell their spoor and me oyna?", + "PAD_8_FRACT_0_2": "Yes! i smell her spoor and me owime?" + }, + "17": { + "INITIAL_BOX": "But, where can--?", + "DEFAULT": "But, where can--?", + "DEFAULT_GREY_PAD": "But, where can--?", + "PADDED_4": "But, where can--?", + "PADDED_8": "But, where can--?", + "EXTRACTED_INIT_BOX": "\" biggie, i'm sorry! \"", + "PADDED_4_EXTRACTED": "Booth, by the way...", + "PADDED_8_EXTRACTED": "But, nowhere! a", + "PADDED_8_DILATION_1": "But, where?", + "PAD_8_FRACT_0_5": "But, nowhere? a", + "PAD_8_FRACT_0_2": "But, nowhere? a" + }, + "18": { + "INITIAL_BOX": "Toog! keep her quiet?", + "DEFAULT": "Toog! keep her quiet?", + "DEFAULT_GREY_PAD": "Toog! keep her quiet?", + "PADDED_4": "Toog! keep her quiet?", + "PADDED_8": "Toog! keep her quiet?", + "EXTRACTED_INIT_BOX": "Toog! keep her quiet?", + "PADDED_4_EXTRACTED": "Toog! keep her quiet?", + "PADDED_8_EXTRACTED": "Toog! keep her quiet?", + "PADDED_8_DILATION_1": "Toog! keep her quiet?", + "PAD_8_FRACT_0_5": "Too bad! keep her quiet?", + "PAD_8_FRACT_0_2": "Toog! keep her quiet?" + }, + "19": { + "INITIAL_BOX": "Continue... after next page", + "DEFAULT": "Continue after next page", + "DEFAULT_GREY_PAD": "Continue... after next page", + "PADDED_4": "Continue after next page", + "PADDED_8": "Continue after next page.", + "EXTRACTED_INIT_BOX": "\" i don't know\" he muttered next page", + "PADDED_4_EXTRACTED": "Login vuger matter next page", + "PADDED_8_EXTRACTED": "Giant mole\" after next page.", + "PADDED_8_DILATION_1": "Continuer after next page", + "PAD_8_FRACT_0_5": "Continue? after next page.", + "PAD_8_FRACT_0_2": "Continue? after next page." + }, + "20": { + "INITIAL_BOX": "But he is an instant too late...", + "DEFAULT": "But he is an instant too late ...", + "DEFAULT_GREY_PAD": "But he is an instant too late ...", + "PADDED_4": "But he is an instant too late...", + "PADDED_8": "But he is an instant too late ...", + "EXTRACTED_INIT_BOX": "But he is an instant too late ...", + "PADDED_4_EXTRACTED": "But he is an instant two late ...", + "PADDED_8_EXTRACTED": "But he is an instant too late ...", + "PADDED_8_DILATION_1": "But he is an instant too late ...", + "PAD_8_FRACT_0_5": "But he is an instant too late ...", + "PAD_8_FRACT_0_2": "But he is an instant too late ..." + } + }, + "Transformers_-_Unicron_000-004.jpg": { + "0": { + "DEFAULT_GREY_PAD": "With the light of hope there is always a chance for victory.", + "INITIAL_BOX": "With the light of hope, there is always a chance for victory.", + "DEFAULT": "With the light of hope, there is always a chance for victory.", + "PADDED_4": "With the light of hope, there is always a chance for victory.", + "PADDED_8": "With the light of hope there is always a chance for victory.", + "EXTRACTED_INIT_BOX": "Anytime the light of hope fades there is always a chance for victory.", + "PADDED_4_EXTRACTED": "Kitty: the light of hope there is always a chance for victory.", + "PADDED_8_EXTRACTED": "With the light of hope there is always a chance for victory.", + "PADDED_8_DILATION_1": "With the light of hope there is always a chance for victory.", + "PAD_8_FRACT_0_5": "With the light of hope there is always a chance for victory.", + "PAD_8_FRACT_0_2": "With the light of hope there is always a chance for victory." + }, + "1": { + "INITIAL_BOX": "Platitudes are useless, prime. we have to hit that thing--now.", + "DEFAULT": "Platitudes are useless, prime. we have to hit that thing--now.", + "DEFAULT_GREY_PAD": "Platitudes are useless, prime. we have to hit that thing--now.", + "PADDED_4": "Platitudes are useless, prime. we have to hit that thing--now.", + "PADDED_8": "Platitudes are useless, prime. we have to hit that thing--now.", + "EXTRACTED_INIT_BOX": "Platitudes are useless primes. we have to hit that thing--anyway.", + "PADDED_4_EXTRACTED": "Platitudes are useless prime. we have to hit that thing--now.", + "PADDED_8_EXTRACTED": "Flatulences are messages prime. we have to hit that t-hings--more.", + "PADDED_8_DILATION_1": "Platitudes are useless, prime. we have to hit that thing--now.", + "PAD_8_FRACT_0_5": "Platitudes are useless to hit that thing--wow.", + "PAD_8_FRACT_0_2": "Flattery is a weapon primarily used to hit that things--now." + }, + "2": { + "INITIAL_BOX": "Pyra magna torchbearer.", + "DEFAULT": "Pyra magna, torchbearer.", + "DEFAULT_GREY_PAD": "Pyra magna torchbearer.", + "PADDED_4": "Pyra magna, torchbearer.", + "PADDED_8": "Pyra magna, torchbearer.", + "EXTRACTED_INIT_BOX": "Python. helghagn hj. to rgb e-mailer.", + "PADDED_4_EXTRACTED": "Pyhf. hjalgh. turch belier.", + "PADDED_8_EXTRACTED": "Python high middle eastern.", + "PADDED_8_DILATION_1": "Pyra magna torchbearer.", + "PAD_8_FRACT_0_5": "Pity him magg. tough brewer.", + "PAD_8_FRACT_0_2": "Pytha imagina, to righe bearer." + }, + "3": { + "INITIAL_BOX": "You know i've never run from a fight, pyra.", + "DEFAULT": "You know i've never run from a fight, pyra.", + "DEFAULT_GREY_PAD": "You know i've never run from a fight, pyra.", + "PADDED_4": "You know i've never run from a fight, pyra.", + "PADDED_8": "You know i've never run from a fight, pyra.", + "EXTRACTED_INIT_BOX": "You always say i've never run from a fight, pyra.", + "PADDED_4_EXTRACTED": "You know how i've never run from a fight, pytha.", + "PADDED_8_EXTRACTED": "You always have never been down from a fight, pyra.", + "PADDED_8_DILATION_1": "You know i've never run from a fight, pyra.", + "PAD_8_FRACT_0_5": "You know how i've never run from a fight, dyra?", + "PAD_8_FRACT_0_2": "You know i've never been in from a fight, dyra." + }, + "4": { + "INITIAL_BOX": "But even if this was winable--and it clearly is not--ask yourself ....", + "DEFAULT": "But even if this was winnable--and it clearly is not--ask yourself...", + "DEFAULT_GREY_PAD": "But even if this was winnable--and it clearly is not--ask yourself...", + "PADDED_4": "But even if this was winnable--and it clearly is not--ask yourself...", + "PADDED_8": "But even if this was winnable--and it clearly is not--ask yourself...", + "EXTRACTED_INIT_BOX": "But even if this was viable--and it clearly is not! ask yourself?", + "PADDED_4_EXTRACTED": "But even if this was viable--and it clearly is not! ask yourself...", + "PADDED_8_EXTRACTED": "But even if this pass was maneuverable - and it clearly is not - ask yourself, ...", + "PADDED_8_DILATION_1": "But even if this was winnable -and it clearly is not- ask yourself...", + "PAD_8_FRACT_0_5": "\" but even if this has happened, i'm still capable - and it clearly is! not ask yourself ...?", + "PAD_8_FRACT_0_2": "But even if this was viable--and it certainly is not! ask yourself, ..." + }, + "5": { + "INITIAL_BOX": "... did we come here to end lives or save them?", + "DEFAULT": "... did we come here to end lives or save them?", + "DEFAULT_GREY_PAD": "... did we come here to end lives or save them?", + "PADDED_4": "... did we come here to end lives or save them?", + "PADDED_8": "... did we come here to end lives or save them?", + "EXTRACTED_INIT_BOX": "Did we come here to end lives of slaves? them?", + "PADDED_4_EXTRACTED": "Did i come here to end limits or save them?", + "PADDED_8_EXTRACTED": "... did who come here to end or save them?", + "PADDED_8_DILATION_1": "Did we come here to end lives or save them?", + "PAD_8_FRACT_0_5": "Did what come here to end lives or save them?", + "PAD_8_FRACT_0_2": "... did what? come here to end lives or save them?" + }, + "6": { + "INITIAL_BOX": "That's where i come in. this doohickey\"ll create a world-spannin' space bridge-- and get every living being outta there.", + "DEFAULT": "That's where i come in. this doohickey'll create a world-spannin' space bridge - and get every living being outta there.", + "DEFAULT_GREY_PAD": "That's where i come in. this doohickey'll create a world-spannin' space bridge-- and get every living being outta there.", + "PADDED_4": "That's where i come in. this doohickey'll create a world-spannin' space bridge-- and get every living being outta there.", + "PADDED_8": "That's where i come in. this doohickey'll create a world-spannin' space bridge-- and get every living being outta there.", + "EXTRACTED_INIT_BOX": "That's where i come in! this moonickyll create a world-spannin', space bridge - and get every living being outta there?", + "PADDED_4_EXTRACTED": "That's somewhere i come in. this boomwickedly l. creates a world shannin' space bridge - and gets every living being outta there!", + "PADDED_8_EXTRACTED": "That's me! i came in this worldly fashion - a space bridge - and get every living being outta here?", + "PADDED_8_DILATION_1": "That's where i come in. this doohickey /ll create a world spanning space bridge - and get every living being outta there", + "PAD_8_FRACT_0_5": "That's pretty cool i come in this dope hickerylul creates a world dannin' space bridge - and get every living being outta there!", + "PAD_8_FRACT_0_2": "That 's where i come in this doohickey will create a world-shattering space bridge - and get every living thing outta thaer" + }, + "7": { + "INITIAL_BOX": "We don't know what this anomaly is, or why it's doing this--let alone how to stop something bigger than a planet.", + "DEFAULT": "We don't know what this anomaly is, or why it's doing this--let alone how to stop something bigger than a planet.", + "DEFAULT_GREY_PAD": "We don't know what this anomaly is, or why it's doing this--let alone how to stop something bigger than a planet.", + "PADDED_4": "We don't know what this anomaly is, or why it's doing this--let alone how to stop something bigger than a planet.", + "PADDED_8": "We don't know what this anomaly is, or why it's doing this--let alone how to stop something bigger than a planet.", + "EXTRACTED_INIT_BOX": "We don't know what this is or why we're doing this - let alone how to stop anything bigger than a plummet.", + "PADDED_4_EXTRACTED": "We don't know what this anomaly is or why it's doing this - list all one to stop something bigger than a planet?", + "PADDED_8_EXTRACTED": "We don't know what this anomaly is or why it's doing this - left alone how to stop something bigger than a planet?", + "PADDED_8_DILATION_1": "We don't know what this anomaly is or why its doing this-let alone how to stop something bigger than a planet.", + "PAD_8_FRACT_0_5": "We don't know what this anomaly is or why it's doing this-- let alone how to stop something bigger than a planet?", + "PAD_8_FRACT_0_2": "We don't know what this anomaly is or why it's doing this--it's alone how to stop something bigger than a planet?" + }, + "8": { + "INITIAL_BOX": "The anomaly is here because our world called it.", + "DEFAULT": "The anomaly is here because our world called it.", + "DEFAULT_GREY_PAD": "The anomaly is here because our world called it.", + "PADDED_4": "The anomaly is here because our world called it.", + "PADDED_8": "The anomaly is here because our world called it.", + "EXTRACTED_INIT_BOX": "\"the anomaly is here because our world called it.", + "PADDED_4_EXTRACTED": "The anomaly is here because our world called it.", + "PADDED_8_EXTRACTED": "The anomaly is here because our world called it.", + "PADDED_8_DILATION_1": "\"the anomaly is here because our world called it.\".", + "PAD_8_FRACT_0_5": "\"the anomaly is here because our world called it.", + "PAD_8_FRACT_0_2": "The anomaly is here because our world called it." + }, + "9": { + "INITIAL_BOX": "I will not let another civilization die because of cybertron's actions.", + "DEFAULT": "I will not let another civilization die because of cybertron's actions.", + "DEFAULT_GREY_PAD": "I will not let another civilization die because of cybertron's actions.", + "PADDED_4": "I will not let another civilization die because of cybertron's actions.", + "PADDED_8": "I will not let another civilization die because of cybertron's actions.", + "EXTRACTED_INIT_BOX": "I will not let another civilization die because of cybertron's actions.", + "PADDED_4_EXTRACTED": "I will. not let another civilization die because of cyborg actions!", + "PADDED_8_EXTRACTED": "I will not let another civilization die because of evertron's actions.", + "PADDED_8_DILATION_1": "I will not let another civilization die because of cybertron's actions.", + "PAD_8_FRACT_0_5": "I will not let another civilization die because of egotron's actions.", + "PAD_8_FRACT_0_2": "I will not list another civilization dies because of cybertron's actions." + }, + "10": { + "INITIAL_BOX": "I appreciate the aid, optimus prime...", + "DEFAULT": "I appreciate the aid, optimus prime ...", + "DEFAULT_GREY_PAD": "I appreciate the aid optimus prime...", + "PADDED_4": "I appreciate the aid, optimus prime ...", + "PADDED_8": "I appreciate the aid, optimus prime ...", + "EXTRACTED_INIT_BOX": "J. apparently type a optimists few", + "PADDED_4_EXTRACTED": "I appreciate this aid, optimus prime...", + "PADDED_8_EXTRACTED": "I appreciate time, and optimum prime...", + "PADDED_8_DILATION_1": "I appreciate the aid, optimus prime ...", + "PAD_8_FRACT_0_5": "I appreciate the aid, optimus prime...", + "PAD_8_FRACT_0_2": "I appreciate the aid, optimus prime..." + }, + "11": { + "INITIAL_BOX": "We just need about thirty of these suckers placed at strategic, uh, places.", + "DEFAULT": "We just need about thirty of these suckers placed at strategic, uh, places.", + "DEFAULT_GREY_PAD": "We just need about thirty of these suckers placed at strategic, uh, places.", + "PADDED_4": "We just need about thirty of these suckers placed at strategic, uh, places.", + "PADDED_8": "We just need about thirty of these suckers placed at strategic, uh, places.", + "EXTRACTED_INIT_BOX": "We just need about thirty / of these suckers placed at strategic points in places.", + "PADDED_4_EXTRACTED": "We just need about thirty of these suckers placed at strategic points.", + "PADDED_8_EXTRACTED": "We just need about twenty of these guys placed at strategic points.", + "PADDED_8_DILATION_1": "We just need about thirty of these suckers placed at strategic uh places.", + "PAD_8_FRACT_0_5": "We just need about three weeks / of that time to place at strategic locations.", + "PAD_8_FRACT_0_2": "We just need about three seconds to place at strategic points along the way of their march." + }, + "12": { + "INITIAL_BOX": "On elonia, if that wasn't implied.", + "DEFAULT": "On elonia, if that wasn't implied.", + "DEFAULT_GREY_PAD": "On elonia, if that wasn't implied.", + "PADDED_4": "On elonia, if that wasn't implied.", + "PADDED_8": "On elonia, if that wasn't implied.", + "EXTRACTED_INIT_BOX": "On earth, if that wasn't impolite.", + "PADDED_4_EXTRACTED": "On zeck ossa, if that hasn't implied.", + "PADDED_8_EXTRACTED": "Can i be honest, if that hasn't impaired you?", + "PADDED_8_DILATION_1": "On elonia, if that wasn't implied.", + "PAD_8_FRACT_0_5": "On becomes, if that isn't impudent enough?", + "PAD_8_FRACT_0_2": "On bloom! if that isn't impudent?" + }, + "13": { + "INITIAL_BOX": "Wheeljack, mad scientist.", + "DEFAULT": "Wheeljack, mad scientist.", + "DEFAULT_GREY_PAD": "Wheeljack, mad scientist.", + "PADDED_4": "Wheeljack, mad scientist.", + "PADDED_8": "Wheeljack, mad scientist.", + "EXTRACTED_INIT_BOX": "In the wheel-jack who scifiest...", + "PADDED_4_EXTRACTED": "My wheel-jack, who sci-fist.", + "PADDED_8_EXTRACTED": "In the wheeljack who scifist.", + "PADDED_8_DILATION_1": "W.h.e.l.j.a.c.k., m.d. scientist.", + "PAD_8_FRACT_0_5": "\" wheel-jack, who scientist.", + "PAD_8_FRACT_0_2": "Why wheel-jack? mad scientist." + }, + "14": { + "INITIAL_BOX": "... yet surely you did not believe the solstar order would be without its own defenses.", + "DEFAULT": "... yet surely you did not believe the solstar order would be without its own defenses.", + "DEFAULT_GREY_PAD": "... yet surely you did not believe the solstar order would be without its own defenses.", + "PADDED_4": "... yet surely you did not believe the solstar order would be without its own defenses.", + "PADDED_8": "... yet surely you did not believe the solstar order would be without its own defenses.", + "EXTRACTED_INIT_BOX": "\" yet surely you did not believe the seas-tair would be without its own defenders.", + "PADDED_4_EXTRACTED": "... yet surely you did not believe the sons-of-the-star would be without its own defenders.", + "PADDED_8_EXTRACTED": "Yet surely you did not believe the sons of starfire would be without its own defenders.", + "PADDED_8_DILATION_1": "...yet surely you did not believe the solstar order would be without its own defenses.", + "PAD_8_FRACT_0_5": "... yet surely you did not believe the gangstar would be without its own defense?", + "PAD_8_FRACT_0_2": "... yet surely you did not believe the golltar order would be without its own deepspaceboats." + }, + "15": { + "INITIAL_BOX": "Rom was the first of the greatest warriors the cosmos has ever known......", + "DEFAULT": "Rom was the first of the greatest warriors the cosmos has ever known....", + "DEFAULT_GREY_PAD": "Rom was the first of the greatest warriors the cosmos has ever known ...", + "PADDED_4": "Rom was the first of the greatest warriors the cosmos has ever known....", + "PADDED_8": "Rom was the first of the greatest warriors the cosmos has ever known....", + "EXTRACTED_INIT_BOX": "Roam maks the first of the greatest warriors the clanshas has ever known", + "PADDED_4_EXTRACTED": "Rom was the first of the great boy warriors. the cosmos has ever known.", + "PADDED_8_EXTRACTED": "Roman was the first of the great boy warriors the cosmos has ever known...", + "PADDED_8_DILATION_1": "Rom was the first of the greatest warriors the cosmos has ever known...", + "PAD_8_FRACT_0_5": "Rom was the first of the greatest boy warriors the cosmos has ever known...", + "PAD_8_FRACT_0_2": "Romm was the first of the greatest warriors the cosmos has ever known..." + } + }, + "Transformers_-_Unicron_000-016.jpg": { + "0": { + "DEFAULT_GREY_PAD": "... if you please, windblade.", + "INITIAL_BOX": "\"\"if you please, windblade.", + "DEFAULT": "\"\"... if you please, windblade.", + "PADDED_4": "... if you please, windblade.", + "PADDED_8": "... if you please, windblade.", + "EXTRACTED_INIT_BOX": "If you please, know yourself - and die?", + "PADDED_4_EXTRACTED": ". if you please, wait until i've finished?", + "PADDED_8_EXTRACTED": ". if you please, mister--i'm yours?", + "PADDED_8_DILATION_1": "If you please, windblade.", + "PAD_8_FRACT_0_5": ". if you please, www.dell-us.", + "PAD_8_FRACT_0_2": ". if you please, mister beladee?" + }, + "1": { + "INITIAL_BOX": "Our allies have been tracking this anomaly since the destruction of a planet called lv-117 some years ago.", + "DEFAULT": "Our allies have been tracking this anomaly since the destruction of a planet called lv-1117 some years ago.", + "DEFAULT_GREY_PAD": "Our allies have been tracking this anomaly since the destruction of a planet called lv-117 some years ago.", + "PADDED_4": "Our allies have been tracking this anomaly since the destruction of a planet called lv-117 some years ago.", + "PADDED_8": "Our allies have been tracking this anomaly since the destruction of a planet called lv-1117 some years ago.", + "EXTRACTED_INIT_BOX": "Mr. allan's have been tracking this anomaly/ since the destruction of a planet called alvary some years ago", + "PADDED_4_EXTRACTED": "Our allies have been tracking this anomaly since the destruction of a planet called "vega" 300 years ago.", + "PADDED_8_EXTRACTED": "Our allies have been tracking this anomaly since the destruction of a planet called vega 50 years ago.", + "PADDED_8_DILATION_1": "Our allies have been tracking this anomaly since the destruction of a planet called livistag some years ago.", + "PAD_8_FRACT_0_5": "Our allies have been tracking this anomaly since the destruction of a planet called cythera five years ago.", + "PAD_8_FRACT_0_2": "Our allies have been tracking this anomaly since the destruction of a flanny called eve back in 2017. bombs years ago!" + }, + "2": { + "INITIAL_BOX": "But lv-117 was unstuck in time.", + "DEFAULT": "But lv-117 was unstuck in time.", + "DEFAULT_GREY_PAD": "But lv-117 was unstuck in time.", + "PADDED_4": "But lv-117 was unstuck in time.", + "PADDED_8": "But lv-117 was unstuck in time.", + "EXTRACTED_INIT_BOX": "Alt jw-177 was stricken in 3712.", + "PADDED_4_EXTRACTED": "Bwt lw-117 kms6 chemtrails in time.", + "PADDED_8_EXTRACTED": "But lt.-117 was completely wrong in time.", + "PADDED_8_DILATION_1": "But ly-17 was unstuck in time.", + "PAD_8_FRACT_0_5": "But lw-117 was somewhere else in time.", + "PAD_8_FRACT_0_2": "But lw-177 was no threat in time." + }, + "3": { + "INITIAL_BOX": "What does that mean?", + "DEFAULT": "What does that mean?", + "DEFAULT_GREY_PAD": "What does that mean?", + "PADDED_4": "What does that mean?", + "PADDED_8": "What does that mean?", + "EXTRACTED_INIT_BOX": "What does that mean?", + "PADDED_4_EXTRACTED": "What does that mean?", + "PADDED_8_EXTRACTED": "What does that mean?", + "PADDED_8_DILATION_1": "What does that mean?", + "PAD_8_FRACT_0_5": "What does that mean?", + "PAD_8_FRACT_0_2": "\"what does that mean?" + }, + "4": { + "INITIAL_BOX": "The world was infused with a regenesis ore like the one that forged your armor--this one altering the flow of time.", + "DEFAULT": "The world was infused with a regenesis ore like the one that forged your armor--this one altering the flow of time.", + "DEFAULT_GREY_PAD": "The world was infused with a regenesis ore like the one that forged your armor--this one altering the flow of time.", + "PADDED_4": "The world was infused with a regenesis ore like the one that forged your armor--this one altering the flow of time.", + "PADDED_8": "The world was infused with a regenesis ore like the one that forged your armor--this one altering the flow of time.", + "EXTRACTED_INIT_BOX": "The world was infused with a brutalism so like the one that forged your armor - this one altering the flow of time.", + "PADDED_4_EXTRACTED": "The world was infused with a blazing sense of one like the one that opened you up armor - this one altering the flow of time.", + "PADDED_8_EXTRACTED": "The world was infused with a bewildering sense of like the one that forced your armore - thus one altering the flow of time.", + "PADDED_8_DILATION_1": "The world was infused with a regenesis or like the one that forged your armor--this one altering the flow of time.", + "PAD_8_FRACT_0_5": "The world was infused with a breathtaking sense of like the one that forged your armor--this one altering the flow of time.", + "PAD_8_FRACT_0_2": "The world was infused with a bio-energy so like the one that would armor--this or altering the flow of time." + }, + "5": { + "INITIAL_BOX": "While the effects of lv-117's destruction were apparent long ago, the actual attack occurred only last week.", + "DEFAULT": "While the effects of lv-177's destruction were apparent long ago, the actual attack occurred only last week.", + "DEFAULT_GREY_PAD": "While the effects of lv-117's destruction were apparent long ago, the actual attack occurred only last week.", + "PADDED_4": "While the effects of lv-117's destruction were apparent long ago, the actual attack occurred only last week.", + "PADDED_8": "While the effects of lv-117's destruction were apparent long ago, the actual attack occurred only last week.", + "EXTRACTED_INIT_BOX": "While the effects of ux-nyms destruction were apparent long ago, the actual attack occurred only last week.", + "PADDED_4_EXTRACTED": "While the effects of lw-19's destruction were apparent coming along, the actual attack occurred only last week.", + "PADDED_8_EXTRACTED": "While the effects of ultron's destruction were apparent & long ago, the actual attack occurred only last week.", + "PADDED_8_DILATION_1": "While the effects of livh'ys destruction were apparent long ago, the actual attack occurred only last week.", + "PAD_8_FRACT_0_5": "While the effects of uv-rays destruction were apparent along ago, the actual attack was only last week.", + "PAD_8_FRACT_0_2": "While the effects of lv-4198's destruction were apparent long ago, the actual attack occurred only last week." + }, + "6": { + "INITIAL_BOX": "After cybertron's invasion by human forces, a signal was sent into space: \"welcome death.\".", + "DEFAULT": "After cybertron's invasion by human forces, a signal was sent into space: \"welcome death.\".", + "DEFAULT_GREY_PAD": "After cybertron's invasion by human forces, a signal was sent into space: \"welcome death.\".", + "PADDED_4": "After cybertron's invasion by human forces, a signal was sent into space: \"welcome death.\".", + "PADDED_8": "After cybertron's invasion by human forces, a signal was sent into space: \"welcome death.\".", + "EXTRACTED_INIT_BOX": "After cybertron's invasion by human forcex a signal was sent into space: \"welcome to death...\".", + "PADDED_4_EXTRACTED": "After cybertron's invasion by human forces a signal was sent into space that was picked up by \"death\"!?", + "PADDED_8_EXTRACTED": "After cybertron's invasion by human forces a signal was sent into space warning them of our impending death.", + "PADDED_8_DILATION_1": "After cybertron's invasion by human forces signal was sent into space \"welcome death\"", + "PAD_8_FRACT_0_5": "After cybertron's invasion by human forces a signal was sent into space stating \"welcome to earth\".", + "PAD_8_FRACT_0_2": "After cybertron's invasion by human forces, a signal was sent into space, \"well come death\"." + }, + "7": { + "INITIAL_BOX": "Not terribly helpful.", + "DEFAULT": "Not terribly helpful.", + "DEFAULT_GREY_PAD": "Not terribly helpful.", + "PADDED_4": "Not terribly helpful.", + "PADDED_8": "Not terribly helpful.", + "EXTRACTED_INIT_BOX": "Not terribly helpful.", + "PADDED_4_EXTRACTED": "Not terribly helpful.", + "PADDED_8_EXTRACTED": "Not terribly helpful.", + "PADDED_8_DILATION_1": "Not terribly helpful.", + "PAD_8_FRACT_0_5": "Not terribly helpful.", + "PAD_8_FRACT_0_2": "Not terribly helpful." + }, + "8": { + "INITIAL_BOX": "But a second, more recent transmission was one word, \" something i 'd never heard before ...", + "DEFAULT": "But a second, more recent transmission was one word, something i'd never heard before...", + "DEFAULT_GREY_PAD": "But a second, more recent transmission was one word, something i'd never heard before...", + "PADDED_4": "But a second, more recent transmission was one word, something i'd never heard before...", + "PADDED_8": "But a second, more recent transmission was one word, something i'd never heard before...", + "EXTRACTED_INIT_BOX": "But a second transmission was one word, something i'd never heard before...", + "PADDED_4_EXTRACTED": "But a second agency transmission was one word i'd never heard before...", + "PADDED_8_EXTRACTED": "But a second big transmission was one word, something i've never heard before...", + "PADDED_8_DILATION_1": "But a second more recent transmission was one word, something i'd never heard before.", + "PAD_8_FRACT_0_5": "But a second more recent transmission was one word, something it never heard before...", + "PAD_8_FRACT_0_2": "But a second more powerful transformation was one word, something it never heard before..." + }, + "9": { + "INITIAL_BOX": "...unicron.", + "DEFAULT": "...unicron.", + "DEFAULT_GREY_PAD": "...unicron.", + "PADDED_4": "...unicron.", + "PADDED_8": "...unicron.", + "EXTRACTED_INIT_BOX": "I 'm expecting you both to be here at 8 o'clock sharp?", + "PADDED_4_EXTRACTED": "I'm going to go with you?", + "PADDED_8_EXTRACTED": "@#$%^&*()?", + "PADDED_8_DILATION_1": "Unicron.", + "PAD_8_FRACT_0_5": "Laughinggrowl?", + "PAD_8_FRACT_0_2": "...lingggrow?" + }, + "10": { + "INITIAL_BOX": "We learned of the destruction of an uninhabited world, prion, where a titan had died.", + "DEFAULT": "We learned of the destruction of an uninhabited world, prion, where a titan had died.", + "DEFAULT_GREY_PAD": "We learned of the destruction of an uninhabited world, prion, where a titan had died.", + "PADDED_4": "We learned of the destruction of an uninhabited world, prion, where a titan had died.", + "PADDED_8": "We learned of the destruction of an uninhabited world, prion, where a titan had died.", + "EXTRACTED_INIT_BOX": "We learned of the destruction of an unhabited world, known somewhere a star had died.", + "PADDED_4_EXTRACTED": "We learned of the destruction of an unhabited world, far beyond any human realm where a titan had died.", + "PADDED_8_EXTRACTED": "We learned of the destruction of an unhabited world, delta zero, where a 77-straw had died.", + "PADDED_8_DILATION_1": "We learned of the destruction of an uninhabited world, prion, where a titan had died.", + "PAD_8_FRACT_0_5": "We learned of the destruction of an unnamed world, where a titan had died.", + "PAD_8_FRACT_0_2": "We learned of the destruction of an uninhabited world, prison world, where a titan had died." + }, + "11": { + "INITIAL_BOX": "Then another dead planet was consumed - gorlam prime, where i had raised a titan myself.", + "DEFAULT": "Then another dead planet was consumed-- gorlam prime, where i had raised a titan myself.", + "DEFAULT_GREY_PAD": "Then another dead planet was consumed - gorlam prime, where i had raised a titan myself.", + "PADDED_4": "Then another dead planet was consumed - gorlam prime, where i had raised a titan myself.", + "PADDED_8": "Then another dead planet was consumed-- gorlam prime, where i had raised a titan myself.", + "EXTRACTED_INIT_BOX": "Then another dead planet was conquerued by forallan prime, whereas i had raised a titan myself.", + "PADDED_4_EXTRACTED": "Then another dead planet was consumed - godzilla prime, wherever it had raised a titan myself.", + "PADDED_8_EXTRACTED": "Then another dead planet was consumed -- forlorn planet prime, where i had raised a titan myself.", + "PADDED_8_DILATION_1": "Then another dead planet was consumed - gorlamp prime, where i had raised a titan myself.", + "PAD_8_FRACT_0_5": "Then another dead planet was consumed -- gorgon prime, where i had raised a titan myself.", + "PAD_8_FRACT_0_2": "Then another dead planet was conquered - gormlam prime, somewhere i had besieged a titan myself." + }, + "12": { + "INITIAL_BOX": "Next came velocitron - a cybertronian colony. you saw what was left, rom.", + "DEFAULT": "Next came velocitron-- a cybertronian colony. you saw what was left, rom.", + "DEFAULT_GREY_PAD": "Next came velocitron-- a cybertronian colony. you saw what was left, rom.", + "PADDED_4": "Next came velocitron - a cybertronian colony. you saw what was left, rom.", + "PADDED_8": "Next came velocitron-- a cybertronian colony. you saw what was left, rom.", + "EXTRACTED_INIT_BOX": "Next came vergo's tronch - a cybertroian colonize you ain't what was left form", + "PADDED_4_EXTRACTED": "Next came virus/gtron= a cybertonian colony. you saw what was left. eom.", + "PADDED_8_EXTRACTED": "Next came veronica-- a cybertronian colonist you saw what he was left.", + "PADDED_8_DILATION_1": "Next came velocitron-- a cybertronian colony. you saw what was left, rom.", + "PAD_8_FRACT_0_5": "Next came vulcanization-- a cybertrojanian colony: \" you saw what was left, zoma.", + "PAD_8_FRACT_0_2": "Next came velocitorion--- a cybertronian colony: you know what was left, bomba." + }, + "13": { + "INITIAL_BOX": "Unicorn is building itself out of the worlds it kills, becoming bigger--more powerful--with each extinction.", + "DEFAULT": "Unicron is building itself out of the worlds it kills, becoming bigger--more powerful--with each extinction.", + "DEFAULT_GREY_PAD": "Unicron is building itself out of the worlds it kills, becoming bigger--more powerful--with each extinction.", + "PADDED_4": "Unicron is building itself out of the worlds it kills, becoming bigger--more powerful--with each extinction.", + "PADDED_8": "Unicron is building itself out of the worlds it kills, becoming bigger--more powerful--with each extinction.", + "EXTRACTED_INIT_BOX": "Junction is building itself out of the worlds it kills, becoming more powerful - with each extinction.", + "PADDED_4_EXTRACTED": "Uniceon is embarrassing itself out of the world's affairs, becoming bigger - more powerful - with each extinction.", + "PADDED_8_EXTRACTED": "Unicorn is building itself out of the world's talks, becoming bigger -- more powerful-- with each extinction.", + "PADDED_8_DILATION_1": "Unicron is building itself out of the world's kills, becoming bigger=more powerful=with each extinction.", + "PAD_8_FRACT_0_5": "Unicon is building itself out of the world's talents, becoming bigger and more powerful with each extinction.", + "PAD_8_FRACT_0_2": "Unicorn is building itself out of the world's bills, becoming bigger--now more powerful--with each extinction." + }, + "14": { + "INITIAL_BOX": "It's murdering cybertron's colonies. which means--", + "DEFAULT": "It's murdering cybertron's colonies. which means--", + "DEFAULT_GREY_PAD": "It's murdering cybertron's colonies. which means -", + "PADDED_4": "It's murdering cybertron's colonies. which means--", + "PADDED_8": "It's murdering cybertron's colonies. which means -", + "EXTRACTED_INIT_BOX": "It's mulldezing cybeltron's con games. which means -", + "PADDED_4_EXTRACTED": "It 's mulibeeing cybertron's colonies. which means -", + "PADDED_8_EXTRACTED": "It's mulding cybertron's colonies, which means -", + "PADDED_8_DILATION_1": "It's murdering cybertron's colonies. which means--", + "PAD_8_FRACT_0_5": "It 's muled-deeling cybersition's colonies, which means -", + "PAD_8_FRACT_0_2": "It's mulder being overzealous colonel, which means -" + }, + "15": { + "INITIAL_BOX": "In addition to the rest of our worlds,\" earth is in danger. i have dragged the humans into mortal danger.", + "DEFAULT": "In addition to the rest of our worlds, earth is in danger. i have dragged the humans into mortal danger.", + "DEFAULT_GREY_PAD": "In addition to the rest of our worlds, earth is in danger. i have dragged the humans into mortal danger.", + "PADDED_4": "In addition to the rest of our worlds, earth is in danger. i have dragged the humans into mortal danger.", + "PADDED_8": "In addition to the rest of our worlds, earth is in danger. i have dragged the humans into mortal danger.", + "EXTRACTED_INIT_BOX": "In addition to the rest of que worlds, earth is in danger! i have pragged the humans into more tek dangers?", + "PADDED_4_EXTRACTED": "In addition to the rest of our worlds, earth is in danger! i have fragile humans into more than 764 damage?", + "PADDED_8_EXTRACTED": "In addition to the best of the worlds, earth is in range! i have flown among the humans into more than david's.", + "PADDED_8_DILATION_1": "In addition to the rest of our worlds, earth! i have dragged the humans into mortal danger.", + "PAD_8_FRACT_0_5": "In addition to the rest of our worlds, earth is in danger! we have peace among the humans into more than twice their number.", + "PAD_8_FRACT_0_2": "In addition to the rest of our world, earth is in panic! you have plagued the humans into more than i dareber." + }, + "16": { + "INITIAL_BOX": "Three billion elonians died today. ...", + "DEFAULT": "Three billion elonians died today ...", + "DEFAULT_GREY_PAD": "Three billion elonians died today ...", + "PADDED_4": "Three billion elonians died today. ...", + "PADDED_8": "Three billion elonians died today ...", + "EXTRACTED_INIT_BOX": "Three billion elonians died today...", + "PADDED_4_EXTRACTED": "Three billion elonians died today...", + "PADDED_8_EXTRACTED": "Three billion elonians died today...", + "PADDED_8_DILATION_1": "Three billion elonians died today.", + "PAD_8_FRACT_0_5": "Three billion elonians died today...", + "PAD_8_FRACT_0_2": "Three billion flonians died today..." + } + }, + "WARE_ACME_024.jpg": { + "0": { + "DEFAULT_GREY_PAD": "Lil' glyph.", + "INITIAL_BOX": "Lil' glyph", + "DEFAULT": "Lil' glyph.", + "PADDED_4": "Lil' glyph", + "PADDED_8": "Lil' glyph.", + "EXTRACTED_INIT_BOX": "\" glyphh", + "PADDED_4_EXTRACTED": "I' glyphh", + "PADDED_8_EXTRACTED": "I' glyphh", + "PADDED_8_DILATION_1": "I' glyphh", + "PAD_8_FRACT_0_5": "I' glyphh", + "PAD_8_FRACT_0_2": "I' glyph" + }, + "1": { + "INITIAL_BOX": "Almost done...", + "DEFAULT": "Almost done...", + "DEFAULT_GREY_PAD": "Almost done...", + "PADDED_4": "Almost done...", + "PADDED_8": "Almost done...", + "EXTRACTED_INIT_BOX": "Almost done...", + "PADDED_4_EXTRACTED": "Almost done...", + "PADDED_8_EXTRACTED": "Almost done...", + "PADDED_8_DILATION_1": "Almost done...", + "PAD_8_FRACT_0_5": "Almost done...", + "PAD_8_FRACT_0_2": "Almost done..." + }, + "2": { + "INITIAL_BOX": "Oh hey, i -", + "DEFAULT": "Oh hey, i - -", + "DEFAULT_GREY_PAD": "Oh hey, i -", + "PADDED_4": "Oh hey, i -", + "PADDED_8": "Oh hey, i -", + "EXTRACTED_INIT_BOX": "Oh hey, i", + "PADDED_4_EXTRACTED": "Oh hey, i", + "PADDED_8_EXTRACTED": "Oh hey, i", + "PADDED_8_DILATION_1": "Oh hey, i", + "PAD_8_FRACT_0_5": "Oh hey, i", + "PAD_8_FRACT_0_2": "Oh hey, i" + }, + "3": { + "INITIAL_BOX": "Pinnacle of", + "DEFAULT": "Pinnacle of", + "DEFAULT_GREY_PAD": "Pinnacle.", + "PADDED_4": "Pinnacle of", + "PADDED_8": "Pinnacle of", + "EXTRACTED_INIT_BOX": "Pinnacle.", + "PADDED_4_EXTRACTED": "Pinnacle.", + "PADDED_8_EXTRACTED": "Pinnacle of", + "PADDED_8_DILATION_1": "Pinnacle of", + "PAD_8_FRACT_0_5": "Pinnacle of", + "PAD_8_FRACT_0_2": "Pinnacle of" + }, + "4": { + "INITIAL_BOX": "Man oh man ... that sure was one heckuva last night ... whew!", + "DEFAULT": "Man oh man ... that sure was one heckuva orgy last night ... whew!", + "DEFAULT_GREY_PAD": "Man oh man ... that sure was one heckuva orgy last night ... whew!", + "PADDED_4": "Man oh man ... that sure was one heckuva last night ... whew!", + "PADDED_8": "Man oh man ... that sure was one heckuva orgy last night ... whew!", + "EXTRACTED_INIT_BOX": "Man oh man ... that sure was one heck of a night last night ... where?", + "PADDED_4_EXTRACTED": "Man oh man ... that sure was one heckuvva last night ... where?", + "PADDED_8_EXTRACTED": "Man oh man ... that sure was one heckluva drag last night ... where?", + "PADDED_8_DILATION_1": "Man oh man ... that sure was one heckuva big night ... when?", + "PAD_8_FRACT_0_5": "Man oh man ... that sure was one heckuva drigy last night ... where?", + "PAD_8_FRACT_0_2": "Man oh man ... that sure was one heckuva orgy last night ... wow?" + }, + "5": { + "INITIAL_BOX": "Summer", + "DEFAULT": "Summer", + "DEFAULT_GREY_PAD": "Summer", + "PADDED_4": "Summer", + "PADDED_8": "Summer", + "EXTRACTED_INIT_BOX": "Summer", + "PADDED_4_EXTRACTED": "Summer", + "PADDED_8_EXTRACTED": "Summer", + "PADDED_8_DILATION_1": "Summer", + "PAD_8_FRACT_0_5": "Summer", + "PAD_8_FRACT_0_2": "Summer" + }, + "6": { + "INITIAL_BOX": "Oh, those jews", + "DEFAULT": "Oh, those jews", + "DEFAULT_GREY_PAD": "Oh, those jews", + "PADDED_4": "Oh, those jews", + "PADDED_8": "Oh, those jews", + "EXTRACTED_INIT_BOX": "Oh, those jews!", + "PADDED_4_EXTRACTED": "Oh, those jews!", + "PADDED_8_EXTRACTED": "Oh, those jews", + "PADDED_8_DILATION_1": "Oh, those jews!", + "PAD_8_FRACT_0_5": "Oh, those jews", + "PAD_8_FRACT_0_2": "Oh, those jews" + }, + "7": { + "INITIAL_BOX": "Man, fuck this shit", + "DEFAULT": "Man, fuck this shit", + "DEFAULT_GREY_PAD": "Man, fuck this shit", + "PADDED_4": "Man, fuck this shit", + "PADDED_8": "Man, fuck this shit", + "EXTRACTED_INIT_BOX": "Man, fuck this shit", + "PADDED_4_EXTRACTED": "Man, fuck this shit.", + "PADDED_8_EXTRACTED": "Man, fuck this shit", + "PADDED_8_DILATION_1": "Man, this shit", + "PAD_8_FRACT_0_5": "Man, fuck this shit", + "PAD_8_FRACT_0_2": "Man, fuck this shit" + }, + "8": { + "INITIAL_BOX": "I'm sick of hauling ass for those fucking pharaohs.", + "DEFAULT": "I'm sick of hauling ass for those fucking pharaohs.", + "DEFAULT_GREY_PAD": "I'm sick of hauling ass for those fucking pharaohs.", + "PADDED_4": "I'm sick of hauling ass for those fucking pharaohs.", + "PADDED_8": "I'm sick of hauling ass for those fucking pharaohs.", + "EXTRACTED_INIT_BOX": "I'm sick of hauling ass for those fucking pharohs.", + "PADDED_4_EXTRACTED": "I'm sick of hauling ass for those fucking pharohs.", + "PADDED_8_EXTRACTED": "I'm sick of hauling ass for those fucking pharmaholes.", + "PADDED_8_DILATION_1": "I'm sick of hauling ass for those fucking pharaohs.", + "PAD_8_FRACT_0_5": "I'm sick of hauling ass for those fucking pharaohs.", + "PAD_8_FRACT_0_2": "I'm sick of hauling ass for those fucking pharaohs." + }, + "9": { + "INITIAL_BOX": "Our new altarpiece\"", + "DEFAULT": "Our new altarpiecetm", + "DEFAULT_GREY_PAD": "Our new altarpiecetm", + "PADDED_4": "Our new altarpiecetm", + "PADDED_8": "Our new altarpiece\"tm", + "EXTRACTED_INIT_BOX": "Our new altarpiece", + "PADDED_4_EXTRACTED": "Our new altarpiece", + "PADDED_8_EXTRACTED": "Lir new altarpiece", + "PADDED_8_DILATION_1": "Our new altarpiece", + "PAD_8_FRACT_0_5": "Lir new altarpiece", + "PAD_8_FRACT_0_2": "Her new altarpiece." + }, + "10": { + "INITIAL_BOX": "And over here are the twelve stations of the cross ...", + "DEFAULT": "And over here are the twelve stations of the cross ...", + "DEFAULT_GREY_PAD": "And over here are the twelve stations of the cross ...", + "PADDED_4": "And over here are the twelve stations of the cross ...", + "PADDED_8": "And over here are the twelve stations of the cross ...", + "EXTRACTED_INIT_BOX": "And over here are the twelve stations of time cross.", + "PADDED_4_EXTRACTED": "And over here we are the twelve stations of the cross ...", + "PADDED_8_EXTRACTED": "And over hereie are the twelve staylions of the cross\"", + "PADDED_8_DILATION_1": "And over hereie are the twelve stations of the cross. \"", + "PAD_8_FRACT_0_5": "And over here are the twelve stations of the cross ...", + "PAD_8_FRACT_0_2": "And over here are the twelve stations of the cross ..." + }, + "11": { + "INITIAL_BOX": "I'll just sneak a little doodle on this wall to believe my anger.", + "DEFAULT": "I'll just sneak a little doodle on this wall to believe my anger.", + "DEFAULT_GREY_PAD": "I'll just sneak a little doodle on this wall to relieve my anger.", + "PADDED_4": "I'll just sneak a little doodle on this wall to relieve my anger.", + "PADDED_8": "I'll just sneak a little doodle on this wall to relieve my anger.", + "EXTRACTED_INIT_BOX": "I'll just sneak a little doodle on this wall to believe my anger.", + "PADDED_4_EXTRACTED": "I'll just sneak a little doodle on this wall to relieve my anger.", + "PADDED_8_EXTRACTED": "I 'll just sneak a little doodle on this wall to believe my anger.", + "PADDED_8_DILATION_1": "I'll just sneak a little doodle on this wall to relieve my anger.", + "PAD_8_FRACT_0_5": "I 'll just sneak a little doodle on this wall to believe my anger.", + "PAD_8_FRACT_0_2": "I 'll just sneak a little doodle on this wall to believe my anger." + }, + "12": { + "INITIAL_BOX": "Ha ha -- they'll never find it here!", + "DEFAULT": "Ha ha -- they'll never find it here!", + "DEFAULT_GREY_PAD": "Ha ha -- they'll never find it here!", + "PADDED_4": "Ha ha -- they'll never find it here!", + "PADDED_8": "Ha ha -- they'll never find it here!", + "EXTRACTED_INIT_BOX": "Hah hah 'they'll never find t here! '", + "PADDED_4_EXTRACTED": "Ha ha! they'll never find 'em here?", + "PADDED_8_EXTRACTED": "Ha ha! they'll never find it here? !", + "PADDED_8_DILATION_1": "Ha ha they'll never find 'em here!", + "PAD_8_FRACT_0_5": "Ha ha! they'll never find 'em here? !", + "PAD_8_FRACT_0_2": "Ha ha they'll never find t here!" + }, + "13": { + "INITIAL_BOX": "Why do you paint twelve christ's, when we know there is only one?", + "DEFAULT": "Why do you paint twelve christ's, when we know there is only one?", + "DEFAULT_GREY_PAD": "Why do you paint twelve christ's, when we know there is only one?", + "PADDED_4": "Why do you paint twelve christ's, when we know there is only one?", + "PADDED_8": "Why do you paint twelve christ's, when we know there is only one?", + "EXTRACTED_INIT_BOX": "Why do you paint twelve christ's, when we know there is only one?", + "PADDED_4_EXTRACTED": "Why do you paint twelvelove christ's, when we know there is only one?", + "PADDED_8_EXTRACTED": "Why do you paint twelve christ's, when we know there is only one?", + "PADDED_8_DILATION_1": "Why do you paint twelve christ's, when we know there is only one?", + "PAD_8_FRACT_0_5": "Why do you paint twelve christ's, when we know there is only one?", + "PAD_8_FRACT_0_2": "Why do you paint twelve christ's, when we know there is only one?" + }, + "14": { + "INITIAL_BOX": "Civilization.", + "DEFAULT": "Civilization.", + "DEFAULT_GREY_PAD": "Civilization.", + "PADDED_4": "Civilization.", + "PADDED_8": "Civilization.", + "EXTRACTED_INIT_BOX": "Iv lizaton", + "PADDED_4_EXTRACTED": "\"iv\" lizaton", + "PADDED_8_EXTRACTED": "Iv lization", + "PADDED_8_DILATION_1": "Iv lization", + "PAD_8_FRACT_0_5": "Iv lization", + "PAD_8_FRACT_0_2": "Iv lization" + }, + "15": { + "INITIAL_BOX": "Oy!", + "DEFAULT": "Oy!", + "DEFAULT_GREY_PAD": "Oy!", + "PADDED_4": "Oy!", + "PADDED_8": "Oy!", + "EXTRACTED_INIT_BOX": "I'm sorry i didn't mean to hurt you.", + "PADDED_4_EXTRACTED": "I'm sorry i didn't mean to hurt you.", + "PADDED_8_EXTRACTED": "I'm sorry i didn't mean to hurt you.", + "PADDED_8_DILATION_1": "I'm sorry i didn't mean to hurt you.", + "PAD_8_FRACT_0_5": "I'm sorry i didn't mean to hurt you.", + "PAD_8_FRACT_0_2": "I'm sorry i didn't mean to hurt you." + }, + "16": { + "INITIAL_BOX": "Match the stereotype with his or her appropriate physiognomic template:", + "DEFAULT": "Match the stereotype with his or her appropriate physiognomic template;", + "DEFAULT_GREY_PAD": "Match the stereotype with his or her appropriate physiognomic template;", + "PADDED_4": "Match the stereotype with his or her appropriate physiognomic template;", + "PADDED_8": "Match the stereotype with his or her appropriate physiognomic template;", + "EXTRACTED_INIT_BOX": "Amatch the sttergo ypee with his or her apporriate physiognomic template?", + "PADDED_4_EXTRACTED": "Amych? the stereo viper with his or her appropriate phisiologic template?:", + "PADDED_8_EXTRACTED": "Matcha! the stergo yipes with his or her appropriate physionomic template?", + "PADDED_8_DILATION_1": "Matcha! the stereo type ype with his or her appropriate physiologic templates;", + "PAD_8_FRACT_0_5": "Mastermind: the stereo type yipes with his or her appropriate physiognomic template.", + "PAD_8_FRACT_0_2": "Matcha! the stereo type ype with his or her appropriate physiognomic template." + }, + "17": { + "INITIAL_BOX": "Sir! mr. magnate, sir! i have solved the problem of railcar ennui, master magnate!", + "DEFAULT": "Sir! mr. magnate, sir! i have solved the problem of railcar ennui, master magnate!", + "DEFAULT_GREY_PAD": "Sir! mr. magnate, sir! i have solved the problem of railcar ennui, master magnate!", + "PADDED_4": "Sir! mr. magnate, sir! i have solved the problem of railcar ennui, master magnate!", + "PADDED_8": "Sir! mr. magnate, sir! i have solved the problem of railcar ennui, master magnate!", + "EXTRACTED_INIT_BOX": "Our! mr. magnate, sir! i have solved the problem of malcolm ennui, master magnate?", + "PADDED_4_EXTRACTED": "Oir? mr. magnate, sir! i have solved the problem of railcar ennui, master magnate?", + "PADDED_8_EXTRACTED": "Sir! mr. magnate, sir! i have solved the problem of railcar ennell, master magnate?", + "PADDED_8_DILATION_1": "Our!? mr. magnate, sir! / i have solved the problem of railcar ennuji, master magnate?", + "PAD_8_FRACT_0_5": "Our? mr. magnate, sir! i have solved the problem of railcar ennui, master magnate?", + "PAD_8_FRACT_0_2": "Our? mr. magnate, sir! i have solved the problem of railcar ennuj, master magnate?" + }, + "18": { + "INITIAL_BOX": "Uncle rodolphe", + "DEFAULT": "Uncle rodolpho", + "DEFAULT_GREY_PAD": "Uncle rodolphe", + "PADDED_4": "Uncle rodolpho", + "PADDED_8": "Uncle rodolphe", + "EXTRACTED_INIT_BOX": "Uncle rodolpho", + "PADDED_4_EXTRACTED": "Uncle rodolpho", + "PADDED_8_EXTRACTED": "Uncle rodolpho", + "PADDED_8_DILATION_1": "Uncle rodolpho", + "PAD_8_FRACT_0_5": "Uncle rodolpho", + "PAD_8_FRACT_0_2": "Uncle rodolpho" + }, + "19": { + "INITIAL_BOX": "The kindly old swiss guy who invented comics", + "DEFAULT": "The kindly old swiss guy who invented comics", + "DEFAULT_GREY_PAD": "The kindly old swiss guy who invented comics", + "PADDED_4": "The kindly old swiss guy who invented comics", + "PADDED_8": "The kindly old swiss guy who invented comics", + "EXTRACTED_INIT_BOX": "The kindly old swiss guy who invented comics", + "PADDED_4_EXTRACTED": "The kindly old swiss guy who invented comics", + "PADDED_8_EXTRACTED": "The kindly old swiss guy who invented comics", + "PADDED_8_DILATION_1": "The kindly old swiss guy who invented comics", + "PAD_8_FRACT_0_5": "The kindly old swiss guy who invented comics", + "PAD_8_FRACT_0_2": "The kindly old swiss guy who invented comics" + }, + "20": { + "INITIAL_BOX": "William randolph hearst", + "DEFAULT": "William randolph hearst", + "DEFAULT_GREY_PAD": "William randolph hearst", + "PADDED_4": "William randolph hearst", + "PADDED_8": "William randolph hearst", + "EXTRACTED_INIT_BOX": "William randolph hearst", + "PADDED_4_EXTRACTED": "William randolph hearst", + "PADDED_8_EXTRACTED": "William randolph hearst", + "PADDED_8_DILATION_1": "William randolph hearst", + "PAD_8_FRACT_0_5": "William randolph hearst", + "PAD_8_FRACT_0_2": "William randolph hearst" + }, + "21": { + "INITIAL_BOX": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to nail their goddamn american asses!", + "DEFAULT": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to nail their goddamn american asses!", + "DEFAULT_GREY_PAD": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to nail their goddamn american asses!", + "PADDED_4": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to nail their goddamn american asses!", + "PADDED_8": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to nail their goddamn american asses!", + "EXTRACTED_INIT_BOX": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to mail their goldmann american asses?", + "PADDED_4_EXTRACTED": "Liggen... i don't care if international copyright law presents recognizable picture stories... i want to mail their goddamn american asses!", + "PADDED_8_EXTRACTED": "Lussen ... i don't care if international copyright law pushes my recognize picture stories ... i want to nail their goddamn american asses!", + "PADDED_8_DILATION_1": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to mail their goddamn american asses!", + "PAD_8_FRACT_0_5": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to nail their goddamn american asses!", + "PAD_8_FRACT_0_2": "Lissen ... i don't care if international copyright law doesn't recognize picture stories ... i want to nail their goddamn american asses!" + }, + "22": { + "INITIAL_BOX": "What our democracy needs is its own native artform!", + "DEFAULT": "What our democracy needs is its own native artform!", + "DEFAULT_GREY_PAD": "What our democracy needs is its own native artform!", + "PADDED_4": "What our democracy needs is its own native artform!", + "PADDED_8": "What our democracy needs is its own native artform!", + "EXTRACTED_INIT_BOX": "What our democracy needs is its own native anti-form!?", + "PADDED_4_EXTRACTED": "What our democracy needs is its own native art-form!", + "PADDED_8_EXTRACTED": "What our democracy needs is its own native art-form!", + "PADDED_8_DILATION_1": "Hat our democracy needs is its own native artform!", + "PAD_8_FRACT_0_5": "Hat our democracy needs is its own native artform!?", + "PAD_8_FRACT_0_2": "Hat our democracy needs is its own native artform!?" + }, + "23": { + "INITIAL_BOX": "Yes, but...", + "DEFAULT": "Yes, but...", + "DEFAULT_GREY_PAD": "Yes, but...", + "PADDED_4": "Yes, but...", + "PADDED_8": "Yes, but...", + "EXTRACTED_INIT_BOX": "Y.", + "PADDED_4_EXTRACTED": "Y.", + "PADDED_8_EXTRACTED": "Y", + "PADDED_8_DILATION_1": "Y", + "PAD_8_FRACT_0_5": "Y", + "PAD_8_FRACT_0_2": "Y" + }, + "24": { + "INITIAL_BOX": "The thief in my picture story doesn't look mean and stupid enough", + "DEFAULT": "The thief in my picture story doesn't look mean and stupid enough", + "DEFAULT_GREY_PAD": "The thief in my picture story doesn't look mean and stupid enough", + "PADDED_4": "The thief in my picture story doesn't look mean and stupid enough", + "PADDED_8": "The thief in my picture story doesn't look mean and stupid enough", + "EXTRACTED_INIT_BOX": "The thief in my picture story doesn't look mean and stupid enough!", + "PADDED_4_EXTRACTED": "The thief in my picture story doesn't look mean and stupid enough!", + "PADDED_8_EXTRACTED": "The thief in my picture story doesn't look mean and stupid enough", + "PADDED_8_DILATION_1": "The thief in my picture story doesn't look mean and stupid enough.", + "PAD_8_FRACT_0_5": "The thief in my picture story doesn't look mean and stupid enough", + "PAD_8_FRACT_0_2": "The thief in my picture story doesn't look mean and stupid enough." + }, + "25": { + "INITIAL_BOX": "Something like those german and swiss pic- ture books i loved as a kid... \"", + "DEFAULT": "Something like those german and swiss pic- ture books i loved as a kid... \"", + "DEFAULT_GREY_PAD": "Something like those german and swiss pic- ture books i loved as a kid... \"", + "PADDED_4": "Something like those german and swiss pic- ture books i loved as a kid... \"", + "PADDED_8": "Something like those german and swiss pic- ture books i loved as a kid... \"", + "EXTRACTED_INIT_BOX": "Something uk house german and swiss pie to make books i loved as a kid.", + "PADDED_4_EXTRACTED": "Methinks uk house german and swiss pics toga books i loved as a kid.", + "PADDED_8_EXTRACTED": "Metthing uk mosie german and swiss pie tome books\" i thought as a kid,", + "PADDED_8_DILATION_1": "Methling uk hose german and swiss pig ture books i loved as a kid.", + "PAD_8_FRACT_0_5": "Something like mosie german and swiss pie tore books i loved as a kid.", + "PAD_8_FRACT_0_2": "Something like mose german and swiss pie tore books i loved as a kid." + }, + "26": { + "INITIAL_BOX": "Hey, that's it?", + "DEFAULT": "Hey, that's it?", + "DEFAULT_GREY_PAD": "Hey, that's it?", + "PADDED_4": "Hey, that's it?", + "PADDED_8": "Hey, that's it?", + "EXTRACTED_INIT_BOX": "Hey, that's it?", + "PADDED_4_EXTRACTED": "Hey, that's it?", + "PADDED_8_EXTRACTED": "Hey, that's it?", + "PADDED_8_DILATION_1": "Hey, that's it?", + "PAD_8_FRACT_0_5": "Hey, that's it?", + "PAD_8_FRACT_0_2": "Hey, that's it?" + }, + "27": { + "INITIAL_BOX": "I'll make him look more like one of those filthy, good- for- nothing american sons of bitches.", + "DEFAULT": "I'll make him look more like one of those filthy, good- for- nothing american sons of bitches.", + "DEFAULT_GREY_PAD": "I'll make him look more like one of those filthy, good-for-nothing american sons of bitches", + "PADDED_4": "I'll make him look more like one of those filthy, good- for-nothing american sons of bitches.", + "PADDED_8": "I'll make him look more like one of those filthy, good-for-nothing american sons of bitches.", + "EXTRACTED_INIT_BOX": "It'll make him look more like one of those filthy, good-for-nothing american sons of bitches.", + "PADDED_4_EXTRACTED": "It'll make him look more like one of those filthy, good-for-nothing american sons of bitches.", + "PADDED_8_EXTRACTED": "It'll make him look more like one of those filthy, good-for-nothing american sons of bitches.", + "PADDED_8_DILATION_1": "It'll make him look more like one of those filthy, good-for-nothing american sons of bitches.", + "PAD_8_FRACT_0_5": "It'll make him look more like one of those filthy, good-for-nothing american sons of bitches.", + "PAD_8_FRACT_0_2": "It'll make him look more like one of those filthy, good-for-nothing american sons of bitches." + }, + "28": { + "INITIAL_BOX": "I'll just have one of my staff artists plagiarize them?", + "DEFAULT": "I'll just have one of my staff artists plagiarize them!", + "DEFAULT_GREY_PAD": "I'll just have one of my staff artists plagiarize them!", + "PADDED_4": "I'll just have one of my staff artists plagiarize them!", + "PADDED_8": "I'll just have one of my staff artists plagiarize them!", + "EXTRACTED_INIT_BOX": "Raul must blame one of his staff artists! plagiarize me?", + "PADDED_4_EXTRACTED": "Paul must make one of his staff artists plagiarize max!", + "PADDED_8_EXTRACTED": "Zahl just blane one of my staff artists plugarville!", + "PADDED_8_DILATION_1": "Well just have one of my staff artists plagiarize henry!", + "PAD_8_FRACT_0_5": "Ranal just blame one of his staff artists plagiarizes madey!", + "PAD_8_FRACT_0_2": "I'm just blaming one of my staff artists! plagiarizes everyone?" + }, + "29": { + "INITIAL_BOX": "Jazz, comics, booze & college songs", + "DEFAULT": "Jazz, comics, booze & college songs", + "DEFAULT_GREY_PAD": "Jazz comics, booze & college songs", + "PADDED_4": "Jazz, comics, booze & college songs", + "PADDED_8": "Jazz comics, booze & college songs", + "EXTRACTED_INIT_BOX": "Jazz, comics, booze & college songs", + "PADDED_4_EXTRACTED": "Jazz, comics, booze & college songs", + "PADDED_8_EXTRACTED": "Jazz, comics, booze & college songs", + "PADDED_8_DILATION_1": "Jazz, comics, booze & college songs", + "PAD_8_FRACT_0_5": "Jazz, comics, booze & college songs", + "PAD_8_FRACT_0_2": "Jazz, comics, booze & college songs" + }, + "30": { + "INITIAL_BOX": "1 criminal plagiarist sodomite junkie caveman senator jew irishman negro honky cartoonist god", + "DEFAULT": "1 criminal plagiarist sodomite junkie caveman senator jew irishman negro honky cartoonist god", + "DEFAULT_GREY_PAD": "1 criminal plagiarist sodomite junkie caveman senator jew irishman negro honky cartoonist god", + "PADDED_4": "1 criminal plagiarist sodomite junkie caveman senator jew irishman negro honky cartoonist god", + "PADDED_8": "1 criminal plagarist sodomite junkie caveman senator jew irishman negro honky cartoonist god", + "EXTRACTED_INIT_BOX": "A criminalist flagrantly sidodomite junkie cavern senator jewish irish negro honky cartoonist godd", + "PADDED_4_EXTRACTED": "One two three five seven eight eleven twelve.", + "PADDED_8_EXTRACTED": "1 criminal flagaristic socialite junkie caveman senator jewish negro honky cartoonist god?", + "PADDED_8_DILATION_1": "1 criminal plagiarist flagrantly sodomite junkie caveman senator jew fushiman negro honky cartoonist god.", + "PAD_8_FRACT_0_5": "1 criminal flagariost 2 slobmitte 3 junkie 4 caverman senator 5 jew 6 irish negro honky cartoonist 7 11 12 god", + "PAD_8_FRACT_0_2": "1 criminal plagiarist flagrantly sodomite junkie cavern senator jewish negro honky cartoonist god 2 3 4 5 6 7 8 9 10 11 12" + }, + "31": { + "INITIAL_BOX": "Answers next week.", + "DEFAULT": "Answers next week.", + "DEFAULT_GREY_PAD": "Answers: next week.", + "PADDED_4": "Answers: next week.", + "PADDED_8": "Answers: next week.", + "EXTRACTED_INIT_BOX": "Answers next week", + "PADDED_4_EXTRACTED": "Answers next week", + "PADDED_8_EXTRACTED": "Answers next week", + "PADDED_8_DILATION_1": "Answers next week", + "PAD_8_FRACT_0_5": "Answers next week", + "PAD_8_FRACT_0_2": "Answers next week" + }, + "32": { + "INITIAL_BOX": "Edweard", + "DEFAULT": "Edweard", + "DEFAULT_GREY_PAD": "E.dweard", + "PADDED_4": "Edweard", + "PADDED_8": "E.dweard", + "EXTRACTED_INIT_BOX": "Edweard", + "PADDED_4_EXTRACTED": "E.d.weard", + "PADDED_8_EXTRACTED": "F.d.wearard", + "PADDED_8_DILATION_1": "F.d.weard", + "PAD_8_FRACT_0_5": "F.d.wearard", + "PAD_8_FRACT_0_2": "F.d.weard" + }, + "33": { + "INITIAL_BOX": "Oh, those jews", + "DEFAULT": "Oh, those jews", + "DEFAULT_GREY_PAD": "Oh, those jews", + "PADDED_4": "Oh, those jews", + "PADDED_8": "Oh, those jews", + "EXTRACTED_INIT_BOX": "Oh, those jews!", + "PADDED_4_EXTRACTED": "Oh, those jews!", + "PADDED_8_EXTRACTED": "Oh, those jews?", + "PADDED_8_DILATION_1": "Oh, those jews?", + "PAD_8_FRACT_0_5": "Oh, those jews", + "PAD_8_FRACT_0_2": "Oh, those jews" + }, + "34": { + "INITIAL_BOX": "See? he pretends to be this waspy christian guy...", + "DEFAULT": "See? he pretends to be this waspy christian guy...", + "DEFAULT_GREY_PAD": "See? he pretends to be this waspy christian guy...", + "PADDED_4": "See? he pretends to be this waspy christian guy...", + "PADDED_8": "See? he pretends to be this waspy christian guy...", + "EXTRACTED_INIT_BOX": "See? he pretends to be this waspy christian guy...", + "PADDED_4_EXTRACTED": "See? his pretends to be this waspy christian guy...", + "PADDED_8_EXTRACTED": "See? he pretends to be this waspy christian guy ...", + "PADDED_8_DILATION_1": "See? he pretends to be this waspy christian guy...", + "PAD_8_FRACT_0_5": "See? he pretends to be this waspy christian guy ...", + "PAD_8_FRACT_0_2": "See? he pretends to be this waspy christian guy ..." + }, + "35": { + "INITIAL_BOX": "\" but really he 's a cape - wearing ubermensch! it 'll sell like hotcakes! \"", + "DEFAULT": "\"\"... but really he's a cape-wearing ubermensch! it'll sell like hotcakes! \"", + "DEFAULT_GREY_PAD": "\"\" but really he 's a cape-wearing ubermensch! it 'll sell like hotcakes! \"", + "PADDED_4": "... but really he 's a cape - wearing ubermensch! it 'll sell like hotcakes?", + "PADDED_8": "\"\" but really he 's a cape-wearing ubermensch! it 'll sell like hotcakes! \"", + "EXTRACTED_INIT_BOX": "\" but really he 's a cape wearing ubermensch! i 'll sell like hotcakes! \"", + "PADDED_4_EXTRACTED": "\" but really he 's a cape wearing ubermenschen! it 'll sell like hotcakes! \"", + "PADDED_8_EXTRACTED": "\"\" but really he 's a cape wearing ubermenschen! i'll sell like hotcakes! \"", + "PADDED_8_DILATION_1": "\"\" but really he 's a cape wearing ubermensch! i 'll sell like hotcakes! \"", + "PAD_8_FRACT_0_5": "\"\" but really he 's a cape wearing ubermenschen! i 'll sell like hotcakes! \"", + "PAD_8_FRACT_0_2": "\"\" but really he 's a cape wearing ubermenschen! i 'll sell like hotcakes! \"" + }, + "36": { + "INITIAL_BOX": "Cheerleaders for the cause.", + "DEFAULT": "Cheerleaders for the cause.", + "DEFAULT_GREY_PAD": "Cheerleaders for the cause", + "PADDED_4": "Cheerleaders for the cause.", + "PADDED_8": "Cheerleaders for the cause", + "EXTRACTED_INIT_BOX": "Leaders he ause", + "PADDED_4_EXTRACTED": "Leaders heause", + "PADDED_8_EXTRACTED": "Leaders make the cause.", + "PADDED_8_DILATION_1": "Leaders use.", + "PAD_8_FRACT_0_5": "Leaders heause", + "PAD_8_FRACT_0_2": "Leaders heause" + }, + "37": { + "INITIAL_BOX": "Haha ... why yes, of course ... i used to love to read them as a boy!", + "DEFAULT": "Haha ... why yes, of course... i used to love to read them as a boy!", + "DEFAULT_GREY_PAD": "Haha ... why yes, of course ... i used to love to read them as a boy!", + "PADDED_4": "Haha ... why yes, of course ... i used to love to read them as a boy!", + "PADDED_8": "Haha ... why yes, of course ... i used to love to read them as a boy!", + "EXTRACTED_INIT_BOX": "Hannah... awy nes, of course ... i used to love to read them as a boy?", + "PADDED_4_EXTRACTED": "Mama ... why yes, of course ... i used to love to read them as a boy?", + "PADDED_8_EXTRACTED": "Mahir ... why yes, of course ... i used to love to read them as a boy!", + "PADDED_8_DILATION_1": "Haha ... why yes, of course ... i used to love to read them as a boy?", + "PAD_8_FRACT_0_5": "Haha ... why yes, of course ... i used to love to read them as a boy?", + "PAD_8_FRACT_0_2": "Haha ... why yes, of course ... i used to love to read them as a boy!" + }, + "38": { + "INITIAL_BOX": "I dunno...", + "DEFAULT": "I dunno...", + "DEFAULT_GREY_PAD": "I dunno...", + "PADDED_4": "I dunno...", + "PADDED_8": "I dunno...", + "EXTRACTED_INIT_BOX": "I dunno...", + "PADDED_4_EXTRACTED": "I dunno...", + "PADDED_8_EXTRACTED": "I dunno...", + "PADDED_8_DILATION_1": "I dunno...", + "PAD_8_FRACT_0_5": "I dunno...", + "PAD_8_FRACT_0_2": "I dunnno..." + }, + "39": { + "INITIAL_BOX": "I use them as a symbol for the spiritual poverty of american culture.", + "DEFAULT": "I use them as a symbol for the spiritual poverty of american culture.", + "DEFAULT_GREY_PAD": "I use them as a symbol for the spiritual poverty of american culture.", + "PADDED_4": "I use them as a symbol for the spiritual poverty of american culture.", + "PADDED_8": "I use them as a symbol for the spiritual poverty of american culture.", + "EXTRACTED_INIT_BOX": "I use them as a symbol for the spiritual poverty of america! an culture", + "PADDED_4_EXTRACTED": "I use them as a symbol for the spiritual poverty of america and our culture.", + "PADDED_8_EXTRACTED": "I use them as a symbol for the spiritual poverty of america an culture", + "PADDED_8_DILATION_1": "I use them as a symbol for the spiritual poverty of america an culture", + "PAD_8_FRACT_0_5": "I use them as a symbol for the spiritual poverty of america an culture", + "PAD_8_FRACT_0_2": "I use them as a symbol for the spiritual poverty of america an culture" + }, + "40": { + "INITIAL_BOX": "What... you gotta better idea how to get laid?", + "DEFAULT": "What... you gotta better idea how to get laid?", + "DEFAULT_GREY_PAD": "What ... you gotta better idea how to get laid?", + "PADDED_4": "What... you gotta better idea how to get laid?", + "PADDED_8": "What... you gotta better idea how to get laid?", + "EXTRACTED_INIT_BOX": "What ... you gotta better idea how to get laio?", + "PADDED_4_EXTRACTED": "What ... you gotta better idea how to get laid?", + "PADDED_8_EXTRACTED": "What ... you gotta better idea how to get land?", + "PADDED_8_DILATION_1": "What ... you gotta better idea how to get laid?", + "PAD_8_FRACT_0_5": "What ... you gotta better idea how to get laid?", + "PAD_8_FRACT_0_2": "What ... you gotta better idea how to get laid?" + }, + "41": { + "INITIAL_BOX": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "DEFAULT": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "DEFAULT_GREY_PAD": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "PADDED_4": "I have absolutely nothing against an art for children......on the contrary, i'm for it!", + "PADDED_8": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "EXTRACTED_INIT_BOX": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "PADDED_4_EXTRACTED": "I have absolutely nothing against an art for children......on the contrary, i'm for it!", + "PADDED_8_EXTRACTED": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "PADDED_8_DILATION_1": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "PAD_8_FRACT_0_5": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!", + "PAD_8_FRACT_0_2": "I have absolutely nothing against an art for children ... on the contrary, i'm for it!" + }, + "42": { + "INITIAL_BOX": "Movies on paper hang in there, mosley?", + "DEFAULT": "Movies on paper hang in there, mosley?", + "DEFAULT_GREY_PAD": "Movies on paper hang in there mosley?", + "PADDED_4": "Movies on paper hang in there, mosley?", + "PADDED_8": "Movies on paper hang in there mosley?", + "EXTRACTED_INIT_BOX": "Hang in there, mossley! movies on paper?", + "PADDED_4_EXTRACTED": "Hang in there mossley! movies on paper?", + "PADDED_8_EXTRACTED": "Hang in there, mossley's! movies on paper?", + "PADDED_8_DILATION_1": "Hang in there, mosley! \"", + "PAD_8_FRACT_0_5": "Movies on paper hang in there mosley's?", + "PAD_8_FRACT_0_2": "Movies on paper hang in there mosley's?" + }, + "43": { + "INITIAL_BOX": "I think they're wonder- ful, because they get people interested in real reading!", + "DEFAULT": "I think they're wonder- ful, because they get people interested in real reading!", + "DEFAULT_GREY_PAD": "I think they're wonder- ful, because they get people interested in real reading!", + "PADDED_4": "I think they're wonder- ful, because they get people interested in real reading!", + "PADDED_8": "I think they're wonder- ful, because they get people interested in real reading!", + "EXTRACTED_INIT_BOX": "Think they're wonders - full-, because they get people interested in real reading!", + "PADDED_4_EXTRACTED": "Think they're wonderful - full, because they get people interested in real reading?", + "PADDED_8_EXTRACTED": "Think they're the wonder- ful , because they get people interested in avail reading!", + "PADDED_8_DILATION_1": "Think they're wonder- full, because they get people interested in real reading!", + "PAD_8_FRACT_0_5": "Think they're wondering - full, because they get people interested in several readings!", + "PAD_8_FRACT_0_2": "Think they're wonder- ful, because they get people interested in actual reading!" + }, + "44": { + "INITIAL_BOX": "Hang in there, mosley!", + "DEFAULT": "Hang in there, mosley!", + "DEFAULT_GREY_PAD": "Hang in there, mosley!", + "PADDED_4": "Hang in there, mosley!", + "PADDED_8": "Hang in there, mosley!", + "EXTRACTED_INIT_BOX": "Hang 'em there, mosley?", + "PADDED_4_EXTRACTED": "Hang in there, mosley!?", + "PADDED_8_EXTRACTED": "Hang in there mosley!?", + "PADDED_8_DILATION_1": "Hang in there mosley!?", + "PAD_8_FRACT_0_5": "Hang in there mosley?", + "PAD_8_FRACT_0_2": "Hang in there, mosley?" + }, + "45": { + "INITIAL_BOX": "I'm hit! i'm hit?", + "DEFAULT": "I'm hit! i'm hit?", + "DEFAULT_GREY_PAD": "I'm hit! i'm hit?", + "PADDED_4": "I'm hit! i'm hit?", + "PADDED_8": "I'm hit! i'm hit?", + "EXTRACTED_INIT_BOX": "I'm hitt! i'm hitt?", + "PADDED_4_EXTRACTED": "I'm hit! ?", + "PADDED_8_EXTRACTED": "I'm hit! i'm hit?", + "PADDED_8_DILATION_1": "I'm hit!?", + "PAD_8_FRACT_0_5": "I'm hit! i'm hit?", + "PAD_8_FRACT_0_2": "I'm hit! i'm hit?" + }, + "46": { + "INITIAL_BOX": "Mean while", + "DEFAULT": "Mean while", + "DEFAULT_GREY_PAD": "Mean while", + "PADDED_4": "Mean while", + "PADDED_8": "Mean while", + "EXTRACTED_INIT_BOX": "Mean while", + "PADDED_4_EXTRACTED": "Mean while", + "PADDED_8_EXTRACTED": "Mean while", + "PADDED_8_DILATION_1": "Mean while", + "PAD_8_FRACT_0_5": "Mean while", + "PAD_8_FRACT_0_2": "Mean while" + }, + "47": { + "INITIAL_BOX": "A short history of canada begins:", + "DEFAULT": "A son history of carnage", + "DEFAULT_GREY_PAD": "A son history of a carnivorous plant.", + "PADDED_4": "A short history of a long time", + "PADDED_8": "A short history of a continuing", + "EXTRACTED_INIT_BOX": "Assassins creed unity an game of art and war.", + "PADDED_4_EXTRACTED": "A messenger of the gods?", + "PADDED_8_EXTRACTED": "A southern hospitality go an dine!", + "PADDED_8_DILATION_1": "Astonishingly enough, captain marvel was an american hero of the golden age!", + "PAD_8_FRACT_0_5": "Astonishingly one of them is!", + "PAD_8_FRACT_0_2": "A son of krypton!" + }, + "48": { + "INITIAL_BOX": "Note: sumerians didn't invent picture- writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people, however.", + "DEFAULT": "Note: sumerians didn't invent picture- writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people, however.", + "DEFAULT_GREY_PAD": "Note: sumerians didn't invent picture- writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people, however.", + "PADDED_4": "Note: sumerians didn't invent picture- writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people, however.", + "PADDED_8": "Note: sumerians didn't invent picture- writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people, however.", + "EXTRACTED_INIT_BOX": "Note! summerians wrote in different picture-writing, daily regular writing, and so are of little interest. they say screen no native was born perfectly nice people somewhere", + "PADDED_4_EXTRACTED": "Note: summerians didn't invent pictures; writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people however", + "PADDED_8_EXTRACTED": "Note! summerians didn't invent picture-writing; only regular writing, and so are of little interest. they seem to have begun perfectly nice people however", + "PADDED_8_DILATION_1": "Note! summerians didn't invent picture- writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people however", + "PAD_8_FRACT_0_5": "Note: sumerians didn't invent picture-writing; only regular writing, and so are of little interest. they seem to have been perfectly nice people however", + "PAD_8_FRACT_0_2": "Note? sumerians didn't invent picture- writing, only regular writing, and so are of little interest. they seem to have been perfectly nice people however" + }, + "49": { + "INITIAL_BOX": "Guess i 'd better get down to brass tacks and finish up that\" dialogue on democracy\" before the senator gets here ... then i 'll sodomize my 12-year - old slave boy?", + "DEFAULT": "Guess i 'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here ... then i 'll sodomize my 12-year - old slave boy?", + "DEFAULT_GREY_PAD": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here ... then i 'll sodomize my 12-year- old slave boy?", + "PADDED_4": "Guess i 'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here ... then i 'll sodomize my 12-year - old slave boy?", + "PADDED_8": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here ... then i 'll sodomize my 12-year- old slave boy?", + "EXTRACTED_INIT_BOX": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here... then pull suddomize my 12-year- old slaye boy?", + "PADDED_4_EXTRACTED": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here... then i'll soondomize my 12-year- old slaye boy!", + "PADDED_8_EXTRACTED": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here... then pull someonmize my 12-year old slaye boy?", + "PADDED_8_DILATION_1": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here... then i'll soon domitrize my 12-year- old slaye boy?", + "PAD_8_FRACT_0_5": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here... then i'll summonize my 12-year-old slaye boy?", + "PAD_8_FRACT_0_2": "Guess i'd better get down to brass tacks and finish up that \"dialogue on democracy\" before the senator gets here... then i'll someday my 12-year- old slave boy!" + }, + "50": { + "INITIAL_BOX": "Monsieur! norman, sir! i believe i have found a way to occupy the men through the long wait between our military encounters!!", + "DEFAULT": "Monsieur! norman, sir! i believe i have found a way to occupy the men through the long wait between our military encounters!", + "DEFAULT_GREY_PAD": "Monsieur! norman, sir! i believe i have found a way to occupy the men through the long wait between our military encounters!", + "PADDED_4": "Monsieur! norman, sir! i believe i have found a way to occupy the men through the long wait between our military encounters!", + "PADDED_8": "Monsieur! norman, sir! i believe i have found a way to occupy the men through the long wait between our military encounters!", + "EXTRACTED_INIT_BOX": "Monsieur! norman, sir! i believe i have found a way to occ ppy the men through the long wait between our military encounters!", + "PADDED_4_EXTRACTED": "Monsieur! norman, sir! i believe i have found a way to occ py the men through the long what between our military encounters?", + "PADDED_8_EXTRACTED": "Monsieur! norman, sir! i believe i have found a way to occ py the men through the long wait between our military encounters?", + "PADDED_8_DILATION_1": "Monsieur! norman, sir! i believe i have found a way to occ py the men through the long wait between our mlitary encounters!!", + "PAD_8_FRACT_0_5": "Monsieur! norman, sir! i believe i have found a way to occ py the men through the long wait between our military encounters!", + "PAD_8_FRACT_0_2": "Monsieur! norman, sir! i believe i have found a way to occ py the men through the long wait between our military encounters!" + }, + "51": { + "INITIAL_BOX": "See? here on this vellum ... crass, hateful drawings of the ugly, fat anglo-saxons we all hate so much! we can pass it around and share a hearty laugh together", + "DEFAULT": "See? here on this vellum ... crass, hateful drawings of the ugly, fat anglo-saxons we all hate so much! we can pass it around and share a hearty laugh together?", + "DEFAULT_GREY_PAD": "See? here on this vellum ... crass, hateful drawings of the ugly, fat anglo-saxons we all hate so much! we can pass it around and share a hearty laugh together", + "PADDED_4": "See? here on this vellum ... crass, hateful drawings of the ugly, fat anglo-saxons we all hate so much! we can pass it around and share a hearty laugh together.", + "PADDED_8": "See? here on this vellum ... crass, hateful drawings of the ugly, fat anglo-saxons we all hate so much! we can pass it around and share a hearty laugh together.", + "EXTRACTED_INIT_BOX": "Gee? here on this vellium grass, hazeful drawings of the ugly, fat anglo saxons we all hate so much! we can pass it around and smile a hearty laugh together", + "PADDED_4_EXTRACTED": "See? here on this wellum class, hatred drownness of the ugly, fat anglo saxons we all hate so much! we can pass it around and share a hearty laugh together.", + "PADDED_8_EXTRACTED": "Free? here on this vellium cross, hateful drawness of the ugly, fat anglo saxons we all hate so much! / we can pass it around and say a hearty laugh together.", + "PADDED_8_DILATION_1": "Sree? herie on this vellum crass, hateful drawings of the ugly, fat anglo saxons we all hate so much/ we can pass it around and gain a hearty laugh together...", + "PAD_8_FRACT_0_5": "Sweet? here on this vellium cross, hateful drawings of the ugly, fat anglo saxons we all hate so much! we can pass it around and share a hearty laugh together...", + "PAD_8_FRACT_0_2": "Sleep? here on this vellium crass, hateful drawings of the ugly, fat anglo saxons we all hate so much! we can pass it around and we're a hearty laugh together..." + }, + "52": { + "INITIAL_BOX": "Ah ... poorly... methinks the block too worn for any further impressing ...", + "DEFAULT": "Ah ... poorly... methinks the block too worn for any further impressing ...", + "DEFAULT_GREY_PAD": "Ah ... poorly ... methinks the block too worn for any further impressing ...", + "PADDED_4": "Ah ... poorly... methinks the block too worn for any further impressing ...", + "PADDED_8": "Ah ... poorly... methinks the block too worn for any further impressing ...", + "EXTRACTED_INIT_BOX": "Ah ... poodly ... anethinks the block too worrin for any further impressing ...", + "PADDED_4_EXTRACTED": "Ah ... poopy l... anethiks the block too worn for any further impressing ...", + "PADDED_8_EXTRACTED": "Ah ... poorly... anethinks the block too worn for any further impressing ...", + "PADDED_8_DILATION_1": "Ah ... poorly jetthinks the block too worn for any further impressing. \"", + "PAD_8_FRACT_0_5": "Ah ... poorly... anethinks the block too worn for any further impressing...", + "PAD_8_FRACT_0_2": "Ah ... poorly... jmethinks the block too worn for any further impressing. \"" + }, + "53": { + "INITIAL_BOX": "We have over three miles soldiers to entertain!", + "DEFAULT": "We have over three miles soldiers to entertain!", + "DEFAULT_GREY_PAD": "We have over trois milles soldiers to entertain!", + "PADDED_4": "We have over three miles soldiers to entertain!", + "PADDED_8": "We have over three miles soldiers to entertain!", + "EXTRACTED_INIT_BOX": "Ha! over trois mille's soldier to en tain?", + "PADDED_4_EXTRACTED": "\" ha! ovei trois mille soldier to en tain! \"", + "PADDED_8_EXTRACTED": "Ha! ove trous milles soldier to en train?", + "PADDED_8_DILATION_1": "\" ha ! ovet trois milles soldier to en \"\"tain! \"", + "PAD_8_FRACT_0_5": "Ha! ovet trois mille soldier to en tain?", + "PAD_8_FRACT_0_2": "\" ha! ovet trois mille soldier to en tain! \"" + }, + "54": { + "INITIAL_BOX": "Idiot!", + "DEFAULT": "Idiot!", + "DEFAULT_GREY_PAD": "Idiot!", + "PADDED_4": "Idiot!", + "PADDED_8": "Idiot!", + "EXTRACTED_INIT_BOX": "\" idiot!", + "PADDED_4_EXTRACTED": "\" i did it!", + "PADDED_8_EXTRACTED": "I did it?", + "PADDED_8_DILATION_1": "Idiot?", + "PAD_8_FRACT_0_5": "No!?", + "PAD_8_FRACT_0_2": "No!?" + }, + "55": { + "INITIAL_BOX": "Do not bother me again until the invention of printing!", + "DEFAULT": "Do not bother me again until the invention of printing!", + "DEFAULT_GREY_PAD": "Do not bother me again until the invention of printing!", + "PADDED_4": "Do not bother me again until the invention of printing!", + "PADDED_8": "Do not bother me again until the invention of printing!", + "EXTRACTED_INIT_BOX": "Do not bother me again until the invention of printing!", + "PADDED_4_EXTRACTED": "Do not bother me again until the invention of printing!", + "PADDED_8_EXTRACTED": "Do not both her me again until the invention of printing!", + "PADDED_8_DILATION_1": "Do not bother me again until the invention of printing!", + "PAD_8_FRACT_0_5": "Do not bother me again until the invention of printing!", + "PAD_8_FRACT_0_2": "Do not bother me again until the invention of printing!" + }, + "56": { + "INITIAL_BOX": "Nah ... these stupid poor people know no better -- we shall certainly sell them all!", + "DEFAULT": "Nah ... these stupid poor people know no better -- we shall certainly sell them all!", + "DEFAULT_GREY_PAD": "Nah ... these stupid poor people know no better -- we shall certainly sell them all?", + "PADDED_4": "Nah ... these stupid poor people know no better -- we shall certainly sell them all!", + "PADDED_8": "Nah ... these stupid poor people know no better -- we shall certainly sell them all!", + "EXTRACTED_INIT_BOX": "What they stormed into wasn't just a bunch of people buttering up to her-- it was all cordoned off secretly.", + "PADDED_4_EXTRACTED": "What they should knowing poor people are better off with all circumstances see themselves.", + "PADDED_8_EXTRACTED": "With these strict rules, people know no better than to sell themselves.", + "PADDED_8_DILATION_1": "Nah... these stupid poor people know no better--we shall certainly sell them all.", + "PAD_8_FRACT_0_5": "\" well, these people know no better - we 'll all be selling them off!", + "PAD_8_FRACT_0_2": "Nigeria! these stupid poor people knowing better we should all vernatically seek remal." + }, + "57": { + "INITIAL_BOX": "Breadside", + "DEFAULT": "Broadside", + "DEFAULT_GREY_PAD": "Broaden your mind?", + "PADDED_4": "E. side", + "PADDED_8": "Broadsidede", + "EXTRACTED_INIT_BOX": "\"i'm sorry.\"", + "PADDED_4_EXTRACTED": "Cheers?", + "PADDED_8_EXTRACTED": "Alright?", + "PADDED_8_DILATION_1": "Brilliant!", + "PAD_8_FRACT_0_5": "\" i don't know what to do! \"", + "PAD_8_FRACT_0_2": "\"i'm sorry.\"" + }, + "58": { + "INITIAL_BOX": "How goes the woodcut bible printing, brother broadside?", + "DEFAULT": "How goes the woodcut bible printing, brother broadside?", + "DEFAULT_GREY_PAD": "How goes the woodcut bible printing, brother broadside?", + "PADDED_4": "How goes the woodcut bible printing, brother broadside?", + "PADDED_8": "How goes the woodcut bible printing, brother broadside?", + "EXTRACTED_INIT_BOX": "How goes the woodcut bible printing, brother broadside?", + "PADDED_4_EXTRACTED": "How goes the woodcut bible printing, brother broadside?", + "PADDED_8_EXTRACTED": "How goes the woodcut bible printing, brother broadside?", + "PADDED_8_DILATION_1": "How goes the woodcut bible printing, brother broadside?", + "PAD_8_FRACT_0_5": "How goes the woodcut bible printing, brother broadside?", + "PAD_8_FRACT_0_2": "How goes the woodcut bible printing, brother broadside?" + }, + "59": { + "INITIAL_BOX": "Look ... see? picture stories, imported from switzerland, which seem to move before the eyes -- perfect for our ever-accelerating world and the increasingly affluent middle class ... they're all the rage in europe!", + "DEFAULT": "Look ... see? picture stories, imported from switzerland, which seemed to move before the eyes -- perfect for our ever-accelerating world and the increasingly affluent middle class ... they're all the rage in europe!", + "DEFAULT_GREY_PAD": "Look ... see? picture stories imported from switzerland, which seem to move before the eyes -- perfect for our ever-accelerating world and the increasingly affluent middle class... they're all the rage in europe!", + "PADDED_4": "Look ... see? picture stories, imported from switzerland, which seem to move before the eyes -- perfect for our ever-accelerating world and the increasingly affluent middle class ... they're all the rage in europe!", + "PADDED_8": "Look ... see? picture stories imported from switzerland, which seem to move before the eyes -- perfect for our ever-accelerating world and the increasingly affluent middle class ... they're all the rage in europe!", + "EXTRACTED_INIT_BOX": "Look ... see? picture story imported from switzerland, which seemed to move before the eyes - perfect for our ever accelerating world and the increasingly efficient middle class - they 're all the rage in europe!", + "PADDED_4_EXTRACTED": "Look ... see? picture stohl imported from switzerland, which seemed to move towards the eyes - perfect for our ever accelerating world and the increasingly argumentative middle class ... everybody's all the rage in europe!", + "PADDED_8_EXTRACTED": "Look ... see? picture stunned, imported from switzerland, which seems to move before the eyes - perfect for our ever accelerating world and the increasingly affuent middle class... everybody's all the rage in europe!", + "PADDED_8_DILATION_1": "Look ... see? picture storied, imported from switzerlandland, which i seem to move before the eyes - perfect for our ever-accelerating world and the increasingly affluent middle class people everywhere - all the rage in europe! \"", + "PAD_8_FRACT_0_5": "Look ... seep? picture storm imported from switzerland, which i seem to move before the eyes ... perfect for our ever accelerating world and the increasingly afflient middle class... they're all the rage in europe!", + "PAD_8_FRACT_0_2": "Look...... seep? picture story imported from switzerland, which i seem to move before the eyes ... perfect for our ever accelerating world and the increasingly afflient middle class... they're all the rage in europe!" + }, + "60": { + "INITIAL_BOX": "Y-yes, but we think it shall sell quite well!", + "DEFAULT": "Y-yes, but we think it shall sell quite well!", + "DEFAULT_GREY_PAD": "Y-yes, but we think it shall sell quite well!", + "PADDED_4": "Y-yes, but we think it shall sell quite well!", + "PADDED_8": "Y-yes, but we think it shall sell quite well!", + "EXTRACTED_INIT_BOX": "Y yes, but we hink it shall sell quite well.", + "PADDED_4_EXTRACTED": "It yes, but we think it shall cell quite well.", + "PADDED_8_EXTRACTED": "Y yes, but we think it shall cell quite well.", + "PADDED_8_DILATION_1": "Y yes, but we hink it shall sell quite well.", + "PAD_8_FRACT_0_5": "Y yes, but we hink it shall cell quite well.", + "PAD_8_FRACT_0_2": "Y yes, but we hink it shall sell quite well." + }, + "61": { + "INITIAL_BOX": "But this is just puerile swill!", + "DEFAULT": "But this is just puerile swill!", + "DEFAULT_GREY_PAD": "But this is just puerile swill!", + "PADDED_4": "But this is just puerile swill!", + "PADDED_8": "But this is just puerile swill!", + "EXTRACTED_INIT_BOX": "But this is just puerile swill!", + "PADDED_4_EXTRACTED": "But this is just puerile swill!", + "PADDED_8_EXTRACTED": "But this is just puerile swill!", + "PADDED_8_DILATION_1": "But this is just puerile swill!", + "PAD_8_FRACT_0_5": "But this is just puerile swill!", + "PAD_8_FRACT_0_2": "But this is just puerile swill!" + }, + "62": { + "INITIAL_BOX": "Some of the finer cuts are almost besmircht beyond our gaze, see? is it not an insult to god, as such?", + "DEFAULT": "Some of the finer cuts are almost besmircht beyond our gaze? is it not an insult to god, as such?", + "DEFAULT_GREY_PAD": "Some of the finer cuts are almost besmircht beyond our gaze. see? is it not an insult to god as such?", + "PADDED_4": "Some of the finer cuts are almost besmircht beyond our gaze. see? is it not an insult to god, as such?", + "PADDED_8": "Some of the finer cuts are almost besmircht beyond our gaze. see? is it not an insult to god, as such?", + "EXTRACTED_INIT_BOX": "Some of the finer cuts are almost besmirched beyond our gaze? is it not an insult to god, as such?", + "PADDED_4_EXTRACTED": "Some of the finer cuts are almost beyond our gaze, see? is it not an insult to good, as such?", + "PADDED_8_EXTRACTED": "Some of the finer cuts are almost beyond our gaze see? is it not an insult to god, as such?", + "PADDED_8_DILATION_1": "Some of the finer cuts are almost beyond our gaze, see? is it not an insult to god, as such?", + "PAD_8_FRACT_0_5": "Some of the finer cuts are almost besmircht beyond our gaze see? is it not an insult to god, as such?", + "PAD_8_FRACT_0_2": "Some of the finer cuts are almost besmircht beyond our gaze see? is it not an insult to god, as such?" + }, + "63": { + "INITIAL_BOX": "Don't bother me again until cinema has superseded theater!", + "DEFAULT": "Don't bother me again until cinema has superseded theater!", + "DEFAULT_GREY_PAD": "Don't bother me again until cinema has supperseeded theater!", + "PADDED_4": "Don't bother me again until cinema has supeseded theater!", + "PADDED_8": "Don't bother me again until cinema has supperseeded theater!", + "EXTRACTED_INIT_BOX": "Don't bother me again until cinema has superseded theater?", + "PADDED_4_EXTRACTED": "Don't bother me again until cinema has superseded theater?", + "PADDED_8_EXTRACTED": "Don't bother me again until cinema has supervised theater!", + "PADDED_8_DILATION_1": "Don't bother me again, until cinema has supervised theater!?", + "PAD_8_FRACT_0_5": "Don't bother me again until cinema has super-sized theater!", + "PAD_8_FRACT_0_2": "Don't bother me again until cinema has super-sized theater!" + }, + "64": { + "INITIAL_BOX": "Haha - tis true?", + "DEFAULT": "Haha - tis true!", + "DEFAULT_GREY_PAD": "Haha - tis true?", + "PADDED_4": "Haha - tis true!", + "PADDED_8": "Haha - tis true!", + "EXTRACTED_INIT_BOX": "Haha - this trade", + "PADDED_4_EXTRACTED": "Haha - this true", + "PADDED_8_EXTRACTED": "Nia! this trade?", + "PADDED_8_DILATION_1": "Ha ha - this true", + "PAD_8_FRACT_0_5": "Ha ha - his true", + "PAD_8_FRACT_0_2": "Ha ha - his true" + }, + "65": { + "INITIAL_BOX": "Comics a history", + "DEFAULT": "Comics a history", + "DEFAULT_GREY_PAD": "Comics a history", + "PADDED_4": "Comics a history", + "PADDED_8": "Comics a history", + "EXTRACTED_INIT_BOX": "Omic - a history", + "PADDED_4_EXTRACTED": "Omic - a history", + "PADDED_8_EXTRACTED": "Omic - a history", + "PADDED_8_DILATION_1": "Omic - a history", + "PAD_8_FRACT_0_5": "Omic - a history", + "PAD_8_FRACT_0_2": "Omic - a history" + }, + "66": { + "INITIAL_BOX": "Wonderful, sweetheart; wonnerful ... yer a natch'ril!", + "DEFAULT": "Wonderful, sweetheart, wonnerful... yer a natchril!", + "DEFAULT_GREY_PAD": "Wonderful, sweetheart, wonnerful ... yer a natch'ril!", + "PADDED_4": "Wonderful, sweetheart, wonnerful ... yer a natch'ril!", + "PADDED_8": "Wonnerful, sweetart, wonnerful ... yer a natch'ril!", + "EXTRACTED_INIT_BOX": "A wonderful, sweetheart, wonnerful ... yer a matchme!l?", + "PADDED_4_EXTRACTED": "Wonnerful, sweetstart, wonnerful ... yer a matchmi!?", + "PADDED_8_EXTRACTED": "Wonnerful, sweetart, wonnerful ... yera a matchmade!?", + "PADDED_8_DILATION_1": "Wonnerful, sweeetart, wonnerful ... yer a matchril!?", + "PAD_8_FRACT_0_5": "Wonnerful, sweetart, wonnerful ... yera matchmi!?", + "PAD_8_FRACT_0_2": "Wonnerful, sweetart, wonnerful ... yera matchril!?" + }, + "67": { + "INITIAL_BOX": "This time, though, let's lose the clothes, whattadoyasay? there's an extra fifty in it for ya!", + "DEFAULT": "This time, though, let's lose the clothes, whaddyasay? there's an extra fifty in it for ya!", + "DEFAULT_GREY_PAD": "This time, though, let's lose the clothes, whaddyasay? there's an extra fifty in it for ya!", + "PADDED_4": "This time, though, let's lose the clothes, whaddyasay? there's an extra fifty in it for ya!", + "PADDED_8": "This time, though, let's lose the clothes, whaddyasay? there 's an extra fifty in it for ya!", + "EXTRACTED_INIT_BOX": "This time through, let's lose the clothes, whattadamsay? there 's an extra fifty in it for ya!", + "PADDED_4_EXTRACTED": "This time though, let's lose the clothes, whatdidyasay? there's an extra fifty in it for ya!", + "PADDED_8_EXTRACTED": "This time through, let's lose the clothes, whatta say? there's an extra empty in it for ya!", + "PADDED_8_DILATION_1": "This time though, let's lose the clothes, whatdyasay? there's an extra fifty in it for ya!", + "PAD_8_FRACT_0_5": "This time though, let's lose the clothes, whatta say? there's an extra empty in it for ya!", + "PAD_8_FRACT_0_2": "This time though, let's lose the clothes, whattadayasay? there's an extra empty in it for ya!" + }, + "68": { + "INITIAL_BOX": "Dude! hey, mr. score! check it out -- comics are now, like, a respected language, with an aesthetic grounding all their own?", + "DEFAULT": "Dude! hey, mr. score! check it out -- comics are now, like, a respected language, with an aesthetic grounding all their own?", + "DEFAULT_GREY_PAD": "Dude! hey, mr. score! check it out -- comics are now, like, a respected language, with an aesthetic grounding all their own?", + "PADDED_4": "Dude! hey, mr. score! check it out -- comics are now. like, a respected language, with an aesthetic grounding all their own?", + "PADDED_8": "Dude! hey, mr. score! check it out -- comics are now, like, a respected language, with an aesthetic grounding all their own?", + "EXTRACTED_INIT_BOX": "Dude! hey, mr. scope! check out - comics are now like, a respected language with an aesthetic grounding all their own?", + "PADDED_4_EXTRACTED": "Dude! hey, mr. scope! check tout - comics are now, like, a respected language, with an aesthetic groundflooring all their own?", + "PADDED_8_EXTRACTED": "Dude? hey, mr. scope! check tout - comics are now like a respected language, with an aesthetic groundiing all their own?", + "PADDED_8_DILATION_1": "Dude! hey, mr. score! check tout - comics are now, like, a respected language; with an aesthetic groundiing all their own?", + "PAD_8_FRACT_0_5": "Dude! hey, mr. score! check tout - comics are now, like, a respected language, with an aesthetic grounding all their own?", + "PAD_8_FRACT_0_2": "Dude! hey, mr. score! check tout - comics are now, like, a respected language, with an aesthetic grounding all their own?" + }, + "69": { + "INITIAL_BOX": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "DEFAULT": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "DEFAULT_GREY_PAD": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "PADDED_4": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "PADDED_8": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "EXTRACTED_INIT_BOX": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "PADDED_4_EXTRACTED": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "PADDED_8_EXTRACTED": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "PADDED_8_DILATION_1": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "PAD_8_FRACT_0_5": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die.", + "PAD_8_FRACT_0_2": "Doomed am i to this life of no respect (illustrated books) and soon, i shall die." + }, + "70": { + "INITIAL_BOX": "Ach! oh well ... at least i have given something back to the motherland, however slight. '", + "DEFAULT": "Ach! oh well ... at least i have given something back to the motherland, however slight. \"", + "DEFAULT_GREY_PAD": "Ach! oh well ... at least i have given something back to the motherland, however slight.", + "PADDED_4": "Ach! 'oh well ... at least i have given something back to the motherland, however slight. \"", + "PADDED_8": "Ach! oh well ... at least i have given something back to the motherland, however slight.", + "EXTRACTED_INIT_BOX": "Oh! well ... at east i have given some hiring back to the northerland, however slight", + "PADDED_4_EXTRACTED": "Oh! oh well ... at east i have given something back to the motherland, however slightly", + "PADDED_8_EXTRACTED": "Ach! ' on well ... at least i have given something back to the motherland, however slight", + "PADDED_8_DILATION_1": "Acha! oh well ... at least i have given some hing back to the motherland, however slight?", + "PAD_8_FRACT_0_5": "Ach! on well ... at least i have given some hing back to the motherland, however slight", + "PAD_8_FRACT_0_2": "Ach! oh well ... at least i have given some hing back to the motherland, however slight." + }, + "71": { + "INITIAL_BOX": "See? they address \"topics like the holocaust, spirituality, notions of identity, and sex! plus they win pulitzer prizes ... and harvey awards!", + "DEFAULT": "See? they address topics like the holocaust, spirituality, notions of identity, and sex! plus they win pulitzer prizes ...and harvey awards!", + "DEFAULT_GREY_PAD": "See? they address topics like the holocaust, spirituality, notions of identity, and sex! plus they win pulitzer prizes ...and harvey awards!", + "PADDED_4": "See? they address 'topics like the holocaust, spirituality, notions of identity, and sex! plus they win pulitzer prizes ... and harvey awards!", + "PADDED_8": "See? they address topics like the holocaust, spirituality, notions of identity, and sex! plus they win pulitzer prizes ...and harvey awards!", + "EXTRACTED_INIT_BOX": "See? they address topics like the holocaust, spirituality, motions of identity and sex! people win pulitzer prizes...and harvey awards?", + "PADDED_4_EXTRACTED": "Gee? they address topics like the holocaust, spirituality, notions of identity and sex; promotes \"they win pulitzer prizes ...and awards!?\"", + "PADDED_8_EXTRACTED": "Gee? they address topics like the holocaust, spirituality, notions of identity and sex! plus, they win pulitzer prizes...and marvey awards?", + "PADDED_8_DILATION_1": "Geeb? they address topics i like the holocaust, spirituality, notions of identity and sex! plus \" they won pulitzer prizes\" +\" annie awards! %", + "PAD_8_FRACT_0_5": "Oh? they address topics like the holocaust, spirituality, nations of identity and sex! plus, they win pulitzer prizes ...and marvey awards?", + "PAD_8_FRACT_0_2": "Oh? they address topics like the holocaust, spirituality, notions of identity, and sex! plus, they win pulitzer prizes ...and marvey awards?" + }, + "72": { + "INITIAL_BOX": "Don't ever bother me again! i 'm trying to get to the top level of my superman video game?", + "DEFAULT": "Don't ever bother me again! i 'm trying to get to the top level of my superman video game?", + "DEFAULT_GREY_PAD": "Don't ever bother me again! i 'm trying to get to the top level of my superman video game?", + "PADDED_4": "Don't ever bother me again! i 'm trying to get to the top level of my superman video game?", + "PADDED_8": "Don't ever bother me again! i 'm trying to get to the top level of my superman video game?", + "EXTRACTED_INIT_BOX": "Don't ever bother me again? i 'm trying to get to the top level of my superman video game!", + "PADDED_4_EXTRACTED": "Don't ever bother me again? i 'm trying to get to the top level of my superman video game.", + "PADDED_8_EXTRACTED": "Don't ever bother me again? i 'm trying to get to the top level of my superman video game.", + "PADDED_8_DILATION_1": "Don't ever bother me again! i 'm trying to get to the top level of my superman video game", + "PAD_8_FRACT_0_5": "Don't ever bother me again? i 'm trying to get to the top level of my superman video game", + "PAD_8_FRACT_0_2": "Don't ever bother me again? i 'm trying to get to the top level of my superman video game" + }, + "73": { + "INITIAL_BOX": "Yay! we won! we won?", + "DEFAULT": "Yay! we won? we won?", + "DEFAULT_GREY_PAD": "Yay! we won! we won?", + "PADDED_4": "Yay! we won! we won?", + "PADDED_8": "Yay! we won! we won?", + "EXTRACTED_INIT_BOX": "Yay! we won? wow?", + "PADDED_4_EXTRACTED": "Yay! we won! wwe how'm?", + "PADDED_8_EXTRACTED": "Yay! we won! wow?", + "PADDED_8_DILATION_1": "Yay! we won? we won?", + "PAD_8_FRACT_0_5": "Yay! we won! we won?", + "PAD_8_FRACT_0_2": "Yay! we won! we won?" + }, + "74": { + "INITIAL_BOX": "High?", + "DEFAULT": "High score!", + "DEFAULT_GREY_PAD": "Highlight", + "PADDED_4": "High score", + "PADDED_8": "High score", + "EXTRACTED_INIT_BOX": "Ss", + "PADDED_4_EXTRACTED": "S", + "PADDED_8_EXTRACTED": "Ss", + "PADDED_8_DILATION_1": "S", + "PAD_8_FRACT_0_5": "\"s\"", + "PAD_8_FRACT_0_2": "Ss" + }, + "75": { + "INITIAL_BOX": "Man, i guess i'll just draw another strip about dope...", + "DEFAULT": "Man, i guess i'll just draw another strip about dope...", + "DEFAULT_GREY_PAD": "Man, i guess i'll just draw another strip about dope...", + "PADDED_4": "Man, i guess i'll just draw another strip about dope...", + "PADDED_8": "Man, i guess i'll just draw another strip about dope...", + "EXTRACTED_INIT_BOX": "Main, i guess it just drew another strip about dope", + "PADDED_4_EXTRACTED": "Man, i guess i'm just drunk another strip about dope", + "PADDED_8_EXTRACTED": "Man, i guess i just didn't another strip about dope", + "PADDED_8_DILATION_1": "Man, i guess i'll just draw another strip about dope", + "PAD_8_FRACT_0_5": "Man, i guess i just draw another strip about dope", + "PAD_8_FRACT_0_2": "Man, i guess i'll just draw another strip about dope" + }, + "76": { + "INITIAL_BOX": "Scribbly", + "DEFAULT": "Scribbly", + "DEFAULT_GREY_PAD": "Scribbly", + "PADDED_4": "Scribbly", + "PADDED_8": "Scribbly", + "EXTRACTED_INIT_BOX": "C bbb", + "PADDED_4_EXTRACTED": "C bbb!", + "PADDED_8_EXTRACTED": "C bbb!", + "PADDED_8_DILATION_1": "C bbl", + "PAD_8_FRACT_0_5": "C bbb", + "PAD_8_FRACT_0_2": "C bbl" + }, + "77": { + "INITIAL_BOX": "Saddy", + "DEFAULT": "Saddy", + "DEFAULT_GREY_PAD": "Saddy", + "PADDED_4": "Saddy", + "PADDED_8": "Saddy", + "EXTRACTED_INIT_BOX": "Sir?", + "PADDED_4_EXTRACTED": "Sadd", + "PADDED_8_EXTRACTED": "S \"dd", + "PADDED_8_DILATION_1": "Sadd", + "PAD_8_FRACT_0_5": "S rd", + "PAD_8_FRACT_0_2": "S \"" + }, + "78": { + "INITIAL_BOX": "Sir?", + "DEFAULT": "Sir?", + "DEFAULT_GREY_PAD": "Sir?", + "PADDED_4": "Sir?", + "PADDED_8": "Sir?", + "EXTRACTED_INIT_BOX": "I'm sorry?", + "PADDED_4_EXTRACTED": "\"?", + "PADDED_8_EXTRACTED": "What?", + "PADDED_8_DILATION_1": "R?", + "PAD_8_FRACT_0_5": "\"?", + "PAD_8_FRACT_0_2": "\"" + }, + "79": { + "INITIAL_BOX": "\"mom, i want to be a cartoonist.\".", + "DEFAULT": "Mom, i want to be a cartoonist.", + "DEFAULT_GREY_PAD": "Mom, i want to be a cartoonist.", + "PADDED_4": "Mom, i want to be a cartoonist.", + "PADDED_8": "Mom, i want to be a cartoonist.", + "EXTRACTED_INIT_BOX": "To want to now! how?", + "PADDED_4_EXTRACTED": "\" mom! i want to be a cartoonist!", + "PADDED_8_EXTRACTED": "\" mom! i want to be a cartoonist! \"", + "PADDED_8_DILATION_1": "\" mom, i want to be a cartoonist! \"", + "PAD_8_FRACT_0_5": "\" mom, i want to be a cartoonist! \"", + "PAD_8_FRACT_0_2": "\" mom, i want to be a cartoonist! \"" + }, + "80": { + "INITIAL_BOX": "Sir?", + "DEFAULT": "Sir?", + "DEFAULT_GREY_PAD": "Sir?", + "PADDED_4": "Sir?", + "PADDED_8": "Sir?", + "EXTRACTED_INIT_BOX": "Sir?", + "PADDED_4_EXTRACTED": "Sir?", + "PADDED_8_EXTRACTED": "Sir?", + "PADDED_8_DILATION_1": "Sir?", + "PAD_8_FRACT_0_5": "Sir?", + "PAD_8_FRACT_0_2": "Sir?" + }, + "81": { + "INITIAL_BOX": "Sigh *", + "DEFAULT": "Sigh *", + "DEFAULT_GREY_PAD": "Sigh *", + "PADDED_4": "Sigh *", + "PADDED_8": "Sigh *", + "EXTRACTED_INIT_BOX": "Slight.", + "PADDED_4_EXTRACTED": "Sigh!", + "PADDED_8_EXTRACTED": "\" sigh!", + "PADDED_8_DILATION_1": "Sigh*", + "PAD_8_FRACT_0_5": "Slight!", + "PAD_8_FRACT_0_2": "Sigh!" + } + }, + "ronson-031.jpg": { + "1": { + "DEFAULT_GREY_PAD": "Junto al abreviado crecia el vigoroso trono de una gran parra, que trepaba habilmente la tierra...", + "INITIAL_BOX": "Junto al abreviado crecia el vigoroso trono de una gran parra, que trepaba habilmente la tapia ...", + "DEFAULT": "Junto al abreviado crecia el vigoroso trono de una gran parra, que trepaba hasta la cima...", + "PADDED_4": "Junto al abreviado crecia el vigoroso tronco de una gran parra, que trepaba h\u00e1blmente la tapia ...", + "PADDED_8": "Junto al abreviado crecia el vigoroso trono de una gran parra, que trepaba habilmente la tierra ...", + "EXTRACTED_INIT_BOX": "Junto al aprendaredo crec\u00eda e vigroso tronco de una gran parra, que trepar\u00e1 habiliente la tapa...", + "PADDED_4_EXTRACTED": "Junto al abreviador cre\u00eda el vigrosos tronco de una gran parra, que trepar\u00e1 habilmente la tapa...", + "PADDED_8_EXTRACTED": "Junto al abreviador cre\u00eda el vigiloso trono de una gran parra, que trepara habilmente - la tierra ...", + "PADDED_8_DILATION_1": "Junt\u00f3 al abreviado crec\u00eda el vigoroso tronco de una gran parra, que trepaba haciendo la tierra....", + "PAD_8_FRACT_0_5": "Junto al abreviado crecia el vigoroso trono de una gran parra, que trepaba haciendo la tierra ...", + "PAD_8_FRACT_0_2": "Junto al abreviado crecia el vigrosos tronco de una gran parra, que trepaba haciendo la tierra...." + }, + "0": { + "DEFAULT_GREY_PAD": "En una visita reciente a la casa despues de muchos d\u00e9cadas, me sorprend\u00ed al ver el abevadero. lo recordaba mucho m\u00e1s alto.", + "INITIAL_BOX": "En una visita reciente a la casa despues de muchos decadas, me sorprend\u00ed al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "DEFAULT": "En una visita reciente a la casa despu\u00e9s de muchos a\u00f1os, me sorprend\u00ed al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_4": "En una visita reciente a la casa despu\u00e9s de muchos a\u00f1os, me sorprend\u00ed al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_8": "En una visita reciente a la casa despues de muchos d\u00e9cades, me sorprend\u00ed al ver el abuceradero. lo recordaba mucho m\u00e1s alto.", + "EXTRACTED_INIT_BOX": "En una visita reciente a la casa despues de muchos d\u00e9cadas, me sorprend\u00ed al ver el abrevadero. lo regarda mucho m\u00e1s alto.", + "PADDED_4_EXTRACTED": "En una visita reciente a la casa despu\u00e9s de muchas d\u00e9cadas, me sorprend\u00ed al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_8_EXTRACTED": "En una visita reciente a la casa despu\u00e9s de muchos a\u00f1os, me sorprend\u00ed al ver el airvadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_8_DILATION_1": "En una visita reciente a la casa despu\u00e9s de muchos a\u00f1os, me sorprend\u00ed al ver el abreviado. lo recordaba mucho m\u00e1s alto.", + "PAD_8_FRACT_0_5": "En una visita reciente a la casa despu\u00e9s de muchos a\u00f1os, me sorprend\u00ed al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PAD_8_FRACT_0_2": "En una visita reciente a la casa despu\u00e9s de muchos a\u00f1os, me sorprend\u00ed al ver el libro recordado mucho m\u00e1s alto." + }, + "2": { + "DEFAULT_GREY_PAD": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "INITIAL_BOX": "Supongo que este recurrido tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "DEFAULT": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "PADDED_4": "Supongo que este recurrido tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "PADDED_8": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "EXTRACTED_INIT_BOX": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "PADDED_4_EXTRACTED": "Supongo que este recuperado tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "PADDED_8_EXTRACTED": "Supongo que este recurrido tramposo revela la escuela que tiene el mundo cuando eres un ni\u00f1o.", + "PADDED_8_DILATION_1": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "PAD_8_FRACT_0_5": "Supongo que este recurrido tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o.", + "PAD_8_FRACT_0_2": "Supongo que este recurrido tramposo revela la escala que tiene el mundo cuando eres un ni\u00f1o." + }, + "3": { + "DEFAULT_GREY_PAD": "Y se extienda hasta el cobertizo de entrada. hacia principio del verano lucia sus exuberantes hojas y comenzaba ya a florecer.", + "INITIAL_BOX": "Y se extienda hasta el cobertizo de entrada, haciendo pricipio del verano lucia sus exuberantes flores y comenzaba ya a florecer.", + "DEFAULT": "Y se extienda hasta el cobertizo de entrada, haciendo pruebo del verano lucia sus exuberantes flores y comenza ya a florecer.", + "PADDED_4": "Y se extienda hasta el cobertizo de entrada, haciendo pricipio del verano lucia sus exuberantes flores y comenzaba ya a florecer.", + "PADDED_8": "Y se extendia hasta el cobertizo de entreda. hacia principio del verano lucio sus exuberantes hogars y comenzaba a florecer.", + "EXTRACTED_INIT_BOX": "Y se extienda hasta el cobertizo de entrada. hacia principio del verano lucia sus exuberantes huertos y comenzaba ya a florecer.", + "PADDED_4_EXTRACTED": "Y se extendia hasta el cobertizo de entreda. hacian principio del verano lucila sus exuberantes hores; yo mezenba a ya florecer.", + "PADDED_8_EXTRACTED": "Y se extiendia hasta el cobertizo de entrada. hacia principio del verano lucia sus exuberantes hojas y flores; ya a florecer.", + "PADDED_8_DILATION_1": "Y se extiendia hasta el cobertizo de entrada. hacia principio del verano lucia sus exuberantes hojas y flores; ya a florcer.", + "PAD_8_FRACT_0_5": "Y se extiendia hasta el cobertizo de entrada. hacia principio del verano lucia sus exuberantes hojas y flores; pero al florecer.", + "PAD_8_FRACT_0_2": "Y se extendia hasta el cobertizo de entrada. hacia principio del verano lucia sus exuberantes hores y comenzaba ya a florecer." + }, + "4": { + "DEFAULT_GREY_PAD": "Era entones cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuantaba el dia y se extendia de sol a sol.", + "INITIAL_BOX": "Era entones cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuantela dias y se extendia de sol a sol.", + "DEFAULT": "Era entones cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuantaba el dia y se extendia de sol a sol.", + "PADDED_4": "Era entones cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuantela diya y se extendia de sol a sol.", + "PADDED_8": "Era entones cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el dia y se extendia de sol a sol.", + "EXTRACTED_INIT_BOX": "Era entones cuando daba comenzola la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el dia y se extendia de sol a sol.", + "PADDED_4_EXTRACTED": "Era entones cuando daba comenzola la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el dia y se extendia de sol a sol.", + "PADDED_8_EXTRACTED": "Era entones cuando daba comenz\u00f3 la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el dia y se extend\u00eda de sol a sol.", + "PADDED_8_DILATION_1": "Era entones cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuantaba el dia y se extendia de sol a sol.", + "PAD_8_FRACT_0_5": "Era entones cuando daba comenzola la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el dia y se extendia de sol a sol.", + "PAD_8_FRACT_0_2": "Era entones cuando daba comenzola la cosecha del cereal..la jornada se iniciaba tan pronto despuntaba el dia y se extendia de sol a sol." + }, + "5": { + "DEFAULT_GREY_PAD": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre miles de dorados; hoz y zocueta en risite, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "INITIAL_BOX": "Requerdo a aquellos segadores arriendose paso entre meses doradas, hoy y zocueta en este ristra; con una compa\u00f1ia de las chicharras.", + "DEFAULT": "Requerdo a aquellos segadores abri\u00e9ndose paso entre sus doradas hoy y zocueta en este ristre; con una compa\u00f1\u00eda de las chicharras.", + "PADDED_4": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre miles de dorados, hoz y zocueta en este ristre, con una compa\u00f1\u00eda de las chicharras.", + "PADDED_8": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre miles de dorados; hoy y zqueuta en este ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "EXTRACTED_INIT_BOX": "Requerdo a aquellos segadores arrendosose paso entere meses doradas, hoz y zooqeta en pistre; con la unica compania de las chicarras.", + "PADDED_4_EXTRACTED": "Requerido a aquellos segadores arrendose paso entre sus doradas, hoy zouqueta en este rincon con una compania de las chicharas.", + "PADDED_8_EXTRACTED": "Recuerdo a aquellos segadores arriendosas paso entere mesas doradas; hot zooqeta en rigtine; con una unica compania de las chicarras.", + "PADDED_8_DILATION_1": "Recuerdo a aquellos segadores arriendoso paso entire mes doradas; hoz y zooqeta en risting, con la unica compania de las chicarras.", + "PAD_8_FRACT_0_5": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre miles de dorados, hoy zozquetas en pie, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PAD_8_FRACT_0_2": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre miles de dorados; hoy y zouketa en este rinche, con la \u00fanica compa\u00f1\u00eda de las chicharas." + } + } + } + } +} \ No newline at end of file diff --git a/pcleaner/_testbed/experiment/Tesseract.json b/pcleaner/_testbed/experiment/Tesseract.json new file mode 100644 index 00000000..b713fc0b --- /dev/null +++ b/pcleaner/_testbed/experiment/Tesseract.json @@ -0,0 +1,4062 @@ +{ + "ocr_model": "Tesseract", + "runs": { + "Tesseract-crop-post": { + "Strange_Tales_172005.jpg": { + "0": { + "INITIAL_BOX": "Eneonered by great gnarled cypress jrfes, the ancient manor stands alone on the outski) 2 of mew ce eans, kept tidy by a white-haired old man known only as bambs, 3", + "DEFAULT": "Eneowered by great gnarled cypress jrfes, the ancient manor ! alone on the eit of mew rce: eans, kept tipy by a white-haired ao han known only as", + "DEFAULT_GREY_PAD": "Enbowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a white-haired old man known only as", + "PADDED_4": "Enbonered by great gnarled cypress jrfes, the ancient manor stands alone on the eit of mew rce: eans, kept tipy by a white-haired ao lo man known only as", + "PADDED_8": "Enbonered by great gnarled cypress trees, the ancient manor stands alone on the pag hile of new orleans, kept tipy by a white-haired ao lo man known omy as", + "EXTRACTED_INIT_BOX": "Fhbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans. kept tipy by a whi te-haire old man known only as bambi] .", + "PADDED_4_EXTRACTED": "Enbonsred by great shale cypress trees, the anci manor stands alone on the [tskirts of new orleans, kept tidy by a whi te- haired old man known only as b8ambl .", + "PADDED_8_EXTRACTED": "Enbonered by great snarled cypress trees, the ancient nmanor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as 8ambli .", + "PADDED_8_DILATION_1": "Outskirts of new orleans, kept tipy by a white-haired old man known only as sams .", + "PAD_8_FRACT_0_5": "Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl .", + "PAD_8_FRACT_0_2": "Enbonered by great snarled cypress trees, the ancient manor stands alone on the outskirts of new orleans, kept tipy by a whi te-haired old man known only as b8ambl ." + }, + "1": { + "INITIAL_BOX": "The house and the old man are alike in many ways; tall, prolid, patient, contented always 0 wait until. their. master cones mome ~~", + "DEFAULT": "The house and the old man are alike in many ways; tall, proud, patient, conten tel always to wait until their. master cones home ~~", + "DEFAULT_GREY_PAD": "The house and the old man are alike in many ways; tall, prolid, patient, contented always to wait until their. * master cones home ~-", + "PADDED_4": "The house and the oldman are alike in many ways; tall, proud, patient, contented a ways 0 wait until their. aster comes home ~~ | }", + "PADDED_8": "The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their. master comes home", + "EXTRACTED_INIT_BOX": "Ee house and the old man por alike in many ways; tall, proud, patient, contented always t\u00b0 wait until their. master cones home ~~", + "PADDED_4_EXTRACTED": "The house and the old man are alike in many ways; tall, proud, patient, contented always t\u00b0 wait until their. master cones home --", + "PADDED_8_EXTRACTED": "The house and the old man are alike in many ways; tall, proud, patient, contented always t\u00b0 wait until their. master comes home --", + "PADDED_8_DILATION_1": "The house and the old man are alike in many ways, tall, proud, nt, contented live walt gtie their, master comes home -=", + "PAD_8_FRACT_0_5": "The house and the old man are alike in many ways; tall, proud, patient, contented always t\u00b0 wait until. their. master comes home ~~", + "PAD_8_FRACT_0_2": "The house and the old man are alike in many ways; tall, proud, patient, contented always t\u00b0 wait until their. master comes home ~~" + }, + "2": { + "INITIAL_BOX": "\u201cand one in ee would appear.", + "DEFAULT": "And one in ee would appear.", + "DEFAULT_GREY_PAD": "\u201cand one in > need of some help, it would appear .", + "PADDED_4": "F and one in ee would appear.", + "PADDED_8": "7 and one in ee would appear,", + "EXTRACTED_INIT_BOX": "And one in fee would appear.", + "PADDED_4_EXTRACTED": "And one in fee would appear.", + "PADDED_8_EXTRACTED": "And one in fee wolld appear.", + "PADDED_8_DILATION_1": "And one in need of some help, it wolld appear .", + "PAD_8_FRACT_0_5": "And one in eee pe would appear.", + "PAD_8_FRACT_0_2": "And one in eet sve would appear." + }, + "3": { + "INITIAL_BOX": "Re bambli-~ we have a", + "DEFAULT": "Rir guest.", + "DEFAULT_GREY_PAD": "\" bambl-- we have a guest.", + "PADDED_4": "\" bambli-\u2014 we have a gliest.", + "PADDED_8": "Zf mbl == we have a guest.", + "EXTRACTED_INIT_BOX": "\u2014 we have a i=s7t.", + "PADDED_4_EXTRACTED": "Bambli we have a gliest.", + "PADDED_8_EXTRACTED": "Bambl ~~ we have a guest.", + "PADDED_8_DILATION_1": "Bambli ~~ we have a gliest.", + "PAD_8_FRACT_0_5": "Bambl ~~ we have a guest.", + "PAD_8_FRACT_0_2": "Bambl ~~ we have a guest." + }, + "4": { + "INITIAL_BOX": "Tonight, he comes noost slamming open the caken", + "DEFAULT": "=~and tonight, he comes host sane oo", + "DEFAULT_GREY_PAD": "~~and tonight, he comes urgently, slanming open", + "PADDED_4": "P comes slamming open the caken", + "PADDED_8": "Tonight, he comes host slamming open", + "EXTRACTED_INIT_BOX": "~and tonight, he comes urgently, slamming open", + "PADDED_4_EXTRACTED": "=~and tonight, he comes urgently, slamming open", + "PADDED_8_EXTRACTED": "=~and tonight, he comes slamming open urgently,", + "PADDED_8_DILATION_1": "=and tonight, he comes most slamming open the front", + "PAD_8_FRACT_0_5": "=~and tonight, he comes slamming open urgently,", + "PAD_8_FRACT_0_2": "=~and tonight, he comes slamming open urgently," + }, + "5": { + "INITIAL_BOX": "Tell me naster. how may bambli serve 7", + "DEFAULT": "Tell me masts - how may bambli . serve 7 _", + "DEFAULT_GREY_PAD": "Tell me, master: how may bambli serve 7", + "PADDED_4": "Tel oe er-- 5 ow a = 7", + "PADDED_8": "Yy i tell me master - how may bambli serve 7 _,", + "EXTRACTED_INIT_BOX": "Tell me master how may bambli serve 7", + "PADDED_4_EXTRACTED": "Tell me master. how may bambli serve 7", + "PADDED_8_EXTRACTED": "Tell me master... how may bambli serve't", + "PADDED_8_DILATION_1": "Tell me, master: how may bambli serve 7", + "PAD_8_FRACT_0_5": "Tell me master... how may bambli serve'7", + "PAD_8_FRACT_0_2": "Tell me master... how may bambli serve'7" + }, + "6": { + "INITIAL_BOX": "\u00a37 \u00bb and perhaps some dry clothes... 7 /", + "DEFAULT": "R warm, bambli-~ and perhaps", + "DEFAULT_GREY_PAD": "Some blankets to keep her. warm, bambli-- and perhaps some dry \\ clothes--7 /.", + "PADDED_4": "We and perhaps c oe /", + "PADDED_8": "Some. blankets to keep he arm , bambli-= and perhaps some dry clothes. 2s", + "EXTRACTED_INIT_BOX": "Some blankets to keep her warm, banbli-- and perhaps. some dry clothes", + "PADDED_4_EXTRACTED": "Warm, bambli-- and perhaps. som", + "PADDED_8_EXTRACTED": "Some blankets to keep her warm, banbli-~ and perhaps. some dry clothes", + "PADDED_8_DILATION_1": "Gone blankets to keep her. warm, bambli-~ and perhaps some dry", + "PAD_8_FRACT_0_5": "Some blankets to keep her. warm, bambli-~ and perhaps. some dry clothes", + "PAD_8_FRACT_0_2": "Some blankets to keep her, warm, bambli-~ and perhaps. some dry clothes" + }, + "7": { + "INITIAL_BOX": "The the old man's fades down the hall as... 7", + "DEFAULT": "The the old mans fades down the hall s.00", + "DEFAULT_GREY_PAD": "As.", + "PADDED_4": "The the old mans fades down the hall sra", + "PADDED_8": "The the old mans fades down the hal. srl see", + "EXTRACTED_INIT_BOX": "The the old man's fades down the hall s.,00", + "PADDED_4_EXTRACTED": "The the old mans fades down the hall sra", + "PADDED_8_EXTRACTED": "The the old mans fades down the hall sire", + "PADDED_8_DILATION_1": "The old man's footsteps the hall as.re", + "PAD_8_FRACT_0_5": "The the old mans fades donn the hall sire", + "PAD_8_FRACT_0_2": "The the old mans fades down the hall sere" + }, + "8": { + "INITIAL_BOX": "How curious the 4 fate. whims of had t not chanced to stroll along the river yl tonight ==", + "DEFAULT": "How curious the a whims of fate . had t not chanced to stroll along the river tonight~~ >", + "DEFAULT_GREY_PAD": "How curious the d 7e . whims of fa; had i not chanced to stroll along the river tonight--", + "PADDED_4": "How curious the a whims of fate . - had i not chanced to stroll along the river yl tonight~-", + "PADDED_8": "* how curious the p whims of fate . - had i not chanced . to stroll along _ the river 3 tonight-~", + "EXTRACTED_INIT_BOX": "Hin ef fare\u201d had i not chanced to stroll along the river. tonigmt=~", + "PADDED_4_EXTRACTED": "We sea had i not chanced to stroll along the river. tonight-~", + "PADDED_8_EXTRACTED": "How curious the whims of fate . had i not chanced to stroll along the river tonight-~", + "PADDED_8_DILATION_1": "How curious the whims of fate . had i not chanced to stroll along the r/| ver tonight-~", + "PAD_8_FRACT_0_5": "How curious the whims of fate . had i not chanced to stroll along the river tonight-~", + "PAD_8_FRACT_0_2": "How curious the whims of fate . had i not chanced to stroll along the river tonight-~" + }, + "9": { + "INITIAL_BOX": "Fas oulckly as t ca, master.", + "DEFAULT": "Aulckly \u201cmaster as t can,", + "DEFAULT_GREY_PAD": "Ickl as t can", + "PADDED_4": "Aulckly as t can, \u2018masrer.", + "PADDED_8": "Tiie as t can, \\ master ,", + "EXTRACTED_INIT_BOX": "Aulckly as t can, master,", + "PADDED_4_EXTRACTED": "Alley as t can, master,", + "PADDED_8_EXTRACTED": "Allckry as t can, master.", + "PADDED_8_DILATION_1": "Aulckly as t can,", + "PAD_8_FRACT_0_5": "Aulckry as t can, master.", + "PAD_8_FRACT_0_2": "Aulckry as t can, master." + }, + "10": { + "INITIAL_BOX": "gasp!z everything's w- whirling around me!t can't stand sr rea", + "DEFAULT": "Gasp! everything's w- whi rns atound me!i can't stand we a", + "DEFAULT_GREY_PAD": "5gasp!z everything's | w- whirling around] me!t can't stand ue a", + "PADDED_4": "Fgasp/= everything's whirling around me!i can't stand ea", + "PADDED_8": "Ega5p/% everything s\\ w- whirling around me! t can't stand ue... slee", + "EXTRACTED_INIT_BOX": "Fgasp!z everything \u00a7 w- whirling around me!i can't stand ue.", + "PADDED_4_EXTRACTED": "Sgasp/z everything s w- whirling around me!i can't stand ue.", + "PADDED_8_EXTRACTED": "Sgasp/z everything s w- whirling around me!i can't stand up.", + "PADDED_8_DILATION_1": "Gasp! everything s w-whirling around wel] i can't stand", + "PAD_8_FRACT_0_5": "Gasp/z everything s w- whirling around me!i can't stand up.", + "PAD_8_FRACT_0_2": "Gasp/z everything s w- whirling around me!i can't stand up." + }, + "2": { + "INITIAL_BOX": "Clark!i'm falling' \u201chelp! help! \u2014", + "DEFAULT": "Clark!i'm falling! help! help", + "DEFAULT_GREY_PAD": "Ark!i'm falling", + "PADDED_4": "Ie lottie eto clark!i'm falling help! help!", + "PADDED_8": "\\ help! help\u2019", + "EXTRACTED_INIT_BOX": "Clark!i'm falling! help! help!", + "PADDED_4_EXTRACTED": "Clark! i'm falling\u2019 help! help!", + "PADDED_8_EXTRACTED": "Clark! i'm falling\u2019 _ help! help!", + "PADDED_8_DILATION_1": "Clark!i'm falling! . help! help!", + "PAD_8_FRACT_0_5": "Clark! i'm falling\u2019 _ help! help!", + "PAD_8_FRACT_0_2": "Clark! i'm falling\u2019 _ help! help!" + }, + "3": { + "INITIAL_BOX": "I-i'm bs \"passing ohhh", + "DEFAULT": "I-i'm se ou", + "DEFAULT_GREY_PAD": "I-t'm eq \"passing out... ohhh.", + "PADDED_4": "I-i'm yr a ohh hh.", + "PADDED_8": "-i'm passing qut... ohh hh.", + "EXTRACTED_INIT_BOX": "I-i'm passing ohhh?", + "PADDED_4_EXTRACTED": "I-i'm passing ohhhh.", + "PADDED_8_EXTRACTED": "I-i'm passing ohhha.", + "PADDED_8_DILATION_1": "I-i'm passing ohhha.", + "PAD_8_FRACT_0_5": "I-i'm passing ohhhh.", + "PAD_8_FRACT_0_2": "I-i'm passing ohhha." + }, + "4": { + "INITIAL_BOX": "Action comics", + "DEFAULT": "Action comics", + "DEFAULT_GREY_PAD": "Action comics", + "PADDED_4": "Action comics", + "PADDED_8": "Action comics", + "EXTRACTED_INIT_BOX": "Action comics", + "PADDED_4_EXTRACTED": "Action comics", + "PADDED_8_EXTRACTED": "Action comics", + "PADDED_8_DILATION_1": "Action comics", + "PAD_8_FRACT_0_5": "Action comics", + "PAD_8_FRACT_0_2": "Action comics" + }, + "5": { + "INITIAL_BOX": "Then, seconds later...", + "DEFAULT": "Then, seconds later.", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Then, seconds", + "PADDED_8": "", + "EXTRACTED_INIT_BOX": "Then, seconds later..", + "PADDED_4_EXTRACTED": "Then, seconds later.", + "PADDED_8_EXTRACTED": "Then, seconds later.", + "PADDED_8_DILATION_1": "Then, seconds later.", + "PAD_8_FRACT_0_5": "Then, seconds later.", + "PAD_8_FRACT_0_2": "Then, seconds later." + }, + "6": { + "INITIAL_BOX": "Great caesars ghost! { this /s black magic! we've been transportel to the weirdest world, tit ever saw!", + "DEFAULT": "Great caesar's ghost! this /s black magic! we've been transported, to the weirdest world, i ever saw!", + "DEFAULT_GREY_PAD": "\u2018great caesar's ghost! || this /\u00a7 black magic! we've been transportel to the weirdest world, i ever saw.", + "PADDED_4": "Great caesar's ghost! \\ this /\u00a7 black magic! i ever saw!", + "PADDED_8": "I ever saw/", + "EXTRACTED_INIT_BOX": "Great caesar's ghost! this /s black magic! we've been transportel to the weirdest world tit ever saw.", + "PADDED_4_EXTRACTED": "Great caesar's ghost! this as black magic! we've been transported to the weirdest world i ever saw!", + "PADDED_8_EXTRACTED": "Great caesar's ghost! f this /\u00a7 black magic! : we've been transported to the weirdest world i ever saw.", + "PADDED_8_DILATION_1": "Great caesar's ghost! e this /5 black magic! we've been transported to the weirdest world i ever saw/", + "PAD_8_FRACT_0_5": "Great caesar's ghost! f this /\u00a7 black magic! : we've been transported to the weirdest world i ever saw.", + "PAD_8_FRACT_0_2": "Great caesar's ghost! f this /\u00a7 black magic! : we've been transported to the weirdest world i ever saw!" + }, + "7": { + "INITIAL_BOX": "...|t certainly isn't our earth, perry. look at the size of those bees.", + "DEFAULT": "...|t certainly isn't our earth, perry look at the size of those bees!", + "DEFAULT_GREY_PAD": "\"...it certainly isn't our | earth, perry look at the| \\s|ze of those bees.", + "PADDED_4": "T certainly isn't our earth, perry! look at the \\s|ze of those bees.", + "PADDED_8": "It certainly isn't our earth, perry! poor a the size of thos!", + "EXTRACTED_INIT_BOX": "...it certainly isnt our earth, perry. look at the size of those bees.", + "PADDED_4_EXTRACTED": "...it certainly isnt our earth, perry. look at the size of those bees.", + "PADDED_8_EXTRACTED": "...it certainly isnt our earth, perry. look at the size of those bees.", + "PADDED_8_DILATION_1": "...|it certainly isnt our earth, perry\u201d look at the size of those bees!", + "PAD_8_FRACT_0_5": "...it certainly isnt our earth, perry! look at the size of those bees.", + "PAD_8_FRACT_0_2": "...it certainly isnt our earth, perry! look at the size of those bees." + }, + "8": { + "INITIAL_BOX": "Watch out, clark!", + "DEFAULT": "Watch out, clark)", + "DEFAULT_GREY_PAD": "Watch out, clark!", + "PADDED_4": "#3 watch out, clark!", + "PADDED_8": "\u201cwatch out\u201d ial ae clark!", + "EXTRACTED_INIT_BOX": "Watch out, clark!", + "PADDED_4_EXTRACTED": "Watch out, clark!", + "PADDED_8_EXTRACTED": "Watch out, clark!", + "PADDED_8_DILATION_1": "Watch out, clark!", + "PAD_8_FRACT_0_5": "Watch out, clark!", + "PAD_8_FRACT_0_2": "Watch out, clark!" + }, + "9": { + "INITIAL_BOX": "Owwww.", + "DEFAULT": "Owwww.,", + "DEFAULT_GREY_PAD": "Owwww.", + "PADDED_4": "Owwww.", + "PADDED_8": "Owwww.", + "EXTRACTED_INIT_BOX": "Oowwwww.", + "PADDED_4_EXTRACTED": "Owwww.,", + "PADDED_8_EXTRACTED": "Owwww.,", + "PADDED_8_DILATION_1": "Owwww.", + "PAD_8_FRACT_0_5": "Owwww.,", + "PAD_8_FRACT_0_2": "Owwww.," + }, + "10": { + "INITIAL_BOX": "Yet the bee's stinger went ws. right through my uniform and penetrated my skin! that means. the fabric of pe ay costume has become dj} satie fued 1,", + "DEFAULT": "Yet the bee's stinger went = right through my uniform ando penetrated my skin! that mean the fabric of my superman costume has become ordinary, cloth! \u00a3", + "DEFAULT_GREY_PAD": "Yet the bee's stinger went ~ right through my uniform and penetrated my skin! that means. the fabric of sera ry costume vis become din a s clots! a", + "PADDED_4": "\"yet the bee's stinger went ~~ right through my uniform and enetrated my skin! that means. the fabric of my superman costume has become ordinary, clot! &", + "PADDED_8": "Yet the bee's stinger went right through my uniform and \\penetrated my skin! that means. the fabric of my superman costume has become ordinar! cloth!", + "EXTRACTED_INIT_BOX": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!", + "PADDED_4_EXTRACTED": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!", + "PADDED_8_EXTRACTED": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!", + "PADDED_8_DILATION_1": "Yet the bee's stinger we right through my tform and penetrated my skin! that means. the fabric of my superman othe has become ordinary clot?", + "PAD_8_FRACT_0_5": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!", + "PAD_8_FRACT_0_2": "Yet the bee's stinger went right through my uniform and penetrated my skin! that means. the fabric of my superman costume has become ordinary cloth!" + }, + "11": { + "INITIAL_BOX": "Hurry. let's beat it before we get stung, foo = aii", + "DEFAULT": "Hurry. let's beat it before we get stung, tod yi", + "DEFAULT_GREY_PAD": "Hurry. let's ) beat it before] we get stung, k 00! __j", + "PADDED_4": "Hurry! let's beat it b=fore we get stung, \u00a2 tool: puma", + "PADDED_8": "Hurry. let's beat it before we get stung, too!", + "EXTRACTED_INIT_BOX": "Hurry. let's beat it before we get stung, too!", + "PADDED_4_EXTRACTED": "Hurry! let's beat it before we get stung, too!", + "PADDED_8_EXTRACTED": "Hurry! let's beat it before we get stung, too!", + "PADDED_8_DILATION_1": "Hurry! let's beat it before we get stung, too!", + "PAD_8_FRACT_0_5": "Hurry! let's beat it before we get stung, too!", + "PAD_8_FRACT_0_2": "Hurry! let's beat it before we get stung, too!" + }, + "12": { + "INITIAL_BOX": "Ggreat guns!...2g, .pa/n i feel n pain! as superman, i should be > invulnerable! 1 have unbreakabl \u2018skin! under my clark kent clothes, im wearing an woestructisle superman uniform ! =", + "DEFAULT": "Ggreat guns!...2gasp/z...pain i feel n fan! as superman, i should be invulnerable! 1 have unbreakable skin! under my clark kent clothes, i'm wearing an /noestruct/ele superman uniform !", + "DEFAULT_GREY_PAD": "Ggreat guns!...3gasp/=... rain t feel fan! as superman, i should be invulnerable\u00ae 1 have unbreakabli skin! under my clark kent clothes, ia wearing an /noestryct/iele supe iperman uniform !", + "PADDED_4": "\u2018ggreat guns!...3gasp/5... pain i feel pain? as superman, i should be invilnerable | t ne unbreakasle gkin! under my clark kent clothes, tih wearing an indestructible superman uniform", + "PADDED_8": "Ggreat guns!...2gasp/z...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ele $ superman uniform ! &", + "EXTRACTED_INIT_BOX": "Ggreat guns!...2g/ pain t feel pain? as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform *", + "PADDED_4_EXTRACTED": "Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !", + "PADDED_8_EXTRACTED": "Ggreat guns!...2gasp/:... pain t feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /noestruct/ble superman uniform !", + "PADDED_8_DILATION_1": "Fain! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !", + "PAD_8_FRACT_0_5": "Ggreat guns!...2gasp/:...pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an /nodestruct/ible superman uniform !", + "PAD_8_FRACT_0_2": "Ggreat guns!...2gasp/:... pain i feel fan! as superman, i should be invulnerable! 1 have unbreakabl skin! under my clark kent clothes, i'm wearing an indestructible superman uniform !" + }, + "13": { + "INITIAL_BOX": "Abruptly...", + "DEFAULT": "Abruptly...", + "DEFAULT_GREY_PAD": "Abruptly.", + "PADDED_4": "Abruptly...", + "PADDED_8": "", + "EXTRACTED_INIT_BOX": "Abruptly. ..", + "PADDED_4_EXTRACTED": "Abruptly...", + "PADDED_8_EXTRACTED": "Abruptly. ..", + "PADDED_8_DILATION_1": "", + "PAD_8_FRACT_0_5": "Abruptly. ..", + "PAD_8_FRACT_0_2": "Abruptly...." + }, + "14": { + "INITIAL_BOX": "Great caesar's ghost. he's spinning a web of g/ant, sr strands --", + "DEFAULT": "Great caesars \u00b0 ghost! he's spinning & web of g/a, silk strands", + "DEFAULT_GREY_PAD": "Great caesar's | ghost! he's spinning k web of giant, silk strands -- as tough as steel! ne]", + "PADDED_4": "Great caesars ghost. he's spinning a web of g/ant, | silk strands as tough as steel!", + "PADDED_8": "Great caesai ghost. he's spinning a web of g/ant, silk strands -- as tough as steel!", + "EXTRACTED_INIT_BOX": "Great caesar's ghost. he's spinning a web of g/ant, silk strands --", + "PADDED_4_EXTRACTED": "Great caesar's ghost! he's spinning a web of g/ant, \"silk strands -- as tough as steel!", + "PADDED_8_EXTRACTED": "Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!", + "PADDED_8_DILATION_1": "Great caesars ghost! he's spinning _ a web of g/ant,", + "PAD_8_FRACT_0_5": "Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!", + "PAD_8_FRACT_0_2": "Great caesar's ghost! he's spinning _ a web of g/ant, \"silk strands -- as tough as steel!" + }, + "15": { + "INITIAL_BOX": "I-i feel the heat of the sun...the pain of the bee-sting ... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers! i've become an ordinary mortal in this world. /", + "DEFAULT": "I-i feel the heat of the sum...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all my super -powersx ve become an ordinary mortal in this world! j", + "DEFAULT_GREY_PAD": "\\i-t feel the heat of the sun...the pain of the bee-sting... the heavy weight of my & pack! every human discomfort... good grief! i've lost all my super-powers i've become an ordinary mortal in this world. /.", + "PADDED_4": "I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my { pack! every human discomfort... good grief! i've lost all \\my super-powersx ve become an ordinary mortal in this world.", + "PADDED_8": "I-i feel the heat of the sun...the pain of the bee-sting... the heavy weight of my ! every human discomfort... good grief! i've lost all \\my super-powers! \u2018ve become an ordinary mortal in this world. x", + "EXTRACTED_INIT_BOX": "I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal im this world.", + "PADDED_4_EXTRACTED": "I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.", + "PADDED_8_EXTRACTED": "I-t feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! t've lost all my super-powers. ve become an ordinary mortal in this world.", + "PADDED_8_DILATION_1": "I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve ie an ordinary mortal in this world.", + "PAD_8_FRACT_0_5": "I-i feel the heat of the sun. the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world.", + "PAD_8_FRACT_0_2": "I-i feel the heat of the sun., the pain of the bee-sting... the heavy weight of my pack! every human discomfort... good grief! i've lost all my super-powers. ve become an ordinary mortal in this world." + }, + "16": { + "INITIAL_BOX": "Enormous spider- like creature is going berserk, as if the sight of us excited him (into mad spinning get back! that 2", + "DEFAULT": "Like creature is going berserk, as if the sight of us excited him into mad spinning, get back! that \\ enormous spider-", + "DEFAULT_GREY_PAD": "(get back! that enormous spider- like creature 1 \u00a7 going berserk, as if the sight of us excited him into mad spinning]", + "PADDED_4": "(get back! that enormous spider- as if the sight of us excited him [into mad spinning", + "PADDED_8": "As if the sight of us excited him {into mad spinning", + "EXTRACTED_INIT_BOX": "Get back. that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning", + "PADDED_4_EXTRACTED": "Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning", + "PADDED_8_EXTRACTED": "Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [", + "PADDED_8_DILATION_1": "Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning\u2019 g [", + "PAD_8_FRACT_0_5": "Get back! that enormous spider- like creature is going berserk, 25 if the sight of us excited him into mad spinning g [", + "PAD_8_FRACT_0_2": "Get back! that enormous spider- like creature is going berserk, as if the sight of us excited him into mad spinning gs [" + } + }, + "Adolf_Cap_01_008.jpg": { + "0": { + "INITIAL_BOX": "Ya le dije\u201d a mi padre que lo en- un aguse- ro en un \u00e1rbol.", + "DEFAULT": "Ya le dije\" a mi padre - que lo en- en un aguje-* \u00e1rbol. ro en un", + "DEFAULT_GREY_PAD": "Ya le dije: a mi padre: \u00a1que lo en- un aguje- ro en un", + "PADDED_4": "Ya le dije\u201d a mi padre. que lo en- un aguje-* ro en un \u00e1rbol.", + "PADDED_8": "Ya le dije = a mi padre - que lo en- * en un aguie- * ro en un \u00e1rbol. |", + "EXTRACTED_INIT_BOX": "Ya le dije a mi padre que lo en- un aguse= ro en un \u00e1rbol.", + "PADDED_4_EXTRACTED": "Ya le dije a mi padre que lo en- un aguse= ro en un \u00e1rbol.", + "PADDED_8_EXTRACTED": "Ya le dije am padre que lo en- en un aguse= ro en un arbol.", + "PADDED_8_DILATION_1": "Ya le dije ami padre que lo en- en un aguse- ro en un arbol.", + "PAD_8_FRACT_0_5": "Ya le dije am padre que lo en- en un aguse- ro en un \u00e1rbol.", + "PAD_8_FRACT_0_2": "Ya le dije am padre que lo en- en un aguse- ro en un arbol." + }, + "1": { + "INITIAL_BOX": "Iriera de agu\u00ed\u00ed", + "DEFAULT": "Iriera de aqu\u00ed/", + "DEFAULT_GREY_PAD": "Iriera e aqu\u00ed", + "PADDED_4": "Piera de aqu\u00ed", + "PADDED_8": "Iriera > de au", + "EXTRACTED_INIT_BOX": "Ipiera de aqu\u00ed", + "PADDED_4_EXTRACTED": "Ipiera de aqu\u00ed", + "PADDED_8_EXTRACTED": "Ipiera de aqui", + "PADDED_8_DILATION_1": "Iriera de aqu\u00ed/", + "PAD_8_FRACT_0_5": "Iriera de aqu\u00ed", + "PAD_8_FRACT_0_2": "Ipiera de aqu\u00ed" + }, + "2": { + "INITIAL_BOX": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "DEFAULT": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "DEFAULT_GREY_PAD": "Te he pre- guntado| \u00a1que qui\u00e1 escribi\u00f3 sto.", + "PADDED_4": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "PADDED_8": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "EXTRACTED_INIT_BOX": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "PADDED_4_EXTRACTED": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "PADDED_8_EXTRACTED": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "PADDED_8_DILATION_1": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "PAD_8_FRACT_0_5": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto.", + "PAD_8_FRACT_0_2": "Te he pre- guntado que qui\u00e9n escribi\u00f3 esto." + }, + "3": { + "INITIAL_BOX": "1no lo sl no quiero hablar m\u00e1s", + "DEFAULT": "1no lo s\u00e9l no quiero hablar m\u00e1s ello.", + "DEFAULT_GREY_PAD": "\u00a1no lo sel| \u00a1no quiero! hablar ello.", + "PADDED_4": "1no lo s\u00e9l no quiero hablar m\u00e1s ello.", + "PADDED_8": "1no lo s\u00e9l no quiero hablar m\u00e1s ello.", + "EXTRACTED_INIT_BOX": "Ino lo s\u00e1 \u00f1o quiero hablar m\u00e1s", + "PADDED_4_EXTRACTED": "No lo s\u00e9l no quiero hablar m\u00e1s ello.", + "PADDED_8_EXTRACTED": "No lo s\u00e9l no quiero hablar m\u00e1s ello.", + "PADDED_8_DILATION_1": "No lo s\u00e9l no quiero hablar m\u00e1s ello.", + "PAD_8_FRACT_0_5": "\u00a1no lo s\u00e9l no quiero hablar m\u00e1s ello.", + "PAD_8_FRACT_0_2": "\u00a1no lo s\u00e9l no quiero hablar m\u00e1s ello." + }, + "4": { + "INITIAL_BOX": "Adolf, lo que dice ese papel.", + "DEFAULT": "Adolf, lo que dice ese papel", + "DEFAULT_GREY_PAD": "'adolf, lo que es completa mente falso.", + "PADDED_4": "Adolf, lo que dice ese papel es completa chad e falso. demagogia peligrosa. f", + "PADDED_8": "Adolf, lo que dice ese papel es completa mente falso.", + "EXTRACTED_INIT_BOX": "Adolf, lo que dice ese papel.", + "PADDED_4_EXTRACTED": "Adolf, lo que dice ese papel es completa mente falso. es demagogia peligrosa.", + "PADDED_8_EXTRACTED": "Adolf, lo que dice ese papel es completa mente falso. es demagogia peligrosa.", + "PADDED_8_DILATION_1": "Adolf, lo que dice ese papel es completa mente falso, peligrosa.", + "PAD_8_FRACT_0_5": "Adolf, lo que dice ese papel es completa mente falso. es demagogia peligrosa.", + "PAD_8_FRACT_0_2": "Adolf, lo que dice ese papel es completa- mente falso. es demagogia peligrosa." + }, + "5": { + "INITIAL_BOX": "Entonces, \u00bfpor qu\u00e9 le preo- cupa", + "DEFAULT": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?", + "DEFAULT_GREY_PAD": "\u00bfpor qu\u00e9 ccuppa", + "PADDED_4": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?", + "PADDED_8": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?", + "EXTRACTED_INIT_BOX": "Entonces, \u00bfpor qu\u00e9 le preo- cupa", + "PADDED_4_EXTRACTED": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?", + "PADDED_8_EXTRACTED": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?", + "PADDED_8_DILATION_1": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?", + "PAD_8_FRACT_0_5": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?", + "PAD_8_FRACT_0_2": "Entonces, \u00bfpor qu\u00e9 le preo- cupa tanto?" + }, + "6": { + "INITIAL_BOX": "El consulado no permite la circulaci\u00f3n de ese tpo de", + "DEFAULT": "El consulado no permite la circulaci\u00f3n de ese tpo de", + "DEFAULT_GREY_PAD": "El consulado no permite la \u00a1circulaci\u00f3n del ese tipo de", + "PADDED_4": "El consulado no permite la circulaci\u00f3n de ese tpo de", + "PADDED_8": "El consulado no permite la circulaci\u00f3n de ese tpo de", + "EXTRACTED_INIT_BOX": "El consulado no permite la circulaci\u00f3n de ese tipo de", + "PADDED_4_EXTRACTED": "El consulado no permite la circulaci\u00f3n de ese tipo de", + "PADDED_8_EXTRACTED": "El consulado no permite la circulaci\u00f3n de ese tipo de", + "PADDED_8_DILATION_1": "El consulado no permite la circulaci\u00f3n de ese tipo de", + "PAD_8_FRACT_0_5": "El consulado no permite la circulaci\u00f3n de ese tpo de", + "PAD_8_FRACT_0_2": "El consulado no permite la circulaci\u00f3n de ese tpo de" + }, + "7": { + "INITIAL_BOX": "Wo s\u00e9 nada!", + "DEFAULT": "Wo s\u00e9 nada!", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Wo s\u00e9", + "PADDED_8": "Es ae", + "EXTRACTED_INIT_BOX": "Lo s\u00e9 wo s\u00e9,", + "PADDED_4_EXTRACTED": "Wo s\u00e9", + "PADDED_8_EXTRACTED": "Lo s\u00e9 ne", + "PADDED_8_DILATION_1": "Es ne", + "PAD_8_FRACT_0_5": "Lo s\u00e9 ne", + "PAD_8_FRACT_0_2": "Lo s\u00e9 ne" + }, + "8": { + "INITIAL_BOX": "Tengo - que slen- \u00bfentien- des?", + "DEFAULT": "Tengo 2 que slen- ciarlos, \u00bfentien-", + "DEFAULT_GREY_PAD": "Tengo \u00a1que salen: ciarlos, \u00bfentien-", + "PADDED_4": "Tengo 2 que silen- ciarlos, \u00bfentien- |", + "PADDED_8": "Tengo que salen: ciarlos, \u00bfentien- y des7", + "EXTRACTED_INIT_BOX": "Tengo que slen- \u00bfentien- des?", + "PADDED_4_EXTRACTED": "Tengo que slen- \u00bfentien- des?", + "PADDED_8_EXTRACTED": "Tengo que slen- \u00bfentien- des7", + "PADDED_8_DILATION_1": "Tengo que slen- \u00bfentien- dest", + "PAD_8_FRACT_0_5": "Tengo que slen- \u00bfentien- des7", + "PAD_8_FRACT_0_2": "Tengo que slen- \u00bfentien- des7" + }, + "9": { + "INITIAL_BOX": "Ahora,", + "DEFAULT": "Ahora,", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Ahora, habla/", + "PADDED_8": "Pe", + "EXTRACTED_INIT_BOX": "Ahora,", + "PADDED_4_EXTRACTED": "Ahora,", + "PADDED_8_EXTRACTED": "Ahora, wabla/", + "PADDED_8_DILATION_1": "Ahora, wabla/", + "PAD_8_FRACT_0_5": "Ahora, wabla/", + "PAD_8_FRACT_0_2": "Ahora, wabla/" + }, + "10": { + "INITIAL_BOX": "\u00bfest\u00e1s encu- briendo a al- guien?", + "DEFAULT": "\u00bfestas encu- briendo a al- guient", + "DEFAULT_GREY_PAD": "\u00bfestas encu- briendo; a al- guient.", + "PADDED_4": "\u00bfestas encu- briendo a al- guient", + "PADDED_8": "\u00bfestas encu- briendo a al- guient", + "EXTRACTED_INIT_BOX": "\u00bfestas briendo encu- a al- guien?", + "PADDED_4_EXTRACTED": "\u00bfestas encu- briendo a al- guient", + "PADDED_8_EXTRACTED": "\u00bfestas encu- briendo a al- guient", + "PADDED_8_DILATION_1": "\u00bfestas encuu- briendo a al- guient", + "PAD_8_FRACT_0_5": "\u00bfestas encu- briendo a al- guient", + "PAD_8_FRACT_0_2": "\u00bfestas encu- briendo a al- guient" + } + }, + "Barnaby_v1-028.png": { + "0": { + "INITIAL_BOX": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "DEFAULT": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "DEFAULT_GREY_PAD": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "PADDED_4": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "PADDED_8": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "EXTRACTED_INIT_BOX": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "PADDED_4_EXTRACTED": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "PADDED_8_EXTRACTED": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "PADDED_8_DILATION_1": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "PAD_8_FRACT_0_5": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . .", + "PAD_8_FRACT_0_2": "Barnaby, | should like to bestow a boon upon this household in return for its hospitality. . . . shall i rid the locality of werewolves? charm the cattle and the crops against the ravages of evil spirits? . . ." + }, + "1": { + "INITIAL_BOX": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "DEFAULT": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "DEFAULT_GREY_PAD": "We haven't any cattle and pop's victory garden is growing fine. and i don\u2019t think we\u2019ve had much trouble with werewolves at all.", + "PADDED_4": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PADDED_8": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "EXTRACTED_INIT_BOX": "We haven\u2019t any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PADDED_4_EXTRACTED": "We haven\u2019t any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PADDED_8_EXTRACTED": "We haven\u2019t any cattle and pop's victory garden is growing fine. and | don't think we've had much trouble with werewolves at all.", + "PADDED_8_DILATION_1": "We haven't any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all.", + "PAD_8_FRACT_0_5": "We haven\u2019t any cattle and pop's victory garden is growing fine. and i don\u2019t think we\u2019ve had much trouble with werewolves at all.", + "PAD_8_FRACT_0_2": "We haven\u2019t any cattle and pop's victory garden is growing fine. and i don't think we've had much trouble with werewolves at all." + }, + "2": { + "INITIAL_BOX": "Then perhaps i can drive out snakes? or witch a well? . .", + "DEFAULT": "Then perhaps i can drive out snakes? or witch a well? .", + "DEFAULT_GREY_PAD": "Then perhaps i can drive out snakes? or witch a well? , .", + "PADDED_4": "Then perhaps i can drive out snakes? or witch a well? .", + "PADDED_8": "Then perhaps i can drive out snakes? or witch a well? .", + "EXTRACTED_INIT_BOX": "Then perhaps | can drive out snakes? or witch a well? . .", + "PADDED_4_EXTRACTED": "Then perhaps | can drive out snakes? or witch a well? .", + "PADDED_8_EXTRACTED": "Then perhaps | can drive out snakes? or witch a well? . .", + "PADDED_8_DILATION_1": "Then perhaps i can drive out snakes? or witch a well? . .", + "PAD_8_FRACT_0_5": "Then perhaps | can drive out snakes? or witch a well? , .", + "PAD_8_FRACT_0_2": "Then perhaps | can drive out snakes? or witch a well? , ." + }, + "3": { + "INITIAL_BOX": "Where the end of this divining rod turns to the earth we'll find water.", + "DEFAULT": "Where the end of this divining rod turns to the earth we'll find water.", + "DEFAULT_GREY_PAD": "Where the end of this divining rod turns to the earth we'll find water.", + "PADDED_4": "Where the end of this divining rod turns to the earth we'll find water.", + "PADDED_8": "Where the end of this divining rod turns to the earth we'll find water.", + "EXTRACTED_INIT_BOX": "Where the end of this divining rod turns to the earth we'll find water.", + "PADDED_4_EXTRACTED": "Where the end of this divining rod turns to the earth we'll find water.", + "PADDED_8_EXTRACTED": "Where the end of this divining rod turns to the earth we'll find water.", + "PADDED_8_DILATION_1": "Where the end of this divining rod turns to the earth we'll find water.", + "PAD_8_FRACT_0_5": "Where the end of this divining rod turns to the earth we'll find water.", + "PAD_8_FRACT_0_2": "Where the end of this divining rod turns to the earth we'll find water." + }, + "4": { + "INITIAL_BOX": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "DEFAULT": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "DEFAULT_GREY_PAD": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "PADDED_4": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "PADDED_8": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "EXTRACTED_INIT_BOX": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "PADDED_4_EXTRACTED": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "PADDED_8_EXTRACTED": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "PADDED_8_DILATION_1": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "PAD_8_FRACT_0_5": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley.", + "PAD_8_FRACT_0_2": "Gosh. don\u2019t go to a lot of trouble, mr. o'malley." + }, + "5": { + "INITIAL_BOX": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "DEFAULT": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "DEFAULT_GREY_PAD": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "PADDED_4": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "PADDED_8": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "EXTRACTED_INIT_BOX": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "PADDED_4_EXTRACTED": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "PADDED_8_EXTRACTED": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "PADDED_8_DILATION_1": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "PAD_8_FRACT_0_5": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad.", + "PAD_8_FRACT_0_2": "When you grow to manhood and inherit this estate you'll thank your fairy godfather for this well right in your cellar, m\u2019lad." + }, + "6": { + "INITIAL_BOX": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "DEFAULT": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "DEFAULT_GREY_PAD": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "PADDED_4": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "PADDED_8": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "EXTRACTED_INIT_BOX": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "PADDED_4_EXTRACTED": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "PADDED_8_EXTRACTED": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "PADDED_8_DILATION_1": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "PAD_8_FRACT_0_5": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy.", + "PAD_8_FRACT_0_2": "Ah, that's it! | shall bestow the blessing of a never-failing water supply upon this plot of land... fetch me a forked stick, m\u2019boy." + }, + "7": { + "INITIAL_BOX": "But we've got city water, mr. o'malley.", + "DEFAULT": "But we've got city water, mr. o'malley.", + "DEFAULT_GREY_PAD": "But we've got city water, mr. o'malley.", + "PADDED_4": "But we've got city water, mr. o'malley.", + "PADDED_8": "But we've got city water, mr. o'malley.", + "EXTRACTED_INIT_BOX": "But we've got city water, mr. o'malley.", + "PADDED_4_EXTRACTED": "But we've got city water, mr. o'malley.", + "PADDED_8_EXTRACTED": "But we've got city water, mr. o'malley.", + "PADDED_8_DILATION_1": "But we've got city water, mr. o'malley.", + "PAD_8_FRACT_0_5": "But we've got city water, mr. o'malley.", + "PAD_8_FRACT_0_2": "But we've got city water, mr. o'malley." + }, + "8": { + "INITIAL_BOX": "Er... is there any beer on ice, m\u2019boy?", + "DEFAULT": "Er... is there any beer on ice, m\u2019boy?", + "DEFAULT_GREY_PAD": "Er... is there any beer on ice, m\u2019bo", + "PADDED_4": "Er... is there any beer on ice, m\u2019boy?", + "PADDED_8": "Er... is there any beer on ice, m'boy?", + "EXTRACTED_INIT_BOX": "Er... is there any beer on ice, m'boy?", + "PADDED_4_EXTRACTED": "Er... is there any beer on ice, m\u2019boy?", + "PADDED_8_EXTRACTED": "Er... is there any beer on ice, m\u2019boy?", + "PADDED_8_DILATION_1": "Er... is there any beer on ice, m'boy?", + "PAD_8_FRACT_0_5": "Er... is there any beer on ice, m\u2019boy?", + "PAD_8_FRACT_0_2": "Er... is there any beer on ice, m'boy?" + }, + "9": { + "INITIAL_BOX": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, . . makes me thirsty merely to describe it . . .", + "DEFAULT": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, . . makes me thirsty merely to describe it . . .", + "DEFAULT_GREY_PAD": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth. ., makes me thirsty merely to describe it . . .", + "PADDED_4": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, . . makes me thirsty merely to describe it . . .", + "PADDED_8": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, . . makes me thirsty merely to describe it . . .", + "EXTRACTED_INIT_BOX": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, .. makes me thirsty merely to describe it . . .", + "PADDED_4_EXTRACTED": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, .. makes me thirsty merely to describe it . . .", + "PADDED_8_EXTRACTED": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, .. makes me thirsty merely to describe it . . .", + "PADDED_8_DILATION_1": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, . . makes me thirsty merely to describe it . . .", + "PAD_8_FRACT_0_5": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, . . makes me thirsty merely to describe it . . .", + "PAD_8_FRACT_0_2": "Not to be compared in taste with the clear, cool, beautiful nectar of the natural earth, , . makes me thirsty merely to describe it . . ." + }, + "10": { + "INITIAL_BOX": "- rocket {oh (4 con", + "DEFAULT": "C rockety jor con", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Crockety jonson", + "PADDED_8": "Ec rocket] jor nson", + "EXTRACTED_INIT_BOX": ". rocket {oh (4 con", + "PADDED_4_EXTRACTED": "C rocket jonson", + "PADDED_8_EXTRACTED": "Crocket jornmson", + "PADDED_8_DILATION_1": "Crocket jor nso", + "PAD_8_FRACT_0_5": "Crocket jonmgon", + "PAD_8_FRACT_0_2": "Crocket jornmson" + }, + "11": { + "INITIAL_BOX": "We can really get along all right with the city water supply . . .", + "DEFAULT": "We can really get along all right with the city water supply . . .", + "DEFAULT_GREY_PAD": "We can really get along all right with the city water supply . . .", + "PADDED_4": "We can really get along all right with the city water supply . . .", + "PADDED_8": "We can really get along all right with the city water supply . . .", + "EXTRACTED_INIT_BOX": "We can really get along all right with the city water supply . . .", + "PADDED_4_EXTRACTED": "We can really get along all right with the city water supply . . .", + "PADDED_8_EXTRACTED": "We can really get along all right with the city water supply . . .", + "PADDED_8_DILATION_1": "We can really get along all right with the city water supply . . .", + "PAD_8_FRACT_0_5": "We can really get along all right with the city water supply . . .", + "PAD_8_FRACT_0_2": "We can really get along all right with the city water supply . . ." + }, + "12": { + "INITIAL_BOX": "Hush, m\u2019boy. this is a time of conservation.", + "DEFAULT": "Hush, m\u2019boy. this is a time of conservation.", + "DEFAULT_GREY_PAD": "Hush, m\u2019boy. this is a time of conservation.", + "PADDED_4": "Hush, m\u2019boy. this is a time of conservation.", + "PADDED_8": "Hush, m\u2019boy. this is a time of conservation.", + "EXTRACTED_INIT_BOX": "Hush, m\u2019boy. this is a time of conservation.", + "PADDED_4_EXTRACTED": "Hush, m\u2019boy. this is a time of conservation.", + "PADDED_8_EXTRACTED": "Hush, m\u2019boy. this is a time of conservation.", + "PADDED_8_DILATION_1": "Hush, m\u2019boy. this is a time of conservation.", + "PAD_8_FRACT_0_5": "Hush, m\u2019boy. this is a time of conservation.", + "PAD_8_FRACT_0_2": "Hush, m\u2019boy. this is a time of conservation." + }, + "13": { + "INITIAL_BOX": "We're being patriotic\u2014", + "DEFAULT": "We're being patriotic\u2014", + "DEFAULT_GREY_PAD": "We're being patriotic\u2014", + "PADDED_4": "We're being patriotic\u2014", + "PADDED_8": "We're being patriotic\u2014", + "EXTRACTED_INIT_BOX": "We're being patriotic\u2014", + "PADDED_4_EXTRACTED": "We're being patriotic\u2014", + "PADDED_8_EXTRACTED": "We're being patriotic\u2014", + "PADDED_8_DILATION_1": "We're being patriotic\u2014", + "PAD_8_FRACT_0_5": "We're being patriotic\u2014", + "PAD_8_FRACT_0_2": "We're being patriotic\u2014" + }, + "14": { + "INITIAL_BOX": "Ah! here's the place! bring the pickaxe.", + "DEFAULT": "Ah! here's the place! bring the pickaxe.", + "DEFAULT_GREY_PAD": "Ah! here's the place! bring the pickaxe.", + "PADDED_4": "Ah! here's the place! bring the pickaxe.", + "PADDED_8": "Ah! here's the place! bring the pickaxe.", + "EXTRACTED_INIT_BOX": "Ah! here's the place! bring the pickaxe.", + "PADDED_4_EXTRACTED": "Ah! here's the place! bring the pickaxe.", + "PADDED_8_EXTRACTED": "Ah! here's the place! bring the pickaxe.", + "PADDED_8_DILATION_1": "Ah! here's the place! bring the pickaxe.", + "PAD_8_FRACT_0_5": "Ah! here's the place! bring the pickaxe.", + "PAD_8_FRACT_0_2": "Ah! here's the place! bring the pickaxe." + }, + "15": { + "INITIAL_BOX": "Crockett jorunnsonn", + "DEFAULT": "Crockett jourunnsonn", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Crockett jonson", + "PADDED_8": "A crockett jonunnson", + "EXTRACTED_INIT_BOX": "Crockett jorunsonn", + "PADDED_4_EXTRACTED": "Crockett jonson", + "PADDED_8_EXTRACTED": "Crockett jonunnsonn", + "PADDED_8_DILATION_1": "Crockett jonunnsonn", + "PAD_8_FRACT_0_5": "Crockett jonson", + "PAD_8_FRACT_0_2": "Crockett jonunson" + } + }, + "Cannon-292.jpg": { + "0": { + "INITIAL_BOX": "This is it. the v-2.7 it will", + "DEFAULT": "This is it. the v-2.7 , it will \u201d win the world for us.\u201d", + "DEFAULT_GREY_PAD": "This is it.", + "PADDED_4": "Pos bo eae this is it. the v-2.7 , it will win the world for us.\u201d", + "PADDED_8": "Re this is it. the v-2.7 it will win the world for us.", + "EXTRACTED_INIT_BOX": "This is it. the v-4.7 it will win the world | for us.", + "PADDED_4_EXTRACTED": "This is it. the v-2.7 it will win the world for us.\u201d", + "PADDED_8_EXTRACTED": "This is it. the v-2.7 it will win the world for us.", + "PADDED_8_DILATION_1": "This is it. the v-2.7 it will win the world for us.", + "PAD_8_FRACT_0_5": "This is it. the v-2.7 it will win the world for us.", + "PAD_8_FRACT_0_2": "This is it. the v-2.7 it will win the world for us." + }, + "1": { + "DEFAULT": "When that nuclear war- head explodes over moscow, they will not stop to ask who fired it / they will launch an allout attack on the (nited aa states.\u201d", + "INITIAL_BOX": "When that nuclear war: head explodes over moscow, they will not stop to ask who fired it / they will launch an all-out attack on the ynv/7tec a states 7", + "DEFAULT_GREY_PAD": "When that nuclear war: head explodes over moscow, they will not stop to ask who fired it / they will launch an all-out attack on the united states.\u201d", + "PADDED_4": "When that nuclear war- head explodes over moscow, they will not stop to ask who fired it / they will launch an all-out attack on the wiree ds states.\u201d", + "PADDED_8": "When that nuclear war] head explodes over moscow, they will not stop to ask who fired it / they will launch an all-out attack on the ynv/7tec states.\u201d", + "EXTRACTED_INIT_BOX": "When that nuclear war: head explodes over moscow, they will not stop to ask who fired it / they will launch an allout attack on the lite states 7", + "PADDED_4_EXTRACTED": "When that nuclear war- head explodes over moscow, they will not stop to ask who fired it / they will launch an allout attack on the lite states.\u201d", + "PADDED_8_EXTRACTED": "When that nuclear war- head explodes over moscow, they will not stop to ask who fired it / they will launch an allout attack on the lite states.\u201d", + "PADDED_8_DILATION_1": "When that nuclear war- head explodes over moscow, they will not stop to ask who fired it / they will launch an allout attack on the lw/ted states.\u201d", + "PAD_8_FRACT_0_5": "When that nuclear war- head explodes over moscow, they will not stop to ask who fired it / they will launch an all-out attack on the wv/7ec states.\u201d", + "PAD_8_FRACT_0_2": "When that nuclear war- head explodes over moscow, they will not stop to ask who fired it / they will launch an allout attack on the lw/ted states.\u201d" + }, + "2": { + "INITIAL_BOX": "'\u2014. and bo74 major powers will w/pe each other out.\u201d then we will move in and the world will be at our feet 4 oer tag.\u201d der tag., morgen o\u00a3 ganze | welt 7 has i 4 has", + "DEFAULT": "\u2019. and bo74 major ~n powers will w/pe each other out.\u201d then we will move in and the world will be at our feet 4 oer tag, der morgen tag.\u201d die ganze | welt 7 has a has", + "DEFAULT_GREY_PAD": "~. and o74 major powers will w/pe ach other out.\u201d the we will move in and the world will be at our feet oer tag. \u2019 der tag. morgen die ganze zene; 7 has", + "PADDED_4": "\u2014. and zo74 major powers will w/pe each other out./ then we will move in and the world will be at our peel derhis, \u2019 der morgen die 25, welt; id aa haz a. 1", + "PADDED_8": "\u2014 and o74 major powers will w725 each other out.\u201d then we will move in and the world will be at our feel oer tac der / morge/ ga n die wze welt? ha.\u201d >, aahal", + "EXTRACTED_INIT_BOX": "And zo74 major powers will w/pe each other out.\u201d then we will move in and the world will be at our feelers \u2019 der morgen die ganze fay shas", + "PADDED_4_EXTRACTED": "And zo74 major powers will w/pe each other out.\u201d then we will move in and the world will be at our feel oer tag.\u201d der morgen die ganze zener shas", + "PADDED_8_EXTRACTED": "And zo74 major powers will w/pe each other out.\u201d then we will move in and the world will be at our feel oer tag.\u201d der morgen die ganze zener shas", + "PADDED_8_DILATION_1": "And zo74 major powers will w/pe each other out.\u201d then we will move in and the world will be at our a tac der morgen die ganze zene 7 has", + "PAD_8_FRACT_0_5": "\u00ab. and o74 major powers will w/pe each other out,\u201d then we will move in and the world will be at our feet der tag, \u2019 der morgen tag.\u201d die ganze zenelt; 7 has", + "PAD_8_FRACT_0_2": "\u00ab= and zo74 major powers will w/pe each other out.\u201d then we will move in and the world will be at our gp \u2019 der morgen die ganze ay 7 has" + }, + "3": { + "INITIAL_BOX": "He's crazy. butit just cove j", + "DEFAULT": "He's crazy. but it just couto ji happen... }j", + "DEFAULT_GREY_PAD": "He's craz.", + "PADDED_4": "He's crazy... but it just coo j 5 happen...", + "PADDED_8": "He's crazy... butit just coup j happen", + "EXTRACTED_INIT_BOX": "He's crazy... butit just couo happen...", + "PADDED_4_EXTRACTED": "He's crazy... butit just couo happen...", + "PADDED_8_EXTRACTED": "He's crazy... butit just couo happen...", + "PADDED_8_DILATION_1": "He's crazy... butit just couo happen...", + "PAD_8_FRACT_0_5": "He's crazy... but it just cowo happen...", + "PAD_8_FRACT_0_2": "He's crazy... butit just couo happen..." + }, + "4": { + "INITIAL_BOX": "Me , cannon... , it will \u00ab begin to show you your duties", + "DEFAULT": ") some, cannon... > i will begin to show you your duties!", + "DEFAULT_GREY_PAD": "Come , cannon. i will begin to show you our duties!", + "PADDED_4": ") come, cannon... i will 4 begin to show you your duties!", + "PADDED_8": "Come, cannon... > i will begin to show you your duties!", + "EXTRACTED_INIT_BOX": "Show you your duties", + "PADDED_4_EXTRACTED": "Come , cannon... i will begin to show you your duties", + "PADDED_8_EXTRACTED": "Come , cannon... i will begin to show you your duties", + "PADDED_8_DILATION_1": "Come , cannon... i will begin to show you your duties", + "PAD_8_FRACT_0_5": "Come , cannon... i will begin to show you your duties", + "PAD_8_FRACT_0_2": "Come , cannon... i will begin to show you your duties" + }, + "5": { + "INITIAL_BOX": "How soon 2", + "DEFAULT": "How soon fi", + "DEFAULT_GREY_PAD": "How soon 2", + "PADDED_4": "How soon 2", + "PADDED_8": "How soon", + "EXTRACTED_INIT_BOX": "How soon 4", + "PADDED_4_EXTRACTED": "How soon 2", + "PADDED_8_EXTRACTED": "How soon zz", + "PADDED_8_DILATION_1": "How soon 2", + "PAD_8_FRACT_0_5": "How soon 2", + "PAD_8_FRACT_0_2": "How soon zz" + }, + "6": { + "INITIAL_BOX": "For days, cannon waits and watches, learning the layout of the castle.", + "DEFAULT": "For days, cannon waits and watches, learning the layout of the castle.", + "DEFAULT_GREY_PAD": "For days, cannon waits and watches, learning the layout of the castle.", + "PADDED_4": "For days, cannon waits and watches, learning the layout of the castle.", + "PADDED_8": "For days, cannon waits and watches, learning the layout of the castle...", + "EXTRACTED_INIT_BOX": "For days, cannon waits and watches, learning the layout of the castle.", + "PADDED_4_EXTRACTED": "For days, cannon waits and watches, learning the layout of the castle.", + "PADDED_8_EXTRACTED": "For days, cannon waits and watches, learning the layout of the castle...", + "PADDED_8_DILATION_1": "For days, cannon waits and watches, learning the layout of the castle...", + "PAD_8_FRACT_0_5": "For days, cannon waits and watches, learning the layout of the castle...", + "PAD_8_FRACT_0_2": "For days, cannon waits and watches, learning the layout of the castle..." + }, + "7": { + "INITIAL_BOX": "Final count- down ina days now! i", + "DEFAULT": "Final count- down ina days now? /", + "DEFAULT_GREY_PAD": "Final count-| down ina few days now.", + "PADDED_4": "\u201cfinal ina", + "PADDED_8": "Final sn , ina few days now! /", + "EXTRACTED_INIT_BOX": "Final count- down ina days now/", + "PADDED_4_EXTRACTED": "Final count- down ina days now!", + "PADDED_8_EXTRACTED": "Final count- down ina days now!", + "PADDED_8_DILATION_1": "Final count- down ina days now!", + "PAD_8_FRACT_0_5": "Final count- down ina few days now!", + "PAD_8_FRACT_0_2": "Final count- down ina days now!" + }, + "8": { + "INITIAL_BOX": "One rocket z how can that be z", + "DEFAULT": "28 one rocket z how can that be z", + "DEFAULT_GREY_PAD": "Rocket z how can that be z|", + "PADDED_4": "Yo one rocket z how can that be z", + "PADDED_8": "Rocket z how can that be 7", + "EXTRACTED_INIT_BOX": "One rocket 7 how can that be z", + "PADDED_4_EXTRACTED": "One rocket 7 how can that be 7", + "PADDED_8_EXTRACTED": "One rocket 7 how can that be 7", + "PADDED_8_DILATION_1": "One rocket z how can that be 7", + "PAD_8_FRACT_0_5": "One rocket z how can that be 7", + "PAD_8_FRACT_0_2": "One rocket z how can that be 7" + }, + "9": { + "INITIAL_BOX": "My hands are | healing nicely. can handle a gun again ..", + "DEFAULT": "My hands are y healing nicely. can handle a gun again..", + "DEFAULT_GREY_PAD": "My hands are healing nicely. can handle a un again", + "PADDED_4": "My hands are healing nicely. can handle a gun again..", + "PADDED_8": "My hands are healing nicely. can handle a gun again... /", + "EXTRACTED_INIT_BOX": "My hands are healing nicely. can handle a gun again ..", + "PADDED_4_EXTRACTED": "My hands are healing nicely. can handle a gun again.. |", + "PADDED_8_EXTRACTED": "My hands are healing nicely. can handle a gun again.. /", + "PADDED_8_DILATION_1": "My hands are healing nicely. can handle a gun again.. /", + "PAD_8_FRACT_0_5": "My hands are healing nicely. can handle a gun again.. /", + "PAD_8_FRACT_0_2": "My hands are healing nicely. can handle a gun again... /" + }, + "10": { + "INITIAL_BOX": "= \u00a5 what's as 7s | fd y 4 foe pin. some one doesn't trust me / |", + "DEFAULT": "Ey what's as this 7 a _ no firing pin. some: one doesn't trust me.\u201d", + "DEFAULT_GREY_PAD": "What's this 7 firing pinal. some one doesn't trust me./", + "PADDED_4": "Trust me./", + "PADDED_8": "E what's y. this 7 no firing pinal. some one doesn't trust me./", + "EXTRACTED_INIT_BOX": "One doesn't trust me 7", + "PADDED_4_EXTRACTED": "E what's yo this zt a _ no firing pinal. some one doesn't trust me ./", + "PADDED_8_EXTRACTED": "E what's yo this? a hno firing pinal. some one doesn't trust me ./", + "PADDED_8_DILATION_1": "Ee what's yo this t a no firing pinal. some one doesn't trust me ./", + "PAD_8_FRACT_0_5": "E what's nw this 7 one doesn\" t trust me./", + "PAD_8_FRACT_0_2": "E what's yo this? a _ hno firing pin. some one doesn't trust me.\u201d" + }, + "11": { + "INITIAL_BOX": "And then one day, as the mad dictator reviews his army ...", + "DEFAULT": "And then one day, as the mad dictator reviews his army ...", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "And then one day, as the mad dictator reviews his army cc", + "PADDED_8": "And then one day, as the mad dictator reviews his army...", + "EXTRACTED_INIT_BOX": "And then one day, as the mad dictator reviews his army ...", + "PADDED_4_EXTRACTED": "And then one day, as the mad dictator reviews his army ..c", + "PADDED_8_EXTRACTED": "And then one day, as the mad dictator reviews his army...", + "PADDED_8_DILATION_1": "And then one day, as the mad dictator reviews his army...", + "PAD_8_FRACT_0_5": "And then one day, as the mad dictator reviews his army...", + "PAD_8_FRACT_0_2": "And then one day, as the mad dictator reviews his army..." + }, + "12": { + "INITIAL_BOX": "A stirring sight, isn't it, herr cannon z soon they , will be united with their aryan brothers allover \\ the world\u2019 /", + "DEFAULT": "A stirring sight, isn't it, herr cannon 7 soon they j will be united with their aryan brothers allover \u00abthe world\u2019 j", + "DEFAULT_GREY_PAD": "A stirring sight, isn't it, herr cannon z soon thi will be united with their aryan brothers allover the world", + "PADDED_4": "A stirring sight, isn't it, herr cannon z soon they will be united 7 with their aryan brothers allover \\ the world\u2019 /", + "PADDED_8": "A stirring sight, isn't it, herr cannon z soon they will be united with the ir aryan brothers all over the world, j", + "EXTRACTED_INIT_BOX": "A stirring sight, isn't it, herr cannon z soon they will be united with their aryan brothers allover the world\u201d", + "PADDED_4_EXTRACTED": "A stirring sight, isn't it, herr cannon 2 soon they will be united with their aryan brothers allover the world\u201d", + "PADDED_8_EXTRACTED": "A stirring sight, isn't it, herr cannon 2 soon they will be united with their aryan brothers allover the world.\u201d", + "PADDED_8_DILATION_1": "A stirring sight, isn't it, herr cannon 2 soon they will be united with their aryan brothers allover the world.\u201d", + "PAD_8_FRACT_0_5": "A stirring sight, isn't it, herr cannon z soon they will be united with their aryan brothers allover the world.\u201d", + "PAD_8_FRACT_0_2": "A stirring sight, isn't it, herr cannon 2 soon they will be united with their aryan brothers allover the world.\u201d" + }, + "13": { + "INITIAL_BOX": "Yes. 1 can hardly > wait, fuhrer/", + "DEFAULT": "Yes. 1 can hardly > wait, fuhrer", + "DEFAULT_GREY_PAD": "Yes, 1 can hardly ait, fuhrer /]", + "PADDED_4": "In \\y fuhrer uy", + "PADDED_8": "Yes. 1 can hardly wait, fuhrer", + "EXTRACTED_INIT_BOX": "Yes. 1 can hardly wait, funrer !", + "PADDED_4_EXTRACTED": "1 can hardly wait, my fuhrer /", + "PADDED_8_EXTRACTED": "1 can hardly wait, my fuhrer /", + "PADDED_8_DILATION_1": "1 can hardly wait, my fuhrer /", + "PAD_8_FRACT_0_5": "1 can hardly wait, my fuhrer/", + "PAD_8_FRACT_0_2": "1 can hardly wait, my fuhrer/" + }, + "14": { + "INITIAL_BOX": "I'd \u00b0 better move fast/", + "DEFAULT": "Io better move fasst/", + "DEFAULT_GREY_PAD": "Id fast/", + "PADDED_4": "\u201d1'd better move fast/", + "PADDED_8": "217) better move fast.", + "EXTRACTED_INIT_BOX": "Id better move fast\u2019", + "PADDED_4_EXTRACTED": "Id better move fast/", + "PADDED_8_EXTRACTED": "Id better move fast.", + "PADDED_8_DILATION_1": "Id better move fast.", + "PAD_8_FRACT_0_5": "I'd better move fast,", + "PAD_8_FRACT_0_2": "I'd better move fast." + }, + "15": { + "INITIAL_BOX": "Presently the leader's attention becomes entirely fixed on the display...", + "DEFAULT": "Presently the leader's attention becomes entirely fixed on the display...", + "DEFAULT_GREY_PAD": "Presently the leader\" attention becomes entirely fixed on the display...", + "PADDED_4": "Presently the leader's attention becomes entirely fixed on the display.", + "PADDED_8": "Presently the leader's attention becomes entirely fixed on the display.", + "EXTRACTED_INIT_BOX": "Presently the leader's attention becomes entirely fixed on the display...", + "PADDED_4_EXTRACTED": "Presently the leader's attention becomes entirely fixed on the display...", + "PADDED_8_EXTRACTED": "Presently the leader's attention becomes entirely fixed on the display...", + "PADDED_8_DILATION_1": "Presently the leader's attention becomes entirely fixed on the display...", + "PAD_8_FRACT_0_5": "Presently the leader's attention becomes entirely fixed on the display...", + "PAD_8_FRACT_0_2": "Presently the leader's attention becomes entirely fixed on the display..." + }, + "16": { + "INITIAL_BOX": "Now.\u201d", + "DEFAULT": "Now.\u201d", + "DEFAULT_GREY_PAD": "Now.", + "PADDED_4": "Now.\u201d", + "PADDED_8": "Now.\u201d j", + "EXTRACTED_INIT_BOX": "Now", + "PADDED_4_EXTRACTED": "Wow", + "PADDED_8_EXTRACTED": "Wow", + "PADDED_8_DILATION_1": "Wow", + "PAD_8_FRACT_0_5": "Wow", + "PAD_8_FRACT_0_2": "Wow" + }, + "17": { + "INITIAL_BOX": "Quickly and quietly, cannon makes his way to the radio room ...", + "DEFAULT": "Quickly and quietly, cannon makes his way to the radio room...", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Quickly and quietly, cannon makes his way to the radio room...", + "PADDED_8": "Quickly and quietly, cannon makes his way to the radio room", + "EXTRACTED_INIT_BOX": "Quickly and quietly, cannon makes his way to the radio room \u00ab..", + "PADDED_4_EXTRACTED": "Quickly and quietly, cannon makes his way to the radio room...", + "PADDED_8_EXTRACTED": "Quickly and quietly, cannon makes his way to the radio room.", + "PADDED_8_DILATION_1": "Quickly and quietly, cannon makes his way to the radio room.", + "PAD_8_FRACT_0_5": "Quickly and quietly, cannon makes his way to the radio room.", + "PAD_8_FRACT_0_2": "Quickly and quietly , cannon makes his way to the radio room ww." + }, + "18": { + "INITIAL_BOX": "Cannon at co-ordinates k-10! and jz 2z.", + "DEFAULT": "\" aannon at cannon at co-ordinates k-iol and jizz... 4", + "DEFAULT_GREY_PAD": "Cannon at o-ordinates k-101 and jz 2...", + "PADDED_4": "Cannon at [co-ordinates k-101 and jz 2... 4", + "PADDED_8": "Cannon at [co-ordinates k-101 and jz 2...", + "EXTRACTED_INIT_BOX": "Cannon at co-ordinates k-101 and jz 2...", + "PADDED_4_EXTRACTED": "Cannon at co-ordinates k-101 and jz 2...", + "PADDED_8_EXTRACTED": "Cannon at co-ordinates k-101 and jz2...", + "PADDED_8_DILATION_1": "Cannon at co-ordinates k-101 and jz2z...", + "PAD_8_FRACT_0_5": "Cannon at co-ordinates k-101 and jz2...", + "PAD_8_FRACT_0_2": "Cannon at co-ordinates k-101 and jz 2..." + }, + "19": { + "INITIAL_BOX": "Quickly he sets the trans mitter to his secret frequency --.", + "DEFAULT": "Quickly he sets the trans- mitter to his secret frequency ---", + "DEFAULT_GREY_PAD": "Quickly he sets the trans mitter to his secret frequency", + "PADDED_4": "Quickly he sets the trans- mitter to his secret frequency .--", + "PADDED_8": "Quickly he sets the trans- mitter to his secret frequency", + "EXTRACTED_INIT_BOX": "Quickly he sets the trans: mitter to his secret frequency -...", + "PADDED_4_EXTRACTED": "Quickly he sets the trans- mitter to his secret frequency --.", + "PADDED_8_EXTRACTED": "Quickly he sets the trans - mitter to his secret frequency --.", + "PADDED_8_DILATION_1": "Quickly he sets the trans- mitter to his secret frequency .-.", + "PAD_8_FRACT_0_5": "Quickly he sets the trans - mitter to his secret frequency -..", + "PAD_8_FRACT_0_2": "Quickly he sets the trans- mitter to his secret frequency .-." + }, + "20": { + "INITIAL_BOX": "Situation desperate - it's reo plan one.\u201d t repeat...", + "DEFAULT": "Situation desperate ~ t's reo plan one.\u201d i repeat...", + "DEFAULT_GREY_PAD": "Situation", + "PADDED_4": "\"situation | situation desperate ~ it's red plan one.\u201d \u2018i repeat..", + "PADDED_8": "Situation \u00a5 desperate ~ t's reo plan one.\u201d i repeat.", + "EXTRACTED_INIT_BOX": "Situation desperate - it's reo plan one.\u201d t repeat...", + "PADDED_4_EXTRACTED": "Situation desperate ~ i repeat...", + "PADDED_8_EXTRACTED": "Situation desperate ~ it's reo plan one.\u201d i repeat...", + "PADDED_8_DILATION_1": "Situation desperate ~ t's reo plan one.\u201d i repeat...", + "PAD_8_FRACT_0_5": "Situation desperate ~ it's reo plan one.\u201d i repeat...", + "PAD_8_FRACT_0_2": "Situation desperate ~ t's reo plan one.\u201d i repeat..." + }, + "21": { + "INITIAL_BOX": "It's cannon? = a spy/", + "DEFAULT": "Canwon\u2019 . a spy./ /", + "DEFAULT_GREY_PAD": "Cannon. a spy.", + "PADDED_4": "It! canon\u2019 a spy.", + "PADDED_8": "Canon\u2019 a spy. /", + "EXTRACTED_INIT_BOX": "Ts cannon: he /s a spy /", + "PADDED_4_EXTRACTED": "It's / cannon. /s a spy./", + "PADDED_8_EXTRACTED": "Its canon he /s c%", + "PADDED_8_DILATION_1": "Its canon he /s c2%", + "PAD_8_FRACT_0_5": "It's y cannon he /s a spy./", + "PAD_8_FRACT_0_2": "Its cannon he /s a spy!" + }, + "22": { + "INITIAL_BOX": "And at that moment", + "DEFAULT": "And at that moment ...", + "DEFAULT_GREY_PAD": "And at that moment.", + "PADDED_4": "And at that moment", + "PADDED_8": "And at that moment", + "EXTRACTED_INIT_BOX": "And at that moment ..", + "PADDED_4_EXTRACTED": "And at that moment ..", + "PADDED_8_EXTRACTED": "And at that moment...", + "PADDED_8_DILATION_1": "And at that moment...", + "PAD_8_FRACT_0_5": "And at that moment...", + "PAD_8_FRACT_0_2": "And at that moment ..." + }, + "23": { + "INITIAL_BOX": "Don't move or you die right now. traitor /", + "DEFAULT": "Vem malt aas\u201d don't move or you die right now, traitor |", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Vm aat aai don't move or you die right \u201cnow, traitor _", + "PADDED_8": "Ydown't move or you die right now, traitor 4", + "EXTRACTED_INIT_BOX": "Dont move or you die right now. traitor", + "PADDED_4_EXTRACTED": "Dont move or you die right now, traitor\u201d", + "PADDED_8_EXTRACTED": "Dont move or you die right now, traitor", + "PADDED_8_DILATION_1": "Dont move or you die right now, traitor", + "PAD_8_FRACT_0_5": "Don't move or you die right now, traitor", + "PAD_8_FRACT_0_2": "Don't move or you die right now, traitor" + }, + "24": { + "INITIAL_BOX": "- search him. otto.", + "DEFAULT": "Search him, otto /", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Search him, otto", + "PADDED_8": "Search \u201chim, otto /", + "EXTRACTED_INIT_BOX": "Search him, otto", + "PADDED_4_EXTRACTED": "Search him, otto", + "PADDED_8_EXTRACTED": "Search him, otto /", + "PADDED_8_DILATION_1": "Search him, otto /", + "PAD_8_FRACT_0_5": "Search him, otto /", + "PAD_8_FRACT_0_2": "Search him, otto /" + }, + "25": { + "INITIAL_BOX": "Tense as a coiled spring, cannon waits as they disarm him.", + "DEFAULT": "Tense as a coiled spring, cannon waits as they disarm him...", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Tense as a coiled spring, cannon waits as they disarm him...", + "PADDED_8": "Tense as a coiled spring, cannon waits as they disarm him", + "EXTRACTED_INIT_BOX": "Tense as a coiled spring, cannon waits as they disarm him...", + "PADDED_4_EXTRACTED": "Tense as a coiled spring, cannon waits as they disarm him...", + "PADDED_8_EXTRACTED": "Tense as a coiled spring, cannon waits as they disarm him...", + "PADDED_8_DILATION_1": "Tense as a coiled spring, cannon waits as they disarm him...", + "PAD_8_FRACT_0_5": "Tense as a coiled spring, cannon waits as they disarm him..c", + "PAD_8_FRACT_0_2": "Tense as a coiled spring, cannon waits as they disarm him..." + }, + "26": { + "INITIAL_BOX": "The fuhrer will be very interested.", + "DEFAULT": "The fuhrer will be very interested.", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Lue creed the fuhrer will be very . interested.", + "PADDED_8": "Ltr the fuhrer will be jery \\ interested", + "EXTRACTED_INIT_BOX": "The fuhrer will be very interested.", + "PADDED_4_EXTRACTED": "The fuhrer will be very interested.", + "PADDED_8_EXTRACTED": "The fuhrer will be very interested.", + "PADDED_8_DILATION_1": "The fuhrer will be very interested.", + "PAD_8_FRACT_0_5": "The fuhrer will be very interested.", + "PAD_8_FRACT_0_2": "The fuhrer will be very interested." + }, + "27": { + "INITIAL_BOX": "Then \u2014", + "DEFAULT": "Then \u2014.", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Then \u2014", + "PADDED_8": "Then", + "EXTRACTED_INIT_BOX": "Then \u2014", + "PADDED_4_EXTRACTED": "Then \u2014", + "PADDED_8_EXTRACTED": "Then \u2014", + "PADDED_8_DILATION_1": "Then \u2014", + "PAD_8_FRACT_0_5": "Then \u2014", + "PAD_8_FRACT_0_2": "Then \u2014" + }, + "28": { + "INITIAL_BOX": "What-./z this transmitter is still open 7 4", + "DEFAULT": "What-.7z this transmitter 1s still open.\u201d a", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "What-.7z this transmitter 1s still open.\u201d", + "PADDED_8": "What-.7z this transmitter 1s , stillopen.\u201d", + "EXTRACTED_INIT_BOX": "What-./z this transmitter is still open 7", + "PADDED_4_EXTRACTED": "What-.7z this transmitter is still open.\u201d", + "PADDED_8_EXTRACTED": "What-.7z this transmitter is still open.\u201d", + "PADDED_8_DILATION_1": "What-.7z this transmitter 1s still open.\u201d", + "PAD_8_FRACT_0_5": "What-7z this transmitter 1s still open.\u201d", + "PAD_8_FRACT_0_2": "What-/z this transmitter 1s still open.\u201d" + }, + "29": { + "INITIAL_BOX": "The momentary distrac - tion |s enough ./ a blur of motion, and...", + "DEFAULT": "The momentary distrac - tion |s enough \u00a9 a blur of motion, and...", + "DEFAULT_GREY_PAD": "The momentary distrac - tion |s enough \u00a9 a blur of motion, and", + "PADDED_4": "The momentary distrac - tion |s enough \u00a9 a blur of motion, and...", + "PADDED_8": "The momentary distrac - tion |s enough \u00a9 a blur of motion, and", + "EXTRACTED_INIT_BOX": "The momentary distrac - tion |s enough ./ a blur of motion, and...", + "PADDED_4_EXTRACTED": "The momentary distrac - tion is enough \u00a9 a blur of motion, and...", + "PADDED_8_EXTRACTED": "The momentary distrac - tion is enough \u00a9 a blur of motion, and...", + "PADDED_8_DILATION_1": "The momentary distrac - tion |s enough \u00a9 a blur of motion, and...", + "PAD_8_FRACT_0_5": "The momentary distrac - tion is enough / a blur of motion, and...", + "PAD_8_FRACT_0_2": "The momentary distrac~ tion is enough / a blur of motion, and..." + } + }, + "FOX_CHILLINTALES_T17_012.jpg": { + "1": { + "DEFAULT": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me...", + "INITIAL_BOX": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me...", + "DEFAULT_GREY_PAD": "Sw en ti en a door nu in fl a rl av ef us ol man ih at he df (n ss ee", + "PADDED_4": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me...", + "PADDED_8": "T last the door swung open to reveal our cadaverous old man who peered t a", + "EXTRACTED_INIT_BOX": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me.", + "PADDED_4_EXTRACTED": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me.", + "PADDED_8_EXTRACTED": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me.", + "PADDED_8_DILATION_1": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me.", + "PAD_8_FRACT_0_5": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me.", + "PAD_8_FRACT_0_2": "At last the door swung open to reveal a cadaverous old man who peered out into the darkness at me." + }, + "0": { + "INITIAL_BOX": "Who are you? what do you want? \u2018yao", + "DEFAULT": "Who are you? what do you want? \u2018yom", + "DEFAULT_GREY_PAD": "Who are you? what do you want? yum", + "PADDED_4": "Who are you? what do you want? yau", + "PADDED_8": "Who are you? what do you want?", + "EXTRACTED_INIT_BOX": "Who are you? what do you want?", + "PADDED_4_EXTRACTED": "Who are you? what do you want?", + "PADDED_8_EXTRACTED": "Who are you? what do you want?", + "PADDED_8_DILATION_1": "Who are you? what do you want?", + "PAD_8_FRACT_0_5": "Who are you? what do you want?", + "PAD_8_FRACT_0_2": "Who are you? what do you want?" + }, + "2": { + "INITIAL_BOX": "I want to see professor blutress. the agency sent me.", + "DEFAULT": "I want to see ; professor blutress. the agency sent me.", + "DEFAULT_GREY_PAD": "I want to see professor blutress. the agency sent me.", + "PADDED_4": "| i want to see professor . blutress. the agency sent me.", + "PADDED_8": ") i want to see ~ professor - blutress. the agency sent me.", + "EXTRACTED_INIT_BOX": "1 want to see professor blutress. the agency sent me.", + "PADDED_4_EXTRACTED": "1 want to see professor blutress. the agency sent me.", + "PADDED_8_EXTRACTED": "1 want to see professor blutress. the agency sent me.", + "PADDED_8_DILATION_1": "I want to see professor blutress. the agency sent me.", + "PAD_8_FRACT_0_5": "1 want to see professor blutress. the agency sent me.", + "PAD_8_FRACT_0_2": "I want to see professor blutress. the agency sent me." + }, + "3": { + "INITIAL_BOX": "Oh, yes. you must be the secretary i sent for. i'm professor blutress rr come in. come in.", + "DEFAULT": "Oh,yes. you must be the secretary i sent for. i'm professor blutress-\u2014 rr come in. come in. <3)", + "DEFAULT_GREY_PAD": "Oh, yes. you must be the secretary i sent for. i'm professor blutress=-\u2014 come in. come in. j", + "PADDED_4": "Oh, yes. you must be the secretary i sent for. i'm professor blutress=-~\u2014 rr come in. come in. za", + "PADDED_8": "Oh,yes. you must be the secretary 1 sent for. i'm professor blutress=-~\u2014 by come in. come in. od", + "EXTRACTED_INIT_BOX": "Oh, yes. you must 8e the secretary 1 sent for, i'm professor blutress-~~\u2014 gome in, come in.", + "PADDED_4_EXTRACTED": "Oh, yes. you must be the secretary 1 sent for, i'm professor blutress-~~\u2014 come in. come in.", + "PADDED_8_EXTRACTED": "Oh, yes. you must be the secretary 1 sent for, i'm professor blutress-~~\u2014 come in. come in.", + "PADDED_8_DILATION_1": "Oh,yes. you must be the secretary 1 sent for. i'm professor blutress=-\u2014 come in. come in.", + "PAD_8_FRACT_0_5": "Oh, yes. you must be the secretary 1 sent for, i'm professor blutress-~\u2014 come in. come in.", + "PAD_8_FRACT_0_2": "Oh, yes. you must be the secretary 1 sent for, i'm professor blutress~~- come in. come in." + }, + "4": { + "INITIAL_BOX": "\u00a38 we entered the pro- fessor's study an unearthly. scream came from the dark recesses of the house.", + "DEFAULT": "As we entered the pro- fessor's study an unearthly. scream came from the dark recesses of the house...", + "DEFAULT_GREY_PAD": "We red 0- or's y an earthly. scream me from e dark esses of the house.", + "PADDED_4": "As we entered the pro- fessor's study an unearthly. scream ame from the dark recesses of the house...", + "PADDED_8": "As we entered the pro- fessor's study an unearthly, scream came from the dark | recesses of the house...", + "EXTRACTED_INIT_BOX": "Re rom e ark ecesses of e house.", + "PADDED_4_EXTRACTED": "Re rom e ark ecesses of e house.", + "PADDED_8_EXTRACTED": "Re rom e ark ecesses of e house.", + "PADDED_8_DILATION_1": "Re rom e ark ecesses of e house.", + "PAD_8_FRACT_0_5": "Re rom e ark ecesses of e house.", + "PAD_8_FRACT_0_2": "Re rom e ark ecesses of e house." + }, + "5": { + "INITIAL_BOX": "Good lord! what was that? it sounded\" like a scream!", + "DEFAULT": "Good lord! what was that? it sounded\u2122 like a scream!", + "DEFAULT_GREY_PAD": "Good lord! what was that? it sounded\u2122 like a scream!", + "PADDED_4": "Good lord! what was that? it sounded\u2122 like a scream!", + "PADDED_8": "Tr tw a yttyy ttt 00d lord! what was that? it sounded\" k ream! like a scream", + "EXTRACTED_INIT_BOX": "Good lord! what was that? it sounded\" like a scream!", + "PADDED_4_EXTRACTED": "Good lord! what was that? it sounded like a scream!", + "PADDED_8_EXTRACTED": "Good lord! what was that? it sounded like a scream!", + "PADDED_8_DILATION_1": "Good lord! what was that? it sounded like a scream", + "PAD_8_FRACT_0_5": "Good lord! what was that? it sounded like a scream!", + "PAD_8_FRACT_0_2": "Good lord! what was that? it sounded like a scream!" + }, + "6": { + "INITIAL_BOX": "A scream? i heard nothing, mr. howe.", + "DEFAULT": "\"sh scream? i heard | nothing, mr. howe.", + "DEFAULT_GREY_PAD": "A | creas i heard nothing, mr. howe.", + "PADDED_4": "A scream? i heard nothing, mr. howe.", + "PADDED_8": "A scream? i heard nothing, mr. howe.", + "EXTRACTED_INIT_BOX": "A scream? i heard nothing, mr. howe.", + "PADDED_4_EXTRACTED": "A scream? i heard nothing, mr. howe.", + "PADDED_8_EXTRACTED": "A scream? i heard nothing, mr. howe.", + "PADDED_8_DILATION_1": "A scream? i heard nothing, mr. howe.", + "PAD_8_FRACT_0_5": "A scream? i heard nothing, mr. howe.", + "PAD_8_FRACT_0_2": "A scream? i heard nothing, mr. howe." + }, + "7": { + "INITIAL_BOX": "1 could have sworn -- perhaps it was just my imagination.", + "DEFAULT": "1 could have sworn-- \u2018perhaps it was just my imagination.", + "DEFAULT_GREY_PAD": "1 could have sworn -- \u2018perhaps it was just my imagination. t(", + "PADDED_4": "1 could\u2019 have sworn-- perhaps it was just my imagination.", + "PADDED_8": "1 could have sworn-- perhaps it was just my imagination.", + "EXTRACTED_INIT_BOX": "1 could: have sworn-- perhaps it was just my imagination. ti", + "PADDED_4_EXTRACTED": "1 could have sworn-- perhaps it was just my imagination. tc", + "PADDED_8_EXTRACTED": "1 could\" have sworn-- perhaps it was just my imagination. 0", + "PADDED_8_DILATION_1": "I could: have sworn-- perhaps it was just my imagination. to", + "PAD_8_FRACT_0_5": "1 could\" have sworn-- perhaps it was just my imagination. 0", + "PAD_8_FRACT_0_2": "1 could\" have sworn-- perhaps it was just my imagination. 0" + }, + "8": { + "INITIAL_BOX": "You are tired. st let me take you 0 your room. we'll discuss your duties in the morning...come...", + "DEFAULT": "In you are tired. st j/let me take you 0 your room. we'll discuss your duties in the morning. ..come... |", + "DEFAULT_GREY_PAD": "- you are tired. st let me take you to your room. we'll discuss your duties in the morning...come...", + "PADDED_4": "In you are tired. st let me take you 0 your room. we'll discuss your duties in the morning. ..come...", + "PADDED_8": "Rn == you are tired. st j=/let me take you 0 your room. we'll discuss your duties in the morning. ..come...", + "EXTRACTED_INIT_BOX": "N-\u2014 you are tired. st let me take you to your room. we'll discuss your duties in the morning. ..come...", + "PADDED_4_EXTRACTED": "In -- you are tired. st let me take you to your room. we'll discuss your duties in the morning. ..come...", + "PADDED_8_EXTRACTED": "Rn = \u2014 you are tired. st let me take you to your room. we'll discuss your duties in the morning. . . come...", + "PADDED_8_DILATION_1": "Rn == you are tired. st let me take you to your room. we'll discuss your duties in the morning. . .come...", + "PAD_8_FRACT_0_5": "Rn == you are tired. st let me take you to your room. we'll discuss your duties in the morning. . . come...", + "PAD_8_FRACT_0_2": "Rn == you are tired. st let me take you to your room. we'll discuss your duties in the morning me..." + }, + "9": { + "INITIAL_BOX": "1 he next morning 1 awoke early and started downstairs. on the way down i passed a heavy barred door.", + "DEFAULT": "1 he next morning i awoke early and started downstairs. on the way down 1 passed a heavy barred door...", + "DEFAULT_GREY_PAD": "The next morning i awoke early and started downstairs. on the way down i passed a heavy barred door ...", + "PADDED_4": "He ne ng il awoke early and started nstal \u201con the way down i passed a eavy barred do!", + "PADDED_8": "He next morning il awoke early and started ownstairs. on the way down i passed a heavy barred door ...", + "EXTRACTED_INIT_BOX": "Morning e early and started downstairs. on the way down 1 passed a heavy barred doc", + "PADDED_4_EXTRACTED": "Morning e early and started downstairs. on the way down 1 passed a heavy barred doo", + "PADDED_8_EXTRACTED": "Morning e early and started downstairs. on the way down 1 passed a heavy barred doo", + "PADDED_8_DILATION_1": "Morning e early and started downstairs. on the way down i passed a heavy barred doo", + "PAD_8_FRACT_0_5": "Morning e early and started downstairs. on the way down 1 passed a heavy 8arred doo", + "PAD_8_FRACT_0_2": "Morning e early and started downstairs, on the way down 1 passed a heavy 8arred doo" + }, + "10": { + "INITIAL_BOX": "Uek/ it's awful...", + "DEFAULT": "Ugh! it's awful...", + "DEFAULT_GREY_PAD": "Ugh! it's awful...", + "PADDED_4": "Ugh! it's awful...", + "PADDED_8": "Ugh! it's awful...", + "EXTRACTED_INIT_BOX": "Uek/ t's awful...", + "PADDED_4_EXTRACTED": "Ueh? it's awful...", + "PADDED_8_EXTRACTED": "Ueh? it's awful...", + "PADDED_8_DILATION_1": "Ueh! it's awful...", + "PAD_8_FRACT_0_5": "Ueh?! it's awful...", + "PAD_8_FRACT_0_2": "Ueh? it's awful..." + }, + "11": { + "INITIAL_BOX": "That's,strange/ i | wonder what's behind it? it's thick enough to be a vault. \u201c&", + "DEFAULT": "That's.strange/ i j wonder what's behind it? it's thick enough to be a vault. \u201c4", + "DEFAULT_GREY_PAD": "That's.strangez i 1 wonder what's behind it? it's thick enough to be a vault. 4", + "PADDED_4": "That's.strange/ i} wonder what's behind it? it's thick enough to be a vault. \u201chd", + "PADDED_8": "That's,strange / tl wonder what's behind it? it's thick enough to be a vault.", + "EXTRACTED_INIT_BOX": "That's..strange / tl wonder what's behind it? it's thick enough to be a vault.", + "PADDED_4_EXTRACTED": "That's..strange / tl wonder what's behind it? it's thick enough to be a vault.", + "PADDED_8_EXTRACTED": "That's..strange / tl wonder what's behind it? it's thick enough to be a vault.", + "PADDED_8_DILATION_1": "That's.strange 7 i wonder what's behind it? it's thick enough to be a vault.", + "PAD_8_FRACT_0_5": "That's..strange / tl wonder what's behind itz it's thick enough to be a vault.", + "PAD_8_FRACT_0_2": "That's..strange / tl wonder what's behind itz it's thick enough to be a vault." + }, + "12": { + "INITIAL_BOX": "Supbenty i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "DEFAULT": "Subpenly i became aware of a frightful odor that | seemed to come from behind the | door. the | nauseating stench of decayed, rotting flesh...", + "DEFAULT_GREY_PAD": "Subbenly dthe nauseating stench of decaye| rotti flesh", + "PADDED_4": "A frightful ddor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_8": "A frightful odor that seemed to | come from behind the door. the nauseating stench of decayed, rotting flesh...", + "EXTRACTED_INIT_BOX": "Supoenwy i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_4_EXTRACTED": "Supoenwy i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_8_EXTRACTED": "Supoenwy i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PADDED_8_DILATION_1": "Suopeniy aware of a frightful odor that seemed to come from bewind the door. the nauseating stench of decayed, rotting flesh...", + "PAD_8_FRACT_0_5": "Suppenwy i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh...", + "PAD_8_FRACT_0_2": "Suppenwy i became aware of a frightful odor that seemed to come from behind the door. the nauseating stench of decayed, rotting flesh..." + } + }, + "Galactus_12.jpg": { + "1": { + "DEFAULT": "Vy nova is ny here, o master. i have heard your call and. stand ready to po your h bidding. a", + "INITIAL_BOX": "/'_nova is here, o master. i have heard your call and. sas \\ bidding.", + "DEFAULT_GREY_PAD": "Nova is here, o master. i have heard your call and. stand ready to| 70 your bidding.", + "PADDED_4": "Nova is here, \u00a9 maste! i have heard your call and. stand ready to po your bh 3(dding.", + "PADDED_8": "Nova is here, o master. i have heard your call and. stand ready to ww your wi", + "EXTRACTED_INIT_BOX": "Nova is here, o master. i have heard your call and. stand ready to po your bidding.", + "PADDED_4_EXTRACTED": "Nova 1s here, o master. i have heard your call and. stand ready to po your bidding.", + "PADDED_8_EXTRACTED": "Nova 1s here, o master. i have heard your call and. stand ready to po your bidding.", + "PADDED_8_DILATION_1": "Nova is here, o master. 70 your bidding.", + "PAD_8_FRACT_0_5": "Nova 1s here, o master. i have heard your call and. stand ready to 70 your bidding.", + "PAD_8_FRACT_0_2": "Nova 1s here, o master. i have heard your call and. stand ready to 70 your bidding." + }, + "0": { + "INITIAL_BOX": "Anz he /5 galactus", + "DEFAULT": "Anp he [5 galactus.", + "DEFAULT_GREY_PAD": "Ano he 2 | gacacrus|", + "PADDED_4": "V2 he /: | gacactus.", + "PADDED_8": "And he [5 galactus.", + "EXTRACTED_INIT_BOX": "Ani he 15 galactus", + "PADDED_4_EXTRACTED": "Ant he [3 galactus", + "PADDED_8_EXTRACTED": "Anp he [5 galactus", + "PADDED_8_DILATION_1": "And he 15 galacrus", + "PAD_8_FRACT_0_5": "And he [5 galactus", + "PAD_8_FRACT_0_2": "And he 15 gacacrus" + }, + "2": { + "INITIAL_BOX": "Devourer of worlds | harbinger of ultimate doom! hi\u00a7 manlike for roy i ancire fa", + "DEFAULT": "Evourer of worlds | harbing! tea ree soom mncie foxit 15 only in her eyes. pum", + "DEFAULT_GREY_PAD": "Devourer of worlds ! harbinger of ultimate doom! i$ manlike form 5 only in her eyes. pom", + "PADDED_4": "Devourer of worlds | harbinger of ultimate doom! 15 manlike form 15 only in her eye: -", + "PADDED_8": "Devourer of worlds ! harbinger of ultimate doom! 41 manlike form 75 only in her eyes.", + "EXTRACTED_INIT_BOX": "Pevourer of worlds ' harbinger of ultimate pom 41s manlike form 75 only in her eyes.", + "PADDED_4_EXTRACTED": "Pevourer of worlds * harbinger of lltimate doom! hi3 manlike form 75 only in her eyes.", + "PADDED_8_EXTRACTED": "Pevourer of worlds | harbinger of lltimate doom! hi3 manlike form 15 only in her eyes.", + "PADDED_8_DILATION_1": "Devourer of worlds | harbinger of ultimate doom ! his manlike form 15 only in her eyes.", + "PAD_8_FRACT_0_5": "Devourer of worlds | harbinger of ultimate doom! wiz manlike form 75 only in her eyes.", + "PAD_8_FRACT_0_2": "Devourer of worlds | harbinger of lltimate doom his manlike form 5 only in her eyes." + }, + "3": { + "INITIAL_BOX": "Cor his true shape 15 unguessed and unguess- able. he isa living r= ab ct 2 air ror. [", + "DEFAULT": "For his true shape 15 unguessed and ungles: able. he 15 a living. force of nature.", + "DEFAULT_GREY_PAD": "Rue shape 5 unslessel and uncles 754 living zowce of narure [tt]", + "PADDED_4": "Shape 15 | unglessed and ungless~ able. he 5 a living ae de nar. [tt", + "PADDED_8": "For his true shape 15 unguessed and ungless able. he 54 living i force of nature.", + "EXTRACTED_INIT_BOX": "For his true shape [5 unglessed and unguess* able. he 15.1 livag. force of nature.", + "PADDED_4_EXTRACTED": "For his true shape [5 unglessed and unguess~ able. he 51 livag. force of natur!", + "PADDED_8_EXTRACTED": "For h1s, true shape [5 unglessed and unguess~ able. he 51 livag. force of natur", + "PADDED_8_DILATION_1": "For his, true shape [5 unguessed and unguess* able. he 15 living. force of nature.", + "PAD_8_FRACT_0_5": "For his, true shape 5 unglessed and unguess* able. he 151 liviag. force of natur", + "PAD_8_FRACT_0_2": "For his, true shape 15 unglessed and unguess* able. he 15 living. force of natur" + }, + "4": { + "INITIAL_BOX": "Then heed well my words, most loyal of ny heralds. 4", + "DEFAULT": "\" then heed _ \\ well my words, most loyal of \u201cmy heralds, 4", + "DEFAULT_GREY_PAD": "Then heed well my words, most loyal of my heralds.", + "PADDED_4": "7 then heed well my words, most loyal of my heralds, a", + "PADDED_8": "Then heed well my words, most loyal of \\ my heralds.", + "EXTRACTED_INIT_BOX": "Then heed well my words most loyal of \u2018my heralds.", + "PADDED_4_EXTRACTED": "Then heed well my words, most loyal of my heralds,", + "PADDED_8_EXTRACTED": "Then heed well my words, most loyal of my heralds,", + "PADDED_8_DILATION_1": "Then heed well my words, most loyal of my heralds,", + "PAD_8_FRACT_0_5": "Then heed well my words, most loyal of my heralds,", + "PAD_8_FRACT_0_2": "Then heed well my words, most loyal of my heralds," + }, + "5": { + "INITIAL_BOX": "Y the shatterep galaxy from which you have returned is not unique! the long range scanners with: in this ship detect a vast procession of such destruction: reaching haleway across the universe.", + "DEFAULT": "P_ the shattered galaxy from which you have returned 15 not unique! the long range scanners with- in this ship detect a vast procession of such destruction: reaching haleway across the universe.", + "DEFAULT_GREY_PAD": "The shattered galaxy from which you have returned 15 not unique! the long range scanners with in this ship detect a vast procession of \u2018such destruction: l reaching halfway across the \u201cuniverse.", + "PADDED_4": "Y. the shattered galaxy from which you have returned 15 not unique! the long range scanners with- in this ship detect a vast procession of such destruction: reaching haleway across the i \u201cuniverse.", + "PADDED_8": "E shattered galaxy from which voliss you have returned 15 not unique the long range scanners with- in this ship detect a vast procession of such destruction: reaching halfway. across the i universe", + "EXTRACTED_INIT_BOX": "The shattered galaxy from which you have returned 1s not unique the long range_scanners with in th \u00a7 ship detect a vast procession of \u2018such destruction: reaching halfway across the universe...", + "PADDED_4_EXTRACTED": "The shattered galaxy from which you have returned 15 not unique the long range scanners with- in th \u00a7 ship detect a vast procession of \u2018such destruction: reaching halfway across the universe.", + "PADDED_8_EXTRACTED": "The shattered galaxy from which you have returned 15 not unique the long range_scanners with- in th \u00a7 ship detect a vast procession of \u2018such destruction: reaching halfway across the universe.", + "PADDED_8_DILATION_1": "The shattered galaxy from which you have returned 16 not unique! the long range scanners with- in th \u00a7 ship petect a vast procession of such destruction: reaching haleway across the universe.", + "PAD_8_FRACT_0_5": "The shattered galaxy from which you have returned 15 not unique the long range_scanners with- in th \u00a7 ship detect a vast procession of \u2018such destruction: reaching halfway across the universe.", + "PAD_8_FRACT_0_2": "The shattered galaxy from which you have returned 15 not unique the long range_scanners with- in th \u00a7 ship detect a vast procession of such destruction: reaching halfway across the universe." + }, + "6": { + "INITIAL_BOX": "The last galactus story con", + "DEFAULT": "The last galactus story con", + "DEFAULT_GREY_PAD": "The last galactus story conl", + "PADDED_4": "The last galactus story con", + "PADDED_8": "The last galactus story cont", + "EXTRACTED_INIT_BOX": "The ast galactus story con", + "PADDED_4_EXTRACTED": "The last galactus story con", + "PADDED_8_EXTRACTED": "The last galactus story cont", + "PADDED_8_DILATION_1": "The last galactus story cont", + "PAD_8_FRACT_0_5": "The last galactus story cont", + "PAD_8_FRACT_0_2": "The last galactus story cont" + }, + "7": { + "INITIAL_BOX": "It begins an near te point of universal. srigin, and envs at sra ptefarts rl fone", + "DEFAULT": "It begins, quite near the point of universal. origin, and ends at sour long since departed former a\" home.", + "DEFAULT_GREY_PAD": "It begins, quite near the, point of universal. origin, and ends a sour long since departed former ome. /", + "PADDED_4": "It begins y quite near the point of universal. origin, and ends at sour long since | departed former home,", + "PADDED_8": "It begins \\ quite near the point of universal. origin, and ends at sour long since departed former home.", + "EXTRACTED_INIT_BOX": "It begins quite near the point of universal origin, and ends at sour long since departed former home", + "PADDED_4_EXTRACTED": "It begins quite near the point of universal origin, and enus at sour long since departed former home", + "PADDED_8_EXTRACTED": "It begins quite near the point of universal origin, and enus at sour long since departed former home", + "PADDED_8_DILATION_1": "It begins, quite near the, point of universal. origin) and ends at your long since departed former home", + "PAD_8_FRACT_0_5": "It begins quite near the point of universal origin, and ends at sour long since departed former home", + "PAD_8_FRACT_0_2": "It begins quite near the point of universal origin, and ends at sour long since departed former home" + }, + "8": { + "INITIAL_BOX": "| the galaxy men once called the milky aay?", + "DEFAULT": "\u201d the galaxy _ men once called the milky to 4", + "DEFAULT_GREY_PAD": "The galaxy. en once called) the milky 77374", + "PADDED_4": "P the galaxy men once called the milky i all", + "PADDED_8": "Y the galaxy. men once called the milky way?", + "EXTRACTED_INIT_BOX": "The galaxy men once called the milky way\u201d", + "PADDED_4_EXTRACTED": "The galaxy men once called the milky nay?", + "PADDED_8_EXTRACTED": "The galaxy men once called the milky way?", + "PADDED_8_DILATION_1": "The galaxy. men once called the milky way?", + "PAD_8_FRACT_0_5": "The galaxy. men once called the milky way?", + "PAD_8_FRACT_0_2": "The galaxy. men once called the milky way?" + }, + "9": { + "INITIAL_BOX": "Es next issu", + "DEFAULT": "Ies next issu", + "DEFAULT_GREY_PAD": "Es next 55", + "PADDED_4": "Jes next issu|", + "PADDED_8": "Ues next issue", + "EXTRACTED_INIT_BOX": "Es next i1s5lu", + "PADDED_4_EXTRACTED": "Jes next is5u", + "PADDED_8_EXTRACTED": "Ues next is5u", + "PADDED_8_DILATION_1": "Ues next issu", + "PAD_8_FRACT_0_5": "Ues next is5u", + "PAD_8_FRACT_0_2": "Ues next issu" + } + }, + "INOUE_KYOUMEN_002.png": { + "1": { + "DEFAULT": "\u4f8d\u3063\u3066!", + "INITIAL_BOX": "\u306d\u3048\u3049 \u7afa\u3063\u3066!", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "\u4f8d\u3063\u3066!", + "PADDED_8": "\u5f85\u3063\u3066!", + "EXTRACTED_INIT_BOX": "\u306d\u3048\u3049 \u7afa\u3063\u3066!", + "PADDED_4_EXTRACTED": "\u4eba\u7afa\u3063\u3066!", + "PADDED_8_EXTRACTED": "\u4f8d\u3063\u3066!", + "PADDED_8_DILATION_1": "\u4f8d\u3063\u3066!", + "PAD_8_FRACT_0_5": "\u7afa\u3063\u3066!", + "PAD_8_FRACT_0_2": "\u4f8d\u3063\u3066!" + }, + "0": { + "INITIAL_BOX": "", + "DEFAULT": "\u7483\u3005\u4f9d!", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "\u7483\u3005\u4f9d!", + "PADDED_8": "\u7483\u3005\u4f9d!", + "EXTRACTED_INIT_BOX": "", + "PADDED_4_EXTRACTED": "\u7483\u3005\u4f9d!", + "PADDED_8_EXTRACTED": "\u7483\u3005\u4f9d!", + "PADDED_8_DILATION_1": "\u7483\u3005\u4f9d!", + "PAD_8_FRACT_0_5": "\u7483\u3005\u4f9d!", + "PAD_8_FRACT_0_2": "\u7483\u3005\u4f9d!" + }, + "2": { + "INITIAL_BOX": "", + "DEFAULT": "\u6591\u3005\u4f9d\u3063\u3066\u3070!", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "\u7483\u3005\u4f9d\u3063\u3066\u3070!", + "PADDED_8": "\u7409\u3005\u4f9d\u3063\u3066\u3070!", + "EXTRACTED_INIT_BOX": "", + "PADDED_4_EXTRACTED": "\u7409\u3005\u4f9d\u3063\u3066\u3070!", + "PADDED_8_EXTRACTED": "\u7409\u3005\u4f9d\u3063\u3066\u3070!", + "PADDED_8_DILATION_1": "\u7409\u3005\u4f9d\u3063\u3066\u3070!", + "PAD_8_FRACT_0_5": "\u7389\u3005\u4f9d\u3063\u3066\u3070!", + "PAD_8_FRACT_0_2": "\u7409\u3005\u4f9d\u3063\u3066\u3070!" + }, + "3": { + "INITIAL_BOX": "\u7267 \u540c\u300c \u4e86\u7389\u3005\u4f9d", + "DEFAULT": "\u82ad \u9593 \u5dfe \u516d", + "DEFAULT_GREY_PAD": "|\u6539\u8036\u7d20\u3005\u4f9d|", + "PADDED_4": "\u7267\u8036\u7483\u3005\u4f9d", + "PADDED_8": "\u82ad \u764c \u5d17 - \u3044 )", + "EXTRACTED_INIT_BOX": "\u7267 \u540c\u300c \u7483\u3005\u4f9d", + "PADDED_4_EXTRACTED": "\u7267\u8036\u7483\u3005\u4f9d", + "PADDED_8_EXTRACTED": "\u64ec\u4e5f\u7389\u3005\u4f9d", + "PADDED_8_DILATION_1": "\u64ec\u601d\u6591\u3005\u4f9d", + "PAD_8_FRACT_0_5": "\u7af6 \u3044 )", + "PAD_8_FRACT_0_2": "\u64ec\u6065\u6591\u3005\u4f9d" + }, + "4": { + "INITIAL_BOX": "", + "DEFAULT": "\u6e5b \u8cdc \u978d \u5e9c \u758f", + "DEFAULT_GREY_PAD": "\u8fc2 \u4e92 \u56e0", + "PADDED_4": "\u66d9", + "PADDED_8": "\u8449 \u8ca1 \u8ecb \u3044 - \u8a69", + "EXTRACTED_INIT_BOX": "", + "PADDED_4_EXTRACTED": "\u7531", + "PADDED_8_EXTRACTED": "\u7267\u597d\u697c\u3005\u4f9d", + "PADDED_8_DILATION_1": "\u7267\u8036\u697c\u3005\u4f9d", + "PAD_8_FRACT_0_5": "\u7267\u4e86\u5c0b\u697c\u3005\u4f9d", + "PAD_8_FRACT_0_2": "\u7267\u4e86\u5c0b\u697c\u3005\u4f9d" + }, + "5": { + "INITIAL_BOX": "\u8457", + "DEFAULT": "\u4e09 9", + "DEFAULT_GREY_PAD": "\u307a\u2471", + "PADDED_4": "\u3042", + "PADDED_8": "- 9", + "EXTRACTED_INIT_BOX": "\u304a", + "PADDED_4_EXTRACTED": "\u5de7", + "PADDED_8_EXTRACTED": ") 9", + "PADDED_8_DILATION_1": ") \u30fb9", + "PAD_8_FRACT_0_5": ") 9", + "PAD_8_FRACT_0_2": ") 9" + }, + "6": { + "INITIAL_BOX": "-]", + "DEFAULT": "\u3008\u246am", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "\u8070\u2048", + "PADDED_8": ") \u3008\u300f", + "EXTRACTED_INIT_BOX": ")", + "PADDED_4_EXTRACTED": ") \u3008\u3078\u246am", + "PADDED_8_EXTRACTED": ") \u3008m", + "PADDED_8_DILATION_1": ") \u3008m", + "PAD_8_FRACT_0_5": ") \u3008m\u300fm", + "PAD_8_FRACT_0_2": ") \u3008m" + }, + "7": { + "INITIAL_BOX": "\u4e00\u8247\u306b\u6620\u3089\u308d\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3046\u306e?", + "DEFAULT": "\u4e00\u7dd2\u306b\u5e30\u3089\u308d\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3083\u3046\u306e?", + "DEFAULT_GREY_PAD": "\u4e00\u507d\u306b\u5e30\u3089\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3045\u306e-", + "PADDED_4": "\u4e00\u7dd2\u306b\u5e30\u3089\u308d\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3046\u306e?", + "PADDED_8": "\u4e00\u7dd2\u306b\u5e30\u3089\u308d\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3046\u306e?", + "EXTRACTED_INIT_BOX": "\u4e00\u707d\u306b\u5cf0\u3089\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3083\u3046\u306e?", + "PADDED_4_EXTRACTED": "\u4e00\u7e6a\u306b\u5e33\u3089\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3083\u3085\u3046\u306e?", + "PADDED_8_EXTRACTED": "\u4e00\u7e6a\u306b\u5e33\u3089\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3083\u3085\u3046\u306e?", + "PADDED_8_DILATION_1": "\u4e00\u7dd2\u306b\u5e30\u3089\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3046\u306e?", + "PAD_8_FRACT_0_5": "\u4e00\u79cb\u306b\u65cf\u3089\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u4f55\u3067\u5148\u306b\u884c\u3063\u3061\u3083\u3085\u3083\u3046\u306e?", + "PAD_8_FRACT_0_2": "\u4e00\u7dd2\u306b\u5e30\u3089\u3046\u3063\u3066 \u8a00\u3063\u3066\u308b\u306e\u306b \u5e81\u3067\u5148\u306b\u884c\u3063\u3061\u3085\u3083\u3046\u306e?" + }, + "8": { + "INITIAL_BOX": "\u5c71 \u7b46 e \u4e86 \u51e7 u \u3044 > \u3085 \u30f0 \u3044 \u305f \u3085 \u3077 > w \u305b s8n", + "DEFAULT": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u652f\u5ea6\u3059\u308b\u306e \u5fc5\u3044\u3093\u3060\u3082\u3093", + "DEFAULT_GREY_PAD": "\u3054 \u4e86 \u5237 \u9ab8 \u534a \u3005 \u30f0 \u3044 \u305f \u3081 \u304b \u3089 | w \u305b s8n", + "PADDED_4": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u652f\u5ea6\u3059\u308b\u306e \u5fc5\u3044\u3093\u3060\u3082\u3093", + "PADDED_8": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u652f\u5ea6\u3059\u308b\u306e \u6027\u3044\u3093\u3060\u3082\u3093", + "EXTRACTED_INIT_BOX": "\u5d29 \u7fcc \u3054 \u4e86 \u3057 > \u3083 \u30c4 \u30f0 \u3044 \u305f \u3085 \u3044 \u309d \u3067 \u305b sn", + "PADDED_4_EXTRACTED": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u652f\u5ea6\u3059\u308b\u306e \u5fc5\u3044\u3093\u3060\u3082\u3093", + "PADDED_8_EXTRACTED": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u652f\u5ea6\u3059\u308b\u306e \u8b02\u3044\u3093\u3060\u3082\u3093", + "PADDED_8_DILATION_1": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u8b00\u5ea6\u3059\u308b\u306e \u9000\u3044\u3093\u3060\u3082\u3093", + "PAD_8_FRACT_0_5": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u8f09\u5ea6\u3059\u308b\u306e \u9000\u3044\u3093\u3060\u3082\u3093", + "PAD_8_FRACT_0_2": "\u3060\u3063\u3066\u30a2\u30f3\u30bf \u5409\u5ea6\u3059\u308b\u306e \u5c5e\u3044\u3093\u3060\u3082\u3093" + } + }, + "manga_0033.jpg": { + "1": { + "DEFAULT": "M \u3086 _ \u307f \u3081 \u306b \u30c8 - \u5a18 \u66fc 9 \u5982 \u5d50", + "INITIAL_BOX": "\u307f \u307f \u306b \u30c8 - ] \u30cb ] \u3053 \u300f \u4e16 \u3012", + "DEFAULT_GREY_PAD": "\u30eb _ \u30db \u306f \u307f \u306b \u3001", + "PADDED_4": "\u306b\u3044[ \u597d\u7f778\u98c4\u7531", + "PADDED_8": "\u306e\u306c_\u3088\u30c9\u307f\u3081 \u306b\u30c8- \u5373\u87ba9\u904e\u5d50", + "EXTRACTED_INIT_BOX": "\u307f \u30c3 \u306b \u3001 \u30c9 - ] \u30cb ] \u3053 \u300f \u4e16 \u3012", + "PADDED_4_EXTRACTED": "\u306b\u3044[. \u30b4\u30e0\u30df\u30cb\u30e5\u30ef\u203c", + "PADDED_8_EXTRACTED": "\u3043_ \u30c8\u30db\u30c9\u30c3 \u306b\u3001\u30c9- \u5b50\u87ba9\u904e\u5d50", + "PADDED_8_DILATION_1": "W\u30eb_\u30db\u30c9\u3085\u307f \u306b\u30c8\u30c9- \u5b50\u87ba9\u904e\u5d50", + "PAD_8_FRACT_0_5": "W\u3085_\u30db\u3085\u30c3 \u306b\u3001 -", + "PAD_8_FRACT_0_2": "M_\u307f\u307f \u8944\u4e0a\u8b02\u9084\u300d \u5373\u66d9b\u904e\u5d50" + }, + "0": { + "INITIAL_BOX": "\u6ce1\u308c\u306f\u3001 \u30de} \u4e0ap \u71b1\u306b\u3046\u304c\u3055\u308c\u305f\u7af6\u304b \u30b5\u30c8\u30eb\u30e2\u30ce [ \u307f\u306e\u3046\u308a\u2669\u3089\u306a \u300e\u9b5a\u6790\u8001\u306b\u306e\u9b91\u8a2a\u304b", + "DEFAULT": "\u7d42\u308c\u306f\u3001\u30fe= \u6cb3 \u71b1\u306b\u3046\u304c\u304b\u3055\u308c\u305f\u5922\u304b \u30b5\u30c8\u30eb\u30e2\u30ce [ \u307f\u306e\u3046\u308a\u2669\u3089\u306a \u300f\u9b91\u6790\u82b1\u300d\u306e\u614b\u8a18\u304b", + "DEFAULT_GREY_PAD": "\u300e\u9b5a\u6790\u82b1\u306b\u306e\u5f2f\u7576\u304b", + "PADDED_4": "\u9583\u308c\u306f\u3001\u30fe= \u5e9c\u306b\u3046\u304c\u3055\u308c\u305f\u5922\u304b \u30b5\u30c8\u30eb\u30e2\u30ce [ \u307f\u306e\u3046\u308a\u2669\u3089\u306a \u300e\u9b91\u6790\u82b1\u306e\u7d22\u304b", + "PADDED_8": "\u7435x\u3086\u306a\\}\u30ec[ \u4e0a \u8a69\u4ee3\u3046\u304c\u3055\u308c\u305f\u80cc\u304b \u30b5\u30c8\u30eb\u30e2\u30ce -\u904e\u6803\u82b1\u3042\u7d22\u60b6\u304b", + "EXTRACTED_INIT_BOX": "\u5149\u308c\u306f \u5305 \u8a3a\u306b\u3046\u304c\u3055\u308c\u305f\u534a\u304b \u30b5\u30c8\u30eb\u30e2\u30ce \u300e\u9b5a\u6790\u8001\u306b\u306e\u80fd\u8a2a\u304b", + "PADDED_4_EXTRACTED": "\u5149\u308c\u306f \u74b0 \u86ee\u3044\u3089\u304c\u3055\u308c\u305f\u7af6 \u300e\u89e3\u6790\u8005\u300f\u306e\u80fd\u529b\u304b", + "PADDED_8_EXTRACTED": "\u5149\u308c\u306f \u5305 \u8a3a\u9078\u3089\u304c\u3055\u308c\u305f\u5145\u304b \u30b5\u30c8\u30eb\u30e2\u30ce \u300e\u9b5a\u67cf\u8001\u306e\u5f2f\u60b6\u304b", + "PADDED_8_DILATION_1": "\u5149\u308c\u306f \u5305 \u8a1f\u306b\u306b\u3089\u304c\u3055\u308c\u305f\u5373\u304b \u30b5\u30c8\u30eb\u30e2\u30ce \u300e\u9b5a\u67cf\u8001\u306e\u5f2f\u60b6\u304b", + "PAD_8_FRACT_0_5": "\u53ea\u308c\u306f \u3001\u30c9y \u8a1f\u6c11\u3089\u304c\u3055\u308c\u305f\u554f\u304b \u300e\u89e3\u6790\u8005\u300f\u306e\u80fd\u529b\u304b", + "PAD_8_FRACT_0_2": "\u5149\u308c\u306f \u5305 \u8912\u306b\u3089\u304c\u3055\u308c\u305f\u7af6\u304b \u30b5\u30c8\u30eb\u30e2\u30f3\u30ce -\u6ccc\u6790\u82b1\u300d\u306e\u5f2f\u60b6\u304b" + }, + "2": { + "INITIAL_BOX": "\u704c \u9192 \u7403 \u4e5f \u5076 \u671b \u7fbd \u3076 \u3077 \u6cbf", + "DEFAULT": "\u704c \u4e0a \u66f2 \u2026 \u4eba es - \u671b \u7c97 \u3084 \u3089 \u62b1", + "DEFAULT_GREY_PAD": "\u56de \u3010 \u76f4 \u307f \u7d30 \u53e3 m \u4ea4 \u300f \u5448 \u59dc \u3002 \u5eab -", + "PADDED_4": "\u704c \u758f \u4f8d \u671b \u7fbd \u3076 \u3077 \u6cbf", + "PADDED_8": "\u704c \u7389 \u5016 \u2048 \u7fbd \u3076 \u3077 \u6cbf", + "EXTRACTED_INIT_BOX": "\u5f53 \u5e45 \u300c \u5bfa - w", + "PADDED_4_EXTRACTED": "\u5f53 \u5410 \u4ea1", + "PADDED_8_EXTRACTED": "", + "PADDED_8_DILATION_1": "- -\u4e0a\u62bc \u3068\u3089\u3068\u53d6\u6c60 :", + "PAD_8_FRACT_0_5": "", + "PAD_8_FRACT_0_2": "\u5442 \u6247 \u6709 \u5c0b - \u7fbd \u3076 \u307f \u6cb9 \u5411 \u4e86 \u307f" + }, + "3": { + "INITIAL_BOX": "\u6c34\u6e6f", + "DEFAULT": "\u3089 \u3076 s\u300f \u7b87 \u3085 \u4e86 \u6109", + "DEFAULT_GREY_PAD": "\u6d6a \u5bd3 \u6db8 * \u8a18 \u3002 \u4e9e \u8755 \u3044 )", + "PADDED_4": "\u7d2c \u7af6 \u4eba", + "PADDED_8": "\u300c\u203b\u6cb3 \u99d0\u61c7 \u89aa\u6065- \u4e09\u4ecb", + "EXTRACTED_INIT_BOX": "9\u3069\u92ea\u5473 - \u2661\u4e5d\u2470\u79df \u6b96\u30e8", + "PADDED_4_EXTRACTED": "\u306a 9\u3069\u6298\u59b9 0\u4e5d\u306e\u4e86 9\u30f0", + "PADDED_8_EXTRACTED": "\u6cf3 \u8b39 - \u4e0a \u300f \u7537 \u6709 \u3002 \u3044 s", + "PADDED_8_DILATION_1": "\u6cf3 \u8b39 - \u300f \u7537 \u6709 \u3002 \u3044 s", + "PAD_8_FRACT_0_5": "\u6d6a \u4e0a \u300fs \u6db8 * \u8a18 \u3044 \u3044 s", + "PAD_8_FRACT_0_2": "\u6cf3 \u8afe - \u4e0a \u300a \u821e \u309d \u6709 \u3044 s" + }, + "4": { + "INITIAL_BOX": "\u5712 \u6c50 \u5c71 \u87f9 \u6c57 \u8ab0 \u300c \u305f \u7576 \u9078 ]", + "DEFAULT": "\u8fc2 \u89d2 \u304a \u5c48 \u6de1 \u8ca0 \u306c \u300f", + "DEFAULT_GREY_PAD": "\u5929 \u89d2 \u6c57 \u5bfa \u3084 \u3089 \u6c5f \u6109 \u3044 \u660c \u8ac7 \u5c0f", + "PADDED_4": "\u8a08 \u304d \u2048 \u5c71 \u87f9 - \u3089 \u3085 \u3068 - \u7389", + "PADDED_8": "\u885d \u8096 \u5c71 \u89d2 \u6c41 \u5806 \u754c \u6cca \u77ed \u306b", + "EXTRACTED_INIT_BOX": "\u8cb7 \u4e0a \u9806 \u89d2 \u3058 \u3044 \u5348 \u660c \u5c0f \u30eb \u3069 -", + "PADDED_4_EXTRACTED": "\u8cb7 \u4e0a \u9806 \u89d2 \u8a08 \u3060 \u5348 \u660c - \u5c0f \u3001 \u30eb \u3068 -", + "PADDED_8_EXTRACTED": "\u8cb7 \u4e0a \u9806 \u89d2 \u3044 \u307f \u6c5f \u5f27 \u4ecf \u5348 \u660c \u5c0f - \u30eb b \u3068 < \u30df", + "PADDED_8_DILATION_1": "\u6c57 \u3078 \u9806 \u89d2 \u3084 \u307f \u6c5f \u78a7 \u4ecf \u885d \u660c \u5c0f \u30eb b \u305f < \u30df", + "PAD_8_FRACT_0_5": "\u5c71 \u87f9 \u3044 \u3084 \u307f \u6c5f \u78a7 \u4ecf \u8ab0 m \u3089 \u8b0e \u6cea \u66fe \u65e8 \u6642 \u300d", + "PAD_8_FRACT_0_2": "\u7d50 \u5929 \u89d2 \u3044 \u3081 \u307f \u6c5f \u78a7 \u4ecf \u3044 \u6109 \u660c \u203b \u5c60 \u66fe \u6642 \u300d" + }, + "5": { + "INITIAL_BOX": "\u6c57 s\u300f \u7531 \u3067 \u30f1 \u7576 \u51fa \u9632 \u5973", + "DEFAULT": "\u6cbb s \u5448 r \u3006 \u3041 \u5f18 \u2026 \u305b \u300c- \u3077 j \u3081 \u306c \u6ef4", + "DEFAULT_GREY_PAD": "\u6e6f s \u5687 r \u524d \u2026 \u305b \u3089 - - \u3081 \u6f23", + "PADDED_4": "S \u5687 r \u3057 \u8cbc \u7d05 o \u3081 \u704c", + "PADDED_8": "\u6c57 \u2026 s\u300f \u65cf \u300c \u4e8b \u2473 \u30fe \\", + "EXTRACTED_INIT_BOX": "S \u53f6 \u90ca \u3089 - \u8aa4", + "PADDED_4_EXTRACTED": "\u6cbf \u2026 s \u53f6 \u3089 - \u8aa4", + "PADDED_8_EXTRACTED": "\u6cbf \u2026 s \u53f6 \u90ca \u3089 - \u8aa4", + "PADDED_8_DILATION_1": "\u6cbf \u2026 s \u53f6 \u6bc5 \u3089 - \u8aa4", + "PAD_8_FRACT_0_5": "\u6e2c s \u53f6 \u524d \u2026 \u305b \u3089 - \u3085 \u4ed8", + "PAD_8_FRACT_0_2": "\u6cbf \u2026 s \u53f6 \u6b63 \u3089 \u300em \u6c11" + }, + "6": { + "INITIAL_BOX": "\u6e29 \u3091 - \u306b \u307a \u3092 \u3001. \u81e3", + "DEFAULT": "\u3092 \u3001 \u3057 ' \u845b \u81e3", + "DEFAULT_GREY_PAD": "\u6cb9 \u516d \u6ffe \u4ea4 \u4e2d \u3068 \u3058 \u845b", + "PADDED_4": "\u6e29 m \u4e2d s \u3089\u300f \u6ffe \u4ea4 \u4e2d \u845b \u5d4c \u3092 \u300d \u3057 .", + "PADDED_8": "\u6e29 m \u4e2d s \u3089\u300f \u6ffe \u4ea4 \u4e2d \u845b \u5d4c", + "EXTRACTED_INIT_BOX": "\u3057f6\u30eb\u30eb\u6e21\u3080\u6709 \u2026\u5c07-", + "PADDED_4_EXTRACTED": "\u305764\u30eb\u5165\u3080\u72d7 \u2026\u5c07-", + "PADDED_8_EXTRACTED": "\u305764\u30eb\u5165\u3080\u72d7 \u2026\u5c07-", + "PADDED_8_DILATION_1": "Fn\u5165\u3081\u5c3e \u2026\u4e86\u3044-", + "PAD_8_FRACT_0_5": "Fn\u5165\u3081\u72d7 \u2026\u6c93\u6539-", + "PAD_8_FRACT_0_2": "\u305764\u5165\u3081\u6027 \u2026\u5c07-" + }, + "7": { + "INITIAL_BOX": "\u5ddd\u641c\u3044\u8a08 \u540a \u54c1m\u305b\u5e45\u3067- \u74f6\u306f \u6fc0\u9598 \u3044", + "DEFAULT": "\u3044\u6539\u905c\u4ed9\u534a\u5bb0\u6cb9 , \u30ee\u3073\u3055\u304d\u3052\u306e\u3067 \u653e\u8cfc \u8ab0\u3089\u304a\u79cb\u3081", + "DEFAULT_GREY_PAD": "\u305b \u6628 \u3067 - \u65cf \u8868 \u533a \u9127 \u5fb9 \u8b39 m \u840e", + "PADDED_4": "| \u54e1 m \u305b \u62bc \u3067 \u8272 \u3001 \u7814 \u8ad6 \u9084 \u3011 \u3070 \u65cf \u8868 - \u4ee3 /", + "PADDED_8": "\u554f \u2026 \u305b \u7d66 - \u65cf \u8868 \u305f \u3079 \u3091 \u4eba \u3067 \u305f - \u5e83 \u6ecb \u92fc \u30dd \u59d3", + "EXTRACTED_INIT_BOX": "\u3044\u3044\u3048 \u3082\u3063\u3074\u3055\u3055\u3084\u304b\u3067 \u304f\u308b \u306bm \u8ab0\u306b\u3067\u3082\u3042\u308b\u3082\u306e", + "PADDED_4_EXTRACTED": "\u3044\u3044\u3048 \u3082\u3063\u3074\u3055\u3055\u3084\u304b\u3067 \u304f\u308b \u306bm \u8ab0\u306b\u3067\u3082\u3042\u308b\u3082\u306e", + "PADDED_8_EXTRACTED": "\u3044\u3044\u3048 \u3082\u3063\u3074\u3055\u3055\u3084\u304b\u3067 \u304f\u308b \u306bm \u8ab0\u306b\u3067\u3082\u3042\u308b\u3082\u306e", + "PADDED_8_DILATION_1": "\u3044\u3044 \u3082\u3063\u3069\u3055\u3055\u3084\u304b\u3067 \u840c\u610f \u306bm \u8ab0\u306b\u3067\u3082\u3042\u308b\u3082\u306e", + "PAD_8_FRACT_0_5": "\u3002 d\u3082\u3063\u304e\u3055\u3055\u3084\u304b\u3067 \u304f\u30a4\u308b\u3089\u3044\u3044 \u8ab0\u306b \u3067\u3082\u3042\u308b\u3082\u306e", + "PAD_8_FRACT_0_2": "\u3044\u3044\u305f\u3048\u305f \u3082\u3063\u3074\u3055\u3055\u3084\u304b\u3067 \u534a \u5317m \u8ab0\u306b\u3067\u3082\u3042\u308b\u3082\u306e" + }, + "8": { + "INITIAL_BOX": "\u8b5a \u828b", + "DEFAULT": "\u7537\u8ce3\u540d \u4e3b \u6065 \u5edf \\\u3049 \u3063\u5348\u6751 \u82ad \u79fb\u4e86", + "DEFAULT_GREY_PAD": "\u30fd - \u30f3 \u9078 \u4e5f - \u5302 \u4e16 \u963b \u8a55 \u758f -\u300b \u5448 \u5fdc \u3054 \u5eca \" \u306c", + "PADDED_4": "\u9675\u7d50 \u89d2 \u8ced \u9154 \u9769 \\\u3049 -\u4f3ce\u8868- \u7f77 \u3084\u4e16\u80af\u5abd", + "PADDED_8": "\u5858\u8a69 \u8ca0 \u7389 \u5de7 \u543e \u8863\u7389 \u306b\u3054\u786b\u306b\u3089", + "EXTRACTED_INIT_BOX": ": ] \u3076 \u30df \u3053 \u3054 \u30df", + "PADDED_4_EXTRACTED": ": ] \u30df", + "PADDED_8_EXTRACTED": ": \u309d - \u3001 \u81e8", + "PADDED_8_DILATION_1": "\u5713 \u500b \u904e p \u5e06 \u6c72 \u5c71", + "PAD_8_FRACT_0_5": "\u9091 \u66d9 \u309db", + "PAD_8_FRACT_0_2": "\u672b \u60b6s \u3002 \u52a0 \u52a0-o \u7e3d \u5713\u2661" + }, + "9": { + "INITIAL_BOX": "- \u6d6a \u3043 \u3044\u300f - \u9996 \" \u7531 \u8d74 \u7d04 \u300e[ \u8089 \u2661 \u5e06 \u9078 \u300d \u968a - \u81e3", + "DEFAULT": "- \u7c97 \u3043 \u30eb \u5eb6 \u6842 \u3081 \u304b \u300e \u3044 [ \u6c5f \u4e09 \u7ad9 \u7531 \u3068 \u300d \u5883 - \u97a0", + "DEFAULT_GREY_PAD": "\u5c07 \u958b \u3081 \u2048 \u8a60 \u88c5 \u5f04 \u4e2d \u300d \u9b31 \u4e16", + "PADDED_4": "\" \u75e2 m \u3081 \u304b \u738b \u4e2d \u5404 \u88c5 \u3068 \u300d \u306b \u3010 \u533a", + "PADDED_8": "\u7537 \u7c97 \u3043 \u9047 \u58ee \u4e0b \u3081 \u304b \u5c6f \u7afa \u9000 \u5e33 \u3068 \u306f \u8944 - \u57fa", + "EXTRACTED_INIT_BOX": "\u6f64 \u3043 m \u534a \u81e3 \u3081 \u8a18 \u8ad2 \u5944 \u9673 \u52a0 \u978d -", + "PADDED_4_EXTRACTED": "\u3043 \u3084 m \u534a \u81e3 \u3081 \u8a18 \u8ad2 \u5944 \u81ea \u91e3 \u978d -", + "PADDED_8_EXTRACTED": "M \u534a \u81e3 \u3081 \u8a18 \u8ad2 \u5944 \u6b63 \u9774 \u978d -", + "PADDED_8_DILATION_1": "M \u81e3 \u3081 \u6109 \u672d s \u6b63 \u53ea \u978d -", + "PAD_8_FRACT_0_5": "M \u534a \u81e3 \u3081 \u904e s \u81ea \u758f \u306b -", + "PAD_8_FRACT_0_2": "M \u5674 \u81e3 \u3081 m \u8b02 \u5e2b \u6b63 \u9d0e \u306b -" + }, + "10": { + "INITIAL_BOX": "1\u30fc\u305b\u3053\u3067 \u308c \u5148\u306f\u56db\u3092\u7576\u307e\u3059", + "DEFAULT": "\u30fc\u30c9\u3001 \u79c1\u306f\u76ee\u3092\u899a\u307e\u3059", + "DEFAULT_GREY_PAD": "\u7d2c \u82b1 \u8a63 \u7530 \u3077 \u624b \u3047 \u308d", + "PADDED_4": "\u5148\u306f\u76bf\u3092\u6f64\u307e\u3059", + "PADDED_8": "\u30fc| \u30fc\u3084\u305b\u30bc\u3053\u3067 \u8a33 \u5148\u306f\u56db\u3092\u6d63\u307e\u3059", + "EXTRACTED_INIT_BOX": "\u30fc\u30fc\u305b\u3053\u3067 \u5148\u306f\u5360\u3092\u7576\u307e\u3059", + "PADDED_4_EXTRACTED": "\u30fc\u305f \u5148\u306f\u56db\u3092\u6d63\u307e\u3059", + "PADDED_8_EXTRACTED": "\u30fc\u305f \u5148\u306f\u56db\u3092\u6d63\u307e\u3059", + "PADDED_8_DILATION_1": "\u30fc!\u3062\u3067 \u5148\u306f\u56db\u3092\u6d63\u307e\u3059", + "PAD_8_FRACT_0_5": "\u30fc!\u3062\u3055\u3067 \u5148\u306f\u76bf\u3092\u6d63\u307e\u3059", + "PAD_8_FRACT_0_2": "\u30fc\u788d!\u3062\u3067 \u5148\u306f\u56db\u3092\u6d63\u307e\u3059" + } + }, + "PIKE_BOYLOVEGIRLS_T41_012.jpg": { + "0": { + "INITIAL_BOX": "Curt! oh... i forgot we were going to play tennis!", + "DEFAULT": "Curt! oh... i forgot we were going to play . tennis!", + "DEFAULT_GREY_PAD": "Curt! oh... | i forgot we were going to play tennis!", + "PADDED_4": "Fet curt! oh... i forgot we were going to play \u00ab tennis!", + "PADDED_8": "Fom i errr pg ld curt! oh... i forgot we were going to play tennis! yy.", + "EXTRACTED_INIT_BOX": "Curt! oh... i forgot we were going to play tennis!", + "PADDED_4_EXTRACTED": "Curt! oh... i forgot we were going to play tennis!", + "PADDED_8_EXTRACTED": "Curt! oh... i forgot we were going to play tennis!", + "PADDED_8_DILATION_1": "Curt! oh... i forgot we were going to play tennis!", + "PAD_8_FRACT_0_5": "Curt! oh... i forgot we were going to play tennis!", + "PAD_8_FRACT_0_2": "Curt! oh... i forgot we were going to play tennis!" + }, + "1": { + "INITIAL_BOX": "Well ...okay, honey! i'd just as soon go for a drive, anyway!", + "DEFAULT": "Well ...okay, honey! i'd just as scon go for a drive, anyway! _.", + "DEFAULT_GREY_PAD": "Well ...okay,", + "PADDED_4": "Well ...okay, honey! i'd just as scon go for a drive, | _ anyway!", + "PADDED_8": "Ma i ts well ...okay, honey! i'd just as scon go for a drive, anyway!", + "EXTRACTED_INIT_BOX": "Well ...okay, honey! i'd just as soon go for a drive, anyway!", + "PADDED_4_EXTRACTED": "Well ...okay, honey! i'd just as soon go for a drive, anyway !", + "PADDED_8_EXTRACTED": "Well ...okay, honey! i'd just as soon go for a drive, anyway !", + "PADDED_8_DILATION_1": "Well...okay, honey! i'd just as scon go for a drive, anyway!", + "PAD_8_FRACT_0_5": "Well ...okay, honey! i'd just as scon go for a drive, anyway !", + "PAD_8_FRACT_0_2": "Well ...okay, honey! i'd just as scon go for a drive, anyway!" + }, + "2": { + "INITIAL_BOX": "1 was \u00a5 a bad mood, and curt sensed it immediately \u00ab+ -", + "DEFAULT": "1 was \u00a5 a bad mood, and curt sensed it immediately -\u00ab", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "1 was \u00a5 a bad mood, and curt sensed it immediately -- -", + "PADDED_8": "1 was \u00a5 a bad mood, and curt sensed it immediately -", + "EXTRACTED_INIT_BOX": "| was \u00a54 a bad mood, and curt sensed it immediately - + +", + "PADDED_4_EXTRACTED": "| was \u00a54 a bad mood, and curt sensed it immediately -- -", + "PADDED_8_EXTRACTED": "| was \u00a54 a bad mood, and curt sensed it immediately -- +", + "PADDED_8_DILATION_1": "1 was \u00a54 a bad mood, and curt sensed it immediately -\u00ab -", + "PAD_8_FRACT_0_5": "1 was \u00a5\u00a5 a bad mood, and curt sensed it immediately - -", + "PAD_8_FRACT_0_2": "| was \u00a54 a bad mood, and curt sensed it immediately -\u00ab -" + }, + "3": { + "INITIAL_BOX": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you harry! j", + "DEFAULT": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try _ and make you happy! jt", + "DEFAULT_GREY_PAD": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you happy!", + "PADDED_4": "\"you've seemed so unhappy. lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try \u00bb and make you happy! jt", + "PADDED_8": "Ne eee mt eu you've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try \u00ab_ and make you happy! jt", + "EXTRACTED_INIT_BOX": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you happy!", + "PADDED_4_EXTRACTED": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you happy!", + "PADDED_8_EXTRACTED": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you happy!", + "PADDED_8_DILATION_1": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you happy!", + "PAD_8_FRACT_0_5": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you happy!", + "PAD_8_FRACT_0_2": "You've seemed so unhappy lately, cynthy! i wish there was something 1 could do! 1 wish you'd let me try and make you happy!" + }, + "4": { + "INITIAL_BOX": "| knew what was coming, but | didn't want to give him an answer . . . not then.| tried to change the mood!", + "DEFAULT": "| knew what was coming, but | didn't want to give him an answer . . . not then.| tried to change the mood!", + "DEFAULT_GREY_PAD": "| knew what was coming, but i didn't want to give him an answer . . . not then.| tried to change the mood!", + "PADDED_4": "| knew what was coming, but | didn't want to give him an answer . . . not then.| tried to change the mood!", + "PADDED_8": "| knew what was coming, but | didn't want to give him an answer . . . not then.| tried to change the mood!", + "EXTRACTED_INIT_BOX": "| knew what was coming, but | didn't want to give him an answer . .. not then.i tried to change the mood!", + "PADDED_4_EXTRACTED": "| knew what was coming, but | didn't want to give him an answer . .. not then.i tried to change the mood!", + "PADDED_8_EXTRACTED": "| knew what was coming, but | didn't want to give him an answer . .. not then.i tried to change the mood!", + "PADDED_8_DILATION_1": "| knew what was coming, but | didn't want to give him an answer . . . not then.i tried to change the mood!", + "PAD_8_FRACT_0_5": "| knew what was coming, but 1 didn't want to give hiw an answer . .. not then.i tried to change the mood!", + "PAD_8_FRACT_0_2": "| knew what was coming, but | didn't want to give him an answer . . . not then.i tried to change the mood!" + }, + "5": { + "INITIAL_BOX": "Goodness, curt, you worry about me too much! c'mon, lets go nn. for a swim! _", + "DEFAULT": "Goodness, curt, you worry about me too much! c'mon, lets go nl. . for a swim!", + "DEFAULT_GREY_PAD": "Goodness, curt, you worry about me too! much! c'mon, lets go for a swim!", + "PADDED_4": "Goodness, curt, you worry about me too much! c'mon, lets go n\\ for a swim!", + "PADDED_8": "; a goodness, curt, you worry about me too much! c'mon, lets go for a swim! _~", + "EXTRACTED_INIT_BOX": "Goodness, curt, you worry about me too much! c'mon, lets go eor a swim!", + "PADDED_4_EXTRACTED": "Goodness, curt, you worry about me too much! c'mon, lets go for a swim!", + "PADDED_8_EXTRACTED": "Goodness, curt, you worry about me too much! c'mon, lets go for a swim!", + "PADDED_8_DILATION_1": "Goodness, curt, you worry about me too much! c'mon, lets go for a swim!", + "PAD_8_FRACT_0_5": "Goodness, curt, you worry about me too much! c'mon, lets go for a swim |", + "PAD_8_FRACT_0_2": "Goodness, curt, you worry about me too much! c'mon, lets go for a swim!" + }, + "6": { + "INITIAL_BOX": "| liked curt but \u00a7 didn't love hin, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+ + \u00ab not give in toit! later that evening, we dropped in at gloria's. everybody gathered at gloria\u2019s", + "DEFAULT": "| liked curt but \u00a7 didn't love hin, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+ + \u00ab not give in toit! later that evening, we dropped in at gloria's. everybody gathered at gloria's +", + "DEFAULT_GREY_PAD": "| liked curt but \u00a7 didn't love him; and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+ + \u00ab not give in toit! later that evening, we dropped in at gloria's. everybody gathered at gloria's +", + "PADDED_4": "| liked curt but \u00a7 didn't love hin, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+ + \u00ab not give in toit! later that evening, we dropped in at gloria's. everybody gathered at gloria's", + "PADDED_8": "| liked curt but \u00a7 didn't love hin, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+ + \u00ab not give in toit! later that evening, we dropped in at gloria's. everybody gathered at gloria's", + "EXTRACTED_INIT_BOX": "1 liked curt but \u00a7 didn't love him, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+. not give in to it! later that evening, we dropped in at gloria's. everybody gathered at gloria's", + "PADDED_4_EXTRACTED": "1 liked curt but \u00a7 didn't love him, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+. not give in to it! later that evening, we dropped in at gloria's. everybody gathered at gloria's", + "PADDED_8_EXTRACTED": "1 liked curt but \u00a7 didn't love him, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab+. not give in to it! later that evening, we dropped in at gloria's. everybody gathered at gloria's", + "PADDED_8_DILATION_1": "| liked curt but 1 didn't love him, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself ++. not give in to it! later that evening, we dropped in at gloria's. everybody gathered at gloria's", + "PAD_8_FRACT_0_5": "1 liked curt but \u00a7 didn't love him, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab++ not give in toit! later that evening, we dropped in at gloria's. everybody gathered at gloria's", + "PAD_8_FRACT_0_2": "1 liked curt but \u00a7 didn't love him, and | knew that marrying him would only be a surrender to my parents. | had to lick this \"problem myself \u00ab++ not give in toit! later that evening, we dropped in at gloria's. everybody gathered at gloria's" + }, + "7": { + "INITIAL_BOX": "Hl, kids! what's up?", + "DEFAULT": "Hi, kids! what's up?", + "DEFAULT_GREY_PAD": "Hi, kids! what's up?", + "PADDED_4": "Hi, kids! what's - up? a", + "PADDED_8": "Hi, kids! what's 2 pee", + "EXTRACTED_INIT_BOX": "Hl, kids! what's up?", + "PADDED_4_EXTRACTED": "Hl, kids! what's up?", + "PADDED_8_EXTRACTED": "Hi, kids! what's up?", + "PADDED_8_DILATION_1": "Hl, kids! what's up?", + "PAD_8_FRACT_0_5": "Hi, kids! what's up?", + "PAD_8_FRACT_0_2": "Hi, kids! what's up?" + }, + "8": { + "INITIAL_BOX": "Sparkling \u2018wit...brilliant conversation... penetrating thought...what did you en ie cte \u2014\u2014\u2014 ee,", + "DEFAULT": "Sparkling \u2018wit...brilliant conversation ... penetrating thought...what did you exe ct 2 e\u2014\u2014\u2014 mi", + "DEFAULT_GREY_PAD": "Sparkling wit...brilliant onversation ... penetrating! thought...what did you expect?", + "PADDED_4": "Sparkling /wit...brilliant conversation... penetrating thought...what did you re pecte a", + "PADDED_8": "Sparkling \u2018wit...brilliant conversation... penetrating thought...what did you . expect?", + "EXTRACTED_INIT_BOX": "Sparkling wit...brill'ant conversation... penetrating thought...what did you expectz", + "PADDED_4_EXTRACTED": "Sparkling wit...brill'ant conversation... penetrating thought...what did you expectz", + "PADDED_8_EXTRACTED": "Sparkling wit...brill'ant conversation... penetrating thought...what did you expectz", + "PADDED_8_DILATION_1": "Sparkling \u2018wit...brill'ant conversation... penetrating thought...what did you expect?", + "PAD_8_FRACT_0_5": "Sparkling ,wit...brill'ant conversation... penetrating thought...what did you expectz", + "PAD_8_FRACT_0_2": "Sparkling \u2018wit...brill'ant conversation... penetrating thought...what did you expect?" + }, + "9": { + "INITIAL_BOX": "He means it's the usual dull evening! _", + "DEFAULT": "He means its the usual dull evening! _", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "He means it's the usual dull evening |", + "PADDED_8": "He means it's the usual dull evening!", + "EXTRACTED_INIT_BOX": "He means its the usual dull evening!", + "PADDED_4_EXTRACTED": "He means its the usual dull evening !", + "PADDED_8_EXTRACTED": "He means its the usual dull evening!", + "PADDED_8_DILATION_1": "He means its the usual dull evening!", + "PAD_8_FRACT_0_5": "He means its the usual dull evening |", + "PAD_8_FRACT_0_2": "He means its the usual dull evening!" + }, + "10": { + "INITIAL_BOX": "My old man says im going to have to take that advertising job in new york! |", + "DEFAULT": "My old man svs im gong to have to take that advertising job in new york!", + "DEFAULT_GREY_PAD": "My old man says i'm going to have to take that advertising job in new york!", + "PADDED_4": "My old man says im gong to have to take that advertising job _ in new york!", + "PADDED_8": "\u201cmy old man say5 i'm going to have to take that advertising job in new york!", + "EXTRACTED_INIT_BOX": "My old man say5 i'm going to have to take that advertising job in new york!", + "PADDED_4_EXTRACTED": "My old man says i'm going to have to take that advertising job in new york!", + "PADDED_8_EXTRACTED": "My old man says i'm going to have to take that advertising job in new york!", + "PADDED_8_DILATION_1": "My old man says i'm going to have to take that advertising job in new york!", + "PAD_8_FRACT_0_5": "My old man says im going to have to take that advertising job in new york!", + "PAD_8_FRACT_0_2": "My old man sas i'm going to have to take that advertising job in new york!" + }, + "11": { + "INITIAL_BOX": "The conversation wandered on aimlessly... .", + "DEFAULT": "The conversation wandered on aimlessly... .", + "DEFAULT_GREY_PAD": "The conversation wandered on aimlessl", + "PADDED_4": "The conversation wandered on aimlessly .", + "PADDED_8": "The conversation wandered on aimlessly", + "EXTRACTED_INIT_BOX": "The conversation wandered on aimlessly . .", + "PADDED_4_EXTRACTED": "The conversation wandered on aimlessly . .", + "PADDED_8_EXTRACTED": "The conversation wandered on aimlessly . .", + "PADDED_8_DILATION_1": "The conversation wandered on aimlessly . .", + "PAD_8_FRACT_0_5": "The conversation wandered on aimlessly . .", + "PAD_8_FRACT_0_2": "The conversation wandered on aimlessly . ." + }, + "12": { + "INITIAL_BOX": "Yeah, me, too! hel} take me on at the bank, but i think id rather work in my uncles publishing house ! did it ever", + "DEFAULT": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncles publishing house! did it ever", + "DEFAULT_GREY_PAD": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncle's publishing house !", + "PADDED_4": "Yeah, me, too! hel} take me on at the bank, but i think i'd rather work in my uncle's publishing house ! / di", + "PADDED_8": "Yeah, me, too! hele take me on at the bank, but i think i'd rather work in my uncle's publishing house ! it ever 5", + "EXTRACTED_INIT_BOX": "Yeah, me, too! he'l}. take me on at the bank, but i think i'd rather work in my uncle's publishing house ! did it ever", + "PADDED_4_EXTRACTED": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncle's publishing ) house ! did it ever", + "PADDED_8_EXTRACTED": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncle's publishing house ! did it ever lts,", + "PADDED_8_DILATION_1": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncle's publishing house ! did it ever tn a \u2014m a \u00a9", + "PAD_8_FRACT_0_5": "Yeah, me, too! hel} take me on at the bank, but i think i'd rather work in my uncle's publishing house ! did it ever um ev let", + "PAD_8_FRACT_0_2": "Yeah, me, too! hell take me on at the bank, but i think i'd rather work in my uncle\u2019s publishing house ! did it ever om ae a i \u2014 \u00bb" + }, + "13": { + "INITIAL_BOX": "Lucky z my old mans got enough dough to support half this town ! why should 1 want to b: work ?z", + "DEFAULT": "Lucky z my old mans got enough dough to support half this town ! why should i want to : \u00ab work?z", + "DEFAULT_GREY_PAD": "Luckyz my old mans got enough dough to support half this town ! why should i want to work 2", + "PADDED_4": "Luckyz my old mans got enough dough to support hale this town ! why should i want to \u00ab work?z", + "PADDED_8": "Lucky z my old { mans got enough dough to support half this town ! why should | i want to work 2", + "EXTRACTED_INIT_BOX": "Lucky z my old mans got enough dough to support half this town! why should 1 want to work z", + "PADDED_4_EXTRACTED": "Lucky z my old mans got enough dough to support half this town! why should 1 want to work z", + "PADDED_8_EXTRACTED": "Lucky z my old mans got enough dough to support half this town! why should 1 want to work #", + "PADDED_8_DILATION_1": "Luckyz my old mans \u2018got enough dough to support half this town! why should 1 want to work 2", + "PAD_8_FRACT_0_5": "Lucky z my old mans got enough dough to support half this town! why should 1 want to work", + "PAD_8_FRACT_0_2": "Luckyz my old mans \u2018got enough dough to support half this town! why should 1 want to work #" + }, + "14": { + "INITIAL_BOX": "Ie you don't know, i'm not going to tell you!", + "DEFAULT": "Ie you don't know, i'm not going to tell you! _", + "DEFAULT_GREY_PAD": "Ie you don't know, iaa no going to tell you!", + "PADDED_4": "Ie you don't know, i'm not going to tell you!", + "PADDED_8": "Ra \u2014 tt bl le ie you don't know, i'm not going to tell you. a", + "EXTRACTED_INIT_BOX": "Ie you don't know, iaa not going to tell you!", + "PADDED_4_EXTRACTED": "Ie you don't know, i'm not going to tell you!", + "PADDED_8_EXTRACTED": "Ie you don't know, i'm not going to tell you!", + "PADDED_8_DILATION_1": "Ie you don't know, i'm not going to tell you!", + "PAD_8_FRACT_0_5": "Ie you don't know, iia not going to tell you!", + "PAD_8_FRACT_0_2": "Ie you don't know, i'm not going to tell you!" + }, + "15": { + "INITIAL_BOX": "Are yau speaking to me?", + "DEFAULT": "Are you: speaking to me?", + "DEFAULT_GREY_PAD": "Are yau speaking to me?", + "PADDED_4": "\u201care you speaking to me?", + "PADDED_8": "\u2014 mb are you speaking : to me?", + "EXTRACTED_INIT_BOX": "A | to me?", + "PADDED_4_EXTRACTED": "To met", + "PADDED_8_EXTRACTED": "\u2014 seeakng to me?", + "PADDED_8_DILATION_1": "M\u2014 seeakng to me?", + "PAD_8_FRACT_0_5": "\u2014 seeking to mef", + "PAD_8_FRACT_0_2": "M\u2014 seeking to me?" + }, + "16": { + "INITIAL_BOX": "A did it ever 1 occur to you that you're lucky to get jobsz", + "DEFAULT": "/ did it ever ld occur to you that you're lucky to get jobsz", + "DEFAULT_GREY_PAD": "Did it ever occur to you at you're luck! to get jobsz", + "PADDED_4": "Did it ever 1 occur to you that you're lucky to get jobsz", + "PADDED_8": "Did it ever jd occur to you that you're lucky _ to get jobsz _", + "EXTRACTED_INIT_BOX": "Did it ever occur to you that you're lucky to get jobsz", + "PADDED_4_EXTRACTED": "Did it ever occur to you that youre lucky to get jobsz", + "PADDED_8_EXTRACTED": "Did it ever occur to you that you're lucky to get jobsz", + "PADDED_8_DILATION_1": "Did it ever occur to you that you're lucky to get jobsz", + "PAD_8_FRACT_0_5": "Did it ever occur to you that you're lucky to get jobs#", + "PAD_8_FRACT_0_2": "Did it ever occur to you that you're lucky to get jobs#" + } + }, + "MCCAY_LITTLENEMO_090.jpg": { + "1": { + "DEFAULT": "Mon palais) est tout pres juste une petite promenade \\dansla", + "INITIAL_BOX": "Mon palais est tout pres juste une petite promenade dansla jungle", + "DEFAULT_GREY_PAD": "Mon palais", + "PADDED_4": "\"mon palais est tout pres juste une petite, promenade valigy", + "PADDED_8": "Mon palais) est tout pres juste f une petite | promenade danslajungle! ==", + "EXTRACTED_INIT_BOX": "Mon palais est tout pres juste une petite promenade dansla jungle", + "PADDED_4_EXTRACTED": "Mon palais: est tout pres juste une petite promenade dansla jungle", + "PADDED_8_EXTRACTED": "Mon palais! est tout pres juste une petite promenade danslajungly", + "PADDED_8_DILATION_1": "Mon palais! est tout pres juste une petite promenade dansla jungle:", + "PAD_8_FRACT_0_5": "Mon palais: est tout pres juste une petite promenade danslajun6ly", + "PAD_8_FRACT_0_2": "Mon palais! est toot pres juste une petite promenade danslajungly" + }, + "0": { + "INITIAL_BOX": "Sinous tenez a rester en ve... nevous esk pas de mol", + "DEFAULT": "A rester en vie.... nevous approchez (pas de mol fs vous tenez)", + "DEFAULT_GREY_PAD": "\u00a5 s1vous tenez a rester en vie.... nevous approchez pas de mo!", + "PADDED_4": "|a rester en | vie... nevous approchez \\pas de mol i vous tenez", + "PADDED_8": "Sinous tenez) \u2018|a rester en vie... nevous approchez pas de mot", + "EXTRACTED_INIT_BOX": "Sinvous tene? a rester en vie... nevous approchez pas de mol", + "PADDED_4_EXTRACTED": "Sivous tenez a rester en vie... nevous approchez pas de mol", + "PADDED_8_EXTRACTED": "Sivous tenez a rester en vie... nevous approchez pas de mou", + "PADDED_8_DILATION_1": "Sinous tenez a rester en vie... nevous approchez pas de mo!", + "PAD_8_FRACT_0_5": "Sivous tenez a rester en vie... nevous approchez pas de mol", + "PAD_8_FRACT_0_2": "S1vous tenez a rester en vie... nevous approchez pas de mol" + }, + "2": { + "INITIAL_BOX": "Vous allez avoir ce que] vous cher- hez etb encore _/\u00bb", + "DEFAULT": "Ous allez \\avoir ce que vous cher- hez etbie encor!", + "DEFAULT_GREY_PAD": "Ous allez |", + "PADDED_4": "Vous auiez", + "PADDED_8": "M ous alez \\avoir ce que} vous cher- hez etbien i encor|", + "EXTRACTED_INIT_BOX": "Us \u201crc cen", + "PADDED_4_EXTRACTED": "Us rc cen", + "PADDED_8_EXTRACTED": "Uss rr cen", + "PADDED_8_DILATION_1": "Us? ~rtt cise", + "PAD_8_FRACT_0_5": "Vs rr pn", + "PAD_8_FRACT_0_2": "Us) rr sgn" + }, + "3": { + "INITIAL_BOX": "Et mate) nant par fy] suivez. mol", + "DEFAULT": "Jlo] suivez. mol) (et mainte ant par]", + "DEFAULT_GREY_PAD": "Et maint! ant par| lei! suivez. mor", + "PADDED_4": "(et mainte) ant par] lei! suivez moi!", + "PADDED_8": "Et man tey ant pari lei! suivez. mort j", + "EXTRACTED_INIT_BOX": "Et mawte ant par ict suivez. moi!", + "PADDED_4_EXTRACTED": "Et mante ant par lei suivez. moi!", + "PADDED_8_EXTRACTED": "Et mante ant par lei suivez. mort", + "PADDED_8_DILATION_1": "Et mainte. ant par leit suivez. mort", + "PAD_8_FRACT_0_5": "Et man te ant pir ct suivez. mot!", + "PAD_8_FRACT_0_2": "Et mante ant par lei! suivez. mort" + }, + "4": { + "INITIAL_BOX": "Mon palais est moins bien que le ou ro! mais il est jolt lil nest pas pias", + "DEFAULT": "Mon palais est moins bien que $i celui du ro! mais il est joli il n'est pas | \u00a5as,", + "DEFAULT_GREY_PAD": "Mon palais es moins bien que celui du ro! (| mais il est j0li inest pas", + "PADDED_4": "Mon palais est moins bien que celui du ro! {| mas 1l est jot", + "PADDED_8": "Mon palais est moins bien que", + "EXTRACTED_INIT_BOX": "Mon palais est moins bien que celui du roi mass il est joli l nest pas fas", + "PADDED_4_EXTRACTED": "Mon palais est moins bien que celui du roi mass il est joli", + "PADDED_8_EXTRACTED": "Mon palais est moins bien que celui du roi mass il est joli l nest pas 1 0in", + "PADDED_8_DILATION_1": "Mon palais est moins bien que celui du roi mais il est jolt ln'est pas 10in", + "PAD_8_FRACT_0_5": "Mon palais est moins bien que celui du rol mns il est joli l nest pas loin", + "PAD_8_FRACT_0_2": "Mon palais est moins bien que celui du rol {mas il est joli l nest pas 10in" + }, + "5": { + "INITIAL_BOX": "Je croyais que les ma. ring devaien [nous accom? sner?ils noi ganididn |", + "DEFAULT": "9 crovais que les ma.", + "DEFAULT_GREY_PAD": "9 crovais que les ma rins devaie nous accorpy bner1ls nol", + "PADDED_4": "% crovas que les ma.", + "PADDED_8": "Al 9% crovais que les ma", + "EXTRACTED_INIT_BOX": "2 croyas que les ma ring jevaiet nols? i bner71ls no: pi sets. y", + "PADDED_4_EXTRACTED": "2 crovas que les ma ring jevaiet nols! + bner71ls no: sunent?", + "PADDED_8_EXTRACTED": "2 crovas que les ma ring jevaiet nols! + bner71ls no: sunent?", + "PADDED_8_DILATION_1": "I crovas que les ma ring jevaien nols\u00a3 fe bner71ls nov sunent?", + "PAD_8_FRACT_0_5": "2 crovas que les ma ring jevaiet nols! + bner71ls no: sunent?", + "PAD_8_FRACT_0_2": "9 crovas que les ma ring jevaier nols! + bner71ls no: sunent?" + }, + "6": { + "INITIAL_BOX": "(ne regardez pas ces gives | ou iesvont vous bombarder avec", + "DEFAULT": "Ve regardet pas ces gives | ou isvont vous bombarder avec) dix decc des noix decdez", + "DEFAULT_GREY_PAD": "Ou isvont vous |, bombarder aveck \u2018des noi k de coco xo", + "PADDED_4": "Ee) i oa ne regardez pas ces gives | ou isvont vous bombarder avec) \u2018des noi x de coc: es noi rt", + "PADDED_8": "Ne regardez pas ces swses | ou isvont vous bombarder avec] des nox decocy! ne eet", + "EXTRACTED_INIT_BOX": "Ne regardez pas ces singes 0 ibvont vous [bombarder avec des noi decoc", + "PADDED_4_EXTRACTED": "Ne regardez pas ces singes 0 ibvont vous [bombarder avec des noi x decoc", + "PADDED_8_EXTRACTED": "Ne regardez pas ces singes ou ibvont vous [bombarder avec des noi x decoc", + "PADDED_8_DILATION_1": "Ne regardez pas ces singes ou isvont vous [bombarder avec des noi k decoc", + "PAD_8_FRACT_0_5": "Ne regardez pas ces singes ou ibvont vous bombarder avec \u2018des noix decoc", + "PAD_8_FRACT_0_2": "Ne regardez. pas ces siwges ou hsvont vous bombarder avec des noi decoc" + }, + "7": { + "INITIAL_BOX": "\"oul! ovi! mais dus. wavel rien; a craindreet \\ pourriez voir |", + "DEFAULT": "Qui ovit mais vous navel rie] a craindreet ne faites fas a tion ace que \\ pourriez voir |", + "DEFAULT_GREY_PAD": "Re vous navel rie] 011 oui asv] a craindre et ne faites pas a tion a cz a wa b\\ pour oir |", + "PADDED_4": "A em pe oul ouit mais vous navel rie a craindre et ne faites pas at tion ace que \\\u00a2 pourriez voir |", + "PADDED_8": "Dui oui mais vous navel rie a craindre et 7 ne faites 726 a tion ace que \\\u00a2 pourriez voir", + "EXTRACTED_INIT_BOX": "Uitovi ma vous navel riel a craindr e efatespr 4 lovace - + po ve", + "PADDED_4_EXTRACTED": "Oui ou ma vous navel rien a craindr e- efaitespr 4 ion ace . fo", + "PADDED_8_EXTRACTED": "Oui ou ma vous navel rien a craindr e- jefaitespr 4 ion ace . & po [54", + "PADDED_8_DILATION_1": "\u201cquitoul ma vous navel riem a craindr e\u201d vefaitespa a 10n ace \u00ab e po [34", + "PAD_8_FRACT_0_5": "Qui oui ma vous navel rien a craindr e\u00b0 efntespr 4 ion ace . li", + "PAD_8_FRACT_0_2": "\u201cquifoui ma . vous navel rien a craindr e\u00b0 jefnitespa 4 iovace - po re" + }, + "8": { + "INITIAL_BOX": "\"non i ne faites pas| ga flipi now! j", + "DEFAULT": "Non | ne faites pas| \u00a2a flipi non!", + "DEFAULT_GREY_PAD": "Noi nine faites pas \u00a2a flip! non!", + "PADDED_4": "Non | ne faites pas| \u00a2a flipi non!", + "PADDED_8": "Non | ne faites psi \u00a2a flip! now!", + "EXTRACTED_INIT_BOX": "Non i ne faites pas ga flip! now!", + "PADDED_4_EXTRACTED": "Non ine faites pas ga flip! non!", + "PADDED_8_EXTRACTED": "Non ine faites pas ga flip! non!", + "PADDED_8_DILATION_1": "Non ine faites pas ga flipi no!", + "PAD_8_FRACT_0_5": "Non ine faites pas ga flip! non!", + "PAD_8_FRACT_0_2": "Non ine faites pas \u00a2a flip! non!" + }, + "9": { + "INITIAL_BOX": "000h! arretez! arretez 0004!", + "DEFAULT": "0001) arretez arretez] 000a! |", + "DEFAULT_GREY_PAD": "000h! arretez iarretel 0004!", + "PADDED_4": "000h! arretez iarre tel] 000a", + "PADDED_8": "00h] ) arretez arretee) 00h! ii", + "EXTRACTED_INIT_BOX": "000a! arretez. arretezi 0004!", + "PADDED_4_EXTRACTED": "000h! arretez: arreteli 0004!", + "PADDED_8_EXTRACTED": "000h! arretez: arreteli 0004!", + "PADDED_8_DILATION_1": "000h! arretez: arreteli 0004!", + "PAD_8_FRACT_0_5": "000h! arretez arretez! 0004!", + "PAD_8_FRACT_0_2": "000h! arretez. arreteli 0004!" + }, + "10": { + "INITIAL_BOX": "Am pourquo! donc) nemo sagite- il tant lanuit? ce sor ilne entree", + "DEFAULT": "{pourquoi donc) nemo sagite-t- hl tant lanuit?] ce sor ilne fait que se retournerl", + "DEFAULT_GREY_PAD": "Pourquo! dono nemo sagite l tant lanuit ce sor ilne {fat que se", + "PADDED_4": "{pourauo! dowd emo sagite-t: hl tant lanuit?] ce soir ilne patquese", + "PADDED_8": "{pourquoi donc) nemo sagite-t- hl tant lanuit?] ce sor ilne fait que se retournerl", + "EXTRACTED_INIT_BOX": "Pourquoi owe nemo sagite-t- jl tant lanuyt? ce sor ilne\u2019 fat que se 'retourner", + "PADDED_4_EXTRACTED": "Pourquoi doc nemo sabite-t iltant lanuit? ce sor ilne' fat que se retourner!", + "PADDED_8_EXTRACTED": "Pourquoi doc nemo sagite-t il tant lanuit? ce sor ilne' fat que se retourner!", + "PADDED_8_DILATION_1": "Pourquo! doc nemo sagite-t iltant lanuit? ce sor ilne' fat que se retourner!", + "PAD_8_FRACT_0_5": "Pourquoi done nemo sagitet iltant lanuit? ce sor ilne' fat quese atu ert", + "PAD_8_FRACT_0_2": "Pourquoi doe nemo sagite-t il tant lanuit? ce sor ilne' fait que se returner!" + } + }, + "Strange_Tales_172021.jpg": { + "1": { + "DEFAULT": "But brother yoo020 1s not yet ready to sit at the thble of the ead! jrnearnre", + "INITIAL_BOX": "\u201cbut brother vood00 1s not. yet ready to sit at the thble of the dead ly posse", + "DEFAULT_GREY_PAD": "\u201cbut brother vood00 1s not. yet ready to s(t at the thble of the pearly pm", + "PADDED_4": "But brother voo000 15 not: yet ready to sit at the thble of the ead l\" poe", + "PADDED_8": "V--but brother yoo000 15 not: yet ready to s(t at the thble of the dead!\u201d", + "EXTRACTED_INIT_BOX": "L--buit brother voodoo is not yet ready to sit at the table of the dead!\"", + "PADDED_4_EXTRACTED": "L--buit brother voodoo is not yet ready t0 sit at the thle of the pead yl\"", + "PADDED_8_EXTRACTED": "L--buit brother voodoo is not yet ready 70 sit at\u201d the thele of the dead!\u201d", + "PADDED_8_DILATION_1": "But brother voodco is not yet ready 70 sit at the thble of the dear!\"", + "PAD_8_FRACT_0_5": "But brother voodoo is not yet ready t0 sit at the thele of the pear!\u201d", + "PAD_8_FRACT_0_2": "But brother voodoo 15 not yet ready t0 sit at the thele of the dead!\u201d" + }, + "0": { + "INITIAL_BOX": "Ablur=only a blur at. first, dark menacing --greets erother yoodpoos eyes as he rises from the darkness ,,,", + "DEFAULT": "Ablur = ney 4 blur at first, dark menacing greets voodoo eyes ashe brother rises from the darkness ,,,", + "DEFAULT_GREY_PAD": "Fll | blur adh ing -- woopoos eyes as he | sere from the carkness ...|", + "PADDED_4": "Ablur~=only a blur at first, dark menacing --greets erother yoodcos eyes as he rises from the carkness ,..", + "PADDED_8": "Ablur~=only a blur at first, dark menacing --greets erother yoodcos eyes as he rises from the darkness ...", + "EXTRACTED_INIT_BOX": "Ablur-\u2014only a blur at first, dark menacing - greets ercther yoopoo's eyes as he rises from the dmrkness ,,,", + "PADDED_4_EXTRACTED": "Ablur=only a blur at first, dark menacing --greets ercther yoodpcog eyes as he rises from the darkness ,,.", + "PADDED_8_EXTRACTED": "Ablur=only a blur at first, dark menacing greets ercther yoodpcog eyes as he rises from the darkness ,..", + "PADDED_8_DILATION_1": "Ablur~=only a blur at first, dark menacing greets erother yoodooe eyes as he rises from the darkness .,.", + "PAD_8_FRACT_0_5": "Ablur=only a blur at first, dark menacing -- greets ercther yoodpoog eyes as he rises from the darkness ,..", + "PAD_8_FRACT_0_2": "Ablur~=only a blur at first, dark menacing -- greets erother yoodoo's eyes as he rises from the darkness ,.." + }, + "2": { + "INITIAL_BOX": "==and immediately egrets it!", + "DEFAULT": "==and immediately regrets it!", + "DEFAULT_GREY_PAD": "~=and immediately regrets it!", + "PADDED_4": "~=and immediately. regrets it!", + "PADDED_8": "=~and immediately | regrets it!", + "EXTRACTED_INIT_BOX": "~-and imediately", + "PADDED_4_EXTRACTED": "~-and immediately regrets it!", + "PADDED_8_EXTRACTED": "~-and immediately regrets it!", + "PADDED_8_DILATION_1": "==and immediately regrets it!", + "PAD_8_FRACT_0_5": "~=and immediately regrets it!", + "PAD_8_FRACT_0_2": "~=and immediately regrets it!" + }, + "3": { + "INITIAL_BOX": "> w-wha-?, may throat--!", + "DEFAULT": "D wwha-z may throat--!", + "DEFAULT_GREY_PAD": "> sid throat!", + "PADDED_4": "Wna? thats b 3", + "PADDED_8": "3 ha? that ! 4", + "EXTRACTED_INIT_BOX": "W-wha~? m-my throat--!", + "PADDED_4_EXTRACTED": "W-wra\u2014~? m-my throat--!", + "PADDED_8_EXTRACTED": "W-wra\u2014~? m-my throat--!", + "PADDED_8_DILATION_1": "Yd throat!", + "PAD_8_FRACT_0_5": "W-wra~? m-my throat--!", + "PAD_8_FRACT_0_2": "W-wea~? m-my throat--!" + }, + "4": { + "INITIAL_BOX": "\\the hooded men have not fled,\" thinks the still-dazed voodoo-lord. \"one, at least, has remained behind to deliver the final stroke ~~", + "DEFAULT": "Nthe hooded men have not fled, thinks the still-dazed voodoo-lord, \"one, at least, has remained behind to deliver the final stroke =~", + "DEFAULT_GREY_PAD": "Ie hooded men have not vks the | stull \u201cpze0", + "PADDED_4": "\\the hooded men have not fled,\" thinks the still-dazed voodod-lord, \"one, at least, has remained behind to deliver the final stroke ~~", + "PADDED_8": "Nthe hooded men have not fled,\" thinks the still-dazel voodoo-lord. \"one, at least, has remained behind to deliver the final strok", + "EXTRACTED_INIT_BOX": "\\the hooded men have not fled,\" thinks the still-dazeld voodoo-lorp, one, at least, has remained behind to deliver the final stroke -", + "PADDED_4_EXTRACTED": "The hooded men have not fled,\" thinks the still-pazel voodoo-lorp, one, at least, has remained behind to deliver the final stroke-", + "PADDED_8_EXTRACTED": "The hooded men have not fled,\" thinks the still-dazed voodoo-lorp, one, at least, has remained behind to deliver the final stroke-", + "PADDED_8_DILATION_1": "The hooded men have not fled,\" thinks the still-dazed voodod-lorl. \"one, at least, has remained behind to deliver the final stroke", + "PAD_8_FRACT_0_5": "The hooded men have not fled,\" thinks the still-dazed voodoo-lorp., one, at least, has remained behind to deliver the final stroke-", + "PAD_8_FRACT_0_2": "The hooded men have not fled,\" thinks the still-dazed voodoo-lorl., one, at least, has remained behind to deliver the final stroke-" + }, + "5": { + "INITIAL_BOX": "Inspector tate (7 apron yf", + "DEFAULT": "Inspector tate 1? prt", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Inspector tate 7 ra a", + "PADDED_8": "Inspector ! tate (7 cf a", + "EXTRACTED_INIT_BOX": "Inspector tate i? tt. .", + "PADDED_4_EXTRACTED": "Inspector tate i? i...", + "PADDED_8_EXTRACTED": "Inspector tate i? i..", + "PADDED_8_DILATION_1": "Inspector tate?", + "PAD_8_FRACT_0_5": "Inspector tate i? i..", + "PAD_8_FRACT_0_2": "Inspector tate i? i.." + }, + "6": { + "INITIAL_BOX": "\u201ci can imagine what yo thought, \\. man/z _ 4", + "DEFAULT": "\u201ci can imagine \\ what you thought, want ed", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "I can imagine what yo thought, man! 4", + "PADDED_8": "T can imagine what you tholght, man /", + "EXTRACTED_INIT_BOX": "I can imagine what you thought, man /", + "PADDED_4_EXTRACTED": "I can imagine what you thought, man /", + "PADDED_8_EXTRACTED": "I can imagine what you thought, man /", + "PADDED_8_DILATION_1": "I can imagine what you man / \u2019", + "PAD_8_FRACT_0_5": "I can imagine what you thought, man /", + "PAD_8_FRACT_0_2": "I can imagine what you thought, man /" + }, + "7": { + "INITIAL_BOX": "With hs, the of te. loa thrusts out a vige-like hand ~", + "DEFAULT": "With hs, the of te loa thrusts out a vige-like hand ~~", + "DEFAULT_GREY_PAD": "With this the lord of the loa thrusts out a vige-like hand", + "PADDED_4": "With hs, the of te loa thrusts out a vige-like hand ~~", + "PADDED_8": "With this, the of the lo) thrusts out a vige-like hand-=", + "EXTRACTED_INIT_BOX": "With this, the of the lo, thrusts out a vise-like hand\u00bb ~", + "PADDED_4_EXTRACTED": "With this, the of the lo, thrusts out a vise-like hand -", + "PADDED_8_EXTRACTED": "With this, the of the lo, thrusts out a vise-like hand-~", + "PADDED_8_DILATION_1": "With this, of the thrusts =like hand-~", + "PAD_8_FRACT_0_5": "With this, the of the lo, thrusts out a vige-like hand-~", + "PAD_8_FRACT_0_2": "With this, the of the lo, thrusts out a vige-like hand" + }, + "8": { + "INITIAL_BOX": "Forgive me, sir-- but it thought: -", + "DEFAULT": "\u2018forgive me, sir-- butt thought: ~", + "DEFAULT_GREY_PAD": "(forgive ne, sir-- but 4 cl,", + "PADDED_4": "(forgive * ne, sir but i tholght:-", + "PADDED_8": "Y forgive me, sir-- butt thought", + "EXTRACTED_INIT_BOX": "Forgive", + "PADDED_4_EXTRACTED": "Forgive *", + "PADDED_8_EXTRACTED": "Forgive ne, sir buti tholght--", + "PADDED_8_DILATION_1": "Forgive me, sir-~ butt thought", + "PAD_8_FRACT_0_5": "Forgive me, sir-- buti tholght--", + "PAD_8_FRACT_0_2": "Forgive * me, sir buti tholght--" + }, + "9": { + "INITIAL_BOX": "505 this one, sam. a little grogey--but hell survive. 4", + "DEFAULT": "505 this one, sam. a little grogey--but hell survive. 4", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "I gr fa ord [ian pan a a aa ae $0 this one, sam. a little grogey--but hell survive. 4", + "PADDED_8": "505 this one, sam. a little groggy- hell survive", + "EXTRACTED_INIT_BOX": "50 this one, sam. a little groggy--but hell sirvive.", + "PADDED_4_EXTRACTED": "505 this one, sam. a little groggy--but hell survive.", + "PADDED_8_EXTRACTED": "505 this one, sam. a little groggy--but hell survive .", + "PADDED_8_DILATION_1": "50's this one, sam. a little groggy--but hell survive .", + "PAD_8_FRACT_0_5": "505 this one, sam. a little groggy--but hell survive .", + "PAD_8_FRACT_0_2": "505 this one, sam. a little groggy--but hell survive ." + }, + "10": { + "INITIAL_BOX": "And. you name: == \u00a2", + "DEFAULT": "~ and your _ name --2", + "DEFAULT_GREY_PAD": "And. your nam", + "PADDED_4": "Of and our name--2", + "PADDED_8": "\u201cand. = your name-z", + "EXTRACTED_INIT_BOX": "And you names == \u00a2", + "PADDED_4_EXTRACTED": "And your name?", + "PADDED_8_EXTRACTED": "And your name--2", + "PADDED_8_DILATION_1": "And name-2", + "PAD_8_FRACT_0_5": "And your _ name--2", + "PAD_8_FRACT_0_2": "And your name--2" + }, + "11": { + "INITIAL_BOX": "Nough intro - ductions.", + "DEFAULT": "Enough intro - ductions.", + "DEFAULT_GREY_PAD": "Enough intro - ductions.", + "PADDED_4": "\u201d enough intro - puctions.", + "PADDED_8": "Enough intro - puctions", + "EXTRACTED_INIT_BOX": "Enough intro - dluctions.", + "PADDED_4_EXTRACTED": "Enough intro - dpuctions.", + "PADDED_8_EXTRACTED": "Enough intro - puctions.", + "PADDED_8_DILATION_1": "Enough intro ductions.", + "PAD_8_FRACT_0_5": "Enough intro - puctions.", + "PAD_8_FRACT_0_2": "Enough intro ~ ductions." + }, + "12": { + "INITIAL_BOX": "\u201c tony bent pown to see how you were -~", + "DEFAULT": "\u201d tony bent pown to see how you were -~", + "DEFAULT_GREY_PAD": "\u201c tony bent pown to see how you were--", + "PADDED_4": "# tony bent pown to see how you were --", + "PADDED_8": "I only bent pown to see how you were--", + "EXTRACTED_INIT_BOX": "Ti only bent ponn to see how yo were --", + "PADDED_4_EXTRACTED": "Ti only bent ponn to see how you were--", + "PADDED_8_EXTRACTED": "Ti only bent ponn to see how you were--", + "PADDED_8_DILATION_1": "Tony bent pown to see how were--", + "PAD_8_FRACT_0_5": "Ti only bent ponn to see how you were--", + "PAD_8_FRACT_0_2": "Tony bent pown to see how you were--" + }, + "13": { + "INITIAL_BOX": "F=~but, judging by the bruises on my neck, td 2ay you're fine?", + "DEFAULT": "#==but, judging by the bruises on iy neck, it'd say you're fine?", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "/=~but, judging by the bruises on my neck, td say youre fine?", + "PADDED_8": "I'd 5ay you're fine, 7", + "EXTRACTED_INIT_BOX": "-~but, judging by the bruises on my neck, td say you're fine!", + "PADDED_4_EXTRACTED": "~~ but, judging by the bruises on my neck, t'd say you're fine?", + "PADDED_8_EXTRACTED": "~~ but, judging by the bruises on my neck, t'd 5ay youre fine]", + "PADDED_8_DILATION_1": "~~but, judging by the bruises on my neck, i'd 5ay youre fine?", + "PAD_8_FRACT_0_5": "-~but, judging by the bruises on my neck, t'd 5ay youre fine]", + "PAD_8_FRACT_0_2": "~~but, judging by the bruises on my neck, t'd 5ay youre fine!" + }, + "14": { + "INITIAL_BOX": "We know who you are, mister : jericho prlmm psychologist", + "DEFAULT": "\"we know who you are, mister : tericho drumm, psychologist turned-yoodco \\ glack-\u2014", + "DEFAULT_GREY_PAD": "We know who you are, mister jericho prlmm psychologist- turned-yoodco", + "PADDED_4": "We vaal nls we know who you are, mister : jericho prlumm, psychologist\u2014 turned-yoodco \\ quack -\u2014", + "PADDED_8": "We know who you are, mister : jericho prlumm, psychologist= turned-yoodc0 \\ quack--", + "EXTRACTED_INIT_BOX": "We know who you are, mister : tericho prlimm psychologist", + "PADDED_4_EXTRACTED": "We know who you are, mister : jericho prlmm, psychologist turned-yoodeo qrliack -\u2014", + "PADDED_8_EXTRACTED": "We know who you are, mister : jericho prlmm, psychologist turned-yoodeo qlack -\u2014", + "PADDED_8_DILATION_1": "We know who you are, mister jericho drum, psychologist\u2014 turned-yoodco glack -\u2014", + "PAD_8_FRACT_0_5": "We know who you are, mister tericho prlmm, psychologist turned-yoodco qlack -\u2014", + "PAD_8_FRACT_0_2": "We know who you are, mister : jericho drlmm, psychologist turned-yoodco quack ~~" + }, + "15": { + "INITIAL_BOX": "Hawking, detect ive first-class--blit yol cancall me pete.", + "DEFAULT": "Hawking, detective first-class--but you cancall me pete.", + "DEFAULT_GREY_PAD": "Hawkins, detective firgt-class--but you cancall me pete.", + "PADDED_4": "Hawkins, detective first-class--but you cancall me pete.", + "PADDED_8": "Hawking, detective: first-class--blit you cancall me pete. ,", + "EXTRACTED_INIT_BOX": "Hawkins, detective first-class--blit you cancall me pete", + "PADDED_4_EXTRACTED": "Hawkins, detective first-class--blit you cancall me pete", + "PADDED_8_EXTRACTED": "Hawkins, detective first-class--blit you cancall me pete", + "PADDED_8_DILATION_1": "Oa call me pete", + "PAD_8_FRACT_0_5": "Hawkins, detective first-class--blit you cancall me pete", + "PAD_8_FRACT_0_2": "Hawkins, detect ive first-class--blit you cancall me pete" + }, + "16": { + "INITIAL_BOX": "Easy, sam--the \u00b0 man wollon't have been crazy enoligh to call us here if he'd hurt iv lorry.", + "DEFAULT": "\"easy, 5am--the man wollon't have been crazy enoligh to call lis here if he'd hurt lorry.", + "DEFAULT_GREY_PAD": "Easy, 5am--the man wolldn' t have been crazy enoligh \\ to call lis here if he'd hlirt 4 . lorry.", + "PADDED_4": "Easy, samn--the man wollon't have been crazy enoligh \\ to call us here 7 if he'd hlirt . lorry.", + "PADDED_8": "/ easy, 5am--the \\ man wollon't have been crazy enoligh \\ to call us here if he'd hurt , lorry.", + "EXTRACTED_INIT_BOX": "Easy, sam--the man wolldn't have been crazy enoligh to call us here: if he'd hurt lorry.", + "PADDED_4_EXTRACTED": "Easy, sam--the man wolldn't have been crazy enoligh to call us here: if he'd hurt lorry.", + "PADDED_8_EXTRACTED": "Easy, sam--the man wolldn't have been crazy enoligh to call us here: if he'd hurt lorry.", + "PADDED_8_DILATION_1": "Easy, 5am--the man wolldn't have been crazy enoligh to call us here if hep hurt", + "PAD_8_FRACT_0_5": "Easy, sam--the man wolldn't have been crazy enoligh to call us here if he'd hurt lorry.", + "PAD_8_FRACT_0_2": "Easy, sam--the man wolildn't have been crazy enoligh to call us here. if he'd hurt lorry." + }, + "17": { + "INITIAL_BOX": "", + "DEFAULT": "Very well.", + "DEFAULT_GREY_PAD": "Very well. en...", + "PADDED_4": "Very well pete 1 sos", + "PADDED_8": "Very well then... pete?)", + "EXTRACTED_INIT_BOX": "Very well then... pete", + "PADDED_4_EXTRACTED": "Very well", + "PADDED_8_EXTRACTED": "Very well then... pete 4", + "PADDED_8_DILATION_1": "Very well. then... pete", + "PAD_8_FRACT_0_5": "Very well then... pete 4", + "PAD_8_FRACT_0_2": "Very well then... pete 4" + }, + "18": { + "INITIAL_BOX": "I... wish lt knew, ingpectox she was kidnapped shortly before you arrived--by the same, men who overpowered bambl and myself ~\u2014", + "DEFAULT": "\" l...wish i anew, ingpector she was kidnapped shortly before you arrived--by the same, men who overpowered bambl and myself ~\u2014", + "DEFAULT_GREY_PAD": "I... wish lt knew, ingpector she was kidnapped shortly before you arrived--by the same, men who overpowered bambl and myself ~~", + "PADDED_4": "Pp am db an apate=lre 1 aea i... wish t knew, inspector sie was kidnapped shortly before you arrined~-by the same, men who overponered \"bambli and myself", + "PADDED_8": "I... wish lt knew, ingpector she was kidnapped shortly before you arrived--by the same, men who overpowered bambi and myself ~~", + "EXTRACTED_INIT_BOX": "I... wish i knew, ingpectox she was kidnapped shortly before yoli arrived by the same, men who overpowered bambl and wnself ~\u2014", + "PADDED_4_EXTRACTED": "I... wish i kvew, inspector she was kidnapped shortly before yoli arrived by the same, men who overpowered bambl and myself ~~", + "PADDED_8_EXTRACTED": "I... wish il knew, ingpecter she was kidnapped shortly before you arrived--by the same, men who overpowered bambl and myself ~~", + "PADDED_8_DILATION_1": "Tl... wish it knew, inspector she was kidnapped shortly before you arrived--by the same, men who over bambli and self ~\u2014", + "PAD_8_FRACT_0_5": "I... wish i knew, ingpecter she was kidnapped shortly before you arrived by the same, men who overpowered bambl and myself ~~", + "PAD_8_FRACT_0_2": "I... wish i knew, ingpector she was kidnapped shortly before you arrived by the same, men who overpowered bambl and myself ~~" + }, + "19": { + "INITIAL_BOX": "And tm warning you now==if you'e done anything to hurt my lorales, tul on a", + "DEFAULT": "--and tm warning you now==i= you've done anything to hurt my, lopales, tll... af", + "DEFAULT_GREY_PAD": "-and tm warning you |= you've now==| done anything to hurt loralee, tll ,..", + "PADDED_4": "--and tm warning you \u00a9 now==if you've done aline tofrt y, l sss", + "PADDED_8": "--and th warning you now-=i= you'\\e done anything to hurt my, lorales, tll...", + "EXTRACTED_INIT_BOX": "-and tm warning you now--|= you've done anything to hurt my lorales, tll...", + "PADDED_4_EXTRACTED": "--and th warning you now--|f you've done anything to hurt my loralee, tll...", + "PADDED_8_EXTRACTED": "--and th warning you now--|f you've done anything to hurt my lorales, tll...", + "PADDED_8_DILATION_1": "~-and th warning you now-=if youne done anything to hurt ay loralee, tll ..0", + "PAD_8_FRACT_0_5": "~-and th warning you now--|= you've done anything to hurt my lorales, tll...", + "PAD_8_FRACT_0_2": "~-and th warning you now-=|= you've done anything to hurt my lorales, tll..." + }, + "20": { + "INITIAL_BOX": "Then where", + "DEFAULT": "Then where 15 she, . prumm 7", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Then where 15 she, drumm 7", + "PADDED_8": "A [then where /5 she, drummz", + "EXTRACTED_INIT_BOX": "Then where", + "PADDED_4_EXTRACTED": "Then where 15 she, prumm 7", + "PADDED_8_EXTRACTED": "Then where 15 she, prumm 7", + "PADDED_8_DILATION_1": "Then where 15 she, drumm?", + "PAD_8_FRACT_0_5": "Then where 15 she, prumm 7", + "PAD_8_FRACT_0_2": "Then where 15 she, prumm 7" + }, + "21": { + "INITIAL_BOX": "==men who \"s claimed she was marked as sacrifice to the dark lord ~~ 4", + "DEFAULT": "=-men who claimed she was marked as sacrifice to the dark lrg 4", + "DEFAULT_GREY_PAD": "--hen spinner she 2 sate rk r bor", + "PADDED_4": "-men who claimed she to the gare", + "PADDED_8": "=--men who claimed she was marked as sacrifice | to the dark lord -=", + "EXTRACTED_INIT_BOX": "<-men who claimed she", + "PADDED_4_EXTRACTED": "<-men who claimed she was marked as sacrifice to the park lord-~", + "PADDED_8_EXTRACTED": "<-men who claimed she was marked as sacrifice to the park lord =~", + "PADDED_8_DILATION_1": "--hen claimed she as sacrifice to the park lord=-=", + "PAD_8_FRACT_0_5": "--men who claimed she was marked as sacrifice to the park lord =~", + "PAD_8_FRACT_0_2": "--men who claimed she was marked as sacrifice to the park lord-~" + }, + "22": { + "INITIAL_BOX": "After next", + "DEFAULT": "After next", + "DEFAULT_GREY_PAD": "\"continued after next page", + "PADDED_4": "Er next", + "PADDED_8": "Er next", + "EXTRACTED_INIT_BOX": "Continued af er ext", + "PADDED_4_EXTRACTED": "Continued af er ext", + "PADDED_8_EXTRACTED": "Gontinued af er ext", + "PADDED_8_DILATION_1": "Continued af er ext", + "PAD_8_FRACT_0_5": "Continued af er ext", + "PAD_8_FRACT_0_2": "Gontinued af er ext" + }, + "23": { + "INITIAL_BOX": "\u2019 marked by the sign of - the black rooster", + "DEFAULT": "/ marked by the sign of == the black rooster", + "DEFAULT_GREY_PAD": "/ merked by the sign cf", + "PADDED_4": "/ marked by the sign of", + "PADDED_8": "We [ harked by the sign of the black rooster!", + "EXTRACTED_INIT_BOX": "Marked by the sign of -- black rooster", + "PADDED_4_EXTRACTED": "Marked by the sign of -- the black rooster !", + "PADDED_8_EXTRACTED": "Marked by the sign of -- the black rooster !", + "PADDED_8_DILATION_1": "Marked by of -- the black rooster {", + "PAD_8_FRACT_0_5": "Marked by the sign of -- the black rooster {", + "PAD_8_FRACT_0_2": "Marked by the sign of -- the black rooster \u00a2" + } + }, + "Tarzan_014-21.JPG": { + "1": { + "DEFAULT": "Ae er tire but the she will be a pretty one-~ when all her cuts \u00abheal. she will ~", + "INITIAL_BOX": "But the she witl be a pretty one-~ when all her cuts heal. she will", + "DEFAULT_GREY_PAD": "Ty one. cuts shen 713", + "PADDED_4": "Ai re pr tr but the she will be a pretty one-~ when all her cuts ow heal. she will --", + "PADDED_8": "Pri tee gees cis byt the she will be a pretty one-- when all ner cuts no, heal. she will ~~", + "EXTRACTED_INIT_BOX": "But the she witt be 4 pretty one-- when all ner cuts heal. she will --", + "PADDED_4_EXTRACTED": "But the she witt be 4 pretty one-- when all ner cuts heal. she will --", + "PADDED_8_EXTRACTED": "But the she witt be 4 pretty one-- when all ner cuts heal. she will -", + "PADDED_8_DILATION_1": "But the she will wien at wee cars heal. she will ~~", + "PAD_8_FRACT_0_5": "Byt the she witt be a pretty one-- when all ner cuts heal. she will -", + "PAD_8_FRACT_0_2": "Byt the she witt be a pretty one-~ when all ner cuts heal. she will -" + }, + "0": { + "INITIAL_BOX": "Toog 2 he is brave 70 come back here, after fighting with our od", + "DEFAULT": "Pz he is brave nen rang with our le4der.", + "DEFAULT_GREY_PAD": "Toog 2 he is brave ih with our leader", + "PADDED_4": "Toog p he is brave re or =e with our leader. 4", + "PADDED_8": "Toog p/e 1s brave geren ine. 4 with our leader. 4", + "EXTRACTED_INIT_BOX": "Toog p he is brave es after fig, with our leader.", + "PADDED_4_EXTRACTED": "Toog p he is brave lt al with our leader.", + "PADDED_8_EXTRACTED": "Toog p he is brave a al with our leader", + "PADDED_8_DILATION_1": "Toog p he is brave 70 coe bach here, after fighting with", + "PAD_8_FRACT_0_5": "Toog p he is brave a al with our leader", + "PAD_8_FRACT_0_2": "Toog p he is brave ll al with our leader" + }, + "2": { + "INITIAL_BOX": "Teeka will die before she will mate with t00g--or hr davon but tals, of the tribe of kerchank! 4", + "DEFAULT": "\"teena will die before, she will mate with toog--or with anyone but tallg, of the \u201ctribe of kerchak! |", + "DEFAULT_GREY_PAD": "He will wit tri of , of the", + "PADDED_4": "Sis, \"teena will die before. she will mate with toog-- or with anyone but tale, of the tribe of kerimnak! |", + "PADDED_8": "Teena will die before, she will mate with == or with anyone but tals, of the \\ tribe of kerchak!", + "EXTRACTED_INIT_BOX": "Teeka will die before she will mate with toog-- or with anyone but tag, of the tribe of kerchak!", + "PADDED_4_EXTRACTED": "Teeka will die before she will mate with toog-- or with anyone byt tale, of the tribe of kerchank!", + "PADDED_8_EXTRACTED": "Teeka will die before, she will mate with toog-- or with anyone byt tale, of the tribe of kerman!", + "PADDED_8_DILATION_1": "Teeka will die . she wit mare wink toog--or with anyone b07 hae, of the tribe of kerchan!", + "PAD_8_FRACT_0_5": "Teeka will die before, she will mate with toog-- or with anyone but tals, of the trise of kerhak!", + "PAD_8_FRACT_0_2": "Teeka will die before, she will mate with toog-- or with anyone but tals, of the trise of kerman!" + }, + "3": { + "INITIAL_BOX": "Y qut of her she is a _ fibrce one! 4", + "DEFAULT": "Ly out of 4 she is a fibrce one.", + "DEFAULT_GREY_PAD": "Out of she is a \\_fibrce one!", + "PADDED_4": "\\ fierce onel", + "PADDED_8": "Y out of her 4 she is a n fibrce one.", + "EXTRACTED_INIT_BOX": "Y out of she 15 a fo mangan! fibrce one!", + "PADDED_4_EXTRACTED": "Y out of lo mangan i} she 15 a fibrce one!", + "PADDED_8_EXTRACTED": "Ly out of her fo mangan i+ she 15 a fibrce one!", + "PADDED_8_DILATION_1": "Ly ag ly) fs mangan) 2\u00a5 she is a fibrce one. ~", + "PAD_8_FRACT_0_5": "Ly out of her fo mangan i+ she 15 a fibrce one!", + "PAD_8_FRACT_0_2": "Ly out of her lo mangan 2+ she 15 a fibrce one!" + }, + "4": { + "INITIAL_BOX": "Just then.", + "DEFAULT": "Just then.", + "DEFAULT_GREY_PAD": "Then.", + "PADDED_4": "Just then.", + "PADDED_8": "", + "EXTRACTED_INIT_BOX": "Just then.", + "PADDED_4_EXTRACTED": "Just then...", + "PADDED_8_EXTRACTED": "Just then...", + "PADDED_8_DILATION_1": "Just then...", + "PAD_8_FRACT_0_5": "Just then...", + "PAD_8_FRACT_0_2": "Just then..." + }, + "5": { + "INITIAL_BOX": "Anil a pair ats apes comes this way.", + "DEFAULT": "Anil a pan fors gistd comes this res", + "DEFAULT_GREY_PAD": "Ot a jie ay", + "PADDED_4": "Ra s30 7 b pairs anil a pan bosse res . comes this froid", + "PADDED_8": "Mangan a dag] sansa! 8 pak of strange ap: \\ comes this {ras", + "EXTRACTED_INIT_BOX": "Mangani! a pair of strange apes comes this way.", + "PADDED_4_EXTRACTED": "Mangani! a pair of strange apes comes this way.", + "PADDED_8_EXTRACTED": "Mangani! a pair of strange apes comes this way.", + "PADDED_8_DILATION_1": "Ih! a pair sostmse des comes this way.", + "PAD_8_FRACT_0_5": "Mangani! a pair of strange apes comes this wary.", + "PAD_8_FRACT_0_2": "Mangani! a pair of strange apes comes this way." + }, + "6": { + "INITIAL_BOX": "One is an", + "DEFAULT": "\"one is an ape -- the other, monster. |", + "DEFAULT_GREY_PAD": "Ape -- the one is an aris", + "PADDED_4": "Pone 1s an ape -- the other, monster.", + "PADDED_8": "Ie 1s an ape -- the other, monster.", + "EXTRACTED_INIT_BOX": "One 1s an ape -- the ther, monster.", + "PADDED_4_EXTRACTED": "Ape -- the one 1s an other, monster.", + "PADDED_8_EXTRACTED": "One 1s an ape -- the other, monster.", + "PADDED_8_DILATION_1": "Ape -- the one is an other, monster", + "PAD_8_FRACT_0_5": "One is an ape -- the other, monster.", + "PAD_8_FRACT_0_2": "One is an ape -- the other, monster." + }, + "7": { + "INITIAL_BOX": "Ww) fdr (0 (6 rirance rs fi jake toog's sne away ?", + "DEFAULT": "\u2019 you hear, brothers? | will you (et strangers take toog's sne away?", + "DEFAULT_GREY_PAD": "S2 a you li a re | take t006's she", + "PADDED_4": "You hear, brothers? will you let strangers take toog's she away?", + "PADDED_8": "J vou wea sromiers?) wiis vo sr een : take t0og sheaat,", + "EXTRACTED_INIT_BOX": "You hear, brothers ? will you let strangers take toog's she away ?", + "PADDED_4_EXTRACTED": "You hear, brothers will you let strangers take toog's she away?", + "PADDED_8_EXTRACTED": "You hear, brothers 2 will you let strangers take toog's she away?", + "PADDED_8_DILATION_1": "You hear, brothers 2 will you let strangers take toog's she away?", + "PAD_8_FRACT_0_5": "You hear, brothers 2 will you let strangers take toog's she away?", + "PAD_8_FRACT_0_2": "You hear, brothers 2 will you let strangers take toog's she away?" + }, + "8": { + "INITIAL_BOX": "Your she 1s no concern of ours-\u201cbut we will not let amy invade our part of the jungle.", + "DEFAULT": "Your she 1s no concern. of ours-\u201cbut we will not let amy invade our part of a ii", + "DEFAULT_GREY_PAD": "Eaa ok hato f the jungle", + "PADDED_4": "Your she 1s no concern. of ours-but we will not let any invade \\our part of the jungle.", + "PADDED_8": "Your she 1s no concern. of ours-but we will not let any invade \\ our part of the mee,", + "EXTRACTED_INIT_BOX": "Your she 1s no concern of ours but we will not let any invade our part of the jungle", + "PADDED_4_EXTRACTED": "Your she 1s no concern of ours but we will not let any invade our part of the jungle", + "PADDED_8_EXTRACTED": "Your she 1s no concern of ours but we will not let any invade our part of the jungle", + "PADDED_8_DILATION_1": "Your she is no concern of ours-\u201cbut we will not let any invade our part of the jungle", + "PAD_8_FRACT_0_5": "Your she 1s no concern of ours--8ut we will not let any invade our part of the jungle", + "PAD_8_FRACT_0_2": "Your she 1s no concern of ours-<8ut we will not let any invade our part of the jungle" + }, + "9": { + "INITIAL_BOX": "\u00a350 be drag t she signe: leap on them from \\ hiding.", + "DEFAULT": "Spmg and drag t she signe: leap on them from \\ hiding.", + "DEFAULT_GREY_PAD": "Fcome--and she along? ip. on. ding.", + "PADDED_4": "Come and drag 7) she signe: leap on hem from u hiding.", + "PADDED_8": "Yy coms-- and. drag the she along? leap on 7 from d> hiding.", + "EXTRACTED_INIT_BOX": "Come. and she pr we wil leap on hiding.", + "PADDED_4_EXTRACTED": "Come --anp drag ti she signe: leap on them from hiding.", + "PADDED_8_EXTRACTED": "Come --anp drag ti she signe: leap on them from hiding.", + "PADDED_8_DILATION_1": "== and she along! we will leap on hiding.", + "PAD_8_FRACT_0_5": "Suis ap drag t) she higa: leap on them from hiding.", + "PAD_8_FRACT_0_2": "Send drag ti she aigne. leap on them from hiding." + }, + "10": { + "INITIAL_BOX": "> they are following a spoor!", + "DEFAULT": "They are. following en spoor!", + "DEFAULT_GREY_PAD": "# they are!", + "PADDED_4": "Following they are. in spoor! |", + "PADDED_8": ".. they are. folowing ia 10008", + "EXTRACTED_INIT_BOX": "They are following toces,", + "PADDED_4_EXTRACTED": "They are", + "PADDED_8_EXTRACTED": "They are following 50%", + "PADDED_8_DILATION_1": "They are following 50e:", + "PAD_8_FRACT_0_5": "They are following 505s", + "PAD_8_FRACT_0_2": "They are following 5058" + }, + "11": { + "INITIAL_BOX": "Here.", + "DEFAULT": "Was here.", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Here. 3", + "PADDED_8": "Was hdd here.", + "EXTRACTED_INIT_BOX": "Here", + "PADDED_4_EXTRACTED": "Here", + "PADDED_8_EXTRACTED": "Here", + "PADDED_8_DILATION_1": "Here", + "PAD_8_FRACT_0_5": "Here", + "PAD_8_FRACT_0_2": "Here" + }, + "12": { + "INITIAL_BOX": "Soon afterward, as tarzan and taug reach: the selfsame grove.", + "DEFAULT": "Soon afterward, as tarzan and taug reach the selfsame grove.", + "DEFAULT_GREY_PAD": "Oon afterward, as tarzan and taug reach the selfsame grove.", + "PADDED_4": "Soon afterward, as tarzan and taug reach the selfsame grove.", + "PADDED_8": "Soon afterward, as tarzan and taug reach the selfsame grove.", + "EXTRACTED_INIT_BOX": "Soon afterward, as tarzan and jaug reach the selfsame grove.", + "PADDED_4_EXTRACTED": "Soon afterward, as tarzan and taug reach the selfsame grove,", + "PADDED_8_EXTRACTED": "Soon afterward, as tarzan and taug reach the selfsame grove...", + "PADDED_8_DILATION_1": "Soon afterward, as tarzan and taug reach the selfsame grove...", + "PAD_8_FRACT_0_5": "Soon afterward, as tarzan and taug reach the selfsame grove...", + "PAD_8_FRACT_0_2": "Soon afterward, as tarzan and taug reach the selfsame grove..." + }, + "13": { + "INITIAL_BOX": "Tug! tarzan!", + "DEFAULT": "Tag! tarzan!", + "DEFAULT_GREY_PAD": "Aug! tarzan!", + "PADDED_4": "Taug! tarz,", + "PADDED_8": "! tarzan! 4", + "EXTRACTED_INIT_BOX": "Wg! tarzan", + "PADDED_4_EXTRACTED": "Taug! tarzan", + "PADDED_8_EXTRACTED": "Taug! tarzan", + "PADDED_8_DILATION_1": "Tug! tarzan", + "PAD_8_FRACT_0_5": "Taug! tarzan", + "PAD_8_FRACT_0_2": "Tug! tarzan" + }, + "14": { + "INITIAL_BOX": "Kre ccgah", + "DEFAULT": "", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "N :", + "PADDED_8": "(kreccahy", + "EXTRACTED_INIT_BOX": "Lass", + "PADDED_4_EXTRACTED": "", + "PADDED_8_EXTRACTED": "", + "PADDED_8_DILATION_1": "", + "PAD_8_FRACT_0_5": "", + "PAD_8_FRACT_0_2": "" + }, + "15": { + "INITIAL_BOX": "Too06 will /", + "DEFAULT": "Toog willy", + "DEFAULT_GREY_PAD": "Ea", + "PADDED_4": "Toog will?", + "PADDED_8": "\\ wills", + "EXTRACTED_INIT_BOX": "Too! witt !", + "PADDED_4_EXTRACTED": "Toe will!", + "PADDED_8_EXTRACTED": "Toe wilt!", + "PADDED_8_DILATION_1": "Witl?", + "PAD_8_FRACT_0_5": "Toe will!", + "PAD_8_FRACT_0_2": "Tog witl?" + }, + "16": { + "INITIAL_BOX": "\"yes! smell and the spoor-- other's.", + "DEFAULT": "Yes! r smell her spoor-- and the , other's.", + "DEFAULT_GREY_PAD": "Yes! 1 ell ther's.", + "PADDED_4": "Yes! rs smell and the , other's.", + "PADDED_8": "Smell yes! r poor-- and the other's.", + "EXTRACTED_INIT_BOX": "Yes! r smell her spoor and he", + "PADDED_4_EXTRACTED": "Yes! r smell her spoor and he othe", + "PADDED_8_EXTRACTED": "Yes! r smell her spoor and he othe", + "PADDED_8_DILATION_1": "Yes! r her spoor and he othe", + "PAD_8_FRACT_0_5": "Yes! r smell her spoor and he othe", + "PAD_8_FRACT_0_2": "Yes! r smell her spoor and he othe" + }, + "17": { + "INITIAL_BOX": "\u201cbut, where can--7", + "DEFAULT": "\"but, where can--7 |", + "DEFAULT_GREY_PAD": "Here can-- 2", + "PADDED_4": "(but, where can--7 |", + "PADDED_8": "(bu. where can--7 |", + "EXTRACTED_INIT_BOX": "But, where 4", + "PADDED_4_EXTRACTED": "But, where a", + "PADDED_8_EXTRACTED": "But, where a", + "PADDED_8_DILATION_1": "But, where a", + "PAD_8_FRACT_0_5": "But, where a", + "PAD_8_FRACT_0_2": "But, where a" + }, + "18": { + "INITIAL_BOX": "To0g ! keep her quiet!", + "DEFAULT": "To0g6! keep her quiet!", + "DEFAULT_GREY_PAD": "Ee x] too6 /", + "PADDED_4": "A yo06! keep her quiet?\u201d", + "PADDED_8": ", keep. her. quie te :", + "EXTRACTED_INIT_BOX": "T0006! keep mer quiet!", + "PADDED_4_EXTRACTED": "T0006! keep her quiet!", + "PADDED_8_EXTRACTED": "T0006! keep her quiet!", + "PADDED_8_DILATION_1": "Cg hi quie] 2", + "PAD_8_FRACT_0_5": "Toog ! keep her quiet!", + "PAD_8_FRACT_0_2": "Toog ! keep her quiet!" + }, + "19": { + "INITIAL_BOX": "Continue\u2019 after next page", + "DEFAULT": "Continue\u2019 after next page", + "DEFAULT_GREY_PAD": "Continue' \u2018after next page", + "PADDED_4": "Continue' after next page", + "PADDED_8": "Ee t\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014 continue! \"after next page", + "EXTRACTED_INIT_BOX": "Cont!nue' after next page", + "PADDED_4_EXTRACTED": "Cont!nue' after next page", + "PADDED_8_EXTRACTED": "Cont!nue' after next page", + "PADDED_8_DILATION_1": "Continue\u2019 after next page", + "PAD_8_FRACT_0_5": "Continue\u2019 after next page", + "PAD_8_FRACT_0_2": "Continue\u2019 after next page" + }, + "20": { + "INITIAL_BOX": "Bur he is an instant too late --", + "DEFAULT": "Bur he is an instant too late --", + "DEFAULT_GREY_PAD": "But he is | an instant | too late -~", + "PADDED_4": "Bur he 1s an instant too late =", + "PADDED_8": "Bur he 1s an instant too late -- eesti", + "EXTRACTED_INIT_BOX": "Bur he 1s an instant too late --", + "PADDED_4_EXTRACTED": "Bur he is an instant too late --", + "PADDED_8_EXTRACTED": "Bur he 1s an instant too late --", + "PADDED_8_DILATION_1": "Bur he is an instant too late -", + "PAD_8_FRACT_0_5": "Bur he 1s an instant too late --", + "PAD_8_FRACT_0_2": "Bur he 1s an instant too late --" + } + }, + "Transformers_-_Unicron_000-004.jpg": { + "1": { + "DEFAULT": "Platitudes are useless, prime, we have to hit that | thing\u2014now.", + "INITIAL_BOX": "| platitudes are useless, prime, we have to hit that thing\u2014now.", + "DEFAULT_GREY_PAD": "Latitudes ape useless, prime, we have to hit that thing\u2014now.", + "PADDED_4": "Platitudes 3 ape useless, prime, we have to ait that | thing now.", + "PADDED_8": "Y latitudes ape useless, prime, we have to hit that \\ thing\u2014now. 4", + "EXTRACTED_INIT_BOX": "Platitudes are useless, prime. we have to hit that thing \u2014now.", + "PADDED_4_EXTRACTED": "Platitudes ape useless, prime, we have to hit that thing\u2014now.", + "PADDED_8_EXTRACTED": "Latitudes. ape useless, prime, we have to hit that thing\u2014now.", + "PADDED_8_DILATION_1": "Latitudes. ape useless, prime, we have to hit that thing\u2014now.", + "PAD_8_FRACT_0_5": "Platitudes to hit that thing\u2014now.", + "PAD_8_FRACT_0_2": "Platitudes. are useless, prime, we have to hit that thing\u2014now." + }, + "0": { + "INITIAL_BOX": "Ra with the light of hope, there is always \"a chance for ac etoryy \u201d", + "DEFAULT": "With the light of hop: there is always a chance for \" \u201cictopy.", + "DEFAULT_GREY_PAD": "With the light of hope, there is always a chance for victory.", + "PADDED_4": "With the light of hope, there is always a chance for \\ victory. 4", + "PADDED_8": "With the a chance for victory.", + "EXTRACTED_INIT_BOX": "With the light of hope, there is always a chance for victory.", + "PADDED_4_EXTRACTED": "Wel ere there is always \u2018a chance for victory.", + "PADDED_8_EXTRACTED": "Py there is always \u2018a chance for victory.", + "PADDED_8_DILATION_1": "With the light of hope, there is always a chance for victory.", + "PAD_8_FRACT_0_5": "Py there 1s always \u2018a chance for victory.", + "PAD_8_FRACT_0_2": "El ore there is always \"a chance for victory." + }, + "2": { + "INITIAL_BOX": "Pyra magna. torchbearer.", + "DEFAULT": "Pyra magna. torchbearer.", + "DEFAULT_GREY_PAD": "Pyra magna. torchbearer.", + "PADDED_4": "Pyra magna. torchbearer.", + "PADDED_8": "R\u2014 pyra magna. torchbearer.", + "EXTRACTED_INIT_BOX": "Pyra magna. torchbearer.", + "PADDED_4_EXTRACTED": "Pyra magna. torchbearer.", + "PADDED_8_EXTRACTED": "Pyra magna. torchbearer.", + "PADDED_8_DILATION_1": "Pyra magna. torchbearer.", + "PAD_8_FRACT_0_5": "Pyra magna. torchbearer.", + "PAD_8_FRACT_0_2": "Pyra magna. torchbearer." + }, + "3": { + "INITIAL_BOX": "You know i've never run from a fight, pyra.", + "DEFAULT": "You know i've nevez run from wavy", + "DEFAULT_GREY_PAD": "You know i've never run from a fight, pypa.", + "PADDED_4": "You know tve never run from a 'fight, pyra.", + "PADDED_8": "Pou know ive 3 never run from a fight, pyra.", + "EXTRACTED_INIT_BOX": "You know ive never run from \"a fight, pyra.", + "PADDED_4_EXTRACTED": "You \u00a3now tve never run from a fight, pyra.", + "PADDED_8_EXTRACTED": "You \u00a3now tve never run from a fight, pyra.", + "PADDED_8_DILATION_1": "You know tve never run from a fight, pyra.", + "PAD_8_FRACT_0_5": "You know ive never run from a fight, pyra.", + "PAD_8_FRACT_0_2": "You know tve never run from a fight, pyra." + }, + "4": { + "INITIAL_BOX": "But even if this was winnable \u2014 and it clearly is not\u2014ask joursele..", + "DEFAULT": "R but even if this. hs winnable\u2014and it clearly is ot\u2014ask \\ yourself... /", + "DEFAULT_GREY_PAD": "But even if this was. winnable\u2014 and) it clearly is ry", + "PADDED_4": "P but even \"\\ piles winnable\u2014and fags [ot \u2014ask \\ it,", + "PADDED_8": "But even if this was winnable\u2014and it clearly is not\u2014ask yourself.", + "EXTRACTED_INIT_BOX": "But even if this was. winnable \u2014 and it clearly is not aske foubsele", + "PADDED_4_EXTRACTED": "But even if this was. winnable\u2014 and it clearly is not aske yourself.", + "PADDED_8_EXTRACTED": "But even if this was. winnable\u2014 and it clearly is not aske yourself.", + "PADDED_8_DILATION_1": "But even if this was. winnable\u2014and it clearly is not as yourself.", + "PAD_8_FRACT_0_5": "But even if this was. winnable\u2014and it clearly 1s not ask", + "PAD_8_FRACT_0_2": "But even if this was. winnable\u2014and it clearly 1s not ask yourself." + }, + "5": { + "INITIAL_BOX": "Did we me here to end lives or save them?", + "DEFAULT": "7 ..did we come here to end lives or save them? 4", + "DEFAULT_GREY_PAD": "Did we come here. \u00a9 end wes) them?", + "PADDED_4": "Did we come here to end lives or save them? 4", + "PADDED_8": "(em to end lives eee", + "EXTRACTED_INIT_BOX": "Did we to end lives oo save them?", + "PADDED_4_EXTRACTED": "Did we cone here to end lives oo save them?", + "PADDED_8_EXTRACTED": "Did we cone here to end lives oo save them?", + "PADDED_8_DILATION_1": "Did we come here to end lives or save them?", + "PAD_8_FRACT_0_5": "Did we come here to end lives or save them?", + "PAD_8_FRACT_0_2": "Did we come here to end lives or save them?" + }, + "6": { + "INITIAL_BOX": "/ thats where \u2122\\ 7 come in. this doohcreyil lrtate a world spanning shale bride ade bry hime enc cut a there.", + "DEFAULT": "That's where leer hs oobaae ll hreare wrb she bee weee be ne sing ctt h, beng ov", + "DEFAULT_GREY_PAD": "| that's where j", + "PADDED_4": "That's where z come in. this doohickey'll create a wobld-spannin' space bridge\u2014 and get every living being outta there.", + "PADDED_8": "That's where z come in. this doohickey'll create a wobld-spannin' space bridge\u2014 and get every living being outta there.", + "EXTRACTED_INIT_BOX": "That's where z come in. this doohickey ll create a wobld-spannin' space bridge and get every lving being outta there", + "PADDED_4_EXTRACTED": "That's where z come in. this doohickey'll create a wobld-spannin' space bridge and get every lving being outta there", + "PADDED_8_EXTRACTED": "That's where z come in. this doohickey'll create a wobld-spannin' space bridge and get every lving being outta there", + "PADDED_8_DILATION_1": "That's where z come in. this doohickey'll create a wobld-spannin'", + "PAD_8_FRACT_0_5": "That's where z come in. this doohickey'll create amoblespannin' space bridge adee re me being outta there", + "PAD_8_FRACT_0_2": "That's where z come in. this doohickey'll create a wobld-spannin'" + }, + "7": { + "INITIAL_BOX": "Ve pont now what this anomaly /8, or why it's doing this\u2014let alone how to stop something bigger than a planet", + "DEFAULT": "We don't n now what this anomaly /8, or why it's doing this\u2014let alone how to stop something bigger than a planet.", + "DEFAULT_GREY_PAD": "We don't now what this anomaly /8, or why it's doing this\u2014let alone", + "PADDED_4": "We don't. now what this anomaly /8, or why it's doing this\u2014let alone how to stop something bigger than a planet.", + "PADDED_8": "Y we don't ~n now what this anomaly /8, or why [t's doing. this\u2014let alone how to stop something bigger than a planet.", + "EXTRACTED_INIT_BOX": "We don't why t's doing this\u2014let alone how to stop something bigger than a planet", + "PADDED_4_EXTRACTED": "We don't now what this anomaly /8, or why t's doing this\u2014let alone how to stop something bigger than a planet.", + "PADDED_8_EXTRACTED": "We don't. why t's doing this\u2014let alone how to stop something bigger than a planet.", + "PADDED_8_DILATION_1": "We don't why t's doing this\u2014let alone how to stop something bigger than a planet.", + "PAD_8_FRACT_0_5": "We don't. this\u2014let alone how to stop something bigger than a planet.", + "PAD_8_FRACT_0_2": "We don't why ts doing this\u2014let alone how to stop something bigger than a planet." + }, + "8": { + "INITIAL_BOX": "The anomaly. is here because cur world called it.", + "DEFAULT": "| the anomaly is here because cur world called it. 4", + "DEFAULT_GREY_PAD": "The anomaly is heee because] our wobld called |", + "PADDED_4": "The anomaly is hebe because our wobld \\ called it. 4", + "PADDED_8": "P re anomaly 3 is hebe because", + "EXTRACTED_INIT_BOX": "The anomaly. is hebe because our wobld called it.", + "PADDED_4_EXTRACTED": "The anomaly. 1s hebe because our wobld called it.", + "PADDED_8_EXTRACTED": "The anomaly 1s hebe because our wobld called it.", + "PADDED_8_DILATION_1": "The anomaly is hebe because our world called it.", + "PAD_8_FRACT_0_5": "The anomaly is hee because our world called it.", + "PAD_8_FRACT_0_2": "The anomaly 18 heee because our world called it." + }, + "9": { + "INITIAL_BOX": "7 twill not \u00a9 let another. civilization die", + "DEFAULT": "7 twill not let another civilization die because of cybertron's ce actions.", + "DEFAULT_GREY_PAD": "I will not", + "PADDED_4": "I will not let another civilization die because of cybertron's \\ actiong.", + "PADDED_8": "I will not let another. civilization die", + "EXTRACTED_INIT_BOX": "I will not let another civilization die because of ybertron\" actions.", + "PADDED_4_EXTRACTED": "I will not let another civilization dig", + "PADDED_8_EXTRACTED": "I will not let another civilization dig", + "PADDED_8_DILATION_1": "I will not let another. civilization die because of ybertron\" c actions.", + "PAD_8_FRACT_0_5": "I will not let another civilization die because of cybertron's actions.", + "PAD_8_FRACT_0_2": "I will not let another civilization die because of vbertron\" c actions." + }, + "10": { + "INITIAL_BOX": "I appreciate the aid optimus prime...", + "DEFAULT": "T appreciate the aid, \u00a9 optimus prime...", + "DEFAULT_GREY_PAD": "I appreciate the add) optimus prime.", + "PADDED_4": "I appreciate the aid, \"optimus prime... |", + "PADDED_8": "I frm ie ote kr i appreciate the aid, optimus prive..", + "EXTRACTED_INIT_BOX": "I appreciate the aid optimus prime...", + "PADDED_4_EXTRACTED": "I appreciate the aid, optimus prime.", + "PADDED_8_EXTRACTED": "I appreciate the aid, optimus prime.", + "PADDED_8_DILATION_1": "I appreciate the aid, optimus prime...", + "PAD_8_FRACT_0_5": "I appreciate the aid, optimus prime...", + "PAD_8_FRACT_0_2": "T appreciate the aid, optimus prime." + }, + "11": { + "INITIAL_BOX": "Y' we just need about thirty of these suckees placed at strategic, uh, \"places.", + "DEFAULT": "Y we just need about thirty of these suckers", + "DEFAULT_GREY_PAD": "We just need about thirty of these suckers| placed at strategic, uh,", + "PADDED_4": "We just nls rs on i ees eve bh stesecl", + "PADDED_8": "We just need about thirty of these suckers placed at strategic, uh, place:", + "EXTRACTED_INIT_BOX": "We just need about thirty of these suckees placed at strategic, uh, places.", + "PADDED_4_EXTRACTED": "We just need about thirty of these suckers placed at strategic, uh, places.", + "PADDED_8_EXTRACTED": "We just need about thirty of these suckers placed at strategic, uh, places.", + "PADDED_8_DILATION_1": "We just need about thirty of these suckers placed at strategic, uh, places.", + "PAD_8_FRACT_0_5": "We just need about these suckers placed at strategic, uh,", + "PAD_8_FRACT_0_2": "We just need about thirty of these suckers placed at strategic, uh, places." + }, + "12": { + "INITIAL_BOX": "On loma, wk cai wes:", + "DEFAULT": "On loma, wk rar wes:", + "DEFAULT_GREY_PAD": "Wk 2a]", + "PADDED_4": "On loma, wk rar wes:", + "PADDED_8": "Wes:", + "EXTRACTED_INIT_BOX": "2 wk zr wi 5", + "PADDED_4_EXTRACTED": "Pp wk zr wi 5", + "PADDED_8_EXTRACTED": "Pp wk zr wi 5", + "PADDED_8_DILATION_1": "On loma, wk rar wes:", + "PAD_8_FRACT_0_5": "Oma, qin bled", + "PAD_8_FRACT_0_2": "Reg" + }, + "13": { + "INITIAL_BOX": "Wheeljack. mad scientist.", + "DEFAULT": "Wheeljack. mad scientist.", + "DEFAULT_GREY_PAD": "Wheeljack. mad scientis", + "PADDED_4": "Wheeljack. mad scientist.", + "PADDED_8": "Wheeljack. mad scientist", + "EXTRACTED_INIT_BOX": "Wheeljack. mad scientist.", + "PADDED_4_EXTRACTED": "Wheeljack. mad scientist.", + "PADDED_8_EXTRACTED": "Wheeljack. mad scientist.", + "PADDED_8_DILATION_1": "Wheeljack. mad scientist.", + "PAD_8_FRACT_0_5": "Wheeljack. mad scientist.", + "PAD_8_FRACT_0_2": "Wheeljack, mad scientist." + }, + "14": { + "INITIAL_BOX": "Yet surely you die not believe the solstar order. would be without its own defences.", + "DEFAULT": "7 yet surely you die not believe the solstar order would be without ts. \"own defenges.", + "DEFAULT_GREY_PAD": "Yet surely you di not believe the solstar order. would be without it: on defenzes.", + "PADDED_4": "Yet surely you die not believe the solstar order. would be without its. \\ own defenses.", + "PADDED_8": "Yet surely you 4 die not believe the solstar order. would be without its. own defenses.", + "EXTRACTED_INIT_BOX": "Yet surely you dib not believe the solstar order, would be without 175 own defences.", + "PADDED_4_EXTRACTED": "Yet surely you, dib not believe the solstar order, would be without its. own defenges.", + "PADDED_8_EXTRACTED": "Yet surely you dib not believe the solstar order, would be without its. own defenses.", + "PADDED_8_DILATION_1": "Yet surely you die not believe the solstar order. would be without its. own defenses.", + "PAD_8_FRACT_0_5": "Yet surely you own defenses.", + "PAD_8_FRACT_0_2": "Yet surely you, dib not believe the solstar order. would be without 178 own defenses." + }, + "15": { + "INITIAL_BOX": "Rom was the", + "DEFAULT": "Rom was the warriors the cosmos ras ever known.", + "DEFAULT_GREY_PAD": "Rom was the fibst of the", + "PADDED_4": "Rom was the warriors the cosmos ras ever known.", + "PADDED_8": "| 2op was the warriors the | cosmos has. ever known.", + "EXTRACTED_INIT_BOX": "Rom was the", + "PADDED_4_EXTRACTED": "Rom was the warriors the cosmos ras ever known.", + "PADDED_8_EXTRACTED": "Rom was the warriors the cosmos ras ever known...", + "PADDED_8_DILATION_1": "Rom was the warriors the cosmos has ever known...", + "PAD_8_FRACT_0_5": "Rom was the", + "PAD_8_FRACT_0_2": "Rom was the warriors the cosmos has ever known..." + } + }, + "Transformers_-_Unicron_000-016.jpg": { + "1": { + "DEFAULT": "Planet called lv-217 some years ago. 4" + } + }, + "WARE_ACME_024.jpg": { + "1": { + "DEFAULT": "Almost done...", + "INITIAL_BOX": "Almost done.", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Almost done...", + "PADDED_8": "Almost done...", + "EXTRACTED_INIT_BOX": "Almost done.", + "PADDED_4_EXTRACTED": "Almost done...", + "PADDED_8_EXTRACTED": "Almost done...", + "PADDED_8_DILATION_1": "Almost done...", + "PAD_8_FRACT_0_5": "Almost done...", + "PAD_8_FRACT_0_2": "Almost done..." + }, + "0": { + "INITIAL_BOX": "134 & olyph", + "DEFAULT": "8 glyph", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Lil & glyph", + "PADDED_8": "Sle & glyph", + "EXTRACTED_INIT_BOX": "Ie if a i ja j] wy by; \u00ae uy", + "PADDED_4_EXTRACTED": "== es ? \u2014 \u201c", + "PADDED_8_EXTRACTED": "Ie oly wh", + "PADDED_8_DILATION_1": "\u00a7lyph", + "PAD_8_FRACT_0_5": "Glyph", + "PAD_8_FRACT_0_2": "Glyph" + }, + "2": { + "INITIAL_BOX": "Oh hey, 1--", + "DEFAULT": "Oh hey, 1--", + "DEFAULT_GREY_PAD": "Oh", + "PADDED_4": "Oh hey, 1--", + "PADDED_8": "Oh hey, 1--", + "EXTRACTED_INIT_BOX": "Oh hey, 1", + "PADDED_4_EXTRACTED": "Oh hey, t", + "PADDED_8_EXTRACTED": "Oh hey, 1", + "PADDED_8_DILATION_1": "Oh hey, 1", + "PAD_8_FRACT_0_5": "Oh hey, 1", + "PAD_8_FRACT_0_2": "Oh hey, 1" + }, + "3": { + "INITIAL_BOX": "Pinnacle of", + "DEFAULT": "Dinnacie of", + "DEFAULT_GREY_PAD": "Dinn3cie +", + "PADDED_4": "Pinnacle o", + "PADDED_8": "Pinnacle of", + "EXTRACTED_INIT_BOX": "", + "PADDED_4_EXTRACTED": "", + "PADDED_8_EXTRACTED": "Os", + "PADDED_8_DILATION_1": "Dinnacle \u00ab", + "PAD_8_FRACT_0_5": "Pinnacle \u00abf", + "PAD_8_FRACT_0_2": "Dinnacle \u00ab" + }, + "4": { + "INITIAL_BOX": "Arr \u2014\u2014te er ren man oh man... that sure was one heckuva orgy last night... whew/", + "DEFAULT": "Re eas p.t. man oh man... that sure was one heckuva orgy last night... whew/", + "DEFAULT_GREY_PAD": "Man oh man... that sure was one heckuva orgy last night... whew/", + "PADDED_4": "Aree ane dn \u2014\u2014 man oh man... that sure was one heckuva orgy last night... whew/", + "PADDED_8": "J se en es man oh man... that sure was one heckuva orgy last night... whew/", + "EXTRACTED_INIT_BOX": "Man oh man... that sure was one heckuva orgy last night... whew/", + "PADDED_4_EXTRACTED": "Man oh man... that sure was one heckuva orgy last night... whew/", + "PADDED_8_EXTRACTED": "Man oh man... that sure was one heckuva orgy last night... whew/", + "PADDED_8_DILATION_1": "Man oh man... that sure was one heckuva orgy last night... whew/", + "PAD_8_FRACT_0_5": "Man oh man... that sure was one heckuva orgy last night... whew/", + "PAD_8_FRACT_0_2": "Man oh man... that sure was one heckuva orgy last night... whew/" + }, + "5": { + "INITIAL_BOX": "I bl ai yu | 3", + "DEFAULT": "= 3 \u00a3\u00a3)", + "DEFAULT_GREY_PAD": "Sumer", + "PADDED_4": "I ba n | | bb p a | we come. ros", + "PADDED_8": "Gumer|", + "EXTRACTED_INIT_BOX": "Ma. oy pos", + "PADDED_4_EXTRACTED": "Hl 1 er 2 oy r [pons", + "PADDED_8_EXTRACTED": "My <& s =i", + "PADDED_8_DILATION_1": "1) fa suter", + "PAD_8_FRACT_0_5": "\" 5", + "PAD_8_FRACT_0_2": "Qumep frid" + }, + "6": { + "INITIAL_BOX": "- oh. ic ooe i j =5 a", + "DEFAULT": "4 ce iy in 1 = e nd", + "DEFAULT_GREY_PAD": "Bh, those jews", + "PADDED_4": "Ud )s", + "PADDED_8": "W hry) es fe 4 s", + "EXTRACTED_INIT_BOX": "sight", + "DEFAULT_GREY_PAD": "N a sigh", + "PADDED_4": "2sight", + "PADDED_8": "3 sigh?", + "EXTRACTED_INIT_BOX": ">sigh?", + "PADDED_4_EXTRACTED": "Ssigh?", + "PADDED_8_EXTRACTED": "Ssight", + "PADDED_8_DILATION_1": "Ssight", + "PAD_8_FRACT_0_5": "Sight", + "PAD_8_FRACT_0_2": "Ssight" + } + }, + "ronson-031.jpg": { + "5": { + "INITIAL_BOX": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre mieses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "DEFAULT": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre meses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "DEFAULT_GREY_PAD": "Recuerdo a aquellos segadores abriendose paso entre mieses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PADDED_4": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre meses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PADDED_8": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre meses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "EXTRACTED_INIT_BOX": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre mieses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PADDED_4_EXTRACTED": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre mieses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PADDED_8_EXTRACTED": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre mieses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PADDED_8_DILATION_1": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre mieses doradas, hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PAD_8_FRACT_0_5": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre mieses doradas; hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras.", + "PAD_8_FRACT_0_2": "Recuerdo a aquellos segadores abri\u00e9ndose paso entre mieses doradas; hoz y zoqueta en ristre, con la \u00fanica compa\u00f1\u00eda de las chicharras." + }, + "0": { + "INITIAL_BOX": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprend\u00ed al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "DEFAULT": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "DEFAULT_GREY_PAD": "En una visita reciente ala casa despu\u00e9s de uchas d\u00e9cadas, me sorprend\u00ed al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_4": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_8": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "EXTRACTED_INIT_BOX": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_4_EXTRACTED": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_8_EXTRACTED": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PADDED_8_DILATION_1": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PAD_8_FRACT_0_5": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto.", + "PAD_8_FRACT_0_2": "En una visita reciente ala casa despu\u00e9s de muchas decadas, me sorprendi al ver el abrevadero. lo recordaba mucho m\u00e1s alto." + }, + "1": { + "INITIAL_BOX": "Junto al abrevadero crec\u00eda el vigoroso troncc de una gran parra, que trepaba h\u00e1bilmente la tapia...", + "DEFAULT": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia...", + "DEFAULT_GREY_PAD": "Unto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia...", + "PADDED_4": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia.,", + "PADDED_8": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia.,", + "EXTRACTED_INIT_BOX": "Junto al abrevadero crec\u00eda el vigoroso troncc de una gran parra, que trepaba h\u00e1bilmente la tapia...", + "PADDED_4_EXTRACTED": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia...", + "PADDED_8_EXTRACTED": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia...", + "PADDED_8_DILATION_1": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia..,", + "PAD_8_FRACT_0_5": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia...", + "PAD_8_FRACT_0_2": "Junto al abrevadero crec\u00eda el vigoroso tronco de una gran parra, que trepaba h\u00e1bilmente la tapia..." + }, + "2": { + "INITIAL_BOX": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "DEFAULT": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "DEFAULT_GREY_PAD": "", + "PADDED_4": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "PADDED_8": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "EXTRACTED_INIT_BOX": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "PADDED_4_EXTRACTED": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "PADDED_8_EXTRACTED": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "PADDED_8_DILATION_1": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "PAD_8_FRACT_0_5": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino.", + "PAD_8_FRACT_0_2": "Supongo que este recuerdo tramposo revela la escala que tiene el mundo cuando eres un nino." + }, + "3": { + "INITIAL_BOX": "Ys es mete -rtizo \u00f1 tra mt ele ade e a 3", + "DEFAULT": "Ps ae ie nac estrenos", + "DEFAULT_GREY_PAD": "Y se/extend\u00eda hasta el \u00a1cobertizo de entrada: hacia: principio. del verano luc\u00eda, sus exuberantes hojas y/comenzaba ya a/florecer..", + "PADDED_4": "Mate ln y ,cober z 'trada a com ao le a , h jas y/comenzaba, ya an y", + "PADDED_8": "Js ee amastae cobertizo e as a la e rada. 70 \u00a1com za! y ya > ec 4 y a", + "EXTRACTED_INIT_BOX": "Y se extend\u00eda hasta el cobertizo de entrada. hacia principio del verano luc\u00eda sus exuberantes hojas y comenzaba ya a florecer.", + "PADDED_4_EXTRACTED": "Y se extend\u00eda hasta el cobertizo de entrada. hacia principio del verano luc\u00eda sus exuberantes hojas y comenzaba ya a florecer.", + "PADDED_8_EXTRACTED": "Y se extend\u00eda hasta el cobertizo de entrada. hacia principio del verano luc\u00eda sus exuberantes hojas y comenzaba ya a florecer.", + "PADDED_8_DILATION_1": "Y se extend\u00eda hasta el cobertizo de entrada. hacia principio del verano luc\u00eda sus exuberantes hojas y comenzaba ya a florecer.", + "PAD_8_FRACT_0_5": "Y se extend\u00eda hasta el cobertizo de entrada. hacia principio del verano luc\u00eda sus exuberantes hojas y comenzaba ya a florecer.", + "PAD_8_FRACT_0_2": "Y se extend\u00eda hasta el cobertizo de entrada. hacia principio del verano luc\u00eda sus exuberantes hojas y comenzaba ya a florecer." + }, + "4": { + "INITIAL_BOX": "Era entonces cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el dia y se extend\u00eda de sol a sol.", + "DEFAULT": "Era entonces cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el d\u00eda y se extend\u00eda de sol a sol.", + "DEFAULT_GREY_PAD": "Era entonces cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el d\u00eda y se extend\u00eda de sol a sol,", + "PADDED_4": "Era entonces cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el d\u00eda y se extend\u00eda de sol a sol.", + "PADDED_8": "Era entonces cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntaba el d\u00eda y se extend\u00eda de sol a sol.", + "EXTRACTED_INIT_BOX": "El e e! fs, y \u00a1a h 4 pb e e a 5 2 mi e) 2 js lo a ni ny to a, ) y vd a sn e. y \u00f1 e > di y e o la", + "PADDED_4_EXTRACTED": "A e e \u201c4 7 ane 25 n \u00a1 es ji in ye mi in ma \u00bb a e ss e) un 3 lo a, a y n gia pa do a \u00ed s nn \u00a1y pe n la y e", + "PADDED_8_EXTRACTED": "A 20 fs, el e n nd y 3 \u00bf4 e gd dol y o y un ys \u00a1e y 308 a 2 \u00ed en =n y pe da \u00bf5", + "PADDED_8_DILATION_1": "Era entonces cuando daba comenzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntara el, d\u00eda y se extend\u00eda de sol a sol.", + "PAD_8_FRACT_0_5": "Ndo n pr e in la )nces e e nu y del cer a, jo nada se in \u00a1ab\u00e1 in ej ar n dr =, un pr int \u00fa o espui antas el dia y se dl la sa fe a de k sel", + "PAD_8_FRACT_0_2": "Era entonces cuando daba comienzo la cosecha del cereal. la jornada se iniciaba tan pronto despuntasa el d\u00eda y se extend\u00eda de sol a sol." + } + } + }, + "Tesseract-crop": {} + } +} \ No newline at end of file diff --git a/pcleaner/_testbed/experiment/cache/.gitkeep b/pcleaner/_testbed/experiment/cache/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/pcleaner/_testbed/experiment/source/.gitkeep b/pcleaner/_testbed/experiment/source/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/pcleaner/_testbed/nbs/experiments.ipynb b/pcleaner/_testbed/nbs/experiments.ipynb new file mode 100644 index 00000000..bde864b5 --- /dev/null +++ b/pcleaner/_testbed/nbs/experiments.ipynb @@ -0,0 +1,7640 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "#| default_exp testbed/experiments" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "from __future__ import annotations\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "# %reload_ext autoreload\n", + "# %autoreload 0\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# try: \n", + "# import fastcore as FC\n", + "# except ImportError: \n", + "# !pip install -q fastcore\n", + "# try:\n", + "# import rich\n", + "# except ImportError:\n", + "# !pip install -q rich\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip uninstall Pillow" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install \"pillow<10.1.0,>=8.3.2\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> **Note: we're using the `testbed` branch of PanelCleaner.**" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed-colab" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PanelCleaner Testbed\n", + "> An PanelCleaner space to explore, play, colaborate and experiment with ML/DL techniques.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "import contextlib\n", + "import dataclasses\n", + "import datetime\n", + "import difflib\n", + "import functools\n", + "import json\n", + "import os\n", + "import shutil\n", + "import tempfile\n", + "from collections import defaultdict\n", + "from enum import Enum\n", + "from pathlib import Path\n", + "from typing import Any\n", + "from typing import Callable\n", + "from typing import cast\n", + "from typing import Mapping\n", + "from typing import TypeAlias\n", + "\n", + "import fastcore.all as FC\n", + "import ipywidgets as W\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import pcleaner.config as cfg\n", + "import pcleaner.ctd_interface as ctm\n", + "import pcleaner.image_ops as ops\n", + "import pcleaner.ocr.ocr as ocr\n", + "import pcleaner.structures as st\n", + "import torch\n", + "import traitlets as T\n", + "from IPython.display import clear_output\n", + "from IPython.display import display\n", + "from IPython.display import HTML\n", + "from loguru import logger\n", + "from pcleaner.ocr.ocr_tesseract import TesseractOcr\n", + "from PIL import Image\n", + "from PIL import ImageFilter\n", + "from rich.console import Console\n", + "from tqdm.notebook import tqdm\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "from pcleaner._testbed.testbed.helpers import *\n", + "from pcleaner._testbed.testbed.ocr_metric import *\n", + "from pcleaner._testbed.testbed.visor import ContextVisor\n", + "from pcleaner._testbed.testbed.visor import Spinner\n", + "import pcleaner._testbed.testbed.web_server as web_server\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "import copy\n", + "import re\n", + "from contextlib import ExitStack\n", + "from typing import Protocol\n", + "\n", + "import fastcore.xtras # patch `Path` with some utils (like `ls()` to list folder contents)\n", + "import pcleaner.cli_utils as cli\n", + "import pcleaner.preprocessor as pp\n", + "import pytesseract\n", + "import rich\n", + "from fastcore.test import * # type: ignore\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Helpers" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "# pretty print by default\n", + "# %load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| exporti\n", + "console = Console(width=104, tab_size=4, force_jupyter=True)\n", + "cprint = console.print\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## USE_PIL" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n", + "\n", + "Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n", + "- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n", + "- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n", + "\n", + "You choose.\n", + "\n", + "If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "os.environ['USE_PIL'] = 'False'\n", + "os.environ['USE_TUNNEL'] = 'False'\n", + "SERVER = None\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tesseract setup" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get current version of Tesseract" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n",
+       "    'tesseract 5.3.4',\n",
+       "    ' leptonica-1.84.1',\n",
+       "    '  libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : \n",
+       "libwebp 1.4.0 : libopenjp2 2.5.2',\n",
+       "    ' Found NEON',\n",
+       "    ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n",
+       "    ' Found libcurl/8.6.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.12 nghttp2/1.61.0'\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'tesseract 5.3.4'\u001b[0m,\n", + " \u001b[32m' leptonica-1.84.1'\u001b[0m,\n", + " \u001b[32m' libgif 5.2.1 : libjpeg 8d \u001b[0m\u001b[32m(\u001b[0m\u001b[32mlibjpeg-turbo 3.0.0\u001b[0m\u001b[32m)\u001b[0m\u001b[32m : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : \u001b[0m\n", + "\u001b[32mlibwebp 1.4.0 : libopenjp2 2.5.2'\u001b[0m,\n", + " \u001b[32m' Found NEON'\u001b[0m,\n", + " \u001b[32m' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6'\u001b[0m,\n", + " \u001b[32m' Found libcurl/8.6.0 SecureTransport \u001b[0m\u001b[32m(\u001b[0m\u001b[32mLibreSSL/3.3.6\u001b[0m\u001b[32m)\u001b[0m\u001b[32m zlib/1.2.12 nghttp2/1.61.0'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "out = !tesseract --version # type: ignore\n", + "cprint(out)\n", + "if 'tesseract 5.' not in out[0]:\n", + " if 'tesseractd 4.' in out[0]:\n", + " cprint('Old Tesseract 4.x is installed. You should uninstall it and install Tesseract 5.x')\n", + " else:\n", + " cprint('You should install Tesseract 5.x')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> **NOTE: in below cells, when you encounter lines starting with the exclamation mark `!` (`bang`), uncoment them if you want to excute the shell commands**\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Remove Tesseract installation\n", + "> I you have the old 4.x version, you should consider removing the installation with the following commands.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Mac (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### WIndows (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Ubuntu" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo apt-get remove tesseract-ocr\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tesseract installation" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Mac (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### WIndows (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Ubuntu" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The **5.x** release series is available in the [another PPA](https://launchpad.net/~alex-p/+archive/ubuntu/tesseract-ocr5) for Ubuntu **18.04**, **20.04**, and **22.04**.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo add-apt-repository -y ppa:alex-p/tesseract-ocr5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "refresh system package cache in case you’re still running old Ubuntu 18.04" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo apt update" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "install the software engine" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo apt install -y tesseract-ocr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and check version:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n",
+       "    'tesseract 5.3.4',\n",
+       "    ' leptonica-1.84.1',\n",
+       "    '  libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : \n",
+       "libwebp 1.4.0 : libopenjp2 2.5.2',\n",
+       "    ' Found NEON',\n",
+       "    ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n",
+       "    ' Found libcurl/8.6.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.12 nghttp2/1.61.0'\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'tesseract 5.3.4'\u001b[0m,\n", + " \u001b[32m' leptonica-1.84.1'\u001b[0m,\n", + " \u001b[32m' libgif 5.2.1 : libjpeg 8d \u001b[0m\u001b[32m(\u001b[0m\u001b[32mlibjpeg-turbo 3.0.0\u001b[0m\u001b[32m)\u001b[0m\u001b[32m : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : \u001b[0m\n", + "\u001b[32mlibwebp 1.4.0 : libopenjp2 2.5.2'\u001b[0m,\n", + " \u001b[32m' Found NEON'\u001b[0m,\n", + " \u001b[32m' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6'\u001b[0m,\n", + " \u001b[32m' Found libcurl/8.6.0 SecureTransport \u001b[0m\u001b[32m(\u001b[0m\u001b[32mLibreSSL/3.3.6\u001b[0m\u001b[32m)\u001b[0m\u001b[32m zlib/1.2.12 nghttp2/1.61.0'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "out = !tesseract --version # type: ignore\n", + "cprint(out)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install Tesseract languages" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
tessdata path: /opt/homebrew/share/tessdata\n",
+       "
\n" + ], + "text/plain": [ + "tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Installed languages:\n",
+       "[\n",
+       "    'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n",
+       "    'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, \n",
+       "epo',\n",
+       "    'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n",
+       "    'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n",
+       "    'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n",
+       "    'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n",
+       "    'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, \n",
+       "script/Canadian_Aboriginal, script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, \n",
+       "script/Fraktur',\n",
+       "    'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, \n",
+       "script/HanT, script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, \n",
+       "script/Japanese_vert, script/Kannada, script/Khmer',\n",
+       "    'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, \n",
+       "script/Syriac, script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, \n",
+       "script/Vietnamese, sin, slk',\n",
+       "    'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n",
+       "    'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "Installed languages:\n", + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces'\u001b[0m,\n", + " \u001b[32m'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, \u001b[0m\n", + "\u001b[32mepo'\u001b[0m,\n", + " \u001b[32m'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc'\u001b[0m,\n", + " \u001b[32m'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert'\u001b[0m,\n", + " \u001b[32m'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal'\u001b[0m,\n", + " \u001b[32m'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol'\u001b[0m,\n", + " \u001b[32m'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, \u001b[0m\n", + "\u001b[32mscript/Canadian_Aboriginal, script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, \u001b[0m\n", + "\u001b[32mscript/Fraktur'\u001b[0m,\n", + " \u001b[32m'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, \u001b[0m\n", + "\u001b[32mscript/HanT, script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, \u001b[0m\n", + "\u001b[32mscript/Japanese_vert, script/Kannada, script/Khmer'\u001b[0m,\n", + " \u001b[32m'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, \u001b[0m\n", + "\u001b[32mscript/Syriac, script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, \u001b[0m\n", + "\u001b[32mscript/Vietnamese, sin, slk'\u001b[0m,\n", + " \u001b[32m'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel'\u001b[0m,\n", + " \u001b[32m'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "out = !tesseract --list-langs # type: ignore\n", + "tessdata = Path(out[0].split('\"')[1])\n", + "cprint(f\"tessdata path: {tessdata}\")\n", + "cprint(\"Installed languages:\", [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Install **best** languages and **jpn_ver** Tesseract lang\n", + "> Much better results than default langs and `jpn` language model.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best). \n", + "Donwload from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) a model trained for vertical Japanese text as found in manga.\n", + "\n", + "See [here](https://tesseract-ocr.github.io/tessdoc/Data-Files-in-different-versions.html) the languages codes.\n", + "\n", + "> Note: I've not play much with `jpn` or `jpn_vert`, `manag-ocr` is surely a much better fit, but it can be educational to compare." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uncomment and excute to download the best language models:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/osd.traineddata\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/eng.traineddata\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn.traineddata\n", + "\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn_vert.traineddata\n", + "# or\n", + "# !wget -O jpn_vert.traineddata https://github.com/zodiac3539/jpn_vert/blob/master/jpn_ver5.traineddata\n", + "\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/spa.traineddata\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/fra.traineddata" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Copy downloaded models to tessdata folder (double check that `tessdata` variable points to the right folder):\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
tessdata path: /opt/homebrew/share/tessdata\n",
+       "
\n" + ], + "text/plain": [ + "tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint(f\"tessdata path: {tessdata}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo mv *.traineddata $tessdata" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and remove the downloaded models:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# !rm *.traineddata" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check installed languages\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n",
+       "    Path('/opt/homebrew/share/tessdata/spa.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/eng.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/jpn_vert.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/spa_old.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/fra.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/jpn.traineddata')\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/eng.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn_vert.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa_old.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/fra.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint(list(filter(lambda x: re.match(r'eng|jpn|jpn_vert|fra|spa', x.name), tessdata.ls()))) # type: ignore\n", + "# cprint(pytesseract.get_languages())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OCR results clean-up" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def remove_multiple_whitespaces(text):\n", + " return ' '.join(text.split())\n", + "\n", + " \n", + "def postprocess_ocr(text):\n", + " \"Basic postprocessing for English Tesseract OCR results.\"\n", + " return ' '.join(remove_multiple_whitespaces(text).splitlines()).capitalize()\n", + "\n", + "def accuracy_ocr_naive(text, ground_truth):\n", + " return sum(1 for a, b in zip(text, ground_truth) if a == b) / len(text)\n", + "\n", + "\n", + "def accuracy_ocr_difflib(text, ground_truth):\n", + " \"\"\"\n", + " Calculates the OCR accuracy based on the similarity between the OCR text and the ground truth text,\n", + " using difflib's SequenceMatcher to account for differences in a manner similar to git diffs.\n", + "\n", + " :param text: The OCR-generated text.\n", + " :param ground_truth: The ground truth text.\n", + " :return: A float representing the similarity ratio between the OCR text and the ground truth, \n", + " where 1.0 is identical.\n", + " \"\"\"\n", + " # Initialize the SequenceMatcher with the OCR text and the ground truth\n", + " matcher = difflib.SequenceMatcher(None, text, ground_truth)\n", + " \n", + " # Get the similarity ratio\n", + " similarity_ratio = matcher.ratio()\n", + " \n", + " return similarity_ratio" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Ground truth" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def ground_truth_path(page_data: st.PageData):\n", + " path = Path(page_data.original_path)\n", + " return path.with_stem(path.stem + '_gt').with_suffix('.txt')\n", + "\n", + "\n", + "def read_ground_truth(page_data: st.PageData, root_dir: Path):\n", + " gts_path = root_dir / ground_truth_path(page_data)\n", + " if gts_path.exists():\n", + " gts = gts_path.read_text(encoding=\"utf-8\").splitlines()\n", + " else:\n", + " gts = [\"\" for _ in range(len(page_data.boxes))]\n", + " return gts\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "source": [ + "## Cropping" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def dilate_by_fractional_pixel(image, dilation_fraction, filter_base_size=3):\n", + " \"\"\"\n", + " Dilates an image by a specified fractional pixel amount. The function calculates \n", + " the necessary scaling factor and filter size based on the desired dilation fraction.\n", + "\n", + " :param image: A PIL Image object (1-bit mode).\n", + " :param dilation_fraction: The desired fractional pixel amount for dilation (e.g., 0.2).\n", + " :param filter_base_size: The base size of the dilation filter to apply on the scaled image.\n", + " This size is adjusted based on the scaling factor to achieve the\n", + " desired dilation effect.\n", + " :return: A PIL Image object after dilation, converted back to grayscale.\n", + " \"\"\"\n", + " from PIL.Image import Resampling\n", + " # Calculate the scale factor based on the desired dilation fraction\n", + " scale_factor = int(1 / dilation_fraction)\n", + " \n", + " # Adjust the filter size based on the scale factor\n", + " # This ensures the dilation effect is proportional to the desired fraction\n", + " filter_size = max(1, filter_base_size * scale_factor // 5)\n", + "\n", + " # Convert the image to grayscale for more nuanced intermediate values\n", + " image_gray = image.convert(\"L\")\n", + "\n", + " # Resize the image to a larger size using bicubic interpolation\n", + " larger_size = (int(image.width * scale_factor), int(image.height * scale_factor))\n", + " image_resized = image_gray.resize(larger_size, Resampling.BICUBIC)\n", + "\n", + " # Apply the dilation filter to the resized image\n", + " dilated_image = image_resized.filter(ImageFilter.MaxFilter(filter_size))\n", + "\n", + " # Resize the image back to its original size using bicubic interpolation\n", + " image_dilated_fractional_pixel = dilated_image.resize(image.size, Resampling.BICUBIC)\n", + "\n", + " return image_dilated_fractional_pixel\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "def extract_text(image, text_mask, box):\n", + " cropped_image = crop_box(box, image)\n", + " cropped_mask = crop_box(box, text_mask)\n", + " extracted = ops.extract_text(cropped_image, cropped_mask)\n", + " return cropped_image, cropped_mask, extracted\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lang\n", + "> language name to a language code \n", + "> every one has language codes: tesseract, comic-text-detector, earthlings...\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "_lang2pcleaner = {'English': st.DetectedLang.ENG, 'Japanese': st.DetectedLang.JA, 'Spanish': st.DetectedLang.ENG,\n", + " 'French':st.DetectedLang.ENG}\n", + "# _lang2tesseract = {'English': 'eng', 'Japanese': 'jpn'}\n", + "_lang2tesseract = {'English': 'eng', 'Japanese': 'jpn_vert', 'Spanish': 'spa', 'French': 'fra'}\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "def lang2pcleaner(lang: str):\n", + " return _lang2pcleaner[lang]\n", + "\n", + "def lang2tesseract(lang: str):\n", + " return _lang2tesseract[lang]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Experiments helpers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## CropMethod\n", + "> Box cropping methods.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "notebookRunGroups": { + "groupValue": "1" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class CropMethod(Enum):\n", + " INITIAL_BOX = 'Initial box'\n", + " DEFAULT = 'Default'\n", + " DEFAULT_GREY_PAD = 'Default, grey pad'\n", + " PADDED_4 = 'Padded 4px'\n", + " PADDED_8 = 'Padded 8px'\n", + " EXTRACTED_INIT_BOX = 'Extracted, init box'\n", + " PADDED_4_EXTRACTED = 'Padded 4, extracted'\n", + " PADDED_8_EXTRACTED = 'Padded 8, extracted'\n", + " PADDED_8_DILATION_1 = 'Padded 8, dilation 1'\n", + " PAD_8_FRACT_0_5 = 'Pad 8, fract. 0.5'\n", + " PAD_8_FRACT_0_2 = 'Pad 8, fract. 0.2'\n", + "\n", + " @classmethod\n", + " def __display_names__(cls):\n", + " return dict(\n", + " zip([_.value for _ in cls], \n", + " cls))\n", + "\n", + "\n", + "CM = CropMethod\n", + "\n", + "_IMAGE_METHODS = [CM.INITIAL_BOX, CM.DEFAULT, CM.DEFAULT_GREY_PAD, \n", + " CM.PADDED_4, CM.PADDED_8]\n", + "_EXTRACTED_METHODS = [CM.EXTRACTED_INIT_BOX, CM.PADDED_4_EXTRACTED, \n", + " CM.PADDED_8_EXTRACTED, CM.PADDED_8_DILATION_1, \n", + " CM.PAD_8_FRACT_0_5, CM.PAD_8_FRACT_0_2]\n", + "\n", + "\n", + "def crop_by_image(method: CM, \n", + " box: st.Box, \n", + " base: Image.Image, \n", + " preproc: cfg.PreprocessorConfig,\n", + " ):\n", + " image = None\n", + " match method:\n", + " case CM.INITIAL_BOX :\n", + " image = crop_box(box, base)\n", + " case CM.DEFAULT:\n", + " padded2_4 = (\n", + " box.pad(preproc.box_padding_initial, base.size).right_pad(\n", + " preproc.box_right_padding_initial, base.size))\n", + " image = crop_box(padded2_4, base)\n", + " case CM.DEFAULT_GREY_PAD:\n", + " image = crop_box(box, base)\n", + " image = ops.pad_image(image, 8, fill_color=(128, 128, 128))\n", + " case CM.PADDED_4:\n", + " padded4 = box.pad(4, base.size)\n", + " image = crop_box(padded4, base)\n", + " case CM.PADDED_8:\n", + " padded4 = box.pad(8, base.size)\n", + " image = crop_box(padded4, base)\n", + " case _: pass\n", + " return image\n", + "\n", + "\n", + "def crop_by_extracted(method: CM, \n", + " box: st.Box, \n", + " base: Image.Image, \n", + " mask: Image.Image,\n", + " cropped_image_path: Path,\n", + " cropped_mask_path: Path,\n", + " dilated: dict[float, Image.Image]\n", + " ):\n", + " cropped_image, cropped_mask, image = None, None, None\n", + " if method in _EXTRACTED_METHODS:\n", + " if not cropped_image_path.exists() or not cropped_mask_path.exists():\n", + " match method:\n", + " case CM.EXTRACTED_INIT_BOX:\n", + " cropped_image, cropped_mask, image = extract_text(base, mask, box)\n", + " case CM.PADDED_4_EXTRACTED:\n", + " padded4 = box.pad(4, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(base, mask, padded4)\n", + " case CM.PADDED_8_EXTRACTED:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(base, mask, padded8)\n", + " case CM.PADDED_8_DILATION_1:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(\n", + " base, dilated[1], padded8)\n", + " case CM.PAD_8_FRACT_0_5:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(\n", + " base, dilated[0.5], padded8)\n", + " case CM.PAD_8_FRACT_0_2:\n", + " padded8 = box.pad(8, base.size)\n", + " cropped_image, cropped_mask, image = extract_text(\n", + " base, dilated[0.2], padded8)\n", + " case _: pass\n", + "\n", + " return image, cropped_image, cropped_mask\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ExperimentContext\n", + "> Utility class to maintain shared state across all experiments.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "SubjIdT: TypeAlias = int\n", + "RunIdT: TypeAlias = str\n", + "SubjSpecT: TypeAlias = SubjIdT | str | Path\n", + "\n", + "\n", + "class ExperimentSubject:\n", + " exp: ExperimentContext\n", + " idx: SubjIdT\n", + "\n", + " def setup(self, exp: ExperimentContext, idx: Any, *args, **kwargs): \n", + " self.exp = exp\n", + " self.idx = cast(SubjIdT, exp.normalize_idx(idx))\n", + " return self\n", + "\n", + " def __new__(cls, exp: ExperimentContext, idx: Any, *args, **kwargs):\n", + " idx = exp.normalize_idx(idx)\n", + " self = exp.subject_context(idx)\n", + " if self is None:\n", + " self = super().__new__(cls)\n", + " self = exp.setup_subject_context(idx, self, *args, **kwargs)\n", + " if self is None:\n", + " raise ValueError(f\"Can't create new subject with idx: {idx}: out of range\")\n", + " return self\n", + "\n", + "\n", + "class Result:\n", + " subject_ctx: ExperimentSubject\n", + "\n", + "class ExperimentRun:\n", + " \"A set of experiment results obtained with the same parameters.\"\n", + " exp: ExperimentContext\n", + " name: RunIdT\n", + " dt: datetime.datetime\n", + "\n", + " def setup(self, exp: ExperimentContext, name: RunIdT, *args, **kwargs): \n", + " self.exp = exp\n", + " self.name = name\n", + " return self\n", + "\n", + " @classmethod\n", + " def setup_run_name(cls, name: RunIdT, dt: datetime.datetime):\n", + " return f\"{name}_{dt.strftime('%Y%m%d-%H%M%S')}\"\n", + "\n", + " def setup_run(self, args, **kwargs):\n", + " pass\n", + " def before_result(self, *args, **kwargs):\n", + " pass\n", + " def after_result(self, result: Result, *args, **kwargs):\n", + " pass\n", + " \n", + " def __new__(cls, exp: ExperimentContext, name: RunIdT, *args, **kwargs):\n", + " self = exp.experiment_run(name)\n", + " if self is None:\n", + " self = super().__new__(cls)\n", + " self = exp.setup_experiment_run(name, self, *args, **kwargs)\n", + " return self\n", + "\n", + "\n", + "class ExperimentContext(T.HasTraits):\n", + " \"Class to maintain shared state across all file-based experiments within the experiment domain.\"\n", + " name: str\n", + " _results: dict[RunIdT, dict[SubjIdT, Any]]\n", + "\n", + " _dirty = T.Bool(default_value=False)\n", + "\n", + " CACHE_DIR_NAME: str = 'cache'\n", + " SOURCE_DIR_NAME: str = 'source'\n", + " EXP_DIR: Path = Path(\"../experiment\")\n", + "\n", + " subject_cls: Callable[..., ExperimentSubject]\n", + " def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls\n", + "\n", + " def normalize_idx(self, idx: SubjSpecT) -> SubjIdT | None:\n", + " nidx = None\n", + " if isinstance(idx, int) and idx < self.subject_count:\n", + " nidx = idx\n", + " elif isinstance(idx, str):\n", + " try:\n", + " nidx = [_.name for _ in self._paths].index(idx)\n", + " except Exception:\n", + " pass\n", + " elif isinstance(idx, Path):\n", + " if idx in self._paths:\n", + " nidx = self._paths.index(idx)\n", + " return nidx\n", + " \n", + " def path_from_idx(self, idx: SubjSpecT):\n", + " \"Relative path to the subject with the given index.\"\n", + " _idx = self.normalize_idx(idx)\n", + " if _idx is None:\n", + " raise ValueError(f\"{_idx} not found in context.\")\n", + " path = Path(self._paths[_idx])\n", + " if not path.resolve().exists():\n", + " raise ValueError(f\"{path} not found in context.\")\n", + " return path\n", + " \n", + " @property\n", + " def subject_count(self): return len(self._paths)\n", + "\n", + " @property\n", + " def run_names(self):\n", + " return list(self._exp_runs.keys())\n", + "\n", + " @property\n", + " def root_dir(self): return self._root\n", + " # Relative paths to `root_dir`\n", + " @property\n", + " def cache_dir(self): return Path(self.CACHE_DIR_NAME)\n", + " @property\n", + " def source_dir(self): return Path(self.SOURCE_DIR_NAME)\n", + " @functools.lru_cache()\n", + " def _subject_cache_dir(self, idx: SubjIdT):\n", + " path = self.path_from_idx(idx)\n", + " subject_cache_dir = self.cache_dir / path.stem\n", + " self.final(subject_cache_dir).mkdir(parents=True, exist_ok=True)\n", + " return subject_cache_dir\n", + " def subject_cache_dir(self, idx: SubjSpecT):\n", + " \"Folder to cache and save subject results. Create if needed.\"\n", + " return self._subject_cache_dir(idx)\n", + " def final(self, path: Path | str): \n", + " \"\"\"`path` relative to the root of the experiment.\n", + " If `path` is absolute, it must be in the experiment directory.\n", + " \"\"\"\n", + " if isinstance(path, str):\n", + " path = Path(path)\n", + " if path.is_absolute():\n", + " try:\n", + " path = path.relative_to(self.root_dir.resolve())\n", + " except Exception:\n", + " return Path('_not_found_/'+path.name)\n", + " return self.root_dir / path\n", + " \n", + " def empty_cache(self, idx: SubjIdT | None = None):\n", + " if idx is None:\n", + " cache_dir = self.final(self.cache_dir)\n", + " shutil.rmtree(cache_dir, ignore_errors=True)\n", + " cache_dir.mkdir(parents=True, exist_ok=True)\n", + " else:\n", + " subject_cache_dir = self.final(self.subject_cache_dir(idx))\n", + " shutil.rmtree(subject_cache_dir, ignore_errors=True)\n", + " subject_cache_dir.mkdir(parents=True, exist_ok=True)\n", + " def empty_cache_warning(self, \n", + " idx: SubjIdT | None=None, *, warn: bool=True, out: W.Output | None=None):\n", + " def on_confirm_clicked(b):\n", + " try:\n", + " self.empty_cache(idx)\n", + " print(\"Cache cleared successfully.\")\n", + " except Exception as e:\n", + " print(f\"Failed to clear cache: {e}\")\n", + " finally:\n", + " for widget in confirmation_box.children:\n", + " widget.close()\n", + "\n", + " def on_cancel_clicked(b):\n", + " print(\"Cache clear cancelled.\")\n", + " for widget in confirmation_box.children:\n", + " widget.close()\n", + "\n", + " if out is None:\n", + " out = W.Output()\n", + " cache_name = '' if idx is None else f\" of '{self.subject_cache_dir(idx).name}'\"\n", + " text = f\"Are you sure you want to clear the cache{cache_name}? This action cannot be undone.\"\n", + " with out:\n", + " if FC.IN_NOTEBOOK:\n", + " confirm_button = W.Button(description=\"Confirm\")\n", + " cancel_button = W.Button(description=\"Cancel\")\n", + " confirm_button.on_click(on_confirm_clicked)\n", + " cancel_button.on_click(on_cancel_clicked)\n", + " label = W.Label(text, style={'font_size': '1.25em', 'font_weight': 'bold'})\n", + " confirmation_box = W.VBox([label, W.HBox([confirm_button, cancel_button])])\n", + " display(confirmation_box)\n", + " else:\n", + " on_confirm_clicked(None)\n", + " return out\n", + "\n", + " def subject_context(self, idx: SubjSpecT):\n", + " \"Cached subject.\"\n", + " if (nidx := self.normalize_idx(idx)) is None:\n", + " return None\n", + " return self._subjects.get(nidx)\n", + " def setup_subject_context(self, idx: SubjIdT, /, subject: ExperimentSubject, *args, **kwargs):\n", + " \"Setup and set cached subject.\"\n", + " if idx < 0 or idx >= self.subject_count:\n", + " raise ValueError(f\"Can't create new subject with idx: {idx}: out of range\")\n", + " subject.setup(self, idx, *args, **kwargs)\n", + " self._subjects[idx] = subject\n", + " return subject\n", + "\n", + " def experiment_run(self, name: RunIdT | None = None):\n", + " \"Experiment run `name` or the last one if `name` is None or None\"\n", + " if name: \n", + " return self._exp_runs.get(name)\n", + " if self._exp_runs:\n", + " return self._exp_runs[list(self._exp_runs.keys())[-1]]\n", + " return None\n", + " def setup_experiment_run(self, name: str, run: ExperimentRun, *args, **kwargs):\n", + " \"Set or replace cached experiment run.\"\n", + " run.setup(self, name, *args, **kwargs)\n", + " self._exp_runs[name] = run\n", + " return run\n", + "\n", + " def _reset_(self):\n", + " # start over. Note: doesn't change _dirty status, intended for use in testing.\n", + " self._subjects.clear()\n", + " self._subject_cache_dir.cache_clear()\n", + "\n", + " def cleanup_model(self):\n", + " pass\n", + "\n", + " def __init__(self, name: str, paths: list[Path], root: Path | None = None, run_name: str = 'run1'):\n", + " self.name = name\n", + " self._root = root or type(self).EXP_DIR\n", + " self._paths = paths # relative paths wrt self._root\n", + " self._subjects: dict[SubjIdT, ExperimentSubject] = {}\n", + " self._exp_runs: dict[str, ExperimentRun] = {}\n", + " self._results = {}\n", + " # default run\n", + " ExperimentRun(self, run_name)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`ExperimentSubject`s are created and cached int the `ExperimentContext`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "exp = ExperimentContext('test', [Path('b'), Path('c')], Path('../a'))\n", + "subj = exp.subject_context(5)\n", + "test_eq(subj, None)\n", + "\n", + "# subject haven't been created yet\n", + "_ = exp.subject_context(1)\n", + "test_is(_, None)\n", + "\n", + "# Instantiate subject\n", + "subj1 = ExperimentSubject(exp, 1)\n", + "_ = exp.subject_context(1)\n", + "test_eq(_ is not None, True)\n", + "test_is(_, subj1)\n", + "test_is(subj1, ExperimentSubject(exp, 1))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can't create `ExperimentSubject`s beyond `ExperimentContext` domain." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "test_fail(lambda:ExperimentSubject(exp, 2), 'out of range')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All paths are relative to the root of the experiment.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "test_eq(exp.final('d/image.jpg'), Path('../a/d/image.jpg'))\n", + "test_eq(exp.final(Path('d/image.jpg')), Path('../a/d/image.jpg'))\n", + "p = Path('..').resolve()/'a/d/image.jpg'\n", + "test_eq(exp.final(p), Path('../a/d/image.jpg'))\n", + "test_eq(exp.final('../a/d/image.jpg'), Path('../a/../a/d/image.jpg'))\n", + "test_eq(exp.final('/other/a/d/image.jpg'), Path('_not_found_/image.jpg'))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`ExperimentRun`s are created and cached int the `ExperimentContext`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "run = exp.experiment_run('test')\n", + "test_eq(run, None)\n", + "\n", + "test_eq(exp.run_names, ['run1'])\n", + "\n", + "# Instantiate run\n", + "run = ExperimentRun(exp, 'test')\n", + "_ = exp.experiment_run('test')\n", + "test_eq(_ is not None, True)\n", + "test_is(_, run)\n", + "test_is(run, ExperimentRun(exp, 'test'))\n", + "\n", + "test_eq(exp.run_names, ['run1', 'test'])\n", + "\n", + "run2 = ExperimentRun(exp, 'test2')\n", + "\n", + "test_eq(exp.run_names, ['run1', 'test', 'test2'])\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ImageContext\n", + "> A utility class to maintain image state for a `OCRExperimentContext`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "ImgIdT = SubjIdT\n", + "ImgSpecT: TypeAlias = ImgIdT | str | Path\n", + "\n", + "\n", + "class ImageContext(ExperimentSubject):\n", + " \"\"\"\n", + " A utility class to maintain image state for a ExperimentContext.\n", + "\n", + " Attributes:\n", + " json_data (dict): JSON data loaded from cached files.\n", + " page_data (st.PageData): PanelClaner page data.\n", + " base_image (Image.Image): The base image loaded from the cache.\n", + " mask (Image.Image): The mask image used for text detection.\n", + " gts (list[str]): Ground truth data for the text in the images.\n", + " mask_dilated1 (Image.Image): Image mask dilated by 1 pixel.\n", + " mask_dilated05 (Image.Image): Image mask dilated by 0.5 pixels.\n", + " mask_dilated02 (Image.Image): Image mask dilated by 0.2 pixels.\n", + "\n", + " \"\"\"\n", + " exp: ExperimentContext\n", + " idx: ImgIdT\n", + " base_image: Image.Image\n", + " mask: Image.Image\n", + " json_data: dict | None\n", + " page_data: st.PageData\n", + " _page_lang: str\n", + " _gts: list[str]\n", + " _mask_dilated1: Image.Image | None\n", + " _mask_dilated05: Image.Image | None\n", + " _mask_dilated02: Image.Image | None\n", + " \n", + " def to_dict(self):\n", + " return {\n", + " 'image_idx': self.idx,\n", + " 'page_lang': self.page_lang,\n", + " }\n", + " \n", + " @property\n", + " def image_idx(self): return self.idx\n", + " @property\n", + " def cache_dir(self): \n", + " \"Relative path of the cache directory for this image.\"\n", + " return self.exp.subject_cache_dir(self.idx)\n", + " \n", + " @property\n", + " def image_info(self): \n", + " img = self.base_image\n", + " w, h = img.size\n", + " print_size_in = size(w, h, 'in', 300)\n", + " print_size_cm = size(w, h, 'cm', 300)\n", + " required_dpi = dpi(w, h, 'Modern Age')\n", + " return (w, h), print_size_in, print_size_cm, required_dpi\n", + "\n", + " @property\n", + " def original_image_path(self): return Path(self.page_data.original_path)\n", + " @property\n", + " def image_path(self): return Path(self.page_data.image_path)\n", + " @property\n", + " def mask_path(self): return Path(self.page_data.mask_path)\n", + " @property\n", + " def image_boxes_path(self):\n", + " exp, img_path = self.exp, self.image_path\n", + " if exp.final( p := img_path.with_stem(img_path.stem + '_boxes')).exists(): \n", + " return p\n", + " _, p = page_boxes(self.page_data, exp.final(img_path))\n", + " return p.relative_to(exp.root_dir)\n", + " \n", + " # Base image properties \n", + " @property\n", + " def image_name(self): return self.original_image_path.name\n", + " @property\n", + " def image_size(self): return self.base_image.size\n", + " @property\n", + " def image_dim(self):return size(*self.image_size)\n", + " @property\n", + " def image_dpi(self): return dpi(*self.image_size)\n", + " @property\n", + " def image_print(self):\n", + " return self.image_size, self.image_dim, self.image_dpi\n", + " @property\n", + " def image_name_rich(self):\n", + " siz, dim, res = self.image_print\n", + " return f\"{self.image_name} - {siz[0]}x{siz[1]} px: {dim[0]:.2f}x{dim[1]:.2f}\\\" @ {res:.2f} dpi\"\n", + " \n", + " def setup_page_lang(self, page_lang: str | None = None):\n", + " path = self.exp.final(self.page_data.original_path).with_suffix('.json')\n", + " metadata = json.load(open(path)) if path.exists() else {}\n", + " if 'lang' in metadata and (page_lang == metadata['lang'] or page_lang is None):\n", + " self._page_lang = metadata['lang']\n", + " return\n", + " self._page_lang = metadata['lang'] = page_lang or 'English'\n", + " json.dump(metadata, open(path, 'w'), indent=2)\n", + " @property\n", + " def page_lang(self):\n", + " if self._page_lang == None:\n", + " self.setup_page_lang()\n", + " return self._page_lang\n", + " \n", + " @property\n", + " def boxes(self): return self.page_data.boxes\n", + " \n", + " def setup_ground_truth(self):\n", + " self._gts = read_ground_truth(self.page_data, self.exp.root_dir)\n", + " @property\n", + " def gts(self): \n", + " if self._gts is None:\n", + " self.setup_ground_truth()\n", + " return self._gts\n", + " \n", + " @functools.lru_cache(typed=True)\n", + " def dilated_mask(self, fraction: float):\n", + " return dilate_by_fractional_pixel(self.mask, fraction)\n", + " \n", + " def mask_dilated1(self): \n", + " if self._mask_dilated1 is None:\n", + " self._mask_dilated1 = self.mask.filter(ImageFilter.MaxFilter(3))\n", + " return self._mask_dilated1\n", + " \n", + " def mask_dilated05(self): \n", + " if self._mask_dilated05 is None:\n", + " self._mask_dilated05 = self.dilated_mask(0.5)\n", + " return self._mask_dilated05\n", + " \n", + " def mask_dilated02(self): \n", + " if self._mask_dilated02 is None:\n", + " self._mask_dilated02 = self.dilated_mask(0.2)\n", + " return self._mask_dilated02\n", + " \n", + " def dilated(self):\n", + " return {1: self.mask_dilated1(),\n", + " 0.5: self.mask_dilated05(),\n", + " 0.2: self.mask_dilated02(),}\n", + "\n", + " def __new__(cls,\n", + " exp: ExperimentContext,\n", + " idx: ImgSpecT,\n", + " *args, **kwargs) -> 'ImageContext':\n", + " return super().__new__(cls, exp, idx, *args, **kwargs) # type: ignore\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ResultOCR\n", + "> Store OCR results\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "@dataclasses.dataclass\n", + "class ResultOCR(Result): \n", + " subject_ctx: ImageContext\n", + " block_idx: int\n", + " ocr: str | None = None\n", + " image: Image.Image | None = None\n", + " description: str = dataclasses.field(default='', kw_only=True)\n", + "\n", + " def __post_init__(self): \n", + " self._acc = None\n", + " if self.image is None:\n", + " cache_path = self.image_ctx.exp.final(self.cache_path())\n", + " if cache_path.exists():\n", + " self.image = Image.open(cache_path)\n", + "\n", + " @property\n", + " def image_ctx(self): return self.subject_ctx\n", + " \n", + " @property\n", + " def acc(self):\n", + " if self.ocr is not None:\n", + " self._acc = accuracy_ocr_difflib(self.ocr, self.image_ctx.gts[self.block_idx])\n", + " return self._acc\n", + " @property\n", + " def suffix(self): return f\"{self.block_idx}_{self.description}\"\n", + "\n", + " def cache_path(self, suffix: str | None = None): \n", + " img_ctx = self.image_ctx\n", + " suffix = self.suffix + (('_'+suffix) if suffix else '')\n", + " img_name = img_ctx.image_path.stem\n", + " return img_ctx.cache_dir / '.crop' / f\"{img_name}_{suffix}.png\"\n", + " \n", + " def cache_image(self, image: Image.Image | None = None, suffix: str | None = None):\n", + " image = image or (self.image if not suffix else None)\n", + " box_image_path = self.cache_path(suffix)\n", + " final_path = self.image_ctx.exp.final(box_image_path)\n", + " if image and not final_path.exists():\n", + " final_path.parent.mkdir(parents=True, exist_ok=True)\n", + " image.save(final_path)\n", + " return box_image_path\n", + "\n", + " def to_dict(self):\n", + " d = dataclasses.asdict(self)\n", + " d['image_ctx'] = d['image'] = d['page_data'] = d['gts'] = None\n", + " return d\n", + "\n", + " # @classmethod\n", + " # def from_dict(cls, d: dict, page_data: st.PageData, gts: list[str]):\n", + " # return cls(**(d | {'page_data':page_data, 'gts':gts}))\n", + "\n", + " def __repr__(self): \n", + " return f\"{type(self).__name__}#block {self.block_idx:02}: {self.acc:.2f}||{self.ocr}\"\n", + "\n", + " def display(self): \n", + " visor = getattr(self, '_default_visor_type', None)\n", + " display(HTML(\n", + " visor(self).as_html() if visor else f\"{self}\"\n", + " ))\n", + " def _ipython_display_(self): self.display()\n", + "\n", + "\n", + "class ResultOCRExtracted(ResultOCR): \n", + " def __repr__(self): return super().__repr__()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ResultSet\n", + "> tagged nested dict to store image results keyed by box, and crop method\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "BoxIdT: TypeAlias = int\n", + "\n", + "class ResultSet(dict[BoxIdT, dict[CropMethod, ResultOCR]]): ...\n", + "\n", + "class ResultSetDefault(defaultdict[BoxIdT, dict[CropMethod, ResultOCR]]): ...\n", + "\n", + "def resultset_to_dict(results: ResultSet) -> dict[BoxIdT, dict[str, str]]:\n", + " d = {}\n", + " for box, box_methods in results.items():\n", + " for method, result in box_methods.items():\n", + " if box not in d:\n", + " d[box] = {}\n", + " d[box][method.name] = result.ocr\n", + " return d\n", + "\n", + "def dict_to_resultset(\n", + " image_idx: ImgIdT, \n", + " results_dict: dict[str, dict[str, str]],\n", + " result_factory: Callable\n", + " ) -> ResultSetDefault:\n", + " results = ResultSetDefault(dict[CropMethod, ResultOCR])\n", + " for box_idx, box_methods in results_dict.items():\n", + " box_idx = int(box_idx)\n", + " for method, ocr in box_methods.items():\n", + " m = CM[method]\n", + " results[box_idx][m] = result_factory(image_idx, box_idx, m, ocr)\n", + " return results\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OCRExperimentContext" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class OCRModel(Enum):\n", + " TESSERACT = 0\n", + " IDEFICS = 1\n", + " @staticmethod\n", + " def __display_names__() -> dict[str, OCRModel]:\n", + " return dict(\n", + " zip(\"Tesseract, Idefics\".split(', '), \n", + " OCRModel))\n", + "\n", + "\n", + "class OCRExperimentRun(ExperimentRun): ...\n", + "\n", + "\n", + "class OCRExperimentContext(ExperimentContext):\n", + " \"\"\"\n", + " A utility class to maintain shared state across all experiments within OCR domain.\n", + " This class encapsulates state necessary for conducting PanelCleaner OCR experiments.\n", + " \"\"\"\n", + "\n", + " config: cfg.Config\n", + " image_paths: list[Path]\n", + " ocr_model: str\n", + " force_PIL: bool\n", + " use_tunnel: bool\n", + " server: web_server.WebServer | None\n", + "\n", + " # ExperimentRun name -> Image index -> Box index -> Crop method -> Result\n", + " _results: dict[RunIdT, dict[ImgIdT, ResultSet]]\n", + "\n", + " _running = T.Bool(False)\n", + " \n", + " engines = {\n", + " 'Tesseract': cfg.OCREngine.TESSERACT, \n", + " 'Idefics': None, \n", + " 'manga-ocr': cfg.OCREngine.MANGAOCR}\n", + "\n", + "\n", + " @classmethod\n", + " def get_config(cls) -> cfg.Config:\n", + " config = cfg.load_config()\n", + " profile = config.current_profile\n", + " preprocessor_conf = profile.preprocessor\n", + " # Modify the profile to OCR all boxes.\n", + " # Make sure OCR is enabled.\n", + " preprocessor_conf.ocr_enabled = True\n", + " # Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", + " preprocessor_conf.ocr_max_size = 10**10\n", + " # Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", + " preprocessor_conf.suspicious_box_min_size = 10**10\n", + " # Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", + " preprocessor_conf.ocr_blacklist_pattern = \".*\"\n", + "\n", + " # Load models if needed\n", + " gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + " model_path = config.get_model_path(gpu)\n", + " if model_path is None:\n", + " # don't mess with normal PanelCleaner, download models directly\n", + " import pcleaner.model_downloader as md\n", + " model_dir = config.get_model_cache_dir()\n", + " config.default_torch_model_path = md.download_torch_model(model_dir)\n", + " config.default_cv2_model_path = md.download_cv2_model(model_dir)\n", + "\n", + " return config\n", + " \n", + " @functools.lru_cache()\n", + " def mocr(self, lang: str):\n", + " engine = self.engines[self.ocr_model]\n", + " ocr_processor = ocr.get_ocr_processor(True, engine)\n", + " proc = ocr_processor[lang2pcleaner(lang)]\n", + " if isinstance(proc, TesseractOcr):\n", + " proc.lang = lang2tesseract(lang)\n", + " return proc\n", + "\n", + " @contextlib.contextmanager\n", + " def running(self, value: bool):\n", + " _running = self._running\n", + " self._running = value\n", + " yield\n", + " self._running = _running\n", + "\n", + " def ocr_box(self, result: ResultOCR, lang: str): \n", + " assert result.image is not None\n", + " text = self.mocr(lang)(result.image)\n", + " result.ocr = postprocess_ocr(text)\n", + " self._dirty = True\n", + " return result\n", + "\n", + " image_cache_dir = ExperimentContext.subject_cache_dir\n", + "\n", + " def _detect_text(self, img_path: Path, dest_dir: Path):\n", + " config = self.config\n", + " root_dir = self.root_dir\n", + " image_name = img_path.stem\n", + " pfl = config.current_profile\n", + " gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + " model_path = config.get_model_path(gpu)\n", + " json_data = None\n", + " with tempfile.TemporaryDirectory() as temp_dir:\n", + " temp_path = Path(temp_dir)\n", + " ctm.model2annotations(pfl.general, pfl.text_detector, model_path, [img_path], temp_path)\n", + " contents = list(temp_path.glob(f\"*{image_name}*\"))\n", + " json_path = [_ for _ in contents if _.suffix == '.json'][0]\n", + " json_data = json.loads(json_path.read_text(encoding=\"utf-8\"))\n", + " # we don't need unique names for this tests, strip uuids\n", + " for temp_file in contents:\n", + " if temp_file.suffix == \".json\": continue\n", + " new_path = dest_dir / strip_uuid(temp_file.name)\n", + " shutil.copy(temp_file, new_path)\n", + " if 'mask' in temp_file.name:\n", + " json_data['mask_path'] = str(new_path.relative_to(root_dir))\n", + " elif new_path.stem == image_name:\n", + " json_data['image_path'] = str(new_path.relative_to(root_dir))\n", + " json_data['original_path'] = str(img_path.relative_to(root_dir))\n", + " json.dump(json_data, open(dest_dir / f\"{image_name}#raw.json\", \"w\"), indent=2)\n", + " return json_data\n", + " \n", + " @functools.lru_cache()\n", + " def _load_page_data(self, image_idx: ImgIdT):\n", + " root_dir = self.root_dir\n", + " dest_dir = self.final(self.image_cache_dir(image_idx))\n", + " img_path = self.final(self.image_paths[image_idx])\n", + " image_name = img_path.stem\n", + " # read cached json\n", + " jsons = [_ for _ in dest_dir.glob(\"*#raw.json\") if image_name in _.stem]\n", + " assert len(jsons) <= 1\n", + " # generate text boxes if needed\n", + " if not jsons:\n", + " json_data = self._detect_text(img_path, dest_dir)\n", + " else:\n", + " json_file_path = jsons[0]\n", + " json_data = json.loads(json_file_path.read_text(encoding=\"utf-8\"))\n", + " \n", + " if not all((root_dir / json_data[_]).exists() \n", + " for _ in (\"image_path\", \"mask_path\", \"original_path\")):\n", + " raise ValueError(f\"Inconsistent page_data of {img_path}\")\n", + "\n", + " page_data = st.PageData(\n", + " json_data[\"image_path\"], json_data[\"mask_path\"], \n", + " json_data[\"original_path\"], json_data[\"scale\"], \n", + " [st.Box(*data[\"xyxy\"]) for data in json_data[\"blk_list\"]], \n", + " [], [], [])\n", + " # Merge boxes that have mutually overlapping centers.\n", + " page_data.resolve_total_overlaps()\n", + " return json_data, page_data\n", + "\n", + " def page_data(self, image_idx: int):\n", + " _, page_data = self._load_page_data(image_idx)\n", + " return page_data\n", + " def json_data(self, image_idx: int):\n", + " json_data, _ = self._load_page_data(image_idx)\n", + " return json_data\n", + "\n", + " def path_from_idx(self, image_idx: ImgSpecT, cached: bool = False):\n", + " \"(Relative path) to subject image. Raises ValueError if not found.\"\n", + " _idx = self.normalize_idx(image_idx)\n", + " if _idx is None:\n", + " raise ValueError(f\"{_idx} not found in context.\")\n", + " if cached:\n", + " page_data = self.page_data(_idx) # load if needed\n", + " path = Path(page_data.image_path)\n", + " else:\n", + " path = self.image_paths[_idx]\n", + " if not self.final(path).exists():\n", + " raise ValueError(f\"{path} not found in context.\")\n", + " return path\n", + "\n", + " def cached_image(self, image_idx: ImgSpecT):\n", + " \"Relative path to cached image.\"\n", + " _idx = self.normalize_idx(image_idx)\n", + " if _idx is None:\n", + " return None\n", + " page_data = self.page_data(_idx) # load if needed\n", + " path = Path(page_data.image_path)\n", + " if not self.final(path).exists():\n", + " return None\n", + " return path\n", + " \n", + " def image_context(self, image_idx: ImgSpecT) -> ImageContext | None:\n", + " \"Cached image context.\"\n", + " return cast(ImageContext, self.subject_context(image_idx))\n", + "\n", + " def display_image(self, image_path: Path | str):\n", + " \"Return a PIL image, a url, or the given (final) path.\"\n", + " final_image_path = self.final(image_path)\n", + " if self.force_PIL:\n", + " return Image.open(final_image_path)\n", + " elif self.use_tunnel:\n", + " if (server := self.server) is not None and (url := server.unc_share) is not None:\n", + " return url/final_image_path.relative_to(self.root_dir)\n", + " return final_image_path\n", + " DI = display_image\n", + "\n", + " def _update_results(self, run_name: str, img_idx: ImgIdT, results: ResultSetDefault):\n", + " self._results[run_name][img_idx] = cast(ResultSet, results)\n", + " \n", + " def _result_from(self, \n", + " image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None):\n", + " img_ctx = ImageContext(self, image_idx)\n", + " extracted = method in _EXTRACTED_METHODS\n", + " result_cls = ResultOCRExtracted if extracted else ResultOCR\n", + " result = result_cls(img_ctx, int(box_idx), None, None, description=f\"{method.value}\")\n", + " if ocr is not None:\n", + " result.ocr = ocr\n", + " return result\n", + " \n", + " def result(self, \n", + " run_name: str,\n", + " image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, \n", + " ocr: bool=True, \n", + " rebuild: bool=False) -> ResultOCR | None:\n", + " _result = self._results[run_name][image_idx][box_idx].get(method)\n", + " if not rebuild and _result is not None:\n", + " return _result\n", + " \n", + " result: ResultOCR = self._result_from(image_idx, box_idx, method)\n", + " image, cropped_image, cropped_mask = result.image, None, None\n", + " img_ctx = ImageContext(self, image_idx)\n", + " base_image = img_ctx.base_image\n", + " box = img_ctx.boxes[box_idx]\n", + " if image is None and method in _IMAGE_METHODS:\n", + " image = crop_by_image(\n", + " method, box, base_image, self.config.current_profile.preprocessor)\n", + "\n", + " if image is None and method in _EXTRACTED_METHODS:\n", + " mask = img_ctx.mask\n", + " cropped_image_path = result.cache_image(cropped_image, \"cropped\")\n", + " cropped_mask_path = result.cache_image(cropped_mask, \"mask\")\n", + " if not cropped_image_path.exists() or not cropped_mask_path.exists():\n", + " image, cropped_image, cropped_mask = crop_by_extracted(\n", + " method, box, base_image, mask, \n", + " cropped_image_path, cropped_mask_path, img_ctx.dilated())\n", + " \n", + " assert image is not None\n", + " if result.image is None:\n", + " result.image = image\n", + " result.cache_image()\n", + " if cropped_image is not None:\n", + " result.cache_image(cropped_image, \"cropped\")\n", + " if cropped_mask is not None:\n", + " result.cache_image(cropped_mask, \"mask\")\n", + " \n", + " exp_run = OCRExperimentRun(self, run_name)\n", + " if ocr:\n", + " exp_run.before_result(result)\n", + " result = self.ocr_box(result, img_ctx.page_lang)\n", + " exp_run.after_result(result)\n", + " self._results[run_name][image_idx][box_idx][method] = result\n", + " self._dirty = True\n", + " return result\n", + "\n", + " def results(self, run_name: str | None = None, img_idx: ImgIdT | None = None):\n", + " if run_name is None: return self._results\n", + " if img_idx is None: return self._results[run_name]\n", + " return self._results[run_name][img_idx]\n", + " def run_results(self, run_name: str):\n", + " return cast(dict[ImgIdT, ResultSet], self.results(run_name))\n", + " def image_results(self, run_name: str, img_idx: ImgIdT):\n", + " return cast(ResultSet, self.results(run_name, img_idx))\n", + " def box_results(self, run_name: str, img_idx: ImgIdT, box_idx: BoxIdT):\n", + " return cast(ResultSet, self.results(run_name, img_idx))[box_idx]\n", + " def method_results(self, run_name: str, img_idx: ImgIdT, method: CropMethod):\n", + " image_results = self.image_results(run_name, img_idx)\n", + " return {i: box_results.get(method) for i,box_results in image_results.items()}\n", + "\n", + " def _reset_results(self):\n", + " results = defaultdict(lambda: defaultdict(lambda: ResultSetDefault(dict)))\n", + " self._results = cast(dict[str, dict[ImgIdT, ResultSet]], results)\n", + " def _reset_results_(self, \n", + " run_name: str | None = None, \n", + " image_idx: int | None = None, \n", + " box_idx: int | None = None, \n", + " method: CropMethod | None = None):\n", + " if run_name is None and image_idx is None and box_idx is None and method is None:\n", + " self._reset_results()\n", + " return\n", + " results = self._results\n", + " models = tuple(results.keys()) if run_name is None else [run_name] if run_name in results else []\n", + " for run_name in models:\n", + " img_nodes = results[run_name]\n", + " imgs = (tuple(img_nodes.keys()) \n", + " if image_idx is None else [image_idx] if image_idx in img_nodes else [])\n", + " for img_idx in imgs:\n", + " box_nodes = img_nodes[img_idx]\n", + " boxes = (tuple(box_nodes.keys()) \n", + " if box_idx is None else [box_idx] if box_idx in box_nodes else [])\n", + " for box_idx in boxes:\n", + " if method is None:\n", + " del box_nodes[box_idx]\n", + " else:\n", + " methods = box_nodes[box_idx]\n", + " if method in methods:\n", + " del methods[method]\n", + " if not box_nodes[box_idx]:\n", + " del box_nodes[box_idx]\n", + " if not img_nodes[img_idx]:\n", + " del img_nodes[img_idx]\n", + " if not results[run_name]:\n", + " del results[run_name]\n", + " def reset_results(self, \n", + " run_name: str | None = None, \n", + " image_idx: int | None = None, \n", + " box_idx: int | None = None, \n", + " method: CropMethod | None = None):\n", + " self._reset_results_(run_name, image_idx, box_idx, method)\n", + " self._dirty = True\n", + " def _reset_(self):\n", + " super()._reset_()\n", + " self._reset_results_()\n", + " self._load_page_data.cache_clear()\n", + " self.mocr.cache_clear()\n", + "\n", + " @classmethod\n", + " def get_image_paths(cls, root_dir: Path):\n", + " if root_dir is None: return []\n", + " source_dir = root_dir / cls.SOURCE_DIR_NAME\n", + " return sorted(\n", + " [_.relative_to(root_dir) for _ in source_dir.glob(\"*\") \n", + " if _.is_file() and _.suffix.lower() in [\".jpg\", \".png\", \".jpeg\"]])\n", + "\n", + " def run_to_dict(self, run_name: RunIdT) -> dict[str, dict[BoxIdT, dict[str, str]]]:\n", + " \"JSON serializable dict of the experiment run\"\n", + " results = {}\n", + " idx2name = {i: p.name for i, p in enumerate(self.image_paths)}\n", + " run_results = cast(dict[ImgIdT, ResultSet], self.results(run_name))\n", + " for img_idx, rset in run_results.items():\n", + " results[idx2name[img_idx]] = resultset_to_dict(cast(ResultSet, rset))\n", + " return results\n", + "\n", + " # def run_to_json(self, run_name: RunIdT):\n", + " # data = {\n", + " # 'run_name': run_name,\n", + " # 'results': self.run_to_dict(run_name),\n", + " # }\n", + " # fp = self._root / f'{run_name}.json'\n", + " # with open(fp, 'w') as f:\n", + " # json.dump(data, f, indent=2)\n", + " # return fp\n", + "\n", + " # def save_results(self):\n", + " # for run_name, _ in self._exp_runs.items():\n", + " # self.run_to_json(run_name)\n", + " \n", + " def _load_run_results(self, run_name: str, run_data: dict[str, dict[str, dict[str, str]]]):\n", + " self._exp_runs[run_name] = OCRExperimentRun(self, run_name)\n", + " name2idx = {p.name: i for i, p in enumerate(self.image_paths)}\n", + " for img_name, data in run_data.items():\n", + " img_idx = name2idx.get(img_name, None)\n", + " if img_idx is None: \n", + " logger.warning(f\"Image {img_name} not found in context.\")\n", + " continue\n", + " rset: ResultSetDefault = dict_to_resultset(\n", + " ImgIdT(img_idx), \n", + " data, \n", + " result_factory=self._result_from)\n", + " self._update_results(run_name, img_idx, rset)\n", + "\n", + " # def load_results(self):\n", + " # for json_path in self.root_dir.glob(\"*.json\"):\n", + " # try:\n", + " # with open(json_path, 'r') as f:\n", + " # data = json.load(f)\n", + " # if data.keys() != {'run_name', 'results'}:\n", + " # continue\n", + " # except Exception as e:\n", + " # continue\n", + " # self._load_run_results(data)\n", + "\n", + " def to_dict(self):\n", + " data: dict = {\n", + " \"ocr_model\": self.ocr_model,\n", + " \"runs\": (rr := {})\n", + " }\n", + " for run_name, _ in self._exp_runs.items():\n", + " rr[run_name] = self.run_to_dict(run_name)\n", + " return data\n", + "\n", + " def to_json(self):\n", + " data = self.to_dict()\n", + " _ = datetime.datetime.now()\n", + " fp = self._root / f'{self.name}.json'\n", + " with open(fp, 'w') as f:\n", + " json.dump(data, f, indent=2)\n", + " return fp\n", + " \n", + " def _from_json(self):\n", + " json_path = self.root_dir / f'{self.name}.json'\n", + " if not json_path.exists(): return\n", + " try:\n", + " with open(json_path, 'r') as f:\n", + " data = json.load(f)\n", + " except Exception as e:\n", + " logger.error(f\"Error loading {json_path}: {e}\")\n", + " return\n", + " self.ocr_model = data['ocr_model']\n", + " for run_name, run_results in data['runs'].items():\n", + " self._load_run_results(run_name, run_results)\n", + " \n", + " @classmethod\n", + " def from_json(cls, root_dir: Path, name: str, config: cfg.Config | None = None):\n", + " json_path = root_dir / f'{name}.json'\n", + " try:\n", + " with open(json_path, 'r') as f:\n", + " data = json.load(f)\n", + " except Exception as e:\n", + " logger.error(f\"Error loading {json_path}: {e}\")\n", + " raise e\n", + " config = config or cls.get_config()\n", + " self = cls(data['ocr_model'], root_dir, config=config)\n", + " for run_name, run_results in data['runs'].items():\n", + " self._load_run_results(run_name, run_results)\n", + " return self\n", + " \n", + " def save(self):\n", + " fp = self.to_json()\n", + " self._dirty = False\n", + " return fp\n", + "\n", + " @classmethod\n", + " def load(cls, root_dir: Path, name: str):\n", + " return cls.from_json(root_dir, name)\n", + "\n", + "\n", + " def show(self):\n", + " config = self.config\n", + " gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + " model_path = config.get_model_path(gpu)\n", + " device = (\"mps\" if torch.backends.mps.is_available() else \"cuda\") if model_path.suffix == \".pt\" else \"cpu\"\n", + "\n", + " config.show()\n", + " cprint(\n", + " f\"{'config cache_dir':>17}: {repr(config.cache_dir)}\\n\"\n", + " f\"{'model_path':>17}: {repr(model_path)}\\n\"\n", + " f\"{'device':>17}: {repr(device)}\")\n", + " \n", + " cprint(\n", + " f\"{'force_PIL':>17}: {self.force_PIL}\\n\"\n", + " f\"{'use_tunnel':>17}: {self.use_tunnel}\\n\"\n", + " f\"{'server_url':>17}: {repr(self.server.unc_share) if self.server else ''}\\n\"\n", + " f\"{'experiment dir':>17}: {self.root_dir}\\n\"\n", + " f\"{'source_dir':>17}: {self.final(self.source_dir)}\\n\"\n", + " f\"{'cache_dir':>17}: {self.final(self.cache_dir)}\\n\"\n", + " )\n", + "\n", + "\n", + " def __init__(self, \n", + " ocr_model: str,\n", + " root_dir: Path | str | None = None, \n", + " *, \n", + " config: cfg.Config | None = None, \n", + " server: web_server.WebServer | None = None,\n", + " run_name: str = 'Tesseract-crop-post',\n", + " load: bool = True):\n", + " if root_dir is None:\n", + " root_dir = type(self).EXP_DIR\n", + " self.config = config or type(self).get_config()\n", + " self.ocr_model = ocr_model\n", + " root_dir = Path(root_dir)\n", + " super().__init__(\n", + " ocr_model, self.get_image_paths(root_dir), root=root_dir, run_name=run_name)\n", + " self.image_paths = self._paths\n", + " self._reset_results()\n", + " self._images = self._subjects\n", + " use_pil = os.environ['USE_PIL'].lower() == 'true'\n", + " self.force_PIL = use_pil\n", + " use_tunnel = os.environ['USE_TUNNEL'].lower() == 'true'\n", + " self.use_tunnel = use_tunnel\n", + " self.server = server or SERVER\n", + " if load:\n", + " self._from_json()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "@FC.patch_to(ImageContext)\n", + "def setup(self, exp: OCRExperimentContext, image_idx: ImgSpecT, page_lang: str | None = None):\n", + " super(type(self), self).setup(exp, image_idx)\n", + " self._mask_dilated1 = self._mask_dilated05 = self._mask_dilated02 = None\n", + " self.json_data, self.page_data = exp._load_page_data(self.idx)\n", + " self.setup_page_lang(page_lang)\n", + " self.mask = Image.open(exp.final(self.mask_path))\n", + " self.base_image = Image.open(exp.final(self.image_path))\n", + " self.setup_ground_truth()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [], + "source": [ + "exp = OCRExperimentContext('test')\n", + "test_eq(rr := exp._results, {})\n", + "test_eq(rr['Tesseract'][0][0], {})\n", + "test_eq(rr, {'Tesseract': {0: {0: {}}}})\n", + "test_eq(rr['Tesseract'][0][0].get(CM.INITIAL_BOX), None)\n", + "rr['Tesseract'][0][0][CM.INITIAL_BOX] = 'a' # type: ignore\n", + "test_eq(rr, {'Tesseract': {0: {0: {CM.INITIAL_BOX: 'a'}}}})\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## SimpleResultVisor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class SimpleResultVisor:\n", + " ctx: ResultOCR\n", + "\n", + " @classmethod\n", + " def diff_tagged(cls, result: ResultOCR):\n", + " _, html = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr, False)\n", + " return f\"{html}\"\n", + "\n", + " def as_html(self):\n", + " result = self.ctx\n", + " DI = cast(OCRExperimentContext, result.image_ctx.exp).DI\n", + " if isinstance(result, ResultOCRExtracted):\n", + " return self.as_html_extracted()\n", + " has_ocr = result.ocr is not None\n", + " acc_html = ''\n", + " if has_ocr:\n", + " acc_html = f\"
{result.acc:.2f}\"\n", + " html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr)\n", + " box_image_path = result.cache_image()\n", + " html1 = get_columns_html([[DI(box_image_path)], [(result.ocr or '') + acc_html]])\n", + " if has_ocr:\n", + " html2 = f\"
{html_str1}
{html_str2}
\"\n", + " else:\n", + " html2 = f\"
{html_str1}
\"\n", + " return html1 + '\\n
\\n' + html2\n", + "\n", + " def as_html_extracted(self):\n", + " result = self.ctx\n", + " has_ocr = result.ocr is not None\n", + " DI = cast(OCRExperimentContext, result.image_ctx.exp).DI\n", + " html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr)\n", + " if has_ocr:\n", + " diff_html = f\"
{html_str1}
{html_str2}
\"\n", + " else:\n", + " diff_html = f\"
{html_str1}
\"\n", + " cropped_image_path = result.cache_image(None, \"cropped\")\n", + " cropped_mask_path = result.cache_image(None, \"mask\")\n", + " result_path = result.cache_image()\n", + " return '\\n
\\n'.join([\n", + " get_image_grid_html([\n", + " DI(cropped_image_path), DI(cropped_mask_path), DI(result_path)], 1, 3), \n", + " acc_as_html(result.acc) if has_ocr else '', \n", + " diff_html\n", + " ])\n", + " \n", + " def display(self): display(HTML(self.as_html()))\n", + " def _ipython_display_(self): self.display()\n", + "\n", + " def __init__(self, ctx: ResultOCR):\n", + " self.ctx = ctx\n", + "\n", + "\n", + "ResultOCR._default_visor_type = SimpleResultVisor # type: ignore\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ExperimentContext.EXP_DIR\n", + "> Directory where the source images resides (`source/`) and the resulting images will be cached (`cache/`).\n", + "\n", + "By default, is set to `../experiment/`, and that's the value used by any `ExperimentContext` if not explicitly set on `__init__`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "EXP_DIR = ExperimentContext.EXP_DIR\n", + "test_eq(EXP_DIR, Path('../experiment'))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CONTEXT\n", + "> `CONTEXT` is an `ExperimentContext` object that contains the configuration and the list of image paths.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## PanelCleaner Configuration\n", + "> Adapt `PanelCleaner` `Config` current config to this notebook.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get PanelCleaner config the usual way or through `OCRExperimentContext`" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "# CONFIG = cfg.load_config()\n", + "\n", + "# profile = CONFIG.current_profile\n", + "# preprocessor_conf = profile.preprocessor\n", + "# # Modify the profile to OCR all boxes.\n", + "# # Make sure OCR is enabled.\n", + "# preprocessor_conf.ocr_enabled = True\n", + "# # Make sure the max size is infinite, so no boxes are skipped in the OCR process.\n", + "# preprocessor_conf.ocr_max_size = 10**10\n", + "# # Make sure the sus box min size is infinite, so all boxes with \"unknown\" language are skipped.\n", + "# preprocessor_conf.suspicious_box_min_size = 10**10\n", + "# # Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics.\n", + "# preprocessor_conf.ocr_blacklist_pattern = \".*\"\n", + "\n", + "# gpu = torch.cuda.is_available() or torch.backends.mps.is_available()\n", + "# model_path = CONFIG.get_model_path(gpu)\n", + "\n", + "# if model_path is None:\n", + "# # don't mess with normal PanelCleaner, download models directly\n", + "# import pcleaner.model_downloader as md\n", + "# model_dir = CONFIG.get_model_cache_dir()\n", + "# CONFIG.default_torch_model_path = md.download_torch_model(model_dir)\n", + "# CONFIG.default_cv2_model_path = md.download_cv2_model(model_dir)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creates the `OCRExperimentContext` object we'll use to manage experiments.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "CONTEXT = OCRExperimentContext('Tesseract')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: cursor\n", + "Cache Directory: System default\n", + "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", + "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
 config cache_dir: None\n",
+       "       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
+       "           device: 'mps'\n",
+       "
\n" + ], + "text/plain": [ + " config cache_dir: \u001b[3;35mNone\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'mps'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
        force_PIL: False\n",
+       "       use_tunnel: False\n",
+       "       server_url: \n",
+       "   experiment dir: ../experiment\n",
+       "       source_dir: ../experiment/source\n",
+       "        cache_dir: ../experiment/cache\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " force_PIL: \u001b[3;91mFalse\u001b[0m\n", + " use_tunnel: \u001b[3;91mFalse\u001b[0m\n", + " server_url: \n", + " experiment dir: ..\u001b[35m/\u001b[0m\u001b[95mexperiment\u001b[0m\n", + " source_dir: ..\u001b[35m/experiment/\u001b[0m\u001b[95msource\u001b[0m\n", + " cache_dir: ..\u001b[35m/experiment/\u001b[0m\u001b[95mcache\u001b[0m\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "test_eq(CONTEXT.config.current_profile.preprocessor.ocr_enabled, True)\n", + "test_eq(CONTEXT.config.current_profile.preprocessor.ocr_max_size, 10**10)\n", + "test_eq(CONTEXT.config.current_profile.preprocessor.suspicious_box_min_size, 10**10)\n", + "test_eq(CONTEXT.config.current_profile.preprocessor.ocr_blacklist_pattern, \".*\")\n", + "\n", + "test_eq(CONTEXT.root_dir, EXP_DIR)\n", + "test_eq(CONTEXT.cache_dir, Path(ExperimentContext.CACHE_DIR_NAME))\n", + "test_eq(CONTEXT.source_dir, Path(ExperimentContext.SOURCE_DIR_NAME))\n", + "\n", + "CONTEXT.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n", + "> `IMAGE_PATHS` is a list of image file paths that are used as input for testing the OCR methods." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Copy your images to the source directory or use the standard set:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IMAGE_PATHS = CONTEXT.image_paths\n", + "\n", + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "ExperimentContext offers facilities to access the subjects data (images in this case) in the context.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "test_eq(CONTEXT.subject_count, 32)\n", + "\n", + "test_eq(CONTEXT.subject_cache_dir(2), CONTEXT.cache_dir / CONTEXT.image_paths[2].stem)\n", + "\n", + "test_eq(CONTEXT.normalize_idx(2), 2)\n", + "test_eq(CONTEXT.normalize_idx('Action_Comics_1960-01-00_(262).JPG'), 0)\n", + "test_eq(CONTEXT.normalize_idx(IMAGE_PATHS[31]), 31)\n", + "\n", + "test_eq(CONTEXT.path_from_idx(2), IMAGE_PATHS[2])\n", + "test_eq(CONTEXT.path_from_idx('Barnaby_v1-028.png', cached=True), CONTEXT.cached_image(2))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# EXP_RUN\n", + "> `EXP_RUN` is the current `OCRExperimentRun`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'Tesseract-crop'" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "EXP_RUN = CONTEXT.experiment_run()\n", + "assert EXP_RUN is not None\n", + "RUN_NAME = EXP_RUN.name\n", + "RUN_NAME\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Context browser\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## RunSelector\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class RunSelector(ContextVisor):\n", + " def setup_controls(self):\n", + " options = self.run_names\n", + " w = W.Dropdown(\n", + " options=options, \n", + " value=self.values['run_name'],\n", + " layout={'width': 'fit-content'},\n", + " style={'description_width': 'initial'})\n", + " return {'run_name': w}\n", + "\n", + " def setup_ui(self):\n", + " ctls = self.controls\n", + " model_grp = W.HBox([ctls['run_name']])\n", + " model_grp.add_class('model_grp')\n", + " ui = W.HBox([*super().comps_ui(), model_grp])\n", + " return ui\n", + "\n", + " def __init__(self, \n", + " exp_ctx: OCRExperimentContext,\n", + " run_name: str | None=None,\n", + " run_names: list[str] | None = None,\n", + " **kwargs\n", + " ):\n", + " self.run_names: list[str] = run_names or exp_ctx.run_names\n", + " super().__init__(exp_ctx, \n", + " {'run_name': run_name or self.run_names[0]})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0c2020d24be648859a860e5164b7a488", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), options=('Tesseract-…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('run_selector')\n", + "\n", + "run_selector = RunSelector(CONTEXT)\n", + "run_selector\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## MessageVisor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class MessageVisor(ContextVisor):\n", + " EMPTY = ''\n", + "\n", + " # _css = \"\"\"\n", + " # .message_visor-yXy {\n", + " # border: 1px solid red;\n", + " # }\n", + " # \"\"\"\n", + "\n", + " @property\n", + " def msg(self): return self.values['msg']\n", + " \n", + " def update_output(self, /, msg: str | None = None, **kwargs):\n", + " if msg is not None and msg != self.EMPTY:\n", + " cprint(msg)\n", + " self.values['msg'] = None\n", + " else:\n", + " clear_output()\n", + " \n", + " def setup_style(self):\n", + " self.out.add_class('message_visor-yXy')\n", + " return super().setup_style()\n", + "\n", + " def setup_controls(self):\n", + " # w = W.Label(value=self.values['msg'] if self.values['msg'] != self.EMPTY else None, \n", + " # layout={'width': 'fit-content'})\n", + " return {}#{'msg': w}\n", + "\n", + " def __init__(self, \n", + " msg: str | None = None,\n", + " **kwargs\n", + " ):\n", + " super().__init__(None, \n", + " {'msg': msg}, \n", + " **kwargs)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('message_visor')\n", + "\n", + "message_visor = MessageVisor('Hello, Earth-616!')\n", + "message_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "message_visor.update(msg='Hello, mirror universe!')\n" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "message_visor.update(msg=MessageVisor.EMPTY)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "message_visor.update(msg=\"seeya'!\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "cleanupwidgets('message_visor')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Status visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class StatusVisor(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + "\n", + " @property\n", + " def save_button(self) -> W.Button: return self.controls['save'] # type: ignore\n", + " @property\n", + " def reset_button(self) -> W.Button: return self.controls['reset'] # type: ignore\n", + " \n", + " def setup_controls(self):\n", + " style={'font_size': '1em', 'font_weight': 'bold'}\n", + " sw = W.Button(description = 'save', style=style,\n", + " layout={'width': '4em'},\n", + " )\n", + " rw = W.Button(description = 'reset', style=style,\n", + " layout={'width': '5em', 'margin': '0px 0px 0px 3em'},\n", + " )\n", + " return {'save': sw, 'reset': rw}\n", + "\n", + " def setup_ux(self):\n", + " source = (self.ctx, '_dirty')\n", + " target = (self.save_button, 'disabled')\n", + " T.dlink(source, target, lambda x: not x)\n", + " target = (self.save_button.style, 'button_color')\n", + " T.dlink(source, target, lambda x: 'lightblue' if x else None)\n", + " \n", + "\n", + " def __init__(self, exp_ctx: OCRExperimentContext, **kwargs):\n", + " super().__init__(exp_ctx, {}, **kwargs)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bd2189871d114efda2d8289cff17f061", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(Button(description='save', disabled=True, layout=Layout(width='4em'), style=Butt…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('status_visor')\n", + "\n", + "CONTEXT._dirty = False\n", + "status_visor = StatusVisor(CONTEXT)\n", + "status_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "
Where the end of this divining rod turns to the earth we'll find water.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "result = CONTEXT.result(RUN_NAME, 2, 3, CropMethod.INITIAL_BOX, ocr=False)\n", + "result\n" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT._dirty = False\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OCRModelSelector\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class OCRModelSelector(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + " \n", + " def setup_controls(self):\n", + " options = self.models\n", + " w = W.Dropdown(\n", + " options=options, \n", + " value=self.values['model'],\n", + " layout={'width': 'fit-content'},\n", + " style={'description_width': 'initial'})\n", + " return {'model': w}\n", + "\n", + " def setup_ui(self):\n", + " ctls = self.controls\n", + " model_grp = W.HBox([ctls['model']])\n", + " model_grp.add_class('model_grp')\n", + " ui = W.HBox([*super().comps_ui(), model_grp])\n", + " return ui\n", + "\n", + " def __init__(self, \n", + " exp_ctx: OCRExperimentContext,\n", + " ocr_model: OCRModel | None=OCRModel.TESSERACT,\n", + " ocr_models: dict[str, OCRModel] | None = None,\n", + " out: W.Output | None = None\n", + " ):\n", + " self.models: dict[str, OCRModel] = ocr_models or OCRModel.__display_names__()\n", + " super().__init__(exp_ctx, \n", + " {'model': ocr_model or OCRModel.TESSERACT}, \n", + " out=out or self.out)#, ctxs=[exp_visor])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "372113f76b744e858ab64c6e2eb4e750", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(HBox(children=(Dropdown(layout=Layout(width='fit-content'), options={'Tesseract'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "model_selector = OCRModelSelector(CONTEXT)\n", + "model_selector\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ContentSelector" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class DisplayOptions(Enum):\n", + " BOXES = 0\n", + " IMAGE = 1\n", + " MASK = 2\n", + " IMAGE_MASK = 3\n", + " PAGE_DATA = 4\n", + " GROUND_TRUTH = 5\n", + " ALL = 6\n", + " RESULTS = 7\n", + " BEST_RESULTS = 8\n", + " ACCURACY = 9\n", + " DATAFRAME = 10\n", + " CONFIG = 11\n", + "\n", + " @staticmethod\n", + " def __display_names__():\n", + " return dict(\n", + " zip(\"Boxes, Image, Mask, Image & Mask, Page data, Ground truth, Image All, Results, \"\n", + " \"Best results, Accuracy, Dataframe, Config\".split(', '), \n", + " DisplayOptions))\n", + "\n", + "\n", + "class ContentSelector(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + "\n", + " def image_info(self, image_ctx: ImageContext): \n", + " img = image_ctx.base_image\n", + " (w, h), print_size_in, print_size_cm, required_dpi = image_ctx.image_info\n", + " format = PRINT_FORMATS['Modern Age']\n", + " cprint( f\"{'Width x Height':>30}: {w} x {h} pixels\\n\"\n", + " f\"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\\n\"\n", + " f\"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in\"\n", + " f\" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\\n\"\n", + " f\"Required DPI Modern Age format: {required_dpi:.3f} dpi \"\n", + " f\"({format[0]:.3f} x {format[1]:.3f} in)\")\n", + "\n", + "\n", + " def display_content(self, image_ctx: ImageContext, display_option: DisplayOptions):\n", + " DI = self.ctx.DI\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.PAGE_DATA):\n", + " self.image_info(image_ctx)\n", + " RenderJSON(image_ctx.json_data, 350, 2).display()\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.GROUND_TRUTH):\n", + " cprint(image_ctx.gts)\n", + " if display_option == DisplayOptions.CONFIG:\n", + " self.ctx.show()\n", + " if display_option == DisplayOptions.IMAGE:\n", + " display_image_grid([DI(image_ctx.image_path)], 1, 1)\n", + " if display_option == DisplayOptions.MASK:\n", + " display_image_grid([DI(image_ctx.mask_path)], 1, 1)\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.IMAGE_MASK):\n", + " display_image_grid([DI(image_ctx.image_path), DI(image_ctx.mask_path)], 1, 2)\n", + " if display_option in (DisplayOptions.ALL, DisplayOptions.BOXES):\n", + " display_image_grid([DI(image_ctx.image_boxes_path)], 1, 1)\n", + "\n", + "\n", + " def setup_controls(self):\n", + " options = self.display_options or {**DisplayOptions.__display_names__()}\n", + " display_option_wdgt = W.Dropdown(\n", + " options=options, \n", + " value=self.values['display_option'],\n", + " layout={'width': '120px'},\n", + " style={'description_width': 'initial'})\n", + " return {'display_option': display_option_wdgt}\n", + "\n", + "\n", + " def setup_ui(self):\n", + " ctls = self.controls\n", + " display_option_grp = W.HBox([ctls['display_option']])\n", + " display_option_grp.add_class('display_option_grp')\n", + " comps = self.comps_ui()\n", + " ui = W.HBox([*comps, display_option_grp])\n", + " return ui\n", + "\n", + "\n", + " def __init__(self, \n", + " exp_ctx: OCRExperimentContext,\n", + " display_option: DisplayOptions | None=DisplayOptions.BOXES,\n", + " display_options: Mapping[str, DisplayOptions] | None = None,\n", + " **kwargs\n", + " ):\n", + " self.display_options = display_options\n", + " super().__init__(exp_ctx, \n", + " {'display_option': display_option or DisplayOptions.BOXES}, \n", + " **kwargs)#, ctxs=[exp_visor])\n" + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "379b9649230a41a1bb6f8bf778aeb332", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(HBox(children=(Dropdown(index=2, layout=Layout(width='120px'), options={'Boxes':…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "content_selector = ContentSelector(CONTEXT, DisplayOptions.MASK)\n", + "content_selector\n" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [], + "source": [ + "content_selector.update(display_option=DisplayOptions.MASK)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ImageSelector" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ImageSelector(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + "\n", + " @property\n", + " def image_ctx(self):\n", + " return ImageContext(self.ctx, self.values['image_idx'])\n", + " \n", + " def setup_controls(self):\n", + " paths = self.ctx.image_paths\n", + " w = W.Dropdown(\n", + " options={_.stem:i for i,_ in enumerate(paths)}, \n", + " value=self.values['image_idx'],\n", + " # layout={'width': 'fit-content'},\n", + " layout={'width': '25em'},\n", + " style={'description_width': 'initial'})\n", + " return {'image_idx': w}\n", + "\n", + " def update(self, image_idx: ImgSpecT | None = None, **kwargs):\n", + " if image_idx is None: return\n", + " idx = self.ctx.normalize_idx(image_idx)\n", + " if idx is None: return\n", + " super().update(image_idx=idx, **kwargs)\n", + "\n", + "\n", + " def __init__(self, \n", + " ctx: OCRExperimentContext, /, \n", + " image_idx: ImgSpecT = 0, \n", + " **kwargs):\n", + " idx = ctx.normalize_idx(image_idx)\n", + " assert idx is not None, f\"Image {image_idx} not found in experiment context\"\n", + " super().__init__(ctx, {'image_idx': idx}, **kwargs)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "9cc6381da8e646a1b118578ad328e52a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HBox(children=(Dropdown(index=2, layout=Layout(width='25em'), options={'Action_Comics_1960-01-0…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('image_selector')\n", + "\n", + "image_selector = ImageSelector(CONTEXT, 2)\n", + "image_selector\n" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": {}, + "outputs": [], + "source": [ + "image_selector.update(13)\n", + "test_eq(image_selector.values['image_idx'], 13)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OCRContextVisor" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "class OCRContextVisor(ContextVisor):\n", + " ctx: OCRExperimentContext\n", + " \n", + " def update_output(self, /, image_idx: ImgIdT, **kwargs):\n", + " ctx = self.ctx\n", + " img_path = ctx.path_from_idx(image_idx, cached=ctx.force_PIL)\n", + " img = ctx.display_image(img_path)\n", + " display_image_grid([img], 1, 1)\n", + "\n", + " def update(self, image_idx: ImgSpecT | None = None, **kwargs):\n", + " if image_idx is None: return\n", + " idx = self.ctx.normalize_idx(image_idx)\n", + " if idx is None: return\n", + " super().update(image_idx=idx, **kwargs)\n", + " \n", + " def __init__(self, \n", + " ctx: OCRExperimentContext, /, \n", + " image_idx: ImgSpecT = 0, *, \n", + " out: W.Output | None=None):\n", + " super().__init__(ctx, {}, out, \n", + " ctxs={'image_idx': ImageSelector(ctx, image_idx, out=self.out)})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bbf5ee92ee4944018eca90195350d5a4", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(VBox(children=(VBox(children=(Dropdown(index=2, layout=Layout(width='fit-content'), options={'A…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('ctx_visor')\n", + "\n", + "# ContextVisor(CONTEXT)\n", + "# ContextVisor(CONTEXT).display(3)\n", + "ctx_visor = OCRContextVisor(CONTEXT, 2)\n", + "ctx_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [], + "source": [ + "ctx_visor.update('Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base image\n", + "> Change `BASE_IMAGE_IDX` to select a different base image to use in the examples below." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", + "\n", + "assert BASE_IMAGE_IDX is not None\n", + "img_path = CONTEXT.final(CONTEXT.image_paths[BASE_IMAGE_IDX])\n", + "assert img_path.exists()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Empty cache\n", + "> Clear the image cache used profusely throughout the examples below." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "You will be warned before the cache is emptied." + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [], + "source": [ + "# CONTEXT.empty_cache_warning()" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [], + "source": [ + "# CONTEXT.empty_cache_warning(30)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ImageContext of base image\n", + "> Creates the `ImageContext` for the base image.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If `PanelCleaner` page data is already cached, it is loaded from the cache.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT._reset_()" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "
\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "page_lang = 'English'\n", + "# page_lang = 'Japanese'\n", + "# page_lang = 'Spanish'\n", + "# page_lang = 'French'\n", + "\n", + "IMAGE_CONTEXT = ImageContext(CONTEXT, BASE_IMAGE_IDX, page_lang=page_lang)\n", + "test_eq(IMAGE_CONTEXT.page_data is not None, True)\n", + "# cprint(IMAGE_CONTEXT.page_data.boxes)\n", + "RenderJSON(IMAGE_CONTEXT.json_data, 360, 2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [], + "source": [ + "test_is(IMAGE_CONTEXT, ImageContext(CONTEXT, BASE_IMAGE_IDX))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Visualize image" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Strange_Tales_172005.jpg - 1275x1888 px: 4.25x6.29\" @ 188.32 dpi
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "display_image_grid([\n", + " CONTEXT.DI(IMAGE_CONTEXT.image_path), \n", + " CONTEXT.DI(IMAGE_CONTEXT.mask_path)\n", + " ], 1, 2, caption=IMAGE_CONTEXT.image_name_rich)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "boxes_path = IMAGE_CONTEXT.image_boxes_path\n", + "display_image_grid([CONTEXT.DI(boxes_path)], 1, 1)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Image browser" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ImageContextVisor" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "notebookRunGroups": { + "groupValue": "2" + } + }, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class ImageContextVisor(ContextVisor):\n", + " ctx: ImageContext\n", + " # control_names: list[str] = ['display_option']\n", + "\n", + " _css = \"\"\"\n", + " .display_option_grp {\n", + " background-color: lightblue;\n", + " }\n", + " \"\"\"\n", + "\n", + " def image_info(self): \n", + " content_selector = cast(ContentSelector, self.comp('display_option'))\n", + " content_selector.image_info(self.ctx)\n", + "\n", + " def update_output(self, \n", + " display_option: DisplayOptions | None = None,\n", + " image_idx: ImgIdT | None = None,\n", + " **kwargs):\n", + " content_selector = cast(ContentSelector, self.comp('display_option'))\n", + " if image_idx is not None and image_idx != self.ctx.image_idx:\n", + " ctx = ImageContext(self.ctx.exp, image_idx)\n", + " assert ctx is not None\n", + " self.ctx = ctx\n", + " display_option = content_selector.values['display_option']\n", + " if display_option is None:\n", + " return\n", + " content_selector.display_content(self.ctx, display_option)\n", + " \n", + " def update(self, \n", + " display_option: DisplayOptions | None=None, \n", + " image_idx: ImgSpecT | None=None,\n", + " **kwargs):\n", + " if image_idx is not None:\n", + " if (idx := self.ctx.exp.normalize_idx(image_idx)) is not None:\n", + " kwargs['image_idx'] = idx\n", + " super().update(display_option=display_option, **kwargs)\n", + "\n", + " def __init__(self, \n", + " exp_ctx: OCRExperimentContext,\n", + " img_idx: ImgSpecT | ImageContext,\n", + " display_option: DisplayOptions=DisplayOptions.BOXES,\n", + " display_options: Mapping[str, DisplayOptions] | None = None,\n", + " out: W.Output | None = None\n", + " ):\n", + " if isinstance(img_idx, ImageContext):\n", + " ctx = img_idx\n", + " else:\n", + " assert exp_ctx is not None, \"exp_ctx must be provided if img_idx is not an ImageContext\"\n", + " ctx = ImageContext(exp_ctx, img_idx)\n", + " assert ctx is not None, f\"Image {img_idx} not found in experiment context\"\n", + " if display_options is None:\n", + " display_options = {k: v for k, v in DisplayOptions.__display_names__().items() \n", + " if k not in ('Results', 'Accuracy', 'Best results', 'Dataframe', 'Config')}\n", + " out = out or self.out\n", + " content_selector = ContentSelector(exp_ctx, \n", + " display_option=display_option, display_options=display_options, out=out)\n", + " image_selector = ImageSelector(exp_ctx, ctx.image_idx, out=out)\n", + " super().__init__(ctx, {}, out=out, \n", + " ctxs={'image_idx': image_selector, 'display_option': content_selector})\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Easier to use `ImageContextVisor` to display interactively images, masks, and associated page data.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": {}, + "outputs": [], + "source": [ + "CONTEXT._reset_()" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "8bfbbd7344224964994f913744b75bdc", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HTML(value=\"\"\n", + " self._style = W.HTML(stl)\n", + " else:\n", + " self._style = ''\n", + " return self._style\n", + " def setup_style(self):\n", + " collate = [_.setup_style() for _ in self.comps.values()]\n", + " if self._css: collate.append(self._css)\n", + " return '\\n'.join([_ for _ in collate if _])\n", + " \n", + " def update_output(self, **kwargs): \n", + " cprint(kwargs)\n", + " \n", + " def setup_controls(self) -> dict[str, CtlT]:\n", + " widgets = [W.interactive.widget_from_abbrev(v) for k, v in self.values.items()]\n", + " widgets = {k:W.fixed(v) if w is None else w for (k, v), w in zip(self.values.items(), widgets)}\n", + " # return {k: W.Label(value=str(k)) for k,w in self.values.items()}\n", + " return widgets\n", + " \n", + " def hide(self): \n", + " if (w := self.w) is not NO_UI: \n", + " w.layout.visibility = 'hidden'\n", + " def show(self): \n", + " if (w := self.w) is not NO_UI: \n", + " w.layout.visibility = 'visible'\n", + "\n", + " def comps_ui(self):\n", + " comps = []\n", + " if self._inited: \n", + " for visor in self.comps.values():\n", + " if (visor_ui := visor._setup_ui()) is not None:\n", + " comps.append(visor_ui)\n", + " return comps\n", + "\n", + "\n", + " def _setup_ui(self):\n", + " if not self._inited: return\n", + " w = self.setup_ui()\n", + " if w is not None:\n", + " w.add_class('context-visor')\n", + " w.add_class(str(id(self)))\n", + " return w\n", + " \n", + " def setup_ui(self) -> W.DOMWidget | None:\n", + " \"\"\"Get the container widget for this comp.\n", + " This method should be the only one called when the comp is nested inside other comp.\n", + " \"\"\"\n", + " uis = [*self.comps_ui(), *self.controls.values()]\n", + " return self._ui_cls(uis) if uis else None\n", + "\n", + " def setup_display(self): \n", + " \"Generates one time ui\"\n", + " if not self._inited: return\n", + " if self._w is None:\n", + " self._w = self._setup_ui()\n", + " \n", + "\n", + " def _output(self, **kwargs):\n", + " # group keys by comp\n", + " collator = defaultdict(dict)\n", + " for k,v in kwargs.items():\n", + " if (comp := self.handler(k)) is not None:\n", + " collator[comp][k] = v\n", + " else:\n", + " # keys w/out control assigned, considered internal state\n", + " collator[self][k] = v\n", + " # group comps by output\n", + " outs = defaultdict(list)\n", + " for comp, kw in collator.items():\n", + " outs[comp.out].append((comp, kw))\n", + " for out, g in outs.items():\n", + " show_inline_matplotlib_plots()\n", + " with out:\n", + " clear_output(wait=True)\n", + " for comp, kw in g:\n", + " comp.update_output(**kw)\n", + " show_inline_matplotlib_plots()\n", + "\n", + " def _observe(self, change):\n", + " control_name = self._ctl2name[change['owner']]\n", + " kwargs = {control_name: change['new']}\n", + " updated = self._update(**kwargs)\n", + " self._output(**updated)\n", + " def setup_ux(self): pass\n", + " def _setup_ux(self): \n", + " for visor in self.comps.values():\n", + " visor._setup_ux()\n", + " self.setup_ux()\n", + " def interactive_output(self):\n", + " controls = self.all_controls\n", + " all_values = self._all_values()\n", + " for k,w in controls.items():\n", + " if k in all_values:\n", + " w.observe(self._observe, 'value')\n", + " \n", + " def display(self, **kwargs): \n", + " if not self._inited: return\n", + " if self._w is None:\n", + " self.setup_display()\n", + " self.interactive_output()\n", + " self._update(**(self.values | kwargs))\n", + " all_values = self._all_values()\n", + " self._hdlrs = {k:self._hdlrs.get(k, self) for k in all_values}\n", + " self._output(**all_values)\n", + " # ux final touches once everything (including outputs) is setup\n", + " # for visor in [*self.comps.values(), self]:\n", + " # visor.setup_ux()\n", + " self._setup_ux()\n", + " stl = self.styler\n", + " ui: list = [stl] if stl else []\n", + " if (w := self.w) is not NO_UI:\n", + " ui.append(w)\n", + " for comp in [*self.comps.values(), self]:\n", + " if comp._out is not None:\n", + " ui.append(comp._out)\n", + " self._final = W.VBox(ui)\n", + " self._display_handle = display(self._final, display_id=str(id(self)))\n", + " else:\n", + " self.update(**kwargs)\n", + " def _ipython_display_(self): self.display()\n", + "\n", + " def _update(self, update_value: bool=True, **kwargs):\n", + " updated = {}\n", + " for visor in self.comps.values():\n", + " updated.update(visor._update(update_value=update_value, **kwargs))\n", + " values = self.values\n", + " my_vals = _pops_(kwargs, self.values.keys())\n", + " for k,v in my_vals.items():\n", + " if v is not None and v != values[k]:\n", + " if update_value: \n", + " values[k] = v\n", + " updated[k] = v\n", + " return updated\n", + " def update(self, **kwargs):\n", + " updated = self._update(update_value=False, **kwargs)\n", + " controls = self.all_controls\n", + " for k,v in updated.items():\n", + " if k in controls:\n", + " if hasattr((ctl := controls[k]), 'value'):\n", + " ctl.value = v # will trigger update (self._observe)\n", + " elif k in (vv := self._name2comp):\n", + " # update manually\n", + " comp = vv[k]\n", + " if v != comp.values[k]:\n", + " comp.values[k] = v\n", + " self._output(**{k:v})\n", + " \n", + "\n", + " def close(self):\n", + " controls = self.all_controls\n", + " for w in controls.values():\n", + " try: w.unobserve(self._observe, 'value')\n", + " except: pass\n", + " if isinstance(w, W.Widget):\n", + " w.close()\n", + " for visor in self._ctxs.values():\n", + " if w := getattr(visor, '_w', None): w.close()\n", + " if visor._out is not self._out:\n", + " if o := getattr(visor, '_out', None): o.close()\n", + " visor.close()\n", + " if w := getattr(self, '_w', None): w.close()\n", + " if o := getattr(self, '_out', None): o.close()\n", + " if f := self._final: f.close()\n", + " if self._display_handle is not None:\n", + " self._display_handle.update(HTML(UPDATE_SCRIPT))\n", + "\n", + "\n", + " def __del__(self): \n", + " self.close()\n", + "\n", + " def __init__(self, \n", + " ctx: Any, \n", + " values: dict[str, Any], \n", + " out: W.Output | None = None,\n", + " ctxs: dict[str, ContextVisor] | None = None,\n", + " hdlrs: dict[str, ContextVisor] | None = None,\n", + " css: str | None = None,\n", + " ):\n", + " # Only setup some state. Controls, values and containers will be setup only when explicitly displayed\n", + " self._display_handle = None\n", + " self._final = None\n", + " self.ctx = ctx\n", + " self.values = values or {}\n", + " self._out = out\n", + " self._ctxs = comps = ctxs or {}\n", + " self._hdlrs = hdlrs or {}\n", + " if css is not None:\n", + " self._css = css\n", + " self._name2comp = name2comp = {}\n", + " for n,vv in self.all_values.items():\n", + " comp = comps.get(n, self)\n", + " for k in vv:\n", + " name2comp[k] = comp\n", + " self._inited = True\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('test_visor')\n", + "\n", + "test_visor = ContextVisor(None, {'a': 1})\n", + "test_visor\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "test_eq(test_visor.values, {'a': 1})\n", + "test_visor.update(a='2')\n", + "test_eq(test_visor.values, {'a': 2})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "cleanupwidgets('test_visor')\n", + "test_eq(test_visor.w.comm, None)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "24553fa5d9f048939f4ac38bc266ea81", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(VBox(children=(VBox(children=(Text(value='bbb'),), _dom_classes=('context-visor', '13217200496'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('vsr1')\n", + "\n", + "vsr1 = ContextVisor(\n", + " None, {'a': 3}, \n", + " ctxs={'vsr2': ContextVisor(None, {'b': 'bbb'})}, \n", + ")\n", + "test_eq(vsr1.values, {'a': 3})\n", + "test_eq(vsr1.all_values, {'vsr2': {'b': 'bbb'}, 'self': {'a': 3}})\n", + "vsr1.display()\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "vsr1.update(a=2)\n", + "test_eq(vsr1.all_values, {'vsr2': {'b': 'bbb'}, 'self': {'a': 2}})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "vsr1.update(a=0, b='ccc')\n", + "test_eq(vsr1.all_values, {'vsr2': {'b': 'ccc'}, 'self': {'a': 0}})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c1e38a469327423b876d69297283e9d1", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(VBox(children=(VBox(children=(Text(value='bbb'),), _dom_classes=('context-visor', '13218749008'…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('vsr2')\n", + "\n", + "vsr3 = ContextVisor(None, {'b': 'bbb'})\n", + "vsr2 = ContextVisor(\n", + " None, {'a': 3}, \n", + " ctxs={'vsr3': vsr3}, \n", + " hdlrs={'b': vsr3}\n", + ")\n", + "vsr2.display()\n", + "test_eq(vsr2.values, {'a': 3})\n", + "test_eq(vsr2.all_values, {'vsr3': {'b': 'bbb'}, 'self': {'a': 3}})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "vsr2.update(a=1, b='ccc')\n", + "test_eq(vsr2.values, {'a': 1})\n", + "test_eq(vsr2.all_values, {'vsr3': {'b': 'ccc'}, 'self': {'a': 1}})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "class Vsr1(ContextVisor):\n", + " _css = \"\"\"\n", + " .vsr1 {\n", + " border: 1px solid red;\n", + " }\n", + " \"\"\"\n", + " def setup_ui(self) -> W.DOMWidget | None:\n", + " w = super().setup_ui()\n", + " if w is not None:\n", + " w.add_class('vsr1')\n", + " return w\n", + "\n", + "class Vsr2(ContextVisor):\n", + " _css = \"\"\"\n", + " .vsr2 {\n", + " border: 1px solid green;\n", + " }\n", + " \"\"\"\n", + " def setup_ui(self) -> W.DOMWidget | None:\n", + " uis = [*self.comps_ui(), *self.controls.values()]\n", + " w = W.HBox(uis) if uis else None\n", + " if w is not None:\n", + " w.add_class('vsr2')\n", + " return w\n", + "\n", + "vsr1 = Vsr1(\n", + " None, {'a': 3}, \n", + " ctxs={'vsr2': Vsr2(None, {'b': 'bbb'})}, \n", + " css = \"\"\"\n", + " .vsr1 {\n", + " border: 1px solid red;\n", + " }\n", + " \"\"\"\n", + ")\n", + "test_eq(vsr1.values, {'a': 3})\n", + "test_eq(vsr1.all_values, {'vsr2': {'b': 'bbb'}, 'self': {'a': 3}})\n", + "vsr1.display()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "cleanupwidgets('vsr1')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Spinner" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "spinner_css = \"\"\"\n", + " .wrapper-spinner {\n", + " overflow: hidden;\n", + " width: fit-content;\n", + " height: fit-content;\n", + " }\n", + " \n", + " .loading-spinner {\n", + " display: flex;\n", + " align-items: center;\n", + " justify-content: center;\n", + " border: 1px solid white;\n", + " border-radius: 50%;\n", + " }\n", + " \n", + " .spinner {\n", + " border: |border_width|px solid rgba(128,128,128,.5);\n", + " border-radius: 50%;\n", + " border-left-color: red;\n", + " animation: spin 1s infinite linear;\n", + " }\n", + " \n", + " @keyframes spin {\n", + " 0% { transform: rotate(0deg); }\n", + " 100% { transform: rotate(360deg); }\n", + " }\n", + "\"\"\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "# display(HTML(f\"\"))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "# def loading_spinner(size=36, border_width=4):\n", + "# bw = border_width*2\n", + "# html: str = f'''\n", + "#
\n", + "#
\n", + "#
\n", + "# '''\n", + "# return html" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# cleanupwidgets('spinner')\n", + "\n", + "# spinner = W.HTML(loading_spinner(24), \n", + "# # layout={\n", + "# # 'overflow': 'hidden', \n", + "# # 'width': 'fit-content', \n", + "# # 'height': 'fit-content',\n", + "# # 'border': '1px solid green'\n", + "# # }\n", + "# )\n", + "# spinner.add_class('wrapper-spinner')\n", + "# spinner\n" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "# spinner.layout.display = 'none'\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "# spinner.layout.display = 'block'\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [], + "source": [ + "# cleanupwidgets('spinner')" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "class Spinner(ContextVisor):\n", + " ctx: T.HasTraits\n", + "\n", + " def loading_spinner(self, size=36, border_width=4):\n", + " bw = border_width*2\n", + " html: str = f'''\n", + "
\n", + "
\n", + "
\n", + " '''\n", + " return html\n", + " \n", + " def setup_controls(self):\n", + " spinner = W.HTML(self.loading_spinner(self.size, self.border_width))\n", + " spinner.add_class('wrapper-spinner')\n", + " return {'spinner': spinner}\n", + "\n", + " @property\n", + " def spinner(self) -> W.HTML: return self.controls['spinner'] # type: ignore\n", + "\n", + " def hide(self): self.spinner.layout.display = 'none'\n", + " def show(self): self.spinner.layout.display = 'block'\n", + "\n", + " def setup_ux(self):\n", + " source = (self.ctx, '_running')\n", + " target = (self.spinner.layout, 'display')\n", + " self._link = T.dlink(source, target, lambda x: 'block' if x else 'none')\n", + "\n", + " def close(self):\n", + " if l := getattr(self, '_link', None): l.unlink()\n", + " super().close()\n", + "\n", + " def __init__(self, \n", + " ctx: T.HasTraits,\n", + " size: int = 24,\n", + " border_width: int = 4,\n", + " **kwargs\n", + " ):\n", + " self.size = size\n", + " self.border_width = border_width\n", + " self._link = None\n", + " super().__init__(ctx, {}, css=spinner_css.replace('|border_width|', str(border_width)), **kwargs)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('spinner')\n", + "\n", + "class _Test(T.HasTraits):\n", + " _running = T.Bool(True)\n", + "\n", + "test = _Test()\n", + "spinner = Spinner(test)\n", + "spinner.display()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [], + "source": [ + "# spinner.hide()\n", + "test._running = False\n" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "test._running = True\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "cleanupwidgets('spinner')\n", + "test_eq(test._trait_notifiers, {'_running': {'change': []}})\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cleanupwidgets('vsr3')\n", + "\n", + "vsr3 = Vsr1(\n", + " None, {'a': 3}, \n", + " ctxs={'vsr2': Vsr2(None, {'b': 'bbb'}, ctxs={'spinner': Spinner(test, 20, 3)})}, \n", + " css = \"\"\"\n", + " .vsr3 {\n", + " border: 1px solid red;\n", + " }\n", + " \"\"\"\n", + ")\n", + "test_eq(vsr3.values, {'a': 3})\n", + "test_eq(vsr3.all_values, {'vsr2': {'b': 'bbb'}, 'self': {'a': 3}})\n", + "vsr3.display()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ + "test._running = False\n" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "test._running = True\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "cleanupwidgets('vsr3')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Colophon\n", + "----\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "from nbdev.export import nb_export\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_NOTEBOOK:\n", + " nb_export('visor.ipynb', '..')\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/pcleaner/_testbed/nbs/web_server.ipynb b/pcleaner/_testbed/nbs/web_server.ipynb new file mode 100644 index 00000000..c505abd4 --- /dev/null +++ b/pcleaner/_testbed/nbs/web_server.ipynb @@ -0,0 +1 @@ +{"cells":[{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["#| default_exp testbed/web_server"]},{"cell_type":"code","execution_count":2,"metadata":{},"outputs":[],"source":["#| export\n","\n","from __future__ import annotations\n"]},{"cell_type":"code","execution_count":3,"metadata":{},"outputs":[],"source":["#| hide\n","# %reload_ext autoreload\n","# %autoreload 0\n"]},{"cell_type":"markdown","metadata":{},"source":["# install (Colab)"]},{"cell_type":"code","execution_count":4,"metadata":{},"outputs":[],"source":["MOUNT_DRIVE = True\n","DEV_INSTALL = True\n","GDRIVE_MOUNT_POINT = 'drive'\n"]},{"cell_type":"code","execution_count":5,"metadata":{},"outputs":[],"source":["import os\n","from pathlib import Path\n","import fastcore.all as FC\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," text = Text(msg)\n"," text.stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, text, \"_\" * 10)\n","\n","\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," mnt_point = f\"/content/{GDRIVE_MOUNT_POINT}\"\n"," if not Path(mnt_point).exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n","\n"," drive.mount(mnt_point, force_remount=True)\n"]},{"cell_type":"markdown","metadata":{},"source":["Colab has issues with PanelClenar PIL version.: uninstall Colab one, restart wen prompted and rerun from the top.\n"]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[],"source":["if FC.IN_COLAB:\n"," from packaging import version\n"," import PIL\n"," pil_version = version.parse(PIL.__version__)\n"," if pil_version < version.parse(\"10\"):\n"," info('Uninstalling Pillow')\n"," !pip uninstall Pillow\n"," info('Installing Pillow')\n"," !pip install Pillow\n"]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[],"source":["if FC.IN_COLAB:\n"," info('Installing PanelCleaner')\n"," if DEV_INSTALL:\n"," assert MOUNT_DRIVE, \"DEV_INSTALL need a mounted google drive drive\"\n"," info('Installing PanelCleaner from Google Drive')\n"," os.chdir('/content/drive/MyDrive/Shared/PanelCleaner/')\n"," !pip install -e .\n"," else:\n"," info('Installing PanelCleaner from Github')\n"," !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed-colab\n"]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[],"source":["if FC.IN_COLAB:\n"," info('Installing PanelCleaner Colab requirements')\n"," import importlib.resources\n"," if DEV_INSTALL:\n"," os.chdir('pcleaner/_testbed')\n"," \n"," try:\n"," package_path = importlib.resources.files('pcleaner')\n"," info('Installing PanelCleaner testbed requirements')\n"," p = (Path(package_path)/'_testbed/requirements-colab.txt')\n"," if p.exists():\n"," !pip install -r {p}\n"," else:\n"," print(f\"colab requirements {p} not found\")\n"," except Exception:\n"," info(\"Couldn't install PanelCleaner Colab requirements\")\n"]},{"cell_type":"markdown","metadata":{},"source":["# Basic web server for serving images from Google Drive\n"]},{"cell_type":"markdown","metadata":{},"source":["# Prologue"]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[],"source":["#| export\n","import getpass\n","import http.server\n","import os\n","import signal\n","import socketserver\n","import threading\n","import uuid\n","from http import HTTPStatus\n","from pathlib import Path\n","from typing import Protocol\n","\n","import portpicker\n","import psutil\n","import requests\n","import rich\n","from IPython.display import display\n","from IPython.display import HTML\n","from loguru import logger\n","from pyngrok import conf\n","from pyngrok import ngrok\n","from rich.console import Console\n"]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[],"source":["#| exporti\n","from pcleaner._testbed.testbed.bottle import Bottle\n","from pcleaner._testbed.testbed.bottle import HTTPError\n","from pcleaner._testbed.testbed.bottle import response\n","from pcleaner._testbed.testbed.bottle import run\n","from pcleaner._testbed.testbed.bottle import static_file\n"]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[],"source":["import fastcore.all as FC\n","import fastcore.xtras # patch Path with some utils\n","from fastcore.test import * # type: ignore\n","\n","import pcleaner._testbed.testbed.bottle as bottle\n"]},{"cell_type":"markdown","metadata":{},"source":["# Helpers"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[],"source":["# pretty print by default\n","# %load_ext rich"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[],"source":["#| exporti\n","console = Console(width=104, tab_size=4, force_jupyter=True)\n","cprint = console.print\n"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[],"source":["#| export\n","\n","def display_ngrok_warning(url):\n"," did = 'ngrokFrame' + str(uuid.uuid4())\n"," html_code = f\"\"\"\n","
\n","
\n","

Ngrok displays a warning page as a security measure to prevent unintentional access to your local servers. This page requires you to confirm that you wish to proceed to the content.

\n","

Please review the ngrok warning page displayed below. If prompted, click 'Visit Page' to proceed.

\n"," Don't worry if you see a 404 or 403 error. Then, you can click the 'Close' button below to hide this section.

\n","
\n"," \n"," \n","
\n","\"\"\"\n","\n"," display(HTML(html_code))\n"]},{"cell_type":"code","execution_count":25,"metadata":{},"outputs":[],"source":["#| export\n","\n","class WebServer(Protocol):\n"," @property\n"," def public_url(self) -> str | None: ...\n"," @property\n"," def unc_share(self) -> Path | None: ...\n"," @property\n"," def prefix(self) -> str: ...\n"," @property\n"," def running(self) -> bool: ...\n"," def __init__(self, directory: Path | str = \"\"): ...\n"," def start(self): ...\n"," def stop(self): ...\n","\n","\n","def setup_ngrok(server_cls: type[WebServer], images_dir: str | Path):\n"," cprint(\n"," \"Enter your ngrok authtoken, which can be copied from \"\n"," \"https://dashboard.ngrok.com/get-started/your-authtoken\"\n"," )\n"," auth_token = getpass.getpass()\n"," conf.get_default().auth_token = auth_token\n"," ngrok.set_auth_token(auth_token)\n","\n"," server = server_cls(directory=str(images_dir))\n"," try:\n"," server.start()\n"," except Exception as e:\n"," cprint(f\"Error starting server: {e}\")\n"," return None\n","\n"," display_ngrok_warning(f\"{server.public_url}/{server.prefix}/pcleaner.png\")\n"," return server\n"]},{"cell_type":"markdown","metadata":{},"source":["----"]},{"cell_type":"markdown","metadata":{},"source":["Modify `cache_dir` path to point to the directory containing the images you want to serve\n"]},{"cell_type":"code","execution_count":26,"metadata":{},"outputs":[],"source":["cache_dir = Path('../experiment/cache')\n","test_eq(cache_dir.exists(), True)\n"]},{"cell_type":"markdown","metadata":{},"source":["# WebServerStdlib\n","> simple web server based on `http.server` and `ngrok` as reverse proxy\n"]},{"cell_type":"code","execution_count":27,"metadata":{},"outputs":[],"source":["#| exporti\n","\n","class ImageHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):\n"," def end_headers(self):\n"," for k,v in {\n"," 'ngrok-skip-browser-warning': 'true',\n"," 'User-Agent': 'MyCustomUserAgent/1.0',\n"," 'Cache-Control': 'public, max-age=86400'\n"," }.items():\n"," self.send_header(k, v)\n"," super().end_headers()\n","\n"," def do_GET(self):\n"," if self.is_image_request(self.path):\n"," super().do_GET()\n"," else:\n"," self.send_error(HTTPStatus.FORBIDDEN, \"Only image files are accessible.\")\n","\n"," def is_image_request(self, path):\n"," allowed_extensions = ('.jpg', '.jpeg', '.png', '.gif', '.webp')\n"," _, ext = os.path.splitext(path)\n"," return ext.lower() in allowed_extensions\n"," \n"," def __init__(self, *args, **kwargs):\n"," super().__init__(*args, directory=self.directory, **kwargs)\n"]},{"cell_type":"code","execution_count":28,"metadata":{"executionInfo":{"elapsed":230,"status":"ok","timestamp":1715453246273,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"VJQya1SRr9ce"},"outputs":[],"source":["#| export\n","\n","class WebServerStdlib:\n"," \"\"\"\n"," A simple web server for serving images from a local directory using http.server and ngrok.\n"," \n"," It is intended to be used in environments like Google Colab, where direct\n"," web server hosting might not be feasible. It uses ngrok to allow images to be accessed \n"," via a public URL.\n"," \n"," Attributes:\n"," directory (str): The directory from which files are served.\n"," port (int): The local port on which the server listens.\n"," public_url (str): The ngrok public URL where the server is accessible.\n"," tunnel (ngrok.NgrokTunnel): The ngrok tunnel object.\n"," \n"," Methods:\n"," start(): Starts the web server and the ngrok tunnel.\n"," stop(): Stops the web server and disconnects the ngrok tunnel.\n"," make_request(path=\"/\"): Makes a request to the ngrok URL to fetch data from the server.\n"," \"\"\"\n"," \n"," def __init__(self, directory: Path | str=\"\"):\n"," port = portpicker.pick_unused_port()\n"," self.port = port\n"," if isinstance(directory, str): \n"," directory = Path(directory)\n"," assert directory.exists(), f\"Directory {directory} does not exist\"\n"," self.directory = str(directory.resolve())\n"," self.thread = None\n"," self.httpd = None\n"," self.public_url = None\n"," self.prefix = ''\n"," self.unc_share = None\n"," self.tunnel = None\n","\n"," @property\n"," def running(self):\n"," return self.thread is not None and self.thread.is_alive()\n"," \n"," def start_server(self):\n"," Handler = ImageHTTPRequestHandler \n"," Handler.directory = self.directory\n"," try:\n"," with socketserver.TCPServer((\"\", self.port), Handler) as httpd:\n"," self.httpd = httpd\n"," httpd.serve_forever()\n"," except OSError as e:\n"," cprint(f\"Error: {e}\")\n","\n"," def start(self):\n"," if self.thread is None or not self.thread.is_alive():\n"," self.thread = threading.Thread(target=self.start_server)\n"," self.thread.start()\n"," self.tunnel = ngrok.connect(self.port) # type: ignore\n"," self.public_url = self.tunnel.public_url\n"," if self.public_url is not None:\n"," self.unc_share = Path(self.public_url.replace('https:', ''))\n"," cprint(f\"ngrok tunnel: {self.tunnel}\")\n"," cprint(f\"Public URL: {self.public_url}\")\n"," else:\n"," cprint(\"Server is already running\")\n","\n"," def stop(self):\n"," if self.httpd:\n"," self.httpd.shutdown()\n"," self.httpd.server_close()\n"," if self.tunnel and self.tunnel.public_url:\n"," ngrok.disconnect(self.tunnel.public_url) # Use the stored tunnel object's URL\n"," cprint(\"Ngrok tunnel disconnected\")\n"," ngrok.kill()\n"," if self.thread:\n"," self.thread.join()\n"," self.thread = self.public_url = self.unc_share = None\n"," cprint(\"Server stopped\")\n","\n"," def make_request(self, path=\"/\"):\n"," \"\"\"Makes a request to the ngrok URL with headers to bypass the ngrok warning.\"\"\"\n"," if self.public_url:\n"," url = f\"{self.public_url}{path}\"\n"," headers = {\n"," \"ngrok-skip-browser-warning\": \"true\",\n"," \"User-Agent\": \"MyCustomUserAgent/1.0\"\n"," }\n"," response = requests.get(url, headers=headers)\n"," return response.text\n"," else:\n"," return \"Server not started or public URL not available.\"\n","\n"," def __enter__(self):\n"," self.start()\n"," return self\n","\n"," def __exit__(self, exc_type, exc_val, exc_tb):\n"," self.stop()\n"]},{"cell_type":"code","execution_count":29,"metadata":{},"outputs":[{"data":{"text/plain":["Path('../experiment/cache')"]},"execution_count":29,"metadata":{},"output_type":"execute_result"}],"source":["serve_dir = cache_dir\n","test_eq(serve_dir.exists(), True)\n","serve_dir"]},{"cell_type":"code","execution_count":30,"metadata":{},"outputs":[{"data":{"text/html":["
Enter your ngrok authtoken, which can be copied from \n","https://dashboard.ngrok.com/get-started/your-authtoken\n","
\n"],"text/plain":["Enter your ngrok authtoken, which can be copied from \n","\u001b[4;94mhttps://dashboard.ngrok.com/get-started/your-authtoken\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
ngrok tunnel: NgrokTunnel: \"https://36a0-83-33-227-209.ngrok-free.app\" -> \"http://localhost:55435\"\n","
\n"],"text/plain":["ngrok tunnel: NgrokTunnel: \u001b[32m\"https://36a0-83-33-227-209.ngrok-free.app\"\u001b[0m -> \u001b[32m\"http://localhost:55435\"\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Public URL: https://36a0-83-33-227-209.ngrok-free.app\n","
\n"],"text/plain":["Public URL: \u001b[4;94mhttps://36a0-83-33-227-209.ngrok-free.app\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["\n","
\n","
\n","

Ngrok displays a warning page as a security measure to prevent unintentional access to your local servers. This page requires you to confirm that you wish to proceed to the content.

\n","

Please review the ngrok warning page displayed below. If prompted, click 'Visit Page' to proceed.

\n"," Don't worry if you see a 404 or 403 error. Then, you can click the 'Close' button below to hide this section.

\n","
\n"," \n"," \n","
\n"],"text/plain":[""]},"metadata":{},"output_type":"display_data"},{"name":"stderr","output_type":"stream","text":["127.0.0.1 - - [21/May/2024 13:22:26] \"GET //pcleaner.png HTTP/1.1\" 200 -\n","127.0.0.1 - - [21/May/2024 13:22:46] \"GET /Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png HTTP/1.1\" 200 -\n","127.0.0.1 - - [21/May/2024 13:22:48] \"GET /Strange_Tales_172005/.crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 200 -\n","t=2024-05-21T13:22:51+0200 lvl=warn msg=\"Stopping forwarder\" name=http-55435-1681ca10-634d-4a9f-b4c3-e9ae3c2b48e2 acceptErr=\"failed to accept connection: Listener closed\"\n"]}],"source":["server = setup_ngrok(WebServerStdlib, serve_dir)\n"]},{"cell_type":"code","execution_count":31,"metadata":{},"outputs":[],"source":["assert server is not None and server.public_url is not None\n","public_url: str = server.public_url\n"]},{"cell_type":"code","execution_count":32,"metadata":{},"outputs":[],"source":["img_path = 'Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png'\n"]},{"cell_type":"code","execution_count":33,"metadata":{},"outputs":[{"data":{"text/plain":["''"]},"execution_count":33,"metadata":{},"output_type":"execute_result"}],"source":["f''"]},{"cell_type":"code","execution_count":34,"metadata":{},"outputs":[{"data":{"text/html":[""],"text/plain":[""]},"metadata":{},"output_type":"display_data"}],"source":["display(HTML(f''))"]},{"cell_type":"code","execution_count":35,"metadata":{},"outputs":[{"data":{"text/html":[""],"text/plain":[""]},"metadata":{},"output_type":"display_data"}],"source":["display(HTML(f''))\n"]},{"cell_type":"code","execution_count":37,"metadata":{},"outputs":[{"data":{"text/html":["
Ngrok tunnel disconnected\n","
\n"],"text/plain":["Ngrok tunnel disconnected\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Server stopped\n","
\n"],"text/plain":["Server stopped\n"]},"metadata":{},"output_type":"display_data"}],"source":["if server is not None: \n"," server.stop()\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["test_eq(ngrok.get_tunnels(), [])\n"]},{"cell_type":"code","execution_count":52,"metadata":{},"outputs":[{"data":{"text/plain":["52794"]},"execution_count":52,"metadata":{},"output_type":"execute_result"}],"source":["PORT = server.port\n","PORT\n"]},{"cell_type":"code","execution_count":53,"metadata":{},"outputs":[{"data":{"text/plain":["[]"]},"execution_count":53,"metadata":{},"output_type":"execute_result"}],"source":["_PID = !lsof -ti :$PORT # Find the process using PORT # type: ignore\n","if len(_PID) > 0: _PID = _PID[0]\n","_PID\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !kill -9 $_PID"]},{"cell_type":"markdown","metadata":{},"source":["# WebServerBottle\n","> simple web server based on `Bottle` and `ngrok` as reverse proxy\n"]},{"cell_type":"code","execution_count":38,"metadata":{},"outputs":[],"source":["#| exporti\n","\n","app = Bottle()\n","\n","@app.route('/images/') # type: ignore\n","def serve_image(filename):\n"," if not filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp')):\n"," return HTTPError(404, \"File not found\")\n"," response.set_header('Cache-Control', 'public, max-age=86400') # Set caching headers\n"," return static_file(filename, root=app.config['image_dir'])\n","\n","@app.route('/shutdown') # type: ignore\n","def shutdown():\n"," current_process = psutil.Process()\n"," current_process.send_signal(signal.SIGTERM)\n"]},{"cell_type":"code","execution_count":39,"metadata":{},"outputs":[],"source":["#| export\n","\n","class WebServerBottle:\n"," \"\"\"\n"," A simple web server for serving images from a local directory using ngrok.\n"," This class uses the Bottle framework to handle HTTP requests and ngrok to expose the \n"," server to the internet.It is designed to be used in environments like Google Colab, \n"," where direct web server hosting might not be feasible.\n"," \n"," Attributes:\n"," directory (Path | str): The directory from which files are served.\n"," port (int): The local port on which the server listens.\n"," public_url (str): The ngrok public URL where the server is accessible.\n"," tunnel (ngrok.NgrokTunnel): The ngrok tunnel object.\n"," \n"," Methods:\n"," start(): Starts the web server and the ngrok tunnel.\n"," stop(): Stops the web server and disconnects the ngrok tunnel.\n"," \"\"\"\n"," \n"," def __init__(self, directory: Path | str = \"\"):\n"," self.port = portpicker.pick_unused_port()\n"," if isinstance(directory, str):\n"," directory = Path(directory)\n"," assert directory.exists(), f\"Directory {directory} does not exist\"\n"," self.directory = directory\n"," self.thread = None\n"," self.httpd = None\n"," self.public_url = None\n"," self.unc_share = None\n"," self.prefix = 'images'\n"," self.tunnel = None\n"," app.config['image_dir'] = str(directory) # directory for Bottle\n"," # app.routes[0].callback.__globals__['image_dir'] = str(directory) # directory for Bottle\n","\n"," @property\n"," def running(self):\n"," return self.thread is not None and self.thread.is_alive()\n","\n"," def start_server(self):\n"," def bottle_run():\n"," run(app, host='localhost', port=self.port)\n"," \n"," self.thread = threading.Thread(target=bottle_run)\n"," self.thread.start()\n"," self.tunnel = ngrok.connect(self.port) # type: ignore\n"," self.public_url = self.tunnel.public_url\n"," if self.public_url is not None:\n"," self.unc_share = Path(self.public_url.replace('https:', ''))/self.prefix\n"," cprint(f\"ngrok tunnel: {self.tunnel}\")\n"," cprint(f\"Public URL: {self.public_url}\")\n","\n"," def start(self):\n"," if self.thread is None or not self.thread.is_alive():\n"," self.start_server()\n"," else:\n"," cprint(\"Server is already running\")\n","\n"," def stop(self):\n"," if self.tunnel and self.tunnel.public_url:\n"," ngrok.disconnect(self.tunnel.public_url)\n"," cprint(\"Ngrok tunnel disconnected\")\n"," ngrok.kill()\n"," \n"," if self.thread:\n"," self.make_request('/shutdown')\n"," self.thread.join(timeout=10)\n"," if self.thread.is_alive():\n"," print(\"Thread did not terminate, proceeding with forceful shutdown.\")\n"," else:\n"," print(\"Server thread stopped successfully.\")\n"," self.thread = self.tunnel = self.public_url = self.unc_share = None\n"," cprint(\"Server stopped\")\n","\n"," def make_request(self, path=\"/\"):\n"," \"\"\"Makes a request to the ngrok URL with headers to bypass the ngrok warning.\"\"\"\n"," if self.public_url:\n"," url = f\"{self.public_url}{path}\"\n"," headers = {\n"," \"ngrok-skip-browser-warning\": \"true\",\n"," \"User-Agent\": \"MyCustomUserAgent/1.0\"\n"," }\n"," response = requests.get(url, headers=headers)\n"," return response.text\n"," else:\n"," return \"Server not started or public URL not available.\"\n","\n"," def __enter__(self):\n"," self.start()\n"," return self\n","\n"," def __exit__(self, exc_type, exc_val, exc_tb):\n"," self.stop()\n"]},{"cell_type":"code","execution_count":40,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":278,"status":"ok","timestamp":1715452866844,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"RJuv6DOos2zp","outputId":"dbd120fb-f4cd-4cb0-e531-6eb5defce0e6"},"outputs":[{"data":{"text/plain":["Path('../experiment/cache')"]},"execution_count":40,"metadata":{},"output_type":"execute_result"}],"source":["serve_dir = cache_dir\n","test_eq(serve_dir.exists(), True)\n","serve_dir"]},{"cell_type":"code","execution_count":41,"metadata":{},"outputs":[{"data":{"text/html":["
Enter your ngrok authtoken, which can be copied from \n","https://dashboard.ngrok.com/get-started/your-authtoken\n","
\n"],"text/plain":["Enter your ngrok authtoken, which can be copied from \n","\u001b[4;94mhttps://dashboard.ngrok.com/get-started/your-authtoken\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"name":"stderr","output_type":"stream","text":["Bottle v0.13-dev server starting up (using WSGIRefServer())...\n","Listening on http://localhost:55470/\n","Hit Ctrl-C to quit.\n","\n"]},{"data":{"text/html":["
ngrok tunnel: NgrokTunnel: \"https://0836-83-33-227-209.ngrok-free.app\" -> \"http://localhost:55470\"\n","
\n"],"text/plain":["ngrok tunnel: NgrokTunnel: \u001b[32m\"https://0836-83-33-227-209.ngrok-free.app\"\u001b[0m -> \u001b[32m\"http://localhost:55470\"\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Public URL: https://0836-83-33-227-209.ngrok-free.app\n","
\n"],"text/plain":["Public URL: \u001b[4;94mhttps://0836-83-33-227-209.ngrok-free.app\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["\n","
\n","
\n","

Ngrok displays a warning page as a security measure to prevent unintentional access to your local servers. This page requires you to confirm that you wish to proceed to the content.

\n","

Please review the ngrok warning page displayed below. If prompted, click 'Visit Page' to proceed.

\n"," Don't worry if you see a 404 or 403 error. Then, you can click the 'Close' button below to hide this section.

\n","
\n"," \n"," \n","
\n"],"text/plain":[""]},"metadata":{},"output_type":"display_data"},{"name":"stderr","output_type":"stream","text":["127.0.0.1 - - [21/May/2024 13:24:01] \"GET /images/pcleaner.png HTTP/1.1\" 200 17709\n","127.0.0.1 - - [21/May/2024 13:24:45] \"GET /images/Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png HTTP/1.1\" 200 137784\n","127.0.0.1 - - [21/May/2024 13:24:48] \"GET /images/images/Strange_Tales_172005/.crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 404 817\n","127.0.0.1 - - [21/May/2024 13:25:01] \"GET /images/Strange_Tales_172005/.crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 200 107550\n"]}],"source":["server = setup_ngrok(WebServerBottle, serve_dir)\n"]},{"cell_type":"code","execution_count":44,"metadata":{},"outputs":[],"source":["assert server is not None and server.public_url is not None\n","public_url: str = f\"{server.public_url}/{server.prefix}\"\n"]},{"cell_type":"code","execution_count":43,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":245,"status":"ok","timestamp":1715453635711,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"fl9GFzKXwIpN","outputId":"7f29395f-0956-43b6-bb57-467b6aa2ba6e"},"outputs":[],"source":["img_path = 'Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png'\n"]},{"cell_type":"code","execution_count":45,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":35},"executionInfo":{"elapsed":258,"status":"ok","timestamp":1715453674774,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"VC-IoChywfNG","outputId":"eb544fac-df9e-478b-a020-0f6b86b1c3ae"},"outputs":[{"data":{"text/plain":["''"]},"execution_count":45,"metadata":{},"output_type":"execute_result"}],"source":["f''"]},{"cell_type":"code","execution_count":46,"metadata":{},"outputs":[{"data":{"text/html":[""],"text/plain":[""]},"metadata":{},"output_type":"display_data"}],"source":["display(HTML(f''))\n"]},{"cell_type":"code","execution_count":48,"metadata":{},"outputs":[{"data":{"text/html":[""],"text/plain":[""]},"metadata":{},"output_type":"display_data"}],"source":["display(HTML(f''))\n"]},{"cell_type":"code","execution_count":49,"metadata":{},"outputs":[{"name":"stderr","output_type":"stream","text":["t=2024-05-21T13:25:04+0200 lvl=warn msg=\"Stopping forwarder\" name=http-55470-05e35e60-2237-402e-b7ab-8507dd7f47dc acceptErr=\"failed to accept connection: Listener closed\"\n"]},{"data":{"text/html":["
Ngrok tunnel disconnected\n","
\n"],"text/plain":["Ngrok tunnel disconnected\n"]},"metadata":{},"output_type":"display_data"},{"name":"stdout","output_type":"stream","text":["Thread did not terminate, proceeding with forceful shutdown.\n"]},{"data":{"text/html":["
Server stopped\n","
\n"],"text/plain":["Server stopped\n"]},"metadata":{},"output_type":"display_data"}],"source":["if server is not None: \n"," server.stop()\n"]},{"cell_type":"code","execution_count":50,"metadata":{},"outputs":[],"source":["test_eq(ngrok.get_tunnels(), [])"]},{"cell_type":"code","execution_count":117,"metadata":{},"outputs":[{"data":{"text/plain":["58805"]},"execution_count":117,"metadata":{},"output_type":"execute_result"}],"source":["PORT = server.port\n","PORT\n"]},{"cell_type":"code","execution_count":119,"metadata":{},"outputs":[{"data":{"text/plain":["[]"]},"execution_count":119,"metadata":{},"output_type":"execute_result"}],"source":["_PID = !lsof -ti :$PORT # Find the process using PORT # type: ignore\n","if len(_PID) > 0: _PID = _PID[0]\n","_PID\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !kill -9 $_PID"]},{"cell_type":"markdown","metadata":{},"source":["# Colophon\n","----\n"]},{"cell_type":"code","execution_count":51,"metadata":{},"outputs":[],"source":["import fastcore.all as FC\n","from nbdev.export import nb_export\n"]},{"cell_type":"code","execution_count":52,"metadata":{},"outputs":[],"source":["if FC.IN_NOTEBOOK:\n"," nb_export('web_server.ipynb', '..')\n"]}],"metadata":{"colab":{"authorship_tag":"ABX9TyOEgPXBN+hXsRiveyDno/Wy","mount_file_id":"1lU3GiBrmigaiHRD2FPnnnn5rGBg9-S3_","provenance":[]},"kernelspec":{"display_name":"Python 3","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.11.9"}},"nbformat":4,"nbformat_minor":0} diff --git a/pcleaner/_testbed/pcleaner.png b/pcleaner/_testbed/pcleaner.png new file mode 100644 index 0000000000000000000000000000000000000000..71355d25c4c6323b519ff5869b2c6e17d3e2a5e3 GIT binary patch literal 17709 zcmeHvc{o<<{`WG=kjN03B4wU=kTHaenaRv!<}qf)!t{HeXjStuJ=0cb$;((N7`hENe&L98txCD;5|GWktjz#eB5lZ;^0=`Azm==CE!nez{Kc2M;$CvNmBP8(i z3w&RNV|w^G4BzM%>F+=4aD+bfA3xPJwDs6U1x17f#Ux=|VNr1zVG$WoQFdWCkdP6P zKy-bR==tr5p+l+cD62ml$!MjnU(KF>kZn#r9A``Of$_ zcNIPJu33ppmDKn7QC`w01@`vCI6^j9A5lJLb@i}U2kegm1q$VrsS7em5d-45|sd{%%<9mh4Z7v_4 z$w7qky)5r%_E%v`3Y&5li-o1fxMGef&csbzzKJ}v%)a3JVA1})%LC+%)988J7N5V( zbkeH1W*jSC=uktmzox-@#77pJr4I?(11V82uAIdSRLI4(;_X!`b`)VMr=@k+A}Bub z`V%lS|KZZUNMb1ElWtdMXo4VA@-Bv^ex}-5GWIwRL0bo$9ab>V z!wX$8L{=ft%huiv>&I?~b#n2P<5+xE&%y5EAje@Mp)IWKrHplUQ4jXP8U*VY+6TMY zOFM8V$dkzi%D?~~SU+3#Ko56MUztETj^E?Tz%hDSh=cw2C4O#l9H!uA$~Ye^ySSjZ zps;{ypvxsu4tX+mSsw>S8GV&=e+~h^$#FRQ`FY6*2?YcM2nL7=;(VNhM5Lvqg@i?g zL`4PQ3IX3BPe0p00Z(5}bcjF3P{I1z`?z@dx!^q6(J^i9aQ=RB931dD`#h!2nYMW?)UQdasT}~4)#J=cdQ3o>I+X5`Ikqc0r}S*s0o~0JiLD21;+lDEB#y? z|7om$nH&1a@7MYJMBw(n#{HM8|MBj>FNUkMwPjRr_WtPfG*sj`(C5oI;Ot!-WPTqy zVx?@wB*i5JY#p&;0^;`4_5xBO5+VYQB90hQX-BNIBo_0xp)@>w{cJt$vFK1RxS$J+ zBP@my6%`h95RjB|6c!K{6Tt}BV#P!Su)?CEQW#MYTVXNLzYU@5;{sl3>;Csyp+h;q zP?EM-DRC(W2>}sD2?+slDRD;uI|+=afSshBh?Ik^s3S(i?)Oj*_A=*iJ|4EPoGu== zPFNu?Pp97>paz#w($kRR5ET^u=NUbBTR%s*L5@Sq#nV6VpC1^ycwi0uY*A~9V1y;4 zq(w0z7!gSkG2uU6`}cUpSRY^TM0CvGsrC2m=(5Pb%Yb2RQ9p$NexHYTkx}-++WO&q z3~@MjIgY=Q@?RfoLpV9u`q`@3`e9+vztXhfKhiWGWNqO;rjHJ%jdO5u4En!ajRp_9 zEL;yuuI}Os&ky>2>W_#rzp#xB{2yFFL_%6zSXkIj0Auf9Cm?Qzl@zeG6Gm4OD=Z=PV$yuV zqNu@y{^wuOR?1FX7%L_&;9w{20NxH!BLx8kBl2`$(oudTC!QM_1gZ;xd|MHRl$5j*;5Ec;- z75#_XWBzpeKUYy!2+jQe@LO4-|IM@ixZrQ40#^Tzb5Meyq6z&~(*AS{nD77O*Pjvf zKluoD_WwTQ-?Hz2&Glb%{aY6Jw=Vv#cm3B~|CR;*t&9KbUH>t2k^PetV?6=O1_0$f zIe5JW=rXaLrkVqL11*anzBKITgU3j*z8^n3#jl3*Hix`O^(eMDD2!6K@pgXl%yTysmb7C;L=uyelU+BO ztm?xoi#(cpc=AI!7WP9rycCo}2bjh+DhN&y>{AVOe)&QVgqdGJKtx1DsW`Mu{v;Py zxl;$LsHmvAmR8f?V2!z4+PilLd_NDf$ml(_k}E8Yx7(SSzLS=w;p)ok)c#;>zPFf) zh9KNV!VB3%`Z@9SWa%4D-a5DPIETAA(?n12$lmta+rB;qCnqO&clUw|xx_LVhdDWO zukANf`_6dz`Vz47@f8osRb^&o&M%u-hpH+nM)XXpojiT|T1g3iS9iCDj?O7T!P`qq zUSCSg-VWD=#O=f?l(B3cI!5*N&Z|v@bRt5+2i1MXT|3Xq%Jfd@JSb36QQ@AOn`>1V zoBniv-n;Lq^;1JkV`F2__mN6m7Duuie0W|(<%+2HxJq+l<5`}cX~ehjK0O+opZXAttV6UnPz+eBh zygW$D$Y@qP`tG6fHJ|w&o^$c6x1K-uP1`fQ#U!z`vO-|fktxR=%dyOte7wEA{U)ni zxz=^Hb1-ign{fDK2X*OrvIr4j zX$;21f0n*Ou5;O@WkYVmc5LOvz7CE-NthosXf zaB`|!SHY-qaiqS!OV<6vhYuVG@i|XVPw)1#JB8VW+jQ6v1-uuZtjo*FY#Ji)=)U|E z(i(a>UpT8h$?X{y5g$(l3CQ+M6p^^cAT1{+XHCFjX&5UjtKfRcQv5anF~zZnn3!Qi zaVW(9aVu#<98tL2*D7!9{FsTkmbP~9)RilQ?6}h160_%|hYs0(xWh$AMD**UP<>g* zhG$fC^x8I0ZEfw+(h_3R{y@6<(kUjH>gsC!9STB70`G1eH>t9EZE957L3*9fc^qO@ z*7*7Nt~|}w&0iCAVq#+0wfWxI9PZX%6Yn*9g?nf6B_^761ZZjUV<)O!*6 zPPY{%KhC$23JeaWp`|tSN}8yvF_bhKf{?b%->C>2wzaj*LW&uyVbr4|%r<&MXKigA zT{Whoqk}9A*WF)T^*hWaueG!O1ClIH=Y{}3e@|KrgOJrpLBaM>Hc@hN@~G&Q>5K{!0Al%qpN7VG&Z+e_ZfW;3i-yD7eL>%J$rNr;(vt=iG z{I+z7V*S+;2KO+dnGbqbuiv_*J*IJ%vN#Iq`D6{RDb!c^I!`ILvtVLtOIesp;$X$w z*OyaR_(+8P``d*qH?C?av0ZIyQYrK&R)GxH6PDNLpD#)t5wstbm&YZO(Qe~e6&LqW zVf*!s8;9hASCM6zUO|g0cHQ!&_;lx(a}V3#QO@MXsdrQspQtB&51aPZ2pYd}Ank5+ z^@Gx_H=L8Xu^H@q<_*uMSh`6&nlG zIVRYc8v3zx8qeJSF*|#`vJ!(lF|X+Ir55CQ`SK+Nn>=$w3^_wlX>&^C#QS*7Tg5-4 z3^IhQ;Qdz0EiEkz&7Mzl@?3h8IkZbnq%0}6vbD2VpGSNhF~qffTG=*B7k621dGGwK zrlRKZWD9ll>)|MttT+atyPsz{kly=mqDhhx5*nIr9A(=&<}virXvlNo-7T@%F~!2A zC{o1}Qrk8jn~Vn5zJ@7<2U4PVxCbyFf#MSadB}?tz9!&w4AQ;jSuW#1D>y6zxGU}rXGv_ zLBcI{h?kR7nM?47Zux$+|?b+!#X+wwB0I zjiaAmh83aovD4E?$|i#gcwBl45^ErE9HVa@G5pL@CF&qfqk`~KLJGHC8hxW^rI!8h z^jPwhQ|M^JhEI$sCCL&pGd(}gxN*-75>iL-Dl4fSSEj1>n8oJ;i?~vV7;fgCRHBBd z(R9@Y`TB1)L=q79b$-cKBJh6!sp2|9iq(3P7y&DF{HtDeVj?vG$zj4#$bI@Y=tJz> z-AnGx_3Gsllf$pl73FHTnDR`2Nigt$VOFstn)nV+Q3&Oe$ zLiM|6jg9XrWn=-ypuIyHq34M)DaJ1Jm(K^I2G5xI{5Ynlb#Kgp! z%j*kf(J~m-3xFa|N=WpwPte0kq_6_m6lbEe35-;NALdW!6%-Wi3R=1@MQVbT&tH4~ zTnrvVVzcq{8!-d>3$y2rNbPEu=1pd4{c(a=u&H)^*d8L~KcB1=LU{Gcl``x{dLCgg z5dSB4Dk>`fZ+ZqXQ@-E72=IubCwcncT$=0Rik7K_Qa<P&hDDJ;BYbPG-Q5JbWP~ zB?Vde;v#R4D|J@yv7VN0CIIko9YRA|CpPr2@xG zUS7hQclm9h>QFF>PA1;=g#YM2^ zhYy@)NNi47*j}(z&=g&rxD`=%!qDL0_~>W@RG-D2mk^V7P1mVce}23FSo{8bH4niH zx4y#{FJ6TETRwcSg{2G5I#?gV1t;Dna=|C%IyrK@Ogt1xOG`rwTxYIYcO`Cw9v>{drMeLpm()m$cjUZg zG%+R8|2p(cVPPTFR}3Ft+>fEk?x)rY05~@HcNRbHUOuIjs+g~nk&3~wvdH+2&UWUO zm{-IySOrEtdi2O{hgeihjIuq&Ea8-5UPDXEbtsH9M~_CAdv^|HCM8817jyCQ#IU z<@MV)Z=MttrHL?pV*aboI-L60F?CqGptW9;!i$xHfWW5#=bF^}*6S!MRpE|G9y|>{ z*pJmq25`%3|L*1mdLgS4+FI+4o#SGTH)$9c@+nwk4AX>dqn5|xgm@#K1uR-&0n)X? zC{NM2=ya`U1*6ibUI4~NiyeI7LM8k2d53&4cWln(gT0O4AKp5btD>gH2dUcV_4Yg; zksbiuQ$)tMR{=qKRjVJ(E}~{*>u5_8GpqDuv9-0WU1}u1yz`^7c6a$B*LIkqBI5u3 z3wCw3v&8Zhy_=icRSL#N$fx}kZVVsq3cT&_Pt7hsj+rQrl>+9)B2Ke0#Ilk_C zGkC}eK<-nmDSZ8dgEY*{H{;^Sfj3P-C4lVEU2GyG>G`$g#?jNH6covgv`zTj0zjX5 zmZw8kK4E$>m(HGz5)EFRwHx_->eQ+8T3R>nBqiluiHYIq?Cfj>w9;d*rmC9KN|Pq; zawm8JyqqtBhKZ>NmX%q?PyG-Tl?e?EO>(ixQ(nNzZhfUj$P}0^!Ni}g9D(ANaPuZb zh1ioNYg5zI;nxozK8%IDJS-2;$`~xfYFenN44J>{k;YLXJ^7slF(SR`wzOOrz3JUM z-V-NI1n-(iOqX!bvcvw~VtDa)q6`o4?mUc96-XGWU%fjZ22kE^ zZf^eThx9~O#cWAQiRr6L0+4Lx^+vutxrkR*S=p!QK^)YsRTsR5&(6Vdmh1%?U_%v1J9j~Qd7SH5CzVTk64GU86|pI?CdPBwRF7(u~1iM6sMX) z8i$Zlp>hHmRKawYz`Hg#H-&>&o#7r~4CZ}vbIjXoR4ebrCeF?3HBjD6f9~YEhTD9u*FWz<5L2 zXY%^^_;?NytCP>yb)tYf)@N_q9}D`&{D#8jC;^w8T%A@&08pIs&mBJ{n^*;@N(U~D zhHea1xZMk8J#^?$m+$FZgac{zhGpH6S(zkPl!w5ccY1QM(%AD`jnRULva)gtyboW* zG8F&ezOk7LL~iQ~1FZ(Sa%&B-p)>6)T=4ST_^z}LkY61f9A?+bs90r9Gq%qJEl=*8qILlzfg?Isn1^l8 z<%@ojuyJ*5ec{sW<>M1P8WtHDNk~EhMYKJNi2P9llp5N}-K`a>wYd?0vj3&XsF+q)w_|6WG5NHanb~iis+b0s^jJ|N)CiEr;v&vCbGa^PHCq* zc%{VyUWvs7ouA9YxOAO_EE4Db)FA(G{r)yz9KArWO_xrF&U^5~{25i#3(n$9nL*Qx z%*@QD<#wutO}YR$?@%yH>D|J&NX^d-j)gZ_>M_tQ9D>Sb;xMi&fBW`r(3>VAjS*nd zQ}%HKI4rg~{9wl#0aPzE90?5QIN%RZa8!We#$5*BDKYrc<0I6EKv=ilA25lU#r{{h zxty?O#P`gq*y}Va?1 z>j;vqjWbeGDAS9svx1^)b@`Vn0)>*_7*_BIGjkgRorS~B^3+E>VKFiL{xaJKGXAkn zS)q3WhJ*62U$e0l8%cmlgtz=ya-<{a0=%<4ihn`V2o~E~{43|kI^Wow5;-asD5Ukz5RAV!jb*W z394w%?+RK=!5cp*6+s|{Y&Q-mZTSewB`qv1&C2bFP&EA#atFswg>z>VM3-TWq@Sm! zAQT@PC?~-mlno3F7@_()sQG8m8`3qkivRfPW_jXb$N5U=wW>B@b z4?r;)h!Wpo{lV+;`T3&uAnxy@T;pUGlInH|WYcSX)-yl9y}HRH5gSQB;xpQSCo3yU zG2Eo9r8NoqRa?fHdw^!<&4dI61z)%i(40Pf8k8>xf4pTo27nURz#y9tt28ls{Ou(U#B-!G` zDEKc(OG^ONL_kfg>ww7}A|=fRPQkUT>D=|`(A~Rt0Un5ATWQTJTvZ_lO`S;4X_(gr z&D6BQmF`oz1j>r0XR^Y>7R&+wsGHUWOT2#l8nmv$6zlx%&X*n+Q6K~pfD+GNZg8it zkOy#(@fpH=t+eF^FZ(D{q?Z_i`Aey#W|n;DF%dgL5U>ad2@PkZ0i1(>eE;%f0;={X zWUhH9C}l8dU?v8xLQVHEI3M6HIXO8}mljfM_FyWH0V&GOT15#-XF9 z0ILa=c~6{6$Kb3^)MtPa0VH^HHa9-DwjyM8HuBZ0Gsecoc`}ZdFUtZS2pL^y&I;SU z0VO;|CM8X8-B9ITiEAI|U0HN|#x0gYS7&FP(L7k8+FE8gedv*o)dg~me@c7tRj#PVYi&?cRh1O5n^g|xi{|ECIjZC!P5`)g|Me?##69aUvs>&Ba6zaZ zMrNIk;48+n%0c&Jx_TxPmCTr-tg>ySI$^QiOQTBk0_IJ?=z4zu<;({t2N0j`%#{EI zeFFn{V^nfiy^~y1Q`1#wa2ld8R$}qEgsTdS*blCTRx=QAE^kfU(_aEIEDuq=3xYHu zF|nx6q`Kp$^cc|8=7ua|&stb8gYIYx7Ms5WBsDW|{1B6bt0AwLf`Gs+AfC^BXLL%f z>q|G%u3aNhQc|j_sj+i#@H<$4d`=lO4nTS{05Y{QWz+6i1#6_^!_&qjS3pXb>&~b8 z`Sa(^$38kbhsVao+y|b;fNokm1S#zkKv9UCF#-Y6Xs=~s;0s{j_$H(>U)Hs3tYiNu?NkqYwx^)c5 z&Hz6jgKgsdJV0&k9~w$ZO>KdaeoWX#F@`D}Bm!bxfL&YD_i@KCp3Lyz$ruJJ?q?lf zfGuEm1Fr&}%Ea_TgQKBA5jA4b^jnCys=!|y^#}VQ)cKDfvwQ|Y2BfL|U;fbP=mK;i z!7vV!aOuox<|L1WTEo>j=ZB`Xo*qMDN~SA-+W}? z$W^uLgKi7oUTwU#3W5{|0zmR+KVTjxYF8Bwb`6ByKF!Er0ZAuE`@Uq}JU2fj(=Fog z@NfWO1Pup!BL|(31f#PU&3Y3u@10kKB>=8^__S{3WMO`$9dMp`CkfXc?%r}*)iD6s zP)fzZ_b;Oa(l`t{B3CJozk}T54AZSP+P@5#JP-At_Hp8R`A+9qY4E+T!K$PFi?qO8@aqf2?U;+PmxeD@R*~c zqwL;lcTb6#0m~t&;8pG)gB6^Tl6L{}%*GsB{Pqe{T3WjC>EdP;Y^voD7EUNA;6~eK z_4{i=kRA`zSrb5FOyT0;(a6xAnVO0zFBbuz3q{hPJ}lI@#PkiM?}7So1qh+}4G?MK zv$CuU^Vf|}LjLtz97gqfUl7I|J2IcleBf4RQ>-{GAfWBPUS3&ga%KkC|R`UtUhmjD4J07u22GXz5cXowmIzX^`H6&0i!Ek>K=4nwIm4j?2A!3>Pk30LzYobHJC9rCM;X43M#f z!HT%l)Kt5TUn?u9$9=pf^xXC>F#sI4j}M5bkvG{8r7XblO@bpfq)BE>mq}GK#$jERRu9ZHm^ML*2$ty5vxtBo*G$bFK3AkNWR%SP{PRS(R@cums zdu9ik+7m(Co z4?rBqa~y(=0BnlXA#2_PT8|2*r86n_?`yic7NtuREODb8qZi5Di1T}(`)00v%d-(0 zC|>bab-{%nVd+#aA3$j%B_q?{!OzLf{iuyVTNbMM30~f!e&$F(Z<||NW3#iS9DI{N zwN%cX!(SS^#y0-*ry!BlyB1*^uJ<24+yLf@=LM~6yKj!i#hoKSmrTI86qJ06_Vw{m zS68=zyuoi#Ri-|*v9^YtY)O<|X%pL!Sc~J7kuj&#m4^g+UaU|9a$zI1LTb0?i*GWD zoui9{oeST!nY&yo06|hSGJb#z22<;dw5YEfsA5g#n<+Pb%&pW(!k(8ZTGH=q@sXt&1~ z+X#(N0FS2BPAtGEcK7yvt*;9jJsukmvxi6l0DA2(3tAGm{8Pp8u8^1kTcyyO*iltc zDKLm3H^+m}AzHpV3C&B3`4QNJ;Rxb1igAKdtaCd**Z8{)2hFf#Lb|TA;fhCL4wNQB zo6V)MJ0j}*$e1lS&(iWoAu#|9hgoISLHLU^#gmkjl--(4f@1p&_L+cOxuVC1ERv zAp=8%eSiJ_B_B>?c zCr1(vObSiQ)8|tT*S=tuznlu&RiHi2D1W(Xbr<9!F3Fh}=AcG50A5C*#VWvoKv3vp z$iU*?$l+f2TAc(Y_nLS|2?8|8H`!L)-XN~Z_{~ND5(IK3*hiL@np$Aa1!5)tc+W|I z{ZuGs!wd&TgI@OB|GP0*DsFPK*t%XGl9UtB#|QGE=?A+r3eBwVKYk=9A-P7T!3vtd zTad-@0s*bArHe(a;*oMSf%FY^nZOIWB|x(c+`}U)D=V!gvoC+o2JBc1qP#0jVr(lj zEj|6?cC$@rYV;hLfnd`+&xG+r88^k`)ZoXK7Vc;9I{DonYr6rgK&n{Prv-Xj~}nSmVIAggsE9-|wm=B*5(;Q#>N($D8fSBL@Ml>*#%eDZbF= zkqP+Ob{toG;%yj!4y-C{yg>mdf(oJ1_{-0UVI7i#h8v*e?b!a{12`N=NMjX!R?rhq zfH)}!4ByLC9kwR}f-LbeO@yJ}NHjaWV#>MP&ZV!u9lt(dMvx#eqUh-8PG@n~*Ady- z*`is_Nr{P(6%`VpJL}DF-rzkk)`SRyX7s7>y)_1Sfb7BU3bR5ObHwSa%Xa`w+(!frpw`76q15R^5!XlXLQ27L*lj#<;Cak&iqloM?a8j4ARpqqFu;x~& zX=#NTsxYY0%1BE~L1VN#6C)$&;%cxvL4b%8pWToa%z#!Lr~nr-JYcU^34>}?Bdg4l zyWn~R!VWD*bh6|Hh)zO7F(5BwCL;hu)6)_XbS*1H>gUgM@bKI?j`2*$$au1!5@7xd zpj;<(b=ZZroc0T@=#{r{D@vd(A)t_=;3^O>A6i@O0IfFvbaQgbmzk21mbP_pxB?U$ zy1ICJ->yqAed3J&wzIwM0|5pYRZU%;RH$zC&hPeTCiF6*0o9g6kX3LVS+=-Zzw`6V z3v&Sw?}AxksB%DLf!4rr5Sv_ki-;7#S3p^M+ts!Fa1U>*e4m7pNo8gF6Rc6`B`(r394L&49+PzMSDslte*E~v z_wOIUJX?MB`>HTMKyv!(bSkQwmPOu$+Z&4=v2=Wsr6&5&2frR4e;PXPw+6EA+{qEt z&6G96g_Dqw07~5dyr7W4aL5@DoK~uEBy^*y1|1PrVH*T?la!Rn@X|-<*`W~nSSXM# zRrxF_@0^-lkTuXyfqd)SThyx@|KrCGZ50*5qo=g80jYCs-(KoS1kJZiSVF?+0J03! zB4`L)f&DPav#+4SH#Id~0czyCv+hy-5GX0OxwkjvV5j~7d?fnw=g%~uz$|3YHX*!u z8c24H6cFIowpviR;cizbj`NZA4xuwR_TU%2*?f#uMq2P)Y89udnWC6x-J`GPJ`YEi8} z{#X%4Lyn0#Y9;ckqFGO)z^Its;IS5-4J0_OpWg!f`~X>9gM={Mk!9^3=nFeD3JCqa zf1w2I4wdH}RCmp<*Aj4Ykc%HK*UkgRkK&FylaS4JxoF}XM#d;ljW&pBh0MCFdaT{8ay#6>SKh?o&uI0aX z2w63~2P9ZX)cas`)CSE^fNnwM;7iH34m-aBnjy3#O!9teiuh0X86AnpB{Er_cthSh zMAp(_g>Jrq$k*Jp)YR03-WguQHMX#VQ}j>BXbmv8jfwF3bt8w{#zlL{dgFJmHzeFE zFAz6YgzcnE2@U|$z-0}$cc2aS24HNDe}>Mzkf%QlgYmB8kFS`l|NO@1JxavS&u>~A zD1rc#;Wz633_KPT1tjQ(jurGcXml}>hLFWR0g~%o146wS;-B9|u6Q_`VbUE^tUduD z$SK#L?U{h#H+81ijfAXJXxs$wp@;u%N{ZclQ!CtIQCQFt*B9AW#W1?GH1?K)NnHJw zh>#%&t6F6h6qCVzDV5)pu4p#8xfVhbSqhKzqrCI;u}zR82PunF=I*Xz{-Rgbe99 zWpf7zHQM_GfCLVYs&IXM8;Q^95zS7RPhZZ;9L3*MLdXk zNGEt8rur9V-2gGDvo0h6Id}8e8%WZ8&HnlM`3xWOyq?~^V%Q^X_y}QW9_%~;G|hW!;8e2QmoHz?h5_gjfGz<1YZpEvNV|XE9?B(b zQNA7*_x9a8RG5jr{FqkN7VotV@Ox>&?$D!4m2jhn2r@M{9|!uu%LjYHGKVU0Ab_cZf`%f1;o;#?-UHxBXd4YC zN~9ojm;zt4_yvNb0XZHV1fXLAA3Fx?()L$*bArm654*|HM?fV3c%bIsa1z~(b>nnq zLr>3(rV)&!8UOj|?`8+IVMfp!CJGgC9OPN44kEN|P|DD3U+ z+cV`pLdp{n70rPzZ2Vr{oy^R3fDnx0&U#~*aHh{$_-`kBl@LS_M0eHz=;5IoZr%~? z5JE)%T3v;<^SP2p*M5dF*x_JjZ!ZnogF#IM)|@OS)wW1^8U8?J|lW-6^uibnw~D7k(6Y>89o6>aO>B5wnEESlF-i@ z7cspBjmkH$Z3!q6evpQ;=Ea~}H*b3R`8j~>tC-pG0lF4Y@QXjY!OjzV*eDAn>RPT^ zoYsP7^~UtbuGC`XiIcYV39wlh{{_iB!!EnHcrv^`3dR5{06lB!Hx*4c@ke()lQuwW zhn<_dpl8Y|_Z%fq1fYHBKI)#Q*47yTdYRDt^a2bD_CVE;pP0p|%{s~O{)yLpR~@V` z!ggv*q@Cs&Ztm-0d)s5MF#%*0piw;q7YH(ROo~o$zF9JR;he~XzmRv&DhIZ$#P|HP zf(`~s$Cgh~Zf$L)eAt?roJ>ebQ3WId+l8B&o2j953Q@G`xJJiu{P$LR(JMRd*C`h+ zH8_ku^zi^W0~!ZFfnWu)d(Wpw7ePe^g(w~%XKwc#+TMiS#oTM&u<7~@mBOy#xpTxI zi2E({Q)_B|4EOVdAcW#{Cq2CtN{nXuk69#0N1mAOO_N?o|INt!NUF$}>i9{nx=*d@ zddkN0reL3r>q*PhXZrieSo)5@M-R$@w5 ziHgvThk3Ad11iw-o{@@Y&&C13!ao`?QL&1(7^PVf6DCUyTr`tZ58r4tOuLB)u_Mkz zf%ue>H4)XOhm6=D0b~Zx7pl!KR$uzT)Sa(;`plVE{CwLi%Vz`L-(hH2;SRE`%_)em kVU1!Z{ZIToCV4;=?D?9$%3>M)pO7FLsyZsAXKkYX7cKa282|tP literal 0 HcmV?d00001 diff --git a/pcleaner/_testbed/requirements-colab.txt b/pcleaner/_testbed/requirements-colab.txt new file mode 100644 index 00000000..cd5b2548 --- /dev/null +++ b/pcleaner/_testbed/requirements-colab.txt @@ -0,0 +1,7 @@ +matplotlib +rich +fastcore +nbdev +ipywidgets +pyngrok +portpicker diff --git a/pcleaner/_testbed/requirements-idefics.txt b/pcleaner/_testbed/requirements-idefics.txt new file mode 100644 index 00000000..38a68b15 --- /dev/null +++ b/pcleaner/_testbed/requirements-idefics.txt @@ -0,0 +1,4 @@ +accelerate +peft +bitsandbytes +flash-attn diff --git a/pcleaner/_testbed/requirements.txt b/pcleaner/_testbed/requirements.txt new file mode 100644 index 00000000..769650ec --- /dev/null +++ b/pcleaner/_testbed/requirements.txt @@ -0,0 +1,8 @@ +pandas +matplotlib +rich +notebook +jupyterlab +ipywidgets +fastcore +nbdev diff --git a/pcleaner/_testbed/test_idefics.ipynb b/pcleaner/_testbed/test_idefics.ipynb new file mode 100644 index 00000000..f57d250b --- /dev/null +++ b/pcleaner/_testbed/test_idefics.ipynb @@ -0,0 +1 @@ +{"cells":[{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":281,"status":"ok","timestamp":1716482606479,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"b6_yW3IxgHHv","outputId":"8d5ea16b-e93a-4a01-a416-714bf5042168"},"outputs":[],"source":["!nvidia-smi"]},{"cell_type":"code","execution_count":2,"metadata":{"executionInfo":{"elapsed":256,"status":"ok","timestamp":1716482609343,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"BP0Y1GtRFz-b"},"outputs":[],"source":["import fastcore.all as FC\n"]},{"cell_type":"code","execution_count":3,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":261},"executionInfo":{"elapsed":93698,"status":"ok","timestamp":1716482708865,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"lxwhxBydCiDj","outputId":"a4959f37-4f70-48e4-a460-6dc8c424fd22"},"outputs":[{"data":{"text/plain":["'4.40.2'"]},"execution_count":3,"metadata":{},"output_type":"execute_result"}],"source":["if FC.IN_COLAB:\n"," !pip install -q flash-attn --no-build-isolation\n"," !pip install -q transformers accelerate datasets peft bitsandbytes pyngrok\n","\n","import transformers\n","transformers.__version__"]},{"cell_type":"markdown","metadata":{"id":"FO-koL4wUMUg"},"source":["# Testing `Idefics` OCR for Comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"HoQukfO-UMUi"},"source":["## Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"L4ZVmMW5UMUi"},"source":["We will install the more up-to-date version of PanelCleaner from GitHub. Only affects Colab notebooks."]},{"cell_type":"code","execution_count":4,"metadata":{"executionInfo":{"elapsed":6,"status":"ok","timestamp":1716482708865,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"37Viz6DZUMUi"},"outputs":[],"source":["DEV_INSTALL = True"]},{"cell_type":"markdown","metadata":{"id":"TZpfdXHLUMUj"},"source":["The best way to get the images source of the experiments is to mount your Google Drive.\n"]},{"cell_type":"code","execution_count":5,"metadata":{"executionInfo":{"elapsed":6,"status":"ok","timestamp":1716482708866,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"6hLwMGKdUMUj"},"outputs":[],"source":["MOUNT_DRIVE = DEV_INSTALL\n","GDRIVE_MOUNT_POINT = 'drive'\n"]},{"cell_type":"markdown","metadata":{"id":"-MhrGXCMUMUk"},"source":["# install"]},{"cell_type":"code","execution_count":6,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":50},"executionInfo":{"elapsed":15792,"status":"ok","timestamp":1716482736022,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"yFeqVBJRUMUk","outputId":"49b20079-fe9c-4472-ea37-03a9be63ae2a"},"outputs":[],"source":["import os\n","from pathlib import Path\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," text = Text(msg)\n"," text.stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, text, \"_\" * 10)\n","\n","\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," mnt_point = f\"/content/{GDRIVE_MOUNT_POINT}\"\n"," if not Path(mnt_point).exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n","\n"," drive.mount(mnt_point, force_remount=True)\n"]},{"cell_type":"code","execution_count":7,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000},"executionInfo":{"elapsed":53809,"status":"ok","timestamp":1716482795312,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"braPNCfcUMUk","outputId":"ee60cf75-55f9-437e-e83f-e683f2fd7ede"},"outputs":[],"source":["if FC.IN_COLAB:\n"," info('Installing PanelCleaner')\n"," if DEV_INSTALL:\n"," assert MOUNT_DRIVE, \"DEV_INSTALL need a mounted google drive\"\n"," info('Installing PanelCleaner from Google Drive')\n"," os.chdir(f\"/content/{GDRIVE_MOUNT_POINT}/MyDrive/Shared/PanelCleaner/\")\n"," !pip install -e .\n"," else:\n"," info('Installing PanelCleaner from Github')\n"," !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed\n"]},{"cell_type":"markdown","metadata":{"id":"gG-H7p4IPHMI"},"source":["**PanelCleaner** is a heavy-weight and sometimes **Colab** refuses (*silently*) to install it. If the cell below gives an error, re-run the cell abbove. That usually fixes the problem."]},{"cell_type":"code","execution_count":8,"metadata":{"executionInfo":{"elapsed":506,"status":"ok","timestamp":1716482823315,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"t3AW6j-JJ544"},"outputs":[],"source":["import importlib.resources\n","package_path = importlib.resources.files('pcleaner')\n","assert package_path.name == 'pcleaner'\n","\n","os.chdir(package_path/'_testbed')"]},{"cell_type":"code","execution_count":9,"metadata":{"executionInfo":{"elapsed":24334,"status":"ok","timestamp":1716482859750,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"q_7GYpnWUMUl"},"outputs":[],"source":["from pcleaner._testbed.testbed.experiments import ExperimentsVisor, CropMethod\n","from pcleaner._testbed.testbed.ocr_idefics import IdeficsExperimentContext\n"]},{"cell_type":"markdown","metadata":{"id":"Op4kiDaAUMUl"},"source":["----\n","# Idefics experiments"]},{"cell_type":"markdown","metadata":{"id":"rVXnbndZCQdS"},"source":["## Experiment directory"]},{"cell_type":"markdown","metadata":{"id":"RtGrr3D1CQdS"},"source":["Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n"]},{"cell_type":"code","execution_count":10,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":33},"executionInfo":{"elapsed":249,"status":"ok","timestamp":1716482865122,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"bL51d4LCCQdS","outputId":"7768d79b-0487-462d-fed8-3ccfe80538d6"},"outputs":[{"data":{"text/html":["
experiment\n","
\n"],"text/plain":["experiment\n"]},"metadata":{},"output_type":"display_data"}],"source":["EXP_DIR = Path('./experiment')\n","cprint(EXP_DIR)\n"]},{"cell_type":"markdown","metadata":{"id":"8Iondm2oUMUl"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"nuHPp1U7UMUl"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":11,"metadata":{"executionInfo":{"elapsed":255,"status":"ok","timestamp":1716482875511,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"vaf4PGLlUMUm"},"outputs":[],"source":["os.environ['USE_TUNNEL'] = 'True' if FC.IN_COLAB else 'False'\n","os.environ['USE_PIL'] = 'True' if FC.IN_COLAB and os.environ['USE_TUNNEL'] == 'False' else 'False'\n"]},{"cell_type":"code","execution_count":12,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":168},"executionInfo":{"elapsed":6227,"status":"ok","timestamp":1716482883934,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"kivkfTrcUMUm","outputId":"8b7e7b3a-04fc-45d8-8627-9ba4509d9e67"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import pcleaner._testbed.testbed.web_server as web_server\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"AUgSvi6CUMUm"},"source":["Creates the `IdeficsExperimentContext` object we'll use to manage the experiments.\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":1000,"referenced_widgets":["b73009bd316d474c83984e19bbe1dd5d","8173703d1170428f9f632d0f9b3c51fb","3a90615cbf054a2c9518f6c7715a483b","37f933c907154d3cb326214e88da14f5","8eac691047c84830b008fa8c74de8e59","e8a8f2864e2346e9abd9ea7e6371901f","9493f753d3d746ebaf860074a43f8b5c","d8416277ca174bdebc879a5eeb559203","bd0155b640a9429fab35df32d32d3b5c","58335b09c62a4c77bb4dbbd2180f00f5","d991113b7e924a9ba14b2ee034bc58bb","b32a63ac227a43989f0bff7182007770","2f658b34d97e48a9accb4f8e69db0524","ba5183d590eb4269984812564b9136d1","8f04aee77f594579a7b257df7760ba07","9175ea3267514e2b946b7f583bd6c448","895dc88a4a704b849983166ffe18428e","6d8ec2e2d9f54c08b42c4fd907012cc4","bc735fd356114f6aab9a94e4ff2e88a0","c6cc1ed486e340ca9c10f83fb6d93473","bca7db38272d4b5dba307fbc893512a9","319aebd2d96f4f1c845fef5543ae98ed","f10a031bce3948e2bccca61bbb6f101c","e2f25159f7b249b9a2d820201413e190","56a8217adf3944b980a92b2aaea2bd39","5090734da55b47d5a2a6087e51891e0d","6aceed8edb8e4105b1f807e57bb25d5e","9c002b71e1f144998d8f5ce683766c2a","304ef8bb5c894f3fb9fbb9309fccb2db","935ded8cabb04c31b334a30acd346ae7","eed1b76b9a824cca8f7ddb490bcec2ff","ae0c642d219a41629b62cf8560823c1c","ea5a56efc11845e2bf38a65d8e93af7c","bbdcdc291ad74258b554e72073e1ede8","ae61d812a96a48cf84a788af5337d51e","9fd71f03002d445c8e70342c0513e369","0e5837b643174914b9a6b6c9e6ac3e22","0888d628f34b463eb01e9e5393a4f4c4","2770478ce8044a83b127904a8f588d5b","3fdbba3cf67d46cfb1632f6dcfb0210c","c7a74d0ee2254e6da29eeef1a3298656","58541ced68a4479d9926c09f14276f23","beaea513e569447fba29ca3df3a089f5","283e34e62cbd43108fea85e4408e1451","d9c15d9a41f24f1a86084b0c863d3af8","69faa9295aa143629f8ba0ce018454d4","14e4633237104f15850409f4ffcfa30a","413317a231404aa9a2a6580775f06fcb","10442533920f484dbf1974e528c6ec1f","ac43bf53858a4c1dadc600f3322f2aca","b7d7719b807048cb945fb958b06402a7","dac4186c487e46c6b56ba7c292629a41","3a50e27548d741118286fabf9630c443","7746e9fad11f4a64996a1c41d0abfc33","74ea647617734b52b8e07d4246d18109","75c820e2cdda451f9ac7daabe0fcc8ca","b7838cbddd984b368ea471cee96ff02e","c3485b737f59434aa7c757ce7d4f86d2","3c4f71788c75498faf2738f751e924f3","d20d3a3712f64dceaeea4b6aeb435b8d","e98b093c952c4e3293abdf5b736b3bd7","1c322cc01c284e21a18f06db8d481636","053288662f604af8a6fbea87e8ef9014","b02ed5020f71474a9ed0c008abb40efb","f0d73ff6d04040f1962fd50d2352f23d","a1b9b514669e4a2fae3a401d770a699e","2c3a3903877e49a58181f813aa0e37b9","28f525d59c094c03955d9215cf189007","789385e36d1e432c95036b6e3a0054b8","b8cd67195ca6414daa236d21c9189e39","ef92abc3751b4b03a673a92e817d39de","4438153338484d178ac76562ada78fc4","6a3306e72c4b447e989229c28e555e22","1b8ecfca8fc64677969da2b325b13ee9","d338945414dc4b23bb1dc1b81cc17be0","6cf2d63005134660a189daae0ad36707","3f3922cb87fb407499422ab1b43ca6a5","05a94a01013d47a5b523bb322a2ef939","1adbc348c55d4e68ba66eb1d597c926e","717d027f1da74bb5affa93b72b99a0ed","9e076e294d964217a1e3ceff9b390b7a","c604bd0d89304ea7973a6819fac981ac","1822f3f564d843dd843d580c3e120a80","3bc4fe63c9574d35bc8a0f3e940212c3","e71b8879e55848479fa6f20a4f5010ea","cd3f6165ed144369a54e4b784cac2a99","bf8adc8c29eb4021a532561b374cade2","786b35b5a60b4ef3afd8f04c9240bf1a","8e263c7c07e34d9e8cf475f8f9b0c707","d753fc74422941cfa7031efe2c996f50","5cb88a274e4c40b3a505582d54578a75","cefeb098a7b04f2782b00e28cd809833","dedf69f896794fdab878d78a44db1fcd","6d0fe13087244d38b7e2c81442467ad0","4cda5365a57e453e9bbdcc0de548f1e3","7515ab4558124374a66e7af8ac063846","9f9efc028dc1431ba717dfdac07ba7da","ac247fdb754c460dac3d2a731a04f74b","47000f0cc4ce485b9f249ac32a0dc75b","d6f64705e9da407f9959f1b124e8e47e","2305ed3b768e4930af09fa8b2809df1a","16fcee1797ec48fdba6c556d996eb0c9","397f4e0b79e84838ba3640db134d7b0d","0e7f53ea18fb47bba3f007b7116b8994","80ae139aadb6462db2ce3671a7903026","a33e2a16d266421aa5658d1ad3576fc7","099748fb95ab4942a89cc37ba2f67046","abd1fbe978bd46208e54ec410778c382","11a3455d0dd4450f87dd73430c1413ae","f54949799fe747e2b4757d73d40960e6","976de42087f34ed28f2efcab0737e107","0279524ba7574791bd706fa97b3b403f","8b9c3fb54710444eaea4519160ca1c2a","2d0c0d03b7234f87b66ee70da99f75d0","df002956627b496a8fe33a02bcec05a8","abcf597b372b42428cdf70189ccfe494","64830881d8854c39ba2f756d314e36b6","144ebe17cc25423a8d5ac32aa7e5c237","8acae939581c453eb0cc904684b730b0","b33ddee7648640558f1fcd15b1c3b5ea","e5d23d25fb4646d48d863ba26b592273","8256e914c50644669d8c273e6a100d43","924ac8d3f282407585506197682db1f5","3884716282074678bc09a72aa2a1719c","8c88d57999e84ea99a3c5166a2c0ed83","53b2c177789c405bb266916416e93109","00fb9f12f98b4e22a58f4b0030eec5b2","6d2ebf4bfad74f0d8995503b31de46cf","e7f41c7ef7b8464899301192fed93749","7f54d75d9ae6463a8779a9215ac24ecc","fb0037405add4963a01046b1ce4d84da","5cef08747ab6487bad4c1dfedc90dc2c","bc43e4251966462eaab4cb1767998f2c","0c7e4532bb5840869ab4d96ebac0d003","8e507b39dcb9489e8f660c2940aa5521","77d5ad9314534675a66ac3ba0b30a906","cdfdd7698432492586d0d19783b20b79","b0708dc0d1764e87b73cc301cdd13276","acf7496b27cd40469ca712e27c399d12","1385375ab40a450f8f23a8fe10c1184b","3b6f8dd8a65d4a389d5eb8f42665c6f2","5ef114d178f846d28108cf4ab47d6cbe","198cb1e53b974f1aa6ac623629b32f70","473175186eda43f8911ffddb1b44fd65","0b47ab0fa4aa4726a6907aaad9a8045f","30ff45a7d5fc445bb954fd9360bfe1bb","317f8b9163d84963a04c75eedff6dba9","64a9f8f2483b46c58fcdb9453cbbfd4f","d9fdbddf880c4a0cb12ae568c7c3bc02","92fc9ec04a1b4a94b0d480e79641c8e0","fc58444ff3d545fcb1714ac56106734c","babb5904ef30440b866ce0f1ead58b26","676319ec997a4ef1b77b6ca5bd1454a3","896dacde6f98494ea11c19059a4c21e1","5eb41f9599a04241816c359ab2654930","36c7b5884cb44aa389c2f12bedf90f09","1a1ad0162b574edb8ce2540c1d5e477b","8c47b62e4954445c99ceec249651bf6a","4f0e6fdfb7674ae8951e3072beef9930","9db747425d2c491a868b931156a4071e","625c065a3ba146c190d3f6b024869459","08da46aa6895493b9d8e425f917d0713","f66a7d2bb62d4ef9aec868904a60d8f7","19317ccee5a04fe4b2bade87cd24240c","60a576a0a174400b92b59f02b7ce24da","7b9b4f63980147a4964ef7cad66ee08e","b8917b9b5ed143df8aebdb2cfa259ac1","421f6c061d744875936807e23f319003","a784f312c3ed412fb4da37803dc623d8","b04c576af2aa4412b9756aa9bd683f0e","7daf76bd51514afe8984782317765a5a","e41cf0472cbf40f9b8422faef0f7df6a","05b278a44567413284655e330cc2df18","ed19a655de0e42529a3eca5b105a8e92","6e98f45681374a9aa3cf231a9327dab4","d7f7174351c44565a4778ae02f7b2d73","2d9290c11d0d45b4a6aa958e0572575d","e49c2a376b28457fab3517524e5841d9","b2397c0db81345bd9bcbecd54eb45efa","2cad0f40664d4dbd984288ddba4071c6","6a0d32fb84a84c49960baeb808bd98d4","b50cb561a7444f488f477b8a1dedbf6a","700c364b9ed742e39d7d066f38456853","a16c8faf8266441db835b2e2a5d79bbf","09ab31f01e0b43149d8abc6d4391796f","3641f29a77d34081afc26bbfb495ecda","47edd13b1e2e4d168bcd27d128c46723","31ec7df081cd4350a7ca8cc554b9f49d","75b1e6f11ab44c15a2da8fec9c9f543a","42bb6c3f4bda46b9aa3e4ca3b01e92d8","8c3a3d31ca2f4967b3f4f6f3d2ae6f90","56180eaabbda472ba401a4c033ee73df","9fa4a57f420841c9affb97477ae0fc41","2dcfc01bb0314e15937a823f9a19143b","1f198dcb97f84081bb02c70bd9c33860","293d509277c54e20bbf463ea33234aa9","2e6a59eb2a8c46aebd1776dea21d5f25","6584ea25504e48999bde51541b648769","bb9faa43334140d29e732b3bf6e86723","29dd2822500349bdb5e76d53e93072ce","eabc054fcd6b447da92f402662469c8e","af08ec8225e948648a4534d4b42b880a","38c0b2d95f2842389c12837771a8e42e","50cb4765423047cc88083d04187f5371","c68f99824c684d668f5e860a8afb2060","71a15c3988114259961d1943dd4e931c","43115512206d4717a02ccd0ef4133555","9bb79599f274472dac09277f81cf0bd1","9190d15fbcd1407b9abc3e16fc910437"]},"executionInfo":{"elapsed":436567,"status":"ok","timestamp":1716483359245,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"wroznCt0CQdT","outputId":"d288c8de-1780-44aa-d782-8d540d43f38a"},"outputs":[],"source":["# CONTEXT = IdeficsExperimentContext(EXP_DIR, server=SERVER) # quantization 'bfloat16' # Colab pro with A100 or L4, bfloat16 and FlashAttention\n","# CONTEXT = IdeficsExperimentContext(EXP_DIR, '4bits', server=SERVER) # Linux, Ampere\n","CONTEXT = IdeficsExperimentContext(EXP_DIR, '4bits', False, server=SERVER) # Colab Free tier, T4 GPUs don't support FlashAttention\n","CONTEXT.show()\n"]},{"cell_type":"markdown","metadata":{},"source":["# Test images\n"]},{"cell_type":"markdown","metadata":{},"source":["Copy your images to the source directory:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 18TSXLCYAPxAlUsdHmgAe6FZM5d8K6gcT -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{},"source":["Check the images are in place"]},{"cell_type":"code","execution_count":14,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":257,"status":"ok","timestamp":1716483368007,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"ZXL84T8dUMUm","outputId":"23d7fc26-340e-4c6f-e8e8-b104463a6cf9"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":14,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":249,"referenced_widgets":["3d836d5327a74372b7683abcfff2db7f","cce5c58aa59a4defb50cc973cadc191a","e4494cbb70ef4e2fb04a138e12c84e34","6c875b66bc4f4c2c82c1ab733a5688a5","4dfd8a5fd8e4484facbd9c0744725b62","9505f71206d54784aa9643f0732ce5ac","35cac4342a9044d991e3f53df06fd959","c84073b5707747e5994e7e21c097c0c8","7f5e49d03e4e4dc699479b28c9861e86","e498874bec694db7930da19e87551331","2ab7e8393c274604a8a33d5f84efcd58","9f20aa7c868144f5bcf5fafa2c366d7f","1ca13fea7ccb43dea1cb1994c60e2af2","bf27826f32934db290de83c493474cce","796a5da82e134de2a279039d3a120b0f","5628322d2c6c44bd882acbd629a634ea","33d7a2f0e1f74398b7fa7b5f24ca8b2d","1e23724ddd3341c4970f0f084c32c11f","1a36a60101aa405d96f154646e1b04fa","0951a0674c6b416d888f8cc62a0a0bd7","09c2ceaac90d48018d137ee2fd656f5d","08d82c48cc1e4019bc3c7c701736b52d","d468d37a817f44ebb5c8b844fc98182a","213d5015356540c19c6e529ce18fa248","2c1daabcfc484227bb8b378e4ab06e03","14620ca258c64c03ba5ed90af4ed7733","3a1dde9734a246a6af73d9b5a52bb090","d19ccb7ec79a40a483fe40e712c74c8c","04a42dffe0854eee9b3b4f12eb7683fb","3d322afd0d754829abfc365a9044a6c0","28b2030d9fc7433baa1111795433b2d2","b654d25c42f849ac9d11ae0c76618d6d","98f0ce2e0be94481ac9bfb50d4305f62","7e90d469d6f44c22ae83f58f19afa6c1","2161a826684744bb95847f56fee5f7a2","035cea2946064cd7bd5f94a4001bffbd","10bb5a346e284e9790de482f77f34109","5d06574fe54043409073268d797ed2d6","81a51fac93124032b47605db442da668","4409342a72ed4d47b00ef8b57104943a","8c8083f3c88c493bb2c86be2ee831cc9","2cf68b7c35634bb684f1a9b5364eebff","6a39213f6bdd4f0aa6f31bc89e58f309","ce3896c172d4497b805ba27a6464c0da","0e10e9ee0da34a5fbd38d18cebc37dcb","f56c9aac9b874cb79be45bb93af2519d","83c57712c02b49b6aa44400265017bb1","902a25db5df048f9a3f5e1b3a37d3d47","852814ab86b64357bf34a7b3d5647259","d47ae1fd98304f549bb15af1885ba182","e3b557d743624c2680fedc10edc679fe","56c75f8d9290496f9f8466515cc63924","06dfdd832b014336bbf0c03a0afde588","be7840a17d064a7c8b2e2d4af600702c","f52b8b4144bd414b97fddf1e63f114b4","3293295b5c254ab8b616e97449ce3e25","4088047b645d4e27830799f7560d049f","96b6b7275b844d949a1fbda10ff8121b","016502353f614814b4e69c704e3b30fa","e7bc0e0e5fed4f6ebf068100805c2439","bc28472a9a3a4b169d12b97e7cce3559","be379bd1475147a3bd8f1bd609a41f19","ba294a8e7603470eb492fd1b64f31b24","7dbd1ebf371a45f7a04d2dbdb19619d6","857613bc6fb345988cb1d55c8b210cab","aa69c29e07674f1480124cf4a5700276"]},"executionInfo":{"elapsed":10562,"status":"ok","timestamp":1716483395560,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"GmAca8fVUMUm","outputId":"8f9ff268-bf15-48fa-e1ba-364b658f3eb2"},"outputs":[],"source":["idefics_experiment = ExperimentsVisor(\n"," CONTEXT,\n"," 'Idefics',\n"," image_idx='Strange_Tales_172005.jpg',\n"," box_idx=1,\n"," method=CropMethod.DEFAULT_GREY_PAD\n"," )\n","idefics_experiment\n"]},{"cell_type":"markdown","metadata":{"id":"26mWhbfGCQdU"},"source":["----"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":104},"executionInfo":{"elapsed":10458,"status":"ok","timestamp":1716483552101,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"L8ILu2EgUMUm","outputId":"771fe6ec-c630-4e49-f55a-9e0cabd2f4dc"},"outputs":[],"source":["CONTEXT.cleanup_model()\n","\n","if SERVER is not None:\n"," SERVER.stop()\n"," SERVER = None\n"," os.environ['USE_TUNNEL'] = 'False'\n"]}],"metadata":{"accelerator":"GPU","colab":{"gpuType":"T4","machine_shape":"hm","provenance":[]},"kernelspec":{"display_name":"Python 3","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.14"},"widgets":{"application/vnd.jupyter.widget-state+json":{"00fb9f12f98b4e22a58f4b0030eec5b2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"016502353f614814b4e69c704e3b30fa":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"none","flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0279524ba7574791bd706fa97b3b403f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_abcf597b372b42428cdf70189ccfe494","placeholder":"​","style":"IPY_MODEL_64830881d8854c39ba2f756d314e36b6","value":"model-00001-of-00007.safetensors: 100%"}},"035cea2946064cd7bd5f94a4001bffbd":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"04a42dffe0854eee9b3b4f12eb7683fb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_83c57712c02b49b6aa44400265017bb1","placeholder":"​","style":"IPY_MODEL_902a25db5df048f9a3f5e1b3a37d3d47","value":"Box # (of 15):"}},"053288662f604af8a6fbea87e8ef9014":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"05a94a01013d47a5b523bb322a2ef939":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_1adbc348c55d4e68ba66eb1d597c926e","IPY_MODEL_717d027f1da74bb5affa93b72b99a0ed","IPY_MODEL_9e076e294d964217a1e3ceff9b390b7a"],"layout":"IPY_MODEL_c604bd0d89304ea7973a6819fac981ac"}},"05b278a44567413284655e330cc2df18":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"06dfdd832b014336bbf0c03a0afde588":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"0888d628f34b463eb01e9e5393a4f4c4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"08d82c48cc1e4019bc3c7c701736b52d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"08da46aa6895493b9d8e425f917d0713":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0951a0674c6b416d888f8cc62a0a0bd7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"visible","width":null}},"099748fb95ab4942a89cc37ba2f67046":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"09ab31f01e0b43149d8abc6d4391796f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"09c2ceaac90d48018d137ee2fd656f5d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["model_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_81a51fac93124032b47605db442da668"],"layout":"IPY_MODEL_4409342a72ed4d47b00ef8b57104943a"}},"0b47ab0fa4aa4726a6907aaad9a8045f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_d9fdbddf880c4a0cb12ae568c7c3bc02","placeholder":"​","style":"IPY_MODEL_92fc9ec04a1b4a94b0d480e79641c8e0","value":"model-00004-of-00007.safetensors: 100%"}},"0c7e4532bb5840869ab4d96ebac0d003":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b0708dc0d1764e87b73cc301cdd13276","placeholder":"​","style":"IPY_MODEL_acf7496b27cd40469ca712e27c399d12","value":"model-00003-of-00007.safetensors: 100%"}},"0e10e9ee0da34a5fbd38d18cebc37dcb":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"6em"}},"0e5837b643174914b9a6b6c9e6ac3e22":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_beaea513e569447fba29ca3df3a089f5","placeholder":"​","style":"IPY_MODEL_283e34e62cbd43108fea85e4408e1451","value":" 493k/493k [00:00<00:00, 5.69MB/s]"}},"0e7f53ea18fb47bba3f007b7116b8994":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"10442533920f484dbf1974e528c6ec1f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"10bb5a346e284e9790de482f77f34109":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":["wrapper-spinner"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_016502353f614814b4e69c704e3b30fa","placeholder":"​","style":"IPY_MODEL_e7bc0e0e5fed4f6ebf068100805c2439","value":"\n
\n
\n
\n "}},"11a3455d0dd4450f87dd73430c1413ae":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"1385375ab40a450f8f23a8fe10c1184b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"144ebe17cc25423a8d5ac32aa7e5c237":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"14620ca258c64c03ba5ed90af4ed7733":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"14e4633237104f15850409f4ffcfa30a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_dac4186c487e46c6b56ba7c292629a41","max":1795881,"min":0,"orientation":"horizontal","style":"IPY_MODEL_3a50e27548d741118286fabf9630c443","value":1795881}},"16fcee1797ec48fdba6c556d996eb0c9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_099748fb95ab4942a89cc37ba2f67046","max":7,"min":0,"orientation":"horizontal","style":"IPY_MODEL_abd1fbe978bd46208e54ec410778c382","value":7}},"1822f3f564d843dd843d580c3e120a80":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"19317ccee5a04fe4b2bade87cd24240c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"198cb1e53b974f1aa6ac623629b32f70":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"1a1ad0162b574edb8ce2540c1d5e477b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_08da46aa6895493b9d8e425f917d0713","max":4999813712,"min":0,"orientation":"horizontal","style":"IPY_MODEL_f66a7d2bb62d4ef9aec868904a60d8f7","value":4999813712}},"1a36a60101aa405d96f154646e1b04fa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","134608506364128"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_10bb5a346e284e9790de482f77f34109"],"layout":"IPY_MODEL_5d06574fe54043409073268d797ed2d6"}},"1adbc348c55d4e68ba66eb1d597c926e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_1822f3f564d843dd843d580c3e120a80","placeholder":"​","style":"IPY_MODEL_3bc4fe63c9574d35bc8a0f3e940212c3","value":"config.json: 100%"}},"1b8ecfca8fc64677969da2b325b13ee9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"1c322cc01c284e21a18f06db8d481636":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"1ca13fea7ccb43dea1cb1994c60e2af2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","134608517037552"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_d468d37a817f44ebb5c8b844fc98182a"],"layout":"IPY_MODEL_213d5015356540c19c6e529ce18fa248"}},"1e23724ddd3341c4970f0f084c32c11f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["method_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_98f0ce2e0be94481ac9bfb50d4305f62","IPY_MODEL_7e90d469d6f44c22ae83f58f19afa6c1","IPY_MODEL_2161a826684744bb95847f56fee5f7a2"],"layout":"IPY_MODEL_035cea2946064cd7bd5f94a4001bffbd"}},"1f198dcb97f84081bb02c70bd9c33860":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"213d5015356540c19c6e529ce18fa248":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2161a826684744bb95847f56fee5f7a2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Initial box","Default","Default, grey pad","Padded 4px","Padded 8px","Extracted, init box","Padded 4, extracted","Padded 8, extracted","Padded 8, dilation 1","Pad 8, fract. 0.5","Pad 8, fract. 0.2"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":2,"layout":"IPY_MODEL_4088047b645d4e27830799f7560d049f","style":"IPY_MODEL_96b6b7275b844d949a1fbda10ff8121b"}},"2305ed3b768e4930af09fa8b2809df1a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_80ae139aadb6462db2ce3671a7903026","placeholder":"​","style":"IPY_MODEL_a33e2a16d266421aa5658d1ad3576fc7","value":"Downloading shards: 100%"}},"2770478ce8044a83b127904a8f588d5b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"283e34e62cbd43108fea85e4408e1451":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"28b2030d9fc7433baa1111795433b2d2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"BoundedIntTextModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"BoundedIntTextModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"IntTextView","continuous_update":false,"description":"","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_e3b557d743624c2680fedc10edc679fe","max":14,"min":0,"step":1,"style":"IPY_MODEL_56c75f8d9290496f9f8466515cc63924","value":5}},"28f525d59c094c03955d9215cf189007":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_4438153338484d178ac76562ada78fc4","placeholder":"​","style":"IPY_MODEL_6a3306e72c4b447e989229c28e555e22","value":"special_tokens_map.json: 100%"}},"293d509277c54e20bbf463ea33234aa9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"29dd2822500349bdb5e76d53e93072ce":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_50cb4765423047cc88083d04187f5371","placeholder":"​","style":"IPY_MODEL_c68f99824c684d668f5e860a8afb2060","value":"generation_config.json: 100%"}},"2ab7e8393c274604a8a33d5f84efcd58":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2c1daabcfc484227bb8b378e4ab06e03":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["display_option_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_6a39213f6bdd4f0aa6f31bc89e58f309"],"layout":"IPY_MODEL_ce3896c172d4497b805ba27a6464c0da"}},"2c3a3903877e49a58181f813aa0e37b9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_28f525d59c094c03955d9215cf189007","IPY_MODEL_789385e36d1e432c95036b6e3a0054b8","IPY_MODEL_b8cd67195ca6414daa236d21c9189e39"],"layout":"IPY_MODEL_ef92abc3751b4b03a673a92e817d39de"}},"2cad0f40664d4dbd984288ddba4071c6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_3641f29a77d34081afc26bbfb495ecda","placeholder":"​","style":"IPY_MODEL_47edd13b1e2e4d168bcd27d128c46723","value":" 4.25G/4.25G [00:33<00:00, 120MB/s]"}},"2cf68b7c35634bb684f1a9b5364eebff":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"2d0c0d03b7234f87b66ee70da99f75d0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b33ddee7648640558f1fcd15b1c3b5ea","placeholder":"​","style":"IPY_MODEL_e5d23d25fb4646d48d863ba26b592273","value":" 4.64G/4.64G [00:34<00:00, 135MB/s]"}},"2d9290c11d0d45b4a6aa958e0572575d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e49c2a376b28457fab3517524e5841d9","IPY_MODEL_b2397c0db81345bd9bcbecd54eb45efa","IPY_MODEL_2cad0f40664d4dbd984288ddba4071c6"],"layout":"IPY_MODEL_6a0d32fb84a84c49960baeb808bd98d4"}},"2dcfc01bb0314e15937a823f9a19143b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"2e6a59eb2a8c46aebd1776dea21d5f25":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2f658b34d97e48a9accb4f8e69db0524":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_895dc88a4a704b849983166ffe18428e","placeholder":"​","style":"IPY_MODEL_6d8ec2e2d9f54c08b42c4fd907012cc4","value":"preprocessor_config.json: 100%"}},"304ef8bb5c894f3fb9fbb9309fccb2db":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"30ff45a7d5fc445bb954fd9360bfe1bb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_fc58444ff3d545fcb1714ac56106734c","max":4999813704,"min":0,"orientation":"horizontal","style":"IPY_MODEL_babb5904ef30440b866ce0f1ead58b26","value":4999813704}},"317f8b9163d84963a04c75eedff6dba9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_676319ec997a4ef1b77b6ca5bd1454a3","placeholder":"​","style":"IPY_MODEL_896dacde6f98494ea11c19059a4c21e1","value":" 5.00G/5.00G [00:36<00:00, 137MB/s]"}},"319aebd2d96f4f1c845fef5543ae98ed":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"31ec7df081cd4350a7ca8cc554b9f49d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_75b1e6f11ab44c15a2da8fec9c9f543a","IPY_MODEL_42bb6c3f4bda46b9aa3e4ca3b01e92d8","IPY_MODEL_8c3a3d31ca2f4967b3f4f6f3d2ae6f90"],"layout":"IPY_MODEL_56180eaabbda472ba401a4c033ee73df"}},"3293295b5c254ab8b616e97449ce3e25":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"33d7a2f0e1f74398b7fa7b5f24ca8b2d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["box_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_04a42dffe0854eee9b3b4f12eb7683fb","IPY_MODEL_3d322afd0d754829abfc365a9044a6c0","IPY_MODEL_28b2030d9fc7433baa1111795433b2d2"],"layout":"IPY_MODEL_b654d25c42f849ac9d11ae0c76618d6d"}},"35cac4342a9044d991e3f53df06fd959":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"3641f29a77d34081afc26bbfb495ecda":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"36c7b5884cb44aa389c2f12bedf90f09":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_9db747425d2c491a868b931156a4071e","placeholder":"​","style":"IPY_MODEL_625c065a3ba146c190d3f6b024869459","value":"model-00005-of-00007.safetensors: 100%"}},"37f933c907154d3cb326214e88da14f5":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_58335b09c62a4c77bb4dbbd2180f00f5","placeholder":"​","style":"IPY_MODEL_d991113b7e924a9ba14b2ee034bc58bb","value":" 483/483 [00:00<00:00, 33.4kB/s]"}},"3884716282074678bc09a72aa2a1719c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_e7f41c7ef7b8464899301192fed93749","max":4987246632,"min":0,"orientation":"horizontal","style":"IPY_MODEL_7f54d75d9ae6463a8779a9215ac24ecc","value":4987246632}},"38c0b2d95f2842389c12837771a8e42e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"397f4e0b79e84838ba3640db134d7b0d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_11a3455d0dd4450f87dd73430c1413ae","placeholder":"​","style":"IPY_MODEL_f54949799fe747e2b4757d73d40960e6","value":" 7/7 [04:16<00:00, 36.44s/it]"}},"3a1dde9734a246a6af73d9b5a52bb090":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"save","disabled":false,"icon":"","layout":"IPY_MODEL_0e10e9ee0da34a5fbd38d18cebc37dcb","style":"IPY_MODEL_f56c9aac9b874cb79be45bb93af2519d","tooltip":""}},"3a50e27548d741118286fabf9630c443":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"3a90615cbf054a2c9518f6c7715a483b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_d8416277ca174bdebc879a5eeb559203","max":483,"min":0,"orientation":"horizontal","style":"IPY_MODEL_bd0155b640a9429fab35df32d32d3b5c","value":483}},"3b6f8dd8a65d4a389d5eb8f42665c6f2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"3bc4fe63c9574d35bc8a0f3e940212c3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"3c4f71788c75498faf2738f751e924f3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_f0d73ff6d04040f1962fd50d2352f23d","placeholder":"​","style":"IPY_MODEL_a1b9b514669e4a2fae3a401d770a699e","value":" 92.0/92.0 [00:00<00:00, 6.42kB/s]"}},"3d322afd0d754829abfc365a9044a6c0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_852814ab86b64357bf34a7b3d5647259","style":"IPY_MODEL_d47ae1fd98304f549bb15af1885ba182","value":false}},"3d836d5327a74372b7683abcfff2db7f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_cce5c58aa59a4defb50cc973cadc191a","IPY_MODEL_e4494cbb70ef4e2fb04a138e12c84e34","IPY_MODEL_6c875b66bc4f4c2c82c1ab733a5688a5","IPY_MODEL_4dfd8a5fd8e4484facbd9c0744725b62"],"layout":"IPY_MODEL_9505f71206d54784aa9643f0732ce5ac"}},"3f3922cb87fb407499422ab1b43ca6a5":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"3fdbba3cf67d46cfb1632f6dcfb0210c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4088047b645d4e27830799f7560d049f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"150px"}},"413317a231404aa9a2a6580775f06fcb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_7746e9fad11f4a64996a1c41d0abfc33","placeholder":"​","style":"IPY_MODEL_74ea647617734b52b8e07d4246d18109","value":" 1.80M/1.80M [00:00<00:00, 13.8MB/s]"}},"421f6c061d744875936807e23f319003":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_05b278a44567413284655e330cc2df18","max":4832008016,"min":0,"orientation":"horizontal","style":"IPY_MODEL_ed19a655de0e42529a3eca5b105a8e92","value":4832008016}},"42bb6c3f4bda46b9aa3e4ca3b01e92d8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_1f198dcb97f84081bb02c70bd9c33860","max":7,"min":0,"orientation":"horizontal","style":"IPY_MODEL_293d509277c54e20bbf463ea33234aa9","value":7}},"43115512206d4717a02ccd0ef4133555":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"4409342a72ed4d47b00ef8b57104943a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4438153338484d178ac76562ada78fc4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"47000f0cc4ce485b9f249ac32a0dc75b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"473175186eda43f8911ffddb1b44fd65":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_0b47ab0fa4aa4726a6907aaad9a8045f","IPY_MODEL_30ff45a7d5fc445bb954fd9360bfe1bb","IPY_MODEL_317f8b9163d84963a04c75eedff6dba9"],"layout":"IPY_MODEL_64a9f8f2483b46c58fcdb9453cbbfd4f"}},"47edd13b1e2e4d168bcd27d128c46723":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4cda5365a57e453e9bbdcc0de548f1e3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4dfd8a5fd8e4484facbd9c0744725b62":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_aa69c29e07674f1480124cf4a5700276","msg_id":"","outputs":[{"data":{"text/html":"
Tell me master how may bambi serve?
0.90
\n
\n
Tell me, master-- how may Bambu serve?

Tell me master⎕⎕ how may bambi serve?
","text/plain":""},"metadata":{},"output_type":"display_data"}]}},"4f0e6fdfb7674ae8951e3072beef9930":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5090734da55b47d5a2a6087e51891e0d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ae0c642d219a41629b62cf8560823c1c","placeholder":"​","style":"IPY_MODEL_ea5a56efc11845e2bf38a65d8e93af7c","value":" 1.64k/1.64k [00:00<00:00, 97.0kB/s]"}},"50cb4765423047cc88083d04187f5371":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"53b2c177789c405bb266916416e93109":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"56180eaabbda472ba401a4c033ee73df":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5628322d2c6c44bd882acbd629a634ea":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"56a8217adf3944b980a92b2aaea2bd39":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_935ded8cabb04c31b334a30acd346ae7","max":1636,"min":0,"orientation":"horizontal","style":"IPY_MODEL_eed1b76b9a824cca8f7ddb490bcec2ff","value":1636}},"56c75f8d9290496f9f8466515cc63924":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"58335b09c62a4c77bb4dbbd2180f00f5":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"58541ced68a4479d9926c09f14276f23":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"5cb88a274e4c40b3a505582d54578a75":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_7515ab4558124374a66e7af8ac063846","max":74354,"min":0,"orientation":"horizontal","style":"IPY_MODEL_9f9efc028dc1431ba717dfdac07ba7da","value":74354}},"5cef08747ab6487bad4c1dfedc90dc2c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5d06574fe54043409073268d797ed2d6":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5eb41f9599a04241816c359ab2654930":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_36c7b5884cb44aa389c2f12bedf90f09","IPY_MODEL_1a1ad0162b574edb8ce2540c1d5e477b","IPY_MODEL_8c47b62e4954445c99ceec249651bf6a"],"layout":"IPY_MODEL_4f0e6fdfb7674ae8951e3072beef9930"}},"5ef114d178f846d28108cf4ab47d6cbe":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"60a576a0a174400b92b59f02b7ce24da":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"625c065a3ba146c190d3f6b024869459":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"64830881d8854c39ba2f756d314e36b6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"64a9f8f2483b46c58fcdb9453cbbfd4f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6584ea25504e48999bde51541b648769":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"676319ec997a4ef1b77b6ca5bd1454a3":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"69faa9295aa143629f8ba0ce018454d4":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ac43bf53858a4c1dadc600f3322f2aca","placeholder":"​","style":"IPY_MODEL_b7d7719b807048cb945fb958b06402a7","value":"tokenizer.json: 100%"}},"6a0d32fb84a84c49960baeb808bd98d4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6a3306e72c4b447e989229c28e555e22":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"6a39213f6bdd4f0aa6f31bc89e58f309":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Boxes","Image","Mask","Image & Mask","Page data","Ground truth","Image All","Results","Best results","Accuracy","Dataframe","Config"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":7,"layout":"IPY_MODEL_ba294a8e7603470eb492fd1b64f31b24","style":"IPY_MODEL_7dbd1ebf371a45f7a04d2dbdb19619d6"}},"6aceed8edb8e4105b1f807e57bb25d5e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6c875b66bc4f4c2c82c1ab733a5688a5":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":["message_visor-yXy"],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_857613bc6fb345988cb1d55c8b210cab","msg_id":"","outputs":[]}},"6cf2d63005134660a189daae0ad36707":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6d0fe13087244d38b7e2c81442467ad0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6d2ebf4bfad74f0d8995503b31de46cf":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"6d8ec2e2d9f54c08b42c4fd907012cc4":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"6e98f45681374a9aa3cf231a9327dab4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"700c364b9ed742e39d7d066f38456853":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"717d027f1da74bb5affa93b72b99a0ed":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_e71b8879e55848479fa6f20a4f5010ea","max":684,"min":0,"orientation":"horizontal","style":"IPY_MODEL_cd3f6165ed144369a54e4b784cac2a99","value":684}},"71a15c3988114259961d1943dd4e931c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"74ea647617734b52b8e07d4246d18109":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"7515ab4558124374a66e7af8ac063846":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"75b1e6f11ab44c15a2da8fec9c9f543a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_9fa4a57f420841c9affb97477ae0fc41","placeholder":"​","style":"IPY_MODEL_2dcfc01bb0314e15937a823f9a19143b","value":"Loading checkpoint shards: 100%"}},"75c820e2cdda451f9ac7daabe0fcc8ca":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_b7838cbddd984b368ea471cee96ff02e","IPY_MODEL_c3485b737f59434aa7c757ce7d4f86d2","IPY_MODEL_3c4f71788c75498faf2738f751e924f3"],"layout":"IPY_MODEL_d20d3a3712f64dceaeea4b6aeb435b8d"}},"7746e9fad11f4a64996a1c41d0abfc33":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"77d5ad9314534675a66ac3ba0b30a906":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_5ef114d178f846d28108cf4ab47d6cbe","placeholder":"​","style":"IPY_MODEL_198cb1e53b974f1aa6ac623629b32f70","value":" 4.90G/4.90G [00:38<00:00, 138MB/s]"}},"786b35b5a60b4ef3afd8f04c9240bf1a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"789385e36d1e432c95036b6e3a0054b8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_1b8ecfca8fc64677969da2b325b13ee9","max":1041,"min":0,"orientation":"horizontal","style":"IPY_MODEL_d338945414dc4b23bb1dc1b81cc17be0","value":1041}},"796a5da82e134de2a279039d3a120b0f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","134608506364320"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_3a1dde9734a246a6af73d9b5a52bb090"],"layout":"IPY_MODEL_d19ccb7ec79a40a483fe40e712c74c8c"}},"7b9b4f63980147a4964ef7cad66ee08e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_b8917b9b5ed143df8aebdb2cfa259ac1","IPY_MODEL_421f6c061d744875936807e23f319003","IPY_MODEL_a784f312c3ed412fb4da37803dc623d8"],"layout":"IPY_MODEL_b04c576af2aa4412b9756aa9bd683f0e"}},"7daf76bd51514afe8984782317765a5a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"7dbd1ebf371a45f7a04d2dbdb19619d6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"7e90d469d6f44c22ae83f58f19afa6c1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_f52b8b4144bd414b97fddf1e63f114b4","style":"IPY_MODEL_3293295b5c254ab8b616e97449ce3e25","value":false}},"7f54d75d9ae6463a8779a9215ac24ecc":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"7f5e49d03e4e4dc699479b28c9861e86":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_9f20aa7c868144f5bcf5fafa2c366d7f","IPY_MODEL_1ca13fea7ccb43dea1cb1994c60e2af2","IPY_MODEL_bf27826f32934db290de83c493474cce","IPY_MODEL_796a5da82e134de2a279039d3a120b0f"],"layout":"IPY_MODEL_5628322d2c6c44bd882acbd629a634ea"}},"80ae139aadb6462db2ce3671a7903026":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8173703d1170428f9f632d0f9b3c51fb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_e8a8f2864e2346e9abd9ea7e6371901f","placeholder":"​","style":"IPY_MODEL_9493f753d3d746ebaf860074a43f8b5c","value":"processor_config.json: 100%"}},"81a51fac93124032b47605db442da668":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Idefics-crop-post"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":0,"layout":"IPY_MODEL_bc28472a9a3a4b169d12b97e7cce3559","style":"IPY_MODEL_be379bd1475147a3bd8f1bd609a41f19"}},"8256e914c50644669d8c273e6a100d43":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_924ac8d3f282407585506197682db1f5","IPY_MODEL_3884716282074678bc09a72aa2a1719c","IPY_MODEL_8c88d57999e84ea99a3c5166a2c0ed83"],"layout":"IPY_MODEL_53b2c177789c405bb266916416e93109"}},"83c57712c02b49b6aa44400265017bb1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"852814ab86b64357bf34a7b3d5647259":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"initial"}},"857613bc6fb345988cb1d55c8b210cab":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"895dc88a4a704b849983166ffe18428e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"896dacde6f98494ea11c19059a4c21e1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"8acae939581c453eb0cc904684b730b0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"8b9c3fb54710444eaea4519160ca1c2a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_144ebe17cc25423a8d5ac32aa7e5c237","max":4644107632,"min":0,"orientation":"horizontal","style":"IPY_MODEL_8acae939581c453eb0cc904684b730b0","value":4644107632}},"8c3a3d31ca2f4967b3f4f6f3d2ae6f90":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_2e6a59eb2a8c46aebd1776dea21d5f25","placeholder":"​","style":"IPY_MODEL_6584ea25504e48999bde51541b648769","value":" 7/7 [02:49<00:00, 23.27s/it]"}},"8c47b62e4954445c99ceec249651bf6a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_19317ccee5a04fe4b2bade87cd24240c","placeholder":"​","style":"IPY_MODEL_60a576a0a174400b92b59f02b7ce24da","value":" 5.00G/5.00G [00:38<00:00, 139MB/s]"}},"8c8083f3c88c493bb2c86be2ee831cc9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"fit-content"}},"8c88d57999e84ea99a3c5166a2c0ed83":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_fb0037405add4963a01046b1ce4d84da","placeholder":"​","style":"IPY_MODEL_5cef08747ab6487bad4c1dfedc90dc2c","value":" 4.99G/4.99G [00:36<00:00, 138MB/s]"}},"8e263c7c07e34d9e8cf475f8f9b0c707":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_d753fc74422941cfa7031efe2c996f50","IPY_MODEL_5cb88a274e4c40b3a505582d54578a75","IPY_MODEL_cefeb098a7b04f2782b00e28cd809833"],"layout":"IPY_MODEL_dedf69f896794fdab878d78a44db1fcd"}},"8e507b39dcb9489e8f660c2940aa5521":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_1385375ab40a450f8f23a8fe10c1184b","max":4899116968,"min":0,"orientation":"horizontal","style":"IPY_MODEL_3b6f8dd8a65d4a389d5eb8f42665c6f2","value":4899116968}},"8eac691047c84830b008fa8c74de8e59":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8f04aee77f594579a7b257df7760ba07":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_bca7db38272d4b5dba307fbc893512a9","placeholder":"​","style":"IPY_MODEL_319aebd2d96f4f1c845fef5543ae98ed","value":" 460/460 [00:00<00:00, 35.6kB/s]"}},"902a25db5df048f9a3f5e1b3a37d3d47":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"9175ea3267514e2b946b7f583bd6c448":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9190d15fbcd1407b9abc3e16fc910437":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"924ac8d3f282407585506197682db1f5":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_00fb9f12f98b4e22a58f4b0030eec5b2","placeholder":"​","style":"IPY_MODEL_6d2ebf4bfad74f0d8995503b31de46cf","value":"model-00002-of-00007.safetensors: 100%"}},"92fc9ec04a1b4a94b0d480e79641c8e0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"935ded8cabb04c31b334a30acd346ae7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9493f753d3d746ebaf860074a43f8b5c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"9505f71206d54784aa9643f0732ce5ac":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"96b6b7275b844d949a1fbda10ff8121b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"976de42087f34ed28f2efcab0737e107":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_0279524ba7574791bd706fa97b3b403f","IPY_MODEL_8b9c3fb54710444eaea4519160ca1c2a","IPY_MODEL_2d0c0d03b7234f87b66ee70da99f75d0"],"layout":"IPY_MODEL_df002956627b496a8fe33a02bcec05a8"}},"98f0ce2e0be94481ac9bfb50d4305f62":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_06dfdd832b014336bbf0c03a0afde588","placeholder":"​","style":"IPY_MODEL_be7840a17d064a7c8b2e2d4af600702c","value":"Method:"}},"9bb79599f274472dac09277f81cf0bd1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9c002b71e1f144998d8f5ce683766c2a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9db747425d2c491a868b931156a4071e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9e076e294d964217a1e3ceff9b390b7a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_bf8adc8c29eb4021a532561b374cade2","placeholder":"​","style":"IPY_MODEL_786b35b5a60b4ef3afd8f04c9240bf1a","value":" 684/684 [00:00<00:00, 50.8kB/s]"}},"9f20aa7c868144f5bcf5fafa2c366d7f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","134608383824016"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_09c2ceaac90d48018d137ee2fd656f5d"],"layout":"IPY_MODEL_08d82c48cc1e4019bc3c7c701736b52d"}},"9f9efc028dc1431ba717dfdac07ba7da":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"9fa4a57f420841c9affb97477ae0fc41":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9fd71f03002d445c8e70342c0513e369":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_c7a74d0ee2254e6da29eeef1a3298656","max":493443,"min":0,"orientation":"horizontal","style":"IPY_MODEL_58541ced68a4479d9926c09f14276f23","value":493443}},"a16c8faf8266441db835b2e2a5d79bbf":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a1b9b514669e4a2fae3a401d770a699e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a33e2a16d266421aa5658d1ad3576fc7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a784f312c3ed412fb4da37803dc623d8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_6e98f45681374a9aa3cf231a9327dab4","placeholder":"​","style":"IPY_MODEL_d7f7174351c44565a4778ae02f7b2d73","value":" 4.83G/4.83G [00:37<00:00, 139MB/s]"}},"aa69c29e07674f1480124cf4a5700276":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"abcf597b372b42428cdf70189ccfe494":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"abd1fbe978bd46208e54ec410778c382":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"ac247fdb754c460dac3d2a731a04f74b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ac43bf53858a4c1dadc600f3322f2aca":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"acf7496b27cd40469ca712e27c399d12":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"ae0c642d219a41629b62cf8560823c1c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ae61d812a96a48cf84a788af5337d51e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_2770478ce8044a83b127904a8f588d5b","placeholder":"​","style":"IPY_MODEL_3fdbba3cf67d46cfb1632f6dcfb0210c","value":"tokenizer.model: 100%"}},"af08ec8225e948648a4534d4b42b880a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_9bb79599f274472dac09277f81cf0bd1","placeholder":"​","style":"IPY_MODEL_9190d15fbcd1407b9abc3e16fc910437","value":" 185/185 [00:00<00:00, 13.2kB/s]"}},"b02ed5020f71474a9ed0c008abb40efb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"b04c576af2aa4412b9756aa9bd683f0e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b0708dc0d1764e87b73cc301cdd13276":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b2397c0db81345bd9bcbecd54eb45efa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_a16c8faf8266441db835b2e2a5d79bbf","max":4249064488,"min":0,"orientation":"horizontal","style":"IPY_MODEL_09ab31f01e0b43149d8abc6d4391796f","value":4249064488}},"b32a63ac227a43989f0bff7182007770":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_2f658b34d97e48a9accb4f8e69db0524","IPY_MODEL_ba5183d590eb4269984812564b9136d1","IPY_MODEL_8f04aee77f594579a7b257df7760ba07"],"layout":"IPY_MODEL_9175ea3267514e2b946b7f583bd6c448"}},"b33ddee7648640558f1fcd15b1c3b5ea":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b50cb561a7444f488f477b8a1dedbf6a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b654d25c42f849ac9d11ae0c76618d6d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b73009bd316d474c83984e19bbe1dd5d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_8173703d1170428f9f632d0f9b3c51fb","IPY_MODEL_3a90615cbf054a2c9518f6c7715a483b","IPY_MODEL_37f933c907154d3cb326214e88da14f5"],"layout":"IPY_MODEL_8eac691047c84830b008fa8c74de8e59"}},"b7838cbddd984b368ea471cee96ff02e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_e98b093c952c4e3293abdf5b736b3bd7","placeholder":"​","style":"IPY_MODEL_1c322cc01c284e21a18f06db8d481636","value":"added_tokens.json: 100%"}},"b7d7719b807048cb945fb958b06402a7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"b8917b9b5ed143df8aebdb2cfa259ac1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_7daf76bd51514afe8984782317765a5a","placeholder":"​","style":"IPY_MODEL_e41cf0472cbf40f9b8422faef0f7df6a","value":"model-00006-of-00007.safetensors: 100%"}},"b8cd67195ca6414daa236d21c9189e39":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_6cf2d63005134660a189daae0ad36707","placeholder":"​","style":"IPY_MODEL_3f3922cb87fb407499422ab1b43ca6a5","value":" 1.04k/1.04k [00:00<00:00, 63.8kB/s]"}},"ba294a8e7603470eb492fd1b64f31b24":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"120px"}},"ba5183d590eb4269984812564b9136d1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_bc735fd356114f6aab9a94e4ff2e88a0","max":460,"min":0,"orientation":"horizontal","style":"IPY_MODEL_c6cc1ed486e340ca9c10f83fb6d93473","value":460}},"babb5904ef30440b866ce0f1ead58b26":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"bb9faa43334140d29e732b3bf6e86723":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_29dd2822500349bdb5e76d53e93072ce","IPY_MODEL_eabc054fcd6b447da92f402662469c8e","IPY_MODEL_af08ec8225e948648a4534d4b42b880a"],"layout":"IPY_MODEL_38c0b2d95f2842389c12837771a8e42e"}},"bbdcdc291ad74258b554e72073e1ede8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_ae61d812a96a48cf84a788af5337d51e","IPY_MODEL_9fd71f03002d445c8e70342c0513e369","IPY_MODEL_0e5837b643174914b9a6b6c9e6ac3e22"],"layout":"IPY_MODEL_0888d628f34b463eb01e9e5393a4f4c4"}},"bc28472a9a3a4b169d12b97e7cce3559":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"fit-content"}},"bc43e4251966462eaab4cb1767998f2c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_0c7e4532bb5840869ab4d96ebac0d003","IPY_MODEL_8e507b39dcb9489e8f660c2940aa5521","IPY_MODEL_77d5ad9314534675a66ac3ba0b30a906"],"layout":"IPY_MODEL_cdfdd7698432492586d0d19783b20b79"}},"bc735fd356114f6aab9a94e4ff2e88a0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bca7db38272d4b5dba307fbc893512a9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bd0155b640a9429fab35df32d32d3b5c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"be379bd1475147a3bd8f1bd609a41f19":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"be7840a17d064a7c8b2e2d4af600702c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"beaea513e569447fba29ca3df3a089f5":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bf27826f32934db290de83c493474cce":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","134608517036592"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_2c1daabcfc484227bb8b378e4ab06e03"],"layout":"IPY_MODEL_14620ca258c64c03ba5ed90af4ed7733"}},"bf8adc8c29eb4021a532561b374cade2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c3485b737f59434aa7c757ce7d4f86d2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_053288662f604af8a6fbea87e8ef9014","max":92,"min":0,"orientation":"horizontal","style":"IPY_MODEL_b02ed5020f71474a9ed0c008abb40efb","value":92}},"c604bd0d89304ea7973a6819fac981ac":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c68f99824c684d668f5e860a8afb2060":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"c6cc1ed486e340ca9c10f83fb6d93473":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"c7a74d0ee2254e6da29eeef1a3298656":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c84073b5707747e5994e7e21c097c0c8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"cce5c58aa59a4defb50cc973cadc191a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_35cac4342a9044d991e3f53df06fd959","placeholder":"​","style":"IPY_MODEL_c84073b5707747e5994e7e21c097c0c8","value":""}},"cd3f6165ed144369a54e4b784cac2a99":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"cdfdd7698432492586d0d19783b20b79":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ce3896c172d4497b805ba27a6464c0da":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"cefeb098a7b04f2782b00e28cd809833":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ac247fdb754c460dac3d2a731a04f74b","placeholder":"​","style":"IPY_MODEL_47000f0cc4ce485b9f249ac32a0dc75b","value":" 74.4k/74.4k [00:00<00:00, 5.22MB/s]"}},"d19ccb7ec79a40a483fe40e712c74c8c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d20d3a3712f64dceaeea4b6aeb435b8d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d338945414dc4b23bb1dc1b81cc17be0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"d468d37a817f44ebb5c8b844fc98182a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Action_Comics_1960-01-00_(262)","Adolf_Cap_01_008","Barnaby_v1-028","Barnaby_v1-029","Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013","Cannon-292","Contrato_con_Dios_028","Erase_una_vez_en_Francia_02_88","FOX_CHILLINTALES_T17_012","Furari_-_Jiro_Taniguchi_selma_056","Galactus_12","INOUE_KYOUMEN_002","MCCALL_ROBINHOOD_T31_010","MCCAY_LITTLENEMO_090","Mary_Perkins_On_Stage_v2006_1_-_P00068","PIKE_BOYLOVEGIRLS_T41_012","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2","Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024","Strange_Tales_172005","Strange_Tales_172021","Tarzan_014-21","Tintin_21_Les_Bijoux_de_la_Castafiore_page_39","Transformers_-_Unicron_000-004","Transformers_-_Unicron_000-016","WARE_ACME_024","Yoko_Tsuno_T01_1972-10","Your_Name_Another_Side_Earthbound_T02_084","manga_0033","ronson-031","哀心迷図のバベル 第01巻 - 22002_00_059"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":20,"layout":"IPY_MODEL_8c8083f3c88c493bb2c86be2ee831cc9","style":"IPY_MODEL_2cf68b7c35634bb684f1a9b5364eebff"}},"d47ae1fd98304f549bb15af1885ba182":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"d6f64705e9da407f9959f1b124e8e47e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_2305ed3b768e4930af09fa8b2809df1a","IPY_MODEL_16fcee1797ec48fdba6c556d996eb0c9","IPY_MODEL_397f4e0b79e84838ba3640db134d7b0d"],"layout":"IPY_MODEL_0e7f53ea18fb47bba3f007b7116b8994"}},"d753fc74422941cfa7031efe2c996f50":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_6d0fe13087244d38b7e2c81442467ad0","placeholder":"​","style":"IPY_MODEL_4cda5365a57e453e9bbdcc0de548f1e3","value":"model.safetensors.index.json: 100%"}},"d7f7174351c44565a4778ae02f7b2d73":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d8416277ca174bdebc879a5eeb559203":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d991113b7e924a9ba14b2ee034bc58bb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d9c15d9a41f24f1a86084b0c863d3af8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_69faa9295aa143629f8ba0ce018454d4","IPY_MODEL_14e4633237104f15850409f4ffcfa30a","IPY_MODEL_413317a231404aa9a2a6580775f06fcb"],"layout":"IPY_MODEL_10442533920f484dbf1974e528c6ec1f"}},"d9fdbddf880c4a0cb12ae568c7c3bc02":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"dac4186c487e46c6b56ba7c292629a41":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"dedf69f896794fdab878d78a44db1fcd":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"df002956627b496a8fe33a02bcec05a8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e2f25159f7b249b9a2d820201413e190":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_9c002b71e1f144998d8f5ce683766c2a","placeholder":"​","style":"IPY_MODEL_304ef8bb5c894f3fb9fbb9309fccb2db","value":"tokenizer_config.json: 100%"}},"e3b557d743624c2680fedc10edc679fe":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50px"}},"e41cf0472cbf40f9b8422faef0f7df6a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e4494cbb70ef4e2fb04a138e12c84e34":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","134608384422912"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_7f5e49d03e4e4dc699479b28c9861e86","IPY_MODEL_e498874bec694db7930da19e87551331"],"layout":"IPY_MODEL_2ab7e8393c274604a8a33d5f84efcd58"}},"e498874bec694db7930da19e87551331":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","134608506364032"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_33d7a2f0e1f74398b7fa7b5f24ca8b2d","IPY_MODEL_1e23724ddd3341c4970f0f084c32c11f","IPY_MODEL_1a36a60101aa405d96f154646e1b04fa"],"layout":"IPY_MODEL_0951a0674c6b416d888f8cc62a0a0bd7"}},"e49c2a376b28457fab3517524e5841d9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b50cb561a7444f488f477b8a1dedbf6a","placeholder":"​","style":"IPY_MODEL_700c364b9ed742e39d7d066f38456853","value":"model-00007-of-00007.safetensors: 100%"}},"e5d23d25fb4646d48d863ba26b592273":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e71b8879e55848479fa6f20a4f5010ea":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e7bc0e0e5fed4f6ebf068100805c2439":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e7f41c7ef7b8464899301192fed93749":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e8a8f2864e2346e9abd9ea7e6371901f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e98b093c952c4e3293abdf5b736b3bd7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ea5a56efc11845e2bf38a65d8e93af7c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"eabc054fcd6b447da92f402662469c8e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_71a15c3988114259961d1943dd4e931c","max":185,"min":0,"orientation":"horizontal","style":"IPY_MODEL_43115512206d4717a02ccd0ef4133555","value":185}},"ed19a655de0e42529a3eca5b105a8e92":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"eed1b76b9a824cca8f7ddb490bcec2ff":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"ef92abc3751b4b03a673a92e817d39de":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f0d73ff6d04040f1962fd50d2352f23d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f10a031bce3948e2bccca61bbb6f101c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e2f25159f7b249b9a2d820201413e190","IPY_MODEL_56a8217adf3944b980a92b2aaea2bd39","IPY_MODEL_5090734da55b47d5a2a6087e51891e0d"],"layout":"IPY_MODEL_6aceed8edb8e4105b1f807e57bb25d5e"}},"f52b8b4144bd414b97fddf1e63f114b4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"initial"}},"f54949799fe747e2b4757d73d40960e6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f56c9aac9b874cb79be45bb93af2519d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":"lightblue","font_weight":"bold"}},"f66a7d2bb62d4ef9aec868904a60d8f7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"fb0037405add4963a01046b1ce4d84da":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fc58444ff3d545fcb1714ac56106734c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}}}},"nbformat":4,"nbformat_minor":0} diff --git a/pcleaner/_testbed/test_tesseract.ipynb b/pcleaner/_testbed/test_tesseract.ipynb new file mode 100644 index 00000000..24ca973d --- /dev/null +++ b/pcleaner/_testbed/test_tesseract.ipynb @@ -0,0 +1 @@ +{"cells":[{"cell_type":"markdown","metadata":{"id":"XLuXdPExZlIq"},"source":["# Testing `Tesseract` OCR for Comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"O02O4qXwZlIr"},"source":["## Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"dD_MtS4cZlIr"},"source":["We will install the more up-to-date version of PanelCleaner from GitHub. Only affects Colab notebooks."]},{"cell_type":"code","execution_count":1,"metadata":{"id":"V3ABUVumZlIr"},"outputs":[],"source":["DEV_INSTALL = True"]},{"cell_type":"markdown","metadata":{"id":"jgisVUTBZlIs"},"source":["The best way to get the images source of the experiments is to mount your Google Drive.\n"]},{"cell_type":"code","execution_count":2,"metadata":{"id":"fFZBHyWLZlIs"},"outputs":[],"source":["MOUNT_DRIVE = DEV_INSTALL\n","GDRIVE_MOUNT_POINT = 'drive'\n"]},{"cell_type":"markdown","metadata":{"id":"X8I28oA1ZlIs"},"source":["# install (Colab)"]},{"cell_type":"code","execution_count":3,"metadata":{"id":"nT4E7IXbcUbp"},"outputs":[],"source":["import fastcore.all as FC\n"]},{"cell_type":"code","execution_count":4,"metadata":{"id":"jpnPDDFIcFh0"},"outputs":[],"source":["if FC.IN_COLAB:\n"," !pip install -q pyngrok\n"]},{"cell_type":"markdown","metadata":{"id":"gqYSM7iBcZsH"},"source":["Mount Google Drive"]},{"cell_type":"code","execution_count":5,"metadata":{"id":"bPF0CtUaZlIs"},"outputs":[],"source":["import os\n","import re\n","from pathlib import Path\n","\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," text = Text(msg)\n"," text.stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, text, \"_\" * 10)\n","\n","\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," mnt_point = f\"/content/{GDRIVE_MOUNT_POINT}\"\n"," if not Path(mnt_point).exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n","\n"," drive.mount(mnt_point, force_remount=True)\n"]},{"cell_type":"markdown","metadata":{"id":"UjPTi7MfcdxU"},"source":["Install **PanelCleaner**"]},{"cell_type":"code","execution_count":6,"metadata":{"id":"7y3qqqy6ZlIt"},"outputs":[],"source":["if FC.IN_COLAB:\n"," info('Installing PanelCleaner')\n"," if DEV_INSTALL:\n"," assert MOUNT_DRIVE, \"DEV_INSTALL need a mounted google drive\"\n"," info('Installing PanelCleaner from Google Drive')\n"," os.chdir(f\"/content/{GDRIVE_MOUNT_POINT}/MyDrive/Shared/PanelCleaner/\")\n"," !pip install -e .\n"," else:\n"," info('Installing PanelCleaner from Github')\n"," !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed\n"]},{"cell_type":"markdown","metadata":{"id":"6ylyum-ibQdL"},"source":["**PanelCleaner** is a heavy-weight and sometimes **Colab** refuses (*silently*) to install it. If the cell below gives an error, re-run the cell above. That usually fixes the problem."]},{"cell_type":"code","execution_count":7,"metadata":{"id":"oE3PogewbUQO"},"outputs":[],"source":["import importlib.resources\n","package_path = importlib.resources.files('pcleaner')\n","assert package_path.name == 'pcleaner'\n","\n","os.chdir(package_path/'_testbed')"]},{"cell_type":"code","execution_count":8,"metadata":{"id":"18HJJTQebWoV"},"outputs":[],"source":["from pcleaner._testbed.testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n"]},{"cell_type":"markdown","metadata":{},"source":["## Tesseract setup"]},{"cell_type":"markdown","metadata":{},"source":["Get current version of Tesseract"]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[{"data":{"text/html":["
[\n","    'tesseract 5.3.4',\n","    ' leptonica-1.84.1',\n","    '  libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \n","1.4.0 : libopenjp2 2.5.2',\n","    ' Found NEON',\n","    ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n","    ' Found libcurl/8.6.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.12 nghttp2/1.61.0'\n","]\n","
\n"],"text/plain":["\u001b[1m[\u001b[0m\n"," \u001b[32m'tesseract 5.3.4'\u001b[0m,\n"," \u001b[32m' leptonica-1.84.1'\u001b[0m,\n"," \u001b[32m' libgif 5.2.1 : libjpeg 8d \u001b[0m\u001b[32m(\u001b[0m\u001b[32mlibjpeg-turbo 3.0.0\u001b[0m\u001b[32m)\u001b[0m\u001b[32m : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \u001b[0m\n","\u001b[32m1.4.0 : libopenjp2 2.5.2'\u001b[0m,\n"," \u001b[32m' Found NEON'\u001b[0m,\n"," \u001b[32m' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6'\u001b[0m,\n"," \u001b[32m' Found libcurl/8.6.0 SecureTransport \u001b[0m\u001b[32m(\u001b[0m\u001b[32mLibreSSL/3.3.6\u001b[0m\u001b[32m)\u001b[0m\u001b[32m zlib/1.2.12 nghttp2/1.61.0'\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["out = !tesseract --version # type: ignore\n","cprint(out)\n","if 'tesseract 5.' not in out[0]:\n"," if 'tesseractd 4.' in out[0]:\n"," cprint('Old Tesseract 4.x is installed. You should uninstall it and install Tesseract 5.x')\n"," else:\n"," cprint('You should install Tesseract 5.x')\n"]},{"cell_type":"markdown","metadata":{},"source":["> **NOTE: in below cells, when you encounter lines starting with the exclamation mark `!` (`bang`), uncoment them if you want to excute the shell commands**\n"]},{"cell_type":"markdown","metadata":{},"source":["### Remove Tesseract installation\n","> I you have the old 4.x version, you should consider removing the installation with the following commands.\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Mac (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### WIndows (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### Ubuntu"]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[],"source":["# !sudo apt-get remove tesseract-ocr\n"]},{"cell_type":"markdown","metadata":{},"source":["### Tesseract installation"]},{"cell_type":"markdown","metadata":{},"source":["#### Mac (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### WIndows (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### Ubuntu"]},{"cell_type":"markdown","metadata":{},"source":["The **5.x** release series is available in the [another PPA](https://launchpad.net/~alex-p/+archive/ubuntu/tesseract-ocr5) for Ubuntu **18.04**, **20.04**, and **22.04**.\n"]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[],"source":["# !sudo add-apt-repository -y ppa:alex-p/tesseract-ocr5"]},{"cell_type":"markdown","metadata":{},"source":["refresh system package cache in case you’re still running old Ubuntu 18.04"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[],"source":["# !sudo apt update"]},{"cell_type":"markdown","metadata":{},"source":["install the software engine"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[],"source":["# !sudo apt install -y tesseract-ocr"]},{"cell_type":"markdown","metadata":{},"source":["and check version:"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[{"data":{"text/html":["
[\n","    'tesseract 5.3.4',\n","    ' leptonica-1.84.1',\n","    '  libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \n","1.4.0 : libopenjp2 2.5.2',\n","    ' Found NEON',\n","    ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n","    ' Found libcurl/8.6.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.12 nghttp2/1.61.0'\n","]\n","
\n"],"text/plain":["\u001b[1m[\u001b[0m\n"," \u001b[32m'tesseract 5.3.4'\u001b[0m,\n"," \u001b[32m' leptonica-1.84.1'\u001b[0m,\n"," \u001b[32m' libgif 5.2.1 : libjpeg 8d \u001b[0m\u001b[32m(\u001b[0m\u001b[32mlibjpeg-turbo 3.0.0\u001b[0m\u001b[32m)\u001b[0m\u001b[32m : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \u001b[0m\n","\u001b[32m1.4.0 : libopenjp2 2.5.2'\u001b[0m,\n"," \u001b[32m' Found NEON'\u001b[0m,\n"," \u001b[32m' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6'\u001b[0m,\n"," \u001b[32m' Found libcurl/8.6.0 SecureTransport \u001b[0m\u001b[32m(\u001b[0m\u001b[32mLibreSSL/3.3.6\u001b[0m\u001b[32m)\u001b[0m\u001b[32m zlib/1.2.12 nghttp2/1.61.0'\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["out = !tesseract --version # type: ignore\n","cprint(out)"]},{"cell_type":"markdown","metadata":{},"source":["### Install Tesseract languages"]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[{"data":{"text/html":["
tessdata path: /opt/homebrew/share/tessdata\n","
\n"],"text/plain":["tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Installed languages:\n","[\n","    'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n","    'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n","    'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n","    'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n","    'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n","    'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n","    'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \n","script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n","    'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \n","script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \n","script/Kannada, script/Khmer',\n","    'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \n","script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n","    'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n","    'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\n","]\n","
\n"],"text/plain":["Installed languages:\n","\u001b[1m[\u001b[0m\n"," \u001b[32m'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces'\u001b[0m,\n"," \u001b[32m'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo'\u001b[0m,\n"," \u001b[32m'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc'\u001b[0m,\n"," \u001b[32m'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert'\u001b[0m,\n"," \u001b[32m'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal'\u001b[0m,\n"," \u001b[32m'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol'\u001b[0m,\n"," \u001b[32m'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \u001b[0m\n","\u001b[32mscript/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur'\u001b[0m,\n"," \u001b[32m'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \u001b[0m\n","\u001b[32mscript/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \u001b[0m\n","\u001b[32mscript/Kannada, script/Khmer'\u001b[0m,\n"," \u001b[32m'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \u001b[0m\n","\u001b[32mscript/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk'\u001b[0m,\n"," \u001b[32m'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel'\u001b[0m,\n"," \u001b[32m'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["out = !tesseract --list-langs # type: ignore\n","tessdata = Path(out[0].split('\"')[1])\n","cprint(f\"tessdata path: {tessdata}\")\n","cprint(\"Installed languages:\", [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]])"]},{"cell_type":"markdown","metadata":{},"source":["#### Install **best** languages and **jpn_ver** Tesseract lang\n","> Much better results than default langs and `jpn` language model.\n"]},{"cell_type":"markdown","metadata":{},"source":["Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best). \n","Donwload from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) a model trained for vertical Japanese text as found in manga.\n","\n","See [here](https://tesseract-ocr.github.io/tessdoc/Data-Files-in-different-versions.html) the languages codes.\n","\n","> Note: I've not play much with `jpn` or `jpn_vert`, `manag-ocr` is surely a much better fit, but it can be educational to compare."]},{"cell_type":"markdown","metadata":{},"source":["Uncomment and excute to download the best language models:\n"]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[],"source":["# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/osd.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/eng.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn.traineddata\n","\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn_vert.traineddata\n","# or\n","# !wget -O jpn_vert.traineddata https://github.com/zodiac3539/jpn_vert/blob/master/jpn_ver5.traineddata\n","\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/spa.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/fra.traineddata"]},{"cell_type":"markdown","metadata":{},"source":["Copy downloaded models to tessdata folder (double check that `tessdata` variable points to the right folder):\n"]},{"cell_type":"code","execution_count":17,"metadata":{},"outputs":[{"data":{"text/html":["
tessdata path: /opt/homebrew/share/tessdata\n","
\n"],"text/plain":["tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint(f\"tessdata path: {tessdata}\")"]},{"cell_type":"code","execution_count":18,"metadata":{},"outputs":[],"source":["# !sudo mv *.traineddata $tessdata"]},{"cell_type":"markdown","metadata":{},"source":["and remove the downloaded models:\n"]},{"cell_type":"code","execution_count":19,"metadata":{},"outputs":[],"source":["# !rm *.traineddata"]},{"cell_type":"markdown","metadata":{},"source":["Check installed languages\n"]},{"cell_type":"code","execution_count":20,"metadata":{},"outputs":[{"data":{"text/html":["
[\n","    Path('/opt/homebrew/share/tessdata/spa.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/eng.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/jpn_vert.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/spa_old.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/fra.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/jpn.traineddata')\n","]\n","
\n"],"text/plain":["\u001b[1m[\u001b[0m\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/eng.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn_vert.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa_old.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/fra.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint(list(filter(lambda x: re.match(r'eng|jpn|jpn_vert|fra|spa', x.name), tessdata.ls()))) # type: ignore\n","# cprint(pytesseract.get_languages())\n"]},{"cell_type":"markdown","metadata":{"id":"fErGl5xSZlI5"},"source":["----\n","# Tesseract experiments"]},{"cell_type":"markdown","metadata":{"id":"op24JaWwfsSv"},"source":["## Experiment directory"]},{"cell_type":"markdown","metadata":{"id":"Av0ceG7efw2L"},"source":["Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n"]},{"cell_type":"code","execution_count":21,"metadata":{"id":"jfMv_sdZfwVY"},"outputs":[{"data":{"text/html":["
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n","Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n","
\n"],"text/plain":[" Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n","Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["EXP_DIR = Path('./experiment')\n","cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n"]},{"cell_type":"markdown","metadata":{"id":"z62cVR57ZlI5"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"qMAn1mOSZlI5"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is `USE_PIL=False`. You can set the environment variable `USE_PIL=True` to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":22,"metadata":{"id":"A0il2cCMZlI5"},"outputs":[],"source":["os.environ['USE_TUNNEL'] = 'True' if FC.IN_COLAB else 'False'\n","os.environ['USE_PIL'] = 'True' if FC.IN_COLAB and os.environ['USE_TUNNEL'] == 'False' else 'False'\n"]},{"cell_type":"code","execution_count":23,"metadata":{"id":"Su0YJikGZlI5"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import pcleaner._testbed.testbed.web_server as web_server\n","\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"2ara95FoZlI5"},"source":["Creates the `OCRExperimentContext` object we'll use to manage the experiments.\n"]},{"cell_type":"code","execution_count":24,"metadata":{"id":"qhQ3nY1OhgdS"},"outputs":[{"name":"stdout","output_type":"stream","text":["Current Configuration:\n","\n","Locale: System default\n","Default Profile: Built-in\n","Saved Profiles:\n","- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n","- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n","\n","Profile Editor: cursor\n","Cache Directory: System default\n","Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n","Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n","GUI Theme: System default\n","\n","--------------------\n","\n","Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n","System default cache directory: /Users/vic/Library/Caches/pcleaner\n"]},{"data":{"text/html":["
 config cache_dir: None\n","       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n","           device: 'mps'\n","
\n"],"text/plain":[" config cache_dir: \u001b[3;35mNone\u001b[0m\n"," model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n"," device: \u001b[32m'mps'\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
        force_PIL: False\n","       use_tunnel: False\n","       server_url: \n","   experiment dir: experiment\n","       source_dir: experiment/source\n","        cache_dir: experiment/cache\n","\n","
\n"],"text/plain":[" force_PIL: \u001b[3;91mFalse\u001b[0m\n"," use_tunnel: \u001b[3;91mFalse\u001b[0m\n"," server_url: \n"," experiment dir: experiment\n"," source_dir: experiment/source\n"," cache_dir: experiment/cache\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["CONTEXT = OCRExperimentContext('Tesseract', EXP_DIR, server=SERVER)\n","CONTEXT.show()"]},{"cell_type":"markdown","metadata":{"id":"5gEd0ZYOZlI5"},"source":["# Test images\n"]},{"cell_type":"markdown","metadata":{"id":"8ecqlXd_h2yc"},"source":["Copy your images to the source directory:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 18TSXLCYAPxAlUsdHmgAe6FZM5d8K6gcT -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{},"source":["Check the images are in place"]},{"cell_type":"code","execution_count":25,"metadata":{"id":"Ha8wqfTHZlI5"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":25,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"markdown","metadata":{"id":"VHtWWQnKj2eU"},"source":["----"]},{"cell_type":"code","execution_count":26,"metadata":{"id":"TZIA3E3jZlI5"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"7153dba0227b423f99fe3417327523ed","version_major":2,"version_minor":0},"text/plain":["VBox(children=(HTML(value=\" + + +

Error: {{e.status}}

+

Sorry, the requested URL {{repr(request.url)}} + caused an error:

+
{{e.body}}
+ %%if DEBUG and e.exception: +

Exception:

+ %%try: + %%exc = repr(e.exception) + %%except: + %%exc = '' %% type(e.exception).__name__ + %%end +
{{exc}}
+ %%end + %%if DEBUG and e.traceback: +

Traceback:

+
{{e.traceback}}
+ %%end + + +%%except ImportError: + ImportError: Could not generate the error page. Please add bottle to + the import path. +%%end +""" % __name__ + +#: A thread-safe instance of :class:`LocalRequest`. If accessed from within a +#: request callback, this instance always refers to the *current* request +#: (even on a multi-threaded server). +request = LocalRequest() + +#: A thread-safe instance of :class:`LocalResponse`. It is used to change the +#: HTTP response for the *current* request. +response = LocalResponse() + +#: A thread-safe namespace. Not used by Bottle. +local = threading.local() + +# Initialize app stack (create first empty Bottle app now deferred until needed) +# BC: 0.6.4 and needed for run() +apps = app = default_app = AppStack() + +#: A virtual package that redirects import statements. +#: Example: ``import bottle.ext.sqlite`` actually imports `bottle_sqlite`. +ext = _ImportRedirect('bottle.ext' if __name__ == '__main__' else + __name__ + ".ext", 'bottle_%s').module + + +def _main(argv): # pragma: no coverage + args, parser = _cli_parse(argv) + + def _cli_error(cli_msg): + parser.print_help() + _stderr('\nError: %s\n' % cli_msg) + sys.exit(1) + + if args.version: + print('Bottle %s' % __version__) + sys.exit(0) + if not args.app: + _cli_error("No application entry point specified.") + + sys.path.insert(0, '.') + sys.modules.setdefault('bottle', sys.modules['__main__']) + + host, port = (args.bind or 'localhost'), 8080 + if ':' in host and host.rfind(']') < host.rfind(':'): + host, port = host.rsplit(':', 1) + host = host.strip('[]') + + config = ConfigDict() + + for cfile in args.conf or []: + try: + if cfile.endswith('.json'): + with open(cfile, 'rb') as fp: + config.load_dict(json_loads(fp.read())) + else: + config.load_config(cfile) + except configparser.Error as parse_error: + _cli_error(parse_error) + except IOError: + _cli_error("Unable to read config file %r" % cfile) + except (UnicodeError, TypeError, ValueError) as error: + _cli_error("Unable to parse config file %r: %s" % (cfile, error)) + + for cval in args.param or []: + if '=' in cval: + config.update((cval.split('=', 1),)) + else: + config[cval] = True + + run(args.app, + host=host, + port=int(port), + server=args.server, + reloader=args.reload, + plugins=args.plugin, + debug=args.debug, + config=config) + + +if __name__ == '__main__': # pragma: no coverage + _main(sys.argv) diff --git a/pcleaner/_testbed/testbed/experiments.py b/pcleaner/_testbed/testbed/experiments.py new file mode 100644 index 00000000..e630487b --- /dev/null +++ b/pcleaner/_testbed/testbed/experiments.py @@ -0,0 +1,2285 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/experiments.ipynb. + +# %% ../nbs/experiments.ipynb 1 +from __future__ import annotations + + +# %% auto 0 +__all__ = ['CM', 'SubjIdT', 'RunIdT', 'SubjSpecT', 'ImgIdT', 'ImgSpecT', 'BoxIdT', 'remove_multiple_whitespaces', + 'postprocess_ocr', 'accuracy_ocr_naive', 'accuracy_ocr_difflib', 'ground_truth_path', 'read_ground_truth', + 'dilate_by_fractional_pixel', 'extract_text', 'lang2pcleaner', 'lang2tesseract', 'CropMethod', + 'crop_by_image', 'crop_by_extracted', 'ExperimentSubject', 'Result', 'ExperimentRun', 'ExperimentContext', + 'ImageContext', 'ResultOCR', 'ResultOCRExtracted', 'ResultSet', 'ResultSetDefault', 'resultset_to_dict', + 'dict_to_resultset', 'OCRModel', 'OCRExperimentRun', 'OCRExperimentContext', 'SimpleResultVisor', + 'RunSelector', 'MessageVisor', 'StatusVisor', 'OCRModelSelector', 'DisplayOptions', 'ContentSelector', + 'ImageSelector', 'OCRContextVisor', 'ImageContextVisor', 'ExperimentOCR', 'ExperimentOCRMethod', + 'ResultVisor', 'ExperimentVisor', 'ExperimentsVisor'] + +# %% ../nbs/experiments.ipynb 11 +import contextlib +import dataclasses +import datetime +import difflib +import functools +import json +import os +import shutil +import tempfile +from collections import defaultdict +from enum import Enum +from pathlib import Path +from typing import Any +from typing import Callable +from typing import cast +from typing import Mapping +from typing import TypeAlias + +import fastcore.all as FC +import ipywidgets as W +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import pcleaner.config as cfg +import pcleaner.ctd_interface as ctm +import pcleaner.image_ops as ops +import pcleaner.ocr.ocr as ocr +import pcleaner.structures as st +import torch +import traitlets as T +from IPython.display import clear_output +from IPython.display import display +from IPython.display import HTML +from loguru import logger +from pcleaner.ocr.ocr_tesseract import TesseractOcr +from PIL import Image +from PIL import ImageFilter +from rich.console import Console +from tqdm.notebook import tqdm + + +# %% ../nbs/experiments.ipynb 12 +from pcleaner._testbed.testbed.helpers import * +from pcleaner._testbed.testbed.ocr_metric import * +from pcleaner._testbed.testbed.visor import ContextVisor +from pcleaner._testbed.testbed.visor import Spinner +import pcleaner._testbed.testbed.web_server as web_server + + +# %% ../nbs/experiments.ipynb 16 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% ../nbs/experiments.ipynb 19 +os.environ['USE_PIL'] = 'False' +os.environ['USE_TUNNEL'] = 'False' +SERVER = None + + +# %% ../nbs/experiments.ipynb 55 +def remove_multiple_whitespaces(text): + return ' '.join(text.split()) + + +def postprocess_ocr(text): + "Basic postprocessing for English Tesseract OCR results." + return ' '.join(remove_multiple_whitespaces(text).splitlines()).capitalize() + +def accuracy_ocr_naive(text, ground_truth): + return sum(1 for a, b in zip(text, ground_truth) if a == b) / len(text) + + +def accuracy_ocr_difflib(text, ground_truth): + """ + Calculates the OCR accuracy based on the similarity between the OCR text and the ground truth text, + using difflib's SequenceMatcher to account for differences in a manner similar to git diffs. + + :param text: The OCR-generated text. + :param ground_truth: The ground truth text. + :return: A float representing the similarity ratio between the OCR text and the ground truth, + where 1.0 is identical. + """ + # Initialize the SequenceMatcher with the OCR text and the ground truth + matcher = difflib.SequenceMatcher(None, text, ground_truth) + + # Get the similarity ratio + similarity_ratio = matcher.ratio() + + return similarity_ratio + +# %% ../nbs/experiments.ipynb 57 +def ground_truth_path(page_data: st.PageData): + path = Path(page_data.original_path) + return path.with_stem(path.stem + '_gt').with_suffix('.txt') + + +def read_ground_truth(page_data: st.PageData, root_dir: Path): + gts_path = root_dir / ground_truth_path(page_data) + if gts_path.exists(): + gts = gts_path.read_text(encoding="utf-8").splitlines() + else: + gts = ["" for _ in range(len(page_data.boxes))] + return gts + + +# %% ../nbs/experiments.ipynb 59 +def dilate_by_fractional_pixel(image, dilation_fraction, filter_base_size=3): + """ + Dilates an image by a specified fractional pixel amount. The function calculates + the necessary scaling factor and filter size based on the desired dilation fraction. + + :param image: A PIL Image object (1-bit mode). + :param dilation_fraction: The desired fractional pixel amount for dilation (e.g., 0.2). + :param filter_base_size: The base size of the dilation filter to apply on the scaled image. + This size is adjusted based on the scaling factor to achieve the + desired dilation effect. + :return: A PIL Image object after dilation, converted back to grayscale. + """ + from PIL.Image import Resampling + # Calculate the scale factor based on the desired dilation fraction + scale_factor = int(1 / dilation_fraction) + + # Adjust the filter size based on the scale factor + # This ensures the dilation effect is proportional to the desired fraction + filter_size = max(1, filter_base_size * scale_factor // 5) + + # Convert the image to grayscale for more nuanced intermediate values + image_gray = image.convert("L") + + # Resize the image to a larger size using bicubic interpolation + larger_size = (int(image.width * scale_factor), int(image.height * scale_factor)) + image_resized = image_gray.resize(larger_size, Resampling.BICUBIC) + + # Apply the dilation filter to the resized image + dilated_image = image_resized.filter(ImageFilter.MaxFilter(filter_size)) + + # Resize the image back to its original size using bicubic interpolation + image_dilated_fractional_pixel = dilated_image.resize(image.size, Resampling.BICUBIC) + + return image_dilated_fractional_pixel + + +# %% ../nbs/experiments.ipynb 60 +def extract_text(image, text_mask, box): + cropped_image = crop_box(box, image) + cropped_mask = crop_box(box, text_mask) + extracted = ops.extract_text(cropped_image, cropped_mask) + return cropped_image, cropped_mask, extracted + + +# %% ../nbs/experiments.ipynb 62 +_lang2pcleaner = {'English': st.DetectedLang.ENG, 'Japanese': st.DetectedLang.JA, 'Spanish': st.DetectedLang.ENG, + 'French':st.DetectedLang.ENG} +# _lang2tesseract = {'English': 'eng', 'Japanese': 'jpn'} +_lang2tesseract = {'English': 'eng', 'Japanese': 'jpn_vert', 'Spanish': 'spa', 'French': 'fra'} + + +# %% ../nbs/experiments.ipynb 63 +def lang2pcleaner(lang: str): + return _lang2pcleaner[lang] + +def lang2tesseract(lang: str): + return _lang2tesseract[lang] + + +# %% ../nbs/experiments.ipynb 66 +class CropMethod(Enum): + INITIAL_BOX = 'Initial box' + DEFAULT = 'Default' + DEFAULT_GREY_PAD = 'Default, grey pad' + PADDED_4 = 'Padded 4px' + PADDED_8 = 'Padded 8px' + EXTRACTED_INIT_BOX = 'Extracted, init box' + PADDED_4_EXTRACTED = 'Padded 4, extracted' + PADDED_8_EXTRACTED = 'Padded 8, extracted' + PADDED_8_DILATION_1 = 'Padded 8, dilation 1' + PAD_8_FRACT_0_5 = 'Pad 8, fract. 0.5' + PAD_8_FRACT_0_2 = 'Pad 8, fract. 0.2' + + @classmethod + def __display_names__(cls): + return dict( + zip([_.value for _ in cls], + cls)) + + +CM = CropMethod + +_IMAGE_METHODS = [CM.INITIAL_BOX, CM.DEFAULT, CM.DEFAULT_GREY_PAD, + CM.PADDED_4, CM.PADDED_8] +_EXTRACTED_METHODS = [CM.EXTRACTED_INIT_BOX, CM.PADDED_4_EXTRACTED, + CM.PADDED_8_EXTRACTED, CM.PADDED_8_DILATION_1, + CM.PAD_8_FRACT_0_5, CM.PAD_8_FRACT_0_2] + + +def crop_by_image(method: CM, + box: st.Box, + base: Image.Image, + preproc: cfg.PreprocessorConfig, + ): + image = None + match method: + case CM.INITIAL_BOX : + image = crop_box(box, base) + case CM.DEFAULT: + padded2_4 = ( + box.pad(preproc.box_padding_initial, base.size).right_pad( + preproc.box_right_padding_initial, base.size)) + image = crop_box(padded2_4, base) + case CM.DEFAULT_GREY_PAD: + image = crop_box(box, base) + image = ops.pad_image(image, 8, fill_color=(128, 128, 128)) + case CM.PADDED_4: + padded4 = box.pad(4, base.size) + image = crop_box(padded4, base) + case CM.PADDED_8: + padded4 = box.pad(8, base.size) + image = crop_box(padded4, base) + case _: pass + return image + + +def crop_by_extracted(method: CM, + box: st.Box, + base: Image.Image, + mask: Image.Image, + cropped_image_path: Path, + cropped_mask_path: Path, + dilated: dict[float, Image.Image] + ): + cropped_image, cropped_mask, image = None, None, None + if method in _EXTRACTED_METHODS: + if not cropped_image_path.exists() or not cropped_mask_path.exists(): + match method: + case CM.EXTRACTED_INIT_BOX: + cropped_image, cropped_mask, image = extract_text(base, mask, box) + case CM.PADDED_4_EXTRACTED: + padded4 = box.pad(4, base.size) + cropped_image, cropped_mask, image = extract_text(base, mask, padded4) + case CM.PADDED_8_EXTRACTED: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text(base, mask, padded8) + case CM.PADDED_8_DILATION_1: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text( + base, dilated[1], padded8) + case CM.PAD_8_FRACT_0_5: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text( + base, dilated[0.5], padded8) + case CM.PAD_8_FRACT_0_2: + padded8 = box.pad(8, base.size) + cropped_image, cropped_mask, image = extract_text( + base, dilated[0.2], padded8) + case _: pass + + return image, cropped_image, cropped_mask + + + +# %% ../nbs/experiments.ipynb 68 +SubjIdT: TypeAlias = int +RunIdT: TypeAlias = str +SubjSpecT: TypeAlias = SubjIdT | str | Path + + +class ExperimentSubject: + exp: ExperimentContext + idx: SubjIdT + + def setup(self, exp: ExperimentContext, idx: Any, *args, **kwargs): + self.exp = exp + self.idx = cast(SubjIdT, exp.normalize_idx(idx)) + return self + + def __new__(cls, exp: ExperimentContext, idx: Any, *args, **kwargs): + idx = exp.normalize_idx(idx) + self = exp.subject_context(idx) + if self is None: + self = super().__new__(cls) + self = exp.setup_subject_context(idx, self, *args, **kwargs) + if self is None: + raise ValueError(f"Can't create new subject with idx: {idx}: out of range") + return self + + +class Result: + subject_ctx: ExperimentSubject + +class ExperimentRun: + "A set of experiment results obtained with the same parameters." + exp: ExperimentContext + name: RunIdT + dt: datetime.datetime + + def setup(self, exp: ExperimentContext, name: RunIdT, *args, **kwargs): + self.exp = exp + self.name = name + return self + + @classmethod + def setup_run_name(cls, name: RunIdT, dt: datetime.datetime): + return f"{name}_{dt.strftime('%Y%m%d-%H%M%S')}" + + def setup_run(self, args, **kwargs): + pass + def before_result(self, *args, **kwargs): + pass + def after_result(self, result: Result, *args, **kwargs): + pass + + def __new__(cls, exp: ExperimentContext, name: RunIdT, *args, **kwargs): + self = exp.experiment_run(name) + if self is None: + self = super().__new__(cls) + self = exp.setup_experiment_run(name, self, *args, **kwargs) + return self + + +class ExperimentContext(T.HasTraits): + "Class to maintain shared state across all file-based experiments within the experiment domain." + name: str + _results: dict[RunIdT, dict[SubjIdT, Any]] + + _dirty = T.Bool(default_value=False) + + CACHE_DIR_NAME: str = 'cache' + SOURCE_DIR_NAME: str = 'source' + EXP_DIR: Path = Path("../experiment") + + subject_cls: Callable[..., ExperimentSubject] + def subject_factory(self) -> Callable[..., ExperimentSubject]: return type(self).subject_cls + + def normalize_idx(self, idx: SubjSpecT) -> SubjIdT | None: + nidx = None + if isinstance(idx, int) and idx < self.subject_count: + nidx = idx + elif isinstance(idx, str): + try: + nidx = [_.name for _ in self._paths].index(idx) + except Exception: + pass + elif isinstance(idx, Path): + if idx in self._paths: + nidx = self._paths.index(idx) + return nidx + + def path_from_idx(self, idx: SubjSpecT): + "Relative path to the subject with the given index." + _idx = self.normalize_idx(idx) + if _idx is None: + raise ValueError(f"{_idx} not found in context.") + path = Path(self._paths[_idx]) + if not path.resolve().exists(): + raise ValueError(f"{path} not found in context.") + return path + + @property + def subject_count(self): return len(self._paths) + + @property + def run_names(self): + return list(self._exp_runs.keys()) + + @property + def root_dir(self): return self._root + # Relative paths to `root_dir` + @property + def cache_dir(self): return Path(self.CACHE_DIR_NAME) + @property + def source_dir(self): return Path(self.SOURCE_DIR_NAME) + @functools.lru_cache() + def _subject_cache_dir(self, idx: SubjIdT): + path = self.path_from_idx(idx) + subject_cache_dir = self.cache_dir / path.stem + self.final(subject_cache_dir).mkdir(parents=True, exist_ok=True) + return subject_cache_dir + def subject_cache_dir(self, idx: SubjSpecT): + "Folder to cache and save subject results. Create if needed." + return self._subject_cache_dir(idx) + def final(self, path: Path | str): + """`path` relative to the root of the experiment. + If `path` is absolute, it must be in the experiment directory. + """ + if isinstance(path, str): + path = Path(path) + if path.is_absolute(): + try: + path = path.relative_to(self.root_dir.resolve()) + except Exception: + return Path('_not_found_/'+path.name) + return self.root_dir / path + + def empty_cache(self, idx: SubjIdT | None = None): + if idx is None: + cache_dir = self.final(self.cache_dir) + shutil.rmtree(cache_dir, ignore_errors=True) + cache_dir.mkdir(parents=True, exist_ok=True) + else: + subject_cache_dir = self.final(self.subject_cache_dir(idx)) + shutil.rmtree(subject_cache_dir, ignore_errors=True) + subject_cache_dir.mkdir(parents=True, exist_ok=True) + def empty_cache_warning(self, + idx: SubjIdT | None=None, *, warn: bool=True, out: W.Output | None=None): + def on_confirm_clicked(b): + try: + self.empty_cache(idx) + print("Cache cleared successfully.") + except Exception as e: + print(f"Failed to clear cache: {e}") + finally: + for widget in confirmation_box.children: + widget.close() + + def on_cancel_clicked(b): + print("Cache clear cancelled.") + for widget in confirmation_box.children: + widget.close() + + if out is None: + out = W.Output() + cache_name = '' if idx is None else f" of '{self.subject_cache_dir(idx).name}'" + text = f"Are you sure you want to clear the cache{cache_name}? This action cannot be undone." + with out: + if FC.IN_NOTEBOOK: + confirm_button = W.Button(description="Confirm") + cancel_button = W.Button(description="Cancel") + confirm_button.on_click(on_confirm_clicked) + cancel_button.on_click(on_cancel_clicked) + label = W.Label(text, style={'font_size': '1.25em', 'font_weight': 'bold'}) + confirmation_box = W.VBox([label, W.HBox([confirm_button, cancel_button])]) + display(confirmation_box) + else: + on_confirm_clicked(None) + return out + + def subject_context(self, idx: SubjSpecT): + "Cached subject." + if (nidx := self.normalize_idx(idx)) is None: + return None + return self._subjects.get(nidx) + def setup_subject_context(self, idx: SubjIdT, /, subject: ExperimentSubject, *args, **kwargs): + "Setup and set cached subject." + if idx < 0 or idx >= self.subject_count: + raise ValueError(f"Can't create new subject with idx: {idx}: out of range") + subject.setup(self, idx, *args, **kwargs) + self._subjects[idx] = subject + return subject + + def experiment_run(self, name: RunIdT | None = None): + "Experiment run `name` or the last one if `name` is None or None" + if name: + return self._exp_runs.get(name) + if self._exp_runs: + return self._exp_runs[list(self._exp_runs.keys())[-1]] + return None + def setup_experiment_run(self, name: str, run: ExperimentRun, *args, **kwargs): + "Set or replace cached experiment run." + run.setup(self, name, *args, **kwargs) + self._exp_runs[name] = run + return run + + def _reset_(self): + # start over. Note: doesn't change _dirty status, intended for use in testing. + self._subjects.clear() + self._subject_cache_dir.cache_clear() + + def cleanup_model(self): + pass + + def __init__(self, name: str, paths: list[Path], root: Path | None = None, run_name: str = 'run1'): + self.name = name + self._root = root or type(self).EXP_DIR + self._paths = paths # relative paths wrt self._root + self._subjects: dict[SubjIdT, ExperimentSubject] = {} + self._exp_runs: dict[str, ExperimentRun] = {} + self._results = {} + # default run + ExperimentRun(self, run_name) + + +# %% ../nbs/experiments.ipynb 78 +ImgIdT = SubjIdT +ImgSpecT: TypeAlias = ImgIdT | str | Path + + +class ImageContext(ExperimentSubject): + """ + A utility class to maintain image state for a ExperimentContext. + + Attributes: + json_data (dict): JSON data loaded from cached files. + page_data (st.PageData): PanelClaner page data. + base_image (Image.Image): The base image loaded from the cache. + mask (Image.Image): The mask image used for text detection. + gts (list[str]): Ground truth data for the text in the images. + mask_dilated1 (Image.Image): Image mask dilated by 1 pixel. + mask_dilated05 (Image.Image): Image mask dilated by 0.5 pixels. + mask_dilated02 (Image.Image): Image mask dilated by 0.2 pixels. + + """ + exp: ExperimentContext + idx: ImgIdT + base_image: Image.Image + mask: Image.Image + json_data: dict | None + page_data: st.PageData + _page_lang: str + _gts: list[str] + _mask_dilated1: Image.Image | None + _mask_dilated05: Image.Image | None + _mask_dilated02: Image.Image | None + + def to_dict(self): + return { + 'image_idx': self.idx, + 'page_lang': self.page_lang, + } + + @property + def image_idx(self): return self.idx + @property + def cache_dir(self): + "Relative path of the cache directory for this image." + return self.exp.subject_cache_dir(self.idx) + + @property + def image_info(self): + img = self.base_image + w, h = img.size + print_size_in = size(w, h, 'in', 300) + print_size_cm = size(w, h, 'cm', 300) + required_dpi = dpi(w, h, 'Modern Age') + return (w, h), print_size_in, print_size_cm, required_dpi + + @property + def original_image_path(self): return Path(self.page_data.original_path) + @property + def image_path(self): return Path(self.page_data.image_path) + @property + def mask_path(self): return Path(self.page_data.mask_path) + @property + def image_boxes_path(self): + exp, img_path = self.exp, self.image_path + if exp.final( p := img_path.with_stem(img_path.stem + '_boxes')).exists(): + return p + _, p = page_boxes(self.page_data, exp.final(img_path)) + return p.relative_to(exp.root_dir) + + # Base image properties + @property + def image_name(self): return self.original_image_path.name + @property + def image_size(self): return self.base_image.size + @property + def image_dim(self):return size(*self.image_size) + @property + def image_dpi(self): return dpi(*self.image_size) + @property + def image_print(self): + return self.image_size, self.image_dim, self.image_dpi + @property + def image_name_rich(self): + siz, dim, res = self.image_print + return f"{self.image_name} - {siz[0]}x{siz[1]} px: {dim[0]:.2f}x{dim[1]:.2f}\" @ {res:.2f} dpi" + + def setup_page_lang(self, page_lang: str | None = None): + path = self.exp.final(self.page_data.original_path).with_suffix('.json') + metadata = json.load(open(path)) if path.exists() else {} + if 'lang' in metadata and (page_lang == metadata['lang'] or page_lang is None): + self._page_lang = metadata['lang'] + return + self._page_lang = metadata['lang'] = page_lang or 'English' + json.dump(metadata, open(path, 'w'), indent=2) + @property + def page_lang(self): + if self._page_lang == None: + self.setup_page_lang() + return self._page_lang + + @property + def boxes(self): return self.page_data.boxes + + def setup_ground_truth(self): + self._gts = read_ground_truth(self.page_data, self.exp.root_dir) + @property + def gts(self): + if self._gts is None: + self.setup_ground_truth() + return self._gts + + @functools.lru_cache(typed=True) + def dilated_mask(self, fraction: float): + return dilate_by_fractional_pixel(self.mask, fraction) + + def mask_dilated1(self): + if self._mask_dilated1 is None: + self._mask_dilated1 = self.mask.filter(ImageFilter.MaxFilter(3)) + return self._mask_dilated1 + + def mask_dilated05(self): + if self._mask_dilated05 is None: + self._mask_dilated05 = self.dilated_mask(0.5) + return self._mask_dilated05 + + def mask_dilated02(self): + if self._mask_dilated02 is None: + self._mask_dilated02 = self.dilated_mask(0.2) + return self._mask_dilated02 + + def dilated(self): + return {1: self.mask_dilated1(), + 0.5: self.mask_dilated05(), + 0.2: self.mask_dilated02(),} + + def __new__(cls, + exp: ExperimentContext, + idx: ImgSpecT, + *args, **kwargs) -> 'ImageContext': + return super().__new__(cls, exp, idx, *args, **kwargs) # type: ignore + + +# %% ../nbs/experiments.ipynb 80 +@dataclasses.dataclass +class ResultOCR(Result): + subject_ctx: ImageContext + block_idx: int + ocr: str | None = None + image: Image.Image | None = None + description: str = dataclasses.field(default='', kw_only=True) + + def __post_init__(self): + self._acc = None + if self.image is None: + cache_path = self.image_ctx.exp.final(self.cache_path()) + if cache_path.exists(): + self.image = Image.open(cache_path) + + @property + def image_ctx(self): return self.subject_ctx + + @property + def acc(self): + if self.ocr is not None: + self._acc = accuracy_ocr_difflib(self.ocr, self.image_ctx.gts[self.block_idx]) + return self._acc + @property + def suffix(self): return f"{self.block_idx}_{self.description}" + + def cache_path(self, suffix: str | None = None): + img_ctx = self.image_ctx + suffix = self.suffix + (('_'+suffix) if suffix else '') + img_name = img_ctx.image_path.stem + return img_ctx.cache_dir / '.crop' / f"{img_name}_{suffix}.png" + + def cache_image(self, image: Image.Image | None = None, suffix: str | None = None): + image = image or (self.image if not suffix else None) + box_image_path = self.cache_path(suffix) + final_path = self.image_ctx.exp.final(box_image_path) + if image and not final_path.exists(): + final_path.parent.mkdir(parents=True, exist_ok=True) + image.save(final_path) + return box_image_path + + def to_dict(self): + d = dataclasses.asdict(self) + d['image_ctx'] = d['image'] = d['page_data'] = d['gts'] = None + return d + + # @classmethod + # def from_dict(cls, d: dict, page_data: st.PageData, gts: list[str]): + # return cls(**(d | {'page_data':page_data, 'gts':gts})) + + def __repr__(self): + return f"{type(self).__name__}#block {self.block_idx:02}: {self.acc:.2f}||{self.ocr}" + + def display(self): + visor = getattr(self, '_default_visor_type', None) + display(HTML( + visor(self).as_html() if visor else f"{self}" + )) + def _ipython_display_(self): self.display() + + +class ResultOCRExtracted(ResultOCR): + def __repr__(self): return super().__repr__() + + +# %% ../nbs/experiments.ipynb 82 +BoxIdT: TypeAlias = int + +class ResultSet(dict[BoxIdT, dict[CropMethod, ResultOCR]]): ... + +class ResultSetDefault(defaultdict[BoxIdT, dict[CropMethod, ResultOCR]]): ... + +def resultset_to_dict(results: ResultSet) -> dict[BoxIdT, dict[str, str]]: + d = {} + for box, box_methods in results.items(): + for method, result in box_methods.items(): + if box not in d: + d[box] = {} + d[box][method.name] = result.ocr + return d + +def dict_to_resultset( + image_idx: ImgIdT, + results_dict: dict[str, dict[str, str]], + result_factory: Callable + ) -> ResultSetDefault: + results = ResultSetDefault(dict[CropMethod, ResultOCR]) + for box_idx, box_methods in results_dict.items(): + box_idx = int(box_idx) + for method, ocr in box_methods.items(): + m = CM[method] + results[box_idx][m] = result_factory(image_idx, box_idx, m, ocr) + return results + + +# %% ../nbs/experiments.ipynb 84 +class OCRModel(Enum): + TESSERACT = 0 + IDEFICS = 1 + @staticmethod + def __display_names__() -> dict[str, OCRModel]: + return dict( + zip("Tesseract, Idefics".split(', '), + OCRModel)) + + +class OCRExperimentRun(ExperimentRun): ... + + +class OCRExperimentContext(ExperimentContext): + """ + A utility class to maintain shared state across all experiments within OCR domain. + This class encapsulates state necessary for conducting PanelCleaner OCR experiments. + """ + + config: cfg.Config + image_paths: list[Path] + ocr_model: str + force_PIL: bool + use_tunnel: bool + server: web_server.WebServer | None + + # ExperimentRun name -> Image index -> Box index -> Crop method -> Result + _results: dict[RunIdT, dict[ImgIdT, ResultSet]] + + _running = T.Bool(False) + + engines = { + 'Tesseract': cfg.OCREngine.TESSERACT, + 'Idefics': None, + 'manga-ocr': cfg.OCREngine.MANGAOCR} + + + @classmethod + def get_config(cls) -> cfg.Config: + config = cfg.load_config() + profile = config.current_profile + preprocessor_conf = profile.preprocessor + # Modify the profile to OCR all boxes. + # Make sure OCR is enabled. + preprocessor_conf.ocr_enabled = True + # Make sure the max size is infinite, so no boxes are skipped in the OCR process. + preprocessor_conf.ocr_max_size = 10**10 + # Make sure the sus box min size is infinite, so all boxes with "unknown" language are skipped. + preprocessor_conf.suspicious_box_min_size = 10**10 + # Set the OCR blacklist pattern to match everything, so all text gets reported in the analytics. + preprocessor_conf.ocr_blacklist_pattern = ".*" + + # Load models if needed + gpu = torch.cuda.is_available() or torch.backends.mps.is_available() + model_path = config.get_model_path(gpu) + if model_path is None: + # don't mess with normal PanelCleaner, download models directly + import pcleaner.model_downloader as md + model_dir = config.get_model_cache_dir() + config.default_torch_model_path = md.download_torch_model(model_dir) + config.default_cv2_model_path = md.download_cv2_model(model_dir) + + return config + + @functools.lru_cache() + def mocr(self, lang: str): + engine = self.engines[self.ocr_model] + ocr_processor = ocr.get_ocr_processor(True, engine) + proc = ocr_processor[lang2pcleaner(lang)] + if isinstance(proc, TesseractOcr): + proc.lang = lang2tesseract(lang) + return proc + + @contextlib.contextmanager + def running(self, value: bool): + _running = self._running + self._running = value + yield + self._running = _running + + def ocr_box(self, result: ResultOCR, lang: str): + assert result.image is not None + text = self.mocr(lang)(result.image) + result.ocr = postprocess_ocr(text) + self._dirty = True + return result + + image_cache_dir = ExperimentContext.subject_cache_dir + + def _detect_text(self, img_path: Path, dest_dir: Path): + config = self.config + root_dir = self.root_dir + image_name = img_path.stem + pfl = config.current_profile + gpu = torch.cuda.is_available() or torch.backends.mps.is_available() + model_path = config.get_model_path(gpu) + json_data = None + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + ctm.model2annotations(pfl.general, pfl.text_detector, model_path, [img_path], temp_path) + contents = list(temp_path.glob(f"*{image_name}*")) + json_path = [_ for _ in contents if _.suffix == '.json'][0] + json_data = json.loads(json_path.read_text(encoding="utf-8")) + # we don't need unique names for this tests, strip uuids + for temp_file in contents: + if temp_file.suffix == ".json": continue + new_path = dest_dir / strip_uuid(temp_file.name) + shutil.copy(temp_file, new_path) + if 'mask' in temp_file.name: + json_data['mask_path'] = str(new_path.relative_to(root_dir)) + elif new_path.stem == image_name: + json_data['image_path'] = str(new_path.relative_to(root_dir)) + json_data['original_path'] = str(img_path.relative_to(root_dir)) + json.dump(json_data, open(dest_dir / f"{image_name}#raw.json", "w"), indent=2) + return json_data + + @functools.lru_cache() + def _load_page_data(self, image_idx: ImgIdT): + root_dir = self.root_dir + dest_dir = self.final(self.image_cache_dir(image_idx)) + img_path = self.final(self.image_paths[image_idx]) + image_name = img_path.stem + # read cached json + jsons = [_ for _ in dest_dir.glob("*#raw.json") if image_name in _.stem] + assert len(jsons) <= 1 + # generate text boxes if needed + if not jsons: + json_data = self._detect_text(img_path, dest_dir) + else: + json_file_path = jsons[0] + json_data = json.loads(json_file_path.read_text(encoding="utf-8")) + + if not all((root_dir / json_data[_]).exists() + for _ in ("image_path", "mask_path", "original_path")): + raise ValueError(f"Inconsistent page_data of {img_path}") + + page_data = st.PageData( + json_data["image_path"], json_data["mask_path"], + json_data["original_path"], json_data["scale"], + [st.Box(*data["xyxy"]) for data in json_data["blk_list"]], + [], [], []) + # Merge boxes that have mutually overlapping centers. + page_data.resolve_total_overlaps() + return json_data, page_data + + def page_data(self, image_idx: int): + _, page_data = self._load_page_data(image_idx) + return page_data + def json_data(self, image_idx: int): + json_data, _ = self._load_page_data(image_idx) + return json_data + + def path_from_idx(self, image_idx: ImgSpecT, cached: bool = False): + "(Relative path) to subject image. Raises ValueError if not found." + _idx = self.normalize_idx(image_idx) + if _idx is None: + raise ValueError(f"{_idx} not found in context.") + if cached: + page_data = self.page_data(_idx) # load if needed + path = Path(page_data.image_path) + else: + path = self.image_paths[_idx] + if not self.final(path).exists(): + raise ValueError(f"{path} not found in context.") + return path + + def cached_image(self, image_idx: ImgSpecT): + "Relative path to cached image." + _idx = self.normalize_idx(image_idx) + if _idx is None: + return None + page_data = self.page_data(_idx) # load if needed + path = Path(page_data.image_path) + if not self.final(path).exists(): + return None + return path + + def image_context(self, image_idx: ImgSpecT) -> ImageContext | None: + "Cached image context." + return cast(ImageContext, self.subject_context(image_idx)) + + def display_image(self, image_path: Path | str): + "Return a PIL image, a url, or the given (final) path." + final_image_path = self.final(image_path) + if self.force_PIL: + return Image.open(final_image_path) + elif self.use_tunnel: + if (server := self.server) is not None and (url := server.unc_share) is not None: + return url/final_image_path.relative_to(self.root_dir) + return final_image_path + DI = display_image + + def _update_results(self, run_name: str, img_idx: ImgIdT, results: ResultSetDefault): + self._results[run_name][img_idx] = cast(ResultSet, results) + + def _result_from(self, + image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None): + img_ctx = ImageContext(self, image_idx) + extracted = method in _EXTRACTED_METHODS + result_cls = ResultOCRExtracted if extracted else ResultOCR + result = result_cls(img_ctx, int(box_idx), None, None, description=f"{method.value}") + if ocr is not None: + result.ocr = ocr + return result + + def result(self, + run_name: str, + image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, + ocr: bool=True, + rebuild: bool=False) -> ResultOCR | None: + _result = self._results[run_name][image_idx][box_idx].get(method) + if not rebuild and _result is not None: + return _result + + result: ResultOCR = self._result_from(image_idx, box_idx, method) + image, cropped_image, cropped_mask = result.image, None, None + img_ctx = ImageContext(self, image_idx) + base_image = img_ctx.base_image + box = img_ctx.boxes[box_idx] + if image is None and method in _IMAGE_METHODS: + image = crop_by_image( + method, box, base_image, self.config.current_profile.preprocessor) + + if image is None and method in _EXTRACTED_METHODS: + mask = img_ctx.mask + cropped_image_path = result.cache_image(cropped_image, "cropped") + cropped_mask_path = result.cache_image(cropped_mask, "mask") + if not cropped_image_path.exists() or not cropped_mask_path.exists(): + image, cropped_image, cropped_mask = crop_by_extracted( + method, box, base_image, mask, + cropped_image_path, cropped_mask_path, img_ctx.dilated()) + + assert image is not None + if result.image is None: + result.image = image + result.cache_image() + if cropped_image is not None: + result.cache_image(cropped_image, "cropped") + if cropped_mask is not None: + result.cache_image(cropped_mask, "mask") + + exp_run = OCRExperimentRun(self, run_name) + if ocr: + exp_run.before_result(result) + result = self.ocr_box(result, img_ctx.page_lang) + exp_run.after_result(result) + self._results[run_name][image_idx][box_idx][method] = result + self._dirty = True + return result + + def results(self, run_name: str | None = None, img_idx: ImgIdT | None = None): + if run_name is None: return self._results + if img_idx is None: return self._results[run_name] + return self._results[run_name][img_idx] + def run_results(self, run_name: str): + return cast(dict[ImgIdT, ResultSet], self.results(run_name)) + def image_results(self, run_name: str, img_idx: ImgIdT): + return cast(ResultSet, self.results(run_name, img_idx)) + def box_results(self, run_name: str, img_idx: ImgIdT, box_idx: BoxIdT): + return cast(ResultSet, self.results(run_name, img_idx))[box_idx] + def method_results(self, run_name: str, img_idx: ImgIdT, method: CropMethod): + image_results = self.image_results(run_name, img_idx) + return {i: box_results.get(method) for i,box_results in image_results.items()} + + def _reset_results(self): + results = defaultdict(lambda: defaultdict(lambda: ResultSetDefault(dict))) + self._results = cast(dict[str, dict[ImgIdT, ResultSet]], results) + def _reset_results_(self, + run_name: str | None = None, + image_idx: int | None = None, + box_idx: int | None = None, + method: CropMethod | None = None): + if run_name is None and image_idx is None and box_idx is None and method is None: + self._reset_results() + return + results = self._results + models = tuple(results.keys()) if run_name is None else [run_name] if run_name in results else [] + for run_name in models: + img_nodes = results[run_name] + imgs = (tuple(img_nodes.keys()) + if image_idx is None else [image_idx] if image_idx in img_nodes else []) + for img_idx in imgs: + box_nodes = img_nodes[img_idx] + boxes = (tuple(box_nodes.keys()) + if box_idx is None else [box_idx] if box_idx in box_nodes else []) + for box_idx in boxes: + if method is None: + del box_nodes[box_idx] + else: + methods = box_nodes[box_idx] + if method in methods: + del methods[method] + if not box_nodes[box_idx]: + del box_nodes[box_idx] + if not img_nodes[img_idx]: + del img_nodes[img_idx] + if not results[run_name]: + del results[run_name] + def reset_results(self, + run_name: str | None = None, + image_idx: int | None = None, + box_idx: int | None = None, + method: CropMethod | None = None): + self._reset_results_(run_name, image_idx, box_idx, method) + self._dirty = True + def _reset_(self): + super()._reset_() + self._reset_results_() + self._load_page_data.cache_clear() + self.mocr.cache_clear() + + @classmethod + def get_image_paths(cls, root_dir: Path): + if root_dir is None: return [] + source_dir = root_dir / cls.SOURCE_DIR_NAME + return sorted( + [_.relative_to(root_dir) for _ in source_dir.glob("*") + if _.is_file() and _.suffix.lower() in [".jpg", ".png", ".jpeg"]]) + + def run_to_dict(self, run_name: RunIdT) -> dict[str, dict[BoxIdT, dict[str, str]]]: + "JSON serializable dict of the experiment run" + results = {} + idx2name = {i: p.name for i, p in enumerate(self.image_paths)} + run_results = cast(dict[ImgIdT, ResultSet], self.results(run_name)) + for img_idx, rset in run_results.items(): + results[idx2name[img_idx]] = resultset_to_dict(cast(ResultSet, rset)) + return results + + # def run_to_json(self, run_name: RunIdT): + # data = { + # 'run_name': run_name, + # 'results': self.run_to_dict(run_name), + # } + # fp = self._root / f'{run_name}.json' + # with open(fp, 'w') as f: + # json.dump(data, f, indent=2) + # return fp + + # def save_results(self): + # for run_name, _ in self._exp_runs.items(): + # self.run_to_json(run_name) + + def _load_run_results(self, run_name: str, run_data: dict[str, dict[str, dict[str, str]]]): + self._exp_runs[run_name] = OCRExperimentRun(self, run_name) + name2idx = {p.name: i for i, p in enumerate(self.image_paths)} + for img_name, data in run_data.items(): + img_idx = name2idx.get(img_name, None) + if img_idx is None: + logger.warning(f"Image {img_name} not found in context.") + continue + rset: ResultSetDefault = dict_to_resultset( + ImgIdT(img_idx), + data, + result_factory=self._result_from) + self._update_results(run_name, img_idx, rset) + + # def load_results(self): + # for json_path in self.root_dir.glob("*.json"): + # try: + # with open(json_path, 'r') as f: + # data = json.load(f) + # if data.keys() != {'run_name', 'results'}: + # continue + # except Exception as e: + # continue + # self._load_run_results(data) + + def to_dict(self): + data: dict = { + "ocr_model": self.ocr_model, + "runs": (rr := {}) + } + for run_name, _ in self._exp_runs.items(): + rr[run_name] = self.run_to_dict(run_name) + return data + + def to_json(self): + data = self.to_dict() + _ = datetime.datetime.now() + fp = self._root / f'{self.name}.json' + with open(fp, 'w') as f: + json.dump(data, f, indent=2) + return fp + + def _from_json(self): + json_path = self.root_dir / f'{self.name}.json' + if not json_path.exists(): return + try: + with open(json_path, 'r') as f: + data = json.load(f) + except Exception as e: + logger.error(f"Error loading {json_path}: {e}") + return + self.ocr_model = data['ocr_model'] + for run_name, run_results in data['runs'].items(): + self._load_run_results(run_name, run_results) + + @classmethod + def from_json(cls, root_dir: Path, name: str, config: cfg.Config | None = None): + json_path = root_dir / f'{name}.json' + try: + with open(json_path, 'r') as f: + data = json.load(f) + except Exception as e: + logger.error(f"Error loading {json_path}: {e}") + raise e + config = config or cls.get_config() + self = cls(data['ocr_model'], root_dir, config=config) + for run_name, run_results in data['runs'].items(): + self._load_run_results(run_name, run_results) + return self + + def save(self): + fp = self.to_json() + self._dirty = False + return fp + + @classmethod + def load(cls, root_dir: Path, name: str): + return cls.from_json(root_dir, name) + + + def show(self): + config = self.config + gpu = torch.cuda.is_available() or torch.backends.mps.is_available() + model_path = config.get_model_path(gpu) + device = ("mps" if torch.backends.mps.is_available() else "cuda") if model_path.suffix == ".pt" else "cpu" + + config.show() + cprint( + f"{'config cache_dir':>17}: {repr(config.cache_dir)}\n" + f"{'model_path':>17}: {repr(model_path)}\n" + f"{'device':>17}: {repr(device)}") + + cprint( + f"{'force_PIL':>17}: {self.force_PIL}\n" + f"{'use_tunnel':>17}: {self.use_tunnel}\n" + f"{'server_url':>17}: {repr(self.server.unc_share) if self.server else ''}\n" + f"{'experiment dir':>17}: {self.root_dir}\n" + f"{'source_dir':>17}: {self.final(self.source_dir)}\n" + f"{'cache_dir':>17}: {self.final(self.cache_dir)}\n" + ) + + + def __init__(self, + ocr_model: str, + root_dir: Path | str | None = None, + *, + config: cfg.Config | None = None, + server: web_server.WebServer | None = None, + run_name: str = 'Tesseract-crop-post', + load: bool = True): + if root_dir is None: + root_dir = type(self).EXP_DIR + self.config = config or type(self).get_config() + self.ocr_model = ocr_model + root_dir = Path(root_dir) + super().__init__( + ocr_model, self.get_image_paths(root_dir), root=root_dir, run_name=run_name) + self.image_paths = self._paths + self._reset_results() + self._images = self._subjects + use_pil = os.environ['USE_PIL'].lower() == 'true' + self.force_PIL = use_pil + use_tunnel = os.environ['USE_TUNNEL'].lower() == 'true' + self.use_tunnel = use_tunnel + self.server = server or SERVER + if load: + self._from_json() + + +# %% ../nbs/experiments.ipynb 85 +@FC.patch_to(ImageContext) +def setup(self, exp: OCRExperimentContext, image_idx: ImgSpecT, page_lang: str | None = None): + super(type(self), self).setup(exp, image_idx) + self._mask_dilated1 = self._mask_dilated05 = self._mask_dilated02 = None + self.json_data, self.page_data = exp._load_page_data(self.idx) + self.setup_page_lang(page_lang) + self.mask = Image.open(exp.final(self.mask_path)) + self.base_image = Image.open(exp.final(self.image_path)) + self.setup_ground_truth() + + +# %% ../nbs/experiments.ipynb 88 +class SimpleResultVisor: + ctx: ResultOCR + + @classmethod + def diff_tagged(cls, result: ResultOCR): + _, html = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr, False) + return f"{html}" + + def as_html(self): + result = self.ctx + DI = cast(OCRExperimentContext, result.image_ctx.exp).DI + if isinstance(result, ResultOCRExtracted): + return self.as_html_extracted() + has_ocr = result.ocr is not None + acc_html = '' + if has_ocr: + acc_html = f"
{result.acc:.2f}" + html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr) + box_image_path = result.cache_image() + html1 = get_columns_html([[DI(box_image_path)], [(result.ocr or '') + acc_html]]) + if has_ocr: + html2 = f"
{html_str1}
{html_str2}
" + else: + html2 = f"
{html_str1}
" + return html1 + '\n
\n' + html2 + + def as_html_extracted(self): + result = self.ctx + has_ocr = result.ocr is not None + DI = cast(OCRExperimentContext, result.image_ctx.exp).DI + html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr) + if has_ocr: + diff_html = f"
{html_str1}
{html_str2}
" + else: + diff_html = f"
{html_str1}
" + cropped_image_path = result.cache_image(None, "cropped") + cropped_mask_path = result.cache_image(None, "mask") + result_path = result.cache_image() + return '\n
\n'.join([ + get_image_grid_html([ + DI(cropped_image_path), DI(cropped_mask_path), DI(result_path)], 1, 3), + acc_as_html(result.acc) if has_ocr else '', + diff_html + ]) + + def display(self): display(HTML(self.as_html())) + def _ipython_display_(self): self.display() + + def __init__(self, ctx: ResultOCR): + self.ctx = ctx + + +ResultOCR._default_visor_type = SimpleResultVisor # type: ignore + + +# %% ../nbs/experiments.ipynb 107 +class RunSelector(ContextVisor): + def setup_controls(self): + options = self.run_names + w = W.Dropdown( + options=options, + value=self.values['run_name'], + layout={'width': 'fit-content'}, + style={'description_width': 'initial'}) + return {'run_name': w} + + def setup_ui(self): + ctls = self.controls + model_grp = W.HBox([ctls['run_name']]) + model_grp.add_class('model_grp') + ui = W.HBox([*super().comps_ui(), model_grp]) + return ui + + def __init__(self, + exp_ctx: OCRExperimentContext, + run_name: str | None=None, + run_names: list[str] | None = None, + **kwargs + ): + self.run_names: list[str] = run_names or exp_ctx.run_names + super().__init__(exp_ctx, + {'run_name': run_name or self.run_names[0]}) + + +# %% ../nbs/experiments.ipynb 110 +class MessageVisor(ContextVisor): + EMPTY = '' + + # _css = """ + # .message_visor-yXy { + # border: 1px solid red; + # } + # """ + + @property + def msg(self): return self.values['msg'] + + def update_output(self, /, msg: str | None = None, **kwargs): + if msg is not None and msg != self.EMPTY: + cprint(msg) + self.values['msg'] = None + else: + clear_output() + + def setup_style(self): + self.out.add_class('message_visor-yXy') + return super().setup_style() + + def setup_controls(self): + # w = W.Label(value=self.values['msg'] if self.values['msg'] != self.EMPTY else None, + # layout={'width': 'fit-content'}) + return {}#{'msg': w} + + def __init__(self, + msg: str | None = None, + **kwargs + ): + super().__init__(None, + {'msg': msg}, + **kwargs) + + +# %% ../nbs/experiments.ipynb 117 +class StatusVisor(ContextVisor): + ctx: OCRExperimentContext + + @property + def save_button(self) -> W.Button: return self.controls['save'] # type: ignore + @property + def reset_button(self) -> W.Button: return self.controls['reset'] # type: ignore + + def setup_controls(self): + style={'font_size': '1em', 'font_weight': 'bold'} + sw = W.Button(description = 'save', style=style, + layout={'width': '4em'}, + ) + rw = W.Button(description = 'reset', style=style, + layout={'width': '5em', 'margin': '0px 0px 0px 3em'}, + ) + return {'save': sw, 'reset': rw} + + def setup_ux(self): + source = (self.ctx, '_dirty') + target = (self.save_button, 'disabled') + T.dlink(source, target, lambda x: not x) + target = (self.save_button.style, 'button_color') + T.dlink(source, target, lambda x: 'lightblue' if x else None) + + + def __init__(self, exp_ctx: OCRExperimentContext, **kwargs): + super().__init__(exp_ctx, {}, **kwargs) + + +# %% ../nbs/experiments.ipynb 122 +class OCRModelSelector(ContextVisor): + ctx: OCRExperimentContext + + def setup_controls(self): + options = self.models + w = W.Dropdown( + options=options, + value=self.values['model'], + layout={'width': 'fit-content'}, + style={'description_width': 'initial'}) + return {'model': w} + + def setup_ui(self): + ctls = self.controls + model_grp = W.HBox([ctls['model']]) + model_grp.add_class('model_grp') + ui = W.HBox([*super().comps_ui(), model_grp]) + return ui + + def __init__(self, + exp_ctx: OCRExperimentContext, + ocr_model: OCRModel | None=OCRModel.TESSERACT, + ocr_models: dict[str, OCRModel] | None = None, + out: W.Output | None = None + ): + self.models: dict[str, OCRModel] = ocr_models or OCRModel.__display_names__() + super().__init__(exp_ctx, + {'model': ocr_model or OCRModel.TESSERACT}, + out=out or self.out)#, ctxs=[exp_visor]) + + +# %% ../nbs/experiments.ipynb 125 +class DisplayOptions(Enum): + BOXES = 0 + IMAGE = 1 + MASK = 2 + IMAGE_MASK = 3 + PAGE_DATA = 4 + GROUND_TRUTH = 5 + ALL = 6 + RESULTS = 7 + BEST_RESULTS = 8 + ACCURACY = 9 + DATAFRAME = 10 + CONFIG = 11 + + @staticmethod + def __display_names__(): + return dict( + zip("Boxes, Image, Mask, Image & Mask, Page data, Ground truth, Image All, Results, " + "Best results, Accuracy, Dataframe, Config".split(', '), + DisplayOptions)) + + +class ContentSelector(ContextVisor): + ctx: OCRExperimentContext + + def image_info(self, image_ctx: ImageContext): + img = image_ctx.base_image + (w, h), print_size_in, print_size_cm, required_dpi = image_ctx.image_info + format = PRINT_FORMATS['Modern Age'] + cprint( f"{'Width x Height':>30}: {w} x {h} pixels\n" + f"{'PIL Info DPI':>30}: {repr(img.info.get('dpi', None))}\n" + f"{'Print Size 300 DPI':>30}: {print_size_in[0]:.3f} x {print_size_in[1]:.3f} in" + f" / {print_size_cm[0]:.3f} x {print_size_cm[1]:.3f} cm\n" + f"Required DPI Modern Age format: {required_dpi:.3f} dpi " + f"({format[0]:.3f} x {format[1]:.3f} in)") + + + def display_content(self, image_ctx: ImageContext, display_option: DisplayOptions): + DI = self.ctx.DI + if display_option in (DisplayOptions.ALL, DisplayOptions.PAGE_DATA): + self.image_info(image_ctx) + RenderJSON(image_ctx.json_data, 350, 2).display() + if display_option in (DisplayOptions.ALL, DisplayOptions.GROUND_TRUTH): + cprint(image_ctx.gts) + if display_option == DisplayOptions.CONFIG: + self.ctx.show() + if display_option == DisplayOptions.IMAGE: + display_image_grid([DI(image_ctx.image_path)], 1, 1) + if display_option == DisplayOptions.MASK: + display_image_grid([DI(image_ctx.mask_path)], 1, 1) + if display_option in (DisplayOptions.ALL, DisplayOptions.IMAGE_MASK): + display_image_grid([DI(image_ctx.image_path), DI(image_ctx.mask_path)], 1, 2) + if display_option in (DisplayOptions.ALL, DisplayOptions.BOXES): + display_image_grid([DI(image_ctx.image_boxes_path)], 1, 1) + + + def setup_controls(self): + options = self.display_options or {**DisplayOptions.__display_names__()} + display_option_wdgt = W.Dropdown( + options=options, + value=self.values['display_option'], + layout={'width': '120px'}, + style={'description_width': 'initial'}) + return {'display_option': display_option_wdgt} + + + def setup_ui(self): + ctls = self.controls + display_option_grp = W.HBox([ctls['display_option']]) + display_option_grp.add_class('display_option_grp') + comps = self.comps_ui() + ui = W.HBox([*comps, display_option_grp]) + return ui + + + def __init__(self, + exp_ctx: OCRExperimentContext, + display_option: DisplayOptions | None=DisplayOptions.BOXES, + display_options: Mapping[str, DisplayOptions] | None = None, + **kwargs + ): + self.display_options = display_options + super().__init__(exp_ctx, + {'display_option': display_option or DisplayOptions.BOXES}, + **kwargs)#, ctxs=[exp_visor]) + + +# %% ../nbs/experiments.ipynb 129 +class ImageSelector(ContextVisor): + ctx: OCRExperimentContext + + @property + def image_ctx(self): + return ImageContext(self.ctx, self.values['image_idx']) + + def setup_controls(self): + paths = self.ctx.image_paths + w = W.Dropdown( + options={_.stem:i for i,_ in enumerate(paths)}, + value=self.values['image_idx'], + # layout={'width': 'fit-content'}, + layout={'width': '25em'}, + style={'description_width': 'initial'}) + return {'image_idx': w} + + def update(self, image_idx: ImgSpecT | None = None, **kwargs): + if image_idx is None: return + idx = self.ctx.normalize_idx(image_idx) + if idx is None: return + super().update(image_idx=idx, **kwargs) + + + def __init__(self, + ctx: OCRExperimentContext, /, + image_idx: ImgSpecT = 0, + **kwargs): + idx = ctx.normalize_idx(image_idx) + assert idx is not None, f"Image {image_idx} not found in experiment context" + super().__init__(ctx, {'image_idx': idx}, **kwargs) + + +# %% ../nbs/experiments.ipynb 133 +class OCRContextVisor(ContextVisor): + ctx: OCRExperimentContext + + def update_output(self, /, image_idx: ImgIdT, **kwargs): + ctx = self.ctx + img_path = ctx.path_from_idx(image_idx, cached=ctx.force_PIL) + img = ctx.display_image(img_path) + display_image_grid([img], 1, 1) + + def update(self, image_idx: ImgSpecT | None = None, **kwargs): + if image_idx is None: return + idx = self.ctx.normalize_idx(image_idx) + if idx is None: return + super().update(image_idx=idx, **kwargs) + + def __init__(self, + ctx: OCRExperimentContext, /, + image_idx: ImgSpecT = 0, *, + out: W.Output | None=None): + super().__init__(ctx, {}, out, + ctxs={'image_idx': ImageSelector(ctx, image_idx, out=self.out)}) + + +# %% ../nbs/experiments.ipynb 152 +class ImageContextVisor(ContextVisor): + ctx: ImageContext + # control_names: list[str] = ['display_option'] + + _css = """ + .display_option_grp { + background-color: lightblue; + } + """ + + def image_info(self): + content_selector = cast(ContentSelector, self.comp('display_option')) + content_selector.image_info(self.ctx) + + def update_output(self, + display_option: DisplayOptions | None = None, + image_idx: ImgIdT | None = None, + **kwargs): + content_selector = cast(ContentSelector, self.comp('display_option')) + if image_idx is not None and image_idx != self.ctx.image_idx: + ctx = ImageContext(self.ctx.exp, image_idx) + assert ctx is not None + self.ctx = ctx + display_option = content_selector.values['display_option'] + if display_option is None: + return + content_selector.display_content(self.ctx, display_option) + + def update(self, + display_option: DisplayOptions | None=None, + image_idx: ImgSpecT | None=None, + **kwargs): + if image_idx is not None: + if (idx := self.ctx.exp.normalize_idx(image_idx)) is not None: + kwargs['image_idx'] = idx + super().update(display_option=display_option, **kwargs) + + def __init__(self, + exp_ctx: OCRExperimentContext, + img_idx: ImgSpecT | ImageContext, + display_option: DisplayOptions=DisplayOptions.BOXES, + display_options: Mapping[str, DisplayOptions] | None = None, + out: W.Output | None = None + ): + if isinstance(img_idx, ImageContext): + ctx = img_idx + else: + assert exp_ctx is not None, "exp_ctx must be provided if img_idx is not an ImageContext" + ctx = ImageContext(exp_ctx, img_idx) + assert ctx is not None, f"Image {img_idx} not found in experiment context" + if display_options is None: + display_options = {k: v for k, v in DisplayOptions.__display_names__().items() + if k not in ('Results', 'Accuracy', 'Best results', 'Dataframe', 'Config')} + out = out or self.out + content_selector = ContentSelector(exp_ctx, + display_option=display_option, display_options=display_options, out=out) + image_selector = ImageSelector(exp_ctx, ctx.image_idx, out=out) + super().__init__(ctx, {}, out=out, + ctxs={'image_idx': image_selector, 'display_option': content_selector}) + + +# %% ../nbs/experiments.ipynb 165 +def trimmed_mean(data, trim_percent): + sorted_data = np.sort(data) + n = len(data) + trim_count = int(trim_percent * n) + trimmed_data = sorted_data[trim_count:-trim_count] + return np.mean(trimmed_data) + +def mad_based_outlier(points, threshold=3.5): + median = np.median(points) + diff = np.abs(points - median) + mad = np.median(diff) + modified_z_score = 0.6745 * diff / mad + return points[modified_z_score < threshold] + +def iqr_outlier_removal(data): + q1 = np.percentile(data, 25) + q3 = np.percentile(data, 75) + iqr = q3 - q1 + lower_bound = q1 - 1.5 * iqr + upper_bound = q3 + 1.5 * iqr + return data[(data >= lower_bound) & (data <= upper_bound)] + + +# %% ../nbs/experiments.ipynb 166 +class ExperimentOCR: + ctx: ImageContext + run: ExperimentRun + + @property + def ocr_model(self): return cast(OCRExperimentContext, self.ctx.exp).ocr_model + @property + def img_ctx(self) -> ImageContext: return self.ctx + @property + def ctxs(self) -> tuple[OCRExperimentContext, ImageContext]: + return cast(OCRExperimentContext, self.img_ctx.exp), self.img_ctx + + def to_dict(self): + "JSON serializable dict of the experiment" + results = resultset_to_dict(self.results()) + return { + 'run_name': self.run.name, + 'image_name': self.img_ctx.image_name, + 'results': results, + } + + @classmethod + def from_image(cls, + ctx: OCRExperimentContext, + run_name: RunIdT, + image_idx: ImgSpecT): + idx = cast(ImgIdT, ctx.normalize_idx(image_idx)) + img_ctx = ImageContext(ctx, idx) + return cls(img_ctx, run_name) + + @classmethod + def from_method(cls, + ctx: OCRExperimentContext, + image_idx: ImgIdT | str | Path, + run_name: str, + method: CropMethod) -> ExperimentOCRMethod | None: + experiment = cls.from_image(ctx, run_name, image_idx) + if experiment is None: + return None + return experiment.method_experiment(method) + + + def result(self, box_idx: BoxIdT, method: CropMethod, ocr: bool=True, rebuild: bool=False): + ctx, img_ctx = self.ctxs + return ctx.result(self.run.name, img_ctx.image_idx, box_idx, method, ocr, rebuild) + + def results(self): + ctx, img_ctx = self.ctxs + return cast(ResultSet, ctx.results(self.run.name, img_ctx.image_idx)) + + def has_run(self): + "at least one method has run" + return len(self.results()) == len(self.img_ctx.page_data.boxes) # pylint: disable=no-member + + def best_results(self): + methods = list(CropMethod.__members__.values()) + _ = [self.method_experiment(m).results() for m in methods] + results = self.results() + # at least one method has run + if len(results) < len(self.img_ctx.page_data.boxes): # pylint: disable=no-member + return None + best = [] + for box_idx in results: + methods = results[box_idx] + best_method = max(methods, key=lambda m: methods[m].acc) # type: ignore + best.append((best_method, methods[best_method])) + return best + + def save_results_as_ground_truth(self, overwrite=False): + ctx, img_ctx = self.ctxs + gts_path = ctx.final(ground_truth_path(img_ctx.page_data)) # pylint: disable=no-member + if overwrite or not gts_path.exists(): + best_results = self.best_results() + if best_results: + tt = [r.ocr for m,r in best_results] + gts_path.write_text('\n'.join(tt), encoding="utf-8") + img_ctx.setup_ground_truth() + logger.info(f"Ground truth data saved successfully to {gts_path}") + return True + else: + logger.info("No best results available to save.") + return False + else: + return False + + @property + def experiments(self): + if not hasattr(self, '_experiments'): + self._experiments = {} + return self._experiments + def method_experiment(self, method: CropMethod) -> ExperimentOCRMethod: + if method not in self.experiments: + self.experiments[method] = ExperimentOCRMethod(self, method) + return self.experiments[method] + + + def to_dataframe(self): + "Dataframe with crop methods as columns and box ids as rows" + methods = list(CropMethod.__members__.values()) + experiments = [self.method_experiment(m) for m in methods] + accuracies = [[result.acc for result in exp.results()] for exp in experiments] + # transpose accuracies + accuracies = list(zip(*accuracies)) + return pd.DataFrame(accuracies, columns=CropMethod.__display_names__()) + + def plot_accuracies(self, + methods: list[CropMethod] | None = None, + ): + "Plots a horizontal bar chart of the accuracies for a list of method experiments." + from matplotlib.colors import Normalize + methods = methods or list(CropMethod.__members__.values()) + experiments = [self.method_experiment(m) for m in methods] + if not experiments: return + + _, img_ctx = self.ctxs + page_data = img_ctx.page_data # pylint: disable=no-member + _ = [[result.acc or 0.0 for result in exp.results()] for exp in experiments] + accuracies: list[float] = [np.mean(a) for a in _] + # accuracies = [np.mean([result.acc for result in exp.results()]) for exp in experiments] + + _, ax = plt.subplots(figsize=(10, 5)) + + # Normalize the accuracies for color mapping + norm = Normalize(min(accuracies), max(accuracies)) + # Color map from red to green + cmap = plt.get_cmap('RdYlGn') + colors = cmap(norm(accuracies)) + + ax.barh([m.value for m in methods], accuracies, color=colors) + + ax.set_xscale('log') # Set the x-axis to a logarithmic scale + ax.set_xlabel('Average Accuracy (log scale)', fontsize=12, fontweight='bold') + + ax.set_ylabel('Method', fontsize=12, fontweight='bold') + ax.set_yticks(range(len(methods))) + ax.set_yticklabels([f'{method.value} ({acc:.2f})' + for method, acc in zip(methods, accuracies)], fontsize=12) + max_acc_index = np.argmax(accuracies) + ax.get_yticklabels()[max_acc_index].set(color='blue', fontweight='bold') + + model = self.ocr_model + title_text = (f"{page_data.original_path} - OCR model: {model}") + ax.set_title(title_text, fontsize=12, fontweight='bold') + + plt.tight_layout() + plt.show() + + + def summary_box(self, box_idx: int): + ctx, _ = self.ctxs + results: list[tuple[CropMethod, ResultOCR]] = [] + pb = tqdm(CropMethod.__members__.values(), leave=False, desc=f"Box #{box_idx+1}") + for m in pb: + r = cast(ResultOCR, self.result(box_idx, m)) + results.append((m, r)) + methods, images, ocrs, accs = zip(*map( + lambda t: (t[0].value, ctx.DI(t[1].cache_image()), + SimpleResultVisor.diff_tagged(t[1]), acc_as_html(t[1].acc)), + results)) + display_columns([methods, images, accs, ocrs], + headers=["Method", f"Box #{box_idx+1}", "Accuracy", "OCR"]) + + + def summary_method(self, method: CropMethod): + ctx, _ = self.ctxs + results = self.method_experiment(method).results() + methods, images, ocrs, accs = zip(*map( + lambda r: (r.block_idx+1, ctx.DI(r.cache_image()), + SimpleResultVisor.diff_tagged(r), acc_as_html(r.acc)), + results)) + display_columns([methods, images, accs, ocrs], + headers=["Box #", "Box", "Accuracy", f"{method.value} OCR"]) + + + def display(self): + out = [] + for method in CropMethod: + out.append(f"---------- {method.value} ----------") + results = self.method_experiment(method).results() + out.extend(results) + out.append('\n') + cprint(*out, soft_wrap=True) + + + def reset(self, box_idx: int | None = None, method: CropMethod | None = None): + ctx, img_ctx = self.ctxs + ctx.reset_results(None, img_ctx.image_idx, box_idx, method) + + def perform_methods(self, + methods: CropMethod | list[CropMethod] | None = None, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + rebuild: bool = False, + plot_acc: bool = False + ): + if methods is None: + methods = [*CropMethod.__members__.values()] + elif isinstance(methods, CropMethod): + methods = [methods] + if rebuild: + _methods = tqdm(methods, desc="Methods") + else: + _methods = methods + for method in _methods: + method_exp = self.method_experiment(method) + if method_exp: + if rebuild: + method_exp(box_idxs, rebuild=rebuild) + if plot_acc: + self.plot_accuracies() + + def __call__(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + methods: CropMethod | list[CropMethod] | None = None, + # save: bool = True, + display=False, + rebuild: bool=False, + save_as_ground_truth=False): + self.perform_methods(methods, box_idxs, rebuild=rebuild) + if save_as_ground_truth: + self.save_results_as_ground_truth(overwrite=True) + # if save: + # self.to_json() + if display: + self.display() + + def __repr__(self): + return f"ExperimentOCR#{self.ctx.exp.name}_{self.run.name}" + + def __init__(self, ctx: ImageContext, run_name: RunIdT, **kwargs): + # super().__init__(ctx, **kwargs) + self.ctx = ctx + run = ctx.exp.experiment_run(run_name) + assert run is not None + self.run = run + + +@dataclasses.dataclass +class ExperimentOCRMethod: + ctx: ExperimentOCR + method: CropMethod + + @property + def exp_ctx(self): return self.ctx + @property + def img_ctx(self): return self.ctx.ctx + @property + def ctxs(self): + img_ctx = self.img_ctx + return cast(OCRExperimentContext, img_ctx.exp), img_ctx, self.ctx + + def result(self, box_idx: BoxIdT, ocr: bool=True, rebuild: bool=False) -> ResultOCR | None: + ctx, img_ctx, exp_ctx = self.ctxs + return ctx.result(exp_ctx.run.name, img_ctx.image_idx, box_idx, self.method, ocr, rebuild) + + def results(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + ocr: bool=True, rebuild: bool=False) -> list[ResultOCR]: + ctx, img_ctx, exp_ctx = self.ctxs + if box_idxs is None: + box_idxs = list(range(len(img_ctx.boxes))) + elif isinstance(box_idxs, int): + box_idxs = [box_idxs] + run_name = exp_ctx.run.name + results = ctx.method_results(run_name, img_ctx.image_idx, self.method) + results = {i:results[i] if i in results else None for i in box_idxs} + pb = rebuild or not results or any(r is None for r in results.values()) + if pb and len(results) > 2: + model = exp_ctx.ocr_model + progress_bar = tqdm(list(results.keys()), desc=f"{self.method.value} - {model}") + else: + progress_bar = list(results.keys()) + results = [] + for i in progress_bar: + results.append(self.result(i, ocr, rebuild=rebuild)) + return results + + + def get_results_html(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, + max_image_width: int | None = None): + ctx, img_ctx, exp_ctx = self.ctxs + results: list[ResultOCR] = self.results(box_idxs) + accs = np.array([r.acc for r in results]) + mean_accuracy = np.mean(accs) + mean_trimmed = trimmed_mean(accs, 0.1) + # filtered_data = mad_based_outlier(accs) + # mean_mad = np.mean(filtered_data) + # filtered_data = iqr_outlier_removal(accs) + # mean_iqr = np.mean(filtered_data) + + DI = ctx.DI + descriptions, images, ocrs, accs = zip(*map( + lambda r: ( + r.block_idx+1, + DI(r.cache_image()), + SimpleResultVisor.diff_tagged(r), + acc_as_html(r.acc) + ), results)) + non_breakin_space = u'\u00A0' # pylint: disable=unused-variable + tmpl = "{}" + padded_s = lambda s,n: tmpl.format(s.rjust(n)) + acc_fmt = f"{mean_accuracy:.2f}/{mean_trimmed:.2f}" + w, h = img_ctx.base_image.size + dim, _dpi = size(w, h), dpi(w, h) + dim_fmt = f"{w}x{h} px: {dim[0]:.2f} x {dim[1]:.2f} in @ {_dpi:.2f} dpi" + return '\n
\n'.join([ + ("
" + f"{padded_s('Page', 24)}: {img_ctx.page_data.original_path}
" + f"{padded_s('Size', 24)}: {dim_fmt}
" + f"{padded_s('Run', 24)}: {exp_ctx.run.name}
" + f"{padded_s('Model', 24)}: {exp_ctx.ocr_model}
" + f"{padded_s('Crop Method', 24)}: {self.method.value}
" + f"{padded_s('Accuracy Mean/Trimmed', 24)}: {acc_fmt}" + "
"), + get_columns_html( + [descriptions, images, accs, ocrs], + max_image_width, + headers=["Box #", "Image", "Accuracy", "OCR"]), + ]) + + def display(self, + box_idxs: BoxIdT | list[BoxIdT] | None = None, max_image_width: int | None = None): + display(HTML(self.get_results_html(box_idxs, max_image_width))) + + + def summary(self): + ctx, _, _ = self.ctxs + DI = ctx.DI + results = self.results() + methods, images, ocrs, accs = zip(*map( + lambda r: (r.block_idx+1, DI(r.cache_image()), SimpleResultVisor.diff_tagged(r), acc_as_html(r.acc)), + results)) + display_columns([methods, images, accs, ocrs], + headers=["Box #", "Box", "Accuracy", f"{self.method.value} OCR"]) + + + def reset(self): + _, _, exp_ctx = self.ctxs + exp_ctx.reset(method=self.method) + + def __call__(self, box_idxs: BoxIdT | list[BoxIdT] | None = None, display=False, rebuild=False): + if isinstance(box_idxs, int): + result = self.result(cast(BoxIdT, box_idxs), rebuild=rebuild) + if result is not None and display: + result.display() + else: + results = self.results(box_idxs, rebuild=rebuild) + if results and display: + self.display(box_idxs) + + +# %% ../nbs/experiments.ipynb 202 +class ResultVisor(ContextVisor): + ctx: ExperimentOCR + control_names: list[str] = ['all_boxes', 'box_idx', 'all_methods', 'method'] + + _css = """ + .box_grp { + background-color: aliceblue; + } + .method_grp { + background-color: #ededed; + } + """ + + def best_results(self): + ll = self.ctx.best_results() + if ll: + cprint([(m.value, f"{r.acc:.3f}", r.ocr) for m,r in ll]) + + def pd_to_html(self): + df = self.ctx.to_dataframe() + # set float precision + df = df.round(3) + # display floats with 3 decimal digits + df = df.applymap(lambda x: f"{x:.3f}") + # highlight max value in each row + stl = df.style.highlight_max(axis=0) + display(HTML(stl.to_html())) + + def update_output(self, **kwargs): + all_boxes: bool = self.values['all_boxes'] + box_idx: int = self.values['box_idx'] + all_methods: bool = self.values['all_methods'] + method: CropMethod = self.values['method'] + + # cprint(f"all_boxes: {all_boxes}, box_idx: {box_idx}, all_methods: {all_methods}, method: {method}") + + exp, _ = self.ctx.ctxs + if all_boxes and all_methods: + self.ctx.plot_accuracies() + self.ctx.display() + elif all_boxes: + self.ctx.summary_method(method) + elif all_methods: + self.ctx.summary_box(box_idx) + else: + with exp.running(True): + result = self.ctx.result(box_idx, method) + if result is not None: + result.display() + # from time import sleep + # sleep(2) + + def setup_controls(self): + _, img_ctx = self.ctx.ctxs + values = self.values + box_wdgt = W.BoundedIntText( + value=values['box_idx'], min=0, max=len(img_ctx.boxes)-1, step=1, + disabled=values['all_boxes'], + layout={'width': '50px'}, + style={'description_width': 'initial'}) + methods_wdgt = W.Dropdown( + options=CropMethod.__display_names__(), + value=values['method'], + layout={'width': '150px'}, + style={'description_width': 'initial'}) + all_boxes_wdgt = W.Checkbox(label='All', value=values['all_boxes'], + description="all", + layout={'width': 'initial'}, + style={'description_width': '0px'}) + all_methods_wdgt = W.Checkbox(label='All', value=values['all_methods'], + description="all", + layout={'width': 'initial'}, + style={'description_width': '0px'}) + return {'all_boxes': all_boxes_wdgt, 'box_idx': box_wdgt, + 'all_methods': all_methods_wdgt, 'method': methods_wdgt} + + def setup_ui(self): + ctls = self.controls + _, img_ctx = self.ctx.ctxs + box_label = W.Label( + value=f"Box # (of {len(img_ctx.boxes)}):", + layout={'width': 'initial', 'padding': '0px 0px 0px 10px'}) + method_label = W.Label(value='Method:', layout={'width': 'initial', 'padding': '0px 0px 0px 10px'}) + + box_grp = W.HBox([box_label, ctls['all_boxes'], ctls['box_idx']]) + box_grp.add_class('box_grp') + method_grp = W.HBox([method_label, ctls['all_methods'], ctls['method']]) + method_grp.add_class('method_grp') + uis = self.comps_ui() + return W.HBox([box_grp, method_grp, *uis]) + + def __init__(self, + ctx: OCRExperimentContext | ExperimentOCR, + img_idx: int | str | Path | None = None, + all_boxes: bool = False, + box_idx: int = 0, + all_methods: bool = False, + method: CropMethod=CropMethod.INITIAL_BOX, + **kwargs + ): + if isinstance(ctx, OCRExperimentContext): + assert img_idx is not None, "img_idx must be provided if ctx is an ExperimentContext" + exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx) + if not exp: + raise ValueError(f"Image {img_idx} not found in experiment context") + ctx = exp + else: + if not isinstance(ctx, ExperimentOCR): + raise ValueError("ctx must be an ExperimentOCR or OCRExperimentContext") + + super().__init__(ctx, {'all_boxes': all_boxes, 'box_idx': box_idx, + 'all_methods': all_methods, 'method': method}, **kwargs) + + +# %% ../nbs/experiments.ipynb 205 +class ExperimentVisor(ContextVisor): + ctx: ExperimentOCR + + def update_output(self, + image_idx: int | None = None, + **kwargs): + exp_ctx, img_ctx = self.ctx.ctxs + if image_idx is not None and image_idx != img_ctx.image_idx: + ctx = ImageContext(exp_ctx, image_idx) + assert ctx is not None + self.ctx.ctx = ctx + result_visor = self.comp('result_visor') + if result_visor is not None: + result_visor.update_output(**kwargs) + + def __init__(self, + ctx: OCRExperimentContext | ExperimentOCR, + img_idx: int | str | Path | None = None, + all_boxes: bool = False, + box_idx: int = 0, + all_methods: bool = False, + method: CropMethod=CropMethod.INITIAL_BOX, + out: W.Output | None = None, + ): + if isinstance(ctx, OCRExperimentContext): + assert img_idx is not None, "img_idx must be provided if ctx is an ExperimentContext" + exp = ExperimentOCR.from_image(ctx, 'Tesseract', img_idx) + if not exp: + raise ValueError(f"Image {img_idx} not found in experiment context") + ctx = exp + else: + if not issubclass(type(ctx), ExperimentOCR): + raise ValueError("ctx must be an ExperimentOCR or OCRExperimentContext") + + exp_ctx, img_ctx = ctx.ctxs + out = out or self.out + image_selector = ImageSelector(exp_ctx, image_idx=img_ctx.image_idx, out=out) + result_visor = ResultVisor(ctx, out=out, + all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method) + + super().__init__(ctx, {}, out=out, + ctxs={'image_selector': image_selector, 'result_visor': result_visor}, + hdlrs={'display_option': result_visor} + ) + + +# %% ../nbs/experiments.ipynb 253 +class ExperimentsVisor(ContextVisor): + ctx: OCRExperimentContext + + def update_output(self, + run_name: RunIdT | None = None, + image_idx: ImgIdT | None = None, + display_option: DisplayOptions | None = None, + msg: str | None = None, + **kwargs): + (run_selector, image_selector, content_selector, + result_visor, _, message_visor) = self._comps() + if msg is not None and msg != MessageVisor.EMPTY: + message_visor.update_output(msg=msg) + if run_name is not None: + run = OCRExperimentRun(run_selector.ctx, run_name) + exp_ctx = result_visor.ctx + exp_ctx.run = run + result_visor.ctx = exp_ctx + if image_idx is not None: + img_ctx = ImageContext(self.ctx, image_idx) + result_visor.ctx.ctx = img_ctx + display_option = content_selector.values['display_option'] + if display_option is not None and display_option != DisplayOptions.RESULTS: + result_visor.hide() + if display_option == DisplayOptions.BEST_RESULTS: + result_visor.best_results() + elif display_option == DisplayOptions.ACCURACY: + result_visor.ctx.plot_accuracies() + elif display_option == DisplayOptions.DATAFRAME: + result_visor.pd_to_html() + else: + content_selector.display_content(image_selector.image_ctx, display_option) + else: + result_visor.show() + result_visor.update_output(**kwargs) + + + @property + def status_visor(self) -> StatusVisor: return cast(StatusVisor, self.comps['status_visor']) + @property + def message_visor(self) -> MessageVisor: return cast(MessageVisor, self.comps['message_visor']) + @property + def image_context(self) -> ImageContext: + return ImageContext(self.ctx, self.comps['image_selector'].values['image_idx']) + @property + def run_name(self) -> str: return cast(str, self.comps['run_selector'].values['run_name']) + @property + def image_experiment(self) -> ExperimentOCR: return ExperimentOCR(self.image_context, self.run_name) + + def _comps(self): + cc = self.comps + rsel: RunSelector = cc['run_selector'] # type: ignore + isel: ImageSelector = cc['image_selector'] # type: ignore + cs: ContentSelector = cc['content_selector'] # type: ignore + rv: ResultVisor = cc['result_visor'] # type: ignore + sv: StatusVisor = cc['status_visor'] # type: ignore + mv: MessageVisor = cc['message_visor'] # type: ignore + return rsel, isel, cs, rv, sv, mv + + def setup_ui(self): + ctls = self.controls.values() + rselw, iselw, csw, rvw, svw, _ = [_.w for _ in self._comps()] + return W.VBox([W.HBox([rselw, iselw, csw, svw, *ctls]), rvw]) + + def save(self, b): + ctx = self.ctx + fp = ctx.save() + self.update(msg=f"'{ctx.name}' experiment saved on {fp}") + + def reset(self, b): + image_idx = self.comps['image_selector'].values['image_idx'] + self.ctx.reset_results(image_idx=image_idx) + + def setup_ux(self): + self.status_visor.save_button.on_click(self.save) + self.status_visor.reset_button.on_click(self.reset) + + def setup_experiment_context(self, + ocr_model: str | None = None, + root_dir: Path | str | None = None, + config: cfg.Config | None = None, + run_names: list[str] | None = None, + ): + ctx = OCRExperimentContext(ocr_model or 'Tesseract', root_dir, config=config) # type: ignore + + for run_name in run_names or ['Tesseract-crop-post', 'Tesseract-crop']: + OCRExperimentRun(ctx, run_name) + return ctx + + def __init__(self, + ctx: OCRExperimentContext | None = None, + ocr_model: str | None = None, + root_dir: Path | str | None = None, + config: cfg.Config | None = None, + image_idx: ImgIdT | str | Path = 0, + run_name: str | None = None, + run_names: list[str] | None = None, + display_option: DisplayOptions = DisplayOptions.RESULTS, + all_boxes: bool = False, + box_idx: int = 0, + all_methods: bool = False, + method: CropMethod=CropMethod.INITIAL_BOX, + # ocr_model: OCRModel = OCRModel.TESSERACT, + # ocr_models: dict[str, OCRModel] = {'Tesseract': OCRModel.TESSERACT}, + out: W.Output | None = None, + ): + if ctx is None: + ctx = self.setup_experiment_context(ocr_model, root_dir, config, run_names) + _ = ImageContext(ctx, image_idx) # raises if image_idx is out of range + + out = out or self.out + run_selector = RunSelector(ctx, run_name, run_names, out=out) + exp = ExperimentOCR.from_image(ctx, run_selector.values['run_name'], image_idx) + image_selector = ImageSelector(ctx, image_idx=image_idx, out=out) + content_selector = ContentSelector(ctx, display_option=display_option, out=out) + result_visor = ResultVisor(exp, out=out, + all_boxes=all_boxes, box_idx=box_idx, all_methods=all_methods, method=method, + ctxs={'spinner': Spinner(ctx, 20, 3)} + ) + status_visor = StatusVisor(ctx, out=None) + message_visor = MessageVisor(MessageVisor.EMPTY, out=out) + + super().__init__(ctx, {}, out=out, + ctxs={'run_selector': run_selector, #'model_selector': model_selector, + 'image_selector': image_selector, 'content_selector': content_selector, + 'result_visor': result_visor, + 'status_visor': status_visor, + 'message_visor': message_visor, + }, + ) + diff --git a/pcleaner/_testbed/testbed/helpers.py b/pcleaner/_testbed/testbed/helpers.py new file mode 100644 index 00000000..f5a99a6b --- /dev/null +++ b/pcleaner/_testbed/testbed/helpers.py @@ -0,0 +1,381 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/helpers.ipynb. + +# %% ../nbs/helpers.ipynb 7 +from __future__ import annotations + +import base64 +import json +import re +import sys +import uuid +from importlib import resources +from io import BytesIO +from pathlib import Path +from typing import Any +from typing import Iterable +from typing import Mapping +from typing import Sequence + +import pcleaner.data +import pcleaner.structures as st +from IPython.display import clear_output +from IPython.display import display +from IPython.display import HTML +from PIL import Image +from PIL import ImageDraw +from PIL import ImageFont + + +# %% auto 0 +__all__ = ['PRINT_FORMATS', 'cleanupwidgets', 'RenderJSON', 'page_boxes', 'crop_box', 'size', 'dpi', 'get_image_html', + 'get_columns_html', 'display_columns', 'get_image_grid_html', 'display_image_grid', 'acc_as_html', + 'strip_uuid', 'defaultdict_to_dict', '_pops_', '_pops_values_', '_gets_'] + +# %% ../nbs/helpers.ipynb 13 +_all_ = ['_pops_', '_pops_values_', '_gets_'] + + +# %% ../nbs/helpers.ipynb 14 +def _pops_(d: dict, ks: Iterable) -> dict: + "Pops `ks` keys from `d` and returns them in a dict. Note: `d` is changed in-place." + return {k:d.pop(k) for k in ks if k in d} + + +# %% ../nbs/helpers.ipynb 16 +def _pops_values_(d: dict, ks: Iterable) -> tuple: + "Pops `ks` keys from `d` and returns them as a tuple. Note: `d` is changed in-place." + return tuple(d.pop(k, None) for k in ks) + + +# %% ../nbs/helpers.ipynb 18 +def _gets_(d: Mapping[str, Any], ks: Iterable): + "Fetches values from a mapping for a given list of keys, returning `None` for missing keys." + return (d.get(k, None) for k in ks) + + +# %% ../nbs/helpers.ipynb 21 +def _get_globals(mod: str): + if hasattr(sys, '_getframe'): + glb = sys._getframe(2).f_globals + else: + glb = sys.modules[mod].__dict__ + return glb + + +# %% ../nbs/helpers.ipynb 23 +def cleanupwidgets(*ws, mod: str|None=None, clear=True): + glb = _get_globals(mod or __name__) + if clear: clear_output(wait=True) + for w in ws: + _w = glb.get(w) if isinstance(w, str) else w + if _w: + try: _w.close() # type: ignore + except: pass + + +# %% ../nbs/helpers.ipynb 26 +class RenderJSON(object): + def __init__(self, json_data, max_height=200, init_level=0): + if isinstance(json_data, (Sequence, Mapping)): + s = json.dumps(json_data) + elif hasattr(json_data, 'to_dict'): + s = json.dumps(json_data.to_dict()) + elif hasattr(json_data, 'to_json'): + s = json_data.to_json() + else: + s = json_data + self.json_str = s + self.uuid = str(uuid.uuid4()) + self.max_height = max_height + self.init_level = init_level + + def display(self): + html_content = f""" +
+
+ +
+ """ + display(HTML(html_content)) + + def _ipython_display_(self): + self.display() + +# %% ../nbs/helpers.ipynb 29 +def page_boxes(self: st.PageData, + image_path: Path, out_dir: Path | None = None) -> tuple[Image.Image, Path]: + """ + Visualize the boxes on an image. + Typically, this would be used to check where on the original image the + boxes are located. + + :param image_path: The path to the image to visualize the boxes on. + """ + image = Image.open(image_path) + draw = ImageDraw.Draw(image) + data_path = resources.files(pcleaner.data) + font_path = str(data_path / "LiberationSans-Regular.ttf") + # Figure out the optimal font size based on the image size. E.g. 30 for a 1600px image. + font_size = int(image.size[0] / 50) + 5 + + for index, box in enumerate(self.boxes): + draw.rectangle(box.as_tuple, outline="green") + # Draw the box number, with a white background, respecting font size. + draw.text( + (box.x1 + 4, box.y1), + str(index + 1), + fill="green", + font=ImageFont.truetype(font_path, font_size), + stroke_fill="white", + stroke_width=3, + ) + + for box in self.extended_boxes: + draw.rectangle(box.as_tuple, outline="red") + for box in self.merged_extended_boxes: + draw.rectangle(box.as_tuple, outline="purple") + for box in self.reference_boxes: + draw.rectangle(box.as_tuple, outline="blue") + + # Save the image. + extension = "_boxes" + out_path = image_path.with_stem(image_path.stem + extension) + if out_dir is not None: + out_dir.mkdir(parents=True, exist_ok=True) + out_path = out_dir / out_path.name + image.save(out_path) + + return image, out_path + +# %% ../nbs/helpers.ipynb 31 +def crop_box(box: st.Box, image: Image.Image) -> Image.Image: + return image.crop(box.as_tuple) + +# %% ../nbs/helpers.ipynb 33 +PRINT_FORMATS = { + 'Golden Age': (7.75, 10.5), # (1930s-40s) + 'Siver Age': (7, 10.375), # (1950s-60s) + 'Modern Age': (6.625,10.25), # North American comic books + 'Magazine': (8.5, 11), + 'Digest': (5.5, 8.5), + 'Manga': (5.0, 7.5), +} + + +def size(w: int, h: int, unit: str = 'in', dpi: float = 300.) -> tuple: + """ + Calculate the print size of an image in inches or centimeters. + + Args: + w (int): Width of the image in pixels. + h (int): Height of the image in pixels. + unit (str): Unit of measurement ('in' for inches, 'cm' for centimeters). + dpi (float): Dots per inch (resolution). + + Returns: + tuple: Width and height of the image in the specified unit. + """ + if unit == 'cm': + return (w / dpi * 2.54, h / dpi * 2.54) + else: # default to inches + return (w / dpi, h / dpi) + + +def dpi(w: int, h: int, print_format: str = 'Modern Age') -> float: + """ + Calculate the dpi (dots per inch) needed to print an image at a specified format size. + + Args: + w (int): Width of the image in pixels. + h (int): Height of the image in pixels. + print_format (str): Print format as defined in the formats dictionary. + + Returns: + float: Required dpi to achieve the desired print format size. + """ + # Default to 'Modern Age' if format not found + format_size = PRINT_FORMATS.get(print_format, PRINT_FORMATS['Modern Age']) + width_inch, height_inch = format_size + dpi_w = w / width_inch + dpi_h = h / height_inch + return (dpi_w + dpi_h) / 2 # Average dpi for width and height + + +# %% ../nbs/helpers.ipynb 35 +def get_image_html(image: Image.Image | Path | str, max_width: int | None = None): + """ + Converts a PIL image or an image file path to an HTML image tag. If the image is a PIL Image object, + it is converted to a base64-encoded PNG and embedded directly into the HTML. If the image is a file path, + the path is used as the source URL for the image tag. + """ + style = f' style="max-width: {max_width}px;"' if max_width is not None else '' + if isinstance(image, (Path, str)): + return f'' + else: + buffered = BytesIO() + image.save(buffered, format='PNG') + img_str = base64.b64encode(buffered.getvalue()).decode() + return f'' + + +def get_columns_html( + columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None +): + if not all(len(col) == len(columns[0]) for col in columns): + raise ValueError("All columns must have the same length.") + + # Calculate the maximum width of images in each column + max_widths = [] + for col_index in range(len(columns)): + max_col_width = 0 + for item in columns[col_index]: + if isinstance(item, (Image.Image, Path)): + if isinstance(item, (Path, str)): + try: + item = Image.open(item) + except: + continue + width, _ = item.size + max_col_width = max(max_col_width, width) + if max_col_width > 0: + max_widths.append( + f"{min(max_col_width, max_image_width)}px" + if max_image_width is not None else + f"{max_col_width}px" + ) + else: + max_widths.append('auto') + + html_str = "" + + # Apply calculated column widths using and elements + html_str += "" + for width in max_widths: + html_str += f"" + html_str += "" + + if headers: + if len(headers) != len(columns): + raise ValueError("Headers list must match the number of columns.") + html_str += ( + "" + + "".join( + f"" + for header in headers + ) + + "" + ) + + for row_items in zip(*columns): + html_str += "" + for i, item in enumerate(row_items): + if isinstance(item, (Image.Image, Path)): + img_html = get_image_html(item, max_width=max_image_width) + html_str += f"" + else: # Assume the item is a string + style = "font-weight: bold;" if i == 0 else "" + html_str += f"" + html_str += "" + + html_str += "
{header}
{img_html}{item}
" + return html_str + + +def display_columns( + columns: list[list], max_image_width: int | None = None, headers: list[str] | None = None +): + """ + Displays a table with any combination of columns, which can be lists of strings or lists + of PIL Image objects, within a Jupyter notebook cell. + + :param columns: A list of lists, where each sublist represents a column in the table. + Each sublist can contain either strings or PIL Image objects. + :param max_image_width: The maximum size of the images in pixels. This controls the max-height + of the images. + :param headers: A list of header labels for the table. If None, no headers are displayed. + """ + return display(HTML(get_columns_html(columns, max_image_width, headers))) + + +def get_image_grid_html( + images: list[Image.Image | Path | str], + rows: int, + columns: int, + titles: list[str] | None = None, + max_image_width: int | None = None, + caption: str | None = None +): + if titles and len(titles) != len(images): + raise ValueError("Titles list must match the number of images if provided.") + + html_str = "" + + if caption: + html_str += (f"") + + image_index = 0 + for _ in range(rows): + html_str += "" + for _ in range(columns): + if image_index < len(images): + img_html = get_image_html(images[image_index], max_width=max_image_width) + title_html = ( + f"
{titles[image_index]}
" + if titles + else "" + ) + html_str += f"" + else: + html_str += "" # Empty cell if no more images + image_index += 1 + html_str += "" + + html_str += "
{caption}
{title_html}{img_html}
" + return html_str + + +def display_image_grid( + images: list[Image.Image | Path | str], + rows: int, + columns: int, + titles: list[str] | None = None, + max_image_width: int | None = None, + caption: str | None = None, +): + """ + Displays a grid of images in a HTML table within a Jupyter notebook cell. + + :param images: A list of PIL Image objects to be displayed. + :param rows: The number of rows in the grid. + :param columns: The number of columns in the grid. + :param titles: An optional list of titles for each image. If provided, it must match the length + of the images list. + :param max_image_width: The maximum width of the images in pixels. + """ + display(HTML(get_image_grid_html(images, rows, columns, titles, max_image_width, caption))) + + +def acc_as_html(acc): + return f"
{acc:.2f}
" + + +# %% ../nbs/helpers.ipynb 37 +def strip_uuid(p: Path | str): + _p: Path = p if isinstance(p, Path) else Path(p) + new_stem = re.sub(r'(?i)[a-f0-9]{8}-([a-f0-9]{4}-){3}[a-f0-9]{12}', '', _p.stem).strip('_') + return _p.with_stem(new_stem) + + +# %% ../nbs/helpers.ipynb 40 +# Deep copy a defaultdict of defaultdicts to a dict of dicts if it is not already a dict +def defaultdict_to_dict(d) -> dict: + if not isinstance(d, defaultdict): + return d + return {k: defaultdict_to_dict(v) for k, v in d.items()} + diff --git a/pcleaner/_testbed/testbed/ocr_idefics.py b/pcleaner/_testbed/testbed/ocr_idefics.py new file mode 100644 index 00000000..2b8b8f07 --- /dev/null +++ b/pcleaner/_testbed/testbed/ocr_idefics.py @@ -0,0 +1,310 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/ocr_idefics.ipynb. + +# %% ../nbs/ocr_idefics.ipynb 1 +from __future__ import annotations + + +# %% auto 0 +__all__ = ['IdeficsOCR', 'IdeficsExperimentContext'] + +# %% ../nbs/ocr_idefics.ipynb 5 +import functools +import subprocess +from pathlib import Path +from typing import Any +from typing import Literal +from typing import TypeAlias + +import pcleaner.config as cfg +import pcleaner.ocr.ocr as ocr +import torch +from pcleaner.ocr.ocr_tesseract import TesseractOcr +from PIL import Image +from rich.console import Console +from transformers import AutoProcessor +from transformers import Idefics2ForConditionalGeneration + + +# %% ../nbs/ocr_idefics.ipynb 14 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% ../nbs/ocr_idefics.ipynb 17 +import pcleaner._testbed.testbed.experiments as exp_testbed +from pcleaner._testbed.testbed.experiments import * +from pcleaner._testbed.testbed.helpers import RenderJSON +import pcleaner._testbed.testbed.web_server as web_server + + +# %% ../nbs/ocr_idefics.ipynb 18 +def load_image(img_or_path) -> Image.Image: + if isinstance(img_or_path, (str, Path)): + return Image.open(img_or_path) + elif isinstance(img_or_path, Image.Image): + return img_or_path + else: + raise ValueError(f"img_or_path must be a path or PIL.Image, got: {type(img_or_path)}") + + +# %% ../nbs/ocr_idefics.ipynb 19 +def get_gpu_vram(total=True): + if total: + command = "nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits" + else: + command = "nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits" + try: + vram = subprocess.check_output(command, shell=True).decode('utf-8').strip() + return vram + except subprocess.CalledProcessError: + return "Failed to get VRAM" + + +# %% ../nbs/ocr_idefics.ipynb 43 +def _setup_processor(): + return AutoProcessor.from_pretrained( + "HuggingFaceM4/idefics2-8b", + do_image_splitting=False # cropped boxes are usually small + ) + +# %% ../nbs/ocr_idefics.ipynb 45 +QuantT: TypeAlias = Literal['bfloat16'] | Literal['8bits'] | Literal['4bits'] + +def _setup_model(quant: QuantT, flashattn: bool=True): + kwargs: dict = dict( + torch_dtype=torch.bfloat16, + ) + if quant == 'bfloat16': + pass + else: + from transformers import BitsAndBytesConfig + quantization_config = None + if quant == '8bits': + quantization_config = BitsAndBytesConfig( + load_in_8bit=True, + ) + if quant == '4bits': + quantization_config = BitsAndBytesConfig( + load_in_4bit=True, + bnb_4bit_quant_type="nf4", + bnb_4bit_use_double_quant=True, + bnb_4bit_compute_dtype=torch.float16 + ) + if quantization_config is not None: + kwargs.update(quantization_config=quantization_config) + if flashattn: + kwargs.update(_attn_implementation="flash_attention_2") + model = Idefics2ForConditionalGeneration.from_pretrained( + "HuggingFaceM4/idefics2-8b", + device_map='auto', + **kwargs) + return model + +# %% ../nbs/ocr_idefics.ipynb 46 +prompt_text_tmpl = ( + "Please perform optical character recognition (OCR) on this image, which displays " + "speech balloons from a comic book. The text is in {}. Extract the text and " + "format it as follows: transcribe in standard sentence case, avoid using all capital " + "letters. Provide the transcribed text clearly and double check the sentence is not all capital letters.") + +# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " +# f"speech balloons from a manga comic. The text is in {}. Extract the text and " +# "format it without newlines. Provide the transcribed text clearly.") + +# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " +# "speech balloons from a comic book. The text is in {}. Extract the text and " +# "format it as follows: transcribe in standard sentence case (avoid using all capital " +# "letters) and use asterisks to denote any words that appear in bold within the image. " +# "Provide the transcribed text clearly.") + +# prompt_text_tmpl = ("Please perform optical character recognition (OCR) on this image, which displays " +# "speech balloons from a comic book. The text is in {}. Extract the text and " +# "format it as follows: transcribe in standard sentence case, capitalized. Avoid using " +# "all capital letters. In comics, it is common to use two hyphens '--' to interrupt a sentence. " +# "Retain any hyphens as they appear in the original text. Provide the transcribed text " +# "clearly, ensuring it is capitalized where appropriate, including proper nouns.") + +prompt_text_tmpl = ( + "Please perform optical character recognition (OCR) on this image, which displays " + "speech balloons from a comic book. The text is in {}. Extract the text and " + "format it as follows: transcribe in standard sentence case, capitalized. Avoid using " + "all capital letters, but ensure it is capitalized where appropriate, including proper nouns. " + "Provide the transcribed text clearly. Double check the text is not all capital letters.") + + +# prompt_text_tmpl = ( +# "Please perform optical character recognition (OCR) on this image, which contains speech " +# "balloons from a comic book. The text is in English. Carefully transcribe the text, " +# "ensuring that you preserve the original formatting and line breaks as they appear " +# "in the speech balloon." +# ) + +default_prompt_text_tmpl = prompt_text_tmpl + +# %% ../nbs/ocr_idefics.ipynb 48 +class IdeficsOCR: + prompt_text_tmpl: str = default_prompt_text_tmpl + PROCESSOR: Any = None + MODEL: Any = None + + + @classmethod + def setup_processor(cls): + cls.PROCESSOR = _setup_processor() + return cls.PROCESSOR + + @classmethod + def setup_model(cls, quant: QuantT='bfloat16', flashattn: bool=True): + cls.MODEL = _setup_model(quant, flashattn) + return cls.MODEL + + @staticmethod + def is_idefics_available() -> bool: + return True + + def show_info(self): + cprint( + f"{'model':>17}: {type(self.MODEL)}\n" + f"{'quantization':>17}: {type(self.quant)}\n" + f"{'device':>17}: {repr(self.MODEL.device)}\n" + f"{'current VRAM':>17}: {get_gpu_vram(False)} MiB\n" + ) + + + def __init__(self, + lang: str | None = None, + prompt_text_tmpl: str|None = None, + quant: QuantT | None = None, + flashattn: bool | None = None, + ): + self.lang = lang + self.prompt_text_tmpl = prompt_text_tmpl or self.prompt_text_tmpl + self.quant = quant or 'bfloat16'#'4bits' + self.flashattn = flashattn or True + if self.PROCESSOR is None: + type(self).setup_processor() + if self.MODEL is None: + type(self).setup_model(self.quant, self.flashattn) + self.device = self.MODEL.device + + def _generation_args(self, image: Image.Image, resulting_messages: list[dict]): + prompt = self.PROCESSOR.apply_chat_template(resulting_messages, add_generation_prompt=True) + inputs = self.PROCESSOR(text=prompt, images=[image], return_tensors="pt") + inputs = {k: v.to(self.device) for k, v in inputs.items()} + + max_new_tokens = 512 + repetition_penalty = 1.2 + decoding_strategy = "Greedy" + temperature = 0.4 + top_p = 0.8 + + generation_args = { + "max_new_tokens": max_new_tokens, + "repetition_penalty": repetition_penalty, + } + + assert decoding_strategy in [ + "Greedy", + "Top P Sampling", + ] + + if decoding_strategy == "Greedy": + generation_args["do_sample"] = False + elif decoding_strategy == "Top P Sampling": + generation_args["temperature"] = temperature + generation_args["do_sample"] = True + generation_args["top_p"] = top_p + + generation_args.update(inputs) + return prompt, generation_args + + def __call__( + self, + img_or_path: Image.Image | Path | str, + prompt_text: str | None = None, + lang: str | None = None, + config: str | None = None, + show_prompt: bool = False, + **kwargs, + ) -> str: + if not self.is_idefics_available(): + raise RuntimeError("Idefics is not installed or not found.") + resulting_messages = [ + { + "role": "user", + "content": [{"type": "image"}] + [ + {"type": "text", "text": prompt_text or self.prompt_text_tmpl.format(lang or self.lang)} + ] + } + ] + image = load_image(img_or_path) + prompt, generation_args = self._generation_args(image, resulting_messages) + generated_ids = self.MODEL.generate(**generation_args) + generated_texts = self.PROCESSOR.batch_decode( + generated_ids[:, generation_args["input_ids"].size(1):], skip_special_tokens=True) + if show_prompt: + cprint("INPUT:", prompt, "|OUTPUT:", generated_texts) + return generated_texts[0]#.strip('"') + + def postprocess_ocr(self, text): + return ' '.join(remove_multiple_whitespaces(text).splitlines()) + + +# %% ../nbs/ocr_idefics.ipynb 50 +class IdeficsExperimentContext(OCRExperimentContext): + @functools.lru_cache() + def mocr(self, lang: str): + if self.ocr_model == 'Idefics': + proc = IdeficsOCR(lang) + else: + engine = self.engines[self.ocr_model] + ocr_processor = ocr.get_ocr_processor(True, engine) + proc = ocr_processor[lang2pcleaner(lang)] + if isinstance(proc, TesseractOcr): + proc.lang = lang2tesseract(lang) + return proc + + def cleanup_model(self): + del IdeficsOCR.MODEL + torch.cuda.empty_cache() + import gc + gc.collect() + IdeficsOCR.MODEL = None + + def setup_idefics(self, quant: QuantT = 'bfloat16', flashattn: bool = True): + if IdeficsOCR.PROCESSOR is None: + IdeficsOCR.setup_processor() + if IdeficsOCR.MODEL is not None: + self.cleanup_model() + if IdeficsOCR.MODEL is None: + IdeficsOCR.setup_model(quant=quant, flashattn=flashattn) + + def show(self): + super().show() + cfg = IdeficsOCR.MODEL.config + if hasattr(cfg, 'quantization_config'): + qcfg = cfg.quantization_config + quant = '4bits' if qcfg.load_in_4bit else '8bits' + else: + quant = 'bfloat16' + cprint( + f"{'Quantization':>17}: {quant!r}\n" + f"{'Flash attention 2':>17}: {cfg._attn_implementation == 'flash_attention_2'}\n" + f"{'VRAM':>17}: {get_gpu_vram(False)}/{get_gpu_vram()} MiB\n" + ) + + def __init__(self, + root_dir: Path | str | None = None, + quant: QuantT = 'bfloat16', + flashattn: bool = True, + *, + config: cfg.Config | None = None, + server: web_server.WebServer | None = None, + run_name: str = 'Idefics-crop-post', + setup_idefics: bool = True, + ): + super().__init__('Idefics', root_dir, config=config, server=server, run_name=run_name) + if setup_idefics: + self.setup_idefics(quant, flashattn) + + diff --git a/pcleaner/_testbed/testbed/ocr_metric.py b/pcleaner/_testbed/testbed/ocr_metric.py new file mode 100644 index 00000000..07ef9a60 --- /dev/null +++ b/pcleaner/_testbed/testbed/ocr_metric.py @@ -0,0 +1,64 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/ocr_metric.ipynb. + +# %% ../nbs/ocr_metric.ipynb 6 +from __future__ import annotations + +import difflib +import html + +from IPython.display import display +from IPython.display import HTML +from rich.console import Console + + +# %% auto 0 +__all__ = ['get_text_diffs_html', 'display_text_diffs'] + +# %% ../nbs/ocr_metric.ipynb 10 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% ../nbs/ocr_metric.ipynb 12 +def get_text_diffs_html(str1, str2: str | None=None, ignore_align: bool = False): + matcher = difflib.SequenceMatcher(None, str1, str2 or '') + html_str1, html_str2 = "", "" + _ch ='⎕' # ▿ + ch = f'&#x{ord(_ch):x};' + span1_g = lambda l: f"{ch*l}" if l > 0 else "" + span1_r = lambda l: f"{ch*l}" if l > 0 else "" + span2 = lambda s: f"{html.escape(s)}" if s else "" + + for opcode in matcher.get_opcodes(): + tag, i1, i2, j1, j2 = opcode + if tag == "equal": + html_str1 += html.escape(str1[i1:i2]) + html_str2 += html.escape(str2[j1:j2]) + elif tag == "replace": + max_span = max(i2 - i1, j2 - j1) + # str1_segment = str1[i1:i2].ljust(max_span) + html_str1 += html.escape(str1[i1:i2]) + span1_g(max_span - (i2 - i1)) + html_str2 += span2(str2[j1:j2]) + (span1_r(max_span - (j2 - j1)) if not ignore_align else '') + elif tag == "delete": + deleted_segment = str1[i1:i2] + html_str1 += html.escape(deleted_segment) + if not ignore_align: html_str2 += span1_r(len(deleted_segment)) + elif tag == "insert": + inserted_segment = str2[j1:j2].replace(" ", _ch) + html_str1 += span1_g(len(inserted_segment)) + html_str2 += span2(inserted_segment) + html_str1 = f"
{html_str1}
" + html_str2 = f"
{html_str2}
" + return html_str1, html_str2 + +def display_text_diffs(str1, str2): + """ + Displays two strings one above the other, with differing characters highlighted in red in the + second string only, using difflib.SequenceMatcher to align the strings and ensure matching + sequences are vertically aligned. + + :param str1: The first string to compare. + :param str2: The second string to compare. + """ + html_str1, html_str2 = get_text_diffs_html(str1, str2) + display(HTML(f"
{html_str1}
{html_str2}
")) diff --git a/pcleaner/_testbed/testbed/visor.py b/pcleaner/_testbed/testbed/visor.py new file mode 100644 index 00000000..a8a7c820 --- /dev/null +++ b/pcleaner/_testbed/testbed/visor.py @@ -0,0 +1,391 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/visor.ipynb. + +# %% ../nbs/visor.ipynb 1 +from __future__ import annotations + + +# %% auto 0 +__all__ = ['ContextVisor', 'Spinner'] + +# %% ../nbs/visor.ipynb 5 +from collections import defaultdict +from typing import Any +from typing import TypeAlias + +import ipywidgets as W +import traitlets as T +from IPython.display import clear_output +from IPython.display import display +from IPython.display import HTML +from ipywidgets.widgets.interaction import show_inline_matplotlib_plots +from rich.console import Console + + +# %% ../nbs/visor.ipynb 6 +from pcleaner._testbed.testbed.helpers import _pops_ +from pcleaner._testbed.testbed.helpers import cleanupwidgets + + +# %% ../nbs/visor.ipynb 10 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% ../nbs/visor.ipynb 12 +CtlT: TypeAlias = W.ValueWidget | W.fixed + +NO_UI = W.DOMWidget(layout={'display': 'none'}) +NO_UI.close() + +#| export + +UPDATE_SCRIPT = f""" + +""" + + +# %% ../nbs/visor.ipynb 13 +class ContextVisor: + ctx: Any + values: dict[str, Any] = {} + + _ctxs: dict[str, ContextVisor] = {} + _hdlrs: dict[str, ContextVisor] = {} + _css: str = '' + _ctl2name: dict[CtlT, str] + _name2comp: dict[str, ContextVisor] + _out: W.Output | None = None + _w: W.DOMWidget | None = None + _controls: dict[str, CtlT] | None = None + _all_controls: dict[str, CtlT] | None = None + _ui_cls: type[W.Box] = W.HBox + _inited = False + + @property + def w(self) -> W.DOMWidget: + "Container (DOM)widget of this comp." + if self._inited and self._w is None: + self._w = self._setup_ui() or NO_UI + return self._w # type: ignore + @property + def out(self) -> W.Output: + if self._inited and self._out is None: + self._out = W.Output() + self._out.clear_output(wait=True) + return self._out # type: ignore + @property + def controls(self) -> dict[str, CtlT]: + if self._controls is None: + self._controls = self.setup_controls() if self._inited else {} + return self._controls + @property + def all_controls(self) -> dict[str, CtlT]: + if self._all_controls is None: + controls = {} + if self._inited: + for visor in self._ctxs.values(): + controls.update(visor.all_controls) + controls.update(self.controls) + self._all_controls = controls + self._ctl2name = {v:k for k,v in controls.items()} + return self._all_controls # type: ignore + + @property + def all_values(self): + """Values from first level comps, keyed by comp name. + NOTE: will fail for nested contexts or more than one level. + """ + return {**{k:v.values for k,v in (self.comps | {'self': self}).items()}} + + def _all_values(self): + "Flattened values from all comps" + all_values = {} + for comp in [*self.comps.values(), self]: all_values.update(comp.values) + return all_values + + @property + def comps(self): return self._ctxs + def comp(self, k: str) -> ContextVisor | None: return self._ctxs.get(k) + def handler(self, k: str) -> ContextVisor | None: return self._hdlrs.get(k) + + @property + def styler(self) -> W.HTML | str: + if getattr(self, '_style', None) is None: + stl = self.setup_style() + if stl: + stl_id = 'stl-' + str(id(self)) + stl = f"" + self._style = W.HTML(stl) + else: + self._style = '' + return self._style + def setup_style(self): + collate = [_.setup_style() for _ in self.comps.values()] + if self._css: collate.append(self._css) + return '\n'.join([_ for _ in collate if _]) + + def update_output(self, **kwargs): + cprint(kwargs) + + def setup_controls(self) -> dict[str, CtlT]: + widgets = [W.interactive.widget_from_abbrev(v) for k, v in self.values.items()] + widgets = {k:W.fixed(v) if w is None else w for (k, v), w in zip(self.values.items(), widgets)} + # return {k: W.Label(value=str(k)) for k,w in self.values.items()} + return widgets + + def hide(self): + if (w := self.w) is not NO_UI: + w.layout.visibility = 'hidden' + def show(self): + if (w := self.w) is not NO_UI: + w.layout.visibility = 'visible' + + def comps_ui(self): + comps = [] + if self._inited: + for visor in self.comps.values(): + if (visor_ui := visor._setup_ui()) is not None: + comps.append(visor_ui) + return comps + + + def _setup_ui(self): + if not self._inited: return + w = self.setup_ui() + if w is not None: + w.add_class('context-visor') + w.add_class(str(id(self))) + return w + + def setup_ui(self) -> W.DOMWidget | None: + """Get the container widget for this comp. + This method should be the only one called when the comp is nested inside other comp. + """ + uis = [*self.comps_ui(), *self.controls.values()] + return self._ui_cls(uis) if uis else None + + def setup_display(self): + "Generates one time ui" + if not self._inited: return + if self._w is None: + self._w = self._setup_ui() + + + def _output(self, **kwargs): + # group keys by comp + collator = defaultdict(dict) + for k,v in kwargs.items(): + if (comp := self.handler(k)) is not None: + collator[comp][k] = v + else: + # keys w/out control assigned, considered internal state + collator[self][k] = v + # group comps by output + outs = defaultdict(list) + for comp, kw in collator.items(): + outs[comp.out].append((comp, kw)) + for out, g in outs.items(): + show_inline_matplotlib_plots() + with out: + clear_output(wait=True) + for comp, kw in g: + comp.update_output(**kw) + show_inline_matplotlib_plots() + + def _observe(self, change): + control_name = self._ctl2name[change['owner']] + kwargs = {control_name: change['new']} + updated = self._update(**kwargs) + self._output(**updated) + def setup_ux(self): pass + def _setup_ux(self): + for visor in self.comps.values(): + visor._setup_ux() + self.setup_ux() + def interactive_output(self): + controls = self.all_controls + all_values = self._all_values() + for k,w in controls.items(): + if k in all_values: + w.observe(self._observe, 'value') + + def display(self, **kwargs): + if not self._inited: return + if self._w is None: + self.setup_display() + self.interactive_output() + self._update(**(self.values | kwargs)) + all_values = self._all_values() + self._hdlrs = {k:self._hdlrs.get(k, self) for k in all_values} + self._output(**all_values) + # ux final touches once everything (including outputs) is setup + # for visor in [*self.comps.values(), self]: + # visor.setup_ux() + self._setup_ux() + stl = self.styler + ui: list = [stl] if stl else [] + if (w := self.w) is not NO_UI: + ui.append(w) + for comp in [*self.comps.values(), self]: + if comp._out is not None: + ui.append(comp._out) + self._final = W.VBox(ui) + self._display_handle = display(self._final, display_id=str(id(self))) + else: + self.update(**kwargs) + def _ipython_display_(self): self.display() + + def _update(self, update_value: bool=True, **kwargs): + updated = {} + for visor in self.comps.values(): + updated.update(visor._update(update_value=update_value, **kwargs)) + values = self.values + my_vals = _pops_(kwargs, self.values.keys()) + for k,v in my_vals.items(): + if v is not None and v != values[k]: + if update_value: + values[k] = v + updated[k] = v + return updated + def update(self, **kwargs): + updated = self._update(update_value=False, **kwargs) + controls = self.all_controls + for k,v in updated.items(): + if k in controls: + if hasattr((ctl := controls[k]), 'value'): + ctl.value = v # will trigger update (self._observe) + elif k in (vv := self._name2comp): + # update manually + comp = vv[k] + if v != comp.values[k]: + comp.values[k] = v + self._output(**{k:v}) + + + def close(self): + controls = self.all_controls + for w in controls.values(): + try: w.unobserve(self._observe, 'value') + except: pass + if isinstance(w, W.Widget): + w.close() + for visor in self._ctxs.values(): + if w := getattr(visor, '_w', None): w.close() + if visor._out is not self._out: + if o := getattr(visor, '_out', None): o.close() + visor.close() + if w := getattr(self, '_w', None): w.close() + if o := getattr(self, '_out', None): o.close() + if f := self._final: f.close() + if self._display_handle is not None: + self._display_handle.update(HTML(UPDATE_SCRIPT)) + + + def __del__(self): + self.close() + + def __init__(self, + ctx: Any, + values: dict[str, Any], + out: W.Output | None = None, + ctxs: dict[str, ContextVisor] | None = None, + hdlrs: dict[str, ContextVisor] | None = None, + css: str | None = None, + ): + # Only setup some state. Controls, values and containers will be setup only when explicitly displayed + self._display_handle = None + self._final = None + self.ctx = ctx + self.values = values or {} + self._out = out + self._ctxs = comps = ctxs or {} + self._hdlrs = hdlrs or {} + if css is not None: + self._css = css + self._name2comp = name2comp = {} + for n,vv in self.all_values.items(): + comp = comps.get(n, self) + for k in vv: + name2comp[k] = comp + self._inited = True + + +# %% ../nbs/visor.ipynb 25 +spinner_css = """ + .wrapper-spinner { + overflow: hidden; + width: fit-content; + height: fit-content; + } + + .loading-spinner { + display: flex; + align-items: center; + justify-content: center; + border: 1px solid white; + border-radius: 50%; + } + + .spinner { + border: |border_width|px solid rgba(128,128,128,.5); + border-radius: 50%; + border-left-color: red; + animation: spin 1s infinite linear; + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } +""" + + +# %% ../nbs/visor.ipynb 32 +class Spinner(ContextVisor): + ctx: T.HasTraits + + def loading_spinner(self, size=36, border_width=4): + bw = border_width*2 + html: str = f''' +
+
+
+ ''' + return html + + def setup_controls(self): + spinner = W.HTML(self.loading_spinner(self.size, self.border_width)) + spinner.add_class('wrapper-spinner') + return {'spinner': spinner} + + @property + def spinner(self) -> W.HTML: return self.controls['spinner'] # type: ignore + + def hide(self): self.spinner.layout.display = 'none' + def show(self): self.spinner.layout.display = 'block' + + def setup_ux(self): + source = (self.ctx, '_running') + target = (self.spinner.layout, 'display') + self._link = T.dlink(source, target, lambda x: 'block' if x else 'none') + + def close(self): + if l := getattr(self, '_link', None): l.unlink() + super().close() + + def __init__(self, + ctx: T.HasTraits, + size: int = 24, + border_width: int = 4, + **kwargs + ): + self.size = size + self.border_width = border_width + self._link = None + super().__init__(ctx, {}, css=spinner_css.replace('|border_width|', str(border_width)), **kwargs) + diff --git a/pcleaner/_testbed/testbed/web_server.py b/pcleaner/_testbed/testbed/web_server.py new file mode 100644 index 00000000..bb401890 --- /dev/null +++ b/pcleaner/_testbed/testbed/web_server.py @@ -0,0 +1,330 @@ +# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/web_server.ipynb. + +# %% ../nbs/web_server.ipynb 1 +from __future__ import annotations + + +# %% auto 0 +__all__ = ['display_ngrok_warning', 'WebServer', 'setup_ngrok', 'WebServerStdlib', 'WebServerBottle'] + +# %% ../nbs/web_server.ipynb 12 +import getpass +import http.server +import os +import signal +import socketserver +import threading +import uuid +from http import HTTPStatus +from pathlib import Path +from typing import Protocol + +import portpicker +import psutil +import requests +import rich +from IPython.display import display +from IPython.display import HTML +from loguru import logger +from pyngrok import conf +from pyngrok import ngrok +from rich.console import Console + + +# %% ../nbs/web_server.ipynb 13 +from pcleaner._testbed.testbed.bottle import Bottle +from pcleaner._testbed.testbed.bottle import HTTPError +from pcleaner._testbed.testbed.bottle import response +from pcleaner._testbed.testbed.bottle import run +from pcleaner._testbed.testbed.bottle import static_file + + +# %% ../nbs/web_server.ipynb 17 +console = Console(width=104, tab_size=4, force_jupyter=True) +cprint = console.print + + +# %% ../nbs/web_server.ipynb 18 +def display_ngrok_warning(url): + did = 'ngrokFrame' + str(uuid.uuid4()) + html_code = f""" +
+
+

Ngrok displays a warning page as a security measure to prevent unintentional access to your local servers. This page requires you to confirm that you wish to proceed to the content.

+

Please review the ngrok warning page displayed below. If prompted, click 'Visit Page' to proceed.

+ Don't worry if you see a 404 or 403 error. Then, you can click the 'Close' button below to hide this section.

+
+ + +
+""" + + display(HTML(html_code)) + + +# %% ../nbs/web_server.ipynb 19 +class WebServer(Protocol): + @property + def public_url(self) -> str | None: ... + @property + def unc_share(self) -> Path | None: ... + @property + def prefix(self) -> str: ... + @property + def running(self) -> bool: ... + def __init__(self, directory: Path | str = ""): ... + def start(self): ... + def stop(self): ... + + +def setup_ngrok(server_cls: type[WebServer], images_dir: str | Path): + cprint( + "Enter your ngrok authtoken, which can be copied from " + "https://dashboard.ngrok.com/get-started/your-authtoken" + ) + auth_token = getpass.getpass() + conf.get_default().auth_token = auth_token + ngrok.set_auth_token(auth_token) + + server = server_cls(directory=str(images_dir)) + try: + server.start() + except Exception as e: + cprint(f"Error starting server: {e}") + return None + + display_ngrok_warning(f"{server.public_url}/{server.prefix}/pcleaner.png") + return server + + +# %% ../nbs/web_server.ipynb 24 +class ImageHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): + def end_headers(self): + for k,v in { + 'ngrok-skip-browser-warning': 'true', + 'User-Agent': 'MyCustomUserAgent/1.0', + 'Cache-Control': 'public, max-age=86400' + }.items(): + self.send_header(k, v) + super().end_headers() + + def do_GET(self): + if self.is_image_request(self.path): + super().do_GET() + else: + self.send_error(HTTPStatus.FORBIDDEN, "Only image files are accessible.") + + def is_image_request(self, path): + allowed_extensions = ('.jpg', '.jpeg', '.png', '.gif', '.webp') + _, ext = os.path.splitext(path) + return ext.lower() in allowed_extensions + + def __init__(self, *args, **kwargs): + super().__init__(*args, directory=self.directory, **kwargs) + + +# %% ../nbs/web_server.ipynb 25 +class WebServerStdlib: + """ + A simple web server for serving images from a local directory using http.server and ngrok. + + It is intended to be used in environments like Google Colab, where direct + web server hosting might not be feasible. It uses ngrok to allow images to be accessed + via a public URL. + + Attributes: + directory (str): The directory from which files are served. + port (int): The local port on which the server listens. + public_url (str): The ngrok public URL where the server is accessible. + tunnel (ngrok.NgrokTunnel): The ngrok tunnel object. + + Methods: + start(): Starts the web server and the ngrok tunnel. + stop(): Stops the web server and disconnects the ngrok tunnel. + make_request(path="/"): Makes a request to the ngrok URL to fetch data from the server. + """ + + def __init__(self, directory: Path | str=""): + port = portpicker.pick_unused_port() + self.port = port + if isinstance(directory, str): + directory = Path(directory) + assert directory.exists(), f"Directory {directory} does not exist" + self.directory = str(directory.resolve()) + self.thread = None + self.httpd = None + self.public_url = None + self.prefix = '' + self.unc_share = None + self.tunnel = None + + @property + def running(self): + return self.thread is not None and self.thread.is_alive() + + def start_server(self): + Handler = ImageHTTPRequestHandler + Handler.directory = self.directory + try: + with socketserver.TCPServer(("", self.port), Handler) as httpd: + self.httpd = httpd + httpd.serve_forever() + except OSError as e: + cprint(f"Error: {e}") + + def start(self): + if self.thread is None or not self.thread.is_alive(): + self.thread = threading.Thread(target=self.start_server) + self.thread.start() + self.tunnel = ngrok.connect(self.port) # type: ignore + self.public_url = self.tunnel.public_url + if self.public_url is not None: + self.unc_share = Path(self.public_url.replace('https:', '')) + cprint(f"ngrok tunnel: {self.tunnel}") + cprint(f"Public URL: {self.public_url}") + else: + cprint("Server is already running") + + def stop(self): + if self.httpd: + self.httpd.shutdown() + self.httpd.server_close() + if self.tunnel and self.tunnel.public_url: + ngrok.disconnect(self.tunnel.public_url) # Use the stored tunnel object's URL + cprint("Ngrok tunnel disconnected") + ngrok.kill() + if self.thread: + self.thread.join() + self.thread = self.public_url = self.unc_share = None + cprint("Server stopped") + + def make_request(self, path="/"): + """Makes a request to the ngrok URL with headers to bypass the ngrok warning.""" + if self.public_url: + url = f"{self.public_url}{path}" + headers = { + "ngrok-skip-browser-warning": "true", + "User-Agent": "MyCustomUserAgent/1.0" + } + response = requests.get(url, headers=headers) + return response.text + else: + return "Server not started or public URL not available." + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.stop() + + +# %% ../nbs/web_server.ipynb 39 +app = Bottle() + +@app.route('/images/') # type: ignore +def serve_image(filename): + if not filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.webp')): + return HTTPError(404, "File not found") + response.set_header('Cache-Control', 'public, max-age=86400') # Set caching headers + return static_file(filename, root=app.config['image_dir']) + +@app.route('/shutdown') # type: ignore +def shutdown(): + current_process = psutil.Process() + current_process.send_signal(signal.SIGTERM) + + +# %% ../nbs/web_server.ipynb 40 +class WebServerBottle: + """ + A simple web server for serving images from a local directory using ngrok. + This class uses the Bottle framework to handle HTTP requests and ngrok to expose the + server to the internet.It is designed to be used in environments like Google Colab, + where direct web server hosting might not be feasible. + + Attributes: + directory (Path | str): The directory from which files are served. + port (int): The local port on which the server listens. + public_url (str): The ngrok public URL where the server is accessible. + tunnel (ngrok.NgrokTunnel): The ngrok tunnel object. + + Methods: + start(): Starts the web server and the ngrok tunnel. + stop(): Stops the web server and disconnects the ngrok tunnel. + """ + + def __init__(self, directory: Path | str = ""): + self.port = portpicker.pick_unused_port() + if isinstance(directory, str): + directory = Path(directory) + assert directory.exists(), f"Directory {directory} does not exist" + self.directory = directory + self.thread = None + self.httpd = None + self.public_url = None + self.unc_share = None + self.prefix = 'images' + self.tunnel = None + app.config['image_dir'] = str(directory) # directory for Bottle + # app.routes[0].callback.__globals__['image_dir'] = str(directory) # directory for Bottle + + @property + def running(self): + return self.thread is not None and self.thread.is_alive() + + def start_server(self): + def bottle_run(): + run(app, host='localhost', port=self.port) + + self.thread = threading.Thread(target=bottle_run) + self.thread.start() + self.tunnel = ngrok.connect(self.port) # type: ignore + self.public_url = self.tunnel.public_url + if self.public_url is not None: + self.unc_share = Path(self.public_url.replace('https:', ''))/self.prefix + cprint(f"ngrok tunnel: {self.tunnel}") + cprint(f"Public URL: {self.public_url}") + + def start(self): + if self.thread is None or not self.thread.is_alive(): + self.start_server() + else: + cprint("Server is already running") + + def stop(self): + if self.tunnel and self.tunnel.public_url: + ngrok.disconnect(self.tunnel.public_url) + cprint("Ngrok tunnel disconnected") + ngrok.kill() + + if self.thread: + self.make_request('/shutdown') + self.thread.join(timeout=10) + if self.thread.is_alive(): + print("Thread did not terminate, proceeding with forceful shutdown.") + else: + print("Server thread stopped successfully.") + self.thread = self.tunnel = self.public_url = self.unc_share = None + cprint("Server stopped") + + def make_request(self, path="/"): + """Makes a request to the ngrok URL with headers to bypass the ngrok warning.""" + if self.public_url: + url = f"{self.public_url}{path}" + headers = { + "ngrok-skip-browser-warning": "true", + "User-Agent": "MyCustomUserAgent/1.0" + } + response = requests.get(url, headers=headers) + return response.text + else: + return "Server not started or public URL not available." + + def __enter__(self): + self.start() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.stop() + From 730e4943c91dc235ea9949deb8ab6089a1d754ad Mon Sep 17 00:00:00 2001 From: Voxel <41875513+VoxelCubes@users.noreply.github.com> Date: Tue, 28 May 2024 20:53:09 +0200 Subject: [PATCH 08/27] tiny grammar fix --- pcleaner/_testbed/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcleaner/_testbed/README.md b/pcleaner/_testbed/README.md index 0bead663..2adfe12a 100644 --- a/pcleaner/_testbed/README.md +++ b/pcleaner/_testbed/README.md @@ -24,7 +24,7 @@ Instructions to use Google Colab are included in the notebooks. ## Install Test Images The test images are not included in the repository but can be downloaded from the following link: -- [Test images PCISet](https://drive.google.com/file/d/18TSXLCYAPxAlUsdHmgAe6FZM5d8K6gcT/view?usp=drive_link). The notebooks have also instructions and code to download directly the set +- [Test images PCISet](https://drive.google.com/file/d/18TSXLCYAPxAlUsdHmgAe6FZM5d8K6gcT/view?usp=drive_link). The notebooks also have instructions and code to download the set directly After downloading, place the test images in the [source](source) directory. If you want to use your own, each image should have a corresponding text file with the same name, but with the extension `.txt`, which contains the ground truth data, one line per box (as calculated by PanelCleaner). Optionally, you can also include a `.json` file with the same name, specifying the language of the page: ```json From 0b236fe452440166b2866d1a9bac5c64e5e62dd4 Mon Sep 17 00:00:00 2001 From: Spikey Date: Sat, 25 May 2024 16:00:32 +0200 Subject: [PATCH 09/27] move accurecy metric logic to its notebook; change ground_truth file format; start refactorin Experiment_run --- pcleaner/_testbed/nbs/experiments.ipynb | 907 +++++++++++------------- pcleaner/_testbed/nbs/ocr_metric.ipynb | 96 ++- pcleaner/_testbed/testbed/ocr_metric.py | 39 +- 3 files changed, 514 insertions(+), 528 deletions(-) diff --git a/pcleaner/_testbed/nbs/experiments.ipynb b/pcleaner/_testbed/nbs/experiments.ipynb index bde864b5..0d9e564c 100644 --- a/pcleaner/_testbed/nbs/experiments.ipynb +++ b/pcleaner/_testbed/nbs/experiments.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -11,12 +11,8 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -26,7 +22,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -44,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -60,7 +56,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -69,7 +65,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -85,7 +81,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -109,12 +105,8 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -161,12 +153,8 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -180,12 +168,8 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "import copy\n", @@ -210,12 +194,8 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "# pretty print by default\n", @@ -224,12 +204,8 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| exporti\n", @@ -261,12 +237,8 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| exporti\n", @@ -292,7 +264,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -373,7 +345,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -417,7 +389,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -433,7 +405,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -449,7 +421,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -465,7 +437,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -512,7 +484,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -618,7 +590,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -643,7 +615,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -666,7 +638,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -682,7 +654,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -698,7 +670,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -738,104 +710,73 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## OCR results clean-up" + "## Ground truth" ] }, { "cell_type": "code", - "execution_count": 8, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", "\n", - "def remove_multiple_whitespaces(text):\n", - " return ' '.join(text.split())\n", - "\n", - " \n", - "def postprocess_ocr(text):\n", - " \"Basic postprocessing for English Tesseract OCR results.\"\n", - " return ' '.join(remove_multiple_whitespaces(text).splitlines()).capitalize()\n", - "\n", - "def accuracy_ocr_naive(text, ground_truth):\n", - " return sum(1 for a, b in zip(text, ground_truth) if a == b) / len(text)\n", + "def ground_truth_path_old(page_data: st.PageData):\n", + " path = Path(page_data.original_path)\n", + " return path.with_stem(path.stem + '_gt').with_suffix('.txt')\n", "\n", "\n", - "def accuracy_ocr_difflib(text, ground_truth):\n", - " \"\"\"\n", - " Calculates the OCR accuracy based on the similarity between the OCR text and the ground truth text,\n", - " using difflib's SequenceMatcher to account for differences in a manner similar to git diffs.\n", + "def read_ground_truth_old(page_data: st.PageData, root_dir: Path):\n", + " gts_path = root_dir / ground_truth_path_old(page_data)\n", + " if gts_path.exists():\n", + " gts = gts_path.read_text(encoding=\"utf-8\").splitlines()\n", + " else:\n", + " gts = [\"\" for _ in range(len(page_data.boxes))]\n", + " return gts\n", "\n", - " :param text: The OCR-generated text.\n", - " :param ground_truth: The ground truth text.\n", - " :return: A float representing the similarity ratio between the OCR text and the ground truth, \n", - " where 1.0 is identical.\n", - " \"\"\"\n", - " # Initialize the SequenceMatcher with the OCR text and the ground truth\n", - " matcher = difflib.SequenceMatcher(None, text, ground_truth)\n", - " \n", - " # Get the similarity ratio\n", - " similarity_ratio = matcher.ratio()\n", - " \n", - " return similarity_ratio" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Ground truth" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, - "outputs": [], - "source": [ - "#| export\n", "\n", "def ground_truth_path(page_data: st.PageData):\n", " path = Path(page_data.original_path)\n", - " return path.with_stem(path.stem + '_gt').with_suffix('.txt')\n", + " return path.with_stem(path.stem + '_gt').with_suffix('.json')\n", "\n", "\n", - "def read_ground_truth(page_data: st.PageData, root_dir: Path):\n", + "def read_ground_truth(page_data: st.PageData, root_dir: Path) -> dict[str, list[str]]:\n", " gts_path = root_dir / ground_truth_path(page_data)\n", + " empty = [\"\" for _ in range(len(page_data.boxes))]\n", " if gts_path.exists():\n", - " gts = gts_path.read_text(encoding=\"utf-8\").splitlines()\n", - " else:\n", - " gts = [\"\" for _ in range(len(page_data.boxes))]\n", - " return gts\n" + " try:\n", + " with open(gts_path, 'r') as f:\n", + " data = json.load(f)\n", + " if 'all-caps' not in data:\n", + " data['all-caps'] = empty\n", + " if 'capitalized' not in data:\n", + " data['capitalized'] = empty.copy()\n", + " return data\n", + " except Exception as e:\n", + " logger.error(f\"Error loading {gts_path}: {e}\")\n", + " gts = {'all-caps': empty,\n", + " 'capitalized': empty.copy()}\n", + " return gts\n", + "\n", + "\n", + "def save_ground_truth(gts: dict[str, list[str]], page_data: st.PageData, root_dir: Path):\n", + " fp = root_dir / ground_truth_path(page_data)\n", + " with open(fp, 'w') as f:\n", + " json.dump(gts, f, indent=2)\n", + " return fp\n" ] }, { "cell_type": "markdown", - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "metadata": {}, "source": [ "## Cropping" ] }, { "cell_type": "code", - "execution_count": 10, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -878,12 +819,8 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -906,12 +843,8 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| exporti\n", @@ -924,12 +857,8 @@ }, { "cell_type": "code", - "execution_count": 13, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -958,12 +887,8 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": { - "notebookRunGroups": { - "groupValue": "1" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -1072,12 +997,8 @@ }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -1291,15 +1212,13 @@ " def cleanup_model(self):\n", " pass\n", "\n", - " def __init__(self, name: str, paths: list[Path], root: Path | None = None, run_name: str = 'run1'):\n", + " def __init__(self, name: str, paths: list[Path], root: Path | None = None):\n", " self.name = name\n", " self._root = root or type(self).EXP_DIR\n", " self._paths = paths # relative paths wrt self._root\n", " self._subjects: dict[SubjIdT, ExperimentSubject] = {}\n", " self._exp_runs: dict[str, ExperimentRun] = {}\n", - " self._results = {}\n", - " # default run\n", - " ExperimentRun(self, run_name)\n" + " self._results = {}\n" ] }, { @@ -1311,7 +1230,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1340,7 +1259,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1356,7 +1275,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1377,14 +1296,14 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ "run = exp.experiment_run('test')\n", "test_eq(run, None)\n", "\n", - "test_eq(exp.run_names, ['run1'])\n", + "test_eq(exp.run_names, [])\n", "\n", "# Instantiate run\n", "run = ExperimentRun(exp, 'test')\n", @@ -1393,11 +1312,11 @@ "test_is(_, run)\n", "test_is(run, ExperimentRun(exp, 'test'))\n", "\n", - "test_eq(exp.run_names, ['run1', 'test'])\n", + "test_eq(exp.run_names, ['test'])\n", "\n", "run2 = ExperimentRun(exp, 'test2')\n", "\n", - "test_eq(exp.run_names, ['run1', 'test', 'test2'])\n" + "test_eq(exp.run_names, ['test', 'test2'])\n" ] }, { @@ -1410,12 +1329,8 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -1446,7 +1361,7 @@ " json_data: dict | None\n", " page_data: st.PageData\n", " _page_lang: str\n", - " _gts: list[str]\n", + " _gts: dict[str, list[str]]\n", " _mask_dilated1: Image.Image | None\n", " _mask_dilated05: Image.Image | None\n", " _mask_dilated02: Image.Image | None\n", @@ -1523,11 +1438,13 @@ " \n", " def setup_ground_truth(self):\n", " self._gts = read_ground_truth(self.page_data, self.exp.root_dir)\n", - " @property\n", - " def gts(self): \n", + " \n", + " def gts(self, version: str = 'capitalized'): \n", " if self._gts is None:\n", " self.setup_ground_truth()\n", - " return self._gts\n", + " if version not in self._gts:\n", + " self._gts[version] = [\"\" for _ in range(len(self.boxes))]\n", + " return self._gts[version]\n", " \n", " @functools.lru_cache(typed=True)\n", " def dilated_mask(self, fraction: float):\n", @@ -1570,12 +1487,8 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -1601,7 +1514,7 @@ " @property\n", " def acc(self):\n", " if self.ocr is not None:\n", - " self._acc = accuracy_ocr_difflib(self.ocr, self.image_ctx.gts[self.block_idx])\n", + " self._acc = accuracy_ocr_difflib(self.ocr, self.image_ctx.gts()[self.block_idx])\n", " return self._acc\n", " @property\n", " def suffix(self): return f\"{self.block_idx}_{self.description}\"\n", @@ -1655,12 +1568,8 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -1703,12 +1612,8 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -1723,7 +1628,16 @@ " OCRModel))\n", "\n", "\n", - "class OCRExperimentRun(ExperimentRun): ...\n", + "class OCRExperimentRun(ExperimentRun): \n", + " def _result_from(self, \n", + " image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None):\n", + " img_ctx = ImageContext(self.exp, image_idx)\n", + " extracted = method in _EXTRACTED_METHODS\n", + " result_cls = ResultOCRExtracted if extracted else ResultOCR\n", + " result = result_cls(img_ctx, int(box_idx), None, None, description=f\"{method.value}\")\n", + " if ocr is not None:\n", + " result.ocr = ocr\n", + " return result\n", "\n", "\n", "class OCRExperimentContext(ExperimentContext):\n", @@ -1741,6 +1655,7 @@ "\n", " # ExperimentRun name -> Image index -> Box index -> Crop method -> Result\n", " _results: dict[RunIdT, dict[ImgIdT, ResultSet]]\n", + " _exp_runs: dict[str, OCRExperimentRun]\n", "\n", " _running = T.Bool(False)\n", " \n", @@ -1796,7 +1711,7 @@ " def ocr_box(self, result: ResultOCR, lang: str): \n", " assert result.image is not None\n", " text = self.mocr(lang)(result.image)\n", - " result.ocr = postprocess_ocr(text)\n", + " result.ocr = text\n", " self._dirty = True\n", " return result\n", "\n", @@ -1908,15 +1823,15 @@ " def _update_results(self, run_name: str, img_idx: ImgIdT, results: ResultSetDefault):\n", " self._results[run_name][img_idx] = cast(ResultSet, results)\n", " \n", - " def _result_from(self, \n", - " image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None):\n", - " img_ctx = ImageContext(self, image_idx)\n", - " extracted = method in _EXTRACTED_METHODS\n", - " result_cls = ResultOCRExtracted if extracted else ResultOCR\n", - " result = result_cls(img_ctx, int(box_idx), None, None, description=f\"{method.value}\")\n", - " if ocr is not None:\n", - " result.ocr = ocr\n", - " return result\n", + " # def _result_from(self, \n", + " # image_idx: ImgIdT, box_idx: BoxIdT, method: CropMethod, ocr: str | None = None):\n", + " # img_ctx = ImageContext(self, image_idx)\n", + " # extracted = method in _EXTRACTED_METHODS\n", + " # result_cls = ResultOCRExtracted if extracted else ResultOCR\n", + " # result = result_cls(img_ctx, int(box_idx), None, None, description=f\"{method.value}\")\n", + " # if ocr is not None:\n", + " # result.ocr = ocr\n", + " # return result\n", " \n", " def result(self, \n", " run_name: str,\n", @@ -1927,7 +1842,8 @@ " if not rebuild and _result is not None:\n", " return _result\n", " \n", - " result: ResultOCR = self._result_from(image_idx, box_idx, method)\n", + " run = self._exp_runs[run_name]\n", + " result: ResultOCR = run._result_from(image_idx, box_idx, method)\n", " image, cropped_image, cropped_mask = result.image, None, None\n", " img_ctx = ImageContext(self, image_idx)\n", " base_image = img_ctx.base_image\n", @@ -1958,6 +1874,7 @@ " if ocr:\n", " exp_run.before_result(result)\n", " result = self.ocr_box(result, img_ctx.page_lang)\n", + " result.ocr = postprocess_ocr(result.ocr)\n", " exp_run.after_result(result)\n", " self._results[run_name][image_idx][box_idx][method] = result\n", " self._dirty = True\n", @@ -2056,7 +1973,8 @@ " # self.run_to_json(run_name)\n", " \n", " def _load_run_results(self, run_name: str, run_data: dict[str, dict[str, dict[str, str]]]):\n", - " self._exp_runs[run_name] = OCRExperimentRun(self, run_name)\n", + " run: OCRExperimentRun = cast(OCRExperimentRun, OCRExperimentRun(self, run_name))\n", + " self._exp_runs[run_name] = run\n", " name2idx = {p.name: i for i, p in enumerate(self.image_paths)}\n", " for img_name, data in run_data.items():\n", " img_idx = name2idx.get(img_name, None)\n", @@ -2066,7 +1984,7 @@ " rset: ResultSetDefault = dict_to_resultset(\n", " ImgIdT(img_idx), \n", " data, \n", - " result_factory=self._result_from)\n", + " result_factory=run._result_from)\n", " self._update_results(run_name, img_idx, rset)\n", "\n", " # def load_results(self):\n", @@ -2171,7 +2089,7 @@ " self.ocr_model = ocr_model\n", " root_dir = Path(root_dir)\n", " super().__init__(\n", - " ocr_model, self.get_image_paths(root_dir), root=root_dir, run_name=run_name)\n", + " ocr_model, self.get_image_paths(root_dir), root=root_dir)\n", " self.image_paths = self._paths\n", " self._reset_results()\n", " self._images = self._subjects\n", @@ -2181,17 +2099,16 @@ " self.use_tunnel = use_tunnel\n", " self.server = server or SERVER\n", " if load:\n", - " self._from_json()\n" + " self._from_json()\n", + " # default run\n", + " ExperimentRun(self, run_name)\n", + "\n" ] }, { "cell_type": "code", - "execution_count": 20, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| exporti\n", @@ -2209,7 +2126,7 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2231,12 +2148,8 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -2246,7 +2159,7 @@ "\n", " @classmethod\n", " def diff_tagged(cls, result: ResultOCR):\n", - " _, html = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr, False)\n", + " _, html = get_text_diffs_html(result.image_ctx.gts()[result.block_idx], result.ocr, False)\n", " return f\"{html}\"\n", "\n", " def as_html(self):\n", @@ -2258,7 +2171,7 @@ " acc_html = ''\n", " if has_ocr:\n", " acc_html = f\"
{result.acc:.2f}\"\n", - " html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr)\n", + " html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts()[result.block_idx], result.ocr)\n", " box_image_path = result.cache_image()\n", " html1 = get_columns_html([[DI(box_image_path)], [(result.ocr or '') + acc_html]])\n", " if has_ocr:\n", @@ -2271,7 +2184,7 @@ " result = self.ctx\n", " has_ocr = result.ocr is not None\n", " DI = cast(OCRExperimentContext, result.image_ctx.exp).DI\n", - " html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts[result.block_idx], result.ocr)\n", + " html_str1, html_str2 = get_text_diffs_html(result.image_ctx.gts()[result.block_idx], result.ocr)\n", " if has_ocr:\n", " diff_html = f\"
{html_str1}
{html_str2}
\"\n", " else:\n", @@ -2308,12 +2221,8 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "EXP_DIR = ExperimentContext.EXP_DIR\n", @@ -2345,12 +2254,8 @@ }, { "cell_type": "code", - "execution_count": 23, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "# CONFIG = cfg.load_config()\n", @@ -2387,12 +2292,8 @@ }, { "cell_type": "code", - "execution_count": 24, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "CONTEXT = OCRExperimentContext('Tesseract')\n" @@ -2400,7 +2301,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -2500,12 +2401,8 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [ { "data": { @@ -2544,7 +2441,7 @@ " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" ] }, - "execution_count": 25, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2564,7 +2461,7 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2590,12 +2487,8 @@ }, { "cell_type": "code", - "execution_count": 26, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [ { "data": { @@ -2603,7 +2496,7 @@ "'Tesseract-crop'" ] }, - "execution_count": 26, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -2631,12 +2524,8 @@ }, { "cell_type": "code", - "execution_count": 27, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -2671,7 +2560,7 @@ }, { "cell_type": "code", - "execution_count": 53, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -2705,12 +2594,8 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -2754,7 +2639,7 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -2785,7 +2670,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2794,7 +2679,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2803,7 +2688,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2812,7 +2697,7 @@ }, { "cell_type": "code", - "execution_count": 59, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2828,12 +2713,8 @@ }, { "cell_type": "code", - "execution_count": 29, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -2870,7 +2751,7 @@ }, { "cell_type": "code", - "execution_count": 75, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -2898,7 +2779,7 @@ }, { "cell_type": "code", - "execution_count": 65, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -2923,7 +2804,7 @@ }, { "cell_type": "code", - "execution_count": 66, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -2939,12 +2820,8 @@ }, { "cell_type": "code", - "execution_count": 30, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -2982,7 +2859,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3014,12 +2891,8 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -3067,7 +2940,7 @@ " self.image_info(image_ctx)\n", " RenderJSON(image_ctx.json_data, 350, 2).display()\n", " if display_option in (DisplayOptions.ALL, DisplayOptions.GROUND_TRUTH):\n", - " cprint(image_ctx.gts)\n", + " cprint(image_ctx.gts())\n", " if display_option == DisplayOptions.CONFIG:\n", " self.ctx.show()\n", " if display_option == DisplayOptions.IMAGE:\n", @@ -3113,7 +2986,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3138,7 +3011,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3154,12 +3027,8 @@ }, { "cell_type": "code", - "execution_count": 32, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -3199,7 +3068,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3226,7 +3095,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3243,12 +3112,8 @@ }, { "cell_type": "code", - "execution_count": 33, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -3277,7 +3142,7 @@ }, { "cell_type": "code", - "execution_count": 76, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3306,7 +3171,7 @@ }, { "cell_type": "code", - "execution_count": 77, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3323,12 +3188,8 @@ }, { "cell_type": "code", - "execution_count": 34, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "BASE_IMAGE_IDX: ImgIdT = cast(ImgIdT, CONTEXT.normalize_idx(\"Strange_Tales_172005.jpg\"))\n", @@ -3356,7 +3217,7 @@ }, { "cell_type": "code", - "execution_count": 79, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3365,7 +3226,7 @@ }, { "cell_type": "code", - "execution_count": 80, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3389,7 +3250,7 @@ }, { "cell_type": "code", - "execution_count": 81, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3398,23 +3259,19 @@ }, { "cell_type": "code", - "execution_count": 35, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", - "
\n", - "
\n", + "
\n", + "
\n", " \n", "
\n", @@ -3442,7 +3299,7 @@ }, { "cell_type": "code", - "execution_count": 83, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3458,7 +3315,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3483,7 +3340,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3520,12 +3377,8 @@ }, { "cell_type": "code", - "execution_count": 36, - "metadata": { - "notebookRunGroups": { - "groupValue": "2" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -3600,7 +3453,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3609,7 +3462,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3640,7 +3493,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3649,7 +3502,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -3673,7 +3526,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3713,7 +3566,7 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -3765,36 +3618,133 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": null, "metadata": {}, "outputs": [ { "data": { + "text/html": [ + "
[\n",
+       "    'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \n",
+       "Orleans, kept tidy by a white-haired old man known only as Bambu.',\n",
+       "    'The house and the old man are alike in many ways; tall, proud, patient, contented always to wait \n",
+       "until their master comes home--',\n",
+       "    'And one in need of some help, it would appear.',\n",
+       "    'Bambu-- we have a guest.',\n",
+       "    '--and tonight, he comes most urgently, slamming open the oaken front doors!',\n",
+       "    'Tell me, master-- how may Bambu serve?',\n",
+       "    'Some blankets to keep her warm, Bambu-- and perhaps some dry clothes',\n",
+       "    \"The echo of the old man's footsteps fades down the hall as...\",\n",
+       "    'How curious the whims of fate. Had I not chanced to stroll along the river tonight--',\n",
+       "    'As quickly as I can, master',\n",
+       "    '--the girl would most surely be dead by now.',\n",
+       "    'Ghede has been generous. the Death God has given the girl a second chance at--',\n",
+       "    \"Easy, girl-- there's nothing to scream about anymore.\",\n",
+       "    \"You're among friends now, you're safe!\",\n",
+       "    'Continued after next page'\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New \u001b[0m\n", + "\u001b[32mOrleans, kept tidy by a white-haired old man known only as Bambu.'\u001b[0m,\n", + " \u001b[32m'The house and the old man are alike in many ways; tall, proud, patient, contented always to wait \u001b[0m\n", + "\u001b[32muntil their master comes home--'\u001b[0m,\n", + " \u001b[32m'And one in need of some help, it would appear.'\u001b[0m,\n", + " \u001b[32m'Bambu-- we have a guest.'\u001b[0m,\n", + " \u001b[32m'--and tonight, he comes most urgently, slamming open the oaken front doors!'\u001b[0m,\n", + " \u001b[32m'Tell me, master-- how may Bambu serve?'\u001b[0m,\n", + " \u001b[32m'Some blankets to keep her warm, Bambu-- and perhaps some dry clothes'\u001b[0m,\n", + " \u001b[32m\"The echo of the old man's footsteps fades down the hall as...\"\u001b[0m,\n", + " \u001b[32m'How curious the whims of fate. Had I not chanced to stroll along the river tonight--'\u001b[0m,\n", + " \u001b[32m'As quickly as I can, master'\u001b[0m,\n", + " \u001b[32m'--the girl would most surely be dead by now.'\u001b[0m,\n", + " \u001b[32m'Ghede has been generous. the Death God has given the girl a second chance at--'\u001b[0m,\n", + " \u001b[32m\"Easy, girl-- there's nothing to scream about anymore.\"\u001b[0m,\n", + " \u001b[32m\"You're among friends now, you're safe!\"\u001b[0m,\n", + " \u001b[32m'Continued after next page'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
[\n",
+       "    'EMBOWERED BY GREAT GNARLED CYPRESS TREES, THE ANCIENT MANOR STANDS ALONE ON THE OUTSKIRTS OF NEW \n",
+       "ORLEANS, KEPT TIDY BY A WHITE-HAIRED OLD MAN KNOWN ONLY AS BAMBU.',\n",
+       "    'THE HOUSE AND THE OLD MAN ARE ALIKE IN MANY WAYS; TALL, PROUD, PATIENT, CONTENTED ALWAYS TO WAIT \n",
+       "UNTIL THEIR MASTER COMES HOME--',\n",
+       "    'AND ONE IN NEED OF SOME HELP, IT WOULD APPEAR.',\n",
+       "    'BAMBU-- WE HAVE A GUEST.',\n",
+       "    '--AND TONIGHT, HE COMES MOST URGENTLY, SLAMMING OPEN THE OAKEN FRONT DOORS!',\n",
+       "    'TELL ME, MASTER-- HOW MAY BAMBU SERVE?',\n",
+       "    'SOME BLANKETS TO KEEP HER WARM, BAMBU-- AND PERHAPS SOME DRY CLOTHES',\n",
+       "    \"THE ECHO OF THE OLD MAN'S FOOTSTEPS FADES DOWN THE HALL AS...\",\n",
+       "    'HOW CURIOUS THE WHIMS OF FATE. HAD I NOT CHANCED TO STROLL ALONG THE RIVER TONIGHT--',\n",
+       "    'AS QUICKLY AS I CAN, MASTER',\n",
+       "    '--THE GIRL WOULD MOST SURELY BE DEAD BY NOW.',\n",
+       "    'GHEDE HAS BEEN GENEROUS. THE DEATH GOD HAS GIVEN THE GIRL A SECOND CHANCE AT--',\n",
+       "    \"EASY, GIRL-- THERE'S NOTHING TO SCREAM ABOUT ANYMORE.\",\n",
+       "    \"YOU'RE AMONG FRIENDS NOW, YOU'RE SAFE!\",\n",
+       "    'CONTINUED AFTER NEXT PAGE'\n",
+       "]\n",
+       "
\n" + ], "text/plain": [ - "['Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.',\n", - " 'The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home--',\n", - " 'And one in need of some help, it would appear.',\n", - " 'Bambu-- we have a guest.',\n", - " '--and tonight, he comes most urgently, slamming open the oaken front doors!',\n", - " 'Tell me, master-- how may Bambu serve?',\n", - " 'Some blankets to keep her warm, Bambu-- and perhaps some dry clothes',\n", - " \"The echo of the old man's footsteps fades down the hall as...\",\n", - " 'How curious the whims of fate. Had I not chanced to stroll along the river tonight--',\n", - " 'As quickly as I can, master',\n", - " '--the girl would most surely be dead by now.',\n", - " 'Ghede has been generous. the Death God has given the girl a second chance at--',\n", - " \"Easy, girl-- there's nothing to scream about anymore.\",\n", - " \"You're among friends now, you're safe!\",\n", - " 'Continued after next page']" + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'EMBOWERED BY GREAT GNARLED CYPRESS TREES, THE ANCIENT MANOR STANDS ALONE ON THE OUTSKIRTS OF NEW \u001b[0m\n", + "\u001b[32mORLEANS, KEPT TIDY BY A WHITE-HAIRED OLD MAN KNOWN ONLY AS BAMBU.'\u001b[0m,\n", + " \u001b[32m'THE HOUSE AND THE OLD MAN ARE ALIKE IN MANY WAYS; TALL, PROUD, PATIENT, CONTENTED ALWAYS TO WAIT \u001b[0m\n", + "\u001b[32mUNTIL THEIR MASTER COMES HOME--'\u001b[0m,\n", + " \u001b[32m'AND ONE IN NEED OF SOME HELP, IT WOULD APPEAR.'\u001b[0m,\n", + " \u001b[32m'BAMBU-- WE HAVE A GUEST.'\u001b[0m,\n", + " \u001b[32m'--AND TONIGHT, HE COMES MOST URGENTLY, SLAMMING OPEN THE OAKEN FRONT DOORS!'\u001b[0m,\n", + " \u001b[32m'TELL ME, MASTER-- HOW MAY BAMBU SERVE?'\u001b[0m,\n", + " \u001b[32m'SOME BLANKETS TO KEEP HER WARM, BAMBU-- AND PERHAPS SOME DRY CLOTHES'\u001b[0m,\n", + " \u001b[32m\"THE ECHO OF THE OLD MAN'S FOOTSTEPS FADES DOWN THE HALL AS...\"\u001b[0m,\n", + " \u001b[32m'HOW CURIOUS THE WHIMS OF FATE. HAD I NOT CHANCED TO STROLL ALONG THE RIVER TONIGHT--'\u001b[0m,\n", + " \u001b[32m'AS QUICKLY AS I CAN, MASTER'\u001b[0m,\n", + " \u001b[32m'--THE GIRL WOULD MOST SURELY BE DEAD BY NOW.'\u001b[0m,\n", + " \u001b[32m'GHEDE HAS BEEN GENEROUS. THE DEATH GOD HAS GIVEN THE GIRL A SECOND CHANCE AT--'\u001b[0m,\n", + " \u001b[32m\"EASY, GIRL-- THERE'S NOTHING TO SCREAM ABOUT ANYMORE.\"\u001b[0m,\n", + " \u001b[32m\"YOU'RE AMONG FRIENDS NOW, YOU'RE SAFE!\"\u001b[0m,\n", + " \u001b[32m'CONTINUED AFTER NEXT PAGE'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" ] }, - "execution_count": 93, "metadata": {}, - "output_type": "execute_result" + "output_type": "display_data" } ], "source": [ - "IMAGE_CONTEXT.gts\n" + "cprint(IMAGE_CONTEXT.gts())\n", + "cprint(IMAGE_CONTEXT.gts('all-caps'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# for img_path in CONTEXT.image_paths:\n", + "# gt_path = img_path.with_stem(img_path.stem + '_gt').with_suffix('.txt')\n", + "# print(gt_path)\n", + "# gt_path = CONTEXT.root_dir/gt_path\n", + "# if gt_path.exists():\n", + "# gts = gt_path.read_text(encoding=\"utf-8\").splitlines()\n", + "# data = {\n", + "# 'all-caps': [gt.upper() for gt in gts],\n", + "# 'capitalized': gts\n", + "# }\n", + "# fp = gt_path.with_suffix('.json')\n", + "# with open(fp, 'w') as f:\n", + "# json.dump(data, f, indent=2)\n", + "\n" ] }, { @@ -3807,12 +3757,8 @@ }, { "cell_type": "code", - "execution_count": 37, - "metadata": { - "notebookRunGroups": { - "groupValue": "3" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| exporti\n", @@ -3843,12 +3789,8 @@ }, { "cell_type": "code", - "execution_count": 38, - "metadata": { - "notebookRunGroups": { - "groupValue": "3" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -4214,12 +4156,8 @@ }, { "cell_type": "code", - "execution_count": 39, - "metadata": { - "notebookRunGroups": { - "groupValue": "3" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "BOX_IDX = 0" @@ -4234,12 +4172,8 @@ }, { "cell_type": "code", - "execution_count": 40, - "metadata": { - "notebookRunGroups": { - "groupValue": "3" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [ { "data": { @@ -4247,7 +4181,7 @@ "ExperimentOCR#Tesseract_Tesseract-crop" ] }, - "execution_count": 40, + "execution_count": null, "metadata": {}, "output_type": "execute_result" } @@ -4283,7 +4217,7 @@ }, { "cell_type": "code", - "execution_count": 98, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4330,7 +4264,7 @@ }, { "cell_type": "code", - "execution_count": 99, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4354,7 +4288,8 @@ "result = image_experiment.result(BOX_IDX, method, ocr=False)\n", "assert result is not None\n", "\n", - "CONTEXT.ocr_box(result, page_lang)\n" + "CONTEXT.ocr_box(result, page_lang)\n", + "result.ocr = postprocess_ocr(result.ocr)\n" ] }, { @@ -4366,7 +4301,7 @@ }, { "cell_type": "code", - "execution_count": 100, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4399,7 +4334,7 @@ }, { "cell_type": "code", - "execution_count": 101, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4430,7 +4365,7 @@ }, { "cell_type": "code", - "execution_count": 102, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4470,7 +4405,7 @@ }, { "cell_type": "code", - "execution_count": 103, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4496,7 +4431,7 @@ "# image = results[method].image\n", "# assert image is not None\n", "# results[method].ocr = postprocess_ocr(IMAGE_CONTEXT.mocr(image))\n", - "# display_extracted_result(None, None, results[method], IMAGE_CONTEXT.gts[BOX_IDX])\n", + "# display_extracted_result(None, None, results[method], IMAGE_CONTEXT.gts()[BOX_IDX])\n", "image_experiment.result(BOX_IDX, method)\n" ] }, @@ -4509,7 +4444,7 @@ }, { "cell_type": "code", - "execution_count": 104, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4542,7 +4477,7 @@ }, { "cell_type": "code", - "execution_count": 105, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4575,7 +4510,7 @@ }, { "cell_type": "code", - "execution_count": 106, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4608,7 +4543,7 @@ }, { "cell_type": "code", - "execution_count": 107, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4641,7 +4576,7 @@ }, { "cell_type": "code", - "execution_count": 108, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4675,7 +4610,7 @@ }, { "cell_type": "code", - "execution_count": 109, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4723,7 +4658,7 @@ }, { "cell_type": "code", - "execution_count": 110, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4747,7 +4682,7 @@ }, { "cell_type": "code", - "execution_count": 111, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4780,12 +4715,8 @@ }, { "cell_type": "code", - "execution_count": 41, - "metadata": { - "notebookRunGroups": { - "groupValue": "3" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -4906,7 +4837,7 @@ }, { "cell_type": "code", - "execution_count": 155, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -4940,12 +4871,8 @@ }, { "cell_type": "code", - "execution_count": 42, - "metadata": { - "notebookRunGroups": { - "groupValue": "3" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "#| export\n", @@ -4998,22 +4925,18 @@ }, { "cell_type": "code", - "execution_count": 43, - "metadata": { - "notebookRunGroups": { - "groupValue": "3" - } - }, + "execution_count": null, + "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "7890ae3c54f44e4b8f42ba1fc487d044", + "model_id": "ae489cc65bb54dcf8215c8807fab2701", "version_major": 2, "version_minor": 0 }, "text/plain": [ - "VBox(children=(HTML(value=\"" + } + }, + "b7ec0258d59d4c4cbe7fda2596748497": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "b9ddec6ffc97453d9cabf78f36bd8152": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "0px" + } + }, + "bb37887f61cb487da67815a8441e4606": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "BoundedIntTextModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "BoundedIntTextModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "IntTextView", + "continuous_update": false, + "description": "", + "description_tooltip": null, + "disabled": false, + "layout": "IPY_MODEL_bc91ad9852e646928b2491514ce5c1fb", + "max": 14, + "min": 0, + "step": 1, + "style": "IPY_MODEL_84d6e759885547feac1bb40b9f6ba449", + "value": 0 + } + }, + "bc824c4742924a72b4a3cd4ff16047fc": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": "0px 0px 0px 3em", + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "5em" + } + }, + "bc91ad9852e646928b2491514ce5c1fb": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "50px" + } + }, + "bebaa8285f044081bd907db14eda2876": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "c1038ace4996476db1708eaee3ea062c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "display_option_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_cf182da14bd84e1d934f8a29c3986d95" + ], + "layout": "IPY_MODEL_eb898c12964d48dca6dc7a82c79d2b73" + } + }, + "c4d45b30e1c8461088df86349146d0e4": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "cf182da14bd84e1d934f8a29c3986d95": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Boxes", + "Image", + "Mask", + "Image & Mask", + "Page data", + "Ground truth", + "Image All", + "Results", + "Best results", + "Accuracy", + "Dataframe", + "Config" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 7, + "layout": "IPY_MODEL_37adfad0552c4b95b892e04a68eed45d", + "style": "IPY_MODEL_ab354dd44b9448868e84aa96c3a0c8ac" + } + }, + "d264052799214924961df8ad52df35c0": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d33528dc39004a07ab6094b00a8371ba": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Tesseract-crop-post", + "Tesseract-crop" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 0, + "layout": "IPY_MODEL_7d7c5cfe0470438095fab691ac17977e", + "style": "IPY_MODEL_bebaa8285f044081bd907db14eda2876" + } + }, + "d55ff8c2cd4343c1a7c2394a0cbb7044": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": "0px 0px 0px 10px", + "right": null, + "top": null, + "visibility": null, + "width": "initial" + } + }, + "e15e755d1aed4ef1bea36095ef4e71c6": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "0px" + } + }, + "e21fb5c1948d4317965fd788878f2e41": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "139619740843360" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_3a8042f94a2f466e94457b14fc91b53e" + ], + "layout": "IPY_MODEL_fc606d552a9d40a5908ef27939278f29" + } + }, + "e493f35b8f21428a975e738588df8222": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "box_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_8029556124d34fdda0849febd878aefc", + "IPY_MODEL_0b84340f11284915a7056b60f3592676", + "IPY_MODEL_bb37887f61cb487da67815a8441e4606" + ], + "layout": "IPY_MODEL_9a1a5f51138c4c349e913786b0488d08" + } + }, + "e6a83dde359f4060baa853d233d56142": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e9851a001fa54db1a4e0da0e52efad28": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_e21fb5c1948d4317965fd788878f2e41", + "IPY_MODEL_19643c8a1d674222a20626830402afef", + "IPY_MODEL_a342b0c239ae4c8c966a197f346698bc", + "IPY_MODEL_4f28be29339d4155bff460a3ccd30b8e" + ], + "layout": "IPY_MODEL_6ee898c098d5463199a9efb201f0f90e" + } + }, + "eb898c12964d48dca6dc7a82c79d2b73": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "edb42bd2e8054ac381230f2b426cc477": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": "none", + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f1f2978a05b64b50ab0206498135b7e6": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "f4b70788e3b249e3bdc7ee247896fa21": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "f6cfe60a03ee4d66b6f7aa4208c9bcab": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_fd8d32ff95bb4b6ba9985214a93ce713", + "placeholder": "​", + "style": "IPY_MODEL_8e79c3c66cef4b96b6c23b27fddef358", + "value": " 11/11 [00:03<00:00,  3.17it/s]" + } + }, + "f7481c76692e45d183a74797d7636601": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fc606d552a9d40a5908ef27939278f29": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fc6c361cfc6e427ab9b80d4518c386fa": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "139619740843744" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_e9851a001fa54db1a4e0da0e52efad28", + "IPY_MODEL_3a8ad8eaf7f54d77bb1c781160aba961" + ], + "layout": "IPY_MODEL_416f0fbdd95648a688f25a67f6a9e66f" + } + }, + "fd8d32ff95bb4b6ba9985214a93ce713": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + } + } } }, "nbformat": 4, - "nbformat_minor": 4 + "nbformat_minor": 0 } diff --git a/pcleaner/_testbed/nbs/web_server.ipynb b/pcleaner/_testbed/nbs/web_server.ipynb index 1e6d9f25..ea761ca9 100644 --- a/pcleaner/_testbed/nbs/web_server.ipynb +++ b/pcleaner/_testbed/nbs/web_server.ipynb @@ -35,7 +35,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# install (Colab)" + "## Settings for Google Colab" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n", + "\n", + "- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n", + "This allows the notebook to access files stored in your Google Drive.\n", + "\n", + "- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n", + "This acts as the root directory for accessing any files within your Google Drive from the notebook.\n", + "\n", + "- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n", + "This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n" ] }, { @@ -45,8 +61,16 @@ "outputs": [], "source": [ "MOUNT_DRIVE = True\n", - "DEV_INSTALL = True\n", - "GDRIVE_MOUNT_POINT = 'drive'\n" + "GDRIVE_MOUNT_POINT = 'drive'\n", + "PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)\n", + "> Install necessary libraries in Colab\n" ] }, { @@ -55,33 +79,27 @@ "metadata": {}, "outputs": [], "source": [ + "import fastcore.all as FC\n", "import os\n", + "import re\n", "from pathlib import Path\n", - "import fastcore.all as FC\n", + "\n", "from rich import print as cprint\n", "from rich.text import Text\n", "\n", - "def info(msg: str):\n", - " text = Text(msg)\n", - " text.stylize(\"bold red\", 0, 6)\n", - " cprint(\"_\" * 10, text, \"_\" * 10)\n", - "\n", + "def info(msg: str): \n", + " (t := Text(msg)).stylize(\"bold red\", 0, 6)\n", + " cprint(\"_\" * 10, t, \"_\" * 10)\n", "\n", "if FC.IN_COLAB:\n", - " if MOUNT_DRIVE:\n", - " mnt_point = f\"/content/{GDRIVE_MOUNT_POINT}\"\n", - " if not Path(mnt_point).exists():\n", - " info(\"Mounting Google Drive\")\n", - " from google.colab import drive\n", - "\n", - " drive.mount(mnt_point, force_remount=True)\n" + " !pip install -q pyngrok\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Colab has issues with PanelClenar PIL version.: uninstall Colab one, restart wen prompted and rerun from the top.\n" + "Mount Google Drive" ] }, { @@ -90,15 +108,24 @@ "metadata": {}, "outputs": [], "source": [ + "mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n", "if FC.IN_COLAB:\n", - " from packaging import version\n", - " import PIL\n", - " pil_version = version.parse(PIL.__version__)\n", - " if pil_version < version.parse(\"10\"):\n", - " info('Uninstalling Pillow')\n", - " !pip uninstall Pillow\n", - " info('Installing Pillow')\n", - " !pip install Pillow\n" + " if MOUNT_DRIVE:\n", + " if not mnt_point.exists():\n", + " info(\"Mounting Google Drive\")\n", + " from google.colab import drive\n", + " drive.mount(str(mnt_point), force_remount=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install **PanelCleaner**\n", + "\n", + "> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub. \n", + "\n", + "Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook." ] }, { @@ -109,14 +136,32 @@ "source": [ "if FC.IN_COLAB:\n", " info('Installing PanelCleaner')\n", - " if DEV_INSTALL:\n", - " assert MOUNT_DRIVE, \"DEV_INSTALL need a mounted google drive drive\"\n", - " info('Installing PanelCleaner from Google Drive')\n", - " os.chdir('/content/drive/MyDrive/Shared/PanelCleaner/')\n", - " !pip install -e .\n", + " pc_path = mnt_point / PANELCLEANER_IN_GDRIVE\n", + " testbed_path = pc_path / 'pcleaner/_testbed'\n", + " if testbed_path.exists():\n", + " info('Installing PanelCleaner from your Google Drive')\n", + " os.chdir(pc_path)\n", " else:\n", - " info('Installing PanelCleaner from Github')\n", - " !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed-colab\n" + " info('Installing PanelCleaner from GitHub')\n", + " !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n", + " os.chdir('PanelCleaner')\n", + " assert testbed_path.exists(), \"PanelCleaner not found\"\n", + " !pip install -e ." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note:** If you encounter installation issues with **PanelCleaner** in Colab, re-running the installation cell above may resolve them." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Navigate to the Testbed Directory\n", + "> Ensure you are in the correct directory to start the experiments." ] }, { @@ -126,21 +171,7 @@ "outputs": [], "source": [ "if FC.IN_COLAB:\n", - " info('Installing PanelCleaner Colab requirements')\n", - " import importlib.resources\n", - " if DEV_INSTALL:\n", - " os.chdir('pcleaner/_testbed')\n", - " \n", - " try:\n", - " package_path = importlib.resources.files('pcleaner')\n", - " info('Installing PanelCleaner testbed requirements')\n", - " p = (Path(package_path)/'_testbed/requirements-colab.txt')\n", - " if p.exists():\n", - " !pip install -r {p}\n", - " else:\n", - " print(f\"colab requirements {p} not found\")\n", - " except Exception:\n", - " info(\"Couldn't install PanelCleaner Colab requirements\")\n" + " os.chdir('./pcleaner/_testbed')" ] }, { @@ -184,21 +215,13 @@ "from loguru import logger\n", "from pyngrok import conf\n", "from pyngrok import ngrok\n", - "from rich.console import Console\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#| exporti\n", - "from pcleaner._testbed.testbed.bottle import Bottle\n", - "from pcleaner._testbed.testbed.bottle import HTTPError\n", - "from pcleaner._testbed.testbed.bottle import response\n", - "from pcleaner._testbed.testbed.bottle import run\n", - "from pcleaner._testbed.testbed.bottle import static_file\n" + "from rich.console import Console\n", + "\n", + "from testbed.bottle import Bottle\n", + "from testbed.bottle import HTTPError\n", + "from testbed.bottle import response\n", + "from testbed.bottle import run\n", + "from testbed.bottle import static_file\n" ] }, { @@ -209,9 +232,7 @@ "source": [ "import fastcore.all as FC\n", "import fastcore.xtras # patch Path with some utils\n", - "from fastcore.test import * # type: ignore\n", - "\n", - "import pcleaner._testbed.testbed.bottle as bottle\n" + "from fastcore.test import * # type: ignore\n" ] }, { @@ -440,6 +461,7 @@ " self.unc_share = Path(self.public_url.replace('https:', ''))\n", " cprint(f\"ngrok tunnel: {self.tunnel}\")\n", " cprint(f\"Public URL: {self.public_url}\")\n", + " cprint(f\"Serving images from: {self.directory}\")\n", " else:\n", " cprint(\"Server is already running\")\n", "\n", @@ -522,11 +544,11 @@ { "data": { "text/html": [ - "
ngrok tunnel: NgrokTunnel: \"https://36a0-83-33-227-209.ngrok-free.app\" -> \"http://localhost:55435\"\n",
+       "
ngrok tunnel: NgrokTunnel: \"https://5029-83-33-227-209.ngrok-free.app\" -> \"http://localhost:63057\"\n",
        "
\n" ], "text/plain": [ - "ngrok tunnel: NgrokTunnel: \u001b[32m\"https://36a0-83-33-227-209.ngrok-free.app\"\u001b[0m -> \u001b[32m\"http://localhost:55435\"\u001b[0m\n" + "ngrok tunnel: NgrokTunnel: \u001b[32m\"https://5029-83-33-227-209.ngrok-free.app\"\u001b[0m -> \u001b[32m\"http://localhost:63057\"\u001b[0m\n" ] }, "metadata": {}, @@ -535,11 +557,24 @@ { "data": { "text/html": [ - "
Public URL: https://36a0-83-33-227-209.ngrok-free.app\n",
+       "
Public URL: https://5029-83-33-227-209.ngrok-free.app\n",
        "
\n" ], "text/plain": [ - "Public URL: \u001b[4;94mhttps://36a0-83-33-227-209.ngrok-free.app\u001b[0m\n" + "Public URL: \u001b[4;94mhttps://5029-83-33-227-209.ngrok-free.app\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Serving images from: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/cache\n",
+       "
\n" + ], + "text/plain": [ + "Serving images from: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95mcache\u001b[0m\n" ] }, "metadata": {}, @@ -549,14 +584,14 @@ "data": { "text/html": [ "\n", - "
\n", + "
\n", "
\n", "

Ngrok displays a warning page as a security measure to prevent unintentional access to your local servers. This page requires you to confirm that you wish to proceed to the content.

\n", "

Please review the ngrok warning page displayed below. If prompted, click 'Visit Page' to proceed.

\n", " Don't worry if you see a 404 or 403 error. Then, you can click the 'Close' button below to hide this section.

\n", "
\n", - " \n", - " \n", + " \n", + " \n", "
\n" ], "text/plain": [ @@ -570,10 +605,11 @@ "name": "stderr", "output_type": "stream", "text": [ - "127.0.0.1 - - [21/May/2024 13:22:26] \"GET //pcleaner.png HTTP/1.1\" 200 -\n", - "127.0.0.1 - - [21/May/2024 13:22:46] \"GET /Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png HTTP/1.1\" 200 -\n", - "127.0.0.1 - - [21/May/2024 13:22:48] \"GET /Strange_Tales_172005/.crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 200 -\n", - "t=2024-05-21T13:22:51+0200 lvl=warn msg=\"Stopping forwarder\" name=http-55435-1681ca10-634d-4a9f-b4c3-e9ae3c2b48e2 acceptErr=\"failed to accept connection: Listener closed\"\n" + "127.0.0.1 - - [30/May/2024 20:04:54] code 404, message File not found\n", + "127.0.0.1 - - [30/May/2024 20:04:54] \"GET //pcleaner.png HTTP/1.1\" 404 -\n", + "127.0.0.1 - - [30/May/2024 20:05:28] \"GET /Strange_Tales_172005/_crop/Strange_Tales_172005_0_Default.png HTTP/1.1\" 200 -\n", + "127.0.0.1 - - [30/May/2024 20:05:32] \"GET /Strange_Tales_172005/_crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 200 -\n", + "t=2024-05-30T20:05:45+0200 lvl=warn msg=\"Stopping forwarder\" name=http-63057-fe3f0d56-9db5-4936-bb03-cb610aa88a40 acceptErr=\"failed to accept connection: Listener closed\"\n" ] } ], @@ -597,7 +633,7 @@ "metadata": {}, "outputs": [], "source": [ - "img_path = 'Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png'\n" + "img_path = 'Strange_Tales_172005/_crop/Strange_Tales_172005_0_Default.png'\n" ] }, { @@ -608,7 +644,7 @@ { "data": { "text/plain": [ - "''" + "''" ] }, "execution_count": null, @@ -628,7 +664,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -650,7 +686,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -661,7 +697,7 @@ } ], "source": [ - "display(HTML(f''))\n" + "display(HTML(f''))\n" ] }, { @@ -718,7 +754,7 @@ { "data": { "text/plain": [ - "52794" + "63057" ] }, "execution_count": null, @@ -850,6 +886,7 @@ " self.unc_share = Path(self.public_url.replace('https:', ''))/self.prefix\n", " cprint(f\"ngrok tunnel: {self.tunnel}\")\n", " cprint(f\"Public URL: {self.public_url}\")\n", + " cprint(f\"Serving images from: {self.directory}\")\n", "\n", " def start(self):\n", " if self.thread is None or not self.thread.is_alive():\n", @@ -861,16 +898,16 @@ " if self.tunnel and self.tunnel.public_url:\n", " ngrok.disconnect(self.tunnel.public_url)\n", " cprint(\"Ngrok tunnel disconnected\")\n", - " ngrok.kill()\n", " \n", " if self.thread:\n", " self.make_request('/shutdown')\n", - " self.thread.join(timeout=10)\n", + " self.thread.join(timeout=5)\n", " if self.thread.is_alive():\n", " print(\"Thread did not terminate, proceeding with forceful shutdown.\")\n", " else:\n", " print(\"Server thread stopped successfully.\")\n", " self.thread = self.tunnel = self.public_url = self.unc_share = None\n", + " ngrok.kill()\n", " cprint(\"Server stopped\")\n", "\n", " def make_request(self, path=\"/\"):\n", @@ -941,7 +978,7 @@ "output_type": "stream", "text": [ "Bottle v0.13-dev server starting up (using WSGIRefServer())...\n", - "Listening on http://localhost:55470/\n", + "Listening on http://localhost:63275/\n", "Hit Ctrl-C to quit.\n", "\n" ] @@ -949,11 +986,24 @@ { "data": { "text/html": [ - "
ngrok tunnel: NgrokTunnel: \"https://0836-83-33-227-209.ngrok-free.app\" -> \"http://localhost:55470\"\n",
+       "
ngrok tunnel: NgrokTunnel: \"https://ef4e-83-33-227-209.ngrok-free.app\" -> \"http://localhost:63275\"\n",
+       "
\n" + ], + "text/plain": [ + "ngrok tunnel: NgrokTunnel: \u001b[32m\"https://ef4e-83-33-227-209.ngrok-free.app\"\u001b[0m -> \u001b[32m\"http://localhost:63275\"\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Public URL: https://ef4e-83-33-227-209.ngrok-free.app\n",
        "
\n" ], "text/plain": [ - "ngrok tunnel: NgrokTunnel: \u001b[32m\"https://0836-83-33-227-209.ngrok-free.app\"\u001b[0m -> \u001b[32m\"http://localhost:55470\"\u001b[0m\n" + "Public URL: \u001b[4;94mhttps://ef4e-83-33-227-209.ngrok-free.app\u001b[0m\n" ] }, "metadata": {}, @@ -962,11 +1012,11 @@ { "data": { "text/html": [ - "
Public URL: https://0836-83-33-227-209.ngrok-free.app\n",
+       "
Serving images from: ../experiment/cache\n",
        "
\n" ], "text/plain": [ - "Public URL: \u001b[4;94mhttps://0836-83-33-227-209.ngrok-free.app\u001b[0m\n" + "Serving images from: ..\u001b[35m/experiment/\u001b[0m\u001b[95mcache\u001b[0m\n" ] }, "metadata": {}, @@ -976,14 +1026,14 @@ "data": { "text/html": [ "\n", - "
\n", + "
\n", "
\n", "

Ngrok displays a warning page as a security measure to prevent unintentional access to your local servers. This page requires you to confirm that you wish to proceed to the content.

\n", "

Please review the ngrok warning page displayed below. If prompted, click 'Visit Page' to proceed.

\n", " Don't worry if you see a 404 or 403 error. Then, you can click the 'Close' button below to hide this section.

\n", "
\n", - " \n", - " \n", + " \n", + " \n", "
\n" ], "text/plain": [ @@ -997,10 +1047,10 @@ "name": "stderr", "output_type": "stream", "text": [ - "127.0.0.1 - - [21/May/2024 13:24:01] \"GET /images/pcleaner.png HTTP/1.1\" 200 17709\n", - "127.0.0.1 - - [21/May/2024 13:24:45] \"GET /images/Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png HTTP/1.1\" 200 137784\n", - "127.0.0.1 - - [21/May/2024 13:24:48] \"GET /images/images/Strange_Tales_172005/.crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 404 817\n", - "127.0.0.1 - - [21/May/2024 13:25:01] \"GET /images/Strange_Tales_172005/.crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 200 107550\n" + "127.0.0.1 - - [30/May/2024 20:13:37] \"GET /images/pcleaner.png HTTP/1.1\" 404 761\n", + "127.0.0.1 - - [30/May/2024 20:13:44] \"GET /images/Strange_Tales_172005/_crop/Strange_Tales_172005_0_Default.png HTTP/1.1\" 200 137784\n", + "127.0.0.1 - - [30/May/2024 20:13:45] \"GET /images/Strange_Tales_172005/_crop/Strange_Tales_172005_1_Default.png HTTP/1.1\" 200 107550\n", + "t=2024-05-30T20:13:50+0200 lvl=warn msg=\"Stopping forwarder\" name=http-63275-08b9c9cf-549d-441e-a6c5-74a0cd0fab91 acceptErr=\"failed to accept connection: Listener closed\"\n" ] } ], @@ -1024,7 +1074,7 @@ "metadata": {}, "outputs": [], "source": [ - "img_path = 'Strange_Tales_172005/.crop/Strange_Tales_172005_0_Default.png'\n" + "img_path = 'Strange_Tales_172005/_crop/Strange_Tales_172005_0_Default.png'\n" ] }, { @@ -1035,7 +1085,7 @@ { "data": { "text/plain": [ - "''" + "''" ] }, "execution_count": null, @@ -1055,7 +1105,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1077,7 +1127,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1088,7 +1138,7 @@ } ], "source": [ - "display(HTML(f''))\n" + "display(HTML(f''))\n" ] }, { @@ -1096,13 +1146,6 @@ "execution_count": null, "metadata": {}, "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "t=2024-05-21T13:25:04+0200 lvl=warn msg=\"Stopping forwarder\" name=http-55470-05e35e60-2237-402e-b7ab-8507dd7f47dc acceptErr=\"failed to accept connection: Listener closed\"\n" - ] - }, { "data": { "text/html": [ @@ -1159,7 +1202,7 @@ { "data": { "text/plain": [ - "58805" + "63275" ] }, "execution_count": null, @@ -1180,7 +1223,7 @@ { "data": { "text/plain": [ - "[]" + "'15604'" ] }, "execution_count": null, diff --git a/pcleaner/_testbed/testbed/web_server.py b/pcleaner/_testbed/testbed/web_server.py index 95d1e3e2..41358da3 100644 --- a/pcleaner/_testbed/testbed/web_server.py +++ b/pcleaner/_testbed/testbed/web_server.py @@ -37,12 +37,12 @@ from .bottle import static_file -# %% ../nbs/web_server.ipynb 17 +# %% ../nbs/web_server.ipynb 16 console = Console(width=104, tab_size=4, force_jupyter=True) cprint = console.print -# %% ../nbs/web_server.ipynb 18 +# %% ../nbs/web_server.ipynb 17 def display_ngrok_warning(url): did = 'ngrokFrame' + str(uuid.uuid4()) html_code = f""" @@ -60,7 +60,7 @@ def display_ngrok_warning(url): display(HTML(html_code)) -# %% ../nbs/web_server.ipynb 19 +# %% ../nbs/web_server.ipynb 18 class WebServer(Protocol): @property def public_url(self) -> str | None: ... @@ -95,7 +95,7 @@ def setup_ngrok(server_cls: type[WebServer], images_dir: str | Path): return server -# %% ../nbs/web_server.ipynb 24 +# %% ../nbs/web_server.ipynb 23 class ImageHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): def end_headers(self): for k,v in { @@ -121,7 +121,7 @@ def __init__(self, *args, **kwargs): super().__init__(*args, directory=self.directory, **kwargs) -# %% ../nbs/web_server.ipynb 25 +# %% ../nbs/web_server.ipynb 24 class WebServerStdlib: """ A simple web server for serving images from a local directory using http.server and ngrok. @@ -180,6 +180,7 @@ def start(self): self.unc_share = Path(self.public_url.replace('https:', '')) cprint(f"ngrok tunnel: {self.tunnel}") cprint(f"Public URL: {self.public_url}") + cprint(f"Serving images from: {self.directory}") else: cprint("Server is already running") @@ -217,7 +218,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): self.stop() -# %% ../nbs/web_server.ipynb 39 +# %% ../nbs/web_server.ipynb 38 app = Bottle() @app.route('/images/') # type: ignore @@ -233,7 +234,7 @@ def shutdown(): current_process.send_signal(signal.SIGTERM) -# %% ../nbs/web_server.ipynb 40 +# %% ../nbs/web_server.ipynb 39 class WebServerBottle: """ A simple web server for serving images from a local directory using ngrok. @@ -283,6 +284,7 @@ def bottle_run(): self.unc_share = Path(self.public_url.replace('https:', ''))/self.prefix cprint(f"ngrok tunnel: {self.tunnel}") cprint(f"Public URL: {self.public_url}") + cprint(f"Serving images from: {self.directory}") def start(self): if self.thread is None or not self.thread.is_alive(): @@ -294,16 +296,16 @@ def stop(self): if self.tunnel and self.tunnel.public_url: ngrok.disconnect(self.tunnel.public_url) cprint("Ngrok tunnel disconnected") - ngrok.kill() if self.thread: self.make_request('/shutdown') - self.thread.join(timeout=10) + self.thread.join(timeout=5) if self.thread.is_alive(): print("Thread did not terminate, proceeding with forceful shutdown.") else: print("Server thread stopped successfully.") self.thread = self.tunnel = self.public_url = self.unc_share = None + ngrok.kill() cprint("Server stopped") def make_request(self, path="/"): From 158020d6ffa045412b139a67bce2ee6039f9249d Mon Sep 17 00:00:00 2001 From: Spikey Date: Fri, 31 May 2024 20:01:35 +0200 Subject: [PATCH 21/27] PaliGemma support --- pcleaner/_testbed/nbs/ocr_paligemma.ipynb | 2092 ++++++++++++++++++++ pcleaner/_testbed/testbed/ocr_paligemma.py | 292 +++ 2 files changed, 2384 insertions(+) create mode 100644 pcleaner/_testbed/nbs/ocr_paligemma.ipynb create mode 100644 pcleaner/_testbed/testbed/ocr_paligemma.py diff --git a/pcleaner/_testbed/nbs/ocr_paligemma.ipynb b/pcleaner/_testbed/nbs/ocr_paligemma.ipynb new file mode 100644 index 00000000..115649a9 --- /dev/null +++ b/pcleaner/_testbed/nbs/ocr_paligemma.ipynb @@ -0,0 +1,2092 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| default_exp ocr_paligemma" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "from __future__ import annotations\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| hide\n", + "# %reload_ext autoreload\n", + "# %autoreload 0\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `PaliGemma` OCR for Comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "import subprocess\n", + "from pathlib import Path\n", + "from typing import Any\n", + "from typing import Literal\n", + "from typing import TypeAlias\n", + "\n", + "import torch\n", + "import transformers.image_utils as image_utils\n", + "from PIL import Image\n", + "from rich.console import Console\n", + "from transformers import AutoProcessor\n", + "from transformers import BitsAndBytesConfig\n", + "from transformers import PaliGemmaForConditionalGeneration\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import re\n", + "import sys\n", + "from typing import cast\n", + "import requests\n", + "\n", + "import fastcore.all as FC\n", + "import fastcore.xtras # patch pathlib.Path with some utils\n", + "import transformers\n", + "from fastcore.test import * # type: ignore\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "need version >4.41 of transformers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'4.42.0.dev0'" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "transformers.__version__" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install git+https://github.com/huggingface/transformers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Helpers" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# pretty print by default\n", + "# %load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "console = Console(width=104, tab_size=4, force_jupyter=True)\n", + "cprint = console.print\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Force reload of `experiments` module" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if 'pcleaner._testbed.testbed.experiments' in sys.modules:\n", + " import importlib; importlib.reload(pcleaner._testbed.testbed.experiments) # type: ignore\n", + "else:\n", + " import pcleaner._testbed.testbed.experiments\n", + " from pcleaner._testbed.testbed.experiments import *\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| export\n", + "\n", + "from testbed.experiments import *\n", + "from testbed.helpers import RenderJSON\n", + "from testbed.helpers import IN_MAC\n", + "from testbed.helpers import IN_LINUX\n", + "from testbed.helpers import default_device\n", + "from testbed.ocr_metric import *\n", + "from testbed.web_server import setup_ngrok\n", + "from testbed.web_server import WebServerBottle\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "if IN_MAC:\n", + " import mlx.core as mx\n", + " from mlx_vlm import load, generate\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "def load_image(img_ref: str | Path | Image.Image) -> Image.Image:\n", + " return image_utils.load_image(str(img_ref) if isinstance(img_ref, Path) else img_ref)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#| exporti\n", + "\n", + "def get_gpu_vram(total=True):\n", + " if total:\n", + " if IN_MAC:\n", + " return mx.metal.device_info()['memory_size']//1024//1024\n", + " else:\n", + " command = \"nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits\"\n", + " else:\n", + " if IN_MAC:\n", + " return mx.metal.get_active_memory()//1024//1024\n", + " else:\n", + " command = \"nvidia-smi --query-gpu=memory.used --format=csv,noheader,nounits\"\n", + " try:\n", + " vram = subprocess.check_output(command, shell=True).decode('utf-8').strip()\n", + " return vram\n", + " except subprocess.CalledProcessError:\n", + " return \"Failed to get VRAM\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GPU" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'mps'" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "DEVICE = default_device()\n", + "DEVICE\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
          metal.is_available(): True\n",
+       "           metal.device_info(): {'memory_size': 68719476736, 'max_recommended_working_set_size': \n",
+       "51539607552, 'max_buffer_length': 38654705664, 'architecture': 'applegpu_g13s'}\n",
+       "     metal.get_active_memory(): 8\n",
+       "       metal.get_peak_memory(): 8\n",
+       "      metal.get_cache_memory(): 0\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " \u001b[1;35mmetal.is_available\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[3;92mTrue\u001b[0m\n", + " \u001b[1;35mmetal.device_info\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'memory_size'\u001b[0m: \u001b[1;36m68719476736\u001b[0m, \u001b[32m'max_recommended_working_set_size'\u001b[0m: \n", + "\u001b[1;36m51539607552\u001b[0m, \u001b[32m'max_buffer_length'\u001b[0m: \u001b[1;36m38654705664\u001b[0m, \u001b[32m'architecture'\u001b[0m: \u001b[32m'applegpu_g13s'\u001b[0m\u001b[1m}\u001b[0m\n", + " \u001b[1;35mmetal.get_active_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m8\u001b[0m\n", + " \u001b[1;35mmetal.get_peak_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m8\u001b[0m\n", + " \u001b[1;35mmetal.get_cache_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
     total VRAM: 65536 MiB\n",
+       "    active VRAM: 0 MiB\n",
+       "
\n" + ], + "text/plain": [ + " total VRAM: \u001b[1;36m65536\u001b[0m MiB\n", + " active VRAM: \u001b[1;36m0\u001b[0m MiB\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "if IN_MAC:\n", + " cprint(\n", + " f\"{'metal.is_available()':>30}: {mx.metal.is_available()}\\n\"\n", + " f\"{'metal.device_info()':>30}: {mx.metal.device_info()}\\n\"\n", + " f\"{'metal.get_active_memory()':>30}: {mx.metal.get_active_memory()}\\n\"\n", + " f\"{'metal.get_peak_memory()':>30}: {mx.metal.get_peak_memory()}\\n\"\n", + " f\"{'metal.get_cache_memory()':>30}: {mx.metal.get_cache_memory()}\\n\"\n", + " )\n", + "else:\n", + " !nvidia-smi\n", + "\n", + "cprint( f\"{'total VRAM':>15}: {get_gpu_vram()} MiB\\n\"\n", + " f\"{'active VRAM':>15}: {get_gpu_vram(False)} MiB\")\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# PaliGemma basic usage\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [Model card](https://huggingface.co/google/paligemma-3b-mix-448) examples" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User is already logged in.\n" + ] + } + ], + "source": [ + "from huggingface_hub import notebook_login\n", + "notebook_login(False, True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAIAAAC6s0uzAAEAAElEQVR4nNz9aaxt2XEeCEbEGvZ0hnvu/Mack2RylkhqoGUNNlllu8AqyAbaLcAG3EC3fzS6/dON/mEYMNBDobqM+l1d6Lbbk1yyXKqyZchyWSWbJZEU5ynJzGTme5lvuu9OZ97DWiuif6y99z33DRIfRavRtfLx8Nwz7LP32mvF8MUXEfhzH3j//v7+ycnJ888/r61RSo1Go1//9V//j//Cn8+y7Ovf+AYzf+YznymKYjKZ/N6Xv/KFr70egh+hw2oB68Vk5yDfu/aQs++trX754+blT9T7N6fZaGVT0AoUAzREXnvExnPV6ACJ1anVdVmlVqVGGw5U1Tq4BNUWuENe7aV4MB7uT4r9cbIzSLYLVVhS7EkYAUBIEEE0AwEygQcI8MMNRgCb+BCEGQAUEhGRgIgoEQBAAQBQwiICAACEbBBFmQZovSof3rn/vTff+tbde7du334HQO9Mrn7wtU988AOfGuS79+9O333vHe/Ot3eLuq6//vWvf+Mb3wghPP/cizdv3jw8vLpare7cufPGG2/cunW7LMvxeLy9PQlNXZar5XJZVZUIaq2NMVrro6NjpdTNG8/duHGjaZqjo6PT09PpfLFaV5OdvV/4hV+4fv36N7/5zbffftsY470/Ojr6wAc+8PGPfzxN07t375ZlORgMssT8y3/xz9PEWJsCgHeBmbVKrbXD4datW7eKfPjTP/3TW1u73/rWt9566y0gQRTPDgCstcYkzFxVVdM01qbee2E0xiCi9957DwABBBGttUVR5HlORE3T1HWNiNPpFBHTNGXm+BkIrBUO8qKu69VqZYwhorquRcRai4hZliGiiBRFYa1dLWahXmmFWmvVDU2KiCbj8fHx8Xw+T9N0Mt6y1oYQvG+MpeGwIKLlcikig8FAaSzLcr1et2uAGVGSJCmKIs+zYjjwvnEu1HW9XtWLxWI+X5dlOZ8tr1y5Ugyy+Xy+Xi+TJEkSw8y1d/HqJpPJ3t6eMWY2W5yent64/hwzK6UQkUhrrY+Ojl5//Tuf+smP7u5u13V9eHg4GAxms9l4PLbWrtfrNE0Hg0GWZXHSyrKsaldVDQMhCRFppBBCXZdN04xHA2uttZaIUJiZ41YYjcdkKM6kiGJmDgIAn//8F5RS5dplWeacn81mWVoIwv7hwXv3751Nl5Vzb797/9uvvwVI21euLubrIExESWoUknMNBg+ovEiS5kqp6cnJ9v7+crk0xoQQjDGLk5P/1V/9q9Pp9Lf++//+w5/4xLe+/OVsa0vY/5CbMQ5p2Fgeb+OynNYeXngZ/g//x//13t7ee7cf/p//T/9kMoIH9+DK/rWmMsHZtVuZQblqFh967SOE9hu/95V8vNuUPk3z5WKVFqlztUqV0lJWSzRkrRWnm3W1s7M7O5/6qtzd3S3nyxCCNgQAjAKIQsgEiMgAGAQRASA+AkAUBVpr5lYsICIiMjMzR4nxDNcL9AyfRhZh7H5DNoYxpn8RN0aaps65uDyYwXsvAkqpVqDJ5q+TIBAaUIiILA2zN5byPM1yc3h4eHp6Mp/PvfdxRxtjR6NRkljvfdM47z0HEJE4LYhorELEul43TaMNTCaT8WSsNS3L9WK+rqqGHQtTK32D0loTkYiw9yKiFBpjmspvTj4RKaWIKJ6G914plaap1tp7X7taKWxCgyxE1N44IUREVNDJ83jpyMIIiCj4lMnGizf6eU7TNL5FUVeIhBDiycRzi1u++zhrTQKhvy9aa2ut1jpKuThdIYQ4aSKiP/zhD9++fdtaq5Qqy7Ku68lk8v73v//FF19k5v39/fV6/d577125cuXmzZsvPv/Cu0fT737nO8bC4Xg0q9bLsuKqOV42evycMilqg6TbKxEAFpCADCRASIRGKSbShDouFwBAAERUgAbIorJKWwJNpBVqUkYhIV5a5cgACoChXcrPtgOYQ6dcAQAghCAgHBAJgVkEBYRFIKAAALEPpACgYXK+aeqqacqmqppEZ+ezRbO6Pxq+d2X3xbBlzk4e3rvzLtBK270sSff391956eXGu93tvTRNT08eTmeLk4fHq9VKIWVZlhiLAsYYgMyQCqNRohObpZlNyOgXbr7gOOxNdrd2tlfzhXOOBIxJ9va1SZPEGFIwyPPtnS1DpglNuVrN5uc/ePPNbJCtF+smNK6uz8GPhsMkMZnNUCsMIISJTrRNi7QIISjAqqqWs2ma2iv7B1587dYBgiGTD4osSRmkqVztmsTY2nmFlOZZotOyrpbzxboqrbWgIDVpkieZzUABO6597SoXgmPH2moIAAoMaSf1ZDwZDHJXOaVQgQoQSCBA8LUrRsX2eCseIckTElpKSJIkz5LBYGCtjTvBKK21rtZrpdR4PN7f379+9dpwOEREZj8aF3mehhBms1kIoSgKpbGua+dcv0UBWGudZVmapgwsErznqqpn08XDhydHR8ez2Ww03NrZ2YkKL8uywSAfDodEsL23CwBZlm1vb4/HY+/9w4cnDx8+tCZdrVYhBCJCVNGQPdjbS9M0hBCNGGPMzs7Ozs5Omqar1arfnIhojLHW5p4Xi1UQFAjRNAwhKIVa69FoZIxJkkQppbCVTaBAAFCjUgpRRVGsCAHg537u587Pz9/4/tvz+byqaiK6cuXKaGs8HA+0tTs7q9J5VMn5bH58NvN1YxMdOG4QDsGH4ElAawSR9XpdFAUgnp2eamOapgkhfO5zn/vLf/kv/62/9be896DUt7761cPnnpvP58+oj0AkNK4+P6/XawAFr7x8eO3qjd3d3e9++/b+PmwN9+py2jQNkXHsfVOCq/7sZ35ek7311nuADtDnRVKW67xIBMUmxoMry7oYDg6vHWpt52er+9X9VVmaxGaJVUp5YUWklAIARBEARlCIgqAAPIde6EfBGhXtM17Wj3PEX0eMdxmjBH/ahzdNhPjkkrh7wucZpN8X8e4H52A6na7X66qqQgiImOd5mmZpmjZNHY3vEIIwXlIqQkQEAMYYmxAiOueWy7JyjXMBohETMM5onN7N04u6DVVUosjA7SOjoAAAKlSi4gcY2jlpgldKGXNpZojoD73oJ4x45ptWV3QbNk9vc3SmNvVTHT+plKKN28TM3vveTNl80ipgZr5169bW1ta7776LiMvlkoiOj4//9b/+1zs7O9PpdDgcHh0dJUkynU6TJHn1lZde/9Y31+vSHm4rk6184EbOa58OJ5CNIEmZSIBQRCQABwgCCAqJkEgpBCZUjASEAARCwoEEFKAllZIUZAsT8kTl1lqjtSKNiCQQGJBBAJ7JhHxsSGCAeEMBhYN49sKuCYgYHV9mCSwSkEUEmaOJ7AOuFouTs+Pp+el8djqv1s1qvvZ1+W767jj77tbW2fGD2dH9O6hLRW6ytaUJd3cmPoTUJhzcYjZbzBdVubJG7e3uGGuzNLXWKhAAVkTG2iIb5IMitYky2uqkauoiK5I0nc9mRVEs9/aXq9WD09PVen10/95qNTu6/2A1n+VpIcjXr16ZL2cnD4/GbmSUzaxJjGbhD7z6SpKYLMm1NQo1KW2NUdqi0MHBwWq5bJxfzKeaYLI1cqGpnBLkQT7c3t0ZD0dA6BvvvJ/PZuuyZh+yIk9tllTG11VVr3d3JqQxtZlJtNUJKgBGhjCfLhq3bipHGgmUMqRQVxXvTMbDYeFqrw2wFxeaRmmGYEb24Mr+/u6BZ+dqPxwPFOrhMHH1KjG6t/ezLNueTMbj8e2337FWW2tv3rz53I2bRVGEEAJ7pTBJTFS33vs8z41VTdNEazRqu9ZgN0ZrWldrMmRtSqjq2l2Zzk+Oz+bz5XpdZlnaNE2AkDi3szs5ODjI8/T9r7wa2AFAkiSJzZh5b3vnhZs3lsv18fFxWdZxTzIzSnD1lSRJ4rY0xmxtbaVpOhwOkyTRWm9uSAAwxmhDWtsg2HoVEjdwEkKYTLaVUloTESlARCSFQrIuS0AQQebADCKCQIg4Hm8BwPb2dpIkIbAx5uZz14fDIQO7ph7kqRMKjA8eHs8Xq9X8TCcFKEVEElrRQ4gi0jRNkuYhBGVtkiREVJblZz/72b/zd/7Or/3ar9V1fXBwYPOcmZ1z6/PzdDR4pv2YpBaQX37fje1de/fBd19+6bX/+fNfKsvy3/6PX3x4BJnxWVrcv3syLIhUOhzZdBtefvnqe7fuZIXsXpvMZwuGRhudJLRYLZMk8a6B9Wr7uWuvvvoqM3yv/IFJkrqugdmSFl865yhJogKO8wUYH1shG8VxXCot0rAhhTel7Z/AQERmYWZjjDFGKRU9sKfZBP1yiuswhCASnuKlMAAxM9IlNeOcA/RKqfgrzrkkSfO8sNZGPCyEqFk4+tPMIALM7FzQWlurkySxCSmlnHPL5dILc0BE1WtcDkHrpL9AIohnHUJQSgUQYBAUFGRkBGRmhQoUKFSMzMCBAwgIiTTOpEWRZgBQlqX3Hluz45nnGS47wa133s1zvzbiDD+iejfXg1Iq4iV1XXvvIyDRYRL8iA7Wi8ViOBw+//zzJycnN2/enM1m88VitVpt7+3meX50dFTX9Wq9VkoNh8ObL7z43LWrLzx//ejWD86nM0gssl4EpGLbTPZ5OGFbsLbxfEEYJEAQQgVEJIjIIBAE2LkgGERCCCoECKwFE6RMqWFiRqkepbZI9MCoRJEiIBEUgM5KAyBGFmBAZgB6lrmOOw4AFApzCK5xde0b55oKWUBCCAECS4cSBBcEmKVq3GqxPHnw4MH5yWw9b7yH3I7QanHhvdvvnh1PhU2RJ4QM3pXLRQgh0SY1VmsNgkWaIYsB2B5vRRQlSTKlECQQkVU6ybNBNrBpmhgjiOKlbOoizU2ajIvBZDIJjSub+vj87Pj4ON7NPEsUjcfjSZ6n3nNyQkqZne1JkmTW6vF4kmYmN0YbSrQhbY1SgkoBChEEWKzK+fn04enZ+clZGbzCoBKNZIhgMi6uHexHiDXutNlstlwuy7KKpuJ8Ts16FYIjEI1IGEgIxCnQypBSCY5CUw9KXUZ/IgKtq5UyitLEJkr5kEPg2uuGqgDy/I2bh9eu7k62F+uVq+rDa1fHg+H5+bVyPa/qcj5brNZLQrW7t3Pz+s39/T2NtFjMtTbXr1/b29tDgtVyHdhX1Zo5wtE+PgK2pmjcVEQU94P3HhUgAjMEz2RMlhVGZ6PhdtM0s9mcmafT8/V6Xdd1lhZFPhyOCqURgvLeV1VVVy4KlDRNi2IYQlivq6hZnXOIGILTCokgz/PoMSulogeplIo28iWJT9pmigN08Gbo9mnIsiwufhHx8VsoDKC0Ymz3dpQViIColsslAIzHw8lkgkgiUhSF9269nHJTGsLU2v2dyc2rB9Pp9OjkvKxrogyZPTMRGWORuXIOhAeDwXQ6JaKtra3lchnK8hd/8RdXq9Xf+3t/72/8jb/xzjvvfO1rX/vc5z53//793z07ezaxB7Jer4KrxuPxRz/6vvny/snx7Gtf/4q1NktGH//Y6GDvRVfr6dkX1uVCeJUU8tKNg+9+/4sP752Mhjsmcc2qBChvvvj89Hzp60VeJFoUTEbv/+BrH/zgB8uy/q3/9jeS3f1xUUzPzuumpjTLB4VCirY8EDKIIIgIb+gt2HAle4sqvtK/Hm8MwlMAzR/TIKLo7hJRDE5FJ69pmid+vgeEEbHzhP+wMxQREBEJAgIgzOy9sLAxmjqcAACi4l8sFs41IsIsAEDtJGAMvsTftTYtilwb8r6pXa215eCD98wBgLjV3BfKLFrGPdLgOEQJjyCgiAAERDj4CKgSIYgXD4FFEIChi38556qqku564BnvSzz5p/m7cFkBx+vdfLH7IDdNQ8p2+Ar2X+l3+qbNLSL6/Oxsd2fn8OCgKstr166FEI5PT15++eUkSQ739h8+fFjX9ZXDQ63UO++8s723PxiOfuonf+Lz8/P79+7uHVyDZDB1qA8O1HhPiu1gC4+GkQAYmEGCEqWAYrCFBTlOJjABNMwaOQRPHDSqjGigcJKpScKjLBknNktUooRAEBiQUaIxQgAM8SeefaC0GAUKEwfX1PV61ZTr5WKOLMI+hMDehRCAWSRUVRWCD+ycK6t6VS7XCpIiGdmhVcooZQgj6MDFMEnSoVZBaQCAEEKR9ZEDDCHbGg+93wmhdb8Sm1lNUWpGzzQxKWmFAhH4FZHUJmmaWVR5nqNA1dRXr149n53XVRPYT89nq/Uyz4rRePju7fcSQ4NiONneCp6VpsODK7s7W+wbACZEJI0CQSA47zyjwsSo0bDQWivh9XrlAQZFXlYiJEWebo2Gu9uTiMFqba8c7q/X67Ksvfer1YoA18uFdxWJR9bivSACIimVaK21TkYjdm7d4cZ5niMisfdNyS4jxNRosmiDXgsHZmtUolV81KkdD4r9vZ08M3nx3GIxOzubrlYLIj0cFpPxlrV6MCicrwi1TbSxWiRoo5BMkiibaABIUhP9hj6AZDsfLoTQ7geSosgr11RlvVqVzECoERUibW1tRaAshLBarZLEVFUV2FkNiTGdCxuc886FEMLOzk6eJZpUDMk3jQKW4BpUQArSNE3zzAW/rsrZbJYkyc7ODirSiiK0GAehrn0Q1SKfwAzAPWweBR9HeyHaEBK2tsdxJwdAbqFppcgUxbCu6/n5vK7rEICZ14tl3azLxVQpzIqBSe2VnZF/30tZlj08m916754gzdfl2enUOae1BiIASPK8rFYhNEonp2fH1lozyL7xza+dnh0Hdv/+87/7oQ996Gc//dP7B7sPjx9IvQY7eqb9+OJLN2fzhy+99MJsNvuDL5yv1980Jv/UJz597+6ppmK1DKnNsyx1biUSPNdf/9bbTPBzP3vt5o0rDx++u3eDTo/5zt1biU2BnNIh1fra9Zsf/OAHDw6ulFXzU3/2s3/mlz4DzP/23/yP33/9OxIYOCxmszzPAQCEGSQq44hqRtEZp5e6gYhR4f0YPGB8NqkVT6B/EvVcfOWJg8WzMIGOfyHKJaQ3/vpFJDi6v4FFojgVCSEIi0SKBm8M59xqteq0OXaYrYpBPaUss980X7z3dV0nSRJAHPgQAgAhkNaaSLNrDWJjjNGEiN433kvT1EBCpI1WWitECkHYC7eKWfpHAQQApXWMn0ZHExER8EdTwI/c3B782HzrkXc3XxQRAIkWf/x8PJ/4sWg2bdpw8VHfunUromQnJyek1BtvvFGW5c//4i+cn5+vVqs0TYuiuH79+mKxePe999783usf+tBHPvDKS++9/dadO3c8qZBkZWXTYkKjXc5HziQetRdGFiGPLAoMiBJBH8EEQQ/AEjSxEgggKAGBLanCmoGVSQ6ThCdZMkxModEQK3EQOOpgEBJkABCM/3u2QQIcWRcghOKCd01Vr1fr1XIxOwcOwl584OBDcBBYIKxWC47MFhGBkOncjPX2cMuaNMpxIkqSJE1zrTURICEiECAYS4DRSmMQkyaAihADswQAQquNMaa9cyKAqJCEhQMHYU1KtGilUABEFBIREiAzF1k6THMyNBmMjs+OxUtqzf72NuPWztZONsiqVSUk26PRaDA4P3vI7AOjYEOgnPd12VRN7ZtQNXVikuEgrUfDsyLhRO/t79ZN7kMYj0Zbo2JUpNpYhWTThACrIvONY8H1amUIkV2W6KZpGFmBIkN5kiZ5kic5GQpNaAapJax9LV4UMTICewEEcYpsmiirE8+OXVM15YN7dwG8eBfEo9BqOV1YsyqXebGTZcnh4T7Argg6Vy+X8+OT+4v54vT0WASz3ORpliTGWm1tWjdlBA/josduxIBrZJD1ChiJPItr/Hpd1bUj1Gmq8zy11lZVpZSy1mZZtlwu67qqqmo9mz1//UokhEFnv0elXte1McaaND5XShHpEJxNjQ9NYjPv/Wy68KGZns+3JqP5bKk0Gp0Yqwi1kAQvjB5Bk2pBcgGI/4+I7EWglVmKjIiEEIApOAaSzoEARBJGQYkgmNa6aZpomM/n8/nsTJrlZDLOjFIaRPS1g93BaGtdu93dW47xzoOjpmlOj89qop4WNz06MoNBURTnDx5ced/79vb2fu3Xfi1N08985jO7u7t/8S/+xX/+z//5f/V3/65JktHeXlPVz7Ahkd/83ht7VwevvfbaG29+ixQYPfjUJ3/6gx/42K//t/+5sH54t97eG82mC2vtZDIq/XHt4PlX4Jf+7KfOTxbzefXJT3wIIf2fP/+VuqyTwnh2q7KebI+TLL334P6gGP3tv/23P/qRj//+7//+F7/4xbKu67LMkjQg+CheI1+mpawIAEQ8NorLqIOjbbTp68CGBwx/qH/5xx6XnPJ4Vj2c8+QvRNMNeVPiI+LTuDKIGN0iAOmNAxGJcG4Igb33yjdNsxETFSIi1EQaNhQVIgpjBIeQxDnnnFdKexeYAVEpUloZAC0iZagip5YUWGsRBYC9eEAGAq3JpCY1CSO7ynkBFAnAEFhINKIQEAMzG5MAQNM0ERtXSmkyIvKsUfvHPeD+cfPPTacWLkPW/YhB395Iwo6v9/jMA4COfJC7d+9679/4/vdX6/XW1tZyvvjQhz50584dCNw07vz8fLlcEuLdO3euHx7sjF96+YXn37tzz+nMp0OTjUK+5bOxTwpPaYMUOAgGJSwgQsgBGIQAAQU0IShkZhBAFmBE0USpVrlVwwTHCQ5TP0hUblWiRQGjiLBHxSgiyBsx4Dg7zzbTCiXGt1AQJLB3dbWqy4Wr1yCMISpgx+ylRUQqQEZApYjIKpXFmWUG7xtmJgKbaK2pXfzBAwAgESqReOFKERmtAIkAtSZgBEKFpAhEiJklcMQIkEgRERAyiogC5BDEB1BRuYNShKSB0aZmkGakuFrX+SAbpFkQX2QDm5qQ5dqqLMmq9QpYJDCKkFKGEI0CrwKTOJ8ldpgPbJaCD427YpXePdjzvlmV69Qmk61RkaVBgAC1oshV4uBskg12d4bD4nBvd75cvPnmmy407IU05mmRFWlqM9JYrWuBYZOkZb12tTeJRiHvUgRIE2uVETJ5kjXBNeuybqRaL6fnJreJTowhXZXrcrVoXD2dnhmrsrQw1nIAliawa5pKawrBrdfV2dlJnmZZniQ2Q8qrqiJqDXDmlkUZ17r3HqTlMbZhTi1VVdWuAcIkTZMkGwxGeVYkSXZ+fh6DQKSUNqas1nptTKm2t7eBg3OuruvgglIqSYy1djqdJtpERcvOZzYpUgQAVLAslzpJvW9Aaa2ITGnTfL5aG6OSBFO0DKw6gz1NbCRwAkQ7IQAAtjQUIhKllCElIiE4DN45BxRdHGAWgCCIALBYLIwxg8FgMBg4505PT6fn8/t33isSGA8ssauWblHWAfQgLQaDwcPTk7QY54NiPp8v5isXQzBAdV1Ti35DMhrVdV0URbNYbG9va60/+tGPvv3227du3bp+86Zz7uHDh4mxz7Qft3YHWZaMRqOydEUB3/7W+WrxhX/8D/7VcgFXDicgdVU2RORDk6R4egx/7a9//NrN8YsvHn71/EQbeOmVqx/50E/lef7P/tm/256kZVXzaj3Z2RkMBg/uP7zx2nPG2q9+/Wv/5J/+6pe+/OWqrKCqQppu7+4t57NODGKUIQQEnZLrJW8bh+pITz8GD/gZRy+4mTl64U+U5v2IZkEQhywgtKEn4gkjwCUvPF4OMwMIkhAJkgDAYDAAgEg8DiGUZUmoI/cYkRSZmJEQVV0M60VL13vP7JEkQjvr9TqIECmtbaITBPIeIpmZkYnaiCmitHrLKtJkrc2KLLWpZx9CEC9kyHsPwECkjEKF7Jk9o4IQwqpuIgUyy7LERNrjkyH6p42nYfWPa+UnvtJ9XZIkCyEEHwKEznISEY7WRv8T/RN97dq1+/fvi0i09F968cXtnZ1bt24tl8svffkPnnvuuf39/bIsnXPW2ls/eOv9L7+0Ws739vaee+ml2ydznxXD4bVZPvAmdTpzygRABocR7BVhQUCK3CdSSKQQxIAKvkEUEiZkg5BoyTTkBjMtuaZMYarQICAIcxAJKD19nBkIhZ+N0H95TglEkFGYvWPfuLpCEARGYEaHEBQEBo8YUgOMpIAElSEDZBUQI4QmpHlqlQro2DWenSEkS5pSz9ySB0QQMTWJSZPQuCAMgkhklAZFFOnWLNLpA9RotI4KY72qSIC5JRoaJGutCKPGsuaqLokgz3SR5Yk2w9EoeL9arxEYBYaDPC8K79xsOh/kaQgKEa21ic0AoK5dVVXMbK1N01xEEqPSzKRJPtke13U5XcwV4HCQp1ZXjQcOwOHB3QfHZ6flclWMRlf2Dwbj0cHezmR7fHrysGqqpmpQYZGlWZ4lJgECq7SxxJ6rJm+qxqaWgNJErxfLIku0skiSZ7luSq0VShgMCquJOSjUSpFC0VplOmlzkHSEvDiyx/f2dpqyaprq4cOHIrJaL+qmtHbtQ5UkCbQYFEQXNsLFi8UCNgCldhmQHgxGKYfgBYCUMlqZEKQsy8FgFG35EARRZWme2FRGQ+eCUZDY1JqkaZpoeq/X6xBCYrMkSaSLhGmta+/WTS1ARidK6+FgTBqr0qdZIay0VWmS2ySGHhCFRISodd970R/PNjF647SjGQHIgkhI7SvR5ibURBR99yioq6qaTqdVvZ7OzmiYiPcc3HpZnZ/PRNl8xLaA1ex8PB4f7u1eOdi7f/9otmqztsrZ7Orzz9+7ffu8aa5dv3737bfrus4nE0T81b//98/iePjwTCkAyPJcwrMZxIPB4N13Hvz6r/933/72NxAABXZ3rh3dXyK497/vw1evLJumuXfvvZPTM8Dga3jllecOrg6Ho/zP/fnPJCbb371hLCyWU2jAJHrdeNDw/PPPv/Lq+wfD8Wc/+9mvfPkb3/rGt7/whS8A4Uvvf/+dO3fqiGkhUWTSdjIhysQYvO//7CN2PQ3wT3hwl9bVQ8FxAT/tfPoVHn0cuYgHP3kgCggDiEDAixfx4OCgaZrlcsnMTePqulbUUpd7MDzSKeIjoiICpVAgeB+IwFiyNlsul6hMkpg0ya0yIUgEk6KaREQiIAIkAGQWb4xWRtvUpmlqjEGPkfZMmoiJKdrNpLX22DLRnHO+bpqqQqViNoH3/lkV8CYL+hEA+fJ0dehUp4P71RInJ8vyui57jK3PXNqMGmyqYR0aV6SZ934+n0cS1unp6WK5rKrqYG8/3oPoTxhjPvrRj/7u7/xPRPCRj378Ix/9uHvz1rsl2eEoGW3TYNyQXgWuSQFphFZYeA5AhIoQJHgn3AB4BcEqJvCagwZvCAzpVENqJNWQKkkUEgYUAWFEMVozhGeF9Z84uoB/EGjj/1qTsZodc/DCDsRpAsDIsQfmgAgEEZwCFIiROyIVd6dSylhtUYE4AajLCggJFHdmYQAvIuwDEBJpIgAR5G5+vOtpdbJBuouZr5FeGAk7VVUhgm8qYZ8aTQrZNUaTJRt8U69LQjCkCAU51NVaAe5Otln8er2ez+dVVSkyRVEMh8PRaBBC3KUeAEajwXg8RFQAnCSDLEs4BESoq7UIKiRgnybmrTe+d/udWweHV78FsDWZ/OzP/MxwNNrZ2lqWyxJLLz41psjSQTZQViFj7etEJ0JSraoAwSrr/MG9e/cQBYC0pixLi0EiIqSYGYigbsokVVuTvd3d7clkrBPdNJUge9/UdRl3u1Faa5On9sWXnp9sj0MIg7wYDAYRdE3TVIQ7LYtROnjvR8Otpmm8Z61Nng8Qsa7rdVVmJlNEygKRVmS1tkoppUzwAkKJRa01sxcJzAzC59OZ0WBMS6MVUsGHwGCTTEjVPiibFEp7z2XjkjSnNB3vTDQZVJGS6A+vXhPkohijAoVaGTLKkkZNhog0KREIwQMAO69IfGjiBiQiAiWMXnwMSymlmAMKEpCxRikDADFLRCucnp/m2WC5XLq63tvZPj56oJS6du3a/v5+ABgW2fWbz83X1el0uTUofuIjH167cHQ6Pzk+Wq+XxiR13SDpZDg8PT1JBgUAnJwcJ6PharUEgAcP7l994fnf/le/CSHsXL36N//m33zuuef+yl/5K/SMZnFZlgDwzW98+8rVq+/d+r5J4BM/8TNXD175F//iX73z9t3Pfe5zr7/+ne9855s7O8VieT6YQFU2o8H47bfefnD/7M/8/Ge/9Y03/jd/9e8Aw+Fz6enpuXPwkZ/+qXfv3H333Xc/+clP/V/+b//5b//277zzre+ODw62JttJlr7w0ovf++KX1HCgWcrjk+2rh2fHJ1meE6B3XkSUVo+cYR/OgA0BHd8ioqdlQfau56YQFxGkC9Ued33PAIjptq0t3n0my1q2cA+H9ETC/sjxUK0vKyFNbYyD+OCJCEDFmEjTNHHdxhi/tUnjnIgQIVIkgrPSFA1WY1RdB+99tN0BwLvg6jorCu99430IgsgAoMjkuV2tVlqTiPjQAIi1WkSaptHKktHj8diadHp6vlyuEZUwxnMgAu/9bDZj8c65JjRWpzbRxSCLV2GsKgYHSl09Pj5er9dN08Q8Aq31crmcO++9D8IkkA8G0f8uQ3mhIDst2d2Lp67DCF/31PFNzhR06hk2AIlHwvA9TFLXNQBZm8oF25mVom7NxNvaLyRoA0UiElmaaZrOZjNE/MVf+qWzs7OyLBerpXPu+eefz7Ls7bd+wMz37j2Y7N3Xw63R9g48WHjAYrK1IvSETASIgMQAxAQAoAFQBFCCRwnEjMAaQwKcAecYMgipSCqNDrUJpFErDAReoUZgAYikJIA2+ttB0BSv5pko0HCxeQggMAAgI7YJSMjM4pADAIswgbA4Ao7xZgJAEkJBFAQSBYiEyMDMyAKe2cfbgKwEQ7z7iMjIGNrkNgBAASRUHbkjZsg9bm09um/bPwURSeJ0ACD0z+MmiWRapRRBS+Qh0saYLC0Q2jhWTNEBIHx0tD8GEqD3DCIjUSDLssl4a7mzsz0ZhyA2Uo3q+vDK/nKZL7JFXdda69TaJDVtDBURSQgRSTQQKSCmF154LlbhYOYkMRHUCsHN5/OY7BtB3eFwmCSmbGoR8cFHY7k3uquqypIkMqtFxGoTvwgQDabewKTeMm0zF6WdWyIi0ooMR2pIuyQoTiGCigm3RBSCFgjMnplZ3HqJgUUFiBEVH4SZg4DWVmmrtUYixCAQECgIK61Iqz79qd/AEedQG6MFrAQQLozrjRXxRMXWZqtu3sIo0yPXejNeqLUeDHJmdhF+J2WtHlNhbDrZOzBJ9uB01lRHi8XC1XWepGKtIIg81aOdz+dk7cc+9rG/9Jf+0i//8i+fn5+/8MILt9+5/bTPP3FoZbNC/Uef/fMC/P3v/SBNsn/3u19wjjnQO2+9/Q//4T+uqmWe59ooH+jTP/X+n//0L/3O53/zN3/z33oH28Ort9958Nzz8MqrH/k3v/VNQLhy4/rnPvefsaj/8r/8uw9uvwdVk125AUav62r1sLxx8ye3t7fv3Lu7M9l+5eUXv/m1r5+dnAKIUio4LyFYa734Z+eWPGH0t2NTTfaK4RHdGd/qwyX9ooVOMvSwTe999sUcNr8Irdt2EXSMsq1lPCDG2hd1XTdNIwIuOGOMQBCJPqtJkhYxcjGE29bbwQgUi1K+LZqhjTGIKm4raOIlKyIgZkBGVCAkwEmSgNKEWgRiIoJWlgzVVRUhZREh4OgHa1SRNck+1HWNEvEcpYwuslwp5eoGFQFL0zTsg1LK+4voAPRo77MH5vsZfvwGPdNx4lQ/Mvol8fgT/dyNm/P5/Na7t4loMZ3FJEVjzM0bNyKf8969e99/8w1jzN7e3unpaZJkd967l4/Gr378k3sH+8kiiIZiWCxRAknAWFkjEu2I2xocDEGAPQWng7MYEgo5SIEwBBggDzEUQhlXmklDQoiEgMKRTrbh9xIAcCeJfrRtwkAigTASsTESAhFRJAAEgQAQQAQlAAeBQK10RorULRCFgCDRqBGByCEMHJgDs/ex5Aj1lVyQUeIOikZP5NUjAEKrB6SL2F+2r/GR7dreNol6QgCorfYSQ42qp0oqRMUsIXAIwVpldEKF1dpGoVzXLgSJ1KHNdHKIyrdbMxfLMf6sSJ7nW1tbk8kEgGImVZqm+SDL8zxJkuVyGUKI6t8YE0mJm9cVZceNGzem0ykAVFWltU6SZDgcAoDW+uDgwBgTK1QkSZKmaRM8Ivk6eO8QI36go4Nbrmul1KAYxZMDABGMVqlAAIQYfOmXSUeSjHpOASCh0lrHlAhCzQKEMYlHoVKCCESoFIKAIAIgMIaQ5gOlxSobbWAKgY13QYxNyRijNCMQxfhWQBGdpKgviv70N7SXs5tUW4XCPgh7IoXYaVwhgMgm62wmIABBQMCArZ2hokUFXf5iZM2weJZIy2Rj1c7OzmC0pU3CzKiMUkYbpVMY5Jk2draqmmo9n05d3RCg1io8veJDlmWxGNDLL7/84Q9/eL1ef+tb34ru7DMMoaYJ5TK8/vqb3jd15bWCBw+OvIM8H6x4fXpyNhhmn/zkTxjLy/Xpn/uP/8LbP7gfqvS5qy/9zr/9wf/rv/7HrsHnbr76oQ9+PE/333jr9ve+/ubv/Nvf/YVf/MyVw2vHp7O9Fw/Pzs7taGytXt65c/u9O/ceHC3Pzz7ykY/8hf/kc0mS/Mt/9s+VTbXWrm5zw2J9tz/+2PSQNoX44wJ9U0w/sioAIAS3KcF7o0268hf9/kVsJQp39Si0JqUoBMHQJpoXRUZEzrmmaVpiqQQWDwBEKk3TosittURQVZVzrmNLEIJS2hBR01T9OQBQZF15743VLQsVJZaRiYdGxEjjiTmBIhLryQTviSgE570HlKh0hAAVoShf+7pywAxEqbXKcJ6mCMqAbrz3ta+d840Tz8AiIH3UKYTAG4zlH37EW7BBNHsU7fghh3Nu80ZfAku6m7j5RMfaOqvVioi892maeu+ttW+88Yb3fmd398aNG8enJ++9915VVTeeuzmfLs5n0wdHx9fX62LncG+vWbpUkLl1T2OCEAEgAwoQKABhYK+CN95lEAqSnGiIMiAeABaAI4AxhDw0SUBDCZFgzFqSmGdHvU3KABcesPSOyzOEnUQEgDgGP6D1A+EiH06wDYewQICewtA7GSQAHklj5FixMEv0NEIEHICE+vuHnQIgaeO9wgECSQhBKQPUHra/8b0rrEjJBuNjUwc/8ihdxAI2llFc8SGEDm4yUV9U1ToardbaTaOPuwxx6qztR1YeERVFkWWZtVZrG/MHbJKISJIkeZ5HkkhvwkeCdwTP+58IIYjgJpiGHT95PB7v7u7meT6dTmPgIx7WeW+Fu+9KPCYRNWV1sWF6Yz8CQdjdNREADsEhqt6H7jlZAIAY70s0w6gzbh6BIghAiLRIQKWzvFCaNCnSCgV1CByCCUGRIa2QjCJkCAqDEKOgSbLewe039ubzSwMEkbEDGC/kiPQyWREBdeJGBBl8P72b4iNaP73bFLXL9vb2wdWrRqv1ei0ALngEaFw4Pz/Ph2NNgAJdCQOGIM419Bgk268HrfV6vf7BD37wG7/xG1VVff/733/31q00zX/4zQgAwmo42vr9f/8H2SDxDpraf+TDr9VV+NIXv7Kzs8fsy2o5nU5H40Rru5iv/83v/K5zFYCZPoTpMYyGsjVu/v7f+9U//+f+009+4vrb7xy//vqbf+Wv/m//7//F/+Pv/3/+4T/4r/+fxe7+6t49feUAhsOqqc+m51tXrvzin/0zL7z04su33keJzWwSb4RCkmeUtn/01W04QO0r8AT1sKmAYaOYRlwqcFma92q43xFxbQOAQCC6qBTRrzqllDBaa2Ox2LKsI/CJ0X9gDwBIpHWs9AIAEA24aEyDqH79xZqvABCCSLcricia1FilFHqPgZ0IhxA8B2ZAxc5FdRv9EFRKdSSvSiRogjzP4rnNlgsOofI+lgFRSkkINgSFGJmPPbTjnAueCRTiZW3HPcb5zHfqkZv1IyjyTX7cpS18+YD9E33r1i3nnG/cYDCIgf3QOMfy1ltv7e7uplm2v7//6Z/52W9+85uLxeLw8Gq5voVKT+eLO/fuHQwmB4d7ZZM+BE/gATeNRxKkiMQCBGJvgsuFx4omWm9pGGoZKB6gKgLmAYYE2xRyJE2AioBi8TEIIiQouDmbFBXcs04NxFrQQNJWv6EedQR6RMrw5XQ9jCRuQGnfQo8tOtdvFUUoAqS0QtUhQtJzFjR1hXcieOxZfPCAbK12HFgYBBhI9feGYnISCEQfNO5bEYyogjAQouI2fYLi6YogCAIQYPSTsWp8goq0QmVIC1DD7ONvRSNGGFrpLZ6ZU6MDQ8xoQVTRBBKkfFAMRkN9chYYNKIA1I1LvReRIKhMkuagjIuKmbTRQEGiE++DILNIEBfCw5OT5XLpgmib2jRXSrkgpK2vHQMVw7EyycnJyen5LAhOtsdVXSNilhYA/QQCIkSSlHMOQDR1ahXZ+QqEo2El3MddOEZMtdZKGRDs+Sy9f8/MjK2mB6GYnKgIiSItNpJNsHGVQDQPgSAqQyQkRI2kkDRQy4uKRWmVMkga2+pVcfm2Mbz2imJMCBAEGJiA4ELORo3LIqKUiZRRatkHHZ4ZQETEi7B0kAOjiEYCaFPvtVKeG2TJh6NiNF6XZcOAiLVjJVxVTb0oGQlRhsNiNChOz6cK0TF7761WTzRwV6tFnudE8Prr33n33VuLxaKua1RP1tZPH7he1bu7uyKYpAoA67pZLBZZWgBKVa0BYL1YfPUPvpaP9M7u6Lcl3Lr99p07y91dbQ3s7Azms+X5aX12v/oH/82v/tTP/3ySDs6OTh4cHf/yX/zlt3720//gv/l/iwiE8Et/9rOvvfbazu7kwYMHAPATn/rUg/v311WprCGtXd0gKmvV0x3+Zx6yMWCTKCsAwB28IRdRSpQIw7ap3jFuh9QnvD1ybjFJDDrMs1XGEGKKRrT+Q4Do0CuFTfCBXaQfi4TN+tKwYRS2ZSbZOV8jUiyVGvxFCaeY+Ou9RwwIChHTNLPWKKWMUUQREfSRvNLl/sIjP9E0TWItIra6H9u9CQDOuZj6FF1J0aJQoaBvfCQ8clcEAxiEWTDCgRuQPl+K2v6Qo3d1Hrllz3QQaO31S8d85PmjHnCEBYqiFXCR9oaIq9VqPB7fvn17Op2+9tprN27c+NKXvvSlL30pK0YCerUq3377VhiOJ698aG9rMl1rACGJeivG2UikK8fBnrw37IdA28ocpOluokYaRsoPiXNurNMF+LHRuQVLEY9ljpXhABkFN80ZuXALnjWrPao1jqUtoU0+lx7Y62Y87pP4AggI4wW9HxEw1sZiARRgJCHRpEDIMLE2pnezLnQzkdY66v7WCW7dQKpdiJoPAEBdALZ95mFvlHV+cPuZR/zgGMiHja0el7VzgTkmVyARGZMAELPvF1zcuszMEp9srsKLn45LP4aFIuNJKQVKcfDxh5IkSZIEu0htr2PkUrF4NZ3OvW+01sPhMPrN8WPz+TxuuTzP8zw/Pz+PxZyrps7ztCiKWBXde++dY+bBMO/dYmUuEiWlhfrjVUTBASKCYKL2VUqBXKBMCNiG0UVi8XoQxeQubUWSjj2BIBQESBSCQkAgQuGoPgU1EEkseSJCQoyAZDvQW7qsUdXHaeJjd5cRAbA9/UtopHR+v1KolCJpXZw4dX3mTDvhG/oyuhGxokIIIUmSZVWvK+dFWasBlVJGJ1KHyjVNYuxkMtna2koenkQsMRYKe6JXKM6JSJIkMVNFRGLgwDfPsiWFjMmOjk4PDnZm87MQZDAYfPXLXxmNJ7u7u7PpXGs9muwslqfrtcez6Ww2a+rADsQPhwVXK1hN4cqV4rmXXlouq7J0wgRCX/riV0bb/+y9u/d/9s/8mReee+7OvXu/8iu/AoT3798NzJPJxIfw9jvvfOc73wkhOHHBOcVgkqR2FcCPIFX+6IEtUAwhPOrXbkpkuihSjZti5HFHKkZqY553G4htQSCmjhXfNE2U7cPh8OjouKqq+XyulCrLkpkByAWnFCoduahKJNR17UMTGX9KoVE2cg/jiCipc46DkFKKVHSR0zSr64oZY21LDhDRSxFJ00R6ykVLqohJTdiTtiRgXddI4r33tXMcxAcWVoDMHBrHzBC49i40Tgg1EmqlABGU9zGDGXt520/ss96gfpL/mMd54vNHXrnwgKPXu7OzM5vNrDblam0Sa4ypXLNardbr9Ww6RcQofO/cu3/12guidO2axbvv+sHgfQc37OFunhqsPUJACAA9P17FapQYnGaXMBQEE2sOk+wgtxMLIyUDxTlXplGpuIFWiRVFKCRCKAgCEETUBZAbu1u0zEMUAoDOyf5hR4jHRYm+bzRYBEEIgXszFRFafcxehCK8E13SSFBqYc+OF6G64CKaRGNXqKFToS3Q2uV3QgjsnBPnJPimqYL4FjwEEuxYlxK112V4SoQUAikREYwYQwwpkzYmtBVaEQSouwhtLCC1wRgkZbQghNCl+3UUG0FA1AgcQAIgxx4ZkTUGwABn0/mqrGvvhagYjbTWypqoI1iC8yFapkRKAAMLkkJSAEBKlDYYuX4Ii8WCiBKbJFmujGXnSBtLant3L82Lsm5CCKTN9u5e0zSzRduMpSzrGGnWWisyhNIV0tAAQKRF0HvvfK00dbVySFq1JMwsHPteABEJR2GnFUIAjj4oREQNJMT71aZwCCKqqN1BGIGRiFBIEbWpUaiAAH3jMPL/CVFAIRAohQigiAihrTrTVf6PvExujUjB+BwBRBoAgVgqptXBCgA2FbCCyOT3vV0TVSB0MfvoZwBAROrS1DJ77xsiWiwrFigGwzxPNSnSujAJKWOMZdRZmmgC5q5y59MdWt3FqqRNu7IxstjVYPphx9Z45/76/mpVNk1jrB4MBsvlsnEVkUaCEMJgWOTFwXJ1HkJdV5zYwd7O1vRs6urapqky+XLuz2azZrU6PZ2DST/6yZ9+8ZWXf//3v3g+W/xnv/wXX3ju5le/+lVm/q3f+tdf/OIX33j9ux/75E/u7u4CwOtvfJ9r5yxRV91CAkcj+I8/NkVtr1mJ0PNFcZi4tePz1uHrrKj4lUhR3JQA8TjR2o5LAjq7EyLjhAWR+oqV1trDw8ObN28uFquyLKuq6uMRiMLstdHamCRJjNGI4kPTNE1MOiWiuJa6SHDbYwARtdFaa0Id9YKIONcEjm2LauYWQSTSCORDaBqv9UUorTO7L+zmpmkCu6qqOKAIopBGIkBh8CFw4wmQiLRJBYEA2x2oce7W/VS3JumPRA7qFXBvefcRnB95bH59U8FvPtEPH9wrhsO9nR2lcDKaHJ0ct3cXsGmareGIER4eHRlrb964sbu7/96d+0lWBN/MljN7797h8fFocm2gkjyUNZWOkhURkwVQUQFAYGLUDKm4XGgL/Y4Je8bvJnqoYKjRCGmltXChQCcU0GNbZpIhOiYdz6hDTTan+JltVQLmFoXmTlLH2VGACkC10IrEaA0BgHAspnsxAGLRg3YyiTRppckgkbaWNioliUgU99BSJDQiRg0VGFjEhZY+TV2N4k22zoYCjrHJyOhiEEFhApT2ORAICwOHwCxE0vGqbMwfFQZAQtCkgEJ7kFZeM8YyH6CQaJN/37uS8TG2SoyhWeloPmmWxZpzkYEVS00xc5qmG6LHKAWR3ziXeb8Po3qIW/ratWvW2tVqNZvNBoPBwcFBzK9FDOv1ejabxTjxZDIZ5IXW2jeNUiq2L4y/KE5EhFDHzR/Pv4vyovfec3TqEQiAFAITWAwOWxcU2/wlboh0V0OTotpDRMUqsK+qSkChChuheBIQIt1yYYgie5NAIZHEFjFC0iHNcScSxSR3jD8SeYsIsXhNG0kQQiFsgyakkDCaNdKT45AVdsHgLmEUQQGGKNAjjwZ6qCOmWyTJcDQq8rypSsTYX1IpbQJ4EahdqGtvMy+xYGGLM1HXf6x9tDZdL+cRTYnVVb1n50Jink0BP3h4NNoar5bng9G4XM/vvHv35vPPrdbrctVMdrbOTk6Pju+NRwObJlbn2przk9V4MnLOpbu7WqkHR0cnJycBw/61q8tqvV6t62px+wdv/ovf/FfaJv/7v/6/+/73X3/vnbev7O3uTbZ+9lOffPftH7z13ddv/+AHhwd789NTYC9BKaWqutJeB2F6RvEtT+lHSIpAIMKhSEiKlFZEhI30ZDrYQLDKsuzd4l4rR5nQSwPoKO6RLNZXfJMuDEyKpAuyQst7H1y9evV973vf669/n5ldE8tGqpg14L1HIEMm0YnRSoTZMXgCT6gUxliHB/ECAZRWhpSPzqzWxhhmKMumWpUggkqxaCKKZRuUUkhEAs6FyjUka2v7xN+Wdqq1FRGtrIADwOClrpxSFgSp45Uxc/TvtdZWtaUDnXPsmIyyyipZA8cvAAgRYEzx3LwtfaYMCTDCE+8YYqdfJDbxi/ifoIBElOwZHqXv5iTYNpYwysR3gNrPEJCA4F//c//Rt7/7HU3KJHY83GKQq1evNt4fHR2leZba7PtvvhFC2L9yyA3v7u7ev3//6OS4GI2CScZXru29/IGwdbj9vo/dDck9nz6QbG636mTkdAKgIXjgtVrPRlzfSPCmgeuGnx+mN0bFwSgdG5VpQK6IG6vYkjCKztPoBXYOgMT8VGldtsfHs+lgbjF6JuDgq/V8Pj87Xi6m6/k5eMehwdCABOC2InTofMR4SoQ67p+6iSiN0dpaa5VJEm2BtM3yC6i5GyLSVZ28MIVCCMzu9PR+8FXLWlS2pzhFej2CikBTV/XNg9RyUaP/YkayLJMuJ4G6lOKo4frN3FteADCbzaIprTUpZaJgFZEm+KgpnXPe8cYOl3v37tV1c3h4eHBwgIixxVAxLKq67mIzuq+rrpTpzyH41ogWCMv5LLCPfK6eJr1arZRSMVm5KIqtra3oUdV1Xa6Wxqr1eh2bcd24cWN3dxcRq6qCDt+OHOOmrFarhdGECHleAMBiuY6We1nWaZomWZHnhdGJiHQxbnLeb5DC4lQTAKZpGpsi9HB60zTO17PZDIiMUiZJsiQhrRViEDFKoVI69hwRYQAFSghJJYzw+DYVBlKoSAswB2EJwkAQEJ2Ia7ufNk3oqmlqUkqhNSYyYOPksPMcPKIQ6WglhOCiB9MaJRDW67VS6uzs7N69OweHV/PRxNg0S9M0TY3SseOhY67qMNnb/7Xf+B/+/j/61YBKpcXZ+SwbFNH62gTM4yMiYYuPRA5qDFuKPEWB9e7FJZHHFG8EAQuxAhQlJCyE2+OtB8cPrNKVr0LTXL1x1dXlw/vnoOA//eU/9wdf+PK9d4+397YX6xURMvs0s2VVvfrqq1uTvd/791/MivHe/vXd3f1vfvPrAoGZY3Al2vKACOs1JInWhpkJ0CaaRDlfb+6RP3IIirZtU40+mBLvl3dOGxPtUSJK03Q0Gg0Gg3fefuuJh+opx9AReWL7o94u753giEv3H46h0778IRGE4NI0TZIkVm5/7rnnXnvttYcPT1599dVvfuPbf/B7v5ePx1rr+XQ62tqqqqbLg2t909DXBWotgJaQVRTFaDQgI6Q1Yiw52ZRlGd8FgIiaE9FmgDmEoIwmwBCkZ0HHGm1RuXrfbDZ3ahqvlTUq1noLPbSepxkASODNIZHrcIEkPRm92Lyjz+7SImOruX+4R2F6wn8YkImVqP4x/qcBpcgz78LZyelqscyybDKZhBDOz8+T9Xo8nuRpZhK7szURxp3dyXx2erCzJSaZrsrZ6VnQt+1e2Ln6/FY68Up7DqFeVI4hGYLNASQhnWm1DbSd0I5x24onptkyZkuboZXEtDwgo0gRC0qX7IskndvYVgn/cQVmYtk5BojNtBkAUIBIo2IEg22bq9bxCGGjokqkYrXAday0EdMwVWsxUKSDYyuMALllg4ugbulU8ZoAQBA7fm8EDBFUCEGpJywS7ENBDAAcGdZRmrU7Ezo+lnRgecT/gVsweiMnJwIAFJ01keAbRCQSIsp1SkZLW70F+qDUYrEqimIwGI5Go5jCpLWWDYQNNorWXkix6MFRTFhU0rHSekMYu8yZ5XLZN3jhLr/CWqtwEOGHaAUjYsxjprYg6EaPdK3I6O3J9vn5aVU1RVEUxbBpGiKdJJkLopRC0qiIsMsh6+RXfN6n5GLbxy0ugBCFY4x/x1C0UsqaGFSO2c4iIiRtlVMBiCwRRM3sW5uvt68hxjMEmAA8AHD0vEEYWSsQRiBERRCLakaGqjVEhKQEkIVZEFAJBd8wIYgERE0kcUFG+0lEBEJkvA8Gg+FwGDOn44iYT0yGQ0AiqatmtSqd8ypNImYjuLlsLj121mS/oOLjU2sj96q3v19xdmM4vO06h4AxcA5y5/4dm2iVKPAy3Bru7Ox86qc+sbU1+i/+r//Vupw2XAJCAM/sjDXDPJ/N50rBdPpwNCzG47wqm3u3br37xlv5qBBAQYqBpM6zwsnhwfn5eVVVaZIQUawkbK19VgldVVWb9UBIG/D1oBiqLm2dmb34silp/dTj9KaeiETqU1zhscNP/EwP9vTbp5/SblZFKW2tRsTVarValeLc22+/fXJysr9/eOfOncViAVq3yjuEsqyBIXCQIHzhf4NIK3ojCkZxUQEhKmuJkUPwztdNU4fgEEUpdC7EeM3mHY+LFxiBCPEioVnaSrFRiWLvsYgIiBKBEEVaSykF6CVqS79t/8UCrthDNT/EeCaAo6VTy7M/Ij/yKI+9Eh/1dDrNsizdav0nEYn8l+FwKCJa693dXdIKEZ338/kcAAajYe0EZN2sl8cP7qrKTa7f1AdE6FUojaSTQmE2KhXX5dqUc+uWmfK5UZniTEtGKjdoNSdGJ0YLgLBoElIsEvxF1ZIfCcv/UYdSkVYjhDqiswEEANxjIeb+xHrd0wV4CImkQ7GiDowNSQREE/TubwvCAAaILr5Ep5ZFCaiOJBkD3dz+a5WuAAuR6v2JTeu4f6V/3mNZm6/E0Qti6Wq4xP7LWluhi7o/vapzzg2HwyzLY1+8eATufiLmrXZpD9jDEp1upm6PgTGJ940iTahixjQAKNLrVRkpmhgTzAQVKWOQEut8DQA9uF2WZUsB6/hHvScNAHVdP3jwoGn8/v6+sTFOmaZpWjVV0zSAFQBYq2IWRwgBL+F+F71URYCIgCh0XbWj4LM2gY2CJ9EfjWdCXdIz9rlALcv6CbZjCBHjvQhVbK6rTRslvtL6UnBRkyF+wHtPCF1uVdw7iggQYwyYYzGjPM+LYqi1vSi8pBQhdSsEYi7idDptGjcoFFFLxn7a6FVuf87yQ3z+8T+f1s5vPB7XTRk7wC8Wizt37nz605/+wQ9+cO2FyU//9M9aM/iX/8Nvz+fzoihIwcm9+Wf+ws9PZ2d/8KVvLRflfFYhpIN84nSbP91vhH5uj46ORCQugxgHiVVLn62ZRLzvAnEyewXDzIk2bYAWIkHd11KGxj1tlkII8RZHBRyjPFVVxduHGwhW/Im+tAtsLBilsCzLLEt6O1Xluff++O6944cn7733nncMiERkrTUmMcYsZotejGyK3F6M9PMWX1TKiA+hca6qfdNICCoWBmkCAiDHaFc8SWRmouhDYmz6joDIEo/QbjoRZCGBEBjaWNtFtLg/pVbK9Xr6Alh+Sgzgxzf4mRXRE0yBttVH3KEba16/9NJLx8fH89kiNhAVkWI4Gg6Hs8WiaRpEtb29ra1BRGMwGomksWzWVqO19my1OFusxCYf+9Nbe7v5sBiOGjoO69XyAbPCstrNVU71Nrqhl5Q9BVZp0MFoJgRCUhhhYZLYv3Bz3v8kdXC7iEERssQ+NHxRRQg26C29jO4gXN3LYiTVB4X6VRu/oroMjbhVOvlFibEILQraLa4AoCW2TEKJrn/btkXYGhMLnQNArxjk8rg44Y057EVDfz7xtDcRJxXTdvGScd2fW57ng8GwaZrZbBZ3CIuMt0bSFRLp3IuLovabcxuPaYwhgtjZtFec/Zlgxz1phRGwInK+rerMXY/ryMbqved4Xd5758I777xz+/btqmpms1mWD5IkGY22mqYB0s45gVprbe1F1znXDWbusQcRsTYhIsILFkyf6dTrnrBR9WbzLvSTLxA2IlCXRv8tuKzGmNt88U3Bd2FvbQogIhRDRDG1Jb7cHzbGAiKjta19z+y9z/Oi1b5EhLQpZ6uqXK1WgS9a4CFGiviT98sjf8YRnoJUiQg+tp3lqYg1pWl+fnTcQZqqKIrd3d1f+2f/9MrVvSRJRqNxPkjqKhBpQqAUfvmXf/nh8YP7946cY6MH5TpYa0OopSPz9/elf/KBD3xga2vr9u3bd+7cidt5tVoZ9WwxbKuNIG/u9LgSyrLsTTFpWSMcl9kfcrQeXKWunkZ0hfs78viy2TQsjDGL+Rwg0iEpz1NjTAihVAqAVquVVjbPc+/9crmMjOUsyfp1u6npew+1Z2JHqlRdigtNn4/bn7lqCwBcFPCK/sZGXdgL2zRifpsWJ2zYcJufp47q3xqpFypY6I+y+f74g1uk8pliwG3k95HXIT6HjUcBQdDj8Xg+nyMu8zxXSp2cnJyfnw+Hw2hcr9fr0WjUeFdVFaFerRcvvnBjuVxWqzmBylNde7eaL++/8V1r0xsf+vj+Kx82JoOyNh4maZGO0wxKC9WIq7FvjF8jBUxqqAgzwqAQdFu4ggQAJQB2t2VTc/zJaOJNOSjdK5sSSi4XN1CXB8XUDWjZfXE9dQWzhKjFkKOSiml1AoEUoG+dYGb0HlvcEVugUgSYQ7csgzJJy1/eWKybQZEnWjD9x/pglepqYElnHHQbL8QvKaVilC8mHsQq54gYK/tHhy8wZ1nGG0S2XilyiDcuuvL9PsE0TZ1T1qbGJFHQIKL3PB5PYj8TrW2SZEmSeO+dqz2zawIzE2ph9I7jcwRFhEopQqXIIGBM7loulzE1Yr1eNy5sb28DQNM0W9sjZoa2dtjFcvLdYGaAniCKzjmlFOGFexqFYOMq7uqc9BCCSNv+r1fJ8eAMT0niiUuEpdWdLaiIBNA0Ido/EZoDaMWidxedA2IokIgA2oIqAAKILMgsnkMEFFmEBVnQed84VzeNzdkYEzPlKNLALnCUC3OtvQREIgpPaa7Q64P+z1YB+z9MwTxilf4hnzw5ORnuTJLEnDx8uLU9yfPBfL5k5jvv3fsn/+SfnhzPrEmHg/zk5GQwKP7Up3/ulVdenUwmh4dXTk7OVqEJoSnL0rlgkguF2mNF0ie8dgUdNy/qmYZSijcERTQfsQth9MtmU30+bWb6XRy7gIiIcy7SDHurvVdd3FXboC5IFBXwYDiMNc9jHcOyLAFIa53YbD6fC4kxxntmDqrrevn4DcKOxtUrwnhWZVkGroPEeevQNaHgRWvbfzca5xFPivKml4ewIYs27UvqCwIGBBYEabNAASjOjG+L+4q0hMb2xH7Uljw/1BAQfCR29Ic/xhwUbMvJPvYosccoYv+KPj09dc4VRXH16tUsy+q6rqoKEbe2t2OGWVVVi9WyLMsiHx6fHD938+p0ej6dnQ/HW1bJ/nhwcHBwtq6rk7vvfHl179bbwys3RgfXx/moqqpmUZWzqUjTqOAVO6m8Rm88DyyNMmJDYIBUjNCIgCDRk2zi/9CWDkQoiRmEUQQu66r4AcQ2RVMkEg5Nv+Cg24EYE3jaIGDLF40BY+ZIulbMHoBiSDH4i4Kr3nvEC+mQpmm8QywSAgoABxAIgWMTlzZQGkd/trLhOW3alZsKuBcNvQrpN5v3frN+snTgi/c+SbSIRMu3zzsMzHVdRyS5B2N7OxoAYi5gL3dESCcqImCxpE48Ae/9ZDJRSlVVFbv2tg6cx9BZ4j1To0WtO6Onc5JaSbezs1MUWWR8BIbxeDwcDpk5VscMLLFaeu8RwgaOt3k367pGxFhAu18DvbrtrfL+lejBby7XuGC8b57Ytis24eauvkG8IgHw3vcIR38jsIv84WWnQQitTZm9dLhf/wHvOeYpxSLhEcyMHWaUbjMyJfRLgn3gJEkGg4FWwMzSlSp7WpJfb4nKhudERODdEz/fTy91wfv2jafsbLda/dIv/VJZrv5g9cXJZPvOnTv/6B/949l0YSw+uH+8XjUApJUQ6giz//qv/3dVtb5169ZyUbkGEBLSmOe5Z/dIWLrVuCG8/u1vg2qrhMY1VhRFtX6GapoocWO3+y6uyQjn8AabKf5Ev/WeeKj4FUSMxKvoX/aGMl64lZcGbCBqUT1HbmN0tZnZ1zWgIqK6rmNecNxcvT1drsrNFQ5ddIm6hIj+/oYQmIPzQbANV0f+RPAS99eGzKH+UMwt4bTfWbARC8MND6GFskKLFvRWC3TXvnGGP/wt+mONPgb9Qz9SzML/4XW2rusaANbr9b1798bjsdb62t7+4eHht77zndVqBUBFUYQQhsPh88+9OBjmR8dHp+cnBLI1GiqR8Sh/9QMfmK4rSIqvf+/Nt7/1peXD957/wEfzyfZyVc6nUw0BFZhUmxSJHWv0OTQDLdvDELSEFBQytSaDAAhdYjv/CajeOLz3xB5BQAJIiGJpk57XK+DIJkC6KN+I7WYTAA8YN0zkNPQYMgffAMRcOhFB5+q6ds6VkbPaKUUWCSIxmU969IYF2TMzMPvyAm+89GRzt/Se5abg7jVH7yvDBpAeX2yaJssK6JRKFKoiorV2LqzX60iFyLKsjYyGUFUVaWVMEkkbAICgAMCYltzEXSmM+PtaEyBqk2iTAPqoCYxlbRIfBEkbmwCqmM1obdoIR0Z0vMAo3WL1SuhwYOqKWiulhsNhRO+TJPFBouxTSsV5dl5EpK5dj2CrywVMHp3Syz1tQghKXwTg+0mWDb9qc26BiBnkSYUdWBQCtnlPUZ0LxR7j1OWCb9oW4gN2+SuwIYu11sy9bycAoMhAqxeVtS3SXlWzECTLLupitqfRcgCDDzwYjyaTScQeiBT0EvBJY9MQgR9un/b2BHQpm9LyFJ+Ebyl1fn6ulNrd2bcmVUofH53kg3QwTK9fv75cVG++8XZTz4tiUJarb3zjW7/3+d8fjLPlshwNh0ZrawbnZ8um8doidgVfNw9/7ebNSMIyxkTLr65reSok/tQhIgikOkM2BoMJyBjbSOOCizyQyEViL/KUiCIigUCkByPiarXyjpUyrrlQXXGTRr9AKRWTxYVRAJ3zzEyqcw+ImFlrm02KWK45z3NjTNN47zlq06qqEZHgQi/2Kznqyx4q28SBsXU/hQgVagCI1W7Yx3B73B0MIrFSVSzwGQGWCw0NGNtW8mXbF9u6ND0/ABAxFjyKoRDqwnsAHbQLcLlO4o99PHOtp6e83p76xiMAgP7ud787Ho+D59VqlWVZbPZUFEVRFIjoPSulwIG1djQardaLe/dPRGR7e/tgb/fs7AyD298aFXm6KKsR1kVY2sVDOXrb8Orlyfbw8PrR/XuZpu1MD1RQ64pCLetZtSjEl+KywDUyMQpA7B7Mz1zM7sc0QoiFFmJtRt50FuMHRATa/pcXNlrrIrfqkwCAlPT6rle3LRgpoU+pcq6OaS19OkGvCzfkY5vaEVM84ylV4SL9Bjagv07VyabQ3FQP8Bhe3dvs2NF5fAhFMQxd3JcuyB1qtSpDCLE6XUx5cs75ELz3CkEp7tW/dKlB8RUi4gs1Q1HZ9/Sl3ouVLlNLdRkIiKitYTHxgqJ8jP4xduHqXuHF7yJiU9fT6VQpk6ap1qppGpFVmqbA4L0PLTAe+qlunOMN6L6fxjTNvPfBC3TxLe5icr2nu6mz++/2fo9SSsUiIU8Sub3q2lwAPeu5PThtAnTQK2C5GNhXbsE25NHpQg3MHNM9Y2F9770xRm0gNxtroa2TFevRVoEvqqA/ZfQTJZ2H1BsuTxz9j/YecDt7T/nK7sGVL33+80BUjMfv3Xp3NBnv7u2t1oum5vOzRVU68YxaAZBzAUm2d3dYmjQ1VdU0i8VwOxHBoshX5Rypdek2L+fuu+/aLIul71v+M0DTNPoPKT7ypMuKDUZ7ExC6voFxg0Rif9wFfbLDE0ecFmttZL9GGNIYEx0kvIxjAYDaEJTxyPHgPjRZlhCRcy5J1Hg8dk04Pj6OnTNc4wEgLwqtdQhsjIkeP200TemPuWnTdzoYlVI9mXRTtoQ2X24zitG2UhXxmwvjEQsS4MLcfHy9PbbFNvJB/iTGj78m2iNDR89gvSqTJIm39t69e7Fc0fXr18uyPjo6QkXW2u9///va0Ps/+NqXvvD593/g1bIs33rjezduPPf6N79+ePXKerFcnz44eef7L73v/R84GL9z5y2YD+dA164ejnJtpUmCr8ppvV7a7fEwswpBKdJai4KAseFgD/H9B7zg9ujYPu+FJhGJF+ca8LWwh+A5eN6g10Is29HphsZFS7NWSimTGGOMsUopX1XaKK0MEgTPLAGBSCGhQgKEwBJc431wwTMiDgYDgDyEEMH/sqxjyd9eiGutqRUKUYtTr2g3XRm47M6WZSldxj0RLZfLo6MjADg4ONja2op1M3qwK86J975uGhHUiW1pZaRCCLPZ7Pz8HCCq3iTqPwCI0UREBYQtqGXSntzUSVgiwlgwIIIbAThPLCIKkbIKEVkkyYu6rvPhKNvYkMwMwRMqVGAtxsRivPALVZIkxiQtklAul8vlbHaeaNje3o5qpigGABCCpGkqqIgoMDZNE+0ARIyONV4A5hKlnrV2tVojoiLTy+4IuCmNMQjXC6Y4+dj1w+jd1nhAZSxsaOhe6EjgfvlBq8+EgW1qERDaY/cAXQTz43Hi9iCtLGj2TQ2xyXRP4TYaAOq6jrUQgkjtVoPR1t7hgVKqLMtiMIhr3gDFhYfKbG1tRfx/vV6PdvbPF8ssy2Ky9RMHX8YGWksUgDfy5uGyTN+EXvpNrjbgyoudj2G5XKajrfb2FcOm8U3jAXC9LtfrEsEk2QgA68onSQbg1+sSIEQzJh2NnHNJkrjGG2P60pIXrhVikuewAY1Go0op9axpSCISQiwp8wha3wBALH7nfVtWqK+F96T5BCJdlvWdO/e616iuXccKbucSEeKKCyGiXIoZEMmYRCnD7JO0zR5O0xyEVssymlbx9GwS67mG2Mo3xlk2r2XjfC7oVzHjn4ii7xntwhAkdOEGahstAMClyO4jzNPNpdKLkf53o76P+E0cwV0wTBNtRAQuWIgiAILgN9bh5q/0teE23+rh+t7uhC6Y1ftavWERQvAcUFEktSnV9l40xqRp2m+N3hq4kFoA8Nj6J+rSLtqckbYnjdZan52dTc9nxpiiKJqmWazW3vvxZBKPPhgMBqPhYDCoK1dWqzfffDPJsjd/8NbDB0dbW1svv/iCVnR+ejIYjHaK/LN/6mcr78/u/GBik9X0+Ctf+crro+HOeLC3NXj15o1r+zvJVjEaZmnM//0Pb188Ptr9D5sVg1uPNhIGYjX0PumsF6aIyG3tNAXQ9zFSKsq5ThCrtpCDMAcWia14BMCLj0VFYuUgZo9EiKDIRGEeoyreN4gYKw7CZQMwrhhNqvdKN5vcPXLj+69EtQGd6RAVc9xRUUeGLuMohOCcm06nqFWe58PhkAMsFovZbFbXdZYVj/gQ8ZhKdc2NuyGt1xvPpLeVEQCx7/i3sUvbeeu8zMtvCYiOfC7YiAz1XhRvhOo7V+xR+l60Sxgo3ikAiDHg1ui+xMZUvSZuf6bj0GzsMegvs780udxQsv/8I/pmUwH3Y/Prm9jUDzk6TCV2dIq3kgAkohTet6FEikVGTOJCQ0RaKW67b7CIRKhDGxszvPt58xx+BEdjYz7xkRd/WN/lCWXe6eItoNhmHCSWhxPAvkQXQOxDIn23tP+Fj35rxEGk+2UWyX29punH4/flaePxWynCF3H7x1ylx46GVVUixrpXut/jm5jThnwAAGiai7Qr1XVoQMT1YgkAsSAldoQDRNQgAYSEAgQSCOIxICMnJgkQ4uvIyBAgoGOnQHFs0S4eGYVEAngIyCjIGjUoUECMrMloIM+BAVxTNxxIaW1N8G52Mrd5EZnMEPPPFGlSQLhaLHsuNAFJx4pWqIKEWBUreB8rZLEE/fGPf/x73/ve0YOHAGCtLYqiGI6yLHvv7t3Dw8PBYJAkCRBWVRW85HmeDbcePoT79+8D0Hg8efDweLVYIuL73vfK0f17H/jgh5b37t16+OBDH/nweHfr9ijP8iRVuDo/ve3KjF7Y3d5ZzRfrrRXjha2JGzSVp5S7+vGPTVEosXZutFBixZzurZ5cgF3BDQCF2J5yG/OgHjcWHW2s4AO74EUgiDAoaGqPJLEmcKxtqZVVmoxOlEYElaZpU3sfGgDoe4p1Z3hBvugXX0x/wg4a3RRtvfSPf8ayShGEjAo4Wl7x3d72j79V13W1bERkPB6D4HK5XCwWpis68bgOVkoBKkJFqLt5Uhzz/3ozEFRb7wFio14kbAOdAIAIIqKV4ZgPuGlLIhEKEyESYmvS9pg5Yl+ACUSASFmbKnT95XcABmLXGQlbq/yCqgrdbgeAaAZFjRg/0BsX/VVHlHiTcdbP+abqwi4SH7oKkZfc376XEUAMp3V2g9q8g09Yq4/uji5o2ZqTnTIGTNKkaRrfSBPtPRCBi5zv1rkJbbDAJolSKs2yNE03r0KCf1qe7tPGI3bVE5XxI1fwlNefFEtDgLbWNIJoaBtjc6txo87+4Qoy/LjGs2ah/nitgg1Vy71ik7bdi4hEBQzRS9742oWxiE/pPPG4PIE+SCzS2TpycTQBRNys0g8AgKyQYghAddXaYu0V7710Tn2EelrZoeIRQAJ7YJEoEsDqC8+4tZFDCADWWgJGQQICjpVlAAGCa4CgbVjH0NabA9YmiaZZhLaiegSEwIEIEJg9u+CChKg4bW6VtpJw3TSKyCZJ8H4ZnLBvd28rpYgVo1BidQQCJKr37pE9KwJSSpAlgKCQUkCkT09PQwh5njvnjo6O0jQdjMbGmMViked59GMEoaoqBKWSwfl0OlvMXfC72zuC6ny2yJOUmb/yla/94O17+/uHOzs7RVHMZ+dqsWTXbI0PtrdGfr06P37w8OHDvb29fDiY7Gy3XfO6gUJdaar/sKMX+tApAOkAWPCeQ6CeBUOEiJEr2NpoFHWMRkRSRrqF2HnGLYOAO58swnGIDEBdlTsHMVcBtdJojElsorVVSokEZ4P3DQAgiXOO2W+4d64/jd4LxC49IOItG1bqhaCvqqqqquVyGWOoET6NFFzVtfXGDtdVzMYk9flZjBcStko6No1+BFyFVp8ZuRyjApCNeUZE7FJpEAAIdY9TPaK9NoDr1o8ERsYQ4QjoAof9tW9qO+w6MkG4sPq7MpzKOecZRAQputEXtCnsbG3EdkFSl5qMiAiqd7ixdVUvqdJej/bObn8L4DGl2z+By0Jt8yoAL+mqTRsR4DEFLNgtvF5iqugHc7io5Bffdc6VZdkGl6N91HoYmKQpKhVrBPaHeqrK/EPHI1L7iQr4kh/8TAEnoW4GNMSCLRj94N4J7j7WdhoFeMZ+4f//MvptyB09ipk3kg4uOvVGjl4MY7XTLn+E4xuHXL41eBHml0sLsV3PtPnF/vhpmrL4eJ6xPnlPkug/vxnOUErLJtQsEhPkUptcnEn3FgHU5ZqRSS79B7ESM4hCjQSEsS9Z9IRDVIqoQCExCgr44I3SoECjCtD2QlGgQMF8ep6k1lqrgZuqrNcLrXVu9UU8RST4Nu8KUWmtEUDaYvsCHBsyskLSipTSXVILKKWVQv37v//7Ozs7h4eHZVlOp1PvfRBYLpdXrlxZr9enp+dFUezs7RpjVsuyPq3vPHj31VdfUdrO54s0KcZbE0Ks6zrNBs+9ePN0Nmet8zx/86030jQvG3f//tFkNL5y9Vq5Xi5WpWcQIB9YkBhQEECIOqZgR0D5Dzh6BRwjaj2M2fq+rVIhjSpW3dhUwNK2PNIAoE0CECNzEiSm5YGI+NDE5goiF9QPRBAJslEImgiUivkJWqnYk0qIQlSKiIKgAjuA+A8AjLSNeS60bIxJRO+2LxS1qQmwLdla1XXNXbf2aFXwRgoNIrYOLnOa5ov1SkSaprHmwtXutS9eJkFc1voYPTK5aOZIPcgUOeEA0hLViGRDgWGLV3eOM6JsZFVRS3+7QJ+kIwHhhruvtRZom5BvcF6C1hpIMzNIjPRcHDlsVLDqT5Van7vFmy9f7CX1CZ0QjKUfES9iB61xA52O6WGVGNqADTOwd+jbBlQAsfZeLJPa0U8AnuABI/V+s3SaRgFw0zQchIiMMcYk3nPsmTHe2u61rG4ZA+1UcNd09tJNeUab+GkK+JmO8UO8SxfJHz3+LL3G/ZMEn/9/CHRjt6Da29U5ABA1crcZN1bsJd8XAUCekqj+iI6EVq3Gp5vhgO5UuuNvWpkAYozxIboTlwr29Qjc5i8CgFY6Mp4RMfa0JkOIuF6uEFFfhqOi8qDY4ACFoHuGGJhBuI03gmrrYQKTUkHaPGNFoAgFQFi8qyGIoAYSFFIkCgEJdraGtXcIPCgyzpLYM6Moir4W/eXr7Z9gWyWdMJqJddWAIPvA4r1jgUColUa9v78fQ4mxWuxgMFis1m+99db7PvCBnsIXOyG7JgyLYZqmxWjILOt1ORgNvZf79+4dHl4dToq9K/a73//ew7Ozl199Raf57uHhZG/v3TvvnS+W+3s7LPjg6PjByWkymBSLdXFAgv2eifKmm9SnLLcfy+jtOO6KMMdCSCISBbAiZYyyqmXAaHMRi5U2xahtD9epnNgaT0JgEfbBx7qSUU/0NIRei8NlSoIIcABuw8Y9LZ8QuY1utBWnpYMNe84OQ0dWjJCydDk5vfrviYVEFIsYR0+oj6xsLqBeeccU/sVioajybQfvi5SbTQkrMZ9kg0LcHw07/nd7T0UQIbSrEjY/0//Zf33zFQ6BuxTnTcXfszR7BdzqP6211m3F747TF5UNEXGXENXrPL5Uc2rDa3/SaA3yjVPt5y3SVmmjTkt8izZYcrCxUTdfvziBaBjSoyewOS2PrmdQG+HS/lsKoI37xt6uiEiEWuvRaKSUatruVVYpBeDquk5zXZZlrIXSWw9EJE8pxPHU83kK+MyXa35d2IjPdPT2ywQXmkA6/Dk85uz+L9P33RybpjYAIEbuRV8Msn3rkcUGT7pNj4ynfEyest4ufXHzLhORAtVvuv6Aj6iufiP3SFgIoS8Cg4ij0Qixlb9yAbmHNMkALi2t9mjppQoEsLHLvG8prlorImLFKqBK1YVIIUQk5sAupJldrhZ1FZqqzLIMhZuqbqqyaXxkvz9C+DA6tlGLFYXbahCIklrdlXlAZVQr50H07u5uWZZJkqRpGoVvvFuxQXosmFDX9Xw+T2w2mUxOzk+++pWv/cRPfGJv9+Du3bupza7feG53d/8b3/gGEQVQZNLhaNsmWeWasqwOrlx78PDh1qDwAB5QgNIsH022BUiAGGP5qLZHnMiPUHjz2UYnykMIvmmapmki/Rg6vacVWWsSrbQiRAziobcW8cJ+DG2Xt+g3RGeUQ/AKA0BAAE2kCRS1MlqhYGxCB0AoKAHYQzCeGYQBgkjw3rP4KCv76hyBQ7d+YvGEpl++2MGn/TrrWZ3QFeWJYjR2R4l4dUxsiHk7cJE/gAAQmENoc23Lsgx+3ZOlYUMzXTwiaq0DM3SeInZ+pDDiRSHDrvomokjbHgK71JoNTQadyABEiI3AvffClxKy+5OhriJHhAFERGsFIbZpE621TdI4T0mSxF0VkxY3PeCIcHQx4It1Iv0WedQsuAi2QReKCl3XqbbAxSV9GTsaCGzw/gDaldD/SkST4bE4zKMa63EPGGPR/Ci/LsCJNk0riHMupiFZW2RZobV2zi2XSxFJh8YYU9dN44OIrNarxWIRQujrSJBWT6uE9bSxKdAv2WpPdhT+KAX8eEA3wgdtAIsABORHbAH7YxnPxFn58Qq3/l5vPMbyqO27Pbwi0n94U622/N4/8oc2jw+BN24a9o9tVbV4YvGREZGasopldGOtfNjgTj7+E/27rT0dpR4SIp4+fAiXw08SWISn0sCTRqzztUk+i8xWEdnkqxPFhDuwVjvnI3SXZWkUj56diN7b2Y5FISX48XBARFVVpWna1yGGi6rA/eUQxuwXjOC8FMUAQGLmitZGaxVf13fv3r12/fonfuITaZ597StfvfXuba319etX11V9fn5e1/Xe3t5kZ7soMgDyvknT9OjW8id/8ieZ+Td+81//zCd+4qd/9me+8IUvXLtx/Rvf+IZOdFmWt9571/vm/v37Sqlf+ZVf+fy/+590Yq9evbo4z0ySrutmNp8Pd64wRna+ADIKI3jpKRU/xMDHxdHTPxmHQOyrLiwSPHvvfeN8UzvnIt5HIEpppVRMz0eC4LovAgBgW8kTiJ+ggEMITlsNbdN1JNQAIowhBAQVgeW+bRYHCBgInYcIUEf4mmOFxQsFHDiyGBBRAbr+iqIPF7URUfCeRZA5MEeoFxFJKedZgGJ/lRDcer12LjRNQ8rEeWFBZAgYSECCW9d1Niis0quq9E2DijJrSdvYP4pEACQ23lLQJssgKWQRQiIlSLE9X5xpBRhAlAgjKGhri2AnkTeN5U2tdoEwR34Zhz483Fu10bbAziKOvG6tlRdHyhCiIFjbOv1pkpdNLQIxrC4iIbQJ0NbauPsDMzAwCLD01AyIPKUNMgUwSoxRgaAAS2AOEUyJk7FJE+2VEV4OnG+68gBAMfArELPxUC4plAjrh6co4P74mweP7i9L8N6X5Wq1WoXgiiKzVnMIdVWtViuFJINRkiTGNEG8iFRVVZYlMxAgskAIypinVcJ64mhRYYC2BE0bdCAB5jYbnmKZFBGOsTG5aF73pNHzqh5pNoex6D8DdP1dL/oWx6MzgeNY6+SHVnvxSI/r1GdVnE+4IpRovwcEAUKBuKIeI3s/NjYITZdNMwCIDYOgj50AYJAGRAG0+pAg0gqIhQUglnnsllcgQI2dRLr8GNtTtXWRBNtHkIBycU4YLs7wQuu3gTkABJHFdBrRu1irkpmbphFmMknv8nauqQKAqlxELWuNyYo0TdPMJjFoYozJkjTP8+hOaKU0sdGCKDGlQUfRiSiIt95+28foN4AmUsak1pLWN2/ebJqmabxIRIBQBENw7757JwSnlBmPh/v7h9vbW9amIuGdW2++732vFkVx69at2Wx2cHC4vb0dOTe9mpAu59sFf+/ug/6i+kcAOD4+BgCtdZZlsRlr1Nx6/+Dgwx/76Pns/OzddwRlvL01Go0AYGdn98tf/vKnPvWpz3/+82++8b2iKF566aXVfKYICODb3/w6Mw9SJIK33npDJLzvfS8rJd/5zncGWXpy9GBrMtIEuzuT3/6tf5UY8+DenWGW5GlSrVdJZkdbQyFBEkQhxcxBAZMEFgZQ/XLvMgQJuvhGH2OIg0UEuescHIu0tKFBtdlPhqWL8ysEazQF3/jguQ7Buaauy8WcwGsFqIkZAquGxSgkoMB+M/LKAMISRIhUHzxmZkQxRhmjEqNAdOQ5AyMzBy/M0lROadRKaaMINTA77+vapakYDKiMUgQinkNwwTexga4HDsAheO5pS0qZJnhiiQutCV48M6Lz7IU1CgGSgBfOLFmlVaJWZ+flYr41Lna3J9tb4+W6rBtGlQSWJEvHWe7r9bu33nnp5rXT01VRFN4366p03iGgQtIKjVGJsUBI0IYpMfa0FWQGUKSMQkUIShB8YAbQWrX95REEBNtcLayqCiSKgUuwPAtDhxBETElpRDEkiWtaN467yhKbJTviZojtGUSEdeoCaSRBrF1bJKv2XikdI7LWxHJFwt4hogdE0hSdA+Hu0oCDRyFUCgEp9nrkwMKx62Qs3SYSEJgwoJLROMcub5gRHLcpjGma9v2bIWwgb+HCsWYRVBRdO6t1V0q8Q/VjxjBdSOoNL4HjVPS4TtS+8TPT2blSmOfpyUk4PT3Wmra3t06PH3rPqU000vn5ubVWiFblWtlkMBr85Mc/9o/+8a/ev3f3+Zdemi/K45OTbDyK7RliGcsY7e55NJsBuXgOpWsikiQQOIQY60ISDhDpMKgQQSEqYRQI1mjmixTMHlGI5c8ifm5tolRbchKQiCDS6NiHEDxE+gtz9LQAgCUgaUGHQAEE/EWqcdRkUZozM8BFACJOqO56jPZfEQmIYK2NMIxSSqj3eGRUDHxzMRsiwuwJQGsVlY1zLjE2yxMQKn0DooSUMVpI6nUdqpKSZDgc1mWFiKRARILzALFMgjE6i2EykaDbYltxbch8PjdGDQcD4LbPLiLOFkxExiRa66Z2VVWBgiLLHj482trZbqp1Wa4GwwKQq6rKk3R6Mo/qM0kVoa7qWhi0Ae+greOOQIiAEjwAQJoYZkYWpVBpQsQQXAgSU4Jfev6qUso1wVprbfLaa68lqZ7NZtP5fL2uAGBra1IMBs6Fre3d9957r/GBiBbzVVEUV69fz7KUQ22tFpH1ei3Mk8lkf39/MBisF0tjzP7+/u7urtVGKeWcm52f7G9nCN6QUtYYUgHEVXXZ1Ivph2bLRVNWoCg1lozObJLk2dUr1+u6Xq8r75s8HwyHBQDVdXl0dBw7o1urh8NxUWTOheVy/tqLBwcHe+Px+MMv33j48OFotLW3txcdgLqum8bF6lVnZ2fnZzNtzftfuA6EeZ4TUeyUvFqtHjx4sD0yRLS7uzudTpVS169fZ+bhcKi//frrlXMRabTWKqXTNIth0T/9p//0Rz7ykdVq9b3vfa+qqtls9sqrrz48P8/0W++8fTvP8/FoUpblgwcPnHN3797N8/zGjRsnJydnZ2dVmR4eXAWAulo7kUZBsNoak2VZLz1JKaCWdcIICgQvSCitGKYNs5eoixn3YQMAD13hboi1ECXCvkQK28B8YOxscYgFEIBANIJRaBRZIqvBNU4QIZD3F7kooIgBUVABtpWuBFosse3O0RJqQvRUUICpq5cQ/9d6bMPhEJCF0Yem8R6QFRmlEcGDQJTtfUQ6bu8ojDrTAYkIEImsSOikDTrvxAeOzVtBiMAYRQLAwOyrqpovK+ccEXjvF7MpESVJPt4a33t4Sso2jXduIb6Znp3cQw7s0kHu6rosqxhXbivHakISBEIUAsFYGARBkByHGD0gECEGaVtIoCIQAXXh6HkO2LJ2L0CtXtNseoQX4rKTy72nG8HezdDLJkSMHZNLLhRDa/B3IHPrYUdqMyKEEJBjr8c2Tsm9XmFuC3mjiAgLg4hvmw2wQKwbGgRijcyLhCUEQuSYjiVywUPuM6/632p7NSAiC5BCkQhlb17gxd2/HHpAjMZ7ewLtmmt5jExE1lpmX5ZVVa1FJG7V3e0DEvB14wGSJBHCuNLu3bvXsMzny9FoVPmzpmmE/Xiy5US0QUM2SY0h68UF5514hVqIgYUpQMAAXjwEYWt0NIhFFCKLqIjFEfWqrqVKCQoyLJcLkDYzSrU9mgAVEsrGP24pGUwA2JWfQdEqFrlCuuDNolwwAwSRRT+GcwsAxEBMLISJRErrJDEKdbUqARgiUSdwWy0bpK5KpXViLSJIYBdqCEygyvVKRIy2xSCL+SBlWTZ1KeyLPB0PsridjVWGTCp2WtUCiOBJME0Um0IpRcLj0WA6nXK4YH1qTVVZzpdnAAQEqLocMw4gYlPblKsGoC4Xsb5VZDUJo1IGAGLJSa2sIKxms8QoX5XVegXB+aZk8RKCNemf+vQnijSzNo1tryM+wezfeef2YJDv7u6PRgNjkugpeu9Pj0+NTmyijdFWU9e2GIxWRHTl4HC1WpXrpiiKPB+89NILu7u72tDZ+Wy9Xo9GW8aY2XzZNG5dNbvb264JjLBcrgfF8NqN6zZRo2GWJAYRl8vl7Oy8qipCcFX5/ve9MhqNrly5kmXZcjZfLpeaINnZ2p+kmkJf0Y+ZXW69z7aH2Xo9inyXGESLlYJsmgzzpM6TsiyttcMiJaJSC+yO27ALoVWcGsqssipPtTPo0ZfD1LhBZhQbCDaxy+Uy0doYjcGTd7uj8aQYKKPXTQ0ksUXKarVaLBbrueOm0sCJMVuDfJDaJEmuXDlAxPF4rH/yYz+ptW6aRilV17V3fn4+n06nb7zxxl/7a38NGbfH21cPrlprv/nNb97StylJbl5/jkBV65pArRbr1GbGmDvv3h0MBsCYJXlqy/l0ce3K9ePj48SkwK7vuFkUQ2tT75mUIdKISlixCCEwaFTAQJu1PftmF8hRfgEiRonIbZIXSUwzjV2eEBElOjRtsjOjALU9zyUQChERBDDMhqyhxKDRytUBAgRE8uKAWbzyilArZRADIgGhQGvbE0LwXqIrJwwiFNsQCgR0yEEEgUUgALAEAfaRreVcKMtVXTtEybIiTW0gZNf0MjqGR5hZIUbQh7E1NVAYAc/PThrvUEBbo5CCsASO5gWDsNIx9855VzaOF9PpfL1er8VVlVHrxFhr82LMSMMiH4wnde3Wy8V4e2u9t58nKstG5/NlzZ4DaG3TLDM2DQzrsh4MBoCxzC3FTGgAIMS+0HN/yzZ16qaO7JXHE1Xv4woYABBavzn+A5AQfNPUItzLqejH9KHWqLao4zF1KbagFHU2GxBFIU4AsaLZBa9NOvacMQYAeyL2xekzQgzUYqvUY88oZfp2bCp0dBMiYg694u/nR0RCdCiiQRBpfRBAUQixG5UCkJ48Fc+5w/fai0VEAMXMENtES7RY2nXesdIUACVJtrWlB4MBopovF0VWBBDnnBAqDsxirR1vbb/z3t3T8zMvjIiz2UwEs+FoPZ0yQsCmcaVVJgD72lWu1qiEQAHFR0ZBBkSJ9woRWJiBYxFfikAFAHR4czubwBpCa7HFmtBd/XPnnXOO21q4ghyYOXgvgoyaqAVvY/opEeRpyjFUEUIPCACATbNLKG63zJIiwY747b0H7xBZGRwNcxCKDIROAXNgNsaQ0YaUF++cs0IR0wGA4Oq6rqdn85lArFJuDR4fn1clWa1Xq3Z3p5bQaCHtwkYHbmNcWZZVled5PZ/bJMkyezqdRZPdu/LV196XZdmgKIwxAOy9lxD59hKCGw6K4XCIwMaYLEsAaHu8lSV50zSLxVKbZDAYzOfL2++99zM/8zM20YEZSZLE1nXZ+Ho4GBigydaWVnY6OyvXdV6kRT4kBZ//979nE72/d7i7t63IAHJT+8Vi8eDB8WRrZ7I91loBR8JpYAn7u3ta653JdlVV5bpxzs3OZgSwt7d39drhYrk+OjoyJgkhaJMopR88PNlznlAbY8rGTSaTa9euEcFwlCkFBLBcLh9k6cOHD+uyUoRNU1dVuZhOQ9ME56N9Z9M0hKAAUSkEFfsQWaOsgSIfDgexx2gHGiBqrd+9c3draytyXE5OTiIazMyz2SyumkiHil/UWh8eXl0u5wBUFEMRbJomeAkkRkfWFJZlWZa1tYnWJnAoioI7gTcYjNI0z7JiPJ68/fbbsQKBMQmRns+XTdMsFitdZIP5YqFIEWpXrwARhRSZKwdXX3zh5WpdP7j/8K03fvCJT35ykA9Xq1IHmEx2lFLr9dqYZH//8Nq1a2+99dZgMIpZTPv7+1tb27dv397d3V+tVtagqxFDwz5Eq1wpFQIrpYEsoGYARgKBrpE9MQJxhxp15usmyIPS5tt4QEYtENOIBUApQiQAxBCcsMQq3gLCEHzwElyRJpoQIQA0npwhryhoJRqBYkwPPArHkB4iWZtiJMQr0khCqAAZQUJgiEni8bfbhBsJIUgAFmkp8dCGMV2FijiEwD74mkGMVmxouZgG5/vyCH11ybIsNyHuVqQgeG7rmUVIMC4sBYqFFQABKglGkybdANcuZIYaCFVdVl4wJOVy8eDBg8bjlRvPNz7UVXP88Mg+d308GpCvYgc3BoyCO8a2o8fIrZZvrZBWlYAiVBfqdEOt9iUeN9Xw4+r5ce17WVcBEqiu73KcjT7pebMSZ3+0qD4368o+wkPe/Dns0sOi1R8dYIDIVzSxMUYs/xmfi4iOpfIIWy1ICG1eOLZROeCYFxQV7Wb53004p+VbxksmAVQiBHETXPbspQuWywZTvb+Qjkynu2zLWKkU1+tl09TGGK2tMUks5SiCD49O9/f3rbUcZxLBmmQ8mTCQc+709LRpmiRJKPZ4cH6yNeKuuw4hJ8aI0Zk3m7dp897VdRkIYyyRfYgRxUCYaCMxbBFj53FfIk8mWyE8mqPCzIeHhxHrVkpFwkvUrfP5sje8QnAiEqsjGU3MKu6YiNHHQx0dn1y+9e2Tj3/8IyLsnF8s5tPpbLVcrRiIAAL0Cwk2or87u7v/X/b+rFeyLDsTxNZae+8z2XTnwWf3GDMycmQWyWKRFAS0SlVdaKGrCi3pRYAECZD+QutRT4KAetK7HgQJemhBjW6JgFTNYhWrq1gcspgkMyMjMiPcw8M93O882HCmPaylh33Mrvn1ez0GRpKZzNwZ2Gl+7FyzY2fYa/rW99mmnFRV3TaIYMxcc5A5y4wxaaJ1xPdBaHzgf/QPfydLjbU2rorrqyurK2s6TfK8Z12I8Xev18uyoizLk7OzNM3Oz8/feOON7e3t999/fzKZbG1tCdCb73w9TdOOoSxEi4LaqIO9fa1pbX1l0OsjSpZleZo45/ppMewP2tYdHx+bNOv3hp988sQgF4nJs1yQnXOJNhsro7RIM5OcHBxqJOKgADWIAlwd9Nc21h/vPDw+PamnEz/s9waZTrJJOz47OXn3a++sb20OBgPnbHBtmqosy0jh+uqac67IcmNMWVYfP/rk+dPnJ6dHu7d23SftrKyfPn06m1V5njvPJycnp6dndetWV9dHqytZWqyvr965eYMMAVsWF3Eaq6urwMF7ThI9nZbjs5NHH3406Bc3b9zuD4oQ2LdVM56lSXeHxKu2vFYso73iZR0Oh+vr6977w8PDk5OT8Xjc6/WIKGaezHwAgHOubRujyTnHDERdd8BkMmma5saNG9b6LMtWVla872oo3oaYeY31sg7J5b1S6p133qmqarGCHR4eHh8fV1WlH3740bScjQZDVDSbTPNegSwgMhoMjw4PUSDPsrqsmrq+c+s2alVZ9+neXpqmKysrWZK98dobo9HoT/7Dn2ysbaBgW7fVrEJEYFCotFIkHDFisRwiIggKQQkQADGQQMyYdtxSAgDSpQTny5YAAMTEahcBR3QBkhADMkCnxkZBEA0SIgaQaJZJoYTgvW/b2rVlSjlSEPaubWw9Y1sJN0pcouaEsexDAOmQqxQrhZoUKvKxihWhWJ1UJAJhxM51SwoKCnMI8d246KCwimGZ0cwmtK313jY1iEu1aus6mtskSdK0I1uWYGMHTkxK+7kqX23b2GvUZll8LBcunlIK2QSSVGOSJJnJnOdqMk6VUG6IvWvK8Xh8eHJ+Pqv3j4512iPSJ0cHdna2tTqoJ6cPH318/51vsUkJyXrXWJ+mYTBIenluPRMFElEAJEQKEEggyvWJAAugCCB1LSLBeSKCOXwMASgSt0XBTETslDMBEUE6TmDpkNKd4YlelSYQTaxJArmY9Q3MHlEURlYsYOmIsoWAFaLCRc8ioARCkuAkBIk9NiHCqAhA0byHASWgAKIoFIUQQWfAvjtqCbHyYP2i54GFJIoGAYESBfOMcqevKygivrULJ0PmaYO4j8zDVY1EooNGnHOOLNg3lz2GSzZYREA6ivy5JwPRDIvIaLQ6m02UUsorYTg/G8eawvP9vef7e2maZkk6Go2KolDKHBwdf/To8aRqTk9P4zIUF63ZbJImGlGiJ0hsYrrbt22/318+mAVsdW3UQ4RogGMESYCoKLqkkZUoGuDosOx9urf4mUnSKfch4qMPP3Qu3g4QAafzDKFaeDDMQQQ0IRHZJgB03roCQIRYYvjd3/z2i05CBGrxrVt3jFHGpMzeWu+9JSKlzHe/+z3nXNU0s9lsMplMp9Oqqlpnq6qazWYn52fW2qIo8qKw1o4nZ/fu3N7Z3X5w/7UH9+5ubW2JyP7zvU+fPfmd3/kdEp5OpycnJ1rrne3NwWAkgU+Oz1zbNtYrpXqDfmLSuq7PJ2Nj0v39/dfeeOvevXt3bt08Pj5eXV0VpDv374mgc21d121TI2Kep3mR3r9zE4C1Uex801RpmqZJ0pS8//yTuj+oGnt6ep6mWVkMnj978uzp09lkWhSFC/7s7Ewl+s03X797925LoEk1Va1JFVkOnpuqnk2mq6urwHJ0cDhN0o2NjdGN4WA0FBfaujk42EdE17RNUyPJxsZKoo026uzkOIRQ6iTP871Pn//597///Pm+9/73f//3rW1HoxXn3HRW3blzB1H9xV/8xePHjxFpc3NzZW1jNFrNi/T+7VtFkscFVpNKTI8AlfjT0/OmmmWJmTVhf+/ZgXBqkn7vjlbEopwIAEUGAsQFAQu1bRNvy7hyLjyqaTmZTM7Lsjw6OkKU1dXRYDCIFdgIOMjzPE1jssGGED799FMRydKibaIgG5Rlvbe3N5tV0+lsa2vrwYMHCGo2K621ja0P3j9UifHeJ0myvr7unDs7O2PmO3fueOuPz4+ZWWvtrQ8unJ2c6ZVhkSVUFEVd173cFJmpy3E87t/7b/5f29vbu7u7X//aGxpC2ksbHxTBweHz2zdurqwOqulsOjtv6xkpqcvJYFiwb/cPnlXTGRk9HZ+ys1NbEToNwMFFNVkE1lrPmzuRiYBjR2Z86gUibhJlAUdEYFIagKNzEBF+sf86uAAC4ufwE42kSFQEColRSAgBXLDT2fh0Nj3zJSkIElxwVpwLbRNsCdJo1WG1+IJeGETEtx2Y6xIRY8eU9GKQBwAKuhbjLt8aYxdm7z06DCHUdV3NeamUJhSoZpPJZBKBJ8tcgDJnk4gGOMZMs6qKPl2WZVFoITp9aZom85HneVEUsT8n2GptNBj0N0h4OpkM+tn65qao9ODo/NGTZ1tbO+urK/0iv7GzXWbq/fff/8EPfjDavLG7u7uyshL1D6qqapqm3x8QBUWGFSgFxIQoggSoBS94Hy9Ch6V+2eXz03k582gYliI8eDHs6yyR9wQXwk0Ll9ZaG1FXNFdaXXwjzjmlFx/Oc7agS5kGROQAABdaUoioFM9lm2HO7HhxzHXtup0hMHK8+ERk0kREQDAybs0buMHadjk6R0TVFTAhxtwiAVHH7KhCtJ45IrLZi2CsyQGw1klEa0nMsYQYJUiR95dTDyiGmQVDXddNY5m5rsvxuGyaiP10t2/fjdk2ZTodxsls+vjJkw8++OnKxqb3AVGms1njOElTZp7UpULQOjoQLCTW2qq01bQEAKVAa4rwEZMYIjg9OiTq6LiQIQBo7NC1iy0XKHqC1+/vRJOf53m/3+/1ejGauXPnTrztI8FZNMDe+5XRGsyzCwIBEQ0ppfDWjZsAQAqVUpq6lAkRaK0XMhXdpZTu+TLGRIq3RfyNiPv7h96HummixZ1VZV3Xzrl33nmncTYGMb1BvyiKsixPTk4IQCBorRXBcNC7tXvj7dfvn599LcsSIspSw846b4N3s+l5U1auatrWCjNlhbR1Y1v2UqTp2vrG3rNPn3/6ZDgcrq+uRDJ2VDpL06ZpqnJ2fnpWlqVAyLKkSLPBsOecda2dlRPv/fr66rDXr6vq9Oiwmoxb66fTUpE5N+dHB4fO2o8fPhqMVvI8L2eV9W2eZPWsLsvyf/C7v22tLbK8PxxUeXlwdDibVScnZ9vbu4fHJ8P+4O7d+9vbuyZNjg9P2rb9g9//V2+/87XX7j/IemmeJrPJ9PTk+PT46Ozs7ObNm1sbG0Xe/+lPf/KXf/mXbd1kRf7RRz958Mbr33r3dm3bDz74yenpMTCeHO9PxmdEBMxHBwdA5NoSnBsMe6tr/dhfCwDeuoODg/fff//hw4dff+cdY8zp4d5kMhkNetubq2tra/lobaaC0SozCWoVc5MkwMwaCY0igVY5CAyKDKkA4enTs7Px6fHhCUO4sXMzSbQErqrZoDdsmio4trZhH3SiUAgg1HWttaYUEDHRmrSGAOd5/pd//hfP9vd2t7aPjo7aqn22t1dOp+PpdLA6cBxODo+E8LV793vDgSG1trnx6MOPQNHk7BwU9bLcGHNjewcRtW1nwsE78K7e2d7c2Nh4/PjxbFa/+cZrT548mYyPCf3mxuj8/Hw0GiHXdTVODQwHWVONZ9Nx3Uym4wmBK2dnea8g9Ao9h2YwXNl7/gkRtOVk0M8HeZakBGy9q0NwSLLIOylAjvEjIHNAQpqzlizWbAImYRYfqzyw6A8joOCJg7cuBC8QmAA0KQVKKVSMQCgY2qocHx7vPzs72T+hljBAYGQ2pFKlOTgIToMwMHBg7znwwuDJHPPS4XbmZiMW9heGeWFaWu+WOSIWycO4sW3bqN4TPyE1ND47b8qJa0oREZJgxTFH5pPFui8XMFfZWB0t6CRjPl/NSQQXADdEIHHiHXu/u7mysrIyGvYVYbCbglQMVpL+yr/613/0Vz/+ydtvr7zztbdurq88uL3Lzc2Dw73/8//lv7rx4A1BKvqDUa8fQqjKum1bk+REpJQoVorNvKzC2gBKgE6uJzZ1EyJqis0gHNlMl8acEk86Xuj4et7W9eKAYG2rKV5xiT3jiDJPimoRM89GduccAJiVyAUhyeKSxX2iAZ5HWip2WS++UCm1jO5a9gmiKyhsmdlzDL8EqbvM1jYMAkDCEBlm4i8NwS2sr4orC3ZaGhADXvYBBUJUy0JrHYvnAIFdxAnHVhBvHZKAkEDwjp1vnQ2eQ2IymSPIQgjO2XjrFkUhgtaF8WRmkuytt98BgL29vb39ZwdHR2tra4Lq6dOnEdz73vs/GY1Wi6LIC/Xm66+3LpyMx8PRKqFkmvLUxJOZpmlRFCGEsiz39va01lmWRQKf4XDY6/VSo197cJ8INFEk6Y5NIEA06PViEj+IRMLP2C4SQW3RyhZFURRFNIoAsDDA8T7vopnYO97BkYSIEk3x3YseamQiiqWRwbC4/BAxxlMhvqnqadu2dV1XVdU0rQ1+OBySMnmarg7X0+JWzEiRVsIYWU1mVQlAeZ4DUdu2wbWnp6cffPDBv/vDf/tv/tUfvPXGm9/+zjfv3Lp9cLA3HA4lcFNWZ+en9azs9/vAsrO1FTlbirzHgNOypNz0hytHxydPnjzZOzj8+JOnm5vb2iQbGxubO9sR1VVOy6aq2rr23tYzmRB98rgWYQJwrk2SpJflGvDs7GQ4GhBRkoox6WRW7R8ePn++PxlP69Zad7a9nYxW1qbT6dnptK5cVc3+7Ps/YA5FlvcGfW/d6flZcD57+Khf9M7OJ2mSn56Njw5PpuXs+afP/uovf3RycrK9s+lu3hit9IaDXlHkh4eT48N9RFwdDUaDPpEu8nR3Z1t8mNVVlae/+evf++a77z56/PHJ2tp4Nj09OkmMevedrxVFMRqtTqfTo6Mj8fb05PD8HKxd895WVeW9L7I8hNBW07Pjg9lkd2Njg5CrctI2pVaQaTLIqVKRw1khKUQECd4769mHzOSJMUojsCijFZLn8N1vf/Pg+OBo/ahsSkNmMj6DADZYtm5Wz5CRpZebBMkYMopoa32jbdvU6KKXx/xNMuyb5M7zJ09ns36WJvVsdrB3cHh40FT1ydnpcOXtcjL96Qc/OT0/23vy6WA07OXFvQf3tze3bt+9g8NRY9u6rEirrY3NzbV1/fSTp4FBETQeBj30zuw///hgCidHRxubvQf33iircmNt++x0pikNYarIba7lhPUnjz4pimKtWHv/6aciMBsfOQdtC6urpIjb6uTTvZNRDmsrvSztDwepUZQQSGjFtRAcBwu+JXaoEIEJGNkj+4hoxNhrKrCAWnCwzCyhK5ciIpIiIh08eC/WincsPuYvgAQNkcKYt+dy2p7vTQ8/OT14KlwTBgIgwH6W94teojSxJyEUBvEokRTah0j+EBgRhUiIeJFLFCFOJfJJKgVLBriqZiGSN4kQdtxGLNLv9dg7ZKswZEVS9Hqj4bAosl76Vl2WbdsqpaJodmy5WUSTF9haREGIPjgRZVkWm8mi9RXp5NYj+XNEC7dtOylntpkeVxOQkCRJf7AagnNtUzfV+z/+8P79+2ujYZJoFB7281G/d34OuPdsMOgZo27cuNXv9yMVaszRiSwo0Tl2Z8Xu5piQx0giIwIICmOlnINwpxkCCLEJhWIRIWLWu55b9n6RolzMgBxcC+qCYWoxohMTTwu/0A/WBdPLBjjuuTDAix2gUzNbirxBkQJkidIFF55A5zSQSXQIAQIEZmaJmRghaNpKOGL4CQSBVLTBC4F0EZkLGwiSKI3CIhIimpBIszhkJcGGeQt0d0QgIGB9E5v6Rdj7YG3bttY7/v4n/5FZot5G0zRVVTVN7Zwbj8dZlpVl+ezZszzPv/Wtb2mtf/SjH+3e2nbObW1tra6NJuenIrK1tdU0zWRWGYXDldWdnd/evnnr9HwMpOpytrU20gpc6xrb5Gm+ur6amrR1LQoqo/I0L/rFsD/sD/v9op8kZnZ+oumFunv0UJumWb4c8a4WQmfD4rosu7OIqIFiR4JRoDWGAEoAVeQ9iNJlAYWJkZAjCCt06SLbei+BBcLHD4/nvIyR6WWh/4gAHWZqZVhsb6xrrYEwK3IGUPNmyA5QE8LR0VHeHzjn9g72J+fjvOivr68XRdHrDe7cGgTHjz76+C9/8FfPnzxHgTwpPnjvgxs3biilzk7OT05PCGhna2djdW18flbXNaEiVLOqPjw+NUm2BbSxsTUYrXz48ZNHjz85PZugNncqO1xdm55PvXV1XbdtG1zwjbOuCcH92ne+a4wyxggHY8zGxpr3ngDvP7iDiIoS2/qnT5+fnf9lWdWNdWmSn56Plc42dGo9uBCGK/21za2PHj1WGlOVUkIGjSghpkld/dVfvrd3tFfea6zwwbOD89m5b/zewYFGKcfne8+eVrPzcPNGcWd3fTRsdrc319befHCvLKuzs1OD8ODOTUT18ccf/5s/+MtvfP2to71P9/b27tx7cPPG1idpMhr21tc3d3Z2bt++Xdf10yef9nq9ra2tqqmKXjKZnJfj07aqNkb9W7fu3thY3dlYff3119fX1wepUeJvbm9sr68o4tn5WNiDl6CDAiFjCIA5gHPVbEbCuihioKABQBg4eA5rK8PVQb9q6tPjk7KuRqPh5vbW/vM9pXua1Mra6spwBITsAzNvrG+cHB4RSm60c66q6sRkW6urf//X/975+fna2lpRFHt7B1H+8uj05L/7/d8vm9rZViMmRiNzVc6m5+eJUg/u36MsHZ+fPX78uGma6Z07dV3j/+P/8L+NcAnPIc4SmEEO9vaDcF1Wx6cnZyenjW1Tk6RFjiYdrIyi4kJ8YLIsi4lT59z+/v7+/n6/33/jjTfW19fbxv30px8VadbLdOy11ElRDFfMYH3n/ptrW7fXd2/lvQERETCxC8ELIUOINF4KCZCjFYxNNXVZ1XXNEpRSWZImSieEztq6nDVt5ZxDZKOQCIajHnYLu63L2WRyPh6P62acZhTYhsDsgxalSSUq0UoZlSAidVFLsN5Za733WlEEg0QE2aLaH+YEUsvZxc4wRM4qpYzWcUUBxDRJnPfeOR+CVipJ0yLPk0SDDzSXUL1kYJY/f/ktmeu0L7/FfMWHQJcKDr61rW2C5zbAuLKTylUO//yv/urNN97+zjfeVaFeHxYJt+9/+PD/+S//naT999577+DgYGtz55133vnud7+7srIWl05rXfQVer1elhYx+302nqQmIa16eVH0e23dpHlWzUpB8NZFzDZp5a2r26atmyRLCVAZXWR5hKoV/V45nZk0SbTxHGzTNraVwKQYxWsllxrevfd5nseSOTPPZrOyLAEgy7KTk5Pt7e2yLE9PT4fDYSzwxBT9nGiC43WMYZZtPc61HeOWRa4iekKxmY/memofffTo9PT07bffbtt6Op2W9SwuxGmRa50Qas/irCfSRdEviuLs7AwARMLGxsbZyeloNPLBEtH0fHx8fNTv9dq2jh++v7+fJMn5ZJznudFpWU3zrDcc9euqDeycDXv7z2bTKi/So8OT//jnP0SA7/69b9+4dc8GFpEkSWL4GH/CG2+8cXBwcLB/eHBwMJ1OR6PR5uYmKfzoow8+ffbkwd17q6urP/qrHwrwa6+95rz/gz/4s//kH/72+ubW4fGpTlPU5ux84q373/1v/lebG6u2tq1vh73h0enR9Hy6sb3xve98r/VtnuTf/8H3DZlbd2+tr6yfj08zjYq6UkvsrYi1kqOjo16vF6PYmzdvRpaeJEm8C0AYW8tieM3MeZ5HFprZbBZCyPM8XpSiKJqmmU6neZ4fHh6W5SxN03I2G40G5XTGzIGd9941rYgURTEY9EgJQOy/6GVZoXXnsrZtOxqNFJn33nvv9ddfbxr7wx/+EBHvPLg/Wl1574c/DsI7OzvTsjTGpGl+fn4+HK2cnZ3N6iozyerGZpZljx4+LvLRo0ePz87Otre327b+wX/8j0TwG7/xG//y//v/S5Lk1u2b3/vOd7e2tg4ODuq63NnZeXD/7tNnT1ZW1vYPj+u6zfJi7+Bo9+aN8aT6+Mknnzx5enx2fnY+YeY333z7O9/69vnxSZ6Y9fX1u3dv7+7uTifnH3/8cVnObuxut219dnb2+oN76+vrp6cnbds+3/t0fWt1Y2sTUXkH3smPfvz+H/7rP3ry5FNFaW1bYxKdGEVmbW1tZ3crScz6xmg6HaNQ1ZRHB8cMAYUOjw9c69M8ydOCNGoyQXxdNnU5Hh/vr6+N7t279/Wvf+2dt9/c3d1KkiSwG/YHdV1Pzsenp6ezWeWcN2SUwk/3nkVmk5iiWkCinPUPHjy4f+9elmXecXefZIbFLcTfcMkztnVDRLZpq6oyxqysrGQmsdaqa0ib8KV2x7gc1rZuncvTlLT21gpionXdtsC8yNDEnI1RSikFLIi41C4egw58/vx5kiR53suyTJGJAY/n8N//0X9ft421djqdTiaTGB1VVTUcDkejERGdnZ2dnZ3F7E7btvp3f+fXllNtix8ctZqdc1VVlWUZ5XF0mpyOx0mW5UkeINjaNq5BRlBQpIUXf2Ojf353o0iLzZ3NXtarrUvUA0NaoxAw+9A6X7WzaV2tbW01s6KeZOCbWEFR4kEYiWQuaiVKKRRgFvauaYJt2TbkWgkBNQokooiItG0TboRbDY6EKeJ1qyaCdo0wQKty6ams9ZD1jBfPjtkHZCRQBhQiajLRaEZuqQAdFUZqzAKlPC8s0cLgvZhcRUHwS/qyy3eD1joEdBpCIEQ0BjWxBmHx2GG9X5gRGAHmDTVdS3xU3+s6HBG6fqsuApVFHLo8EwEK6VQrSoOAEWSVBuVCHXq9njFGadKoNcbKKL377jvJcLWeTff2nu09+8S66uhgD7X67re+G29KVMqQGY/PY8UlzwsiStfW2qaeTc/0qW7bNi6UsZsc5vyu0XZubGwI2wDQluVkfIKIeZ770NR1rRq1sLId1wxAmpAQIibGKKVMUWSxbvrDH753+/ZNRDw+PpxOyyxLjEnPz097vZ4xSmttjCIi761zwXt7eHjYtnVdt1GhWesuRTwejxfJycVBOuc2NzcvsE5LZeOjo4OnT58OBr0sT5y3IEEg1E1JRGUoiXS/t7K2tsYMx8enDx8+/MlPfjIcDgG4qqqmqh+8di/P8/Pzs6asDg73RoNhmpokSVj86cn5yspKmmdtC9baH//4R4eHx9/5zrd2dm58/PHDH/7wPefawWD067/+vd/93d/9Z//8f9LvD7/93e8dnZ4rk1pry7JkBqXUbDY7Pj5GxF6vt7a2RkRra2u9Xi9Jkqou//E//sezydnNmzcH/f433v06AN/cvRGE//f/5X/ZtO20bB5+/OhPv/8Xj5481km+Ohz80b//t2srwyLrFf3cqOTjTx4d7B3mveyTh4/SPLlz6+4nHz8kUJPp6c7WLrOHYF3b5WCirYM5b2sEhCdJIsE/fPhQRIbD4Xg8bZ2tZqUyejQYWu+m40kQHvYHMQBgkCLLY3iQFXmR5Y2tV0drZT2TwGCQQJTw1956QyQQYmz2C8HlSZ71UhbPbKNL7L1vGlvbpkVtjHn86JFSuqnLg/39hw8ffvjhhyurq6fj0wevvxaCS5IEgG1T2YaA+fXXXz87O1tZWRmNRk+fPuXDo5t3bhPpum6Hw5X7915HghvbO1vrW//iX/yLP/w3//5b3/zmcLgyLEZ1Zc9OJ7NZOTkfu9Yj4rP9vfG0Pj0bO+eVmT16/Mn+4dEPf/RjMmZtffOdd96pG/v8+f7x8fEf//Ef765trN65DYE10iePPv6TP/kPwJwkxtXV82dPP/roo5/evf3WW2+NBv3hcFRkeVmW+twMhytJljX1zHu/s7s1XF179PCJ4+C9D8JaieMOM/HJJ59Us2l0ZMfjswhHCs5HqKNIMCorijwyS4hrf/KjJlVokAd5kiicTU6TJOn3i/HJYQhBfJsnpHqZCCYqIUM722uta2IEL4LR69Ja13W9s7W9tjoSCS06ROkZNAab1goKYSeGgjGxjBgSUkg203mCSqlBbpQihQSBr2TyWsyxcAPAIMTIRgEwGAVagTLU1e8URC7bBRqACIiEkFEBiXRSqhhpDTwIrfQLY0yaGmMUorACjeQ4/IPf+J71jpljJjJGp23bhhB6vR4ijsfjyWQSkT1N02il2kvWIh5Br5chImLO3F9UNIk0qTtCqIAce9+61lt2gVFiRyAyeAkalUo0CbYu7G5uSAAUpwWCt+PJbP/4/HBSopuGZuJmKfoqUdromLuc112jkJZS3BH0BV9VEjw5p32rRMgTSYWxN9c7HSyIFwyxcows0DIICwqBpIiZAUzSQJo1BNAQQAIAAwkppnjCcZHzVSg0b2LpwDIduf8itxbmrMvLMwBgkjFeLtwCQJooZtQKQoglMCRkYIcgCFfcOgTQcU4Bo+B8u0hEGwPhvEEVgCKFE0jUhLk0R9EP0ioR0A6JiT25JtRZ0Q8gQSRRKoAkKKQgS/Xq6rDfT1CCc3B2clRNzj2HJ48+REWjwcrW9vbKaKSNyZI87xWfjKdpmp6trUUe/8FgsEAAlrNZjFqMShwHFJ9onJyfROw+Zeb8/JwDo5immo6Gw8VplOwi0T2bntV1GI/HTVOXZTWbTauqtrb9wz/8t/fv31tbWy/LWQi8vr42Gq0whzfeeBOR29YyB2YfAsZc7v37dyO6ToQXjKxKqX6/v9wDE1Fv3vt+v49z5NcS+I5m48mPfvSjb37zm6uro7Kpy3LW7/fLulpf3zg6PDk6PQPRKyurRd6/c8eXZfmNb3y9qqpqVj579swk6s6dO/fv3LW2vXf39uHhflEUg2EvUbppqrKsVzfWW2vLshTBDz549+HDj3/t176zsbH1e7/3/75x4wYAW+tfe+3+u+++E4KbTGZlOS2KrOgPo3iltR0Pdl2Xm5ub/X6xsbFhrTU6iS7R6dnJ6w/uJObBxsZGlpo7t3eVwrXRCig6P5+Mz6c3d2689fbrr7322vODfW1y29TirHUNMiJwNZsoghs7W8WgOD7cJ0Org6EiQOaD/efnxyfOtSQSXLsAT0WPKj4sbdsaY0IIZSz7iUzOz4fDoQSvCQb93q0bO0B0fnpaNU0vz5UxBGDSdNDrWe9t0+gk6ReFDXbYG7a+FR+UwrKsE6OMJkRMtdFGBc8+OAXKpOrZ/iESa2UQ0VpblrX3TET3770mIr1eP0mSwWC0u7v79MmzP/3T73/ne985PT45n4wjntG11rNorc/Ozh4//mRrc2d3d/fp02dnZ+O1tY3ZePKjHz/8xrvfJNJVNUOku3cffO97v/GDH/z5P/of/6db2xvsfFmWzoV+b1hkvX6/f+/egyQv0jRNsx4zty589OjjJ0+eOOcSrQhFAaaKEq1KZ89Pj8vjkzxRwToJbVVVH/30J/2i17TVzs7OwfNns8k5ys2NtdVbN3fzrFeMzXl5Xs7GeZqtr69nOnvrjbCzuWu9/+C9HwfXEmpFhBBsU56eHALwwd5TALl79+76+rq39dnZmbc1+9ZZ28uT1VF/c3NzbW0tgt59W/3ZH/5L35Qp8fT+7dN+Zl01KHq379xSCBpRJzrTheSCiIQaFbVtzSRBgc5MV+bP8phE7OWF1qquW88tESlWigV9A8iRACCuxwoQAPI0VUSOlBYNABnFpct6jGTGeGmOMSVAFAJHYe4CGw7ILQQB1MhBKWOIULFKkGPreicczoiCyPPGhmgZad7HhkWhlEKlAmFs6A+EosFvb4xi8jJ68xHWEH36KIdT16sRgdsZYN/O5g0CXRt/tMBaqa4HF1FR7HcVFjEmAYCYfk21yhODmABAXdeIaIxJkp6IWGtD8EYbxBxEFCSGCCUMB1lepMNp3e+ZLOEEGnKBvYiPImKhbWysGkY+fU3Q9Sh5rzggM2PcVZCRRIJ1BKxECAJCrBkLCEfmNJQQcT5KdSiY2raCoLttGuahKwkyxLDXBQ+gurKfdRYAulYKIZaO8gJYOLZbRObCRWOSXNREacEdjUDsRFgDk+p6dmIHCUUtuUgJuzRjxxzUzQAYPywIz5tNl2e4bubgEFATMRIRMioiQKUEMSbi2rbNUuWcywwgyvbm6urW2jtvv54ktLm2mfWKVBuVmGpanY7Pm7IJIk1V7R3tB+vTIh+Pp877GHgNh8P79+9Hn2Nv7+lkMhGR+PTGvLFSajKZ9Hq9nZ2dJEnG47FSyvshAITQRig1zht8ETHClCKB6ubmRqTliu/+k3/yTyLeO5LShRDSNO31etGTjSWDCAVfLgMvqumLlHI8yPhOZJMVAebQtnZO4YQx9xC9qYODvYODven07uraME0TgN5oNDLGPHr0qKntrG5s66fT2Wi4uraxeePGDa1v/eAHP+j3+9/61rc2Ntem08lwOBgMdxTCyuoQEUNwNnhmNkbZumKQyfR8Nq0Gw943v/nu1vbGbDo7ONy7d/fB+saqd7y6NiqKjEVXVWVdhZxHHGxgh8QApDUNh8MkSQaDQWTjGg6HvaJvrS2riW9nK6O+IrB1lSjSCtumShIzOT2C4M/Pjs7OjsTZzdXRp8/2f/CDH/xP/4t/Pj0fj8fjk5OTs7OzPM93bu/0er2NjY3pdPraa68xv2aMiS2Vs8n0G+9+XaEoMqTA2dDamgMgSV21gDwcrJydn2xv7aaZQVBNW5VlGavXRdG5C65tiWg2m/V6vSTPB71ev99vmoa9V4gAbEh5byNIxPsgke2rnAGASXSSJAopJqJUjVU100ZRTmmSIqYiyAxa64cPH0bWP6VMWZbOBmPM0dFR27qTk5PJbNrvDdPbaa83mJazIu9XVd02rixLa32e94LH4CVJ0v39/fv3Hrz33vtZlnz65Emv1/tn/+yf7exsP3r0qG5KWzd1Xd++fXtra2PQG+7c2B6t9BtnQwjDQUjSrGmaRKvD/b21tY2qqZ88+uij9z9onXXOMWKi9Kjft02pFe49f9q2bUJSl+PpbKzBB29v7G7dv3frzs2dza21tm1TTQ/u7D5+/LianrbTQZpmO5sroW0++ODhsJ9qjC0edeus0x4KZRI6O/x0ZWW0sz54++0HB6u9jz+G09NTbnl8fLw2SNcG6a3t1bW1VQA4PT2dnR7vbK6wTbfWBoNcJyQMrFE08tpoGD1UZg6Ou7WNBBmUMkWqo/VN0zSilFFAkRcfSNoUA4iDgGCdEcdx+QoQtVy6PnpXd1A7Z5m5CW20MtqYK2NfDhABjJdm5721lq2JkLqQJOCzuDR1ONIX6Qqk027BjpixC1IjmT8KqjBHbMbMXDPzra0JNSA7G8TXbBvnWw4QbBlFZjUoZTAho9HrXp5FgxE78zpTjIACQTiCZWIXLAqIiHNddzMiglIQNfJEYl9epFoXER8ldxLVtDMiImQQQODCyPZaMRr1xGQ6j1I6jr2nAJF8Bhob1RKARLQWBCQBECWCsTUTOLoD0Stx3kaeZOraLCPCIhAydNAfRoSOmcejQkbESJenkCT2EQMbpUWEWRgkdjsBAIJETaRIxNFdxphSVqqDvC/NQmhbB3N6fZofgSAEZ+NZJQTEaE9lbiavqGNcSm6/vMPnGsgA3Nl4AAYMggGQmYOINmnd2MbaQZZ7jnzUanJ6Uvq2rsavv3b7zdffMkmSZ1mv37eNO5+M27pVRgfny7pSoHuD4flkFm3e+fl5v9+/d+9evB2995PJBABi/rMj5DMmeoJZlkXcUJ7nw+EwSvSEOe/mMnlNluj5/X0xIiK3Y4eIHQveAwAR9YvheDwGliJPtUJmL3O7TkTMF2zD0TBnWSbMPsgcViaxEkSkQTiE4C/oOBAAACUvsixPicAgBgJATtP0tddey9KCSI/H0yef7u09P3jy5FMR2draeP+9H+/s7Ny5c+f2zd2/+IsfvPfeeyx+fXWlPyjYeWsbY8xoZai1Pjg8rds2y7KqnKZpcu/uveFwMJtMsyQ52H++sb6yu7NVFHnw1jkr7Nu27o9602oWC0akydoWFaxvrnnvdaK8Z8/OBVu3NSKura1ByIaD3DVt2ZRE6LyvS5+m6f7zZ1s7O+X49HwyXtvYSYxuy6l3zZOPH+d5nqZpfMzjsnV4eNjr9c7Ozo6OjhAx+lIhhH6/f3x8whySJO33e8Ykgqr1rffuo48eNk197979uq4EdZalITA7F9hJ4LZtJTAKtG07Pj+PCGf2oalqCdxUdQQqJ0ly3nWWS57neZYhYp4Y50BIAnsJDCxkwBhFgKhgdXUVFSZJqrV2LrjAofXO8/3XXjs9PdUm7Q/Mxx9//Ed//Cenp6dJkjVN44MM+qM0zUOQspx+8uRJluVf+/o3VlfXj46OZ7Omta5t2/F4kiTZt771rf3D/YcPP9za3nz2/NPhcDgY9D/++OFPf/rTr73zVr/oraysrKwMszypmnI8OTsfH00mkwgs2Nzc7GfJ5qiXYtj75GEx6G+urq6vbWxsbIxGo3iqx5PzPM/v3b5TVbO9vb3ZKN3b23vrzbubG+shhMGgt7k58G7a1obZr4yS1dXB7Dwfn0/PD57oJONAnz56/z/823+9ORwct7OTs9OTk5OyLHd3t2/vjm5sb/Ebd1aG/a/d333z7vZaQQXZyeZgOp22D25sb2/fuXNne3s7z/O2bXNsMy7/F/+zf24Urq6ubO9sZlnmXJ0YMxj0jUIA4ADOucBzwgaClc11xy7eOakxItK2rbOtUVqcKNS5BhYKIUBoGVGBV/MGhDmpLwBAPasjRCOiH13sa+AgQS16u5fn2Hi4eHLn7XwAhBIsI3t2zjlgh+IXCq0wT8ItPHXkABh/z7IcCM0zoBfrMwohcpYYCayUECGJEDjgBtkG5yXEJLZonUROHkNBN00FLwYHiEiAzrtFZyQopUEjkUIwaSJzpmKIET4LAhgEIYTg2QoAaBCllCZy1CqlNDCIiwT3eZIWOndAZITJWW8pOOUDcOAQMjRBOHJIquCVQmIBEOecioLl1FFMdk5DvNagEER1CNiuURgRVZe4j6sHcjS0kSM6ALCHACyELEgGgYmA43eQYKR/ZkYEhcQQOIiIZyFBDqCAhIWARBaVhgCJRsZlgyqRjQ8JEACX8FMAgEBzbuErDPCyGf6SBhjAdH01F8rqiIiklTJZkZ+fnsVgUTiKe6jVldFZOUtS2tpcTVPlXMNMti2LXl+bEQBFmtOmaYTRmMQYhVr1eoOTk6Omsc7X1vok0WvrG3lhRLAoMmMSk2AMzkJI+v2iaWzgdjDsK4Vn5yfMvij6kW2K2UctHSKNiOen7QIKvsxvdX5+XhRF1C3O8zwypJ+cnKytrcWgNvLJxV+nlFpYaJjXpGO7Tp7nANDpeiDPCTNI69jdHyvRHa4OEXd3d5NE7+xsxeUgQsCUUp8+20MkEBJRiLizuyWsAODJk8fR8a+b8vnzZ3VdP3v+9Nmzpzdv7Ny6dYud9cENh8M003meHx0dpHnv29/+9tbWVlVVKysjRLS2PT8/f/z4sTF6OBxubKwjQr/f7/f7otSTZ/unk2nMmSdJYq1n5sSko9F6nufTaRndlOlsjKAG/U0fuKlmtmmBAxEBiEJQCPfu3Ny9eassy2lZr29uTmbVg/u37929PSvr27dvx3Ly2dlZTBtYayMmUWs9mUyeP38eiSN2d3f/u9//fWvtaDh8+2tfe/utt1bX1m3bVnV969at53t7u7u7pNRoOAzM3rler/fhBx84a+u6jsA6Y0xULN7e3o7Y6UiPsJCRYQhKqbou+/1+lqYhhFSrsiydt+AEpVPh7NJGJBq0FW+tbb3zrR9Py6ZsbPB5XlSNPT4+Ra2Gw5W79++PhqvP9w8/evgxIG5sbE0mR9NpOSur4+Pje/ceNI1lBudCmkia5tZ627JKkpu3b3zyR3/0tXfeJKKDg73BIP/Re38xKyfHJ/tNczsxNCtxMj0rq8nR0dFg0Lt75xahAFsJQUJb9IZ3b+/u3bv1e7/3e2+9/sbd7dffeuvNe/fujUajqqoOjo9W3n3tvR//uOipza0bt29v7+ysfPDj5Ld/57d2d7eda/tF4b3TWmsTEHDY71Xl2daoP0rT1jmtEmWS5vbW5Ntvv/v1b56OJ9PpdDwe13W9tbP59ttvb22uP/7op8L25o3ba+uDQvnNkUlM5nw7Gq4mqTY6JQWEWiDc3Vlt69uaVJ6kWZZpQwAskiEwQrCNi5gpDoEECUErjVoLWwk2eB8sOCICjFgsDg4pyvMpFO9dy8zkMGAAWDCG4mIZBN+CdC1Hsb8BEZVG6+uXAyFGgMDxdYx8pdtOmU5RyCiNCpQoUqJBGAPbIMgESkgUapGoXCeAEq0LIxAwIxAjY0CIRK8ohAqUECqIEjwW2RGJIcMUAECBA2SVdCgwRCT0EABFFLBeUK916J/5f+KFsCt9ISM7FhRGNMgAoEB1EWjHxUpePM57XhExiZlqHxKjiUADUEfEL0AB0HtmDApZU3DIVgOQOMUBDYZOcIgVCAnoLq5tSQQEEASFCSEmco1KA82pjEQ6fiYAQCUAQbqiABIoIESJcbwwIyMzRr52YAnOxiqwkACELhASAB+ISECCePESxCtQoMA7x8gqXrD5zAhKJ7hE/7vw4KKHJRHwLMvAvGvHyxHw4tM+/yCieScUiGhAQNKoRRmdZIXnUxdEgPycGDFJNEw5T1OFeHS4z8xGb0cUORFpnUQYWgxJW1tvbq0zwMrK2mCQl2UdgptOyzQ1/X7R66UL3zNJUqUMESCqfr84P/90Mjnf2tpKU2OtVSrt9fL4biSFZ/ZdBRZeUCZYVNaHw2GWZbHxxnsfud+qqorKJIgYIWYxVo53ZvSKF1xLEbgYwkXkDQBKXbzbuZgx7sVopKGcThJt2rat63JtbS1NDSMURbG+unZ6enZ0fOScFP3haLSSZwMi2t3dFhFAVkqVk8mbb765tbl+68Zu0ctu3rzZViUp7PV6WZZIYGZu2/b4+Lht2yRJFuq83vvf/M3fvHHjRkwnRCJDpdTR8bExamVlGHHpeZ6LoLU+hJClOSISQa+Xj0aj8XhsrU1SfXJw6uoSEQe9XKEW9oqIUIaD3uT8rGmaEPj48BCVund7N80Hnzx5vrGxEVMUxpjZbEZEt27devz4ceQYquv65OTk2bNn4/G4qqpPn+8hotZJ63zdWFB1cD4IHB2fjqez07Pxs73neZrdunO7lxcss9dee+1g/3n8pSJijImAnaOjo7lgEXTZwth4JAFR2qZJjAGRqqpSrU5OTgbDvrWWALXWiVaA6ENgCJQq8OwDEBHpJM2zEEScUibd3h1Us/r45EwCVE376d7ef/iTP/v2t79e1y2RBqDAkqbp6ur6vQeve8/TyWxtfeONN946OjypyqY/Wsnz9MOHP33jjftvv/328+fP+8N8dXX16ZNP3nj79dbOfvPv/z1jzHg8Xt0Yra+v79zcWlsZnuztr62vW9uMx2NfziQxO6vDt+7dvvu//l/evHFjY2PDGJNqEFu1s9PZ6f5rr99aW+s5N8vz3s7Wje3twe7W6LXX7mpD1tJoMCirWQjBmFBOpiWkvpoNez1OMHiT5wNUZrV47a0HdwAopkkYwDmX5clgMCDhG7/29Xo2zvOeUkgDk6xvDocrbVsTaWZvrWvbGoDSROeZDkk+Pp85K8JWRzgTMM655DpOWhHgaFAChmDZMoQu2xe9/EQj6nI6AwBAEqWC97ZtUFilGoKTeW5webXTCojEKECMxVohQq0VC70EPI0chd1rHdsd59sTRSIq1Ro1akFQkCglQiLCnUEFFSFbwiAMGCRquiGAKIzijhBlIJGi/GWnvwooUE3LiNPmNO2AXc4wc5qmMmfCD14WoCKdJMlicV8ey7zEi5RdVGKLITKLxIYlhSRKJDAZTYBeQmRnZR/qpsZEIwqQJISojIgEhuAbQSOIiIbYI7KmSFkFiF0OG4FRGCUCjERh5CCOCqCIyBJBabEg3F0vJOlSEPEGCkFYPAiRAkEB1QlHR6S1IsIoyYQYvI+uR8xiSOjYrDQphUhIBhQDaCStEm1oNq00EYJCkii4hqAYwYe57iFybEZdTowsJUMComIMMM8PX2l9X974RQ2wE4iRWmBB8ahICUSrpnXiGTwHBgmudZz44EIQUhDDqel0GhVIptNpv9+PaPu2bUOIbBhgvUOE2XQmIQBRv8gEc/ZeENu6JK0JoLEWmHWSZAkEoRBs01R/+qd//OmnnzZNc+fOnRD8xsb2p58+j4FLtKaxhqd1ErwsDPAie8zMW1tb55MZMCdJFjPbWic3btyIXOrR7kbgazxpEee5GG3bTqfTsixHo1EkZo40D845RAXASZLFXFS8diFEXirZ3NzUWhf9XllOjUlFZFY33vvBYJAk6draBqAyJuUAVVWXs0mWrOZZxsz9QdHWs/W14aCf7exuMPPq6mhyfhZJ9k9PT8dn5x999NHNmzd//1/9y7Zx737jHaPT0crg7bff/s2//+v3773mfNvr9UyivPd5keZZ73wyDqj6/WHkRDPGEOlxOx6fjWkozNLMpv1+f5BnzWzqglcimVbWWW1MnhhE8Y5F2DahV/SDbTbW10XkydNnp+dnT58++5M/+/4//S/+55PxOQrUTe3bdn/vObBsrK/Zug7OJ0qvr67lSapJBe8h8ObqelEU29vbGuGnH/zk9Oy4rutYXtVaP86z3/u9/48xyT/9p//57du3J+en7779Rjk+Ptp7kmWZubm1PlpJKJRlefD8k9FoFFk+IobAWpvn2cPHD4sis1WlB3k/6yfERVEIO2EvJIiQGMwSEhEn7JgRCUPgEBCNIsq08hrEy+H+09FoNc+L+3d2bOuPDp7+zj/43je+/npd1w8ePLhz587p6bn3fu/g6IMPPjg9eHbv3v2jvcc3bt4ujOw9/ejjD3866qc9M8qw/R/+J7+DiIbrG+v9sizLnjmYHT+4vf1r33wbWN5//32DtkgEg2hpE7SbK1kIhkLNzmYqjHbXiO/tbu8MBgPv7dnZGYEfrQx2Vm9urRcYyl//ztdi/kbsNCP/xr0biQ7BW1dNWiXNbGKUNpmWUIsNqUaS0MxmrQ/iXdPY1vrV1VWlCJxnECIy4DVAOz2pq9molwdbBgJRIK4mk7p6en52rFVCCoQRxBNq5Mge6NdXhq0LCiVNNaJYawXAGO1aRxQ5EgCAQwiBvUf0bDuNK5QQuHUNBwBkQ4q7vmxh9ihsElUUmQvqAsEaLkpO2nRqJ8trICIapa/Ue17QKF6kG7ustSALomhU0mmkggJEc6ExAwAkFEUEgvOAnRqsICMidwsqoyCjwrnFikMrpQi1IqMVBwohzFPDXT8IRYYiYSLSivDo9/+Pl9b3z7PKx3rnnFIuijfL4vXFu0CBuv0XxOYd5/NClSym+2MOUKCr3gPMkURdRCtwKVU7z/UjcKzMIgsjLol+X1kbIOo8poXqJ4ICgGgwAeZIqPkBzM/G1Z+2KM4jRn8ABYgvWoM+a46/76rzfanNaXEkkbnp5St15VXrEvQSiJlAANCxboKuOHl4MK48fPTRR1tbK7/1nXea8d6tteLx40fnLXy6f3Dnzt0kSeq6vnHjxmxanZ6eZllWFP3RaJRlWdR0ItJ5npMyZ+NxNSvTPFtbWUVFp8cnh8dHRum8VwCLC351tLKxtVmX1dNnnwaR1lmlDDN/8skn9+7de/fddz/88MNHDx83TbO5uVnX9bNnex9++OH+/v7Xv/7u1s6N27fvRsGuzc3N0Wj0/OmTn/zkJ6RgbW1tZ2t7dXU1TVMijNqJjx89ivHTb/3Wb924cWN/f399fT0Sm1x5JzPz/NpJTIBHMEXbupWVIQC1bR3fBaAsyz7++OONjY2iKJqmstYjinNhOp2ur69j7CPvZAk7plJr7fzSMDOTdMQUSinrWgAgorIsY9RrjOr3+ycnR86Fzc317e1drSnmA/78z/9iNBr88IfvvffeD//BP/idN9547c0333ZB6toGpgXvShwhhO3t7aPDk8lk0u/3d3d3lVKffvrpp48fvvXGPQ2BiLTp+tpjJjlqMCCic258Pn385JPpdNofrty6e59MEqyblDMF2BsOMp3Z4EloVjdNWTkOJNB6V45nZVmen53NJtO6rokwTbMsS4fD4XDUv3nz5o9//KOmab75zXfffPNtkdC2bZppjU7rzrWKNDKPHz9++PDhb//2byNi7BJZdN6HEPb395XGxGRZnmRpoU3XE4h8xYLLCJ47wpZOVnz+mFhrYx/a8kZEFfziqSeY99wDwHRSSsezFqFMHV3oztZGZMqM5z903LHtT3/601//9V9XRE3TpGkaG7HatkkVKLpAOSwyOtFTxDnuN66lAQLDC6StkT4cliVGFkjd+MgHFwMkJL20doG1dvnHLu5JEFEg0Mm1divn9esnhNiZAQCwFJ8ig4cXq6TdCBgWjxoALQVIL+yJ8w9j8XDVICK8Kv0X5iQKi+zgq9OEchXgBubnc5G2nH8Ic/ALSzR/F2H5/F86pUti3ou/WnzgpbQoAOhXHOsrBiPg3KLGOYAgYADppBQiGgsCiebuF7wQ6s0PMGrJwTyGj9tfsLXx8+WymYqfRnP+uXijvgoPPJ9fupARhXWFAaMXjrT758U8P6SlLXH/LoGCnz1f/P/PaggQo0TJASUSe+Kou0VESAWGINGzCwBQllNjEhF5+vRp8OJdlxR9/fU3rbXj8dS5UBTFcLgSF/2eyYf9gVG6aZqDg4O4PPXyIrpTAqCQmLmalWVZtm07GK3Oqvr5s8Otra1/8p/+Z0qpTz55+u//3Z984xvfmE6nIpQk+Xe/8/e+92u/8eMf/7ht25s3b7/51lsE6uNPHjVNs7q6evPO3TzP67oeDHuro5U8zxGROWhUWivn3JMnj99/74M0NSh/TzBCe+o8LQQZhV6aEaJDhhDrSxg52Fim06kE0Ika9Hou2Mn59Pz8tKnq2WyikJCwyHKdKAI1HPZd6+dqR0EJglgFWoCVBEBBoSA+auZyUKggkdR7S6BAMwoohZqUUqpf5Nb1fBuyPCEQFs/eM4aNtdW0SLY21oe/9Rvf+dY3h6sDb1vvQoIaFAbABFQCJkVxCpnZV7N6cuLrOhlkWmxoQ0phe3M1N0QgCx+BRJAjLWvnMpDWg162sTIsEt0bDhMMWgVJFUlKRL08UUoZJ8JYTZvp+UmE2qVpmmdFv1iDtlnr94b9YnVjfXU4SvKsl6VZr2iqGYQHvrW3djdGuWpcMABZSs5ZEgghQAhEpp+rmztrCmyeAIAgBoVAEkAAOZDwrd11mFN8Izq2HNvGIgMJ4gsPN8Z85fyJXLyLiCQexM1dcLx4WoQAqHuSEWOFDgBW+2Z5ne2WVA4IVgUvgZSEQhMasBYaDgl4Iy2JNmANKE0BUZEWg4IkirplSEAQWEBYXMfMyl0EEA2Xpo63dX6A0tXQ3MUiubzcc+DYQ4PzXxePNhJWxKc+zt3+Lopnskj3nSKx+BKWjuJipisNWORI7R6kF4ZaonG96BS6rNC8tAzy1QZS+Er7Cxcmf/FFr67TXbPeXme/o7jeYq+lebHDF17Bcc7WB1/aAL88FtXfFzbOS2iv+Ct46Tf/rYzrjuEzz+/Lv/rnbszv0fgkIyKIKKXA+VhfjN53JG3uF0XTTh8/fPj973//rbfeXh0Nbt+8ub25GWvY3tnzk8rWxcrKijEpqy5vYZRO+gMiCiHEDvRIARGDmBgiFFmeZz0gNRqua3xcVZVC8/DDh7PZ7Nvf/PbZ2Xh1dS0x2fn5uUK9ubFpH4SDo0NbN08++fjZk2d/9d5fba6t/9Zv/dbu7u7KaHBjdzvL0l6ez3+CJVBE8I/+4f/oRz/6q4T07vbWsN9jCApBgkdZcAW/MIPEHkGIixtih9/c2lgP4l3rSSN7t7/37NMnz1rX3L/7QBNqwiRLJEBdV7ZxLth+MRAQirUnibk1DySaOtwBCwOziI8L6HhaBvGpydI8yRKzOhpKH0yq+70cMHjr8yLXCj2HKH995/bNWTVD4Ju7u4N+kRoTvM2z1HsWCUoBsxhDWZaEoESkqipjAgD2+9qY4H3d66nV4cYgz3Ge2omBuNaKCB2zsBcAIirydGN9te0XvUG/blujtEpUYgyRTtPYrRGePduz1uYZF/kgy4qYKM6S9D2usiwbDYeD4TAxKgiDNM76xMDu9oow93LdNOd12wALgnG+JoTI2RLJvAb9nrqxa7TqYk3P0TmO/yRj4ovu1o4RJAcOL0ROsqDxXGpCu/QCFkvpxVskgRcgIFmy2UQUS1/zXUEAhEjYe++ZAVGSJNNaMXNUzY7U5RBhnQhKkYgi5thhCC9W/V6w60sHGQK/cMDzEV5U2Vv8Cc9lSJatLwB0EOKX14aX1r2l+O+K8UWXup/3tXFpXGmDI1BxcVGWrxRcc1O9YixM7+LFV2aAXz70+IWvupgv/kl3ZF/tAf21x2ckNK5wIK7+g7+lG5E6x/PC+kYYOWqtAXxsorXWZnMFoTRNjWlis9A3v/mNfn8gEsbj8e7urtZ6NpudHJzs7+9vb2/v7Ozkec/ZlkViYYOZASRN0yQx1loRjp21ZVk6Z0VA62RlfQtI3dh2f/ofv//f/tf/7f/1//5/00i7N29/7zvf3dzYXV9Zr6rm+dPnP/nJw0cffvTxk48FXK+Xn5+fV1VVfOubIH5lUPR2Nsdnp6kiTaJIVERUiBCRrabro+G3vvG13d3dQS9tmsYo2VgZtW0Ly5mS+dxh1CMhdczskADAbHJqjDFaG62bpnF1lWhYW9n4b/7r/2ptbe3+/fuvvfba+vp6kZhemmg9KssSEQFC/GRkBAgQ5qmt2AtHTAyITERNaAmAwBtMtKFEF4hojAGUfpYGo43RBIE4aBJEStMU2KWGRr3C21rlCSKnhnw7w2hNEUABKACDAJgnucYN732/nyWGSbBI0yLNCEWEFq2GQAziWNC7RkCzD6RVlqRZrrWSPCPnvYJWgUJkwoAcQIjEba33Y35YKRW7jUVEpP7GN96IypLOt3U9jRyTxitENApRS3DT0obYxSGikEVQ2HOwrQ1MwloniSLxgTvFpxCr8jE12lgXdaIQRSmjFGpUWkM0nMtJVJEYTFJEtzIySuxM7bbIfAswAQkKsQQE6nIiXR9/15wpzItef2CJLZoikqZGYiUTJASHpJi9ACuFpDDy04kEQAFgAgFkgE6e66LY+eKyvryeeO8WBnXZYMd3r/YqrpEXW+ywbKHxZ2yAX1H6+WIf9DMe14WCyyf/ur99ITXyyn2WL03c8hUb4C86rgv8fyHG4pr9onh5iBjTXESgNYmIUsq51ra+yHTwgYjOj86augYJt27uvv7a/em0DCGMBn32Lgi7tnG2CSFwcBziUsi9PGeG588/ffr0WQjuzp179+7dqes2Lp0huLZuq3KqlFE9VU2rjz95Uk4rcZIm2Rv339je2kLSwPjRTz76k6M/3j88UEhKm+D9qD/YvbG+ubUWMc/9oifOfvTT91dWVvIsAXEGC5UkiIISQEQCfPThx0qp4aBIE2XbqqkrEK+1RghXnhPqGsNgkZqLIYUnAfHBB4QA4vPM4OpwdXX1n/7n/1mSJKPRKHbLNE3TNm0jQkTLD9/idg48f/aYEVgRECERjIa96DEoEhAvHAKzdw0piIDH4IXjsyqCSJPxWZ7nd27f3NnZIaIsNXVdj08OEQJSVxRcFBEBIElUsTWKzdYSql5miJSIC45FBFkCSMRtRCSHhMDE7D0LMQFCUMggPjVMaIFjBIpBFACA8LCfAwBz650PoYuxlFKpNgDgvQ+uRnG9QvV6eVEUx8fHWhMRMQcRpiQC6T2zKFIq0VqlIojAHBxEOQ72HFgkEAl1GVRJszSEqKHEiIKdCEiYMxjwYgaJbf5dy2LE1TAzQbdFohoVyMUc2xmRIoeciogSBAZIE7OohaKIjx3lwooQkRjJe8veeXYSRIFoQhWpmDhAJGVjca7VSi0bxQVZHs21Q5aN66V1f9kAL/oC8MVxKTJb7L/AlMCLZkB9RSHP9WvgV7Ow/6wNxPL5uXK8HP7CNQ7QK8bLH/IVG+DL2Y9F9P7KcZ338Tc5vty3/9xHwN2Xd8XyuQFGRK0JUJTCpnLOOSoMs0NUR0cHWX8wKHorKysk4L1dX1m9c+fO86efts4TwMbG2mgwWF1fz0zWOKuVFgnsWSksstQzoXBdl5qMIClUkFBqksEgV6hNmg2GW5GK6Pz8/Pnz52+8/uDu3ftVVZ2djveeffqjH/2oaZrNze0bN2688+1v7exuHB48yXK9urp6586d9ZXV8XhcVrN+v99UJbGHYMULAEc1PhHZ3V5nZgRIDBJylhC7unUdyGRRgFrMWmuO6D+Z1/0QBXF1WNRNM5tOLFGeZcN+pjEA2+2NFQEAtuOzo/gJ80++YI5b/nzvXGyxl3lfG6FCIQXMIMjA3sdGMQjBhwAiDIFAiQICFRsjmNnVVZ6qteEAxfmGZ6FFofH5ycqoh3Px6ZhAjohN23Ke5xq4sZWIKF0oUE3bAhB2N4R0bgcAihCB0RAEgnhhS8ACHgNkmkQCM6MwAGDwiIoAqunpYtHXpJVSWoPWeHJyoJRClsZZ5MAqDS2U3GrwIACeAFkjAopw8M5K0CJsVKK1AkaGACEwBEUowgZACBUidtEoUgjMQbEIsoq/hVlQgg+CTEIMgSTGuRQBr1FvPHaHKhQUjoS1HW1trD9K3AKEJBCwyx11BUCFyMHKwjsD0DExGXnoumpuEGYkJCKlUSQAMggCskhg8RDAx2v9oimNq0dkVuALLuIO+R9LP5dS1vP7dCmQXTLGyy8Wf7W85YUXgZff+qUdL8emL++w/GJ5n+XzKdc4HC8nn7/iCPjKCwyfVRGHnw/r++XGL8QxR00RWFwUjM1tTAojFjHSgiMmzKIAEeDOrRtF1huMhkWenpz68fnp6enpaDjU1mda68QMen2TJsEFAkYOTW3Fy3DQWxuOAoRgw2w6Hp+OvXgFKsmTUX+kU93U5XR//6PH/+7O7Xv3799PNlcO9p8pkrPTw6ZpNjfXX3/99oP7t2P/7mw229hYyTP993/j18aT0+l0Ws3GgzwlZA7tdGJXBn2liDDEICk2LYiIgG5tS4DWNok2OjHiGQmDc1fi0INtGbqGuoVsoiCcHB4AoWutMjrVatAv8sSQVuwDKvLW1U1FgHmvMEq74CV4mRvkixkBI003R/TJfMUm8HNmtKicpbViQZFoZlSUwSOUqGfpQ+jlWXAOhcvpVKEqS7u5vplnSaoRGaOWhEjs1UdEFO9r70SEIlmYd95ZDEEpw3OxSAUYIEbAyM4nhgRV65kgBAkongAlWGGOLRoAIBJr5Jj1imgkACC2ddWTKlKb6cQQivEogUmr4G3dlAQongkUaWTAIBzl3hRp4RDEUqyWS4gxJgITgqAIzmGTEkTYOhviPgREAIgQGXxDiMKWggLCQHHpmQPt5sQ5LDKXO2VGUSCx41MIqGNPsoIU74F5fwMwQggs0dzP6R1iFkEQYgMbs0/TXCkjAhA4sIu97IhCKq7KHevey5EuXFVTnNtgeWF9n48ra7rLtvbSarxIBV/azvyCbf7S47pPkKuk3r7EuG6x/Qpdh2UDuey+LIL4ZVN1tTfzyvGyDYav1gBfeTSvNlK/EDbs1UN+AVLQNE+ezRNW0CUqkWABaYnXYm00Gg761ayajtm3TZaYldGobmyilVKK8gwIbVuPJ2cEShsj4qPX79m3zgbxCnVq1KBftK7xNhiFvSJLMnNcVqfH+7vbaxvrg7PT/TRNv/bW/bfeuEukm6ZRSo1Go5OTs8FgkGXZdDod9EcCbnx+tLrSH+QJIgZXK+CVfi/PU5EIbg0cGLlLQSOAQtIKDOlZPWtmM0Z2jUONo/6IY4T04mxrGyBAAC8+bom0Kr71o7VRP8uqtiqnEy8eGXWqJ2eTrJeRUNVWhow2yKCm1XTUH3W1RmYCJSIoBCiJVkJCQgECAnIX/3Evzy6+F0TYSWDvmpXBSoAgXgIEjRoUiBcW6Re9aTXtFzljOigGx2fHq6MhodPAEnAuT8wx6QQIRum6rkUkikZHpk+lVCSciVzuvAjWBQBYI7BCHQCAkQNEERQbIjEnKUJEFgYRJPT2gilPKaVJ6ULlWRIp0pCUUVobpRMjgeu2ca1lIa2UMQkKuOBBk1KGSAcvIQSIbAcxmUCKOUS0LwgwhpjjYOYoTTi/aYV9JwX9wsqDHaUACEAsBEcmQZBIo4cMSKgAAYUiS51Erp4IeuqMhiBC9AcQszyTpTYkCRxRda2zrbNRo1NrTZTOm5Q8M6t5p6lEgR8CAMY5U17MJHeP6JzcZnFKY7uac+2lpOWlZOmVS+ilkBdeaTaWl+7PXM1+8Rfsq8eV1vfSu/DS2f781nex2+U4+OQP/k9f6EC/kLERAAB1pQu0uPMu/TYlL2xceHOxFf2Kb8B5l9OlN665U5i/jPPy8rg6TQFAZL6Yy0evQicuO7PdE8JXp5Kufg6RGBOBYNgReGIOiBbTBrNnE3sybcez+sMP3v/O2/ffuX9D+9n45ODJ3rPR6uraaC3JM41ERmukAKAABRUBRNVMBtCoUStrPRIpVKgQGIJ0/zs/Pe8NesP+UBnlWueCU6h0YiCSdL/QzEAA4JwTERASkTl7KCoUAA/INK9UzdsyQWvNznauA3MILpIjAnQyjBFiE7WlGYIms2g9igCcONvGLcA4y+/GGunL2xXqLi0MIThubB1R0JvrW5f2jH+bmqx1TaJTZci13gXrWj+enq8MV5Uho5LFd8V94vFA7PIXivqsy1uWjx+AwTt88Ql6VRoNgQgEwlIza+d+zSk5X7ivQEgRxVIpM4tc1NEXmdLlhT7uFkAgcEdPQwiBA4hGimwBASQSvcbO+8Bu+cgXt3HsW335Vr+kw70Y14F9rkMNLT8vL1qga5eCxUmDeYQKhCox3vtIrxZCSJIEESeTyU9+8pPvfOc78YdE3nKlFAeJHFvXLehXfu1nHv9fZ9AX/pirz/P1EfDV2Itrj3+5p/lzJEe/6Hnga1LE13wOU+ejXrF/HMt5IGZW5ovFtD93IKxf3Iz0z+8QAqFLYIvFooOI8daJWxSSQkFgYC9IwACkqOvCEIzhkggiEAoCawTBrtkm7gSABJIlRiuMVOEKO0UIhCDCiPBiwz4BAIEH7JZLXOTMkTESe4MAACECMEX2U2FGJhREZAAR0BjJuRVCzGGiAMfSIUWEs0A348WM80bgxRy3MPKV2yOCJ/oEQpBogynoQCIBQjw5wOARUSBAgPPyNFK9i0jkZBgOh73ebnQ4rG2kE/okyw1YiBLYnRBMPP6IGLrq+EmAXziTsjRfuSDGjh5cTkgu4D/dRyw/eiISkDruBSQ0C3Prve8Y+RCYZc5YFJQyc17tyE6PIormYYV0hXDCLrXKEmnuX7wtYU7deulevXTfLm/5WY94vS7lePFCp/Ji/Grt+tX4/ONnboDl+vvxymd+eS341fiqBwNQ1xFBABhTZBCJdiPdU56axKhEEyFogjgLIknEiKKPWFUEFTshUZCQUGIejxABUYEUeao0gQRgQEAdG/gl8Jx6BQCWWUiwA7hENrjOaxYRWq6KyZJhBkRhAlBEghRQAUTMzMVNtQjMYrVr6TzgYl4KnGS+oF86aZe2yxxiBUQQ23CiKV0c5/KLmEJkhrIsDw8PjTG7u7uj0YiIvA8heEQ0JoklvXlzzmWwxiufiIsYJhpteYUBlvluneCqYCc0Knzh+F50sKCISUxMS8z34dg2LYAogkjCgbljw2AOvUyLRPgvCET1kZgxwfmTHbd0aECZQ5uWjxgRcanGuXxKCa9JMF13hqKq9hW7y/I+i/k6EA2DXJy3qCGgFBEFAYhY7MV/AJFFeJHIhuivAuF1B/+LP667Rf9uL+aX3K9X/Njr3vpbi4Cvi31h/pj+ItRWf+6HRCDnpSwQA0qMMOI64pzznlEpEcnTJE/S1GjSigBjIQ8I2YcooaggdpLGlU1IWBiFAjLNIzNRQLFMKxKidrRCAhCIXSJdEwjFxg+MYlEogEQgkZGKQVAuTMsLVq1DslwQEZBCCGqRFF2EKctp/Ov6Dl+Orj5z+3KSZpGAcs5dub8xJjI+IuLR0VFVVbPZbBHezQmcO6EnpdR16lhXDkaSSPUXqViXZoDLCqkxCxI4zF0JjNXSOObEDvHpizOyQN1YxE7ar3OxAAQ5eloU0wIBGViJAoj9QLxYbebQ7/hYL1j2O4MXWY8kwtPm8LdORXsOgLrY0r2mZfnUhYjqtWSvX9ESsixXF69XvPTsw/Ll/qxVi65L4f5q/O2Oa67atZdyXrC4MF6vzt3+3BngOF4+6OUtf7e9p7/B8fIzz0orkRDFf6z1zjnKUwAgIkVI0WOPzSrCIIjSFc+XiD8FOBIohwgmhSXzkyiKsgkgQESEBAAd5haIBBgiW/h8C4CAIgERJOjyvvxiclKQJSqSAAAIMwcRBGUwNpjO2ZEwComKzK2vvBBsvxDxzPlGY/Sz/Bzi1dsR50+bRP8hvpX3+ovjXH5R17VO0qzoDQRW1zecc6vrG8Ph8PHjx2ma5nmukVxgz24uOLG8mi+/eOEHLOY5xhoAIky3mxFxsX15juYVXvYVIhZB5OI/AAIcj6dEFPHkiTakUJMCItu2iCSIQEBIWimlFDMBA0NE1gJi1BoTli5oBuxgpd23R/qTTqoT42HFDANghxkH6EoM1O1w8a5A1Km56t35jIJ8bS5gcTZxMV8bSKslvVhEBhQBZiEhElKgUJCZSSLZBnb/IcYdun3g54x+4qsbX9Tw/KIHV3hVW/DPYwR8XUL5ugj4xXXyotLzq/EVjYXunoJLETAqEQzOs3fMTEwMQhwilwEAoHS0BAvuAJQQ221E5BIH3svwHESkeVISkBRAp4MBFGWbO7sWIMz/XCN5uaAGhKXndoEhIqKo3ykiQkhI0UAuh7yvvoVe/vBXb7+0g8yLuFf+VVRhqus6Ui1mWVYUhdbaGBOFm2J5ePFb4il5+em47hgilTMJLwRR5rIokWSDl2cAYolGjwBkMXfS18CIHYdUJzRCnOQZoigkRnbBhhCQJSBHvVWNIISagGOfEoLSRAEkek6IXfq5K+p3KW5Ahs4xEiR9QXYPc9q2zlOIbt5cxG2Zr3H5FMUteGE+FzMvhfhf1bhUI0tU8nIe8uV46G+yXP2r8SXGtRHw9Tb1Um3oywWNPxcRMHzWQvNZZbBfjVeMebT0olCJUp00fWwFXjRyxNeRzy9GUSwBAAhjjjfEftO5hdOIan7BZH6zxjJYABFFsfLHsfKHSIgxtI5/cSF3EQ2HhMiICUJASqMCALuQz6AoBAYc127PISYAkQDxgvU0HiLPE9Gxm/LqCjB0WqYQb7yl/OG12+cnCl+0uHYJpb9sg7MsK8uyraoQAmmtta7bdlqWK2trsZYYubhiqZu7c0VLhdj59bpafYVjDxZ3pUZZzHHLpRmizml0d4DjHM2wzJFWABRr6dEk94c9kRBVrZx1rWudtZ5dL88kNukwBiIkEkIiSjQxdZpdgEEAhICZCXUXk8afhBCbgACR8aLcu0heM7xgsZZfyFz0BJbWjesjyy9aA74atctyQVhx4XhFZvUusYwAND+NFF8vvSuISmQJAPHLMf5uR8CLf36m9b0+Ar5CH+YrmwGvhX1fd3CIKHLRoIhzBvS5Q4wvzn9T43It7br5Z/btAPPf+wUeYARR4mKqNAAFUABAAgo4gaAkCKKQchycMGKk75FFlSu+iACsRVV12cFnEa06Ga9Ld1gIYcGWF631nNtHXSiCLddWuwRgYAkoEYrFSIiMC0MYa8IxhPYiwBK/hYNGEiUEgiJBgLv/JFpnQHnB+1gywAuZLOqsrHSw6otzP//h3ZLBjBEUji/w3PLcBMxv3e6FQgnsgDlJTZL2CbVzbjab7e7uRgoUANJaK6WZeS42FzDGn9IZTEYgwQVt5Px1l6KP7km0S4t5oUyzPMNF+19XHY1VhUVUGf9bXhudcxjR7yBEpLUGEWTI8x5DgMhIhVoZ0lE+PAQCkBdTrSKx4s9LC68AIJIAAiLEPmkSCsDIyMixpSv+RgWKgUmocx5QFgJ5i9eRROMqET2FctX2OdEGREDhfIZraskECNHTU7SoSS9d8V/28QrbwxGuf3H3AmN33i9tB1i6UwFezGhc+81f4CCBoPsuepXPBjC/Nz7785eTfK/66usMsCAyEsHl2SgdgCVIiDAeibcnMrMQKABBUkhAhIJAil3gTs1+aZbrU2cvGt2lNxhp+fZnEZCOPP5KswfXWOKrv/fKdsFLZ+eFfJF0LLQQl4rF3MWUL87Xp9yvOw/MMXK6YHbthEu734CdWAAuuj1x6actv7jiaxEYecaAnpIAGkGhMAVv0AduewSzwKtrm8+fPKIsPx4fqQQEmSF4dhiASCsERQoQE5POZjMA6vV6IFSWJSk1HK6UZSnYeUqXfq/AHHCruvZdL4xIF8ENXhQjhQMq0Yo0gjACegYfvLjWXnnejDFFWlDenTdmH4J47zBgkurEGOec54CCEjgwFEUhEjtgvbB0mmsopLSACAdEJCREjGTFivQiIRz/gFkIWBNKpxIKUYg7Zo+99ws6kSzLrLXMQWtdV2WeJCrGiCIAmGgqsl1BLIo+aRW8tG3bWoeIilRbT9I0TYwJwm3dBOFEmzRJCCD2OwdhFkBFiISKcKlvEpddi6ufd4IOvCYAHF2jaIQUaegeBBEJF7zKgQVAASJiohJjDKXACBAYUROCKCBGDsIBOw4rUIt0S4ystVKRPWJxb8A84BRmQBBhRIFI/tXxlccWJ0EEFKYYw0vcX0Auzx0066XtwCE2zl2aCairHiMs74nXmHEdQ3yJLNXAEAEJKCgiHL3VECK7NXtvRQKiKEXRM5jrTEf04rL+4Wf0fYQv1rcKXxTkdXW8/6pxzffSlevbBWfIctoJO1Q5MMLyDAAQ/CXdwVe7N3LtunqVfRUJoKSjV6f5scXcUABYXsJkcXGuNNULNaqLHJVCpZTwNZzz15w3zQBdxebFOYhI19aAIUIiMb4rwBBQkLGbYe6Kv/w5X3TE5kBE6aqOsXwUFmw9Xcvg8vwzH5es3avnr3y8HLl9oRQWK7CAJJAwEggq9AiAwgaD7sIl5RHb4CMRZSeX9FLpfd7Mis45rZKiKEKQzvp+kREgACqI7a3QERQhIiMLdLrFcy9YUEAjXLmmxBhxqYQxjzuBvbdtaNvGAUOe97KiZ4yZnk0RkVAQhYhI61ikdsGHIBz1BFBFAXYEmjMThWh9u2QAKYKggGIF3Xtf13VVlm3brqyspP0eALim9m1jjEmMEZQ0Ndb6qqqstdb5tm3rum2sHY1Ws6zI8lxrE3msAYAoEGpm9hwQMc0zxE4nuCzLWAs3ihb1dURk/8UW3Pndw5fmiCrvCrZLs5p7SwoUYuzeRTXH0wEAMQIAcVwpGUDNF68Xv/D6gCOG159zlpfj+lfO+EJz1sU8z2RfnmUeil2aBQSCBBER8cyxUsPMw8Hqcn4onqtXx8SyVNH4Oz9kyRv8zBkvBcCfY3RY9y98VDy37FfelsvH9bO1MtfWgK9Lai/fai//868/cKk34tW+4a/GlxskDAAEqLUWK4jIzNZaTDtigUsrSLwETVMXRaGUadu2trXWGoCstUmWfsFvB4a5wFzsqxQACC+H8JHVd5mQYXnMYTddg2kX0qGUZQkkzgXbeurqcCpyFQFEOFkXksxZcAmEPcckOWrURASotEqY2Ur0D2DeegLNrFKaFMfzJkJKpxkoLaTyfp+IptNpay1FwsXGTqfT1jrvvVIqy4p+f5jm4j0/evQoL3qDwaDXG6RZlmVFnuepSVpbAgt3S70EH1rfMHOapqRAISEiBPbOO9eGEJK8+ELn/7qxrLC7/OLl2vMv+Yg5jyhgHEIY9Lt18sqVann7lWvpYofrFrrr+pL/9sYXM0goX8xBnDtbn3PXa/e/svIvMZ3RRUzYeV2v/oqfsQH6DAN86Qgu0Ad/s6ioXyqf8W9sJEqjgFJKROq24UFGhKiutsFxSwRttb611qZpnmXZ56nxvzBi2ZIjISEBhFfnmK4TEl9mxF3MipSIKNJpkmgV0WNQlmUIYW24hi84djHFCiZJhVRsGSEiUkYpRaQBsCNTnDcaiUhgzopeCM5Z19g2OC8ICkmbJHh2PiSakjTTyghC29i6bfqDlcz74AUAtE5Qq0QwCH/tnW8AgDB6Dtayc2VTe6210hjBWN5bZ621NgQngZEgM7pXFHmeZiaJIGpm3/ovnkS8/ny+PC49d7/Mj+Hi/of5qrh4LUvCgnHPS6Z32cq+vHj+nQ4zCD63DSZgYP350DYMQhhLk1cWDeTlMgK9xFuMgHMz/sIl+Ju7HK8ywJdumrj95Sfw0g5/zRFv5uVP/jt9d/7MB8MSD+VcCgkFSNgYBcgmUSBUVy1AMV9hOhvc9bqKAECv15tMJtb6PM/TNI3opzRN67b5/AdDIMyhK4FFWv+5i78A2gG8cP+Tuua+unS/zUm4VlbWlNaIGAKzF2ZoG+ddMx6PiUgr1JqUinVtBCQvwIJIWhEopUBpIQoCTV0DoVJK6QSRmNla52yzsb5ibeNcaKxvqsp6r4lQqWG/f3RyZpQq+v1Em8baEFgnRZL1U0Rh8N47F3xgQqVVMhz0g7B33HrfNs57b720wZ08P8myJE1TQPE2AItSJs0MSDBGKTKIihlQQgjBc/iqSh/XYTIuYUx+aR/G2GUXHw1jjFLKGLMwupeWSrwqh3cpa7h498tFwH+rntDnD4KJmL5Iea5DiXY2+7PmWK+KX/TSDFdtZ0CZVzCxa8OL2hid4lb8q8UB/8zv9i+cgv5ZX3jvfRck/RL72l/tYOwogAEApbvTmFkrpUAiE1PbtnEtWBhgWEp4AAARHR8fn56eb25u3rxxO0mSWNpE9cVSTFHqHDlAZI24Gqa3+MzA0EnWXMJMwhxFGeY44fkThCEwMzjnhJFgzjBlPRGLqJhCjPcYi6ApBEkTAREDsfXeswu+rlpBUEolSWJMygDBOef8T3760BidGIOUZIU2zIRISjHgrCyF2TH1iiIwGJPnRW9yPjVpkugU0CAphZCaLEnTvb19ZdIkyXSSDQb9wBxCcBzkfIqmMHlPIbDxwMEkKk81sBAGhSIMzgdhz8xBvDHmSqKJLz0uudrLK8AvrfWFJZbQRX4oFjUi5ubSavl3NwLmL1sTvSoefWlGYYHPa33jx6IE6UpRn3+OL1QsYM0xEMsGeDFkHmF/3vFFzdbnMsDLH/qyitFXO+LiuDAAn4lo+NV49RCgeTVkwUkpBMDBK5UAeGMMIjoXWCLERi1O+0VEKtK2bZIkRVEAQNu2cRHx3ifqi9WARYRiW8dFYw8gokSuym68AHyLLqsAvDALRKFzQYhzVPNtm5YBQpAQBBETBZEwSycZzVFmLKETsQP0tlImSbRRBsVzXdez2axqaq0T6z0zGGPyPE/zTJMC0vsHJ4NBb31trdfvJ8Z0MRHRZDzuD1Y4BAGyjpXWSqcCutdfIWUIMTBDcC54Dq62YbiyIUAxI89erA/OBRf86uq2ydI8SZGEvRMOCgVIxqenhKwJNGGW6DRNemmqDE0m51/+5nhpXErpA3TXZHk1+MWxFl/liKWQhSld5plZtq+fp1j2hQpq153tv81V8QsUaWO+ja5Ap183wxdE116785XbeckAL8CztLT/3zRR6KuIOK689stl4Ffv+eUGM0cD/MIq8KvxpUaUzJUlvv55QYZFSKEgyryDIsSE83WnnZlv3rx54wbWdR18cM4lSZYkib8Gdn/dwKhZi1Hh56JRuDs6ABCKficKRrI/Bo4tbcszCwQBjMJ38+3CJGiUUkojAChlFJK13nMTAguDNgSKNJlYZ2XBw9OJZoVgGMG7MCvb07PppJytr2/UjW1bR0QDLwNlhr3cGLW9e7vXyweDQZIkzByROACMOltf2UDEsiy998okAagpW0RCkBhhk85SAxKARbTJWhes9Z4DgdIm7WcpabV/fCxOWLzRpFEDomfvvd/a2fW2bZvSNlUzmRFwlAMohsVXBdS8ZH27S7MEzrrOKf9lGPFyR+RzTKLME0UdRmE55H11CnoxPk8K+hd/LOWJP9fsGS73B183A4Isi7ssjysN81Ig+df/YV/J0Ndd+Cv1NeVFhr9Lb83JbLvOyLj9OhDNNUO01osIGP4Gn/PratvwRc7PlyjIzde7ZVqlq/B7F8/21fi4VwxGYYSArLqnnRE4TXTrucjz6aTe2No8O3wSQGQue97xGvCCBUW0ImstokqSBJMXooErx7VviSiNhAo7Qt2IlKJEJ2VZkjJJoq21LGBIO89RVAYFUJEmhSo21Akp471zznnmGPsSoCCTMtYxc0BEY4CRBLQ2+U8fvt/v9/uDIk2NJiBCIgiAq2tbj598enr00GRpUfTKsjw6PJnMpnXjdJpkaYFK1a2TaUmYDAa9vaOTfGyGw3plZWVeBQQiStLUeUGEwNjakGYmLwqoW++5Pxi0tW3atihM62xbtb3BYFq2Wd4bDIcueNc6533dzFrvhJROMhHxgU2Wim99cIlJTZo75wSUSXvMcH526pxLM3WjSLSO7cscC5POubqui6LogvzI7x1ZMubZCwAIIXjvRWQh7HPp8nWh3nzLpVzUNajpTj/15Vv0uufruvvkunXmOtDftQsFX7gLn2cxue6Gruv60pZ4bmNvdjyHWmtE9N5XVbUIkePJjyXkaLYXv+7zPL8yh3ct14Yirc1ihxfzE58LTLcYy5iy5eNxzg2Hw7Is67oeDAaI2LZtr5d7f9GXvxBIFpEoxf0yYqCqZmmaRpnk5W+J8skLjz+eEEJ0ocVIeEIkiKSIACkSrgizD7GBWGKjushg0Gudbds23v/xEoiIt2Fx/i/OkohI1zmPCApJpBPTNB03bne2Lp28z+8kfdGMxc+KivKvE7++bH1/2dztr3wsYfIZgVEAOSCaRad8NL30+dKMXyiH9uLgrjwWIViCnmOVRbQxpAwiMZCgAYCAWkAcA7MXQQzsiIgCAIkEY1IBAaUUBYxKikAMwIJMwbOXAM6HEGzbttZaId36gLUDRbrISFMIvnVufHp8fHI+Hs9yz6QypKTXX6EkT7K+Tow2KSKyiHVc1RaQAlPjRTdeppVCap1lH4CwyPLIl1Q1dVPVs8b18rqu6yTJGFSwzjOYIAJaGVA6S9Gg0tb5WV01ZdN655yzLqBW1jtgURqJUBEqnSRpUjfWBVEmUQjMrNJMkEhh27bMKvKJxtU/1rybpoE51Wh8NxJvxXfjqrTgA1+WsvgZjV/0CO+6Gx6XVUDmv/ESB1wn1f7KUOTaz78oxC0KQ13r4KUv/YzPuZ6w4kqHPoRQ13VZlm3bpmmqlPLeV1UTgkOUyAemlDFGZVmBKE1jX6zpds/1yvoaS3BNWza1+EBG50mKWhEik0BgLxKRHMjCiKRj4UMYgghImHf6dgQosmAlQwQBGU8nAWR+ToKzIZ7tqD8GAIIoHTctiwigQon61BTDHqJX35l/S33A141XBz2Xslhf4sFGRLhg8gP4lfX96w0BXAChIwILBQgYJCwajpRSDOI8a1LhBYf66lgcFy++7KUJwiAQ9elEiAXK2k6qhgPoJAQvAIjoG2uTLA0hhCAATMREgKhEgjHEHGIggSiIwhwCiLWWBQEijReyKA/aQwCdNt77qkWt0lwRaet8Y3k8KavGWifKQxBM0nxosr4IkdaJiT1a3nEQaFrHgr3+iAhMkpJKOHBgjPDYsmqDcDTAdVl5QWe5aRrEqqotsAAp64MAoQCjLorCBW7bdlpW9ayx3sWQVCWGITAzoSiAxKhEkYhUbUuC2iRKkQpskhxQJyn6IFqLzJtTrbV5nhtj2rYFgJiLirGXtTaGvFEhMcYKOEf2/m0Z4F+Up/v6CFItwtlFcn4Rni7HiF/ueVkEcAsDHLcvyNsvHeEX/YrlCBhe9CEWvc7MHO8W59zKykpknQvBhSDee4AAwGmaL1OELubZbKaMRqQ0yxVSkqUKKQh76zjKbiECkVakkATYuRbgCirQxJgoNBJAIHDojDGykNE64tIXydd5Di/6QCACAp1WWwgiHPuROlaZSAkw1x2XpfmrHNfd/19xBHzpLvzSnvWvrO/PejAzaYo4qyjI0zpbpBdsz8s74wVu86KDokuGf8HnXXCe3kYiJCQCViAwLavJtA5eVOKDR1SEoNq27ZPxDBxAABQBRTFCJBdddwZAEA4swbvggieiAAJAxlCmE1KkE43aNK23zcw5T63TdWuC8947DzrJ+v2RUkme9fKsn2QpIgoQM2udKKW8MCoXQhDSXkAnGRFpkyiTkgZRCQmgVsE6GzwJGKHgEVWKlJCS1tZQVYhKAFrro8Mza9uVwILgXLDWBuHIpoxaaU1KU9NY590MURtSCN57o0nFJLvzjfVOAE2iE5MYnyQqJvSapvHeL3SWFgsoQCc8bIyZzWaLClEs/8PfSHj6d9cA03KSc9lSxn9+zgj4urFsgF8uEyyM7uLwri6NXZ/Sj8/+4gMv/UmaplrrmEXPsizyrSJi5AUn7PpxBYIwcuSXnJN9IgAgZPkANUKA4BoRsp6DdbN6tjJYQSUI4NhJiOEsCoB1XU6OiCTWNAkJcRa/96XzXNaNMolRHDXLGUQhoSL2vABmzg05AhBFyjxRIIioQAAxYCRP70DRyyfhZ062+JVFwJfOziv2fPVA7JiwLtngX/QU1t/WECTBxTPJgEyxKCysVKfoqrVhBmu9pEpeGNeV7v5avChh7tADKSSNpEQgNCEIAmlSacTgKTIKCFWGxEiAwEg6Jo0AGJVB9sLA7BnB+dZ6dgEHg753jh17z1a1RAQizF6lBbH3bdN6Gc9qUqyQtEpMkg+GOi/6xqRJkpBSIiJISAJKg1IkogSROMaKVVWRAmZIEBWSZyZAJYDaECIBJkTeMyrFSEIqz3oiorVmBO8ZARShdf5sPEGlmCEEQW0SrVGQQptmChGcbR371tatZRQQHwbDHoE0rVjX1mVlbZMkiWHVN4lSEGUSYgq6bdsY4y4C3LiARnMbCavhxdrhzzr8/eUZ8ZR+ifN57QO1ZFyXv2VZ/vLzxL7XveuXVLxetsR5nkd3Lda5EZFQxxsKEZjF2tbaxnvX7w9EIPKox06FqG2tUYeWy2k1LSdGJcOVgVGpSaRu2aSaUPkQXOuBhIBFgogCFCJCXnQYEAAwJJGqXZgFBLsefTMwwoLsQ2ttcAxEqI0xiU5wIaq5iKQBILjIPB1D47nNYjUHOywu3Ff8RPzMI+DlmsciCP7SD/avIuCf9Yi4g5iF0VoHEOccohFZDoJfALov6k8wN8MA8Goeq5eHEEogXuSeUAEqCWI9A5IxRZLlFARJG611KExekESsM3YdwIG9cGDxooDZi0KRgAYQBKH1Yh1bG+FFokkBgIDkeW6CjxXixnoWnyS6rzMXgtaJMSkSQVREhlgzRxaJAoHRI48PLpEiRECFoFiAAwRhAY4ZYK21CLBgsEHYWmuLPA2uJaOVUs4F0sokqXOusZaIogoyKYWIAsAgzIEUR1cpKkZI4MZZrBEAxLu2bZumYQleUCAMsrzlbnFMkiTmsZumWSB3Yp83ztGRWZYtjETEBL2c8PhZjF/0B/m6UxSj20uUWMvwougAfSVnePEMLgzw8ln9cilua+3iz5dfxJxKkiRKqQhAS5KkqS1R0FonJlMahVHiIxA4z3osngMEdlGVGkEJQlk6IHSehA2aDCG1DmZTe3Jytro66vUGzgVrg9aUpgkpYGZBFiEGZh9V9VCQs6TPELzjuq1s4zw7TUYZXeSD1gXbNGVds/eCmBqjjC2yLIgAs2fGueQIAPSyFDmewKhgwMyexaskAcQo/xNPQ0dHAV8mb/H5x1cPworP+V/nE162vksp0F+NLzwYICoxwFIL37ITHVGazoZXn2fp6Jf/WtVfpQyLD8HH3BygBGYXZFZWNrBOSOkkSACltcnJoEoyFJDAEYLBwTsXXAjB+SAcfVuFBGhIK6O4dTZEYLIikySJMfGAtdGoGlRe6YTAOwcs6AREJNp6EWGG0JlYhZ3MIgZhnkNABCDJMyJKksQkiYgEAGFmRMfsRVSEqmrNIXgRZm6apmmqHkKapq2zKSEiemGtDSKGWMmKkSiCiLRtY5RIcCRMpJiFkRlCWVVKKYraZSZBCV6gquuyFi0u5pzzPI9BcDTD3dXnTqsn2oYkSfx8xNB8kS/9chf0c46/swZ4Lo+9HIEsFsBF+iFW4uN85edct12Wvn1hfV8OVRcv6GpVos9AQb/8aVrreAtprWP6BACapjk+OkvTtN8f9vtFnveytMgzJRKaxjJ779l7eyENScoGIG2cw7oJZTk7H89OT86fPX9KqHdvbK+tOufbumq1oSLvm0RprRmZhC7NCmyA4Fs/q2dt1Xrxmcl0koFU1gfXWs8h9kooJCAc9geLCDhuUUiaYHXQR45651FnXAK2+NVy2Vw1ro2APxdDydK88Caue1dEOuVPERFR+AU0hEFg0bP62UHw59Xo/WvM8Xuu0ge9cjt89UWD5fbweGa+OI5DSAEDgJL4ZBAgBQkJooZgIHgUEnASgcfRsZUFf9ul1VnmIKwvPAQBRSnlAwMQMwSGAD54bAM0zrMoQIWkQSGgAq01aQFCFEEl7Lxn62zTWOuaWHlCUEojxu4DowDZOhNCEEGllFE6+tTzrk0i0sYQkRFElsAslKQ6TTUpFzx7j6CU1rGfx8dsjhfxEhXzADmEC2iriEBg9h6IMpN5tFmSqsTARWAh1lUt20xyj+LYKTaBAgOnKYEgBw8QQBFqRYzKQFNaSmJZjiIpSjzlzrkkIZWYNEsSkQ5U1dqmFcUBUPIizdIUdNpWtRdWOmm9823jOBhSZHSqDZEilUa5YWYPCCSoFBLglU7zZ+BDrxi0dJfK8owd0crl7T+XjnX3EC8p7ZDI4h+d/tNi7wBIoAFB0AQQz+QFgihGItSgBCgBJQyK57QPyxpM83F17TYCiKI6XEQXsiALEizkIy+qCQyoyVz5fF69igrprL/Yf7l0qLRmPw0qUUlCnKgkEZGGq9Wdu4RaKdMKNKV4X3vPIbi2dczeueC9DUFEAqJiwNOzKSOVZTmbzdI0XV1ddc6V1pRlqQvnsZlOp8fHx977CAy8cWsXliBEi4J6v99HVIJGpUmRUJqZQX/U6w0CY+yW1FrHeF3mTwcAE2ml0JjUGGWM0Qqb2Qy4w0AgCXIIbCXUTTVW4q8qA/9shwaWiDv+nLNcs790pIFglEJSnVkCAGaMxNmfY56H/xFVuLgtlrnHlsdViryfNUcNHIBYx+y2I6gQIl1j9DShixcRBSNJ2uUZQS5RQ8QZ8TrxgKsdC7qk3ioS+aoWPi/Mj/XS51w5rkgegNEAulO7ZAUYKBEEnSvrmlFK51ySMr3UTBueOZXmoyQhIh1XBASKdB5IKl6FpRR06Ha4PAgAFOnFMSwKyiLh/GxMWhmTpiZFMizIijBAYjJtMp3lmCRZZoIXy0ggCtnapmlsXZfxIY95uH5/GB0/kSDsXRvi9yZJAkrjxRBUGhKqqqpI0zyNka5XSS4ijCBArTjPAQlVqkXQS3DBW3Ex/xy7aRd5xaIoEFG8d7HBVP7/7P1ZsyxJciaI6WJm7h4RZ7t7ZmVW1oat0QAamJ5utnCR6RkhX2YopPCJP41P8wP4zCGFFBkBn9gj7G6ZxhSAxtIo1JbbXc4ai7uZqSof1N1PnHPPuXlvVmZl1rAUtwKRcSI8PNzNdP30UwoUzYwhIEPuS91uRQTAFCEkLoaL45UhZqjd0ZKZC+S4oAqDARoboBYtw27tF6nrWhUFCsg4FAEApFDEDLmIWRGH8ohYVUBqqyaDsO5x8/ka8QoYycDIcpXUtQfLw19++smipU9++Ukg/OCDDze5ByDESDECoxIhAM1k4Z4SGGtkN9Kbt57cJ2o4OWnze2cDrHuvjyYD71F2++t/33jc5xPYvfviWpm8pa33+VzoaBQ/AQABSKnd7ErXLURps9nF0PR9vzpoV6sEQKUM3aJp23RxcVXKmVowi4bBzAATIjBHYtsNZd/WzhXcEJMD151ofbvdImLXdX0eiJkDA0CdliIAlAIhhJzzZrMhotVqxcy7nM/PNrkKMx8cHPhaxaktbd65DhQYhiGXen7ZEycPcGcCAADwygVA9jeXUswMkUMKYAJQ3LC5/2uW2m5RyrA4Xh02MedKBF23JKLHffYcgEfSs031b5x3qVdwaq259MwYQogxhpDm96uMaoSZ3aAyR0MosmcaJvKNCJBU98NDARUAAoPxmpAPZDMV1h1rf3bxtyg5oTYJmLmqigL4fIibaxJuYo3h5vrcD1f2n+je8Jj9JwGmtORbPtp9f8U7Xzdfvj5N+AsfAWAkZrgh00GuBW8+ueNx+vGvP77pU7ceZxX09kyjX61MqS197Se//SEQAMgMUF15CZIBGaKYMUgkMcFAXEQrUDM66WTecXePfGFG0fNXk36hSeciIoKaVAOyAGZAIlKr5VyL5mLrQSDGBMhIicy2w1qk1KqGEFIEYKKAaFUFQGkcSx+IgseLUio6/GPsDvQJ04qIOhoXMWQD8vaEqmJQwQjJyMhs6jPmZCYmoFY99nXuXxFBBCMLBohM5gYMm6YbjTVUkVK9fIuarQEyQkImJqbAhASEw653fCYQEgEFRgMAQmXzucMkbEiMhIwEKTYcKHDkQGAoWqUq1NoF5HF8r6i3WIMi6rYMINhw2ywPY5soXZjJLmsTW7csRgKIhuZXZrqvBmD71Yovle7wYHd+hL1Hu/kIv+aA44tlbFDxYdV+gTwAQAE0A4MEPhgydqzx89Oztk1mOAy7GJvFou37vC34yYuL915cMMdac9OUUgbmaGYcO9U6q+85wXu527kBjrHWWjebDQA0bT44OEBiNkafmc3mRcmrq6vDw7Y9PMTmIOe8rTps+qv1xmKXlQOFoMlqcMcRUZtmgVPLGQZlLjEWFPjw8Qo5EgWHjqlWxw2HkIiAKJiJNx2pghoeHz10G41TQ/lc+faO4ZSSp3+apjGzrpTZyXC54cP5UgQfOl8MqgoCAVIgiojJcPL4aUrLERFFxKBAaiTzNAWAfR2seGcZVAENkQEJRnRICWqGJkZo1+S76F3GhPNYQ7s58vk+T/QN1YE75esi4vitfFUy3/ivvIrmx2Rmq+YMSrc6Gqd8wA3/Dt7C+gJASsmuezCumdG6rlNVA3bgLmFQLQByeHhYFHLVzWZD1CMFwGhmL168mFCl6hUrojD510CEzBjGYIUBcajD5LL4T3BtoSJjJDT9GyXGxpsozASNEMD3JwHbmAJBJCYGwoCIZ5cXPqCQgJljGEGhtDs9c8hWtSpSqhZVVZOrzaUhhvm8iQKRIWqtCsCIQCMWjhER2H1HVfdECdHc4Xj06ImJApqJIrLaqEt2RcnU3VYbub4V0IZdUUOkqEaiJEopxmrQcUBP/tCIgvO2gzuUBH6V7LivqyFEBMC3DUt/XYJ3N9YREdWiV7t+V6+GwV6dXSLGXd9/+vzzpktm2Pdb5rhaLcxwu13/xd/8tDt+slisQqCjo8gcurggooPjB6pQa/V6cJh6WA9SKqUAgBdfl30PALFtRASnTicPUX33/ezvfv5U0+PHB83BYUfkIIa+lCGrVGNmbwevteacHROwT4iWknm02y2PkMgN7b4B9kcn3EBkkbElmCg4tQUgArEhAoKpdsulIYcYY9MgR/8hIhJpNDGznfbN57niKd8IhmCoRgJMQAQUgIIR20STgcjuUQOxISvQ7GTvDQT2W6cAcOdtxGs+/NuiqugeiAKzE3SQZ2bhV0C9fGHG6LcG+BuWN3tSc9Zoz+f6ysywqhJxCMH6klLaDMPMGDAb4Pk0prz92wLU3fV28cDXN79bepmcaD+Iqh4fH2/6XNfbMhRE4QCiWkr57ve/V0VEHNUEiMAciHAYsic2kVCRAMf8yeLwcGZXf92NMBBPQc+/seQeNRiZWSC3rN6/LoKY5oTnfJtCTIZghgiMGIwIOADRk6cPx+tlWrVUySKiWlfrwznPts8mGGOcj7yXk6Wm68RgrjHPOz81zX430ZjUUtFcyAkF3AfBkZZkKDqIyXpXalZjpPjBd7//+OGjV58/x7FLBInGKVmIYwnlV1xR36Dcr+nufv0d9KmREQy1qJlBSN2qO+jC4kFqFlntj/8X/6vUtgA0DDsAWixa5ljK0B2//y//5X+eUqtam6YTKTE2hhA4qdq0Lwwm2ixiDkncKw2qvChEFJu03m5xQrDXWhXVl8R3fvAHq9UqLhaGKAAYAhGlCBjFs7XAQYAEWACLFgoNTh7rPvBKFACQTcXARMSAQA0RTcSMQIAokOZayzDshtJ1oIZoQIEBxsyNIQzDsBv6UoqDJZEJBXMtZchOEwtT1/A+hsbBjWggNnKzM0dkd7QRp/5cA2IiMSUjoCk3aeZu6Gs+3P02z/D+Wrvd+B+MugCm1PEXmtIbh7rnyevyrTPAd53r7Cf9isf5zZNZ/359EXAIwSw3TXN6eVlrHUvSNxL4d+PS33xwd5i9ZEU0wppCCLnmWmuVMfGkKDmXnEvDnao6XWJKTYwRBfuSP/v8+VBLHmouvQoQA1PkgIcHx2P7v1WdEsVmBsQ3b/1ohpnHLaSqY3eRGRqYFJjKhwFpjhLMCa5g9A/8xERkm7eeXDYzRCb0lDh+9v/5N5PrrSJFpHiUo0UdFjCbYZhyjzAVh0ZOEVVFaNrWq126N+Dd3zmf2+y1mJmWOhlgmwwwIsLQ97nfDXkHUruuA4D//X9zeLB6QBTQdJovBVOJ9GvfLPtfsbd4vp3dDXc4Im23rBBa0uNHT5vueNFLWhyI4suLy2oJkTOaGdZCWEGESliWsMTQ1prF0lCEFRCxbZIhAIPRNUeHmaGgg+hRwAxFmIgCYIXWcdZVapURR01ID549AICsKlUQkYERURUCNAJSpfbFi6BQK+WMq9XSqZ8EUO16KapVMHQ0oQrqNFc7MHtClpgBkZiRgRhS0zkKiJhjCEjjVFEE4Fx8fjaYOQU2GSgUMESvFRGNqMLZ75yLlAhAhmPfLiEFQB7pqwwMSJ3BD9CTFGpuvBHgdfLre7N0hHrfJCc3vGrelDDGz7PuvX7PF8mtN/82Av62yxdGwPs2GOArDIBBVTG4AbamaTxVZRMVx3QWNu3Va7DYfiL6vvW1WCz0enrMNfoDCYmIDGEihYa9Xoj5IyLS9/Xi/PL/8t/+t1XF0ZVmSAQhJGZ8/vylJ82cEs9rVGY29MUnpUx9w1MbA6Ij832GUp2KwAeLMcmFiDzGqISIweMSGIMPZ5WqCrvqA6am2zRpj8UijfAFFVVQA1Uwg3hPBpf5+p7OECFDEEfUj/v/+okI+EQlmqhIXFOoqu2fjXv4CsfHqQx5twEkiBEOluF3f/+PH5w8OuwSagVA8IZnRUP9KlfVNyRfTQS8Vw0fP+yuDgQjrsVKtaJgVS+2meo2CyxXD6mJDIhpYVWAiQyUZb0tmwwUWLnj2ARKXWqAw+XFGpmdrQkBlMxMBbRrWk/9iqmWqqxmIIqi47otQEDBGAMzhXB2tfbSRkjNom1DSoHIzFhBRHKupQyIzIxRgYYdcDJQNTQVB8QhEqIFTmPC2QogIQggE4HaWP5gRkQOWAECcYMUcJoHNWfmVHWxWPg8CuewhHlmFPOc/tm3SDhZYr8NI02YYFb1dlwA8OBYFWc3EZF4Cn8NUFXtHdu67pP5/ZP6c4DxDU6Vt7Sp72Swv3UG+L4I+J2xR/f8+K88jvxaZV7iX8dpmxl5Ddj2asB8uwZ8S96yDHx2duaNASEERPYgstaauhRCIGYjRiADDCE0GObct39cVbfb7en52X/4n34so5Ps/OleLbXFYjWhoB2aEdw0HS8PbfKBCdHQCMhwpHH3lNfUVSwAEMiVEY4JL/92M4zJnMNdVRGJOTVNAjhOXqslREJgh3IAwEjIZ2ZSDcTMIW9IoR07T27u3luUgfP1rFqAxt84D5kA0O2297YKf8VMRsqUPeeMQEEdtg8I0HSJwpA45JyR4smDx8/e+3B79gLRKbgBkMzUDK5nRo9nY/fc/C8vs0N58ye//WjZX694KRhh1jvn5+d95WzxGMNicdDBIrSrzrjPFQqYSFUFzyyoicHq8OHq4EHbtEPJRWCzLUOvQBhDY8SEZITohVT0IVoASKiWRbWODqKixRgJwcRBYUZMzIFjWKwICAMxBTa1bT+YKDoOwkDESlVHTFTRXJUCmZmqt1EoohEBogPg0cxEQXxaAXpkqswEBlodwyG+cvepMV2ch2S32zn2ioiGYTCzGQUy7q2bZmmsAU9JeICx9Wjy9cl13mgMJ8WAqET+J1+6dgcs/ka/zOv+7911FpygENcGeIrT90/7S1jfN3/kW2eAfyt3ytdhg/eiW2DmuSgF1+pyfKerbHgX9+Uv/uIvVqvVw4cPHzx4sFwejDx2RI6ONnB1IAJeZKH1et0X8W6HEELTNCllx5IYByeknd1tM8s5O8UQseNIW39DHsq1i+AlYkQEEJC5+xKQ3KkxUMHryeqwx9yrgKqq9Zo2OYTACMOQiZA5YGAkBq+aAagWMzOtqhXUCFQREClL0emS2s39fNde1dSMjQneyCem7jqkEA0J1BQBbaTTVjDkCIRkQOQDnpHA0GC32aQU2maZmtj3p+vNsNuW7XbnEHeYNA2SJ98Qx973bxkm+dcsNhXCDcckpBcs0bqug0KmkUIS4EHqMNQqdbVYikhVI0BkYmZgYNXtdjvs+kAMasTcxJRSIo6ep1EFkyrmsR0hmgAxKCCTgSEn8k4EIQqqVc18KaIgBPNdwMiIaKI551IKM6eUhl0/2jYEIANCQxVTBVFT/weghAQgOJI1+CmNQa2nWLynFhFFRCT7tnXj6jtiH9IFcA0rm/kjvZHp4uICX2vq9ff7FsCJn2Te2rO1nvNDZuZjFmdOsZt75xYIS+7qWX2XVfAWBvgtNeEXGuzwpdkib8k9x3G1fcef9unZ9p/c1y9Va90b9wgzisFraXceH/bU3H757Y6z3KOFuvX6fRf69Ttxq2Bwn7ylZ3SfzNf51s+5dZ7X3wLzupnXM9iEWzAzpw5ephBjvLq6eu9R69c2xujbzy9CjA0AmN2m8iHmvu9zzl7lzTm/enV2enr6z//5P5/PKuc8n21soqqqkXvgtdpu12/6st7WV+eXTbeMsam1np+fP3r09Ke//GXf94+evQcAL168WC6Xi8Xi6uqqaRpnqYUJwzJv3Ri4lBpC6LrOJ7My8+Hhocf3Xsf1U0VEUS0gq8OD3A+Xl5dPnjw5PT09WCzbts19f12ik+magyYCBBtyQdPFcmFmVaxdLi4vLwNS07YphRQiOWuX6CZbu1wOw9C2bdM0l15on/z9mafQMwSqkghLGaRUBQvMbUxuGLXK2IQUxgRm5EAh9kNpFt3m6sLXMAG2qTk7e9W2rdOFtW1LxES0PDhQoM3V5sFhh8ylDCGQAWqpMZBVGRfLtdcFY8ltbxMBjFuPp9Tifu7u1lrdXyqv7y9fk8w8j7Dd3xr7n32bnTIf/879dd82eV0njBN6DEwBQQXM0ERRNcTYiCUAEAPiGNslF621kEHYK+oDACGuui7vdofLZS3Fam1jVBEVAUfXA+GU5JxOVk0MCSJTIFStImoqUIUACCHEazgxSA2IILXWAgCMyIEREaW2XQRvliMkAkBBUg6ApEye6eDpPF3TjgAFN6iyJ/Nd8Pywv+jMPHNQO/O3eMjrzUhumOdJXLDXYTzflDnqhT0tTUTL5XLGbYxICzIEULmOFlQrEXl6fJd7nLmbYPwtgAqIOWepFmNsmpEhrtbKY1uEeeM4Tt+Vc07k40nEzADBzKTW/XnY+0vlvtEa85Qqm6J/v7Db7dYR70SkewOev7EI+F1D9X2DOgPVfiu/ivgWmi/sTJg3L7V9ue8g2+3W2yc8Wl2tVsvlwePHj/fX6/4xR/NDARBFNGcnN85dd9D2OaZkHBGpSvUOin6w9eVV0zTkDYNqkUPkIGV0ydHAu3YQEQ1ioGW3rEX7zSaE8PjBg5zz6YsXXdcRUZcaX/fjuNN+tzw5VK0cw3LZPXz40GGPVXJsGhzTvOINRJFTILVd36aIiNw0TbfcDXk39CGl7334XdFShlyGXsogtVgFBTw8WECIANY0abHomiY50jXnbHvil4hAFyGYVJsgV+5biMjBwYFfkJyzEyOUoR92u8Vq1cWI7ZgAQLPDw8PVol0tur7v15eXbdsyokjVKpdnlwwAQPC22+fet91p3r49cks/vMGTfu2TI/DO/4vA1JRAyVSdPHgUUgBFiKYI6khc9LIlgAEwCkIlqAiVABGQQA3IFBABTezmYyQ2BAIBRDAVNEI1QlXZB8rZRI8yTtQYORJ8fxkgDrkAmVYR00AMMZhWg1KLeo15aixygCExj1lfRLBxmgKYaSkVwHzoApEDszwvzUhGwEBGwIbqj2A28jaDqJhocYbDRdfN79lnPuy3g/kkJVRQ9NcVdXux9SM7qSRycAQ1ExrgiID2e6tiBG0a6SoFjEa2OlBABlgsFgGpKpShz1UTh5SS5P4tl9B4Sd9RZoykm17f3bXWpvEA5tplcafk25KC/kKD6nZCx0kP1w3Rv46T+5+jzPt5duW8a9Cf37K+d6YHXObROjhNgw8hLJfLkuveca693VwyMzONmKycc9/3w1COHzzb5RpSKxjMoFQ1Mym1S/j4wcMYY0AahuHq/KKU0m+2OWf3KGc3IoQQGB88fLBoWwDo+54wtG1bUgqqBwcHOeecq5lPpAABAABJREFUq1ZhhoCUusWibQcr281V4CQ1m9YYaLcbhu2m65Zm4hvaDJDGuYkffPCBSrm4uNhuNmXIhtQ26eThyfnphUjRXLQWRuhiWCyW1MSfffLZuh88BzAn0lNKTnjkgoie3YkI3/ngQ5r+010i99x9jKCJNESrw8M53vrbv/u7vknDMCwWC3LwzKI7XnSnp6e11vXlJZqtFosQKcXQD9slsyf5RpJRVUTGd6/FumZ5w8L4RuRWnvDWn/At4BTOWwMIaLMNBjNnkTM0JR+bB2pmaIJugM1G6B+YjwwhU0IjUwQlQzAhMwFBCAAjX/P+o6komBnMY+dBzUzU6p0/LUWeP70X36uxF3gRDQMCggEYjZhrIEDzsSbmBliHrAQ40kJN7MlmomKmZnuYA+9Nr2UA0NkAz2Z4KmHYrcfc74BmJAbN729TVBA0mh9B0RDicjbYfhvYu5JNFUY9YujkfGZghj7eDZQRwJAMEAhR1lfr1HTUtkxMMTAbqJlcj366U67DBgQb1debP3HHEW5ljDwU7rrOqb48azuHPd+kAX6nIBjHycmeaRwV+m/j4F9F/ALOOXwHQsPNgBWvkRF3i0/X8VvjwZlr9sDx9fAXJsUtIgLqYwP8TzwJcQTAUscRAprNqiCHRdNqqQr14OgYAJbLpSO83IZ5vBgQlm1gpoPlquna3WZ3fnnRdemjD37380+f523pry5KrZFTbFITU2zi5enpVb9eLpdXV5tPATxTbaJ5vQYAulZtCABs1r94KUN/er7ZVTg4bA5OTp6+9/7x6vCgW1bJZdvXvpeaA1gbE6eY0HTYdcRFq2x6DVyHvGPSUqcB48AARhiQmCCfvYpAbn3n8NevkpvqrusODw+b1SrGaAiU+2HYXl0NttoiYs6ZtbSL7j/+x58tFjAMQFaePXu2Ojw8WDbsI5ztuvqDuG9672wFvhsjPafa3rw8fm1yvzK5oQpnpXH/Od+6CCP5LAOCjbqeQMGEpgYYAjW0kbjVzOkekIym6Z+ASKDqmEEQcNz6Ph+0gY5paJvVNwAAaphOc75h4/nruHHG0HU61xjIzIQRBRCNTNUEpS4ODvYvi42lU0opgkMcgRHAwEEB5NGfGz8wU0NTNUNVJdOZpmN6pGEoaIoIhICEzvWISOfnl/u0Hv4IoM4cZ27aDR1UCKBD3t1IwMF1hnzOfs9PFLVpPap2zAQZIBgY0qOHJ6VqGXpDalPTNUlq3e12Ae+evHBLTX1pMbtu8vZUvIvrxjk/Pxf4vi0p6LcxpTrx8TK/KSb7rbyNuB+jkwE270QaLuEmPugLF6XX5mOMvvJUFZGJSOWGmpvXt6dlpFaBET8ZY2yAd7td3/cJiJswtQsCqKYAkZBM2xjWUku/a48Oa60Xp6985O0wDM7yg4godbfpU4DVIraLbnu1O1+XRHDy8GjZLdZXl8NmB4hCkrebtaiyKSr08ODhol5uti9PSwFmWLTNdjsQAfHY9+N7qhT4BLYJQAFaBiZaX16s1+vPP//08vLSRK3UPBTvpkYAAjhYwMUWnh0FJhyGEoC0VyNZBEDGGAMGJgMBsyqmevH5pbOTu161qVzv1jQLAFwyfE4EVaEC/PM//sFut3uuz2OgqiLFdpen/ZpagkfHh7vdbtGlw4PFwcEiMJhU5GhOMmoTEfqk1K7xR9ctwvfusn1065xChy+LbPiq5D5Xfg583xwBjwhyIDKYweQASoCEDAhjUGuGYKQCqoCgHvr6EWC2hWTI4z8ABdJRO6vdldgMIXh/m6kDkf08kQJ7exvOaT9AM+tLf8s5nm7EyOrsXikwajUT6LfDnZfIbO0ZKudlm42kifgrU/OekWuJmPx7ZmY6/4RKdQ5U0xuG9mC1eN0AIxpznJD846PH2QiCZIQjQ6fDFxAxxuh2F6ZaLwAgicAgICBQVa1a0WoCYjCAIcdAMJQySOXYMHi5+02rej8CBrzuA3x78R3hWSsiSil5nPDZZ58NwyAiTdN4e4hvmW9XBPwG2c/XwVsjnn4rbxZVDek6Ar5Yl5n/4S0do5yze3M09aiiz802vZXxs4n50gNfAYdKsipUk+12u91uFShiiDG5BimlPH306NHxibuT6/OLjWjDofZD3u5QlJlJbZEab0OsZZek79oIANvzSyJ4/2Fbi56/uPj+P3uPVCCPzcSqYEAcWVGDDd97+qwF3V7tShxQcdHExowZU2i8D9JMtJpJYYIYowFgTBDiq8vL56/WL16tDzpKKS4W3YPVMoARWsMhEilq8/L0937wfUQ8Oztr2/bq6goRSymeNp958GutoMqr8Yrp3lhZIjo+PnYupDmM801+3KYFgSw7DGxmLUPbdX3Ji6fL977z7MWrl0gWUJk05y1I7VbHAGRq47ANRFet0/18Wz6s2QC/TV731yD7C/Xm0h0dwX0bDPf6lDQxYd8QNEOPfc0IBayQAaigKSAagk3z0wxlHCqDbAjmsCcjBVNDM6iOfnpt9ppVBRwx7qZooCYIqAYyJ4fdRPk9qqKIRhbmvnCfmhmdm1zRjCIEpsBMxtZyMyZ1CR2wPaaWoc7H3zeQIaT5u64f1VIIql4pVlOYOa609d4lsKl91yfi5aF40nikGacxnL46v4B5at70KUArZYBrrI+NtBgA281u0vwT0goAUKr1YlJLGXLJ/TCUWrOIwl/9+C//2Z/92X/+n/2LkwePpNSSe0PCe2Y1wlcXAbuIiAcGjgZt2/bs7MxdIgeg+Nb+JmvA75R/hj0DPMf1v7W+v4qYmTfjhKmI6zVg2+NgmhWZ2X397gCT8cCpRuCkkIS8l/G7oQTNTNWQAxMbkSOKDGnWjDgBLEsp/W6Xhx0zHx2uTo4PweTDD94/Pz/fbq4CIxEE5tVqeXx8zMx5GzNKG6jWOvAQQloulzmXYOfvP36ERahWVfCgnzmmNprJy5fPHy9Xslj1EImhFk1NsIUhWqBIBMzxuh93t0GiohLatl2uUtuExKJ6dbFmgiZwG5hMUYRUTeVotRgYHi26nPPl0EemRmqMsTlYTSWVEb9NTULEyGP0P1IPTi0f2/Mzzxa4TJV7zZurpmmOFi0gKsKijd1yte13Q8nLJnw29Nu+f/Tw5Oj4IBDQNE92ups0XfB3zid59uJGvvTbIXc6jvPC+0L1Oo5eAO/QEgDwjCs7XTEoghEomEfLahgBYLygvob9CMSAbD74BNAByIJG7BSknma4flQ1RMLgHWJgzvBtqGQ0tr2OCGQzBEAO1/ziY+yoAGopNGhgVYoKA6ERqoJi4uTUNMDEgEbIgIraLRZquRQpZai11pHQRtwAO8XNTHQDAP1ma6L+yr7ZzrnO9eO5Tx1AP/3089mEe0zsz1++PL3lUvjjZns1Z3FFROrYHHV5uZ4M5B4MG211EIsWyWWXS971uyFLlqL28vOXy+Xqj37/n6SnTxVQdSBQgHCbaeUeGYNgeGfP0umMSik+gVFE2rZt29Yd1hhj0zTTpKmpBmz49v93x2TcNzy+vXzhNp44lVxHzz0SX0be6fx/g+lxAQBGMIEhOshw3AmgaMqmCBZcoSAyR6kmgGrg/75QvRoSAHl/gbfdjmTFQA6Nhpu5Ch0HzICABSAOrVao2uesy6MmpRRSDIGcT8e/veuaNkUgbNvEjFKH2m+352fvPzgKxFBLrbXV0pWt9KKXZ+8ftVJ2sQ3t44e16nbTHzTh+7/z0e7Fp7q5XDEsD5dNu+j7vu97GPKz954M5y9CWXPeLFAPVstaayRyfkpSAQACYOJIABxgdWxoQ+khRIiwWef15dXV1o6OmkXbPVx1Ry03CAEsUIyMkYk33YcPltuB82U8Pl70B7xcLmcAWh6Kez9t28QYh6EwRSJSKaWQu0QM+OjRA2acWzOzVKsiYKtucXSwOohYSsl5qAZtQyzUhrYNoeZhu1VVTSm1bWKOgiCIXgVWBLrNwbG/3veHzOi4msBmUO6+3HOEG4vlHV//MvKFauRLBesj4NlXLwBcFxHVXRdyfxYA1P/bK8LjbG0A84l4omCpaebD3vgO75QF518DN3qqEiPjTRS0v9/74OdOXPebQTQaoVlRg1qLIpQyDMNut/vFT3+2//HxCerZ+lUpQ9/3m81mu906n4aIbLdbESlDHfJu6IvHc6p6fn7urqFMgxHdFh4dHflPcoTOeKEADo4Ob90d16tOj8qvdYWJmVd4iYhxbCkGgBCijXYRDZmIDADJzi83aqXWWoc+l77mUqtKtf/yX/+v/+QP/+Dk+NiqDEMWMU6JY5gGdd8te0Gw7T95e+n73sxKKbvd7uzsrO/7EELbts+ePWPmtm0Xi4Vnod2cBUMzGs0rKFSrqCggiZOiEtDNRwjE9rr/BuANvLfm5sIIKLxOQsJrm+S1wP9uZ7zt0nq9Tk1crVaqKlJNsZQcwjjzcoZo+VJ2SgcPGuYQLYRQVdxHVRsrHITuwNrr569w57zb698CjpDEazzjfSrgvm1v0/H3y6Vwo68abz65+/j3q55rgAYYAZq31SU2sbLkcH724vGD43/45EVsUhZY70pz0Bx0qxhi7reyG9o2Ha4O5HpgO8McKBim2Nw6eVMwgP0Ot/m+K2q2uul3CE3TdUbdLvdFY7c6GXJVBCKokndD3qz7bnFIRLXWw+PDoWRDMSoXV7tSrr779Oj0k09P2rZJrEV+8P1nL09fZMm61O8+IqkcmQ1qyZqODpF4fbW72u4+XLXt4qhddBxStUWttao0ie3Z4cuf/83Rsj05OVq0ETGSaeKwiF0kzpt+d7nVKgddtzg8OC9X3UF7eTFwE9qHj64uz3Y7e/DsUR3yy8/P/4s//tGqbvTqrEFsuwWGQGbxuDmmQcv5H/3gEQbqs4YGtn0JIbbt0d/81d88ffre5nLz+PFSBUtuVW0YhlrlvQfHFxdnjx483G6ucs7LZdd2acwoEPbb3cV6vVqkNkAp245wcbTY5SFEODpa/fLF6cWr0+2V/OCHH1ytt4+fvvfy7Pzhg8fAsDNdpoaNqvQExkxFBmQgADRCU+cxuIYHIRB77KxqCuhcDRpC8Fxk0ywAoJQSI0u121oeboDtb0mtGV5TAojvXF1ytNDeJpuf3f29+7oI98TfTehsTNPeBA7cbTJgbLIYVcCYhiqBm1AEAQRBEAzVlR4arFI6/eST905OUow///iXFayaZitnlxeeiJBqeRhKKVINAJbt0mysCzCyNwsZWkxoJk5FPqf9VdXnFYYQxjlIfb/b7aDI5z//mQzZje7FxeXnn3/+/Pnzq6urGMZ9aiMflppZRSlWIdCyW61WK1ebbWoODg7ato0xNqFBNMS4Olg2TcMpPpVsEzjR9pjMU2zRuecATLWUMgxDLgXbKAiMxMyBSFVrLpILLxbb9Wboe2YOSCKiVSratlbzGN1MahYpPi/i008/VdUs/n1ohtWUDEx7mu7x0xP8l//izz547/0Pv/PdDz/4wfHxcb/dNqkLqQPAalpFkQgN1XzOIRICGZkYM9M+J8+0SO7V23b3Oj86Onrx4sWnn3764sULAPCpzMz85MmTefIVTNNaiSgoKsLY4KaoYHuPcNcjMExe7hc/4r0DtN9VZndPRHLOqhpjjOkW8/5tMzalQKcIbN8a7T3i/b/iN11wpBVgwLE7wgAYFFQZAAgJhVQRDSEYkgDkUndDIaKQ2hglEe1ZXwBUsAAACgg4K6lbXsL9QkiBwViMTXQoWsvYxoFEIRIQAXIII67q8vJyKNnIODGwAzAkEh518dGiXTAHaN8/Wsa6AepqiR88XNaCgRo1LFlT6ojTNoVThpBS6kLTMgUww6JUxVJKskqtdd2yfXDYpcRogoAk2ja1wVCVm8JWbNVym7CCLYJAEE4aozVBmQGQMcSU4KhND6CCpZYgNOM00+0iHHZcBwwtGhmBxWhULQTrIhy19KBLIefjxKp0kbdI3AQoYAuWiroMSgHP17vUhQ6SgoizHrJqm44OFym2sg4BpCMFq1oBFLsYr0rOGbpuGXSsSMUmlQrVuezHHJI61sYhvTcbhOnmVrAp/B2zQzbB7kopODahTSS+o8wH+7Ylqm/3UIya19NEdIMe24DG3zyFX4BoigJIo8mciETGLQaA+v/+8//+5WefHh8eVZXPXr7IVk8vzs/Wl6ltDUfTZeLlHgRw+izVaiXP8aV7PNlRvk48GVIMxIbASBQ4hZjaJhA7wSqBdikwYEppsVi0q/ajwx98+MPvqep6vXEWo1p0Zp4qKrs8CBiqqWrf9wZQVa42681mN76/VquOuGZF1eCtRGOdaK5YXZxe4AQKG3PIpRbQde4Fgcc6B5qo1gpgDcWihQAChC41iCilZrUcmTgwE4KCKJgAKCImDgLGzMiEEAyAAQGg44M2IOru8vLqyZMHH3343vvPnj55eMyohMCAOBbjwccX4vUg6juWxC3r+yVyrDFGZzH64IMPVHW9Xjtx0B0HB4DfLCpKT2+a2ew+MHPJsgf/uQawO+GIf3DOXX/r1MC3Q+Yr5onfWuswDCnQou1SiKTqBb+v6ruYoxqbWc7VOSUUxxID+cQ0H3gGICLbDA4dTK3nbSDnmg3GfE6MbSBP6bSLZuitWx7WzGhBxRCkaZoYGjQYm2tj5ETMBGhiIMaEKS9WDeBi1Z0cHDKDaEE1MEkpJWqRuSrUqhq5JkALnGJqGk4pphQ4OVxZ1IipaZpVJMIaUJm7ChBSaK4WsWtj38TAhgaYEiaDGjW0EpbQLrEtkFtoFHTQHGPEgDlTF22I2kbALp6dZnTUqQaBCkyBQ0PSpG5ERYCNrcMAtda2bS+uNoNA27as4gjMlNKQ61iq92EUI4kDvuvOmJOfOo58/4KewG/h1nvdWQe8t27mGWLdU6NmZmCCCAiCIASCAACGygp/9/d//7d/89cHi+XR8SGluDxeHT04Wjw4SLEV0cmj9S0HZjZNyDQR01JV1ceJEKmgoJo3qnkdV8AuTs+AKSCZE4ATBkajsFYpUvPmMn+eSylOdFNrzcPIBZFzVVWHQdSSySBOkHsiTCkFYlUFxdkAo5qr0770xqjorOwjA5WfdgzNDMl2q+yNAIeLThE8ogU1ZcUQHLTWQkjEbduuukUIoeayq/nz83MAYlMGH/Sr5GhkKUiIzgpmYIRIARFPDg6bRHWgmq+Oj48//PDDp48fL5qlChGReVIfGCYkyluuCre+NtKrvIOUUtq2ffz4sWcmzs7Onj9/fnZ2NkOX4Gb0/BtjgOd6g2eVAcDMhmEAu5715u/cTyjBXrEKvpVa4BsX17++Wn2bqYLjCAqHyOkLdeu7CCFACCgaRSTnmnPNRYCwL4M6I73T0tqIgg4AMcaU2rZdpDgybMBWjibodUpJRPq+75aLodRStRYDqyJWsxAVBK61NMk3gLApWQEzQgjIpRY2SMgdx4SMZlhRVWJMTBGYIJI1JKgb0mwDMjFHJ8ogDACg4/yZHMUQGVk5BhIxM1GNqYWIhiCqJMRgWA1RV9yZQCjMlYIEKoQVySyadIFCCD1CChZJUkDymRHg6Tfi2IQQxTRYdRLQnLMnT4lGoKdDrL1ThMBm8sh9BCZNC+BL1GGdK3juUYZ5D96zVL5tW+/1CPhtPrKvWABAANwvdes7XlADJA1dLFLOL15dbM4vrs4HgWyQGhDBWmwagHmt3a8pD6dHAq+DgpqYASKIXucWDhatu8s3UtMIG60WnIwCR8rVGJgpBQ6xUfUOZo5NIgwxM2tdpAhTUbltG1Db7bKUCkpmKCIpxBijVKBiHB1Q4vZszn7hatn5iU1J6ZH6Wc2cPNWmhDWDh8LCzAQYEKJpQ1gYS5bjZes4bFBVq6hO02VGk6NIBOYc14IcyBQUy5D7HhBxtVp1XSdFGEfOu7e5s/Ba+PulZbPZnJycmNl6vfbzQcS/+Zu/2R8kCnvJ7d8YAwwz0ADAK9jb7fbVq1dPHr/n9nX/Ct4yt7MB/kptyW+2zNfB1/UcAYsINdGLr9vtlkAXKX21Xdd+m2qVUsYCkqmpKjISBVXnwzMAqKqpHZFHzjUfAhSVutueNA+YIxCmtjEERxteXFCtUAQIPdYE7/0zMwNVrQYG6ryyhmgKKfe1DNlEsCpUAVPLRax6gksiVFWLrDxWjSKFWYgZOIwlWf8iREQGILMqoFWlqlaRolJrZTFGwmIRuGsWpeagoYEmQgwWUJjICIUQmTCQMSqiEQMpeOOgiFCgGFNKbc5ZSy4sYyp4Tv/AyFrTNA3tmQ33VOa0oatEePdqq8u+QvlN9G5vne34nwZvjnhu2eCR7QlJUBVvANU228v15jwiLBaLwEARG7JuuZIMHimPaacpkRtpJF3BW7jFkqdSb3CXlIjatn11esm+KRUCQkpspn3V44OGm4TI03QEUFEt5fjgwCHOixC8DxWAlJSqLRIBQHDnGGqRoqWeHLYAkPtcDNoEh6tW1WKo7bJ1ri5Pns+3HqX38wcABJqLxMNmaJoQUiJEqRVEDJCIay4Yo4psSpHU2GolIv366uDwYLS1YiNtJyIjrlaHVaXWWhX8mpuZgJGKVhmGXVFAxKZpQoibYceJkBiZDZkmv/ANEe11FmRvSRi8cxba87IA4OPP27Z99OjRe++997p5cvmNMcC0NwzHpe/7y8vLx4+e7f+e1/fVvvX9rQG+U0ayFiC3u0RNCAFMxsbTGL/abxMzESu1CiBzZMaqJYTAkUIIQ67iIx94JEMWnxauioghADPDFA+WIkQBjAyoXSyIqOSqAhyd7lKQgxIZuietCDDP20UAQxtUCyggAvE0RAUZ2KoJKEBVRgwciI1DIApZA8cQElJAZiJiBg81WCIim3mrLjMFQq4qVaXWLLUaMRAGixGCZavZsfYRKWWjrRho0RCUuCAWA0OogP6PYwAmIAYaWSpBNOfcdZ2H4yGM2D2ddEeMiQFWq1WWOgbEU4MZ7MOYwe6khnizzHXE/QOq6n2dlveFF9/Ufrz7e+8/l301QlM+2lu/bJpfa+j0HYpmKXAA0AJahohgbJsB1nldBogATcQQia65NUwRSxEtwAxNO5YStWpkIqKmicy425VeaxPTYRcef/cpMwKQSImxiZH7Pp9fXr643DQATdMoAoWYUgKfNBDC1W7HOS+Xy8ViparDMDhzZiJLIVKbxmU8pUmk5A1opvzwaPX++09TSlfbzdnFmRvaWq3WKuOKwocPH/a5Si5G2IQGmGqtkssAsFwuHeFVh5xzBjNmllK71Eit2+22bdvHDx4i4tllW8G8xkzAphURIjExPHv6dLvdbjaboVZAFsNaa69GgasJmkWA5WLRtm1IkQdBDsA35i9NcjezG3wV1hcADg4Ottutqi4WixjjbreLMf7oRz+6dRqj+/UNDmP4EuI22NeGEw479v2WzEpBbw63+qqSDP8zk9n1w2lcoDmJGiABppQ8L/1VBcFmpgq1qAiAcQgoClIqEzMHgCn7rZJAEVFE52g415ILIHJqOmASsJJFVYuYRwY555ojgYZEHBKSUYpmNGBPRECGiOzU+A4jQsqsJQYikxgwJnYsvMpomRx+wxiIhL1gyoakTudo5lPfAMiAqkrOedDMfTE2xpaZcik1F8miWTUBAQMwc1pf9UOpi9hZ0+lymZuLDaEoxmZJgRRgQGgwDRwzxUIlU2hCQykGCgBgtUjNKsW0IkZmJhpRUTbNg/M63JMnT7JURZ1JbGCvxOWhsNq9hvMLF8/s8k9ZtXfrAvimZDaosLf436ByPeDDW0HwlB/1xkU2AAA2Y9Pt+VlQWHa0WrRFSrtslY0pXr66PFgcHB2uPCFRSgY1JEtMfd+Llq7rHhwfLRYLMyvDsGiXkUOTOgM5O724vDpfdKvHTx5eXW6IQQVESwwNoL56eQZX9Q//6e8sFgtEXq/XwzAAQC3Smz04OXleijXNd77znaPDk8vLy7Ozs2qlWFNRfQCFSJa8Y+JF0xw/PBn67ZnqwPre8cEP3396cHDQ99u//0kVkaH4WBAsWUREFX70/rOrza7fbhWgjY0ibLfbdR0QdBXopEnMvDPdlEGlognWmpqoaBW0JVilgIiFadCM3ghqAlZRNQIz4oePjk/PgWvfo7obOgyKg1jAOlQzjRGapmFmBGaOhMFbsWH0lO4tjsxr4M5F8q422OsyOs0Ldb10dHQke2Oj9lfdb4wBnmvAvnNSSsvlMsaYB5n3w/6mgmmPzVf2twb4ddm3vi7z6gkhRA5N0zCi14d+9a8buYFUq5oIIHprgpmwASiCmOZa+pxrNR1xooDIROzwq6GAqiKRt0lAFQRStaKmgA7HZQgxpth0ZIAhVjNNXfHGMiaieSWoAg4pl1I4gKSoKZACIZGCjwMWEFRDUDG1ChWEjEWsFiVSKipVRVRVc642yG7Xr6kPu62F0HQGgFVrzVKz1KpGWgMRklDaWV84pK7jo0M6PrLNOjcpF1BulE1EekTlbuBFT01ByxgsBm46BjO1WouUClJzziFG8w4hL+ATuVGsQwGAhw8fZqkvTl/MhJ23b4rZl1M0YyGcaKYTZ2a9h+/+27b1bukKf+XGhMC73n+N9Z8s8AREIoAKoGQaTIPW7z57ekT23uPHEfXl6YvYxoOjg5OTk7/49//j8eHJg+OjGOMwDLt+a1UAdLXsdrtNKWWx6J48erRaLUSk3w4m1sbUdZ2ZLW245MXBwfL9Zw9+UTaOSAVoHF1F2/NtkD/6ztOuW5rZxUXc7XYI4+Cv1WoRryIR/e7Txw8fPnz+HD8t277SDkJfCzgXpgYRWS6Xx8eHy8VivU6x769kWJEdBjqK3At/79GDWvMwlG3f932fc621qtoP33t2eXl5edmISOBUVM5zVoDlanlyePDg5IiZdzFcmA7DAGqCuGoSJgtaF11zuGwJsO7SAUXfdFKzzzEOiERw2MW8wY2paA3MSIqmvdZSh5L7WjICkKn3a1XVEBGBDdnxWob668m17HY7p93o+x6mbeJAjdeN0RgB75/ZrGdngzd/wJ/c6EjZkznKvPV+Vb1zHvC7pqTmIAwRQwhObA0AbdveecIz0s9zZfNIy/2vuPOHv/353PoJ9mV6/O+4DnNC710P9U7iCkVqjTGVYl3Xnb64Oj4+3lx9DI+OzKzWmkJU1SwCANvtdrVapdTmWkxRzS4uL09PT3/4vR/CXZd0vp77fzKlPufV8YP1+vzF87OTh8+Ojk9ou6MYxOr51fmrV3nXZ+QYQlCwfhh+9w9+H6YsVq41BNj1fQysAtvd8PT4JEstQ//s2bPPP/98sVgS0bDbDaWEdmkhCnKlkDEdPX687oehFqbAMZhZVQGQ4w9Xn/3tX/3v/vV/efrp8935eZfiMOSO4/HqcLPZoErNu27ZGuHp+auD1VEttoMdcyxFqFYKnAUWIXZtGHYX293uw8fLvLtA5NOzM45JoHShQQVQUgiCrMS/fHkal0uL8VTrC6n/zf/2v/rF//P//tnLF8++83656k8vLwEgNIurnBcP34/HD0+W3fOz7VbJdn1ESABswAht0xhz3/cxRpBca12tVhlABcQ4BEsJVqvVT3/x86ZpVHUc1T7lh8bJAUQBA5hOAd08Bwjnf/tppLHyZ6iqXpk2Gxf/MAwIhmg0TV/XPULN19fD/mq89cq7bqX79st9+3qmB3C9MYJUA3v1Y/rfeBFwBIvf1p6EzGIAxt7Qb4BgASABPlkdHIqEOkSm7z48Way61CUpu+89PDo5Onjy5NHl5fl6GB4cppxz23ZN5NItTl++enLcfPDsqJRiYhlJi15dnD588GEI4fN/fLkA+/7TDxmG947a09PT1Wrl1vfy8vIHz04++8k/HnA9bBAA81n//rMHr16dZasHq2TWd9aT0RLyCssWyyFLixgMD7vlDz763o9//OPlcjEMw/rl83/xh39wsFienb2izXr76mUYdri9+v7v/OCTTz6ugSuFTS6JsMRwudsV0ePjB4+67kHT/MPVWglNa1mvH7eLDBeA1l+cSZuOHjxQMtbSkDFTAbG8W7Td1bBbHK5agqZJv7w6T12KiU0FQSlQ6QdTXbYHR133ed9byV1kJBDTSEhanzx82A79889fNQk2m42ZUQxBOMSmzyNLfKlVVLzLOQS2Cby9v6phDw2Dzq4JZiO9xR2ie1Ss+7rOhW7OEvX1NreZzF058BtUA/6tfH2yv5LKxDg2EWH5zC/PUEkppUpFwJDicrm8b3W++dtMEZEVMRfphzzUkksZ6lBqjRw8fEOfLsiMiE3XcmzMwNGRMUZCkGswAKqOPcnV1JAUoF0sBcPZ1Wbx4NHq5PHz88t0eLK++vwnP//87OLCAUrdYtV2vP3J3xHK86v1ttbPX50edcuD2FHTvFxvG+aubYeS+6udkXHFZWzOhx0YmYFOXREAAEYAYoaqUBVM3SahmQVgNkrctU0B5PUuU2qsW/QYFkdHFvjFZ5/+9//2f/irn/3kP/30H1/8+f9XtgAGR8v44MFxDLhatJ++PG8THx+eLNu0jIkky26XN5t+t9v2/WKxhLE9aUJIAIiYofvW4DrIps5dnSjxUoykgQzBqunr/MdvK75GJuyrmSmizRrNz+0N3uqvJy65T2affu4PecM7fYzOrGQRkQHJDA1l4hNjg2AQRUOVFrQJvEiMaB1jROu1PFyEwwYOggiJBe1isJBWBwsy3VrZQG61LlGErYKgDojIHT1oAzAcsAnIAVuz4JADHzZNILEeBFrMHfJBBMLMPAAQQK+6DSETmUgVEcLMxEQ9UQ4hh1CtalOMlJNpVAkiqrVRS1qTyTLwUdssA0TJOPShDkuCK83RzFAiWzUSpmrQERwG3u5yyDlXZaIlh5j4uGti2w2lbwhZC5smMgBmxoYb1coEKeIixcBGKlJ7tkCKVQWlEvn8ZGAEUiFTcmYxJ1NSQVDJQ7/dfPeDo3/yh7/3ve99QBhUIaRoCObVIkQDAhhRim+QO/NAv0rmBudKEOKcf5pTL26Mf2uAfysAE3iPmbeleMhyay3O87NqrUyMiG3bfonV6b28RsjMbrEASNWcAy82IYTAMSIHZsTACualnVwKEYkAhuBMBRWx1FrYiggBoJkofPL8Rc3lcVqEZQftann8KHQHL3/5+b/7f/356cXF+eU2V1HVYdBsAACHSyCCTz7+vz579LjjePSjR9guPn7xouOAITLybqigtWuSQrBqZFhNTdWIAAiQDcBBXmJaFVTBzMRMwUghxkQWzciAB8WdWhtiXC4fvP/BX//k73/62af/8Iuf/cfPPvnZL3dCgACrBvveTjflYvPC9eiSIQD86T/98PHR4XsnRwdN2ywIEftSaz+YGcz1SDNVdYybsQGAKgzDEEIQGAvA3hVqZgBoZqWUPGwlr4+PFu90H/cj2jn7baam4kn+2bbNcudxvikDbNOUi/3z3E8y3xLXnrrH/QTjRSAAJQMAAqwEyqZsGrQy2opplSJCjQSgpUoOsouQumC1QRLumigii4iLZgllx1I8RgSiQbFIQQMkZc0iNUJlkGAlGi0T0bIh4N0wxJQiNV3THh1h6JCWhEjWaubBWiXgYTcoqTYKBDVWSWKtQQdYjAUaxAYgSAlSHDcWVBLaMvFhl1YpRhOqOVhtGBaEZkqBM1hFyYGyakPQIAwqAazWgUJqQ0gcjhaLdrW62kAwQ5Fg1obAFDiQig3ZIuGibbo2BUKVAioGakYgaqLe2cKIKTCo0sgDQ6CGoAaKalKGq4vzP/ynv/d/+j/+H8SqZzpTbAzYm5X3b+Ib9JXd1RHg++rO97++sG/lb+Y/0USusN8HPL/ztwb4t3INpQkh5Jy9sxAmNmZPQU5tMNcUSPba+n4bSbHti9SixJFDbJoGmPq88y/13nmOAYAcxFhr5dgoWM0lhODNBiMbrSPyKomoAgJIEfvgg+9VU4rJOBHKf/r5L//mH/7xP/zktEEoBgoQCQJBAkgIxLDeQBPh73+Wh90nm0s7Pbv8wx/93rJpQgwbs37bXw3DQduuDo8uzy/W661QQANVEACCG1fAFERMVcV5DFUUASkihlzsape5XfByAYvlxuBnf/1X//Yvf3yxydTBq093geHpU+7S8kH7ZFgXsVprubw6F8kcsBb7D3/5iweH8N0njz567+n7jx43q2Meqqx3uUgIdItu0XNfZqYK2+02xmhiuAdadqtptdac+74v/fZLGOA5le2x/p7cSNDduERf29ykL3fYL9EnOkcwAGCEBkYIHl1NyW4j0MBIzG3ABk20el841v7y/LxJHODxIkXSJgTcllr7XVh0bGClSi5WDdGgWM2Fifrd7sXLz0Uklz7GuOs3/iQ43kckdgwY1WopZgwaoWtSWDTKoAED47ArzGQJkUgjQDTqArfBkLiXcTw8moESGBEgGTP6v8gWE8dEMYbA0DYMwAjKBQtRYCxQQfKw29ScuzaKFM+COFS2DEMZMiPVHKUWEzUQE2AiNAhMXdMyU80FAOJew4X7iLNqmrMOvuY8AQaoYNJv1+89ffInf/InP//lz9a7bUwJEM0YkBXI4I7xVnfKragD70cUwk0Tizeba64T2ntPhmHYH6PiP0dEwjebAvqtfFOCe/UPd82813BmXfdg4Ia6mcobCKiqzpUxA3DeUoxwu946Uh8RY2wM2fN5vtMcsjhmwQEAxuFFQHhwdGhTSjNXzSS1qrCICCEBQjX65cuLZrm6Oj2vgKFt/+FnP//Jz08fHYAoHCyXTx8/fPTgYReT1hLAOIbLfnu2vvx3f/ELFbro5X/6+9Pd8NdPHj748P33VjG1DDugNnClIAiqqmSiqqZT5zkjMNgIInYUlOlMyUhV0DBW42zYNV1cra6G/icff/wffvyTvkJcAG6BMvyL/+y7v/M7v3N1dv6D934oWYBpm7e//OSTz55/+tmL52eXlgA+O4OL85dnF1e7H+qzR48LphqabS4LYCblyVtHRCI0MTMTg+12e3hyXK26J962rQ8oZTawQJYQuib8Sryr8yJxfTmnoOGm3fpVvuLrkDdEMHe+eX5yXZsxMwLzCYY+9gTUUBWtXUTCEMmIQKSaGBERQ5UsqoqAgTEwsA8MDru+DsWKYK6w2RVVLX3e9do0vOmHTT94G3ubml0uOW98mIFjkRcHlEWHYVj3sOl3tmlSbEPToJoiEgcxZGbkiEgKBMgUUkytaeaIFAMGFh/6S4hMBkABpa9ZekWJbWiXbWgCkLWLBgAMFamKF74RqunLi1ei0C667IBE0G2/KSq1aM3FYjJRH1HgXcg+lhQnfv5+OzRNs1gsDImIqvfCe1oC0etKOo7YBgWrBqbg6kgEQqAYow9a6LrlZluIw+RdkXcGMtC9ELs7re80FPhtFs/+63eWV87Pz9u2Xa1Wbds6SZa7yL+NgP//V/Z1yhwB76Uob1jfaYoIIRMT+4ffPewgEdtstrshS6W+77d9b2ab3Y6ZjQNRULs2/4joiXE1adrm6ZNngcY+YL0p3t1XzY4fv2ccr84//vj5p1fr7c9e9Abwpx+8x4APTo6+95333nv0qGWS7bYMgyE++ehf/fsf//Un//jZ4cHJciEff/rqF59dfPz8YlPrs5OT9x490CbuFM522yL18OBguyvqeeYpvzQnmgDIzHTs7BwnffSlDmIQUlocUNNd9sNPfvnJj//2J4NAaOBw1XYpfucBfHD86P3VUVgcvPzk5wzWrQ6O29R+59H3P3ySpb66uPjxj398djacb+EfPhsq/HSofHxw2B492J49b3iafLInqgqACrDdbh8+eZwlu2rYj/mIKKQUA6ISQPkSi2deHtcJN/TBczdmxXtE7s/npfWOK+etzuedZP/k3/5bxl9qXmhQ8NkU6AhQQAVFENLUtWQ5gTJUESA2ZouRu8UiNq0RFy2iyCHEpmna9uJykxVCbA3iepN326GUMuRSASqwqppRaJehXVbgQWB9dukdL0REqSOBLnXf/ehJvxmqnK+aVUOpasUKnFLDCZQiBEJiJYLQUJNCUgbgAWOASBVNrAKzhTGNXkByHSoYJYpdxIgVhZoAalQCmqIRJyYJoQ3n6wszbLsDZTAmZOo3WzNLqWHmo6OjpmnW2w0itm17eHjoo/q82lVrdcPcLLpcKofA7joQqqo5lMlzcTSOYRBVMTVFMzUFKXXYbYZ+S6mJMRbp20hGvGdUv6CJY9+puuE+vtEAwz3h7/4xHYe1Xq/NbA6CfYOY2W8j4N8KwMTFwcyllBka6jKvEI9Z3S/1iuN9I27eIG4viUgRN5sNhXNm3m633SLJDHJRVaTG+1somFmVukrLg+WKCMDI9Hr4lZkpGJohoCD98sXpLz5/dXF1ud1ur9by3uP2n/6TP/jou+9Hk7pd6/bixU9ftIgt4VGXUnf8/Cc/XWHzX/2r/40EuszDZvvv18MuNuGnn3y22W2NbBExpLhVLaYLJDVDA1VPbu3tQ6YpDL5W0wakBuu+HApAbK6G8p9++cufffrpuoemgaePT3740XefPnz4aLW6fPny7Ce/POzCRwdNybtSL4crA9Xu4GCx7JgOfv/3fvf07Pznv/zs5Yvyi892hh9/94Pw6GipU9SLgGAw1oAVzdgMFMAHou3rC5jQWCYysjm9cd7zF8peNICBCWC/RDouof08CnxrAuI5sQlfZIbVh70hjr6FodO3GfGY4fQBSqQKqqbZagBT9nVpQAYMaKDESiSIglgAEbgaFw3bXoiatDyiZrnp5dXZlYgA6PlmuzpYLFYLMyulDEoqaKEtxQyDICFgL3i5K8fHx9/7/u9eXVzWvsZMB7TotR8ytSkc0qLv+6YiETeVmxpA08IaBSCullgYK0FlgID+vKAVtEIw/VMh9ZlOiCoBzChAalcLDWF5cNiXutsNQnGXB6bULDpYb0w1NqHB2C0aIjKTEOjhw5MPPvjg7//hP12uL3IdVDVqqDVXq8xMABRCNFNCRIOKnsjx8NeAdExCmxgqQq1VBNQqEaWUlEjEAAiRxz1o6BjJL7zFsyDiTE1z30fuDH/3jbevcLe+qupTCF1h7mMSA9k4wePNjzY9H8c53jFB1/908/Vfi9w5zXf/9fH53keuB0B/0eNvtCAAoKL5eBefVwpsoEDoK9KAzAgloEWSQFiNCrIiiyGAghc00WKIRaqvZkMwuR7VdlOur5kikNE8PNUAFBApETepCap6td3i5jI2qdShxeDEQB65EXJA8lxNLuJcTouuRQPQalIojnAGARQIhgjEFY0Wq1++/BsTbUKIJL/7ve/9ye/+6POPf3Hy6CQjiNVE2KFhyZebq6rnYfkdGPTRyREtmj/68IO2of/wl3/105+/oACf5VccwtPHJ8cPHnIM/Xa73RWAQGqOc57m2CvgOJbc43Y/GSUwJOB0mXNX+oL46uriH3/xs/WlnnTw5NHjP/3TPzk6WH78s58eMx7EwADcD7u8VsucmshoAMmKZoTt+vc+fH/9+PHx4vAv5e9/eZp/8ulZ4WaQR0ecJJAxm6CB6jhsDgRMgQWgihARA5MBK3RNbFOMMQQQVVBRkKxSusgIqmNjq+m7zPOeRgGSD4T2OALuajS688k3KPN5Th4TAZm39t78+fPMUCfgZB/1q4jTWM7xbQrB4QHDMFjNigBsPhcOwdR4vem7lVUJgK2hidh2l4csRaVrUrtYxRhzkfVmY4bM+OriVbPo2sVKRIZyVXZZBVJKJ8cPiWi73a5325en55999lmuuuoWx8cP1pdXTUyBuOZqYoSYYux3u1F5q6EBATJ6IstzFWQGpgjmpKqkhoiEFIBAwapaEVGwqoUAvT0/hBCbZhHi8vCgnK2HssHdbrfrl4vYNE1KQUSGYWCCnFvVutlsRMtisXj85OHHH3+MaDUXQ0XrABTVzIwwEAZggLGhAcxEtU5DqRUATb3FQAGolKIGhKFrl8vF0WbItQhRuDaEqOYk8yPlOfmhZ72lCAQKAGQwD+8jREWg+/vj963vfhDsr+/nezxUePDgwf44Qp1IogKYIMBIAbP3iIC094o7yo47AQCfqLv/iORjnlzNkl+d0Y2wO8P/G57C7EQrXDfy72/jWz94flJq9RHQTuFtgD7H18BUbTSlPF5XVUVggrGYsP9oAjDV3Pcf9a4mZrinv3CGCeyfvz+Zg8X9k4f71RDf07942+16oxYzADY1MDMaBwwBKiAamqqJGAqgEWIUSZAD1YNHz1719kyRwaoWDlzz0DRcrQIhYBRjECPEiT1HDceyn9E4XQcAqgoAcmATq7V27RIATl9e4aLbDnB2cUUUulUzyK7fbleHLRGYUd/nfpe71QoIpWikIArnlxff+eC9g+Xq41/8rA1QNusHh8slUkTKpYoadunw5EFvcrb5/K//x3/brNrzz6+6Rv6LP/uD3/voo+Zyja9ehSaU9RWDtF3LABXp4Pjk8cPHLz49y+XKhgqx+9u/+FlT9V/9/g//4L2n/92/+ctlE3/+2emLq+2HH/3OX/ztX//uk2dDX0HRApSiYHVGNopURCxSKTCm0IsO1YzjoEwhwmrJD48/ffHir3/6k+1WW4B/9tEP/+B3fhQiv3r1fNheRj7Z7M7Cpj9aLgy4SMhFyiBG8Or5ix/8zo+6Zffys89qX3//2bMH3erP/4d/d1HkSvK/+fFf/us/+2NeHrw8+zzk/vvvPf3k4180y4XkXEFPNxcFoIj2ff7048/+9A//qAnNZnMeSQLI0K8l79qGUkzFRlw0TJHCSPAFXoJjH+cGAIw0UfQZIiAhE+8v44knAOdH/0uMzf6m2E+r7L84v07Ed6z2N/bl7x/hOiX+rgQyagA+C9kMzIv5CKYKtWrTxRibbamixDGKYQAz0yqGhAFjHGPgYubOoaMrIoCpYMnVNOWttXH5k1/8pNZ8eLBsUtpuN00I/WbTRE6RYpeePP4nV1dXP/vFz9u2+eC7H77/7L1PP/304vSMiVTk9NWrZ8+eHR4d/d3f/u3Hn7z44KP3Pvzww3/82U8/eP87JuX48KjPu+1223XLZ+8/+/jjjxeLBTIWKW3LqQtGBYPEFrlY17a7zbC73CaMbVows1YYttInuTrvQYIWAOEmtiJj/UKqEKCo7LaDFkW19dnm8cmjB0eP/vEff3r+8vwHf/aD4+Pjl598FhC5S6r1/PyUCJaL9sWLi5Pjw367WS5aBD08WPZ5ByZNCiX3m83u4ZMPr642VYauSZGBtORsJe/63TqlmCJvd4WZkYPuqql0i2XTvFgdPOgzEi/yUNrmSCSjU95qRlRuA5ghcgUzQ0Ky0bgBgRFhICICImDmxEiMAFrHsPKt4shZXZdyo5RDiE1KADBjr8bHuQwEk6/3No+AOrkIbzkR+E0xpGNZYa9wvY/oubXTXs9iAYDaO58N7uuGL3qEa5foV5U5ZXqdOPXi5dcpNDrf8wWgcSbmJIiA3jUBGrSSmXHKxhUQR5pSpyqsAKoI4xGAwPNBNy6OTqtEARTIpiKZGrIiVIOq9vnzV7u+IkeOkROnJgBLLr0XhFTAzBg4EIWQQgi11lpr0zSr1Yo9y4fW7za7zdYZK4VIjDdFr3rZVlWzzz6/WnXwz//0j77z8IFtNq3U4xCbqqyFqjNXmQIYMAChZJKedUe2C5gbqkuEAwp//J3Hu6uClK56CcvVv/hf/hd5EBNSIzH2navmUKdxXO7st6mhAFbjCrAeBg20A7sq/enFuio8O1l++PhxvdrKdotSIxuxRbZERiq1ajEwZWfilppDrUmMdsMCCfuBan1wctQ08XK7zQDn/dAbxvYAYyfGSIEoAIeihsQAsMtDHgozMxIUMa0mg2kmBEZgQKdxwte85HdPYL3RF7wpt17ZW5BTLLq3RzyPtz956WuWMWuD15dgnBI2ZawZfF4GBQDzMUhkiEZgND7OA49o8lYsiBFaQAx50DzUMtS+73POtVYOyMF5Us1ARWuVUkqe3YgQQorR+ekCcc3FRBeLxXe/+94Pv/f9k5OTpmnEtG3bl6evXp6+AkIgK5I50vJgMY4IQRWrVUvVoiCKGokDsbkfbgSKBAyKZRCvRE1tEOhJ3aZpOKBXbfu+VxEAYuCSpeYKionYNUMgCNeIvBua2F9BA0RjJGZMIabAKcSXz19st1uroKqE1rbNatk1TSQCJnfIlAxQCXyONZDA2HwPGsEYPO8/fZ3S3rRmIBgXNl3fWw+xZt2FNpk8T2e9mwOH98h97/8qp9zcc0Z65z9iUKtq1f9TtFTJamP4e1/C6tbu/dpP/quTfXUz2+A3/AS7R77CU5pLX/viyA4z2++PfE3xfbHfQDgi/eYvclN6cXHhA6vdm04pOSzw9SP4j/URAimlGONu6KtCbJIzVs7XREQu11evzk43l1dSawD46IPv/OijjxomK7mNkQjU6nTxR2KapokppVm/mxkBxhDa1LRt+8f/9I9igBDCxeX2xYsXT548WW83FHi/9nznTbn1J7+Az58/f/ny5XoDh4fho48+Oj48yv1I5ea/3d/szLrzuMDqNH8CAODTzTabTSnl/WfvHR0cDrs+Mp6enm42G4eVuvetE+6DmRFgu91udxuvP5VSzMzL/IgWIiEZeBMNquvNie5AZ0Ksr0TuW8/713B/Hc47Zd/6vsEA7yeWbiWZvhLZb/+Fvd6BN//e13+OIy2cyM8ztI559BXu1J7mDWJD6fuBJmZv3ylN0ziQp5Sy3W5F5OHDhw8fPvQ2/VKKVFtfbftd7nd5fbUNnA4Pjk0xcCIMYCTVatFaVAXARuil53gRccRnqO52Oz/DW9fWI7laa85ZFZhCSiml1Pf9brczsxACkiFZGNub7hXcw356ejbGeHp66ktXVVWgbbvFYhVCIgo0yjV7o18rEJi35Hzx56+4dVO+1M1/B6F75L73f2MoaJxa9b3HS/UGWbyL3UxB33P5fk2V5l9RXlcKX0473LeGvtzRcCZfmxRKjFGkqgAzm2aY2n5ut5rCHhrAU/43bwSOwFf0eoz73r69U9MAQ85ZRFNKIXXMLNUQEYn9Rnt2pJSyWCxcB9VaLy8vc4GmabRKRI1ti+yJJru4uPr84nwzbPMW/vj3Pvi97340rNfD5cWDxYLQas6oMg0xBWaKMcW2CYmrQVVAA3IGbKSUQttAOjj53R/94O9ffl4K/MVf/MXKoFZNKQ19Nrueqn0rh2F73qGqqkG7WMTS/91PfvLq4hwBPnj//fefvVdrJQYQZUZEzDnnobJCrtmoAQRFNe8kVq2m0Wi77RcHutnsCvCTR09fbvufvXi1WCxevXp1enj4ePXMAHbDOBLOiUo4NglgvV5vt9uD5YoC5zqYSc1DyaFNIXJAJ7s298Svf8t1buMrUln76/Z1RTmvmfnxFmr69Te/LrhX03lz2PEl5PUDur6/7ztetwE6sRKGwH2/rZLbFFWVaHRDAcYEuOrI419KSV3jB4lx9BdN1J/nnNfr9fHJiaruht63yfnVZYxxuVyu1+ta6/e//31m/uyzz7ybAKYJAb5CzIyZQwB3AtzVJqJSxBucVHUsIE7DR/rdUPL4QUKOoeXQmuF6e1VKNbO5l3ecvnWzI3y+R/vGad9HMbPFYrFaLnb9Vc657QITTRVTnt+MNPKomMlMxOYXSvdcnxu3RL926wv36+H7Vu/XHwHfI6o6k7n7qFefnOUyuzP72+91l/nX4NF8VTJbuP0nX62OeNfzmZ/MQtN8e3eG/Dq7AZ4+p2+pkm/5GXNUPTu8M1eqy/7VuHHTEZyRQ1WdBgSBASCkNoZGDMUAEPthuNqsRUQz/N73vnuyWly8ehnAgsHVxRkjwPVES6lWVSXnwcljZ6NlUsyMEQNRzf0/+f0/kFxWDXz26Ys///M/Xx4cDKXO+3y+PvORr895L3QzxNXh8atX55sNtC0cHR20bZJcArFInZRazlIxsO11E03qilQtS2VmMKq1WpUYwsGiW7UpMO56PTu/EDPgINV0dCTG9RYC7Ha77dCntgEmV0yllJx7ACVCAFWrYxw8Fmhs/9+XW13vKne6p7eE3kiagV9zBDySRU9MRvO6ve/9tyJgmGLonDMibrfbWmuM0S1ZjNw0jfdnj28Wc3oTmvlwEF1b+ibquo6IPJkEADnnpmlCCKoGzKFpMIQsst7t1rvddhh8kKcRVbMsMtSap1wLEXmTIU28iaWUYRhqkYkMAEXU4+bLi6tShDnE0MTYeDvvbrcrpfR97wbYHWi/YjDFzfN/empn3/rCVI4spaQmHBwsVwcLDuSOgpkBUCkyh+NIe+rUa/U3r7YCAOH1mMhpn+KvxQa/k3xjEXCt1S3uMAyI2DSNr4P9LNOdzi/uo5x+jSf8K8otpbCnr+9+/7v6Fl9C16B3E006y8GQbbu4vLx0KL+Pb+fAUxPwjRMcLz9ORXO8Ix7w0fKq1R3hJnVEYmZM3DSNaBGRPAw55xRbEcEJejOb6t1ud3B85CqvbdvIkHOuQ1ktO0OSKkyYmtaZpWPkZYRg1l9eRrNHJyey3pxfXi26BmysfXgEoLXmfujXWyBUMBOBWkspDMFE0KwM+fDBSZsaapPV8vx0WC6X69Mzntp+9k3EqGj8uuwZYBUsRZ5+8F6twAwHy8BIWisx1CK1FEhsZqUUM0ypNciCODE6A3IAwlKrVlutDgEgpWRApd81KR4eLM/OL0PCi+06i0byDo4AAEyRiQoAMzi1WYyMiMAQkERrKQVMEKPHFgxzB8O0s77qPoZ9BwWnMOgNPuj+fpkV6Nt8yxwBfwUnffPI1zvXYd7jN939/v0IeP69IrXvt6q171VVY4y57GAyUUQkVlVB6timQhSI2MzcDu3HHvOWdEbYkXaqlK7r1uv1brfz1NHZ2dlut2uaZl6lMFm7WmtVQxGAcYPPE3tyzmYyucVsiiJWSh2GstvtlosFUySCoa/FtB9ktxuQQ84ZgLyG5R789CvGvey63Q3tvgG2qSpXSvGZxO5MZLNaNTIw8263K7maTXvN4Hrmh43rFhGRCdnJOvbxBDD2xr0pZ/HNyK8hAtY7/6lWIqg1n56+fPnyed9vSxm22/X8sVvW987w9zcoAr51/reKFt+g3IozPM3lrrGI+IrfU2duxt5w2tcxwRy1+KEQ2blg3HPHafywE+LMH/En84VyzTKUsu0HCoEC5CpGCIQGIApEITULpLQbdKjywdNV3WyGq6s2MJua1iaFENgLWmKmcN37f3FxgcAApAJStOZSS9FcrOREeHl6+t2PPvDIY5HgarOt4jODbtT/Xq/x7N/i2KRHT55ud6AAjx49Wi6XpQxaCyOYCRF5pk5VDUEMDGGKTLwMT7XqZrNp27ZWWbbdou1223Ub+PHJ8W4rsWkut/12yIYERMih2ojZMTP0o6liYB3zjcFDEFEFVDNRHUs/nogmUALF6fGrWWT3g1P2Be5KdM0G9Q3W+tbiufM/f0XZL/zvOaz3fsUtP2B/PXuBM4TQtu3+ylHVWsfM89TMiogoVWuVWkXFfPylGWy3OxE1BSL2+SkpNqbAFAnDbjvkoTapA6PddgicwKFhwN5GL9Wkmo9XUa0+x9OjbUR0jxCAEMb960XfYSi1jv0ztdZhGPq+d9oAdwJwApHUWv1+wuReeNILAETE0wCv332YSg/OluX6oZRiCv1u8JT4vPuICNECkn90ft3Gs759a8jeobPuS8udC/gNev4bS0H7XSmlnJ2dvXz58vLycrPZXFxc+F/trth3/5Vvg+l6J9kHP89Pvm4U9NsLTt59CMEMzdAUdSJ7u+sTsy9lgL60b4Pex4lt6NVfIAoxpuPj4xjjXKd0TbRarWYEyuwR+3tijCk1w1AuLy9rrWYgYE27GDGoxE4mVAE3FXZbffb0KaqQCtR6fnrGBI9OHpRShmFXSjEYdYQHHGZmbsjBVFWraKkqxUpJkU9fvvzBR9/rd7vNZhMb/Ozzz2OT4GYwNPv4+xt+f+MdHhwvl8vBIGd49OjRg4fHYDLkPgRixhg5hqAIolrFHJY1wo50vKBFap+LAvnYwa5pay5t4AeHh2JAgTcDbIY+qzcBq0dLzAx6Ta+BiICKTBTYEMRGPNEI7H2NSGuuAX9VOut1bXun/oWbKYS3d1L3fTh8zZ/71WUGx/l/zqng+95/y3WYXyGi1AQOGCO3XWJmn10xY81Krs4oDuBzgNjN9vyGGQs2J3Xd8i2Xy7Ztc86LxQIAzs/PRWS1WqWUHJ03X+r9K1x0dLVhL39wnexF9LZgqVarLy1EYDOPicUMQ0gehc+/V6aZ4vNdmE0m7NXC9/86vofBXXxmdANcsgxDKaXknGtV03nlmJeBwesmtp/GQ/P88wxnn+7IV7AOvmq5NwU9X8F5t8yvK95Y7v7kvp93n40ZhsEX0OPHjwGgbdvNZvPq1atHj57c+X6Pk+ZLPC5rRACav2B/u967N+7BUd5pZuz+87/v9f3jvI0i+MJl8Zba5M7j2P3c9yEEKQWJqkjOPaW2aZp8sQ4cN5uNf9axta9evTo+PhbVEBJTqmoylCqKTCEEp0xFxLFii+YYpdnTr5KJSBVqrYbEzE+fPs2Sz8/Pr9YXRIQMpRRvQApxpKSebXDbtiJydHT08vknVS0kSE27uVwvls1mNzRNm4u8PDt/+er06ZMH589P29RYlSamRNiYicjFxUUIQTCqiRrUqmhCBt4Ivdn21aDWahVCCAFMh4GN1+dnTx8/er7rv/fdj37605+oWjU4PDy+Oj9TVVBJXbvdbjebTdM0FxcXi8UihBEgOtvjdtEB4f/tv/t/PDnGT89ttVzWWvvN5r3D43591TXtbsiqWkpdNI2IxKYzx5GmkEsZvZbQpCg+6LsMeZ23gUCr5O3V8QKKWrdKn798dfKd94zAkBFMRFQwpfZiB//n//q/7oehz8N6s+mW7dX2qmnSarXiFMUQkDkmotFEE+LslJsZAtg9QfCt9faFq/SW3zw/uW8f3bd/73v/nZ663U/Wdt++G/0SVQAFNQBDJAPlxIhTrZEQAc1MVCOT1BpCREQpBRmJaHO52e12TQOr1aoNuL44L1IBeLfb/c7v/PDs7Ozk5KRpTojo4uLivfeeznhj90qJQs51s96ZWd/3zHG76VUtpXYYSuSoBKoq1UqRtl2UIgh8cXEVYwRiMWia9vnLV54WrrX2uTxp2pAaZvY3GJIC1qIURwRG0zS73e7g4EAFatGUwAy3293x0QkiI3K/y69enh503cuXp03TLbplHuTqahMTNqndXK2Xy4O+73WaEu1QbUTMOTtkTFUXi4Vfw+12u1wuHcDvW2akho682Vw9e/LYgzFVLUVVdRiKqpr5AsMQgpgGg5QSEYhIIIptky9Od33ftm01J7ZGNTNRMyP0EHzKTIxu0VjRr7UKiYAoAdGo0whJq0w8ozdW+Kznby3pGSXw5mU2yzdWA55hOH63uq5DRI8A7pS5nr//ot1PoXffL7+P2/NuA3bf2fwa5Q1G9Fc8rD+5tbAQkZBVbNaYU2KKhmFQyRzTommYQPPQD1tOPkXHD6Kvl1jMxgKNKQITU8Q9xOP81cwjAGQ/dCCirlvUWvu+93cOA9Rau66rKtlQLQtWMuxz1RTVQxMUGEtuMnIzG5hrTDBSUlQwtCqqYGRqpmDsSarJ/pABG7DNvwJMUaZ7oRPDHDM3TcPN4tYvmuX8/PJivR6qsZ8bmJmWMvhg+/ltijRSzs1blxAJgRC8RRQFjAAIDdiAwCJhCrxVVQMBR0yR01EhqlRRJgKIKVUwZFaEokIcgUjBDMgQFEGLmmgaYdBIcINV7r4y8L376x3X6tf9/i8niPj673unr661UpdUdRhqrRVpxFvUWj0ORASzMZ2rqn3fl+LhKDoKGgCIghk6asHTxbVWArwVHdnUNeAveq+aex4XFxdEtFqtfNrY3O+3r1Vev5VzoBxjs92uU0qIfHp6PgzlaLlijoTseTIw8tN77Wg3SuCvZzheT37sx1eA+2+gye/aIydEZ+oyBEMdC7zXX/HaExeCL0A2eCCxf6r71xm+huX36zHAdzitzOhJyxDIcYCIzdHR0X2HuGWAR2WHX/kF+bbIbITe8MqvLtfpDUQAR/YHIiqlOPJfdezozSUrBmIee2orqPe6XB9rHyk9FpNMb59tSqnCDSZnsBu71Kah8TQNaPLUX9d1XbswgyLWpShZCkjVKoAAnKtgbNx4uj7KoCZKKoAKBCElBVIVMBNQULJqWsEiKqJ3WYAZgKEKKhIa21gKNTM1UDAZGZJMRbC6k01N08Suc0D16zb4/PLy6upKFZoE3v3MSCDK18nd+XPkMZciOI+t0/I5UY8rRFRDEzBD0IZp0ab1TquBKKghINpYog6qg5kxQNu2wDBiU/33q/VVOjfQyAZUVQITKwCiTtx2hvg2Dd/fEvmq9sW+6b1lG2DP4N3pbO3LMAx01Kpqv90Mw9B0Y5K21IFD8uOZmUhBxFrr1dWVTZOVAUCqmeF+0bQ4CKqUQLzvpMLkDrqJReTNeleSMEWpdn52uVqt6CD0uyzVMDE6N6bRvDfVRLXORtd/rv+1aZqLizOiBRF98slnZchEgWms5poiIoOhB6/7Yd8srxtam/qh91/H69SmzdGp+x8+HU2qecBmKgA2Vbf8dtww6orgrJq3YgFyxOs9y+TWLb71p1tPvkL5ug3wm2D609g7s6kI0TTxvh955+tfGOD/povtcVt+rb7GvBmYmTmOI4Fx7BZT1VKkXS3atitVN1fr3O+6GLuuM1TAGQt9++T92ADmw03MjJlLNU+17X+7VPFYzsXLEz6fuFl0TdNkkhhjbMD9AwZSQDaCES0ciCMFKlWzCYCIgaiiKYEq6qJtTBwviW6UwRhUR84Jr4l66RsN1RhBDXByElSh6tx8cgOSM//Y/dU4KhQKoFqqIkHbjkW7GCMxgBmgs19f52YR2Map42DorEqITIQMyM7+7wV3NktEXdPKdl3NBMx/k09hwtm1cjwLJgrjfLdqoEMBFWaGRROJODUMDFINYaTIMwKEiT/97sazb9vWe9fdcd/793fc/M77fuobLoIHhSLiHUcNjBT8wzActi2AAqJTrfh6rjkTBvBJDqreoUZESGg+hmEYqo8KjerK0xuQZhusqkShFoG97/J0kZntdruZaOEW+mQqKl9PCJjta2pbVWCOCHR2er7skm9houD0XE3TAJKjmlVn6maXaiaAYd8Gv8Ew4x62cQzQx7kXAEbeoOxXAwBohlyN23Osi/txX78rdC+p8/Vdnk7G8PYwhhvq96vVw98kEYffpdExnGACb3i/P7mRarh/A9z/p9+MFPRsdO3mdMmv3AyPy27PALvZU1VgEJGY2M2w37Jaa63ZtUMIoeylUUdLbPMWuh49PZ6/ESKWMvX478lISkq27yA7FeUqRmTanO02mw0zxRjzZseIKQASMUcMiSYoU65lK4P4kAazAIYGCrJANrTxvIzJ0LzGaahgAsZmYGqAoAYmTFb9p6mpgm/yqiAiSjjfmpHMCHb71/MapUmUWteSQASlDEoYCBhJDXykg18eJ1aeiNfBqS7BUcmAHquYIbn2AUUVRmhTEDM1HP854yGCGYQQByPxVDZM8UKIIFYkWxZab8Bk2YQuxhSSqajRWKBxptx3gRx/afmqDOdXJYg4Fxpx78XZUuwrojfoHw8KJ8YodYQzIuac3XD64vFcca21ZGEGNKxVRUxHdidMsSEKNZdSRPxPCja/TcEU1XMiQES0KbtmsUTEUkoptVksHzx+cnV1tRsyEQEHRcpSi5qAJ3rGHYd7fUpE7D/aXcYZ2RdCqkUR3QADMzMHQFbdqnjF4jWB62B9voj3vQITWtBMzKZGJgMzqFViTJNvpIjMAamO22U2wH40ATNAr7DcuLlfFAHfuMt246/w9ay9X4MBvhdkMcPWYcrxT0XyLyAwg6/NGn3bZPbHv9Zf6j6j218iZI45VzfAqsqcSq1tuxxK2W53gNy2bToIEci8vnr/4Cibkj5m5jk3715w1Ik7sO5ywo001I3pIohYcr28vLy4usyDAjERVZEgAZiAkIjASBWKglNzZG+WIJqyU6qO6xYvAiEgkakZyZS+MjMaQTeCikiA5DQfYAbVQCbCnRk0bFN7RrbeuQBnoQkm26TG4w0D2G63O7WFqqEXp3FfPRESAegeAaSZqVn1jxuqCiERIBqYKKkFh40i2DVyytPplYhMTaerCgBGBogUGDSUnLdDRlMtARZtoBaBCH0akv86erP/+W3bevfZwl/9PPd2x80w4IsObFOSz3XdMHjjZYkxApqqeceRZ5h8zatArSrVVEFEvWo7u3q+/GZE9GTXp55eVW/Y7brkReVa62KxePTo0cXFRSnFccU6MWHN1mYOhKZ9N8OSWVVTbIehXF1t2nbhDjE7XEAAEWNMBv5mnP3s/QLTvMLvvD7XZnqUqZzre3JSHToBp2flj9NcVFdA+wbY0O/Oa5nkN4ZTe+b3NXThTet7y2P4FeXXEgHfOVAIQc1hb8HMJLsxTs529MWH/KJ99a4X6L4I+BtXNPZryULP+sWbK2qtY9gnxsxD1vkciCillGIgsSmNfAf2CibrO26lSWd5Mm0YBlVFQiJSEABwLF6IKee8365ARLkUp21JqRWBUkpAJGLv+VMgBJxJm0KKmD23bGKG3l+kJmJFraqRWUBV9PS1mJmOOgL3tKo6NzKOWegxAhabRvfc0jJ7KbW5QYWZkSiEUB0IppBzzsQLEzRyi2ooe4qDmdAzAZPXcC17oTISgKnamHUmA1SHU7kfMfkT4s2kRABjHGMgWbSKgGlR7HMhtCYFMWAgH9ah08AVA3iDK/xVLcX7jvOuBlXvQUff9/43nj+Oj290fCfLce/xzaxWQcQYovudbolDZC/xVBs5oczMGehKkVqrR7Q6MUbBnhFysJVOY108hvYNlXNmigCgYqVUBEIgJlp0S0KWqpgIgVSsFhFRZoZpY84LeAQ7TR1WtUqMcbO5AtDlcomgIkZIpihSJ78Baq3IcbZM+6J23Uu276Heur83PzT6Fmg3fvusCcezJSNG37I4vXj/Pf0C2bevuJeCfv2vX/or7pR3M8Dzeb0+J/jOxzc4iVPR4gaH3+SA6OuTec3QMw/+CqKNc0bAAF1x2M1HeO0V/yJ9++7n+fTfcmryl3i8T+5cT+/qVSgSwf5n9NoNNDJ0oAIBGhmwVTZBZECsPuUHJ2fTKOfcxKZrVwCgtfa7Ibl1kbnQC/OkOvASJ4IieaewIiGyIdVaq4x8Z1O0y2DkAKUQU4wJ0YfPVPf43SSfPHxkIkSQ+yEgtYETUUBTEwAhNGAOgWOMQQMpEAiOlnMakVtNBQC0kvmQVgcW+zVRQ8QxHQ1jRVbJFEAJwHRM7frO98kO4HOE0AtXPvcFaYrjA4EREQbHsxABKKJ5CymqiiICGI0jl72ZeMx9oY//NDEb425QQTXgawdcR1JMo3GgqY7jXl2HTb2YzDzTKUi1YbtRBTRFJAVTVa8LGBKaTmOzRyAr3s+f+66G8+uWL/peVyxv8+ji13b68N0/ll5vanRHCEEZyfMbjMQcc5EiNYbOvLJrCGqKKGJeTw0hmoHnO7xxYLQ6AAAgCqoqCiJSxVQqIhuCCojIUGUouWShULyiPDd5eqQ755bnYHosqe6ZzPlXe/GBmcy0lMrMuz6L6tHxg6FfV4UABABiICJqpiq11hh4L9CaYQ1jitv1uEMLR4Chq7jZW5wgyjQtYZx9zjETZGMt1sYheGMqCEZcJBgBiJe9RrU2DjKiCVShhjpG1agAYOTlJXCe6Glwk83XAeBG9Ph21nfvszee7P/n9Yv3GuBbXzavb5xGdo+qXCbU+WQwCBBhZN00dbzdHeeNiE1oAECyAECkCABSyp7+1v3H3BdiCJw4jG14KqoI5l9kBKj7jwhMoGi0/wgAYzDyRb/3+nXgsTvlnkf/pTgPIafbl3mqJI7J1vHL/OYaGN3dmMy8fz5vVfa+9UNwLIeMdUUEm6YTGgBhYCsAFAKRVsEyxFoaEgBtVourl58KQq0VOy59AYBgaFWKDA7RJWRVHYoipekEFWZjhmYGsWl3fdnlGtsDorTd5VLy2dWpAnkua+iLqgIhkW13pWmaIFBr7ZZdKQVAF4sO1K4uL0spm83m1dkFcoyYAkiDcJDYtIjJUOHh0fIXZxch0ONHD/LL0m8vUTSFxAxq1TeXd765W15UGICYat4yQV9rMWuYlbmvQgLRdHN1ng4PmkhmwBHEGGNSMzJdLDplDKENFDeb3dHBo912AKAy1IYbilzKEMKyog1DiRQPVoevTi+JCBUSh6uLy2DKXQyBUFBFEQy0FlUEiYRmmpgK6NFycXV5FjAYKARixpKzmMUYkazKJYFpLZGpayIMOzMJkawvIQTUErye5/RG2aTWlkKftwerVWK6OD9NmpqHJ4xQpBAhkiIoqICJ62cCrjV7xDbh0hkRh2HYj2w8ZkL0iUx3hAvj5Po9BLF/NrzGAeJCSPNS339itzXadPx7toUUT10yoqFrDmRHmsOYMhA3vWO7C1QkQwNA4pFVmwx42/dddxKbhVQ1RqIAGJqQcr5SKQE4EBEomzoJTM197rfHR6vl4aGIbHdDLdYPWzC+urhatstSCiIkbrZXu0gpD7rZ9GbIIfV9BrCQApc4VKGQnj//ZdemqgDI1f8fccmigAfHJ1ebIQ+1Xa76vk+x4cBOy3x5eXl8fOx80Yh4dXW1Wq1evHhxcnLivJW11pBinXLdDFhrZo5tCjkPu6EPnBSsqiCEs/Va8u7q4uKjDz9cb3e51kB0sb5MKcU2epNKCGSmWqUMuWaRUkOIXdPkfuDo3DPYxLTZbcuQQTUQB6Kai6igQWS+Ktuj1VHph2W32G63peRaK0emwLEJKUXVVAoyIBpGCpfDsGzp+cuXKTWlVhWK1JgAhlSKOI6DiFSqjjkdVLBq6r6yEXoGTESAoObCwbpFW0TUrGvby6tz79MhIvXuTF+3IYwE8jaOhXDnJnh+fkqV4bQLPFvgsFZTtWkcxZdJQeNdj3bX6wBARnenoL/gO/TWI5Ih+qHYQMAA0F2ngAAjTuWLHgEmC/kr/97XH++8Am9xfd4UB//qYnvh/j6uYEbuMBCBIkIADWCINpKpqkIYk0UEiMjOQGAw8QaPXbLTUZF8gJ2P25RSJIoZGrIiiehuyEMRVVW8zpWO18AwpSaE6Om4OekKAAgaiQFoO+TdrnckCxm2gRMbmg0o1RSsgopI2VxeweDM8oEAA7IxeVuUzandGdZoOjrdCApgSII09gmiOYKap4umBrrnSs5WgcyRTrjfxTsXn+F6hN1IL0WA5mEuOqhKebZYNkKPDQBQQQzQyBhMEBFUzQgICQgItajnqwkAyQhG4OhUygIAYBrHYISYGJiBrWzYoPY7QSMxVS39YG1CxKmUoOjocDAAzKXMigYmPYKI3te0n1p0HTQ3ptkeuhv22gjnT42Pb0d0Mzr3bxxvd6eIzCwK++b8OnDav6EOUzCtaN4QreDJD9Cp5oiTl+2IOSAi0/GCuxPAAIHARE0URI1sxtONqYksmXLOOXAyxYnuSsfO2tfEgMzM157ObepmOmYryBAE0FnUveQMe/ne65ztnuz/6v03A4Bq9a4kAABUp251Cgwj9rjUc1N1SmSqCiKY3QDMzwecJu2a7T1HHDGHY7xr00ecmk6vl9Z0PJ3jdT8m7kFM5u59MvSQF83zE57kM0UgAMNpHrp5EEz+G/2RiBiRnGALVaSWik0TEQ0VRAoIGFmkCAxWFUADkpKSkaEx0Hhbxus66zc/7blONwb0ZqBq3xgK+l3FUbj792DU0d8YmeZvttiewH4QU3EeEOlRi6rSBEMw3ySTQhu397TEPDoxgPGJTbyPgEOt/z/2/vRHliXLD8TOYubuseRyt7fW1kV2T1MU2ZA0kGYwkAB9FKRvAvh38is/kYIWDMgBRqTIJme6mlXVXVVvvTdvZiy+mJ1z9OG4W1hEZt73XnWT6G6O4b54nhG+mNty9vM749j3UyqWXjs33zET4rKfLRuI90dVmSMi9n1/OBxm05nqrIqBJtXKTwZ3d3drmRqigDynLSMh0xzJ5NAHZmioZgj4YWCWml7NY3L69UTOrPIX1ES9HmFvF0TwObvL5R0AmFltdhg7q9OltM7Zbc+rbBHBNE1mttqs/LS5kt3Y5+yVkuccknxSShcBCBQRPQjI39FnpMb6qRmq8+a6vHE5zZ6p2zgfPBMjUu6z8Pd5hTw5UE+PpBHNIeuwiMFuADMzqczOWgyPM3s2MLW5IrLH0S+EpuZqpkpEVoEilX1UD0I9lQCnUoNe12tJp3naEnZ61vmQqio/urOvigt26yecIvPPV2w5v6QALb7nUD8aFsewVeu8BIVdpBQCwMXTHw9C+clOzpSn4bXL2oPzDVXf9vdoFxHRvnXIStUGExEYpywDMwUKTkgUDExAIaeEjExOtszAEDxv82yyYFkVF/tlIbD4t4YBX8THltf4T6k9/hfUTgx4hoO2nDNR51s6eC2d5d/yX20NPNsMZNq0kZhFgQOSI+elrKoqAISX6QGIvh5VrQbddYU4eKGYBeuHiEzOFC+quM7hcGgjxXbVUGADJnK9UkR0wR4iAFWjosk/1Qrpd7oPC8UJJ8IBWNGRmqCUO5zHggKcM2BEt3x+qAPzwTmDKRmQBfyoDGMZEHegA8B+vweA25e3fjeveZemQVWbVUNsBUVhqfGjqCeXW7uUp7RzIaMEi110mznCoyFFxLqr1bsYPhMqUqTAQrnq7f+9m7DbBJ2J1ghf6oYxRoLyvYFUlu/5TWfJcvEdQTUIBsBMes5mcCnruVSkl3K+iLRtW14Nlqms6PJ8Zj3dZmcRf/BIsKu5msppxGovb71NLsSmap1jeVxxgdXjX3Px+vLCTgr3rfkNPLVO6meVzV4LAYUr1+eX721BEPv9yhmQgeH5hTobyLLknCc1D2qE9+/edavmenMdY2TgSSSNQ9IEAhSJuAEGNFQTMzJFFTE8m6CaRJSRL2/3t4YBX6zIx1/+L+33aPUqWXIPKMaop5qdqJKJ4pMM2E12ZzwMFQEMiJkJHeDCZeo58EpEPC3VDJSWcqMzsJw7FRRENWdJY5qG0iteGi7I9apEVWkaImJGEaE2NE0TgEgUEZFQxNGszA1Es+V8Vr8+ND4Vo4RCZZZBO5PxC4G4YMBzFGiVy3/Bgpd7fGiCaupVrvyw5mQzEic4pu7nP/7cb7Pf75um6ft+moaBIwcIIH3fn2gzEhqZzSFy7v2dPVjnOhZUG7DQ2Tmf++IlAZhPGuTZCAOSPaHUMqE5ZLE/DgxNYXY4Pfm+z2Cz19oXKMxKraoBOmzDEvtpoAIL0T9X3w1MTakiOz5vH5AFuq5zz2uRv/xFuq4r4G7eioXfz6zHp5DsWiq1qpXB91ZW49kIP5qL+g5a3ao+4eJ1yuUFQvhiHnWBCqiGu7b5V4P5qP8XnYSKLsG596G+8NHO+MGNqhJJqgoKlkXSNJFiYER0IDwyBRUQVFNJY55ylkmzsRCwcCQCBlRVNA+e1PO3KySCCADBDExMZ4n2bxMDfjxnf8UJ+C+51VpjvdZpqWS3FBUAj76Bxf7s/8GMOQPkfhXAJQp3dqCCaPY0SGAA1ex2KnRqND8LvYwu48Ji/emu3nmJ7xijLEXcPJHReysiqlwyNOvXmSsdiQvyXG33p8XwJ1sZExfKPVKj8KFC78odHhOOmebC2aML70T3HC7PP7sPnvpQtrInICHRHPSH6ANi+6NZRYKrV/MrHx4e6km/u7tjZsmTar7P98Rmm+7t27cfvX45dwyIwP39hojjUncWl5R9fGTnhIq8LqI9IxpRQLQ56Gn2MZ9nN5iAPM04i8Zsi6ZVXuG5KXv2PqiwBGaW45yVGAiN2PFX1NQNjKagOP/fU9DAQHWxTC7rbH7zRT6Awo99EDyqX1VNsqNqeH8K7EHhwZ5KvkRFPP0Ws+b3iOPWf8K5PFR/eWHa9Z9mrRovYd1wqUtolWn6YnM9ZuRlYZcO1y/z+MVq2wZVNvwLRlu6XbmZzmTc77kMvPm90DwypmIlYCmN2jFqFkmiEBREMoC9uLklVgQdh6Nmy5rQiAlSnkRNKQflJrTIYApZBR1ofQ7uo5Kz41k8RMFMzEw1+zl/axjwxaAXsehvDVjt37B2IcPWPNiZ1pKoYOKOLneXLqbnhQYBMpjX5p1vpoZgSDmJmiFQw4E8uspdJaAe+UBEc54fASJImoiAObZN07aN6oxG2XXd7jh4zG0hXhXRP6M4xTwlIpoERAMRenm1Ktp27ry/0TNbuCwzHyermO7FcMHzhEBVna5CxWjP2+JOP58FqFhaYcDlcu9GjHG1WqnuL6Ax/cJFTYG+n0u+u3DTtq2IbDYbMzne7yzlVaS7u7vb662RgRKhkAqAGRoRBS7mxDktymFET5JExYNPEoCBmWaRwm5FrCQT1uQJ9Wkf8DiORSa7EHo+MF+Pm4hUuvrpM+VMikTCRojkphox8/AAUDNQno0mZgBKdMYzkBQQAVRUVYnnyXW+Jks57cmyyeRI4zUzKzNCizsfZliby0gCrOrV1wz4wkL7eEEWq/UFhys7xXuI/CjsEZEWXEmojORwToTLHUpVksK56wc9nqC6AxfCQb2/ajpfv9fFfb4TDuW5RqWMqq+TlECQGBUNDVR1mkZJ4/VmDSYqkjVZNgUJGJCAQFNOZtkgNMQU2MBMsiGBeWCt1GIfGiG6fVAc0d0EAP72MGBv9YyeSOP/0n54q9WXi++L/OvfnNGC5cB5BhkYufTvYSzmBhcDNMuIHEIITaTQNCEwOvrEKZl1lqIADXEYekSkLjBz2zRm1rZd27ZN0+j+OGNTV+njsPBRqMiNLnpqzhlSRjWL0a3Hs83wh4rM5+PzgcufJBDf4+YfOqe+g6rSLLXMmtCsAZsVDbhcYmbMXsIBCsir87M3b94Mw7DdrFTzF8dhShkAhmEYhkHIhIlJHa2fCYgoxpMv1qOHvDBA27a1R7A8OqVUiwKFrLtUBxVpNjMzic+UC/RMVq8SXQQve+T2Lu0ZzfhktDiTegByTkTEbO4eLV01JAVDAwM18dA0VgOI8WJC/UYn12zFRXSpZp1QNU+EwbvBXMbMK9BEf8EQghe6hyWD9vHGtEW4qYfxYp2UF6z5X/1NPf6FqV/MlC8V78/FoNWdqTadFgZcP9rbxaZ7rs/1+RdvVyTOi+/he7iQnmxkdBJ1ZuHPkbaMaM4nM5U8DcMwgEyRcTbLeXi1CQoSAWYTTUEIQBmCoBoIKs4hfGBoYgAIYgBoYkY4p+eK2XxOqPdtfVAWLjwSQ55+q6paUT1hlp/1UT35/YVMd9Gxi6VQL7InL//+7Umf/wfu80O//0B901IOvX568aVd/FQIzcVPRWK92L3P5U3WFcTc6auqm83m/tdvY4zX19f39/eInwPYXLCTmZjGlEXzqu1UdRhTCAEDLsqDoMmSyU+qcP/23c3tR2+//dasuXn15t37h6+/+fbNxx8dhn7xseUQ4zTlt2/frjZXnryoYMMw3N3dXV1dtZGnafJK45vNZv/+LiVpmgbTXLh+GBO07Wq74rkEG8YYp2nqxTaxDYQpJRMVFUvCbePO4KZtIWtKKTRtDFGNdBwnSeumJSIzjbHJAE3T7KZps9lME7x6eXN3d9d1HQ0jEwcywZMiUoJHZogDMyImIPdpr9frh90REaZpos1mGIZNjIAgIlmFmbkLkYNNjiwmRCQiyLharQ79se/7NjZMrDq7IZ0RGvrUgJeYE5GmaRgtp2RmwzCs12sz6Lput9v5FB8OByIahuGL3/1mv39Ix0EtjYfVyxfXv/jFL37+0x9dvXzRHx+madxs1sx4PB6Hg3iRZkQksMgYuga6ZrfbOQshioSuxpmZtZFTSlkyAsQQEDnnnFIiwCwZEZsYnY9y4K7b5CmpCi7h0yXObt11vtkXf/+8PVdt6+cUV4XvuOPxiI8aAMYYiGezuapXngQi2qy7RWQTFVHVcRzHKce2i23DxOM0jYe9mW3W15vN5qFP6Xjkbmo7nWQSjhBgHMcvfvfbq+3q5as1M6dpFJgRE31wUr/vmojA48Nu3nQm6/X6eDzGGN2uczgccs4y48pZrUo6Ee773kO3+sPRDRi4wKR7mgAANE0zDAMgMrKXju77frPZ5Jz3+z0zbzabL7/8EgA2m42XVyIvAjFK13VC5H5oXUAfbcHn98EvmJqWJ8fzyjl3XWdzqIERkdvSS6DG8hZnZKcQcM9OLj1BRDe51Rbvmo7lnH2F1MXCzWwcx/2guLhFfPs7Fy3hI+ABYoAAgAYpZ44tMqikJoaIcTyMiDiOY7fCyGEcjgrWdc1q1WqaGM8CTXw9m9lqtXI3f0ppv997ycjbVy9hyfQFN/QRIZHknKeU1NErAIkCExJ/NxDH9+G+he4/EhI/cMWH2gfY57Pi4e/9sN+r/dDHPflGH5YRfugU/H4du+iblzeJMTJTveymaQpzIVIiIgRG1hCCAAAqzLmQBagMQmzaVlzGF2FVRZ2LusCCBH48HokIKYQQ0jjCwsY0zBBOIYSmaRqe84PbtiWClFKzvClWSnmRozlw27aRI2ZRETBjZsET2i0WC/QjOe90qyqSougJF1LaD2qPL5pJjJUpQMSC/zP/6XbjGCMZLX73Rek3rdM/Lu686DRgi9HYb5vSZGZOJafFhAgArtqKSAgBEWKMhMaMjldW1kkZKIcOpcUwWz6dSvqacR7p87jcGQvPEJGUJjz38tZ6WHloPVx939OSn1Y4tAdyPz0US5R1cSL6VSWz2duiobL3360sXdfhUrCciKDY26t9W0U7Q93h+cyz/81z5wfMTBg8K6xpmnF0gfh0Zj0O9dvNi/xcoP9OfeAxS4NFUKAqDLso9PhUgxMc+pnC6uC1Pqcn6xQiEYmcLBDf2dUPkP3H43B6r8pVNA/dMw9CxCfwyxxnwtQMRZTMNR8DALVMDB5NUl4NAJweFgnJx8HXCcCSx+972F9KZ9wPAaDlHP/m+5qgv5PoPDN2P9hAXN+nVn8Lg68n8mJdXpzwt7qVt3h88IOu+nCzc9uOmYUQMiDADNrcGJhKzjRNYkhigHQiIohoyUEl56cCWEBUQERsY0C0GNkARJJaHqfh/fv3BSdPADebTQzEjMdjX4RWZtacPL5XVbtV42t9vV57pabrVVv6oNW+dX6DOOdT+VWMRMwKJzEWFwaMrhgtyGgLhfKFdMqvmJ2slfW7HgH8gZZt7y4VegGoeqKSZSLcSFAYMOa5Y2VybSnieaLz59Tfo6DNbJomZ1Gu55UiKH6OS/Rjf9jv9y9urtuGAztFVkQMMRLP+WDlZRHRtR9vriQtmxRC4AV2EBGBmZip7zPRrA8AIPOivBoYiBl4GV7RZGYGAl4F2SHmPL4PEYlEU4gt8byiQggpT8fj0ZkleKENBIDZJiz55GR08cnvk6ZU7BaqaoqEoWmAiNRMVJGwcTM78kx8K6VKl8es1+u2PaXMllkop5V5LnwOKv7kLD+EkJIwc2F89YKpKV6xgpS5tos/5/V1SUjLy9a3RURevq+5L1Su39L8knquyyu7XghwYs/VboKL4yff66JX37mzasGCzhlw2UdPXlie6zDvoFZADFWSJDGYHDPWUC0rMmql5ZcFgEt0uj/YN2kIIaWJfPMuu9hUYQ5vBIAFRxORAdA+CMRRD185+ACpuXhnXGK/fr/25DK6oDJludTr/gdRw9+7PV5Pdbf/2p/y3OOe7E9NpuF7OEnq7ZRzVuKc8zH3+/2eWmxmTGC3/BiCQ9SKpKSWVZYy2rTEgpoZgObJt+tMiUQQUVI20fv7+3Ec1+v1zctXq9VKRA77PXHJ2bDCFVIaj8dj7NZ+n81m42YrIjITIrJzwqfqmpmmlAg1iBS32QJkdKYBo+dNLnFSNa05H5kTeWJmAppR7R4RtSfn5bm5m39abg5w0mmc8xcJYGZUDmm9qMawqL94HskCi2Zj2eOPwI1jfs4ysMkWPVhE+r4/7vf7/X6aplW3NsnDMDj8VoiXIa81cawztqESBbAKHfI/i67gXy7KMY7DUHa6VZ7IJQtuAWVb1nPbtm3bmpmrILbUyl2v148XPyKmdAJDvqAb9fc+YsicxDyEpsybiIgaha5kqqIuxB5xvV4zGRHp4pwujy7zUgQkInL/X3lZXYAslhm8XC3lT3vUvPwfPEVzLsgmLEF58Ijb1by07rbq5XbAc9XfFjtwiY2/6EB92zLsNaEuZ2Itd563es8++QhnbIuscNKAy91s4UE+A/4znb8IggLOsSOMQqyMrKZmAnCqZ1wYsJkVfdebS1ExxmkaL6dpMRJYxarK231fE/RzROQ/RSvTUB9YxVyfm8WLL//zdPKvcv4HbnEx/vD9puAHnVw6Vm8AVQViMxOVaZokBCNU1dg42K14ARbRlPqBAzK1zg5oqWDny1nEMETJE2NjxNmsaQIRbLbrIW3bsW3btosBdS7n8uajGwBomlZV2Uuwycn5F0JYrVYRgS6CUS8JK7x8+TL0e5tyluxAHKYmOWPzNKe0p1jvxWTVJmgKhLbEgVfM5sMzcklGzzsgomSgOsvy5SenCCmlEanBRkWAGDyNmplhrkUDFZsvQxFjtJRdbfMQNrcAA8A0TcMwqOYQQtQoMh0OBxUZx9EjA8xsGAZCW6871blocYl3dTJUbNreVVoillNK7nO1cwZMaE67VBbeT0QzfqcCgFdoJkdKMQBRsBlP31/SKx13MRBYlgySwQwQAkIbmE+QJrNNHxHBEM1oRigEtzQQIRlGCowcKJgZESooM2NgsUyEjARoIFlEHIbxYt6c2BNRDC1YrhYkop7Z4Qpf8I6VsDIigqXiQs75OUCJDzDXmvue+A2YnZPNUzdmIXU29c8C2VIPESqtl5Zg5no1mhmcxy3XGFhxce2XqZe5KZ0HdT73jlaheVzsrLPBrLabmXFg5qXnerI4XIzV8vozqi4iY5U5vhA/MRO1zAjAhLS4LZApMNY2DDOOp6AzVRUDy6o6mhmYIJjnsZstQTgmMIN7uDRJnlnxwzTgD7dneMbvyajq5VW+uaAyZV7xXLz6/n3+vdtz6+mv97nffwouBKvq4NkLHw+1j6GLcpzZA0nawE0TaTHqimjOWTSLCBIh5Jm+2ixWqpmAETGHMGWjgKgoWRhJVadpurq62ny8ZWbXw2KML1++XK/XiNg0nYggxxijS9arpgWAtm0FbDzsc87URueaswZc4UKowna7BctZejSl2QuVs+RQYRdb4agLCMMF97VKz7sYtKIA2VOq53dOTf0IM3Bw9pkBe2WmJWAbFnKZc05IJ+zlqmO1IFJPOhExclEcXQMu+IgeLINoEefgl0Gmq80qpdT3fc7b4FQGIYSQh95VNXckwyLLuy+/frp3L+UR8vwlLaCM6IikVTCzzXaOCfFkVy+kv7Z4XwydLuVsYdHqQghXV1fPmSJCCIRcHnEaH+b6z/KsGCPQHAU9p8kB6VKb58xFvXRY5bRmmAnlklvXrUQ+UwUi7ff2iy4utKqVAZ8f90ENuN7d1QbR2tfuiyHGCBUQlS65fBdPt8UtUvrgXPZip9gSKrFUKZ7l+yL/Pdmqd7w0AOBTGnB5wYXh4tk8nnum6rvNB8tzynNPwiK4+0mYIng2O802noICZJXxuSxmM5vIAmI9So8n8WJgf3AQ1nNyTD1A1cHvmSX03PKFZ5Rd+8/uAH6uh8914Mnz7YOc9ckp+E7F+/vz7IvueZumiUIsHaYFgsrjeUoEBhHFGGPDkh1OaF7Tcy4lIAeOMfbjiCQp6eE4jON0OByabrXdbtebVdM0h/1RRAwsBKqFa5wzh2cK7sGiALDb7Y79yNdbXDyUeCmEwX6/j+OIqrwsPiJiOMFxLBZdqy+sh0tVFRWpeDHPBpK8ltwywjUj/PB01EPtT/H00NkOaaDAtgAhEhEwUQW8TESGWt/TFh9w1ZOaKmEJwnIfMCzct1BY0UWpRVutVuM4vnv37uZ6fbvdxBgRZq3IZs/63Hw9PIaWLCZ61exiPjN7nXZVmaah67oqQta8lnzDAckQ0VNp2dDMa+HNLreF8hsREmHOqR96M/O7pZQQsG1bfRJr2oAwIvL5LKAZuq1lIbuECGYmWbltkkySMhI0hCEEySDZRMTo5CKtZ19VHQGpNlHCGVM5I77wFHtzEFZYCkeercaF69sjyn75vufH9RPLnyVcrtwWHsFAOmYOnPMnVS9fqfWXtljvS+pzWZYuseXsDiNznftip5QePrcZn3vfcrn3upig/eQPWxZrNlxs0SZKDRK7ZGE2p9oHd/v4DgUDJqLAAJB1BEQDUEAFNCRAh7lKWNWyxLmiK5jJrCov2x+RzSwQOJ6m6RwfNtduJOO64q8RfrhuTz1wJ8QZ0DnkzGsifZ/PJ03QijZD/xetDgFgRmEFQgcKmkHT0RDQsEJ+rT7h0TdW6mM88ys8UTXU18vj7+nRNx/4BAB9Boz4OQHow+33476ny83G/hiIpmlQkSlLEktsQQwgM6JJRgVCC8jWQtu2x+MRyYiYCL12JBqQzYbKnCcAHobc74/9mI/7/SeffGZmKSVXAkTkuNt/9c3Xn376OTOH2AJAtFJRByfJ/ZjHcZSUHu73ABBCwxxVRAGUUcXDg8nL93z5zdfXYBuKTGTAoBiQKFAWITX0ajJqHn8BAICMCMEIFIIWRi2AnniDNEd5sDA7eNJcW6tmzjWUxBmshAqpkHkGvnNIQcpggMaGZojiWCcgZBlNRdkiEiAyBSYMwATEGBhdm0Av6WJZJakIADHC/OXSBQAwNRFQQJ2joHWOF54AZlIo6s5gaEMIodnvDnd37z968+pme8UhSk4iFpsIi7nSP12Bu2AnhYy2bZsz55w9gtunWET6fiQKXRfIce3ncJ7Jk8IR3CRLRApGRIDAxF5xS0zRQNCBvYFFZC4gjWEYBhVXc4OjWTklQVQwmgO4zJe26YL/h4hEzoDzsl1QVbIKt800TePQh0CxW4UQJOeckxIV8RNIyyybmRrSAoZFRLqoVtXIzIsNTXLOOU8iCdEASDTpXFtIn2PV5iYlMwBgrOjFXInVdxxkR+mypfTSQo6olApyY76nwZjNhn07mStgkermYgxqc83GRWAF/1Xlwg1ERHmaFKBmwGIqdirVcMF6H7fHPLiIMvAUQZtHmBCIDcEIQcwIPcJJz0QW5IXzuvDshYENQZeablYUAA1qIyou9T9mcBVbJONaWCkddqk0EI7DdIINnzs6F6s9m1lUMzKQEBhEvSYWElBA0Cxeggvni3GpFMJogFqL4afcX0mnQAkEQAIvLA4cZoZuAuhFl+cbgy9aIHBIQmIAVFPAZXBLODeSqLhFkZhxCVdBgILCpIvCbfMxej7M5SeQl4Y2BMKKSYPVbPgMNA/nooH1JxI9ycjV7MnzAz59vu+LZVHVB2UHlrnEeT6fao44WBRWWBL4ttvtc8v9TG0yQVAm/vK3f9Fsr7s2/uWf/8eHn3yOKtc//vR+//D69kYkrwMxcwzEzGaUUlp3nUcJS5rMRFGZIwcaxj6rNYEV4fbmKqu9ff/FZ5998tvf/vblq9dNbKd+yjkrWNuu/uAnf5AVROS4P1zdXN/f70BAcxaRZNJdXe+PQ9c077+5W4eoWYZhCAHfvr83M+w6AB0lM4W24a+/ubv5+FXTrSgpYyBVx9iynFZdO419jDEoTOPUNsHEjCICBmkoD12DqyYKO+ifjWkCpA6bjiEJ7ER7tC++/eajFb267t493AfLb968Wq3aPqeu62iuN22qCgGZiSlAQ732XRN3adq9v5ft9qhJABpmy7lZdxGmb+6+3Ww24fWLPI0xtprUGt6st8b0Tbo/jFPYdoqQQMlUAScxSzOM0QRADO8PD8d00xnocLxabYZxJG6ut5vI8Ac/++n/+G/+vyml6+vrw/H+/uGOCGOkvh8Z8fb2JYFJGt9++36z7oyad/f7m9uXV9utTKOaHA89LRoFcwAAEVVNZsWlOicFeWzXanULRoTBcUJUdRrzNOab6xcAkKZaZaeu3aplA85i0zA5aB+RswmVKSFyCITIns3CgCJ2tb1BZBVJkmJoQ9cwY0pChA5+aYaqWRVUDdhJGSIhLVYNAMgmSfO0QJTPJJVwt7tHps1mw4wElvNkYLFhydq2kQMa6Ky+jz0QTlmJAzFPw9C23X7//tW6GYYhpTHwBpsQUBFh3TUw5uGYm7hqYghMTKiiaMoIMdDhMEqeCAOgV+sDBIzMHnU4jiM17dXV1f7h4fb6ZhpGEw0xMhKKSkpo0FIwBEmZEdM4dk1zOBzW263m7J4MzbmNcSKKMXp+cBNjYkYD82IbAITo/yTlcRw3beOTSGbMPI0TchCDJJJEmIOX7wOxJjTDODZNO01T03UPDw/IgZAa4hjiNE1937vcVtiqLhneRbwLGNIoF0ZyJ1aOSlvkuaKs398/7AfJooJkhArmud7MIYkisAqggWYBcr1TxbJBg4Ayw/aBAYQQEJQRm9gZB7GsAoR47AdfHi53eudTSu4SKk5r72oSMWRcNPLlLbKJxsgyZbEMAIFZRA6HwzD0oe8PLn8hInNk5qUeqqIBAIHarNWf62quWT+i67iwj+Vso4Whusjg3xb5DC4+a/vBYmpzoYUQkZAQXCcBAK9vMtsaL5TLGeDk8SeePgVsRgc7//4/5+dfV2vbFhY6Uhjwc3midSv7wQXEF1fbsNmMrN163bZd00bkGENjZgyGBIQGKgZmSIHI3EqWJwANIRCDAogZqiIaEYuJozoPh8PxeCz4CYjYNA0AGJKIbLdXfd+nlCRlAGiapuu6rut0NtRz4CaGEJDIyMzEkIkUhRHQyJbiJgowoWU0A23ccgIALsa52bxr2qYVSYCYVBEBkFwhNlHVrKgGYKSiZjjLnkCYECemDZFqFnGcKVRVNSEiVdElwBVMVFExC5KREUEgbAAiYeRALEgoKQEYGgbAaEhiqjnlzKoIYBkkZYN5k5/svahkTKaqgAYEBgSGKjWwrQmYahYTyRk0eVzMHFj+6aefjGP/8H43DIN5BJDkaehBLUwZAI7DOAxj0wQwKKWfLtZJUReg8qH6rzlLzuK2x5wFEVXNC60u8+Ak1dee67iGqGYnOmCGMYZFE3IDJgCIZzdVtKKEjvvxTC7MnAeLqjpGyPw0RFjoiyh41UtwZYeBaAbcdjbtYryZLLri4zY/HdH1SYOZ/qEsKqOLt0t3AQlmhdZLL7sqWqlWM1jEI2dn3XDR2ABmJEXXYMQMXcVZxrH+x4tyzEt3GRFcpT6zlkNACkjZI8tE/YmIyETMLAuNP623xbRT3hQWFai2Bl+osLWWD8WeBJfnlOM6yqFcK2BebkOBAEhBFMhmdnC6FUGpowyGJqBo5mXlF7YALvOpgIJqNgEj1WQni7G3C5gUPQtAUbOZo7sRxleAqRlCycUHADNl5tWqizGEJVZNzIxZS7ELmtdWPRxuSahH0y3GVfjDgovw5Dh+pxUCzjSzMvTsd8Sqnc58xtr64WeVUSsHf13tr/du3785M4PvlxsD5xbUsqQI6ObmBtpVG9HLuXiAhqs4vIS9zKIfExHl09LEEAIHTCI5z7Y+Zs5iaUrH43G/3x8Ofbu6mvfqEjebdc7x9SCg4/E4TKng3dQ9rM0+81ssxKjYiJQ0kU4gjCmCGRmyGuNhHCJ0PU4YOTcqExhayoKcgXUKWSRNOBGyolggC5LUMklmkwDIJkGVlCOV2BO3seececW1o85UFVVRDTSIsGQyiwAtQEREhHYmwBYNIkKDFBDZTLKQGjGgAeQECGwaRGyccKOsxmBKSipgEFUjUoG4NjNEcvBZlwIAQACIaLVaNU0jIpry27dvHQ7+6uqqIRaRh/d3h8Ohjc0waE7Y7cLhcGjbwETEPtpnCQiPd5Yu0V7FF2gnSya5KlxfWAZqnlk8C7yq12f55uK5F+T7Yqmc7kxkT5ECXPJZ66XlJzMDLDSlcKUP0JLH+72sxvnixSBZL2CdE8qx0G46T1hCRLO5BMhz7XIjPyoWUnePiMpTit5ZE9v6EmYGyPWDcIlcq597MS9lWmvCcka1zwO16psXBnzxdvU4X9zhydN+aCs3Wfz38yuoKaCinmCxS4d9DD2zoNABXKDWiLgS86AMkU+N380Hf04ddmwzx4XxtOz5MUvMZL2g635X33/HG5Z4s9M33zUip/lbWs1U/irjXtORsvJ+77v9zWl1gENN4J5rF1KO34GAYox50U1FBCDmnAlARBwbCxbYICLDJb8zhODzMwdrLDsWjFwTdwDhnDOMYwG9g8W/4PAavg5zzrvD0QGJHDoRAFSzh3eJiFomagAdcoEI0EyKT3e2bVhWkUzgPlsihgDZdMgjDEgEk6WWAjAIJAQyFIWUYRJrDAWQDNUMVLMZoQHhrDrEGG3oC6VzWuaAxsX+Xyq0M6DlhEkgJQIAUZQMokbYhqgCDMYKCBqRIpAyBzRmzAiaxQjYq9TmiQxwRpA3MCM1QmNCdj1KXU2Zd6OCGQIzB4DVanV7e7vuVj43d3d3IVAbu7ZtmxBzzm3bbrdbr9Y85nw8Hvu+n6aV2xtwWVEXAmuhXDVL0KUKUKFHWEAZU6oXZzkmIrOZPdQLsgRd04LNAgAhBJnSBQ+46ExZ275yxpyeJFy1+rIQXwQAIiwJQYXIfxcDPutPbbHwq2sefM5BEQzN0GPUcQkb9P6XrXQxyPXLXrAlWChbPQ5lnMt0OOYrEck5DbwYvXlM7ImnP35uTbehZs9weqO6P7UX+UTtH6Gal7s91oB/P7pdE8n62DcusxGKLZkOiBhDLCv5YthL/4soY2ZEjASw1LUsC8zUmGcJVXJKyaHIOSAaMxI1ZSBKcRUAQFQzQOTTJJVbA7gvdnkN//SyIL7mzqYHvosleCuvWn0q4im22xfuPJHfxf4/MA1PChZ/9fbXe7cf2mra9JjFPndyOXCalXNuIy3piZBSWjEtVbTm3FMzw4WKMXMgdiOnaDJE5DBL8WqFjviCm6ZJFyTCcRwRsV2tm6bZ7XZm5g4nXYBewWluBfsuukDSmAT0LL2TtMlgpEIqbIAGbEAGBMiAL25u21XX9wcTkZRJLQRgpiEJEwYwIyBPyTcgBTNAMSRjsWgQzRq1oBqWyOTSCq3npXiAMtOcrkuYldQ8nIUXyVhVMbAq5KwpicicHEhubeeYTabJiTghck46K6IOritojIgcgOfbns+mqgoIECEBN/F6s3UN2Mxub29zniTpbrfbZUHEJvCrV6/ev7sDTVlPAUEzSV3eEc7XdnlrW5CwdAmvdXQnOwF1na61c4qPlRxcS5CFi9Q0tyYLjxnM4yyXenfXjKHuAFXBZctTyP1YZ2zy+YYlimJpRTEq3bh4r7IhEE4KccnRIvLMlO/WDcpQ1PevuWU97ESnwPICpp1TumCNpfHSCE4iy4VLq37HD/fzgvvCOaXyz3rVPeavz43n75FmUy/scrfqqWePdh98Wck1Dy50oNxkNnKgwRzNuQQggziWNTMCgIqYqYiaQViKpZTMeHTSqXJ6Ur0TyiOf/P6JtwWp0G5PB89d+HjL+Qt67diLTYX0gyfAnpLlP9Cfvy2tmEpqgvJDGbA3EeGu1QX+VEQoNiZZRGA2+8/5cABzIW4/LeecJVEIMRICquo0yTimnGcKy8zIwZWknHPf94jIsWnb1gvsbDYbRJyyENF2u91s9rTg+TGzL/h59XuMIhkSJ0AEZQQkYqUgFJXJIEKMCCAZDV9sX1AbDrsjkLXUJYQGWgUbNLFBIEZkRiYjE2VEkMAqmiAqtgqthoMACzJ5GDAPQyrMBhbMyLmyDZEzYGZGI2QiDQCTISuzZUKwQS2piOCgkI0SYgYeFJCJkEbJo2YKrKHBttGkGVCQAMkMBUUBBdFCYPSYXCObLX4+RKKCzKJejw9lQb0/HA6qGRRFRMYp59wElq4JIYCaafY3qqjBXLYZztmYLogcF0xxMa5Cre0Vcaq0hRz7VWfctKznsjKLQKaqkeZA9Qua7vBYet4AAAPXN3/yYLGyqKhSCCX28/sQeqwyA0tn5IRsBVATd53/XJTvmaaLCFGQbKpApCcF45E8/ZiZ1ao8IkKVxVufVkzQnkJWz11RdmfTRYV5TkQMfBqfah7rybLFMFt/czFNFwNSE6iyfs5M94+MJY8n5fcg2jXRq49TSglzIkMW9TLeixRW97NcWJaNiDiewcUJ/kJmBmpmsFiAAsDsffPzwzKLyUzM4sLVlzJP5lzWg7ofW6HnQHhEXOREt5ksevBTr/3hAXrO1Fzz+7JogDAn/YEs+Ake/HegXSxcrCIFvvP8uhXaWvZbzhmggRkyV8lTjiobo6pOU1bNhSjD4mbr+/HQjykHNzub2YuXLzabDRF5cipXlVW6rvPLt1NiZi9457AUIQQ/IfCClc8YmBFnqZ4BCZAhhARNjjE2EaWFGMDUkBSP932zaW2y0IaWWgZjYc2ZM3CkCCFQ12DLyqZCGlBDzGZEjYZGsFVaCTcCzI6lwHo8qKo7cvSU3ELMLBW9zsAJGQgSwIQ8AmaAAEhqYrziNneg641264mbHpmYsWkHhH6yNnTUrltq8pQHCsoYiQVwEFVkYFJWxCWxCuaUOZ9cYEImAXB8Kzc8dG378PCAaG3sYoxsME3Tw8PhsLPXL1+BQzst5QGYiMnQaMlrPBPppmnyM4tq5fNbogTqk7VKOa1vhYgpJc8DvqCnhYMWxRrON2x5hB8Uv4ZV5k3zzJzqcRdMFyqiOWuubGZnJcTQRZBnCo/jYhCqd1ZxDepihS4neKCOmqkZ0hywIwqkIKaiRsaEbAAGJHAamYtW+NmJAS889WJ8cDaNziZol5ULfcCK9eIZiNWJzTjWVBnq8uLlEqjYIVZ6uVUWlHr8Ly4pHa7b46E+u+0yCPDdYaZP3+eC7uechcWT86GwGGZHPIWKMdV9AAAXbZ0UhDAjxOliLzQznHPiY1kYTtDmAy82t6CW1MFmT0D8+Mg8+f2HDTXVad/RuKobuszuE4Bks9TGlCZ58qYf5qx/93hwURHqUfrAgD9e6DW5xKoMXNIsIgFRZalEu2iiqkoh5JxBs4MzEzM6RV60rnEcsxRcOnnx4kXTdrW+7jx+vb12uyUsleZUdRiOZmKkIVLbxrZtQ/RUefGceSIyNAIFj7ZHVCOFCNgAmlFUUyEyoC+++mZ7vTn04zU3gk1CA9E+WcJIGIxBFI1aIxITgIjYCIBZo0AIATWAsUNwhBB4KWNOFJhZH9lRfGwVaVIblc20BzgCHJSyEoFGDhAortYQGxjF1tvUrsZ+4BixbSeA0Yi7dbvqQrPCSYYpqYmEoAJHUuSgTEJeyAUKoDwtpssYo4VgCyCRiRBg13Wffvpp3x/SeMGuRFVxIbiuxxMieVmN89BcPyh+xDJr3jxqr6aS9fosZxZq7OwJK+7un140wke78EvmkiB+domZ9X1/fuclNrtiDHV/Cq+qGU8trdZd/T7Ere6MjwxUqnO93c53JZme+KiX/MATrccZvvicgcFiPL/Yxbi4Yy5WI1TUoFxVT+gFd1RVkVn+nge/4tDwFHWtfy0DaEt6dH1mPeyX+6US1C5o15P06q9Ouh/fk4gAkAiZAsd43M3pnaUutbdi6VFVR5oDgBAaT4RWO5WsADUA7RqvKJPVC3vzPINhnHpEJAYOjDPTnaO8yrH30O0nHGvwLASYNV2bSX/RgxfLDM4vBucz8XgoZwOIzmiiZTrNzlaPt/n1VNza97i5yu8SPSIOw3B/f384HD7++OMymmUEP8yonvz+ubmvF+hz71u3C4diOfnx/S9278U5jynU4xX8+PLiefLeOrTQMAxN8/rm5uarr776yadvVt3Kxzw2zTSOZrZarZh5mBIiHofh+vqaQB8e3ovIerMRs/cPu/VqixybprFDv91uh6TTNL169erTTz899oNzhffv379+/frly5fOm30N7HY75nB/f399fU1Em81mPwoR7ff7w+Hg8tmqbTdtbAPmnCVliM4SoR/SR/+rP+6utscxbWNzzDpNfdO0h8Ph0z/8Y4h0+OabYyRNduyHq3bVXL9EMm2bNIwWprzqAL3QGKrS3ZCu37yKFD/6yc/+7a//jKAbzWK3msa7CanrurZt+4f9fr9vXmy32y0c2q+//np3225jtJRD00zIirG9vtk9vN8B/J//r/+3wPj/+X/8P2OgTRMFJKsd+um37+664/hpbHizvRv6/ZgEeWDbHfsgwoA5y3QcQBVt5NBwt1LCQxp7w+ub2/7h/YubG015c3W92+/NiEIwgKSiAE3TvHr1yrMwVfXm5ubly9tPPvr0V7/61S//7Bf39/c/+8mPA8Fw7JtAKvD27dtf/SrGSNdXV/vDw1UXCM+4na+W6+trWwCicYm08o2GVZG7shTHcSymznKfAphVEudKtsZqtarjsIpTGQO7srter4mo73u/s5tVXXSrrZ1lbdedqXdK0a2JyOHXBGZZFtTMxAlc163HlBqRljkt548pQaCc02ZzhSaHw4HNVuuVD4KqpmliyxjIpcxxHI9Dv7m+5qbxjFQxE7DjOBDl0HSklkUMwURz1hAjlCLTROM4brfbaZqcfIlIce13Xbc/HlWVET3s3JN9ix1LRLquG4Zhu936QAHANE03L17kxXClS3TuOI4c27Ztc877oZ+mKYbOfy01K9frdeQgIkwcQkgpNU3T9z0zHw6HEMIwDEQEC3SouzbOSb0WGYuW5hu8sLcSsO2TXuv9PmtN04wAr1+/ZmadEiKu1+v9MF6QO2ZmQmZWUAEjJCSwpRseErVaNcxJNXdNC2wqQEQ3NzcuGVWhyggAMca+7/0dr6+vfQTGsfc1iYjuTRvGngjX63UaezNzsCszS5PmPIrIJRSlmeNmXcYhW6WJPtfsyczg72q1XAbnHGLZLXhx5yf500W7vr4uWtc4jrvd7u7ubrfbffrppzUV+C+kfXji6nYhKZeFPk6jIEzjSEROX8Y0V3pLKeVp8CgqYqClsvo4pv1+TCldhdB1HQDc399/9dVXm+2VF0GKMd7e3nZdl1LaHXpVLfqTLsAOMUbKqiCIxpGIQCWLpGmSVbPZbFfctJlX+wxI70bL159+TKHZv3vfj6ONSSVdr7tps/oqTSHEfcNdGy3E/RAnM0pTLwnTNB4OkvMrgKvtttlsm6Z59+79W83jcOxubq9+9PHV/v4wjNaGrIIiMzrdEnxUmvdcUSVnpDQSU7vhtrt++Yq+fvev//2/1yy/ffd2u1r/x9/8xsyYvCZ5brLtfvnraZp279+1XQSmBCpIHIKp5il1EN3LyzEQh0QwSppyJiI06A9H266cHLg8LijAFBFW63Up45innKe0G4+MYRzHq6srVW3bVtIYYyScg+MKsVsim8502aJCwSPfGAA0TWOL47ZedSWB8pwXnmnGeJ6rg5Wh2M9xJuQU2TUEXdJpvBwhnvsa/cqLzpcF9uTuCCEQkomqKqkBkBkDhgtLJz6Dd4iPtNK6KVgpHqyqHqIoIqpQYly81SuqHuqLPpdPfGQmhHMpvPiArILMdC4O56pwubbuQH1tPd1l1hBPRTFPx4/ygOvufViH+fA3H7j84t3RcUVkrm36TM2Ls+WKOENXqepx6F1ALNUmfH95uKVHHhQ6gMgi+fb2FgCOxyMAbNZbBDsej3Gx2AEQmhYDyewDnscUPHivHinvljt4fMlWiu3sGCEAWLDZ/Pu6QNWzGmQ9rFbZhOsRtCUIq6i5Z2c+PwfffPNNEcxXq5UnY0zT5LL542X0d7VdDPLjLy8aV6VR3GACACJye3MTCadxVFWvBauAzDxMU0mp9DPdHsvMw2H/8LB7OA7rzStfxMd+ePfu3fbq2omm56e6TA3LTm6aBoiLUBxCYM5mFkLYbrdN0+g0+FrXPE2COiaNZlm6pt1e4b/+xZ9tNpvp2DdAkCSncSXDcTz+6l9/fX3bZpGXr25fbK/H42ETGiN8u99boOPD/din7abZNB2BBY7vdw9JtFl/ub66pa77aro/jOPexgwYrNDNE5Ws80rLYJLBYXf/7TffbLdrUfhX/+pfmWiWicBSyuuulWwi1sR2Svn9JIAaCA3AiL3wUUYTNcnaREREJgYkMczq/qLQH3YRiAE36/U4DGw2TqNrKpmQCFar1Waz6boO1Y7D8f7h/qtvvnz/7p6Zb29u3Lk+mqABo07jGT5RjBFRCM8EVt+Ael64BpYN6+unBI7CeaTxI154YodOEAqfnqbJ92+hA/79ME1eqMOH3ReJiDgpvGB+Fz2sW1mxFz+5/GQnx7Oj+GlVK/LU6neHyuBcxNaLBsW9Ik7x0ZG5y6/+oirghZL0PICjHufzS2akElwyTaHyDXsrda58kJ0BhBBEBBdzhVUJNuVaPQ+M4ioLoEyKf2kwB49RCSSbs2ieHjqoiPmT7WJp1TN7cZ/S7CSXnES6Gi3gSYsjVAy4FtHskV+v9MqLkdCS12uLQZEImL24RbAFmUdVKUQzBFJEJMAid55hg9WDQmcpa2cQzU+25Ve77Ot3nA/lifWSqge9HNYjXl3yNIf3+qA+KMWN5FLMkxvyb3v78OzA2dL8UJv3JGIIQYeZNbpWRDyHOh/tmHPuxymEENsWAJqmubm5MTMOmFX9Gyemfd+/ffs2tOsYY6tzYUER2e12HuxjU5o38DLLPjtExE30xYeIq9Xq1auX2/WmH44mCgvUwyiqnA6HYRqOAviLX/3F5nplQ+pCJJVpmlb7djeM29er9fXVw+Fhl8fp/tuHtw+kkDN0t11ctTkEXBs27Yg6HHs1yQlevr415LcPb1e2aVakHNabSHAq/1KEet+QnpvvS9Jm16b19w8P336zDR+92YZpvw+Rbtart+/2hLCOcZBpHFIAU0VTuH1xk/o9gpJlBSBFMUURNu1394zUhABGGS2ZZgAgNNHter3dbF7e3B6+/pLMRKRZd3k45szOBCmGUgVPVfu+n4a02Wxe375g5r7v+8Nh3a0IgZlJThokkUdgPaGRlJkqJNu/KUEr5ddib/Rzaka+kIuZSMGyYXGJG8Il1q+wDTPzd/ESHc6Mi3pXP6UoGR/Y7/UkAlQhbLNaOXeyToWtr4VzBoCICGfc64lGMyS3qrP2WiZGM1QVWEwRF47zevxrBqk6o4Bd2Pbqx+qC4mSLf7rkOITl+5oCFx38svvnzmCoNeCF4Bc2fCGdnE/92Vq6mCZb4p6KMHExgx+Y1uWG1WmzvqeqSs+owBcGG5sDpsDrfHioMyzekKZpXMGF80WOiCHEw+FgZqvVSjUfDgcwW61WS2wzIGIRCMws+MEyUn5HNTiBZ/j0AUCp1LHcChZ9d0bIqoZDvcAInIoOfEd7vMg+eOZ3m6C7riuyvO9VX09uCwX4vgzp70A73+TzwXMD6HlvAMDMaXHSiMgwDBCD8zwwKu6QxXUE7lVyI4rfpG3b29vb9/vj4XBoFEMILczOPL98dv4RxxgP/ehUKaVEIY7j6OCaUxq8BsF6vX716tV6vT6+NUScpmkVu65tGgwZm4c+aZZxmv7wx59xww/v7ixlEIkBb682m018OO6lCzoMkqfQdtercNU0ivTbb/egykjr2L6+ue5iTFcDAIxj/9lnnx6H8bh710Lz+cvNu/uHu69/8/c++YyZi42NKvDtkyogJiKQs+L0atX+0aev/97PfgL8k7u7OyS7vr7+8svfMceb7dXhcDgeh+urW0YWsavN+mF3ZybGKIEA2UuhMHBQiECB2BCzagZNREZ4GLMOA6NploDUNDylIauEtslMGWAcR4/SjBy6pn358uXD/n44jr41hmEY++Nw3HdNywwhBLXIS6m+C5PdiTqfc4V6XRXNuChVetImH283L7yg9bX+Qy3cQEVwa35fKDstVaIL4cbFmq36dJhszTPKJyzsH9TcBG2GAMGAJz1jvU5Fax6w0Pri3j7nZydOiFlsyklViYIHKRkQuAAKYABegljsBMlwMdr1QC1/ztLG45PLNy4TwxLo6hyl8OMaK/Gyz9+PSNbcDpdvzC7rbReOWz+onvSLmYXnafXF8ig3vPgGFk72gc5Xr2qqPvCKioEiVBJAWVdO4mypC0dL2kixhJnZXHgY1QmEmaljVZuoqoiJPK8Bn7qzjFdZ+s+Nvy2s8WxRPsOA7Vzrrcb0sXH/rFelkwAwS6dP3b+WUJwyepCInOeSf8+19Te/feeLPLeIL9rsFgIIIQyLIVFEEOdCpk3TxNCqqgKu1+vd4ZBzTpJm0w4qMrdt2/c9hebly5fv98d3dz26w2lM79694xDbtm3bdrVadV3nWNBwnmhoi71rmiYDAoCmaTabDQfMOWMVhg1Bm6Z5+fIldBslXq3jdrUatjcBjMTU8tXN9piGn//RHzab9quvvhoOe1Trdw8tcsr6D35+xU2bpsFEXl7fbFYRQSNT3/cvXr04Ho+vuvDxJ5/cvHzx67/8i0aUPbfvUYX29Xodxs1ms1mtVnESGScFINM32/X/7g9//qMf/ahpwpdffdEPw/XN9pNtx8xgNPRbMHzx4lXXrcd+mqYhfvoyaTZCbAIENjNGbjl88eu/ZGBWUAQDymgJLQH//Gef/PrXv05vv33//v01s6Pt7A6H9uqFEAKAR9W569StQZvNRpK6jbdtWwJrAqkqxcDMwQKfq0SIp8VTfXlmPfZBwCq/ovzqclUJlq4vnzd7Ff9RhpSqAMmiy5pZAUbwn1ySKwumKCLFzTTJqWxi2Qj1PS9+nU3QomZq4iZotadgMS7p+1MacP1SZejKOneQISf2y93O+F+2y/jQ+m5ljlS1BO7IMiC1DOStTKvbDESEmNG9Bq7wWbai9y8vdyH6PGnJKKbyE8c4H5nHg3bBTU4D+JTSXEzH9feFIz43OBU7n+0ZH2hYUrBAhERxLlrq8VmlDIMthreu63wMsQpl9VJXq9UKET0U6+rqCkH7vl8vLhJdmLD38MwHXM8rLIgtZbgRDfHkO6k7DwBz2hKq20LgqcX9gVZtvMdXuTZ+6qc9r8CVtt1uy1p3z7l/Pytq5zLXBwWLvwvt+7+dx8rCkqdRTEDDMERC8h2oqKpAsx9ORKDAcSxwd4hoJ3CotFqtum64P/S73W6c0qtXr169ejWbncGOx6MCFQ5BVS6p04JCiHPO47R0TzRNWXCKuGrb1ZvN9Xa9efcXv3oZIofmarViIk1T6Nqdwf4//vrmxXXz8NCibbsVX73cNl3KMoVWkB6GqT8cWqXQcwCIkTmNOg4bpk8Mro7HjvDVOAQMnFIWyRl8UXmEZxDxtOai7c3ys2U77K6I3v/FL0MbME9hmpJOLbMMklJiAxH79uGha9ertpWUkC3LlAmoiQI2TRMINMgvQqPZ0BQQgUiJksnBsoyDZrnabMmAmff7BwcfAy/M4rOfRfMsrXsIq5kNwwAA2+0WN2uTtH/Y4XkEE85+KDkVJauobUXdznJVSxphMWD6PQu4d02+F7ZxpusU/XUxrp7VllmtVj7UWCm+hbvXpPkZnfsJDez8p6yooKaaaY6CBgMzbh7frTzr9CcgwNMmaDgjXGQ27yM3b3bdCp5i6uXa+lkXfXYG7Of4yMAJ3BjLXJQpq4VsMWNmPyNrRkSqXrGQx9LqgI8T03oEtFL3/PFYPRrzSyGjfmI9eheP+AAXqA3gs1/oubIBVffMFuw+nK0fdZ/L1jazaZpKBzwsa/kJ58ldzif0LYO2+PURDGf4XjqLgn68LuvRmbuoAmdJ6XUVI4KzWAWHEj3Zbh69vbuXzn5/SiZQRHIITKggMOdbzM+9bPv9vt6NzOyFSOcIz6VQoBEwoD1VQPBv8KeSkaKScfVJz30KiB+joi3fMAQ7neP3ZDaNkFkTAAA2CWIyckm9YWoiA1AWMyTVTCamk0kys7ZpttstEQzDkE3RaLXaeB3faUio1jXtarUK9LBqaeh7naaGmNQkZ6aYxqyqWYyBMTApStI05jQkImKvbCNZRVJKE4ABZxFoIscQKDBS34/HcZ/4/YsmbEz647Ef9x7LeAVbTtP97n5FkPtjiKzEkuSY85jyhAPEmMcB1EKgrusCUdeE4xFFUrNZrVXfvbtL335rph99/MlOYETskY7AK6Q96NEy2PD+7fv88PDqCj87vm5EjknJAMDGvpecf/nrX3Zd9+mnH3OkdDjGyE3TIeJqtbl79+4Xv/jzNnY//elPt5sVGiRRNYAxTTntdrs8jGjw8x/9RCRJykzEQcBwFO1Ff/Pnv0hZP//JjzuynIYv7u/X2w10m904mHUAwETsQCVoSNR2cbVuiWGc+iRTE6KLtp6YqLgEgNrMTSEn90CRIYA7q83MmMgMHeXOABE8QAzVCqExAEQKDtvCRG55A1HAucAOEE7TAHDmucST9fis6Kz/uVqvCpKix0IDQAmKLnc4sT1ydYKQDIy8ujDgfAxGBlqOFSx2hIAGGZHn+qVAZjEv/lqzp6OKAMDYIIPCXIOLzAFSCIDEUIAUAnJAZAQGA1uAoL1sVKGxaGgAaLrwQgTzqu+ogOLU1oxcJQJUA17qEdfG0npUi3RoVRR0CGHKORDJbGwAZlZEXfCwdWFaXLqmCmpemw4WDJgFwEIF0AULLwZrhqY44wZc1meyRwfFv1iWGxlKdXz2iUBgJA7FMQdaOcdFUKQSbaVFguHHoeueQ18Y7SxPmAKYIhCh52K5qG1LCRlmfnh48Fo1ZuYM2H/qum6/3wPoer02s91uhwardSuGueQ5IxETADBAODfFnCbMxZw69RgAzIQsFQasCDCXQkIABmAENAGBTBg4EjGDppPyb7Lcx5DRzObKb/OzVRFETCsouIX9z+PpfpcZjxoQlBTQM5Sr7ecOubA8C1z6kGyCSmaISouwCujo9mDqdYjh4hOBTzj49Sc++sa3nMksjAKYgYNlLusCTlWWl09/v9qvfjIF2LxE6k8EIFD/BAP0MHVUAMYZhP/s01QR52ME8msZ/QQ1AwMxASAjpgj6stU2H4fD8OKjH/3yL77aT9yttgT5qkMdhgm9OmFoCXXaPbz9qs/QbrYxRhcJiYKbdmNsGAyNfvr5T49D6scckEilUfzRj38MhDZOr1+92R32b9/fvXz15uFhn3Ma9mOIbVjRH/7BHx8Oh6/e7tNxEubr9WrVxrf7HQBcd1Eg9AJ2SG3glkyHgRTWImqTrmAvGGPEEICJOQys0DQo7dthb4wI2k89EbGCRPz27ts+TUPfiwjvvum6puvWng2FiHDcMTM2a6dZfz7m7cvXxi+OBEB4AAqb6//Lj38yASByE/i6Cdw1bdNuY/QVmKeEpj9edpeRgpGXjvfd/kbk5X/z35nMSkhOo6pLGilNk12/sGG0JP/hOJCIStKUc0o5TyKmhu8PY7fe/uJ3v73ZrLsQ8KPP34/jmIYkmA/HTz/qotntek05o1rThf2UhnGXpb++Xt+9/+blzauubSNHpu3u/fu2CU3TvXv7/vDp4Ueffb6737esfX+Y+iFQ3K43bdNokj6N7WqjhgSWwRRIEcQIDBwvFBkpzF5SAEPAlEZTQRUEiwhoimbJtIlNxtNOx0UL91xSWKD+cMnXnKNPmbIpGXAT0fkQkwEoAjHxcmHOOYbWLdYmSoREzIEBLKUcAocQRXBKSSQzh9CElBJHatuWCCDLMEz9cZzS1GwaMVMBU1BQI0OyGAhN1l2XJSkaoSbN7boTSZAkHacVNdMwZjMOq2Hsqd1wWBOvjsPXRNQgTFMiYgQ+7I6FzBJYFgHNTMAc7+93TbcaphQ5ABKEOOXMxGNKm5vbSS12K1UFNUTOam0bY4z9MGTV2LbDNAFRt17vj0eOcRhHQxxTik0zDEOeUiDGpj0giQF5mN4wtO1qtd3sdrsQ42az6fueDGzSTbM+7o6BoglMOROFJEaRAGGSjMAc2AQ4cBtIRIgCIIcY+2EKsW3a1bEfRWEcJ1Ujjq6cpqyqmgSmLIdh3HaBYjMNaciTASpSygIcYmxh7GUcBTBwICBBVABhzGiCQIFnD/c4gSAoqgLNKGEkYsfjMZsyAWRF1bAi5sBIkVhz5hV33RoABCQEMpqrHrmwApVYc3t764ndfoLb/xxHwX2dOSsidt3aGZaYC2MhMAOAC5HsFbafbE9q6whgJgg6V3sw8opnAIBeywlPLllVQzNFMlSvVGNuYpr5ontBFOAZL+5Zq3VuPB3Mu5sua1RetKpgonM+W+oVF8Zmj1jd/Lk4sb/np5Wrzu/z13X/Wed//IlPf2/Pn0+A1TloJmjWmEZQBBbjQeg4yjikOE3cNi4b2BwzopEQGAYDQNQZhBgQ2XyVAhMFM6LFdBICxRhTEiNcr9fcNcdp7NOUVXbHw/pqi3EyQCKCiNnykNM0TaBGKJBTnka1TMzURGhi7DpCAmRFCEBeL8Gw0ZAG1h4g5TH1aZSsgIJEHIEptF0ITdt1oW1ibDDw3/tH/1BMAahpmtV6vd1uV6tNCEEMyeFwQmAOIQQggkDQrYURAyMTIAuYqIkDXhIFiiEEZ71etzi0QZ+Cy+v7vjYyzYKmmk4jmRddNlRTr56k+fiwM8koWVI2yZIyqKrYr/7yN2CEZimNx+Nx/3C/2+0mpN/85jeMlrP84pt3KUsQ+5wjKX61Oz6MItxyQF5dU7fGJqDYtttKNrJ8GMa+7x/eP9zd3fWH3eajmw5WzBxwYWxehBTVABUW9xqhkJAX9/WKvGXzoZmZgIEZudg3y72CYFmmvOxoqlrRg2lBmDEzV+NqDa+MYY2gV/wmZhZC9ETQovnNdABFdQ5EKmF0ZoaEqjqOPQD4Ul6t1m0XJ0PQE3iWzXJ2cRCfpGdX9NsQmxg5GSKZoRqKUTLqx2mTPWFUMwFTBCNVDTFC0ZsBEDGpBYSUJCVxag6mzGhexDhrFgO0lDUnVdU0yTiOHhBUxqFYES7st84tzjwm6ur+bLwdczLCLGLFxJoFDVTVBGwpkQNGAGqKBjbLlIJCAsC+skWMCPzAS49MU56mTBRg4SPLjKihxtAwBSNX5Mx0/lQwU8imCARMCCRgAmZIAmDE4onUp1JWtFTLdZvFPHdE7EWOVcVynhhimvI41fxOEWZhDl25r1XBxSTAnOY6KnNYPi5Z6RfG9mUKZteNLxRZlst3MuDaJ4Gzl32JbbZKZ1vKODiTXbaBAHrFrUr3nfVXP3ERftHxtn6I2/i8uzYz41N7lKNc1y2uvN0fcAz8LWoXG+w724XRz85DOUrKh6oKGAPMy93MVJMKoZKZEWNkDUE8DBgQGclQDJhRCQFIFRXFCCkwd80YLW+65vVLCvF9miY2vO5GNghpCKOBgxkBEiYeoJFVFxGJwaaxH8deUTPDQRO08ZhTGg5pGMdhSOOUUhLTNz9603Td9vrq6ub65up2c3u92lw1Xbu9uobIFJqma2PTxK4NobHItN4ozdFDsW1jjOhw0wKzFEHkeJNIpMS7cQJiZDJEQ0IwNEBz5wBMhoMquo9cLYMdYNLFulaTQrzqHk8KmTaiEYmRiDAQ0YxxrW9igyaQFURFk4k6HfnMg9dydu0wjWNKySTFGNM07Pf7H336yf39fd/337x4ubt7C90L1YjcW5Kd0eH9EadJpvGTFy/6fd+AjMMEigFp03ab7pVgsoZD6AjQAL0cB4cgJGpOAQEQFAAJERAzkZGiG6YdJM/ZUgKQDC6RAaGLDSCidh7BW2xvHkngrcSZ15X+6oOCoFTuUMs3xfpa/JfOfnTBfvLVLiZDmoCM0aPAkJmRg0GTpsKlAHEunAcw09wS6GtLLGHTNCEEVvEvSx+GMaWsHJo8jqLATatI2UCRKkMAqKEC6Yk5Voyq2r9YuUh1LoM4iykFBktE6hFY+BBRlVA0O3EXR3IIIU3J3clapUIgoohkFVCca84jiGlWAZgPENEyBJi7FELAudKi6cJy1a3oswn99C5EWDDR3Opbou1c/CrLAErMJs4iUb0YHpN0WwInQwgCCoamjuMGVOWsL52ZV2+59jF1rWgmFlt06SFWrndvpVrXxed3MODL55ob658GJsc5oHHutDrSGoPOPHvZEmBm7uVQ04okuacX9TvU2fPmntHvf7ItodpQ8eDv/7i/S+1imdoceZdhEZA9c7QmhaaWVSlnADU1BaMQMLAtvjHyen4AYtkQENBQzUxBiIia2IQIXcubtZkd+wMyrq+uDEFEJlYzySAEIqo5SFiFbr1SwSz4fre/O/QH0Qc1HYaHr79uV9319fb2J5/8+PXrly9f3tzcxG7V3dzGbrVer1ebzXq76dbbbr2KbSdmQgBGho6ADwCYiR5UJ4/UcxNwLzknxzUs0rTZjDJjiH02QTIzIVDVycGM1CgGl5VVFRUBgAAF4YjiwTx1g3P2UBoCbEJgl4Ec/sKAEQHgxc01eo0WNRA1EFAE0MgIoOQMa30Vb19EDkRgxGp5A3hP1Pwk5OOx+dmP+asvV/2BptFSlinpMMg4an+wafj6/g4oBjMhhhDfZ/u275uWTYQJmBhVwJTMAiNzyJIAAUAAFQGY0Lz6MiAAkRKgmhGhDwYgqTldAzIGRc95VSLCaihKOE9R45w4ll9rqfFiPZeNrEsqVFHyahrqc+RlJOBE6OaHTtMUGm6aGGOMSCKWk6Q8IjWFfzsDVlUDmiF4F3HWFoWyDgIqDzeEJKJgTbca0wTEIUZxyEsvSq1e9sFX6SmiuzBaEZkdwMQFE6M2EqgKwJwzXVC3zKwkqTtLw3N47bIaS8+9MKiXKXMe44bWbJpUUDCbRkMBU5fIDTxm2z8FjH1lIAEhGLgiKaYikiQHYwUzxwAzsCXSvogOHt5Ypg8WnwIsOvrMgBfvdy2LPLkwXC0MHNjYlND9xLTUEDwtqksWXutpRVYoOUh4Dt/mnLjw3cLa3IJdpslPDiGEcxun99fXpXt//VQsx+UEgEWzXF7SToCROqvLquYBBLPx2Wnxco565QlXfU9vPJPHOT5rUfxPv2I5MABw5w+c7EDz5XMnKz0Yznpb82D429+eEyM+8Hb1qqq5AoACKpGnh9g0TToMfH2NiKQNzWEpYmYGFkJQMgFR04Dk2oyRU1IlYkBVFZ2rNSBRELFDP4jI/W7vZl6Koes6liQiBpA1oQIwhHX3xbfvOK5pfdM2q5c/+dk/Xm+yyvb25kd/8FNuYlytu826Xa9i14YQjJvVzRtB9g3cT+PdlJNkOeQxTRlM1RQsiYipGSbEMTajqYhoyQBRzGZNw46ToGCmS7SRWdNunAFnMAXNCIoqDByC+9zNjIyIiJGQobdsjxgtPAJLmo9RH8KClX+qrwAAMH3z4DMDAKgGaKaAIJonwAyCSzatljR/YrjZXh2P+4/evMk5/2i9Pb7dfdY0awrtmpottogtwhqtA8uH+5BHGw/Hu29z/9BfrX+DuFJ9tblCMAOVadSUUHMLtIpkSGgKoGyGOJudXdhGDwT1CCYDJ76Bo7j8gAZEQB56wSRnhqhCs3TBxqq1kwv7c33gpLle7U4WmRbZsXqEa9IuWaqq50kzMwVqmoZCVaBQNGfNmWgBZCj7xapoLN8LcwppBVNKFddfLuFJlELEEBUQiMcpAfEcQ4KmRnMkMs3coPTfabo/k8OcETRNk/sd60ErUWwAME2TV86oGXDpVeE9RKSG5aemaYZhCCG4MHpCOwFQs0lyFoEAoppNSQQBROcMmwyKAopoACKZQUFtyomZ+3Hwf21sFMzEQTjRIWUULKlAzohY3A3+dOe+uECw1UulXgYLG6oNt6fSvydzguHCOM+MAcutZg3YFXeoeHA52WMRmqYpK5OIHBbGR3jBWgFc7DdPtu/2AduFmviMejq/OQASmADMGGSzzjlvqsJ84cwzMS9oXweA37/AFH4f9/FZ8+c+kVL8X1qr3RVl8QFA8FIsi9qQ8rjfP8j7tz/9+IaYI0dAMkUyIwkIYAwEpiooakZ+tYkCACFyoJANQE0FUAlAhmni/kHUgGTID0O/ezhsrq+213A4TkYYmkgYKHQh0Bav/uF/+3/i9vrF61evPnoT2mbQTE3b3WwP4yCMSiyMA9peJYlk41//2X80anyjTlmzint02tUaAIEYCKlxNxILU480+eol9CpACEyESlSkPkJeqnOSzkoeMAKhR76RIRAGsznjYQZtxoBoME2Gi0SqpmDoAQhWUgdOnxJsp0NeyDWoL1FCRDwcS8ZBWbEGypgBHTxxDt2SlF3DM5A7Dl8ch68P02738G8fhv7h/Y+u1iuFQNAiNkSbQJtAK8JPb682TeSuwa6N/Mmw7h7WLUQ6qpkpmmqcNBxRMhFyQLGeLbMFhcymSMa+q+ZERC+cJeDeIQRGALC8KIIKJgZmylnKKnTq5m9XopprwkdL2LO3+gQPQy3spLRigC3f2JKdjEttPjd1hhAChvV6LZZVcs7ZsaAROcZoJYq7VprxdKw25654/3POIoEq03dKaZqEOTwcj22IokZkU5bjOCCHIU0gOrMcRFwgwHJWd7fSOdhIqcAzDENKyZVdRCPCnOcqRqrq+d+73c5rA5QRwCrvSxckxbrws8soIUYzc9DjovOZWV4G0MyyCBcquqiQPuKGoAa4+AWyiluwRWTCVCuIdU+KGAFVMqS/fgl6t0qyqe9Q/rzgwbBowCklUSEsxg+7WB710oLiTz1/HCwG+WJEKc91S0P9am4+LJVFyvKY6e3ZY82JzummiDyLdzCzXkRE4EUUPyvP5Gy0vPj8DmqI4PHPc5/cB6xWLNwIjuSC8CTi6ocbaqUkF8CvC79vrQfP41jz4L8D7Tkx4rkXLIIk1OsV0c2r7rP3pTNNU394GKcJEZUbYAJCFVAEAmy9cEvOKsIhsAAiqyohM2FkQoPAyIBoGsCgn4hE09RttlfXb6bhy7t3B8DNatWIGsemWV0BB26bEFqM+t/93/+PI0dDzKD74/D+uO9Tll7eH1JCG1VHyV6+PkkWo279Aqhhdqt4sX8Sr9eICExIBETu3EXiSERuHcNS4g1c9i6+SXCnJgAATP0AHv9PaEBeb3bOdQEEnWP73THMALFbAcw1UNx5459pHH3xKXicBCKCAEBshBaaaASEHtLVba4A4JSwsWjMh8MD0mIKA4iqUU0139/fu0hOn1jYXF9/nEBxhT++29/dySQp65QwZ04STVsz+PrLmyZGyC3Zy+v1tUI36evInw7pBeK6iR01DceGdU2YSS3HYFNUCZYBFVSICEEFB996qG5WNEJAM1KxOVaHBESBxECzhoX1npG8JcvoMUmtT7tY8+U+J0UHQGcwxxMyg//EVR0wV1ycf4uIZwGX5xIxYMjLbaHSgBEuGbAuoUxaRT8t3Hfq+4liPE5pu96MU2bmYUrHYaSwmAcMECAiASASMc6stC5S4lST4VTZ17NfmqYBVLPZBF2s0Gbmlbb5vB4RLZVUShaN0/OaZwAAEXVdt9lsDocDIiITEEqWJBkIAUBMoXgTCBFOYB2eapVNYQkiUQT/l1TKeBaK5LppcTnD4oNIKTkkZG08r1W4C0L3mOiVxeKvz8xz/hOdoC6XFWKIc6gUImaRcnFZYEUe8rcuETMeh1FOqFdsWa4Xn89qwMs6u/iOFlLNAHpmt1Y1EzOq0q08+3i+x6UQsWjDtRjrwRwf6NKjLioq/1AluP7j7xIP/kHNlnZG1yroXSJoIntQpZn1fY+BLTYGrGjk6pmXrzYFURElEM8rIDVgcJVSwZCCYTYkQ04iHTXAYX19+/L1J3fJvjn8Ttvr689/TmPmdhW61aA6KBwA3lr+1a9+N4QWCA1hFJlUFDAzZuwUQSPbiqiJ67YJbcOhVSHiyET+LgBz0bGUsycDiEo2EBOb/xbxWECcrWg5a1bp2rWXpfNB0pmgSBPIFVmxOdkLgZUUjKhEFwKgAQGowWGaLhaY/xljBAOpQlXNLKHhNrKbAsUAwJQMsyFnHc3d1wAANKfqITSrbmZ0ZmamgApqGF9/9pnPMrYtM5PIfr+nrqPVq6xJUzYRFDMDMZ0UZOyNaDw8pOHQHcR2uzwO1yqfTunTpnl1c/P65vpF11417TXjGnDVrVqZWpWgU2saEAJYwKwQCBOpIAKpuEiCbgFQJFMFBSUAMTFQjV1HVeqjLqgOXt2o/ClLKz7LusFCHIsGbMvABm7rE8pPxULLzE3T+KSIycNhz5GawDHG4ODMgqJzMYaa5ZsZmM3Bp7ZAaD0lB/tbTNM0pIlVpyT+atFsmCYvp+i+Q5MTQScDMwFT5jNvrjPggORKVdd1aTU57hCSqeYYgwPgAEDbtsy83W7fvXtXhAxaSiE5Az7ByjLbEoPp0Jg0V0OJm83GE2Gzpnp4L+ai1gi9jVlYGQBcTZ+mqdjM7RxCa94IOktFC1gY5pynafICMHaOn1irEFAxuce0rhwEdqyBaEAKwCzFf19uZdU9RQTP9WxYQmTcKj7jaYTgoozb7YtIB5XAVw9R+Qwwy/DuYwBEcLP4bOkynHN9XDs1JYg4p1WwwkmvJSrRdELIczKGh7Ojkq9fhxdRNrO8UDCnV0QEaAasWoGqVPhhp4Nq0Ge5Bax4rP0vANAZ/8O7StXxWbuQuy9m9Du/f67VV5Vp+M4z63Xw3PnPRcA9d5/nxIsCrlaEaDPLIkS4WnVTGhG7zWbz1Vdf/W9//o8+2uBh6Nu2xQCAs1iaJYNpE3IkWsUWOjIFNUtiptiPPUYbhCG0zfo6WJAJeE33336LxB+9+RRvb98Z3v7sj27+8B9Zu/7Nvk+8yhrzEDOyUlTE4ybctXkIEYqi6ZGTCF2M6hmoYIqQwZIZCIz9ADA5sEI9TVNOlf5Jhur2Y0sJTf3bstwI4bg7ZNObmxfTNMUQvn339qOPPto9PECDZAoI6InVAADEoDG2rhijGqi560URuAt5MXMVCxsA5OlMk7M5PlHT2wlmx5XDhKEBGHh1IEZ0pZ2jq3qM40HkVAhu1oMR0SQjIiHexIaIMDav1xshHXjKaCKiSfMoaZqmJGO2LHwAtW2Lm9eTiWoGkyySj/svpwHeH/nt/ZroOoTbJlwTfnpz9bINb1br22a7JowgQa2BUYYx2hSROuKWmo4sGrApmICKqKEqEQbmNjIATONwsbl8vzw8PLjeZosJVFWPx2PRPJxzwEINPUrIDde0VAEHAC93XwYZF2th7aJzBUhVxaTrOkMFcJBLQGQwRsTD4dB1m+vrawDo+16h4YazKqioKsbQNA3qFJqGCO/v7z18KYK1bZuGUVXbtl1TiLEZp+zOjr7vu/VqypmZnXB7vd79fr/dbo/DEAnDwn0R8f7+/uXLl3fv3q1WK5HZGLvf7702gKoayG53T4TOA7xasL/yarUCgPv7+67rpmkq1gV37s4Fhheas9vtrm5ftG07zbXO4Obm5v7+frPZDO96x1Bzd4AtRum6MF8ZakRE1IeHh88///zh4UFVb25umHmz2dgSCnc4HBzA9d27d13XTWNy6uRar6Oo/vEf/7HDn5VZc4FmUhOMgeHq6soH3BysdH9sYmPn2gXiYtA2FXBRXDJmFJGl/AwziIyTZMMFChwxLAW+/JyU0m63a9uWiByvvu/7ErC93W4L6y2j4evN59Gzh33EmqY5Abd+gFg/ar6mFfAsIhrnaEA33SmAAqKZQFXCwWaT+rn/3C8zQ/Ccl0fqcqWqnh0YAM1FRU5ffr93uLjtc0958rQf1P4q1/6na7UU6bYpMyOlYQl+Jg8iXfxS6/WamIVJweuOMSADaJo0IGgwNgBkATSkHLhpmwnjgJwgDmh9ZNk21trnr39Gq6vUde9DOwENxgnClGH16c8ShAF4hJAMJ6NkeGQcI6WlLlcxLXpXbU4uzCmlSbKIoApB4lOowWn9NF0DAIjmWhKyW6K1Bbc7AyCX7WqIMcaksupWh4M2TbN9efPyenNkbUgRsgG5jXWJjoa+7wmQEZiJkYIzSMK9TNlT4ZBmbLhHs2CLPYoMQAKBokdrz/HUrn+vXETOIh61bWpZcGLMS8qHa+r+ziklICRgCjNEABApKXcIjBEJgaEN0KzNM14UPC92cpukZhFJmg7Xt6ijpolSej+lb3Jqcmon0V/85W0bPu5WbzabV9vti8365XZ7Gzcvt5s03Enfc04r1bVpI7lRawnJAIEjz+xE4VTTEB4ZmT28xTkEANTEt5gBuaqBURYzYhWw8nzDpeBbTQBh8ewud5hBeW2BuH/sY4aildoswRX2Ux5USIqqdl0nOtS7zxZE65SSq+O7+wd19GzJfd/nPJuOj8fjarXyatyR5nQdERHM6CCRljebjUguInWpmnd/fz9Nk2es1rbT7Xabc+77XkQAuWka197KEKmq2Qzo6/jhpRU1zlmRLllPUhVxakMc49w85M07ViwQRbmf92nTwBKbXcQIL1paxrOM6pNktdaRLlaC9xkrxb28iKr6XQmJgX2dmVl/PDQx4uKvLLkhzkT9nv5qtjitsfJ0FCGvXg+8WBqsmKAXX2/xlRIYVgFOZYDMdYiKL+KinV4uept9AI5QhuC8cuG+popohISAxAAwkw5bMMnKXeYeLsdYR6bNFNYAZBZXATyKq76u1n2fZOQX3f4AD/4+3LS+4d9A1ustxlgomi6BoCWSxckQEU1u/2EMMahqzlk0AXNkIgoomI0VAkHIFoyCEgvyhEFiexDoE/VKg8GI3diujx0dVtvUNKHtwmoTV1to1xxWzM1vH/oBeBA6Cg5Ze7WUbRBJooKglk3Uspi4r0364zEgRQ5NiLHhm6YNITBZ7u8ZMlXpAbwERyAioCIaAQAZAbLpmpFnSQ6gVMdDRMgZJKTehv0KV1ctr3TqIAdUAlFQcNPqMp5vrjvHQXMAQpqzpmENyRbINf/ExbQFlSvoRLAiARAqKpbgC3c1orrJ3xgWsVeQDlnlzCYEZKQARCSmeZIxTeM4Tsdjztk0UcTAaMgIEYgV2CCg0YuXrwQphyC0ktYMFRFTgF/df5E5BNiSKecM0ximxDmH7fYh6xdpig998/64Yr5qmhuWf/TR9TWm69C9XF2/iswgNh1tHDQPEaBBY6Ywo+CpmUbi4l+vGbDH38JCi4dhKOFUTs4K4a4I6KmV8SR8Oqyk5A1ffO+kiWaITYCZhBkzA/FCwbGuMeOXACxV03W2KhWi64e+v7bbbZqLuhuYEBGaOAPOOV9ttuuu/SpPIqmLTZ8mVc15fuuiZsGSx+yvKTpb6dXyixc3x+PBFnxs51vr9frm5ubdu3eOL+ZD52zj/v7BmSIzZzE3FK9WKzuz6qvOlQayZ8cVe3gxmHfNzIBzzkJL8jFYCNxNTRebKTbutI7EVsF3TxwicUBiQAak6MV0yd0NzvDcnnHBxmoGfCG9PSmEXch5pxWyCHBmsERGL0zKrG3bgl3l419ubosvg5dKP4joA27zStDCL/RRpS+fslBe7PuIjTCzVQTAOYu3yt9CNHT0dmMFQTMzQhM79RjKi5lJKaHlHVuI0AytVV7y9NynuuNJTsu71Zc8IavWt7rgpuVLOOfBxXUPFQ9+vj9wIYjUl/yNauXFTxwXgJnGlADVctIQHTp7mPqbq+jZe72xMDTtuomBIDI3SWPCBpmUojBNwBnjhHx3lAFDD3GKrYZOY6cUew7XP/tpzzipHSbd99P9btgND33Gg0BCEmgycTZWZPVUFhHA7ABegSEwERAbvb56Te6dywI66dSrqML06rojMPSgP3W8XQDQ67aFGZQpm5mpoBGpyGGPNsfryWnuSEwBIIcw7vYxbdu2ffvNbySlrpnL5y2670zBD/sdAIBmh8gAXSKiF99PsT/7n7e3t/BIA3Zv7oxQfNLDyMy61apMFhEBU0Ayok278rQoABBbFi0iIjYeadYwr67nWSZ79+5bQxBDNVajpJbU1Owv/+2/VQoUGGNDgTEgUhgae/nRbc8GaqZiWSAnSx51l9M0QT9J3+OQ2DQIXmX49S9+86alj6/Wn1+tP1u1n3b8Sdy+aNe6uwMlVg2gYEgmpoZucK63/7JTnAQ7pYZF1auzYmoyalU6zeX2fEYAdh9evTcRcclsXG4C4AzYhVGtYnDqXe6zW/enprZQUQ/QvN1u9sd9SsnUM5rAzHJORJzTFEJou0ZEQIWZDXS1asutmqbpui6t16vVKhIXa1DJWMMlIByWUGEz8xCtGGPf99M0+Z/DMOx2O0Tc7Xaul6/X65T1eDw655tEy3rD80ZETGSeJ4UYQyDmwCxLDVq/wNc6IhM5sAwxkqKigZoRuBOImNnB8gJxCMEq/3HdLqjWLBzMlolLmvZcq5l2fc8iyZWZUtWsJiJdbGiJxHaDfNH4bRHg6ssvluWyF+dJqU0+PneBqEboeMy0qrjiueNFA/YgkXmJz7eG2ZuC6NAnc7D1gipusJzusJVACghkznFV5u2i1UMLAz4NY3XgOdwC6oq/5wK6/aSKfK7M0vlcwa35bpkVfKTp2jNq8XOtnt3vecl/5uYuNFqwxVXVyw0eh0Pps8dxiEjTbFDGQnfKKGUMU7yesBOECTAhj8AjhAHjrqExrrTd2vrauo3EVYJwJPz337yfIpvZMKZDPw0pK5AS74cROEAAphiaGCITx4jgGq3HNAWwyBwQIuKwex/AGsLQcIMYYmQkxvb92y/NkhUMIMmgaia//eZbcGPunGIloIigEYhAFQFhSRhFACCO0bWEcZzk2BLRL37xC2b++M1HPoDO2Od4A4TNqkUDAvQk0sBMGNDAKYp6mTMRne3J8Lt/96fwiAELwrt+L0jFhw0ALkz0fQ8VfRczNFXAXd8jx7Ztu67rVpvVahXaJoSIiEghhBCaGEPrwExE9MnHb8AAkQ1NAYw5I4rhj/7+jzJgUplSGqbxMByOwziaaN5mduMAMDOFpgmBm3YaRuAGGw3baxBFway6y9P9rnmn6Zf34+brL17r+PduVn/y8cs/fLl9vb6iiXgafDrI1BFtiWJd7r4IKB6EBQt99M7XpkhvRcmoASXmCfqg1FvTSjhTvn+YrHy6iUGRJFwxAj3FQhclp2lCZAdQEwYIBIQADmOMEJkiISOgKSGgaddtygppmqZt27FpmqYBeapGPeCFzROXPNr7+3sA6LrOqwu8f/8+xviTn/zks88+/+Uvf3l3dwcAbbd2fJLCWsrlruS1bZvTSIgM6OUtgMjrNICoyy9MtITFooDlpKCG5pidZqLmQWmQgdCz7xzuLRBHDlmqiORzVRXO6eqTE1EufMy5z+92qUSdWK+p11dNajlnEKXl2qKR+yhJBaFVj1i9qIrIUmwG9VpV1VC/Sd3v51iGmS+0pZzIxbjMnFbNaHaKsLsM69vN1vZybcnmnTP68Qk+d7GdFt65aMyLrAEAC0rpfF35uLhVzRrLVD3mzUUDrk9+3J/69hfPwr+RGvBJlwIYhsGrV65WHTM3gYkhEsYmeGBLjDGwgnGn3YSRAgtYNhWEHTQDtRk4AY5Eo3HPbU9t++pjDe3A62Noe4g7sd2Q9jnfZ5YRc06HYRiPYzaNMTYNvf7oszKwCgaWLSW2fE2JNJuKSQaTABYA0PRNGy2NMg7T8fDuuJ/64zSOOafDYUfu6CVg5kDISIz2kzdvEBx0EhkQyeP1aLXdADhIv9fLImRCRC+26HhAgDyO4zdf/OWrV2/+wT/4hzPXnRnwDI3hwNqMSIABkGZHDoJ47o3bfkBVANBM/5v//f8BHCDcS2KYAmAG26Vh1mgX+Bp/zn6/JwDVvOg9c3yHIuWcpzH7JPbjMI5TSv1+fxTTacxjmoZhGsdxzMlyWnertgmb7fX19e3V9c3m+qZbbbiJ3EQM3LXNpmFeBXi5BdgOxH/2zUOfYTJJBhlUMSlTRlqvNjkgBAQAUxSxnNKYG4mrUVMc9u/f0+6Q8/0Q6P009v/1jz8FGoHYNBFYAAEQlzoMLjeIbzQPlHUS5gqHx7DUOlnx48KzJOLpVscTPP51pubg/rUZYNLoJB/U++iChEJlb6wjkoo2CQAECohISkSEwMyRMHQdEahqGwMziySuCjPXPRcRshPcBy7Qv2oZADyoG0sWgFlKqe97Z6XDMBwOh2ma/uRP/uSf/JN/Ygb/9J/+03/xL/7F8XhcrbceytT3PYZYsz1nG02IE/HplReLwQyFpLNkp4gMqIikhvMCBt96BOhLWkTICIjdAEIwi1lqGXA2sM/BKFUscU26qzF/Ivj0YtDK7MwAKVVZpMI7/SlgUi0NCyFYZWfWUjK1YqjFiFjEwdqr7X96QJwu1VppiSU8MeCT9OfZDk8wYAKzEnVlZkXiK4+hGXqGzWbDHiKGk1yJ5ZMqgVWtOO3Q9MlHL1DWCyNcBtd03n4CAB7ABSD+2Grgl/d61Oz7abrloY8lr+9sv99V/6lbWQcAMAzDw8MDMyMChdNiAoBxHI/HY84ZTZApxmgYFVBVxCQh7Y130CoFYc7cpNBNcTXF7hivHoDfZbrv5V3OD2O+H9M4pd1u14TYrdrt+vbNJ+t1167a2DAddzswgZxUkqbkcMck48vrlvKYpmGaJs3JcjJLYPo///qXAYUAIgITMMEWESP89Gcf+05u2hhj7GKIIQSEaRiRjAARLcxZs6jEvZhSKbYGiJ6eAGA2Tb3o5EErw3B8f//2o48+AkN1tC9nkMC+usSRFlXBRGY3MJTExxJ9DTh/vnv/1rwKlYktUB0GDiE50zNQA1ACMLP1euXorQDgiRJkAKiahRAImQKHECgwYTDi+/c7BRNREZnyTKlV8/v376c07neH9w/3v/vdr9796d1ut9OpX93ehiastqurm+3NzfbqdrvZbJqw+ZPbn4mthGBQ3aV0P07vh/GQs+4HATZijDF0q6ZpN816IPpqvx8Cra9ubq5vwv596t9/mffw9duff/KRioJZYJ6F4qympiJ6ckWdjIGlrq1bTT0KaZomOwdqwFJ8+lws/s7dalVcOlUpmwjgZAgqBgyAbk4pRNYWarKoVlYdA7hZUk5sAxdV0iShCc3nA4FFQiFkxqZpwUTy1DYhMOY0xrDEH1Z0yWXi6802L4hRJicxovAtP/Y9nnNer9fuxC0lBFar1e1nn8GxX69nxTfG6MAd9bjVwUR+jrPSeSJ8MaqFyJXmZmpgol6YkBEDUXRqo0pETqBd4GXE6h+VOS2+aji36NoSd12rTOWgnoIy0VidICKi4njviC7+FveQ2VKcABFDYCLabrdpmnxUzczTqHLOMcaSF1fnrBcbdVmW3iX/1cXHIoqZWXCL/TJ/UrFeMpxRe+yEPUmGQEYGjkDvzicEAKI6yQw8cFDVCMHATlWezbGbT1vIzATRwCIGQDRCeIIL6sz4HSN7Qco2UAQ2E8cSApsRhQwchAsK6pDj5hsCqtqlo/dSdPrwvv0gN9XlrP+Exufljc4+wcvQgFsQFqwlAAKZT3B8gLmKBvXDRERd1zBzbLquS23bvnz54uHuPQnaNCkMOQ/92N8N40OCkCHE1ppVim0CzmgRN0Oz+QJe9PHWOFjTatNpt07NaoyrP/3NFzuFXcadwohxRBJkiPSHf+/TBmDVNl0TA1vqj7uvv/zy4V1ECyANUWBbMwWG2HAAeP/bP7c0jOOYxiENvaYJJYPpH/3k84jQhtA1oY2ha0ITIjEc+94TT2bfg444jWS6ISZwPdUca40MFPEqdhlEwDS7oRhFVZDCen0vk5A2xAhkFBtsPnrx8TCpJxstNFoJBEEbJk+BjxQjoVdvAOTB8lI35wmrSaEj5cANeDif7KxKAADE8+w9LtfVX52TsE1UkphOImKqAgIWmgbB7eDcRsKGEREIP/3o1eLmRJuRe8XMfvO7v9wfd+/u3n75zZf/87/7j/u7t3DcwQAf/+QfX1+9uf3kk1effrp5/Wa77j6hbiR8vz8c0nSchmkkHQ4Wu8xhCjFcXWezfgKgFayRMGLPacpfW1TgwGGFBggoXk8JkiqgGiEhh8VTyIgPh/sY2VTzOAoTdZ2A9cNA59HLhW0XaKHSlq23DOP5pw+gmZmpGS6wqeCJkfO1M2VA8PKJaEty4wkOhYgAjMAYvIYIIjIAKYIaJk9r9Z3olUpEF4AzIJvr7AZmImqbxswk5RnRcErcNkyFvgKz11xGAF2v1zlP48gpjSImkjSTqE3T1LaNa5BQZRt6uhEibrfbpmnevn37L//lv3z9+nWM8U//9N8NQ//ixUviGYDs+vp6d+zRHdSqKglyQsmgU+TglZXVMgDNBkhUZgZ0+47r5GJmJkpM4NyImYmyauAFM43Zg/Nx8RciomhGYgIDNALz/OoSVn0hZtkSNrzsK3IZFmcnTrUYyLxml6aM5mB180/ZdMavNpihkxGZGIkLT132JrnlWVVLVKAHll9s57Iyi97o4WkppZr7ikhQKQsUCRmYPG1exYyQAT0T6vTaorokQBJApRCL0wrRWXRFYEIVSYA6A2ctQFeISw0LLAVPTIF8vKsgrEKAHE8QaK7ANKNfIQCgyxBgBmBkCjPg/rx7GJGdPfmHF0ZbrFhzdwAWM7jDgZSbL8XX4PTFfOCG7lrgclnEsRAQqPra+XHtX68xueqY7WrFPMO5OQYgMhFATOOIzNfbzd3DvUxpc73RpEMaNt0qto2mTGghj/5CHu9qiAZsSKFrVPUwZkThEF+8fI2IaRBKIe/S5z+93Vl+u4YJh9Wbj/dhe3t9uzvkY89JN3rzIq1WD5q+SdR9/EfS3WKzOqp8uz989X5/198d7A5ie8z5kMZs0HR4e3Pz8uXL2y6uBpXdw/t3X39z/z5Nx3UTbq/Xn320Nk2Qxzz14/Hh4eFu9/D+sNunsV91cbta397cvLq52rRvVqFZMbdMOk3RMICxAYNxRkxGkDkPxMbMHHAuJWRABg/376jUFQdAFZd4IzexaYacR81tuwIOWTG33Tf73Xq7vW/CO8EudBu+uv9yuomvu5evv75/ZyKrGGEaIug6UDBrAGwa8zSZSFYP/zIzSyoOI6GLW7pEY+FihChzreDQRw7feCbamxmSuR2s4dDO1jkY+qPnVnEMHDtkRibkcOh7RAZCBFYv/qyqpofD4Cj/gAwLgheYffbmcwzcdc3+uEt5zCK//e1vr7bbP/83f3o4Dv/jv/l/53/+Ldy+evHzn//oJ59/9PrNj66v4jZSs5kM78b89vhw3+cRiYa77cuPjiLHRHH7GXQphZvVi8//+S9/899+svno1YbSftw/aJIWImHg1r3BJoCqBjmzGBtQMsg5AEbulE2yCGtoQxNCiTlyCpyzAEAhggC1oEMpjwBgioBqCQ3E6zE3sUOygEzMhMFAJKtophgUzKcqCyBoCEAMq9VqP3kiGYNSiA1xtz8+YMTIZsSasmUNhASYk44CWRVFTLNky1nRoEGe+gkVV82KmfOUEDFQwICIKEm32y0qRooyydXm2lCHaUI0RNYsTeT7u3cxBmYc0mAmApI0AVJoA0bMAt16dTgcXq7XD3d3V1dXjowoZk2MLdE0TbvDgZl//vf/fs75n/2zfwaobYgvXt5IzsMwxIbHJN/evduu1tDErok69ddtHPfvt5EwT2gaKU5TymkMoRHJYtKEVtLokKpkymiREAgAEUIAMkXlSERkWbPrmWBm+TgmIJtk0mzdpsuamsBiSmAguZ8mkLxqm0CoJkiAiiKCTCEGQ6BkCjgm+Pzzz83siy++WK23YKYpx9gJCIEGmrM8CijYNE2ejkNEnu6TVZpVF1s1nMaUyKDpohE7spWzqmlBwVyt10TkXnNnZFnEquBntzTMosuy37uuc53eF6enLANAWDTRKtjKCAEEDQEUqUQGArI5yC8CncozUJHvYTGOLUxGdcF8XRRWWQ4eN9JZ+74IBNPlblb+XLI/1IAIHEb/5LQBAJydbWCoqIrIM7oxAp6YHS7Il7r8+Vdv5d4KiBcFEP8a7o4wDEO7WonZYb/POd/c3BiSqr7++KNhOArI1dVVjPHdu2+HYXh1c00IBSrMJ00LtXcRyIq8Zgh0e/OKMdy/uzs0wF2zfvnyGNq/2OV3U769/nj98UcPFr8cp4cUwyc/u/74R++t/ctv91/8+nf3w2BNazEeQncYRsnjZrv67JM3t9tNRByH4/Gbr77YP+x+99sXm9XL25uff3LFuB36/eH+66+/3t/ffaV5tDSgatfQq033Bz/7qOuagNS0YRVXTSDMYDmFPOFo1yEQQFQghQAYyBgCkR3HhCgAwLgIkgpZ5L/+r/6YiQJxpDnskgER4Nuvv2pXnTAfp3EYppRlyHY/SccwShZjIRRghLaBGKF5uN8r4qrrIigxr5m2gSmpDsf7d2/fffXVYbcz8epjbGZ5Gu1RA4Dr6+siX/uOFREx5dDoCVjjdOA71i4BPXTdNYgATMxMbnskAsIQWwzcNF3bdbFrQxNDCIHCJoY5bcnQzOFHTMAAeRrT/nDY98emaa62mz/8yR/e3mz+8U//4Hg8fvnw8Ha3+2a3++Krr//0f/jv/3+//c2Ln/z4zctXn/7oR7dvPltvrjC2m3Z9G5q/3N9R2rXxOndXGdsvvtzTIa9fbZCvfpvosxEa4mvigGCiWBakC8gIBGBLvTU09LgetNPudPWqHpzHomr59fTJ4Ca9ZcvzXIIH3UwmvmdNbZomIASdmbpjWhDHwz617U2MUV2xMvKobMAEoGRspgiAZiCmqt5rRXLRCUBnpWuJSMI5OxwJZ6cpGqCagpdunxvNJHauvrvsXB6GIyzB4YhKFHSB3YTFM13Wm3scS5Ku/xpjBJhToSgnZUNEMURUZtYlgowMvH4YgQYwqehw+fSFbAYe+6zqXEc8Eclsdqt6l7R4LZ8yTcy2JVQ3RXhoRalm+1zTUhLeE+ddgzoJaopes7xoysuAwmLV9x6W4oZEhEuiV6n169IMLPCcsFjLi7VZF4jTss3hCY/12Z9hWaMXvtWz1WzzZc+qZeXMmrea2ZzZuyRUlPvXe6OcjMin4P+/cltS8Tywy4fDAQNrpniJEf1UXeG/Wa1tVn0/xhhfv/4IAIbhuNvttpur+/cPUxrdJ9E0TYwtIq83N0PfL3tlTnQlUAB1KCcGQ0KPhQAAMP327ttms71583rM6X7/5YPwtLr9+PO///Hrn37xxd2fffG+e/Xxm//qT17c3vzZu2//h//wP/3ybt/cvFxfX/O2eb/fjf2xado3L6+utxuUDGOf9w+QUxR5BYZsf/SP/97h+PD+3de//d3bYb/PwwFlYs2btrmO4fb1y9v1et3FyARmaKmJ1DC0pBEM3cwbMBjev7szsSkbZh3V2BSR2fQnn3zccmjbdt2tVqvVqo1NaAPh2PfztnTTo6qJCtgf/sH/egLViFll3A8ppfcPh/6bb65C6CdtSZU5WA6Wu0AN2V7zatNGkNz3IQ+S4f3dw/7d23/zL//7u2++/ubLL6d+WHXddrttYouIU38SjWsbWt/3RUYunjlVbVYdnjcAQMTXr1+78SosbQ7lWHdIgB4aE5iIkAIQcmzBq6syIc2+NEGgVWPuX4uxaVpuYuAGmbqua5lCu/3o+qZpmt3xoU/j17/6y20T+3G4Wq8/+oOf/xFzVhmH/253f//nf/offv3LX/2//qd/3t2+/vt/8r/59A//QRfC/rj/8dXm2+Pdu4dvbPX6xac/v/rxJ7q/mnT49tD9uh9fNbJexya2MR0bHSKhWDBzzC8PPTNw9Yic6OJi9UKY+fVMoS5GyaOja8ZcGwPrHVQTH5+Rmu4xM5APJ0X0yhwMSH3fv3n5Wdd1kwgGNJtTZkGTnYes6lyXd7l5FSVTmOJFfxCR6SwvGRfihYgGT1DmYRj+/9T9abBlWXYehq219t5nutObX06VQ83dXdUzuhtDdwM0iIkIkQIpgLJIk5RtKRiUwxEOh61w2LIUoT/2D/+wpaAcDIshkjJFiDQHECSBJhtAdwM9d1V1zZVZOWe+fPN9dzzn7L3X8o99znnnvvcyqxoUA+COrFv3nXuGffaw5vWthpSFhRGuDan9ATDOi7jAMBCDDy8cEecqwy+LUYY5aCvoBZ1n5yVC5RiYwTO4UDReSFABaXHH4xy+cCuXugk6axq2vMhth+4TWEmbdZ048oSTpRVC3x7q9rXNnxRKODcywWKEFyERhQ8K3W5iphrDVQAMwVYEVoBVMFo3D2qukpZTtT3v0C7GgMfxTSdfsrVkHztqp7hp+DOg0Dd3PPn4E0P5ZAb/h25PmL9/y5oQAHkvSgVs1QiAiiLPsoyZlwbL1tp5PhPBOI6VMpN5DmggVOkFoDp0lwIDFhYQQl35hQE9Ury8Usb37w/HRZYtX33+hdWnelc+Mo4GD7eONjavPfeJy2Omt/d2379xewhSdlKzsjIs8q1HQ0TsdvsbmyudNEu02r1334hPmGOR2DtyDq2zmP/w5t25m7miJOZOHG2sdgbZaqb1C1ee4rxws5kUcyWcIKVpEhvkMmdf+NnY5kVRFK5wXDpkObe2bmKT9rNukvayTpqmSRTHymhPiuuiLgDAgLkwgHKJty6UZitm8zzPy6LI2VFn+3A+UbFeWlpaXxpsrK6t9TbjpP/u4e64nCeaCYGd18SJRq0gjpQY9LPSF/OEpJgc3X7rrdvvvvGNf/kv/WQMYw8CkEKn01VKCaMCJU2QahNbWYdjYAvToOLHzkIVYorQqpJ25/s/XFgJbX9I+EcAodg9EiAM1jdVZJIkSTtZknWzLIvjmIzura8gkTI6iiIdR3GU6sgopZywIgOEnV53aWnJl+XlixdGhGvLKwfDfYvo8vxwNHTs0zhZ1tHnX37pS5/9seFk9t3X3/zu73/ztX/1teRjH3/xEx/tJt2sE/eizoEVO92XuGfZbY0mqyq9Y+3SlFciNVBxjJih14ROCJhYoFVKCBmACSsDDQLWVjY8K9ZGaptec7wtuAQ7xOmr2iytTR+MMYKANZgaM1vrPPuiKEIqV15yQ3CTOPPlwh3C8XaulNRRMlh7r4+ZU6sFH62vCx6HtVFFmLZqLrVv276W6lR+ZubaS8fMXpgABYGZBSGMp/e+dFY8W2s7aWKtLZ1DZRRQ6QpX+jgW1OIYHIPnGouYCAj5VGJP05kTokyQIBopM2je7TOfROdagb1tueRxrRkfXszCOi2Eyan+yzG6S0iersqdNdy6QhdpZVeHzdvubbN/T4gmze5uDp5gxrr+4+TPcIpXY53v/4QhQGicSiIVOlv7mmB5UCd8omEtwb8Wp2wZRhBAqPbyEtamYBGhiiRXW3mx+FJLG67huP+wnfk32GazWRQlRpudnZ0s7Q6WevN54VzAPtJao6ISBAEoMkZH8WTuhAiFlQiIA/CqsvAIVbYeRiQHwAAlAEaxLK1MdYRLq8n6hTWV0MrFmdXnn7+6sz959b3726PxCKhItE2jUvBgPtKR3thY7/f7aWS8tZOD7b3h4WqnE7lC+xLms3w8zo8Oi/F46idTU6pMbfT7a0ura/2lQZp2tY4Ftt57s2/ipSwbpJlBkKIoh0e+mB/uP9IIxphOmm52u/3VfqfTiYzppB2NpMkQ6ZCSwaW13jlnvOX5fD6dTueT+XQ6zeelc+6dd97z1hVFmef5fFbkeV6WZSn+5qMHcy5MFl/c3Hj+6tXPf/wTn/v0p65deepwkh/Oi8JJYSB3NtI+UqCJgZlLb/NZQtKLzdbd/Te++803vvOtjSwVLZI54RAbJWxL76XbGbR2xLFILnVk7ElpfdFE1JAJs7Z65k1UXWpUAESQg7kQ4MGt+4BwXNyk+cwUGK2zrNvt9pYG/f4g63TiOF5aWU7TjvU+ydL9KHm4/ehTn/rUw4cPrz51mRGyXndppb927nwo+ONLO5nM2Lr13uBP/Yk/+aUv/ezb9x98+/U3Xv2H/3DwzPnzV65cevHjm8uD24ez+1v7EvX7/cFkSjts75TFRkErkcSoekpIgXIMVcGGEFMjoaCwaGAEhAonFACUCACfJnzNdzzb1nc2STlBcBq2ByHhIhiaRdiDta60VfR1RR4RhZuArCpapelAgCk+/qnuZJjKRgJrnhtaw2kasQwROST74km7ZZv7hiONKYVBvLBj74UZJBT6Avb5bE5aEaAyWiGhIiFmkJK5tK50nESEikrPtrSpZ1LgUbywEwYEV63LheyaNlc7EZkc/lSAvqVinrjqca25T6PWP4EvtBfA6afUgk5lx20N/MJKwMqSLKECRVNROzDUoihCbFqQwLjOzGx6eBoS9XRr+oOLZmB91s9nzHF7gT654aJo2bxy63h4/Nnj+IHT86EaBj9ao0BUr8Bw1gz8W9X6/aXRZJKm6flzF7vd7tHR0aOtneeefwaAxuMxESVJ5px7tLVNRBcuXhHQNQnyEOSLyhyFAuQRPSkm7VBZjwWooznz+uWs1y96S0c6HYo2kkFn6Tvff0vHfRV1caMP7OZ2PvXe+vLy+fOxVgJ+cri3dzQk9qu9zqWLawdbD+aj4exgpzgaki26Wg060XrWu/TCU6LFIJEXtI5mh+yFGb/w4vPlaDzePdi//5DzMkLsJGkWmy98/otBNgqgElprgiCEMjsorZ3PR9PpdDyazKbTooD3bz6YzIrDvf3t7e2tre2d7b3hcDifF91uz0uo9QTC1VL0BFNb6NRYX77++vXvZT947ZuvzH5l/B/85b+wlvXuHx3mQhrI+RK10waRQkQoKXCxwnJ8+M5r33/9298st0Zb/ggZlIBC0AREFeV/tJ03cxe0CERAhDgG78FaaEfvIoIO5R1CfD8AY/WdHQiecZxCqKivgn3DPwZY7iEG3Fpj4jiOktiYWBna3t9zwmWZ59vjyYN79/kYdHHz4vlOf3D+wqV+vz/c37/0U19MV1Yf3LiZdrIDcRipjXPrOtbT6VRELl68Ms3z8fDI61xlnY9ceuryxYuF++mvf+23b3zve3euv//MJz+3fOGyXkmnGHmCQquJT3a8vT11a146Rve1SUPWoUDwj3LlCQ7xu8FHr4KTliC4GpEEm6JDbToTCCK0iG/45CqnTHDR/Nv+85i4VWbDKizCkAFNRIoUzcpyOp1ClOuk4xClhWbc9AQRhavyedQcPyUTnCBBJ7gFtMDpKhUKj/n0CTbcNAxxtuwbBTcwYwDwwmztaDIOKBwB2THErGlrxXNRWAYBVIxknS+cdSgaiavCIuhAWNDDGUbd9rvDIqesKG81CwuAJE8g8u37NGc+QQNuP7Ftgj7RtyA2cRUnK8xBrz/O4g1DHjTgUM9b6mUTTBpN1aMQYNXgOTfyU2Wp9r6ZaDyl6+MpO8GCBtwegrOWyIKL98yBO4HQBrjI8STIs2G5h+e2nhW+/yH4bw0HWNczblot/y/UBj51Yb0lW5e09OA/Zvw6TdOj8eTg4HB7ezuO49lsev36dSLa3NyMkyiKIkSZTCZ7ewfWWha1tn4BABBYCQfdFwAEwaN2hAVop6KS4kJ0STATPe8Mdn1xOEfVSbF/gU3nzlH5aGu7v3FlOCsOh6PRbOq1dJZ76xc2Vwfd+daW2z8sirxjcK3T9a4YPnr41lvb+4/uZQaXsmhzNVsZrCx30l4Wx4YePbjd7aRLnUGijYgTZ8lxzPj9r3yln2Sb/eUXzl84t7y61Ot308wofXR0VFFbBj+Xo9lkNJ3O5/OHW9uTyWx3Z//egwd37959cH9re2/3aJqzzrzSCrUy2ujYGKMuXBqQFkEQ1KHiAukqZAlpaWmp2+3s7m3tbt2XyejdG/de+cEP/9SfOlzu9TtKzRCJcCKOwKNipvBFGUIupvdv3nj7B99149FHX9z4xHNPx4BZZHqdbrfbj6LIs1jrNzY2avn6uCHi4eFhyLEOAPdZlnW73SxJ7XwmUkFRIktgtB5kuH/ghF1RzsvC5sW8LFxRWvYhWIY9WO+896V3zOwZ3n77urPOzd3c5SM/DovHA/QHgCF4TSBBQAWogQiRdI/twa33D27f0sp4L5f/2l974fzFX/jf/uKLn/1UdykF8s+/8MzGxlqn07ly7en7t97v9FcurqxzlI29H89nMXCk8M/9wi//wTe/+e7dW7vv/DAb7S9deZbS5Xs7k7i3yppGTt+bz1bZLQ2S5UiUn6eIWgBAUADBU7BFExApQajYM1PIVBJg5x3jMTlueO1p3aBmq2eY1tqsqzkZESEQVgQWVkpppQm1UposJgmNRiNKlpZ6JkSxBaOxqsj08Z2DJhotygc1CzgboekEw1CtcjpKqSeTxIYNBA0MACz73JaFsymIEDrP7Bm1AkVC6ITZ2YBU7r3vpb3prPScl55dUU5mube2dBxHJEiMxAIoyAwND253u80vm1c79gSH9M/WjFBdsPlJr9Q6/zRff8I4yCkTdH0tNgwVGrMEC9XiTtBrGzMwVqrmcbWJZkbCCSH3tx0OGTY1EUnLiw8tZnpC8mvea6Ee8GkJ68SvH549ipwMZJLaytTm7yee+CM3bPHL+jlVvbkFbbuqavLH0qj8o7W93f1eb/Daa6/8l//l/1sEfvEXPzOfz/b3969du/bCCy9sbK4F6ezKlSta626360sbABxIOIgUDsmTZmVyMXOKChUXmM5R5x7HYq5vj3F5Qw1W86y3NfbDcnJUCutsf38oglEnu3JpozvoeCh3Dndu3H1vHSkDSdnPj2Y7R/uz0YEtZwrslz/50cRAFmEaKYNO2HM5Kqf25fMXlHXlND8aPpocHoHzvaQbp51f/flfMqRSjDSSOPF5uT/ctaUHHRWlm07ne4cHDx9s3bx95+b7t7d397713e8BkqDSWsdJlmRp0j23sRrPQJUg3okXLgRnIOhAkEHQCwizBwRxgICkCfCljac47uR4yKZjMjrcu/XWOzfefvvdT3/x8zGoGEAIAdmDZQWCzN5FQgTi5rPhowfT/Z0XLm/+h7/2Z4v9/Vg4i5L+oNvt9L3ng8Oj4XA4238YfEuhNTuZAGA+l9mUvE/TdKM3OHdueXmwlBpNpygaAERR1JCYtjtZR0lA/3fOldaGokEeBEE59rZq3nrHzAx4/cbNaV4Mhwd7e3u7+3vD4XQ8gtyKFxvle8UYCEElhSG8trqytnnpL/7Fv/AX/spfWlsfvPPWKw8e3Hr11R/cvn374qXLz33k5cOjyXB7X/V6pjfodbvLSeS12to5+Lmf+vJPyxf+1dd/9/e//bVzo70Xf/zLg6eW7h9MAckCHxT2EcIuZMsmBtBrqsjEQ212A/AAhMKgEAgZUANKSCdjEMTcOqEzjHOhnVYQtY7aOkebKba1pYqH1SUTvHPMTIyE4j07R8aY0XieFoVSKqCVKqUKZ9WpWg+y6LM8oRRCmw20ji/0p6X5YYVrcFIvarMEqqE6g5c3RIG1tXPvfafTCVpvU8YxnLY6WAdFpWcoS8GABS3OsRBynQ7KiF5QQvAinm0EPXNxNlWkmtds2hPIfsPjT4zYB7bTpzW3OsnXKhSRqldUZfdiYFL1YqiK/oZxa2akGXypne6nO9w8tLHMN6e1GyJqX6nM6sQ6bvLqmLn2S9U+GKywx6o06BaxYO8aT4kCZARjYj5ecNSiLJXPGGv7cOCOpNpeZJEK0aIZ3IXPetf6GvO5ecNKSG2uQsSQ1uB9U4sKatTocA61PpvEpMea3JvVf4aYchZFeJzR5bS94cktSRLv/Sc/+cn/6r/6v0ZR9Morr/z6r//9559/5ktf+hIAAAbUtDjc2duCvEfviEjHEShVspTezT1h2jty6tCpiY9mlIw8juZ2ryiS8y/YtOtMOnG47/x+UUwKdn4eGbO63F/ud8Dn+49uzWdHUUyXl9OuhYMH9x7eu5tPRr1u8tTG8rnVC73UdGM1He0VB0eQmOXVQZZlRYl+ONp+9a2ERZFZStJrG5fPnTt38dzFpf7SztYOOLTsvXhXutFocrC7dzCavv3eves377z++pvv37o5zeeKIpOkpKNz1z7uBTjQBUArWDq0XgryrmJwCirrZgCFRECCoE+EpA9UXuDO7iFv7SYdNVfGQv7Cpz792is/OJpOoyhaWVm5tXObOivGmHmRR50UtDKkivlsI0uGe8Var/OxZ679O1/+iVVD33v1u5/+6IsXNs6laZqmnf3DgzHny5k+d341MlWVt8a9R0Sh/FSzn5VSiAz5QT73IZ2kEa7DNkiS5PDwsNPpAECv19u6f98YQ6TTrBuyFa21jbnVgywNlpkEE2V6SRRF2hilDKL61AvPiaBj65zLbV6WZWFLx37vYHj79t2d3YPDg6M797Ymk9lr3/jGz//yv5sIbd+5//xTmz/74z++3P+S0X/p9ddfHx6N/+Dbrw6ns1wmajotRkcYm97y0mBj89Ly5mg43dm5++VPvvS5jz/7+z989Xf/zn/zM7/6Fz5z9bk33rmFLL3V1eHk8O2DPOms9ldWpwdb6MZaQaKVWFvOS9GQdLK5nQsSEHkGJeI9UwBYIBJaIKZhi7Wp5OmtirV3NhwJA96mjFWWF0DhrCDoEC2CzOKYQ6F0XF9fH6yseO/zMgdM2/f3nrM0PTw4WOkmFrGJpfLeA3NVyJkQPAdQqjD1TX4LEYFAAFfK81xhFayUJIlzlcDRcOjQ4aIosizz3g+Hw1A613t/NB7pyHT6vcPDw+3tvel0ur8/iSIYDPpJkty7t9Pvx7NZMRh0Q4llEXntjde990oZ51zprNZakPcO9gEgFLvt9/vCbL0zpoLjDmJBSGkNX5xzk8kk1G8OCztUByqcLZ2rUm+ZQwnkcH6ACgmtoaXM7AKx0lXttRBbF0XRZJ5LbR4AwjqqS6OgB7h06ZL3/sGDB88/NwgTHW7fJsJY1wFMkiQvXBRH4H1ZzlOtmTnLMsRcKRWbtJznBwcHghQnSVEUVFeOUnUJEKVUwO4NexkAgl1aRNSiJSacEDh6KAkMANPpNEyu917Lokm64Qpy1neoGUyty7Y5zQIqOgAoQFq0PzQPORYW5PhPaIkqH1Lk+YCGwQlSJWZ9SG178b34CTz4j6SVtmDAOO71+/3BYPC5z/0Ys3/uuedEKrgxkTrZWgRBFJSRRlBY+LJ0ZFXkoh6bdKeAmeqMTLxb0sEc52A4XZGV3qy/NnRyNM5H8zIHpCRb3+gnaaQJuZjl4x3gIsMyMi4fDXdn02+/9vq5lbXL59ZXB08lCgz7GH3qOB8OL64sbZw/Z8vZ9oN7Nx49zPNZyvSLn/1iT8dZ0onjBIms9dO96eHDozwv5rPi8Gi0s713587dd9557+233777YBd0nykyUTLYfHYj7QjCdJZP5/nUJ15QMFjGgEUAyIsXYJAay6XKVw9ReARINVgpASKIAqDSoxdAVrmARigRCmRbG5KacD0hZARWECkDbKdHR7PRUddEn/zIi+dXBsX2w5efubbWy3g2Ho2H3O8lSl+6sJ4kEXBhNISCoQAi4kQQmDOjvHfei4gn1CglCBGwQgBi75jBB5E1pI6Vs6EvjiblJEnjHEqDBXkXqShWkRJH7Ax6qVO8RcTODgCAULEx1hnR2qESViAmAHEo5A5xlipJEha5vLn2wpVLWsVA0YMHj+7euX9pZYnK/PKFi9//zndnBw+2H7x3cb33sRevbW5uXnv26mc/9vFxIfd29t++ceu9O3dGByMZbk33HvUufaSXdi+/8MLh0UM3Gf2ZL35+uZf91t/4f53/7Bd/+hf/zHBc3njrnasry/ugvnn7oPvCUzpKI3YI4BgI2JgYFShsy751ziwQihCgX9QInyzCNtHmzcnYsle3lbag4SmtgJCgwaes/G5Sm/RE5ExDYFsNglPe3/ZpjTJ0goR+mNb0f2lpKdxqMBgsLy8vLy9PJpP7Dx+YODp/6eK5c+fG47GIvP3229baXq83mUyMgbW1teXl5ZdeeilcPh6Pd3f2t7a29/f3AVWmlFJqd39vby+/cO68UsjMXjx6rxQaEydxNLHFmR1rOA210Ln/EO1xLGDBcts6flK1XVwYJ7ohdbgc1BOEtQxnrS19WRIYRUE6sZ6ZOWBoh3rG0kItbScvQMvs0cTxheO1fovD4dA5F8pSee8D9ieEIKzQrda7Lrz2GV/OGl1fQXQcM1eU9k2roASstxbW0BrHRxAb2I32yEptqT/dQUFo8gWOf6g9wfWeYWkymBEWLShBGw6HfOvOJyur/PFpiGjL0nuHCM7Z9fX1H/uxH9s8tz4ej5sqFCISpCYBj8I6iphUMXczAB9nPhlMdLI1nY9YH3h94NVIjI87prOEncHezE29nxfOASoTxVpF6JTzs/FQiyU/4/loOt6fH+0Vk2FZzL/whY8bhFTpVPkOUYcoFTDsV9bXDx8++uH3vl9MJ8vd3stPXb504fx6f6ULmfLoBfzcz4ryYDTePzg6Gk9/8Mprdx4+fOfd67fu3J1MZlES9/pLyxefcdCbW5kXdjJxOJsqo0nHkGXjsmQIkGcEAKFWLqCP2GmprUuVpYYEiQEECbFCwUfGACfDlq0weMviS+QcuQDO2TG1s8ERQgADkHNFGsX5eOjLsqPh2Refu7DS295/tLq2vJTE7CwrSoxSkYnAGKOK2cQQRYqVCkqYZQERH0WJhwB/6UA4gJoz+yjS7C14Fm9FkAi0jogAFCdaptNxFkM5d1mE3vs0wkg5EAcGtKr8VWE3BTMjAiolSgW0n5I9KUoESFhCOjgQCokQKTtLlWSpSbNeArDW63I+LafTS5cuffefvfqZj12NEez44I3vbN3OEse0fuHptXNX1s4/9Sc+9+mf+cJn9oY7r7/+6vffvv7bv/21ax95+d/7s7+cdLLhw/H0fvHjzz99fnX1t7/96s3vfePS0y89/dTFnQfbZdZJNi++tj0eLOkkjpBJisIIRSomZLasBH3A5AtqHxzDcZxJlB5H8Znr0rz1OQ0UfnNh+9ooikIaElFIRzk+oaG2sOhiaw637xbo+6nTxLeK1bd262PZFbaioBvST0QBFCKAEidJkqZpoO/LqytpFKdRrHronFOAs7yYAcbGbK6tPnvt6SiK2LrdR9siUpZllkRah5pEoo1Os7ibp8LjXq8DyGB9ab24EpAAYqUf288GgLrNgJ/wXic0omOuseAmP56a6qdTITlSG40bKeoJT2xmobq/CAdXcG1acI69VxpJa+3YhmhnVdckbsz+DbttdbV6hcYw0O6PiMRxjHUsCFRWE1+Wpa57LCIn7fULi+DYB7zAgI+lkqoTbaEAPBynSbTuefLOC48TlFa9B2ky2X80iUpEfEgBhNr8KyKPNQQvvs6iJHW2wPtH1aJIF9aKiGd7eHjYH3SjWI/HR+HXFusNsEIAhA6g9JCTtlGXO8sjyLZmvAOd7Vx2C1cmKfXWsNMbMU2m+XCegyId6X4Ux5FRIL4c28k8Re/z8fxod7y37WbDXkxXz2+srS5HnRi8N8wZUoaiy1Im03Iy+f71G+eXlj955bmrl57aWF6NtLHWuoLnM5nPiuFw9Ghn+8btO6+/+fYPX3/r1r3743muoijOOkl/8/x6JohFWe7PRCfKa6NUAt47BisCrADQcl3hHrBCY0MCCfi6DlsBdwLECAStqlzECAqRGcmXlsWWEYN3IFyit+ILdoGFEyAKKEAFSgEhqnw27wx6iYlcZHQpy50sVnR+bYVHR1mkKCYBYGLnCsvsrOTTiTckno0JRUo8CIJ4DmUnHDO7gMwjgiienbArvfXeWwBChagUAXbSWHySz2aRpjwvut0sz0ttQMQSeIWiVIgWoeBYobQBWAirXhiEwSFU+MQsXsQLCRAKgmcsnRTTyUgdWCuD/vLhwTgy+tq1awcHB2marq/0OzjNj45iRjed33lrcuud65h0VjbOP/PMtctXLlz+iU994VMvrf/2N//Hf/bbf/36Kz/z8z/9Z375l966ef3Gw/vPn79oP4X/9He+7mfusz/5M9PhaOalSHrXH2w9m6jMIKA2Pu96ihSReFtYpQkFfLVzfQ1e1EaQ/VDuG2olWzcN6/qsUPPjQDdZxBjjhbF2kDWclZmpRW1PtIpS1a2h7y3OX/3XPPdD9h9r31zDgwMDHo1GaZqG2oK7u7uhrC87n8bJ1tbW7vYOg3TSbDabAUtZlq60pbP5bH54eLi99Wg8nRilldEiMp1O2XoVobeFCC8tLW1sbHS6KXhfYuFtXorzFrwtXKnpMQyuzVqkLs+MiPD4KNYTI9mIF3ycqXUs0LQlpYYNiwjXVaUb4eYE728PstRmieMJqr8TkVZaqQAW66yrQK96vV4TwAEtUBFcdNtju1Z07Vduv93KykrATlFKhaQmCVgu7SVV3+XY7Iy1yv+BayVYt4XdsYDBwgiKDBxvmBYzro7S4khhCBBv9+oJQg0AQLvu72IT8YgAlekb2yn5i3f2zR1q03qQbqCCQvtj1rQhpTFJorkUiJIk0Xw+bXxgVcgGiACwiFVx7nAulJsMeufyePBgVF7fnxxScgTRNImls2Q6faf0uCxHs6lJE00QK0iVj5nBF+VsBPl499EDX07J5ytJvHnt8vqg3421Jjka7XbTuKMjPx1P9g/8eNoV7Brz537+F41gDMagmQ/nM5lb6wuH3/7+W+/fefjaqz98+933dvb3nIAyMWbLT10+N7cuL+3Y+/FUSGtUXUz14c4BpJlO0yiKNID33gZsdAriVG28QQTwGIQ3IarUYoDgyReoQUwrRDqssMCArQV24hjYAzIjA3gf4McDOxdFTFqAQGlRWkfWWhTRSFmSaAKXz/tZSuShyD27PM+P5nMmSvpLaRLPRsIKvBcioWqJESJ4L+Ff2HbVFhZiFi/IQAyEqASRgTCgAZJGZQSVr74LgnLOOanyZlRrbVeog05ERKGuI7+wLGehkKgg125xBYQiECeRoAHQqpAsMQe+2D/YPnfpeVB6ODzwRe5k3IvU+ZUerAyGIx7N/Wg+27l1fffOO+/006evnr9w7en/03/yl//kT3z6N//VV//Bf/e3bt68+cWf+4Xnnv7Y9fsPnt689NOf/dx79x699f1vPf2RTz48nPzwrbcvdWAr9z0Q0rqPcRKiiETIAyr0jILMHCq/iASIkVBq5JSC9TgC1VZem/CU4KrEVnR6rWBV0SLHkLKLPLVRaNq6uFSFdKQ5H1oqckWLBbGpL9niKOEp8hizNtQM+OTTAeI4TtM0OCNDCaNQr1eTKuZ5wcIgxGCUHnR6OjKxiba2H03Hk9LZfrfX7/ZcaafTWcDJMJHSUeS9KHTGxJ1Op8oFQ9KkPIYyieycfRxRalhO4KCtCTqbestZen+t49VlnhdPDgMmi6qztDTgpmoCtlpz2pPtmSISRAjvS19aJ05pE7XqSp1oISiyefEgxhGRbYFCtye68XY3IhQiVtjQYXFCLUfAoioMrcWNiMzS2Fca7wgAVGHZUhVchFML6qRIcsr7CwC1KnA8uHKsAf/IKnAzT1gf+fAa8IcRTv8IGrK1BQBbG0IDlHMlNmH9KKF4FQCIQNDwgKKp4ynEEvWt7uwUdHds7838SIka9M3Sqo+TsbPTee4FVKI7iTLIEYpxcz+b5MP90eFOPjkqi+mgk66vLW2sLi0nqQbkeV4W00vdlGeT+WjHT6eJ57Ve/+Lq+sZguRdlmkysUwDc3j38/g9e/Ve/87s/eP29168/ZJVGUZRm3e7mVRXFDsAz7E6tkGYdiyYGtMzOA1jXuXjJsy3LcjYdgXNABForYzxADWddTZaqoXbbgZonK0dV5XurcgcgojyidyH/BUhQBXYdTmMUUowalBc0bAhUv9Odjw8hL+bT2aWVbqS1m0wclLF3tpwppbQhP7FOKAFm5m63rwlDBFa9nAFRiwiICmp2BX0Xlhx7pQiRlTK1ZK0A0FoPoDudntZJtxspFWVZHCXRZD4RCem06BFREELFJMDKaE6oSR8XR2MREQ9hLDwAey6BKQSmEYFnEaDp9AgR7t2788zVly9fuwoo5zfXyv0j7eyD2zfYsklXFcQb/aW028ln492de6/ef/uN736j97WvfuInvvSf/6f/u49//ON/9zf/1fe/98ZHPvNjsekPDydf+rGfEPn2a+++s7pxfmVp8+H+YYmyPZ/1BbLUdLRRoNFbct6gdiAMDFUsLQAIkpJWRmy1IT5on4Z4qED+2gS6yvBZZIQsEvCYxYexpIYYhhgXOEsfaFhjW++p544UKkQCQSJoFKkTHOIJpImIPPjmKY0AEUWRtTbU5DHGNCXiJ5MJCvQHg6IoptPp0eEQl0CVZWc9i00U4qqICB0golHaRHo8mdiiIKLYJIix936eTxGgwusG1gQY4EyfiANxWrYgorZX8cTJzScutGMbryLV3Ko97W1DdAhmxlaQ3RPWhohQu4dYFdZDRGstGxGp6nCQpjiOTRTled6Wfhp2+zgXRogaa0kMx3JJW42W2p2sWzevot5PM86WNhxOXWDAQVUMYPLelSECHhENKVAnLT8AQcjEpkJDa6QoCJoNdnR7quqQtsViDMfm8GaaF4Byjg3bIkF6aoz44XDd/Xr9IwsErK5j2/UfqybgiTCovCIym5VEJMBSF4yqHd4sAkLKop6T8lG3NL29mb9xcHh/JrnpSbrk0wHrOPcyK8rCWR3rbhrF6MjNfZ6X4yN7dOQmQyqnHS6/9PlPkgJgcWU+PRppoF6arQ3Wj95/I3H5RpRcOH/p8vmLq70eMZZ5YR1vb2+//sY7X/vWd7/1g1cfPNoGHcfdleziFUcJIpZCObOdFt4ysICJARSIgoCrLjq8yXR0CEq0MVE3UVWKhXVurrFS6aDWbhWgR7JKSwOwiu3NzzX82TGwgWKIBQ2zMFhhIFBV9DSLeBJQAkpAe3KMWkgLESoRTOJ4ezIxGwOQCi/IO2utTdIoTbJSYOackIxn05VsoEO2vYSCRFztfAAQX5UaFIKQlIgsnpEUKU0KILhSOERzAAv1Byve+zgxRVHEccweEQygA0JABFISiqAHIkuh8BsSKOe9c9Y7FxtCZAQPwCBOgD07Eez2+qV1ReEca60z64rNc+v3DnMvfPXatd29vbULyWw6Wl6KRxPb73aTfv9gOD/YfuC2IItpOTEm6yN5zcPf/Nt//e233/7YT/3Sn/zZ+Cvff/13v/aDP/FLv1jsPCjm5YvXrpXeP7j1/voz6plrl0Y79/dms66TZYo3s74C8GVB1hOiEmEBBGj7/dr0rv35pP2yKM03f4aq9Wqx3juLgCIvDOwRMSBrYxVY5NuXNw2PIZZOJkdV1FeISAFDYMAnWO9xDx/zHoFRNCHxUEsP4YnhC9W1Fqy1RqlQkssWRT6bEUASRc65g7290XDYzbL5fF7muYgkSZKkMQCzuKKcB5Aix8DM6NGTFgIE8N6KMCEQMAHX1U9PthP+1w85O3BKoGkkkobhHY/DWfq0NEBXi6k+Z3JfEcHWFAAiYevPWk/WWqtIBS6Li6bmEJBFRLPZrN3bYG868eLYsktTnSrGzEVRiEiIBtdBbbDFdgEAAQAASURBVAIRBlGgm5ISCCBAVHNfIQz4qA0Dhop1VVZ1a0vnnCut86WIKKWCiczoMBwnPcGn5RRsalhU49U4S7gedz7x2cRlUJX8C4xMEFa7MCAJS+D2hBS4K2AFmHn8iQIA7KtawuH3oDNJwDH/wEDo1mTj2RJf/QonxIXmJ/xwn4BGk9J5WShRSRSxs5GhJMnyfAYCiEoAGASRBMGJmUuvNB2X9qYmuz+eXB+O9yiN1vvR8tpUcJZPrHfAvmdUoiGRshPxZDzcf/jwYGcby3x9qf/ctcub6ytuOionE+39apouL/fEuv2HD25tbX322sWN7oX1ldVepw+ej3ZGw+FkOsv//j/6J2+9+/4rb761OxzH/UFnec2D3s9FjGE0ICQgDAp1RJEmUq4sAVWokQcAgMGsI2xFuGxgclVtnwh0KcBV1AtGKkjD9tY7OX5BxlJCHMplMhJUUKWIojRqAEWgaqt1WHuskFCAhPJprkmt9pfu2FJs7m1JyJqw3+8f2RwAEJVWKibSxoDz4rnRYAKB0EQVFRBpNncd0+FFPAkFpRgA6oJmHLa30XGRT4ym6WTOHlhclMYolbyoqmRCEYYiLxGxigZ35Xw+n07neT5bXuoojcqQMUopRK1jNBWn8JZZEFUc0Xg8TxM82H8k1l7cPLf1/j2ApLQuTpcAIEmS8fBwqbe23F89Go9m02GRzws/K+ajtNv51V/+pbtj+Yd/62/eGcP68oXXb13/vX/ufvHf/eU7W/c6afLyR1/8wbvX9+/dWX9KLafZcJe3PWymMKUoFxaGyPlYM5IAsBCz9yDAuJBv++Hpe0MEm0USFk+aps3BRj/2zAiG2Yt4TcTkERBQcUP2pUqkROAqLVNCDSIPACQV1joAhLKyhDUAMxKSNPpQmwEH+smtV2kxOJIax70urMCIikgQVRxrrSPnyrJ0RVEEgSGJswN/MBnP8mLe7fQ3NzevXnl6nk8VmTfe/OF8VhyOjtaW10DBeDQ9mhw9dflSbBIfCQDOZjNbemNMlmUNQ2Jm71kErRflz+a+0GKZbRYYNIEPnKPm/BrXoTnEVQUphIrgE3DDDQAAOVSOImGUyn5RMUXkmpcxIIXIecbGuMsKkIPZCwERI6OV8gAWEckoZYxnzq2LFNWDUFWRCpZkaVlJuZUxmCZJMwhtYWsymYSQLmbO87xZltpxQUbHOmYgcewFEEGRDrK6cPXyNYoDKyICEqjNdLWG7ErP7EVEqyjSWmtNBFLT0yphuMofaJm7wdfKdNVYuLZCMwDUcRjgvY+ikBzmtVLGmMlksr+/u7q6Hqonk1aEQqiIUAC99YQUqDFhkF+EALyzQIgSynwhCCAQEIr3AIiVJzhERCNWRl2AGqEb8WSRwUDm6sk4UcriePHRif/XzYsAcqhR2v6kgECwaEJlgtKzZ6fiRIRtUSRE6L2fjhOkgP4qpEgrVopZ5mxGfqBWrhx4/8qNu++OhvlyHzc2Z2lS6vlkltt8lqFeS7KlyCTsZTY9uH/rxvvvHo2mV64998ILn+4kaT462tnd76NdT6Jl8nK0X9x+NxL5xPr6xc+/tLq0aq2wx9nUHg1n3/3B67/5z776+9/6PkWJQ+3NhcEGWYKZDc7ZqLSqjkQPPAjAMaMQEqPUPA9AgB0wMAFqk5ZFISwmSUKFdtJxZYJu2bgIwEMwpUrNdNvEImiUAAAglVfNCzjFgliWBVCkGIqjUjkFVqwrtFEYy8yNMYqno1nW71j2KDDo9h7dvr6xPMg09bSB0TCK1WQySTpdRMxnBTIqzyp3y0nmXAmgEJEQtQ46uAB4ZlaEBpFZmD1C8EdGISaTmUOCDIJohaAUxQYR2dtOlojw0qDnvWdWBhQgIKGIePbeu8CxrbVKadKR1hq10lGSdQfMHrAUYBHvWKwXsZXYnnAEQFqBAJfF2Gh++OD6aj/zo4Nf+tKX/4t/8fd+6qUrSda/v7O/uX6hyMtu1hFrrfXkvFbohNBEabb+9LXnpnO+8+Y7zw1W7775/ZeeWv+Vv/Kn33z44Kv/5O/8iV/5Mze3dkfT6U9/4fP//Le+ig+3Lj777I3O8r4rbg7LrozTTnqh0wHDLBOG0pMTZFAQKrazB6iI4DEDPqFHNp9tTTf8GSyHjTpyosY7hDAiMqS190qgJAKtAdFbD46tB1GkLYsC6XU6OeCszNmVN+7cTNN4dXXdukJrXRRzRSDstAbHTiEhQj7PUenYxF6wKJ0XDtVh8zwHAKN0WZYCEGpnIlYe/xCQYq1XipIkZo5mszzPZ0pRHKdFYZnBWs8sShljDDM4V85meTfrlYVTqJ1jW/qtre0kidJubL1cuXL1WvLs/u4BaTw6HHX7gzxn7xVh7JzLZ3lZlpAiJGgLRwSIiBSRVkTEFHnGWZEHPMvAlITQs1hnE5VVURWKWNiyJyLSSkQ8W4FIGzKRQhJAVhq9D4XoGZCtKwR8FEVRFE1mY1TgxQFJ6QrH4MHfvntrMBhoHaEK+dRAoDwwl56AO7Hm0nbS7Ob1G1/+8s/MZhPSlNvSE4MJcC6CCgFASkFEa60xmtkLu9ignU9BbKTBu7yE0igRBOucAwWoxrOZIQz+9SbUy1obkp6hJVgHhjoajULOUjBUNHFh4XsoKhzFceX+INLOlYRVbXkWakzwcBzGUmsYyAsZwYHi1S1JEuYQ0gm6cjKLr6osYNuqfGKrtA8elx6u3FiMUGUa1ZYAX/NmRQQhkz3owdUnMIDCSj/mIH22tGwgEWYJMWCVtbZSj6RisdIIFaEYpZfKWVDfYsE20gB34IfLGD4lD9ZF8j7cJzU8BauiRqzEkUCnk86snZfsABC1x8giTyiONq6+u1u88/D+Vjmn5bXu5uo0iea+HM1GRLTUS9ayzhJqNxw9unN/b/vOwfD+tWevfP4zn0Uy09GwHI/WsnRlY7Xj5mY2MuOj1JfLG2tr/f7Gynqn298fTqeFv3dv59vf/eHXvvHdN9+5NZkzmb5g6lF5JCbwCEFSFdAIpvaDnswCb0KlFseHmAFQgTAziCCQhiq+vY2dAh5rhitP/qTmkxFYxFPIG/YoSgkRaKxiyRnACXpGqZd+EHVF2AF7BR7BIVfIa8xMqEFIIQGKAlHCUHkua+GubuKqdO2qeoIAewbxzvugDJ0wzUmNqgP1nq9qfbsQNsTBFlZ3m5MkQURBBQASSigICqI2EaAHiZAgZBgjEBIUeRnsYKRAEYIiTQbYFOPxuc2nLpw7Px5N46TjZvPcskK01iMLO6ziLgGEFBC+/vZ7vWwHCqvM7DPPPrXRoStddctNnj6/8ub3v/PsZz9PB0c33nrr53/qS1//6jfuC6y98PTu7vbuZLyf+Zk2cwLw6KwESi0iWAUoER9b3xb8U209+LRdzdenNVZEXATlgFakNIJyPlh9NaKVqiYDgpK0k0VZFkWRczw63D+aF5PSeW+TJIpNpLVWSEAOAAkQhTGU+EVREorfISEqFMGQ370wv5XS1prugPjddFBEAuZowPRQyiC6xfVfBdIDC0JIOgcRKQrr/dFkouLZfD4vnPd+xuPJJEkSQNQUYYh6kGCOQe+lKGyel52OASAAFGEBYsEARRlKK7cFlzPnohFtGiGpuaRRCk/foR4KEakmBZRQLQEEsl+HxAfbBrDzRpEmxc55VwZThEdPaJCrmowh1AJRSDV5bYIUoE5ZgEkEgLEaXEJEJhWQydM0RfbM3I7ai6JoPB63c5Oad+l2u1CjjAVdOY7joC7GcRygtQLqSxA4tFaECMgeUWkkqSK0hKUCnKlCSeWYMi6aCSo9IyCkMBOEWuiVYs5YB7YBnMF6TzLgyjFc1x5ux0OdwoJRSoXkqgV7zinKdWY7sW+ffGYwt7cPwYczf32Y9iPdhwQUsAJGEBJGYAIHAIywd3SEUcpJVoKaOyqFVNKD7sYre1vvHcz23MSsLi2vr88UlUejYl5GCleWllc6AymK+1u39h9sucmE2D3/0ZeWlgYxGQLsJHFXUyJ5NJrBdATlLEI8t7Z+cfOpNO1MJ+XDrfHb199/7Ydv/cHvf/e9G3fzElXUMf2s9MRiPCqP4MMyrzCoqQZVqJnlIszLGU2EGQEVEDkvAADKCKLIKVYNQZB6rDPtjGMCDF5avzaq1eIqYgBGFFWTEmbG2i6J9WrnwAgRA44xYMB8P445kNb5ASBC1Zj7DW2Sxmpa2yqPdwpXMQ2BGINnOHZ6HedCaFSMSC2kIal8hxoBbOkBXYi3aFw3ABwgQRBVcDcpItIUQby/v/uxT2bPP//87u7da+d7w9lhWZapMs45ZBKurHkSvFVEy4PMOV5dWRpP8rWlwfa9u6rX/87XvpEPBqsvvLh7797K5qXD7sR7/9xzz33vrbeeefpyN0mNLfZHo7vg0qVsTSnnKAEEj4iMAOhDTq3nILvVMyOnkgbbn+GL86eCOp+445iZVMUygwkCgvYMKvjwHHOeF7PZvGQA4KVB3yhtjEE5LvwgIiGynTCg+1NTWfIE9WvnrjyuyWLB2pCW2l57zUOhRn4IXfXCIdlURHA2DcHSRVEcHR01AxXuHG4bRVETm9a+bXCF1gEMZ3BTWKS6zdtJC7DixFWPe9ng+IN6cxGRIhVhFOQZEQFmkFBVAIkooIBprfOyLGzZ8AilFbEPSfGV4NV6Xww1TE65n5VSWodtWAkCWusgxPFiGasA5tWYVYKCy8xNXDPUGzm0oCtK7WMOv3rvdZqmUochESCSqjgMcBDZCRiOEaEea9A/4YRvhhtJwZlzc5ZCDBCCpGqeXakIAAC4gDBSwWyeYMDNTR7Xyeqc+uR6RJ60J9sMGBtM6T+yxkEqUhKInwMQQWBEh+SErKhSJTMdzUEXTg3H+dfv3Pe9te5T61HWHZf50cFMBFbiZHV9DVimj7a3Ht7f395W4s5trl/c3Hj26qWth/fH+wfrg8FalsJk6I/2qZyvZ/Ha8vLF9c31tfMO4xt3H33nlTffeff9X//1X89LX+Tes1IqMSrTcT9S0WhqGYkRGMEjLLjGm9F+fLxi00QAmElrAOCyBCIVlviPwmgf94j6UOBDYRmp9nJqSDbVieiBiAbMdd2KXpbKssJASEoBI4t3DAC+KjISdnXdoihSSjUMuAnQVVo3+7a+LZ/YL02mR0PBg7WQSIlIqGzPgojonUCNFRxFqVI4nY8BlTAKePbAwuxZwCMoQBJGBrGldyQIyqHdP9om4Beff/Yr//yVjz69MSJVlmWnk3pwQURGRCQgqIqseO+LWZ5g5IpZHMdQlvnwKBX5ym/99s+tbMzd+4DxS8+9+P1X33jm6vMPh8OtO/cuXjy/sro+fnj7na2DBNfTtV4H4rJwhlkDELAIingGERC1CJLTfGkz3bYU1bC9OoqzuiQAG51oIMIMpCi8GrN4ZgKNiGVZoikxcmgwyzJKMq+MUkgsiEJE7IJNG3yQuxCFEEURCqIPM9TURW1PaDPXT2iNLAV1bYA2226kCqkLKIVzFEjAYwlaV7ikKIoQ2UtVxm0dM2tMUOmIKEmS9tNDVx/HgJvncqsaLtSU88RuaibohKjUHpNG2hAR9qIVqUiHWCsfBkFAoQJAAlWWZbbWj+M4z/OiKKS2HrV3UEW9CVW7oJPI8VNFmoGtxI9aAnDOKZDAPsPdAu56lmXt4PPGIuWcwzrkSqroKBtU3vl8HqoqZVmmtbbWTqdTbTQ557wTQSHUErakWK0iqFkvANCC/Zm48pKG4BUOcywigcaEWoANeBWesjY8SQKqNOZTDBiwCQJshjiKolq4OT7eyF6Pe0SzDtoL93En/5tuTxZ+T558zHoZK8sJMIJD6m1u7szKvQKtijhdPfJ4e/vgveFuvr4KK4OpNnujYT4uUpOdW14ddHsocP/e3dt3bs6K6fra8vmLG4NBP1Z07+7djqJzG5t9rebbD+ePHpxL9YsXNq9trHWTmFT86P7Ot9688S+/9eo3fvDW7Xtb+cPDaG1j48J5pOhgOD0c5zCbYNwlHQkSN+YPrEPnSBpN8EO9PiJ4H+jCvChAJGSy/+gj/bhWe1Jqk7gCbNuUUICACQURCVCTaoeyaiSpGSEAe2HkOm6Wmb0nWgg/bCTiJI2CBgx1zm54ouegQ1fwxcGQxcxZlkGLTjUUCoUQkXRQmkFEQsxXSAhUBCKiTJqmaZb14tgcjbMqYFE8M3hvmYHZeS/Bhhm+MzsRJNCz6WQ6Hl+6dCmf5UoZRbGTsoLXrvJzvYh49uwtEMzLCXiYzo66WY+8P7c0SLR++elnvvnKD7/9la986c/8ueGDrV535epTl7a3t1984YVvvflmPpkWmcE0ncr87nTc7+inBx0uCw1MgiQMwAzgwfuaAYfW3rbcSguBNj9WlbIYcIAbNvy4VpPjhbqBUrvxrLXaQJZliY5YRwBczObBCO/Yi/cMhIIM4hsiE8q8A4TtcILlVwJMq7LhiXaCezWr6HE9V3qBNyNilYHGlec7cIjAOcqybNhQ0IDDyUEVPslNRcI6F6DKHFO5F5UAOS+KARBYQvXIYAISAApB/iBSfyEQqI9ApYlWiQBilBbPACiE3gs7x+AjiKSiIASMAAIiIf3QWt/pdJIkCQy4kbcWhib4HCs3aE3wTzHget81myu4yRaC25vdl2UZ1SjQ7f3bZueN5CciIWEMa+uX1DWUdD6dFM46x4Q6itjoWAS9Z6O0tDVgqWnoYgGl1vwHlf24u0opogbq8ngxneB8CyQYFxhwJUDVv7TGKFwISqkqA3YhFkNE5APZmnw4DRgR29hfdff+aBoJoDAKU22KYARGZSkajme5yWAwmEi8PbE7Mz70cT5Yzy5dOAI7Gk7EuaWlwcZgNWY1Pxy+89ZbZZ5HCjbObWxe2uwv9awUxXSSuHwl7qZlWeyPkrx85tLlZ9dXLnSTrtFHB4fvvP/O77/y1u+88vYPbjx8eDgDC+c+8bnZLN8Zl4Bi0n4nWy1ydrPcGwPH3FcAqILmFml5+s/w3p1qKAChFPZ8PIaWK/Tss/+QGjAAUPABIaICBBYQX2G4SDXylaMTOPwKwMHO7L1ordlbH3ClA2i7oIigqvDQiUiTCvZDpRQcFwU53v+I6PwxlHcQqMuydM71ej04y4DkSh9Yb/gMTUTEHQ9yoK1pmiZJMi9yRCAK1vSQ3goiHEVx0KWZvXPe2pJZCkjuHj7a2906v7FsjHFWlDIeqfJHBpmYA6qX8+gEpZOkCkkJDXrZ0cFYRerg4X1D0S988af+wVd/98Fb737kC2s33njz4z/2E8PDiTh7ZfPCzuGuHfPlcyudpeTgcOf2aLTU6/RUnAihdwYcgwfwLoRvkFATinyK1DZc7Zjm0ILNk+rqNK5Vh3nRB+xExHsOQcuBDIlIFEWgKuXbe+/BWS/MbJTyIp7BOxEnoJpqvijSBmQ7nrX2pEOtAT+OATcU9fQ7to83d6sgvUJcdw10HRhnECCCihzMpyF0K9iom/tXckat8zW2FgBgEUM66KgnOhYqDbTpJCJyjSXaHGn3//SbgpBSRilf89EarYzIeaHa+Hg8mwLOQbfbjdNkOJoELT/g4oV3b9/ce/beK9Stx9UD5Y/xSht7PyAholYaqwD5SsILo9fkHTUjjLWHOEg5lY9JqRCQdXR01O12g715Pp8H3NBut6uPhsOiLL2XOE4VaKNjItLBNRf8duFVQ5xIUPARqhiWqsY7ATAqEgZB74WRGy0B+Czd97HUFhdOq/5u3SG8P6G0lubClLQm+OwnhOVwgv2fuSCOe/LHhgEDHHNfRgBAh2SVLshsjXPpdQuIH1m8M3GHTlN/bWllcHe+M/EzQ3plbW0p7pbTcuvBo+Hu/t7uzubG2lMXNweDric3Ge0j+gzhmfUlPjzKR5OOil546sqz586ltpzt77978607t++98e777z86sCVeOP+UGvDhrHi0MwRBcABclFMPOqG0E6+sFXleMV1oBqyJRKq2Udsn+niOSkBk4riigCJABMygHyMIPhZR6AylAQHkOMmt6syJlYBQ2X5UyCphkda+9Z6dcw4kNrFlF+AaiHRw0Usd4d8se123WT7Buv5dY1oMFu3ggkVED6DqI3Iiz7LubbXaa7uPiICwIDCzeHYu3Nl6a31prVJl4UKYFSkAIUBhDwJsdGwiFZkESdiDZ8seSoqX+9Phwd7T184t95et9YSGMHLOE6GAEEDIN/RCAlqQhX1hi4iUt4UiVuCgsL1u/JELl7708U/+i9/9vfNPXaXl9RtvvfnsS594++bt1V5vMjqYu3LO3sRxGUWPSnvzYPhClmUeQ8QAIXrgEK6GYUMCwFk+4KY1Y8Ut2tr89AQBLlgymBmBSSEhigfvPYNXGhqlx3pxpAEg1pFvqDACKk1KKaO5DvcJ3Q5+gRM8uFlyH2iCrhWPY8ms/VP7nicIbPNQItV4OpxzoSpREAcbIyq1AB1DnvTpG2JdU+cEWw0MSSnVvgSD0xChAoslDLinIZhSAELlSYH6iAh7L04EUSlNwOJZCBFUlSaKrJEYEIFYvAdxAEmWxnFcusPSuXoPVZnTQR/HoOsCs/Mmrqo5ST2S1bvX71gdCZmrRM45Ej5zSNuLqrFstVbRcclIZk7TNERshbFt8GF0yE9iQUQlmRilSEfMInXK9ULi9cma9k0SCAF4EWEvAgwsTeWmdvWD05vkJP+rNeD2Bqmms5rQmq8zN5rr4/beE9oTOO6J1uz31rP+CBlwaMQADOSRSqUKinIVL1996tbh/P2He/uQ+P5G0l2bQzSc5cPhkYpkeWWwOliaHIzef/fGwaMdA/Txz7zcTeJObAAKV86N2DjRq0blD26mRXl19dwL115Y7iyPtvcePNzhPP9b//0/efBga/vgKFvbWH/6xX7SGb9/597t+5D2gCLKYq0jBLLW89wW4yl0umFbAQDUwFINaEbTPnAWEFEQg3cKaovQ/8RueMFWOZDw0BAACiiV0x1r0QeBRdizZW+lSh61zoFKEotKxAuAByGgELjbCNcAwcZ2DKnfLOhmu4bc/0AWw/5sTg5mq/awVEpGjYIoIsjAIMEmrHUEAJrRh+xR5iCYa6VCFnLY1Ry4C/PBwUGSJGnqasoLAKAAB/3udDoBrbvdrrNAGCFo75wxikBIMZJnUkjCoBi52+0Mhwda6Xw+iUzsnU1QYk1c5B+9fPk3/sXvv/EHf/ALf/4vvnn75sde/sT6YLB7eLQ+GIw5GU7Hk1J6Op4j3dw9uvLMWs6UidWCBCWCB7DVi7c24Jksp/1rk75Z6zcLmuKJBiKIKohYhBK4nvfAzLN8lqp+RERKMSAihhKT4F29xEMOJGmttYqE5xCmHEEEG4tnu4cfhlKdmHGo2cZpSTG0hjcrpUJkXqWftUKryrKcTCahikOWRc0AUqs192+PG6JirPnZYufbjtvj9XnK9QuP14ABQBDKsvTWBubHrSZyHPy+wAsBlDGoq5BDqJ/Cp2KSuE6mP81KmbmJr6zwcgSAFCLOZrNYqxDJjIjW2rIsrbXdbrcRiRoNGABC9SStdbDne++LoiiKYjAY5Hk+Go201mmaElGe5wcHBzqILQpVe/K894S6SmoArrVY9iJaKwASlApVV+p4VCGloEpvqlQbAQDhhf1wetBPNO99CDoVqc3+QfeX47w9qTAIw/Y7mZWrAvyWHG9LqSXlxj/cnv7wvXK+L0gYVUhqMH4fv8KixH1iUzXq1BPowmI7mwO1JaxmAzCQ96x0hFo5oKmXOatSmdJ0Hh3Mbg3nQ8rSjUtlsnLvcPro6FDAPn3+QhoJKb1358G712/s7e1dOHf+I8+/kKWxAS7ziRT5IDZLnY4vZm5n60qqPvrcc8vL5/Mcxwej7e3xP/gH/+J/+Dt/d3nQf/75558+/+ykLIvCepinJN1uOhNiRLautAxIIIQRQZTV5qM6H6wemBOmiWZYWhETp34y5uDgABFNHItIWZYUx4/j3I8bZ+8cBK8OUYPv6p3XpMUWYBQUXjQhqsLlWZYlSWL3LLCkSRLco5pIIXnvGTnowdZayw4BsiwryxIAjDEs6BmdeCRKkw4paKxVjbEx0IIGHrKhC+EIMxdFATVRQ8QgO5/5XnEUAQBiUCC4SoFG9NaW1iJqQnSlpQxD3AehbvxuYXSVIqUgjuNutxv6EzB6nHM60stLvdfeeg+Kz/3Mz/zPvvpbv/nMxU0uZiTI4IFdQA4xhDqkRRLubG+RAidgGcSLAhMb4+ZTLuGTL7z0v/y1P/3//Nv/+OVP/9hzz77wW//4H/7pX/v3Z9NxFnX78eAff+U3vvCln1SKx4dHWsVvPdj55Mb6cq8zPdol67NurJwb7u/Hy/FC5bZ6GYS3C4bldrlfXdOHRpQJ3xsTdEvqQgA0JhJQzBQIsWcBMUqpTqej6rgtUkRIwfUHnpXSeV6maZpPZyBYFOXKysrunfcuLi/Njg5sXihlZoUHJOfFOUeKgms/THdZls2qOLGSRcS3HJWNyGWtbRwxVIcRhKUS7hbuTHhcDd6Xfn19/fDwUESuXr26srLS6/W01vfuPTDGQO3LDLcqiqJhIcEJ4r3Pskwpxd4CICitNAKiZXYCqA0AlJ65tEopIsWIAsgCXiDOOh5QkTocjUHpwjnvvdaaWViAkQBBiDwgeh+WOjM45wFVknYQVZ6XpBUKIJCOYoBgsafEKAQ4f/78bDZTSgX8kMlkEiexdxBpEzZpYowws0ASxWEzooiAh1bsVfBreO9JgTEGAR2g9z6OYxJullYQU0LcdRixOnSrijAIRmYRCXBXYY4C/kYcx010W9j+vV5Pp0mnsCUzGB3FcQqkmYU9kK5My1IlyvoKuAJrFiO1gbEqVIIAqiK41YoGgAXczn8T7SyCK/A4trbYPqQS/EfYpGVkC59Rpz+3dl4wG81pp0SzV/jdYb41c76/mvY2JhhtHx4ezV3czfpJtGoUFJPb92+9c/Om0/jRj3504/w5IZjZWSw+I+mkUeItjouB1uuraz/93MXx1sO927ct9l57485v/NbXr1+/d/Wlzw0PD2fQUZKqNNWRzovSF7MsVvO87isKigCFSjKVXZcEjj2+AoLgHy9wPOHP/wkaIjxOJMIQM3Js6UGpYJMJgAgUk8IQd8SRIiQfJDWFgCgo4L0X7wEovL8A+ICRKT5qIR8Fn26VvP5BAsSPOgINZGONeo10yrD/uFI2zRNPCKaIqBQahflk1O8OXMGoYqAInCMFRIzeh0CsKv4MfSftkBIiMmQIAnEFBZAu9e5ef/sLL33kzS/c+Hv/7d/4a//n/+xcr/N7v/XPf/zLP/Pa9XeV7n7qE598++13vvjFn7r3aH+pv/Rw/2BtOu+afi/rYikenUnSjY0Nb8/2lTas94Sm1fYfweKGgpPcFyAoAFghUAssFGE7PSMMAgiq8geRAHBlWcCysIW11lrwXkB777GVxr0Y/9MKdG/NfvM0WWzcipk/3TGp9WMiqoGPjs2kQYwLZudGe2uUxbbK2wh/DeOXxYD8xpveHGlEycZy0yg84WAjZJ9oTbcZSYINtXGqIISCR+wCjjMJA0qACxUX8FsVAWLpnfUOAIQWdlbIX2gG6ANpfvO+ASaalKLa4d4eogZhA1qKKwBEUdSeEazbfD4/83G60+vb0Ug8x1knTjtEypZekCTsVqqq9vJx8h1xjUpBQnWWBVVgbK24aFyARfg31R7LgB8/zqfV338rOLGICJAXNQeYElqKHaYjMdu+3HVs+ysu7Y0KvzXcGVuOB8tLq/2lKDq6eePg/r1Hw+Far7925WJ/Yw0jzeyAhV2pUDKtOo5TW17q9j9ybpkmw3PLq6++eftv/f2/97037+tsI105/3BrJ+6uzFQaqThNNWkqJxMubayVAuGA3YlAIAxSWVOkFoPqhN0KqerxL3j2D6gAQx2cQFW5ooyPE7Eec5+gDQAAhNIFAFUc5rEFJbBhqrDb6vxRBWhIKaUIEQWMMVTHQlQarQg7L16wQs4L8AWOmUW8Jh1UW2mBP+jHOLBFpMl/CAQseLBAjvMiTg/Q8bc2Dw6vJCDSVPtCQVzIB1t4tK9RbgBRqn8ksUET0f7+/sXNTe+FUGttnEelFKEjUiIgHhgk2GI7SYepsrpTbThDUSBlxD4G/ys/9ye//q03v/ob//hX/uJf+u671/cf3fvoc8/88P0bz1+5dvfBwxvXb62urB/O8wz1VuGX2Zk0i8lOpocR2m4SF+XZBeFDXmZjum+YypmWlTa/gcXtHxhwCK+rQ1DkRMjs8WQFtyUuEFwAxQioKPhNuILn86I0URWTFO5WM6oF/Ao4ZlEVB4KaxDfcN0QyNz1vdyzoZNWt6NhBzq3gPudcnufhnkEXbw9I4NPhEeG2FTtfTEfmWpTxXJlIK/y2RTiO2i4M0ATGCiIQexEB4UrsFQYGseQD9kkACQZSXhhBvAg7AUIAEkQU50VQpETmWp4oyzIgi4W9FvZFI3GGyOxj7JVgVmyNeTPR2D5BRGtNwrjYACBEXDdDHTxNRDSZTJq7nb6qvdjCkOo4zZLSimDW6UVRXFrvBZSOABWIgKAE1CEEBGARPkH3FvVg+GPfsMY6OHP7/fFszRJxAEezguMup0kOejeHQ+YRZkUv46y/M55uHe47geW19cHySl7Oth89ePj661iWK+vrl198rre+clTOJ7OpIepEGkswpUuFN6N4vd9/qj84l3T2H9579b3r/+z3vvvqa9dz6C9lHctG4tQbA2kMSeJQHPvSsxXyXCGhkwAIIIqCKriq+gSAOm9EKi30McgbJxhna3ZOCEwNUfiRxrChIGc8Reh00pqICDsUQRSl0CjSCIgQac2+FPEh404RBUBnRUSkkDST8oLolWPP7LACdUDvPfsqHlUW/QvQ4grNq7Vp/YdvbR6M2LhPFlTAM2/6uMNRbGKjD3Z3Lz73QhQl3kNkMl9MiYQQSBEJCAEzEgarrw9OKYYqIQoASUpylBq04+G51XN/7T/8s//tP/hHr3/7m1/40pe/+Qdf++Vf+7WN5f6j7Z2XX/jIOzdv9rsDnXTmpbs3nyVHEEf9dRMjkBQ+QXdWJ+t3X9R9K7ZR63DN8DYnn/UFpUY7CYOHCEgkgOw5BMg2xX6bQRVBEGI4XkVYuQRIgCrYc2ZB9jWcfjhS9/tkcnD1U2DAtJAzIjUU4ulUYKg4Qdv3ecyAK38HQODfs9lsNpt5H1LRqgisRtOV2ncOi74w730IM2wfbP5sJIDj1ROAdxbX9gnai60JEg4eywDtggHiwEMISQrx+lVYUlAIQzETFRlQNJvPp/OZiNSliupHSEsePX7mAhWqRv4URQlLiNr5+3WTqnxhJVg3660xQbetBXCK4zTfNSmTZn2lVJp1Bai0JYCOo9RaG1afgAcMKIggBDWgngBAQAMioRoCWwXvLAWaW3lwT77VH3k7PRB/nHlws3aZmUk5HRcUzUQfOtr3ap/NzKSFyh7tTSdFobLe5tpqr5uMhgf3bt3Yv7/VI3Pt+WeXNzdL4IO9/bibLUdZMR13iSLQXfSrGD29tPrUoKdn84fXb736vR9+5wevvfLu3ShbvrB2aQ5qejghw4xlkkUq0bPZpLB2LtpiPC5nghpRNbBWUDFaDJhohC3DLtAHL4jF6Ti96P/Qw0gt8IrHyF4LJluS2poHoLBy8ygiTcBCBOjAA1a5B1rrLEk0aVJGlGYgx945x+x8kTd1jZiP9ZuzOnBMhU8cf8L6rGPEAGoBH+spOC5VIqCq6BSEUBXqVEOq0B8BAJCD/w7ER1rFkR6NRqD12ur6fFZ04qQgLWgRkQgUIikDTKy0CM7nUwAt4D2GoodMKEKYxmo6ny51orsP7vzST39xe3//f/g7v/6Jz366n0Xf+YNvfPonf/L23fsXnn3eXaWb9x589GMvHk3z2WwivsgS1V1K+91ePAFg3zYntlsTcdr2uCul3BOXzOntXw0TElIFLhIgIJgZa5LaJtYVNtfxDSo2tru72yW2sxGxF1J54UhLUdr6qorltINJ20IYB7wnEcBj3P+Gsvu6CNIJLggtc6i01DmRCkoCW1yWK3hF1cQQYUvThUXLahPNW1sDGpdOGIE2hnFLp0RGrCyhIQcx0IMQ8AxY7/cGHyOo1yiIKhgAGCFEGwEpAAEMPs1aXFaaASqQgPk8VCjSWocQiifMeDMsC60WqmoZ4TgX/ATlkRroo6loyS38E6nhUNo7/fR6Cw/RWkdpFmmtldLeASMpCuW7K/U9aMA1IX0M9ZR/O9Rf+LdHAz5zoXhB3ekd5Lg7LY4gmsTdPE6HTh+M/d6k7CwNlleXjIGHd289uH0jnw77afzRF15Kko7SkWYvzvn53CD2gaK5XTVmo5NcypILaS8t7L0bN9/84ev/4vf+YLB54fJzL93a2j8cT7rLqYlk+/adi+cvkLaAelYWk9xOczd2as5KUENTqabpM2LgthxKmtWJtoIMgHjWUpH6rdurs3WsOvivw4NPcL6QrAk+xDic1IARkaSR7kETaYVKqVAvpXITOg8aQ1hjv9cjVFpHoA2D8iGCh93wcB/FVxE3As1bUGsFnpjl0z0583j161nstOHBUGtzC0856z4nFKCmmUglRs+nOcznly9ffe+tN1YubcyUQXSIECRvhQCoIooAlDjvwQN5gdITQoCVZSpc8fTVp7b3Dsh6P5v+3Je++NWvff1v/43/5i//p/+HV2/euvf+zZeef25Y+AR0GnVu39teWu44KYbl+OFsei5RfR1pHfnpGA2daUVv8l+l1vnCG0ltvG0GExa93YtfqrVGREgUUtQCaT67nSDiGMz3AAB7e3v9mLCYGQTSiXXOUFRLkidtEu1ZltpyHtg9EnILm4VqeIc2D26vH1hgnMdPKYuicpfUym49Vgubojk/sJYmPLAtATf9bIeXn+g/NHfEY/CRdj9lMY2neSMAYWQB34CWAFZw4O3R5tq1XzFgrfI8n80qDVhqc3ej54aKrW0ic+Y2aHf+WLKBYx7cdLgZeaytC+GcYIJuTm7eMRQFgVO8XCsdhZm1XljQ6Fgp7bwAKsHmRsck87GOXUKAyu9bT2Ogy/7Uqf9TtrPY5wcw1D/mrPfMVm0twXHuRqUaOxwTTVlP2IxYHXnXWbuQddPC5ffv3Nq9+662k8ubq5vnLvTOre4NJ2j98mApAxnvH0rhep20J7yh0yvd7FwSyXjy/q3rb3/vB+/cuGO6GxPfKQDT/orLy+HR3nwyWe6Z1Fhx0xycFzd3vD8pDmbCqgMAJMcxFxjQewEYCYSawke1b9U9tlwjYmO8rjhHtaYRQNXfq1JZAHRmjcgQ/v6YAcSWnZkAkIKHzJ9xfjspkFv4f4YU+rIK565IhjLGpGkaRRGhUsqANkCmtpjxfDYRX2HRkcZmo8IJs3CLPKlK7aocYUHheHL81FnDeVKHpmM/8hn3QgQ6jl4JvMwzO60jbZRIwcPx5aeufvebf2CuXWpRHGZBBiYEREVAWZJZ8ACFADooGQC9F5RylvcH3Rs37y2tnDva2Un7g//Fv/9r/4+/+f99+63X1y89dfvG9S8+9UxRTovx/MpTV77/9hvpcjfqD6CQ3fn4/l65Muh1heRs7X1hGINWEbrnnGM5YygaXvI4UiCVllfhL/p2CsYHiYBh9ZbOe++ViK81qeOJoGMDqEhVFvXEW3CIw65Zf/iprfI2XLbNxto3aZthocYebxgw1Gk5SlH7Ps2ttNZVtY9FWMfTEgzUKqCcrshbe7ub4KxW31pCUo05w8yoiUUcW8H6KVLJNP7YrsvB0OCQpI68CxCbjFDnIj9+dk6NVT2vZ1ihYdFJ3HwGgS8Y6qkFzRGCsJohahq3zSetAdekY0T0AUZNMIoiAHTOQlOZr7ogSO+hOElVprGBJgFY1CGOfRDconp8tp+4STc+Pq11z6pCpNSQgdS6T6CTpwm6HN+nspJAWIsowYKhoI7iaaSY5hUEqUp9FgQBCbnVpzSkJ0Bd1q/Qpvgn61g3rnSEqlBBc8d6JCggunkkC+QUeOaJyt47nM+SJZumOUZDK0NbFDqO02iw2mMudx8+enj/tnH26qWLT5/fiKLkaHd7KekJ8uzRA4OwnnW6cUfP55tZsqpoNU46iNs7O2/+8M333nt3ZzS/9NEf35qU24+2D8dj00nXltdCZIGJ0rz04Lyj2KM7mh1xYaHbB++kBakhje4Fp911ITRvYQ20Yx6qbP2G+yIiKPb+A6WkZjWEGz6uvMPp1Q8Ajjx4AGQQJsbgLvJYlbwg9sozem/EaxJFDM4SOAUBs1VYkFSs4tgLCFZBEyFPOeBqGWPKqioYoiaCitycLfwFGzUwQlC/sC6tWO2+E+Upm1E9PrMZztoRL82yakY4nL/Ihts4D9CiSopAIQHAdD5ZXV+bzmaoDSAhKACFngS8B0/kGUvASEcGhJxnJ14xsTCwAoG0k731zjvnL547mljv58Ynn33pxS99/uW//zf/u1/9j//q5tL69TfeWL/67JWLF3ZseeHi+f39/fWVnlPxcD58UPDlfrTeWzEmKfMhgcUKFa5ZRewBGUQAlUKDBoGlZOs9afJBsqMKjDtEt9bFPOrtX6+LwPMQQQSBGRlC5QsRruPUfMMUUYjEY0BflCpsS+rhBEIhJSCOfemYrSudj2IDwFKpK9WWCR3hWhllEUL0IAKiFll+k0bVrKJjRS1MHNZrHSHARYYLK9TiRdSn49VyajVqOvZuNucE9IxWskA1fADg2Evw4QYNPvzC0EBLiUh4a2YGHwwnIYi5qaTpnbBm8MHN7GtsUVKIlQzkA5sHREFBdAGnhQhRgtMnuACgMry1yQs3+Tvtl32yOBXG6NhCvjgXjRjR3IqZA8Z4O1qtGs+WhaYR/hBROxdVdiQSAPHWhkUWRZG1tvQOAJTRisL1DtGzeGHAAIeNSgSFUWndrIOmAjlVp9VLrAo0BQB2zlFl0xNmCXUMAQAriYygQp9WQADI7DxUsH616CcA4DRR/b4NGKwgonc1wC9AVRkMsYpXDEsh7KCq1qDUM4cCgUrW2SOVP/v03JyZl8mMUrNrqdiRVPJm4DGIKCRICACCOHeFkBABUch1QWIUwTIvVdSxXo+9ONPxaedgOru+P5uuXh7rjAHHuR0WkxxpsJytXtjYHR68/ebrD+/eOrc0+NiLL55fGsSO1bR8PunECE+/+KxSamfr4c333r147uJwunuuf+nqWg9n07uPtr7xO7/z2g9fXV9d66aD7e0tnQ5Wut3R8Gh/a9dkuYrTpZWr3ZXNo+l8fzg5HB1O8sIJQpyAtwAiFUZpTdPqdRc04XpkwrSGsIHaNBpORwAApQ1j7UFTLUl/7hH42GwkHJilqhF0vXPMgqGSrXcUIDBPNccWEEgHTT142AAgIKuKIvAIMaAhFABn0JKf5ZNBFvcMUWzG+/ux8cBzQxbBkThfWq2SwdJKJtYkMXsHCpB0Vc2hylqCJO0weC+MoZ6Ec1wBBqMAgGffwGAFakPI4oVDHLIS8Czg2SoRpADPI1XmCyoACLDYgX0qxAZ6jtlrUtaxY4lMKqi8MBmtSuO9rWsfHWMwTccTV9qsk0RRxN4KO6OJhI2K+p3u1sOd0WzSW9t45qMv7I6GjNqzIowMgkJXz5V1wAxxWToAzkxCHofjIrfWGNNf63soS+ACyqPDCcyOdJz+R3/+V7/61/4vN7/z+p//y3/lb////tG/9/yLkKn337937dKF77+2VUbq3NpqObFTkG/cOpg/s3q5d97PRxd6HVX6YjztJmkSxbN8Pi1mcS/F2AAQec8FG+tjVqKSCQgYpYkcs7eWQ+ImUcN+mz0e3kGRC2sYBEk0IJEmDUZKRVQBj1S+f1Ag5LgU4W4Si3ASxcVsnhJpra0VY2LnnfWcpRmRnzssLXsper1uSPU2WgsLM0dRREo5511d7kACYrPSpbVJkmRZtr29HdSslZUVEdHGQL3bGuxD9r7f7xNRpDSZqvxOYKLz+TwE7oaieNZa5z0ATGbTgHIacosJUDzHJpqMRjqKLpw7zyB5nk9m07v375XeXXv6mW6/34kSts7mBTOHzCs3n83zeW5LRIxJK8CQPqBjLSImNnNXDodDBsmSFAE0YwAvBxAiEqUKZ6ezWRLHWmuttFYN4iwhIpAeTcZK67iTFqUrvVNGeyIEGAz64/EYSRyD92IdA2pAcqXNwcWxU0zsHCCbyDhfpfOCgFIqSYzzFeZXg5RS8xGEAMxZx1iFOINgOZhNpiH4w7IQ+QC+EUexL633XLsRsPEEl6WTOlAr2N68985ZzaABWIkAeAJgYAQGYPaFsEPxgWMguDqkggG8YCABuhYRsMWjpAmNZiRVEWOuLdKVcR4prPgaox8gUIRFO2FNvoWwch9KE1WLwIAKwEFVxb0K8SfSxxa+MI4S1OhgHsfglgpdamTfQM4Eg0lEh2dKxf9/pMY15FNt26mnFACERYhFQrAlevRV5SsK2TFY26RUnGWTmS8QIR2MWD3an44YeeXivkrnJptPpkejUZylFzfWLfrb7799/fb7rsif2ly9ev782mApFjRIg8icS+LVTnZw88bm5ublQXecmMP7N5+/fGUl0f3IPLh3940fvnbv4YMoy3SvM5uU/eWlyZzLeU4AkYpAlEAUxebgqBgXfppD7sCjAQhYqY+VIENh2rbO3/wCtf6FiIAAhNIkUCIEZ081VXUob81/BWvluBIkA/yf0UHA/JAlGhqhlTFI6QIAxBwEvLATgs6qRDQLsdPiSQTQIngChxJQNTRhJMIOSJESEE9A9VYgH2SsSsKoozef3OrRDIafsJBCUl/ANK5iroICXUW4tCT6k7dHgBp/qw7WZUZURFWJIak9eWmahHo4gSU3FdPYlZ0sAeTJdAQa406aT0ep1mAJWQkGtRoBfJ0eZoBEARkyZEgSVygPhIeHh0LKEW4f7Gw92vOIJk5XZ8UvfOnHfud3fu/q1Wuf+fhL3/r6V3/il/7Upc3V7YO9K+c3hweHR3vDCMzEc7J0/pvvP9hZjj9/cXXr0a1Y8Oq5iwmZB7fvFDY/f+Wp/fnIcxD6JXIeGYxjEeUJy9KX9byjUtAuBiwEdb5kW2wjCQWRgsVAhUglAGHgyjGMxEBQIUg3w82MlXWUAaIkG/S6sVFR0t3ZPZjsD4ejoyuXL3S7XRFJkqQxY0ZRtL+/v1gmVhtjImNckWtSWZZ1u12lVECcIKIGF6K9A31dZSvATDaKMjOHFJ22GoeNBZiQGitkJTlCAEQry9J6F4KuO/1eT6nJfCaEYL0474oKRNoThGgKCWxHEQlqQSJSgUyETUd1/A1ArIxWSjF4CLV/BYlC3V9E1KGYY0hHQhKsVepmn7QsiIjIARC2GpCwI6rKpzV88sn0nRONiAKdacK8pcLKVKGuSttmgPU4n/DBcw1s2fitwp2C4hvkJBFpJihJEn2mTw4FvHPee5Yqmotqytc8rN2blkJzgh6fcNoshNVVzHFRu6/4ZqvaK7aMyQu/HrsJm1aZOLCOpwgbrG1zwGY1tN/3lAUGj900j6OZZ07oCYWvOkh1RkHFXULVGQQRUBXPEawCTwEZQMgJFqRy0bmDw9IdFq4wMUTJbF5OrC/y3CTx8vJyHJut+4/eePdtL359deXppy6cW1rWeVlOZqlJ+t1eJzLeur2d3fOb52xRpiYC0ufXN2LP7NydO3def/W1g6Phytqq0bFzczQRlGVuy/F87jDqZCnraDS3e0dHcy/zwoaCA0hEpBgZ3I/m45dmbClAQyMhwilHgmBLgqo2xsLSkipStCqKZYyp1vfjZuusKT42PX74/osIVJJsFRl9VgpTHdsip7sdmlIkrZIhpw1cj3sFrFvrLbAGaj3jcmk5rqpNghhSNZr0iQYeDyuQV2gkfc7zQb+rEQ8P90HR6srKrd3t/lLGFmq5OTgVgjsdvffCDIjMTiuKY8MA1jtjTJxkOknE82QysSKkc4kefeJjL/z27333q7/1m//Bf/QfDx9tbd+9ef78paPRKI4TTpJHWw+eu3yN83xii/FsSvn+pWTwzMpGpsz2wQjmRZp2s6Wl8WwORAzeCStg1KI0lQYBmBV6dsxARJGJiEg8H+fRwjFhrYa0DhyrrKuEAhpBeRQAJaAQNaBhUcH+aaIIvHPB+4CgCIUAFPWXelk3VWxF2HtLhJ1OCsDlfF5GmojYOyEQEfbO2WCDERYG8eytZcfeeqfBc+krWDQiyvN8Pp+HuN/2wsA6FGhvb69ZmVh7iwO/b/hxY8c+Bgxu6XyhdbvdAICV57lzzsRRlmVxkuweHCiltBPwzLbS6jwBGFWrd6SUUoIaqOnk8dKtP5MkIUTygsKMoAjqPIOqIWLAvEQkoEqMbUSH5tXC0nfOWWux5nmnN/sHNsRj7gat2KuqSG+L0YYWTPrtUGdZbLDo86YahqUhHSFSQUMVRBOexwgMwoLMPvi4uMZBqVD0BYQrJ0goGAJYOYnab3Os17Yat79gZf466Zp+YnsSfWnfQ0SUqkT44/Gt+P3JEV+QJE4f+VEodCVtATUuyeAcAmRCBchcRQJDANhUAggKGUUwSJEs6EWx0ORoTtlgxmbraHoEhvorYKL9eTEt3Bwgy7orSwPv/Y0bN27duzufTD7y0kdW+r3lXg+tddNp4nm5n2wuLU0fPSym00G3pxHu3L7lbfmR555F7wzou7fvXH/3vcPDwyRLoyjJ8xxIj2dzpoi1npUWjFrOOnMHewf7R7OyAHIhUIE0BHwYQHlcUNVjGh7b4bFZ2YwgdYBNkMLai/14altzXLHkVj5AFcShnmSxWJzrD+rnqT40onHDxpRSZ8rWdZ/PWNunOeKTe9L0p82AoU3UPmiVniAQTfqE99C8SAVhIa7J4RERa0sBGSwtRUYdDQ/A2/X11etvldp0S5ZQ7wkIQla0IIA464QlFFKsKs66Mp/OZ1mnV5Z54d1sNhHxSZx4ltl0lCa9X/qTn/vK73/nd37rN77w879w/bVXPprEl9bW7m092lxd2bn/EADQ6L3Do/OXLtj9B1bHDw6HGZmeMlknVkoxclkUKjOeAch7YUJwyMggIkhKByR/AkQPwCGxuwpiCvanAB2D0AClNsxYUAGgoFKGlI5QGVLGEXkgzyQIsSInAkCefaOICDIp8N4W86m3RZqUINzrpr1uev/ubaNJa924CYN+GXyHoVqRtTbIRoaUUTqgnAakkcBpwuUn5hdaPLXhYVDvlHbkcyNjnZTmWi2Uvzyhw0lVdvN4TVZPoSri41gwFVQ1Aw7yYcWuQILNwBgTLAXCPtg9n8yApVWKuHlrAUCskNKttSFd8ENuqBONiKiy5dTcF6s3wsVSGe3hbUauPQXNsDQST/hujInjmOpUpaArawpOtbP1uZOR4szM3jM7ZkAkUKGC20lLyGJ3m+PhPs2zjm8bGiIB4Bm6bxigymcLp1VSEWlCcJpBaI9X7a8Ny/H4PFhQiBeY7tmr8oPbiUg0rh/LhCQoCiRAFQZLNwASA4AwkhdilBLQsnKgpohlCUelO3RUdjJIu2OW3WLilep0OoNuv7Dl7du379y5Q7F+/rnnNlfXDHI5mYKzS6gvLA82e90U5OaDhxfOn7v41IW9vb3ZeBJrfX59Y35wSFq99cPXbr9/O9LxUm/JO5nZottbnYmalt4CdZaWPaqj6exwOjuazkpAH1alIlAEhKHqxo86QKiIEZp8RFBUTZdvcAkAasutEggJkfWQ1uyqnp4KOb0qTOTFWlTx2c89FXJS3eNxJvSzSFPDyZrUyWNKJ+1zBKrQVmlCSdv88nEs+Qm0o335aQZcKxbHiSKI1H41qUEkTgwFLDJmkGMNOFBAZgdEWRpPdg/t+GhteaWtNkHQFkUEOYQiMTskzexLW4TTyjKfzWbbuzu581bg/qNtFlrKUutcPj5USfbln/zM9VvvfP0r3/nZn//ZgcLbb77+iR//yaI/mFp79fKlR7tby/2VeNClbspl5/7RaENBSXgwPOqAvHDtWj9LRg9ugwv2YRGQUpwXUMIIYDDSqFAFr1tVjI9QtyIlm72PgCQsBCgVtm4YYYWoFCFqpUwESiNpEWIGLyKoOARLg2gAQWKw3vu9vfHk/CgjMZHKUgNgC2+t9UZRUntMAkSwAgmclYQNVY5G0QoAlFJGRUQUxzEixnEcUMrjOD5REhtrd37c7bZ5WDPFzfnS0sPa6+mYW7eWYuDoYT0EjOjGT4E1J0JEC+zYNbyHKACg4LE+Wj+HaqN9dSUBgUBTcazF1ImoDiKrHgWLfA7geK2GovfBrttGAvnwLWzhIF1X62JxizU7i+qKWM3bNWOFLV25zYAD9nXT+UATAr50cNaGSKHK+1vZQAmVUlophaSCy81zyN0uS1eW1pbeubYc1rxKW/098dkQ2ZMUp+n9Y8anoSVnct/jQVwQoFoEtE2zmse1f2of/MPx3rMbcuPhBpYK7U8YAvkOxay9ElHssWTKnZqzmrDxnaWdud8p2HeXfHd5O7ePZoUzaZR1eoN+4crr19+7fv06KHr26Wc+9pEXCRCcB2dToo3+YLM/0IXdvXfPlsWzT1/LkvTBnduDfq+fpXY+i7WZjI6uv3tjfDTKsq6gKZxnobjTxSg5nE7n3vfX1nXWvbe9fW/rESsURagItAKtQpBUkIw/KOdroQkAakVKIVHDyKt/1XC1PqGpMS0nKIKq4ZRDN4L8+yE33oef4jb9gtZKO+b3p1JZTuiaJ3xC2Grt0z5kt5/cHndh+ykN+Wi6FA6GAWzrN5UeoxGBoZwPOgkKH+7vdgfdbrfrnQg2SbLVqyJXqpU2pE0NbU+otVYKp9Px3t7O3t5OWeZxbLrdrNNNsyTuZQby0SdffKar4Fu/85Wnz20M7z842tp65uJ5O50+e+Xq4eHhaD5dPnfu3sHODPHd7T29dm7l6edv7h3+9//kn/3mV792OMnX1s87Kyg6VpFRmogYgRWCRu89CocQC7alcyVbx+KoInTVlFZvLWFofFjcKEIB0QtYoIp2VrWai3WmOHMFqYigUEA8s3OaIFbKKIoVaRBkS+yIrSGFLQ2pYTYN7VKtRkTGmOBuDFMWJtpaGxhhYDnBgBFaKNfTtMCZ2qW0ThPGM1dRURRhSQTtPDDd8OeZ1zbLpk1725wJW8Q56KztTQF1NFl7e2KLk7W3zOKfAAAhBi30s722P3xrkZmFgWoe156jtgHjZOZVszYaF1VtcA6jOp1OJ5NJKAkMALrKk68CRBiBA7a60sp6EcFQlziIRex8UZTMXgQUCZFmZqGWzR1b+gowIFfuczmRYhVMQCdz5IkqTOnTuq+wNHmMTTl6EGaBCiYEEfF4NXONgtceFDn1pf39eBCldUQeR9YfR/LoWPc9bhKi7wCRsfIrCAoxolcsxIAWyQrOgWZiSjTjuZ9SXKaJj7MjJ3ulz5WJuh0V097B7taDhwd7+4OVpYsXL25sbCAieo6VSZXugmSkEhY3n00P9p+7+rQx5vbdO957g7Q6GACLArlx6+7+zm6WdbOsO8lzimNt1NG02BqPpp5LpDLPdw9HR9NpyWKICI0Pb4cY7OcADPIjL3QMlp4wfljFZdRx7Wde0KJ3rQ1fzvMgwrf37eOLBLfv9KNx39DaPDg80dc1us+8odT+3ROsuk07Fk7+cCbxE7Tv5PHHs/KGuDRIPQ35CxRkNpsRkTbUkJVAa4xiNxv3u2kS0d7uzsbVa/1+z05GIBRSq4URQlW0kAclXpNSSAUii0SRVkZ7ZKCLyeGRE+jNcxWnSZIIUqYjcPn+o/uXN1d/6rMXvvm7333+ox/b7A8eXn///IWn1gd9YT537lzu/O7R4dTaNEsGF5/64YNdjPtXP/25b377e//3//r/88orr/3Pf+Xf6WUmiVWkDCh0jh1YRRRpYsfsfCjjrIKZUQhYUIgAsIpEQKjNj8AhFw2rEEMGQhb2dl4wxmTnYFKkRKMSZCSEAB1djUXFwsW6tUHaTztYznyRO55BWUYq1lF04C176+qSwyGMH4EVIVO4D0MoiysipC1aAGDm+XzesIeyLOM4Ps0wAEC3ZNP2emv8/TWZFWxDEp2SArHlP8bG20Jkazi5JrxBpHGXnrFlGit005egAVtrQZrgquM99YT1j2cGgki1hpk5iCNF6Znhgyosn71HoM3jAx+xjhY1w7ap/MReDrIsnNqtzds1Y9IAtxFgHUWMQQOu4OiUUkbVALcgVPfMOeec9068F+8X+H+rHWvSEAjsqdzMwGibNdReK48ZnYVc+BOLD1o6dGjta9u3PfMRpw9+GBp9ujW4gMHvW7+0AIDz3lVUWzyDFxBWLMoLsSgnugQ9BzOHaIZmgvGtvVGZ9fXKxoGVh6NJoaNoaZnSDkb6+s3rb7/7TpxmL7/88pUrV5zz2w+3vfeaKEJUTrAolLN9ZVa63Y985CP3H27dvHlzZWn56Oiok2UrgyVblvfu3MlnxcrKWpx05pZ13KUo29o7vH7nrkMFJrr7YPv2/YegTTZYLp33RMEfBrCQ0Pwjt1rrRawU3ydwX5ST09oI+9LSPhvWYurcjDNu9eHm/QkntLcZ163djRMt9IoXE/Aft85Pr+cndOnE5R9yrbYJYnvbMnMABw5BNyGWrRIvPCsCV+ax0SZS4/ERaJVlmfeeMcQ6ENfYT1K5fgMBAgAgBXEUddKkl6Wb6xvrG6sbGxvLy8tK03w6no4n7MqD3R30NjH6kx/96GQP/uU//c1nLl062tt5ePvO0xcv7z/a+eiLH9HGvPnuO/2VZepkU4ruHk12PSxffebyy58aA/ydf/i9//Vf/c/GozyfWi4ECpFcJGewgl5p0iQojkFUZJI07kZRQhgBEIgGUAyKwYTPkHYLLAGGE8Rj9Sm2KHyR+7IAZ4m9YlboDbL4sJ8xJMUiAHoA50lAI8VKJ1rHSitBdFZKF2kTFLVGNwqt0VOpriabJEmInAoLPnDBEA6dJEmzuprWkPhmZZ5JKtvrp70mT6yWoHY3vA1abOP0+XIKWezEmj/92YiwbbZ3JgNuGMSZx6Vew4EC0JmQ7x+iSUvCbg+ULMo3J8hRezRCd8I8+ro1s1OWpYhEUdTr9QaDQa/XS5IkiiLtXIkkFEpchi1knXNlYJAMJEJeWBAQKYqitbU1AJAqZ/M40K7uddXXOhY8MFoW4ROv10hGJ83OEjIgEQBUBcV1vLGD7htCJSq/vMYTKbnsAaAqSF4/NBAd4QApenxcoFKSkUgBgMBxJY2KYD2Gup2gvM2X6r1YACv7qRMGgLTbKcuytA6RlIlIGe/FlixoSEe55/1ZkZvId7KZp0ejfP3pF0YOd4+mh9ZD1o36A6tNXs6/+pv/dH25/8lPfnJ1ZZ2Uns7mIJSmWURgizzrdlZSs2JMptTOo7vL/QGwTKazpZXlyXTaTzqxiUZHR9PR9PVX39jcPO8d7x0Mo6Q3d7g1PHz/4faVF15+sD988PDRcDZTacpai4CKEwYAwsqDX023gMIzkaSgQeK1losCjOn1esaY0tq8ruchgcrVUjRUYniwKFUxM43ZpCI3NdEJCof3VUUEqKvRAQDpkDFSYelVgjZRe+0d8x4BUATeKxOH65UKfudKzA8UIZBIAPDel7ZUCFEUWV3lWYYuaaqAHogIBL0Pdt18Op1qA8GHF5w41SvwMcBQeD2qozMUVWmpuFjYB1pk4rQ2cGYLVzcDopQqyjnUpsJGqAUAES6KQptjNHkRiSLt8nnc6xR+ZowZjUbl3t5LL3/8777yg5efu3r/5jsb/VTrGL2N0nR0NEk6mXK+KAoUzpIEFITHx3F8sL2XZZl1kKUOtVFRtLqeWO/6/e7OwSEW7tzla5/5eO+H7+3+o1//H3/uV3717s3bF55+ZmN9dX84vHTxvAU3PDpYXV5m0txf+sHN2yrOPvdzv/D13/3awzffJOv+6n/yX/zf/vP/zWc+8TGRIo3j0s6j2Mzn89lsrnVkTExItsTgt2UgQwkqQlAC4jw754QFwXeSSJNoVZE1HyA40KexIaOMAkWCxAIswt6zVjpJsslklkYxOOcL2+92R4ejXtY93Ntf6cQKsJjnGolRByU7LwKMNmmjQiUtJCBlFJD3vrRecVBkSeoZt9b2er3AoSeTSWDYDeXButKlcy6J44ZzhGUcmH0Votj6KayiPM/Tboets9Z24jTcJ4qi2WyGiKF6JgAEdOU8z7kucVFpvvUiNMZwPg/Xaq3BemZfbRAUrRQFD5xnEQnKpffeIxDpMBrGmE6nk+d5v98Pey2JYhGx1jelzLB2XYeyUkqp2EBZlkqpR48eIeJ0Ok2z3ng0rRdwFEVRsJAZrZ1z2sQB+6HCu6ysHlyWpVKstFKaEJGJpH5cM1ZY2xK4hvNsKH8YNxHp9/vBoRN2WVURq0VPmLldKlgLeGEJKCaexbNl77jC6UZEJYiAGhUpDLaWwDgXKFqLOggAi/jatcx1YXapP4+H8kySIeKhDkVuUYfaNwB4LIm09Mt/zXaCwFVfPoRe0YhmzZegBAsAsDAcozjlZeFZREUM5BwCCwiBMiVHo2kxI6LeskO9PS2noNXy2m7hp05G1jllOsvLqte9cf/+G2+9vrGxsdTrpp1eFMVY1Z8BBMrzvKf08mAlms3Iy2R4GCMOuh0g8oJeCEiRVkja5cV8VnjhyXSWdgad/tL2eHLv4b2c1LkrT79/9/7BLB/N5gUIIGnUHkFCvDa09NQgpciTht9aK9aCUqF+dZBFghgELV0wiFNSERSsbh3iEDFEybeGu4mS+KBJ+ZAsquL9iwIv0RmrtFl4bevT8U9yLCxCXcih7WeF2vMaEOf/dYwI0Fpv1fcfyRVfX9Uen0Zab3i8iPhQrZFdCOAcz/PC+k6aMinSsYlSKyglKxFQVc6E1hqqhS/swbmSPVjxRVFESmsTJUmS29l0Ovdu5kEuXX7qaJwnvaXt7d3PfvbHPvlT3d/4l1//qdmsk2UaaXVpee791JYGaTyajJSejSfdJOmtrrz7cOvplbX/1f/+//jrf/2/vvHt7xxO7e37uy885w3i0eiosPPl9QGL6i1tBinHM3jHPlQTIJULEmsIwd4iQhEqpdA7dACWPTZmYCTFAKCIlAr0FJUGUN6CCFtrA//L85LYKyDSJstCJJQiIgXIjOJFgBxzf2mZImNzW/qSSlf6ki0LoSucB09CoEAB+crkxwpPyo6niVV7KZ5Y820Noa2oNWc2whbX8QrBBHJc1/aUshs24ZkLrln2dKpjJ1qjRIcdfULQPLO1iW04wszeV8wvOK2ttZH3p8fhzPu0O1Nv6iqvqTkzGMybITr9Fs2Z4c+Qb011oBYzB708HG9fFT41MgOy986JFw6L1IuILT2gItKolKrrNyvE4AgUEUQVsmwbI3792f4SbLL1roY29Wwrvm24SsAAtQ2V4zmotAoRgEPNjaqga5iMhVhPOuvOcvwrHhNEbJXBahPrhsQf9/nMTJt6BqWxugAgKBEJEWbV+0jlIHGORUVAEQtZIfYEpElF07mdirYqdpQcMRyyn5ExKtkajryJqNPtZB0GePjw/t3bN/f3dl74/Kc7SdzNejqK0Cv2AWgPB/2lYniYT2d2NHrx2rWyKE23m09nXrBkKVkAlYpiZYyd5ePZfDovl3orHtXBcLQ/zSXOGGn7aHLrwVYhyAxCBlXkkbwACyOqVmXrSsqgJyJLSFkCs86yJEmgXo6IlU3hmDRIa7yC+QEBQh2a5khzz0ZjfgzLaW+8D8WGmaGO84RQThUVLSbttalYkGqbUJTmESK1VhBkWV+ZBKlG/pVFc/TjWGYjWJ4gnadFvWbHNe/4IZnwCYLe9O0MkyCIArZFrnWWZZk9mI4m097yitIxqCjKet5OvHWREnTMQMGeo7z1EOKSRACZWViODg7j0mb9QRRFnQ5CUSgycdaZTa3WnTQb7Iz3P/bxz/z4z/7C9966tf1o78rHPjY6OnJR7Iu8m6TPXrp8/fbNcjxZXl0XkYPpLGWc3L6zEUWP5mWeZOvnC876lPSTJCqYDNq0P5jkk92jKaiAYqAQiVSkTUQ6Go0mpBWCRlSiCBGVMoSu4KlHwoADTcHuo0BF03ys0UnsxTKRK4Uck/eilEJFpJXzXoEYrTyzio0VsAI5gwZwjE6g9FyyDEdHOo3FA5BEkTI6AYNxGk14CuAJFJAAagZ2nr23aRRjq7ROe3ZOzGk1ZTU68YlJD5pcc3Lbe9LmzbwYYAhnxSsEBtxowG120l7kVKuPZy5CIgKp0ehatvQnr+FaqF0IJCQi733I4AotWJJae+3E4j/jIS2T8oLQLMxBC2gfhJYrp3n3QCjy6cwYE3xhzUhqrUOMRdt/HO4TgDhYhNlbcZ7Fh+DvoiiIiJQxEAt5YEIVBrTqwAk5Iuw1CCosclUSFDmUbjx+AfBn4Sq3BqIen3qp1cir4tuEplk9T5yvs5pUBRalQrqvUv8adnvMgIMGf8x1zmgnaSL4Kvuk7eEOSpaJGLWAsqIcKi/IrFnU9myeDJbKJN7Ji0NGl/U8RQezYioSR0l3eZlJvXPrxhvvvcOEL734XMgDMcrUUTAaCAhoZ3+4GkWXLl0e3rpp8+Lm+++/fOnS+vmLU885Q+mBgEgnqIwXsM7rKLZeRkeTw4mFbq/bHezv7r5541bBANqoKALSAsoJMAMIiGpJHB+iNkC18YxJkkQpFeRTJDKJYap1QQkhpNLw3ZDzR4vSDcgCN6pEAG5MDSfmN/DCD60BA6AxAZhMRMqypDpjEhbdYw2pCmoQ0UkjUJjsoOM36IBaayTf3LDp2xMyuE5rLc39obYMnRC920P05NZQ8NNHGuoZCAQzizgRKct5GveSLBPA/cOji9eeibLO3DodZ87NWdCQYRDQJljd6ll1RKRJswEBeu65F6yAKC1KCxXWgSAZncxm8zQbzOYsFHswz734sT/xc794Y2v7CtLB/jBbXQHrdcTnl5dHO91hnnPp415v/9GjlacuDbe2rr/+xse/9OXLv/hLL1+6dHlpeYqyvbs3Hk/6K13H6mDuOr0VEbGOi6KYzvPCTrwTD9jvDbQYgxEZTRjqFJFBD640ShnCADwJQaomVUIhEOVM4EGDQR0rrSFCdqVowiSSvFCRZu8OptNJaSFJvNGWyAs7JNHkFQFL1l+K0lgce2ClTG6LYjafFrlG5QPmMABSDb5KmpmJsGEtbb4Spo/q/ByprSzt4ycWlSw2qMs4yqJ+fCyHwcktVvXh/8/an/VKkmRpgthZREQXW+7mu3ssGRGZWbnUmlVdXd0znJqZxjS4YIiZB4LgAx9I/gXygT+DfBoQIEC+EAQbJEGCA5KD6Ub3oJeqzq6prqwtM/YID1+u390WXUTOOXwQVTW77h5ZlURrJizU7Zqp6SIiZ/vO940r5ZujK3996nD6tnGII2xQVbOXNtjOb3cjJzsNo8srIojgvc+TIhPy5IuabtVbjzP9xjSp9wu6+/cnpTSxteynvl5ziSZPfd8i4NijkV3byVPZR2+53JmODKagoGZCiI4QRBSyGOXO1O0vR7B7Nghj1yOMse/4T3ut+jt9bGSUfIsx3ouNsoikIWiuVuW6rw4ZDFUAtG8Dvu635O66hO2N3PJ4bm81wOPy9i0n+eaaaDkCnsw5qAGKoXOhj7buY1I1JjUfFRqNbah69o3wtbo1UeJiC7ySZnb3ngtF08dnL7747JOPU9e88513vvfRB5lROte5TQFg6Ku7f+/h6vTZZ198aefnJx9+uDq5M69nZ2dnPFv2qtHAAUYzQQeuQF+iKy+uV1FdfXhny8Xnz08/e/Fyq+hDCc4TsyEmQc0OD+4s4uSPIOgv8aVMFZzLMkGZT0dEQlGAZbi9oYGpja2bg74oAWbyoenRMCDuk/2NyYZv84pyhXj6ME4p7rdORQBA8N5L0znEzBacHdjJud6fV0SEilNJeDqmqjKOjqKpSsYqphgjh0z0N1wOjhkA1bcDPt+MgOHNAbbX4GF7I3TKBiG+XW1tuquwtxbnN/fX8d1kByQkjQqE9XwWqvL88gLI37n74PL66qAspAnEyQU2EWIypODLBGiSnycSs3MMiEVVb7o+KaBzSIUa9zGBubI6vFy3V22nWCyO7617bQWxrFZNHzg8Xh6oardtSrHHB0e13/7l05d3uDg5uXezbSSE6t693/6937sfws3Tb/7q9Kw2hdS7ok6+/vL86psXL378az9AMHPQq2vEb6WLKFE0qnPqSygceFPKsBmQnqPMHJWF957dyKVqSu7wHrlawzJSLeaJCqKSmZrNpWoyT4AhzKrYbq+2TSo8zuYp2AbFovRqYprMgWqz2VQp5gjYSgIkF8pQ+s1qK5by+8LAnhx5R6QpKei+Vdg3tNmxm4aBvaHzMVnE/XcmQz4dNhu2fQjeZID3UzU41Y8HHZ7xd+GWYOO3jrzXxvn48X2/Ar7dZtvOMxjOWUTMABHzOWcDrJppVm95G1PWzfZO+7Xz2Z8d005eXScDvL8UTC719EQQcUKn40iKkmFZ2WWfwHfTF122uIRoREYAim6PKIsYaVgURzbO4UTzWnDrMcNQ9N3fyQ9SJ5/jb3w8lHWwh0/nW5PXtV3sO95HMwD6tnLEt295nZx+4LUI+Pa+2a3Gqte319bEjPgeDy15aGVweZ9k3cbVVjolYDS2JLQWDMd3ztq+QdXZHFy47GJrEJZH9cHRutl+8flnn3zyCx/od37jR/ce3I3SARYK4x0yIGIANMCzi8sZh/l8mbbbm5v1ixcvPjg6Ojk5OQM08sacRLskMQmSq+r5q/Pzw4M7y/robNN/9vTrz88v1wq+XuRhlFTFUI0h96HlvgUDgEECa2BGA9VRLOzNu+yLIleS+r6XlPKDjH1/6/OIWR3VVEEBeOQOA5ieuu2Ns+np7PLTb/vp6dH8zXGhmXMuajN+2ObzeWbrtdvg/Mml3cdk6dQLONwOBYCcf842mAPn4Tatehmopd8u07lzQG9fgr3N2xvnxd92Dtj+Pbx9WBjTejr2IIGiY0eRwLCqZgcHR89fXoDhgyfv/NkffX24uAvkFRAopLghIsiCjGaqkBJYVgJImsDWm0aI2IfAvizrJblm23WCF5fr0+tmee/+nXv3/95/5z/++tnL/+qf/rM/+I//IwqFmDWbrTMU1WVRHD1558vnL5uH/ovnp9/5/odfPX86n9dHjx//2eefh647/+TTk7L83qNHR4vFbFHfeHx6cxEXB5+dXxfkiqJE52FWujk5oxJxtd46V0QKaJQStL12XYTUzYy2DivjUomJECzHZKGcRQgaQVNnLQMrUkS2UEIbWw6FkhYMHUgkvP+d9/4f/89/tAw4C84hOBd8NUNXs8H9e/cDwHbbdl3TJxnXRpotlin1fZ9EomQFJUxoGkAVdlCgaZsM8P5qbnvzZVqU9u3ElKGdvjvhdbMNm14nA/zaHNsN4/G39kfONE0mi/xLxuEwcQCN/lbJqun8cYQ6519U1e12u9ls8kFijGCU8THf8rujHQGYTlhFdQgL8swfvOYQwmsp6LwvIvv/nG64Y87ui42ZpPwUMgfWfoicv+hUEqEDRGIYyUwM0XxgQgeZ9OB2GcwyTdGbKeix6Dvu7xvmvHOLzeStW16QacwkAgxmONPjZ8NPU5BAr607bwRkRq8NIHsjAh7v3XQV4xnuPvbWMsbggow3NO9MEGjLqVUYkgDcbNum1ybqNqJiaw6QysTcKzToOmZhtzXskCCUxWJxvl5/89XXX371JTG+/94777/zyDl6dXnl6ioBIjAYITkwyp0HR4fHm7OXn3z6+R2Usizv3L9HzKdnF3x4h4uSNKZt2jZd07UVYVFXXJTVbLHp0ydffPnZy3OZLYv5fB2jd05VLUskIiANmr44BLsCMFnfv2HLDmDf9ymlTJ2Ry4E72cH8DAEBQJIAkRkADx5Mnuoyzuo8YfZS1t+y7f3pjfH51s8rEZlqxss4BwcHB8fHx/sL3PTN/SSS7UUSIgLEeWhNwcQYUgCggJqIaBpYHv8WN+8tl3D7Km9XgodP/+0P/Pr6iCOSNqOKpuMJmJo1fYc+VPX84vqLvo937z3YbFt2wZDEICbdtn1RFJ6xbVvTzLFAqtKn2LWxlRiKogwFep9S6rrUiXRdv2rVh9m77z25+95797/zARXVP/q//p/WfTy6+0DBCheur68vX519+vO/fvn40e//7k+WoXjnTv3V0+dXZ+eHB0eu9N7R+fObUvUHf+8PqqRE+NX5GbRrc3AT4w+//2t2vQWAHjmpiVhSExUFpGKmLkQqgFAIoqeEAbUUAyHomRSBwZjAEXrmBrwaWaJkkPpewAxEMdVzaPobYt+2bV2U7fpmxnb88OH/5r/4L1iabnNzfvrq+emrV2dXry6ut1c3f/wnf770CEDO0cHBUVF454Iadl2fdXfy+FLL4BNRHMhupue1Z2oB9pas6Z1plNoYmdkbG+xlX/GNvppdeeWN4bc7wu0Z9Vqz+54h+KXDb3i55QX+8q+oKu2BKnLn/2azWa1WuRVCVTNqev9i33om+761qiqoohLadFL7n5zOMO9kkPL+TcufjH2cPjb1XufGs+loU4YfANyQ0p9SjAgKhEDsPSIjeaJsgAedRcxqLwNhxniKqCPlUxYUMLNMrbW7d3s7OHzltjQsACBolsBAREAFRQOZQv7pXmQ1mEw/+7fKd+xtr3EXD8qfGU6cSSOBDAGMco93Fj958ziIDKAAZLaf81FSJQMxIyQFToCJuAd/FdsWaEOwAeiUUYMLFZbVy1UX7t6hIpxvNlepd4tlmM8V9etvvvrk049T3/7wB7/23nvvNm2fUj+bHwh5AAZhwyxuAyqqKbadMAKCOue2bdt2XW/iC8dEBZM57sEaiZuU2Hkqi1//jd/6xV999hd//fnZqinLWefCVoxdcIQCIjbw6iGSmGYBbMix9jhY0CjTAd/mAR130Iw4iXV9UkMfSgBoY0/sdUzIAgCISc41JAMyZEDdpRNMjUyzkgmOMXHO698yjMPgAQMQU0AgIwQlQ8pkCuNoee0VDDSlUlKfuoKpYAmei6KcLUohFQIFUhiSxghKBqTijAFIjCK41jyAgZFDRyYowmqQ0KdkMXMugaGYmaaBuMP2itMjeTgYjLpJONxbIAAjy3l+RFMEMjRSUAI2VFDMGrdgNnZUj3ztgIpmhgpOMBGSAgnSIMJpk672rYlpI12AjJKxBpRE+oTQ9o7Es1uv19u2KWfLrXDyiy2t15Y68euks2IeKay2awdMOfkG0iZY92nTK/WpBnDAbZIEUNUHs8PKq5+dvH///e83IrOTk//3P/0X/9v/3f/+D//hPzw8vvPVN09/7dceFCH8xdN/+3/+P/wfi6r8X/+v/pfvffT9brv+wQ8+/Pjpl/eOll+dvvBVee/Ju9evXr0iN5+Xy1DcIPkQNn3z8uLsfn3Yb7Q0MGIzM0YgRnbMvu1i5ndGZC0IAJBdYcCqqJBARYXQHBN6R86ZIqBTcITBGZlRUlLrv7p6drU6N8OrqysyaDfrx3ePNJRfrJtl6Zd3njx+/J33fIXskpp1MZ1fFmaXl5enp6fnr86++OKLr7/6Yvvi9Pri0hGHws2rejabVWXl2TmAfrMCQEZWUwEjAwI2pDF+y3EKIijmtRf9FAlZHmGIefyYohqqEQEbAiACsmdfkEtkSi44RwDJe+8ZMmlwnm40LZqYjblkTEiewTAmhW1o8Ml2TUBx7Dm8veTuxptCjjlvfYBsXyd574tmujdcFUxVSw+OIMXYtm0yBWQgRWZLmQFN2cxMXovU3rTHqpnCfOdf5Jm4XwOenBVEbJom70y4qmwFrlbrydxmA5z5CfCNIkL+vLu5Xmcj570rfCByTd/3m+18Ps+J56z7a0AwRCA2LBM8JjpMATU4UJV8qLxeqcAg5WCcQ9VbEYnIW3glwQgMTLIis2VRaQBEdEXIdIMIaGqqwkjsne1IhGGMs4fnOBxyV3AnBIwpAQOTR2S1DHJDZEJAIIfoQSGl1HRN3yeT/u7xHEwsE7vjjkYuS9kBEhKOnHzi1CpTFO2MlQP4QqnYiNsY/8WL6+gqDTWWM3SFcVDATig8fnRjdnF1ve7bxcnR4uTg7Orq488/+/O//Ou79++9++73To7vtMCKBfiqS5RRbYZiyIaGhAzMZBjjvCr79ZWg37abdz549/Lq6uTuPey7O2V5Fps12uVm/c3lWf3kveLg4NG77/2zf/Kvnn/97OG7H+ji6K9fvmzVwp07IilnYlQHGJ2nAVkzOpOqOwIWA/ajjBkDIoxpFm3bru87JCBi74XIIdWh2q43u0SFDc8HDQyYFEnHMgAgGzKagQDKSMs+PEtCBBtyg7uZAaCE26YTAuj6ru9RbZC2R1jOF9P+9OosHdUH0GxPZuXV9atXZ98c/dp7/7P/+f90flT/xcc/60Cq2UyREMg558BIZeGKtO6Olifp8Qdn6+2np6uPHj1azMvLFy8qchVC0IRNA1vBNoFJu20ji5kxDAjqzOo3qJ2omioQELERJjAGGIShKdtkJodsyOQUFA0N0AwVEAFMtO+HplLvPbEHQhVLqgrYSerVIrEiswr2XUlFPZ+BpRyfT/AQM0MmMbUE7MwDGVBKklJq23a+OEzAEjU4evfhw5/+9Kf/4D//H2+x/NnXNweH79DBRx0FB/Rytfr07PnDuva6lU7iINRc0vIOOi4XcyxCtVw8OLlzcHToipCirhJ+fZ3+fNv/7M///L/8//5XF1eXf/jf/U9/9OMfP/vm5ftPvnO0PGTAypXHdx9dPHv6z//lv37vBz88uXdw/eIbYvnm2ZfV8pDr2em276vF58/O2IXr61UI4f7DBxdX3fW1Pv/rp7ReV8RZXA8MjXIrUcHMhEBOvS9CcEVRBF/MkKXtSxUiYiTPREQtERp0XYdGZpZS0zTdar1dr9ebvt3GjaACDIR/VNWfblo2ti66bYcXDe7wccRgD49PAmHxeHH0nY/uO/4tdh6BAb7+/Iurs1fffPnFl59/8eLZ0+sXp7HvXLLvPngkxh6ImdkDqCaJqZN5PZc0EgKjoYnk9tOZT2YoQqoOyRETEiKz46vrLRDOQinEimAA0vbWa1o1ZsZJpe2JrAw+I3zZMRIBcTJNSaNZNMh8XwoDipAtp/2yKFnZbdZdTPPamWmS5AqHZkRIzqNZUkhJohcjACBnBABJ1BCBHLJY37HjFDvnAgFI7B1751yfImFuqw2ArEiECJZERDo4ffrVvcfvf/bpF1wtvnj69PGTdzfr9bKuNjfXswIKnsWoGlXJx6QhhJQimgGaqsaoOZlclqUHINBccmV2SoyI0seJUgMRM0dKZkSZrM5EQmBmy+VyKj/lr+TEUlEMHPUZsJ2T/IjovPdZ/tY5diEQYUbVIzMCZ1TqwHSRPXEbmBfGBt8B5wxoWSk9u+M2ZqHfdGRuGdzbG4EajIRcAJOFNrPpeiZ+FgBg5v42ecrfkMQY9HZzeWBwRAwJFI0Ix94QBdqNs1ubAvAUAk6tJARgoxB63/dMRFyKDxGLm8QXCW4SpMW9m96uN3Fzc81FVS8PlocHYba4jLbq2x55cXRczqqbm5tvvvnq+fNvHj2+d3B8Ui8XrioAiuxnGhFIwuzSTnU7VLZccjYz7ft+07cONaFtutZdX5eqtSPvQFEvV5eX64OH8+Mf/vqPf/jDf/vsyxfXl5eB3aN7J9dI6xQNp1b7XEDKBaEu98sDABIzo8v3mahbrfbu71AzMrPy4GByhsjEUjIAA6rLsOO3AmTEzK+7XW8ADDJ8Qs3yDqT7j+8kafu+77oudf0wEyyrteyqOABABmpw5+7BYKjQIDvYCoZ2c3WNoComJkks/4813VxfonRV6Q9O5n/w+7/+h//Rv/eT3/8NV1gnrYIYalRBVUZiBJQEpsCOfJDg12vrzy8uNk1F8J3792uAHqwEAPLqnDpKFnqRlBvgCD06IcfkzbH0pmhqomT5WTpkRIwCqEhEaPn+gyqqIiru4xZzOz4BJAwAgEgKDo1AWQAiCLuQQBKKKkQXOioclQi+7aMZAZAZG3pjMxoSlXlCkSt9mFEICEAaXZV4NiNw4IrCNTSrNyKXFxcf/NbvLI8eVMtj5QK5MvKzJjZXL85/8dMaZ84XReEWZVXURT1buMqrYStd0/Yvz65f/tVXn37x6aeffv7l6dnHn3wFJ3d/7Yc//sFPfvve3btHRwdVPQt1qMtgKYWy+slv/+asKk5PXzx5/NhMkvTLZXk3zk+vN7FroCjBuUZg/vARlTM53LZ9vOByWy3X2/iLi01FBtrZpjEEAgbCnLkZsiBKhsBIyOTIFQbvLxYFDES+gd3UNHK4PFBVTanv+6Zptu22iU2X4mw5xzFBgoicsximqesR1AECGBogGRmh6eVqw2iO2BE6JFZlUzZ9ePf+4d0HJ9/74Y9S362365ur9c1KNpt//V//0+v1enVx1W43jDaflceLg1kdui45NOdDcOSYpO9UmqgpkEMmT4y59KGqagwayrrwwbJeUA6cyJF3hmzIBqaYFAFsAL7i0GVhGStphpaDydsrog4CIFnSZz/+GT9geW2yIe81sB4R6OvYncyEnNNaNJAF0PCcdtN8jIABAJAAqgCOKfa9qi5nC1+EqJl4RwGUTHEwKMNSpGMX/uS321CKHtJrGQChqoZDp89kcXIMkpPPGd0Ce7X2fIb78Mz8pzx+8rdsr3SdAzlXVTPVZGbOk/eemQEshCCiCIzIiLQP8RjvseYk4YicH+MWNRjXxSEs+RVzxPtB+vRPGIv8UyJ6hwUY2eP3jrFXaR6OM0TDlmkiRw7b4VzJ8tIPYGOAn3FnCAACgiBjGtIyV/bYqWpoCJOuGZiCbQHZeQyhZ3+T4CLG806vhXmxqMATuBkx+sBF6YoAIVyfnhnTbDGv59VNs/r866++ev5NG/vvvvfDajavZkvHQYVtSBtm4QLLv501Wwa5XGRiAOea2F83TahKCiGqedC7hwufOGInEDfr6xcvvzn25fe+//4f/od/f3V59c//+L99/vTT+sHD+clx0rRKCWigk1U1EQMRUN1jidu71Qp3D+c81juHqqepmc2gzxUeVc0ZjTzsiiIQgIoOtFCiaiZmR7M5DAivAQlBAALWXj/vJXfYRzQjREfESK+ef46IDLukUO58OP/iGtHIyMgYeNgjk17IU13Us7pYzBblbFYXtfP0wXv/fgh85+7Bk3cefPT9d7//ww9DRc+++cqkc8E5ItAIQoEsMCTpGlAXSOfeHc5T35yubp6ensXNpnx4VBAUaA6SUSvYJ5coyZ2Dk4HEBBGZ0TljViKVUlTBjUMdURCJKEWdKK+nYW9vyMCNt19b2wAoIucQSYHEIIIwupgVAFCJvFow4VbCpue3guZy/o2MgoQqVgEDEan1Bs2r9XbTNIa+i3pFEIJ7FZuTD98tZ8eunAt55JJD4ZPN71Tf/fARdJvtpr26uby+Xp1er7pXpxHSzXqDnop6VtZFcfLuB8u7d9//9e9v1/+T9x6/ujivqvrevbspxs1mBRgPj2ZHR/OUuraLy+P69//ub7dtg4iuCqvN5ni5IHZNTBebVrvGjDBpTBqQK+8RwBEe3L1zOJ9dXl8t7h61sU0xqpkjj0yaJKkwsoJpMlWNqpmfY2P68uYVw8BKNjRuIiLi6ou/YubMEDmv6vruvCzvFM5fX1xR7hkiY8AMVSGwrmkZB9+GAREUgFjVV7OMVE45I5wNn8rF+VUgLogKZlfOqayru0Yp/Y9+8rsupdj1q5ursxfPn331xenTZ99cnrU3KwdSMM3LclYWBXso2fui6/rgPHlmIkQgAPbEzKo9WQRAZ15UDYHZjG3F0DoCkwRIhAaYFJwBQo4SCZWGbK+CaVZYH9phsvEdk6tvwffB4NiNnxhHLxGBvp7+/NtvQ4oYwMwWi7Kqqsw8defOncViYWYhhMmS7H9xygPDZJ7GWrKCiokOfMyZSFkQ0RHhSKtntwHksAfFmLb9Zvr92SojX/1k1PMAc1VVjfG1ETqaPBRIYDRIBMKQ4dvZ26FpR6b+CkAYpH5QzfZouv4W8LY37+/uRo/bPvVBfmeAydC+fzTs/pKDiyEbDeqSOX9iWWAARvCR5U5oysztg0FWAyClXaseGmiGgyEAiA1JUimq5IrEYat40ctFlCulBt06RqoqNzuYlWUibvt+1bbtetVbPFgezZbzm836k88++/qbp1T4d999/+johNgjOhGUJKqQWxMBMVe+GVFhYG0xQmRCT66u4008W69Lx4uyAFd0TVuWZcl8OJ8ljM+e3Zy+enZUhJOq/s3f+dFiPj+4e/L/+if/7OXVS02bdZLl0YPs1ea8egIxAAE4PjlUM9BMnKZiYKLOpEpbn9Lk2aWcVkWgJk7PCxGNkQEB9PzVMzOhCSSZR7PBNy/anUEdbaoBbGIDTOxc6UNZVXVdV1UVnP+H/+DvM9KU1HXOeWYC+/XvfkioRI4IiBwzIjKiLRYHROBc8J69L7xn5wIyIHtX4GJR+5LabrVpr7/45uvPvvjk4cP7IVARKIqCqmd0CKqpk6iF49It7h6KB770FxfYYvq//fN/VhfucD5fzIp5VdbBV4uqwPnVqueRxRz2/O7MDfvm+yA76PX++L++vp4G+fSqaODGuIFcTlyoQFRDxCQWk5oZMHvvQyjRla1BAs55AVCbcgSOWExBDZk8O3JMgIbtnQPXdqvVZkvOIxdXqSm0CBfPP3nxlMOZsRclI+9DrUgYo9tug0rKeC5LVhY4q4Covnc3qvSmbQaRcpWcrw5mCVI9c0R6cfkCzA4Pl3dPjp1nYkFVtdjHSKaAQszEWjr03tPcbQ6bPl5uto0KBFccLI8ikhJ7hC4JidQurB2HqrQqlGpG5ImNENWimGcWQ1QTsPxKRgKSNL5GvJNzeE8+fD8j1LquO+36tLrUayW10igPWoYsEoYMRojzegYZNIBGBkiAhqzgo7ISmhIAmiEAK6AJJG2TSOy0S440OF+Foqjpm/PnJUFZFPWj+/ffe/Lu3/073qxQi9vNy6+ffvpXf/X1J598/upU+94BBtD3To5AtYkKqTPR4P2srArnrq+v+r5zzqElBCM1FugBEkHPBABiRAxgmDEZBGYGbGg6ircp2h5RxhRcTaN4Gsy2FydnWzn5kbBn+X6lbX/k744MsFwuq6pad0pEh4eH8/m8i1Y4L+32tVhu8mjfNMBmpqYGpqaENoW/ACAqOArYj5bx1lm9ZuPbtp3sNIzwrteAWvvFYxdCKZL1n8XMRMZ+YeCdJuL4E+OPDTIDQ3Q5wtjGq829r4YwxcW/wjY9vOlZThHA5G7gnixUVBkTkYBDjm6EakPOUtzaMEOpiXZU03lTTTk7aYZICOYQhFlUjYTGQs5gq/P1EdKI6SIEA4vmZDZvwDfJrqJc9nat2Poyhjopqy8ELHVtNEoqhoDBHx4syrpYbVeffPbJl18/JcePHr/z+J33gFgNUlJTJGOHTOiIwBRzsksRsgeRe1CSqaBzZdW128ttUwbH/nDu3frlKwfaF1A4OD5crNeLq7NXLy9eUpe+8/Dd3/uD37n7+P7jj97/o3/7Zx8/e/rN87OLr75A8I6ZXSh8mBeh8AWF8MVf/CUQMjocGPY8AQKmF6dPGWN+HAMrEBEg9pKIiL3LbbXO++AcEf6Hf/BjR5C5LLz3wXnnHCP94Ac/mAzPDq9PWB4eUghFUdRlVVVVWZbee0eMiA5pX4uNiRypdhu2hMDEgMA4pBhNkhmIJBONkixJr6IJrVzOrtarV6vr/qJ58eLpzeqcHdSLMtSuKL3zJDYg/hDAGToENiuY/XzhvA9VyVVRHC5sGGu6knjet2mzEhETPVme5Nrhvq0FANFbGCjI49XMTal+vMUxVzx6DHvLEI7VB2FLKKhmxEQEluHZQMSieblBhHyXPDjfDCI+O5Rq3nd5qKtm99mGU+KvthcqHQZXz+dA7sKk6VdffvHzJoqlJikmNYVMb+5QbE6ODdRUQJIlBUNFM/QuJEtRUnam2XtX+Yoo9N2Do+OD5ZGBpJRms5kjvrw875iLwpdlSUR9F7u+BQFv/TwUkmKF/PDosI/y1el5aqxeFAfBr7ooiN45FrO+D664vzy6urix4IsQkBmjJRMyCMTQJUbmbDiRFICMhIiXc6XxuegupGvbDpHZu0U5d6MOLiFan6aMhcutz4AE2my2Y7tpbihQAlaDvk2kQ0cfAjBgxtcU5LLL6QxMtBXZiKg0eHJy0TVd29pm48HmIRyV9dz72Wx59OPf+A9+8yck6fr09NOff/xXP/vzl59/+ovn50elO1gsZ/MDT0hinaZ+s01Dg6QSGqKKiMa+E02okQHUlNERoILkJV3ByHBqIFVERdqFv9PwHJfo28QUry3pb/qav4JJGNdt3EtBT0ceKXHSa31Q+2cyDvPdbIIR0flt5zxtqgq20z0bVrm9BoT9neli4Y2pOhlgvR36OzBEZCLMzUuaFCA3QeUvvGnAbEzGy5CJNUAyGFh7B359HHUAf8m1vXXLFzA9IRtDq5ubGzPLKaCMMUNE2WMe2N/BsWHp9Wh4IELI5W2GodGciChFkD72fRLL8iPeMRKzQVIQQHagSJYJmFAQmFHBcJAHNUUBSEydK1fqbqS/inZj2LiQfB2LWVRUX6gPiiRqBp6988yLg9nlxdknn336xdOv2bsn777/8MmTajbfNq0pqQ4keUw+uwUKPSDqkHHNl5TXU42SCke+LNvt+nzTsC+8wp3loiiKULuiRIZ4dHKYpO/79PLqrN02TdPcuffgf/if//f+4A///s+//PKTTz4/+/K82bQ3lzen52eXZ+fnl6fnq00b+4/efY+8q0JVVNWsnBV1VYXCe/v+B/+pI3HOe+9cUXjv2HtgvHf/ATI6513hgy9ccM55JrPYMsG+gmnuOJ9g+pPjBQACxvNFRkMAAIz9tbllAEANJQGIYh8RABhks7kESKgoINOrojbrRlFzlENGioqKQtCcplfnZ6qpqoqYWipocbhYLGcACohqmNlYs9p88P4A2AwpibEDX1gFZhjK+dn1JRKRYwblOokZIxjSplEgQoOB4YtyLDT0f76OygbAUUTktSF91XX7bw4b2UZ7yQhBRQLOQzFPRFDM5V4AIEEyBen7JLAn6zitCyZ7Au9jZINg88UBxgLJWQiGVC6CEzXik6O5GIqCGYhleStG02Z1g8RE5MiXGJiZ/aBTq6PrPL0Wpvc8Y9cQawhF3yOocKCTO0ebm5WqdF1HhAhQliEjt0vHm7YhcgdV9fD4cLNpzjYtpra5OmNXeizAuVD4mNShHS0O0llk8hUVBqiaohgDAyCBN0QGNEIyUgAEE6PV5VZIs9PGwIiW+x2WYZ73EQ0VTUQVBEQEDAWQAVUAGU2BDbQqaoBc+t17lAY885jLd5LMcLLEry6vXL5xRDkTJIjKRVXPmGxOyAYYozTN6bY9bbrCwItWiHNfLo7uffDvPfru3/sPfN88/9mf3jx7+sXnn3789ddxu1nW1YPj4+Oj43hzmdoG0RISIRqqisUYVVE1TdxzaEBmYMoIgxzKYPUU9oVD98uxt7f9Wfzaqm6j0Xvbwv83b/lHcQD+D8fpuq7vewCKAhcXF5vNxhezrGT8VuO6F/UO/xkmAhIa0sCIQRPu2YeQ2+r2rTuOIKT9i82vOw7t8efyL06nNNVSc0jpRAwg67pSZp4DyO0R+eQsjw/bIxNBACDNZhpyxRcxPyBTAzAjA9Rd3vpX2fYvZv8mXl5eMvNsNstXOOQ0JA0KdLbrcc5YZdyPfaeMCAIiI7lshgEMEbImqKmklPq+V1W04Iic90akAyJswuFbpi0EA8ChMCBIhqgAEdx1hxcKG+EtuBi8UNFT0RmtekEE9qxIETSZYkxJk2/wi6dff/nNM3L+0ZN37z166Hy5bXpTFiNEZCocF4hsokkjEwLm7uZd8zKjuRAkdsBULeY9aJO6881aNpuDw7tR1FOQlC43Nwnx4Pik2Wy16V/cXK4+ax9cX9+99/DJe48evf/kN3/0w9AhRNOU2r6XXroUNaZkCgLouHDBF0Vdlr4oyhCAzReKKEQOGYAcMSA5IGv7BGRGDGSIDDkShRTbTaY1m7JSyaKZXW+vp2ct4yxVw35zKTbY3dgNGuOqOq9qG8lEd19E28a1kIDu/pcBWRIlJ1vFZHoFgFk561JXlwXNi5mrQkHeuZuunc/nsY+aDIEQXBQ0dLNyVsRGRJIIMXkmx0VR+s7L3M8UKap0se26ro197tVfVIeGjhGBKC/nuQGIBkQfTvuZvIpw1y84zXYAsPItS5uQnlQuwjBtPXlEzAG3iFD2ni37L4wAjCKpIdhluWkUJbPbvAF5I4AAFLvezBQspeTnZVVVitBsOwUzl2l9MBf+AWVxcggoADC5SpQX8VFAPvtb+ULQwCN1NAS7DTWx66QXMyvLOqW+66Jqcs4VRXDOOwAQpaSAiZ2e1PPmzrHKxfl61dxsnnzno1DXmy4JU9PFzXoNbXuEDFGw3xgCGpUIBAqCZAyEjBmWJUNC3nAZgiEgMKLRaIARrVv1iObQTe8AkCJBWSgqAgNmGkXNBttGRirauU1mTJFBzEQsr4021FDhzqMHJjo0rsDgnpKnq9W5mHaipELova/8HELuaOr7VdttDa4SuCimyfX9wx/+ePnhB/d+93e3N9eXL18+/+LLzz/9+E+++PMff++713CFfW/RykCOCwDGBNq1kJQRSMSzyykUNiNTnxs+AQCBURIK3rbB+3nmfdNrt7kep0RONsC/mj3YP84bDqiZZQPMfgYAr169Wq/XJ9Uitt1EBv3W45iZqqFqzpnmicBZKpWMiIAIR7IdhJ1w2X5kuL8z/ZNuc+Ttn+ru5iAi4hCEpKR5WUAY2mGz2VTVMUYEAMlAaELDTFY9pKnNhvB3yLVkdkRAHRGbv/KWH9L+jZ7uYwZBVFXlvY8x9n0vqroDIw+38m2PagSt5PADcRJShGyUM7pbVVIvqo4RwBM4YmxFMuYJYJLMQzM1IgQQAgVWJEESw57CVa835lul6L1RqeR65W3CozsPhV0HELM9Qy7LUJbhm2dfP3vxsunaR0/evffocSiqpuujWBFmAAbmMnAQAFLS2PezGsFAM32U5j8KGszKok0dM1dl6Q2a9dWm61LX/+XZ6rAIhw/vbTF9ffHCz4ujk5OA2CYtDuao/OLq/PnF5d3zV8d37qHocrFgMOZy8tFyROWc20uHDAUSQ237jYBI6qWLMWm0KApiKYopSFSL0qeoyaIkU0sF5tVJM2Ir6Y5Maqov2ShIYgBx6ivP4IXRKp2tryes1jTce1SsXGLNsSYzAXHeF0Ig9OzYu+A8e5d146GLJz5UVWFmJmk2r72j/upKwTdJkmHhAmOIxgYh+ApjBElqxmDehVBw6TEBHs5MiRUsDQx5hmSA3Aoq3MoG7U9C2FsRxtdbOacpQn3zCPn+CyWxgQPBkSMiMhq0DhERBgwRGgAQW19ATxZtisGHXnZh9kTA7BFNFURipjzxWOGMsgDtZrMBQke8bTc8nwEAs2fvGbGXXlUNU5JNrlGgz/BsdMRElFLKs852QFA0okSumAVEazdt27R1XddV1bTtZrVlH+bVTHK3SQJJ0kuaOXaGUQ1SrMr63uHhzfX69PT0T3/2l/N6dnzvofZxeXB8cLi8dhxCSCn1MaYYDaDwpfOekRRMYsoeNOamNgAgUwM2AAOzBAI4MLr3ALBwHgBADQwQsxodALIkEQKAND4xxSFuubVe5+hNQL13CU1Jc+8JZt8o1/55EnjN6VxJkihUQ9HHFES1i33suz4Vs8JVwAtwCIAYY99tG9nydXPjFYp6Pjs6efDBhw9+63d+7fKiv7r85//4H58nw077Xg99mPngPCA2tu2cGBGggs82yZQNghmZIhigGgKSEiQke5PA7bVg6bW/IqLtx8rjB3/lHPS3bNnJK0MAgPV63XWd9z62zf7p2V4KejePxnOBydMFzOnQbI9zEHx5cel4kGTeRzhPxeDXDPB+S9JrO/mn80EG2Ir3jskbDAXg/Lkx1t635GaWhknsGE0yMn1we00AVFICGFDKqKqasjPIY0rtrac1FavzkkSgIsJMOa5dr9dXV1dZyCnXh7KuTtd1qhpCqILvoxiNzeY7EsNMZAAjNGqIjMGsqqqx3LYbN6oagru6umqaTV3XdVkgWuy3qNalLXkIznv2iJhS1zV918XZbG7g6sXh1aa5+/DJtu/bru/AX2xiE0ol36lrxXpCCNWsroF8F9O2jwpWFoGDl747Pz//s7/4c+fc+x999/E7780Xy7YTBXPeATp2jEaIpAoEFpwvwlxlTQhDtwMiWIZkab9dl44DIaRU1cUsnJjEopNw3VyuV1/+/GOs3eLkYHF45ENVVgsVgiSpSQpJ+/TN2dmLs0sjWSxLYuO8lA8sdwgD9dpY5tGJexbathcRUTATIFZUNRQQQ1KQpCCWAEhREZnBAtBQxMg5C2JkZwh930POp++lKA2h6bvBP83l3rH8VjJT7qwd4zYiUsLeYyKYkr3Iu/SvIeTXKeWLoIUYD8IOwKZNgjaqK5YCXNSVCQi5pgOFYra8u27UIXNRspEiqkBuFnDIjlw2iYAADiCnNBFj6ZReL4OZ2Q6ENWYC8qLA5G8tMCP4nN7Kn4UquU9+EGhOAEOIQpkyBXlo+jJAZIIYnDJEsMxQTYCDL0fZY4hxKD8RAhCSi5HAvK4FAGooQAFVCzfLJQMDATFULRDNyIAiB0ABG9kxDUgNQCpymSfFDMzIDAmgB2iUDAkASj8v3MzMYqNontRrNAEwyl1vOV7XZnOznNepbTZXawi9K6t37t8XsdX16uuf/3xRVQcHR07l7Ozs5M69bbsxNOcSgwoYU+ccVKEg7/vGDPO1Wk5EMzgA6PuYbwmMAM983x2JmeVqPuiw9gGAgTGOIHRmZsqwv0G/POMCAExNVRMqyBZICR0RIRMhZYxr0mQ2tHbm8IidNw6zcpYAx+BYrHDgCiiNAEFN1KIlVFPnoKj46CD1RyKxSfFakkt9QFeWVXHvwX/2499uzl+9+uyLz//6L59//ll3cVU7d1SVaix9rKraOSddjxJL78vC920H3nlGYgeMCYydokjXNYvFgpk1xeBDVhpm8pFg0w3cFG3beqQwCmaLCghZBtKCmVmM0RuqDTTQk0UQkbZPVbnEEbskIn1K7J2qOuduVte1Yw4FIs5ms/Oby8xxcXp6SuM0yWtFpnWcMjqiAylV13WI6JjVEuzVdK+vr0vq1Ynz4JxTtQQJAOq6zmHnvitsZkVRTGJHOlLIpZSWs/n0BGkUJRSRm5ubzMiRi9Y5P7Tdbh3iRHeaYzzez7i+FvIDwJ6Idy5faM5f75hL9siT9+363hHekkwbJhiSKwrUiZBHiKiqqqwmO2k85WuOMSZTpFspu9d+bkq1AUAum44sDntlZjBEICIkldS1jTqG3JEVwBXeAYPDbIoEMk8W4dV6w76mBYkvN+auur6JdGOQsIzgxFjQKXngAsknQ0kSoyDyrC5CCE2zOTt9dXbxyoAOTu7cufeQOGy2vQD6UDkOKeXwljDnHBBybhGRcrJrx3ADQ6EvoJWMpeMAQIQm5CDOT4qyCtQ1kQDINdu+7XozW8wWoKo+Sh+1E43JBBT0dHWmmKZHP6UKRgVIHE5pSIH4ol6IYPZDBUyBVDUKhiJkLzdDQ9ExETkk6zODyVARJcZsFmdFCRlhBgMwCJEA7PHBYgpzbQ8aMxikXJIfrZogIJLD/J4C4EBGLqaAZioGmU4n/xUtNX3DNo72oSc242IYkUHAOSOg9Tai4LaXdnODEA3YiA3IgAGcAmUXm7IQamanAVCCm9TFtyWDbsdGu38KxLd8+m0zMW8EAqioZFlNFoZacib2ySxcABnFD6AKHuiN2Y1j/+Jr7yu4qN4g279c5hnKUpoiQE7CQIa1A4CQcsljF2K+pcPONvUwiIru8IySB8YwuaaCgmOzw2WVn3guQKiqqZnKcnlcOE7A6BOFIpp1IMuyfHBy9PzVeX9zdThfzGpsHXpJFaGYCBk4EAMytb7VvhPCWVErGkEGjJoqkKEizMeSFmBOrikqAigj5YgC0XiC+CHmpSnqwL0gnfQiY88rDQVwx8SE6Ay1FVEERAETTDw5hcMqNpT1wFKC1Km5Pjolj4hMxA7JFYCIyJvNBh0CgKK3QZkgKjiYFaoJRTBGl1KfJIrEpK/Oz46Wx/d+587DH/3mzYvnX3/66ZeffPLs+dNFmK1Sn9q4qIr5/AC1395cXVxcvPPkUdf3N5u1IYBjZBIUGXiWbqUnVdUGWOut9VZve5bT0BoyMjpEpTny3AWmv+K2AzF8y9f3zmg4YZyKLKqqg2hgURQFoafIzohIxw8T4mAd9o6SDfmEDs552Zwv3NysXruWbLzruqY9Hp7pHBwiI6oZWkYO54yU0cizkcOs3fWojrxPYyAJ+6CvXZJf81Kq39Lv9VpgPhpg8440DmIyZhZCcM5VVYWIY5vyDucmKbnSA/IYAed5TzDWR4e7ttcWhZnCYhSNQByWb0ZgBIIkMcUOCQpHBSO64DOMkdBQyciYPTpebdaezKOPvrhK+GzTG4ebqNGVyXwyiszAAb1XYgWIMYqoL4u6rNTS9dXFi+dPzy7O77zz+N7Dx4uD4y5JJmpBLvpkiI4MsuLypOiDaDmNTmBoxoaERqBk6hEqopqpclwwk4pJAqaaQqqcS1UUSaCilpIkU6wQ0bnScwEwQ5AsFB8TVMnavOQBAOJARFCWI/PLngKSgW/Fg+YgHYkImABAzVwRMu1JzicPeX9gSDk1QQMX6fjqOACqKRqIChiIKQLq5eXNpFU2qYaa2SANMkgajvMckGQgjRmELzMbFurV5c20v/ealCJAAhiILREAjBAg+JIANCmTZ+Cbmxs0WK2PGrlWiggekSzzxJlDpHbbZP7LjGvFfAYIUnsZ+fl2AxJgu91O7+w7112akpl/80ZmhAagWUclg7AQgAyYeQD45OmZU0NAvQxEOq95ADkD8drcVKSEBCON3UgokadDvl1jpTM7HEjKfurNn1YsRAzsdpN9xCUhAKqAaR4quRlZB12psfjIu4wIYCLtkUTAQlEUc+liv2raOvh7h4eXZ+fXr07rUJZELkXZrj1o2mwIlQAZAdSSSowqqp3uGrFMhn0BbE2UII/D4RkamUnscgqQiMChY0YiZ4SKQN4VRVHXdTWr67quZhV5l/n58uCXcZyiSpmHxjBgk5jmNrCU0hhB79RyBKAqKgNvCGIGCsnEABS1CA4QgSmBmWGUBEpJBatKTFGSpYybSElSEkVfXPd906fKY/Xh4QdPPnj0O38Xbq6++um/2J4+uzh9fna9WYbusK7qwztHy8PzbeMY/WzGjAmt7bpt33V9gr1SqE1IjqGjaqeqm8tM2S+328leIiKkzMwzaYPDrjSzq9fsfO5xTO4M/JiB24kL7Y3e0XDe8hX2B/a+Ac6X4L13qIxKlNHEIKqq6nzYgZ/2CsCTHIvtKVAhYlVV0xrV972IZDL8DF2a2KGn47jc6QsDgyxk22+oo+G8NUsHqHNWGAQBAzPBPFUzPcTQF6s7X0ST4Vuc6/1tsL5EI5X9QMqTra/3viiKg4OD/QcwBP6me2XBXeEf3kjZjbluciHPjGkMSUb3GWgoqK5LAw0Fe4eOAUEc+5x4IgPIjQiBvEPuAMpZdEWrvOnk2SouTg62ih37CBSNDNmcA+cQnZolMBd8KFxM3fn5q2fPv+7b7XI5/+DD76MPfQJRdKHiopRet9tmNlsMdNKYBYmAxua8bIsJjUHZwCM4s1kRSoKKuWIMZAM/DaNipILqUAxucg4wEWlc1xiJ0fHgmAjxLGP6p9Gfg+Cu2y3Qkw0WdL5a9DBoomXwAgwNDyAwcAvHmHLFF3Inwzj4h7GrBgA3NzfDDNmnjgeJ2+3Ul7nTCc4pVkS8XfVnpWCOd7NvBzL6ztE92LN2eUdQuULDNFVec5kFAPqmU1WJisCmyoCodrBYapeUdAD6ARsxm0OA5fyATB0gATjAbIkVIVGmH6d98A6A2vJwD4w1vEomcMfMs61/4yuAEuiIVkUYQ8xJjTXzX/KYohckXx3mlO900/KFZxk1uF3TSmAXq0uh3ZOa9LmDc5Bp4cbnwogK3Ckb8JvH1yTTUx0moxqaeBSwpNPv5oATwLkgpipDgBIzVkBBwUTAOadGbdO/Oj+7uL569M6To8X8ztHh1c3q8uVzNg1lRT2D2t1q5mjgugK13L8u4+8NHEii2QBHxKtumwim/uBhyTYrjoppcA6DDVAZr9o2mWzXN5eX5zHGPkURS6pixs6FEEJVV1VVVKV3hWM8qg8CYW7Py/J5ubh4s1lP7NyayV5TMpOkN2DOCA1zpo4NQRENTIlVEZkMiBnJOcbQEqkRGhiTIgm6lFJPcjg/kKbZbNtepEcX5iaLI3d8/LvfebI9ffbss8+/+fTjq2fPVjeXfis129GsRkIFjV3f962CFeV8eVS+eP5q3/piljGwnV746E2aquZ0k5riFKSNU28/LMMh7wVm9oa+ztszptM/c0Z3emcavbi37X9+chFMB3qL3eVk6vmssGQ2NuXZvkTedKiRoGVgyJpcjdKHyS+ZOCkzAGKaEbcNMLCBTP4oDvxbE9n3/mueSTkaG7Is+WBmwDkGHcZrzgaPVcO9ZiHbVWR3x9w/uZQiZGkaZhhr2maWUz3TQj8cytTGh4pD7Jv9gPEijfZuh5klF3w2YnkpyQRqAAYqZWB3uEBE54kBzcTQyLzq4I0TkaELHBT4wC96LnsuW+RXq/b5uvePDnoHUTACibEyI7ERC4CAkWMuvKGeXZx9+dXnl1evjg+PHr/33mJ5eLVtk6gvKu+KLiZLVpQ1DgjMMdcMhqgjrQkRKBswQokYEAPygXcFQkEYTJ0AmJhIsiSoREhAnMMycs459g7JCdjYKiqmmWUYUpvIMhkTmY2QGdOSSwB4jT5O0K2bPilmmu5p2A0bmI38/jpCk0AU90hzCCD/syrKYTDsFyYMZscnE92VG9o0CAAYCQDcaFrykHCGFResOxM7jYQ8cl57X9miT0Mvt02iTwgAB/OFmcUoRKSqV1dXJnp8/2SVNkoGQEYZPkMMCEBMQz6awRwYoRGgA9S2JwMYZBNoQskSuX3TOzKdgeaw6Q1zy+jeaoB3S9sUpCKSQUo9jpQm0/1R8tebJPgWA5lhVtNCM7yi+SePdPSJcliT0/4a0+QAwbBwgKEzKmwMYvaPPynVTAYG1BRSJxuFlEauBhjVLdebjKMhHfMo2TYf3ztu+oYZ19v1an39zenp2cX5oyePP/rOB3fu3Pn8yy8ur1eB4d1HD4KvpI/UKesOE2BIaGCATJRBaAY0wtEsET1yGHHIn+Ak6m62Xq9VdQIqZwMsjEVZJ0bkATOBREYEiK4ok0iU1MaUofsxSt/q868+h1v3eVD2/tGPfoQ0KF16z74oy8IxswmYoagmlWQqmpIpGvYp++ZkhEhMjplZEbUXAjCDgcQUckyH5ykSMdclK2zFUFSRmGyLYf7hR/e/8+H9v/P7V998/fznf/3y45+/evm87SFoDGiVC2FWAWjf95vLjd2SLBhxPHSr73ayLm9NKO+v/NMnJ86JaW7u/wTs2b9xrR/Sr1NadP8z+wb4td+aCM4ANcex+aZLksxMloc0EzkanIyM251+Pf9K13UAQDTRRw6e4qSKmBPOIQz2eMC43K66AoCzDLzESfSNRoalrPYzXOfendpPHSsAImgGUee3p9z1/v190/7vG+O99/NcG4pS2b/QkeYQ9vISw0qKpLcMML72o7dGwy5XmQe9AJipYiYrVfOei+CYkQENJKXc5ZfbnYGAiRwQAzBDqMoqqdsaN+ivuua8TY+KWRe105iIDJ15FgJFi2CZxlssrdbrF6fPr9cXVV3ef3T3waNHp6tNFPa+8kWVorZNCiEcHh1tV2sEyutPLryhGWRAvAEBOdQCoSIoiCuUhXfexIF6VVBBE1BDTOxN0TgBCTgFUgkmqIpOAXL1ZiwiACIQuwJhyOqogoqoiZoiBlWVZHHcMgLhZr1NuhPemm71NJ08c4kE5Ig9gFbLAhEYiAg5o1CAGOHk6AQRKNe4sxoWEoA553M9mHemk8gsV4+Htp7xlc0qH4Z06210YlVVr71pZobas05kKjD27QBA7HswtOCccwaKfaeqR2V94OcKgEiD8MsY7aXYEWTCXEVQAgE1NgizOe5F5NP4z9DCN99P8naE6NtBWLsLzIZ8sMEAYKHIk9oytWcGnakezSsYM1L7E2RCb469DQAAitqvNjZIUzINyEwixIyyG+byxNYLJrbVyQDvHb92zhCAwQyy7oaZGVIrKQKPXhqrWTa6RweHlleh7CohILIgvbg430YpiqLtRTNMrBfv/cvT58x8c3X9/Nk3V+cXs6pm8pZ0WR2A7rTfAfLKNjhk+/UURBYELHzCrDe/N37UlotDGAXm8uPwxMa0tZRAVaYysCRJCtauOkVAco6pLJY8c8yM5OG92gwnP1U1qSUz/dlf/wJQcxOqczTQ1zA9vHvMBETEzrEPznFgb4TEPpqJQlRJahL71KkalVxlPTcBFKREKIBCFiUpZQdYQDV4Xy/mVXHyV19+Uoosnb9z7+7xgwd3v/vdzVe/1bx4/vG/+dfdxdnN9bWAncxqx7RuLy+v1kUYdVluW8fXtqn08C1WGIgIM/OyGegwRV4rte5/d1pShg8McxxySfW1GWGWncB9i2O7382JMeR9Awxp+ORQCBgJmPumfS0Czjsppfy7NDKQ5Eg3hKAj1XM29vmvNCo6j6U9HGOG4bg2wPDHKYOIAHz7FsjepM0x4f5+DmgGkMa+GX7NyuZ/0hvMKXnae+81mo7kw/mkJ2s9Bf7DNUyYkKHdbjfhJWVoVb7U3EIjiKiaxoc0Njub5M4YYqBBf2tIqRllY4xTVs+AskRdr7hNujHtgtsIXffWYthKFwnREbJTdgIYVRKhMLKDm/XmxctnFzcX84PFO48fHh8ftn0Te2JfMTtJpgqhqIL3KSkiw0CYiQACYIMDz0yGDtCDFmwF45yoIC2JWITFyBKbIggZOLYWk1mPhh4oGLEZq2pMmokGCJFyZG1okMD17JOxpmGBSCmJmKq+On1uZmNSRTO0j9QeLg+DChH54IsQQgieBs2o7AN67ydqQySbzyvAxOhyVyUTMDCaajJAJSNEQyOGHC+CDP3chLCrGVPuvARFIMj03arDGIxbuz17846m0ejubUrKOtVHhh/KizLlTA+CJ1TEBi2ZFLl4mAPQnJHAwW7VhQdTyCGK9CqdifZgN4LAbkJx7+LRcoTd7K04gNinN/o8hoXjLW8qQK7v2AjcHa9X0fGYELKp6g2gFlc45q72pyfx6xx7eVJ7RzosZtPcYwRg8rkUAjA0iwIAoLZxA9jDHkFsfgwpbfOndpT9CAJWVt4pp4TZ382KIkDYbldRre9i07Vt2zZd23epNevYb7u2qqqmXS+WlXPDejeral+EeV2eHB2XZXm0XMQYcT5vyOdmz7wsTwtOCLuMzmue+pRomgYPAvRMJqr7BP3EzFz2uZ8LlUyCKZgYKuC26aJK7KRLXZs2SUUVenCvtslcFUIoy1CWZVH4IhTO8W/93X9fJDNddrFr+r5LKSXt//TP/lvvrCzLalbPZou6moWqZu8UckrIeyZnoGC9GYiwREQ2oMQYEXrACBgJyBXoHXsnhm3brrfbV9tVf9M9+P531+v11c31adveRb5X1EcffHj3ybsP33n34rPPv/rLPz//+qsX56vK+zIsH7+zePXi6/1Fe38b5tQIbB4zvbuhaZl7xszAmAgzrk5zr/6u0p/t696vvM0hHbepBgy3p/w+VvTbNkQkGjosdO/N4U/js57S1PuvQxeA2ZT5yzHJ8vBoyvnZmJpW1dz+PjFCT+uAA8ydATAQUA9XgJPNm14BYF/bCBHReGr5VZMM5zNDA7EsMZcxw687+vktglG2Mt9qRBSDugidiXR9G/ucCHJIwISq6LxnZ4SoKGZMhMiigvTavTYwUo3ZxhMRU6aOcsaCmnWMs7SqWea0GDoxIGXWMTViT+SRCiI2RUUE5AQhgu+AG/DXka4SrYmNqha3jWJvvGmjKxjJoXNGpLlD04TAm9lmszk/u2r69PjxO0/e+0hVv/rmtFo8Aa6jSuxiWdSL5Sx1/eWry8W8zs8A9kCCDqxEdSYOLABUSHPk2lGB5E1HpTozMEKHjMCuFUnoCyR03vtggKKoYui8IxQERcwaL7Hre+lPry+7BHkliDFqpp0yms/nzOydr2d1CEUIwbMriA7ZO9WciqmKcjDAtJMB2RfLBLAk2wyQMwM0wWiY4f7OozHAwEmRIc5gpKPDZwbj+MwJjAgGZLI3K1RRe41DcWfyqQERsYm71sDhZBD2xSon8GD+jxu8V2ECMAVNmvrY97U/2A9RFRTVANWaXlUktTF1KbYxdpr6pCDMNvJleu/ZhTwVfTEw5iSBadkyBO+LN2UTFYH2pBX3Xwe1mCxbM/CxI4Bpyn2Au/xw1hNhh5RlynZGHwAgO6bTXLXxLtkoPZIFKsdrJ5FtfkqjK5unkbDrAZPZbrUa0guOcl1QR8JwVVXD85dXUSQljTFGSaqaJci2TZcXZUVAYEPAAgNyVVa2EmYx7Yswr+tgIF3XFIVPKW632+AohKASt9ttuQydSWJkzLT2NN1qGUYRAGT6oLFGCPn+DDHTVFyPXQNDKm7ob/HsPFKFLvuxSOiIkckQDWk5nyWVtovbrm37rosxJXXApXIESqm/udleXeXyTjLTqqqcp1D6bJXrZYWOPdqHH7wvsW3bdrPZrNbrF69eNk2TomTY18HB0eHh4Xy+LEM5D4RKm+sVokA+j9w4AWBqCSD2Xdt3AgbIoS5DVQvBV68ui6KYH961vr/YNl3sGx9iwZDg3snDRz/4jdPPP/3iZz979tnnV6tNQZqMzHBqRAQYFNYNJBPsgBqakTEDEhCYqgEDJlMCmPQCMuDHTNQkA4cINPeDGZAiKA5idIMDvccbPI1M2ENBj7OYYKqbGmTleDLF3CxgNiEEYc+gIqIqKGimOIPBFuLOAAMTQW7ey85sLt2CESIQOhfAu0It9X1STapgJogDJAPRmL1qMsMB8knA7JnRqbUwBoL5kmyPvGowmAQjWBjzqpRRZtn1GLUcCgPIvQo5x5KLi0M/54TFUFXJQe1UzR36gkQVTLdNMjPggV8BEdVAVdh5A4qCoETAQKzGZuCDs8lvyGVzVTPzHMzMVEQzIkwJmRC0izHG2dGxID07PUNyR0cHKqny1GzXq9W273vioihLLuqCaXt55dlxVWO10GLeUbhWtzZ/leD5ZjO780Cc93P75vlPt+tmuTxc9ZuDg0M1fHn2ShSP795zRXmz3p6+OPvys6/6aD/44e88evLk4qrpo57c/d6mI1XnDLyvCSG2iZFOjo/X11eOkR0hA6MDVDUj7ar2akFal9WsKEv2WaQWVJgZBFWhM57aEqPnHuuIGAXXapeKJkoCALC92PZ9v91ut9u2bzsRATUHWLkQCAvnTopZWIQiBO89oTtcLjGziDmXzQkjOaRlURDsIypuWbO8Oy3uAEpJ9/86DQyZsoGD7R0+v9Mf24mCwzDhYWAFGCcSACD7kt8I7wAg3O5Hn7Ydu7zdCgFFxTP1vaiic16BFKg+OLxaxbpahoIsmUp0xGia+q5re+eJuLAkQL6sS7WU+jgvSzRIA89ak7CjonJFAFRkztOplwSAPlTee5ERxg2AOKBLc06JBjEvyKTBCECKnoePK6ohADojAjAxHRuHMjOlahJVK4q3pOIB4Bb2ZczvASig7HwTnFxwdY6G1qbxC9kQi8qU8Z3goABweXkpQ7fMDhMgaK2qTJ8HyrLjiOyWPoPFCACR8mMiMAf93aUjT9LFktNyFpZ1YDKwROxV5bPPPnv/g4+apsldi0XhEQB0bJVEYAIzCDyQzEyB13gSKcZeFUJwNzc3H7z//mp18/XXX6/XN/PZbLlcFoVX1ZR6lbY3W12vUVFEkqpkHwjREKvFPCat5jMXfBn4yb3HKaVVm+5znczlulpKyZLkhe/i4iKZ9u32fH3Vdl0b+z5FSXi0vMvsQwiLejFfPji+X5TOI+Jmtdqu1pevrr757HMzmdX1wcHBvK7u3T9CMiT0jB7QqzWqTtWIoloCSGBimY4UDNzdMAdgFFT2bRUaly767vO2u3/8YEV0cBDro/u/8dEP3/vyq7/41//64z/5V3i9mXn/8N7dWVVvrq9W62tE8HWZJR77trlzeDwL9c2rq5mvHGNMkR32201RF55p02xotpCUIKkjZiYzJUJi7pNKitEgZanvDFyxLP4OzoXYCwD0fW/ELvj1ep0SPH78eL1eX5xfAoD3Rdv20kfvCk1dVZaOuG83YBYcEXQK5njWR40xESEhm2nO5xGR90VgRUqEhEyqKCJVVceuy4WwpmmJsChKkSSq2a1GBDOQNPSMNF2HCERM7HOQSYQATgGBHCGgsRmoior2SV3mjQPIUQmM0fCweO1HlmM0vEs/TO5wPkBOBefpbPkODo6kDQGzDYGRjfJqkxUHAGYA0JS2g1M/CUESguVu/cxq5wyy0pdXVFIA4uxCZD6bCUwIqDQkvHIuV1ENTBA09bEzzKwX7FvQ1KF1bdM1KSmSgiCC6dbE95ZQVMUsiVnj+Bp4bXwj5I4ebJSbRuqDkzsPHj579uLdjz5wZbXtY1IJZeGL2nm/Xq/Pzi4+/fzLspw/fvfh4dG9trVtj4ZVBK+A2UUiBkZyaATIJseLGkxABFRYLdeBKsa7xwe1tQTI1ksSsIHPfdsncuxcYMdKKAi9ahS4XHXRIPUx9X3sUt/31osmqUJBwB7doj4JS1+FwvuiJKhI2cyPXM2eHTMzYFEUeTXnEdaDiAwIKe5Jdu6W4wR77TR78jKM9NaUEiK+tfaJe/Rbt2RqbicPB6cYAQ0VaArgpkDvDWnnvXMdf+nW+/j2/5eL+vzqcv1s5QgKcioJUkTTx08eomorfSZ9dQXPyplHaG9WTOR9sFAYggICsRLOqrqTlNSc41DVotp13Wazndez/XPDXX0HxtmAU+BOAJBG6CyKmQnooAjqMswEcntS1qBFpizc9uame60UexMfmRkwmWGOrccIW9sm5f3s1w+vIOvNtY7gpdtY+iFqyfMRxjIDUmbGzjk4G9LUmABZBl0AAMjMjcCATDE4qusiHcwOZgVos1xUdelOjhZXN+vtZoUIh8v58fFxjNKZxbYFypC5fYAPQt/l7BswoQ4UhGIpeFeGOqWEaIWn1fri008+efHi2e/93u9l8RBEBB18CDSb3TnJLY05OzAClXG9bdquc4UX0yjSdiszi6lHHxCU0RyaRzTHIAwAy/eeJDAxiKa9qgxKif6rr09Tor6Tm+bGTi9MRPtek/zg+98N1eydw5PgyETbtm0268vV9dPnn7EzH8qirubLRb08OJwvXVWcXlw4JmBniGLaJ42x6wWO6llClwAEMDovharUqvLp9fWFo2P2J/PF/cOjh0/eXXz40Y/+3u//4r/5/2xefPXXz08rxgfHhw/unPTt9ubmSpN4F6pKQwgKJIDRTEUMOSflshqEIiojGgmIG2duHmo01hCzELvmYpAZgCqCJ0LeSZ+NixAURZHxuQCZkGKwSnnsoynmkBwEMwHB/hzfDdG96lQOgJXNTDXTaCiO7KpmlGu93mf7Cqq2L0G4ZzFvvQ7ZzMycBDaBnV32/HAI8C1b4r3c9y5VZWNv7TSRaOxXG/+0/8kxd3073MHRgE9mfB/YjIgiaIRmbCMfiAEhoRFm33hILexpcViWLAAwUMsyv5afgA3TeSxRAwAzi0KM0kbp+z5phgOIR5UURYyQMh9viprUVLFVSdIJOqS6M+nINSq9QTmbn6+2m217/+jk3fc/+PQXn95/7wnPyut2ncQWi0U9m2/a7tn5q9Ozi1bTvQd3H7zzxDhsms4ckfOd9kZEgETACI7IgZABgxaEmqJJREmEVnpXcCh8IS42UBKiB2IkB8gGBCjJzKw1i13fdV1OfKU+dtcbAmYiZq7JL8lRUXKB83oWXJgVZVnUdVmGEBwHQqk8A6ZdH8uYkVQdJLB4v6JvoIgTFmD4RLYZo4pK/ug0BghHrNPtjd7QrRrev1X8zMyt2eS8JZVkAKqj0dor2Py72/Tjj//qxenL7XpTl8EjtdstGywXs7NX3xTeOU9qRgx+65kJAOZVzeYcIjsGgJh026ybmIxdrymKAaGLHXmHHitXmyrtecDTD+/m0X75zSDl2A4Ih0UJARnJgEk1WZIh1Yt5atu3cex4/xpdSJ5F2vUtwJBSU4VsaM2kabpc/HzNAPexywYYbkfY+0Qf0zMlhGgpV7wETDF3roAM/Q4AIAqGyJlangFSH0MZgqP5rKqrou18XRYqqdluLs9frW+uCS04V3j2xN6AoymhQzdV3TKeSzV3xxgyZdckM4efXV3Ws1IlIeJiPi98aJqmruvDg4OMfxDVnNsnIjTbts0w6gkRCYgyNHC5nPvOIXAbe7QUm21Z1mCWUZ1ECITIhACZPgXIeQQH6BAKYs0OH9DR3XtRJPUxpSR9jH3fdW3q42fPP+9j27cdmlRVdXRweHJycnz/7kGaq/R9H/sUL1aXZzcXGbH/3nvviSSNfTL1gJ4ce6cV36TGCCXbLSRiBucIfWzo2rSN/UXsr4rifj0r3ntcHFW//fjg6Z/9yV/+8Z+8ePp0e7m5n2hRlvOD+zfXlymlbRNX225eO5yVyn7bNc6RMrZJGaFB6BETETuSKJwjJ4B83YDBgN+6OMBoUybXHwa7A3VdM7PeZpuwNzbY++/0mYlYwMa+4XFevF7hfi0WtdttSLsWD4BcYHpz2ZnO+dakNptAWH/ztsvSjF7t5DXvHzF/dvxJnKop+1cCey3M+f3xzlqmNR8/PiCxJ388501euwaDTAu39wyGI9ziORvuLxMDdiJt3+X3+z55QiUwMTIEZCKnSACkZkIhgvTIZg7AJXYRXUIWc22SqKDEfdKHj5/86Z/97Gq9WS7KqGLM5v1N17w8O7u8WQnj9374o/nBYUJr+9Ycl2UFxG3beke5PMWADIamKIKqkhKZerCCqXSu9r4sAnvYWEouBHaGZAZ9FEhiKTWbVmLq+z7XbjM7pDe7U85KckVRzEemgDJUzjnPwSF5DkTEU20M2LnRgA43dUBKm0IWoMhyV7kkC+NiOtQj9+6/G0QFclv53hDRt4OM/v+zlK9FwHkVxLf96W8/zn/p7+l6db5YFE8eHi/nCxTtu2ZR1vdO7kjqi6IoimBmMcY2NrkN35QUyIjUsRm2sd32cdNsf/FHnyCzgrWxB6DDw+V773/w6OHDftMM2VbQ28INCHvszdM+88DZCQhGQAiGgogxtWYGqmBCAAAZBo3e0/7dmHYQxwahEVSSS0ibdpVxM1M4m7e0Rxiye3YIITh925MUkdc/DKAIhYAjyJ02ipostyJZNMsJuZzTzZyNBNZ3TWuRCUySSZLUg8rV+dm7jx/1ff/eO483m2ZWlxojEpfsZkXJ5CcgggxpBYxxaJNDIuYsaWcKVlUPwqy6ubpebW48U4zd5cXZyclJ33eZ99/MMko5BxOSBto4NSBkVM1q4sycvViP5EPRtm11UDZJN5J0eB6EIAisqGDUNRtDEgQDFCQdMy5VVTk0DlaVjsAD1KpJVX/37/x4u91eX19fXV01602M8XJ7edXAdz96F22A/8Sub9s2dl2M8d/80b+cz+d3T+6enJws6pqRRKTVXjg5NA/UK3SKvVIyioBHd05AUr/eXq1l0/UXpoFphvi9jz76zsP7x7/26x//8U8/+Zd//BdPv7k3qx+fHJf1QXet2zat265aLN28UoBNmypXKGpkEsQesUdUYgQwcAYuVzUNPYEDS6+Vgfa3jPoc6vciMAKoM8FFHo0Z5wijAZ5Qx1OEOQgwDKH28JkJ54sDOjqjLwck3j58MhvXbO8zSyPupXXhDazTW9aP27BwRHSw56hOlvU1Q70/V6eThj1P9o01buo7mv5/65jT+e3bcjPLVSuA7BjlGct7n78V0+TbqiZgOhQADQAkxwq5IgYAWUFwsPoABKYITddtu3aoOSmw9yC9CmhSQ0mZfQ4gASkVETVxsFCrCwmLyEGUgYqz6w0XdajLq9VmcXgwXyyvV+v64bGvS2Tfm1xcXp1eXZjzd+49evjOe6umXTWtsSur0hypAQdmFDZFMFQwFTQlFRZxZhXzLPh5CLUvCmZCFDbw8x40xdT2fWo7aXvrIiRZ36w8EDNXRXF0sJzNZnVZVcwPZ7VTJdplbXJY68gB0IB2GrxJMrCUOkCZuKIQ1AzJlNnT2M6CyASKwLrD/tiYK4XBWiACDm1suOcbGX2LSse3GGB702CPDGy3vjWkoO31VPK/403v3ztcLOZVUfRtt7re9O3mcntzffFyvV6DWkpp2zar1appNqpKzv/oN36SGxwy5jFpbNu26bpPP//cEESkjS2zf/Do/ny5WC5mVWbShClgHfNSRDBVhHc1WvCOLfM12tAaJpZkYFYiT+zZETMjZYS/SPfm8gS5tGYTOGrw6A2kl7jf0fCaHzN5O8M+Qkpxh4nee6bO8ZthMQJ4Rw5BDB2hKrKCZGIMnIjmh/Q/IzCxEKBqu9mwQ0gdm5aOt6ubn//lX5ydX56dvvS+IJU6+KIsTTCw9xyc94goYlFFwcQs9R1axvuhcTIiNRMwDEFTdAQ5URxjim13uFgwoENSAkQqisJ7n5uS/GzQnNi7L2hmXdOImffACEVRbm5WtXMbxJbA0Sg9mQsEBopQVsGADEjAZCzHmGm8uchwByPSoTMTzOzZ07X3fjGr7hy/A0yqGntJ0p9fnjFTcN6XYTYrlrpAABJ7/50nm6ub89NXP//qKwI9WCzv3r07Pzw4LC0SCGLP1CptBboEnVpqGwNS56ScRYkdIBMU3l3e3HxwuHzyk9/7nYfvHN175/M/+qOrzz7/7PnZO/fuKBWurH1VCUHTdkbYs3oGBYpGDkkxc4MQISiQIQMjgSKyIdtAPvHL2u32RxQRMecIqs9dtkVRhBByww/uDW8zM810SjAanOwz2WQ+LSMDUXMzWE4ri4gIZls7Gd38/a7r9sPxCW36GufGvm19c/qYmdPb/bX7M2TyC/bt6zRFAWBkGEREHPl0p0x1tpq0Lzw+HXB/At+2yoADSDOHXTbySzJCJqzmvXBazUBNx8G/t8qb5Iz0lK8bn591MRpS07XbTYu+BgNRIWI2bwwiqIYoBIwJKQG0CuoqKyrwdeKyBWqEW6BEfhOb5bxA4u3NTY10cv+BIZDjws3E4PpmdXWzBgqHh0fHd+9v+9j1UYnLsgbmtotEVFcFxC2bgSYCQBAG84QO+aCqKuaZc7XzHgkkaYx9l1YSW4lx28ausyjBMLArjN6/+7hwflHV83pWl1WR9dtQKzK2ZGZ53uawxgxVESxNwSkiIjGCZiLloeuFCQApN//kUDa/PSV4CXPfKtpA1KmoZDjoYtkUvcEYtwF+S6r527Zvi1zf+v6eYYLpuv7dxL75aKCff/oLIlCR1MfC+aosrU+bzabdNkVRzGazWVXWZdWnjshxUf7ik8+MBvfZFSGEkFvjfvKTnzTdtm1bQJ0tDk7uHB0dHRWOB06/nCEzGAk6dGAYA5pqsXl/2/YZoKcI+SErGoIWhUNEz0ygZhpFTZKYdl2r43SfbDDs9wHfur2KJPv+02t31UyHEwWwHJMPA4omUrxxDPC0nxPaAKRgPgRFcABqqKh5KcmjS9UEDc0QgYkdOyYoZzMAlZiYiQkKTyfHB9erm1/89V++fPHq/Ory6OjkyaMnsxDKsrg6u6ICnEEgUACNYrEXVUGTrhPTrGSsREAoZgp4c3kOREVRaN93SWPsUuyrqoIBu0tTAk81pZSY/cR0O97VfGeQAdkADQJxv208EhvMmHqynL0gIzPNYd9Ad45myEpDdxlBYp6BxZzcYGZFyOQ5m22jMbYxNpglTBwiKuPB4XFvMfWxb1tLQmCs4MCqUCwWi8P5IvVdt9muri+//vLzzc83H/7gI/DIRV342ruydkXyPgJfbjojFseudlFSF2OvqUO3QV6dXrzg1Uezw9/8B//J9z/6tZ//N//80z/96dOXzyw1AkChENX15qYsw7wuVQUog/Cz3E5G1QIjMiLnfr7M16QgtifGeXsbmpqmUJXZe1+WtN1uw2aTaTHqus6czCKya3LNdm0Y7VnHl0dbM3jGzBxTEpRkAiiIpmrJLMaENuT/EbHrumxlRSTGOHUV4tgfy8xTo9GbNnhvhOywEc52fbG3bfWgobbzuIdVQSfYMxLtou83DS3sir4Ab1j0rEoxRgYTN16ew2SaZ6yMUi4jTHMqAw/BlZrK8O4wB4QyscRAcwNmMvYIo9qA1exT7GJfhDoTDSKwqIiCGiYgMJRkEaRTTCGQq305t3LeUbEx3gI24PpeisXSQtl1HRdlElscHrnCeQ4AcrNanZ1dJLGTk7vLwzuAftu0Cq4oCmYnWbIMGRU4yyorIIAjCkQFOY84m83YVFRWfaN9Sl2fYhSR65sbRCrYLV2Yz6tFWS+rqiJ/7/gkEAdEj0TZeeklWWysEUpElOk1xqIuiwqOGgcAZKZmQqaBiXZ5C5zC17G0rkMSORvXTC6JuSFVp1fAoYMg/59sKMLnNf3bnNy3bjhE0nvbrTzVjlUx76jqW+0tfkuE/aZ1md5/8/8A8N47715dn52/OtusVq/Wzerq+uricrNaHx8cL5fLhw8fnty761yQqL32pHD37n1gN7YhcVmWVV2EEE5OjroUU+qZqSyrEAahkW7TGOTejcwTPL32Ez/29D6gJk0KkIMHxMGGGeTcjqTeNIlJ0iSmKpZE4mThh9t5u7tjnJV5QuWJzK8tDnklmJ7HWGMyAAghKALsNKcyrJlUBsFwQCNCAzQ1BiC0PCTVUAERkAhFEQkVkLL4NiIyOkZP5Byzs9gCOgJVR/jw7p1ZVdw9On724sWLFy9FLBCA9NLA9flZeXRXvZgpEGqfpO+SiiDw2O6rBgZkCmKqhsdHy9V6Wwa/XcfTi1fb7fr0+bOb68u7R4eqYqIGGlXywppUyIXMFICIYERqmLUdADivOKJkGtsmIBdIqNHtuLI5QwsVtesTACkQ5GYNQERkM44dqiAyOSY2YKeGyfDw4IQcUyiASVS7LrZ91yZZpdQrmbqU+ezAwBGAXW2aQFSw897Pjo7mhwf3VdXS9eUZRIAO0QM6YzZmceCqUPcA0aAn7ch15JKKogJXm7NXX19vsMfy6M7997/zI+eefPjuT//pf/3ii4+vnl8dxa4qZg4gqHnQPiZkMrNgkPttvCiKEoLP3e2WdbssmaglgNtqYNMg28u/gioBZHGh9XrtZrO+7wmgruuyLGmkvHjNAE//nRo79w1wmiLJN9aN6SC5nXcqZ+x3QOHe9tbVxt62wciE9fYI+K13Ybq06TP5V2VcyGwvAs4TeHf5e3O+aRoa1SH2zhgJyCCPbxjZuF67HgUgwH1USj7u7gQyvWEmKtj7FhIAMhEyZEE0ZENnKkTupl1pTL0kAyeUImKjujHzxcz5EsoFlrPeXCfWCHXIm16P7t5JgNvVerFYiAGHYn4wQ0SJurq6uTq/nh0cHR/dC9X87PKmqGeGTg37PjH5qqgBoG/bGRMZmTkEZXbs2AUf2PVM1ltsYtts+qZNsRMRSlooLsvizsHRnZOTk+Xhsp7VzgegtG1REkXRFBHQIQV26osNao8OAHL/panh6KEj5v5IRMzgNRNVwWyMX1+dixB0kKuBkUosaRaYwqF1zUCyTjkMVJEDtQWNlGoAlPH6v8KG+w8Rh3dssru3h3ueLW8LfL/NAP9q52Lw3Y8+2mzu4/cseN+sm1cvT2PX13U9K2fOuaIoybntdnu9uhGRUFQWSiSXqe8QMQRXVVVR+Ovr61C4ynsA7TarzfUojuYDAGT2R7VdhNo0DbwxjcVsNq8ApMtdTlGS9ElETXJfGagRKCM5Akeeshj9LkE12FoYakAAryUQALgYcBhTd+MUf8OoDkQ0CNdnf9eyGooOYXE+DhGNgPZcgxiNEIxYT4IcCQEqEIGZoOYomYiYyOcsn8bADrxDMpEIJvNZxQ77LnmmRVVfXF45MJQ0ny9PDpaQOmJEYDRmSwiJQAyIcucnQAY4GELWxmOEvll7wnazXl1dKkhdVXdPjpgIUBlJbAcF8ghdjEDDPAIgMshLpEPKzWOWBNU0puB8xWypHRJIxAgKmSLUqApOkdRAASRTwBogwnx2gCaIDETkGIjFIBo0Xdtv+213ue1jn6KKAWFitiqA894XdbVgJM5Oj0qoBVRQLZmIGhgCMwIfP35XJcbeui7G1baLGxEQJUHu1SIahIBl4MBVGagIN1GP7j6cHYrerD8+fXVh8N7x0Q/ef3L48OSf/Jf/96evnm2kf1idHMzm2m3jVeNDgQBg6g0LNVF1KiDqDRgJgRUzRJoMolgCfHuJampgs5SYGEfqvaZpqq5LKRFB5tYmei36HQzvNH32xz8RGREPTR/Iw4qixFkAEULwWV07O/chhCyJO0W6UxFnssevxb55+1YD/Bp59NRHa2TZN6DxZ0QkmXZ9mvCE+ZxgpLWaUtM5Hoe9UHjAH6p2XZdPfTab7bsMNtK8hTBTRVFRjflmERGMdP9g+V4MSYCUetV2BFsNrnT2Y1IfnafU9Yg4n88RIXYd+9D3fTEr5gfLTbSu64jBkW/7hBSMQRUFKCFHcolYkI/uP0m+TEWpFG5aueyShjIsDg9c0ar2fb9u2171ex99+NkXX8x05tn/2z/72ctXl+99+NHjdz9ok52fXYVqjhaSIQAFDsw+L0bIoWs2Dsw5H4qi8IEcRpU+2eZmZaIiEQ15Nvf+qC6KGcKP7j2qDJjIAxFBm2KKPSs4VW8YCLlgBzRQcw/BRKamGjRZMu2u42FcZ5fPETli80SEIiCZf2Mc+qrado3shUrZbQTCtuttUstBGB+BmYytXyNQEETNjEOx+9Rth/G18WCWBfX2a8BT7GuZ3GmMhqccIHjvdW/Ewy91KGFom3uLT0BmsW3AjB1r7FHFIcQYY+yZCmYkpINlebg4QkMCyE2Kufw5n4d6dqCqCtbGhETOuSxlbCYW+6ZvDma1gZqKaiIVB5anwKpdZwYAu52qyuJgU9JYRzaJi/W5Qp63ktRUh9otZrUmQMcY2BESMiABqADuKkEGkP3j7Ae/uYnEKXWcZ+JIsDVVf22g3M/pVHT7ou37iKu33/+BQ2RAFzhGx96AttstMqJCMkOw3LyqpkSaYvTOYW6sQosxBseg9vz6+t6duyLabFtGMk3LxTwYmllK0TAhQQhOxZJa02wTmiABITHrQNEFN1cXwRGZBkdPHj64Xl+/++Tx+ub65ODoZrWu63pe16vVCphns9m2bZH22ANNRFWToVqvyXvPCGRa+jCvakbr1teLuhoELRQUBICUGJCbtmPnPXvyLhshMRAjDkUXU9fFrm+bvuv6lCPdXgSdJ+d8UaKvqHCGwEBXq41hBIAxRaHZp9EkkNNVQ+Q3xE6L2QyRnSMfZvXSHZB34BC5a6OYJpVeZStx22/X1+ebPkbviaglOmSuFnNjuCDtmqsHP/jwP3vnf/HRj777j/8v/+inf/qnP3zyzoP58VX7qm96YyqqQttobSvbbUNXj+4/6FYbiz0xB+/UYSO9Yu89jh4n5orsuHQIADnnUkpFUSiSc+709PTOw7tm5r1v2zYplGUZY1yv1ycnJ83lGXJRFAUAqOqQLbaB1JOI+r6b12WzPl8WxXq9ppSE1NiIkIjBZcZN9N5nbAcilmUpItfX11MleDKFGZk12bv9BSfPtbFoeysMMLNbs25/Ncyoxf3D5e2tXZzftroBQN/3IhFGxNZ0Hm+uttNak3sdh7wmWgY1EFEG+mRba3ndRGPODVumaqIDmSqi5fUOAMwG8prdiqyoaiKW6QsFTMxWmy17R77oDZsEPRFV89niIBWzBlgS9mpboORKKypxoYnp8vpqvlwe3b3rmV6cvlpt1g8fP/jjP/5pH+X+/YcnJ/fqasmA6mOvUBZLNstFaSI3spe7uj7KuU1F6hS01Uza0CVQBQE0YxRkNhfTDCB99UWtmkkwHBKjZes7K0pvUCAHwoJdIOcZEbGoC7TBW8IsfoACJI4YTcCiJlFVME0ABtBBjJBUAGlApJuiWnIcFGVC4RKAKANSD70qMOY4ZsgYMqAPTGNzURZgB0EBi307YJVvG2Ab0RD7owIAmGyoQCBm8pZR/tggI3ttIoMGyHJab4x+fCMgHke8wreO3NdnSzZpuSJjRoqWdMBE5Za3LMBpAAZoaEAIqJUrxjGJBqKWpS+02a6ypRRLE/A4gW1TL2/L0EeNAJm22zLVUB7NydQMlEEVFU0xw9fRJKIBA0IOUs1HjRmKhZQ5enZoakSFW4jr6XW/cHDrdSzxmhmMd1cRc8bib1tiINtF3JPHDgCZnIAMFHQwcBkRbTK1t2WIOCOpQxBOlhjMIWXCLTBBAx6aKgdSI1VNJinFKGIgloV6kNRMDRRMDRwGNEXtGQEYHRGabK5vqu8V6zWmPkZmE01mfd+rqndshGBEAJj1QpgAgJEdsSXZdP1mtW63Tex6T8yxQ1NDUgQizvkEA51VVQKQMURJYqoawZ13lx2wqkrOJhKlohAPbUxAaMiWksWUtMmUsYUr8v20ERYw9GICAQ46GqoDrU0C+/TZc8TcA+QCUAEUgNDo3smdodvK0+GsPvQzZOoBz242KoAxWt9dds1lt3WxdWn7zvHyyMHDX//x/6CuP/0X/+rpn/35zaur47oOs8IQ0DsAcaEuKyuquigqECUDNeli33Sx1V5Qq0Wd1q1NS/wb1dP9eZ0tXwhhvV7n7vbVatX3fVnWm83m24bga+44jmna25ZuGJaIg8wMjAHuFCi+GT3+snVm/K19C5133EiANZT3JuClmYztg0OkazYCuPdOd//ob14njIJ0NjZO5Sv5NgZts6zKQwaA7MBkRGDimFbO608+GwMAZrSBgUAkR8lqxOCIydRMVFWTIJlaImMBSyp9jF3sU3LkiBmMeNN2BTnnfTJo1cSH+cFhdefBiop1gjaKECTn1Tv0ZUTiKmzPzyuDJKks69X1jfdZZ4kfP3l8cHLXOJxfr4RCD9wJCCY1TJZr5/1QfZW0HTo1k4CpapTUp75PCTl7BqogRgiIRFRaOjEtNTJRVppD0EzvXIfCIVTkCvaVdwU777g0Wl4UNbpQ+DIUdfCld4GdI3919opMURJIAhHRCKI9pCZgJAEjYkD2OKxcSWEgYRAYzPCo6pM5cIbx6ogwc4lsEDGn4QAniUFFMzS8FfLCnpncT67kp+7Q0Q5FPGTvEHMifW8c5hMgzMLt0zSYDji1wfwtt/15cjvLNGRQs5goDAySkBO5BjAwV2HGm2ERHA0DO/WDaHsvIm3XGYiqRk077DHYjXSTfjDutTdMCYnXzjCCZIFHxdxHm6Fb0PcpixWrKpBDJSPwit4B5Rs4nC/gTkgU9qu541+/3UPZqzeNdjRP6rcGu28rAezxCw4J8MFjA6QBUjZ0v6kickapwkjmk28CY9Y5yuVTysKReX0nIkcZmzDmm9UIFE05e3a5ng6KhKiKBp4tIYJq5b1z3iTOirBdrzxjTnojFkXhRUSTgGrsJMNTGAmRMw8rIV68OivLclbW3nvnabGc1WVIy0XcrAjRkIBAxrU7kZFKr9om62KKMSZRM2s4vFLeEiqomIFBlq9NagkEDIEGw6CG5oiUSvBsmdeEMIONARSBCBUVwMQks8uaWUTb1pUSewUGCwLe0CkE04tX36hEVCMG79kVzgWPFI6P7iOwJ/QMBZNn82gFys2Lr0+bzcOjk/f/4OHhwV3D8NWf/exlF5tXF0UdZotFUfpU1X2Smyh8vWpvblASO6xm1XyxKEjSdrVarchw3wDvh2bDEqKaqT9z3ng2mzVjui43/hFR0zSzb2m2gDfCxWmi4SheMhhgRERMKeoermpasib79TaL/raRfht6PO3vpC3e+v3pT/mH2cyIpgDmtet562977xFNVadOfCLy3r+Gvh4PQpmKEwBH2DPst/MOAfT4zuguDMV5VSUaKFVEoiqmlNSSaCAYZiyI5vT16Nk4EjQg4xABk0jHDsrSLeY0X1g1WzepUWyRkR2Emr3vAbs+FpUvqjrU1c3FOfMiVGE2q7765qnzha9mFKomaRsBK1/Wy8IVfVRR05RExGISEZOUUprXM0UVykknU6fmPKigQ4SByVVAMqS4lXTeNwVwlgpAtVw3A1Bqtw4sIAemipx3HJAro/nW5uCqEOqqmJfFvCxKzxWRJ2Zkz0TKkjpo+15itH6jEp2BITEix/x4xSQlMTRTUBNTEFDUnJuQLCeFiASZIxcHN8gAB1bx3YqM7ADGkHV8BbRMh0DIxAM1AkI2d0M/JTMTOSaf5wuzz/Fg7qrKadXcIj5ahF9mOfa2bwFhjf4s7uVOBotoRAMIfKhQm9kE7jbKQ3QI2tU6MclDrk+ZYbuPKtvtdoiFVePIrJRQ1rETZwQMtHs1VEfeUF97HwhzvTBfr1ia9iMoGyoaGiZVB6ZmAhBoAAyNs3Xyyt9ugH/59obLn2/mW8KPtz4OAwAbmsjzP9FEcWIiAcsFE8BcwEK0lFF/4Ih0rPjfemQ0SlDkJ5DVaVwmoDZEYURETqwmlqtcYLlcS6akjogVzIzLsigKADtcHpyeverbDkRNDNQKHzoYKM/KqoRxHVPRPg66sHfu3DEzBsqEr6p6fX293WzqUKBBAjTTCNiZdWpJoem2PUAnksRiBrUTNYBNUW6ABpbsPa3PoiqJCNmTc8ScdTkLxTKCl8w5BYZDYV8IjIbOBAGTgYDcCPHeciYIpMamnCwLprFBs1qlPsa+TSmZRNhG22wN6LOnLwKHqgx1XS/qej6ryoJLR/NH79n65rprq6K4/3f+7n//g++dffzF2dOv/uTf/NFqffXs/0fdnzXNkmVXYtjae5/j7hHxjffenDNRWZVZWShUFQAS3QJAsrs5yMSmWqReKDM9yCSjRDOZzDSYUSb9CEnUA1+ogWaiKJOJomjNJtVNkQ02mt0kGkOhqlBT1oycxzt9Qwzufs7eWw/bPb64N28mqki0hpNZUZHxeXh4eJxz9rT2Wg8fXn18b9xuupRevPNU+8wzJ3eeKpt1v77eleH64mIk3WnR6hPnDz0u1YN5kw9TvDfAp6enC6L89scAVqtVznkcx5QS/BFU/6fNw/3M3we4kbrn/fSeP3fOp/qnRbo012qf+LmfFrImP6gz0cHf0sz0wfM7w0PgRw3wgfXlxz4mHImcc5QRD4/f72v7ubv/3Mi2M/O8R0wg6jkQCRTQTTRjE5u5uisTeErM0lAHFpgWn1l1yB1kITU11aQpS0qGpMTtajWajg6kJh+fpZMzbdvLMl6NGKVxEeoW3HYqaRx1N+yG6iBarVZutbqu11elDpeXly++8iotF0WStG3Tpa35rh9N6Go7OLGING27bI/b3GQhZ7r34L67Rn4pQj8xy26qVWiSjjEzdTev4uacitu0uU8um5KbaRGzBGLyxlnUGbqoepvyQi2NQ1PHbnu9YMnsrdsvPff0AmjZE5S8jF5K3e1s1FVToUYUzOSAVYNayamNjpAgzYmkubv16w25RhonmKLVKBG3TQImjOmUuiUC0I/XAILWfK9uBDKmFElvFghnFjClIONnCFPUcAKCmOC8WCwi/mFKNLdhOIw5ufPhMvADvpcnr40nWZp9ZA03N3XTvaccS0UQqP1QGSLz4u7qbqYaPQTucL/ebWC1hNJNGcdxLNWKadDiR69hSE9VN3PvuWrZN3TdPDbSGJlg+sfZBeJMcTdsckN1v8QU7oAQlCFCGnTyjJ/HrP6c4yB4fWSXdPp5kw3uQBw9hb/7M8RLQfhiE2whFOLU2EjNJH7wfcgS3FJERJRYhBKMvCq1EBATC7ODk0gizq5VvbqNphYT9EbRlpW1lJJyZkJOvFotywcjzNrc7Kzvh23rC6uqWkTk+vJCRJqma5omNSnxxOXEjqur62Eou90uS26ahpIsjo/HUR00mg+uvflGbXAf4JtqlblCCrtGNtJpUNwtm5EEgIiknJt2svfHxyvMduLGVpHmJkXtP4QdneAOoeAIDLEc9xnWXgRDtcogc5jDPeRjqvvy1nkYfJsF6lVd3fq7D0ZgNL+6vP7o4sq1xob8/LNPHbf5mPHRbvNMu3j5xZdf/OJXvmD2m//9/+79j9//6U9/8oPvfufH3/veBz/70+98fO/H7330peeeO2mb09NzqXXTX5Vh45S6RVOut3jErOxtzU2xEnM6SkSOjo6a4+OuexPArVu32rYdx3G1XOrm6olT7pMR5iMfNDNHxVRwdxGxOunChfkP21FnApbHguPH2vn243ALeiQC3nNo4cA64gDTtf9TDJagonr8a8x9CzcHH4YOmC3oPpu3l3N69LJoHMeQiRAhwqTTMJNyzJAzNzrobsIcmhBCfzCqg7bH5kwFUADmOTecc9N0XTcqWkinBhJxIlIhFl50+eTYl8st6KIfB0voGmlapFzB1aGGCjpZLXWju6EH8Pbbb3/47lt3zk4//8rLL7z22t3r3boftepguBzqqIUafunVV4dRh2EY+u3Dzbbv7w+7fqzD4mQ5MfIckMKbWaJPJGFg1byVpQcChmkWuFdyz3lprtXBpoMrG8hty6gsLcCwxjVXa9lbeOPlgzcuFuwnTTpq00K4YU8NlMUTzKnWWlWByX2pbjstwNQMpvMVkStxNB85iwtTymhSkhQrxvZTIAjMABAfVBNjpyYFUK1MvRdGRP3UY+fslRiyN7FMUwOhWiEIs0xWmRIzgyUJbN6J93P9k+7qzaz7lNd9rtb4zA/FzA5zVzC5ewVCdBlWARvHsbpW0+pV3ab+Rth6fR3TftSqqkVrNTd4cdPg/oUWr+qqbgp1IaeJbkxdMbNqqw0AiGogqKDx1ThJE/uwEfbRPJkThawUKcEJRgATCOb2yfj0sVDjcNjPkUi48aQBgJ/4hiee3wCeaTuia9DmJzebyf7yos+q1hnyycS+bxIhoiinHvZWlKIos7/OxITkBBayiU2e4EYAMRMHHMScXBLUmDGOo5W66LooZJ2dnKRt2uy2hUp8Ste0kZ5JYC3VhrIxjVrs1cOLcRxXq+PlcrlarJbLZUppGOum1tFsUNupbqz2Tjv3gZjaxUBS4cVR1Es1Va8OTrkhjqzhosk5Z2Emt9Ash3lgG93U3QnmrDNYkve/SCjvEiZm9X3yI6vzMOpcCAjsfWy1u90wVY8lM4kRqeto+sxrr7i7jxWj2li0mJbqru8+vCLXlr1jaurdxZ++/dTxybNnRx3Vk0W+9V/5i//Mb/3mX7q4uP/WO/d/+qf9hx994+/87vZ6d+/+xarNR8fLs8XRetj16+vDxsJD27avN4V7tveGQ3JDRJrEjx7/5HFg0W9y2nurNH/QNGPNrGmSlorZ9ExG8KB+Sp8Yn7ZGHrOzMZLq4xZ7b4DDLz38YAdJurkXN3fkSZ8a59HZhzr44R8957x+YkMpfamGuKkTAJvgYGcyixVicGNiEDERO4dZoDkCMDOHNimLiKu6e4oEL1RVKU8I3pwa5oakKdUdvKsjNc1ydSzHx9p2PWinNhq4aaVdcG62qrthNBawtN2iXXQGvbq60nH34XvvNzk/9dRTZ08//f7dj+73uivmqeP2WFbHp90xL5bf+P73DczMbcptk5rlUXd0pOzXw6Z6NTOhaRtgJ2YSiZzRxGwf2VWGTA6WB7QE5lURFAJEEHYYGdyYQQ5l682JTWDZ0QIde0e+AOl2t6h15TgyOVt2J4vueLHomrS9vDYdxzIOtcSUcXeD78Yhpnz8Uu6ucDZdZmGfiNNJIBLYTNaxuBvUzCaCfZ6oK+2xGTLPjYMCDDA5mhAYmUWjWo0ZQmCASylhdEVSSs3EQkc5iYHTnj0OBy7aExfGp439te3zfjS1fo7ugLlbdS2q6qrmdRh21UqtZdSxmho02AQDHuIRHIMcMGEQVYaaV0dVL0RKpEYKsJDfZFYjSzRXa+OHf+QpGRI8OinnojVHuxiEDGCZIGJQuE7xZXSFPVJCMn9SksDZgc8gCJzfPl2nE9zrE6koP83AT5qGcyLQAb/RuNoHuGaEoIOOHcDMGc6EqYcXiPpYZNpyzkHQX8eChctE1jaV5s0hhlKqq2Jq4nCSgDhBXaXJARitdXToycnR6mjxs5/99POf/3zTNNt+F0vAig4+rBaLWmu/3W373W7T9zMR7Msvf8Hdb99+quu6YRjM7d333rvejfnkqZ1jqLYx2xpGoiFJkaScCskIFPfKhEaIJDk93a3YnMyZOYWuoikcVkpwtrAbAQIBzJkGjJqiFZ8Qv7EBQEM831/GlGIgcT91IkeQDymlSl6ZlWRUq6DiZEYGUUOt3BPuXjw08dakQ+64bRapXSYiOrr97MXV1Vh2nnin4/uXFz+6e2/x4O7nnj5dbbFaX591zZ1uceeXv/zSq1866oe/8Bu/9cHr3//xN7754Vtv3L/YssCslmLNgSXjA+YNohu2ExyYDFX94J13SimLxeLu3bubzeb27acuHz5YfsqcPYSYzLMrWHj3ldbQ86OwzNgXnubjox+haZr9SQ69/MewTYfznz5BygEgmLBs39V3iIGc2GrsRgvF4ImaeRe4gUo+usfx/tHCUDgxS/QbssHNZnf1hrtjXo5Ua40ma5/ArntNjHjubh5MMgKAwAJiVzWBq0ayyqlisVgmZqRsZiIp3led4Zl8MYBHgvHCqR2hleh6LKvVsj2+xUdHO8rX6r0nkyY1i9w0ztn6cdiN3jR5tepy8+DqarVaDdveuaHV8edffeXoePXmx/c+Hmo6Oe3OzykvlURdLnab/vLi/M651ugir+46jONWq3qVjgXG7EzIDAmyGHerhdypWiThmFmcJgAcxEPHdwIEswN1rAwzIoYzsZELkYG9ZQ3xU6uiJlozrPVyeny8G7cPh152u0XfnwztybI/zfmMCUV341BrVQ/ZeXOCcfDtMDGHJDsBbFp0K27kkGCmhLgrg7hJMIdUVcCcKAWoshR9bF7GkxnNbrMz7uRupOTsVMhhU7E5CDF53O2IOXGSnLI2klPSTJxq7UnarmmIc6LkRALSSHNPGrq819OFG6CHcooHxmOP7iVHMRSHA1WtN6grqo5axlKKaykWBlhLGUYdxlrVDTAjSOqIZtwZJxImYZB4cQR+kDx4S9zYnXV2WPZL4pNbwM19I65QELOHLCsTOfvEARe4RfPqPvV2u0846k/uDp/cMmg6GMBnpZR9quTGVU1x8Cd1i6H2ST1jIODD852fZbWmaJjgmDhQDi9yf8zk4oeDQq4hu8PESVjEyYqOkpzNI6J2NncTVyPXcWfqZgrAhMXESYjJXSkJwYUYsJxztzw6Pz//5je/2bbtnaefcTUWd62by6uxlv/sRz/iJG1uTo6Obp+cvfjsM+dnZ8vl0o2GUptuWU2vd7vcNlh0q+NbHw3YEvdEO0JhqZIspZrSppTipYKMRXJu2q7ruo5TW4xrJYppYoyKajA9bpvwAsngZoCFejoyqoAcEMdUTicAWZic58RT3EETNxp6cgOLGpS4MhlyJSxyHs1Ho1GDnsiFyIlLysqWwDCYealaIihN0h3fasSrlWpldX7btVId/vTBRz70td8ls1td99zx0bO5O3V87Stf+9pXv/a1v/rX3vze977+D/7zH37v25vry2UjpOJoggaKYgmSJ4aGTaTgnNdgL3H2UoZ333q7juOiae5+9P5mffG5X3rx3bcuuvNTDtUtMIKfALO6M1MAR3ye/LEyeJ8uIHKa1IvDCYySqDtUa2hpLpfLw7UYCGV3E0mIBo1HH/2G6mw6Mj48iRCIfDKVCjI3A1nXdGOpWqskcqOxVDfKOQ+7rRMR8R4UE99HVQEmScFxUdUBNiSHiiSWHHWcmEcOY0nu7Ba462APH6v5rVtn+w0ovp8ggWCjw0RAzIKQrwAR1d3moWMUkaZJEBuHQRxd6lrXsh2SQVJTi43myJ10Z3evsdthV1e7fLId82ioILCfvfRLnmnNPOx4Axqkq3lJ0p0en+6GfjuO7H56tLImV5K+lqZd7KpjcaJmd754/KHW9x+UIZ/S6WpHvDPoME4gKkDYUTYCZIBo1l4VApJ7CR4sgsM05gs5oo0k/NigTyaHO6sWImHmFDl1igoxQaaiO4BAiEfwGqQmgBCx5uSwCh293WjNvJQmJ7PkdndrvBmOytU/9vJzorvrzdbIzs7PKdG235qblqgLh04YETFDIuxuGu6atm3bRhJTaGwqEZErwrKGBDHY3UUyHRKzuMdOWqJvmCVCbA0Uvhm7AcaAk7BPtWMjCIsR1FEUY4WNUe/itjkm4mtnTtKkNuXc5o5TcjVJTds0wjmUoafk4UGq32wvZeuUZLfbtV03jGO1+ua7P2tTrtQ7K6I3dU8Rw4RkAOpY+3HsdXA4hJiFSXRyHDGhGcz3nbjwkI7d/wsCuad9DvfG5LhTmjGMUyZ/im2m9Eh0ZE1FU7AHsXf8UeAGV3YXgiSGgw5JfMJ7/oQJpjBye12rR8c+rTWZ89kcEkgwlccJUSDHrFQKwjRpCGD+LID1OI5TF0AIIE6sTr6/nbHp7bfAlFJum10dj85P3n33PTT+wYcf3D45HdDLvjMqoNCMxLxYplCAmFFNg6pVuDFvylYNPbZOBMdmt/7ia685+O333v3+91+vtQpxm5vT4+Pl2clv/1N/mZq0TGkhuXNKBq5mm61WzdxU7EaWvFpdjXU9Dpd9fXvjQ+pIhCSl3ERPCBGdHi+JJLToJRbZaOL91O1BHuljJqcEISaOlEp1KIWaPTML1OqsBukMYkw6UMNuLWAGJWKe4SZEGHXHDOaUSABXQ3FVhXvOjqaiOCoYJNSIJVkWr8YAQ8lBGsBMomEoVqsxSWbOLQk0u+ti+czJzKWnfS1v1uGtseTS/+53v//C8dFLp6ef++3f/mf/ub/6Wx988B/8O//27/yf/y9fSu1x6c5Xndl1HXdd5szU7zaaJGWWNrl46tJ7H797fn76yqufe/DgwdnpqWG7bGh3cf3hO2988fOfu3PrdNf3mTACGazViKh1a1iKemrTth8lyTjWbrGy4UpVjayUkkmnOrBBiFeLrpbiWqwaM5qmW3Yrd1ItFw/ui1DObc6SUsMSHPuu6ofh6564JkkObhVMioQU4W6aeP6iIXL/HCh1MDMWSimZGQrUio2VJfOUy/H54APE9w0xAjQ8XLBDYt24F/cwMZFh3ycT5tUbATPATjc+8gxJC4pEc/M96757k7J6ORBsMXdyq7WyqwbDTTWMQAVX4gd5MciZ8ZHRMvEyUcOJnb2v10bVGINj5KZIZ2lF0hTnahhKKRYBjaDhzM3dy+vCZEjOotR4apHFmAdm42i48wiiIlMkFpy6TG4TuzJAbiCbIzC7oWinaAmb8Hg3Kn+kLhpl0thAo/dbKcoYEQrggBoAam4gwMMbrsRGzDAYj+5CSVSTWwLY3IW//877zy+lPT7LDXOb+2E7DCPzBAecdvlZoVldiW6iRo6eENgEVZp7RaZMGIFdAkg3MVP6VM4OLLdRxHKRW3VngqlPig8CUnMmNnMGmbqDTKfn8yN4KJfwRCRUqUiTShpzI5LbZgFDURcoQQIfwKT9uIFPRW11i1xx3MbNZiN97vu+ql5vLujkRBrSSdjU3Sfx2shbKZsnUMNCNwh/9WhXJSKKeC4WjcE8QO/7yimCRyy6qWe85T63dLOyENGcz4BvJwWioZ2iYjtzLIAdtA8vKbqYaXLX7WYKTVHuYR5qfsEBx6dRe2K6yP3iJUy8JvNdQeQJDzyJfdhxWBHYQ6BBmJtWp/B3apGk6SKnXAKwf5yCmEi2caiIcHBvOrmSOonBHsW6M2AiAf8OEDQzuTASvIAZVghmJuDq7mpO+MpXvrzbDWUYk0hmaUjapuHl4v3dpQvJngzUldzI4O7VdDf4hrA2vyp1rXYJGbpVSYuJuuGA11AmLKDliVC7EgnBObxYOIPITeBMzu5WnGHsxmzkEAr1CuuabFBXi2iL3ImM3Vt2co3VRQZoeHIWxGtEBVA3MlAT2r21ZqAaVVCQtJEnNSH3MSowjOqmnpW5gurEFh8cbK4ViqrVc1oSCdgpkbXBuFfESnfn6Q9Lef/iwe+/9fYz3eKLzz//j/93/qW/9t/8b/8b/7N/5cP79y76i2fPV7fPT3zclH6Xu7ZW2w1l2w8JOFsunn322eWyXV9ePbjaPLzebnfj5vpqu6vri/tl7FerxW63s5DmFOHUCHNmKc4pJU6NqDNNlm5f/YzJIUF874jFwzBmFnEAZlV1Uls6Pz898I9VdSqiMbOZq46HdWUiMptrh0Bs28E09Wnc17i+vo5qyr4TMSwcy5O5Oh9dnAcdxz4tVBysQ8xyhJgj8fmN7lZBCLXX+ftNXwwTmmTmJnSQU8NdVQ8CGnOGZ3cfLWYjnBjOo8hAXpg3xA9Ojq/ltFJrtCRaEDfCINJaG1cUGxSkmT2xJSbQx5cXRERt17atpzy4X++GzbjeVrXAHTmTEEuKyq2pKTw8CXaOi59XiGPuLJr5tQ91lINQamIecCF2oXBGbm6buTMOCvBKAEgc6nChsAoH5TwOzP4Tf6aQZiNiM6pkQjQyvXF5VWR53rQnlImzeXZlUs/OUSQLII8TjE1ckwMe3t8Mm4eAjcwBCcjVzJoULskNyGEf/iIS2oGymX5zcwCSzJWmnjQ6wE6TT/KH/MgjUDUMJANgraJZSmFOC9OUmlQaiT6oSb7V+90lTUIV09C5Er3ZbCSnzWZT3S636+54xU0exmH2HKCz4XG4GkCScsuSYzLWWqk6EU3N9XOojbAuAUyd9Yf0ZgmEGstU092vmMMDgLlxKP6ZFtxsonx+99RJcBPCGlDNZFIvnFJjU3h6uH7nJ5/4y+OD6BEbPF8/YG6ECePucCayqRA7RXgEmWLrw9k59ZCFcdWbDc79AJ968OkHBQP36Paeqr8zVmtiFfjESIEPYDZmU7gkM1MG1AEjdRANCoKRq5npiEToFl3Xto0kV3M1H/tTbhycwcmD0YOKozIGpK3huuql1utqa9cetGPOyyVCA1Qk8wRVICIdy5R0hU0/LizBGEowcQLA5AKIO8NghdwTojoEQoBFtO4GkM2N6LQPeVc8QWpohslFh/9u2B20erMbm1MGVUMDUlDoFxkErtUFQplgjgqpDnOvQAEBnBwjmRLMKtxNa1VSK04GJjCDnRjkIgQ1b1bL0+URnd7R9fqdq91mtOeI/pV/9X/z+t/9nT/6e//JT9998+2Huw6lJeratu2WRuVoldpFl5HF6Pr+xZs/efP2Cy/du7o2cEqJUa836/V6fXxyNu1FzJwyA8JwlsPWpHChI+/MzBO28QkznEKFMAxqNOkAiLh0r5CIA9iyR293rdG8xDNPFh3QR09qYz+PAe77fq+D+MRLfOKgKc80L6lPrJxAn8H3s20as6cAB2MiqAMmxjqft57phOQgJNZUtBrUWQgAeVVXjzxl9iQqrMKVac1y3a0+RrcdbKg9XFNqWuFM3mVW1WoOBjMkCQmUqCewNJIzp6YSbWq57ofrYVyenCoxKBsILFHVhnlyY504hCIHO5UWMGOR9riIOcYwmsoP+5B3/+14SjNP9wYAyIJ5J25aGG2P6h8cU6Q1zYOARRJBASGL9EpMOZ+oHDGT4KPCB27k9OwD14/vXZy0zedu3zqmNqWjrMVqEbgJmag7jM0g4En6YKpxkjATmYfzDjhmZm+d0i7ieTIQkRBkcp0CwyliCtvrQm5T5XeSpIy+8GmdiJNjL5A1P5KDc7Q/UZCOKSqbAzpsKoskziQpAkUGsZCNuwm7d2CD46fqdWwTDbCqdadl0Dq4boY+oGX7g6fZngQACaecAIgqM4+kOrtPNlv3eB7ch2ambjp/9N5xok80Gh7a10devwkCb16LahDmanp8osITyImMXBCGcP7tZmeCD84VbOt2QLp+OPZ7zeGL0QHt878TMDcc55ic0/PZvhLtT7+PfTE72u7Yi2qZQ56whxw6Jcg5h8SLu4dYzWfsV/s/iQjPWGohdjaGMRkpAQZFjbagQYWIRVChWrxqLaWqH5/ddiKeiu2m7sUxAj2wdjy0elltA4zS1pyQ2rxYhiIKB9XNFP66ETF5BGI0p8cYlqGR7WWQwBku7kIKGHshN5iyOWDiINgxA6QUEHGIkDGIySa2AAgzhIQF7OKMUfLM1CZRJFLzauj70YgNqFQVpF7VbHBGbguLhuklKY5KSE6pldGQnItbJVcDAwQqgDlUzc0qPIDW4rUhGtfDjuk0r9qT9nq3W2+Gh+O2u332zG//1l/95VeGex/K1YN6cf/tH/z4T3/0Q/N0ua0555Y7Ve2oOV7mcbDNZrder/PiaLVabSuYOdQJmZlYIEk4Q8wBNZSqhkq11lqJHF6TaJqyNY/MimluT7Xo6cWAX8Vvt16v90syrGw832OqJ1f7oPvoUD2JiCYaiim1tffqMXndtRiAoS8xsxeLRdd1KeX6KYLqs3Wc0sWYTS/P5QbsFzY9ZnMfPY9VxOKnvf4sAMbstu/7HBwgEhSFJiumBM5JEgWFsqulnE2yS7ackETJBpF1Wjyo6aqOYylJ5DilvGgky25zERcn4ZsyB+F/d3ZrW/x66PvNVSF3SWjb1eKYcwNic7CTBYGXA6Yp0n37bCPACEchbo3duJsUG4vBp/RTVHUnMqEZWEEzzhPzpunuHr6cs80BZTT5wVnnnL07GZEblMFE6gyGQYMzwpzIJQoC6h4phpG8ptNr3emuXq4Hlu3TTXtkqZXG+zVIGXAykLqTUcVEL81uFHEwAGaC6+xtI9A0U/6VMBcgyKFOZF4NBJgRYxKqc41KhBNARR+B0O+nzqftra3MvIgAuU6gLdMybFmyMIMkNI55ohKrmHldfKZXi1Fcc2LuGio0wq6H3YP11dV2E/RqjxngZdtFU0RENcQGEpDuSoVjCqwxZblt/iyPIPhG1O8Rq3Zobx4zdTevz6sKQLBh0tSCFDTcbgyN38ygZJnIwTbVuaIi5UwTCvrwQziagg7zKQfjJkp+NLnlk5D5zctT/pj2SfV4PmG7yf3G9B4897kQoB41p0nXQQ7974M5ENHCbreLF2utYYDp4FL3twxzmp32PCRT1iFkJRJRtH1XBhV4dVssWyCq9shElDNS0morSWqoboNqNe3Ndk4981Wta6crp7XIwNnbjtsu5VZyy+DI61P4ReoKjyQ2R/JrvsPimlHFld0CXSFwcROYm5KOpArX5CRCQTG/aoQJAmEGkTA8kPVNaqP4RezsUw7C2RQpdmR3uFoppahXOB+1SqzwYjqqbcd+1MLm0pwOYINUkuqcKRV4IU3UJCZxH0Ah6adMSXjktoCLowTXZ9CbGbddd3l5ebFbn+b2vG1Wy5PFsYD0x5sHz56sVkupLcvx6tZzL7zw6pd/85/8r73+J9+5+IM//OC996/XfdfKnfOj27dOz2/fubfZGrjWOhQDuMld27YiwjmF2ANYTBmw0dCXyqQyqfk53CAQkaZpaNg+bn3p8Tm2n3UR4+6j2301Zx/XRty8D44jIN7LDu0BlUSfKr84hdi11nEcYzY3TaOqn9o4+ejYR8BMjzRlxmczw9WYefY79nlIc3VyM7DTxOJgEQ2HYSMhsptuNg+UawY5QVmanKSijmMNsoqUMiRTSpKE3BypTYvWu05IoEmaNqdGUgapIVErTZtSQ9Iacq1e2C5L2TkX5yKixJDEkpByiXIheN42PC4/sZMZTxbCMMHqIklqkzAfEGkiBMf8bJXZ968jhNsIIBw0bnr0XmBfOyQQSOEUgZZGM880gVgJLlOvrhAqaVTDosQRLpJDmGGuZFyF7w/9cnmcz9rddvfRzvrN5rZIOj6C5OQgKJzcndyCXtbMlERBBncjl4ino9AbJBJTBiDYAJ3F3QPsF8zI5nAEgXP0UFYNSgAnAMM4OgsfpC7jeQo23cdRtTZQcXcO1yQSoc46hWM1UTIC6nQG5kAC2UxkMacaaJKgSK5VoE4Fdj3uHqyvt+PWoKZTnAkYOwPmYEmUzFvyjJbJjdjFUXmiTgXMvZrdmF5MMfFsfaGTnOOTWe6eOB6JT2ly2z3mhDmB1EzJqpm4VefqkKggIzAhjiC+D9QCaJ930slcku+lBQ8fzeO5RcGFAIuCwvQbKXz/ePBbwJlCSUNAc4weXwTwR1JDQdsU2YIgGY+/yWNFrvlehRorADMbx7Hrus++dY/dWyISUGICiBlTvyKPjYoaaR0AePWq6iktuk4kJ5aGqJCrelXrVdfmG2Dr9HAsW05bSiU1lltqOnRLTg2ByeKWKixoXhywTMJTnsw4GuIdgtpYySjsYEAwGeDkgBX2IowENImypCZJw9TBEyilRoQSZxFiCPHkjJsBVk3dXKPBzpgUPnGIm+XwCHnCnphQdR6Ldu47VSEdbEgs6lwhCh5h2a1wHh1wmBGcnKUCimjoUacIUqKuGPmqtFPj1WpxfJKZ+6r9OEgpl1TORDZlvC357PbTm6G+9+57p+YvHJ/9xX/6vz6gy9/5bpfp6VsnRwsRlF3dPfvqa7fu3bu8uP7pm29uNlsA0SCUokeVYpeSmNdKLLOQTIA9IrObc67Dk+ZGxDbziIPjryE8TJPv4o+lo2Nmzg3r0f1R9jM2TjLtMJ8xNaPZPGZ2ZKH31/TZ4yBYwWx/ZzkjRGoegJgF9vqmhuTu8AArzb7z1HbipkZEwqCZisvdySFt5zIm8gKSJqcmxW6iVRsl8WwuyRMoi2kecTLgaeVjyjU3wpnVsF6Xoo2ja5o2tSR5dN4NNqptUe+NRbtV0y5TTgIetfal1DJQEoIAKiAimbDrDHJn2MSBHME7OWag2r7KOyOfIbXOICujKd4Fgtd+Nr3xrsmQsUTY5PDg+w89lxIqvTPjpiNyd+ZMSrDYCgEL+g5HiSsERxRAlAxkLKN3SZbI2Vq5LqX2u7GMmja3ck7ueW4LY0MDENQVylBDdSgCbjHBWxDCasQA1BXERnFYEOtYNVdTU5hXB5vVYq5aNMi9wQ6Mag4NB4dnavJwYz75CBhqASx6ombDzArPnOEsqAqHTub8saa9QwMca4aHIUxjAY2OrZZeozWbKKwCIxb6rlRSbwTVtGkgYYrgRlCwxU/gbqAp/2wRB091hSn9FHXiuf/18JLmHNKciN6nATz6/SJpGRXU4PMDu8eNq27JrZoxvDLZxA/qALPHdwk+skA3ziHqHKjuo9jHHs3m9l33/Su2x3pjilzt4JtExBs03jfGL/JuNCVL4rkfCDWHmxLFS5/9y8dscJjeWmtgmsdxbNs2EoBPrAETbnJymPqYoVM+gJmFwYlg3Cjrfhs18whl2uVCJGv1yBSM5IP72vTasAbW0A2nPreWWqRO0oJyS5TI2c0ZioBHwQkuBAISlABxk6lM6wwk08bHZKMQsSMqvgku7ossDeeGqRWJ/mCGiaGlRFq1H0sZNkMZhl0ZqtXxzTfe9hCUrEXVVYsr1G1xfBSzvU15sVgcHx8fHR01i26sJTU5t620ecncCC27ZgF/6GOCKLG6FHADr8DgyGH4nQZnM1eSChIytQmPY4CBjAjMSjyU0jVpIAxl5FFbkaPlEWcMur0c1gyT3MjpHd/WOuiuXR0tj177C79954WXj1p56fnby0Tb63vDuGlWi89fXb/91rsf3nvw4f01k2eWsZQ5VUYASFI0V6TqnLKI1FrdwwNxhe4xiY/lZmNaRyCKucq7N7d6wBHtcxk4guBDSxzvCiHhfeFmPz7VAI/j2DRNqCbknLuuC7GBz5KPOZzfc2V/n3+ev97N/zPzLBd6oBHhGt2ZE2ozdgJjm/uynQ7y8gTOwpJBRgbOiSU7FzWYsrvAmDyRJdEsxk1hebA5ElkJc9dwkxXY7ca+DOIiOSdaGqdSbTMO18WuUOT4XKUZmbxataKBKEoCkn2Rm8mZiD2YASpNEE7Q5O/ZFP6G0Q1HcEZEwwv5bJIBQnSuOTPTnpWUsKdTnpnWg0Q+Mg3ugFh1AmZmYIUj9L3BlUxBlTy51+Dp2DfGkCO4/z2S/Hy0OnfQpi9cKLcrYuk3l9vNlp6+1Tk68xaenZJrciPi0VQ9lGdJiRRB/xxkkFPe3aaLIXNUoLqboaoV9aphgNU85rkVe8QAa1RkD6gr9xpNexrL/SNDyzjwI/Imk4ktaVr9HpvBvDaeGCS5e26bXguPPQARUQayUM61DkYy53OmLI87jyGWa6W4VSMRJmKDk+RYyBoAWbhhioOdMLfPumKiZXL6RA730WWFg+zrPgd+mJdyJ4eR3xjPcL8MXgmjgTFxIkeDb9Q/JaoHU7Zp4sfApDr1SJ05HtXs5pXJ55v4LzG3wM3Pb/7Ruaa0L/3SnGpGTGzfJ7Gnz/JpAmD6rp+GKFR190C+BPN25AmfePD+Ts537JGKcsQeAk/MYScNmmQhIgqv1YgltY0TFFocA7hXrMk3RFfka6feeWxb5I7zIqUO3IKyO3lVt2JwIWI4AUIQmMDZTNwSnNxSxGtA8rHVMaOygckTkCIF7X77aNEwL3JqhQlmtVo1r/X64uG4HS4fPPzoo4/ef//9Dz744N69e9v15oc//CF85paILdbnX5iATCcnJ88888yLL7744vPPnZ6fPf/Si23XHZ2eHJ2sFqtl0zRdxpJ5WF8muDoprIILMMITVBnZWIAMriQVkTcCiwzQxrw36wFxGp0JnNqUckbwtjRJmnYkftBvGx1vtYu1at1c32qWt158hS+v3v3o/mDjMy+8nE/Od5f3N8Sjlyrcnhyvjo665VEttlotCGhyylmG3UjwfTQCDtEdyRX7Kk+khUfXkrSU8klD+FgEDCDofeI/Ly8vYxZFdJpzzjlHDiZOvn9L2NC2bSPyPrTizJyYU5D1MIu79X0/DIOZjWNNqVmtlsH15Q4z5NyEP+kTjkCi1k0kbjqjCpi5ISIDAVDXfdydJAg93F1rrI34D41lUzEhs4p7KOc4wNEGm9sFEalbHTUl5LZlEtXS6+CEAUVhiWlXx1Lr8fHp9XhthZWJjEzZlLtu8ezJ+Xl6+p276+Z09fD6al3HynR6+6kHH1299EuvjC7XxbejbkE76XYJJnnjqKrR+OMUvSvxEyqicgMkgNwFBChIiUFuERdTMGPAAWeab170WbiLW2KdcIxT1XRCTZPVMGUSBm120Eop4ddZRBQOAIa6TCm6Is08ULWmasQpN4VQ3IpqdRNiJXJ4k9jAThxaOhONH2SBXNXb7tjabmfjgCwnR6UOP7x6eJblTitnLCtFUiSQCFkSJd4MY1/GzLsup0XTtk3WsWCmdlF41HeV8eDyyiYyy+D4VXWAvJaAK5G7OVHYBSOEcNvM+kLAnrmZPvkvA0jZHu85wbTFh42gOR3hjJA6f9L2bGPNTdcPpWmasR/N6eLy+tlaq0cdQIjciX3qdTMGw13NBq3bvkRq2gicROmGrGaa8kR1Vh2ZL29yKA8txD7Oe2RTeOKT+Hrh7cR3ZgvZBbhXUx98HArDW2FhpJQST0xhkR0MOeA9QGHODFjcK5qRJvtAwVXn5bunk3cEvuwxEznVXObaLW7+n6P+AUzc5uEewR3Yc+pOUcn8CeZ2WELb3wRm7rru+vr6qaee6rru/PzcfaLanpGemGOcg9j3wEsjQMDsBjDvtVAJRIwgxSUnMLIY0VCLggrLw924VrsehouxXKnviPrcVm6a1XGlxriBJ1YiuIBBPJpDlEFCnpwINmeVLcEzuZCzmddiVVmHjovYCPMstGy6o+XieNF1OW8uLzrIwlnMx13/8MG9ex/fvXp49YPv/Ojtt9798Y9+9MF776EAABIALJbLRHzIEBflAyUykFUtfX3zZ2//7MdvmFa4f+3Xf+3s/PzZF559+oXn7jz91K0752e3bnUnR8+fnnvOu368d3lxvR1zu1guT6zJl9ueTNg5OY9qxQtxRmoux60It6CGqIFvzalgAKe2tVGd0LAIk7saLOfEstjVseW0Ojof1psPry/aSie3nt4Y3Vfmdrltri8vHxy1dOv4KHeyXa+73Ny6deuF55778MOP7979yLS0iXajHR0tlnMZohoM3jStqo/jKCK14vz8vO4ug7V+HMdFY33fK/niaEHwcbSUchmHMKLh1QXKLybb0dFR4P5UNedca12v18zcNE1IgACIqNc9NBFQStntdgAiuJ1+nP1Spzk/zszn5+dt2y4Wi73UcFzHGLWQT0QPh2nnn2cc7i+H7xUCwBY1RptKm5GSplgEE6KdwmUey8itUMOJcl4uXY3QZCTyo0Y6SQvj7KAKVmutNkM/HLeLlNtd2nYnJ5fjIJmfe/mlnWME76hdg68ZW0IvVCBVAZY52Nx/X4uQVwB2lYDURkjBTuyABSqXQezG5EJObogiXzTkAcmscROPzhBiZgYFmiqzRHZYIj6dQzrLB21gztHIYfOG5Q7lyQw7kRJ2KNlJYYVQKRroyZj7qlF5NSKLhnoHg7x6BRloBFeRgZmQ+mR90eJFR63MDiSkbKbuNXtEuhPnWVVHKaY6FsxqR0bwqcvQ1aEEBysMUZkCBTQsuJyUHM4GDXdFZ6HfxzuOnvSoYPAnJKv9YMN9ZAoCcxNqjMN8tBIIk3pM8O9M3oDHl+VgtAl6CYrZ6Zh7BxnBbEXBxTPlJGYnItRnD6/uCeOJoflnD/e44VFG5mhnJOY9CG6u4UPNJvqsSJrA/RCIcMB9JQbAmPmQlm9vbm9C8P13+ZSrfuLOsH8pigrs0Pl5ZHaYaBLsnVvX6NFxeP7Hxt4hmHJORDS18U2YjYOq9oR/07kYBDhTvNGnChCUkJzJQeo+KPpad14fVrsGNsA18Va8cFO5qZJBySBiwVKEcNONLPC2QkY+hbPslk1bYa5KdWRVmCaQMBpCa3a0aI6Wq+PVqknJSx2HXb/enC8XWurm4eW9ux+/+ZOfffe73339e995/90Pt5sayt5dd7Q8X4buXFiO6nDzoioz4s2Id/0InnTMErdNmvag17//IycwI3Xt+Z3bL3/h5S9+6bWnX3jm+ZeePz47XZ2cPn9yPizr9VAvri8vt3dXt25nQitUmYrRoFZ1LF6PvI7GSpzJxUkIiamFqxYlNmK4xb7HxGQEZ0Mq6iOTUEvN0quIUV/MSJLzSI1LTmxbIJudLBc/+t73fvazN955662mSYs2wy2n1PdjSE8e0lREst0P5szh2jl8rqaqhjp38RNFQTYMKjNvt9txHN09GCLCNw0re0h1efgpRBQlXcyG2czSYYo4TGwcfXx8vOc0V73Jkk+J70/J3e0/z3+O/YOIcGD4A/UqIpjx2OFjTzclYLbEHMqAJO4wp10Z26YFiUtSYiOpxCxLy6ppBVkpcgEVl5FypUWPrG1ThIY2L85Pru/d/ej6YpQuLbqe8tbSNfFaeMPeiwPcjpQ0MP37q/Wp8Q6hPhQsds4gkJK40dSpyjByMIzNMke/oZLWqS2YKJMuhBKQSJhZEglNwKAsQTxiE8bOb27s4T0M5DOAYYjOjcBjT20VSnw99IWoGoyoAkqIRGiCVZA6Vbgzq5Mzu5GYG/EAGFNhNkpGVpIXVh1Ny2iQJDkLCwRWixtFSBiVv1LHaokxyco5E7u5O0wd7l4j4jIY0WSAnXQC5cKjZkxscAZPTE9PakV9IufqHNw8itulqePziZPw8G4+RjkRzTNRqQPf1CQ9Grc4GBEiUcUUisDOCNwHAGYns7lo44SJK8Xmcz72Ox5c0Ccj3U8ds3sRgaJNTo+pR74+uO84oAfJUdWco0HdGZG2IYDUpvD30XsXEKHIWk+P9IgUSizQ4GeZ/vfEmis/0TWPsJ9ufFuaS92BnJntLSTS2nTD5bvv/Ti8S48bYUyk5fDDGrMbZm032tPwPlIqjpvJs3MHMiZxZkhmpqq+HYf1WC7VPq6+JRoUA3gQUU5ILacMcApPzZDgYibuzspi5saRZ3YT12zGbo071UplICsZ6HKzaPNC8tOn57rbqiqGvuGlsAhop3r3vQ/efvOtb3/zW9/59rfeeePNq8stFCB0i1PMXaOl0jCWQNEuFgt3VwuOkrhj5OTE2ZkIhImSkKBEROdnT4219H3fr3cfXL3zwYf3fvD6T1cn3V/4jV9//sXnvvDal55/8cVbJ6eLrKRWt31bBiFN3DhMKRXm3mywUZgKeYU2zhncECVCIeq1KkmFgQkam54JKFGmCoUXo8SSmkU12RXP5ESeuFhOyVpL5kwOY/bN9SWj/vqvfaXpFp9/6YVhczUWJWnghQPzN5VZYrU84r1Ns2Ru843/9LnKC6YmT6JB8cq+E6lOvUwUxtHMolC7h98fnHDKY8frwblLe9GdmMeRw6GZeYOIAku2/9O0oasG/PrAjZjQFY85pH/mmA8mzGgxZoYH9m7yTwFY7N8ULdxCnEDCIhBRqAIpNUk6BVWgmFRjpUZktbahw6ppbtHiJKeOmkW7WFhe+YAH2+vu1uo8l3TWnRwdZ/e7V/1lSb3LjtOGZMPYCPWi4mhJhCKEsAPr61FIi6pMQqSSyGAEV+jUPgRjN3Fn1YaJLVDJ3jAlFhFqOS/EBROiPREzQ5gp+DqjoZ5MpmIz6EDuat6qJlKtrpnY1+1AINZAYj7CzTCaV/ViFKRgTKmCCtUKMofOPciZuEKJ4ezK5EwDUuxCFTQYb1QfGjGTUmoYqjthcucoIKqD1QazZiqUTqDcuUBIasAeMg13oyjxOkcEDoKoe/BdR7r3559UAPjTgP2OT9aMYwLOrW6YMUzT7b0RfSJizBL20c9M+w5ZBtwQLOqPs4IAbPCAgM7Y9APg2ByBPXKZn0g4/xk2OGI4kE6x2vQhCvMpm+LVLRGTh9Q8zM1rtYAN70sqdmM4D9r/oORBBkQznOSxlf5zRupPdpg8CETjbkR9IS4/rord3YhApBGgE6UD67uPdOkgh/fY5dnMlxWuEqZ8dhQC4FFyRpRz4CHECUR9IhJt7HAWJeYklpJDipbBaV3sspQLox2zulRml0yp5dSJNACRgaf0sjNZij1kQqqZuCVzQc3uyRSlT7Ds3gktcu7avMxtl+mIuQeGWsWhtl1vNu+98+6H73/0H/2t//DiwcOPP/zw4v5DDKCWj49WuevIF9WsFitl0OrELtw0y5YgTqoWGAMKyktiz5L3yX13tarVHcAwDLltFovVYnVctPZlvPj44cWH4+b+w2eeeertP337y7/y1Ze/+Mrt5555/uz06Vvn7318vxLGoqMBnEWaTqQHrlUTrELEjYPonngkJrcCyyBVIiLoJCgukZlRHdkyMZpWTAavqUtVq7umZtmwdjw2DTLVRsrnfumlX/7Sa888+9xQVB3ri4dX292dp56DKcEYPruLQCzdT7pps9btYzWgSPzsbd++qdfMApV8uApmcLXLhKfgQ745n5FZYcJvzsMszIGxjq4miKSDD45TMDNU9VA66XCizxvLIyAR/wQ85JG1NzkgE1CbOThe2XW/R83fLbxUTsyJODmzRzcnASSL7ig37agwI/AC1IAbX5y9/NKLkKPKy01Nl6M9GG2z8Z6wvP3c22s/lePL/uE7P/jZ3av7J7eeeu/jB+e3PzdSO1oeQdVJoUYsbgIXRN2IaMJNKLkJObtH9jhRrDREwwlPTDQm7mLGpsktGZJ7Q2iFW0ltzk2SLM4ojGhbcnYlgM0Ai1stoKgQ39yxOmcHg4ODBIABIjm28mgumX5g8rTMxaHqQ9Wh1L5abyhmnqWQj47iNHqQV4EAFWOQs1vgvIgJUERzAXubd8PwoOow6CbLcWIuuiAwZ4rcCyZ2I53QyiCiWULSPfhHJ+CHT4Q9AYPHxFZuBJ5R8QEveeIUoifFWeQUklCfMmj+6OnRJhv/hEPDMJhGzQOJEgByZvC0kd/AoEATOesjI0LT6r7nPWOQukd/7f7xiZ/+80fAvje6NAH1oo00dg2x6BT3CiOQuIVeARhmrkGzBwAwu+lQj1R5QAU5ZGRn6/tEG4x5cjJAs+V+/NZ/Wmp6Ejfd75ETBJyZ3SyInPQA7/z45nmQ33vs7rm7uVe3SKlN+ZGpUgLGIZbe9+hun4ioYhY7UQhc8Fi1govX3uxqLJd9vRrtqtqO84BEkiFJpOXUImWmXKuxg2GRG2ME242zlUiJwZXNGlgOtg2rnWDVNEdt6pK0wsmVqj18+PHxcnV6eqqlvvPOe9/6xjf/6Pf/6Kc//dMP3nwLJDnlo+WZHAvAOpbrq2HcXCG3TdOllKWZf8lArDgsJv/EBp2IfBx7AGEamUhksivb7XawoY41ujiYiXMr1F3cvdg8vLr3wb23f/bWa7/y5a/82tde/eUv3X7umaePVpV5O+rlejeUkmDCbcOpKCj0O53UrWGK9QKQQBRQJ3gwjBIAdg2HSc0HchepDbHTydGJbzdWSsqLjm1BeUllSTheNC+/9OJisei65eX6ehgLW00wLz1ZEXJhqAGh5hCSSo9Onr0bd2jTaM4H16H3mXzjkNplu93ui7D7+HhPx0Gz1dyfMXLJgdLfW2sOLdUIpaclFMwsIsMw+NxQHIbd3Wt1IiHC4an3C+ATa2BCYj554U2YI+DGO2Z4JHQNIDeBhAdPRMSSJ+uLyOuwE8CJkagmLVqdJDcuC+dFkeOv//Btas68Ox/yaov2mlIvuaTFcHd8sG1ONvzOvat37z2opK+9cHr+wtmwY7PsngjM0IYYKE1g62+aI0BwiXQ4TKCJDnoDyOGoNEV84hAP4CIJOLs3oJZ5IalL0ohkEiEtdQRViqRQcA8FjsanriQAE0tB3KO9MTZMSj9AIiIPelN+NJWHppEKV/WSaUi8qz6oD06VaHTembOB4YXMAQ/FVA+QmCnBnBOoEg/VhASEQXQsujHfaD2Fn6oxeUoK5oYAjjZtVg/uI4JPIqM+Zf6mWbufLjH799KTfIgBjiX5CyRWeD56b0QOUqoT58zB4581JjO2X1PmApoQ2fNs59nXPLzOmd+Yprg32Kbg+z8dPh56DJ+MgPGZZjgQvEbTs/3BZhHs2IxkDoQzOU3sPObOZsytloI6AAEAAElEQVQclBOxS9FBAVgBkLFpoMofM8CHSKj9wlfgzyaqPRjss7bEZB5prjmRREzMHNzc6aDwvB+POQGH92o6eGq2tqC9dHNnkony3i3oBXyihYumNSfE0oqNOhRCjXm7Ww9UB4xrw8OiV4Oux7IzQtdAGnBKQRHNmZCDpBuAEJFb5HcdxnAxDQgIWW3cM3lH3jhWq0UndJRlkSSDXAcfq2k5Xx2x4/4HH/3gBz/4/d/7gz/++jffe+c97PTk6VtWXdVVSSsA80pm0q1OwCSUbIKglfi1RbLTnG4noj2xIBwwcuEpxxZJHn76zlNF6ziOfRkDU0CJiXDr+PZ2fX3/g7uXFxf3P7738YcffvD+uy++/LlXf+VXjtrloskJfr3rDYXUq0nDXVRkDJSdTFkJzmSUmag6l4mudN7gfCoWFVVyJ2ZJyRTNyWmtBtqK5AW1K/cVaEmeSWXRArZdX7Pq+fExSZNSUi1kyoCQOwV3rjs78ZMj4P009gkrbgCLiDRNGNd9CBuhcFRz92HxvlVJVfdIt73b6O5hgOdeXOzD5UQHgfah6Y5XYpntcVgz/cdNJYaIbEpBP3kl/Jkj/M1pSTtDokLFkSrniUKUOAmYo1I44YKFWUmUuCYrMIh4a9btNDnJ8s6LOz5ea/5wo29fPnjncn1vN1xXGXW5OjsZf3L9/v2fvvLlXzq/vXA5vnVy9uHb91hTtkTkyWR0reZM3qglp2jMnSj23ARguABCzlAJMYOJsosBBClUIs7uiVXcFiIt0LG0RA0oVYMpuMBHUI31OplhGCYwGsgR8+fmds03jcIIT7JdsBp3cmqSRoBayOGcCRmUhTPlLvtoUsDXxTOIq7MpGwXHhbIbqoHYkZwahNng6s4WaORkAuu4eh3gVfuOsDSMrgSBceII7abAgqZN33yOMWiScI7vsi/dzdbrgFXYpmbiJ1vKQ463R8f8OwCfeO/jb2FEgny+txGn+nxJ7jRLsTJoJhQhQPY1GKO5K2z+Lje0EoDRhFyK74NDSPNBwfmRXpn5YvbO603q9EmDHD7ni2/ixDlVPvPbuc39vSEDpTMplc0IYdjNXTs4ubu58U0BeCoDT0/m7QvzJuaf3nf7JE0HB0CP29EwDo/VgB/rAN7fosPnmO3uDR1gPM4/zXwF86FPSEHHnLyJqmmKNngoded6VXBV7UppaxggLomkEW5FEnFiauARcO0T7tHxV5Wn8nlCQBtUCJm4ZW8JDejWyXGGtq7JlGuFjl6qWa29//SnP/39f/CHf/iHf/TGT9+oW0Xi7mS1ue6Fc85t7hp2qdV2ZailXywWVcc69golSNNITi1nurpch1A08dR/7A43bbIE8WUIBESTCsD3Pl4TkUhKIk3OhkhRV05t5tbFtdq9jz7ebNbvvvv2+dO3/urwzz/74gtPPfvcUZMYbTUfq/Wl5kWqyGbBYk0MTpScpOFUpiqMBK4NgJOpl8yRgtXBlCCZWVJanZ3t+gHr68Z05XZsdIyyYq/9RRInIsrctKlpsxsloVoVrtF6GN5mzCI6QBvMRtcBpJREQCBTK6VU0+qiqs0cfIatDSx0rfX27duTQA/RJEaOSBJrlHsfq97u09FhTLEn4phmsHN0n/oEuyed5i4S2JHMVTWVIqnbH5MIEpuVG/ZyaY9ksA5mM6YpzrHhTKYjKHIRGrgEOHMTIQe7q4NiKrOAE7NoMMPKJApL8GZxBEoZxSjl5sg9W8E4jNeD1kQ1L9ucbx0trWlOVHdoazq//cLz3/nhH2ulX/mVr+VW3n777Y9p08oqWK3IXVBb9QxneKCUb2rAU0ZahYyJyFUAobh3xuQJJkG+QhB4Is9wgR8lzoQmOg3cUdVqqVaoCdDxdINoJtsjYvKgzJlYe2OLUas0g9eYQZO6OoUnFs0x88RiItJSmJkkCackosQtSEHkdTBO7Mk9Qyu4OlX3mdJhcnYEVEL/ITVjDZFJzk02aK1lvRs33LSoDgm+fFdtCIDLFP7CmSrEaApG8rzfHu6ewDRNJPDlwZREQXjxpDahTx/uPhNlz/nFyCgwx+kfOZowA4Hp0bdMoJ1Z0YsmPjO/sTizw4C9BXjkxA4PXI/NOdk94N9u3P3P+haPPvnMMQneUtSifL4cd3DY7wCLscHBySYAVaB2ZpDotFE9dnsmyg6ao1Wxyd6CiOFuFC0C8/HsBCUj58duNdETDDMBExN5ELxNOivMQEx9NkQjYVjKcItiP3VXouTR9Yyb2xVcbzpxmbq6C010XVPtPrb9R4x+XCojQOtwAgmEJmKZpCIDpbXZldpDtbVy4cY5I2WSxEmYeO9muU8C3qElStNGZUQubg2Q3MhdoJm8I3RCLdmqcVancbRxdFUyTexJ8h/853/49a9/4/d+7/cffHi/XS1uPXdWil5drYWzGe22Y0+aOItIk9umaVQLAErUcENE7t4P27oJZNCUxaCIx03dTVWjXTDUOSlxAkXwR0QGYmYnVlWtVa3c39zPwotFl7s81nL18PLy4cO33kh3bj31K1/7atc0p7fvHGceXaGjmC2oGhG7wRyeHE4ubEDoqzipB2OAe2icu4EJ4EIVkUdkFtbjJXMnNaFT70ha5MY5CXaba2QWkXEcx37w9SCSWbKpTc1txI/90kQEvpkA0WEiQsxOCrNKhapWIzXN/XhDg9U0TYSmofkReOQg0opIdW+n90m+/bQMcvL96+4e6ehU1SU1LGTg0GGqZmUsqW2iJ3c0r4PVQuud7Ho+bVuHmwui9EkEYpJIGgH73mfoHsVqs3xerFkOY29mZiUoETghlqIlc6UZGMJO4VNUtWQp+kMzC4G8KqAk6eEwUJMebjant54lpN319nR1++HV7nZ73NtWzY4o/dW//JsqeXC8+eDyqc+d/jt/70//5Hf/xr/8P/kf6TC+997HTddSbnaluDBLZXJ2E7LEEPdc+zS56REGRUuuJBaYkjuohl+ZEjVufnl5Z7U8Wq0EZFoY3DAloof37qYmNYvlsmuFufR1M/bb3brj5R61O6UBWIgopSbgZ+7q+5Qa4Ll1mroIfNqMgk5MOYmIpJzCuwqym6ZpYG5avRYiEuacMji1mSqLQnqnftTNULf9sC5G3JTcQNJIVIy21VxV3bMkEjF4dVVVV4exSff+5mrsmnPqjklgdQkwNLmRVmYmTqW6uVVKSDkJ6ThO+92jgY/b/iYEfm1vFcTpCQaJ+AmGmfyJYB+eT4VHpDMBAjKJ0UQneZi4HoayWi0cUs3BVNRGNU88jJUxCZvwXkgOZOMEj+D9t5o97RsfNBLOUVz9lAi+umJeok884BPDMdWSpzS4KwAITQwuHJVsDitte7ET3BRub2pPh68DYBIYJu1yi2RMNLUjiws5kYiCmYWZCMamHmLmxLxvqyMhUi3BOYpJEnjqrtVZf3L6xNk58TmV7q4ONaCYunuikBWIXPrkazggnMI5L1q5ae5fX926dUuHAWDsOUMIDicyB2odRKSRtL/X5E5so42LNjfIqUIUbnzdl/v95sNdvXA8VNp4LrlB6oRbZ0IisPo0v0KuQWaUarR2GKkREZsnt7aMHcy0kpejRXvnfLVsEtfxaEkXHz+4uHd31XTP3rldC771jW/+8R/8yb/3f/+b5AnOTXfqyhcPe4CEuyRNOPix5aqHjrunJvkErAlXAA4WzgSCmlcj5gDgNimltt0NOyNxRKXIiEiZow86nDhVi0KJJBI0nDPICqzuBgDLdAyYm/3tf+dvfuePvvVbf+m3/9I//Zc/9+rLgBkXXvFHuw+zdG1qF7nZquXKg6EmFqsFzCSFSB2VoG4EU6JxHB2JuKVGDOyOTPrmj3/4teefptrh3mXj3nWLZ56600LH/g5PBDA2JdpiHrlv+3G7GY64I6SUBES7cSRzIxYhJ1vvtifLxW5zD8JjvxuFjhtx8DDsCM7cDNvdcjkxYWAOmsdxjLau/Q6w79Ajoq7rAESrcVjc+Ou9e/eYuW3b1WoVfB3RPZzGcSSK+JKcErlaeM7hpTiDxJwciZM0nagVpxqGIkwF4bNjFDsMgoHoluFwVCfPMxpFiIwoUZ59bExeEVTIQu1u/z3juQHUtqnt2qPT1LSqXouVUoS4DL1wXq1WF9vd1//u337+pZfA6QuvvPKDd69/9z/6d/+n/8P/3vXmcgu6fXb+wcVFm7MJOSlA5BaKcAkkUGFnNyJiMkH4SSC4RHgecuyMJMyMBfzk7LiD07BzaANOKXmt41junB9bKf1uvVtfCIgFIunk+HgYR0q5y400OfiNyby6bS7X1c2rFlMrtZh6VYXmNkX9IDeSc845pZSYUUrRasOwMzMiD78sceDxUpPAzAgCtbFXR246gRkJQxKZiKdMSRnqrKZUHWxOjcMkkWOACwETXMuIhGDGiVcn97bXxYbFnVs50XB9gWGb2oarQjA1ywYbJUKO7M8YU7g45Xvnlp6biPGTTx6fbb8YbBqYU+JPfrTpZxanYhHTuvPUs/GE8vRjaKNf9GL+S44bJHP831wY3le+7QAsGUdFAjxooefsBG7WF0VtFFMoESlahwaHJRl4snBMBCeTSfeInZObEQWb1Bx6Pj4iR7AnZjOapEfY6bD0EopV8cSnDrW5M4z4MP0QXHVOqORRIOBPsEYDkBnGF8ntaDpw98Rg8qjAQbNC+1E3ahuSDdEGtGU2zszJKYHI2SIfMCd8IsQSAticYeRK7kJOsGS1LWPD1ua0WhyfrLpFx6Rjrf37b77fCt85O2XQ3bt333rzza//wde/863X4QmRjDv4kQH0/Ug0dSfOwJ0E9mHY2STpuc9PAkBDSeEETyAm4pwWbdsuFqrqNGFm90V2OxD5fmxEUM8TTp5DWs1gJ6dnu/X229/4pmr5zf43v/Tl1466rLvdnePluta+qNWhQWfI7mQjGmlAkdmOnzqkW10oOjLEIAxRYoMCbqUfthfduF401BGkIc9SjahdTb8zQG40MQRiu9150POBIifGLEkaEjZiyQxjWFHVoe83m/V2u11J0iRZpG3bajpWLVp8sdhXNybYVEpt20aX0HRPzKIraW4RmszTlLNUVdVgJt+3EUc8LSIJsAkcftPb5+ahnYRYDpE6a9u2aXIZL3AQkBERP7KpHv5uc37908eh0z3FyMSHr/NM3LX/VocGOCpz7Lxol8JpLK6g4uRtm9Py6PTOe3fvb0cbNP393/u6gX6V2v/D3/xbebE4uXV+de9B2+T37t979sWX7l0+DJYPIRciAUfzAAEkU69J5NDEndnFPcHFVcgykFkSexZqiFckqKPWSkRNbnKWMvpQd+v1CDVXE6aQ4U6ciSgvu6J1c725vL66fHjx4OLh9eXVbujffvOtECYoWutYilarqm5nZ2ck0jRN27Zd13WLNuecEv/Gb/yGJGqaJv5TlXRUds3izJqYgolMJKWmJaLdUOBEIkmALKFalZyHnQJeoFBTiJNEwd9qJUwIKkYUNhK5GbsS9VWvt7vFslnkxmpdDyXDGidOaiyYiHzdP7Vw++c5nvgZn7KffOpwoshk8iSiF23Kj0/nm4j804q0P28g+w9r+Cdok/HoF5ls7U0G4sZCE8DwiJ9pSmlH8Inqzg4OkBSD3CKijUXJZADUiJlAExxsD/meyK55yplPSV/MSGj/BOxuAsjrVNCNnZUeyYL4lAiaTrXfNIGpyot5DkTE7xzwdsyGxwGQecpJQNUBg6oOqpfjeF1rbzYQF2fd48DZCXyjlelT0WdqeAOIjUzJPZsRKpO37qtELcnxojs7XS2ylLHfXa/HfnN178GzTz19tFx9/OFH3/zjb339D/7wx6//6OOPHjJWvu9G3hf8gOPV0sysVlU1LeZevQdMsvD8800GmADgeLEYx1FrNTNTM6AAzL5bX4KI0l4pTyhIgGdLPN//mBwWuMgZwL+XjgGRjMP49pvvPLi4uNpc1Vpf++UvLhcryak4hn50VRZpc45Kr5ExqYDiMcrQQmQgIuwLtZEJUXip9erqyne7oyQNk1A0bRqlFLW/uDMcmQyi7Xa3L77iBvcUreQQEYebainjdru9vr4+PToSKX3f93Ug8tw2y+WSJI1lEpaOym7YXRHZbDZhjA/7Ah5DJu7dmn3RdxzHOA8wqTClruvcySCz9SUi4ZANnXh/pupJTpmZ3BKx71Pe7h44jvmzHzfAn2GBDy3rzRlmJ+Bwa3ui9Y3g24uNGIQXRJJa6U475FUjy48vrhm8Qz556pmnnn3u6KkXjk6Of+cPv/7N777+P/hf/i9e/+lPj+/cyYuu3K9Vx6ZJIbMoIHZL8ASkievZJBw0IiEkJ3Ek0uzekGeyhtGyZebMJOy1jMKeczarqsWsjsMwjuOw69ssi3bZ5uSqFxfXD+8/WK/X7733wWa9e3Dv3gcffXT/7t37Dx/uNpuhFInG3MDj2aQMN/3LgDCSRPwrQsz8R7/3x8fHx08//fQLL7zw3HPPPPXUUycnx7ltTaGq6k6kSSjnlBoE9J2FiFWcwEwkQp4gvVE26qvuZhZ9gIW8AsxcJvW4+deh3G93J6fnMg7v3X9Qtvm1Z5/punZz9yMHOVxMaQoOjL0ELPjnTq7+wmPfvfpffux92EPn7zAT/g/vWzxxfNrHfZpjcViF2tvgR974KSSXhz4xACdnkJLDXSYTaQIydcDZLU1EVbHfkFCiaN+BhcSHT/aYPNrtHApKQXdAT/4G+wo6+ZxdN6fQH5lDtceudv9VGDOgbJb9gDsffN/Du7C303sHJXN2c6teqo1F11UvRr2qugN2TIUIJCHXELaWIT4Xv6cNgx2BH3QjaHZLXjNRAlrYnaNVQ3XRpgWh7rbXDx/s1tcwfeHOswJ+5433vvn1P/77f+c/ff31H5ZtldxAHsmhzJkhK8MO5iAXpi6lmXMYm36zXwXMN/mkzdUDVWWQRJspc5eoTbRspLqZFTjBhFhB4sQEOObsx/52TTUax5S3mGvpxFdX6+XxcpGPri+u/+D3/mi73fa7/+pX/tFfrVYTsMzs7gXGbpxAWXRQJVaqGeIwITIPwG1g0H0uGNwg7zbbrey2ZZEHYJkTXBkz9encRjGBNEJpVNg5dIfgUEpERObmDtcZpjdPh+VymX3rZWeqIpRS07YLTjKM633/7qTtwWxm2+12zwK9j4wx45z3XUZRP2bm8/Pz4CcPc74Xckgpy14TfMJ0xcZsI0K0bDJ7DCJmzjmDPHy96S0gzBJLv5ABxoFBvfG7Z4f0MLH+aeEFO9hYR8ur3LSLpjlapMXWk+XVKy9+wdPy+IUvVvAHH9775X/kq3/8xz/8X/9r/7t/8X/+P16eny+G3fUwWNVXvvjqt7//vZdf+cKu76duIkzdSEE/4aRMKkTJKRG3xNmR3TNpA+/YM6OBN7BscPjGlDPDfBzHzbYPe0Xmp6enWsrl5fXFg4d3P/zo3Xffff/d9y4uLl7/7usBcPBo8BVOKTWpaXJwPM44osh2Oplx7FvuDoWpqhtg3/zPvgGRpuvOzs6effbpl1566fnnnz89P33ltVfaRXNyvFqtljmLu263Q62laRr1GtIrIonIWIidz1rplbehFF2VQeIolhbkIztDAAUndxSoE3nTUtMVtXVV3uidvs+rZT49t811CADwjAGYbfaT24qeOE3sz0yh/EMbj1ncvT+LT9iz/w9b4l9o7O3K4ZMnHrlvkHjsLdG9jQk+ahH4Oczh7GFEA8UShShHCroJCvaOqf8YHj11Bgg5ARpYCn8M3s17/4mcZ+6SG8TDHOY6wO7EHiA4MYJaBe0dI44D3BG0ZT71nk7nBkBENlGwhZWK+BXkUkspoxa1TbWLsV5UvXZsSUZiZTaSlDI4qCqRSBhw8B7uHtXI5BDShJLhLVtH1LG0oLOFNCAht91m3Kxtt2tBTbv43Auf+/Y3/+R3/uP/5A//wR++88Y7ZdCUmyYvq5LvY9+ohzgIvsgNXFULzFCKlolKdL1eRydG1PGCWZId/agCLBbtyfHRqluklLqmbRfdatluy263G4ZhqGpmVV3dIKkx4skGx1yiCVg3dfo7LNjfAMAICYqUc5O6/uH1d77x3TYtNrvtF3/9K+3pye2jo2bQq74OOjhxEspMRgTKoQvu7k6oRBJ9USB3Czlzdzd4apuy3ux2m21NKGNeLPhpJfP9jz7tlu4gMgRdk0xQMjW4c7QMifvEwasAcs7LVXd2fLK+/lBaW3VdXjScyEn6cRjWNdSF94Zzb49OTk4ed1UPnLl4HtZ3n52OI+M88YqZpVqrqavBzN1mWzuThU7Wl4NoXlVHEQLJnuwwfpr9RTzBAH/KONzC9iaWmSnAAHMjQSRGnviWuIAuN73KarlEu+DFasxHdVu8ae9dbynzdtw2ixM5Oh+A//3/6f/2V/65v/abf+Wf/N47b61OTy4e3B/rcGrnd26f16FvyBgWvHENucDFIJMb65kos2dGBhqggSezhryBNYQMl1o5Cie1VOdaa7/ZlKEKc5uysKwv1x99+OFPf/SzH/3oR++8+fb9+/e3m42VmqXJ3HTdYp/NiO81jiPCf59HrMGj7jg2ITOL+xTHL06WIaf94KOHDz+++OkPftY0nTTya3/xH3nq2duvfP4Lr7z6ueeefma5aplTkqJW2NzNSBVwnmfRsbQdUevSwpNTct9aBdCy8BTWCEzDtaxOR8en19u1F21PTr2M796/dLWXbp0Npl5Hq8XNou2frLqTp1+oU/QXHn+OQTA+EQHj063vp5rhXzT3/elX8il/efIH7CPgP9P0PvEtN08OviFHQjBgZaEPChBcnAikUTmulYiY4KyRLiOCkSeaS7ZOTDNjC82ha3zGwXSP+z0jug8Hxd4zH3YDST/8LSa7HRTcPn0UIv6OEqY7M9ssOBY/sZBY9TrqMFrvvlW7Vr0yXxMPIqOwkZAImJlSdAowhGacy1TpRpR+jVEzrGVbEa2YF8Idpw6ayGqtw3ZnYznqusTCTu+9+c4f/cHXf/d3fvfDP/0gLxfP3Hm+Vru83nDiG+sbbgXAbjruyJXMydXMXDUIX1965gzCiSbi4iwp2G21lJTSslssFgsBlVJMlciWLQHsAyAQompCVQ0e/D+TDY4vOMej002myaMK2tXT0/Pr68vNbtt2zeLoxKv+4Duvf/DBB//ConnxCy8fv7Q86ZpStPZ9UTOpLbfRBmYsDtLJKYoAWMzd5y7FgLinJgOotV7urteXV6un7rCau4rA9mXQA/84TicixEwhiOjV3IQS2aTzk4i7LM1iuTs+vrj+0AmmKFShAKsjAYgYNwJcnQVIHll+BztDXOHh5LRZuDBeTyk1TQOglBJBcKp1dCczmJFWV9VqalaPT5ZRnWEiZjGlWmopw2qJG8u7XwOfZWo/dexv037MlFjY25V9+9STt4/oGjI0uevNr9abLco7Dzd0NBzdfkFl8cHHHx7T4plnzv+1/+Pf+INvv/6v/hv/+gfr7cC+u3woXXOc8wcfvPfSSy89fHAviH0zKMGSRV8viZeGPcEzIQm1HJBmNCAqSDCBJTh7JVV3VXI4jWXod0MZRzj3ff/xw48vHjx8/buvP7z/4P133//4gw93l2uogplYbp3dju2g1jr0Q9/3pe/h3iyXT7hjzpebB9O28+hIKYlw0yzDX6t1rLuy3W7/wX/2D1Ynq9efff1zn3vxlVde+fwXXnrh+WdPTlaSUkQZcGfziZHGLVPKQBIkEJNIVZqAJMQTgZT51EvozqRMhYhSlrxAv73aXKXrddPks+VSB3Yz0ypmgIkHN0T6VHKWP6fxZOKOX/QzOXQbnafu74ka+pEPmlfCZ9m2/0JL489r7N2Fx7aJx63sJ8b+eJ3u5gRcj1MAiG15SkpHIjLCP1UAQkwEZtapzkfUyJT6IAJIHe6UZl//UbBaoEAEoZwHTKzMcPfqgBsbR7VXnGbXcdqvWZ327GAW2F5E8twRrClzutrc0iRUBSZKRMxciw2j7Yr2hI3T2rEh9CmNKSuxcyIR4TwbRCRKgVa1cB/IAROvAs1eG9iCsGQ+ynycUydO1juVod/uNtuUUtMcj315eO/Bv//X/+brr//w44/uI6W2OzKkomOw++BR0xss9OurTSs4Wq5Ojk9OjparxbJt25T4/Pa5M6WJ1lCitCugiwcPRaRtmqZpSimbzab0g8K7jhdjXuQ8jOOoOhbt+3E7lpl3kY18YtA6mCazhQHAExTdiDlhrF4oNa0I9evhrcs3/97v/J1f/Qu/LsQnt+607jWBvLqBmcyDEixZCHrOvZ5Oxi4Ei0YuI9OgCBUywna7rRf3Xzg+SuK1KA5aNGccwyOGkJmDqCZmtZZqk7iPEtRmK5PbRqSY1WHcqWrq2sWyXTar3Xbt7pMUr9m+FXiz2YQ1jRT0HBF5tPkGccfhaloul/HXqCLvEVvJ3SeCLkBVd7thu9uNZXt8spx2FwquZqiWYdwtF93eK46AmukG9/XzR8CHY29iiUiED/eLm5/8idsEUMZRHQ7d7cq9TXkw2ht3L+W4v3rj47vXfbM6vzXQ23ev/vV/89/6l/6lf7k9O3/vre+ePn9ns7l296Pjpfn4wXtvvfD0M5vry2SW4Mk8kSY4GbLbCmjIspOAW3hmSuIJUK2RsiavcK0oMC3wtl324zgOg1U1w72P7n37W3/yg+/94Cff+jaIwTnnZnV0ysxuZtUffHR/QmMyM/MidUenK2bepyzoUf6/YTvsXzykQ9lsNl51HIf5NkpmztLJoru6WH/33W9991vfevrZZ772q1/99V//6udefumrX/3yRDMGioIekZGZcOV4URimxl7VDTrh/IkVFCXpaJm83m6bdimNlmGn4KZbbLS88dHdX331C2RmpZAqYOzm/kQY7P9/jMcm5OFs/GwbTP+QvY2fczy2pvwTqekYn7bu9iEmTTKjE4VXJZtZsh2AEI1aicgiAe0uFG3sltyjVzk6eYPdPbZ4nmFzn8xeTHxhiEyku9PUjE/T8U5TL/e0Bc+oKzs4AwMVs0ZWfF/C3I0dO9y0uEBSVUuh3jCw7Mh3nAanIqlKckpEiTlRaIEzzcXmsBTkk3RWFWiymmyCInaUl2JLQZe4H4taLUO/220Wi5WqPnxw8bOfvvHX/6//D7RpdXTenXX9rty995A5HS2XZdjNLqWJT+IuBPvVX36tbdJq0R4tF8eLRdM0OTEJX19fu5k5G1k1Aqae7PX1umtSK2dd052tzu6cHcNZEhl8O2yv19vNtt9u+wdXVw8ursysHyoIeyY1cvJglQn35RMk5hcPH56cnh4fH2+3637dd4uma5Yp8zf/3h+D/c6tp17mlFer49xmMJnvdFSJ4r4rsRI3kNE9O4wlIZSzDeAb35eJhGutfd+bFmGYm5kbIZiuoigezWmqVdXYLZiKCJSIKqbMIjkcWr2WYjoMfd9vNpvFKi0XTcrHtVYSBrjWenl5WUoJDHNYzVJKxK/70i8RqWqIXty6dSvi3T2qMSbuntvqULhaRFLOsl5vN7taRmw342azI+bV0WIcCgutjpcEubrc1oqUuwUtmiaD2J32HcfEFI1N+4V6E9ICKSXdkwQ9ek2Y6BEegbT0fR9H7ivYccXhOOx3jcnjMGuabtj2H3300cWgOLr1+uuv3375NW2bN3/2MyzONr75/Jef+l/9b/+13/qn/pmv/MZf+ODBg/Z4tdltiYjY++vrlmjRtbvLBwsGu4qVZNYw58SNpCX4Ttc1IV1MZla9jD6UAm2TbLbr3nW5aEl80/dlGMByde8yNQur/ubP3vzjP/rGd//k2w/e+xC9nT3/TBnqbrOBou26Wmu/6wVUdv3p8ckwDF3bxK07PT559913mXksI4DVcjWOY6mFiUUkwVNin3PU4XBVMwCLtm1yG7d/HAcwn9w6f3i9gdvJ+a2my9eX67/zH/7O7//+733ucy/95b/yT7z22he/9qtfvn37fOh3m801kXfdsuzWqVm2KcMrMpMICftQzSoRE3NiEQeH+SVfdYvRVYsDiZObiNahKH/9u6//tX/6r9x7+43Lq8vby/b06Pitn/302Wef7UuxRxlT98kPfHIEjdOTMr2fyoRlNwWRzzYtj53wscHMIWzS9330dMWcjMTRY1mfJ7qMnz34QE/ssdzp4WH7037a+T8t3/6kfujPPM+neRhTrpgBzGVcAExTbHpIgwF1tKklosAnEODm5Khw7QeBi0gSSRRoG3aCa7WJUY7AaS+7CWcWTpaUmLSPnHIUxpI0ue2anDF1gKi5jyWEf7Hebk7Obn10997ZrdvVsOtHDi7riRlmKl0LsZsdLZZd17laSik3zTjWdT8OTr3hooyXjjVxLzxAxsoQYhJwAmHKbkoAMiIfpEH0yWTZlXVsSFdJ7nTdrW65ZEEtdez7frPeXm/Xu7btzu/cvrh/8e/9P//9v/Fv/rvp/BiK7W7YbkYibhddSg0BbZO17IZdn7OsFp0w3zo9/fzLv3Tn7LTfboRwdfnw+9/5ATM/98zTktNPfvKTL3/1K4tutV5fLRdHTZtKX5ixWrSLttmsrz768N1Eyaz2/eiuL7780vHx8Z2z06fu3MqprY6P7j5454MPv/6Nb24HE5FmuSKSNjcGv9qspUtt0+bcmnm/G1UtS2rbBcCj1rqtRNIksWJ9GZ31+Ozom7/3jffeef+f/xf+hd/6K395sUgYKze5v9o07JEnt1JrAVHK7WJdazIzGDvx1DFOIBlLOUryzDNPffDRu/fufUyvfD4l3tYBkKjdE4ETBByEFOdnJ9vdoDbW2ufcjlXVymq5hNXL9fVSlqvVQsfBvcZ8W61WKam7ElHO2ZnGWsdxZOarq6sHDx5EF2/OOcKbO3fu7IPsvWygu5dSIjI+7Eoys3j9UF0wjk+haziOtYxOlI6PTrvlYrnsVKuZlVEDXJVSSjkzT0j/R2tDhxHAYcFpPvQTFZrHFv/h/rVn8LIDKYlP3TLIU2L1YdysLzd9QmKmZ5555vjZXzp77uWfvPvRy1/+9d/9z//o4dXlP/nP/nMD+7qOnin8dTGIm0DZazalWhp4x9y1aSKXY25Mu1KzVcCc3KHq1V3drZayWjYO9KUfhsHMkLM7rZZHP/nRn37961///ve//+Cj++M4Nt0KHXSoY9+jwln79QZAJ20jfOeZ4+Oj5XvvvadD3zTN9dX1uN1kwq9+7aur1arruj2gLtIEWgbAXS00fcCkpQ5lXF9dP7y8uHx4GeqeYz/2g+KBOTPcBivQtstNvn3mbu+8897v/p3/9Gc/+9mH73/w1a/98gsvPLdYrKyM/WbbNQthA7QJxztJhVfjMhS3opGuQTKbCIKrucMr2EmMTRWFk5nl5dEP33jz+bNTuXiQuvbu/QdPP/10rdWRP2muPs0K+kFw89lT6L/w+IxT/aI29Rc9/2MH/Dl+qX+Y4zBpHAQXB6RXBIWHkSMQHAYTEDnUHEzuYHc1q2zsQXvGFFxINHFURZAaiWKdw1+N6BJgJmUYvLjBQp/N3H3QagR1q/CGSd0rvMDcLGHSswozHHqNgXypM+IkIph+KKPRAOyIB6KeaCRUSkqJPBESQ9iYacIeOcFDL8oVZAwVrxk1e1k20oJOkhy1eZFZtA7Ddre7fnD1wKDdctE07dtvvfuNb3zr9dd/iIRaqyCnFPQ/sGq73cZr4XF3uupWJ6vjo9WzT985Wq7anI5Xy5/+8AcwOzs9Pjs5Wr32RYafn5+fnp6+8vkvdMvFer3umrRcLpkZKz8+Ph6GIee8W2+ul4sAzJZSiPHw4f3N1SXAlOTk9OzWnadfeuH555577h//7d/+zus/+N53X3/73fcrkHNzdnrr/Hh57+LhMOxEcpKGWRJzrXUcr1NK05SYe5bYEY3QzHT94PKbf/SN5XL11V//tdX5GWppvXIdKguYTtrcZh4hKl6KAqTkCbCA+YYQbZIHdy+eOu2arrn/8P6HH3+w3W0uL+4fnZ3Xqco6wiosVJXQNou+jCKZmQ1jPw5Mqdbx5OSs1po4rH5pGOFeb69rYesA5hS8UgbnZIt0vFjcQKgwwxU3m03kn81ss9lEiHh6ehpx0X7ss5WHlenoXokDEsjiz7vdzjSvlsdN0zAnFjYbzaLC7UyUs4iQ27A3wHvTe+C5H24iT9hRHttlPpkK28dDPMdJhx90eIy7O0v1WmxUQG1oSI8W+fmn7zz7+c+drOvxU8+WtPy93//7L33hpa/+xlc/vHd/9EpEDGM4+5Qparw20IbQCS2bvMjcCAsBZtmUdUwGkBmZQR1mVn3S1muL1m0/VFNmXm/7y3sXP/z2j378gx9/+1t/0n/8EIz25KRNjarurne11lXTtW07bIdaKyfre7vcra8ftv04PH37zquvvkpEJycnTz/99FtvvfXiiy+4+/X1dUT/u92OGbdvHdc6EpByTpyrafQHb4+Pbt0+G3a9urni4vLywf37V5u1uHHiqtqvr5tFt1gt+zKuL9c/ebh++8133vzTt958883f/s2/+Nprr56eHLV5YWZQdTMFMUtu5UiEEvVayKcMSoI5JWZKnErAWELCCeQYi2cjTU33k3c/OF0tz595tr+6vxvLU+dnV1dXM7QCPkNj6EkT42aGfGLmfLah2nNK3zwCwOPl28ePf+KYS79BXGcHhM9/7uP/h60v0R5CPDvJwFQgnHQNpgqusaOqRv/LnJSGuTOMhGFweAmuhGoiZFRzhC8gB/GE8mECuUcftlbTaq7uxc0Jidnci6kpoF5r1eoKH+oIpuJwYnVX8uIo5mZF3Zg5sEhCHH0dWmokD5zJCerm1ftSevOtS++8he2IBhKlBi7MjbgkpAxhj7obEMQvZOzGbtlrdsuwBnaW2iVj1aRVFnYdhu319eXV+vJqe708PloeHfeb/k/+5Dv/r//wb7/14zewWJLzRPHp4XsYkwnb7Tunt49XAadadfmoy2UcLu5tvI5P3T4/Pz07WS1XqxXBa60M6rqua1o+omW3WC6XYSr6vl+tVsw8DENqm4jkAHRNfu21V0sZdrvh4np9dXn9g+9//2q97sfyT/ylv/KFX3rh1Zc/9+HH977z3e+/+/57u/WDQeszd24NwZasxUoAlcXgTgmAgdkPU1M8bPvFclX7+r0/+W4pJSX56q//+ur4SJftFtjYgBo1+2S1jn3fSMJU5HIFRRejk6UmX4w956Oz27dSm/pxN9ahlOHq6qLWUUvRMjpMQImFmXebDYB2sdAswm3DJDl1bR5221pHIlItQ79JnrgM2+1WVePGExGTeGIhJDeYpdREkjlYoDG38M5omzqOo8+KST7jlvYpOj4ghd6/GOhoVU0ARMisbrdbrSmntpRqZqdnq3FUMw81ORYWEcA1OpZmdCI+YYD9BjU6lZA/I9VGn0BpHl4uzbLGeFKxiogc1NdhsD5lEWHXcv3gwQdvvzF6vlI5efrFf+tv/Hu77fV/47/1L3LLW93KsmP2BArl4QxryFqy1uxstWjJ20QNE8NMi1elWuFubnAzcicj6ISzYN5sNtuhV4PkZn21ef1HP/rJ6z/9+//x37XRrNR0fJxY2DH2RUvtctMXZYDUrIwMLFJDyX7tS7/WNLlr29XRUZNzVXWz9997OwvcyuXFxb37949Wq2EcLy8ujo6WH39czDSyHO4Yx5GImqZpm8XJ0VF35/YwDMNQnnnmqe32+Q8++vDi6tKA3dBfbdbDbltrlZy6xZKI+n7305+88fDB5ccf3P3N3/yL/+g/8usvvfRCXzeJ4MQVBsriqclCTbMdRnHYCPViHpAIEdhIBAiLF5DBFDA2pzSimtObH378F7/06of37y1PTh5er4XZ5glAB109n73/4+e2vn+OI1zAT/qLf44f8Q81sv/zGtEJevgYLz8mIRHDiN1AHqSxUSikUBwig5DBUAE4IWFSKc6CSSqRnGZZOncHuXk1LRo22GwqHlMlJ9PqpkVrraru7kUrmKtphTNDfXqvak1wMssiMjHKMhFPbayhMWcTR7eDd1Y24I1jsr6cnRJTFs+JUgazMwcXSMhLBVYPLm4Z6GAdoQWdclpmWmYR877fXF9era8vtkPfNO3R6tgr/eQnb/zRH37jrR/9FGttzhbCyYrVcaxmmaVr22W3XGb+/HNPZ9hut6u16nbzcH3d99vE8srnP/eFlz8noM1mc3J8lFK6f+/ji4uLDz/6+NkXnj86OimlbDa7rmtqtfv3741jBfvmejuU3gxDGV0xNKnvt4uuOTk5feqpZ0atV5fX15vtUMp7775NnJ5+9rmvfOnVX37t1Q8++OA73/7eN7/7nXG7hUgiiHCJCkhikmQ2AaKNmN0IbGRwGou1i65N+Wr98Iff+/6ibVJKv/xrX1t2jVUMOvZj1VI5dclIRpMuO1wZCq6zWCUROdFi1Tn7Ytk++/wz1fWNN35Wdtu+781Ma/Gq7srk4Wl1TcOpWa6OVbVrl5ybJnVdk6+vN1nS0XIlQmMjx0uxnbdt2+8YMHNXc2diT0wsosM4cgrbN5W9Ahedcx6GYRiG2H4jFO77fg/K2Xfx7He5Paf0vvCqqqnW0fTmv/fl5aEv/bCTyiklM+QEfKb7H6f2vbgKMPEe8SMp6CdGwHtjHC8eGtrDL/DYJxKRMxcbB+1NU1Ud15fvvf2GUtP85O07n//Sn/7xN3/3P/pbv/GP/eXPf+HFj68+Lhiatkt10jxJhMapI18SNULnbUqu4hVaYZXUXA1W60QXMFGugiZ8NjOVcbRikpr1xeZ73339H/zBH/70Bz8eLnZNs1g1R+4+9sNQBoFk5i5lpWHc9i5lkZuTk6M7d54+PVqdHC1qHV9+6Zcg/PEHH56enULt7bff/PwvfW4cdpurS7gumqxajhbdM8889c67b6UkwaSx2/XjOObUMqWjVXv37n1MxUtbrVar1fFLL6Snnzq/3lxfrzerZXe52a53fR1LbjoSOVo1Yx3u33v4+3/4jbv3Hz58eP21r335S195VYRzzuxe3FQLCMSyWjRczQMcoQ4rpAag4wQQQ5hQhdzduHHxYt4uj+5dXn/08GJ5cpJK//C9926fn4a63KH1/exM742UzX85K/WpEfanv374p0e9zF/gPH9mzPxzeSH/Xx2xghkzp+jE1QwAc77RABgFcycmyeTAOgUbJSEWD4Co5Vp1ZjYyCIJb20DMSTQksGCm6l7NRrPRVMkVDPaKAO2bmXkNtAsMKOZEqHB1U6dKVNxG1wZQBxOpkzgThDkxMZMygUgIEgllYnCyrY47tp1jBFcWUCJu2FPDOblkMIMnqWxMwhfuEPMEa8mXxCuiJeFY5CinLLTbba4uLq+uL0qtktJqdZy5feuNd37vP/2917/zfaiko4UN2mQhdapO8EZ8leWka45aQb8ZdUhEd26frbrFw4cP2fLt81vPP/tMk2Sz2WgtdSy7zfb6aqNu1XHvwcP1ZhhLv1nvWLBcHKXM1+tt7nLTLlanJ6dHp33pN1ebavrUyZkImWG327n76mh5+/bt3Hbvvvvu/YeXVw/vld2u67qzo+U//lu/8ctffvXf/ut/fVBUQ2pStzjmph2rj6WAJ6UTmn214Bxr8mK7qbmho+Xprr/6zp98u20zyF75yldYUgcaXV2ZU26aLmfZKpSg7oWcyUP73Yn6cTg9PdkMG+13L7z0oj64+61vf/O4axhBrvH/Zu+/gyw7r/xA8JzPXfP8y5c+K7MsqoBCAQVLEgRBNr1rQzapNuqmejTaiQ1tbIRmJyZCGwrNajZiZCZidtQbo4nRjtRaTRuqZ7rZTbajaXqAAOHKoFAuy6Sp9Pn8u/YzZ/+4mYkigGqz0y2hR30CUfHy4uV7N9+79zvfOednDFlHzuzjmsmTigmulK/8UHmB9LwwKPth1SuVuFQAAOiszgNV4oUdKmNFhtXOckCO1jEkLJjEbwCpGGNKKaVUv98vqmG1H8XEt9C6AoAD398i3R4MjIuONyIWRZQIgsA50JaVy6bfS5Mk5SIOSy5JRmk24pIFQSCl53tvtH8PGod3YWj2GsV395MR9y2v327pfGvz+U1r0JvW5bf+iIjAkElmyIDNuWAlX5WVkGRdFvW2Nn/1V/5t/fCxp59+stvbio3lAVrUBX+eAwoAHylgImQ2QBAuZ06jM2gNkCVyjIA45tYWhuQArmDbU4HzyQ05JAvdTvfKlcXnnv3B5ctXqR+XKmOkTRrnZC0AeMITjAtku9s71XIlCEv1amVmcirwfSlls1mvhDKKhvVaabfTHvTbQShNrpOoX6uG2ppSqMKSCgNJIAPJGrUK0pwX+pyLOI6jKCKHnudJ6THG1tY2jDFzc3M6N/3eRhAEvuJTMw2OhiPU6tWWdlud/m6vl2Z53k9LjUa12oxFHHU7l19fjIfJ1evXf6HyudZEs9VqCU85Y7UzTjsNPPADZNwiWWSQW7ROW0fWKuQWCqc6DsQtR0vOMo4kLLdC+tdu3nrm7JnunSUmpXGF4dPboIjvmYb/NADBX1Lc3aR505G/wLd404N3YBxoAhY3875C0T2C2J5C4747EyDHIkPBnhF0gYIq6gOHgHbP2bAw37GIhQWTtdYBaeu0NXtCQYjAuCFXiKWDddZa6yy4wtymMPIlS6TBWecsOUvO7fkykgOyQLJo9HLGBC/kkDKdU15wlzE3LnMuQZYjN8gc445zhkKSVOhJQg7IACw4C2AZOCLOAR0xdJKYj1jmWGMYoK1w4QGSMTpJsyTKteZK+n7IiK8vr7/43A9fev6laKMTVutKeKPu0GktOPd8z5PCk1wJIclRrntRLJGazebc1ES1WlWSRYNorFEPfW91dXXQ65dKpWg4Wl9fHwwG1XpdBZWtzR3OpVJie3u31+vU683WZKvfH5ZKQblcHRtrhGHVEmTGOpf7pZADJUnW6/WIqFar+V6A5GqVcq1WY4x1Op2lpVvGmPHJyXq98fnPfub2yur1G7d2e32tM87QOWZsLphXVMB7/OCiXwLMDyqD3W2buPp4tRxWBtHg9UuXcpfXmrXq+GSl2kBD/Zys1YhcMTTILYABJoAJZBb3WGVJkjQ8kcW5h+7Q4UNpwPOddqVeKUuvaGzwgnx1AEq0zgKSK/D2HBDzLNHaRknChIpGSZrFVudkJiqK0jQlYyxaQ46h29N+B1cAlcmZA1Qz7jOIsiwLgqDA6Giti9q3QETv3Qo/umUviExFsit8DPda0FIK5zAIRKXiktiNhgkgF5IZkyVpLD3BOedcHkhzHCTgu8ex+Aab8C0zYLrnGvrWHPwj9/L+04oX5/u+jD9aOTmmuAbjXOap6vjY2KGZyep4S/PwD779x5trKz/x8z/falZvtruOQalSjjItkSPtUXt9ZIGAkKHPAUyG1iBpRrRnKAPOAWh0jiOA3bOZpT3/1TzL0jTfWt+8dPHKKy+fv3HtNiUZiMDmxubaGhIMfOVJzsCR1XmovOOHj1RLYa1anZ+fHw36nU7HFyIaDpDBoNdt7+40atVatTLqD84+/FA5DICzRqUSZ2k8HAE5wbDf6yIyxSUR2twKFOVq1fM8Y1yv1wuUX2qUKmF5o7eVRIlkMjbZ2nLf80Qp8ByTUpBrcS5kdxi3Xd86yDODwGVQMcZsbux2+t3KV/z7Hjh29uzZqelpKSUgAjjBOAPiDHyBFoQDBrlJbLHMkSRGgIRkERiw4sYxVktgBGwQJ53BELgIy1Vy9u4r5O7E8yfUwX/ClfPWKFrcb6XE/Xkr4MKgtPALOdCF/surgN948I5gLf1I4J73xBtcUIS92pfwjYHfng8EY/uM4L3JMGJhcIIE6PZGVAyhcDUCa61DQuQOANHyonJGNNZaIkvOOGscOChkpVFbyxgDAnLOOiJAhrBnbcrQAXOAe9m3GKViMVXdky93zhWSXYwxY2yWZcYYk2SIKDgfGZcjaMQci606Yyg4E4KkJCaRiUJdC9DCvqkUB0RgDiQwn2HIsSJ4iZEC5/I8zeJ0NNRaA2dMCSFl3I7OvXTh+e+90N1sA/fBMJtrnwnuwOe8GgbVMPAUZ+TIGWf19Ow0I+d5Hgdi5HwpMoZ5mmys3dna2iqknfM8j5JYW7O9s1NvsSTXDF2SZ7mxlXrDD0u77W6/P9jaNnmufd9rNseAgTPO98TxwwteGChFAKC1TpIkTdPRaDQ/P59kmZRyfKwZeGowGOzu7i4uLn7mZ39+ZnZ2amrq+q3bqxtb/SgmEFJKAigUAg6uh+LK0LkDFYJLs0xLhaGv0mh0+bWLU7NTJx86e/j+UuiFidZRllkLxElwIRkwoAIYz6EwsELkLNOpj6ACP5SswWe8sVbNVxWligtJMODIJMM9dhDnjtA5IGRMSEuY5ybJTD/KhPKVr7RJyKGvVOCj58tOO+YeSY8zsXctWQfaOI9BIWV1QOHNsqxgRhzoJhWd42LXeDAbxgNpqb2BLByIUGqt8zzfU8IajDQBIyeEVEJKYCnj4AWeizQg37u0sRCgs9bp4jYgh8VwGAEYK0ajxVvSXnJGgD8DnfetOdjRG7f6wb9wUE8Tc+CK2VIhgscAnTGkmeQOOXOAaZYPiX7n975y9JHHTzxwajAajU+1Bjs7ldAfJR2GSpLjYD2wCq0P4DMKEJw1HAppRips25wjw6xlZJGKNggvpvTAidBqjAbxjWvLLzz38u3L10CjrFRLfmCyXEpFgsg6q3ObFtKR7uzp06cfOJWnWZanApzO4jyNAl+YzNaqpSSK8rg/vbDgMXuns3n8+PGtrfV6vV4ul9Mk63Y20zQFhsmmDiq1KNFkbHfQD5QXlusALE6Tfn8wMzc32ZpcWbuzvLxabdSnp2cJ8mef/daJ+w5NlqtxruM4FcIbb41VKrVardbvD3u9nrU2CIJKtcQRDGV/+Ht/vLW7FQYV3wvqzQZXUgoBQuTWSmAOmWNISMAI0QGRs8YgucIbEsgiY0xY7rIkUYHXHw5a9cbN1TsPLsxZBMxTq81eRwffSDZvZLYfwUS9oW4Db5eG/7LjrW9kqXA9/vfxXu+cIHT7pe+94g0LcL7/rGIN2BOS37+JYX9bw2Ef8+wA2V01EwIDh8RyZwFgv/YFICCGDNEdeCQRFowzx5AhQwaE+5oMROCKXSErGt6AZBwxJAtkyTFiDsE4m2hiGpIkRQDBVde6zCuljFlCAoHAELggLtiecCIhEBa6EQhADIznmHI2JFcCLAGWGA84BQyd1lk6GkWjURIbcsgZMGEJ+sPo2tUby4s3gclqpZL2R1qbVrUORoeClRQre9xXknEi4ujYYw+dTeJRp9MZ9QdOG7BOcG6NuXrlih8E9WqjgN2eOnWKc7544yYQjDfH8jzf2NjgnD/22GO1Wu3ixYsP3H//+sbG9evXN9ujdnvEBHgeH2vWv/jFL85MTQZBkOd5uVxeWFjwPI+IOp2OBaqWylwwX0nZaraajdlDcy88992puUOnT903Pj72yrnXrizeSHLjySDNtMM99ebikigepNGwUq1xXoqGPZPltUaJmB0Mh9/7xrOWVLM1W51QkkiRRUZOYuyMASaBCQIBwgI6BEKmwsqwE4VcWqCdXntSQKtS4iZTSjqd6yxJs9zl2R4LkZHRDhgKoZQXBEHApEqTbBRlXAaeDH1fulzmYDgj52yWZVGaSSZ8JTnjyAUigrPkDBMCERkTnqfK5SoiAbAsy4xxg8EAkfu+CsNyGIbWFqa/sqCGMuaICJEzJhBxNBoV4OeiTi4OMsZw9ff/K611kmSj0SiJMyJSSnm+7LV3AaA13qzX685oRCyVSkJ5wyR+4wYrUjMTiAjEiq0BInpe4Pt+MbhO8uxgC3CAASv2EQcz7UJv0xijtZaSw56QOjFiFqi4LQUyQw4sIeeelISYJckgjjKd95OcqzDOYO7Y6c7I9LT4h//0v7t4c+W//uV/MXXfqXauVXNsaLVhDMGxNA2QfMZ8TgEaD4x0OXc5NxrI7vlpAys82i0jWRW9YZcIhZAus2A5B6EzM+yNvvn1b33nG9/t7nS4VAIZETIkQcgQFBdZGo+G/Vat8cB9J6Ymxo8dOSw4/uAHzzZqlVZr7MaNG41GrTXedJSVAt9oPez141HktBlvtY4ePbqysuKc84MABe/2e+1et9Ptbu90J6aPEPOBKEnTNEkcQegHfljq7LbnDy80as0ojq12fhg4Y7u9neZYKYoHUnmWXK83YFII6e12er4f5EYPh8PBYJBnpvh2tM2bU/WN9d36RPlzn/vpj33io7VmLXOGC4FScc8n4AbREdvtDvuD2PnhroOEqYxYDpgQS4BlCBqJK+zsrNc9EejYtTcfnJs53KwvX78yXq8iWYA9LF9hUkt7i3iBjdvzUkVihTH62/obFcSAt8a9bNTuFXSPXyj2swXBvRj59Hq948eP52kMb4dXuNf53Cuz3rOCv8f53ztD3xM/8bbB/pyJfq/RddeGeO913sQzxoIW5/gbcrnIGENGCJzfxVbGfXzW3oO3PSFiB7J/B7JWAOAQ0tw5BNqn8x78hgXS2qyvr0spJyYn79y5s7CwwBizlhCJM5QcJUPJkDPkSHmaMRRa63a7c/To8cEwcZZioXakN0JpiRNwRMmZx5kSTHLgiOjQASPLnGXWgRVkvCRpSD4eBGOeVwbnOc2MRpczATvdzmZ7RxP51Sogz4xljv/yf/c/bK5udLd3OYEHAFkuDIWCVQI/VArBTbSa1uqwEjxw+tSw15+ojkWDYZqmcRz3+33nnBBKa/3www/7YZjG8drGRp7nc3Nz8/Pz5Wql3mhqrTOjYV+f3xiTG22MqdRrnucVH2yn233++ee//73vnTh6NM+yfr8/OTmZpmm73X7iiScefvhhIcTG5mav2xVSVsplZKxQuEhMvrG51e12m62JianplTsbz7/w4vpWr1qvGQfakSFgSnGhMp3rJPGC8p54CBXSAQUIz2Uul6XgXR94/0/+zOcaU1OLK0sa3Myx+7ZT3c8pctLIcsxLQ4M5cSZ4KFHE/Wren6RkysatPBkDU+M0Go2mxlslT6XDCHIT+p61djAYcE9xJZXvKaU4Muecy3VuoZM4h6LRqHHOh4NeKfQqoRjs7gy6m6EEyqJ+Z0dncbnk1Wq1wFNQpC3CIPSBcHtnKxrF1VqFIQ9C3/cCApelea4zBCalZFIUbeo0TYmo8KwTQhRt5z35SSEAoFD/EFu7Q+eM1TovPO+c0SZLUjDkfF/5vs85xqPUOiMk55IzBg4BXSFwU3R4rAOOZIoi2CE4Z3KbK1DAQSAjRoWJLIc983NiJBnX4ApfJYEMGUjGSRQKXs4QAoAFS4QWAAg0WSBknEspCTHPTZobJDYzNZutrgPKwFe5tlaoV89duLq09MjTz4SNhkEEIQv2AnCO1ilwHlmPmHJOMMMpZ04zZxAcItG++SkhAghAo7PMV4qhMLnR2kkUOned7f7vffn3r16+1t1qA4H0JAN05ARjLs+TOIqIAk+dOHz4zP2njhw6xJBMGo2SaNTrzE6NnbzvaCkU/X5/Z2fzwdMntUn6u5HOY2fyXre9uXbn5rXLU1Mzg2hgLGmbD+Mkd9o5MDZfvHWDi0AppaQvhBCc5SbPB7par2xvb7bbO7VaIwiCJB0a7bxAZdpoQxZ00WPwpXKApHOvVGZA5PtgTMyyopFlHSaj3PNFGunnn/uh53nveeapqenpnLRgwMhpaxBQcq8s0AnIsLCvMAo4EdcEvKhhEOI0c0xoAGcdEHSjuBGGlVrdmJyBAYA911IEANrnghZr/J7FG9xNMH0nxVuz3Z+a9v6qx1vHS295BoP9tFqsEAwZgsNCO+stxfNB/+PtLJUBDhhf+xyK/X8ZERUWDO4uPhvAHoGE7uqtkHPABJFzyFihboxYmMcQknGWIebGyCDMHDopMnLO83LHHZOFFjICZ8AKvpFDBwwJnUMH6Bg4QCudqwisIZTI+k57jCQ5gJzQZUYP0xH3FAEkaV4uV22kXz138cqlK0UlZKKRQz5WrYTITBI1a+Xri2tPPXay0awCw1SnV69fOXPqgZXbq4H09wusDgBMTo41m81Lly/Pzs4uLCwcO3Gi3mxUKpWCkHrr5o0sy+I4TvOsmE0WZA2lVNE69kthJSw16rWPfPhDTz7x+PzM7Pnz53/3t7908eKVajVoNBqdTufLX/7y+Pj48RMnjp840W63t7e3wzCcnJz0wmB7e/ORs2dGo3h5eXl7fa3mB08+8vCdje2Lr10BKYQKpZSJ1kkco1RhtWr1fq8eGJBjIAHIAYR+oLVdvHz9e9/4zuPve/fCzFSkk+21ZVZvKC5ASC3IOZs5cMgQWZxmZekBKyVR2hlG0mVjJeWHJccwt8YMchPHqMlqLbkQnkqzDMkacMZpyYUAZESCsXolzBwITs7lzuYmt7nwgeFgGLtAeCj8UrVUCkOPC8Q4jkulEjDGgeXGoAPl+0bbbr8/3mxlWlvjUBS2vSxP82EcIWKBsTogI+V5XmTfojIualSlVJZlURQJk6cFQJpz7ivPWNQ6y/Nccu4rEfqe4EybPMsS31fSE2xPdq4AABYSbAhEzjoGJDjaws3LogNkiJztWWsjWSAkZ6xDS4YhF6zQt7DkDFgAQgbOObevHwcAgPu0bkS0rmgD7e0RkKhUCkqlkrU2zxMeqDRNE2O++c1v5lH0kY98JAxDY4yQ3h7+WwhGIBgK2iN24v5YCJ3b+7OQFxBOt4cFQeuIkJy11hJDQYQbGxsXXrn4/HM/SLoD0E6EJcFRZ7m1lpPwpfCroe959Up5YXZu/tCcknx9dQXI1qqVhfm5idaYM9YYUyqVqrWKEGJpeeP8S+e6nWR6vHrk8Pz83MLc3IzWtt3e6Q2Gw2ggeoPEpMY4hyJuj5K4PxyQECwIgkLa2xra3dHW2jAMjU4LLMDk5PThw0eXV5estZ1ObzAYGGcnJibCoMy5REQlJAYMgSmp8zyPKTbGZHEqfS/V6euvX43TyJJ73wfeNzN/yJIjIq21JQhCPwgCYwwAegCGETpyjgRYQUwAGQKd5Z7nIRkHKLjsxVl3lMw0xkZbaxwsYuHGWrh/MKA9cNbduk7vzJ7svbLvvXLwO7m3/JcUBaO1WBgO/rtrbP8jD+45g4e78+7+9OFHIfFvgvK9yejNWstFMe0AAnCusGuHwvbbOUdgU52Xy9XcGmTMWC24KnqYUEzvoEDiIu1ROQjBcSIkh0AM0EOse34JyBOcF/6E6Ip53DBNBkkkg9CTvhll4GB3c/fbX/9j6PVtqeIzQcBIG51mhgt0NDs9c9/RhcnxiSgeREkspTxx8vhuu/fgIw+vrawtr65ubW0lSTIzM1OfaDVbrZ96+Ey1Wg3DcDgcXr565fz581euXNnZSZCAMZASSiVRLpf9MCg+lp2dnVdffTlJ9CgGyWH2UOPEiROz0zOK8KHTDx6bP9wb9AuJ48XFxZdfPrezszMcDo8cPRoEQRAEnuf1+/3endVWq7mzs4PIp6enB/1oe6ft+/5T7353muad/nAQZ9a5wkmenLFWQyEPtu9EuW/esNeJWb+99PVoCBI/8ZM/3qjU13c7Msy5AE8QQ8rRKcYsEDGyzjDJGLHMutyR5SyytDUcMoDUUABceSUiO0gTm6cG7VirZRlohCwzpDOnjc20c1AeG0+1zrMEEXWaIQkGSJbS3CBYjQatCRQwLot++trGhheoWqWOCFY7P/TCMOwNuhZclqbOkFA88EJCp51JklgIAUCFCxPnnDEkcsbYPM8LeawkiRljnBdi6SiUktZqaxHAcSWcY1qjNoiOOC/8JJ2UnEgQ2Wg48MMSEaFDV/iRMQRCYsgIGCDniK6YFxtEvpc+nbXOFupN1mpjnLU6DMt7sp2WckoZA+egUAIDhlDAIYHtdaiIcc6tzfdUb7KsAKHVq9Ukihlj0SiW3CdrVlY3Xj5/7tH3vPe+kyeH1midy7CcOmetZdYxQIkoAQQ4VgjsOEduz3sD9kaQnHCP80tAnPPRcESWfBUoLne32xfPnf/mN75ltUYpueSh74MDsJYRMaROe+fYwtyJ48dq5UolDEqBtGmeJtG7nnxC6yxPR0kaLa/cvnXrZr/fj5LR/fffn+fp7PyhY8fUWKOJjtY3N9Y3N0pBmOncD4KZufnjp0rVRt3z/TTX7e4gitPBYBBFURRF/f6w0+kMskGWZNVqJfRlEvWyLPc8TzCnTTTWHEdEaymOY+ZY0Rgs+YHNNZNCCgFBIKWXZRkRaWeTPLPaSiaJ6PaN1d/7yu8T4ic//YmgWhaFO5SxQNZT3Aaec06RdsgEEqE1VhggveemzALfc1nkmPDLtTwedaN4utVwjDMqLLIdIH9Ljfv2AorvtPiz175/UcXxX4kET3d9fW/Kjvf6lXuOEva1+u5+BdqHC7wVEOCcE0IUCfjA8U15zqHDPfAXOuccI7B7ktNERA6DUnmU5EJ5hoDtmRDv2yMxRgwcJwLgDNFZosJoARQDwVgAVPdVSEYVu0hwBsmQ1WS6UZQ5csYIxUul8rA/ev3CpZuvXQ4ajTxOjNMVz+fS2iwF3x8faymlPE9tbW0dO3Fsc2ezP+j6Xthosms3b2yubfZ6Pe6pmfHWzMwMU3Kn2/HLpe88+/2XXnppezuSEur1sN5szM4fAq0RABkrhA8ZY5actXZ2djaKotFoVLjSEtH68urWnfUv/i+/+9BDxx968MypB+4/c/rBsFw6evRouVxuNpvPvfD8t771rXK5zBirVqsnT55cWFi4fPlSY6xZqdTyPPd9/8Tx4/3BaPHa1TNnzty4vRTduD2Ihn5QqleqmdFJHKsg2OMHF0y2/QshSRLhe0AU31l74QfPj09OPHj24emx8a7LmAFHMRTy+0w5cMZpkMiRtDUCwKtUJbfdfnt1Y5Oc8ZjwgfsMy8ofrzcnpg6Va+Vrt24AL3b5wBwjC+S4tbbb7RVy5VJKxbnVEOV5nkWFykWa6SweJAhkXb1cln5Q5YAC/dDTzvb77XxoPCGTPJueqHIjbK4dAhOIQlWECMuBMYbtd2K4QCELf2oCdFmeOOeEZJxzAisVH2s1hDG5sbnOLaCTXHCOyhNSMTIW0GVZwpgXBJ4fCHA0iodSSgcErrimARgSMUDkQnAEBECOSIgcGFIhs+7IMkBkAIw5xjmiBsPAARSkYQeuMEcEQ0YphftqRmx/1UEGCG7fmrpInMZZnWXpMEorlUovyjKdo85fOv9qmsBPfPYzqEQ0iFUQSs/TxnBk5EgKphwqi4wsL4QO37jPsQCsEwNLYKmwN3E2NzrTnvQ9L9jd7J4/f/GlH760feOWqtYFMo4IZMECguOc+QIbsxOnThw+eeIYONJJTDpDsorBKy89f+jQ7NTE+DAa3rp1a2trY2pq6uzZh4bRqFqtykkReF6lVOaAUsp6vT4/d2gYjQAAOHNAXEomeJqmJ06cKO6tPM/b7fby8uqtW7d2dnZ2dnaTJInjHhEFfsnz+KC/u7W5liwcD4JSKQgnJyd1brXWWxubaZ5VKlXhKSk8hlwJzgCpgLsgj3WihAqCsNPrrN3Y/P53vieU/PDHPlpvNnzfhzwr2Paco0AoScaAcsfBADmyABrIAirOJBcZMORCKKmzrD1KO8NYKcXdXs8Q9kgpBX3wr0YX968r4D81CpJsgWYmeEMf/uCDOPioEAtX1reJu4T/33hA6P6EBHxgSlMU1lrrHzkrsERFXkcAx1BYJOkpJlRuEifIMZYbRwR7dQUTwBlx5hgyKGwgiDsngDyAANFnLESoCvQs40ACLYE1TscmT23ei0foqVGqmdCNUuPyravnXngZkrxUkWQim+UsxEpQqtQaU83G1Pj40s0bszMTs4fmbty48drl1z7y0Q+99NJL65sbGxuD+UOTZ8+enZ6e7vV6Gxsb127daLfbGxt9KaFZL993/yEAKPrMjLHt9TXcgwXsfW7OgbVQKknnXBAE4+Pj5XLZWpskicn1+595dH19/Q9//ytf+p3fmZxsPXz27JNPPvmLv/g3+/3+4q3FnfZ2rV5hjGmdL60u7XR26vU6WceR1as1BCGUl6T5aDQKwupYo3n0sL21thbFqTVcCW6VKr6cfWAtHfhkFN+R9HwNsLm0+q2vf4sBf/S9T1pnY4LUanKp4oIEGgKjc46InCGS4zwnFgOhob5x//gf/De+gnpQEs6VhGpW65VKhUvemp70Q69SqzUajXq5Ugo8xZRgQBTtKVhJqaoVIhoOh8NBL0vjejX0gwo5Z5MoinPOM6W4VKo/6kdREpRC4fl5mmTGCuXl1gHjKEDnWRwPkLNSEPq+4pwbm+dZboyRJJEDY8w47QUqiiLrbIFxi5KRlLJarYrCfWlvH+osgBR74sPckdFaC8EAQClltbHaFOzjvVkLcnCAWORRAeSIkCEWsm+FZbODgoBMnAshBKIqXrPAbTMGsEcQACLL9u6QPcEaR+4A6q21LpDf1lIhj5ymaZxsEfNUWA7CchzrYbf37AvPt2abJx441ckzSxQEARfIiXuM5c74whM5cTIMHJJltH/3I3PFJYHgAB2BJasdOWddnnIUYVjOovy1Cxef/e6zNxdvAILNNRIjBjbPrDZkreSekvzdjz40Md4qKTEY9PIkch6XnAe+OHPmkY3N9cUb17vdNiIenp8vl8txHHueNzExMdGaLJdDgWI46KVp7hC+8Z3v9HqdKEqiZDSMEiGYF4TWas6xUqtOtMbrzUboB+VQPXLmQWB4Z2Xtxs2ba3fupFlmte7HI0+qVrOxub5ertYLcDxnrDsa9ft9IUQmUuccKkTBC2647wMhEGcs5cYYk1tfeVro5eXV3/nt35mbO3TygVNjE+MkFQA5Y4CMAAgFMkBhCQktkbFoiABRM4Q9iy5wKCxTI63X273DVYF7aOJi9SxgdvZt0he+EwfARfzvr4D/vIn53q/z53qZv/Sw5HB/HHv3Od9rv3IvU427jVsOHhACEdLdqPm3JGBjzEEFDG/wJ/ZL3gIhvTeARi8oZcZk1jnjpB+ktgBo7+8eEJEzKha4QlATjATyAEooqlwEjEIgjg7IogNLOrVZlKUjncbWhH5gUpukGSX9KxdfX7p2M1ClrD/wES1jehQz6c3OH5ocGxNAT7/3PdeuXXv99ddPnDju++FXv/aN3U4yO9s4ef/RWq3mEJbvrN6+fXtzc9Pm2hhz5qHjnudJIaIo2traiuN4YmJi5tDMJz/xEcWFUioIgjAMwyDwPE8IsbK0XIyE+/3+9vb2xsZGGifGGLCuEpZmzkwR0U6n/YPnnnvuuedOnDjxU5/9zMzMTL1et+SWlpastWma7uzsnD17dnl5OU3z++67L02z9kabIXvskbOvX7k+u3D42LFjE8tLr1y4uLmzKz2vVKtFaeb2kXb7Ah1AAEEQxFkKjFQY5ll6++r1841mpVaeOzmPgjMAdBooI8eUs5m2FlCoUHoSMj4YpmDyqvRq07O86nOAzDpjXJ6Met2Bs2QczB2e8kphvV5vNOv1aq3k+R4TAigMvFaruae0CFSr1YxxubY3bt46ceRI49B0KQxHvXaWxO3OgEh7Ie/1O1EUTU1NHT16NKzURqNRGIZJkkgpUXA0Trvcag2YAzJyNs/zNMpymwcKHDB0mORJrVzTlshgAtrmdhgPPeE5YIKQcymUIiKyVudG59oiQq1cYSiY4LnRJteek0II5XuF5BgRIO6pRe5x6O0eub5AWu/PY5yDAwFMV9wJxjitbZJkxbrP9omDRYdJ57agPjEGjDEGBcMecm0lMJvnaZoTkRDSOhhFkfSFTtKwXOnbuN3pLd/p/OTf/JnckSXyQ88P/TRLAZinvHSUMMUEWQ4WyTFnESwerPIMbQHuADIIGlzuHBnHgSsu0lF24/rNF59/8erlK5DkXrXmcis4E4TO5GBM6KuZyfHpqXGbJ8mo45FGa0ueqJWD0PPRZq9deLXb7aZpmiSRUqrZnJ2fn6/Wm6VK1Rizu9O+fv36xsbmjWvXVlf7GiCUoDUIARYgNUAAioFxe2BUjuAH0BoL5g4dWjh0eGy8NdEaL5fLx48c3e20V5dX19bXdZ5Hw5Eny4wAHVWr5XK5KoQIg6DRbK6srDJtNOTMcqYUk8yXChGF8hkT/X7f6lxKz/eDVKfrqxt/+Pt/oLU++8SjfhAUgBQGTnIWcoYEAhw6dIgOSRO3CArQWGIoHMjUOMslStVLs7Qs0DksaAp7ZrKAwA+uADjgIr1DabH/MYKw/uxBB5goAKC7PqI3OGcFHwkAABEdvX0CprtmwG882HfHeuv/OpAOLSpg2G9u7ynKA2ABxN0/Q0PWEatUS4MotYTgoFqvjwax22uUMmAInO3bShS64E4ASaIQsMKwyrEsULoMnSGyBM6Ay7Qe6bSfRJZzjegHoUn01atXrly8bAdJeWwsj/qBktzzuU/1MJCIJs3SPENw1Wq13d29ceOGc84Y9+lPfTiKojAMV1dXf3jj+eFwaC01GrXmxCRjbNDv93o9rfXc3NyHfuyDjz766MLCQrkcktWFcEThmlcoQwHSfadOlMvlUqlERKPBsNfr9Xq9OE5feuGlfr+/2+0QUblcrtfrK6urt2/f/sf/+B+ffOD+T37yk6VK2ff9TqdDiGmavvzKi7VabXJ8fOnmrW6315qYmp6e7fYGM1MTgSdLoX/8yJEkTfM8HwyHJkv3sPP7APqCZvbGpWJBOIYoXZzfuHw91+lP1D7l1cp+WEdAYzJjMWTKMUyJ0KZMcvS4S0SkMwnc9+XJ06fvXL8xbPenx5pzYxMF+GZsYpwJDmLP9gCBwNg0TcHoeNBt1iuAvNvtktkr+RgTt26tBL5frVQCj48SE40SkybGpvVGpVobB/TSjNKM4jjZ3e22Wpxz6Ugqqaq1SqncLGSiM2MFIIFEDpJLLn1HmMTpYBT1uonyJRJLsthqJxQXXAyGqWBMFGfpnEmjOE2HaZo6o8ulmlKKS0+n2TCKc+PVKmXPL4Pb0zAnwAMbKEAkQuMIHAEjCQyQAznrnHOknQPrtCWjnXZWp1mcpWQsVzJwyJXkgIYAHFoA41yR3RkhL8YGyLCQYDY0GsWDwUAp1Wy2lK9kToQsSvTY7HQJlWkPUcEHP/7ROEudDFQpEIKl8ZC4UEq4PCMBnAwnB84ycAiEBMiQEB0g7U2GwAEZB8YSOheqwKX5zk77yqUri9duwDBhfuhJmWtSDBmBISc4mxwbO3P//adOHrly/sWSJyfGmxwxGg6cTgdp1Ou2gazgODU1UaudaE1OHFqYJ6L+MPr617++s71769atft8pBdZCDsARmISJ8fKJ48dnZmcL0y5ETLNk2O+12+21tbWNjdHSarK0ev0lfj0I4OTJE6dOnTp8+PD8/MKD9z/UbrfPnTv38quvl6o20LZerzcajenpaUQkY8MgKOoIazUAOGtBSs5RkfADL0kyjkwJj8DpTHMpxhpj3//2szMzM4cWFsanxplAYIxxUBwcOLCAiBacAa4JMnCOMGWIiFbKzLlcp0wqBjw3cW4dt44XnzogA7Y3hqCi8Vdk332sBrp32lT4r7PvnxxvquwPfry78D0ojotG2p/8Oj+Cgt6/GN5aAd/94sWPB700wH35jL1Cdo/mRABSyjQfWgAClEFoRynZ/fPct3Evrk9GjpMRzipyHjIfRAkhYAjWktMWihGzNc6mRifagJC5ddWwOop6t64vbq7cEUx5DoUQoLNSqTw9OVWtVNDZJBqFYRhF0dWrV+87deLK9WthGBb+RRMTE5dee63b7SLA1ORkQdccDocbGzvHjx9+6qmnnnrqqSNHjjDATqezsbERRcNhNHC05w/kjOWARevLWqu4KGafzXpjfHx8Zm7WOXjve9+7snJneWXl29/+9p07dxqNxszMTKlS7vf7165d6/S6jzzyyIkTJ06fPt0bDH7v937v8pVLGxsbzVrz5MmTWZZtbawxgEqtMT83d/P27fX19cnZuRNHjkRRdOX6tTgaYVACfJtbOEkSjgicWW3QOQLobO10OttPPvXw+NxUgweKoTBWMOcr4MKTDK3NNEFZCa9WdQxGw4FN46AUlkrBkanpH//4x87e92C/vdvr9cqVMLPGAjkia7TNtc1SkxnKczLp5Ni4MXZ3Z6ff6xXtAUe22+lvbXeqpU0leBoPdZ4yJABcv7b0nve8qz5WHQ6Hg8hFkc2MLFUnL1++LIQolUq1Wi0MQ+1Ytx8Pep37jh8XVitlAUAIYYwZWBNFtL29MTU1pZTqdhNEnJqaCkrlNE3xO//i/8wFMsacM1YbR5YxJhmOjY0Zm8fxKE8zz5eVSkUyHmdpMkocMIFMeMoTEjgDC7k1kslisTTOoQOHoLhAwYlIegocMcFLQZjmWa/T1dZILuI0qVdrpUp50OtnOg883wF5pXA0GmWZVkr5vo+IeWb28fQJIlYqFSllFMVpmlpkh44c70SxlQErVTuGdlOTyZL1y1CusqDiV2rGsThNfd+XnueiAXU2q4opwQkcEnCOhdGvUio3OopT4Ex5wSiJozgNlRcy7nL91T/46m9+8Tddf1QZnwBjR71RIIXiIk9itHZuZurEsaNzM7NjzXLVY2nSi0cJB6yWK77vJ1Hc7XZLpZJQstkam5ubk16wePPGd77znZdffd04cBaSDBxAswpnH33kiccenz+8MD7WQs4k30NSHCwuzpqCZxbHcbvdWVxcfP755y9cuAkEhqAS4unTp5988snZ2dnhcLixuX198db51y4WRPtqtfqBH/sQAFy5cmV1da1SryVJkmb51NRUuVyOoijLDZO+5/udTqfT7yGHwajfjwZ+OQhKvrb5ez/w9C/+0heOnTjaG/St1aVadZRFmpg2mBmMrRwa7BrqE8ZCJsgSq1OjXa6tyUHrUMf1eOfwWOnwwqGbi9fr5Qo6F40GjVrdau0AEPm++yxzwAAcL9LznznMPSqqe8W9eMBFL6fQnKtUKoPBYHNz8/jx48X+veC5wl0p5F5gonu+7z0Sz5+bx3yvCvIer8//nD0F+lE9zj99t3GP972XP/G9jr/t+ROAMfZtP6KiAl5aWtra2nrve9976dKlarW6cPhwlCdhyY/6vWalwgHiwbBRrcVxDJw74ga5EwEoz6DICFLLUpJOedLzQXAD6IAcAidXlpKlqW/zceVPBn5FgGct2JxhxjlaoDhN2sP+II1TACeZRbaxtnnm5Jlrr17+n/7Zf99f3hrzakLnSTKanijPzx0aGxsLPR9oz+D95MmTX/nKV4BhUA6Wl9cfeviBhx85e+Hc+eWl2+io0WhUq9V2u93r9c6cffjjH//4sWPHiChJkt3d3e3t7eFwaK0FRqM8RsE9IYUQUgjGGCNAAimEtRasc85ZbRhBkebL5fL4+PjExIRzbmlp6cKFC1euXNnc2SaiWq12Z31teSV6/LHDP/dzP8c5/+53v7u4uDgYDAa9+Nixw08++W5rXL8/nJyaYVIlabbb6+50e42xVrlS+1f/5lfQU+QFcZZ7npdGcb1ez7KsHIRZlhUTegTuEBALhROwLDdm+JHPfuKTP/7ZoNFa3x11jePVJqtUInKDODE29wXyLBtsbrRX10x7O19ZuvDd7/03//Af3bewcOfG8rGF+eXlZQDivgpLpUaj4Qcq7g/XV1d2N3bS0bDT3p6ZmjDGOUA/DKTwhJLOmW9961uCM84Ri+kkkK+klDyO42IFZoyFYVir1UqlkhDi/Pnz7Xa7Xq8/8sgj9Xp9fX19NBrVa5WZiValHBadhjRN8zwvhC56vV6z2RwMBoPBYGJiolKpRFFkjBG9UWqtBWsYY0JyxhjZ3Fo7iHMhBDhLQMh4nqNhkOc4ShwicQ4FYF/siScwh7JYsPq9zvb2biH8EYZha2LC913Rne7JNMuy0WiEiEEQCBFut4fQHnqeF8fZrh6NjbfaWz3jLEdmGeRRbsmBQ+Q8zkEEFSlETqAzYF657FUMQHsQV1oTCUEnzbQIWOBZ4sxXjiEKzpDA5RLJQ2BGZ1ki0bF9lXgq4AEExpLLMwJAwR1Qbk1xPyMi5+rSaxcvXbjstAPPT+OMGRcoj3TOGFOMTUy0Hj378PTUBFoLRsc68SUjT4wGw3YaVypVpVSlWvK98NQD949PTrx+9crvfvn3Xnhp0TlojYuNbbMwV37k7KOnHjh16NB8rVnnXBijB0mkdZ5leRbHea6tKXz/QApRLpfL5bJSanJi+tjREz/5E58BgN///T98/fXXz5278MJLl27cuPXwww8/9dRTH/7Qh55++n2/8e+++OKLL7b7KYC7cvnS9PT0hz70oeeff35paalZq9WaYzs7O8PhoNFo9Hr9LM9ICSV54EltLQPOmVBcmtxmeb6xtnn19Sue55WrJY4i6g+Ez/dEU5A5IA3gAXmEmigHxwARmWPoGCcO1nHHWJRkgNwBcqGyaOT7oTEGAdh+Cxrpbo3Dd+4k+K/jf3/8qRXwjxz80zYoBXbkYMMKSIxDgZxABiY3BY4kTTMvKFkoGBvokFnkltAiEeO4L2LPCAiAE3BylGWSbEmKkmKSW+EAnUZnmAQLzhiT6axAkjpw1qB2plqpjQaDW4s38iipBKEidEZXfV4vl8qhLznpPM2yrFB//N73vvfgQ2defvnlze3uz/zcT1er5a9+/Rtrq+vHF2ZDz4/jeGtz89ixY7/0t/7WwuHDeZ5HUbS8vLy2sV4oYRljpJR+tVyplyxzjBiSs8gJHAFnQMMkJ2c48ND3KrWGdXo0jLfXVprN5p3drcpyaWJiojk+9vSPvf/Yqfu2tra+/OUvx2ly8uTJM2fU7du3/+k//adPPvnkZz/72XPnzl29enU0iBDxwoULhw4dmhgb31i/MzE5bbRpNRthGN5Z3xiNBp/9qZ/4wz/+5ihLyYInlZW6UFRGxLvxcYz25KML+R1eCs69+Coj9cyHPjY5NWd7gygeBpXQOMNMnMdR7ixmWa/f3epsJ5sb0e3bR44sHD16uLvbuXz5kkmTTqfNGGOC15o1xsGa0rDf3dnaWrl9u99puzwfdjtRlEjlHTl+YuHwWKVWBWCnTj04GPR2drYG/aEzJiz5UoW+Ks2NzwHsqT1r53pDM4iGzrmJ6aNeOEZE61uD7XZcwMuTbNhpD8PA9zyvoPw65wotjsnJyWFMg8iNEuC9rD+yo9HIWisQA62TXGvOocQVMqFNkqZ6YnLK8zyGlGWpcy7JmdFZHCfGcgBAA7l1aW7Znh8IZVlU2Ew69IPymPCqhXjmhdeuh5Uy7jtOFArUYRg2GkIpvHlzpd/vT01NxXGcJMlxkH657IBri8OBjqNoFEXOEJdibXV9YmqyUasDQ18FrfFmvVYDwS/fWAwnPWQ8TQ0oDxk3uSPrBGdKCQByNvcY+pxMnph44DPHkACBit0gIQFYa612XEnOpTMmzw0R+p4ngA97wxee++Fr5y8C8jAIk1EiHIRhYJ1LRlGrXm/V6yZNPI6B79++tTgxVlLoT7TGFmZn+/1+NIhKvj977PihhSO3l5e++Bu/+fyLP9zcHdbqyBhLEvN//bs/Ozs7O79wpFavZNrutLfv3Fnf3t7Mc1MQt5CcQCEVV8LjnGdJppRijFlrOZPVarXZbJbL5b/5N/9mu92+dm3x+eef//73v/+N7zx/7ty5++6772d+9md//FOfOjQ7+7/99m/1u9Gw3/WVWF66df+p+/qDrjHG5lkyGubWCI5EpPPY09ITPPB8yFLBuC99wWSutdW0trL2w+dfVEo98vij5XK4vdureTUBwBgVOtA5owAwRZcRSCAGyBCIMccYMXKME2ejLElzI4UHANbasFxK40SJd1ar+V5xd/v07oP/4c7onRX3+iDudfxeIKw/9/vuG7IWKfbA8a2Q2Cu0h+w+pHQ0GgnlO0TizCJzxA2iReYYIGPEBSInQgTgBIwcR4Lc+B6v+l4oUYAjysEZQEeC5zpL0jRK0kxbW0xcLThjxmr1rZWNC6+eS0fRuF/D1DCEQ7NTrbFaOQw4w9waSyY3WZxGUnrPPvvs5OTk3/47f2d8cuK3fuu3bt1Yn51u1ErVNIl95Z0+ffrp9z9z//33tzudG7dvbWxtRnFsgarVarlaAYA8z1NnelGSuTxP8jSNsyS3OnOGwNlb128qzjgKzqBWrk1PTy4cOtycmMxNliZpbzjoJ9F0no6Pjx86cnju8EJrcuK5732/aEo3avXd7Z3l20uvvPTyqVOnmvXG9sb2uXPnlpZuCWSNck0yvrF+p9FsKR7uDHfr1cpup10tVx596Myrr1/NhkME5wlORpPRRJTnuZI+wB7Eg9F+tx8ASeze2vre8NtC+O/9wIcnxsb7xox6u43xsSyF1KRJEpPR2mRpGnd77VajPh6W1je3bl9b3N7dadbrG2vr1pphNCrXqs1WI/SDZDjaWLnT3tpMo5GwzlMiTjJizAtLlWrdOBJcHTtxcjAYNMbGkygqmLdF/6BarhU7hjRNjTG4L/48NzdX1LiFl3C1Pl5gAHUSFcAmMoaTzwG8IPCD4MbSFmOsUOFIjSx8k4QQYhCZJDFpapCZJEXGIE/TOB7F2VIYhlKwLMusNUIIjqRz6/adDp1zzsLesMG5QjVaCBGGoVK+1qbX2+0PB91+v9bIJRfGWSTIdM4Ay1VTqo6nidVOgixpJ1PL4wzWd/reyERZptNMO0vG5tYwYkwKEmFqRZSDJTcYRZ1I+3LXcezFo87rVyrjE6rZyrkyDlCKjKwSXCgOzqDLPelJ0DodURaJksS9Wa91zhICEDPOGnKMBBccrbV5zpX0hDRJfv7VC5cvXYNR4jWaivua5RKRrJXIMuseOHnfzFTr1vXrtVAdO3q4s7t5bP7M1GRrempKCFGvVrMsK4WVSr12+fLlP/zqH128fKVcrYxP1tM8e+KJJz7zmc/Uq7U0TdvdzrUb17Z3d4ZxpLV2QLVKFYATEVhH1mVZlsYJEYVhOc1TJEDOEHEw6vcHXW3MlStXDh89cuLE0RMnjz/11Lt/8MLzL/3wxR++dPHa4uVf+qVf+ujHPtgab37rW9/a2Nzs9brLy0uf//znz5x+4OrVqxubq5VqCZFbndUbY6PhMM8SzrnizHDmK+WAyAIDLrga9keXX7vcbDZPnDjRqNYAAMkigkTJGAJnAbGUO8+iIsoL4ZKiW4u4VwcjM9Z1+/1SpZqlqRCKIXfOAQlAt89JggOdowPk5Dsn7u7K/glTzP9jx1/UX/0XhQbHPeIuO6iA95gajKzVnlIF4kEJP0vS0WhUrtYd5+CQgDlEC2gALDIQEjhzBfDKEQMngBQxDlARquJJDzTqnFwO6JBhavJRnsZJFKWJcQTAGCARCSYC4d9ZWr29eN1Zg9aA0dVKaWp6QklwZJ1xAEQMrLVxlirj0pw++7nPffCDH/wn/+y/ffa5Cw+dOVYvl/q7uxPjrUcff+zxdz3p+f6rFy8srSxneW7I1SZbjPNhNOpsrqc6HwyHO/3uSm/HIjDGJWOCCU8KyaXgrDU/Z/N80O23t3duLO9WVpdmV1abzcYD95+oVCrlZt1os7iytHRndWJ8fLI1/vDZs2EYvvDcD65du8YAH3300Xg4+sZXv5aMogcffihQQa/Xq5SqaZrevHlzYWEhSZL27raUMhmN5hbmuWBXrl5+7D3v6Sdp9Po1HaeIKIXIsqzw6XvT17enQEgsGY5EyU+Hybe/+g2X08d+6icnx5r99TvV6VbqsUhABjmCCxWXihlr253u8qXLKzeXR51eicmbN2/fWVmtVqte4GMBwkIkbZw2ofSqpQrm2XizEZTKozStlspIkESp56PwVKlUDoIQEAt7Smu1MybPjBBCKvCCCkMUUjJEY+3O7q7yPIboQAAyB4IBt84S8yxw68A4MiQAIDNImauPTcVxLEFyznPLklGSZZkQQnBe8XzFRQmAODJAJzwVMG8wijKdonOj0SjXqVKq4Ln3BiNCIAfW2sImwlo6SMBKqVKpFPglY0y32+31epnLNfOq5Yryw8APQsF95dUa9Z3eqD8cMJDVsXpuneOBCPja9vDQfLM7ivqdgSHnS8WVZI45C2P1aYOYaCF9Txu9udXL4sRxmpqfu3z1xqyGU9Pzca5HxqrGmHaWKykEy7MMwXoSuM0oGQmrGTJkrCD6WrJF49MhFMmCMQFgiMgTkqzb2dr+5te/2W53QQWCSZ1pJTwPII6GPmMLc7MnTxybnZm0aRz1e8Ne75GzDz1w6r6J8QZYt7u7q5Q3PT292+m9+OKLv/pr/25iamJianIYJceOnfj4pz554uR9WZKev3ghHg37w8EwjrI8Z1KE5dAPg52tbWutybVOsyxN8yQtxLZ83wdGnlLlSqVebZQq5cDzw0Al0Wh1/fZg2G6NTx4+Njcz/1Nzhya//e1vv/TqrV/+5//q535u42/8zM/V69Xf+I3f2Nlpc+4tLd2aOTT/4JnTy8vLjDE/CLMsy4zmnHKdCKcKLn8QBIQYJSkg86Wf6nR7q33j2o3l2yvNZtOTvjN7xgySMQCuCT0OPsHIkQAUDLhFxhgwRBBg0QFjXO602wuzs91Bv+L7xb4SAIDYOxH0/KPx1xXwnxZ/XrrUX8pXfgDdKkBYBcYFEa21w/4gTVNjHKAr3twRWkBC5pAD44gciCEBIxKACtBH8JVXVspnDLU1OhXMOg4OcZAmoyxNskxbC8SQowCGAErIeDBcWryZD4YeZ3mWlpGPN2tKCW1ibU3BPBlGg53Obrc/8KT8x//0/zk9Pf0P/uF/9YMfvnbm1MKh2fm1leXmeOsDH/nQE08+2R8NXzz3yp21NZDcL4V5Ene2N7c6u1vb26Mklp4q16qqFr7rkfeT5L4KQl/5KvClUFwJBIVy0O/G/chZTYY6uzvLt1cWV5ZGJpqdnT58aL5SLjPF0izb6myP4uGtWzfe/a53/e3/099+7nvf/+Yf//Hu9mYpCBcOH3r22Wedcw+ePv3Rj3xIZ+bll19evH5zZ2e72Rzr9gZpFk9MtKzJp8ZbKysryWh4//H71tc2dzttxpgfhlEUmVwrIYuvye1B84rvjAESQ1kOq3Ecx5udl3/wwsTExINPPjFRLrEsLnEoS5aQMWQUdwJslifOOvRK7UFsNXGBy+vbo8xN1ZrtbseQIyJwhrQNlScagfRKo0HfGFMul7mQ9WptbGw8STMpvXa7SwjOOe0sOuKc+75SSjGJTAhGYK0BAkPEHOXWjrXGgbMiQ5GxcZYyAqWUMbrovhSGg0XLnTHmeR6Tg9A53/edc36SFIox4vLVWw4K/K9DRGSFyYhjHGRssyzr9TtJFDOBHJklqDcaWEz4FePOyb3sC0mShWFYLpc9L2CM+Yj11hQXQngqKPnGuCSJ8twMh/3dbnerMxgfn+z0Y0SeWkzTXClRLjdB5Z1h3h/lvdggAjHuOYmI5NAwlee5BaiHgSyFvgHgIZOsXGvVx5Jaa1L4YRp3UmOkYMwyoQQyIGM4kMchT2IdD3yFeyRURAeWEBgDQsYcIPKDyoYBMsCdTuf8+YvXL1wCJoNShYzLs8xjnBhngJVK5YFT92ut29s7s9NTSzevdzu7f+NzP9UaK+/ubCajuNVqBUFpdXXtu99/7uVXXj1y5PDi7SUvCD/+6R//1Kc/7ZfLV65fu3VjMR50iSxjolwtKRNEyajT67rOThyneZ7Go2Q07Ef9KBolOgZjwTiQEnwfwhDK5fLk5NSxY8cOHTpkHWZZtNzbXblz+/Dhw/fff/ojH/vgk+9+7Kt/+LUv/vqXf/WLf9DptB97/Imf+ZnPr62t/f7v/+HF185H8fDxJ9/dajXPnTuXZzEiv3b58thYK05zYJYjZ+CU4OD7aa6dMcSYECpOo5XlO5cuXBofHx+bGjPGIAfBJWMoOPcc85jzuJPkWAGmYoAEjDFLBIwDQ4EqjlOtjZK+tRYBObB3fOb9kXjbNPwfVdzrD//LVv6618u/gVJ0e4iTfXqSKTwhbG6FEDrNNjc3i74dcmCADpgFJESLjACRYVH+AgEjEIA+Yz7Dmi/KUginrcmRDCA4cLm1gyxOtDbOuoK1QcwBCgDJxe2bS8s3b4EDTypM83K5Uq6UoLAllkz5cjiMOp1OnCaVSukXf+ELMzNT/+bf/C/P/fC1U0enZ2dnN9fWDx8+/PFPfLhSr97ZWL+1vLS5u4OByq3Z3tq4tbq8ubuTk52Ynjp89GS1VmtNTrRmplW95jhy4AwIHZIzoImc+fKXvpLEo0D4s1OTE2MTrZmZ8ek5qfC5H3xneWNtc3d7ojU+NzM73mgKZFmufS6vXbt2eH7h3e9613ij+Z1vfXtpaYkxVqvVLly4UCmXT5w4IZi01gZ+6eLFi1mSPfr4Y1dv3PTDIAzHOGONamVnc3P6yH1zs7M6z7u9HgMUjFlrpZTGvu31g9VKc9AfgHVepTbq9b/xB380ypL3ffTHkkHPK/n1UI4GLDXWoQXSVmd2MKpUG5CYJNaZQ+s4MLXdG+YWuRCCKyRrKU+16UWZwpGJ4p2tDc5lqnWtMVYqldIsT3ODXABD5pCZTBtrwaEh4E5yDgysJUtWG4eEZElbDcrP0izlMiyHSJjmqWDCVyWtcyyIcIggBDhnndPWJqPRKI49zwukROdKSimlnHOiWmtZIiRCpL3RCTkiq7UOfVWtsXqjxRC9QAnGtTVxrpX0C0C8c84WLqlEAMzzPKWUs1T0GTjnwlPdfi/VzhrHOCuXm5Vq02jr+coaNzMrkjgVktfrPoHjTNTHwsRSqd46woRSQggFAEIIKVWtVtNaF4joLMvCMuNSazDnXrt8+vFHDh051k8zTaCCMMuNE4IXUx+nFYLHWZzFJo2qzTo4TUSFc1mxNyFkiOgIjXGFyItk3Gmzvnrnue8/C8aKoOQckHEcmdGaM5potWYnJqanptCmd1aXG5VwenpacXbp4oVTp472+52SHwZBsL29/b3vfe8Hz/+w09W+H37iE594+LHH62OtpdXVre3dTr+XpCM0xtgUiLmcklz3Bt3BMNJOLy+vlgN/rNFaWDjUqDZKge8LjzEqVf1UJ0mSFg6d/d7w9asXb6/ceOCBB8KwPFatW2u32uuDV/ozMzOzUzMf/eiHZ6amf/VXf/UPvvbC6urqF77whSeefHxxcfHS5ddv3Lg+OTk5NzfXbNZ7vV6WZlygUjLVuZScS55khMh83w9zMxhG1lghmJSy0+m+funK4aNHG2M1YpYBOnRcoAAQHAVHAVwYYkgMiBXsj0L52QET3OocOdvd3T08M7u2fKtVrZu3uxffsfEmiYn/aHPw28a9QVL3SNj32nrdK9P+iYm/SMDFUOyAH1yYAllrA6VGvf7m5maj0bTWctqzfCAAS+gAgXMHDJCRI3CABAJRIvcQK8pXzKI2ZDRDQsGsNcM0ivMsdwDIGCciRq5YP5HQLN+6vbG6gkiKsyD0x8fHGIPc5oROeoJx6PU67W53Znr2ySeffP+PfeCf/JN/8u3vnr/v6NSxYyc6O7uzM3Mf/9Snjh6bu/j6a4uLizlZ7qnBaLC8dmen0yZPTB0+VG026uNj49NT45MTQblkGFomgSFwyTkKEJKjIM6Ari8tde5sQgSFUXOpLh9/9Imn3vvke973zPrGyvrqnbWtzUznaZqO1eoeE9PzCzevXl+6dfuxh8+eOXNmcnzia3/01eeff3720PydtbXFxcVqtXrf8ZOHDh3Sqb569eqdO6vH7zvuSxENB5VaLYpyTwl02NnaWZidAes6nY7WuuBqc86NNe6AG05v4D9yQ04D5zzwwjgZrS+vvPrCC8xjh0+faMxMBpz5HDU6AY4zAnAQhEG1Ocp6IAOmAqFIKt0dRNJTnAtAyVAYjgjccZ+4DIKSr1gQBMY6wQrxA84Yq5RrwBljRbp11hrnHDmjbcYZFPZDTDAmmUDBHS+Apw5cbnMOHAUKIRwjlKy4ogpP4uIK3FOJ4aCUAoHRMAYAYbLRaCQOHz2qrXFmj7dUjEyMMc7oIAgkFwVVlHOuTRbFsSwxpZTneYho9J7VAxEBoHHkci2ECMoV50yW6SiJZ2ZmHLjhcJhn2lprjEvTNM7ywWAwPTvjl+qlUmlycnL5ztri4mK5oskrKc+XXHSHo/X1xfX19SRJhFBpkiPiaDBcX18f9oeARESxtn5d/qPHzrJSuHHzpiuFlUplaLQnPcmQOY02F5wzBJtnxhhPyTTPoZAkRYfAiSEyhgBaU3HfIjKO3Gq7u7Wz+vpVvz6GFtIoFhxD5cXJCASfas1OtGqhwtmp+SWb9bq7T7z/mSzL/vl//88/99OfeM9TT0xNTJ8/f/77339udW1DKa9ahQdOnzn76CMLR49s77RXVpb7g6F2NtcpIxelyShJc5uP0qw37CU6Q8T3f+yD5XJ5rNGslMqcYNQfdDud0WCwtLPBOTYajYX7Tp1+tBxFUafTGY1G15ZvKSmnJ6fm5uaUL3ud7tKtUTIajtVaH/v4R0qB98UvfvHS5bX/4Zf/31/4T37pP/97f+//9l/8l9baSxdfU0o99sgjq2trd9ZWPnL4g6+9fllxrjzBkJHTiFwJL/TVKB6CMYx5nlSj0XBrY6u93bGaGHeI6AQB7ImAC7QKULksBK6R5ZZyAu3AAjfIcxmOjKn4/na3+8jpB29cGqlm0+a0B3BlezoNjAD2xsHvrNr4r1vQ/37iT1EQI/YmobQ3VcAH4j9ExJFzx4x1PlMmzUe9frM5bh04RIbMcW6ROWQAWID5Yc+XywmyEtED5yMLuPLBWmcQHGMCuNBax6kzeyZtjNCBIUMObOH8AP3NrXR3oBCkpEpYajZqo2GPciS0nqUkzzZ2dnsDePzJQx/72Me//DtfeeWl80dm6/Mz06+89PyDDz7487/w+Uq98vKrL/YGfeCQZ/nOna317a1BHJPitVrzzCNnZRBevXG9O1qptWamGlO9wbBar9lCT9AR7ClbM2Dsv/z7/+D57z/78osv7W5u5O0kausLr50HST/3hZ+bODo/sba2fOtme2t7sLw03WxNjLXWfvDsmZP3h9K7dvNGv98/e+bBD3zw/cjZuXPnpqcm2u3uyy+/PD8/Xy6HcRYzDqVK+KUvfekXvvCLg2i0urLUarXmZqf7g/jStcXTZx5xWp8/52yWcixYUczd9f0WhgHF1xXt7FZbDV+qQa+bZ3GpEvY3t//ot7/0s9VfCHyhyqHIM8xStJo5DUSIQgHjgCXPN9rEg2E1LJXLVW1zMi61KRKBtRU/HBsbm5lo3nx1PVTVUrmS5GYUp+1et9/v++VKEHqZ0VonhFDIaHPOyZF1RapwheDFniSDQwCmAr8oPh0RMpEZHXe7Qoji2itkpjjfU4VExoSUfhAIIbQxUkrP8wBRDKMBsD2dVm3z4rJGRBAiznOirCAaFtAG4ZestdZBnGQHTR7kDAGstQRknNGZdklcOL2Cczvba0owQiRr+r3ID4PpmanW2DgT0g/Lygu2trb/6I+/8/VvfuvW8h0N4FhJEwNKgVmQhS4NAIHnB1k/mT98ZHMwKpWC6YnxNBnlnd1f/jf/OmFwa2tb1WuWQZJGYRgEvlA2y+K0JLgveHd3J0kSrxSmWU4OSDuQTAhhgBtrrdWEoDXVG3WbGwlCeOF3/vibX/vyV1GF6ShpNZrJ7g4LfYV8lOfTk625iWolwK21mzUPSqH0+NjVq1d935+dmz5z5uGx+vjaxs63v/vcxsZmrs0oSd//Yx/65Kc/FVYrr1+5fHXxemt8vFRWi7dujuLh2tZ2uVGpN8YGcbIx6k/MTT186qQX+I1Gg3POGW9MT59/6aVf+Z9/I+oAMJAIUkIcw9GTrf/0P/s7Y8cPDZeXD58Ip+P7Bp3OzubGyssvjlVqD546WfaC1ZWlwW6HI7z/madq1fIXf+N/e+7F6//f/+lX5ibn/s7f+k9/8zd/89aN23meT05OVqql3Qs7x04cm2pPWEu5MRsbW9VquL3bTnWKXJRL3mCUS4RoFFfC6sbK5v/6G7/1vqffy8hyqbIsy7UNy1UuhGdNXYgszYUt1NA5oiAuHEHOsS21suQH3sbt5eFwtDA7t7u+UamUMiAnmAXGORcEAlARAEBmnX07fPQ9ZQ7/fHTcey70QogkScIw1FoXTbOitNrrTr4p4957k3B3uXz3A7dv2vOW8//z+Qo79/bH70nvuWdh+SOKGQcPCrXYt3mte/B37xX3+pwZvfF/f6Sv4O7xuSFjjDkL1ukC8+yc01ozyTjnQnCtc0LyQz9O4zzP/bI36vaOHDtxa6tDlF9+6aJNbb3WFGEp97xcSickcMlQSscQleMeMZTWchszk/iSN31/rCQx61mbkzXOmFGqu32bW+NAekJ1el3GWBAEhjljrMeREQljX/nusw0hhbEN6TeCYGd7S0ruizC30B0k33/+yqOPHWsPbj7x5FMXzl/5H//lrz98Yr5ZL2+sLj905tTP/Nxn663gyrWLne6mJZdmI0+o1ljj6uL17iB66gMfmD60cHXx1nef+0G805s6ff+Jo4/NTYUVFQZWIGco0DrQjhzsgcMbLe/HP/uzP/HjPx31u7tb66N+xxfcq1d0KfDrpbnxljc5vnrj9s7a2vpotDscnjx8uJ8nu92OjuMG1Td2t8Ig+MznftKa/MKFC+WwBOB+/dd/9XN/4/Mf/MgHmWQXLlxwQF//5tcfffTRI4cXBoMBac1J33/sUNRZn2mN/eQnPvqVP/h6udlyKOLcMKYIgQEKBs5oBhQGXjkMdim10WCUazLWA6Ao0joFid/+7S/f/9hDDz3+6Px4c7i9C2SOzM9e/OPvVFzdi6K5UmlodZpnlVqZMWa0DgM/iqJSGHLOba5Nnq0s3c6jHgh/5NilG8thGNaAxUk6PtkaxWkU9wuYniGXJo4VbhaSCwRnrHMAhWSTIYfAuTTaEhXaqADAkXHGgCM6MnvUdkRLRM5xZIgYRbEQwhmnrfakR0QmN7VKTXiBetMdePdFf/dtWYRN4rufc7C+FNSuItlLyfeyPhLZjHNUSvlhuVytVWuNcq3uByGhZFzm2mUW3/v+Dz742BN5pnMQQy2i3A6jzm5nY2NnZWNzbWNro98bqLAMMoyNM0JNLSxsbt7JkvhTn/uMCzxD1jlHDIEBkbNGmzRFyTk5DuSM0ybTzkpgwBkSIiIHdMAB9tC2hOCA4iQRJBja9sbO6tLqqDcSxC2jfr8vw1LJ4yaLZycqp44fnhqvZ9GoWitzsMlo+OEPf3Rl7c6//Jf/80986pOe529ubD/7/PNaGwLmAD/56Z944MHTFuj1K5d3Om3G+c7u1sb2VpZluTWT89Pt4XDxznK1WX/8fU/PHlmQge+A/KDknDPajizLWOCP1SLXl8h011nfa8xXTz767skjJ0uV0hihp0Rg86BWG5ucTIf97tbW4u1bY7V6o9FQTG5tbTDGZmZmfumXfqka/s53v/vSr/3bX/vbf+c/e+KJJ6IounZt6Q9+7yvvfd97H3vssa2trQceOPWlL/2utqS1boy1pGIz07PLa3dC34uSiAFyQAY88EKTmQvnLz78xANEwBg6dASWATLSgpxnc0sidyIFlAwkQyB0TMYoMSj387TaaO3udCaCcIgMAAjBIDlkBMgQkAidQyq2x2+zdr+pD/y21/A7JO4umu++re51/K/jTwgEDlRIp71hVFpEr9dTShGRMSbLMs+T5UporfaE6u92GuWqjrPN1Y3ZI0eEUBaZZdxy7jgiK16TIQEid47IagZWcQwEBNxJMNrGaI0zBM45R4aYAWmdY0QMOGPcAdNkCslKRrC2vBx3+yJ1gjEFwB0UinOMiX63t7axdfL+2Zdfufn002e9oPxr/+7fHhqvSc63NjcnJsZ+4lOfHJ9oXLp8cWN3887mnbBcEYHc2Ny6s7kzfejQuw4frzZbz77w0vnXrqbdQThz6JlnPnrq/kdKpWaSJJ3OqNDeSI2NC4t3YFxgnqclTzarlfrk4dbkPJmUg0OPb+T9UZ465xoT0/XGWHvu0M1Lr6/evHVtaYkBTrfGqtWycXbpzmqtWpXy0Hueekprff36dZs75Xuvv/6a9L1jJ49tbG8tra4M2oMoGkrGszjiQGBtMhoqL+i3t02Wt5qN3UHPC+vOOUSyDggcOEIixkgw9CSePn6CnDG5TtM0S6IoSdI8yRK7u7S6JARl2UNPPna4NbG6u7XW3p6endv4wSITfQAWxyMHoITwpW+tHnRNGHhxX+c61dYIYBMTU4yxxuRU2feEEJ4vlR9wqZgUUnFOhSolCmuJiDEo+GxKeETkHFjaNykADsD2+LeFHjNwwj3FNFNsKPcGswVAigDgQE+J9hTyiREQgSgGJHAXoaL4N47jgyv74OonIs5+ZMk4iDAM7/5x76WAgDFtHRhXkqpWbVRrDYvYG4wcceQ8yXScZJV6bXZhwVra7Y8MLzvGAbWhNEn7vX673W6PhtEPX3z18uWr0lMTM1OgVC9NDs3PffyznwEpyZIlV+i9WiDS2jqn1J58ibMuz3NjjBRqbxi5Z5m4t7HfR2tQlqZClpI0vnb16uXLl4f9vhSeECLv9putJpk0TZKTR+6bmZkJfVUvl0aD/u3bt48fP170MT7+8Y8/9b6n4/7u4tWrV65csdYqpe47dfKZZ54Ja5XbS0s3b970wsBau7mzu3rnztjYWJQmRHp8avxY42S9NT4+O6vCUIRhvTnRHwwRpGByanyyVj0yOf0AWVBKSSYtkTZZqRKCX+mlGfgl5nkSjB+UAo5osvXy0q2rV5fWNne8ztzEDEdmAeem+LETxz/x6U+tbW69cv710z98/uFHziZJcnPld65du3X6zOlTpx/Y2Ngo9HE2Nra8ICgqjF6vxxjzfV8IwZAVU5wgCNI8+853vnPi9GFVUcITbk8tH2Bflqgg97ECUQrAC/VwIqlkOuhNN8bWN7dmTh4RShpX4BDeyEx7j/9ERM8BaO5tk/E7Ku51hv/+z/yveo7fW5IYwT7zAsAxBoiY53m9XgeAarnkSUF2bxgsJO/1ejPN8ZtLV9c21h968gkhlUFelIaIhU4lFPtyLMyDrOOEgecFPhOCFZgYsMY5yI0z1hoLpnBm2oPO7MtQExW6Aku3bqWpq3GshuVarRZ6PhEZcr1er9/vI2IQBAAwPz9/+fLlGzeWn3787M7GHSXlu9/97tMPndnpba+u3dkd9meOH+uNRok22/GoncRPPnSWPO9f/Mq/TtoxlEuPfuyj73v/B+9/4CHPDzr9UT9Ke4OcqRCYSDWOYp05YJwrT5TD+nA4WNvtSWbLSpR8WQmUX4Zaq0mD3TjVHCEMS8HMrHCuWatdePHF67dvJnE82xzLuURrwEE37B09ejTP8063u7y8rHxvcXHRIfv85z9/3333rays7O7udrtdRixN00KuQCCrVaujzR1EPHHixNaLL2mtpfSQcbIGHTl0SI6wGB9ApVThDAWCtTaJR4PBoDfoRmmiSgHTbvX6zSAITpw5hUk6WNsSma1Wyg8fv//E8ZOeL6NRkmYxEkOk9fVNT4rBYNRo1NBhFA+PHjleq5bXbt7wpGCMSSm9IOCKF80txnB/fmFonzyJjDwhLZCzUGTNwhadrGFsL28CZ4iF4DgSMGss3FUxFBRMACi0hIGADgKIiIQxhn40YE9YIzvg1QG88Wth4MPbNZQKl6W3BJQrjSzLnHPGUpLlbjAcpdkoTlrjU2ScNs4i4wS5tsCFXyp7pSZKqTwshUJ5gAjOWOMcR/Xyi+emp+ZE4F27uVidmv7Y5z5bnmztRIPcmdwZjpwx5pzLrGE5KE+UgpAppa0tmGcOyDhbfGy0v8oXWA1yaK1VQjGA7c2tS5cura3eAWORg0CWC8E5H/SGgRStsabVOiE7NjMVDQdHjhx57LHH/tff/lKapk88+e5vfvObh2emrly/xhjrDwanHjj9iU9/ihA2Nzdv3boVZ6nwva3dnd6gD4x7QeiytDk+UWuOH7//5Njk1DDNDfDQbxKGXhBaA474IPakLB862pTAEJFJykwmpWCCoiyKcwdeLUejGBdMJDr1uX/k1P2NVuv2tes7d9av3rp1aGqmVK6tbKxFiZ4/PP/Tn//sb//273zxi/9ubmH2oUceurL4+vLKysrKSqkcHD169PVLlx599NGLFy+laepJ5Um1uLh45PgxKMDhjDHGtNZhGKZ59tqFS9vbO37VU0ohkXOO8cL80xZNGUHACRk5jowjCGSWcSJHjHPJu8PBMEqkp+J4xARnhECAjg5c2v/UHAz7Oewdm4PfVOa+ddPw1uP/YU/4nR54l2HRXSGlrFTKWZZdv379wx/+oFIqiiKrjXOGOSeFyHR++dpVi1CpNZjnAUPGBDLhUDhAcHsOwEgOnBXWKoElpUJPcGatzbI8B7LWkrGUO6cdGYdElu0vksXyzQHIujzLbt++TRbCUlCpVOr1OgckolTng/4gTdNyuXL50o0nnrifc/5Hf/RHh2bHnTNJkjz1ng8888wzGxsb15dvcKkcYozu+vqdwShyCMcfevDBJ59Y3+4k2orp1k/81Oc++enPVOutnd32+nY7TvNUkwjGuKwQ55xrMBHpHKVk0mtOTJs0BpMJtGC1ToebnYh2dg9pnwtTUwE4MllORFNTM7OTU2TsyuLi9Zu3Rt3+9Nj4VKOByDe2NgPlHTtx/Iknnuj2e2maAsDOzs7rr79+4vjJkydPrq+vd7tdMuT7vud5Bf3GD8NWq7XbHRw9MnXt5u2tdq9RrWrrOHAABwjMkbEuzbWI493tnbLvV6qlalhqVKrjzbEknUiyrDPsKaG2O+1LP3wFnZ2en5trjCdrnXaajI+PP/rYWc/zFq9dv337trG6HJaefPyxXq+3urp69qGHkiR57rnn2rvbYPPMaMbA555UXHlCCCGlBCDOOVltrQW3r04PAADWOQTgCFTcm46cdQ6IAxToXQaIQIQMABhioSzD7hJlK1rQBzm3OA4AxXIqsiyDu/LrQQIOguBtE/DBPOhNY5vCXvBgU1n8W5TPBCzNsijrtPtDQp5rSvN8daPjkAmpvFK5VKpM+uH9px6YmZ1e3xlGaTIatNu7m3k8yrLE5NYSNSsNJHTIuqMkj6Kz73/vQ08/vdzZTa3OTOaAFCrh+N6gDkCkie/7B0qzxQNjDIpiml5suAo5LCh6+b5SWZTeunHj1uKNLMm48olImywI/TxLskwfXzjcarWSeChLwaWLr+k0OXb4yNWrV5eWlo4dO7a+vj42Nnb9xmK32ysGq+95z7sOHZo9d/7i2vbmMBpxzne7nZ32LuPSD8vI5eTU3NEH7v/6d7690R185BOfrtQnuVdCVbqz1vaCahTrPDM63eTkCSFN6izlqR7kLqnWyqVK4CgvlfxmoyGF46DTaDAajMqK+0GF+6XyWKtcqd947dJ6e9cvV1vN8d1ep94cO/vYo73h4Jcv/8pvfelLP/uzP/vud7+72+vduHEDGX3y0/f1er3Jienp6emXX355ctqXUo6Pj8dxLGRw8M3mubXWSi56g97Nm7fLjXK5UoNCnEsQY4whCQbcFs4yjjEhi3wMQNK3eVTyvCSLgfGN7a3xWikz2t+/QA9aMXbPD+eeIkpw16DknZy63jbp/gnH/zr+lMBCPxgRqQCZWmvTKCoH4dLNWzdfeWl786ecMYIxT8g4SrUxk2OTm3fWXrt8ZWrukPB9YAIZ51wS58gYOjQAAI4jABG3VoALpQw9pSSCNnme7yvTOUugnTMEhhiRE/vFknWOrGOMO62jwXDp1m1rgTEmGGeMmVwTQ20NZxKRb2zsCgG/+Iu/+NU//KPd3ejow3O3bt06fnjhqaeeqtSq5y5fWFtfL41Veegvrt250+tkxh49cvz+hx+tzEydnD70//hv/1lYHavVxwzxy9dvDIaJp/wgKHFPBaUpJgMHTMaptVxwLYTwPMmd4KIkVeBx4mCsH0IlVzi2c+d8GEKpUg7KIVd+ptMoikZp8q6n32uN2VlZ0wTbu21fyGq5lsXp0upKtVE/febB1bU7586dY4w5bV564YfHFo4dO3xkeeH25cuXN9PtmZkZ6XuIqDgbRsPmWLPdG3qenF+YW9/ZkZzlucFC34cL5tAYbYxJEtfRHROGHDEQKqj4lTDAes0BTSXRTreTp8lut3fj/KWAS99Znpn7T9w3PjZm8nxna+v8uVdff/11ImrW6isrK1LKPM+Zc0S0trpaL5exWRuNBi70hWBchkIJJhhiQZW0zjpnLJDdT3pARNbs5zVgiEQciAAckTXAOLJCVnEvv+5dl4Wk14/Gwc1+EAX6QRysBW+6+Q+azwfH947cJf5+9ya0EHs7iAIJ5oAYY9pRkpluv9ftD+M0MxYssnK1mVurLaW57vQGxtKRI0fve+D+Q/NH42Q06O+mUZd0xhkIrhhXd1Y2giDYand6/V5w5OjcqVOb8Winsw1oiKyUMiCnSAIAFpqX1joEB2CcNc4xwZFz6xwvLHfIWUDrqMCUoUMOSNat31m7/PrV3e02IhPIyVprrfBlEg0qZf/w/Fy5HKYuC0N/cuxYvVIlol6vV61Wt7a2kEmGuL6+TgCjKPqxD3/owYcfurV0exCNRqNRpV7rdLtbO9tCesJTJeUzLmtjE88+9/L5F6888K6S9Ou+39rpR8Dz3CrKVaaZkCVjreBhtdrM44xx8isYxR1t81QnURQNorw/jBnqhdlJY5gfVEtlb3V9/Y++/Durt2+fPnnf0088du6FF6/euvVkc9wPS2tbm0cXjjzx5JPPPHPhm9975eT5V97znvfMHZq9cePG1sbmyz988fSp+5dW7iihtre7pUrNknvowTNf+9Y3Z6YPcc4B0JPKGp3nOefc8/zLr12enp2cmZmTngDryJmC+8sZcgK+N5oHhsCBBDISgnKGTKQmDwN/p9sba1SY4EQEroCnEwE5gH2KyP+hutAHJ3yv4/fKwX9Rf91f9uv/ZUfB6NgvI1whd5Dn2dra2vHjx7nA8syM1jqKokqpnEQxaIvOeZ63vrl5a2X5Uz9xFj0JhdgkZwKFRXZgEc+RwGpG1hOsLKUvuCDK8zyP49zovbcD1ESawO05EwMUK7W1xVlprXu9Xme3LQV4orBbBa218BQRdbtd3/dNO/7CL/wNJLh48eLcdN1ZncTxe97zrompidsryxZIeKrd6UEtTJzzmvWaFx594IHpo8f6ScoZPfzEu6zBW0trmxsrUgSNeksIBcQC4elkyIzhTITkwGOgAuV7vq8Ec9bmkGXkcmSuLFitWRmrNI81aWtjaWNzq4tUazWCStmTSmd5rz8cJkml0Wj44dqtJbOyWq/Uq6XQEa5trE9PT585+/D61ubu1rYxZn19/erVq/Pz80ePHl1ZWdnc2R2NRlmWeZ6Xpunu7m6lMQbgRoPe9MSEZJilsdbW0t4GBRjjXBA549xgFJs8y/M8juNyGHhe0TCG+cPzOzs7VT9EcHF/dOPia0zJEhePv+vJ8ca40TqOhgDAOQ57o404mpqaOnb0MGdSSLa5thl40vM8sq5SK5eCsFwtl2vVMAw550QWAKw2eZ4arYlIMhRCFDcj3zNsK7Z7nBMRR0uUpikDOsiSDMgCEJFSam+cBnsXhiN3VwUMxVwPAAopZHF3IXv3zVnYWR/EwTsJyQ+O0F11cGEVXOxGD/QpiahSrnqKuRLGibYuSlKdO0Iuk922CktBWBWBUKUaIfrlSm8wfP0bX0WyiruSL1rVUrXeqJZr0g+f/cHLaZKnmQFP3nfmwZjjcxcueiEXYKWAUqlEnFlGAplgXPLCg4s5tzcAFoxxKQDIIBIgA3RE1lpDjiw5h0p40WB4/erVxevXsyTlwK3WHJknpc4Sq7OphUNKqWg4rIUlJNre3p4cH1teWm02m08//fTS0tLC4WMvvfjDLDcA7PTp04899pjWemlpKTUaORinB9EoydKx8cmdbm9ybmI0Gl27ufSDb704/8gjH/7QZ8qlmf4g63Ry4al6bYbJEuO6XGpEIw0kpVeKk4EvRZpGpdKY8gSAi5N+t7fb3t2Ihx1mXMnjjbLve+Usda9fvrF5Y2tjbWNudnZifn55aenyjevHF44JZDu99kRj7GOf+OiLL7/ywgsvzM8fetcTT4Z+cPny5R++8MJPf+7zo9EoDMtzc5PW2iRL0zStVisAoJTKc6uUIhBpmoKCUqly9cr1M488pHMjPeUcoCOOIDnjTDNHDBgHYuAYkERmATgiCJFlI8klel4SdQ25UqWWa4OOoLBFYQAAdh9G8KdWwAfX+v+fi/pfZtydce+udO91/D/kuf5VCOMcMCYYFMuPc84YnWXZaDi0Jj96+MiPf+rTw37v6uXX3/2ud4163WoYciaSKB4Oh1maVOoN7vkWkZAjcMYEIj/AnSMSN7kCKnFVksLjnGyq8zROE+MKdhFacA7A7eM3naMD8hMD4MgSrQe9fpZkoYfFHBQAnHNSSuXsaBSXefWxsw8888wHvvjFX++2+w+eOj7q9x577JGTJ09aa++sr6U69yulQS9LsvzOzo7XaEwtHJ48NB+EJQBtDLXb3ds37zjHWo3WxPiM4EEUJdZS2fcYSyTPuCDggmFJeioMQ9/3gazkVPJV6AvmTJYNdJZxyGcXHlyrV657wcrWRtwdGGPCamVyeuobX/v6cz94YW5i6t1nz3LP2+10N3Z2nWsempva2tkpVSqHFuZPnTp1yRibW8bYSy++ODE+Pjc3t7Cw0BuOer1ep9MZHx/HggJrTK1a3tjpVBvjh+ZmVte3/VKVrAO3599snQMAhpgba22SZHlv0FeSc84lQ4a029nt9XqlSigYlvwgHYyCUvj+930gVJVy4HtStJr1E0ePMDDbmztJElWr1XLgB0Gp1+t4Uhw/dqTVbIQlf3bujBC8sNorhT7ne6NfzgARnXPoLDLJ99OkASoSMBQgfCIAJgGMEQe6p4TMOQf79pf4o6jRoiousuF+hby3c9Rav1G2HqTYIgpp6SLu7i3Tvh3bm36lmAccrCBF/gPCrd22EMIROmRCSKF8DowpbzhKkIvckbU5l16pXHKEd9Y3K5UyR+dzFyguOU/jRMe5RUmG0sEIyqWxUyfGpqe3ev2N3vbE9FjIXckXqITvAm45cBBMIOcF6sw4m+e5toZzDzlnSM7ZYqkz5IrpOlkAB0LyXj9aXb7T3txFh+DIJKkMS+Ug3NkeMEetZj0eDXU8aB5bGPY7M+OTYRgyxr72ta995OOfOHz46GuXLm1tb9fLQRSnH/rIRydnpi9ees041x8OCHF9fa3THxByGYTtm7cffPiR/iD+7nd+KBuTX/jC/+XBh84u3loiLuZnj+cGLYo40kmiAw+dI2u0g2QwGNhyyCCXKJM0J9Ce78+Mz8w2x5SkV196drxZ4caUuZoYm3780Se/P/h2pRz863/76//oH/7fHecXXrlQrtYPzx0axFGe52cePvOTP/XJX/uNP/ze9773d//u3zXGXL161Wr7ykuvVuu1NE0ff/Sxq9cWtdaLi4tPPPrY9RtLUvA8t1JKxjCKItToh6WtjbVhf+S0w6IzQ1SMezkQx0LUGQUQA4fkGEMyIIVK0rwWKjIMhMgd1cqlrNPbmwFDoWNQ2GT8mbguf1XK3z/78b+Oe8XdrbxidSo0cScnx5VSjUbj9P0PfO3rf/Tyiy++68knEYAR+JL3+31tHTDupGC+rxEJGUPGAB0iADEgYMiQhLMeA5+jxxlnQNporfM8ByAC54A5IEusuNyBgMAWlywRMUTBmDM2jROdAfcYAjhrydiinmGM1ev17qD/kY9+NBqOXvrhi3Nzk9bqbrf9Sz//81KJzGTa2o3trbBZa4y3urtbw1E8cfjoyfvur9eb/f4w8Cu1ai0eap3n8zNHxsem0kSPun3PCxrjY81QjZe4JA2MO2CMCSmU53nKk5Jhlo6szhnFgjkMnCxLyYOdrY2j03Onjp9Y2lx78bVzS+t3jLVSjqdpunOz3d5qP/TA6Uq9Fg2G253OcDicmp3IdB6nSaPRmD+8sLu7u7u1a4y5cePGaDSamJycm5u7tbyysbExGAzGxsZCz2s16ojYarU2t9q+kvOzs0sra74nMTfa7jG2C0Enx0n6viUNBNbZPLOcAUfiCMn6+kSrIX3Z63fCUilJEnJ2ZnLiXY+9NwwrnufFcXznzp3V1fuH/QEATIy1kiSRUlprPaVKpZLWWgiRmwyACp40MkIqWEbO95W11vCiQBBSSsUFMSSj72buHaTXA49CVugo7l2QThvztjPgA7vSvWa1c8V1JZRSd1/fBzm1UC0p4u5Ea+5BtHTFjcH2ZtF7zydsSAXE4jTjPK3Van65Moiz7mDAleRSemHgAIFxYEJ6/lg51Flar9dLChWHwe72+NwhRqwxPv3/+h//P6paKU3PTM/MrbfbfZtoD3cHvbrHlChj0fTcvy2NMb5f01praywRE9w4m+aZ4Kh1XvNrANBvd42xtXKNCxH1IxGw86++evm1S2SdZJLIsiBkjBmbI1lPiSMLh1v1ik1HWxubE636xMSEJ9WJEyeuXLmS57kQqtfrNZtji1de/8Lf+vmFhYWlpaVRHO+0d8JaJYqTwXBYazRYFCdZ+tTT7zt/6fXLl6+efODB//zv/7eOlbrtfKI5b5GRZQzAWpQMamWfbOYpJMEJzcxMkzPEHBHs3lDCWEYkUTKdv+ex9wy7O3eWFzurGw+fPvWf/MLfrgfVX/vVX69P+H//v/4n/8Xf+7v3PXT65YvnW60WC8GmuSHz9DPvffnlFy9dWly8eu3k8RMnjh575fy5c+fOPfr4Y54KlFLHjx+/dmOxXKkPh8NKpTKKIwDI89xa9H3fGDMcDoNa9Xd/9ytz84c+9NEfS7MoTzMpmB+W0pQxS0gGiZCEABJAmlBKSdpW64329kqTO+mrG8u3P/zMM8u3l8fHx4kwS9OgXLLWxknk+74DcbChvLtbc/dy/KYL+M+1oN9L6KPwdwMA3/e11r7vF+/F7sF/vftM3jTivdfT3vrkPyHu9YS/qKKZ7mqa/fvdE7x5KL539KBr96MDMkLIckNKAQAZI4TwlOp1u6PBkKyLRoNBr7O9sTk3M2vzLGdMhZVaqby8tvEb/+rfzj5wqtEa7wyGQa1ODkIVIIosM1xI5Cx3ROR0OhqrVpvl0FM8i4bD/m4aDYyzRO7/R96fNduWZedh2Bhjzrna3e/T3v7evJl5M7OyWhAodEVCAAWSEkEybIVgOSxLevIDHXaEIvTmf+AnP8oRenCIEYxgmLJEAiAJEAQBFIBqMiuzss/bN6fdZ/ernd3ww9zn3JNZVTRpSpTCXjdixY5919ndWmuOMb7xfd+AoJgJbRE8/5CIuFlwkqooWEa9vPPRBx+AgySKtre3+2neVuVwOGyNefTo0ZWr1x8fTL/2ta+9++67dW2Q2Rnzyp07d+7cAe9ms5n1TkgplDqZz370/gfb16/dvnE7VQlrN+6NVsvykwcfmcZ/7Stfj2Sak9jZHnVu9rKsE0dRJiDhWSSkc1zWDbONI0wUsmvL5SKNpWfjTB1JYG+41TLr9GO1mk6jNru6vfML3/gWSXH/2aNnj1Z/+Vd/9S/+9LuHnxz+s9///b/11/8DZ/xnn3z6a7/6y58/uN/r5I79g0cPr1+/nkTxf/N//286WZ5l2e/+7u/+3b/7d3/lV37lB+/+CBHrtlksFofr1WAwUEnOQrxx77XHLw7393Z6nRTZs7fOOBReRrGSIjCQMVZNY2IpB/1uEkW6qdhoJWjQ75OiJEtxTd77N998M03T+dn05ORkuXxojAlUlcCEDzlZuH+DM0ZRFADQti0KQCGAkL1HB1IIIZEAmTGM7/PeI6F1YVYegyA4R6ecB2YmIiCK4xhgA9YJRKUUIwFh1dSMKHBT9TrnjDEXdmzBFjCIjDtphogyfL4L99SXoPYX4+7F9rPGh7lzY4EvrJKM3gN7bNu2aZq61oYhOBu4oCMAAELHCN6BtUIiEK7Xay1h1E2jJNbWJFH+/MWLdVGOdvaz7Z1Km3LRroVxTjqQwyRl+sLnRAYKCQQihsFNAIjACJY9CNEYTYhSRd6ZumqV4FjFB88OppNZUzRsHUoJDMEM1urWO/fKvbtxoggBpXTO9bu97Z3xj955d7y18xu/8Rt5b/ij995brsskkvvXrm5v7co4anRrjGGEum0OTo9QQFlXy7K4Ohzfee31vRu33/7az+3u3fVOMAtCyUBE6DwDe2SWjCStJGICZufYM2vhgY2OJCVKRXGiIpLEAj2i7nVSNxxcGfSfP3n4/PGz3e2tt998+zf/xl/9p//s98HDi8npjf2r+bA/L9fb2+NiOp+uFt1+/6233lrM/vTFixc3b968evXq+++/n+d5HMfAUCxXq7JazRfFuiYp8s4giIDd+arJzOARGZ1x62XR1rUUGy4osBOAErwEJvaCffA6RfDIAlAwEgvpiS0gAlZ1Hcex0RqYpBDgPDOTko4A/U+ZBv/vLEJ8iRvBzP8TDQ/4X87277gi/9d8uy91x3+Cdrdx+8uTtNfr7ezstHXT7/VYm4iwLquzswlIyAc9kSUWhQUUghAFABITMDlgACaQeRrnESliYoNsCBAFCRDWesaXfMAwvYcYmBlDWuYD1Z/WZTmfzgQCMthW10CmbZmw0W1dtUdHx6+/cs1q++zxk+GwmyRRtV69/ea9OInW62VZV3VdN84Ib+fFKsu7X33rqzv9rTxKu3FuGl0v1/00v3Lryu2rVyXFEcWxSmKZKEGSQTjTtGuMWMgoTyMAAua6WlVVladRJAWTd4iCuHXau9Zo6R2z9bqsHVtd1p0o2h9tWeA4Tf/W3/ytv7/+b48ez0/OJjevXzs+PXlxfHTr6h4KWhUFAVjvO53OrVu3FrN5yFOfP39+55VX3nz93vHx8Wq1ytNk0O0hQF2stQcLYr1aokwTpZqmAiSlZPDtQqE8gAVk5y0iIlokJ0hmWSQ6WSLH/f5qMT9bzo131/Z3bty41jTNarWaTmdV1TS1llI6y8wshCIi51gE103gMOYBQTB6xyABgNGFZwE8kgdLSCikkEDnJCxi8my1CZ7hwgN77z0Qgd+wDwABHBOSx00MohCJUZzjzETkkc49Fr9wqYdn5OXMF+ALCA/8VHKW+Ok3zIWeGL6wUFKiIsdonFdKKcvAkAAa72erMlC0UAj2hIhCCCmkjGJTF1prD1m3P0RBUSf74P3313V5fXc7Gg4Oy9Wq1k3M4KM4yYlIANJP5ApaawQQwI49IzgEZg/spRC1bgVQaIab1oBhGSUfffDhi6fPqnXBzqEABGJmYBaERLA9Hp4eHVaxSiRKgq2trQcPHvzu7/7uvTfe+q3f+q2i1rPZrN/vm7Z+8+23d3Z22radTKdFVTKhA1e3zdbObmOdIzXa2b16/SZJuXul3N6+czYlFLGUJKVkQue9duyYHTsGjz6kYpbC2QLRSdMsSbp51u3lWZZGCkl4AhcpZGv5yl4/id9794fT47O9vSt/5+/8R2KQvDg76I7Hw73tpJs/PXxx/eo+RjRbTO/euPXtb//80yePHj66/7WvfuWVO3fGo9HZfOWti+IoDOvodDrGQdbJ+Yu0PjiPwYTSaH10dDyfLXd2h8zGG8/OCQJBQMjBDUsCC/aChSUglEBIUeSD8yfwdLHs9nvFciVI5XHqvffsZaQcsyBE+CkB+N9Nu/T/3wLwv32K8z9W/P5Z2AZzcJ/3l/jyG5ILgffWWW0EQZZExDBbLOKr1xbT2ePHj0GJ4fZ2nOVGe8sgpUQhOVBbA/kPQBIMOnkqgbyxTuumsU4zMyB6YGBkOLc3YEBk4A3YGDDGsKSs5ouzk9MsxTROkMEbe9G/E0oeHs3+9//Zb9Z1/cknn4xHwzxNitnsK2+8mSTRbNau18tVsWy1pUafLZZbW1t3btxOsm4/zROS5WrpyubW9VvfePuredJFRmIlQBAQsyfWzJZlXHrjausdKFJKKZSpTGVlNEQAHqwj4b3xBCilUCLiCF1jTbUq26pOhRh3Oq2zj58+/ZVv/4Krqv/6//b/+L1/+k//i//iP7/x6it//kf/4uaNKyKJiqpMorg1utPJ33rrrT//7p/1u72iKD788MOr16599atffff99w6ODld5evf2HfaehJKAlmnY67KI79y++cP3PkjyXiRV65zznogRBYAzbB2wQGicQYexlFGa5L2s0i1LUhglSbS1tdXpdJxzWuuirpzDWpv5ck0krQfngz0cOfAIhMgCBYMH3Mh5fDh1HhygAEAGB4hEICQCEbLYAKmIHiEEapQIgOjpfOIlO3cOgwCSCA8ZoG4aDLrgc2oeB7KVlOEAPPfiCNmcDM2JEP/gUhgO0PRlFGhza8mffoN9CZq7qIDRYyRkEsVZnDjP6NkwKKWcM5eCPaPYRERmjqKEPRrPIJVGz0K8+8GHMk9Vnhrv1tXaxgIkgjVZpCQJGViRDKHlIxCRwWgtGFjgho+Nod/vPQKyN2HMMAml0DV2Pp9/8sknx4dHrq6BFAEBe+cZEZzTw343iWJdF05SbcyV7TGB/8qbb7R/+7d6g2EURU8++fT09LQ1/vP7D3/7P/5fx1l6cno6mUysd23bJlHa6WQkxWgw2L7SuXLjloqjsmqLqpXLxWB4XYosiqIwxtkzO2+sc4PBwHijtW5065whoiiKIhlnJGOV5EmcpnEUS4EAyOAdIFusiJI3X79H4N//0XuT0+nNe7f+k//0P3344lEklUIYbm+fPHt6/9H9N+++ZlpjrL179+4bb7zx3g9+9OLFi3uv3nvzzTf/0e/+4dnZ2fUbt4QQpKKtra3Vquz1+8tFCQAEKM9ZowCAnhGEt3zw7ODk6HR3Z8wI7D16FgIlgkBQCAKZNoI5QI9E0gOJSHnTemCJNJ3Pbu/tl/MlgI+EbKxhYJDSaS0JN/bQX1zcf9ZC/7MQmn9jaPqcN3Fxlf5kMvq/hO1/ioL1J3/tf/vtZ0LoP0Nl9q+A3L8ATYMDAGRIIimEMMbUde2NTZIkSZJIyJhkuS6ePn5CaTLYGnMUgdMOScgIEYO6nQGZwywGzCMpvbFt1Zq2bsq2rcNKtXlHgICmAQD60HTbXBjGWklCAK4Wy3LVbOdJsEZwzkWRiuNYWxNFkYPqq2999fnh89PT5c7ullQ0HA1u3LyGyFrrtm2LujLAtqlqo+/cvvPsyfNX776WiaQqqnpVjPv9V27e2N/eKtcVAUmwGGaqekaPjrxQkfbCcRBMSUKVRHGciWK1QKEco2VrwTovANkBSkmRFGQtt66TxIg9JeSqWnWjpJgtvvr227/869965513GmtuvvrK7/2Tf1yZmsRAO5tR2jRNN81u3779zg9+KFA65x48ePD24eHulavbuzuHpyfW2tVqRcgqSqI0U0r0unnV+t3tLfZA4KUi7T177wEJyTMKIRmUA67bxlqrIyEFJkZ6a5RAEqLX6YxGA6WEs3o2XQJTt9d3Hqxjwc57aIxmG7iiiMjk0SEjkgDwQJ49ulA8CACwHihcQ84DAAkR7Og9s2fPSBTFITCF+tJfYMjMQAIg5GCby9UBi0gB+IsKmJnZeT731Qj94MtXsgQAIURg9ofuaYCIe70en5tmXe5mGbY/9c5Aevk5zq9UQICqqqSUgfDGzjtjbWvaugndb2OMd856EOBDCC+LYtDrChEVVUMEKpJmOfvowWe71685hPlyprWO8q4HDwBZFEckJJJkJA/Cg0AgDxLRG2uRmNE554AR0TNb77x1SkjnvNVNJ8mTJJnOJ08fPD58/mK9XAGDpC8kIutV8fW3X8vTuDvuD7vZcja5dmV/Op3+6J0f/tzP/dzu7v50tpjP5/1+P0ryre3RzZu363o9mUzqtkFBs8U8NrUD/vDjj994++1Xrt8ZjIatNrWxadbp97v7O/1gixacu2EjUPZZlln2oZnBHkmKKIoiJYQPnvEA4Lxtg5e1914IjJK4qso0Tb/1rW8VRfHOO+/Yx0+7t0fpYCCB19Pp9Vs3bVN98tmnd2/d7ETRdDm9vr137969T3788dNHj1+9dfcvffNb/+T3/3Aymdy4cSuOY9u0Usr1em2BCTdcAUQkwjC5F1EwA6I4PDw8ODh44827UgF6x95KIaUgJYgYCZjY07l7PhGFFRC8ZBKk5HyxuHfzjhAKL7zJCDw4/7Odnf8dxMKL6//f5Zv+z7v921fA/6Y/0c86/nIi9aWufwADITApgyEl+rqu67qWAtu6bKpaIHlryTuvW1NXk8mkO+j3Bn3jnUWUQpCKGAkdYjBXZU+EKhKREtQ2ra7btmrbxjnjzicchc8SXHzwPBwTUWsMbEgDwlq7XC7BgkRSJKwx3rFSuXOuqqqmaXaG3V6vd/KjE0FgtcFY3r3zSqfT0Vpr01j2TduKTraoyjjvpHn2T37390b/m60b+9fnkzNv3d3bd65fuWKbmk0DIDwggRCIAAFlBetJyDhOImTQjavbtioLZO5kiZKxEpGUEsnXFVX1el23qRCpUlESyUjmnnOdkGfTlG/evfu9H/4g7XX+8//sP/3FX/nFtNeJkvjeV79yfHa6PRz0spykaNvWGDMajba3tw9fHGVZNjs8eP78+bWbt27cuPHg0aO2bYuiiJTwjCCkAsrSuNX1eNgX52cTN4z0jdejAEQS3lurDaMjL7SUpYDr+/v1enF6ckTWsbambtazxf1PP3/19W92B1t5t1vXNQKSkAzoGGxIjxAknfOmGICQPTAHwigCADJymIXlPBExIQLb84ke4P3mw/F5Co6IgMwghAQUiOjhXDLMTMwkAfHldCfmjVgtRDfkS897BgAZiPIbyrW1fM4q3LhHnbeHN/ymkO79tBsmeEF/+aZiJiIlpECIYxXZyCMp55WSeZ5HkWR23nOY/R5FkRQqTbJut4/ovKsdehR0dHjU1OVwe6cxelUWHNqK3ktUwjlJIrReBCKFBnBIUxnYeQdg2TMCMjtgBwzMAjjENmY2xpwcn3700UerxdpqDUJJEsRgnSdGgYQA4/E44EtN0xBRt9st18s//MPvvfXWW1LK2Wx2dHR0fDaNVPqr3/nlKI4Xq6nWVinlwS8WM16TF/jw0bOrN28SkW6t5TLrDvf2rl7duxqhEASRFFKSxGBXRsBcrNeREFJGpGJAcT4OwxtbA/iQVQEAAQiJALiuyuGoVzfFbDW7efPm29/4+vOjw0+ffb7d5cHugJ0rmmqn1++Nh59+WE6mZ90rV1erhe6PrlzZ29raOj09nc/nr77+2uuvvvrZwweBVOIci+Hw+HjijAUpNyk/bnJAImIPnjmK4unZ/PjwsG1bFUVExOwkKiIIinbCYAbjCQgQGIVnVDJigyBIxdF6Om2aJpLKG6ubFsQG02NCByzhy4DzvwKC/lnP/38XUb6Uff6s8vp/xu3f9Hv96/w+/zZQ/78pAuF+xvGXe2YXDzxuhJU+JHPh1IAPZJZYRUkk0zRl5vV6XZWlc25ycqqb1rTt1v6NpNOttbagYiWRZLDfIUAmQkYiUkoBaO9aY1tjW/YBHYQLk1TYrKHnUDQAXOLrAUBdVrOzKSCkcZImCVrP7MPEiKIo1uvmm9+417bm8eOn/X4Wlta7d+9KSW1ZBMfAuq7742FxNhttb83myyc/frz6a4u6qlar1d723q2b15Mkmk+nWZISOwJB4GgjQwUPmEVxpe26mLdVW66ral1ZayWJPEsGvSxJ4iyXnU4q0szrxvmWJWs2CqSSQjhojdNVVS1WZ/PZ7nDUeJcl6c9/+xeOzk4PT09uv3r30XvvXtvazpPUIxhnjTEq692+ffvhpw/6na4S8ujoyBhz7caNPM9PJ8fsraSIvW+r0hjTHY6t1VHW6fVSh6C1ZhBCSMfAAehiTwwIAhkkYUQCPJtW66YVRK7R08npZx99HCnRlEVZFO+9915/tJNnXSISpIAwJBlaWwJGFIadDLAdyjAa8FwYtsmfGDaoNQUyPL8cZ4ns2XghxIUs2J1TUqSUAbbFS1UTswc2IQC/bNcxIGJgcfKG2hXeGgDOvaAvbpsAdUoprbX+fINzUjUz0s/oAb+sfS/3kgGSKI7j2DlO2qhpLSNZBsvQH4wpjlkqFjLOst5w1O32I5UQSElobCUirpt1o+vnH3xI3U5t9Fpb6x0QNXUtM9WJIvKsYBN9kQOWBOF94UJuxR5ocwczMxIaY5gh0Ngmk8nDhw8f3n/Q1g14vvCzZEbCIMeGbifrdnKtm/n8bH9nCxF3dnZeeWUvUqppmvV6HcKVIPWtb32raZpwjhGRw6QaQs+8tdMfjsdpJ7feSeatre0rV693OgnqAsEJtOgJQDAQMiFjJwlAl/UGvTcABEKgYKcLJkMQvAjEZtwVydqA1k2axo3Rk9l0tDX+yte/8XR25JE6/V65XMokbZ0lIfavXnn6/Pn+eCy8d84lSTIajZ4tV/P5XCn19a9//Z337s9ms8FwiIjb29s708W6LOvGXlwkLwMwAHuMk3g1X0xOp21d97oRCiQAQSQJCJkECs/EnkAgbEAc731oEaMUSiZrbReLhSSy1tVFGfVyImq9EUKElt9PXaB/6nX4PxZw+lNjz/8PVMD/H3+ff8si+Gedl8sckX+d4y9fbC9Ru/PhwcE84QKPBoCmqZq2kpRZa8uycNYy89Zo/OLZMwAgot3d3SzLtDGgFAoVjMk3TbnwFgKlFLpuqK2bptJGM3OYvWDZ+w3sBMCAG89z5wGcA2NMHMdKKQJYr9dnZ2fgIMybYzDsIUkSj2Ct1Q6uX79ZluXDhw87nU4nzZBhd3dbKbVsmrZtm7ZdV+VOmlRVdX00+t47Pwrfcr1eM/P+/m63m9dN6ZxhjgAwzFUN5QYACCDybT2dnZxMylXZ1q3TBjwrKSvCOouSJBoM83h/O05EV4JFxcTGaWs1qliCIPARQC+OP3z27Ks/982T1fLg8EU27Le2pVhmvaxq6lWxDvxeJtTWaq1v3LiRJElAUo+PjhaLxWg0CiNr5/O5FChVbB1zq7O8Nz07jbJ6OBxOl+u2aUWUSiWd9c45IkQLCCwASchIikRKCehavTib7mwPB/2+barZ6cTqdjTojQbDH73/47e+/vN5d0gyQpJgGVAQkXWGkBE4eDYTow+/l0f2CACbPYMHcIB+Ez3QWR/ciyE4UHpWwIAcXCatPw9txqEQQgggedHWRXZxhHA+geqyDGljkmFtiO4AIJEQUTrHDviC1EcqiiJiQmIAwWgdCCYGJlQkmJDR/9SZ2xe31+UODTEY7dE6o13Z6rKpdehwOnd1bxukYiFVlPRG4+293dFoHEepEGqxWBTlotPLZovpydnJ8dk0yvKz5VwzYBQTWFvVSdrvJiryXgJLABHUKgx07px0rlomZgeegJiAiEGCtLqWILI0BsPz09nxi4PZZBaAaiJiZnbIzCG+RQSdNHv1zp1yPX9Srvb390nAoDf87d/+7fF4XBTFbH7WNM2oP7TM/X6/KktmZkKtrQUXp3nazQ37wdbOnTt3t8bbdWPjPN/dHg36uW0q8C2xc66xjOARmcgLZEqSTNdtWbRFUenWCiGTJFOJ3NrrOGBm9t55Z4w2joGZu53OcnE8HG9vjfKjk7NE0Z2bV6/t7330/LOtvX5VFf1+19QVK3Htldsf/uDdt+pmlHaYhPeQZZlSqq7rtm5uXLtqAY4Pj/r9PgP1hgOxSVT5vOVGiHzuDuOZnVIpOFcURWssMKGQHDjPyAKc8CQBFLMCkMySXQSuZS+QHRELCQIbcGdFMU6zFoxu2wHESMI7p5Ri7y0AMAKG8WVh7x0wIIfnX+4B5Pn5B/CX9/wTz/zMQUuXtsvl77/Wxhs8avPH6BnAb1ZuoEvh+1/psPk/4favTiFwM5j05YN/sxcH8Mwev/BNw/ZTxVsI4OCnB2DH56oKeEkCAECHzoHH4J0PQRrkAfyfffdP1/N5N+8cHR5+/N6HKsJq/itbe1cmJ6eD0VCSGPaGaRQvnMOIUJBDCCswghfsYvboKQPUdQO6bdvWOBtER957692XOC7nV4/33juvSYAkAZ511ZbLAjywduA8W8fshBAA7BkdQH+Qa1NNTue3X9nJ8shZk2ZxwK6DMLSuW6WU0S7L8oNnB9DBSCldN4kUe6ORYi6Xq0xIaOowCIKJPAnYpCZudTZfn521i4Vg7ifSINdF3Vb13t4u+KZeLtGu8tj3eh1CjhVVrmmaijxlkUrTPJIilmJnZ8d6P6/W8+lZZzyy3lvvx+OxrkoQZLz1CI6dB2mcrdqq1+sMxgMS4L09OztdzWej7a1IUhZH1rs0y7rdvnXsUfZHQyEj532n05ku11a3UsVKoDEOvBckBDsEIPASKSKUROy8Na0aDBKVRCrpxGmWJt7qbt5ZlO3JRy/a1kgpnYvQs3VgvQ3LuAckYPbExN4jhYwLA+M9nH1wHMDpTfT1DJ7J+dARBkCSQoAQKCQjMDKiD7eQcY48eNoM52JgRvCel6syTNzbRF8hFImA0Nhwjo0J6E44QGrr4zSJpDLOmlY76z0CEEZSIQIpSReLGwMgoIrw3PHq8vJ0kagi4iYKAzsEVKIBcELINJfWLafz6Wy2ruqqbhx7T4KUVDJGQcxsvYvj2HjTWBMl8de+9XMff37/z//8+9nW2HjnEZytQIpuN+5mMgOfI/SkzIVISChmCQzsvBfeeyGUO1d5h8Y3ASqKsTUpJZGImlX9yUeffu+7f/b5J5+ZooxUysQEZK1lzWmaCsDJ6fGrN/ZTwrPjo5vX91f9fidLptPJ//Mf/PP/4K//jf0re81Zc3x8PBwOHz1++tf/+t/wxqRJdHT8XEqpouTzzz7tDscijh7e/+zXfuOvRipDxGK9vH3rxu6oE0PrXKU8WO3ruvWWu93uqD8Ej3VRL6azjz/8+PDw+M7tu03Veu9nkxlKvP3qzb1ru1ev7iNx05SN1U1VtLrpZfudhNv1MaG8Nu4gW93Uf/lb33jw3/346acf3rh9i4SodTW6fvXo8ZNW0NLYNIJ13eyMtu7de/OH3/vhO++886u/+qtCiH4C3molKM07O+Otxfby9//oz2/fumY8BwhBSmKU1upKtxYx9jFE0ecPH77/44/3r/66Usq6tl0v406nL9TybM2tSaK+BajrqpPEtq57kXCWAYUjOSnXydbWwjVnx5N+nPT7WWlLakWcKuesMR5RIAY79PM9shfwRSu2zSLvHIHflAUB+SaSiGyMQ9ykZQAUXBU4MDHCvfZl5hFazyEv6XQ6Zd2gkNa7i8zWe9+2rdZaCBXHsRBh1NMl5InZgWtdY9kxc5gldXHLWGMALpKFL8C/FynsxTMbzCAEuS9KZr/UH714cGEN+6XswTgb1gU6H47mNvPXNnN/N8ef/xV5uvyOF3trLZ17g8N52u2ANTofumTnT4ZIrogBLkz9NmvFudrg5cEXWwCfLpe/AGDROsEe2YAjx4Cu0Cu0vtNN/87f+pvvfO8Hzx98/u73P4QFvPqta1tZ/vz+g36n2+8O1rNlP+voWjOKzlZuiSq0MkmVF6YqRaN38k5CZCdnVbFk33hgQPSbcXIgUYjz6TfMHHw3HIAHH2WCa+29McbsdLdeLB999uHn40GeUDTu9ku/MAYiqZ4cHj4/mqcxNO16sTjqD6AsZkm6H0exlBTAZ2PMcrHY296ZnEy3x7sS4/nxDEq4enXf6Xbc7XWIPv6L7+VK9fPOj955d2dnpz8c9cej/Zs3VZ7Nl8v1cvHZx+9d2d7d6sv33v3RJx99bLXOs64U+PRh3u127735ehLFVbmanp288uqdqlxTKuNIxhSBd3W5jqQi9pPT44PnT2tvBbLWTdobLFZFFHU9uNfffP2zTz6+/cqdLptivh4M+603eZrsX9v99ONPhv0Ogy1W06parKYn5XKxns+2dncoSher5bUbd5z3g/EoijOH4scffT4aDCiKZrPpYDQqXUngwDSIjoSQEBGCYE8EKkqR8cmzA2LGPDcgSchl7VCmf+03/31isq3tpB2rjRKbeZQ7W7v8RQ5H0BkLJau2McYIIRIVBWw5wgQRjTG4sYCkrJcppcqyVEq5QBNjJkVys4CAMCbIfWHTLoEwiFdr3e31ApsYEdu2rbROkqRpTBzHi0WRZZmSUms93t6u61oCCee4ZcvMKGR07rwRnK2+tHmEtijDbXQR4ZEIEa214YYJDEE+txD0nhHRk5Bx0mFgoChOB7qdL5bgmZ123goPQklBBOgZGpSwv7NDSi3Xq3VZZKPBaGt8NDn1AolIEitUEXFCHAmQAiUhoSMCRCYSiMzotW6AUCApkogiuDSBc9zY7qBPTM9ePPzkvR8/uf+oLRohY2aEjV4s2ONsRH/CQxqph599Pj053Br2ut0cnf7Od76zWMzOzk4Xq2VZlqOtPE2i7e3t4XC4mE9DdqK19kiBHxYnWa87EEIoIQa9zrDfTSWyraUzkYhVrCKMtdYCsKnqtmqX88Xnnz/o5r03Xn/NtG1VLHa2t29de1sqenrw4uiZmZ2e3Llzo9tPjg9Ox1v9NGLBWhIyIntAUwObyNtc0CBJAYUCrNtmvV5LKY1nFrIoa+iOPaP3EOaW1HVdVOXVvf3xsCujCBHZeWbXybJOilprC94xsfDE0ntPUsRx7EwLxECstV4sVmXRRCp3jr33CCDJR4IVsGejWCaIxltA9uAZPABxmI9ENCtKXxUCXGqVEODAMnrD3jm4KLcva9OFEAHh/0JA8qhACZREHFrRznnv9SYPIxLCiw1sL6REAGBt4SeSSADQumVnPYK3hp0N/prWtOxTYzd0B0KIIyWEFATr1RpegvMbh1dGL2PEjX3DRpEAngEgiiI8F9LQZb0TB/UiX6rT0fPLZ5iQABhJIHoAdu7iSIEX1T16qxmRAEL+Eh4ziiBdBecdswAM6JcD8MZuhK2EF3gYnHNVvoS9M3Ok1MVJuQifEkA3JnjkhihOhABA570h9p49+0vQsfcW0CMIJD7fU7hfgTywAPLABOiBiZAtOsAwxMyB9WAdWU+Or+zs8Vtv50mcevruP/txJ0pIu+//yXfvvfbGdL4ejbaUiNiwzCJg9AAghWHPziFwJCgliJ1tdGtN68Hyeej9yQwGAC4EwR48M5JgZhZEznJbt8IjOdR1c3RwGAuKIrlcrq11eRY3baskNvWaPQBYY+s862dZIiSSkkQUqQRiVHm+NLqqKqihf21IhIvVUhg9n5yeHb1Ye1xHyb1bt5IkaZ1fT6ceOOp0PFGaRF+599qP333n3R++09b1vVdv3b59O43iqqrqul6tVg8+/ThKk6989e0kyw5fHOT9PEkkAUpCJQR5oM1wCxNFkZCJQl+Da6q6LsooS4UQIpaOvbatQyCJjJ4ZmDjLEmZHUiK7ti4Ho9Hu9pbWOkkzZk6SJG71wcFBrz+y1hblVCDFErp5SjLSTRNLMkIgcnfYpfPLA8F7jwSCBD55/KyqausgTWnY6/d6vcGg3+vk3/6FXxqNd/MsD5bDF4TiwGf6SRKlRyCJkiUiO2Cw2nvg0E0XkKYdTFk3BpFNa6uiJBWFe0iIkMqjEAo3Jn3+PLKIi8d53lVx6r1n76VSiVBxymmahsIXSALJKMmEij1Qo61M4tRaa/TGKc0z2/Ma+ScDMACElOECHfL2ElX1PGWFc9YZMwshEVERcSSjKEqzbDg02ll89sJaq6217IlISoFESshZOZsXq7TbYW+ffPrB88OjxlQnkyOkYCACcURJLLJEpYnKEikjBIWg0AtGwUAM5AHRWk1KEklG8MzeW+9BOO5nGXo8PDj64Q/ffffdH9UnZxDFMkmsdsgc3oUpZBLIgDdv3hyNRtOzszxPQz20WCySNL5145XxeFzVOtiatG3LzPP53Hln2WtjyqYOccIx93q96XRatc1oNO53e+PewGmzXq6aus6TXCklUMaRlFKAd2W1ms+nd+/c/vDHPz54cbRcLKy1TpvxeDtN06//3Lc6vY7WTduUUtoXz5/m+Stluc7SWEpJJDwHO2WfxLIn83G/d1LMTd0IJfI4ieO4UFEeJ/PpDHauArP3PphvTCdn8/l8OBgRUaAvtq0Jcz2jKNre3rbgjYPGGq2tNwbOiWGIKERUV+3R4fFsNuv3U++9tZ6ZJUmlBKJh55C8UtIiIwLCRrqO5+AEO2e1c8ojg0ABnsEwsxcYwOfQ6fJ4cZH5l9ZuFxcnIuaRQg63sPPes3PoPTHneX5+vPfGunN+QywIzn3cLr+Ucw4BvNFsG9siEaFvF2en+9tD65zRLjjPIKI1WnufxcnFfcGegyc6gEfGl56uzHReP+nSXFC+6fytfVjcvwirW4aL0OQ8BwgeCH3YWweEzMCBK4TADEAoSVwcebFnBCUUnCMD56gWeGZA9nyOc20CDANAXTcXpM6LNQEBqnUBcIEobL4Io4/lS+cyAAivRAx8HnaDHPCc1+TB+9CtQOSQQyMCIhtjEDdox0UqYsHFqfLomRk9sgWwjJbJc9Wux52hYNgZ7PQGsDvam51M59PFbLa4//TJtdt34iR3AEmSAYBAjKT0zjljFUMSy0gQGuuMtdZ6eGmDf7le/6mbcwFhBimlbtvlYh1whSiWbdvmvW6WZWXbMnOnm5VVe/369bpa9ftRFEXOOSllHMcBmyQheoN+xd4SNUaLWI1f3/3ln/+l3nh4cnC4svZ4cnrw4oVelzHg2299xXu/XK3XWkedTmc02L9+486tG+99+OHZ5GRvZ2t3d3fYH1Tr4snBi6ZpDg4OkjR1zqEUw/Fg/9rVxWLxS7d+ed0UCBz4RezZOm+0dtrUZcVKWEUtmyzL8jRLVNTJ8iROneOm1swoZYQovGMEsb29q1ScxkmkyqrRN3qDV199vTUWkJqmCZf3ixcvBmUjZHQ2X9x59V6SxJPJpNHWAzjLdd06Nm0pIklSCgDw1jEEWwz6lV/6RUTMkmQwGAyH/X6/P+wPsk63rDwRrFeLqqoAIE1TIUSIxJcD8MV5jKWQKsYIQ0qH4J1j59hqa6ytPHtvda1VJCKVJJGMkoTxvI3F3llnjWF2UkYAHkKjjeQ56oWewFsd+OGBZgQASiAwg/dprCJJApkEEvhYCUnnkyyVUkopZg585jAv+kubR/Ds+BJQdjF34UtGHHyuG46UANz8lxAbu6+Mef8XfsFYq7Uxznrvw3LsBDw7ebL49GNQSAobW8edeGtneDo5HW7tkEIZRUkadzpZv5t1O0mSxTIRMiaUDMKjkIAeCRgYJAM6y0AW+KIeB8qS9NmDJ9/97nd/+L0f1GdTiOIozpAJvQ26bQHgzystAsjzfLlcXr9+/ebNq48ffLZYLFar1eHR+taN62Hoivc+juNOp7O3t5fn+WI5C79hWZaIKKXUpu31eu+/997O7u7Nazf2d3azOCkWq5PDQ6vNDEUWJ1mWdTqdrDckRehc25T/8J/+09FweP3KNrHeHm+Nx+Moit97770fv/uDO6/euXJ1fzk9Q5/vb4+ubG83vY73Hp1DYAFESISC2aLTO6PxZ48fdPu9KzeuSxLGGLS+n3VmpxN7R3tj2fk8z/M8Pz48Wq/Xu/tXrly5UjVtkiQAlCSJlDEiJknikIVlr9EYt2lnOIeI7L2U0jXt4eHhZDK5eXM/4Dnee6FEJJUiX3uHyJIQgYHQB6IjIoJAIAHCenCtbgB0lmOsgl7Ys0MRevlARCH4Buj5wlz3AoxBRAJv68JbvrCekVLGSgkh2mL5ErYhUkQoCFE43W7C8gXVlZkBJLOQEoFBomTrLUu2Z9Opqa4CoWQGcGw9h9TBWuk9ChJIjOSts96x8wDgNYYmUPhIRESAzKBbfbGs03mP0yOISHkEpJcrfvhQG7IknC8ovLnhLV9OgM9LMwfxxXSy8OLnnVatTUCuXg5cO2eFAJzPyb54X8aOeDn/+3IoSs7xt8t7AHBWQyAFnde4G/I8XIhBmFBcxGhL/jwNYOANbgDAERAC4Ka3uUkMPIhyVW8qdc/sLTofEq26qPI4+eE77x48Pbh97Va9qv/gn/6RN7Qu6gePjr/2K38lTXMjojTJjVCChBLSttpbp6SMlRSEjm0Q3APQRSr2rwi9EAAJ5xVF4L0USbWsJ5MJIoaktqtUHkdSygRp1VS6aQlge7x11JSD3pAkWrOBkTxzWVVM2B8OdLmaN1VRF1u7W7/1d/727Rs30zyx3mii1jTam0Y31vuHDx8yc9XUrXMyy/JiHSXx1b2t508fg9ZKqaooJ4fHZ5MJEY1Go52t7e3dncFgcDqZzM6mg8FgMZ2tlvPOoGO9j4VEBvAurM+Bsqu1rrUrTNMZjfIsM1qbpk2j2HuvtQbniSicaETsdrvMHMho6/VaCLGzt5s+ely3mg2bxrDzsYwI2RqDnh/e/8y0WslI5co72Nvf7XR6aZo++Ozj4ai/v7+3s7Mz6PXD0hQnKlaREBifazWdM8aY1WK9WlcoFDMC+ChKQlxyzgghEDcwGDNSmHtIUFeFEJvxGEGkQwzofRIJY7wEz4heQKxUv5u5ThrcDAHAWqu1tsYEejJHBs4Rr4uGDgBEUgTUJxQKzN5a1zR107RBDg7A6/XaWpMkqRAktbPGOxSkknjjhCkFM/NPu/IQwGgTvhiGPFqgIMF80dwKzSMG3HiOOOeYLTN7YGDyIcFH1LphBCEIhYIArBE5wVv7O93T551hhwnTbpwOOy20GPNwNBYSoyhKkihN004n73QzlUYqJpIM5IAcUiBueGYIF4r3HhgEbebES8RHDx7/8Lt/8ed/+mfl6QyTPIszb51tDTKdy+wFIgsQgfkjpTw9PS3W66JYsG2/8pV7X7n3+rXrVz/75OOyLE9PT0OkybKs3+9LKUNj3LEvqyqwfOuiHW9vff/7P4yiCDyj53pVzCdn6+k8QCWVEEmSGD2MhJSSyvV8MT3ppGJnq/fa3ZuC7PNnz+7f//ArX3nr61+/96ff/Z4xZb8TezZZDFd2ttfzeZyI2dkZIhJJJZM87wqVsdW6Kce9fr0uUDvFePzsxfPnz88Oj8ed3nS+NHXD2oLziYp6na6Ko7Zt8zy/cuXKZDpj5qaptdZKJXXdHB4egiRGadiHAByyy+D6KaVsESeTyWQyCZIta621VkU+kkIKJO/JWyFlaFPgy5QUA4PdaVOvKqSqS1GeZUQgI+XRCkFAQSyIFwEYEdkYAODzxkN4AICMUgJKAJIi6AcCKqW83FAXjNbnDH/wrLUOVzJ8cW+NkUqFO6ltWm2MrerF5OT42bO828mSlIHBsxBKIUkhTVWRFCQkkEDnBXAYuF2vKlQJInqtnXMgBIQFOorhAoI+f+ARVvP5BTYAP9EZvUjnxfm8r4ss+0uba182Vi8/UCqSEpXC0LS21nlt2NovTT+72BaLdWCWvcS9EOFnTUtDb+paXCQWl0rh+dkUzkvjy0jD2XTqETbMvksUOSmjn6yAPbi6bTfHhp6/Z/QMzJ9/9EkaJ/c/+6yT5deuXI0p7WaD1169ejA58Q1Ecc4okySLlPKAkkREwnkm8JEUkZTe+3BJR1HkYePB8q+jOmPnIilta2VK6/X6+PjYI3jmRutrO9uurpum6Y+35mVZllXeEeWqWC2WIQWy1gpS4RIFQY49ScGEHlizU2ny9jfeJg+LclnbJkkzlDQcDzhNIwDJIpKqyx3LYBG198vJ5PmjR+RhNp/OZrNYqv3dvddfvRtmxmRJUjVNJIWzej6diNdeIeR3f/DD19563VqLDOwcaxtFUduayeS01+0aZOXN/GStm9Yja28VCSUlMoSZd7zxhQKB6L2vqqrf6XrvF4tF8F7W1hBgnKXMLIS4ce06SXEymXfzDgrx63/5r9x55dUoSefzpYqS0Wg0GA1n01/K87Tb7cZxDJ49OwAgAqcNALD3umlDbq1IsODBYBBFkZKxkEgokdgab2KBIEgAgmBw3gESh9GEVctxHAtArXVALwQRM9dFKYHTWCVJYlqNiARsjRbMIvhwSOmj6EKUC5umsg83Y8i6HHvjnZIS4hgSlcSZZ6tbqyKRJSkSRyoxttWtDZ9KKpJBwRbun6Zpqqpyzl2YQnx5Q2Z2gZsPX1wdkuRlpvxysWCvW+PPSwtEBBQoBRPMJmcgQgtZEhFJoZRiAdP5GUaEiuu2tmgjKXr9/E58M01TITCKoiiSySYMJyKJvEAkEOCJnWAX6iNmiKLIOI/OIQrJ6JzVTVOU5g/+yT9/+MnD8nQGMu6kHQ5uFsYroRCYOHjKBL01EJKUcnvUPzw4ePbMfP3tN6WU7733nork1tYWM7dtm6ap1lpKaYxZLpfhfDjgqm3iNEPEuq7jOC6KIixgy7PZc6bVYlmviyiKWJDVpqlqW7e+NUqKo8OD48PncSQ++uBdq8uvv/3VrWH2L/7wD588/GTQ+9avfPsvPXr0qF4v807cVqs163d/9P3BoNe2LRHFcTroj/b2rg4HFAtKFUVCCsd5nBTz5R//4b947733OlHym7/2695Y07QcmEjMeZ53u93QutZar1arLmJdt1VVbW/3+v3e5oID54FDZelD8eddWzdZJ5dxulouT04mVdkkKTnnvLEBYFQCyTCwI7BBrY3ISIznPkQCREQSDBurdVorh0TIsScClV0m7rzcYkrOl0AAB+CAmRHY6YoFEEqPvjG+1XVTa2PbtjHOG91abZqwd5a99+ISmyEshSG53NnZCUBOp9MJ/krOOV82f/5HfzwcDvM8D0tQON45R5uKkKy1bduG+CSQ2kKncQKAVVXa1pBABHLW9Hr9DULmnPfsnEUPFv2iKICAKEQxPEfR/PHxycbUHEFKJaVQKhKC5vPFlwhS4a+yLN8UsfwFfD1JEimlFBEJ8A7CL2OdPnx2uKkzAzd8A4JjaBV8KdYCgNN68+NvngUgQoBESUQW8AUZBgBEUUTncknw7IHZeQbKuh1GIBDBcReIBUpGzw4YfXhMIBg9eGQEis7XK96g9957ZEijVJf6xtXbCPD06cH8bKmUeu9HH3e2hpDKk8ksGu3s7cTeekSSgCIIKARlkRKIzjSmbZBYKeEBAo0Dz93Qfnb4JfYslWyNxgTWq9Xx8TEwee+aphFCOAAGl+VJlsZRJIbDYVEU3kMv7zlwji0wt0b3k16WZcZapsYTJp2MpJivl5TFvSSrijUIIEm1qVFAnCcZSrQ+TRLnQTvbOt+ui6ODw2Ixc6bd399/5dbtNE66eUcpVaxWk5OTuq6bphmPx+vlip0vV2vTtI8fP/bojTEE4Iz1rUmSxHs4nU8pitN+d9DJjudTRUJIIhY7o+EnJ8ebJqs2ToAAlLQhHG0AHiWNMUVVtkYjopBCEHnrBGASJ5Y9W0dCvvbqa9ZxHCspxWjQA5LeudOjwxeHz0PPS5LYJOiSIiEBfBzHSRxLKaNIRkIys211XbVCSUnCAztjG92aVhtnBdLF89660MSRiphdnqeRlFVVhTWTAJ1zSRSv12GisPDGElHoEQghAjYcuA5h6ZPnGdsFDheQJO2s8aySGBw4cFlcO3BsWSVKoqzaKk9yBy6N0ihNi2VhrZVJGgu5aXuXVbFcLomo2+1ezP39UgQO3zwEfz7v5WAgNMKm7xvuM/aemSOhgnw+oIghdWfE/rV9RvTeW8/hzCmlOBHa6e6oJ2Npa9Pv51knd6D3s3HTNEJQrCKlVKRUomQUS1SyRYfopffSOQGOEDcdorrxxrJ1hNI6v1wuX7x4cXYye+8H75rGg4wlKdNa9GGiwIa8HaKvZ4fgkQQRVVXVv33l7bff7vfz/d2t09PTf/AP/uEf/8m//D/9H/8uEU2n0ziOvfej0ajX6yklTWFICkDU1iS0mY9BUrStiaQSgIvZDLT12rhG27oFJaxz1plyuayrMonkanZmmnI8HqMfPrz/yeP7n0SxvPfa7bqu/+K7f/SXf/U38iw+mxwlyZXJyXow7BWrNbJfLBZSyiRJ2rpBAG9tkqQMUK9XptWKxOJs+vmHH5cHGoc6lVEilTcWGQRga2wcx71ez3svpWyaRmu9vb3dtoaI0jS9fv06irg2bVnr2mhrvRBCnA9Cta0WvUGSQLGcn56eLZdLwDxcoMJaZBDEilg7y15isLrh0NLdWCkIwKa19bqoiyoxUKvIWh3I65EKBIfNdnEbhITvS+UdANTrFQIDo/NWt6bVTVO31pnlYoUEhEJFUskoipWSG727O4eS9KUAf/z4RchFRqNRWZZFUXQ6naOjI0aYd6ah6+89K6UQsW3bUCw5y1VVlWXZti0ASFKJjPI0QxRFsdK1FgIRhdVtlnUAPDMiO/bo2SKTB5d0ukQQmNsAxOy8B+/teLwdwDQATySlJCkiIXD76u3w/Jf23W7/ghgS9iG0lk2NGLzUnLNsSVr0zpsb37r+E2QogYjeWv6i7jD81Jetal+CGUGVgYiXKuZQBxtjLgr9kBQEqMpBqHAFEIc9MgFxU7Uh9IbnLwJw3Tb+vBbwjsMyxMzFsmnbdjAYNE0jZWYc5d2ur82qqLv90f37j5PR9t7du21Vc5qg9eRZISRKxpFCtk1bGtOSCPTLl3j7RfLxU8MwQtCJktMGPRbrajadhmtaRqqoq1hALJOQvaVpGpgfxNDNO7VttIVQOA6HQyC21ooklpFSyI3VZ/OzdNDppolxLskzFjRfLaluM5SeSDB4tk3VVnULUrVGF0W5nNl7d27tbA16nW5d17PptFytTatDnBiPh/1+V0RCSHl8fLhYLIpipavaOScAvXUhojAjOF+tCxGpLIklUhxFhW4ePnrorY4ERUJJlNY64xGRhCBgFCSlDObTkRBSt8Y5n+c5O5jNFmmSkxSTyQSlUELWrX7y6PFitZ7OFkLFw+FoMBrGUVqWpUqU9uyMFYhhlJDWrTM276RJksQyGJ54a8xyuZwvFvv7V0FQoiKVxAKwtcY0rXbWaSPjKJbKI3hjjXcCUAgsi+VoPEjTtGmaTXPas9b6zdfvnRwdBb01O58kSafTkURnZ2eRfBmAA0QfLv7Qfg2RK2ThrfPb+/vOtOW6Kqo1eLTeIFPezdpaG6e3xztVU1rtZCRWi3WaJ9L7ID4V3oewL/O8u709bhr903STPpAvwgUaRZE4n7x7wZq+CM8heez3M2YM8BoGiI8EEK6LtXG+aZpVUVRVY70TQnCCqqvSiJumLsuiNxx0OtlsPkliCSyVoCSSkZSRxEiSEoIIEMA7H4FX5FWwZXeA3nPj2Bi23iM2tT598eLzDz54+OBpuyriuIMiburacptlWawi41oByIAUDFICMCiYiPI8Pzs7C1XY8fHxN77x9n/1X/2Xr9977eToEADKsiSSdV1HUaK1bq0GeolIMKEHaI0GAG1AKBlFUd1qti4SUpOt67pc1EzovSMGb3UnS4FdJ0vm09Od7XG3k7I162K5vzdumsZb8/lnn2xt784X07roHp8cSbo57PWFxGG/T4QAaJp2enpimjZJMku0WCzqonTaNFXN1oGA0XCYRnGiIvCbSiWQ8tM0DQq5oiiapun3+0VRTadTKeOiKAajjDVrreumDkbigZwvENlaRIxFXBi3Wq2qqo4TAQjeW28NMAkEAoeA6DTJSAL6TexlAAYH0sP8eDI5ODbzVdNZCA9VXQRL1LpYB+1voBJRECIRJHEaeL1f2APv7+2AsxsdvRBxHHfiRMadX/7Gty9DuBsCPwopQ0IJ3lvnNmQ9ZpckWVGsiqIaj4fL5XqxmG1v717bueaci+IYmFutI6XyTk8g1W3TVA0QsvOttm3TWOcipZRS68Wy0+kIlEWx0toqJSRKY9o87wJ4gRKJBUqiTe/DM5IIJCoAJs/WO/BsEYRna4133rB/eUwcpQybEO4dhMcMLrCZAxAXjgwBddxhd25xemG2AwB1XYduALFARDpnnoOQIH5KosPWh1AKl+aFAyJJYh8EgB7cy3VASYmI4jyuhbKYBUaggi39BjRzwOzYMjITECIgEwAjIzMjg2utBwbPzsOFZ5/3kKZpFMvTyXy1Wr3xxhuTyeRkssx7velqkeedg2cHN15dovXGaSkkWCOcY+BYiEQKMtaa1nkjpAoJwkXE/VcHYABAzwIlOwbPpm1t2UhADxDH6Xq9jru5VOLs7HSxWIB3JyfFwcFBlsTGOB9Y58zBDKeua8s2T6LWaNfWYbJenudlU9dtg5IYfFlVylipvAKVpbkAbLUuilWUdiKllJS21q2uP/rooFwXcRxvDYZpmgqkuq53dnayLJvOZ1Vdvfrqq7NPZs653a3tuiiZWQnJzM5aZ63zoLXuDYYkRJAm21Y/f/bsv/+H/92zz+f/5//yfxvaH+C8dxYRg7jOX1r0nfeNbo13IooTEb94diD2RRzFDyaPu91ufzRuThtkf3V/b2trq2mN1rZcF9koHg56B0eHeZ4Ph8PBYJCmqXO2LqumrV599VViMMYY06pz5lpdl8+ePZORGvT6Wzvbg14fCHXTtkYfHRxGSRyriBGcscZZZCBCa0a7e9vD3lA7bRrD7Kz1bV2t1yV7HVjrRFIIVAjG1G1VQqwEp6BIkVJS5HEUZ7E33nggVjKWeZLLWBKTYb9344b27hRPynJVluumbQUREXfyPM0GN65ff/7ixcMHD9ZFUZXl3v6+JPZhNoSUtDUcDPu5d6CbKo3Spq2WiwUSd/JeuKU73SxVg3ALBbjSWsveklDADhGVUsESZdMgJFJKLZbr0Fo2xqIgJWNr3c7W+AfvvPvJZ59+ev9zQimEqKqqBv0f/x/+d01ZVcVqOOhHSharxf72Vr/fnZ1NoyhKYyVJCAZkEMFMxHnvGa2RjgUxEaFH76GpWnS+bdrFbPni+eHjx4+fP3s2n1V5NmBPzBypCJjZWEaIo8hau2GleMfOETCyB3aLxeLzT55IIb75za++8dorT58+zeOobdtOpzOdTuu69h5u3LpT1y0AxHE8GO189PnH/dEQBRlnZaR6w0GUJq0FpVRVVd1Ox7SGPUikYa+PRChISoEATVOtlstuN7979+7x4aHTbb+TO6uBrdFNv9eZJIqdev+9d994443FbH50cGh1OxoNTGs49CNAMPlitS7XRRQlmGZCCMu+apt+v79Y1Kigl3cW83lVlIrEcDhk5m63ezI5PZvPAEAptb29vbO3/+mnn969+9p8tXTOff7506xzKmIlVIKESkkGcNpYa5WMgamp2ryfq273/fd+fPKbv76zOyyrslxznKV5mhatUwixxMaaelEPruwZw8tFHQsUiEVVQdN89v4Hom6V8e1incfJIO545Y0xe90xM7NHJCYMsRtDmAk8xlC3bWQq4Nt5dbE4WnC1b8LC/uMffBCKcq21MUZrZy14D1ICIhASEoe6kD0ysCBBAgQpFQklYxUJQYoENG0b3i/IdRwgevYIiUqEUlmSREmaqAil8OwqbDqdLngAosFgBEzWadMY7/1ithQCpYyUEgL9xfcSIIKFXpA9hIpZIjnnkVl4RE/eb5J6Zrc268uV7kXH9KKGvvy/jHDZYhY20iyBiN04vxxlA23DM4OHQFsDAGawdhPzoijClz1dDwAeHCPHvTyE9pAD4cZBjy961Yh4YdMRWI+EP7VXrS5OVtjCagOMTEIAMgoAQCHSNCGhjDGkRNbtqSQ9PpuqKE6z3DEnSRJFyc4o/dM/+uPKmb/y1/4qW5tLoatiOOh100xXZbNagbFSSuu0dpbxQif1ZW78l8IwIsYyXpxNd8fb60Xx6MFDiCJbVkwUQBrv/Wq1qpo2/A6EcOv6rX4v996fzE7bpl0sFsVqrYS8e+eV2WIORE3TpFna63eEoOVy0cu73W6XrJs8f35z98pseqBJdPevPn3xvJ93siSL49ijbNq2WhcvXjx/49U7w+F4d3uv3+9LwOVy2ZhWCNXrDZ48eWK929rZSZNcCPXxx59+7WtfM63OssxZG/poTdMY6zv9Xq1b29Y7vasBJTp8/uLF8/lbX78SSeWM3dnamp+e7Q7HSZK06zLq9tu2lVJKpcLxd+/enS7mz58ffPrpp7t7VwKY9Nprr63X64ODA6NdbzBcLpfegzbu5OTkxeGRt64/HFjvr127dnRwsF6vlVKAXpEYj8eHz18ksZJSat00VS2lHA6Hg2H/5Pjolbt3nTUPPv88S9PA28jy3Dt7droURAywXCyMtaPhsNfrPH/6sKnWendfxcq0xlgNjALhycMHw9HAa3NyfBRFcb/f09xYa65f2Y9idePajcFoUKyKoiqKVfHk0cOt0Va3313Ol2Zt9t/YGW2NPv340/c/+vCNqpivi5PDo9aanfFWr5s3ZbWYT9/9/veiNNkejdNOvl4sT84mWZxY08rp2XGIlBd6vqCrWS3m1tqmaeI45lR775um0W3Z6fQu7oegHw+ma0FL6pybz+fh3gt9lPV6HXIZqzUARGlidFOU9eOHjx7e//zxw0f7O7uLxeKtt7/25MmT/VtX2Pthty+EQAHOOsmIxlSLRSwoIowAiZkcE2AkKSLlax0EogIIcUMTt8ZvD7cOD48efHb/6cOnk8m0qirSPIiTum4RFRFFJAL+4Kx2zkdRQsRKRo6cQW2d0bXWtrl567pEvVwsVqvVarVyrn3xZPL5/c/++m/++6H6b9vNsBRrbQSxUqrT6SSdvNfrsYo8MBLVRv+tv/Mb977yloyjtm2VRwAKCIZSqmrqujJExM4yOLaOmfvd7nyuq6I0tp1Ozpq6vHv37ttvvfX++5+/du/1NE2fPHssSCZZvloVHjiNI6CgBA1q5qAscKdnE6GkiqJ1U9kSgKE76Od5HvgmQoi2aQMUQ0JY5z7//PMHDx5cuXZda312dtZa07btcJihiCmSKJQFRiR/Xvd457I0C/qYXm+wKqYff/zxV7/2Bls2ZKy1HSnzNFo2moxJZDSOclNXbVMrcHHwzinLxfGpYlaAEcmISTpAduAcOWjrhpnRMxNKJBCEni37C63q5T0AKImAnph82IMDBx79Vj4Kz1z+5wE2roKA5zxoHzCQi8r6gpgVUMlW6MA9uYSHC2aWIpJShnaRDJN2ADy42WQKAkPXVgjJ7J22xmqB4rwOV5GMhCBEEgjkYFPwBSg27IFN2zByMPIUYXIPABNFUbQ5+vz48K+tWyYggFBsohDEBAjatJdxY0lCkKBLNk9fCjzVuvTnCmxm9s55a71zVau/XAsieuSyXDvYyCLOm2cioCwXhTLChaRbSKkYX77CxX65XIbOVFhbACCwtfOsA0Dee2Nca4z3npEA0W36wmgBiBkjJUgxuHE6XBZrISmT4vMPPugPe/e++pU5+hu3bygE1zZtXZm2BudCge3AhQB88Qv8ZCn8EkphjlWkUQuUq9XqxYsXoHW31+OyXJdlJxapiqWUUrrIOyFQCHj8+PHNG9faRuvWAhM7qOsWEQe9XiRVZW2qpI1kGsWzydm1G9fdRqzptPWHh4fbvd5Ob1CUZd7tIFBRV3XdBj2glLLX633wwQff+Nrbr77ymrV6tVh3Oh3wOJudAVDWybe3duMsPj6dzJeLbqe/oZ45F7AExDCZgMH7Xq83K1aT6RkApGlaVRWdi3yCoo+ZA1/a1a3WOk3ToiiWy2W322WEVVlUTb27t3dycGKt3d7e1tY1dWu8G4/HJycni8UMURRVvVoVzsO1K/tt265WKxVHnm0URVvbozzPdV2dnZ0dHr6Io8h765zDc3zi4aMH3tvxeHxynChSq3IVy9iBs62VsWyrtrVtJCLjzWq+cuAWZ4M4UWkclUVxgsehc9Q0jW211toZu16u6roWQuxub4eRssVqBcjz6SySajabTiaTnZ2d8Xg0mZzev//5N7/5zf39vQcPHvzzf/4HURQVRXE0OS3qaufqfr/XOT49evedHyxW82F/dOvOzb3dbUYfRzJLZL67nWZKN6at1zJL4gtGVVVV6/XaGENE/X6/1+uNhwMi8t4vi3XTNGmaOt2atg3ZqDfGOYfeSYS02wEArZ03WrftRQD2Rm8NB3meTxdLIur1u0DU7ffGW0NGT0Tf+Llvvf/++9/++Z+ry/W3vvGNR5ODuJ8JxVVZM7usk3bylAiYWRIigzPWaQMM4BAcdjAi2jBdAciibzyiMx++88Hz5wf37z88PTo2xgohgMl7zqLMOA4WS0QUSRmriADLsvbWaNGG5T6Lo7STS9eenZ3led7tdLa3R+PxuNfL/I3rQcuplErTtG2Ddahr2zbvdeI4Hg6HKk0Go1HtnAMmJddl8Z1/79eyNNWVtk3TjzMSwljrtBHxhlnnnKvLstV1LAXRlrW2rmtkv7U9GvYH8/ns5HhiHcgofv2Nt6ank6PTSS/vGAdNY3rDgdYtECrBzCAQEMl6ttacrRYySzBWbNvx7W6xXN+4caNpmtDkiOO4bZplsQZBaZoqpZbL5dHRUX84CnNdVBIHYnOexaiEB+G840ubZ59lWdG07HzaTYtK/uAH7/zmX/v3YimMaZuq6A1HeZaoZcmmjmKFsVpUpbQmAvBNQ9oIY6vprJjMUgfo6cLTKnQuYhmxRwQEj1IQAgEzcbBbAwxOL+dCFgCviwbACxAh3Dpw6NGBEwo9egTh0QOTR89MHs+tmBg5jHUDj6HVUlWhFyslCaGkJCKJgiJUCEhAGDSroZ/KrCvt0RhsiAjOhbMWXWlLJpa4eR1E9padNwEWViJSSkQiUkoIoQTBaroECP1OH7rCyMToY5WEZy5ISSHgBppSeP7irxi9M/4ifF/upM6Xi8DJ2EDB58YFF+MEvrQREyGF7wsIAbAR6C8KXLjU7mX0q7byAERSqigOMwGVEkI4bV62ivFl+kIkQ/J67tNnQqDNsizY216Q48LniaI4hI2mNdQ2WmvnX1q1CCHIO2AilETE3jtjq+UyH/R2BoPHLx4/+vjDv/Tz3+hmcSYl27bRpi4L32pCFiQA0bvgbfkzMecvZSrecoTCNO3h84OjF0cAkGXZarWq69r7jlSC0QtLZEkQIcPR0dH+3k7wKYuiiJlX84Vt7Wgw7Hd71XQaKSWl2hoOXhwfVcVr24OxiHBt3LX9K7osnPdPnj1TlreHI21NUzZVVSGIJEkRRZpmf/In/9Ja28kH21ujum4nk8mwN/zWz/38hx9+nOfp9es3q7b6/g9+9OL5YRQl3oExLvCBjTFBX+oY2FEmpYqi6XKhksgYc//+fWthZ2fHW9vvDpAJmXqdfifr2lK3rZnNFkmaE8nlco2C6rqtymY6nSKi9a43GC6L9XJdaK2Hw7Fj3+v1xuNtFSer1WpdVuH0aa2//4MflKul6PUG4/GVK/sIvt/rFMX68OAAAKSUiZJKKe99Xdet1mmsBHKkxNZo0Ov04zQiECqWL54dkMQ0zqw3xaqUkejmPWa3t78bx7EiEcrLuq7LdVFV1dWrV4uiePLocbkuimyVxnGwLiGiJEnKujo6OS7LUijpgVUc3bn7ytlsKldLkqJum8n0bDQafe1rX7tx55Z2dnpyFil5dW93a3sYkYqUnJydykTFJBGy8aC/szt2ra10Lfe2R8wcbsKyLOfzqG1bIUS/38/znDaTCZhti94geynIEAW+D5+LhqMoevHihdY63Nha66CCTdOUgsVSURwcHLStUUmcZGma587x0ydPdNPaVvc7Xe9sEsXD3rBfrmUUCYHkwTpDmjVXgQIXej9sHVonUCiBsRexiqz1utFFU5dFvVoVq9W6rNsPPvhotSxWq7W1XsmYSLStaWud9VIRbjZJBIIoEMfs1mjY6jqsBaZptam0gaptlFKpitj7pmmOj48XCwnWIMHO1lgplWXZfL4MAbgsy9H2WEqZ5zkL6na70LZIFKXJbLV0BE3bmqYh70GSA7DOeWDbtkSUxJlzbj6dTaezSMjd3V0VJ8PhuFyvyqJNkwhRLperpvVvf/0XUMjHL17MF0WnO3SePCljQVuWcmPt4ARLota5pvWNNTJPrYD+ePg3fus/nJ5Mrly/9v6fff/G/l5/NIyzNAl+ilKmnbw3HKAHazkASoGOt1gsmqbNuxDC7bm2C0JPTpIIVaRzrq5apdSLZ8/ee++9v/Kr37aVrqqqrkvZ6SsB3mn02pXriClLk6pczmdT4Yz0vlmvFEMmZVdEKckwcBhJCiKn7WWwNOjrfxY8iEz9bvQl7gxvHJc2uOJ5qwq8t8SIIgxdCIsPCKHCvZDHyReO18b61gOTjIIMJpCIPGPgKSdR6sGDZwMInoONhkdgZIfOM1sCIgfg2UEIwIBeQIvIAqUQKIQSwM54vBQ4L8LtydGLi6D7pTB8EapDAA77JErDM1/aZ72uB3ehe76QXSkpz9W452zokAp5QkQRtOXBT8575/1GNvRF+ZajcJ9umCmRUlKEFhi4C8YWg+ONhIkAqrK5HMUlklICAFbzRThxoba7wOcCn8h7r53TWpvQ+EYRxymSdBtoxG/0qd4Pu2lM26Sk6mZPn7mnn3928uRJmijpbdPqpq5d2yCCEBKRAnZyUZFfvsB+EnwGAMHgtMni7PD47NOPP2mbhqJIawsAnm34ERwHCmGQrwMzJ3HW69nZai6V8qynk9l8Ntse3tnf3Z0ulsYZcHx978qTw8OzoxPf+jdffZ0tG2PZo9bm+Pj06vb26dlMMHjr2LIQcC7Nd7/xV39zPjv7w3/5x2/de/3VV167du0aoVSR+M53/krVVgdHJ+++986PP/wIBFy/vtPpD8rlzFpprTXWhuzKATLwqlh7gdqaVKYnJycfvP8CCPb392fTRZ7ngQA0Go2SJImiqGjXp6enSinn3KpYg6Cj4+PjyemTJ0/qVXPjxo0oTfR8ppSy3hVV6Zy7detW2slHo61IxWez6cnJhJk7nSzJYkQI4IduKwBQSuad9PXXX83ztJvnUspgcROQ127eIYFG27qpvGNnjXFaG9jZ2UqzpJN3nbd11eSdLM862rR5niuliKFt2ziOkyRJojjLsrqug3ihaZrpdBpm6njv5/P5K6++WlXVcr1WQjx59uz+/fv94bAqis/u35dE27u7zhjHHPCe2zdvHZ8eTY9P+518dO0GCpidzYtq3TZ1kqpISbZGt80g76d5dwg9+f6P3gnjtLIsE0I45+I47uapt3o+rQIQ1Ol0nHOrxayu2hcvDlerdV3XwRIrWMImSRL010qpwWBQVdXh4aGU8urVq1mWTk5P4jju9bu6NbVuhcD+oPuP/off+d4Pvt/t9herea/XO5ufzWaLTz/5ZLpeg8RurzPaGqbdrmPnfEsC8jQNE4UpAoEkUUoSAqXTpi2a0+nZycnk5Pj0ZHI2PZsXVW2cd449CyEjJOkBSVKUCkGUJipPO0KRt9w0VVU1VreFsd7bJEk6aWKlYOZAZD04eO7a2ll79erujat7V67sSmAksNZKKTudDsCGDLJer0ODLVFRaXWSJA2wF5Tk2eHx0eTsrN/rRVIQUmONtq23OibpvDuXVDJJ4YHPZotHj558++d/YXRvsJxN79+/X1b11vb+q3ffSNIs7Q//6I//9M/+4vtpmiZZ14MAio5PZ91uF0huVBk+zAl0K28L3Yg8acGnefrNX/yFw6fPm/nqeDr59je+1Rv0pZRRHDdti4hREnd63cOnL9I0klJmnQ6iiOO4aSZZlvJLM5Nz52WisMRUTU1CWm2KYj0YdwHoT/7ku9/55Z9XSjln66rqdXppEkWE1pu2bNJuLxJYNa0rq0hAtZg/+vSTXhx1hOrKOAZBYVKYUFKIluugddm4RxBuxHAu2E9cJuhuhPAXlRZcQhFDpnh5rUdEAHIe/PmLbEooIiJaLBYbYTHhpVEjkHa7HiDYQBKA3XRvIY1SB4yeHSMyb44h1OAduDDeJARd8Oi9lTJiduCA2SFTqLaJoCiqnxpor9/oXwTXEEovB92LWvlir0QUjnRsL/YenCMfPqfHzScPAL617stWlMHp0zlElMhMPlhXBokQOHfRC7/Ye/RWN4AeAIQQrVQbWRfDhZ6HLp2UMJf18hm52NhuOjuMyNbgJeefAF8L4JiEigQTAopNFoUARA5YYphZxO1qNehly7LwNewMepNiuTw72R18i5z2umbTIGxGgDvnHDgSLwMwnys+4YvjVi+uFkSIVZSo+PGDhx9/+KEgoQSt1+tuklhr+HyehBAY1vo4XnsP1trQ/RFCgKfVajWbnJlr167vXXlxeFhOT20Lu9ujfp6dHBzevHKTQIyHW2ugxwefjbPO9s4eA2ujFRACkhQMwjhutW2Nmy4WzvrZfHJ6evri+dFX3/5Kr9dfr1cCRVmXf/Znf/7i8MUrr762u7+rtTk7O1PojTHWOWstSYEEDkkhVG2DsXLMgWBLEnavZIPB4NEnn+2NRoiYZdl4PL6Q4QXyv3G22+3KODo+Pn7y/Jkx5ujk+Gvf+DoJUes2zVNRytPpKQoh46hq6vb4OM9zIcRw2C/LsqqqXqdjbBsQkWK9zLLk6pWdfr9/dnoaRVIJaZ0BZiLR7eTdbte2ulyt2tY4Z5xjITBJMimpKEpkq0h4b3XTEjhvbJAehQm8bdvqutnwC5x9/vRZr9fb3t7OskxrvSoKq3WSJFmn8+jJ4zzNsk5eFmVRlcjQTE6H/cEv/+qv3Lh2XcWR1Wbvyv72eGuxWh4ePB9vj375l75dt1W5rqbzM7WzdSu/dmV3L0oUeKzbyuimbRQxWG9kJEVTF3VZ6LaKo0RISiIVR0KQ7HRH4+HgbDopi6puKiWot7e9WDbrdRE4z4h4IRp2zjVN45wrimI+nwfk1nv/1ltvnZ2dZVnW7XafPnv++PHjoq5IilipXqfrmU9PTrTW0+nUMhRlZZiMs0kid6/s7e1v9Ye90bg/6PSEwKat2qqpWmNbXZVNsVxVRd22bVU1i9VyMV+uyqqq27Y1xjrtvFRxlORKxUjkGJxlBc4b7a0ry7UxJnzgSEgVSaNt0zbGaqXCMKKo2+3EioJRFCEKIZbLpRAcC5JKJJGK4zjLsssB2BsLnpMkqSubpulKt4Z93u20B3ZVl8OtcSft6KKqqgZaIyxTQlKIsiyXy6VSSsmo3x+ul6vP7j+01n/1K2/duHrtrTe/JgWORqO6rO4/evwHf/r9H/34w6Zqbr3yqmc8nc62x1t5T1jrUDI51NYSsmWw2sxtPa+qzpVtS7Bu6zSKNbtHz592h4P+YJD3uihIa71YLEBQpCQzP378eGtrK8/zvNNZrYrlcrlcLtM09RwEoRigfgZwDBu/N+uQlDGWrRVCdPv9Tz/99MGDB3v7WzKWdV12retkSZpElWHhbYzIrbZVFaMn69fTs/XJsYq7hNKDVIwYph2jEAIjiZe8bBRRgKbDGFl/YeBwQTgqrbu8oF8ULurcu/jyBkDWs4cvzz8AgOQSaejiBRmgrNYXElcmSYhAIADKasnMcMm10aLwCB7JIwA7IQQKTxSE5tQWFTOH8EObbMYCUZIkfE5KevmpGEkKZmJkYNyg6EH5jABAjIAgAAFZAAKBNO7CKCMo2mVoCDPbQIKSL38EwEvDHuCL1V4kIsSNmeXLuh+Ynb/47S9mVDH6uinCrEBJQpIgJARE2Ax7oEsKn/A4EhLPk7mLzjqeGx1cZEXnAdgZY0KyAgCe0YUXJLEuKhCSmY31HomEQCSwOoKm30nret3UxbjbrXV5+PRxvVr0+jk6C+wEbkahe2Mt+ziNgrXYl05BaJF+6ZJgZhLy5Oj4448+WhweimzAHq0xcadXz8rW6JAmRlEUJ7J1rlgl8/n8bDYfDvuEwlpLCLpu5tPZYj7fGo93RuPpcl7WTe756s7ew+cHWZL/43/8u7euXf/2N7+5nsyK6XSYd3VV5XnurWPrvQ15ibaOUVDbtFeu7t++nT569Oh3/snv/b2/9/f29/Zu3Ljx4sWLV197bbFYbO/uvfX2Vxzw48ePV/P5zrBjrLXWamvABUkRMECaZbXVcRyrKBrvbP+VX//WaDRSpJyxvV6PGLIsG41Goc9ojHn+/HmWZVESO+AkSUQcJUlSN7qofG8wsOyZWTubZdnJyWmWZcv1otcbAONkMonjeGdnZzgcLpcLwH5VFdbaxWLx/PTkdNKui2Wn0+lm+WpVWmOcM1LKNE2rCq3Vr999dTIRdV0bY2azWVW1bdtuLjCCNNVKKSGwbdu6rsuy9LixvtdaO73pHjJzp9MZDodJFIcJs1JKSTTe3h6Mhv/od/5xp9O5efvW44ePtvd3b9+89clnn3rrZKSsd4owzTMPvCrWbVv3+91u3pFSIrIkEceKiAaDwXRrGmyMmV2apv1uTwjRtiAFgtNtW7fI1htrrS5X6/Vy1rZmf38XURwevjg+Pi2KVZZ1tnf3rBPr5apcFyH30VoDgG7acDmaVs/OpmdnZ3Vdd/MOAf7e7/zup59+urWz/corr5xMTieTCQpZ1lW/P9za2vrks09v3LhxdnZGRGz02elEqdQ6nrbVk0eP0yza2d3a3h13eymzq+u6rWrnHDlcr8rT4+OzSU0KrAVjAQBIQpQoFcVRpsyyBFKAwiN5Juud88zeO63DJKq2bdvWRJHs97rDYf/WrTuz2VlZllVdLBdrY9uqsm1de+9v3bo1Ho2MqdM0SpIkkQI2XrUYZl4GZKwsy+AAnud5wy7LMreca637o76M1Nlsur+/j0IwogsTHQm0MQ6l9aCt165OVJQmmWlNXdd/9C/++KOPPvrKm29dvXpVkUB8dPDi2Q9++O7JctUdbl2/cWs43q6Lcr5aDwdjFadFswKJyK7WmhjQOtO083rlCbqjAUVqWRbrspjOZg8ePfzWva+ISPUHAwVisV4dT06jJFZRtC6K+/fvd7K8qqo0z4koMFGJyDnmMCQZNj6+GxGItXEc19YZ53vDofe+2+2u19M/+IN//mv/3q9cu3mtrRvd1jJOlJLQNBFipkTdtug0sTd13U2zv/QL3x6wSJkSh9JDMHNGQYjMvkW2zHCOE4Z39wEoDfBnsK1AJAAI/cXLRXBYTB88eHAeWs6jC4Pf+CQSAgTg62LNLU0TeP7NZjPaggXYHuUhXAR/rUtvJQAAzl2sNu+AWDU2PHlOUwDw3jlXFeVFkBPnpCQmLE3r6MtMKOZgqvdTtsv8qYvYAOdOVReh4uK/V9WKf+JgCAPGv8hDDhVqGO/5U0c5Xt4zIAEAeCk2Ly/P4QRmZnc+bvxSyCcGQm4bowjiWGVZlud5lmVxHEspf/zjH4cPErwDLiDopgkBGADAOrABl0FAIVFIYDLOMiMpCUxsGmYjATCCfJRuXdnbHg1tXa9m0+29bTaGrQszho0xzjGAb5rGw4blcKGhgi/mYecMMiSG58+ffu/P/vzjjz8GioINi4iUMcYYCEhpUGyTUGXTIGJZlmVZXrt2pdfrTedTD7Zt2/l8PpucXb16dWs4Gkz7p4frxdl0f3vnhrDB6wABAABJREFU6fOj93/0o9/7x7+TqGg5mXz9zTdtWZZl2ctyNi6koY69d4FDhkJGMvIvDo7SOBmNtn7pl35lOp0mKtrf3+90+9evX6/rOs7Ss7PZbLFQSg23xm2zVmYzDBGl8IQo0HjnnS3rKuvkRJQmyS/+4i8CwMGz5/1+fzTaYs+RjHu9gamatjVNrQ8Pj2/duiWkfHF0qGQ87g+iKFksnsUpoKBGtyTF4fHR1tZWmmUqiiaTCRFFcVq3VWt01snzPBdK/vj9d5qm6nW7UkoVCRJRJITTuiUSApMkIooEoFIyEhRL8cGP35vP58HKF8ELgjiSRHR0dJQkSZbGg343jmRAmIUQ0+k03IZ8Tj32xgZOTCiGEbHX63U6nU6ns7+/P13OX733+rX9K9dv3cyyLO91r+1fyfrdTpqdTs+asorSZNQfrMpAQMu1bh8/fjifz5l5e3s7TdOmMXVdMrMxLSKnaRzHKnyXLEvkYr0qW02C8v4gz7K6aZy1FnC+WhZNXVdVVdd5lm119q0x8+WiKu18PmuaptPpEKG1pmmapqmHw2Gn0/Hez+ezuq76/f7169euXr1y55WbTVsIJQFtVa2E4G43q5uiKlfb49H31jwcdA9ePL1z95XT48La5vmzk2EvEUpUy3I1hbZYTA6etbYuVuAcJBGMhvHO9nZEqpMmbVZHaWatMy6I32MZJSqOCMWw1y/rdrkulouZNo6ISKpIwLWd0fZouLW1FcdxMLvpdPJOp0NEe+NuWC8mk8nR0dHx8fHxqn7+4tn2eKBNU5fF9tYwy6LZdPXi2dNf+7W/HFSkENxunbd1660HoDTNO86naU6OrTapjBIVHb44uLZ3pZ90rHdCSakS1+qm1azr0OQIVjWSRLCOG3R7Dx8+/OM/+a7W+uHDh4R448aNKI6H49Fr9+4FTDVJkr73RVHMZrPBeETOeXCNdWG4R22apa5lN+0M+jJSbh2s5u1iNr+6f4UROp2ONL4sy9Vq1e/3oySuq+rp06Pbt6+uTidxmubdXpwkWXfqCmiLCjyFIeTMaDcaee0tj3qdcrV2zm6Px7PlmRJJnnX+7Ls/vHfv3v7eVQZvaxsLjByQMZI5VyAcZuht3ZjV6tbO9l/9xjdfv3o9dj62IFlI2uDASMyuCUk+XubinnuP42UjaCIAsPala8flAMOX5KoXf4KIZa0v/zmfW0/xF/F2PHcpth6ALt5UXI7xwHTOi8bzGAYMMnDKwn9578NpOK/QL0dPYITaGY9fHKEAhARG2+BOxeDZB9b2l+Pu5a8cAvDlaMrMjECSgq/GRQi/aLFfHHzBykS/GWt4UftuetvAX3pmswfndc28cdkNnyeEsSDtQX75C4cPoeilUfWXSsyLDCNUwOGDCdism8xoHFvvmNEjGOtIKI9kjWcEFBIA2LaDXExODuNubsCvdPvk8MXj4wNpHVe1rxtwnqQjEmycYBaK6rrysDE/CfuAuCgVIzKSDPuNWYqHzz757I/+4E/aWdnZ229bZ63NonhdrCQCkGQhhSBFCAIFO28aKWMUor81GtTr6Xxqrdesi6IqiopQ5nm31+mjO1hNFjfu3unKeJT3/oO/9tf/0T/8H/7b//rvv/l//b/cuPPKJx/8GHXjGg3WCccSJQISe/SIyDJN0zRu23YyneZpev3mDdPqw5PjO3fuVFW1KtbjOJrP57qtR6NrxfKMrWFLzlrnnfWOfeA+wunppLb6+rBf6gp01c1VWRWPH3/6rTe+Mcj7y8VCooyjVJdta1zTaKniutHeN0IIInlyeHTw4sho3cly02pEI5AOXxyMhuNOp2Otn81mh4eHnrHf74/H4xfPQ4W6rsuqrNbA3O/3FRF6apqmbRpr7fb2eHs09t7Pl8u6rrM07vV6iKi1TpMcAMqini+mCCL4u+WddGu8k6apFFEcF02tVZTcv38/tFGEECHb07qty2Lr+nWjddM0SimKZKvb48PFfDGdzmbf+Orb3W5XSfHGG68vFoujo4NbN296769c2Vsul2VZMjvbNpPJydnEO6O3x8O9nZ3A6tBtba1Pkmi1LpQS/W5X66Ys66pYdbv94bAvb7zyat7tzKezVbG2SMez+XRytru/VxuXJ8KiOF0s+45//tu/0Mnyjz/+uDWrV1+5iefGY2VZBgcvZn92ehhMlO7euTEajapi8ez5A22awbgTRVGWq7fffj30mL/d+8ZkMjk4OPhP/le//Nprr/1Hf/s3Z4tFXVRJnjnt8m5fm6YoijiOiWCxWCzXy16nOxgMnHPXrl27fv3608eP0zR9/4OP//4/+O8Hg+HW1lZVVQGLPnha5ynEkZosDQF86+27O7u7Ozs7d+7c2R2PhNd5LJfFOkmSJ0+evPvuu4JGUrjBYOBIamuMMdnO8M7+FuJXPcPZYnl4ePgv/uTPv/rWbRKuP8hv3Lh+7817N69ee/z48f7uXjfvLGfzr3/9m+/+4Idfffvt1XwddbIkzneGOwf5CZJs5sXdK7f+5Z/8yermzG9fjVXS6qoqK9tqdNbrBiurRBRFyni/Xq+sNomKmOHOnVeCr+y9r3wl9KU8ArNfrs5ipdhpJaUQ2LbrJKG2XgNaVsIJNgAe3dLrma6vXn+jaBqpIqWig+eHH/3oxzf3rl3fv9qPs93dvfd/8M5iufr008+u7u3/9m//9gcffKA19Pu9JEnKspRR3O31iIgJR1vjqmnr1qCUQkjPLIRIstQ4t25LFUtkePrkAYAvFlMSyBb/ye/84WxSfOc7vxrtRrB2HScsySSFcn7cVrUoV7ReJFWphJg9erBElsaS9eQdcigTjXPO/ITc5WKNvggYF/wsIYQ7n7oTYmrwjRNC1HV92R/mPBLLKEk2psLeXybihmxyw+S/VBlfjKKDL0K1UsrzwdNfCISd/uByOXXxUiGoXIxh2IQcwigOFpt0wcoOeyHUBeR+yd8KnOXLr3Dxvuc98i9AqR4BN3OUv9B2vcgPfspGCMHnTtDlji84vxmqsPHcDSiEZ9IMDvzLwBneOjRrvvQhCYPi68vOU4h44TV9+UliAG2B2TMgIpL0CM6D8U47n3V7q/W6KEqUotfvdDqdqlwloK9v32mdS/v9lvns5MXs2bMfzRcHDx8mne5gOMx7XSmls6YqyrptynLtkYPBfhTFcRzFUSylIG6tNULIXq+bZdl6vXrw4LPnjw/+0f/r98kr2Rk065YYIxLOQhznKrYffvZ8ezzMRoN6PcuTKCW9v917erL84Uc/cpJv3LixtbU9n84EwvvvfXT1ys3Do+m1q7dq42fz9ceff3Zy/9nf/M6v/4Pf+b2/9Mu/eP+1O5++/+hP/+LPv/Od7ySjYbfTnZ4cu9phayK2GSmFCFbXxmKv0xgLKPJuj5nnyzWyy7uds9lUkuh2c2aXxlGWRk2xjoi7qZycPtu7fgtUeng2jWQU51kFcDCfv/6VN6wAY9rhsFsUs6ODT3aG2Z0bN73GUWdrd3tnfrbI83y1rv70L74/2tmdzee9brfXG3gPhy+Oru5eyeMkT+J2tdLOVkX15uv3ziaTxXK9s7NX1WspVaIUAiwXMwL0bJm5381Hg56UEjyncdpwg4yDTn8+ny+mC1PpPM8FSmRaTNfTs+XOzo51vFittTVCRVGc1nVLQkWJTLNOWTcPHz0JQxoCx+L1e68cHR1MJ2fOAvumWIdIHK/XZ7FU3TxCRGtKZBMp9ra6eW2Pdb2eNURkqjURRejPjl6kaXp6sF4sFoEqxMzkdNu2sZLzyWTqT52zAXS9EDc6ZxEpTZN+fzDsduM4MnUtj09PBrq11gbdkbZmPp9Pp9Pbt2+H4UhSSkYgok6ve+XKle3hiAjqsqmaEjyamOJWhuVCxxSpfHv35q0bt08mx5PT4ytXd+698crZbFIWRd5J9nZ3806HvW+13tseDXp5VZZpLAW4TqK6ST/vdJzjbrerta66aaAqDLt5VQ2vXbsWx/FsNkuVZKNjJa/s7QLAfLE6OpmenZxOpmfjwfCbX3s7jeLdK/vXr1zVzo4Hw/HOtiLhEWKpBMHTB594VqMs7nY74uoe168xUZZluzv7QLjhpjd6A+4plWTpcr2SEmbL2da4X9bVfD6fnU3Y+cFgkEbpaDQq5k/L1TqP42dPnt569V7Wj2SUdLJuGmfTxVxKtb+7c+vKtYOnz1+781p/u7eczkjKRKR1WcSJAk++deW6Mq1m5ySSsxY8eGAfsFEgDKwfYnaWAMA79ho8EiJ759kPB6NlWRRli7FiJWqjDXJ3NOj0e0mvc3p41I3T9XxZrda/8O1fLtfFL371m6vVyhjz7rvvXtndu3vnFdZ2eTbb38uttZZ9L0+2t7cdQpqmUZZNZwvHG7kHAwQLacfsOEQFT0iwaUsSMruWT4/m77/7sW358Pnp1Wv74/F4pzc+KefOGls1zaooJmfVfDlv9RnSp997F7yWlilIHBics94HS8IvjOe72AdWvAcWSChIkkBB5jzwhABw4eNK536tF53FUKL1eoNwfIi1IQb/vyn70yBLsiw9DDvn3OvrW2OPjIzcs7L2vbp675luNDDgDAyDwQADwGgmGUVSBvyQSZTJTL9pJjP90A/9kEiKJAgBJKEBMGgSJAazNmam967eqjtry8qlKvfY462+33uOflx/Hi8iIwcDj7JbLz1e+HP3d/2e7Tvfx8wPHjyYN/a1GaBabGQ+UHPbvDjB/H7U6oS1c9u8gZm3d0HQguOYbWfmXa0Hn/j0NMlq+ubjx+n1evNW3x2HwVZVWXPSHTeHjbri8QyBcFkB8IkPbd7veoTcRkSanGTkEXq5Sfe55N4JgwoAvV7HkfzMc3gJ2N2d/eZ1M6LIwdYOimtz8rwgIK2BlBV55tnnkOjew0dbO9vaDxeXl5aWlsJAQTr1NYzTot3vL29sfPzJvV/85Ofj1KKHOgxanXYcx8r3RISrsmJrTEla+b4fRVGr1Wq323Ecu386yKHv+0VRPHr06MaNG/fubitsg2gH3EKAmp4SiAFFwXCSLS32fN8n4G4c5Lnf6oRFVWVFHsexXVgajSZclq1258GDh+cvbLX63aXFlQsb53d398fj8WBr79krl+/cvPWbv/E3/7vJP/q9b3wz6rbfeOONwe4uBh6yFWNMborSigWsLDOX06QQcQ0eSqkwDJXC0PettcCWmauqQuE6grLFYj8Ya2VMaawU1igEo1AULW2sq8AfTw8AqqJMb954f+vxg7df+WyZ5pEX9nr9M2fO9noLk8lkb+9gMBxHob+0tCxs47i1sriELLu7uwowjiJTFYQqz3NSXp7nRDpJ0zzPiajSuigKT5H2yCOFCFmSunkFAK5NSAFmvn9uc5OIqqqaTCbpNCGiTqfT6rR393fdPB8MwKnSdbt9IsqyTETSNCWiTkcRUZaN0nQa+DCdjAXY8zytSES0VkHgh55PRCAsAgiiCMlTIjIZDfM0cawJbCpmdkb3/PnzrprgYMhEZKqKTTVOJii1SptSSs0YrWnWT+RI0U1Z2cqIiCaxHkGn2261WlEU9drxYq8DAP1OCwDKKGhHAaEU6bRIY2JDyFVZTUaDSTrVqApTmjIXguWFpU43joNoZX314rkLSsNw/yDwvSyZlEVWZqmIzdutKAq4MtPJGCwLG1+RsEG27VakAFGpMs/ZWAIMPD8KI6WUJtVtd2xlRHuhH6BAlqST0XgQHSaT6V/7tV95+Ghrf29vPJmc29y8cPGip/Xi0tLB/r72vLIo0mwiSpVVtTMeV3nRbcXWmF4cI6IfRQvLy1tbW8YYzw89z0NU0yQbDAaOXTJotRlwbW3ti1/8DLNdXFycldbom9/85l//a3+t2+2ur68/vvdoMBi02/GtW7fe/MKXlmhNeV4cx8vLywfjQxaJ49b58+fvPXjw8OF9pXBpaSGO23uPt/Mi1VqJNVWZZ0liK/aUJkZb1auzOC1cAFAEqAAFmIWcCSIRw0TCDMJpmhpjAs9Hz5sW2WQ61mGwtrLqk8qnyXQwSs1g++GjhV7/heeej1FfPH/hwZ1Pd3Z2hoNBr9NdW17p9Xrvv/9+p91N04w87cBZH9+5PRyO+8vL1tbUZkjEAk1oyAxISKSaLgt34mEcV1V1584n29vbv/jFe2fOrG1ubvZXl8dlkVVlPp2MB8N0MCjHCZSlZ/n8mbNalBHwEJQmAhAljKza8akGGBxlqOVa1VaRIAkhMlsQRGREIEKtZa6CyMCMs3okESKWSdkkPJnZWrYWmKG7ttlYC5opjhHRYDQ8Yb3cC/fAz5tA9892r9tYteYgiNhwKZ94v6nq1/ObO/6Jd7ptYS14cicADIdDARESQZFZ+diKlHYu7S1H49LyGsyBoVzwiiSxFwjYJ8/HsQXMG2ClFIG4Ra1JHTd3viHiOB7pymQyAWTXnQRAAlYEAXn90nOO3cyZ3hnTGVy++opD4yMRaU8IhcEK7x8OgygEvx10l3u9XhCFo8QYoc2Vs3Go4XCcltU046i9tLC4MckfJ4mVLB+OXBNUfUssQBR5DEdliCaR7mhEndweIjp9DlOCCmhmeptmdKfKTErhYDDgzbVO1DZl0u72p6VtZ3x/62Bra+u5a88GocdsyqJot9sPHz369NNPl9dWV9ZWz58//2D78Wg0evz48aufe/sPv/2nW9uPfv3Xf/2//m/+v7//+//m1Vdf7i0vTg6HltAKGDvNbVUKe4SoVLfXLixba1GgKnJbVSKSkep22w5zRArR8x1ZobXVYFxUqLyohVqpvCi5LNMJBsHSylJpCqUUgr+1tT0cTJeX1jY3Lw4eF57Sy8vLm5ubQeDfvn17a2vLJYTb7VaRZ0tLS4sLi4PB4KOPPgiCoN/vl6XxfJ2maRi1qqoKw/Z0OjWGGdkBpjxNnqd8z9Na29LirB5UFEVZlp7SoPRHN24230g7bmnPG44mj7YetzotPwpRJMsykzNqNc3S6XTq5FKIKK/KvCqVUkVRlFlaFom1led5OvQ83weAwPejKDZFWVUz+jY5egYdNYfreamqyhl1AHjw4IGjonIxKhHV7vsMAtZM8ma1ca6/Y5Oe3X+rr12+0O/3tdZlWU4mIy6zzfWV5eVl3/e11sv9Tr8dZVnWDj0us6pMPfIEwfeoE0ftVgsQ8ywTgFYcx63W0uJilufDwf7Z9TUNMhqPb9+81e21u52OMWZne3syHjsa/aqqpDJVWdqh8ZAWFxeJKMtzNqV7tj3Pc/Unx+jrNO96vR4ihmHoINa2Kh/du6c9/dy1K77vLy0t+b6/u7s7PNj1FJky23r0cDqdLi8vI+J0PKiKcn9nK0/SjY0NRlBKu3UQEHd2doIo1MqfTqc7Ozvj8TgM487CYilKNK2urO/sbhnDZWF8Pwx9/c47P/rc2293LnbOnj3z6WJvPDlcWVrd3d159OjR6uZmpD3fC8+unx2nydbezmQyuXDhwu7+/tbWViuK7k+Tbqt97uxmNgmLNCnSxBQlgLhvGi2QgLUWWJyQFNcxsEIUUkIgFbFYRg2gCACs8P6jR/3lpSCKRtPJ/mjghcHaysri6vpulhyOhz6pmzc/zibTz7zyer/duXL2vFi783jrzo2bZ9fPDA4OoygixBs37r3+1guoqNPvZXmZJMn9+48AsdXrGYsigqCAkCu21hpmO6tDouuorkU2BQSCIFDklWU5mUwno/Hdu/eC4OdeGFovsAJsKrSsrNUMmllb2dseIVsNQgq00wISsczDaS7HQrt5CwdNbxTOtAqlbjk9ud9aV5GFeTOFAE5zZIbtAgdMFoDQrz+ifudMQNE1nj1pS1yEKidwTAhJkro/h+PBX1k2KWKY1UMBAMLAP/X4TcR8dPAZZaOIzGrCR2MYRk8yeQFBxfZUR+H2w51TI1RPIXBNbHfcANvZva19FPd+31N1n/Vsc//0fR+f2NzVzH9u87opk8/X+Eng4ubZI3CUoBE2lTVsH23ttFotVFopFXb0dJzfu/sg0PgB8VK/Vxo7TjPl361Edg/GZamXltestZV1VNI1YI2I8jIXAJmh2UXI/QKFqkKKrADJAVFr7futsOsXuT12M+ca45Tnj5PEsHhhYE0eRKHvJ3HMbA4ePHhw+/bttdVlACitybKMiO49fLB2/0xvod9fWtzc3Hy8tXV/Z/tgf/f5a89+950fvPLay3//H/xHP/rpTwaj4cWLF4oiZw8rAmZjmBEBSQUqOBgM3L0nAu18KSSl0DHJi4hPvvK0rz1rrQEzSEZMSgIfSFHkWSWMVeiHoGyZp76ndrZ2Pv7og+V+7+K5C7du3j27dLnb7a6urvZ6vcHB3t27dw8ODqLQF2PTNO33uhsbG7tb27u7u4eHhxsbG71+f2trx2I5maZ+3CblRXG8ezhQSqGIBURr6+RTaRu6FU0kM6HxKI7bcavw/eFwmKep7/u51oYtAYZRa5Kknqm0awFHVVaVWLHMO9u7fuiHflhW1XAwAgJPedrDXqdnTe4kn9M0z7LEVkwK+p2+MaW1giiaPLeUOV1hz/PKsnR9Vq7w2uv1dnZ2mnRaQ/7veoIAwJWN5pEEjmfedXN4XuAoZkWsvnhuw4krTbgamyLQ2I46a8sLo9FIAUat0KPlyWSCYtLJME/G8cKSIh86bVS02F8AwnSaGFe3I1jodcsyf/Tg/nMvPH9+8+xPfrbdCvy15ZV+vz+dTofDIViO/MAlmQeDwf7O7t7eXhzHa2trrpO43V9wTofv+7YWfbNxHHueNx4eOsez2+2m07FCQbHbO4/b7bgd6dBrg82rvEgnh4iY53lVVYP9PREpUq8oisnwQClvOk0mk6kQZVkWha3F5SUWBCvGMOSVUZCVVVZWkzQrjIjyREe7h4dZmty7d+fi5tnzF84lSQY2WFxcZCt+4K2fWTt/fvP69etJMjG2fO8X189dunK522u1OpXI8sLywXA0naRrq2c6nd5kNEjT9I/+6A/3tnf+z//Zf3Z288zu40dFmpTWhJ5PBHleKKF23MqTnNFp1THXtsSIAsUowowIlplBKQWEDhBp2E4Hh493d4J2vLm5Gcbx3U8+GUvlt+PJYDTcO1jpL55f3+i3OufWN8aHw8Hh4Z3btxfa3W6rffnSpW//2bdaMYZh6AV+u9XN8n0RWVzsaS9EIjtr72GngGTYWgtIhISoiBSCU/mtSS2SJNNah2EcQjgLLm2WlMb9ni0iASkUBBFr2QgDI6BQJUR1iswKB73FUw0wztWAZYZTdRxP6gSUFxEAAq3n7UezEep5R3XegooIPPEnO+PiVAM5fybzox90BYGf4HMIekeR6/z707x88uCISEHw5JsBgLHm8DoxJlnZsEM3IwAg0fHm6ZmnoiJ4okaLiJU1rg26BkTP/pTn6KJExFUfACAg7b7r5jtiRmbUdQMSABwpOwNAnhfzNenm0+epK+dBczcf/KI+NwCnAc0MVsD39PZg2u32oyjyxnlRVY/2Bq3Az9M0fLhPnieATGPDYkGHcW88KlwZBQAVenW2kIhcTxcdS1ogYiuuJQdkhv/Ps5JNGkYBAAvQ7KQAAEGIgT2lirKapvlir4NKCyqlvX6/v7i4d7CX3rl90ydst9vAkpWF7/vb29v37t07d+H8xrnNy5eu7B8cTrLs+9/57he//tUvfv5z33vnB5sXL/yt3/pbRVVmRRq0Ag40EVkxVkyVFyIgxIUtUAhYRKRErFO7FolI2CrHaO4rpYjBsoGw30+KbFJZ8SDstnUclghRO87zNIqCx48e/vznPzd5cXZ18/Bg8vDTh1f+0guLi/3lxT4Bbz/eun/3XjIdt1qtPEnzPHv+uWfX1tbe+f737t79xNfe4uIikS5MxWWVJGmfQXuBkMryotVqAaLShKBJAFEYQHiG9reCCgFIKaW8IAjjtfWN8xegFcWe521tbd29ezf0/Y3Ns0mWjqajMisZmdlkpgx0ELXbVcWgyAoUZWlLa8R45GmNXJnKZMKoPfKULyKGhY05MCNmQ0JKOzISthUbU2pfuSZbl7LO82w8Hu8fHjSP5/zkBKjbKkAE0GEuCBBRQSuKjC3LwrCYyjADuvmmpSrHyQgZAbkdBlUnMoUZHO7mSV5xFfkRIxdJWnGFjMA2SxMALKtcscqLlJkn00lVVd1udzQYpavLvqcsV+PRIAxDENuK4zzN9oqyLEtTVehBnmYOoyGWCdCU1bgc2crkeb6zt3vx8lXlaaVUp9NZXFzEWf/GZDIZDAZlWU4mk+XlZdd8VhRFoJUpi8O9/fFwkCep5+uD3T0kKIvK2KpIs6LMx4NhWRUI1On0PM/rdDpVVU2TrCgNaWWtTdJcKZWWBTO4xEJZmqKYlBbAK4qiCvyw11sCIASaTtJWGL355meIyFUdrl698vDhg53t7e7C6ocffvj8q69tnj/X7/Qq5jhut9vdrMx2dvaef/75d37wvcP9g5eef+Hf3Hn8r/6nb/yHf+/vtLvdvCyZAFiqorIEChX5nuQlILATc5XZik/IbK1YADAohKhQEIkBWv1uyXaSpVErXj97NgzDn/zkJ7/7R3/w4ttvvPDKyx/+/HqA6trFy50ofubCpVB7D3cf7W/t7O/sFqPp5z772aWlpd/93d99/vnn4zhmhZPJZDweC9D6+kZZme39A+0HQgoIhbGy7DTtSStQugGpitRVa0AQVsxQVVZElFK+HxKRsWKtVwcvIFoQgckKoNWeh2Klpg0SAEBmEJ5WJ9TwZoazZuSAuYUPAMBYRkRns+ZtmJkdReCYLazKo3ad+S2YM3jzIZoif95QNX9Ic2Z4/vhWarbpE7ZtkhenRqJxqzdvZXn2mhw9Z90WVF+xiA2CAGYawDDHZKVqVS84PgIgMpyCt6oNnsM2NbeOBKw69XrVE3fMbS4HQrMej8ZPakBhzREEABHbcW/+FJtrR3sUWYrrLAYA5HgxwlqknRR5OIeKn4ymmxeu9Ho9ZuHJWOkItL+01k0m48JyGMRIypQVMBUlCtb9x4iuO5mZURhacZ/BWivGlFUpmcnYCohVXmBNCVaAgLSvNXk6FmVBGBzx1ux+yCylbQUUqYPDYb8dtaOwtKz9YKHdunj+giluDYfDLMuWl5cV0sHBgbV2MBo+3t56tL3VX15aXV197rnnJll6b3fr7q07l65dfemFF3/40x/lVfHlr365MBX5HmolyB60SrZMkhV5aTjud7XFqqryPK3K0jDmAJZNGIaI4qOnrKayyLA0ZZkWaTvqG88zSuvAa8WBJdjf3xuno7DVjlR4//798Xjy+Tfe7nW6e493X7j2Sr/dW1paiqLo8PDw7t27u7vbVVV5nmdMhYibm5vMvL29nef5+vr66vLKOJkKUJImWVFleWkEJtPEWjGGBdFTihQqJIVuDrAxjChAigCsgDVVlpdap3uHgzD019c31paX4nbHD4MkK3b3DhZXlgNTEfraV7bi0WSYpVO/LOKolZdZnmWOkDLylSltWea7B4fMRiNFUaTaQRi2YyQROTw8JEQiECYEcFQHgGo6TS3Y0AsXV5bPrp89HB3mN+/sHe51W13U6CvfghAQKPSUj0rleWnrkNfOp4I2N5eh9EqbFpmpqkJEEHMi0uPhICtSXwd+6LGpwBqxJi9LTV6W5VllvUCjsEYIwiCKguFgCgBllgGACzWKNBWR6WikALLp1BjTa7erPJ8Mh06Ifmd7zxjTarW63a4RuzPedUXs0I/OnT3f6/Qd7GUwGKRp3ustZEWe5zlAopTnlm/Xd18UFZEi0kp5SnlEWmvbimLtURy1szyZjhNAztOi22ujpwix29ZZrtnCmfX1wI+SLL/+gx/1+otlWRrDYQhJmkdRNE2KqrLjZFqWBolYkJSuqiovi8O9QavTXV1eX1jsmzxrt7vTabq0sFBV1Ycffnj+3Ka19plrV/b2d+7f+7Tdjgdb448/unnu/MVnX3phcXF5cTRYnkwG09HHt26++ebr5zYvbD1++MqLL/qe+s63vv1v/uD3v/q1rwXdCH0ajUaVRa8Tg5VBNhZgJ0fDKESgFJHSRFhato5mD1ihGBJSAIjgUVLkfjte6nWzqvzZd771zjvvTA/EpsX2p/ftNLtw9drlzfMXNzbXlpaz4eTurTuf3LxVJllnefXatWvf/fZ3kKXb7bbbXSYcDAaIOB5PFlZWQVdBEFg5Wg0b3VBEVFojKJyBGMX5CqCiyBfhsiyrogAia1ze0mgVI2gAQGCLiCIuik6L0i2zSHVvqxFrmVHrp6SgZWYvjlk+e6ROi0QksxV/HiTVrPUA4IfRieO69xezNh6YJZDJqfagYy+d2ZCZeRY+2UsDgAxgj/Y3JwuI6Ifxkx8KAOLMQS0KIbUHBmCtwBOOAqKXZEWjClWzWAkBsu+FR8pRsworg7h08rw3UI9KN2cpiK63FhjL4giEdcKHeOJ63f0/2T40n0KQWR92s4eqo3apeU/BFarqX839iRUQ6xIbDFC4Yg1bu7CwgEpdeeaZlZWVu5/eH03GiIoFMmMTw4hKk0Llhe0YQVV2Rj8n9QGYrUsXlqURqnMGhMrXAWgC4FarU5Z5UVTGlMAIjJ7vaw1lnpx0EJ0QCChrDWu1tbfX7bQ67TNVlYdxuzKwuNBf7PUGg0FR5MzWChu2rShM03R3d//GRzc9P3z++efPnj03mIwx9H7wsx9//OGHX/ilL0+SyXd+9MPOQmft7Ea71wZCCDyfWqJEfMwS4sxMh3kImomtJs+LwihwCc4kSYjAairJChcAwGCNwr3xuL3Q063WKBlt3f9053BvOB4sriw+88yzWw8fVEX5xqtvPHv1OVNKP1y6cuHi2eUzq8vLZVnevHnzo48+GAwGbtZYazfOnFlbXnr33XeLLO93ewv9rogMBqMgjidJTtpL8kIA0zRH5RkGVGgYBAFolqlCKk2lPaW1pz0FlTVlkRUFM+d5sb2T3Lz1SRj47VYnCH0vCJO82L91hzTGYUv5nh8EXcIsyUtTFKUpSmMqq4B8D0hQgARpaXkFEYTZGJPkxSTNwLK1VmvtyAScWicRKaU97VdsQQwqD0kDaaX9uN1dIhQLyiNP+Y6xjhQqL9C+Z0SjI0iogQo1CMsKCBKQAlIMxjIDCLLosszFsgrQVmY4PJxMJmEYdlrtwWAwHU8QMYoipxsKoSjPd5LFLhtujHFlS5c9vnDhAgAMBoNOp+MQy3EcTydpVVVEut/vr66ul2W+s7OXZZm14vsYhnFVVS4bvrCwpP3g7NmzOwf7yTQ7GAxGw8k4GYuR7kJ3bXlte2+bhPYO91YWV7zQ63f6nuft7e72+/1er7e7uzscDl216erVqx988AEitlqtMAx7vV4c9ZMk+cmPfzYcjDvdxSwrWKQoy9F43G53P71/r91uD4ZjJzjh+0Fa5EVRQF5NJtPD4Wg6niwvLwZKeV4wHOyFnv+Ln79XZMlLL7zY7rSevXL52Wef/YPf+zdh5Pe77QcPHty6devKc9eWl5eG08n+cJQVuSnML37x3le+8oXvptPvfe97f/VX/rIi+O1/9odXX7i2sXk26LUxT8VyEIR5km7v7bTDlsw4lzUSowPnoQW0ghYACEgDaSSNQDgp0rwsFttxRfDT937xZ3/4YwB49e2rLz33/CeffPL8lWeunLuw0lt46ZlnTV7m0+STO3fufvKpNebFF19cWlj87d/+7ddff33ncD81Jmy3kizNi+rB4y0m7QVRu9sbjCbuWbFSq8gKEoJyKhcAAEwi9WKKSHVyT2kIXMHMr6qqyA2iIFoCFBF2gQ0ykWLCOrhTCOQhCTKhiwABGsbjeeEBt8yJ40yeiRY4ekSXAxQjDVmjJu/4Edz7wVo738/a8DoppRgELDPU/o5Yd9drEkorUjcJzVVfFaIVcQlfF2a649QR0gy5LQhgzIw96tgo9hjQzFFdNb+FuTOsRyEh91rN8VVRZYrmihBc+5IQ0MylOLbBrA2piVbnHBQP4HT8eXOGDovu9odhbKWmzKzZqhmtGF8H8/SZc8SZIMgK9Anu6zKvmtdOTGKmd+Xur4MDKgLwWNx6mudZEAS+9oaDg8HBoa3KIGpVwH635SRQk+lUo/a8oCjKGmVWO2pIpAlYIwiAo+ZwiQQRcH7hwcGe7/tBEERR4FLQRZHlufU9IamJdRo0lwNhWRYf1WA0Ho2noDxTVd04Hm7tOtUsACiKYjKZTKeJ0+vNymI4Ht+5c8cL/NXV1TNnN86sbVDgPdx6lBT5B++9/+brbyyvr/3zf/U7r7zx+pufe1sp9DzP0yF5BFqBVpUuWl7HB1UVpaRTa22poBRjbOl3IyLQWpOnSWkkUQBKMBlMwnYHtXfj9q0/+da3Dnch7MMvfe31Is1+/M6PXnr2pS985vP724do5JmL1/I0O3v2bK/XOzg4+OST23fv3k2SpNft+EqDyMbGehRFd+7cEZFerwcAo9EoLavVhSUvSP0gqoxloGma+2HghFOZUVistaouQ0hlGX1NfhCGvvE4BbEVF9aqIFxb6IN1VHReEEbWynB42Oq0/ShgK/uDIVvxfF0W1WQ67nZ6Snu+DoytDsdjy0aR9hQdsnVML8ZIVVTMLuVGbEQp0CKuv15rHZKnte70l5hNVVUHh+PROJ1MJsaYfn/Raag3vRWAKKSQ/KgVMGBTG3awea11kiTkC/mhH7dre+oew3/0f/27LlJuVDzd43cC9OH2M3OalEKET2xRFDXYCJhBTImoKoVBnCc+LxieZ2WSTqaTtDIFgvID3W51W5327uEBK0RBww4bbzVp5SmX+BErRVX42m93257yqqriErI0ddSY7mrjOI6i6OHDh40fnaapu4TReGwJ/CAKggAUOT89CCLfkXJo7WD6pmIrnGVZkuakg9FkevbMRqsV3Xj//TQr3nrjpZdeeI6QFcjVK5dWV5fBmLgV3r758T/959947fUv3328u3Zm/Tf/3t/74i99ZTCZvvv+9YdbD3f29+7cubWw2D2zsfbo/t3dna2lxX6v3/8nv/NP/+bf/ptvvPHW7u7uaDDstzvTcfLxhx8FXmgr4yGFnq9Qm6riyjBCxZWOPOV7gIi+L4rysphkaRS1nn322ao0f/iHf/jT73yALfji59948fkX9rd3xsPR81evvfriS5fOnX/rtTeqLP/GP/sX3/yDP2wH0eLCwn/yv/uP33nnnf/8P/+/P/fc5ZW11WGa7g0OX3/9zd29vYPhyLIUlR1Op1YQPU+Apmk2miTGmCCMo3arLCs3edy378JfPE5t2GwEjrex5h8G4Fl/c52VdjNulkptYqaTZkpmZBB/8Z95qb75H7F8ZKjkyNSd2vgE4JhI4ET82ARoVMeOc/sBLNRz3zEtayQhlBn38hMjMtCTbFMN+/SxEVnBKbKMf84oAg1f5rGw7Xg+vN6Q3UU8eRxf6dOuyzFNn+IwnZCOmBuhkY6cH8Wcvt8RcuAs4lfoQhvI8zyOojiMXn/99cVe/xvf+IZSKuy0JiYzTtgCCAWRqab+dJXvOrg/GlGd3g996nwGEAQjCIwkQADoisEoUGRJK/SVGCnz5X7n2cvn11aWSFiJiNiiKK5fv75/UHz9619YWl39/d///bNnz3a63ShyxMhLL7744ltvvXX+8oXdwd6tT+/8/P33DkbD3upie7H/+GDvxqc3x2nyzLPXnn/+WS/wR4OhUiqOAslMvj+mCqqqKqvcqeN4nqc1JUniecrzPEEwZVWZgpkRvLMbF7a2tr/1nW/94md3IYCv/ZVXXn31Vc9TP/vJuy+/+NLVC1elhDIpF9qLZ9c2F7rdM+vLCuX6z3/x7W9/e39vTykqszxJkgvnN3/rN//W9uOt/+R//395+80rALCxsaGDMGN5vL0/GIxIe37cqixPpmlRFIgkBB5ppchTWitXTIWiMs6tQ2HXuatRk4KyMKRAoXa/JWFEBQo6va6DODn0g9PYJoLxeNo8JfOuIlrrpOudddRaKyQAQBZEdBYw8PxOp9NqtRwbV5Yljg0wCAIRmU6n0+k0DENXGI6iSGa0SN3+ghXM83w6naZpyszuDb7vHx4e0oyWAGasA9ZaPZokMusXbNLW8zWb+d+KYNBqwWk1pCyv+xTdusS2zjWVldOXPNaPWDvXQbwYxE7Uwa3dDBhEbYtiK+O4BQmUI63zg5C0Qg3k+QqJhSwDoBcEPoindewuDxGJNLMOgg4ABEGIiAB1ywejv7S2nFe5w6wqpQCVtXaSJq1W2/GFlpV1vwrDMIrbhrHb76HQZDK5fPny+vr6yvKiMby+toxsHz58vLW19eyVS6try+1298LmufF4qDRMp5NfvPuztTNnLj377MWLFwfj0RnSAHDnzq0yyy9eOB8H4fbjh6TU3/m7f/fs5XO5rXJbGZScTdBpXXz+minteDAs06wiNMYWplSIYSv0/Qi1YoUl26wqrUDcaZ3dWF1aWlnf2Hj3p++++/4H4MFf/atfvXr58t3bn2BpPvv6m2dW11YWFl989nkuqz/+vT/4wfe/f2ZtvcqL559/3mmYXLp01gnm+WF4/vz5re3t3YPDhf7itMgiPxqnKYCyIpWpc3eoiBGMMcy2gceeunI9sZmmb0Owru9KXThmQaqLgyK1sDwQICshJiZGaZZicHuO/cwnY58YnQl9YtRHkvXznNJPG0l783KHta7wTG3opN4wsrVCwICkwM40jhBIkPRpBglQqHFA5kdnIZ/Yr0AsIaPQX2RUAORSzX/RTQHw0wwnAgMgAc+uC9x1zf3t0VgbMHxyBAAX3B4fNQAooGMjowJkV8duJhEhIHC7FfieunDuTOjT3U9vIZjVleUHO1vYDmVmZtXsuwJgJARwThXPfCt30KdMYzzVAAMAo3NQYE7FAcEPY6UJLVkqS2NHSdbpmE7kLy/0th4+2Dyz4Xne//p733///ff/+m/8xm/9nb/zJ3/yJypN3RK9v79/69at5eXl5ZWVhe7ChXPn86z8+N7tSZoJjdph9MIzz7/73vVPb97e2dpeWVs+c+bs8vLicDC8feNjO85jP3D0UgvxSlFke3t7h3v7vV7PiJRWfF8HvbgbLGitFerpOPuDP/rDmx9uP//a+ld++cue5z249yBL0s+9+Xav0y+TKhkmHvjt5fbq0vLSwqJCe+vWzXfeeWdvb29pcaGqqmQ88TT9lb/0dRH5r/4//8VLL25sbGwcHh4CQJZl+9Nsa3cvTbLewmKRpLt7B0met1qt8Wjq5hKS0AzDBsjd3gKLqUsnjISCoAB5cWFZCQAYZOsQxa5MMJwmVgwbsWIcTYwmDxVMRlOXHEYFjRwnAHdaEQgLAxLU3AFAIjwZTYhQBJitr/1WexSFMSl0xNQuserkkB1IyNpD15vk+z4zOwqtVqd97dnnhVTY6vhR7Ah0HaaiMEwkFqjiCgCdsbXW6GlhZ6WXum0QUAkI6FofVESEWZiBGET8uF3T3jYzc9YHiTP21wYZIQwIxh0XmMVaZHYJm6qqwPUQeh4zl1lWFLlhDuKWVhSFChSB5awsijTLymJludeor5iizMqiZKO1H8UxUujPuAmrqiqNKU3V7S87B4SZK4vgeOx0URqLpKPYdy2MIlBVlbbG90LL0Na+74cikuW5tVYpNR4M/SB4/PBxmiUvP/eC1npv70Aj9Ls9j/DO7U8PB/udKLxy5cqZM2c++9nP/sl3fhi1+1VVXH/vFwsrq2tnz545c+ZwNL5379758xfHg+Gjx/cX+v3lpTUxPJgO0tEouZn1lxZXV1edCnQ6TaJuTEJWDDookWFQEPp+q9OZVmklbFGsQqUDP/QXlpYWlpeKonrvow9Z5O///f+0TLK9re2P3vsgUPq1F17aWFlbXlh85tKVfqf7w+9+70fvvOMrPZ1On7/27Fe+8pVbd25//4c/iNstQLQgcRyvb5z94MMbWZatLOvx3lh7UVYUcatblkWe13SpmnyoGXStzJMLAgAyEtWEUXWwNXu+gAEYhBlnoBWX9KupIYREAAXEVSGFxKmtIwoQOtC0ODFeUk6N99gI8NT/ZhCkkyMRObUCQJiroYKw62o6NhLUHYooCERzmkXArhpcR9t1lK4ICcBpxVuoZQYV1H/HiCdHAAJhoCcjTuRTI1qG0/efPgK4L/kUB5pOZcJCBjjtPBHBCiIg1N279fIGQiSnOuh4HHrdWK/Tdj79fIBFUBCdnSSpxZQAWJjFwGc+8+alixe/+61vra0sLvY7nzx44B0lDuoDA1oSdGl7QHcODABSm9inMIKdfqqn7HQJDK2VBYOAgCovzeFo2u3k3VbcjmIx1eBwvxNHl893t3fHP/vZT1959bXNzc3SWEItgEma3733oNPu+UHw8muvri6vRWFHB/4Htz4eTyZBp7XcXfiP/sP/zfd/+P1fvHd9fDjAEm1W3Lx58zt/9qeTRxVo6PXg3Llzl69evXLlyvnLl55/5YUkS40prbVCqJQS4bKqbJ5Ulf0rf+Uv/8qviO/7g/Fgd3vvzOqZl774YpnlxFQVZTvobKxuXLt0dXlhkdk+eHj/Zz/56d1PPwnDUIzd39lVBC+98trVq1f/y//y/72zs/P2229nyXR5eTFPU1a+MZxmOZBaXd/oLiz2lvbLwiwuL7VaHacSJmKBxQHrRFiIAKSmjQEkccUc8f2AABBJ2LIVFotAQMDMjeIXiSIPNXqonbAkkyhQokCDEhIFyMzGtQYBsCYPXQkHuNdbUAoJlIhVyouiwFc+IKd57mJR1xkLAA1fHjNrrYMgYGZHNB3HMYNorX0/9DyFqFxy0Nrq2RdfbhTPRLBpT9JZJS4ZB4Q4qyYJOYojRkErFkQ5aBogjKaN1sTRBgAVIxFZCyQOtIIiJICVGGGH4AcBZGBBAYCKrbVWypLIuHhchEh7oHwWKSxQzXdDHClRfmHBNVYTUZKVg8HQGBP64b5MTFVzRLBTaS4KZna8lQ5Bnqa14PM4GU/SdHGx5bigq8rkVQkA2vMQVVEUnhd0ewoAnDYWeXp5dRkRd3cwgoiZf/aznw0OD197+ZVuu9Ntx4gqS4tbt+5cvnz57MaZF1988ecf3EAvHCfJ6PDg3Z//dHF1+ZW3Pvvcteeq0jx4/OjKlWfa7fbDe3eLLD+7diZsRT/68MclmKWlJbC8srLmXK1utzscjNfOrKt1RQJouSrKPM3ysgi9KAo8IBJNKoqiTpu0Mtbu7e/7pMIw3H+8/cmNm1WSvfHyq1/64he5qBTitctXr1y8dPPDj/7sT/50f2c39ANkeemll6qq+pf/8l9+97vfvfrMM0Q0mSTdxXA4GgVB0Gq10jwbDsZ+WDkQXGU4L4uisqQ81IqZy7J0kYHroUVwiNmnLar1AsXIgtDEvjNwroZZ1y4BotSGEwFr4oUmcG1EdZxFmRsB4PT40R3jtP0OWwyNP1AX8aCWy4Vjo4AjlDipyAskbOTotUj9W3YGQ5r+UAcpYma2fEqCtYm1n0i/atQCLELHR0GYeTl/kbFOpZ4S0Yp5MsZ1LgGclghmBcol5pvv1dUQxFiAY62x9ffytGnxlMjyaWbQgmPCdJjZWd5FRGs9GA+nyWTvYO/B40ePtndAQbsbFs0BZ/OEBLBG8NVnAICCjOAEGp8a6Z5y7gAkzEizwsPRWw1bsdZDUSoobDEcT4fjyVK/M51ON89s3LxzWwjffvvt92989NHHNzr9Xn9xaTQaZWnd5MbMDx48KIqCSF+6emnt7OarL2ml/Vt3bw+TyeRg9MHh9fNrZ5+7cu3Bg/s/effdj37x3uXLl//T/+1/PBkNHz148N57773/kwfv/+TB+pUffvWrX339zdfG45E0shZWKmvyPLd5Odo9iL0oLYvdnbTT7r3x8pv9Ti8bFcW00Eq1g9bGxpkXnnluY319PBxuPXzwzo/fuX37tsvQ3rl5azAYfOHzn33rrbe+8Y3f+eEPf/jCCy9kWRbH8Xg8VohRO4Jpof3Q98PVtTMXn7l61UpZmiCqkY9uWVaIBA6zJCziAq2jCj0iIlZVpZFm7i8IguO/IyJGQRYh9EihVr7SoMgV7J6U3ayqwsXWSOIrnwic0XWq0wo1s6lfg7LWkndMpKQpxbrqr4virLWOkcPzvKqqlEe+DrxAa/JcYyCDtRXXUTgJCjUiofrC1eePYA5zMuBFVs7riTrQBAAUaeY46Of7nxBxHrjRWGhETPIMTnZC1Jg350Q0LL6+7/tBOJ6meZ4nSdJk2MMwdFQj7s1ElCTJcDh0tNKLvUWnQeSk8ZxvAgCOmsRpvBRF4SgJ0zR9vPuw2+12u10iyrPSFY9Jq7I0k+mUGZwwQ3dhEQCiKEiyaRQFvlZhGJ9ZXv/ggw987V++fPlw/0AhXrhwUSn16Sf3fvKTn7W/8mXte1/44uc+vHlr92A/y4ubNz/OK1MJ/eX/4D947bU3iqIae/7CwoIY+/jxw5YfL68t/e2//jeuf3T9wxsf/3h758zGxtmzZ7vdvinKTisyZbXzaPuT23eqtFxaWGzHcVYU0WJ7/cxaZ6E/ydOsMtbag8Hh9vb22uLqh9ffe/+nv9AMv/zZL3zlc1+IlLd1596FCxdeffXVF557/uH9+//23/7b999/PxmNFdLf/du/1ev1/uU3vvHjn/yk2+sJIXm63e2gop/+9N3l5WURGQ6HLqvfbreyvKiqyhjDLOSEfwSsMEHTXuLws3XYhPMGrfneUYCJnUWAo5ERCAgFUIgAFLseIxIEM4MvISEwIGH979MMKjZHfGJ7WoKcLSM5afp6CQZxKSJoXs+P1shcqlmcKWKsf1xUqurqLLLjeKqNmaCIoFjhmbJvvWdubOrNJ/YL16lgODYCEJIAuFLtv3OcPYN8WoQtjO6Kjo3uWzvtfAQIWEAQRVBmpDHqKUEt/nsa4KfUXEHQcVu6b2z2bTMk46nSOivKD2/c2N7fKxke7+51FnpFVc2sOaE4fgcgcClzBjje5CYEcFIhoz7NU+fP/Mkjz+lGk62xg4iorCmnSb57OGgFer0dPnflfJInH9+6PZlMgiBIEvPuu++urp4RRHeqoRfGcWs6TabTT0nr4WT8pvLXNtbffPWNfq/38Z3bW7s7qNR0byiFfebC5WsXnxkODz/99NN3f/jTq89cvHb1ymuvvAwAeZ6XpvI8b393rwnUJmkyGY6Gk2GWZVKZDoUT1P3+4ovXnjuzdlZY7e/s72zvXz5/KQ6jtaXFC5vn15aWbVk+unf3gw+u37718Xg0XF1dPTw83N3bfu211956661Hjx79k3/yT65cvqwJ02T64rPX/vRP//Tq1asFy/b2rlJe1IonyXR3dzeMWlYwm3FOEZFCN9akY14YOCxFY1wUuC4GZoQZPxuII5hBqExV528RLTFaa5R1xDqu6jtfvmFgdm4bO5+cldsNUkwTrcmhD4SRFIBFYwzVZc1jxg4RNSKzlNZIUTnNNJcaXFxcMJUpcguZaPS8UAc6VL6aTKcOUOicWEbrXutnXnjp9Iku0qQWj5X3zDF0TPMrZ4AbM9wEx2VZ8hylXEMsh6AsVyCkPYIZ6EJr3ZpM3cwljZ7ylUcKtSA7gXHnU9iK8zJDIc9XeZ5XVQEATpaYZ9IuDk4FAFVVpWnqqt9Zll197rKTlxORpUXf8T+XZbmyup7nOTNorY1wmqZlWRLBJ3dvdXudbqfje+FSbxER79+9f7B/uLe7a4pyaaG/sLB466MP37v+wZm19eXVpddee2V/dPDJvbtlmR8cHO4eDOLuwsLy2iuvvPb225+7efPGJ3duPffcC+srq48e3t/e3lUD89K15z7z2psf3fz4Rz/+8ccffnT27LlLly5FUZQn6ccf3fzpj368twWBByhQGrj4fO/5V18+f/lSbqskL8j3jHAxTX/3u/861v5Xv/jlL77xmX7YGjzeYcHnL1556fVXL12+fPvmzX/9r/6Xn/zox1uPH68sLn3tl7/68ssv37x583vf+97y2ur6+vqn9+6eO3fu2nPP7R8ODg8PhTAvSiLth4FlyvM8TYuqqkAIiOuZcWTruH5SQOrkB9inxTCM4Co+NfwKwKWha+geAwkh1/ZYkATFEpGAZVRQjwyE7LzYYyMAsggAErgqz9GIcnIPwcw7ZlDgjsBC9dGQhdGlgo+NDCyiGACFGABECSKIEpD6NZABQNAGAERZax0yzaUHXDYI6lQ21Vp/R+MsgYDgFBCa0crME5kfAfC0fPKfsyl3tCdGRjltPwEAn3KeZF2QD0fXBQDIDsR0SsTscOtP7qen7J85NCf2AxG4hmdHVuWQewJYGbu2eW55bf3dd3/KiKtnlofDYVqWDlVPQq4NBaV+DeAcRnH0Is7/qi/4qeH3E5vLx8xQ0G56g5CgU8zS5LSeUFW2Go7Gj9h00SiTLy0snDt39mA0Xltb88PoJz/9YDi+s7i40On0RNAU1loO/UBEbt++7bQwX3nt1TObZ69euBL40criyt7hwb0Hd7c+fbi3td0Ko97iwmdeev3t19547/2fpePJYG/fMbpXVZFlWVbkk2SitVa+p7X2PNVqtTbW17tRq6u9jaX1lZX1qpT7n27v742W+iufeeXtwAtXlhY219cXet08ze7fvfPjH/3wgw/eM2yY+fHjx4eHh+fOnfu1X/u10A/+f//D/7i0uPjw4cMza28sLS09fvz40qVLYRh+evvTnZ2dtQuX+wtL0ywb3/4kjNtRq01EC4vLiFg7kgyCoEQYrcnrEM49BNKodYmz03V9sw7wasTcKfJlUVQTy+CcLWcE1/TFzChQkmuEFGBZWFjwVK0MLSKaFABYy07ccj7jWx+KZ4+FiKd8FcQiAmzzquSZoIvDbTlN4k6vCw2kdN6QZ6Zu1Ju3uADgEF+OWVBmzY6EqIidppjUjKn1QZlBBARcNCHMINYKWiIlAgLI7Njs3M2ySiGzIAJYsdYURVZVVgCYwY/CdtzyQp8EC1NmeVHaqsqHqAkZKjYkqHytUUnKxh4ZYJpJqrk7VRSFtdZh0lyQnWXZpQsXRcRpyKhQa60RlbGys7PHzEbYWlsWVZZlSZaWVbZ5bs2lHIsie/jwYZ6Vg8Hg/V98+PJLz00mkwcPHvm+7vUWxuPp9evvX7x8Yf3cxvnNzfE0/fn1Gw93D8ppev369cLI3t7BV//S1y5duDwejoSrlcUlRXTv/u22Fw0e7xwiLsXtv/5Xf3WSTD+6+fH3v/0ttrDQ660srv7m3/iNThhronSajZKpBIShPxmN9gaHj3f3Dicjh4r6/Fufu7x5/sLqhi7scGt3sdV56eqzF69cDvudd9999w//4A9++qMfp9NkdXX1rdff+NKXvvTee++9++67pTUrKyuj0YiIlpaWdnd307zY2NiYJOl0Ol1cXC6sEcDJdJIXxiIQaYUoLGytuEmJFhyrUT1JpNbJwzm0rQsUhMBJys8Wr1nw4VbSGeRWAJmIAQEsAmiei+GwGS1bQReBHY3N2nlivyA4hqOT++vkMls5QvbUwF+X/AY4MTLVT7jA0Yvm0ZrfiYiCLts1x/w0Y9eCp6kPPcWgHlMfPNoIjgMy/p0bHwXDx7fTAtRZXv60Sqe16C52dr0ijqoUwUkRHB8FQE7b79AADsE0PwriKfsB7BFsDwBYXNCJ1F1crQwMJumN25/ub293F/sQBH7cqdISBEHINRiBC0sFgFFQCaJLswvWDhXIv9/9fHoZGx2kwYCg9jxgZhlNJtd/vj/cefDZz3/h4vkL8XC4uLoWtdqLS0vf+d4Pi6rENImCWBEVRcFGPM/LkvzO7U8Hh6Pt7d2XXnl588LmYqff63SCe3631UbEiquth4+272/t3n1MPnzuM5/J8mSaJsYYRCmtSdM0zdNOr4eIguzAqmEYBpEfaI/yYrC7/84PfjAZ54vdtWcuXltd2gh0dGZtY2VpodOKJ+PB7Zvvf/The/c+vZWnSSVsrBmNRsvLy1//+teCIPjhD76/tfXowvnz77///ubmZpZlD3Z2nn322Y8+eH9na7vd6y4sLHS73bQosrysEb4Mk8l01hPvNLQFBRBRedopvoBLNc9MUhSEROKpGhxALjkNoLVuchiNVQMAnqOOEai5ZQTZ9wMSj5mdRXcmA0QMs8wo7hFRkdZag0ZQwuxaxQFFcAYlhrmkjlJKaZ+IRKxkQgGR5zlYMRFVzLaqoCjmM8QNyZquKiOno6CPgZaba5OqOno+G6dDoHkPzNwWdzQ/9CyIGFuxdaNrXVjo+qK0QiLf8wBV4CMLaq8251aSJDGVRQLf97utqAxLrTVXNW+qE80ty1xpv6pKEVCKALCqSmsZQIyxIkxEnqfjOA4CPwqioswPdnaIyCeFikye5cYUlTXGGMNlWY6nk8lkIoxRFEVBEHrR5HB4ONgPgzj0wzwv47C1fmZte2drc3Mzy9L94ajbjlc2Nh89vH/r7gP0g8WPPr767NVWe2F3b3Tj5h1k2d/eOtjbb4eRNeWv/dqv/fIv/dKPfvD9x1uPVtfOdjqtZLo3mQ7G02lecFeFq0tnlj+79uarnznY29/b25uMx8l4MjkcV3nhe16n2z2cTu7dvjWeJL3lxcub599cXF5ZWVlbXVVAZFhSI1bOnT1/5dyFs8urRPpHP/rRn3zrzx7df6BJxVH0pc9/4ZWXXv7Zz372/e989+6Dh6S9rZ3dB48effHLX1o6c+Yf/Xf/+Pyly2fWN7IHDwEobneTg30/9pBUViZKa+1rJWTQWitERMotuK6ehi51WlMbYp1OrVtrEOqI05JQjUyuY5oZjEZmbMxSEyrWFhprco96hNOqv/MZQnQCTSdGVKfuFwIHVHRrpotVnft96ohzLUjzL06kTGvPeqaLgqBc4kzQikNWOGDVCbQ2wNNy6E8BJTnD/BcPgpn5lALt/IUcPzoI8VPOqP6r5g9FBAXc8dF5VHNjXQN+2nd26vnUX8bRiFATnsjRmgv11CDZefSoqoq1tbXBYKCU4izL0wzF6TE5DIGrf3CNPBAQYIEZiOHPh/GfTog6wxhK3TmmBAQZBNhYIbAWCIxPpMMYWLhKIVSd5XVW/rQ0g9H49t17y6trly9dev/9D/b3D8fDZHVlLVpcVqBEUEADesPhcGf/YH9wOJ4kr6SvXHnm6vLy8uc+89mf//zn9+/fN8L9ds/XQZFl42T8R//mm0Hsdzq9djuO4zgKWv3lBc/zrHDFNeu1iJRpuXdwWGWpZ0UJXNq8srS45qvYGmrH8frqmXMbZz2lR8ODD95798c/+sH24/utOLh69er3f/QjPwojP3z7zbc++5m3v/nNb/7R7/3+pYvn33vvg7/7W3/bWnvnzp033njjk08++ejWbUP+hQsXwlbLFU3brcgPfDZVUUyRXQq6fkA0gaPNKau8CTbVXG/6aHDQyH5oUsrTntLK03mWAKIiIqU8rR1vIiD6Ws+loFls/XhmVcXAwE6oxQNFiIQi6TQhQica6JGmuLGUHrMRsUSktSIiZrQWXPeRA2Q5lTVrQWxFCoi0RwoUIUvF1pZVVZUekdMhZgSNJFo50CJ+4x/9V05ZvSzLmdQPOgt3wlw7iz1NJk1Q7y6JmZ2+MQDUei9Q53VLUx2OhoColSKltFJKa0UEiNaY+ex8A2JQSjV8tnXnFgsARHFgjDFl5cjTG6dhdm4eojBDVRVVYYwtD/cOHe2100kDYGAUsVWWsBhbmUY41hph5p2dPQAgojAMgyAkoqqqirIsuRBsKkVorRRVZQzv7u7v7++LyLPPPXfp0uXhcPDw4UNr8q9+/u3Ns2deef0NL4x+7/f/4Hf+5/81L6qrz70wGE2uPvvc17/+9V/62tdWVlf39g4eP348zSYHh1tllU3TJMuSmQqF0lr3ul1mKyIEzBbKIkvTNM/zVqeNSinPr4VZgBwuYDpOgLkbdS5unr9y6VIriocHw93d7X/8T/5hWRaHBwee0l/+wpc+/9nPPX68/aff/LePd7Zb7a4RHk7GFrDVbluQ8WT64N5DF1c5lmkjXFWmMqYwVhxmyoVcrg4MDGJn8NoZIWXNPFU7ia61pumLtZYZm0Dx2PJ9BJOZW+J4RhR8tC7PZt2p66RyUL8n2pCeavAUza3mR4vsCeaso+Pj0wzhsQzY3Hm6X5/sKXbkHU/ur132JpI+Xuh5YqPTA+M/r+Yqx3Wr6jigmnOs/yLHeerx69M6WWPWSKdis5HFoWFPjB55T6agHenj8a2+/iAIRqPRP/gH/+CP//iPP/nkk6IsLl48f/feg7DdOQLhuzJHDUsQAHAq9lBP1PlbSSfuPOF8+1YD3xKP6vq5o+eSGSe2bt7v9gKgCEJlzTSO9MsvvvCZN1/XIDc++nBwcNhrdw4ODrOsePBop91daHeXorjd6y3duXtnfX1Ze8qtiohqYan/7LPPXrly5a233grDkJkPh4PD/YPRZJxOkySblrbMyzxNsyxLXRbUwV+01qDIcYD4vu/VOp3YjVvE4CqH/U5vY/3M8sKy73lZMt169PD996/funkjnYzDwNeaDMvd+4+mSfYbf+Ovf/atN//wD37/29/5k9j3EOXs2XPD8RgA1jfOCNAv3v/gwaOHUbtnKUTleUHo5B3DMFTaR8RGXtMt4J4mrTUqKo3BWTfNfNm1LMsmIPSU0r4f+r7WOvQDZnbd/DMqG7bCoR+gIhSorGFjgTAKwiAKURHXlYujLmECVuQ1K4NrfHLrg5EapdRMhhNp7XoW1udmnfKjrYzTR3C6F8rTwOLYn5ueZIUEhPgP/x//N5ihohr91FmLjsxHzYgoiMZWTajv/tBhxhUcpbJRoGa0YFta06C/CJTryhJkhXqODYdmIC+eTVoRseRUQh3GQ8SyYcNQK3gzCTGz5/m1sS9Ltyi7lm4F6Piiq6pia2dXAWAKltL1jbERw7Yqysqwp3VljOMhUkiVNUVW5mUGWrEDuyCCoBF2TMg3btz0/PDZZ59rddoH+4Pe4kKn07l351Z6uPv5z7716mtvrG+cKfLyz773vT/91ncOB6N2v+8F4erG2S99+Zf+xm/+5kuvvLK7s/fu9XcrW+RFmqZpmk7zPK+KsqwKrkwUBUVRlFUObIMgcOwinudNp1MrLNblN7TL+AFLu91d6PXPnTt3buOs1t69e/d+/OMf3/jow+l4/+GD++249aXPf+HCuQsPHjy4dePWaDopC0PaY8K0LIfJZJpkoikIgtHBBFhcJd8IG2PyoiitEZc7JmdiFcxsiqotwJFD5n7VBFqutafRoG2cvBOL+NNsDM12n/iTpxpIV7V8Yjv1+IJgBeeJOBo6joYb6wQRR026f5o8YvN6nqkKGKWuZ59O7nF8ZEJpzqEZGy6t00Y69fgNwciJ4ys6eY2OP+sp738qLcmfQ1dy6vi047sl6ckrPbG/uf/CBmZUmvPzYTKZfPnLX37llVf+4T/8h06KDgCSNPeCsJkN8/OtceBOHMqKqefdEWJ0buLJvOgCAIieo8l0i5+bHkTNkk04q9MBWis5S7Gy0H/h2jMXNtbJlNPhqMgzk1d+FN+7//hwlBqgXn/5wqVnsiJN0pFS4LCQjnmw3+8vLCy8+uqrm5ubly5d6vf7iJgkycHBwXA4zMq0dAuiMSiCSgWeh0o5eE7D4NYwtYHhxcXFteWV/kK3HUeaKJ1Ox5Ph97/9rYcP7x/s7YdRsNBuF0WxvfN4d+/AsPqbv/G3+t32z9/96eNH90eHB8aWa2sry8vL0zTPy4KUN86y25/cLcpq4+wFUZ5hcPlYp1mJczVat9G8UqciIGwUvh3vGxD2u73KmjIvSlOxse63Sql23Goo5xxWt0nZNiJFLk4LgsD3ffe8z325x5YFnNvcP5kNKnrSAOOMP27eDAMAcI2UdnCoOpRXykXMTZ646dfV7vuDmSPsrH1z3k2g6f6YHdj4aDrWsQ8AWGOttWK5KRgDAAF2W7EDVFiwbnQtTprAUW9YcE2agsIwk1hBcLR9UjdYgihVC+84rmBEAUbXAY2IYaDDQIvLBVSGmSejsWOMc23btasFAlJZNmDFOhNsjK3KqrLEnmUrRhy9ugUBNgjseb5haw0ba43hwlR5URaV9X2/02vneXY4PKwqs352fXNzY7Hbvnvj/T/+4z/++ObtL375S8tLK6+//nrU6vyP//S3qyLXWo8PD7737W8NDvd/6Ze/9vrrr3/pc587GBxO0slwOByPh0mSFGlWFEVVllmWiEaxyFxVuYzyZIyp+xa073darXarHcexrz1mZmNffPGlhW4vCIK9nd3r19+/fv36w4cPi2x6eLB1+dL5z372s5fOX7p/9/5Pf/rTTz+9p7U+d/7iNMsZEZXO8vLR1jYqtb6+4XmetfUkmn37YK1orermoPnaLqJihXNTWWbrU53UdZNAQFGzzNUz34XER3P3KRHVLHV00gA/PTKDOTDqif2nHd9WgEiIIqDqchEIIqlTaDgAQGZMWHJ8bM5p3jg5D/9Uw3OqgRckOq1hChGfQsQBitSpx+fTDSGRK0/DrGKAACxsWT/lODhrNjo5no5Df+pY54Cf2E+z/e7u0QkDf/xzAYCJSE5h4htW44vnLo4OR+k077V7ruUhDAJAqssLc6sqzMQnTswlQQTw4GhdnjPDdTnk5DQSZkCeJchmK6I00wWg7mCrn4w46pQFDYfT99//sJhML5zd8MIgTdMkz3qLS4uLi6NJOplMK8NBHMVxnCVTUuj7vu/7CFDk+fbW1v7e3sH+/ubm5rVr1y5durS+vr6wsHDp4kUB2NndKk1RZHmaZ1mS5mVRFYVhq0mRVp72WmEQBaEfBr72lFLrq2daYRT42hgzHh4+fvz47iefPN56eLCzbW3V7/eR4PHjx1tbW0HoXbpw8a/8yq9mWfHf//f/+Ac/vfGZly9snlmfTEdhGO/s7DFAkuXTvJhkeVmZ3sLi6pl1Y48ZOZ4xQPn66Ets7I4Qep7nnkckUjXdKAlAniVOtpBAtKe05zn94Mj3ZIbJcmbSWhZhpbRSqJRyJDCIqDUphaayDrAAs+R2c2JHoS0R1EzywszKGRv3DIrUDzUIADDXnKhNvC5U9+PMx64AkKapq8k6dd1mNtbMWO5sXMjofEMHwmqO0iyvbPkIdSJHmy0rBy2juU3AalVndrA+iIAwAbOtZEYWzxZqzl6xNMv7g9RwMGQR5CwrxZrGuqPUKpJNSsp9tWVZVkXphJEd3CDQ2tEfMjOKtWzBGmuMdQqxbAnAU5ClU8NWLAMhowZEQtGaTJmXLLYyxooxpqxMWZVVZTY31oH0+++9Vxn4whfeJpB7n3767LUrk6Ulpf08z2/evPm93e9vnNt88zNv/5/+j/+Hf/47/8IymCrf3370Z9sP37v+sy998Stf+NIXX3/zrThcXekv5nk+Ho8PDw8no1GWZdzu1zfWWrFHLKFhHMkMJddv9xYWFvrdbhRF3W53Z2v7px//7MaNG/c++XRra2swGOTZ9LXXnv/c229evHjx3r27P/7JTw4ODoIgMFaMwDRJk6JkUtM0y0sDyJNpQohi7IyfXuq5i+QcL3BLIbrKrlvUBABIwM767dzpNasegLjCaW1LwGK99xhx41MMzBFeGo8vgL53OljGlfpO/dWpWy2/1Dx7s+1pKW5yon5Pj/ZORNJPG9k8NeJ0BPXHDE+deDj1/XyqgQT1tE+vjw8AROigk1bYQ3W6oX3K+DSH4KkjnR4xi7W1ueXaGM/GU44DrmxGiAhu3cOZeHvg0eBwP8uyOPTyLGHmKIrcQ97MQ2xeIDqK7yaQwFk+z9NqrnOUGsZvcM1yciyR3vCAzM12AKCjPrxZArtpg7NGAr9lsJgk2Sd3H0hlVpf6YRgODg7zPA8Cb3VtKe60h+P0wb07pHV/oUeWENGBTJ2NIaLt7e3RaPTw4cPl5eWzZ89evnz54sWLi4v95649A1CDieZriy56dvlnFwu6eLHIsvF4fP/e1oMH97YfP97b2x0ODtJpEgUeAJuqTNN0PBz0+/3X33j1M299dn9/8Gd/+m+Hg8OXn1nzCMfjcbvTqqxtd7ulseMkn0wSh6cdT9N79x54vu95fhiGURQ1WdWG0cGFrc3WhK3zhtl9y67DpSHBqKoqzQsRCVZXm5iyOcJcafJY5MoOCXxaZefICZuZPLf0iT0GmnAGSOSYlZ2PjJ+Mid0bnGF1iZnmq7HW4u/8N/+vecdQ5oDQp6xKAJaNIAPPvY0FZilB5e4p1QaPmS0XDXNvw9/LwAqVK4a7Hyu2BkPMTrrWtBTrJrm1FuXoVog1VVVZU/U73SxPxuPxZDIp8wKcT6F1O4pdGd/dL5eXd2n60hRlXpWmcmkxYGQQU1aGra3YWCtWGEQsW5RJkhhwyHdFRIDKChuBMIgMy82bN4H0yy+/PEmm49H0pRefX+53bFm99957o9HomWeeidqtdrv98quvxXH87e9+99vf/c5wOOp2O0srywv9pVa397kv/9KZs5tXr149e/ZsHLSstWVRGGPu3r1rjKnyoigKa5mIPKW1VkDohV6v3el2u3Eca62F2Vr7zW9+c39n9+bNGx999NH+3l673b5y5cqF82e//rUvbj2+f/v2Jw8ePBgMRqayXhD6YZxmxd7Bwe7BqGQRrVjE9Zd5QA2Arl4yhJkZ9czgIQLy0WJj67xbw7jqvj6ljgxkMx0JAUwFAPMm6s9LZgJVIDV49Xi8cnoEjDVi4C+8ibUW6Qhj2IAbTk1ZN97en5OSPXFdT0u9/jkp30bqoNkDhE+JmJ8WSf95d9UKA4tL9AGhEwv/d0TAf+HP/fcdbXVMlKK5e6emoAWPHKbGy3f/fPjw0a/92q+Ox+Nvf/u73W6bmYMgICIL5sQkbCLg0+eS9hiOeMcsOPpKQJ7j4m7Ag8jWFoDCMPOQEF0b0qyDy4HDZ0EFQJGVgSKFgFxqtr1WuHlm9czKsq9VnudAygsiJL2zt3fn03uTadrv97XWcRy3Wi1nWpwxbvponSKqy0t3Op2Ll85HUdDtdvv9frfbbbVavu87H8Va6zpWXcXLta7evPHxdDodD4fT6dSUlQhrhUqpMk8PD/fTZNrv95+/9szly5cDz0/T9M/+7Nv37n7S7/fjwH/06NHiUv/chQuHh4fd/sJwNLn74OFoPGn1+kEYZ2VlrNVKeZ4XhmEcx2EYOrs1D99xZekGY9QEhPMG2FWyG8PW1BxdyxAROZ7IOI6DIGgoEZvp0ZgqAcAnMBxPriTNHkYQPkbvCDOz2DgTzanW78GjHLVbSN1a2m63HY9C40W5S6gj4GbRadYddwHzcx0RFQiSZrCAtXIyQB0J+b7vFmIiQoEZlLoytnLcueBowdzDRqRRWUeXAe4HqJYGsyiuQ2Tm9ioEtu1WLU+mqDaoZVnaqhgN98VWaMvYV7GO3DeqlDJVZStbVaaRniBAVMRsrSlMWdmqcpO4lqdFJFfMFmtFkBlEUDDwtHYlHEKltKBiEBYsy6Iw1XPXnpmmybs//TFpfeHChb29nTJN3n7zjTNnzly/fn0ymRTOmn5y5ytf+crXv/ZLF8+fvX79+vb2NhGV+SSZDv+nf/HPVtY2Ll++fOnSpXMb59bW1paXljqdzqsvvISImki4dmXqSFEhIHNlxuPxvTuffPzxxzdufLi9tXX37l0RKcs8z/N+t3Pt2rUvfOELr7z0/Cef3Lh9+/atW3fSNCXSytOGASqb5nlubFpWpTFxt9ft9EpTTccT8pRUx2yPQppFRzVVomDNLKUQYFacU01XgQi4zOvRktfYLVYEVFegZG6qH+2ZHxkkgIa18tgaeqqBBJTGh/t3Pmb155JD0jb/yew6Tn0/wKmfCwDzkVb9twIATKejjsl/GnT5SPgdZs/2U68XwOFaTzvNp4DUlGcMu+ZkrUkpEh9d68VTzuf07c+HDD+5WXv6fXDSQ3Of3ty9085fiIln/L6sEYWsRsfLDZvrC5NQIcBavyUEw4NBt9e1tolgmzMWEeGZ+uL8hzISi2F0vc0uD0eAtqYzqzeaY7EGi05QpK4scpMpdETZ6Pq+hBEEBIRaYVRkOQhHnqe0yrJi6/FOOp187q03h8NhGEe+JiBYW12qqnLv8GB/b0BalWXJYgI/IgWKPKWx2+1VpnCUEUVR7O5tDwaDMPC+/71vhWHYbbfb3W6v0/HDMPA8IGpFkWMczMuyzPMky6qiKI0pskxEPM8LAl9rleX5dJIZU9688eH6+vqz15558cUXr125HATBvU/v3r17d3vrAbI92N0Ze97q2vLi8nJRFIZl/2BwOBoPhiMG6vUXF1dWK2OrqgJhZoPsXD8mT/kqAAVVXgmJRx5qR7XBYoDRICkEB4ayyBpBFPiEPNjd9wMdha0oDuKoha2YLVjhra0tEXEm2ZmkJg6Gudi3+eZ97c3byMYDe9rzhajwKSAsmHPTm0MR1aDO5il2NtjxM7o3uBAxCAJrrS5m/UnNH7iDxnE8HxDMVgSXY6zfVsNWXSII0VrLxjoUQ9PXpJEAWSECuaW8psauCuMAAYgMjtIdHCODAai7AhDAJaIRJM/S+lLFMnNNPlLkw4PdwNNRFHXi0JuRYVlTFElirRVjnZfUXEuSTIzUjVxUs+qIOGZAREWIgOTIfoQEIIhaxoq11giDIINFBrYiXIoxvlbCdpxAv2NaUWCrKo7jd6+/t7i42Or2siy7cOFCFIc//P733r/+i69//Wt/+au//KXPffbHP37nvffeOzjcQwGtZH/n4faju+98X/XaveXl5ZWV1U6ns7F+ttVq9Tr9Vtxx3p+7/Bu3PkiSZDAYHB4eOvnINE2qspyMhyKysND77Ntvvvn6qwsLC7u7u7//B//69q0bHqHLOOVFlRZFlqfleFIJloaV5/naV17gmtxQaQABZAErcJScJSBrrZsIAO57ZwBSjpFGzQLcoxIw6Dn70mSPEUgTq1nHsJv5ztw2e04kHaX+0FNs26nPCx0j/p0/h1MMDAEpt0geD4aax+nJ7WmG5ykBOsupDbZPvwR0XJ2MzALgEq1IRE9JifNTi9tP+1yRiqCqXCAlnuc8z6da36ctTP++21Ps78nvpfm4U69XkCvjDDCAgmZk5JUQ8sH2hbWNNsByyzNi/E7Qioita6mQJus4+wg88ZUBgIAYRD6CQB99sG3ACMe/OGuVi8udAbYgUrPNgKNOYUSuG+pcO7KvLLAxCsFXIszT6TSZTu7cuTMcDZ5dfhbAHu7vLa+tXji35mlg5jTJsnRqTd5qdcLQD4LIoK3KPM9Ta0Vr8rxAKVRIIrS6vEyECqnI0r00teK0gpiNJa187Wnf85RGRQToa6WjqCxLtrYsMjY2TdMqLwTsb/2tv3327NnNc2eZ+cMPP3z33Xdv3749GQ9tka+vr/cXFvv9/sLS0uHh4ePH29oLVBgq7fUWlgQJUY1Hk9JUSqnY1wBsLbO1XFZ5UYNw23EHEUAI6oqIsBAAWyTXBQPARJotimYiaMWhUqgIbFXayjQCbP1+t07tCtuyKKypiAAgDMM6PpxLkzBCWR1Z0CMDN2fpjj2/iNayQnGApZlVQkKypjy2VggIC6OLSmoLTCiKQBQSUppMaqNJ5CQcfN9XSuFv/5f/z2YWzufcnVPcWN/ZZkHVth1msW99eQCuTaix8wBAYALfqaOeTBk5uYwTDx4Biz0SQhcREAfLsl6TuzCVI7dKkqQq0vNnNxTWXxgwWltZK8DGGnHoW/dVlWVelsbaand3FxW4O+B5HoJyHgoAICqpC+HWfb1WoGRxzCksSESMJAwMMk1zBkzTtKys53lVZfM8R6XjuO37/srKSrfbJeE4jgFld3d7MpmsrCy99uqrb775erfbffDg3o2PPtre27+7tTVNsiTJAKAdtzudju+FiDg8GCIqruu/BgC08rWvtKd0oCM/QK3KLN892N3d3h4OB7/yK391c3Pj8uXLi4sLWZbdv3//7t27+we7mtR4PPY8b2l51Yhsbe9Ok8IPo/3hJMvLgq3SPpBfVKWpGJDRlta43A47sTAiIpSmbQAA6j4ZAQDwNc0WM2lmJLlEYT2vjpxQJeyDKNeDW1f6aiWiRo/oxIinQV7BKVmdtvn69MjyVIOKIoqY5gx287an1oCf0o/b7D9+ts5FPeVQT0NxI+jmYQM4QlQ85Xwcp/Epv2pSeSc/t5KiKMqydFkrl5+cT32d/ICnRgb/vhHz6ceZjyROZOCefDMjFCUfi19mm3uEf/3Xf/13f/d3EbEoisXFxbLKxTLUoP6jGANm+NUT1yIAFvUs4VIDr9wZzb6vuW9fCABqoReow18LAkDGJT+QAMCggJDDRgh4+/tT34u1QgSjgT0lKMZWma241w9/9Vd/tSzLGzduXHnmahzHn9x9oLzowaPthw8fZlkWhqHr5HFJPvclhmHo+z4AeJ4XBX4UhETk2j4diKmehSJIpJVy6zXP7gVbu3+4Nzg4ZOY4jpeWFjY3NlZXl1964cX79+8/evxwOBwe7O48fvw4z/Mo9Bc67TgOlfJKY4IgiFrt0XDy4NHjcZp2egtBFPtBpLWXFQUDdrttqApEq1ycK1TZssyrosqjIHbKRcojp19EoMBxjIt1BQCF2vEhkkb3Hk/52lduD4ECQh0Gxoo1hkWaqwbEqixdUexE+2tZGofha5LbbiYEQQDHk8luS5PMoaBdlNzEcnmez/95M3tFBNTREZr9RGSMcSSMLhHtGo7wf/nH/3XzwMs84cbskXC/ciAgZpumU6XRZe3d21xtNfD85uy9oy4uIWSFtgnhHRzgCFY9p6LjTjpPEwQ5yv5DnUa/9fFNz1NhGLaioPYdEEEMmAqkcmAuZKy7h9kyQ1FkeVoUZeZMiyPCtMzaU86HNsaIuASDGo1G7uqVUs4ql2VZVEYFvnWgBiMiYgUAgAXH0wQVae0LKmPMNMnG43GS5dO0ePGFl1fXlre2tkJPf/WrX2234u9851tVVfX6nQvnNi9fubi0tESEJIC+Lpk/fXD/+vX3P/7442Q8CcOw1epo7QdeGMdxFMYkUFXORSAiGE6GQRTkWTaeTOIoWl5dunDu/Pnzm0EQjUaDJEsHg8HDhw8nk5Ej+RIL1spoPN4fDCxDGLUs0jTLLBMLWgDLUBowbE3FwkZBSe5GkCATOvk8YOMEHPHIJDgYI7MhFCKqBT0VIKLrAaM61TPDKAKSsCcGRRAJEYiU8z6bqNe9PkpQg9VgCY6mZbM1Hu784i4iZZ6dWFUbJ/LEQi8iCOwpUYQN+L95zFxJpUnkNA9Ig4VpMsNuP82kuZv1XSmFKEVRNG0z86c0/zw3x2FmpQK3toqI68UviuJp1hSAtdbMc/reONcNOIcvBXBsPpxlFcywJE027ISBn7+fDi/TLCXNIvW0vuFmO3H/G4e+2WCW+ptfCpqVQWYtHM3NMcZYZvJD22Sw5pY/z/P29/e//vWvP3r0aGtryxiDiJqQEGl2KJeoRETP87Isc2lAt5i4MzTCAmrG/jc7GUYRcfHWXIOJAICg9vxYmFynjdS6WYoJ0zQ1gCJiUJzLLiIMOqu0uDZTZmKLYFAMgmm14yrP+v3+pauXOp3OeDwuiiKI4mnGlsEYk6bp4eHheDwmojiOJ5PJ2bNnHRnA4uKiiOR5HkURWM6yZHdre5ql/U437rRDzw/iKNBeaU2Z5ZM0yZPUCAfa04G/0O1dvHJxeXGx2+2WZTkYHNjKHBwcfOc73zk4TM+u9y5dujSdTieTyerq8pn1VTaVQjGGrYgfRpXhT+8/uH3nk6tXr5H2tRc48mR2yVsULRUSa1TkKV95TtfaiB3sHzKKR5o8FQdREIdxEHmeTqep0hQon3zlobaz/pnIC0WBh1oUKCEDFowY4Uc7u72F/srScrvbIUDX9SsIDtMALA591EAjHXMczW1uNiqlXNeMM09uDyhaX9+QGa9UHZVZ69aBJhA9mopEbuK5bd6QN096PdOMcXSVWmYtU40j7KZdq9VK03QymYzHY6dYoLVWis6cWSNVE264dY2NFZF5goKjVyxGSsEaTNucK8woN+cXC/eIaq2F66S5KfMsqwkozqytAoDDYblqtiIkELElzrhAkWd3hGfdU2ChJo2ou8U6vQ4iuufZnYYxpTHQ6XQQ0VpxLbkiEoWtTq87SRPFyAhGWWZwiQYkjALNSOTY3TRFoQaJfN831aCqqslkYowp2D569OjM+trFixeJiMVYa3d2dpIkiYMgDMMgjsTHZ65cfPaZy5PJZG93d3/vcDgcpWmaTbM0nR5OR4Hvezpwq4bv+53u6uLqYr/fX1xcXF9f11q7SvP169f39vamSVKWZZIklisEVZZmdWWjrLI0r8rKai9QQSgikJdKeyLClTWmMobd+kLAChGREQGZHaRA1xlaQURFzgaDpwQREJmBCZEINDIREBJh812zdk4YIZEQggLwRBGKezhPjEdR7ywmJiAtQuhO4Og/ACnyYWNyVANWAGjFGuqE35HREwBF2hn5eYp2AI48BTN1IIXa+d1OmITBAmsrRqxuJEmU8hpZMUcXw0zMhkiJWBHPESYohe6duX/U3tBkvQCO0kjNY1kbeyOImAqIcDsgIqi8QGuapw6YH0mBiDf/fNUZOcCZASbXiCOimLFVVzfRpfiUQqXcteg5IN3RZzFrt3QxG4cIdtfOQXDq+dTkOU/oKzNrtx/nl0MnQOFEBsUyQ0O/Y60jbp6/z74RJs8zwmDZqd+AIgXICL7SnrS6Hlf9sBpr5UdcGc/z2Bpg645jrS5LQFSep1LNSqHnac9zyFsB0IJgZ/o5jrfIgjj4FVfsPrdih1kREmBQxpJhZAtWUEQcckRQosh3zMNW2DgDbNkARr5nUQELs0EhYBJQKKrMUmurweCg+qhYXOr3lxYXl/p+0LIwLStRSH7fX+wvZEU+ODgcTcbAsr+/jwJRK25oH3xPnTu7eWHzXK/Xc+vAzs7Ozs5OWZb9fp+ZYQG01u12e2FhYWFhIW6FGxsbYeiPx1NjytFoVBTZ44eP7t2712rHnq+jKHJSct1uV2udpmmv0yYizvPJZDqcpBYQSS2trBkGxUAs4NBVRESgSWlkQCAgpVC7wAcRhc9unKk7X5BdfAzC1pTtOCICrX3Hd+XmiZMIRBQ3IiqPjXhohJ+7dnU0nezt7R0O9vu9xf5C1wsjQDYVN7oDR/QaAFYYUB1ln10ogOjQS77nKaUajmW2/ODuPR3UKG7f9xt30EkTNg79/Pg0RxNmQWajIiwi2oXDM4f9qP13d3e3qqo8z621LlUVRZHve0ojogCwiKDTFVEoAtb1CPERCSWwCDCizNRaj/FnOdZoBmAHXBBnua2nlJUaQ2+qqsG51S5wVTR7tCJNGPr6KKSxs+I0gAgwIKAi5TnWJkQE4DzPXZraHcTztSKNiEVRaa19X2lNSqkkSZJ0Mk3GTimIGUjAmlqnzQKHnrYCLGwBFWLoa01RGGKWV1vbj258PAaAzTNrn3zyyf7BXhyHF86dz4s0LwszsGlWhIEXBIEXeIPRvpND6HXbi93OM5evOJB9HLacJFTg+Upp51iFYWiRfd8viqKqKrBmOBo+3Ho8Go3293d3drbzomq1Wt2FPhFlWZHuD6Z5OZ4Uo2mWVdwKNHoBWMOkrAPIVbYsS2sFRAiAQBAsCiOgwloaxlENaF2rhimFmkDV36aABhQmAl07lI6mVTQSEiokIpeSIY1IgD4hzhZiIt2YXsdWdmLhJjAeEM3wTXMmFaQVNDuPEj4oDgX9JCa5Bl+caBZC9pCZrVPnREHSpEk7l8Dh9psfh97X2nOxu4vRm8jt00/vumfQxfSO+Y0I19fXG+vbQD0Rsaqq5pk88mWZXXPCGJnZ9jqh52lrWWvFLKfVyI+e/MaKN2DL+eca5hK87v9OwIIIldLzeQjH0dWsJ+61o+hz56CUK0yoU8/Hvec4yO7k0eazHSc+sXldFOWsC7ReJB3QqRI2DqWgyMnPuaYgX+kooIB4udfKu3F3oZ9OpkHgsbGuaYgUshVjIwTSnkqmKRIQKlKoSLusGBEZtnMydti8BgMWBCw4M9wY4CwTBlXnSCwYYUFwUkgMYrnWXa3rsKAM+QaImZnJWue9oYhKpYqjdp7nO7ujaTIWkaqqinLvmWsvFZWZjidJlmpSUdwLtNIeLfa64+lkOp6wGK7KSTJFgSJPD3f2UOy16Fqv11s/s/rMtSsO5dPpdFyqwwV5iOiE5m58+EFZFQ/uP0yzJMuyw8PDNE339nezLHMxSZIkS0tLCwsLWmtEAVJAUFkejaeD8URpL4zbK2vrpnKtt0qRIkJPa8/zPCXWWABWgIig3IMMAAhx4M+pitU/iBIEviIg1EqjIqU0EmokYQtIQujQ8crBkTwQ5XtL/X63ZcqyqIrsYDf3/cDzdLvdAXANxQodgQQSI1hzRD5TS+8CAAKBKF1Tf7hOAVsZKwBQooAtq0JAfN/3fU9r5flFUcCJ+S3CCK4cML9SNeMJR9xtunn469bPGWx6MBj4vt9utxv4uLObk+mgSak5bQp3MBeY4yz0ZGaxDChak8w6epl5/uNhls5q8k4WBarKmsq9M47jTqfj3n+wtysiSnluGmmtPa2UUkU+FbfuCQuSgBUgyy5hS0r7qAidnywEwEGoiyJL01o9CmdJsOXl5f39/YcPH+Z57vthq9VqtVowo8ZkVorRoi0tMta65GJFgB3oTVEd2ZxZXzscT0ejMRF6njcajQbDw8XFxaKofF932rEfREp5liFJc8nS3b39nf29GzdutFqtM6tn1tfXW62W1npnZyuO41YUMXOWpXmem6Ks2JamaHc7xpjpNM3zfHA43B8cVpWdTCaTaY6IqILA7zBzniWD4STJMMmKJC8ZiMmrLBeVLY1NpqmrMzpXCRE1akIL1hA63ipSKASoEAhYeaQAFYIi8lzOlgARlPYQUQE6Q6sQkEQ5bQwUItIIWikHEkES7brcn9jc3ZufsrVDRhGgdQJk82MrjI5L6TkZEJE5VPD80U4cv/5QYGCWubarJr3cpGGbk3GbN/eAwQycKCJra2vztrCZ58PhcN4AN/udH9kY4Hnf1+WfrbXtdst5yk5zFJ6+NQ+UMcY5Z66422Sqmrc1T+L8Hzb3v7mE+ct3J+OKUFBnwtTTsuJP3rfG/J94w6m3t9kaDW+c5eeUUkCY5Jkjp6a57Hr9Tw2VycMgCCNvoddGMWEYEtTlYdcA06TZoihqCu1uj1tYrK3mzvDo1kmdmD4mXSOgTVcJzxpOHBEQiDCW1jCINWKMqbjOXhqhEpQRYQZrsLRgLRhGESCMwjhqtSKtR4IwHo93D/YPD9KlxdWo1fN9fzqdTtMsiqJOpxNFERGNx+PhcOgyma6vdDg8fDiejifDH/3oR77vb25ubmxsuMmT5/nCwkKv12Pm4XCYJAkR+b6+8dGHWuvxYOhkGxxeJE3T9fX15eVlRwmwuLjodiqFWZaIyDhJR9MkywsvIB/Q1z5L3a0pbAUIrCEiUlgjdsGgVQLGCXCjSFlkSAREKLUlBLEiYKrCACCWyiilKm211nbmRDq4A9bKoSQEYEwZxe1eLzDGTCaTyWSSJFMicmQXM5cXj9xc13B+fOI5+6UAGFChIiIUJA8Vc9jvClBTH3HJYER0hraJdxujZoTl+CRvXvMcxvnIAHue57zmsiyd7+xM6fr6uud5rkbi1ouyLKuqbMctgGMHqgP5ucfqCLGPYriSJ9oqiKgsS3B+twiRU7cTYCsiSMr35yBqbJi5qIxSGHi+53m+plkwLaQ8ERJBIIekJmBEIkTFiJrARVeITr/VKpIgiDwvcMcXkao0xpitra3xeJxlGSLGcdzr9aIoQsRkMgYEYbTC1iIZttYaAQNIJEaQnUCqFQMMLAD63MaZxV53NBqV1uzvHDKzEd7Z31tYWDizugLaQ1TK95TSAHz56rPGmDLLy7I8OBgcHg7LvEiSpN1ut1otYJlOp84XMWW+d3DQW1hUu3uj0Wh3Z2+a5WmSp2mqlLeyuo7gg1BZSFlMi6ocDtLJtLKToSiNKvA8bQBHSZrmeZpmWZ4BgILaOUQRYANgiVgjIIIm0Qo1oiJUgJ4mhaQJNClPoULUSiGK7+varBIpRCfPQCi+rwndfqwNMBxZ2RMbzEBVJ1ZtBFYanFLKk122WHdAOR0VABYE8IPwBHtl84DN+3zN5xIIzhWGmz+Zr+U0b0ZEmjM8R+uwaz+QhqAC2EGxRXQYN5csiDxLB4GekTMQgfNJRJDZ06SCoGQ2xgStlls9tdb0VKH4o15BEcGqYtKiyjCOTxARuOfO2qo582YFae7/k2bSGWCyFo1BBwbU+oRdn99OrGvwhAE+cfwT/kHz2sx9Iy6Trj0PFSlhZ3LVbGveFipdGqt9CKJYeb4fRtq1wBrDzLWw66z9lHy/gbYAOP9RoXKMbc2tnms1qaFZxyFjjKH2nBAyM1srzGyFhbGqKgtirVirHQ0GM1vGrGQGrKxUZFXFFYqyaESItFgmon5/kV0rR2GJ4Ic//OHGxma/33eUusCeQl95qizLbjvutCLX6Ei0XhTFcDjsdrtK48HwYDRKHm49DIIgSZLp1Dz//CWH+mHmLMvG4/F0Oq3ycjyFlgetCNY3zvQ77XYUhmGY53kYxnEQqlgFQdDqdsbjcV6Vvbj38O7j0lRZUVWV0WHkh7FlSJLUPVOufqBFQBP6hRhNqoamcS0/Ro7KRaFGAoWABChOisg5OQ4Pi9aSUsrVdJhVGIY46xKc5YxRgDzPz7NkMh5qrVtx3Ou2y7IsikLYOFIrRaAVaq0QEVA1aPYTnp+tjOWaZ7mZogxUmsRljBs20JrVhDqNxzyboaqutDVz/vhz0US58zZYu1SYiMwziRBRFEXO7U3TVGZ14iiKEI5qt/XHA4iIgqPFbn7NssyAM9nFWenr6NGaKwwzMyCGcYTCCOLcgul0mownWZ447J92azmSMZUL1oPAd4VeZgWuj1cERbuDqtndAXCFYcyyiSJsgCdlWaZJVhTFzs5Ot9u9cuVKHMcANJO5kNCvF1wjzNbT2hjDllk8NAxWxIJYI6WpEECAnUxQFEVFUZgsVUqlafrpJw8Wl7rGmCzLwt29drvT63U7nY7nq5WVtYV+6JFybK6D4cF0PMnz3PeC/b3721tbSZKsra1dvHgBWbKsuHv/F8bycDiuqmpxeX1hYWVl2dN+kCa5YGAqOxhmyTSrqkoEScVZUWilPC8ARUVp0yJN88xF/wRISIRIDACMYkVMFHqEVinP0+Qr5WnySCmCUCsC0USaKFCklKu8iu97SOKMqyIgAoWkUALfc+lrItK1OCoCgHVG9IkacC2Y8QQ6+mlKP8YYZ3kUHtvUHE3m/Ausge4nbarYWl4T4VjjjqI6NprPF8kcI1UN7nCRN4I1ll3SGuulpKZcD+ITrFggwDN1JBRweiyOmoOJmZC8IGK0wmEUCwJUhjyNTyHuQKc+C4iKkIWUp0Ap5ekwVp52UBRH+uE0ZExZzNV5j8YGtPIkyQaDoGVgS8YyiCaFip5KADIj0DjBCEZPoQqZJ9yYJw8JyTPs2hpZBMTToD3UKoih+V7ceuWWFPcFlWXJSO1eH5QO4pbWmhnEfSWOPNj9rVLkgcsCu2W0ng8oRNhIetVOQv0/1+txhL0XEQZhsLUikoASYga2JCJB6ORcXRuotta6M0nywrJYi4WlstK5sZUFKyBKj8aTNC2U5wtAVVnPC1ZWuocHg729vcFgwMxBELj6FABMp9M4jtvtttaamTudThzHeZ52F/qe5/V6vclkgojW2iAIVlbU7dufFgUAwOJiuLm5efnyZWNMniTPXrlcFeVgMIjj2Av8JElcniCKooarZDgcbm1tuXLkcDQpTMUCXhBGcVsHoalsWZatVkshKgASVsKKQCFqEHT63wiERyUYt+AT1uIQbjV2zyPDUZymZjxZTfzaPIn1kk64fzhwX42IuMpLEARBEDjmr3mWjzl38JjpdftdRmQGsrMzB9Gm08RKnbv1fd9lRoMgmMcMNifs0lwz0tJj+efGyJ6MgOu1mMhxiDTu7Xg8PvEBzIwIaTJqPESc82TrQiuf9KCBwM5ChRNraOPIACALOxJ6a62tyoZvrKyK0hpBtbq6OltSGVi0+CIiYK01CEpEnGh7bdrd8UVccnXmg1sgWVtbq6oyTdPReDweT9I0LUvDzM+/+ILneYTadRiLSBDGcRTk05H7WA+BWbRRxrBlAKCKrbFSsbWKSYFCUho6cT/JSgDodrtxp726ujoajR4/fmxZxpPpcDQWwk67t7DYc9/i4cGoHbfCMLTW2rICFM+P/aCllJ+mZTLNiDShTpKUBDzPj6NOGLWWFs9Ya7UfZVnxeHcvTXMQNU5StmgZxuOpFQ6DmBUCepWALSsGKaoqLzNjDAMEvnKBoxJQhApqF64Ve4pEay/Q2vdUoJWvtCaIPE0AWqFH6JPS2lXnAFEck5RC0ATkKmnCga8B2JsZRSJSIEKKpc4fOZJ1Uo55Gdzy2+CgHTOSIFSO/+iJyRNFrWYez0e0pirgiBPjyAz7wckUtNtvioqPo5fr5+i4tW4WCCM1FzTN6pnO0Oi5102I5FAQQOpUw+OMNBxl4BjFZOk09IOg4wFiGIbGWihL7Xls7akVYLEASCAghCiAypJopQ0FEXlaKc0gbCwgkNLKV6D1/BEaQW9FNA9Pm/8tIYKII0hjEZebetr54KwqduILwJkRc3epAcdpxy3/xHG8qFUZ4/JyIIJKoeehUoHvW7A4R2fv6igAoJTyfL+qqtbCQp7nXrstjOzI4JFRadQa3ZSdrYMKgOaCfgJRxC4Ik5kaen0/6uvWzcxhdtisHECoFgerw2KYERa67DTYo/RjK/OZnaAL54ZLA4UFKySkSGnSSWXZMmhNIkJKrayspHk2mYyKwigFSTJxKWhEnE7HbrolSWJt5Zi/giAQFOWpdrftPJIY436/f+WZK476yvM8R49lra067SzLsnR6ONhPszAMYhHp9nu+7/d6C4PBwBhzeHj4aHtre3tbRLZ3dlrdjtKepz0viFB7LEBaBSr2/VATaEQt4hFrolAr7RGQGDH1t+MUmGZtrmpGjek6Qt0XWhlTi/3OCijOdjYlmOZhJCJE5So17XabiFzxhYjCMGy6FRqT7+5/802dWB+0risU80EqACovyPNyOp3mWV7mBRsLLGxsEASKyPePWXdBmCbJPFX5nLGr80yNPXWj9jzPxSAMwFWV5rmDWyhE5XmB7wtiVRTD8XgyGqVpsry8SAp0fWmKFM1uihIRaASLWUTEglVHPuMxv8OZ89mT6MylAOPh8CBPkyRJqqpyHGy9Xj8IfCtojRVjmRmQG1/BCSXXiu+KQIR4zthTbedFxBKwkbzkNM2Hw/F4PK6qKm73NxcXe71emqbuhkftoNXtiUhZmLIqlRcAMjq7IIhkSIm11gKKQRarmMUVqHxAi3mRFHkZx7HWwXA8QsSVpUXP19vb28bawlSEurImSfODw+FgMDjYH4kICXie1+12u702EVVV0W139g6GQkGn3y8tfHzrnrVVu91VvsfkJWmys7M3mUyKyirlddr97Z29sjR+EGrtK08LM2qlyMk9ZbMSFDNbhRhoUsIoliwoFJ+Ur7Xvka90FKAm9rQOfO372nVpeEiBrwnEI6UV+ko7wAKiVKYAp8dJoLBWCEYEpUkBIgmBEJGzsPVMmXUCnJimp7wgtJVpuCzmzbDn18xoPON8csUXVOEccUdzKPJmfX4nPki0sdbKjBYNtVa+r5QyTi7TTVAil/lCRKpdSXSOg4MvIUJVGUSYUf/XpkQB2No2HjP89WXPNf4BgLWWxKTjVKPvUl4qCLiqEEvyPDZm3pLNRuS6x5WQnAUxID7aknWkPMXkCVgrDMisA/A0qgDnQVJS4z2RFAm76xIBrM9frOUaosUWWZCtu142FutWsWOj0/8F97gAIkKjC+xeu7tU3zcQ0p488bkI4gchlAWrkihnFlQk2kOtGISQQQg1Impwci5ihBE8l2+e+PHSONv1/a4xRsCIJbbMSon2AQGQRJG17EBeirAJJURYa2j6hrkJHaTO28wmrRKxJChSAftA4tR7CLDx/11viHNv8CguYO1XwFxZqQz7xlQGCmbDWFpe8YNOp1MUVWlMUZk8zdI8m2Q5C0Zh4Hm6LIrJJGFrmO3a6up4Minzwg8DNrYoijiMFhb61po8T4uiCkO/1epMJqMkyabj0cPhuN2Oo6g1zUYP7z/IskRrPw79gHS73W7FnW6/J5aTLCXSYejv7u7u7e25dXw4HEZRtLCwQESWmTxPa42krTVije+HURyxsQrQQ/QUalS+JtepShoVEAAqRQ4e5UB/SmnnuFDdzWjds+CwerOQqc6zwvE++wY2gUhXrjxTFEUDNIvj2NEWuQSAe6c0/YQMOlA1GyWi+zj3WaUL95tYe7bFOhDBpaWlPM+n0+l4PL57925RFN1u1wGTHTraWVYGsczzBrhx3B1mQo5vAID/8z/+bx03rANrO81CVBQFYVGV6TQZTcZ5mjFIFIRB4HV7HQCuAS9zeI25sP3YQsnWIjr9IpQnNsQ6G1wUxWQySZPJcOdx4OtWq+XU90TEGGNt5XAHes6dcbcUOMfTSIUc9ZdjwnKbc232tneqvACATqezvLwchpG7s5cuXcqyzNFNuNy753lRFBV5Ul8m1m2RjoO0yCsRMXIEXmNmFhiOEgtiGZi5mn3rLJgWuRUoDVeVKV2tXUAY19c38qrUSJ7nGWOSJEFEp6fm1Kpp1h42D44Lw9gV7RjBIaL29g5mX7qCWZUeAIajQZ0ZVqiU8ly7LkgUhmAtiGiEwPOjMIyiKPAw8NHX4PvhLHOjNCkiCoO6z7teTaBuD+31ejDr/HZTjZlFrENakWvUQlR1folQaZ4zRc0scrD+xjgdPTNyFIk2X66IOBDEE5vrLnPpa5g3wMcs3xwKw9gqSRIH+XH5JcfyesIbaP5p6loyziN4axMyM73zGGA7x08yP9oZHz3NGoidk6Tg6DznXyRJcnT+czcEUdemAqyDqM3SuqppwJgftT5V5kCqyjiDhAgO81xVhtnGcau5osbhaP7KGa0GvexSZqce3x35xP1xqOnGiZnHRSNSnUFg63ByzpjNdMprvfCGNYkZmnLGrG0JnLiLuxYRbvR1cA7H3nxu7WM/hdoTj7EVUv1ZwoCGmcEyKPKVxhmYznU5zi+1dWFFZt2eICLomNQZBAQra8rS5HmeZVmSZaYsS5a9w0lhuczyaZamk+k4yfMECguLXUBNkR/FnXav3fHCQAEax/s4dx9cWUfETiYJESjleZ7S2rXbeERkDBORAqzYmqLMysJUlpl3d3ebOUlENR5Iq04rbpLDnhcorxZR8LWHiI5H2iPl0sZIEoaeawFyJJqerzwdKI2KPO2RVj4gswUWg6CE0FgGOmoWaO5h87yfeDC1HyNpESnLMssyl4XWWne73SZQbg5iQZBqKsoTR6MZFnj+T5jZaUa5YI8bBsaqunnzZlmWSqnl5eWNjY12u51l2Xg8NdYqP2iEEXGmEuEsS7N8HdWP/9l/+1+cMNdu29/fb14rpZyGhuepqihhLs3WbPMozXnDbIpczZN+HaUCqF5hrXXWdzgcJpPx+bOrvobAC7WvnGawrdiK8ZTf9GgCoxMOZC41GgCeT5q5h56tNdZWZVmUZZHneVGYqrLWBuTneelSMS6Tk6bpdDp1JxZF0dLSUqvVcuXnLEveeecHLvXf7Xb//6T9S68sSZImiImIqpn78fO4cSMyI6s6a8DGEOCC4J8lN0MQbE6DxAwwIP9NrwgMFySbja7KjLiP83B3M1URLj5TMTE195tZNRoJT7t+zM1URUXl/Xh+foadx1fhS3CApiFXY1UtWmu1uVpVU+Lvbx9F7TrX6/V6uU7X63WuWotxHqa5pJROp5OIzPOMa1QMiFyttv6ALs3EMM7z+WzBu7CQdqbL+xuLZeGcc06Sc84sSWhM+TDmp9Pjp+fHp9Pj8TjmnLOw6SUPyS1C3Gx9bjvyncU/hzxC//UoHhetOhlwwRNjkhTL7mPPPE0IhtmiS1Nr+CZD2kB//zY4S7XO7V8SvpfmXxQ3fgqJsZU6vZ/PqGuDxAzQUBcIOt6JWCgnx4G83qAOCAzrwse8CUFcETpxqerD4Rjf6Bfn81pgZCNMcDYzFKIBA0baBtJo9gx4G3qyDscrblnykFmRCxBet/FpxcPuWBGJwM2xhaf6Y/fDtqU5zGwYRiLq1sViqHyHtaPkzgITWoQbC5U9KFRSi68WagfqfgMJ71CLAjX4CUL8PH5eW22WqIG5pN4BzY+tNROotz6rxudC1QghKSjfP0+11vqf//N/+fj4+Pr169vbGbQ9JUqJHh7GnMU7iKNOVkrJ6UMEprLkdIBSgdqCHx8fiH1xE+44jsfjEc8Zc/r0/JRkiYDLLSqHmRGrG62+EL6rzgiEZmZwcRQPgQl60SIC56skJpwpW7JkSUW5cuWaKauoqFgy/1SmYTxRkkQya5kvU7GKoh+ZkwnhE73oxViZKrGG5uVx960FE7hrw8yENHFfeEdVU0rfv3//53/+57/85S9Is/73//7f/8M//nlWcxs74pqBUdDLt8BhZub/6f/yf/RJODtxHuk2+uVcabmeLxSKC8YDbDsN2MyszEFkX22JzAzV8/39HRGnwzAMWf7w0wtTSYQC61KstC7CoqyJEtLgZ52tmNr0+vV34pKWRGv2NJXjMFYyJM5bqUvyvvFPL5/Lddp3pXh5ecGxZOb39/d/+Zd/+ed//ue3t7dxzIfj8PT09OnTp+fnZxBoM0M8ejS4q2qFvm4Lv6zFplrAgD8u01z1MpXr9fpxvlwul+tcarH/5//8XyC5HDLlTKUQM42jfHwos0fIAmhLOIgqocuaLFUpluNHi6WPUqKcE47Q/+Z//d9KosSUcx5yTkkGScL26en5MObHh9PpdDw2EwppTVmHtDQFc9IgYfj3IkJpKTrZSVeRAW/2naUWM0FZOsauoefMmLIJs1ox1blc5qlO86z1dDj6/THpaEx5ST1qz8EnaTFBjqbAsSJExqmlKvGSwYlmc1RLrXOZQA7gizIz2D86hoELXgsF95+0Y8AIRlA26MjQR3B9GAZcL3qcLcHYoP4dl6VWCjG+iGEFZ3iVxMtc4LNWu1Mow0KU7zqcIlCzAEH7OZ1OtOP6FBKZaMtruwIF/icNiU/dxc3ndMSk/VMaTq7FW/AZNWDPJrelaWnzLzRENTM3CfYTMKMVQyimujkGOjYSkSSyuoRSR/ulqnqEEbUOdKWVld2v2r+P0omxFE7KqGHjQv/yq/f3999++/Lly5fzx4WZT6fT8eHwn//z/8da4TCE0WAf397eXK7C98i8u16IWj+SlLjVexj//Oc/o1LYw8MDWGbOWcgeH47SKhU6O2Fm6MEO4QWdxC6XD8DfzFJKh8MBDtraKqxF0Y1TLgoRJ6EYjrGiAA4vJRggNkv7KxnnlHOWwVjrrEoVBSwvH1e/E4U+EmcSrrr0/+gw0OOqeKsBp+A55RB5cLlcoJR//fr1L3/5y/v7++FweHx8/PmPv7pcssf/jkiaGf/f/+P/qe1r89yamdkf/vAHl+Ocn0/TNGbhW1Y1R6Du5AySWkbGRphFrSgUxkwpoTjL0+PD6/evHMK1nYKrrg9ZY9W0lOlN+AaTQEJR9yUz18uM2ApuvScxWxBfVf3999//y3/5L9++fTscDs/Pj//+3/+vuJkRAFPIpzAJ2q2hrEjYV9WqVo2qsbEU1VrtOk/TdZ5QiazYb1+/nM9XAIGZYd8moi9fvnTiJOb5pz/9CaDwQnqYxk8//eQSqPfXFKEsxMwoIekFMZj508sLa9VSTZGQqmLCYjkzgqocJXwLXGShwJU9qc5xK5LayICBD1VtCYHcCmSOSJ7UCOHx+fk5PspvFtm8t11oyIGjaGquNfLL9djPdULWM8iliAC1uiPqFzmNvtF7Mtrfz0s8gt/vv4rtzOICp+u1Y3X4lFCoLt6vlaKBPZpM6MbQbto+fGedfINww0rUbcF+vd1zOgbcrXQPqD1I43W8uZQbnTMoaNJxnktQZ4iw40bxc+iD7pMUUr4Nnl44aL/Swzis5sTgnoQpC3yLmV2vjYQ4ritaONYXEZMk4xS+XESQcRyJRFXLXKHAgE2qVZjfS5lK0Xm+Ivzj4eER36MMUa0zSiV9/foK4W+ulc04pcMwpGE4HY+c0pAWYbyaoW1cTougg3pwMX8hZjGESmfVTdlAD88jj5vuVHqu6hpqd2T2aEPEc9GUR4+Hd5YBjd+xdFVh5Qb6ERGCyW3HgA95sOb+859wa0eIb5Ar9Pr6+nb+KEXdNwxRI8Z4WzNyeLRXpsAaJdSGhaAEZpBakayFClAXCUJExOLxXRQulJKYMV7nKGhm398/DofDy+efYdQ1s2up05dvTGbV2pFBwYfEImbFzIxMiZUI5bUs8eOnn6Vp5BGth5axZ0QV2S9GRCYykBCZVdVSV4if3z8gl33/OFeWz3/89R/+4R9+/fXXy+Wj1jqpXq8z0UxN6+XhgLPIWxQZx0y8di9TYiUxdl4FkszVlro5z6dHZPJh/k74OonSVwcfWGQY+Mm3b9/wTdxySAO8RB0QewSvGTNrnes017mYmSQa0siJ5vmKWHZVrVR1EY45pwxPsh8FqOeIrlmgS2RklJJ5PAUzMa9/IlLEXIQVmRkx8m6JmavRbFRZeBgTkYyHjvTjJxKCMjZki7V5v9qXtgjjhjAY1Q0DLiUJw6MlKTGzkNCiVt449pzyYosIBn9uAmI3HyUyVaKKdVL7NLPXj7PTiyhpGS0gJWK/ICJJCyHgJnkIkt3dJg4Q8WIV4XtNI/h28wYnOmRGVDmREJMqp7Vd6fpwXgJ943qdERrsMNjxFlvFNzfLBQuUAQjPrCFve3O0G4dcWXuDu8EC1DB2AR2LIKI4GNhVVfKiqfOW0Le2m7sRJIlFB1A1o2RMnCh5RzBZOlgZG3Mx1oX0sElmTrLOd4PVB94ILut80mC8mkxRmNrMXt8+xvEwjmMes7Fcr9fz91ezOo6jCOc85DwejkPOP8HnfT5faOebZ+b/7f/u52o0X6ePy/nycT5fL1qqkv3Dr39ywzv86aRmVo2qtFru0XMfff+YPq5TSkZrMwwH59g0Tj8CzGycspqxxDvjdjvolgtKmlREeGkNsJxKIxofThacdNQyiHlLN/zi7f18kwFf8+yTjzrq4XCAuf5wOLy8vBwfnypxMTp/XNRomovRBb5FRxvelsHC2/PLywuKbLiQgjldr9fI9mGLFpHpcol1X72aa0qDB0TEWrJlLkYaBUA8849//COMfp7gPE3TXOuYRiPFqeTQs4JsAhUTM0oqZgl6Gxez6tAJAHrwnfPNM7Njk+gtxNdxk2imaUqH0x/+4c9Y7MdU03BkqdYEkW0+2YaULNca2lRRMkGaTiqlMFTQPDBza2NPH69vUDJcNoyM1ufvA5IdVvr+/u5BASg1BwbsnhVV5Rw1jIroLPw7EbGkdBQxIVI1JlWVtMT1kKoJilywiIyjgLJ4NIoIiZS5eAwcsxPaxcaw4ZqLBJQo0Gtf11wJmFmVi4nJEvtAeQwUtb3azNqTdXNWlSwxGy0F5nCPwPm7vI6X8vpEZFQrJZZkaaicWo6+sHjo/iJe+MWsG+aLGjssola6m5cJcVmqNyydkZYP44L5MS85rajaXGoocRdodOWspsqshk6aQpKY2VsciMRaOCTpNgPe9SN3wNGCGWSVSFEzRAy9YxCYim0AYFGrcfkyzHPWecH9ttjWnO22BmzEi1S9SIcsIsTc+l9vhhFR3njf/XSb509FHkzIgEgsbCJg0pVqNRJkZwR0XebZq/TLWBmAmdWqVqqyml6KRbKwlJ4X4SGZWSUqukoVLOwasHWyWrCLNqxtIGJOlBZjeEadavp8OHIahpSUyGqdSrFixYoQmVgipiRsNKtKVWXKObubZnUAkfzlt9+dKxwejsNhBKgv09XBnlIa0pKMe72e3ewfQ7240XyzyrS0FDRDC44Bi1rPL5GyKKuasjBKYqmZEvMwELUaNYFQeFIyNdkBF2MWZZLmsoSzslId8qFSzUsrh8WJCaLIDSGdBDEzzJ97BmxmLAKDOBtXq1ZNSX//7QsnPgyHw/GYJBtZTsPp8emPv/6pifgV0fKwN1yvc3OIoTAUAYZZ8iDEyagaEdVqpqVyVZY05EGCHG3MxkJbg4MuTHcpSNBozYJCZlaWPAliSVnWqgkoFz5N0+U6gdSeHkciul6vEk/Xor9adRmcCNWIsDUDEySsjgH7zsUDTETz+Uru8crr9++XKzObST6c4PZAaNjL6ZlrlWGNqmhnsJfQjYjFhBKbMjP6oqBpvRGLEUGV56RmqoZuzaqaEy/B3VZRvVpEvn39vSMxGDlnJmJS01Lm6zxdTYuwHQ+DiOTEwoY8CjIjNjNp0qsZqJ0RqQ7DIJDIzEipaqlFq1kaj9S0ZArVGYmIRGzRM8zxoZIZr0LlCg0zi3S2rWIBIP5nhjaaZmSSTcQIDQiNhRH4Z2ZOTo1Wam7+2PavFUqK2UHMX5QxOHfJBGBhIjNm0uEBvK81u1QFPV3P5/bYX+dpAS0zM2dJiZOxVNfAt5L1bK3X/faG8fQUIeZEkIo5KBeEXxibmUlFXMjSBjclSZQXdZi2Ag0FGSIOu2NjBQcCA1YRJTVKZlZ5lTj9sFDjK5g5tkdYiMgSR1RY4RC6J0UQLThADCySFvoPi7LtNOBaLfJ1/3+tGzVrZcAELswkS4RUVS5EifN+PkSkdq9xMa3zSGpSKFVVPV+vAwtiZRuEGU7M7vAuWMQWX+fXk5vQwzESslIK0rzNICRhq6QY1TpfdOIkWVIaxjTmkfX121cyBhw5JTThM6b5OsFCYOhdo1aMjKuIsGS3mkir228Fgf3CIsRgEaxmljKREi91Gy344J1shE+BXNjk5hU1iqoqm4mwJE6QwEq1nNbmmIA2FEZrdIOi+GLCImZalIybxZ6EmUvFRqQFSUlI2axWqp7mFJQDOz4+dk5PCwp0ooRq1crLf4+PL7PO5Vou82X6/joch+fH55/+8MdmWyZqbUuIRLXkPEJk2UZ91Pzbb7+tq21hWsz88fHh+dHRbC05ESVSM0Y1HBQZSLVWdDExRpiJoXNRNRZaupqkNOQsOY8iNM91nudaYRhIZjZNZSplHEdDGXQrWqy0LiRo4wznPJzqwpnZLtePdgwTS0ZsIoWUZ2wnjChkdnx8WaXmwLbTuDS7mOf5WqxSYc6H0/OsbJSMhYWNeWlNWDWlYUGCRv6YmUlVp0XLMFA7cAMhSUqiSlZnVZ1nZHnUP3z+acgiIoiMcCQ4Ho9+RCOB/u2336QFJ/sGoVhaR0qIyJgkZ9RsilxqSVc0NeNKlUVY0jDwyDzXJRFeVaXZuhFFiWRYIkKveGYSIksjSPEyV1kiOkyVg5hPTe222P+VTE1Row5uajNTLUuXgHyU4ThNUyCmbV2B6WKoKhh+sx+a6xJQiNM4GDXT6AqKdDoc0SyilFLn2VgtJcrZ+TlvNeBJp4XCG4kwOpIkTmWtTsPhwqolo6X4Roz9Lig8o600hy7nRfIBL9vwYKJaippWIlt6AAPbE2UjZqNELfpXKxlXupOGJHcY8xJjAQbMbCKw06v00hWuZ6sL37WF+4J0L6U627nwn9Tgu40X6xuxLhFOSZktrdQ2MvJCpVFea/XEBCFSvnYIwEs0uDFB4JZkzEZWGf9bS5+GT6t3uizKNrYoiVKtrDqfZ7aUKHPj6MxM3No78qJem5npKoCuw8WhdHCXTRA3LQ1L8tJaGEXViE+Pj9Nc5+tUqmqtrEZaqlXJQzuGosSERkxEFVIj9Z/DeFzqu5mZKtPS6U6G1fWgqnPzWY6Hg6GxGC9se8FPKwC1IV5sMTDwcHiAExg/x2aKcKuewonESJi4qJZada5KS/iVUOJkyZjE1NawLPCCJQjLqBpZNWVNJMzQVXmaZkqWaMkVN2GkCiqcY8qGVhDLc3SeqlKF3p44t+Cv5eRUVe/dBB40pJHJJMsojOp3bx+Xt8v1OB5QwY2Ex2x5HISMZOGPQnVxg7Ujx/+P/+t/jAfMgR6DPrRF+S7f3wrQ90xiBOhX0zLNVefEwqGtmJspch4VPWi0wJQtkiG3GRPMBqziIec6m4n6N5RMLLFYrfNhzHCht7KoMgzD09PT+/v7ly9fXl9fPenoeDwe8trJ2OMCUkrTNLkrjojcSd4Bhxr5hsnCA3aW3wpbvZJWWmqqLc4MJCZRn5xKoExgrjHSnVr/1GgMWZz2d4rg70jJMqY65XGJLZqmUmvNOY95mOc5eSlAa6kjRNdSKSpkbclRC98QkFtNFIgIHQUcvBLS4eP9/pOc8/v7O9KgT6fT4+OjiEAftVsjTo8CJ75cziKoVzwEB8wCoiQDNx5ca1WynDNcGD4ZgNqj2+LDieh6naNI5IDq4rY2oGPdnxe7VVrS3+iT8ffC24SG3khMSCkdjycEG66ZqS0GGEecgjHQo6CtVf7i4PigENIf9+jeQLFVFEBwmwHOYK31eDyiHCB8IgipWxlYWN31upo6uz+Z2wBD/kb7K9gRd26v/fefP39GngUaPE/ThH583759u4mHVvWmj9zxv5MhYrgokAHTdoW4G/WHTTV8Mj6lTEoErWuNyq4EAzJ7dHu1RT9LzJW0a1KiTIOkLq4bn1VDsd6GAw5zaa16bKHRXO/UJPesgY5rIL6KWmi9W5g62C54OIzzPCuROK1vn/hv9z1RVWQ3tEQjSyTaYqZZl1ajdemaY2qFeWGxVmmuU5lq0XnMB06UZZDMWYbWkNTqXIwJb6PKkQfhE0buYrMVqqaHYURdDRIe84BysCR8fv8AZ+S0pEe2ErB3iqHDZBTVJhFRWso87j/TkJc6qw0LK5K9WNSKljrXYrWASRuTiCqxmRrk5CSoMTsXNTVVeIvhV1samEBZINhUKxkrVXo8PV0uH2/v78x2PJ5eHp+Zk2r5n/9f/2/VUqsRp4fTw+EwHA4Pw5DUjFh4MVuTkiVTIVbjaqTVZqvIRjUlJc/5S9bkL3SK/bgUEssypMPAJtXKXOk6F/csLZBjYhMjYsm0O71ERDygNGEls2rKLeGKk4kxw7eRlIsYK5f2TY+gibNibqzwiCCViylP06RL4PSIc1LRCJg5SxJbG9GTcWVlEUJwSUsDMDbh7NJi+FwEMsI3zUphrHlIQFhOlIDQyix1rYu2ZVTMPB4eJA0igqRDW4MP2Ra3xmK6ZiYJzRusRUUxkaRZEkvO4oY1JjLPjljbfxEPzJVFUGMlCKBIoV2l+0VZWDzfLS4NBnle/u12eIsmMlosoOS+0/Zpwt03i+bchAUKlgMikgznYiJJkgcoOkpGktobeSnzhJCfFom2BJS1bKXF5o/bljqiorAWCLcTbBvY3hpTqUWtGhGxsCixmqlRGkalmSRVo6JGVUl0rsppKQPp6p3Bjp9WjXn9H5GpEpMr0R4LspB1JqzFllrhIkmIsMakqqZgG/T712/DMOTxMJVSa2UWknS+TmnYFHIJeGg3g7CiLB7vt2oGHUiMOEPUMqlGN8+LEvff4NN1L1gyFOfOKgz8zM07Y2ZwnLMQixnMSHCbwsnNzGxqxIs/cLHXsKDMWPd5LRdmXvrFUWIhTgOz1oItYmJVY7XKlgjGvFv12dUrHjItCMbaLFXMjEafCZJfUXMBV1WNrKiRWi0FG6pMRBI/TYhBlDafhBiIhRO1CEMUVycYR2gxM0FdHtLBszxMjIRFatah1sV4ooVVmr/ZJOcR5EDZmJdPYzElRGsbJxYSHlkomZamueEVIxMPLCaSQ/AQcEeYiTKnNeTM/WpEVHSV6NHwiIgyc60Ij7iNoMzr/sAxW63O8zxfp+s8QTFPLJLTb3/9Av0rDXnMw3AYD8MoRiJJVbEvburkFnFnZuwmHSMz/Thf1SzlcTzkIR+K1o/3t/Pl/V/+8tt4yKeHp8enx+PhNIxJOBPrPM9whVYj1aWBNpWl4IMi9NQIdrWFLgrTYgBJJEooxlfVRKuSkVK1JVeNyJjSQviIKJSnDxqbX4jBVK4oP6FGRqLERrIYvUnAIVAoOVNiWiIsu08iYRZCxIAt+8AsiQzBdTnn4XBg5stlOp8vkDplcZDBg2iVWNJgTEQJFNyYiNmYJA03GfDCbNbMvIUNj4dcrKDPZ+K8/ILqltitmFRKyePh8HByhawi2bl5fWmx5y3jjgZcx+Oh6aU56FJN96K0RBGTyiIbVW2dAhYvJrMxFd0YXRceTMSpcSZmYgb3JSMLcdfOg4k0MRPdUIZ6U2Qb1YtwNQbMRIbcaUlKQpLTcEjDqKrVmJpvjEMs+vrzxufwSURGsmQQkBGzklTjJU6NjESajL0s/57GZsycKI9rqZZaK9Wacya5Ss4kYqzVOJEoSZIULKuL65eIOLV868CbmRldm5oPchF0vDgzuWQQs9I9cElVS9GFjtDL4zNiVqdpQpe6aZokp81zlgGL+439snobdVlt8bawsWScCTMiTjCp95/CNxmwEJuYcDaxpdoBERFXK2QcdFZGjruwKMlSN32hM8lYmc1IRKguFuFW31sELpru09DzmMmUYGJA03u1wkIs2awuJgY0MoLeeQNvw2GEbMS8+BeIEVuXEnNq/aqVmNlA8UyZuRonY4p5hGHEwx6HH6MbWxMqGfiFDNkWIcaMjJMkoEKLUUCWCtESOdDi25moGoNvsJHisxqjEgGLiSQW41qpFATtmogyVxzPlnceg0YZ8a60NbXFZXQmGma+CX1yWaZpEmYGgwOr1VqqVoKWnNYqS9Qst8icWWo7V+VwqHhrDo1SOQhrKQUJcPM8//bbb6+vrzCLffr0aRxHNDNGAM5iVTZdV8rEKJBElMfBuTpcdfDfQw7hJJBcGKowpdPTw/V6PU/ny+WiqijyMgxHpsK8por7J0xCe0TJwwD/glnxYiOBwS2aN1FNIjDN3zzA7H6RLSPMOaVhWPZO9Xq9fnycz9fL0+mJRSgJ5YG9MQBzko2Je3GpkHASbtF24ZOs9R8C7RMSYhYSyTmrqKowYyPRU1CCehEPFWzj0ZgZnEYbiO3/aetAhxzzJknWjtPyqDUdZql6qJR4KxY4rBzzI9bFkpnxwnbVK4mIOfGdoJ57BMWf06E6NeecnxdUd8rb9ojddZxVe+9ypvyIxaIrtDvy90ypqbUE9hg9nC88zY3/mK3PZ79q2Qqmfu0zt+aRwUXOawxBnLCFQleOEkQkkkopsesO6JLPKt7cfGR/Y2xWIVlIjU2Y0a/BxMQywqAIJyJ8KuktTS7JIP5oY048cGZmm88fRKpglsJEsE7IotEaoerqwmUpkcAyIkyVTISVlJmVOC/fbz5pPD4sMSJMwks+D6c0DMj1ZaXEpS6xCyR1CafqYwu0svfrZkrElYyJa84JdZ59rwFtr/QXt56Z9Sb7vX9eeGfBjXfuTwHe3szj66uPx6OFGgbN2Z/whRIUNYiAREbIa1QjU4PNH8A4Hk51WNJ3O84VyNT66uz9ETse7KBp37SfQUzZjTxk9XKJ6MOlVGs9jGMa1ypc0SNo29DlqVaqdRAhMlilfQ2IUQqzcs3GDofHUsrXr9++ffv2/ft3VT0ejw8PJ9QCTSkxS63afLp1qaa/zcqiLb3b4sRCs+JirYUxI7aAiJgl52EcR6O0BE2ISTDJGvzCO8JdF7M+EyfiJCjEJqbFlvL6aNfNTCYtb2V/kBQGKPiGoDfjmzSwSFbV8/n89vZxvV6Z5PhwGg8Pzeyf2UjQjYduVwii+wdAW+Gm7jYjNmJtlmPXIu9pfh1iWIv/io/dCIKqNzEbBHp7CCHPxn7D3FgOM5MZO6f3V/vrgt8Rz09BDw/rvSW5Ei2R5PvxAwYcV+rzAYOBdBLDBSKDjLt2T3NNKZttZotHgSB2cKb7mnrLAV1dTrxk+gj+JyIiFTWDzTwK+kcMOIIl5yFCoA31hNvuJ1FgEhEXDt7fz6+vbzlndPi+XK6oEp8zBCnvPQh8sKp3NP5AyqMwISJIdsaLgU/U7A034Ca3v6elaIX6RueUcpKJL0TRhwEiIOTRfiJkxMKMTyJ4PFmYKrewpGrmrqLwSTQeHlAlsJia0bw0BrBBkhLL4qpoCd3CgnbM8D6HT1v8OInJ0J6LRcw451Qr1wrGja1hZjmfz8CTtsVkRigMfnPcA5vcOowrMW8WKQyktsGHoetBE+AxE5JVFqxOS2UkrVD+ja3V1TOr0PKrtgTopWeJo8cS1+MkZekGx6Yw4wCdiLIGAtGRXdsNZcrD3SjK4HintozF8Ql52c8qamBFlu/XqXWticMfGKkk+Pd7G6qKWs1+QjCfSFYWwZyr0/cUYLRfPhFtLZnreH19NTPvNwkNnhvmLU8gWqy4tHQAWkphBBp9vc5ERCYsiKpgNWYjSdmlyxZeKIwiZMy0FIvpP21pvIODgSw9mucZLbjP52tK6eXTT8/Pz6gMxZ5kQmSUBAmm3IuHdKeyki7dpm5gv6uw1LQTZiYmOAI6fDMzbFzcKRwDT1/pnr/lc9Tds93KhVB23zCIlbDqSlW7n7tGFfBB9lyEd4U41hneYWAdst1chf/T2XBsFGFb7TaeFLpbCQsa7arzRZhTOGI+w24yPhBUFW/WVszHq2biANbgFdsv8B6Ddw1VQ/m8xiZv2BsxHFCOQiml9/cPNKwFY9ZWUMh/Eh91b1d8/hH+SpRS9qIFUcO785j7gmygn05FW35B88AhVZ4WGSQIicwQ0JmN6uIEM6HFb2rQs3vuy0REysTEKsyK6kCK5lI2DDDIEVHVVsBLJYn7GDeftdaWMeQkiFAvx2k7VurmT8xdddPPZhhuB5neFQR1xYcfUwMzS0S2ZJmv4jtGDS4Gp2CMNq0kCw8VQ795olxKQQ9P8FBVgtO1TBORMiort0KkPh9uxifH6lwp4F/UG9Clq8W24KLx3huweH9fKvvIEkucRbJZRXcRawE18eS7hTme5LptQkDtEEZFBLsFU9K3b99BvhHkTERoJ1JDeXQcRRBcE1Yt2ABkgFrTCBaHs/uW2ixd/VczteWQVLKUk8ejEuIhzSTl1VqA+ROZWV5Ud9iLHGlErWBbWJioufGUhiGZMcFNwkQo2EqCSBni/hPMPnwDhVjm+frx8fb29lZKeXg8PT4+nh4eh2GoVJatMBSWk5QTM0qKijWsQOCeiJjd6BLDRPdIjRPfiHy0kMiVAUfyF1mCbKOmKRynm4eN2jGb59IiQ/1O1HErRGS6oV2QOmotjpmqS702FGjjEIjuuHdzGqq1rYLiRb4juv+ARt+DJ/BZWwqDtY4mHYQ7rkxbngE4x4OO/1tMbtt+G/GG/Qqo6S4OPWauVWsteIxqLcXM1NXrNkkOT74h9WLuUd51hgrfsHNZX2ZnqPBfPT4+ppTmeTbTeZ6GYTgcRuTFNKCtb2eWmw5gum9REBHbKt8RSf7+0Zl/VHWaJiM9JEGCE4P1thkv8TGU1tC1JZuIooAIqYXu41stZbFook9Ua9ZUDV5fREWQLR5R6FS3grCWmAmRjUlDa52YCWy1gcVSEpHROV8p7GH59+Bz70+CYJVN3n+3fPAx6PECxhslMArn2mUCD+FOwwFxMAgABW01MzYhs5SEVaVxN1ZDqQ9VMytmbLa0+5vn6jiMeYLsrKG53endR4oTEZnM9TZuod0SN/sP9EJmtlpYeriQF2TAZjcZ2cyOw8ho1M5ExLUWM0IrMYLTTmut8ORXpIscDochH4zq5TzN5cqUHh4echpT5iEf8iDCGTmChcqQU1GBV0NQs0ZNSRGEdav/CaNOBPqrqJlWUtLTw5NkHtKYBkEUNFNSKrJ0RQie5mXtK6FcqjfCx5uSYy235ChbUsWBJdw41iIhtAPWffpJW+4xMyaZZv24XK9zeXh4+OWPvz49PU1TeX9/FxGUvlqixoRRiWmaC7Lkmgd7CSKjpcDm9r82K9pR+UiUwxHiqRZnZvHTea20jCz8fFjzVh2SRkQpLT6z9naY1OpUISgorW05K3Oa50JbcWGpC1SoGuLl1bswzbUcjydjYU7opKRLAs+yF42NbTTOKEOsx/uO5H5zKBGR6JI3jNxYQ8U5VYRyZxI148UpxaLNP0dCYoTdQhEYT8xhIvj5SMgMkflhDxG3K8CChHcjC1Lxu1v/DcOIKyXlKtWqGJOQFjUmbjhTTanyXEuWTEgfXKLniUlcFHMU8mt4uF3OcGGoVk+DZG7Z1caUU/ZkSFI0R2TURXt4PKXL9H5+v16nx+dHIXk/vz+dnmBOXHO0jZnJeKBbw7ha0JI5nsOgS1H45l81gpKw9D6ap6mUcnx4AK1AHJO/S7UyMwdb4fJe6yG5h60PZSpVWQjOKDQ9AQTnqTAz4CKcOC3GNxKm5jNe8jscIMybTyJjKmfNY0opEzPXWmplIjVEXcONIcwiaal8VubZAjnzT+gY3fdEhCa6cVPWC2vVzdoFMnqJqKVutRPSqlgjhc8MShpVqgcZjTeyV9QTwFNdFLaqh8Njna/TNDlHw83X6xXSs4SkrFor/9/+w3+QbRIqRsy/dKxiZtTRra1fivPOn3/+uUNEfB4OQ60VLa7Am900pKrzPCN5N6WE3MGPjw9Prveepiw2XYta0UpVZ7Rag1evBcWseZC0FAFnz4OMgFayWJLNP/cZcvjMLHhbTPupVFNI9UHcBUqdCWIjdsMlrBX5lSlE1nTKBzMje1JEYMows4pKA82dGUGNO511obRn1fnt420YEswDKTSTEBEl8X62dWGEhNKkOmuxEuu/UKWbeXj3hH3Upo4WArDY4Y5GiEgZnyHoLzOPw+CEmJtvBnbOiJ8r+ROapouZ5Tziscw8Doe2C/H8JGYrpXDmzHIt83S+TLUkYs4Jn2PKMuRB0tJlyyw2n45ELYUmBPHinuY0jqN3qmlGo8TMc6mVDL13MgslQYeoDjO9M0+5TpRknaFwZuGcMstlnnQuyAdFv6l8GI/DWExRttD3tPsvc/brOtWbaW91qrgDJRAr1cyZEh3yYdYZ4YCDDCZmxaY65RbfG59jVoecYwvkyIR4la6aNZtsGEf0N6tkgyTslDLhG5TicDiYsM6FkojJVCes5Tgch+PQAhYlnmIiBY2S1qS5trbNoGCdiZiITg8P8Yw7QkbDyYqfzLVWWGGYl35KyzJ3DBJ/nec52kr9fpdQ/f5F2GwROvHmHwxjUl5LS3qVQ5QWdlZkjXOBzgAzEyWnHkvnMZOApaKsbFVZgYHIS8Z+DZIu81SukzI9jId8GAdJlaxcp9j9DLtZyfCrpQKqGr6nEBTZjXvnbtbKzMAOpuRtK2/3zybYf9cGaJ0csxO5NCqWGoaIwCg7DMPxeMw5g4dmmG2dQ/gLYDWiJs4HtFvj1mDm7va7Ywxgz7L4pFc2Dynv4+Pj4+MDxBf0aFHSmdy1iXjwnMksWTKzYQsFR3SPp0DOa4peigWCQerOzNTsTfvoXv9c1BxBfC9URc6UzMwjfrnldBIvDQ+6wU1hcsiYsTI0/iESGr/AgYdrGU0XFttj7UHte2HNgup21Gp1HA4yJE6DkpiSGRWlqkSqrcRTnCddLlPgf8VdLznnLjPvXjw8Bky4zeSysr26c6Auzz8ciWhWneeleVzOQ855KeFjC3SFk3Bi4nHIEb9R0BLVbaohl8yIljShSiYpI1LGlpJPBBN9GrnFEKlJYjUSEYjnkkwSL/3guJIZ6bCETxPd90t1W3/ze1Q9Y2bvnKGq1TTJqKYmS20aJlTxoBnVXZhRCouUjJmMlIWNixHK+LARJUpK5zqXUs0oSeLMkNKJ5FpWfxvONTMadhihox/Szds31u/48lmpsHElM+NKasZ1yaNJWVmRq5iEiShb5tExVZBhQMnMkklKIrZBaVzEym6RARsJkSkbmVXiZFwBE0lsptL6jtASyYmUehJONNjAQsQZe6pkCNWVSkbGS74psVaFZxGmqKrGLXPahM2MJTm/dLIZee3NHe+Y5c2bF+Zty9+Iej7qILrHgEvZ+Kr93N2e0mKBg0C/0EJmbhnVQHXoMzCz0HKgl94JqG2x2vdAE+JnNaYlI3iJ5qpEZPR6Puecx+Op1vpxmex8hbCuxqxcuWElLTi41GljLGyx79EShnJj6B3Xyby4OEHXl97MZpbzwkF3nxK8Lb21bzdWl5BD3lmec1LQt4UBQ+fwKH9qgSduD+TmJwdlHMcjdjoyVGaOEitGhzSR9arq169fnevDjIwKzFFTjA90v71/0yCyEU8cTNGEvnI4XkInaHse9v/cj04CvX2chKnc8Fma2el04q2nChRwSJu2XPG3rhxTKLgjskbzRh4MDh1bnuWcE0vO2WQNfLAQLRJXFK6TzxliE22Rbw+Wm98jqMo3nW7t6R7++zvjNz5tt0nGH6qq8Rrpo6qecsPNUqTbCTAzmhZE67croxzSJHyPPIq1w4d7EvcP1hsjvODzm2t5fjqKbVbty9m/1B9VQw9v3IOmHcgCih4vVGXRlrBA4XjGdflb7uYBNxrkvoN4cvHkGuqlR36wvig8rbu4Hb1CVtaSz2ZBbVjPePAC+PBzRCEZ5ua6ujgVaqiV1/rzG/hrXWJcOtT1b7oXcVh2fJSGWDOz2902f3yC/m0Ds4yHdL8X8aUprea3v/8t3e7Q1sWAb8Bf4tHzt1iL9rcd5/ubdLsbHenz6d1/jjmf3r6Ow+d60VkE/UV+FjQEndVal2xCCljeTdGaRQWgeXh46CcYRkcXmBmKqR94ZxLfv3/3vonoiRQZ//YJhAXEiTkgUur7ekYwRfSlxoC7+3+8hR0p7MDS/QkKs9Oa+CdPb417s4958S89dxmNqmxhnCmPPSGIMIe9eiXESZjNe5z693t60T7Z0YBaDhh+uG8k/uPREVCf6j2T9fV6hfXvcDhYs/6VUo5poECAHGJ+gP2BIktlrszZmUG07hJRSr3eYLYaFZnZWyk72vsGmRmRVFXhXoP5ATG6pyVHDcZPY5krIitvQonDiO5AZ0XOCGGi5xCEGO0iq9kgHPy94OuE4+b8nSB2zn5/UZTgI5Jv8ZaLLbbE7hh2BrlljUxq7IGQ9kMG7M/hrRBGIT8i/tZa7MLinGshM9piCTsKGScWIRAZfCQyK03YsZC4iWaGWufSRtx6X5pvX2Sc3T0/QEsfpRTd4TPt8DY8agNnMyP7kR0IMOt+Yman0wnmz3Ecn56exnG8Xq8fHx+N0Elczg/m829gwLQlmx0F7sa/9vl+crujyswu8vo5VdVcW81hlxAjWvvuoh0hEY2ju9NWnhrPSdx1Zi5lzUOIz395eXEfobSmtqUUZ/AdDuFXe5SKrCviH4LC+pubxBdx98dseP9SP6i0lxxZExFytNtMlp9cr5M73ik0pqbDYYUyM7d+oimlaZo+rld0nYSPfMx9PUtfr9szKaDUkr4UAkqJCKEPDp/d8sXJU+TW93wtPz7k25X1AtYezu6tsJ2w0tFxb2BOjdGKyFJxiNjxzbmvtnYt3XPmXbAPGHA8SH6x3MkLFXVayryWylwWHiB0GzJLDaW2KZLyMPKdTgkUgnQiMCkw8shIrGkM0QUQC5t0h8XhY0FPtZ0laTP/W2Yn2/ZMxXVnrnDCCigaOkzsfGzzVOOLAjhTbQzY1x6lh26STvs651wkbhF0Lp0sb2ubjrSrqEb7KyLBvGmoWy+YOaqY26lGWPpjh1ZFx+fTIeQKmB0TjePmuTNG0O7f/nm3HLNVPOI1p+DGEBGk5fDWJjGOIxDSczgjikY9sAMj3QHvzXn+GA6O/3RfUO6xL0i9N+/vJuCrcCpkQRRDstBqprNtBSI8yKlSC37pZU+fWXeK8DlNFyfosd/t09OTC/4QAjhkWXBgbD6NuBkOCDd9R7IST7LPhJmhAddbxucfANRv2COEbcVnohY+tkVHDpXNeVHFlopge4kJT5um6Xw+f3x8XC4XIoK7/XA4aO3lfV9vXD5gW7TmLDWc7gjPDWlonzkvCbgUAknucc0fjI7A/U04j+PoykdEOao3go2JkC61UUrAgFWXKs61VqIoQzAvCZMcD16cZ1SX9zu4QK8Rx+45PyZb+xGzY1PoZ1W2uqnfH02gEVWiaS6KTSimLa3wtT8T7bd5q2TwD03N95Zw708SulP4Pf46CqDmJVa7Yz8rAYm7w7xUkI6Y7Puy58F+mwULR/zeb2Pu7VX+K4cVurw4uNZju53SvYVEiDnD03BA4qwsmKPvacD3RgcHv7jHgDFF7hSJZvnYP6ctSiKK/mBKZsa83hZ39nQ6nU4nBAOhScbpdJpCGmo8hh6TtH/+vffe/F5CcFz3intjD4QfP9/3nXbkhainHkuVib3K6yBwzgd6Mc8bg/j+6fFRZuZdUEBivPCF3+wECDP2LH4/LXGPO3ZFO8y4iTHrDQ3hInD9RX8P9O/d9oMfYsC97U5ul3sulwuH4QC8Xq+XywXHHrZ6mApqqRzkr0iARCQa1nybOcDBd8cloQ6rYMGOp0tDOu/fXKaPKMNZEwjoDiGgQIYc62hnUImY7brIFm42zzMlRnS9GUHEVkVvTknSmxCh7O7ReL/di4wcguwief2xpnhvyY4Gfi50Lp2YHN++3zI/OFimNT1+GAZngQ7YqFh0NOgecfmB66GbTDySDmHnYTehwcw5xEBoYDwc2JI/k5inaTGtcxATO80+rjoSXJ/Dj0+xCxD+BISI7n9otlYF7KZ983VGi8a5wN968RQrteCViD7XCPDuh/5lqetzuov9gAZscuPObls70motbk5E0HP3HonQFuzp+wLATtMEDQT+Eef30dLTgdpX2pGFe++9+b1sM4D9XfdjONzKxUTre9vzfRrLBY6hbl0k3Ut9JoIihd0RhYyMTwlJSwBTSpu2U9QwIBLuaJSG5gfui3gQMPLr9RrnASPPPM/H4/Em6sQjSuGQD8Ohm0zEyO5IuAmatvTiJuh9ej6B3d7082TUodwpT0SEtnH+Us+i6WQ93zxEyYKSHo/H4/EI0MVF+fMtGFGdzqaUUMlDeNNpDjiBClMRCLhAkE7EdezX3vf/49HtXUTKm/e7jQR4YmbX63WaptNwiPB3XIWGF0etleCrNkYWFooVpJRqreOIwMlV/sNFZMBxtrLzOXE7iPHOfxVM4vCEMSdwzTtrEZnvnQVfRbRFd3FVGrqI4gZPsKHAMKI4sl/UvdPhFcq623Tbia87mB23ICJK2QXEiNXRtL4uk5mSSHuIm/U4iDJ+8F2O6fY3LrOjEhSEMApWlk7a6xa+J1P+uu4C/7D1jZv5RByzEAbhb4lwi4CNIEUa0p6y3RQQ7b4P2Bm/fx9x1Z8vIsKrwWM/OgYc6QBQyG0/SIoB/Y9Qxc16y/8YEaZf2p3vXZCyIOv/gAVEOOx3fz+42ZbiBnV6kb+amXM8n7gDW+7fR1uZtBgfCgQRn/ds6KrHiDrWbN8xgtpJHjg0FGJmRsXK8/k8z/PT05PDKyoxNbTjjdDxPqNuhTMz9H/1KOi4hLgN8aKGWk5xXaB3IHnx2KectPbncAEvo9PL5q9Da8tVagXbQBI3EY3jeHw4mFlVmoumxGZGd6qV2y3D0aLxbyRcaRtd2g/904iolLUNJTWc86Ck/fDAFt+UyOb9IY4e9zA4fg8MXPpz6Abv/QBz0JjdvK9Ua63f31/f3t6I6HR6hEBaSjkeBU/uQJSHDTrdo2vrPHNoLRCAXxYbd4uN2hPf7ZO9BjuZ4c3MTJLyrnSfwz+ijR9gEfn4+ACsPNLy+/fvSPumVjPSD5Qz6W4+EES0BXY4ke0YGwc1Gvfjn9ZqAxyPR915WFX15eVFW3CWtXLWIvL6+qrN9UChDAvmjyBE3F9rvV6vlPLNcypb52sk3x3rwj87hhHR261EbvavtaKrMfxB4ziiY2ZKaeDkM4+AinnD61sgWGxnstCxwJnQJA3b55I6N+0Irhmn6Y63+NRNDbj14NxeL1POmdK6mxFcHWSwldgOs8VsY2imvUqKkfEokY7j2GSJ2kHDdTz/fhgGRxjeilNg0vtZdbEpkVD4NxFQmAlSXh2qTUYfRQTB2K20MO/hjOGKYve9KqWUkIRpIS90aOmm3WdGF4j4CPzTfauRvMouxOAePY1Qpi1+cxNbIpQ9yAtHEUwItx0OB6cmTnRWxK23zRFd8MIilfBm83gbf7E/vT9YIDdJh8L5t5bjFalkXHL3TDNzSwC2ymubPD8/QxzxMHVsZ+Lbgs69wRx6024BcvN+R3QLYhrflzT/JgJ0o3uO/9xNnd2BoW353/hXCe4x4G21CoEaBoPT6fTw8ADGs1huTLYPp7lc40xcevD8eCd/GJ1p6x5YOiZ677b90J0ziJumbttCmJELAklwZrHeDjN5O2wXbBVZrAY/4p4Ugkn7+fKHcIjz7PbXzH7//ff9NIgI+q+EXEnc7xq2tdIxuI3umOL3L/03jzgTh48z485AlQ5jFDg0uHgshIn5o635RJlZeKVj1Hz5ZhZbArkG7JPxV3QHc2EAf2tpFA+RIHSUIwXb43lcoMgasL0AJ3CNWHQBBT2+ffsmLQ1yc1RrjYkt/i4XXDgI1vvj4ygU5ekIjXsYEpeJdTnHISIUg6KGdbCTx0c5QYBzMMru7V0bNspb6bnbCCLKbspz0uP/dNBIC+KPekxcG/+QQEfU9OGxNr4ruAEmUNe5EXwECaWDZvfG7p8O6EiJ4PO4OXP/cn9xc0QG5qKJmVG5vfEtB9UfTkTGTEVrQ0pmTiKWM4vo8Xhqwh3SkLhWU7U8/A3isqOAick7p6wXcmd1sAhGPI6IfhMOkUXtUa0bkYXspx23o6HNRuFzyhjt5P4N7J/SQvpVFb0pSykvLweiricSURM4/HS5HqPBNUNhi7XvBdYo4xJtvkA42BXiBRbF8YfhGqvo80ojQkaZr6MLODXOyeJPOFggZOtS2Z8a2+pAGgKRKGQxxp3aS0JxCfjT5XKRFuNGTVRV1UPe5JW6/u2OMGo0YSltf0fT3Q+HzL0bfvArB5GvxdMW3O4FTIZ+09kYdRsH40+2JS697UsQSCSKMsENEVcRn+zPjO8lojR0dYrIyS8HwWvZrO3C18kENPOfN2sfNQC0EqGUaJt2GMF4vV5bF56mMbctppYdy8GsAslGt079iLS2VQw6C6V/RlSMcMBwjHWWdz6fVXWe59AYt87zjIjaPZw9bTK3/uVEZMrTtDQi5O1wRaubTHaNraM4MczBgt0Y9LNbLd13eju4I+HoloSleiUsaRGwaVtHyScdQdkKuPQLiyta34s00Fv3d0f6b55wDnTHrXBmloaVMVsY8YHxJAzbSliOEHTrmN2bzM2BlUrjtN0T7mnA7Xc31nsPDt2+dOvdP737Le70A9w9rXV77CEAiVW20dpm9v7+PtUl7g/PR5glDsCeAUtaA178bEuI68HmrptCvccobh8HMtqd/w4IP4BP/KFtFZ39EQAJoBaL5ADh3YgEnXYbGglZ/BMH4TjqK177vQsa39MB/Ol0OkVpe2kWznw+nyWUUHWTHZp8uxkWCsfhcKg/PJt/89j+naMjO6BRngmCqS4BRPPUUTZrFsSO7pkZNGBrgJKQICuBLDCvr/Zn+jduKI6b5Tccdh088U8Yz30sz0EpWb5NDeKKfKiWWityYbA7UY9njuqgEPHpdEqJvTWAM1ev3OfzsS1ndZ7dMct4v+8RB4qKG6KrJX5GDHGpmohE5HK5vL6+1loPhwNSkxEg5lPyVxPRNE2pVWuO8tb1uhqB4kLcwtfNPHcb43vm7eF2x6/f3R/jupuzeBtcjihNEEcnf9QSZKH4SvMtaQiK2dOgiFVxhTcYcKiE1Y2Ign//Me5wVNEGeWvQ87nxdiwYw2T+FoDIjBDkgqPODM+YiJDqzVKXdL9gwr92/IBt/OD++BM/S/fup1viTgq1x6MsKHVjf6Yth4g3l1KKzm9vb5yXuPHj8cFVlre3DyJC0YD49rlcYWuC7cvTw/yTt/kDtOVkHGQI2iLnvxaSPx57xrZF7L6ETmSWkYDGJ8Q92p9la6q/7ipR+A3+fBdi8jZV3R+OID7fX4DXzN7rTCKUhESYiCoxJapUTGetyZSScE5aS0UvK9vQ3Jszj9/8L9kCDnIP0IO26EeNyHCwFFLjFt3bmdda0HhIsdAsNaKlrqdAdgG0y7m40bdqUWYoWD78+RGHnaRra90QZyshC9/f4uIsvL8iS5L9MAxJBl7TQZlX4DOzPKCZRHh1lGh9mdS0YVf8Oji7nOf3u3OkA84eJvFLCbnj8dQ8Pz+jKwE2GvgpdwLsiVajOm3dRg49a4FN+D66YuNJzLGvZ8cg/ekAvYt+Kz6FNd8bbgHz6fr3IHxoDOxxDW2bF4cWhKBhGGI6RHxjrdZ9iZ/7QmxL8SMR2pMbB/HfPL2RomEDICiUy9VNbXs2HDeSmZWszLOGyXR3ugzo8as6XfeToW34VUeAbKun7mEYxz2R4979MWZHtmb/e+MmNPw5nSvkIKsHxdcF/Ix8egnU1wKxGQZMD/1Y7dVtLQ6cLkbBywI45F1Mxtzqtq+tbcPBHFaRssRV8z34hts4aDwOn+gSim9puQmrHQi80MlHnIbTnXubsuLMVr2gYPLBS3PQtLiVi4IFyyEcJxwtYRyyLZg3R9Xhdr1e3aeA4mgNh/+GgervhPO9EQkubbcY2nm3O6Osmx71hJu7H99CRJ0tziGMWqTOgCMd888OvD48rdEJr99mYSyP2v66o2YdNOIe5SxENzy728UakaaUzNYqTM4IdDfwc+w1BSEGtgRpzpGOefv5vYm0ceAbxK9FbMRjT6fT4XAYxxE1XOGZneeZl6ZrPUrso7UxxiGbbZR1p1cdnDGyS6zdhsX3xQt/nW2J7D2MN9so+9p8SHDOIZojpaWxLtRi3xIKpXzuv+uGeBi3oRP94hN4S3Q4cOvu4ta61gdys6rVWodtdyPbmoy6JTA8l+2bOB9n4RHbVPWe7zbqKOxenGDy2s//9rpuOZn4fgWrCAQKW3MPH7a4tA6YiPcblLYlPDuk91cvgrPx8Xg0WU4vEqlxD9LV9hrwMKZuKzlItbQtW8g7XhuX6ZPvKJ3/kLfq8s3RCTFxsXHt/mQYkPZ0NoUyim6Fckju8f9m9yF/jojgnLrQDILinlFnqLqNGqVwvuKKfIDgWgg6SWnNK4WuDO0Z4pQ3bN8//2/i3t8zNLQe90laCILjbdmi4XCsbVgQ7KLJcd24hRz1JTuISGvsF7vSjZgB5WDkWzqicxNfCIUSxN1YfosgrBAB53iVUn8uZEmPVn+tLSLpbFuNJRwEgKXGh+A5Xu+hm/9mem3T967i7nxFCtmd0Ai9OKKohCcMw/D09HQ8Hh33SinEymyC7uobIwtgtUyhTSyRCYwEHag7CuZ/zcMwoJ8oJxFidGBffAPCaMtEhCYZTMLoougdc9FnVMkSS/wenxQUaG3RgyAZX758ORwOKIaCw1xKQX3B5bdtJrXWomi4svTubC0H93i12ctICJbtUuMkwoxDED+tVjXzw6FEiRnfKOL5tp9sVlUdbauq1aqlnD5/ZmZAwKrOFV2J9DCMBGFZmNsqmFkgTIa98TPfiSy4Pua7DcMdRzkQettaTR1l7zJU2gSyxvn8ANQUks3jwbg5+NZwOkVbHBVJqpqY0a8X0CPheZ7R+ZWTjClLTsCN4TgQGTpGz/MMtpFzPp9XHzCFAwnnYoy3BLRRKs9NUtyCEBtg0bgtfnKHHbY1lvLfx4P9FbYVayLZpUb7fB+5GUvidlBgpdCJV3qq5g0N8VmnGa3i0DaumFqpxfTx8ZGZvSUXAIIabSICw9XhcPDcGAjW+2V26SJmJqAeatWqFZ21iLEJDZIt8SCpWGU1ER5krLXMF9OQ7shbdnsTn38A53vDKXtERQ6Kl2z7FUoa1Iya3gANXREFTWvnWuwcMVcyaaVhKRyW0qQoEalMRmhdZglJuq1BnnE1FWIlycZKlNCE0gjf0yF3fZHRT5q01NaFmRNauBGTcKXezYyFozKdK0JgMNAKakgowm8gJ5kZ80oE0E3IrEbYgpv67jhP9XdFgHNrpldrvVwubp3qttW5r0/MmimeAjHBJ3y3LjVSs1W8v78/PDw8HA7ZMSylIfE8X00kEZNIbFyrc9k0WMyU4DyZZ/AOY84ixixkRjxdPuwW3+H/6X/4H415SMmY0dORQ39H/8QP8NebDAknoHsBEWlZE59pS9AlRKs6/U3DONeqpcy1shmJDClxSkNK1Qxz808zaDvrhvne3OMB81yjGctZuR+V7lN4I3DgbmPKkqYyXz7O13myqmnIh2FMQ2ZetgQtp723JTqz7vsNl/l2kJEG33n8q81LghZooqqez+eInRsKJXy9zrozoQA+jvpQE/10WTCfOmBPp1P02Tt4x+PhJpy7mbtwKkEn7zg9NYbhRidp6d3oCUpV0Qu2mKIj6SDJ+/UuHUMZBHCjddF9gcM1jNRqUXlaQjTDuC9Hltq2OBPLJ20beuNMAEN/++03r3nutCNOrNv3e3jrP4w/txbASETH4/Hh4UFVv3379v3793/6p3+iQJv8J2vZi8YqgOe1FGII4UxmiLQptR5Oj87dU+gnDRBdr1ewds9WoJ2FAzabtCviz0bGKkyG3rzbz+kyc6IhjWmQxLnoPF3mqcwkadEGgoNGttl6tEV4HxG28eZ4kdMm39QH6DuHRuY559PjcQnSUQN+Xsusc5m1ng7Hm+ddd0ZdjCVFu1RuHSqxuW2ZAwp3ApHNasQ64JuHozoN90/QZ79GnB7YAwTu/XmnwCApxNOY3e6+wHdknVIKy8ZjjUfdD7pcLXkR1T8+PuLNPkO0D3BxOTLj1BqHI6lVQtAyIuozrzFGSyGp2tfAL3Xybi14Jc7IkDMhdr1xCjJTM6EURRwXg7Ik5yOtN70ZU+aUhBmySolyGdYP6hmgjJVDuoif1vaezJR5+dwSjvgQ3gahLduflmJPkvNxm4A1h/xa4AIqqVJjVE5hF0JzZ4OJmAO6SDMF3/v0aM9l7bUhChdVTSkd+eCOaslpmi7MS8kyZYqfdOvzB5S3+xNwAi8iommavn//Dq/b8XjsSgYuP6HNcaItZtM2hARfev5it19wjbgS4KPeCQpzY909StdNFY2+JUQ1473LicKdMHwJi8nC5ZjYrJiysjEHd4TdfNd++IG3preBFB4OB/BgbrovYnGHAXy6EjGRfxIKm3DrYeqE4/n52QEezbwxaC5u0A+C6SIM49Lc2Fhbnw/ETERu7dcp+CyXM+tEDXwRL2pqNKxAGtJs8KLD4QCZz1EI8kputRQ2O9HesqCltbezzlqZF3yrWsIaK1WuNBMl5VprLWWqVQdO+0bUtjMqRN5G4QR1QPO/duT+3oiPNbNampmKTatWrcycD+PQyNH+vDtud/Nf3pvEiCqZAuWT1EqqpFSVkogyQ6KRpu+03uWcMG+keZkZzB3LJxEmamZeRwykQQNuUGDAHoLjCLlsNN22wN0beZBuI0ATOvrsYN/bzAFqtHONXNyVY5dBIUxDLsSZHdvw5VCILNtstxp5EoSRqRry3Y+DBQHFcQAnAjzOwiYqG/oZC0kN38+6RsVHLMq0lW7iNtCWhNniS7vdFaeDlx9CDpOOt9l2LJZqyBnBhxoBffN1/i7fSLeZxN31hXgpTdopHzeHF6/3h0c4wnvt3MiWDL/ejuqzugWuPm0pzm2/wCzsfjgIB15h+wZW2Vr5q1sp86b2jbTgvc6H5wD0aHlumkec1c19IdoQbnzfyUl+gfg7atE6zj+QF09bM2xEYtqe4TifuN4fzNNxnkM3uoeHB89AcAZcax2G1D3KWg0KCpvuj314OGmo9MQhaa1bl0Ps5jw7n1nA56USEzQAPBxlm/bbQUS6byfXnkPhVDJzzlnDJlojnZHTOw5AKay15h19sEWzWfedm3GeWEuZkSdKIdmUg+9/Q0zCpt/cvgjVDtu7WaWU9sAkIq138cSf6RellMNx8Glg72Cait264rhJBh3I3Lx1jida1ZqWBiOE+9pvrovuHAE34fha4g17gXuPjQ0xbi7r7ojCdPcKCsStm09HPPHPlcyGdDWPlQFkpFXXf39/B0p7Rmtcuy026hVhXIEREaSHYb0xncwxjRr+7M+7fxl3oXsOhdjk7CbHzkscsTOe1XSn6LwDbk+e6BbaxTi0Vb4QTmmgdsgx70b4hu5FC7zCqYjwjXOO/xTphWXbic9xeDS4Q8la7JgDkdxTCw9yWDjtKF030lbQuUkUNicq5cvl0kotng6HA4yBEpIHVpJE5kEr+2FBWJGWbaLbKFDfI9mmQzhR4HQ7nziyxvhl3R5pCnjlEC6tmyyHoB5/QiQZ8ZR2F92Rvgd//5VTHAyXqcNxJUTi3Hyp++C7Z9YQhh3pSN51luwuulFDlHt8OwfhCQwY86y7qHhqx/Mmsnm10RV5mIUZ26XB34zlIHmBQlxr2lbN9Sdz80Gs31h7O6/yX7c6CbnX7FFgxKabV0SK1kHGml5+kxN3PCD86m4tqbi/7rtJZc1YBWTuxT3F4cjm/9RWQ2Z11uxqwlA7EbILFPCLeiv/lXYhGusxkRvn4iYV+reNHyhONy/2DBgDpYXd40CBh6VtuQgUz399fYW/DD93GEZYuUQnIlrWLAyW5Fg91Ym2QMNn7E52b4HduaOAtD6fHLc2EohYCo4Cot+T0OMB2AN6Tzg65Fv+acyc6q2MlHSnHnptVnsKxGg/jf0E/s4xz6vZMFJSFwgsDiaR1SIRn3MPbnf41wYv48ZfdQkRGsfxdDrlnOHh0JZ55nMRESYbR6bdgYzw7OcTUgsoJAXuK93ghqJ3K2T5/DvCGr/3vyLWCWqctlR9ZyTxpZEB/2Cvu897m96xZ3+FF1imVu0IFi1UqvKxR+9uuCbqC4/09N589uNepSFuXkkXFHSXSLNhinf2q/P9OwESEbU+n162wfkpRP53ulS8XmHlF403xzl3Zz/SWWMpc7WgxPtj/bOTQaNeET/v4f8PRkQVaV1qXl9fvak5LP8uvd0c8TjHmd8bbgjE/bWV5HR2QuGIxUd11/GfHOQw3Ql2urMg+q944+X5u8Y9urefZzxKe8bmAK+thCL0WnfrIIvXUejh4cETATbzD9dCK0e3tFQCVtVqUNWEWqW8PTWWrWvv3lb6S1MobAXRbbEY+YHh7eh8ij8gMR0cu6G7vENnD7L19hMt3TlcNcafoIPG50Ry6cZ92QZhdYcfFyAc/qW/4gdnoNZNv2E3AdEW6MurhUuZNBSy8Yt7AKzbtqm02+w4iOjj4/10Or28vDDz9XqFKpy2/WeC6kAQGagLowjyo9M7C6Vr90c6LnODJ3cIuh9yp4m8ZZy8NT25AkFb4cw1M3+j3MpDoC2Fja+gH9I43totfYaXywXGKyd8jWr/KJhrxeR169eZ+6MiesdX0/2D5oelu6czLVpTKNO9Li62OgXiEXATGQXDg6kOw6C6GtZ8+zyfkprgu2zoThDHizfft8oM+Ju2dvcctPkY0boiKkJ26bbfoTspGBpcKhEOUVLfY9F+OLi0hQUQUa0VYWiqCqe48+B7KNchpF84aXZQtxWtf/UVgQnFCcd17RcSNzp+H89mh7dRUP4BWP7mcITpJuDw56122E3eL9A/PlYFx6MeHx9bAPYSpwJs+fTpUwdq3B/pf25WbWZOgwAJSylwkeCcgvt0QIsPjN/vt9WxLroyMY3FQu66Y6RckTLeU21vjj1MdVevRLd+HQsasPH62zj7OHV/UbzTD4bPoePuYeW1m+EPqDMF06hvLZ7m7fziwrWaalXe0AILJov9cA2pQ3HeMrDuacyMw3+9Xr1qhIPFFyto2XTrOV6/0OEPXNyX0MPT3MQa4Ulb4tVhQjRgrBtKt03QTggiwEspUQL1V8NC01HbyKL8+T/e3P3wLQZUnVg4fdy/Ahf3GfDt0xv/eZMGdWNv4PUXOfOLFpoOGuv1nYpycWKrcIYuSZX8RW7ug+85rnpZ8m4J+Lf71YiIW8cnYlWtqG7ozjwgoQtkDlJVNSZmYWLbUbq9BSiCaA+KaFmJTxO+fU4dSh5eizOI7ABgo0dj3NtECnsXZwXYRvODL7nM6mkzFNzknWZPd5DHv/S+7P6Nmwr2P9yTr3Du72i09wRH3pgkbxJzf2m8p/tTPIxxcx1Xj8ejl7cE3YgCXDeB5boxWiIiSdTsf9K+h0GOt/nH3Xw6HIu4FLfGN9RPKAxsq3rhNNqVIQro4s/6sU1/PxufcfzGAkuzZjczMxIehixb/bK05nQ33xgJU3z+fiN5+9gfn5Pwq8U56sa9qG27fLfsltZxzM6Ao7HxnsmrlNv5alE3deJCRD/99JO1pmCwfXV44Ktz45Vun+OPxULiJDnUaPVvfLHdi+K52g+fc6fw2SbSdX3C6+srnDfjOEKZiJpuBBFG3dUY99k6EOLnPfjHh/grzAxzoCYTUDMcDcPG2OBY1Blg/MlugbNGW52XE92gnvfk3XvnEdHjMaToBw+hrQUiXvjz43YbJmwSMd+VP1+Or0hVaUuGiJbg6s2UdNWAx3Gc5yU+3NuuEJHX5KGtFsVbGd2XEBlwNHv+YN/jPFcEkB+RhWgVx/jpp58+Pj7e39+RAN1ZLPdjv+Pd852wWPPI+AZJa/kchdpuK2NXsfhkZ8BRtTWzWOkpgmIvymD8a033kRJSQ7DuhnjRafD+K4RWxaniyb///rtrIMAfVUVMDG1PqBO98M+VKs60rG4YBqQn4WQV2nRp+wETiQvpSIqD1KNbpGWT5/gHC4amDkHj4G0Fdkd3D4906cDM9v0aAYLHx0eUyIfwuGT65zRNhcMG+HANr/vsttN/1UU5+nVXk9N/iISKEhqm4lGlrApW3LxpmroZOn57gy4K6AKckBbrxMyo/EW2BtNbsMzjwFCgidQsCnH+voSHhwcnWL7GWutPP336/evXy+UCCRHFoTyhM+KKhiieiDqYbdcH2v86bEvB+V+j5GgheVTrzM2Sn1p3lForuuXknE+nU0ppnmeEeSPFeU0z3flQO4HAscKjIq0JxZs9atTNBbsomQ7D8PLyAvz09swtsSHfJPTRQhABorp02MSTXb93DS8SJgkuEtoS63vnkbmve0d7hhcG8BaB9NZkOBF5e3sTEcDZG7Ua0fl8LrZSBmumJrcARYYkIvWWz69jmesBR6y1Lg2FUCQB19gvCY6SUkpVVTLlNfgRw3cfXzp1YuYOnnGP4sQ69tPRekDMw27xTxEZxxH4+fLy0u1XCW0E42fXFccHHhupFnA4yWCtfhE1PEmhMV33Xgq4x0FbcJh0iJEy+xmMqpc2134k5mZWysZi5yCqdeOy9KGtn3dnG+goeXecaUtnqGVDbLCImYIA6qS11ppzxvdeFwFWCgTPxm11SGZJ/t6qy3lPKbGt8+ne3gEZeJtCf/QGmeqUGUQp7lR+fX2V5tD2CtTMvG/S4GjBgaXTlhH6nBxX6jx1AMV4e3uzEFOAiSrdJRzxXZstvHn3/XQX9+F1FA1dWUCDnDrXWo/H24n5HdL7mKYJCX/deg+HQ5cSjrcgXcHPxroxQeOPB7hDXP9E7VwK4TNExKZfvnxJOT8+PiI9Luf88vIyjuP7+3vjEBsKFfsoWxCuY2m9uK7z+ewIDRSMvhMnza5Nmq6Vp5zYpZR+/fVXmGQgk03TBPgDDuiU1cFzP0kn1rZVvvd8y9erLXwpsnCLVplwMzO/v7/7N84euMUiOCj8gfO8ab7mU8L56siNNRVqj101pDnFF0VNeo8n+7GmgYZX15bChOsVD4lEstFadSvKgrxNoLqJHj409Lhda9gxSgbcsFd19NfhMwxZOejoWwoeH9U9sHvyXkNqf96A0X/CQQ1NoYiS2uqViBf7n8f37kc3Df9JpwvtV3SPEFHT+e6tBQ+cpr5QUvdbCnhORJAz9/O/ty66tR2RR8T33kMe2naXigA5HA7aSvdQk1o8bChqnBA0Y3peROAtDt+bBYV7lhFPaKSl1kSZPWwjADOmlULerYeh3nt3Z53AcNuLbl0LfKctVDRqOQM2rTmPN5e/T8NYIKi3oeVzi++N4KDtfkdsi4f/HhxuIxyT6uIG6wgHWAiom5tKvJCva4Q3EfHmPLt1gZF3z2Hiy+Xy8PhIzdmMekkey9CdPUep+A01iX4PfNrmSWNFzr2cWvlhk5Y/4LTebW5PT09mVkq5XC6xvhLyrFz/wM0d9YwXaVtsPQbP39z3/ZnHD7E1UUOlrWYZsZebRrh/IIcallHljb+1na3+BmPYvpQD49/fRrfIcXwCNZOSGxVcYPLzyKjyw8wtetFNXNTS87hJMB1HvDHi9xvwrwaAm8fNd9zMYFzyFgIOqw5cvB17aMQDvoeQ3xOXA7yiZjzkbeWfPR52PC8+5yZ4OEiBEQdSK4wTH/ID4rwfe2IeSQfSezoG6bc5qXcF2ue/x/M766Lu4Xva0gHh3iq6mfvPO0qLO6FI+HFzjtPBkG8LkXEBN6ezLMSCIqrbDLT4/LjM7iI/Pj76/NwGW2s9Ho/3AOE34xsJRTt9MaX1qUbt4nhU/HWyc9cpiPLdJTeYbOT9u/fEnb65zRHuLkl5AihEk1jLNI59pS0iMqacxTVgDeP19TXnfDwej8cjsmtg4RTOElxKkYp1n8uLbpn4InpZMJBW08PhAJ2SiJ6eng6Hw/l8/vbt28PDwz3MuHcGLMitfnPKa5zw3AYCxEDKc+vHvfy2vQj3QPGC4usQA/DRnATYCAuN7cKL9iQv8gk363Ew3WvwA3UIE/+JxuA1FN3EK47Ho22H0+XuCbz4kgefPIQwa/WE4yqcN8sd06JtC+j461wWiWKxbS0om1k1IxMm4GHebnaO4jgxz3Ml3oCXguXAF77SwZtvpR8w4L4WG21tvw4BTK+UYrJGGvpPHD32hz0+6iZux/v1jkCPM9vZ4Zg5ySYGZc+HIv7cvAFDQgLCeti3TRHi9x0F46Bhc1Dp9p9xYn4c4qzwfZyPfx9NdB2Zuj/62/DMe3D48dhLaXDtdc4mqAFQdRCNBWJba4WiSFvi/4Nx756IV3LHGxLxpCMjfn/uHIEptHL7wbT8rU4LIElJMMfjyfcEjX17Jm5lY//mguOn3DnyK0XYmlx+fAAkNL0C3Szlb+Q9R/RSspwTKr56uITredDn4GwGfRdZqq7UVnXEUdx93n5OlrVs1+twgI+EtxFDRWvOI9zJz8/PDw8P1+v19fV1nmd0mIkHGGOPcNxMYTc3Akb1aZrQUted6NqyNTxqFE94PB1Tq26hofIRNVzCQlxLdtcXws387V4itCNAtQ3HTDzK9cuOcMdFRZ2mi7K2JuriuLhc5U/YF7Lw7922pLswi6gT0y65MF7sSTBGZ/Xy63uaseiaMu7MO8Y9cFCyidmMKfVReBwqMfl5WWZ77wjfYcC11siD43qjtQAvqkbMsiJrwNioI0Zip9ssDA5CavwmkqkIT/+nC0zArtWAIZud8vl3hsC/yXL21Mnf7k++qQV2z4+Y4yQ3Yr7/0Al+3FzHDfTj01Z3yO0cOQtqlXTT2NONNoteAeuOYbfqe1CKk+ye01Ek/BMNu7ilM0iIE+SWyM5BvZVQkXBrB7i9X5Fk+QGHgBhnGAF78znZ0dHx2AnWzR+kbZsqn8o8z65wxG6sNk83werRtpEqkTBz+puiUTylP9gwun8AeMdpwKVSq7RsjT3wnaZLTrw2n0yllEqbREY89vPnz4APeBXY0vF4RG3VPfr6Yespb1huPGxLMfGtmGlmCG56fn5Gx2mUj35+fo6lDSMSd6TqJszjhZvIgItevMJNlCupwgFOG6KJgmIpJUwJcgmWfz6fETHkSBWFSp9Dt78dRkUyHS00/g1tvQkOt7pLU8En0tT9jT6iSd9BSkTjyLU1sQDMXULqkESaI2a/ub4dPvzARv07wvnegccc8HY3pYKjWFCjfddzHmXIbth3yUZ3luflvXsBjohCMwaijQ/Yl0PNx4xR2nBJjpmN5fTwaK1QUVTdIO53ZgAKbd73qmGk1w7nLmrdQQFNy2mdmS3RajuTJv55TzC6ty/d8LXEdMcIq478+kUNFdn2VG5PH6IisUcAf0KbthJlulVo/T6/2ByuTuLsJk9/y0fuZ9zDKV5eXnSbHwwqdD6fvX4OAIIAQyiKC8kiXsnaxixzA2I/Hh3EHHl8u/cCH+5ZiZo1luPmux+/iZrbWUOlKm09qx3jS1kRKBJ6J/cbqip8z6h8F4nlb6cZbIG44VJ+4Rsf1SAzuye2avAurINpnq+1vUJaWCmUaRhpQQHXsF7bRJTYVrvaUMMwIgydKOjWYekmzcPDAxpNv7+/IwRaWqWzyC18Dt2LnJDtN4KIxuMBdBwqoAUNLz7E973MS+ECiCAun6J8MULJwMIBLo8t8AjtOGe6owRIMFVFkPq+RGhbiPz0+yMk4y5DIOMgWEizAEW67wsfxxEuANzgKRMe09AdtIiTHJDPwduR4Hig4mz3OBMXEu0Bvoo9/aUteteWFZO2SeccCnTPO80bc7KoYQQGHPeHWicJDuKIS8YpJU4onbvAtptA3D7fQQig+LmEoJibFIlb6c099bher+i6g+dDhh7HUW2T9nOTkcR9/LFg1LFDM6tlo+T5HkW0ia/uDmDA21XRj3vaETB/5p6hAvXmeSa6ob/eQ7m9ouJPox2S33xvfJHjKjWTQAw68dtw0EBkPB3DTbP+xsiA6Q4Dph9WwXALAa39qocITH9+tBjF7/N0uRhzFmERtPxD4yqh231wrVZlZeVZZyt2LVedtVj5+dPPxYoVneaL1cqZEyVQuYjfLkXWbdoGOWkwtO0TZY2fiVKlKibx08z0B17y9tj+ov2DaW3HdhzHUus8TXMpTCQpjcOQc/aw+z3oqUNeM2pR0GLEOQ2SDsfj6XBM4/D69dtUi5UqIg/jQYaMFnvXy+x8iFrVQwDHt8oPlVElQ7eO/vPj7axWtBKLCWdJRCbG9PLylIaD675w7b++vqIRekeG4mHoDm29E0w31zX61w+Go2Y81cv3dY5CnlPGy+Xy/v7++vpKRI+Pj3CWM3O+k+bUERS/8AO/QCywK9saHvHlYgNXUyY0lUvElkSMYsfcYkZVlSy0b96MFOqHUBAC0CIwETNzZhnG8TiMnNP57d2E0UjRmy1WspR+5FP0/fJlSvAB1xD1fc8H7BYsRQPKnMlMzeZpUjNcM6PgxdJAXkQySxFCDJQYKav3RjWhRGxmiVjJ6u68oNhwxbpuzAeMH5QX7XmYiHIea0XTvdlaI7jEcrlcKOVBUsloVJjQ7jOz4DRUIlZTVeym+whtG5UqwdrvAhnD5B4EX/+ESdMjY1w1n8u12yleLB+rrzEyyHsMBsYeCU7WZWi9+X3H7+NUXZzioI3t2aSZGVVrsCqmwHlvn4prEk7EdTkdoNsRE8GuQE33nxv7jROKPX9yWC0WnV0bR6pKOSXilHM8NV++fHHDm7NkVUWWhLTsIHcMx5dGs3MxpSYahuK3mijdMUPjDC10zrXwnBMkQABYhInYltZ9RiQdlDJpJSZV5iRGLMIinEWypGpa52KmFX3sJaUkWfJ1vlyv18t0JuU0yOPjKY+pzjWxSU4kJsREJmRE+vR8QmBOgS2Imi2IKqYeD4CZJRE201pKnabLfL5+TJd5rtOvf/gTiQklToRPoiTMpUwdF8H1HR+YEFMxsqJAOLBJTvL69sE5DWkY8mClKpPaMicR8lBeDaHtGC5nYQNSGlJO4zCMx8NxPEhOddZpOpPyIENlPl8uU72mIQtxNeXMpdJ1ov446aqcudBHxpfLB6M5NBivKbMQWR7ELFsmeGgWDVDEzN4/XqdpItY8iFoRkcNxuMNIzEJahRsiiYilJcRtGjZSrZXQvK4Z67lp5BSoDzW5EglRcBhDjfj06dOnT5/++te/DsPwhz/8AUzRs6qQJEotwUBk4R/n8xk2wLYFi6FyGI4fHx+llIeHBwRMnc9ntCeLGOLyQWZiMiZNxCnL0BjPkHPVZQ9EOFEy4aqahgMEiFKq2ZrrDNPWOI45D9fr9XI5H4/HT58+6TzNl7PW+ZDTOAzEXMtkhbTOpDzTbLR2pGZm3alBTkdczI+0eF8yNh6HiKUL48liRpfrtZI9Pj5yTpf3j8s8HfJAZKxYLMuQx7QYJ1S1lmJlZlIxLaXUq47DYEQwCMT8BLhEuSU9Q1mc5/mqOo7jIQ/WIjQhdyIvlllyHgF7Vbte56enIxGJDIfDwYxEOOcBXhvsy/I5FSVSs5nIK3GQWWYW7ObzYzPyGy99D90fscCsbjIsNtVYHeuuE1edr9N5GIbHp4fDcfA4+dT6y0YrQjQdx02JvAecA16Yh4eHr1+/vr+/Hw4H7yY5jmM+ZMc35yW11ufn5xqyS2NmVDTMxLX4PZuA2VKJlJkz3PeMkDsr8wwP0zCOw5DnUj6u5/ePj8eXZ0xfteCAolcxDNXM6IVI6ERMRKrnaF/pFEFH2hVKtYhIEkng7a1YxsPxqGYVfeBo6eNOzD/99FKXlNElvHEYkgiKFpiZEqkIuaUttpclXrRgIpqnmYjENptFxO/v3w/DAKuM+0Tolgs1ieQhvb+/MjO6NZsx4CNCpSgoEHQ3Zst5zDlls6VPMFU1EVZSMjb+uCzh6UmE0mIDtNne5kttSc3MTJxnuRplEGxdlDRlY6VKRK+vr7W1Sl7sSMwcKhmxO3jMLPSgFubjw3g4DvayiBhEBLHbP42oSce3MwJ79sJmtSqxMQm3Fi5A1pyYuZKZmpKR0VSLGHGttap7TN2Y2YXjpzU1vqW922qiry3PstbKRiySGMcDWQIb1otrN2VsLYTlkJ6Y+9hXWjTy5CAFDEn6GCvn5fdMYd3ZuAdJH/FEOWPwR0XJHVP9+vUr4sBhaoZK8dtvv8V8YmtVD1NKpSxFbbpHoexfPNhgFeC+OWcPok6tbW23qEXgaz4q9nSCdgcey8wAKOY/nS9wGnj+FYe/+j46tLVWa8/pDBvLbQ1pCBJPVQ1WBIetI54/3JcQ0cb/6YSmW+/Hx/Xx8TEfRipl1kqlQPYvpiJCicls1krXWlJJKXFdvLN4dU5JmAfsEZawERxNDIeUhTRLkpzHLLUOr6+vVue5cUnMmFjNfObUZEojore3N4+na6dgFhHU+92v3aG0AQivzSQ6OHTY7hed5Tb+yvP4/a8ScoIxVQ1Bl7RlLZFG+TyXVAiRYRgeHh5yzqDyIlJKeX19RU3jiG+OCX6+OFh6fLMictK25rzvJi3NYMQx0Ocs47jw+3k2VWYex1FSMmVlEuHD4QFTwoSZiZZWweCMOYJOd1UcOoz1s5OjoNxcG/C+4Fl+XnBDneZKyw5qi3a2ljflO+uxxqfTKe5IPKrdxIhIyMqciXSer46KoEvzDMGR0YikUQD3SxZftQdYNPgs5lfVUmta/Xa0deBDaXAD4FpEIpEjhOz6woajuAwo/rqt30bNpGnNFuSbETE13u84bdtoambpbou42A1j0rp6XUVYBJqbAodjDpSqlmKZzKx25K/7lJCXOU2FgqJsrQiUNaug/4SImBh5wxZsShhuKowHTFW1VMQU844E39wCP+oSCuLQ39Em7O8cvD23tCU6Ps8oiHCLjh7HEaFhX7588fdio6E/RZt2RBJtEbx44DRN2jqDqlJK6XA4HA4HKKbwu6dtIZ64EU4jIjz9xEpIZVbVy2WiJLHJqGshjnvWxMqcs9ZN6c143G6OWit8bPFmCTW6O6jeXBTdqsyF7z3PEKQEtZw+Pj4eHx+lOaddXkwp2bxWEPNFUbBwbN9rVipsMNykPaSCfHx8WIstp22Qf5y/cw4UKnHC7YuNrpCOjHbHgZmNaBzHyIAj/uxRl4iY1330m/FwGGb8J8DPLg/elaRI7roTYSE5wp82juPj42NK6f39vbaCTdfr1QsiOcphMigchLd32OvXHHyfnnZBoegbc195k4Mggofg+EBTPxyP7+9n2PuAP46KHXr78G98C5xa+nZE/Ix0KT6nbPth+3h/f6e0nNB4luF6SKGyAkiQBc4SL1K6EQzLizF54aPYWVAwYIKIeC05HJycR95yIoeAbze+wXPW3InuJGNC/krPMPn00zMHzSbiaFxABDc1BTGqLCkktvv31hKBIsOLhyS+BZ9DXkuLRTygW8OomokFO0MUzdyv41hV6ywstRY/LdG80w08ByRm+5BaQ94CBSkbDpUOZTEcAtaE1sV1WuZhyMjJ0dCOpoPVsjssIgYVrIPSvdGRqg7++8E7KuY7FXVWt5r89NNPAAs8atKyv/Y7CBZSQwWouO/ORWDh9E1/eHjMOaMZ2TRNb29v0Ik/ffrUTdLpwn5QY8AUEJiatmdbJQY/Qe1iapSLYQ+XNJeZQv6ibUVMC2YDf7I1ih8Vnajbxd1xgtId4U5BD3cat6TBcRwfHh5eX1/P5zNqXzsVqy09zALm4EJa3v+tfTdlNSNtYUqqimBDrwSnIf0pkqRuaRKSlSkc6j0O73FjpUK38NmP1R51iUhkQze7WcXvsZCuYp0T/dpqMux3Ia7FX4Fax6kVMsS+H49HFNgBKABJR1pp+a/O+C2kz/nzsVIvhRtxRmTJKaItgfX1xj0SERY5nU48XVEtp5Ti7dIjiHinmne7I616eYSGtffFn3DTGTp8Wx5OdL1eTdbStqnl4CCapJRNJeeUkteU7pYsW7/PMk+yIcmQGEJkrRWBou5wBP1BlV8naxw4i8uLnhWC57sXYMWeTmuE0O3JnQ4LR6yohOGYRSz3RTpK+etrK5PU7TGuo42eQ2ZFLCEWMSxqpZFpRZPC+sN43V6NgaXtRddpmqIbkltApm6NgS751rou/6YOF6mPqrrFhbZn1VcU7di11tM45DykhDjhxY8l0mdQ43sEB3hUdsT4m/ChLQmLn/fuj/CPFy5r++SxLw8PD6iC+fz8jKogHx8fEaNclWwLr93zO/ik1g0XgeVPT0/QuogIzmZImnt6iqfVm4JLY8C8BSszL44cU6pLlVthJiadJ0Uga85ixkyJjEi9pqaERFVpIbtOgpcZNsNpRFEK5h8/EXjITXXBnxbxzWEIIn48HrEp5/NZVR8fH6HluJHG5cW07fZBQUntdhwXOeeqi4TkxUyganOQEpwUwFYZ4RzZQ+QZwIqYnxpJVoefC9y2Nmrmja4Wpx1X55Qh4r8D07bJ/R2cuWnGnWzhD/GKaf4rXMzz/P7+LiKIHoJd+vHx8evXr07KS6tG5/SKWhF7r95qIbLdSZM1fatDwpTSHNJE4y7UVqEP01t8n9frTz/9/JAk54zXeaJglNt8htZq5nMQBZyJ+J2RDY/CGpJxmBkzqdv0Kmqi8DAMxVYfH8SUnHPsNeCiUmpZpnGlDlK6NVS1CLNpZpEhD8KUJJWSGnOctXKZKaG+YS6tJK2GgXMXSaXLH5mDFNaRXU/FwzaP45hznuaLI40fD9rSiO4kRHHGCSvwxrbKojUBKg48J237vfgkK60umXiu7jEM4tVXalu7RISDc9xrs/VLSGbojqsG09PhsBS4SCF1FYgIcHW2XxHRVq0trs7X66ADAh0OIy7c4YRXeFukiNZqVooqrRTEV30XPgDSTqXYcy+MEorOxwtUFnM9lVslDbQ3OBwOp9NJRL5+/frx8YGfgAE4A7Zmq4zymeOY60bgHNyaW6RQ5QPL9NJj3SoAEBSZoHCqObhIaBvh4oSMdgTUXychzmWe54+PD5TgcSTnUBm7AxpeZ7JKk/4n369oRooMoDsyvtKOE5Qyw/KP6X3//p2Ifv3113/5l3/RYFBJrXbKmHKHAz9AhmV6aZGl3H5mZthZeO5j/EfE/Hjhy9eWIozh6VgumGJKXQ1t/KTxWIrPxxtdkbBgIOVtsYv9Yv0Q+Qz3mLDu446uWmBILl7ggYfDAW5vqErx1EQaFSVaQMDtn1DO8E+fsJ/3m/9kZg0BaBF6nvXnttl5nqsqkeTDOI7j6XRCrxQvHGvBQrAn4E7tmw91TYOMn5rWIrUWmtOkVulsQ+XMnp6euBZIA+C4QN3Pnz9TcMxbMOrcxFu9ZYypZGp6nZbwLlAY8Hho0oC8qqK1Sc55up5dv9dQSg+2H2qlTJ18bXrLR4Rz8QoUDb8REWKNkHXMi+2iiDYchbfUnAPn1mC7xoxRCMmB4sfsdDrxfQHWcZS35vE7Y60WwGyQXFVBIjGrQuFcybZWMzdJ30+Cbw8zj+NSqlCCg7xTGhwIifDAFfV9XcAn2PEca0VknidrLN+Fu7SGgK2bWGtVM3h5Iljied6PDh+67+/dH6/9CbU1tIBKCkPN6+tran3L3USJnzteWhvMLLLI/v5l9yIOcr2ZIQRDWm0awA3JuBHCjsPRNxwfCwGCghEMv/WSjf6NMwZqFUzxjTd0wjY5MjhG7eFmRClllDJ1Qu9Y7TfHIxMpXeQBnaQfQYqeHAh/e3t7Y2b4AjBnDha5PftxEqbbmIx2QfM8SyLeBjFQiylJIWRpWcudfNl4ii0MYIJLnz7DEpphODFR9NndCbgdJsQLva8JrdsUbEKxJG1E0X1tfIdVpJ9+EkFAmh8xI4AfefDO6X0mPhkgEnDVmmuvO8Idksffckvzi8Dv6JuFgCYz+/bt23A8PD4+Pjw8IMyCmv2ctgU1MefYnzFS77ormyxLHubsgJIw6I4ZY5qmShahB7EPQZ2wilkwWkRLaoSS3MHDJMmK1Vq0KlNlSoQ8EZPj4XR6kFIKlIrLeWKerelOEryNRATDdW2d5RD6zp39pyO7IJQdrYnh1xoaKujWV+RA9L6eFuQXbRqw7gzIYGN4ZnxRvZUY7ogSYYdDvr+fiIjJbCUZ8SRA4pPmbHPGBpl9lT/amUG8IggWtx52KSXVNcgwzr+DMNZoTMzG2yho3APa7TWzvNf3+XKBFOYS4jiOx+PRgzUsJKVV1ePx1DKSFpA6tG/A51YBFrsvNvr93Vny3awhTwN5QW9vbw8PD8MwvL+/o2XY09MTN0NT2mbTEtEwJCjZtYVx4hUOefd+NTNUthYe4nZCDZpTx4Bzvl1cPtYVcTVFVV9eXpx9ajD9eWllaNuYsIu98Y2RpnSgs8XTtmq9dkdN9LXI1mPiw/NQI1YQUc6CjPBff/315eVlmiavOOb3OI2rtdZtNqdPO+oT8eJ6veZBIlZgPtfrFXVYpYWrLE/bopYvM2+7tjnoIp/rTo2F3kGuitVaPejS7gidHaD2yNzxUd8dHEx/UQ3Nel3+oMBlKeQHxyfjTs91SSk9PT3VWl9fX5ENH6m5NUUFR+bh4QFlZd3q4PyPQxCWW33j6kQky1oSOP4JRaMul0vUxIyoVgPLAdkBG75cLhrMVBZUWKc23KwLuTXl5CAHrKxhWiscSzM6MvP7+7vfwy3pgIi+f/+exgFBl1g+WB1KHUBQgNEForDcclVgX5g3qL5Mg0zLUp6viQillIL4CWT5v729ff/+HbDC6vAZAXs4HEDPXStYTvf/+B//IwilZxaBvu+d3ss/5bY9yk0uTlywB+VWPq6ZRU23+5PD3Z+PSXu4jXNKVX08PUdQRonGOw1Lc8lITrXa1Fzo/kMzAzG6XC5eeQdveToe4vMdDtGUFA9Szmt3KT+WGjpPOFSZmYRVCyWJrB1/+vbtmzWLDTJqlgKflymKPpEcu5jiW2BMDw8PNUjn/vaowTh6iUhX0cnPxjzP7oaIAikEEU/PoEAK46bEV9/EH1Qawi7DEAcWWMrklvwYJQcJ15mZH86UNiU5/aXxm3it07V7goXhr3D+ZKZe0BvQBpLj/Dt6uPZQyhpEFmmNywcrMhBBYMJ+ueiGmUATcpHCD3lUelwWcSxKoe8y/nq5fDw9Pf3222/zPP/5z38upfz+++/Pz8+AZ9zxZbPK6nujrYBrQVRqqyNWUyudYG1mP//8M5bw8fGBvr+YvFKKEFgJcRPoHbHLth2WbA1dfpw1GKUYbk6tdc1l2pSTjJOXxWpCEc4SuonEHfHVQfDtjjYFAU5EPEuYt01BLHBfakajSEVF5OPj4x/+4R8eHh6+f/9+vV6fnp5A9F2jSi3sqLRGMhosn93pox09f344+uuY2RkV4JNa0PtixxrH63UutipO7miDTSvuEfbudDrFk+7DVQhroh5+nmyNtokkDiYBF+sXy6jZ6XTyftUpRGU7SdSdtS+aM7Wlq5RQwzluqN3pc/zw8MCtdDHY5WKNn1f67FtDRC6oeUQzXpERzg4q7zuRUvLou3j2MCWfRFyYMxgHgb94v+vdb+PwnSutaK2DEuIebXnhXrn0aeCfGqqFCdk8L6WYKJx2aiHQ1KqT+4HZM9p+h7aspW7TqxwgNeThhVfzOI4guNIiKt1si92F7quq5/N5nueDLA3hnWpQsyjE5fjcYKLx4fN0k51/H93btpWUOdRVgMvHWj4cLBxd9IcDqpsP7WybfuElNSjYomuIXfLn49qbT1CwNJhZShsIO0wc4+Mno5RJkz/inu5ZAt4b7ahxRbEdYZzPw8Mpzsch7HJh/FLNpmlyjS3uqYTwHwyQyHEcsZX+RjwNB95Ban3KOFETkTmYrGl33o+ng68oul0dXA5k0PCUWG2T64xfIQ3JnTg+H6PbpymKRBGAvn0aTG4Rt7mZVUWEYH2ltY+WLyRt0078RfG9HDRICbaxiB6erx+lJdrm8cecOvd9RgIYYR7Phao+Pz9/+fLl69evCFP//v071GI4jM0MtjdupiCw5/1hLLuCLbh4fX3lJmd40ik3VVJVo720qpaiLeBo01LlfD67DUBC/o+bfDvK6fjZ0RwUxODt6I6t/5DMzucz8oAl9EQyM+CzCz1BIC7xjSF25xDB4jRnSBuN2QeirCWEfYE9XWk9aFEaQKgpb6NAiCi/v7/DmOCB1DWE2+0PJG3tGH7dkVo/k26Mirfx/T6mtLXcOsR5KTO0sigsI0ax7jcJi8eKiCiRXa8X37DUlDkzK3WqWlksp9Xuwcw29dGM8Zh1iyIitGHEDZE2aTDIrABhHobBTRyAFayaQHE3ZdTWceh4OhCtfkRZ0nhQwrCijk8gVZiodQeetiTPdmY32XpEOJhhMQ0zg86Hg2dbCTQiRnzs/kWRAlrzDGGj6xKsJ/69SxsaCqFQsBxQk5+6Tbn5uv22xglLMBFzcCuO4wDgRyrs83e89dlKsAT4BQchPc6HEXTGG5HCgngEiQcRle5B58DPpMUrxBPkmrq16CFrflNrTLFjSP7eVqlqAWZnWIunAK9IssI/spPz+ZxSOp1OHsaMG5A3b2Hgn+6K6uAWFdC4X/5bCSERuhURsGQgcOcjDzDZ5PpL628TTcpx66OAGBdSWhkAZnZ+H0eHn91D/PP5+RnmTfdDIbLPF+uIbVuFz8kvByF7P1xdlRAcZM2ChXS1EADEZoVzct3OX/r4+BgZsO++h1jy1grl9N+CrsLMaI+7P8LOwCQUXUggrUwUUk4cCH6bht50EIwo0D2/J77ODxTnfuMwPMgUhno/mNFn7+iqwQ8VNRAzy6h8FvPJEDMCXfMGrjTIxn21UN49yoz+hA4D7IdpMBZCHB3oQD7anlUz82rZEWspnChHTW6aB5M5wvkzgWop5CtTM5X7u7rD7yMiECriUSAZGL7xDlJmRuE+aRbd2kJnSymIU3WzEjAMDiHani5qQf+8rcekqmY6DEPi3gjM28AiDSZo3VoUnECUViwexJ2ZD4fD8Xh8fX2NaOA8o2PhFgjoDaQiyjm7ywDCR9PPkoM9IkBtaQmyzcUUWYNiIhPyxVIgoMwswQTqVJV2/lfHAYetthB0X4hDWIKJfourq4LlzTM4CC5qZsbopqVB4/RjhaPqQm1UQ+OEbUuL4ymgZvwAa+Et67UtFyGiEgpxRJxxk5qTGOCbcSVe7eoarMdmllpYiWcbTuWG0EytkIjtJLb9TsXR0ZllH2lBGJgNEF3hEnaEWHdmKVjg9i/ChdvSpMUMd/PvzkXUtOKL3IbUbVyt9fPnz9M0ff/+fZqml5eXWuvXr18fHx8j8oBWuOxlQUTAe1277T5Bl3D2OSjNv/zyC7IEOfjjUs7jqDBBRytdahnkHFiOLQLrWhM7AtABEnfBWdf+J8DSyH2ZmRAlztQ9wUI8WjRZMbM3u4tbQC2OzCEWXYd7NHO41RZ8Dqku5/z50wtvOQLeBT7i36jXjkabPAkdfOl+hE5EnQ4poRVxo+y+oxEJnATYfQYcBX8/9iKCVEWX2eFiUUWa6ALQeFyjgy0SqZ9++sl9QvGNPp9OkqKULHTb4Gad1uC9izghsiofDkluQTHdCTcms7XbfGkVwxEGCa+8u3UB2DKtEdoaKjbs0zCIyJY6fxtlnbcmxzhP35f4HGvMzxPpoJ1A4jsejxE4FBJ4bo66S3uIny4VRW7XId4CusDPUohOv1zWKEcNwxEmIgNt+1J38/Ep+ZdmxmqkxYgqOic2w8DHx9Up9Yr/lHgb/KUt0XzPIIlIzea5ehR0NCDhCS4f+xnJrf4ABaGTmb1tgIPLcbLucqIiqOPegWHEeTrh6FQ6DsyGmkvF/+TiLMiivx2C9R74ROSlSX0jMDw4q0PRuLkYIsLYX61RfERTIw+a65RIkdXsHwmxB+nESXb8gwKh8/n48iNf3A9H+Cg1EtHHx8c4jlCTnMp7M29pAw+BluyaaJxSvtPURJuNBNQVHjci+uWXXxCToS3HUppPnWi157kP2GWsuHzdhY77SC3c0s/vMqsyd0TM74/4ubzC7Hq9ggH7Q7AWN0E7z4502zHEb3CF05q7U0LI6n58f3uHNDweHyQvtbsTrxXi/MmdquN0YCkx5pPWFlSSQiTnDdhtXXfdhQXN2HEi/lVCtbCbC4siZ8Qwr+DPzEsjv2Zg7YY1CdQnH1Hh8fHxWmavUOgeNTj548HGNBC3pqFoV+cC3COKtBhsl8V8Jt12MjN4pLQwxfh81/sjQo95MZ25nTy+y4IOxMxkBAS1LeOnrfHNZT0O+bUdSDuNAV8iMktCu/tIeuJb/CJ63+NkSujSiCeDyjvk/aWOVL04TEQhmp1Dh0QnbX6bw3mU3hpMAecjfcRLUkoiC5V0g5tPknZksejmBPlfEcUaiTLuOR6Pvl9xSql15C3b4j7dkzsiaIEKt1NAAKzPFjqT7Hot85Ztu30SYXeIHYmDmYkMQVgWfJCYBjYU4bLuwFbVUtZDF1EiMtr4fVw7BXJcWyqqy38555TzNE1zLb5TwzBAB4XFqwPy/vhH+hbB4iPaDxwrtJk6bacSACc5WNc7mHNg2ECq79+/o1DlMAzoQfL8/Pz161duwpPb7dwnFV+tIT3dtmKKNQFrf8piY1BqXj+aZ5igPYjJGsOLokx8lxvw/I3+QA2GN2kZEEY/0lgAAHB4SURBVClFa+JKN6Dg2ZbXKCp/yXIQXKhy1PVETZ9YR6b8FZ1Fh3eCaTeQE4waA0DveZ5rLbUq7PoU2D/g6ZG/Lkwwc4YT3uHFwQpxc9Rgu48QcVoZ/0rBCe+vpEBw90ODiTJODOWT/HUOF2nVNGl7lvw2RxEzk5Ku1/NlXowGARfNDEFS+BVok4G+8bbyfmTnjui2ej56SRz/BAJFODAzCTNbrauVzyuWoURRRBGQV9d0Iw31BVI4RS7bakChjqPEJWDf666GsINdt6nxjsGR3dq20hltD1LHMOIu4wyDAcOqY2bjOM7zNb7Rz8ZN0hwPYRSrHW00mDEWW25ZOEHdBY7G5zubH4ZB0qJERiE1ps/FKU2XVWGN3/shdBiqalU9HB7cBB2VIW8fmbc1Jud5jrSPwrH36PTuUGiLrHH9I6pcEVyEUn/BtQzRPOf88fHhX8Ylq1ZtUbK+TZhSKeVyucDu7UHIpWwENR+RsXUbvcdeUEBnwNhKpKa8v78XrZ06wbvkhQCfEq43AOkORUR7P3GuMbvLyaUQ/NUP+B6BO/TzC8guaNUAfokmx37caqh0CxHHj4kfQ+c9eJ2/Iq1xJC5Fkaqi6QXkFZyU6/Val7Zjm+OsLbjJD5cEG0+skBjxKkah15AT7OlGHXC6Y7U8k2gcx2IbRo4pgbzX1k9amgWxswQ4jQV91mC0iGdqP56fnyU4K9ljbtTM1udzkLSkdWF3I1+tNfteOmjw7rztJ9pesOmqEanbw8NDDUGVfg+c8JGEOQbcW1tERIcIaGtuddcWhipCt4Jc4pytFSIGV/j27du1zOU6zVpRXWxM2YTRPXTtsSucWZQpjdk3Q5s1BtGGcXrceLBZMSYyQ/0pJcP1NE1KxkZKJsQkjE/OjAOGTFmPqfGKo9TKwOJT64Jt2ozGrsQ7BFyCNi0poTMwKRM6fXq/T3T6VCH010R31Y/XN8Xa0Q239amt03wts5VKSY7DKENmtVlruU6AGyXJLCaM+71np24/WQ3fE1EiNiJ0ltW5pJTGlFNKrFZKScQiQlVJBHuBjryJmJNQVXSipbYiMVJZMY2iCNIK4zljAHokYtu5vTs87GjBMAyYvYRhrcJRFF7x2LlYxBMK1myn146lqvqqr94D1XvuKrPOZdlBdGZt99RprqnizkTMOR3ywImPw3g2Y7V5nqkqJRkkUVo8opkFcGbmzDKZoQWn90Veev2aZfBpIoMOZ1ZLuU4TERmOGJBQFzHvOk+1zrUas6U0DKopDcx2Oj0VfZ+molSYU1U1Y1IahkHNGAFTZn6t82y09k1tSU4c3Sr+KyOapynlLMzTPJd5rqoPDw8iwjllXY+nY4UX43Q7hFNJajjpeIVT4zuC7rlUtZjWaTYhYH5mqSlZqegqjU9Kgl9Zqcw8X65+Bv1TmQ55WPaabIkFUFMymKBRqPLp6emnn346n8//9b/+119//dVCrRunsYvAZARMSOPgq6hEibi052N/39/fqQn0OXRU9EBLhOhyi7LOeahk5TpdcRJzGlPmnAdJxRSY42ufWxCfhYF/eiChEzFt9RX8rEWW4VkbsrV7zaWwViu1qFLVmQy7k1kKmZU6awV1GlOG7k5bcQTv9ZgM2irlesdS6/enFo+G2XFOqkxqxsKcSJKwGNOnx+fLdJ0uVyUbUk5DJrWilf+H//6/dyoQ2T7y2zioKbgu9XaD+ns0S27lz/ljo0MoEqn9uPe91o06qNtkidrS2lJKyJuutRqTgJAZoRerMVnV+M3CILfRK1Hk9/B9H5jP6/tbJJ3e1B0ELrNwTpmlmOpcplqAi5gbkNJLcEgIe3EhLjV8iOIktTgsid7rBjdjJbNSq6kSc05JUrqcz2omzJDiiNlUS61ZhoUEMpEahAZjmi7XNOTDMKKTcdFapnmuZchLYriTQieIxIyzkkQcrljMkHPKecgZBL3UmkSGcTyMoxFN1+v5cpmnqaq+PD/DO+Lk2FSr6kPrC+sryikZEUxnrqwjdzm10ncOSUf16Xr1imMSUjZBgABSqJLDMDw+nhJx1blL5iMizwPuBFDjFqywxX8P+oiTWfZaBDuCfcB6p+uVmBP8cO2vRnIcD5KHxDLXMl2u13nSUpXs3/3DP16m69ffv1zn6eXpWXKarxMnIlu8Tdh97IKkhOdL0248kCbnsZK5eBpxG6QNJP48XefLtdb58fGR2EwJn2AoxDYOB2LDk7QasSXJIrLkcZZaG+nUucxaE/GsdUz5cHpIxJd5oqqc0yEfLvM0X64QoNM4HPLAeWF7OpdrmamqCR/yIEN+fHy4XC5I4XOVxSGfQhgj6MZ0vjBzTgkyrxEBPwVlw82AveAAanY5nyUlnK8h52EctdaP8/l4ODg8HfON6Hq5YAdZBCIlXoyzsD+n2pq1gEuJyNPT08vLy3/6T//pp59+enl5MbPX11eUd318fIRQ5TyqqgJT8Xx8n1Na8KpWVLNyIgzEhksOddrBhhG+zsxfvnyZSzHVPAxY4zxNl+v158+fI2Z6z+bXj/eYqOO8YO+KwkZkWrlsPDiPj4++RxQ0ulKKi25aV9wGzcEhdGgQcxezwk1J+/79O8gFZA5oq6WU8eFUW3kMIvJaFDjv4NxeazalhLoFUFES8QRxtZbn0yN6z7syo3OpZBmmBmpKlatTnQbsI+3i6W/yg8iAZRupj+GRIPc46985YqUxCqLct2/fgDdPT09OjlPLb/aX+sUSDIL4l9Cjq3p/4lZdxPMvcYNr5LXWano6nZaw+PYEZk5EFExSzJyUVRWlKI/HI47B5XLxNiP4JsKHt06vCHbaJpm4KYKZL9cPCvqWi1mn04khXqhq8BEaZ2R6s5ERCTFxK6arpqpcao3tKXmJKuyE3Lwr2YiRh2Ghgy0iWkQGGGrMUE3GeRs3Cwq5A17E2mNzSuYgajKsa6JuGoXkjvPj5jKH59jSUWpLVAAL96A5xM2i9E9KkoiNlgPsa5StvT3uiwdldLxWg3OhOwWmWj0CUYRTGplnz0fHT/AratkHkk0LEQkZiQhpSimvLhFl3GXLJCxtYr+pReda0MuhG16vs0lbY/MywrJszZ4mIkdpPjMhIpK8ceDxUntZjEyNtfEjI5sVFRWUiAy4lkTIUs46UyUrZSkFIuMwjuM8VzODlX5m05lqrTK3vBdGHhczkTKR68HMqLHTeWo66k9En15e/KQAExx/1iMWothKKYjRqLVys+gew+F1Kg+0QPQyTujcqrGa2QyjQndOUzocDpUWtcQDnWqt//RP/3S5XL5+/ZpSOh6Pp9Pper1+/fr1NB6cDDrJWoJlzAxyUaha5QVtUgt19oIQcIu6twVeczQ5cBd+alHQb29v8SGYsJqNKdPWwor3plvpgsxcdnnAqSVnRinWwetrIVgiwZtDZatIfIjo7e0tsgNpBlSIMhT8JljX1OpTUbOOrFANEVu+hIeHR2YmESKpRMwpjYeDDtdSbS7nhiEiuYrVec6uMVCsoNSi5vaD7/DLm1zWr51CRf7R0Z3/hSPakSiYPpgZNBRI88svv9B212/O0Ed3RN1l4jWNERUsrfJUKSX6XCMENATI+JOfnp7AgMHIayv8Fol1nNKKcLsgHQvRjNTijB4fH3mbQYv31hA2tTHVyu00gOPx6No/tZCcWut4yN1z/Nrf62TF+ZbvlzQllYhQiczD6bH8GuI5JWTd+D3WjPAgT7VVenMfML5HrIRzFp/ntcVzpVb0B1P10p7TNKGhIYB2PD4YSbSy+GJ9pyIortelsW6kTY5O+8+Y1rX/YfdzIip1EhNRNapmxmJsRGwiKFqnaqXWmQAxWUtScHDQ2NY87uQ7mTEn5U1lZqzaNQl/IETh8/mdtvZ5zDYSKQvDfYE+KwkuSch5uIbnrJSls43jgHmZnfA6CxY1j4eyFlPp5yW+160djiHcwsFSyxPRXZSMh0l6UAsQyWM+LHAdaiWfwMOcoRLRb7/9JluLV0qJRV5eXhz+MNVcr9ePj49//Md/fH9/RwMlcE3IjmPb4trKIkaBz4+PUwNtXZbBaP0n4Dp+Ity1/I//+I+4GcQKS9BWRTyF4btGrX953Hp3A0ViG6mHAwGP6ny0HiIQS1bE1UUaG/HBg606BhzJSCnFo8xQaJaaidEPZmkl5yiU+4BFwVrF8jiHlFJpjaKlGbfnec7YNijRbgtFeR36tw4LjAGWn0iLrYlOcQP8J/dYsm35Yny+L1Jb4myt9U9/+hM1DQYAxQQ8gr97l0s0tuVtGiKZJYSifPr0yQ+8eu1lW4MvujlHw0v8aywtoqpuq6ktsMLv92Ozf75D1ZfvcyutTHGkg3FKth1RO4yEHiNSVRBKteIYH2WFGvI4LTBg0AWPT86hSJCFAK5YasfPOVwJ8XW8zTQlIg47IiGy93K5+PMjDD/e36WZnigotQgyIiLE68kSQHsUEbU1xMyxJa7dt8N0EzHrPJtaLWvaSXgx75wCNUm7KHQKnF457OPiuJ9VFdbyUifiTEzMOa7dQeHnUbZ6mzCDAUfqqc31RU0n852lFl3sooMT4sjCLeTl31RJpTWQj6Sz1UUfJJSM8BucQEe+wsxgbNxcfRjcgkD9Cf799HGOGlIKGW7x5MZ99+FRZmmXM+Nvd1hpMKUS0U8//RSlRmqVvFApT4LzCxD761//Sq1AI6p5D8Pw008/cVULEqE/3wuqODXDlDwv1ufmdEaClundnRGSDTutd0NSVZhkaSt7EdBGbkSudfqSgyuFa6dpTm0c8toSkeM5ilsTC3f4QoiohOAvCV5LaSXKqaWrLR7xUl1GXGNHWkqC44nTnEhnLDDgl5cXxyVrzJ6IMlRDZ2NQR9A9m24NveOUlua9ty17wMwkBA35+iOCxi//VaNjIRQkVvzVS6nhe9dsbj4nTomahOWoEN/1+fNnN004D6gGanjj+Y763cFANXyXuKWlfkaaFU+7w7+DIaKmawuHdsKnton/jGqo4xAFEzTZJk/XSQ+C9ZykOpmYyxpk4fChll/rFArwt6asNAPnEv7goZKp5c5jy6wZMPwc8q5yTbfknJOqmta5LlUmUkp5yDBlLwePmZ3cty+9c7CzSV9jSunh4eHp6enx8fH333+j1ZGcnb3UkN9sZk4tKDDOPRbtUQ5ReNHR41J/3I5wXiyirr+ilLkU5EWUUmZmagi1+qR9IQC4f7+KKUREAhO07zvwFvTXFUqXgVyCiQyYg8ldtvlOjvm8zdPzqHiH2zzP5/N5HI+OKm6OklCbum4Lo/71r39FOLRsq6N4jAWm59j4eFhqDvs0gKso8ahNA44AB/nG/S7uo3ub38ONzUfLYoSDW9Fqi6sC/J+fn2ddrGLW1Aki+vLly+PjIzyjUE9zzo+Pj+fXt9ryEv2iIxcdtnT7oq1aS27DxYta65cvX1DeGaUxkaDs++hEAHzRFjrTE3lrfd/3oLAmkTrH1aa58laAw+pK6IIVqWWkRRzSInwiIkKmeIFpVVMmSkhK1Fpm1Vo4SZKcyKpWnY1qAxECr7SSGZki9NlK0XlGmUUyY1uCoRXk5dxKUWqdpusixZJlBIOM44hoN+gBHXTiuMeAu611Ct5purcoyGYDmG+xr/vvddEDbN6T1v/617/K1oIHIcNFje5droR1z/e0AXhB3t/f0eHVg26cUw7DkJsJOj6fg/8gtSol1GhBDOdxdKfgiojUeX+W4kWkj9LiiQ7HB8zQmrnGETea2pxAwN+7f0Ws4BMpfqSbKZTr67Jl3GTETQ7wO0FbI3lyzuonTYPpz+lU3DJubBtbWkLbBj/Mcb98DMMYBRHfMrQr9nTk0+mEKDkKXNbVx/16HXrjuGq0dRupHlfnjBmMx/E24rlfWxhEplpUyawypxYXDDFrcYbi5apkZsOwVIL0A4UJuwYZ7fNGlHOCw7WGqBkK9WooxLVZy+P0Q+G7XIPfNJ59sw117kDaFdoED6amKtSW+xsJToSYf+luDoTMuEksh1p42IjH06MFRcJtkh0DluBboVAhzg9y3DsLsmm0gUVolG3++hLBIJJznq4F+JxCIg0sJYh4SEuj0vn79+9UVmtEPCOx4EwcyOfOrZxLt6dNqM3DMOAsWOujAFWPml0QC3cBrrZmCU9PT16LPp6vPaXFqC2aydWPqErK1uLoO3Lr3K14Hjd0HAenSK65RulZo32Clix52pE+DgqVv4K3RYEo2PlRMsHpv2NRhuSVmjuTW0MrvsMIfzw4hPv7Orf0YrmtbtMT9+fn7xyl1bhxXMEcoqmZgsrVvegHF7h2zQDf4CSLyJ/+9Kfa6jMjNA4m6KenJw6l0Trk8GtHDm1lHeNfJVg4nTDFfd2DHakCjiXUdGh3oVlIkaStxBMJCtntdl2orOSb6N/L7Zi83lftaEdB6cmt6iS3pheYJ4CpoURXpJW1DRwhP12NMSyCjp8EDSbTuC5b9KpigYU7TfT5a4g00Waq9XucsDq2RymBmcGAcacEy0ENAXF4Mp6zF+y4mWppx65goqs6ayUWS0IsxswslrMYSc6SBxEho2pqtc5m5kGyERpe6CAuZyF2WludgfUEff78+f39HVVwI5JHzqQhKVFDOQgNvhgOIqaTMw0+9dpqF+AkXq+zA5CClOaat9tOaMm8XPy7qH6FZcIP0gEZLMqdmtYy+51uOg5HRiXNPem7iQvvP+3Ld0ZrQQCKoLNmbsG5GMcx5YwKlLDfxNAQyB/OPnGC5nl+PBzjkyOJ6HheOy8pTk9Cvqw2P440ZRQ+Tg4Ri5GMdE82z8fltSCgNAtfDn2IOdBkmzcarWMUmljjXGvwTURe4+/lwOQoWChVFaZpCQ33dJuf7WcfNwDrOAjxeLubvh0IkUZx4CYptAf2b/yfGcVFa6tCrNuYrn/ViHDkQHApeJscWB0//re90TcGPglmLqUg5eD5+bmGJLl4lugWu3V7cvcJHPLCHSmll5eXnPPHx4cLYtSkdRIWEW7WzXi8OwXCceJ6vR6PR4RyONeRbcm0DazCWYqHKu6r6zG11mmegvllVcHdyOHouNC7XW1ejM50v1IN6k8gN40/ajMRnqUVuB7ayDm/v7+7jTraNtnNyM0B5llDMRAdOFxKGce1iQUH6wgH0cQDN5j5el3g4NwRj4KGgYppjrHArrizztejxSUC/NOntQRmJA1z6CQdyUdMo6Jwjtw0YttRSqlazExIRGqSbGxsKQ9CPAxjylPmhR+hK9EbUmxSCCxSVUTxQNtze6yavb19zFrd8smtFOu3b9/e3t4QHI5J1qXS0xiRxz/hv3eSFyXa/c2REyOIBOUgiCiltb84BU7vgTPSlFELrhl/da0VSnCsT+Ckk5mpVER+uWTPLRTL5TwPsDezh4eH9/d3iLnctBd/3X7LlkzIoDBhL9wy59R8GIaUM7y8LhZEm7DPDU9OoY59ZKWO9nuiR0RoolDacDIytPaCzkJAA3FOYTFNLfoMAo3TOkymlFJxMMl8UdwMZo7P3I281Fh2EElw4Ts1iOJOPD4+HB9SC6LGl8fjo593aYk/Zvbt27cNX2y/zSnV5hPEn8AprtdrPEG+lbb1cMfzC9olLbwc/+T/8N/9d/TDYUHoJlr7AdPW396xbUe4/UOsmSg7bMCFFyONYGVm1GCD3AcjEo7NOBz9HNYQDOmaa+T6++n5fMDIY0iUPwrfwFn+8PDwyy+/fP78+fv37464rtIZkyOcS7J+Ml08hyD2+vp6Pp8/ffrkx8kxmHcWAh/ZQsxXKN7k1tFoWlFVBEn5HjkEooTuEyCi6bqW53SMl2bQBup7tLaI5GHRrZ2kSjPIW9AR/UXjOP7zP//zNE1//OMfP336hDgOZv74+ACRdY0HG41pRwLq9Dcinu+1znNsBuDs0O06KRQsRK1m2nqMMFIwJWE5KD73X//5n/FAP1cgRrFwd4R/TikCk5voGS14wBMQYhRG2GOpWzWtKYU555zTx8cb+u92R/LXX38FbIG3WIVwfnx8LqWCwVirzphaRJWHPi3EiHkcj8PxoKpvb2/YKQDwT3/60/F4xFb+u3/370opX79+fXl5+fbtS0RC5yidNqzN0Ie+qk6ao0Dg8PRdJqJxPDo8MfBPF/ioSQlYwvv7K1RDVHAcx/F8Pn///h0MBiUerXWLe3x81Gn2hg0ajB+Ois5C8M+npydMg7f6VmoRsynkDpjZ9+/fHXsjxUcXHV8UJI+5lF9//XU4Ht7f3//lX/6FmX/55Rdm/vLli1u8dBvSpdNS+MkxNnKmeDNA9Pb2BtL09PSEpvGgS9Y6Z3herLbmP35SUotIdVZkTfgwtE2bZxGxnUKyJ/sr/f8481a2iMJrapYMnCBgeGr5C05/pMVk+FT94pAzrETUQnwAEA8ejKTSmOG4WdlfzD9ug7YmWCeS1NhcDV1bAEZutfT7clfx8N8EkKSNXTFytfhPv2fvTu5ElW4AuBH0+H5ofWdFBFEVoBfHw+oI9H3ibdh993a7ZWD3PFGXaHwtsL+JyPPz8+l0yjl7toxD3xlwSskbVlMrAGstTsSdnTiiyO1x0MX57Gfe5i8SmoQ7ZuhWY3YGEE3E+2dGroM5PDw8eDoQaDeI3adPn8BsuigbozVdgQLPuBfsdrlcPLiDGuKaGTL9Uys9AzTAyY9IdY8BN06vx8djDblYLjo4XkX8ZOY0HFQ3wUd2S2KrrQhzJHzAQMjCT09PEsySFPA8kmBtWeMu3buI4IJLZEhuOnM4RE5mZk9PT0bVlNUKmaBeE4uVWYloHI7DMKC6FRP0IRmGsWtvbmZgMzAqrFA1m6YitaaUHh8fn56eoO/C/PD4+Pj8/Pzt2zcXyFQVuqC2qkYSjCsUnKbWjHI4ERToSRQTKcjW7WIlhamZc6LE4+fLTzFyZFGOw1uaYgkpJTAb0M15nqWxFkiQqVlTEHPkm+hzgCAbjyQ1yh7n70cDYVN7BowM+HiKU0oEw7JWEfnll18gGWBFc+sr7CtdGEArVYtdgEHFzUW+49TC3JyFexQnEQ2hwRE190dpfcojB10EBYRcbUulppQydjZE1jupcaoVWayZUVkZpwUJ3l/qXB/XX758cQR+eHiALy+eEQritZm+19lhhSlhJjgR8aX461zNbilyqIQYQVpb9F8kTTjONeRrgTT589dCyj4ihfJ/+npENn/1azepOUrFv8ZH7b+PIyJrvICSAaEVhwHB9/sZ+gmkQGdvziH+0xm881RqBwk5Wsfj8fHxEbEY7+/vHta/wS1euq+4buoYBsYGk6YfPw993M//JnDiimSbXOEoosFBoqrSGkrbNlUmbX3z/tK//vWv1ow/p9PJeYMTo8hmmPl6XUswWtBgdOvi8plP0+SBcq4vllKwp/GYOW31BdYWVCKhlb1zOxEx02EYhEyLkVYiSjkdxwFlfZxkqCoxpZQ45aIr3aeQzq7BamfNm+UhlxaSvnAnatjiyIF+LUdxGPyIcvC8PD09RZyHUdQa9XeYl5ZX5mkezo2anE5EypzM0A26mrFZfX+7ilBKgwhaNCoah7WyFusqojbpmL/QFNVpKpd5AkOCvAgfgZk9Pz9DT/3y5QsRIRZ3X6BGgkWkhoE3ekkHbvoN+KIzbz8RYAPeIM8ZngttvpwoS53PH2gxixaEucUnv7+/43vYolFp+Xq9ztPFJ0Pb3GI/dH7uqBXx5636W2v1wh20ZTNOoyMb8Jn7zi5CWc7TNJWrPj4+/vzzz5fL5S9/+Yuqfvr0ybZyiZ+C63XNVnAscs7qJzQSQF+p/ymlFEvtAphgwFFA9Jk7vfXlLCeXaJomtQ2d5OCi8lX7fqVWSNkpm8/TAmtEyPA4jk9PT+/v75CiXEiq2ypPtjJy1UKy7afus/LJLK8mUhYUfokHBM98fHx03HBSUFrGVPIGjsHF3mH+YrqvIRoicrJ6yyeKGyMn8Auo8LwTYNOucpaFGAoOMhEuOp7qo7bEcHceiAh6b/mBj3Q/Lqrb+zhzv47apIMVgiG12CtmhrjnlQt9DxxpOlmJtvqoW9V4FxNhW7er3eHBpZa4U/7q3Nrt8VbC8Kd1b8yhU5AFk8Avv/ziU40I57asuNKOxMSLeADi6iCLHI9H+FOd6UbUpKCEec3YqJ5S6Hrkd2Kq5/cPVN+DROiSMpQAZr5er9jT4/E4HuX9+7vJZmA+Hx8fqbVD8VmpKgUKgocDDmC6wBM4GhZYNSyaQx128DMKOj1y8Uspx+NRmkrHQatzS1KHY6XMcdpOuRoJKBwc26qa81qVQlq+Y2rxBxETaq2l1uPxdC2z+0TdgZpzBgMzMwgfeMXLy1Ok8rxlWvt91ODph9UUnogS8oOdu9Rar9f55unoXueoCKeGtug5lGxEReWI4V5WwoJ5OT4cUawele3aqgfpcBCPHNki5mCUVnwDAHHy6CEOzgJFhEWu1+tUZnigwXWQauy+Ya9LRcGugPmkls5H24pyEkqdmBmsApCcYGGm5gOKXCe3+gTcWCzf4sROhXDt7QI7/rLPd1/+2mDuIjiGCzFARQ+m++Mf//j09PTx8QEjpbYqAo5UW6pVBz4S9eosM+N8RXlooatCdU0qNEc8+MK9bAM+EStOQRYEl3X/lDUjAdCylJIjI4xguseAlzr6W4duhGN3EWXY+JM9p/RjHyfjf7LWqh3Acjnocp7i8dat4hWH4188t/EkR85hQfk4nU7oBVZrhevOnxmlDVVV01JKbf13HUfNDEFb1BL+umnQjvXub/AbO7hxk7mcrsVNidthgQ1HphXFwHE4aug54eTSa4NH+Y52BymHrME4B2cbcB/AgAG/PkiVBq3F5ywiIC6RPfh2d3dik6freht0NVjtoGQT0fV6/f79+wIlSfM801ad8ud3mNOWw4h3EpGch9RW57nmIlIJySDKakk2nSJ9azydJqod3PpG+7Z6DEHXTcsBC2B26o62bjxR7MP5d4rflrBWPopcE6tWs5eXn14/3r35IDPDHvvt27ePjw+vr46pqmoMbnL7rVNz/1N3SFMYgMnXr18peBm5kcUIHwuCoIaGehzscE9Pp/f3d1VFSdqvX7+WUj5//szMqEoIYv39+3czG4bh+eG0B7IFWzRti/ZA+EjNN+nR8ju0WQaSaO2WBmy7+lAOMVSdPJ1Oz8/PKaWPjw9UuHN/kG/cp59/rs1dMocyik4EHHQ+Df8Tpg35+O3tLeKMB6mhKx0AzsHZL6HvpLUenTNMRLeyQrRp4dEOT0QoJBJRNLVKWE5wEA4Gagx59/Pnz4gVR/0cd2/5aPBUIltIdaMeDupmdFiRTVWR5mHbQUTzdLGarM7WgmOGJJxzmS5sTKoa6obGXop5GIbEKSXLUrNkl1b2nMl2ahMzl7JxQfkYtm22uhtuXlPTzOJ7XXXQrS0a+A3BAUIQ0N1tXPFm2rF2/16D+SWOmHwVhZeHhwfkgFLLspdWU6Kjzo7HRtaBwszABnJLMIi0spsnbyWebsR8PmtyqP8qAhkPz8ONblHWYgT81U65fn/9nQLuurjQBY+soiWtCQm+ZBeunQH4BFCbtwaniB/XSBEcLJ0YzkGs4SAgN8ZJfDgwG+gO8N4z8LDLOL25ZVmM40jt4PmiKLAHCzINoRwBrSVT/Kx6EJ8/ZNmaUrllFXNoqJVaApWGPtwSiiFEcikiiBWi5jX3MwItCr2OhDP8wUaVTNSKVqo612L+/fV6jeE52nx4vok+E2aWhvPaosfdFv3lyxcPiIWUICKlFKLN+cIhihTfkdy2whOFah6AEgWDSm4J4ofDqMHc4s/RFjgdyS4ziyxxGKfTSVURuU1EP//88/fv3+d5jhKkOxH9sDhaStDjLXQ4df6B2zSYoDvKgOG0mLcM2Fmp36yq1lTPeZ5fX1+J6OXl5Xg8wqUdRSI/DjmUU+2oaCRuzrC94DOc0Cml4/EIndJpiKMEdt/lOX+yn2i3wWLrS62Hw4GCQiVBY3Yq5wiAdduW49jWz+2VaiBefP/+/eXl5eXlBWn6b29voGzxjETSNF2vHYo6/tguf4mZjW+XUIXaEFfkBNPZPzUJOxa2cjEdz9xUD4iHwbEqTtTMqIkz/fe3qLztShtGXKQdm6RAebsTi/MDd6yTg3meYbRw6cEvXJXhHWfq3ujv9c12zY+ZEaXcVYpwCdcCG04pCeoNUY/ufiC3qMZ8h8v+YAivFccsSBupheY7vet+aFsNLAKZm4WfmSM9chGYiF5eXmK8N7vjSvv+8C7LO3+NqIVoTxxUT4bJOZ/P59J6L0oLanN1La4UnzDBxVczMxZEtNh5sF+oYAUP6/l8BuWCz6+UIryGj0Wa0uUFLmiJt4T6ya6yoDW3Hy1XLt++fpEW5wwWhWfCe+pRx66CuwvG8aeEUnz+ZGlRqdO1aCVT5WpYBHzArSgHmzERkxk+HW0i+nW4RF5jUvVymS7z4nABkqD0/ziOYANOv7CV8B0Cc9wxpqoQYWlL76wZQl2idfx5fn52JuHyk++2U4l4oDqsxjUsT74p3hoLpQHf39+xBW757/J3fbj73zmNbq0FPvMoYPmW+Z3eDIC3DBjtESko8WZWcZSGzMyQHT8+PoZh+PTp09evX6PsLs3e4DZkP0dOgjbHthk+a3Olwa4LWOWcQQei7RRb7ATBKS1OBza6hNwtuDDGcTRbGa0LDRxkskjnRXvtxXEGM5GmE0MUwHvf3t4Oh8PxeIRvyz0dNcS1CQImUuKWJxrxMKI9B7bakR2f7bAtOezCRxe/5hF/HpSKnwPOKaW8dL0lJhH/ROM872opRn69P724iOlDFhiwL96HY0z8uV/M2xq5fv/pdEIihLaCyTj/p4enIO1KfGPcRQsCfvfe7p9usgciPjw8fFzOl4+zkh2GMY9Dnct1nsY8GBMReYdaMTKmnDObon0bVS1a6zTPWp8eWts1VZ2LmTmc9/1fTRjtC/G9fzrG1G28LrVCGdRkro40dPtCobEBBYGJiKZrXwsaA56n0to8+NlOmbm1VxNm1GFSM4RgiAiatbFIbmZSnBm39kCfRniaI4nPLYc80XjhRdX9CIH1vn28p5QSixLlPJ6eHn/++ZeXnz79//6///kyXc/n63UuQxoOD6ec8vl6qYYjnSHi4w1mOo4HZjKjWlE5oRIxMT8+Pk51LbvmBiuHdml9oph5kDTkTEvPIsXzmXkY8jRNqrWUisCxcRyOx4dhGL5//06tUgbT2u/24+NDzYQ5D8OhVm+BZ5TIiAx2gtWo8PDwQCQszCRsVitrrWp8OJ5EiJmrak5pGMfD4WBE8zQZrQ0fp3mu12spZRxzSgndnXUus5ZBkh715fGpklmpaK9ZyTILJUJbQPQwziyVObPMbGPKjslUdSbcSYmYRTKL5Lx0bG0nYtaKp2UWIwIVItocZGmeeJdINGSfA5cgE1irGVlK+fLlixfG+u2331T16elpGIaPjw+bN/jvDN7pstNrcLj39/eUZBwPItwsICnnxTUBnAVqmDGRPTw8qFYzYiZgHaB+vU5m6grYQj5V1SwxP4yHOef5cn17e/v88unT558u7x+AJOiMMWeWQdIsm+5tzo2iQhLJIHQD7478+vr69evXaZr+/Oc/15bcVVsQFhiwPz+SF1eLI9GWhWMRq5Esn6CT6ExMVaspuvZSVSzZhddokfK8ZKf/3ATZb9++/v7778OQf/nlDz/99Ol4PJYyf//+agZD5lyrEhmzJCJJS586Rwk3kLjUSEFPrbYig//KmgspPgeI9/nzZ2osmZo+qS3NyQGFFeWc+f/8f/jfe09c75JrTKfjg5JpqdUU3WHxV5IcCZ8fBtvaTv1LtbJUdWlOSiCBVz6ipnwAuJ8/f/7999/P5zPEGZD74/H47du3yG+cvyKQx72S0gykU2vv1bHYTrxyggUrAZg6BPbPnz+/vLz85a+/owV37IqKltTHx9MhD1MtaFMvtlZ4QLPlOhcY/jgJGxWtVlVyOo6HNGSrOtdCVo3w67XBuJodxjF2BjWiWkqtNVa8sm0xJro1SqigxMFwWkPsK9/y5fj9Ls/GtzgMX98+0Iq8Nf02EIWH8TBrnS/Xa5kzy3A8AD7/9Od/nOfZvTUQtAFzCS5Jx+yITt32RXzzz/P5g4jQcVOMZMisdi3zH3/+BVBGh050nOWcaq2IIhYh5sRsiBme5wptEt+AySrZ8XisO2GOiGChAbVatQHV43h4OAwPx8eUuRab5ss8VbXy/PSp6mzKeZDD+LD8tZbffv8ya2W1fBifHk7D8ZCIiym6ioIhDZJkyIMkZaplY911/cyjrGOoiJl9nN9EBEwOO4WG7YOka5lZDU8GnqdWgeH8/nG+XupcvD+0lmpM//infzg9PX757fdq+nA4flzO377+7pgsvHbDfX56YpEhZ2Ims7kU77ML4cz7UkMIOD08lFqZiEW01sv1qrUSc20hrBQC9zhYRJzMuVISj787sP6b/+a/AQVHUB7IUc5ZpzneHzmx0xkOIQuDSDT7I92LWId8IFZQC61U6lRmVSsPj8+IVydS/2S263X2qHXEtJvhLapmWitglYfh4XgcxjGndLleP97fP85nrVVSOoyjq19+iLSNmKXiq+BQQcWFmPP5fL1ev3379qc//enXX381s7/+9a9fvnwBkRQRKHPwJcGJ8/LyAluCO4C9bECtlVufYBfQjeh4OEzzXEsBfVOz6Xq9Xq+I7KPQCswzLzwNAYIvZIJyvVad56nO5Uomp8fjT59+fno+vX5/P1/etVIepMz6/vGKv7qU//8v7E12JEm2K8ErIqo2+xRTZr6BmeAjC80/4nexgUIDvWKjC/UtXHBLgkQ3CC7yDREZg7vNpipya3FUjh1V82RpAA4Pc1NVkSt3Hokkyu6C2L4DwnQX+q7gf23qiHFC0qQ/wXy56qWRC2Qf1AVwBhZ24hUNpIUF9DTCPzM3NARQTdNitBgOL1uPUwudEnHiZAgh9PlitUCQ9pMG3l3ys0spaL2GHEtoJSCkSW/PviZJMgkliIWXaxq6amr/hZbg7jCpUW6Pet+U0na3izFaMA+ezDx6gnunxiYxzdRiaOF7bFLMwzNTSX24ug1zzqEPHofy9pSSR48xcppQEHV7OBvhL+7uMbrEiiYamcZ09QIjViTj8/Vr/ILGJvULtLAJNDMr7pvNhr2v9Quo+oir5cwH32zf914biqlkxe8os0nTrMVSxll1vHHiQZGfwcw8xhCixdC2s7Ztl2axbd29y33X9R0SjkKIPRJPvD54iCPWV5lZgQShUX447Jhkp+TKucvubqGE6KkJocTlct7EmEvXnwcX92zexDg7nvZA+HRJaBMRYyzui8Ui5qHgMpuHvu8AhzrnY5iYG6PHEEO4eHUJpphSasNAJvAosGUNZfBmvXT3HNwHXui9efTIhs/JPMfBP9kEay1a8Zxzf7k2wwKUBs5YHJ3LooVoAQz0FrtCGCYZQx7HEABZpHepbMMty8XC3MG1wVyAjlFqWqLkKGiSGgk/pcSksCQVvSBAhj+gr0NydEOs/8qCcVHFpynp7mZ+3O0teBlOodiAM8GG+VS9u6PmLaVk1vY9stnh+PWmGaIwKGvhkyngT6eulJJZZ5EzhNDT4+Nqtdqs18hpYKNQKOjxxs3LjSjrs5sevV6TPJDtBXmz2Wz6vt9ut7vd7vHx8enpifIPOAD3mNdkjiJNFWOMGEsQYyzy6lJKijHU/gEpRiT06fY7mQF8f39Pqsd+Y4wpxfl8Xjyl1NmpoFFX3/cv29nT01PqUggwl93C2mqxL4WU1RBPqY1futqWn9iSwmCqujuHBIbxpZ/Qic0gNJ6JEIyyNRBFc0sqk99Hb6qIT3Qko0rjciOeOo+WiBtrcSdfTQosdbIHMju4YXdnXRqd+3gFahNTzU5kbAbH7+NwhYnE0g1atRShrSCeDzQCQ+dSrwxiuQwyUp4agIvSHWtpaaqXV/Uw1koAC9duxuQUAWPI6nYmMklpie/Kv9I5i5/zdgps1U6oKWtBuiKDhhj4wOKeUuvj1DZ8oZUxZzhKwBZ1nC7TCKz2PeA2i9Sr5HG5l401gNtzwQZRKgYGDVyymhSaa8YTNpFSQlKG7kufSW4Ohgt+qhdOYRI7HERODDlnkyrVWL1zZC7UL9u2jU3Tti0aF1jt4lJqDXGpCWt6LkU88EGaUcPiidWTxvj0LTLgOAAx3mVsSrxYKdooo0EYDOtHbtdyuVws71/FKz1HMsFSCutK1SwDvrmUyjji7mbz+byEwcWn1Ed05frxk7HkWEu0YzVhKYDZXcTM2tUqiOJO2Oo8WrHMQnuf3EbZ+7j6m57Pw3ulQYdJ0UcvU330dJ6engjkXLPNQUd4CI6VjbRsrP0QGhPWr4iqAjhIPViMEQYJ4/rQ8sEekVsOIb3b7YJ40Sar5Y6I/Ga23W4pa0st6HoVRXHQx+MRmhOQDSIzxlnJOaYAMww8M9RQZqnZFUkm+6LbFxbPsrdYI8opJVb2h6roc/Fs1VckTqxMIEiL2VQrgIEJOKAQRu2QQwijDZtECpOUDwmpGyyeCRMk2Uyw0KSldappqH0tjQpiMSdpJ4ZHsbDYzJAHqA9sahkrZRu53gTb1BrmTm8ZStd1s9kMegqSR/Cay6XHPEvFaQMjGDcrH0IU507XQLRm4oz+1d1ns5YhFpfY0vPzc5FcCcr4JIUKSmm/JoBZPqToXqQpOZVBE9mjr8DFmIeJTLIQ+r70PqoIwl+RtIWOWoAScP15t1U+W8ahNbJaehcVv63yCx8rIpML9h/7JoI4ybJVASolN01jplHkERBsjN7Rbb1eMxPCx6Hf2ye42+FwaCTvUXVHrhaaFgRwTLO+NnLJtb2UapNEYPyuilpXOzaD4Nu2hV2VJCMU4yZ1v9gCAN7JdO2mVjmbGbJyWhkGBfplcXOsrVq+fPmsLq5cUxqZZRbHmUGsl70aTPX5VqvaiBIFdb12VcRNmtoq3yQeUs71dXQx6AgtDGMd/kFxvmxnXEaQQTfKNOK1fjpGt+IjWevSu5/kdkUn4av0BpGTkJsRr9r2RKLg20MIf/7zn4lLobZETdKOWIEw4TlK4FwzP4SEKLX63KuMR98VjE89HA6cfFxqCYCyZW55IhF4Ond3d8TJItlk5KiAQ65xaF7K2HPOl9OpnSUV3rF6PmCgl1psDRUTW6BywI7WQD+W1cFX3Pd9EwNLGYnnLu0BvNqZpdadT2BONVdVOgLkagHzhtuDubLGYPPZMpecx0XrFNsm3BnXar2wKtch2NDgkPdStAB8SI6AMEPCKv7EXp1csFfrVoUrJQ1iclkS7ilpfKyZ8pYovWx42jEmzPdVaadMEGTcc6pgRSATsTHhCKSlUspiOdP/Ur666EPKK8lr/DVpcXsRPgQR9U0XKaJMR0UO38jevLmWBqaUYkrnc6enr4ikDIgIU6oZx6/ZePiEnpeLv0hx18V98up+Q/Upe9Xc0SvH68zHNIzURjLXaCAg2ZwenO6usTqCIly/0Cyu2b88HXhP4hgHlN0Q38AdLMamXfB2QimYxSpWmpiaEJMFK57NUzNodVmC+qWU5qalK9a2XIyGJRAtoVAqi4e9CJOC0terwYTvwI+yXC5BsGzM2UjJLAQwfcUToijVX6XSQnFDQRdDOJ1ObG0IBrpYLNq2RZCSXIugY89a/dDM2EWkVLsEb5nFV8bJxeriJj/BvlKK86YtN/gzOruxMG4k0yLnjO54cIFQXSCvD7VBBFdClOawGZp6FMaTwyXW3bIRRQD+gt9Jrfv9PucMZe7x8fHLly8vLy9I4Ig1q3+xWOSafhXGOeqUT/wEvzS16zsdvKwPVP5JKgbB4hzpbhyyHQfV9zo4q1L3wHNQWgbR+Lzdp5Rm8yXaGprZ4XA4Ho8oFGww4DukZLFYDOGymLW0IpIEpFkOYyJQ3H0xmytUCVgq6DS3cF6jYYfKefta/BBE4Hmwc99NBFuQSD6VMj5zNn8H5tJLoS0Jm7ilTDxWx4VJiKKVruK64VRTiuymDRORzOVSqlA+uFqt0C0WzAidLw+Hw/39YwivyDm4QULNXOjr/Aav/oMJB885T1ZC1FSqa2q/ZSAN+SZFEQuiqFgRhva/u7AScEb42HsZq4mnsX5R3+Lud3d3fc3rKxwxlHMItQWGvMWq5Z1SAn9MtYVhqsMJrk57EXg+LiY2kX96cKG2NuRS+XYEm0u1jdBBJYTAFoZRhreXgqTHkX2ju9Dn4zuX2kAjiPpotZm+Mjvcu5rNB9fIeMbtxMofZKT75Xz2uoAiRmGq/QLpUnP3UPyw3/Z5NAwDBwQDhcoWux3l/qJ0RAYBS5rkE6tvtjsM59jWZulQNIEPEEvL5fJ8Pu92u8vlstlskhRVc5vawtBELdCzo7JIcQKKMLIIuKari17JnB4/ylR8Dreh9rgG6NgqkpiPqw3XXqSqkAXpSqY8czabFb+mCvPo4bylOcvnZAmKTSJToQpXE41kvZ7WJYP60FCTHxLHlFj0Lrq4JxaLjXUFIj+dyWiYAwRASyIdIQzPzWazgReasKIh0UtDHsXnz58/Y6cIEoFjwM+s+OPV30CVhcsrmCWas1sm8IkYsUaLcaGXQ9M0h9Ml5wyhSzWx1Lpz9QDFGNN8OZu3fC83Yq+Vy+Lod7udwpDeIMpTEhfuarrcX7HZrqwUxWcj6VuK1aHuUWZdmXBAymAuAr3aITbYASDKvMwwvhBrVFRQYrtFLLWNVJgx+cLE/rZfj1XH8TQVXqUUJN24j36Gmq0DGYaCyKZpLpcLy1vJEby6JnjxLVDi+tqvIFZ/C5weJjZEqCG9yU65TnvtKlVhJ1ZRS/WqjhF9TXRnEy5ZSqGjhvgHZjObLfw1cQXbyMT3UNi87HTKNSJIvhbFC60YRZLGfynw6Fa9/ek1q2u5XEIeQHvFG722dQwhmPn5fEbWDOFDhLEbhanUcKyNC+1jjECAiccl3Aha2sfQpVh5OTAs95zNbxZAWjDhZXjs6XzhkQ3wHPKbPEULUGeb2DYRpsXp2N3SkZkh9/VSB7xzAUGilcrr2dw/VPs4hNA0zW4/tCJqxh2FNMapgI3iWlf8RGEMOSmeZvAZhKsoAgDRYJztRBT/0bnJRMzQBOEbk+RVzVPDPWYJgsBlqpynlOJe+r4vfh0gplqFV18XX03ljxySfn4q1vgrYdV13wgxYleM8fn5OYRXHAZ3d3fK9FQnCGO+rbCa0LsSFFuqoXnnZrNBMxAINiiU4O1WR2so0qpZoufLkyXjDSEgtJzGQ5aIfq/tq3gpIY5a1uA6HA7EWMgaMDF0Id1ut7Dsm6aBhcBe7rzwuu58dPeQmvnyGukopXid8elDBMuKm1nYbbfKTJKMTUu1M6geweAHiNXdRx4UJXQP3Bo0rHRtuWeSRUbGh6oyNq769vzFqkXYSL9TClrsNo1TMPDGWN30ZgaBRHFLscG7JgcPV5gWYCg5TcR2KWW320HFC7XWPqW02Wwul66EKSM2M3QmwmMZcQwhIImM/IvMF1n7STLRcO0P275eVn3vKSUYi0naWeCBsCx1IxRv9trFell+n8cfqh3p4jvF8jQKhS8gKK6xzFJKLsU91BrgEQ0TN3B7qlW/1ndwHpiIbaX8yTkGUVaUNvgFPoHnzqAjkafrOnRaIITLUPWUuq5DknOSuoI4zqrldkop2ilJOddut+OyI7swhvi8e+Yn7kPCMBowoSuIu7MBsrvPZksXutO3K1WCZeecl7MFstBJQSCNSTLd+Xzebrd4L08WvwDyLy8vTJlmtkHbtneLlVfWT1EKdsx7yTGXy+Vu/0Kg8dRCnfLEVxOvCOfJ9/U717/G2Pc9qjCiZIqpsJ9gDn3LUcpFKBeb2smL3KCxkCUpSaFE9OPR5FzW6/VEAOOkcLJlPCMVW3AJQlm1g4OoREGuyyVTP4ui0RYpeLParJ7h8DhOO6X6zncpuSkz9JvoJpATQZzdbpdSur+/32w2X758AdNz99Pp1I6H2UzObsKvQgjghzgRlPe4VEPYuC1aKeXu7o5wAKjNLASbzWYxGZg2NafL5fLy8gKARBn/mnP+m//2fywWi4eHB+wI7mWUDCCLkE4y0Ndxt5/Nm9VqhWxfqkom8UHlP2GsZJByObzBa3uTwaz6v//7/0m4B1EuJvNi+dDL+TqPyGtii9duSuQmIQRU9cCjY1LazOWqNOUCTBLPggRLuq67u7tDszE0dIWJEyWZlowJZxBrByLQGMU/F6CYYdKBj/ANMZoNFRpFXO6UQKp5YPF3i5Xgx/WbmJZ6f38fYwSna9t2Pp/vD1sVdVQsaOneAkeZVJFwgHJDq00EGxnkjhthoG+32yjJsXwg55eVGhtrpI/jJEWwuCNJLdXqjhACvjabzdDq7+Hh4e3bt9Ax9/v95bAP4wvAb9sWCIPfSQNF0qRxiNiLZnGX2k8R8h69J5+ent6/fz+bzZ6fn798+aLpIcKFMVjm6rDxqotoZyKV3JNYOE8kV6f65FEuvXu8pkHgXEgUOrf13BUeK6Q12NPj4yMgwIMA7qK3MEUXN4iJdeAsVrOomqY5D/W3OdX0NPIUrhlEDURaNjNs3McT9ADwEAJQ+uPHj13Xfffdd09vHv793/8d545XozkRDzHV2bG5ls1QkCjA1+s1dFDoxECM2Xy+2+0O5xOOmKiLWEMIAeNst9ttKYX+UkT7+r7f7/cw2hAYDtWlRB29lIJxeBN+ZXXWUy9Db5CEZbm4jUQs1RR77fIbdx0uqD5eB5WShC+XzLNT7Opqj3Sr0SsmupaxewzrUZXaROUNN85n/II+7VbTiZHNdLlcPn369Ld/+7cfPnz49u3bly9fQu0Kud/vMaoVrbigp8IzgeODa3A2mx0Oh19++cVqqBEdrEjXpaZJcu4v0BVJnQhl0otQSu7Pl8VyxoAUmZW7Q9N1GSJgZsdz9/Tm7du3b5um2e/32+0WkAdJJhkWHmOMKZSb6WGA236/R8UXisjxCjPrL0PeEl5HnFd2oYt8ZR4wbuZ5K6MMITw93V0DyE3TSPksQqdQN8Afm6bB/OAJ9VKeTd6O44RXFmdAOK5Wq8PhwKngKEvd7XbosV4kAFbX+cQHRjE9g2iaZJT8XZ0eIQQLIedrnwqFBlob8psEOnmNij1ljmphBCSV3Fh7Nnbm6EFAsQg3Avv+/p7IoWRpoj9ZLcimc4bchHCYWKI0UFCTTXEYa8Oey+XacxyMFeeFyeEI8ATJENHnm1jwUXwwxBPoc/TsUcSWmtxOjZ6KBZkjpDUGlpkZsr7Jfaq9kuGCjuNCHYLdJTqIFzHGMzl3Nr4gtPGKVCtQQ00bARNhU37VfspQXBEVAgreVAOr17OWvAeaFLG6bWOMNIXB5WezQegS+am86nZIsC7K/gQ9IBUI81RHTq1WKwyXZUkGtBaGxJSfcCMEHfYORdDdke+D5YHTzfw6r5B254cPH6i5Nk0DSXk4HJjUSZWCREodupqzuZTSiP3J9U94lF29O7GNyWzUVbHUXGsikquRJMEUpXp+Qn6VpXlkNx51h8tleEOoypMaJMolgkyjInoH6ZqnK8FdUPhSLfEC37i7u/v8+fPlcnl4eHj37t3z8zM8K7DZVDpa7SrYysAouEkeHh5Wq5VVaaSx2Dge1BHHftMYI5sw4+ia+9i0cfJ2d+f4nCLOjOz++PgEKsbWHh8fgQN0QYfaxXbAgTKa8kdAQSsCi+NoWndfzMazHMR3RWQjiHLO18ofXvgEda5R3EGlplnjeK5quLs6eycUZTYK5pGAe+lwyyuEgEqvnDM4EXluoI+oaTAVBBTS1MIsH9cgQUK7WLqypCs58a4ieZj8MkhXB0rzTzlfNWW9uuM5Sj4FQfHw8ICUdwKTXg49LTJZF6kcxAPBUhAFWgjh8+fPLuYdF4ZMco7P9JptyMJw5QJBOpSRYvta0uc1veL6BffFYqENSr0WOocQwKCRXgtrLOeMgcokDHKTvk65wH+J7tvtFtuMMmqXigU9xkRdsH78F29klJ3My+q0tVLy4XAIwfk06p1gvkUK/gABJhNF8TKZGd5i1RkYGeKVWKOLXcLgQhGPfSkl+5BsyZ2GmhRpNW0qSbOUc9WQKIBD7ZLhorBTyjIooMTI35UeBzZRvYBkJfgvPVL4MuixbVsk7MBggswr0uz61sk0kb5kuIgFltrDDyAtXWdmuVwTbr3mdvzxj38kZcExBmzBOWbxOQ+Mr/IxAmeAZ9eru4IAb2ouGPWhnHPfW+cGCzhI7wV8TSmXCHPuruMUlaGT8Ivo6KWU+fxqGrpECSfo569d5GxkC2SnUbL5yBL1F+TQqJoLhtz3PaIVIYSnp6e7uztU6WB6FaSpuwPsKSU4dRspFWuaBthSqlada3zX3RHay7X/Uqx2HdmOCiN3tzA4q+HsIYErpaiAKKW8bLfn83k+n6PXIbpNwMMxgZu75/7aGU0vOFHIFa8wrxmCE67e1rng+NrVE6bSaHIYPGYefynl+fkZTIGlHXD1gN8hFw52DzwG7ew6Jo+KmFelTKUdMC9LnwTEVs0MaZbL5XK9Xne15wuCzVmC83pCfW2VRdDgc44zm+CcLvLKmyTrMo6TqiasmcFRq24T+OiIlCh7IDHwdev1esKIcU0Mbi5ASY5P8+v818G5x/fCwgYea2hADSOVZKiPpKXCt1CNpfHh7nBBZyF/E6XHagTudDodDgekPi2aFKppTtrGuSeJMXs1yHQAOxxWaRww0/dCBgDpu65DqAJhnlDNYhYBQwAvl0v3HOo0Cz1f/lLGqQbKEHl2EMC0vMlEDrtdGJsXeII25Vcq60sIrykWVWO4CjOw1BhjEeBzhXAMMv+RrrBv210Ug9tEOVBhAKTq+z70o47/JrbyoHF2Xc4ZIa6Xl5c+X0jmmv0ODwG3rEIiiKLPP+GkSvXlAk8u6O3lpZGWpcCHv/zlL4vFAj0iVOApevDtoYpkJTE8raulgKXWCJCJEwFk8ebFLYyS+PzGd2Jy6e0mim9Tu/bn8fCo2WxuY6GexukyE7i9Sok+HqtAgoKAnHBC4pvVpHc4NqBZbrfbu7u74/H4yy+/5Jzfv3//7t07d398fIT8g+UDCb1cLk+n02q1gibU1xJNTDXmekx0EbhOvfrnvBoV+L6eYCnFvTxs7lIztFVJdSikV0++bqppmpDaw3F4Dn0n4Cpv3ryZGHtDjHY+Z8yKAtVqjhHlVxSv1fV11SAJ1WVLOirVtmkyXcHuXKyFcKnulyCBsZxz7gaLPtdxBTB0UISgkTlF6wmuey3uvmUEQwvDGHPO4NqbzWaz2Wy3W9xyPp+ZwAY0ypIcOKE6RdMJJSjO2TgVglKtwCaII40m1/nerz4ZqJZrU2945NjrnIEuEpKF66OU9UdJoyDpWk2U1/XgruVyOavNYEljuCBxS00NAy++qpDj9FoIaWVhuNhbm2RQSsmlxDhqjKC78+rngK4GMXY5DLEJ1jsV6VxG1Ofy3rx5o+ByjPiuWdMKAW6Ei4dc5JgHEk+8xkHyer3OuSti1pDmx6y2mv5jPyQ9BFB62pSW8/l6uez7vjuf+1reQ1cHCZXPVyCHEFK8OhhIIGbWXzoK4FC8IPJdctsOlYRu7sFCjMEsBLucTznn3HdespkFi8FGDgwyGtV4+NJrlY4NfIAGE2BO6xyGPvTIT58+/fCb7+CCxtweOJ/7YXDZiOJw0ZlB7AITRFwwV18u4NY4stYH32aoU7xSSjADYAkcDofn52fgydPTE1SiUlOmU50apAoQOWmqHmCT1NQYI4VHEIUpBFu0s1djwCwjnKh06r1Q1AXAYU169S33fb9cjhLNuNpOWs/y1dC67LULgNKHkLFPmCF+eXp6Yl5FlrQAM0M60m63Qx4JXMrv379nAkepRRzL5XK73XICFSk3SKc/q5l0ePi3b9/UA8RgAUNsUSLEIdjleMLEVWon0DbI7qi4xBhT08zn89lyRXBdconF27Zp5gtLjXUd+UNbSs5dE2KRFBOyuHy5dH1G89oYo4UYUzNrm2jX1H1y8lBDV0HcbHjOtQ7YxfwKY2Nf0QVRdLQUub+/R2gQRgayyLzaf/P5fL1eQyP26iUjUjbjfFrSP+gWfJaZzDjLy+WCDiwxxvV6DQ9VqjkdRE2rSTqKmmRzZRwdIdrpesjNU4yzWcuyhyxuZ6UrSkcz80uPOB9ghZESbdsye5loh/WcL9eiuigBSE3imJDxqwS22+0aabt/ZegpMZGHB12qRUv6Jyh0HKECMEjokRtBFjRaE3NH2MvxeKTtZeoyEgWclrSZMemvVKU71AYRyrBKTXREDInoynP89u0blEJw8LZOetHiRVmtUR0mBmKdnF5C/AQo1hKaIWRSSkDL+XyOikPkhVpt4haqP/x2wRR+hI+JA42mMMoWbSz+U0ldueadKmOF5yDWYUH4fu7OmFyk6gV5nDIIqju5agkuxjpOGek2qPeIEjBGxQ5M/Fj99sR/H+vijXQOoqjGz1CDILF2QXdRARHzg28D0T4Ep4AwGLFwOp222y3SA73OitdSkCwBoIEuZnMeDZUV1YaVN8YYcs7ohEVShTbGUNHkStUVqUqe3kvXa4VGYfxIXdzEJTKfKPnVpTrAuYY0ToLx6mDnmDwby+CuNnPWmDrOArj97t277Xb7pz/9aT6ff/fdd4gE46IlhsCB0lERJbjUoj6yglCTy3gc9MTAw1RqDkqlYv/+/YfUDAYhWAcKlx8eHgBJhs8vl0tIl+LWLpZwzKBxNOzmrraGNen7bWar+YyfE57ujrQ+r40ohoMI1p1ziNd8Ot4IciD+UOG7CmAyAiIfOT5/4ptAaNhb2DPkMbi/0rZaS5Pn8ySKRARDNc9BP23bPjw8zOdzmL8UbIvF4u7uDqxNnRgq0YvUpF8BJOiuvM9uXNBAkTBgz7ScLkhnE24Nf+0OJ3A0yAAYxKfTCXlqiv248XQeGCWxCs+XWtWrsQvFRZm4ygCXbotcEmO6vHD7xBXP9U88sXxXW0eCUHq5e3F/ft5Gu/JQvCLVTDpoSFBXcVirGhNSWag7IkOB7qUToHEjfOlYP7+s6w+SW5RqezxFfWE0SPLsqZ1QB4oSjO9rHbZJh1RCmOoj8bmTdm88aHWZmCTZRcmRpgDGSmh1xdrokRhOmOhzXNwAvBQ+2UvO1pWcx32Lcu01TZ5L8rd+UE0gV1TBRbyJNSSr1er+/v4///M///CHP8QaQ6XawV7KyoZCdYY1tTcZok7o1ptrISKIaDabtbWmDsIJrRvwhJeXl91ul3P+7rvvNpsNQ7b7/Z5dJ4N06EW6aBl7m3jchJ6yFIKxXNNqrDud3a7am9lVpZvQNferD+d/+zpNFq8AwM/nc85DsoiN87YmKqCL8OYT9I2qlCue6Hr0Qlld0zQIqPPUSg0KsMX66XR6fn6mLNhut6xAARDYjBbfJ7enGqF8abPZ0FbmRkIIcLHQBqgxvksbU2qu5ftWA5d4uwoIM8seFstVV4a56fgrFgBXvCoxoToRcYjUmRQZQghICoP87rrO+z6m69BYPurNmzd0JOhBNC76F7mYS4sGXARHDgUTzoncwBuEaaFPQas9Ho/fvn3b3K1uEUIVilIrC/HJer3u+/5wOGA0FRSZL1++QAAg9N33PYg/13hJEEU112RIMkTlRGnciIPo2EuTdGcHxBDOlwvmnvZeLBdO7bVcSgyhOH7ir6BOAGS9Xm82mxjj4XDY7/efPn1CDBvSiAops8RJV2MTbcroU40NkzXjUZBwYHO4i4jS1GJzkwlcnEJDuAVRI5RQ8RNl+P1NOcq7d+8sDeYLKK2v3emAP+iwPeBPn4maoNIrHG6KFFHPVkqBAmTmKaX5fDafL5om7XZ7MzcLAMxQk+zl4eEh574Uz7m/XDDN10rJbTuD+MOGnMOABjpxs4IxcGbRPS8Wq5RCjI177rrc9xcM8mkFf7ymtXt1jWJk+uVy2e128N/Q8tPNhpr9HqrPnDBvEliwlZK7rrgXrDnG1LZN287MHCZiKR6CdX1HKYITT7UzF93jzqSbGHvvSimWS2ibedOGJlkul9y3MV1yny8dMLl3jBgos+bqKVFSglMXLz2dTqfTCdj+L//yL3d3d6hBAFjYUoasjfQFOMxmLc7U3brucj6fL5dz07Rdd0mpmc8HZ2OMcTGfnS/dPFoTYo/5xDHk3oOX0vWX0/F8OJa+m6WmNKl0/X77EkO6eA4WmzYt5ssmhtL1ubvkS1c8l+whWopNamKwGALswuJuMYYYUwgGvMo5YyY0mLB7wRTs+Sy5D6K9ke4IE1dzKaW7ZLfc1KluSmvgP63MBoD39Xw+b7f7lFKMIeceRppXN0MIIcZR0/9ytaotDtlAA7bj3CouRTOk0/piMTdR2vjLYrGA8hSCwRQPIaQUsc6c89evX1NKb9++RQ3Sb37zGxwo5zfQlwZmDi4UY2RVCyULGXUp5f7+nn74WGNVqaZ8wxtaSmFE7MuXL+0szdrFbN4s5qvFcjafLReLxfZln0tXslnwFNsQHS0cHx8fz33Oly7N0ma5im0T3XovGMqJ0aWl6zF8NqWh/s2rOc54E1ywUFBAuZfLJVqYbdZNtBgaC6VkK95jSKWX4O7BklkxjyFasBRiCf/zH/+xq60iVcsDgVFbSTWJ4/379wAQWudQv1CLilzGalA9VoeD1zbC2+1WQ0ohBFg2X79+Rbneer3+8OHDZrPJOaOc4FLnQWIleCDWOZHB/loMFQvLpaP8oDaA76ubhY86nU4D2prFMMw3tRBWy+Vuv+8ul9Q0KcbT+Xw5n7GX1XyBuDUdX33f/+lPf8J7NQ+olLI7HqigIM0BMXW4ECe83syaMIqpcyP9r9UdSjtllypP4o3KWjM7Xs6vPgcuQfIUAryRBgtqXLpYNlZLV3POz9++rddr+DNyrVw6Ho9v376FnH55eYECC8v1dDqG4JiTGmMTo4WQzMrxeA7BOcGXv3vvfb7k3kP0Js1m86ZJs5gs9465rZjYGpPFcK1IgcDjTzPHbmJMYMf8xMJIK+Xe+75/fHxEDNJqHunLywsVPoIIV1sbDFHNBVQRYPMSzpejlxCTdZd8OO4u5z41oW3ms3nTNvOYDKqgSUi7r41FgyR98DjMrFg8nc7E52EGcrzOaoUiA7LH4h4fH9FngidutciS7LXrug8fPnz48KGU8u////+33+9//PHHd+/e/fzzz4fDAcW4CJHQlepXB53P523OfjzuU2rX62Xfl+fnr8vlGioRTj+lkFIbgu/3R2BCKX3X5a47I1n7fO7Mynp99/33H3744bdtm75+ff78+ROUJyhYeEIpVkq/2dyX0tsgdMvlcjKLTRO99xAdGMKfIXoMDef+8pMQoUKNg1AORQ89XgJH6IQQZ7P2fDlSESEJg30rPvAowStYBE9+gixXWBptrb9HmZaZcQ5x8d5LKN6DCoKl4n3JBuporvlqUakbxlWUMR5EXQ8phMjA3+l0ghm23+9/+OGHv/u7v/vzn//8T//0Tz/++OPf/M3f/Ou//utvf/tbYD5cvojULJdL2PQQxtDRQ/WmqIeM8kjBojwt5ww6hZI6n8/u7u5Xq2XX9V++fP7ll8993y2Xq81mHWMqpRwOh9Q089msnc04nbq4910HDh9iNPdL1x0Ph/P5/O7duyCes1znNJxOJygZRdoN5Zzn8zmUZq4KlizUOFH9C4yHppNS5Sj+Flow6p2LNUuZRhXRKOdRwbJJ2RLVfPKmWKfl9H0PpyKiBWb2V3/1V4p/qGrAhArKIXKBIn1J6CtQi4Qozuv55fiqkNYYA8/bxR8VQoBpaRTMaI4D1D+foZR9//4DcwRMYp9wcTDAFmo0GtnIVGxzzsxfwHtpMoZaEUiSCLVoIdS5NLcXBQAZRJQCBupJJkL91edEcXYViZRcOySNlXpY5G2dEE5lDnNGbVwqDc2j1JkwoqAw0DXwYrOB37Xt1RNAvDILOXQhhBBLCCFEVF4W95BLLSewEKLDHI0xljKZo3Wl+frkwf8WYwzB3EOMrrACWOikYncL0IgOJyCb89oOs4wvd0cMG0BOKc3CLDVhsVis1xrDc3cr3kFgExNMoir9r4y30+x3F8cpXbIx5xzC4IB2z5eOCqLSHe0bMhD44p6ennC4s9ns7du3KPNACGlyWHDv8XybppnNWhhJi8XscDiAH+KvfT/ELDerRazx5r7v+34OOoXjIXfn/Xa7W397enp6erhbL+fPz89U/rDgvu9ztsPuJdRxDqlNwVvYBtlyCLFqSwN4QoizWeMOqKRKSihrGY0XtKsAvpJVziXnEoLnHLtLLt4XiWdBDa2K4CjaZWaHwy7Wbi1Nneuec7Y6wgu6hdVGMTR4UkqpiU2YhRDMZl3XhRBDcMvmlkt293MuEVzt1iBZrRahetRzLjn3pQSz2GVPach+NSlyfXp6+vbt2x//+MfNZvPTTz9Bpfjpp59eXl6sVmTgcCk+rabgaXQm14ZWqhkQc9I49TVIvwqA5XQ6l/J8PB7v7u42m7uUGhiKu92e7MJLOVd2zYPbbDa57zvGpFNar9dEcn4NWg44W6jqe1OrEnzcmYpUr2g/YbANCpAb6RUCXom6Ur6e7Obr169KugQNIaVoVGS+7IQdtLV1GSEOFQ+CH0EgTrxCOiU5Y5bSIwKx1OQdfCcl0sn1cnda6gQWtU7lql49+J1kgwOURaLLXstqoUnMZrPHx0cTc4RhANS38TlczyTJiHtkb8sgWouZpXSNaIaxama/chEhJm/nTvX6tYeQRHn6g7ojg0eUrfBnqfEePCfGSNvXajk1EvrAQ8ETyxAfghkxcpFRYNiNAuFjq4JBXL33yp4GL/oQBJosm7FelwypAc/tKvv1yYhdwYUIKi11UluUhvIEl4JdNTDuItZwbNu2bDhTrm5Gd3c2ZvFxzIlw4O7w9l7aW+pFV5tLtCiEEF1Fi5MB8TTB4Pb7PdLEkPjKuSYg/77voUNPXOIQPOfz4NkCuNguXvGf1IEqCeWJ+M7T0xN6EuWcj8cjwj2bzQZBK3r4uAaYYkA2YKNS+uQyGXrI8ypSYM0/WRXAJZdybUnLuo9pC1XeSIVbuYG7Hw47k05w9Hbg3CnJKAiBGkRLBePEzLWBg40cfvXDQbHz2oWw4lUKyWABNzWhGsC5u7v79OnTy8sLGj1++fLl06dP0MZ44hAxTO+68pAYY81y4JhCk5auNPxeZen6s68NWMBy37x5c7lcvn37hnYCUSbEg13jSikhIYsZFWyeSIOHcAaV4bzKaxNWSu18XmolXhi3MlX+31CYmbQp76X7/0SAcyzg5E+4VHcL1XGda9NmLgWvABNEa2x3v7u7u7+/B22gLBp6NMiSoRGv3RYVn5Td4BNN0sEb4eTp80XpilybHC2OfdeKu6pktHU0NDjXfD6/u7vjDEQwqSwNKZEfXiSKBjLo87XkxiTBjwJV2Z+7p9REMV65pElse4KjZKxKh7pxrmEy/JhXFAt4gv1AA3T54OcqYKjouHtfMywYk14sFqjUQpuzRiqUqtR/paRSdWFdP+VilEA1XxfGmgHEGWDJu4JIdJ4UeWs7S16u+fxEEq/tsqEUo2sbsM5kNIWPcyN5L7GOeBtrAAxfwHxoglFxkhJXn8kQBuEAiB1fm+YUQtjv9xOEwYvWiyW/7JLpw5wMECmr4O6CQbaRseD0UbIfxYXWNE1K8XQ6ldIz1AfxOUmDACgGWOXMpFklHPBTsMtSyna7hQYAdq9O/mFf67VJ58JUG4YohijKFQk36J/IRgi9KpMGesSruQt3d7s2P+AzrxsU96G7kxtpjNlFAw6SdmpmOY/8WNTntIHMGL2z7otSSvfbXAsrUsyOVfMJvPe7777r+/7r1685Z0QMn5+fn56e9vs9W6JSg2xqG9FWxppRSeWTJwSon5RxAl2qQ4cgvD5+/Pj4+Pj27dvFYvHmzRskLZPv4VAQS8UDN5sN+VWWjiU8O5c+fV47jQw8vO8ZbcQvqeYw9nVKHilRPX9m1kAwEI5UmfnfiZRNkkhCdHF3Wi0TQTJh/URT5gYjRA/ORT9wW/sINrWlTqkVYKTeppYF09xRI4MIRChAC0bZT6qtu+gQhsgnZ1T8DmJoEnAwfIFVy+USFVlN0xx3ezIpYTTTvnTc1Ol8KpINCI0s1qw8HjA5SHd6vTWa3+iGuOBRIL4qK+Fe9AuxbV59jkojon6M8Vx7StPcJA6Um4sQiLW7cimlaZr1eo28d/QdpABuWzz2Km90Jdy4S8ggVqnD4yNG6Rau+kHlM0hOKWVYW6q1VaUUBa0KXYI9yEt5LlgAkjWAbFgPo78KXtJXrBmnFEJYJgnBx0Xe6jzMktKi87BjLSZpmmZ992jC93m75hxkSTZZtLMgtnio0QQsAw01T6cT7J4QQjgldGZo6/zgEML9/X0r5TfcaRjGSIQQAqbFgS2Qo5FfXxFAHkJqsupKIXNkkg4vhZ5VyQQAks82437LekBQoSZMzGyqirm7WTSzu819rPkNx+OJR9b3PQWYnj4kAT/nsoPol1l6dDTSR8HE/EDUhsjJ70NgTPgYxM2En+Ciha1ADiF03YXkoPR+PB6ReQcdGg6/2WyGpFo6hEysySBDD8EtY4w6bKaIgsUhDSb196WUu7s7H5vLABemYLn709PTer3m+CZ8DmRg3VSpvgoCgc5LXSrQA2tGuWyofi9SK503hE+prUmVN17pmifEY6jJLycT9c2E5ZloJRPOTsmnPJqHSt4HvoDu/CEEZK8wxQC1s0D68/mMFGu0pqOsJevhIVHDwvM5PYO8GDrmav1kEgfl2mqixJWTEsl0/dz4drsNISBnirbv8XjsaweupvYJwS9oAjCxa0MICOOTNTBsMCFI6k29X6dI4RdlQLeX8gsXSVLEFp/wqVefQ86l/JfSghl8pVobyphcDFMK11xbKIA84HJvauqfnjUEsG7BRTPlf4FUM2nQH2UeOBgQ90vsnbULG3PbCcGXcZa+2VR94SvAbhgDhj1H6lXxbJJ1bze8HijU1FogHOLDw4PSGhkBzM0wbmAS6oz0S53Dza1xOhYumAVmBrVvopjGGHfPL70M4TAZPgEmCAaKPjx935/7Ac7kpGAI+t9yNUlz0zQ5D20LEWnq+x6b4tey1Mu2KSHcQ9lAgFyVME6jkjmDubr9dQtsNFFqax2Gul4lGUo1HlwUD0T9ZfgEj8o5n8+XPJQSec4ZqXOTq5He+8Qrd2+aSNtdAUh/qY151OUiMWApa8QJusTvqro25Nia1L9S6tCeIQnPZjP3cVqWu9fC61IKCAfkvNlsLnXgJuGJoyH+l9p+xGrbIn5TLw0BlOrOxakxc5YPzDmjAwwi0O7OhjDb7dZEioXa+Xm329EdbbXNFFXwcnVIDPBkvjq0RmU4ehxWObNqjaNz5zAAKrk2TlAiWsQaNldmzQNg3Srfihcj8B5rXSCDQPDXoZ3sarVCBkepcVzU+OPwJplvZIsuzf35k0oNy9di9RsgHLVcjWKuvFefr65sSj6rjB5sruu69Xp9d3eHBngpJWjuLhlhZLXKQQhMLK9tXolVmxkcaMq1sapmsQhiuHBh/a9kQVNyTA50cl0l2a8IYMVaJXuOZVQYNuNiZf1CW+f5gEju7u6QlsWyb/Z0TCkhz4VZpi56sUnCEbEx5xzaNkgBX5YptkG8GteNh0Z3d6vxmCSyhTDk1ijkvcZu4YmF1MQ2ofgTbr9GhJPzghpHjbtpmvl8vt/vi1x2Q5gUV149NIrkPIvs14HzipNYcIwR+i7S+Ofz+eVyQQ7z4XDoZaj4er2GrQNlEYR2Pp89DgnYpXod8EsvZX4U3hDAfX/p+/5wOJRSMPTJ3b98+UIpQoeeu8PP1NReQtwduD8wEJwUPu2Ja73UBA60Tsy1e0NfW5Hrl/V8Z+Oxnld4VqvURHaGEF5eXmKMiK10XU//Z4zRwisKHwTPBK/cPcbRAAzyQ3A5utlgeJVxoFGfxileLq7UUkqojdB5i6oXt/i5Wq2QIG9jQwUkDEAxgnk4HNBTmvEFNcStareYFWhmi8VCG8ggQg+hqNP5HF1ZKj8hTHTXm80GjBp4BRHTNA3qpuB5RVsnpF5///33qZY54bDojGSVEE8B26QXHT1/qAIqGSp/INER4CGEJkvWRpYwiTLuKKYk51xOJAqawdLtnCXBKkq9P42J8/l8f3+PkDsCZmhahD52SIJfLpfw3R+PR53D6tJBzWSkRiMN0xHxzRJ+xtqen5+VfgiIUqutqMj0tWhaqZf7WiwWm80G/UBiDR82TXO+dCp1aJkh5qQgxTOPlzOtPRPv38PDg76UhzpLo/GCJOA49ozxyuMWEyQwGjRcKh7V9a9nU+u9hJv6JLP49KI4YWwsG4A5aGOEgnLYavv9HtqMiwbT99fQqdlIKabypwJ+crLKTUptmqZxhxBCdxl5DpTD8qXE9hAC+t5NGKjLFDkwdKvtEuFUJ2so1S08mSvM63Q67XY7VmmnlNBdS1dCMrYa2zPx/SgAySP4/HM3olyCq9T+IfBLoY3UYrG4X29yDbtiMZw7iXslQBjatu29sGcC9gh/MquBCbFSBryI0VjCjtqK8/n8H//xH/P5nHpAU2cnZKkCKBLzamuvcvYICrVjESHfSxU7tbRQvQVN7XVM4EwY7q0CFMahHyKMmR0Ox7u7u6oHNJV9l67r2DvaxgyaeKV4TuzGK6i7wJutXBpqCup6FS3LkNW8wsr5ZRts+qtSS6vJzFDOq9QXY4zRQ2r7ftRS16pnhT6bEMLT01OsLRDQN4l1pFhGrLY1HB70DP/bv/0b8Ha5XCIrCGxB4aM/V6sVvThUodydKVQoUzYzdGYMIUCnZNIAngzvSysDlGAZopDhcDigEQIPghCAwpdqWj4qrJgDRGqN45HtpM3wf/3DP7zKCHqZ4hLH4YFbbujj8gYbx8OwMkAZVV+r1erNmzc4HpgOKBAMIXz58gVPSLXymBxWH0hK0M5EynNJaVw8bufAcKuBanwHLmVdNp5zOBwo2gFZmGgfPnyAqzzW9tRofrScXV2XFOpwQUcxv0K1Yi+5J9z0xlh70elJx4jh00GlJpUeerxNZB48DbflQJrzaeJmsRSJglywu3NIA+E/MI7Ltcev/sy1Vbhqu+7ee4G3Bz6Jv/7rv3b3f/7nf/7Nb35DvixoiMjCKxPT+lq24WN1cLVYhHHAmJfig4/FahybC1YZ+sSItDp/F5hAlfTl5WW1Wr179w596tGWz6qqTv1Jzz3dDNsI1XOrK8nS+qeVIalcPHsn4ZZSMxzJNCck3F9j3qbwyTlD2YUjB60Sfvjhh3nTllKwKWR0M8rFTcWa0J5zni0XFFF6CgwJjy+cdUHzzv1+/91337158+bz58+wgGGFWB2XO5vNjHJ7PI9ZKSJK9iyPKVRvGb4MHxvJKkgjMAJHfwFrVnOlHsGoIsPd4YI+n7rFYrFer1erVYwJTTEPh/1ms+nzxapbhToBfaQThGyaURqNMhYiP6Wsu7fttZWsXozBZ0kUCCGsVgs+kHEHPanx80Nq5zkX5hbF6jdVsnXRYL5+/fr4+DibzeCSIcPMdcBDqT26gVrwHNwI/ldcu9yC4gO/kMfVs2SJ79+/v7u7Q9uoT58+ffv2rZSCDHNEA2OMaBIC1ZlztcH2yRVBp9SSyehITQo3M8PYKCQ8YbND70j7lauRxrPcc3jNk8lfirhKeHjz+RzhAdQPrNfrx8dHDJXMtYWsVs3SpUlZiP9CIyMD5c8ydsdxqQhF3F6wLK3GBTHBCezmlhua2fv37636ePE5WN6sTj7u6+AjUm8QHYVIr0SeJQ82tiOX/oRCrHoFmRZ/PhwnrDnXPoKp5pxHyUTjo0i0+JAmoKKyux8vZ6psJoY1jR4GGnE6LJ+YIENfs9yVnNz905/+uFgsoB4+PDzAt/nw8JCltEYehdjPKwL4lk1YFXjKjn2Uw3z1QIaazZjGxf7E4QkLmMCKugVYD2df0uFhNZ0KVK0fDoqXhGwU5SYhj1DFBrUrXYaZIcoVpWcQ0MDHlhlBZKGxMYtUYUnNwMdNbm9BpPxBdVwTrkddZwJPOeioyg158WazgUmknAd/bavikmq6KK5Oxvx5Na1ijIfDgc58XbBuhwhTZOrXBJ+ZTW0ia0spoA/9PnaTxzVX7KTR930uWQHuElmkpInitFCicMk31L8qnt8SNQ+Fr+DXyCVCFVqTM+IX3N09nA8H9+uSeC8r0/TIzOzh4QHm42azgSc5hLBarb59+wY3D0tM4S5SlZ2goMDTjRBnwng+GLOXlS5omaDUAoodvJjQ9nLOb968QfEVTCkzW6/Xz8/PeCMFCrcZ5SI0lCL4uZnVtmKBadLY45SeeVFjnXxOcjVhTKEOqC83Pu5Qp5PigoTAnDgzgyXEIqq+7zmez8eaJtzxUYxIxUu7UQh47+Sb+8N2wjLg6NZPFNAAHJUgssLVasUU7lIztGOM3l/LtxT7TYhfqe5wvjZDN7GQCFgqWXia2nAuFrBanEEsPJaN6aZcWlpOyTiQs4zsxffv3xeZYRyqvnw5nsJrScIXGxX5Da8I9vbtWzg/zOzt27fb7fbLly8o4tTbg4hJ5InYmLPcMgurFKtf5vop4FVPijEuFjORK1GfU59KvEIW6HVOMF8BbcxrlkORUZVkpirhYm28oKsNg8Uzmg4ksmoQNqpUxRhhkfOvvIvJbi6jzEops8W1PE8v5ct8VCklNCN4elViKAPCRBuuvTWi+DlJzpQrdVPoGXL1fEJTZ6+0ro6V5S7KOBRHQgNfi5ISZdU1SkWQt4Ta9F/xgXilJ4JLMOQa7nERgeMjGz7sr00bZoivuRda3iZ9y5VTT6CU89VPoyvhl3kpXeh1ux0lHDYSGZ/LyP1uV9ILfY+GHlOnEYSooj0ulFmDeaY6rCnGiApdhGDhpdAXcQ1cyau7sOrpjBJlQGicjW54F7ARBiH8gk9PTxzTjuopdM6H0wWgRnMxyp18M1M5inmdZQairpP0AlTkvvq+/1UBPCEV3qOmfbjh7Aog2lixxvyxMUR80Tk2SvJYrkmVuiQiHDv+TFZFYPHzCTK5aGqllIeHBzZ8DyEgwIbcy1dPV5BvSCVA3y7klQQZVQsi707nJIFkApNlDHzsoE/MWhVUvJAfzluo9i43G31OqAK7SLhazWKdQ2ljr6ACij9///vfTxQgHAEVLAqYQa+KafKQG3509SoX9/dv3qZZSw8MwIIY4Wtkht9fcbpoUo8Jl8n5WlahyMkkDsWKUIdemAgeXKCxsfrv7t7314ZToIW+DkWx2o2oSO4eFQtyClVKdOU2Jlq+ZYLeXDx2h/AYmbIyAn0CLxq4JuaL3kheD+6zmi9UFZucKZd95QbSqzxIJoTLMHlFPJAJVFsE7RA1hE6JqCGUbzwK9ZoqDnFRoZng820QhBjCe4PoHP9FSIs4QwFcSsn5lmUNinLOuabOOdoWNk0qpXh3tV/58F762AzEMpzO9bh5BFxtkKxs3K74rCSTxgPt+X31c0xwj8cXrup+nM/DjeMmmBnfq7op6AuZtphd+PDwADu41FpTcOOu6xppBmXiTyWeTM7Cx+I5ije41AZQE1TEM2FNAQ02m83DwwOyqLque35+dvfHx8eUEnIP7+/vXaQevcokOoK01OEoJPMg8pEGLe7i7b8qgEkhulUbdyoguM2MjSZU6QghABFpPq5WK8wqgUtZn0AVQ1U8PmqS5ctVEdBFPI38qWFR8Jf/93/8P3j4fD5/enr6/vvvf/jhB+hBExRUvEfE3mq9f9u2cFxblcpU9unuuKVwE3OE27nkIbOUr2NHsCSlFPRoobsidT3Vh8gZVWyoJyOIWKLLbsKgv748T+A/WE6zme7CqpNtkdpbsPs4ZHU9tWDPz8/fti9PT0/v3r37/Plz13XwP0+4WEVcWCQTNXxwSE5Qd/jv2H/Lz1XweDXjSimXy4mIyitIgG3C6/W9UIdL7WROIicildo1npuK1USjhTrm3W7ittGtMdNEJUFKCUmeLiEbfD5RKDVRQPGBfHaiuJRq0BOGqtCAi3E7LlZIKFcGShD1tbNgkv50pRT3wg4GwPyu65AiAEuFvfB4F3sm37Im5Xf8K9dpwiKClP8FEWlBOnryMhGTE/4wOe764fBA+FSPx+Pl0t3f36/X6yEzqGcHcldU5NoIOiJ/kGS3yTlOEPVyuR6ZLp4d90y6Ybj7fH7NISjjyJciYd01PA0jgKt3QdEYv+z3e/gXm1pEC13k48ePOGVUkfS1WxnScktNd7Wx5kHOQxwgbwxj45v1wVa5LqIbUIghX//yl7/sdjuERH/88cfj8fj582cMASIWAVYsNEJ2GEz5Iq3Q+HamTzbSfdbMmlrHz0PB8n5VAL/KBaym4+s3dZ9lHHnGa4B2VsOuLDmI4k9WR3QR8ytUpq8uO3IKLp6woPBACB0G7qyOpXT3v//7v2fU1qSLmGrQitkwlPkKcmq6dpNMqso5z1KDwyai4LEsRynjGHDvhfiBuxDx/emnn4rkcueaQN6fL0QpGqNB2jtMjkzXYBI10JirQjvN2jBOFPJq+OKMovg5Qwjd+Rp7U5TQsg15jaF3mLufz2dMMVssFihCcBHeVR5gCMQrAliZi/43yjhFMjL9wnRJkrhhUq5XRAHXlyru0WRsatMYFyXV3QE03k5WMrECb+luco5Wk9qCWLR6oEVCBvrYcHMVu8JBxRWPG4ymSE71hLfqJ8qncG+RW4g5yCCzsaCCAAZ9AexQYiB3QbZwbCqLR/BCjx7/bWv5mVKZ13JH9TrgF2VTXI8+0Ma6jhIRfiqn0ueYASDD3i+XSynDvcvl0AwZ/IeqnuKnrj/njPOkoqMrJNthvYlLj4vJTxcrRdXKnKN6PkjdVBDHl7sblR+rnU9ibZ7Dc+fP2Wx2OBxCCEgP/vjxI6oNf/vb3768vCD1lSyaQpfb51kTAfBq2mlkv0VGwsdaf8jToegppcDn3Pf9drtF8uzd3d3333//9PT0/v17zLfGrIXlcvnx40eNuyFiDQceP1cZzGRV0D6BH6Wiml8OIfxvBPCrmPHq9yFTyb94y/F4fHx8hI7T1WnJ2+0WyVBBTA2r2h/RmmhHxOJjbwVJlsnq7o6GdqEGIUopYP2n80DA9JADfckgFFNd6p3KeHplrt3UiCsDcHNR+iRaqCZuwo4X85mLnh5jXC6XMH+RLs+pU8OyLSgHj1Jh5TVnx4TzUvDzkwlCKKESnvoJdUBKF95oZqmigyLShM/yTD1YCOF3v/sdOqvAU4r02iBWizwQL7oancpwJ59we0qoimOEuQnDTbVcJ0mCd6mlRPqQuqOr6DLxc0IAZxmlNXgIFtdGH4q3E/K5FXIqHiZ7pHLs7hzr5hIy8FooSXrk3ou/7jnAF/J4TnAnDfmyjHEFg6a8p/SNMSKHgMiJBdMdR5ug0pcdj8fVasB2LhWWfV8ncyhzX9ZY42QXedw5IY87zKv5iGVAKlAkW5VnjTR80F8mbJB/osAT4IcQQu4zMkVyzjEOXsAQBk9MvknhDlWdIl+qAmYa1SZOlnHUACtv25GHcrJaF8NRI/QTTcIlyW78qFBysTELwu0I8dwi9nq9zrX5KN4O3+Ef/vAHHOt2u93tdtRNUTLEdRK8E1d5rGk0BH6svh+G5CjO+QWEuig1IbyhB5RS3r59i/AibCGIZwhaMFJKXOKwqj4TOFN2lLEqz+PGY381C1rRTtX2VzXQcBNLS9JEG8YZ4u0oroI/RN19nbR3d3HLKMETgXSd7a+MdUMLQPg34G7S4YlcJA9skkVJOHJh1HRwCwg71orhXPs6NanhRkotQ1K2W8adlYBwfW02BN1qtVrhds6XDSGAE60Xy4kIAe4SCAqiINdEZoRqNvHLcWi0klTkePVqQG3kq4UYXkEGoh1PZFhbsJeXlx9+99uu63755Re8fbvdsvP7zfmCxl7JgqZdy90p3argxMYR8pgwu1LK5dIlSVYgGGN1w04eGON1qo9LCg91IIUz96LS0YRxT+hWf5+c4yRyzLVphzV+gRzca1NurjmkGSGgFzdO1p+lC79qk6E26+eWs/SfivHqTSVmeh0acWOj+/l8vrtbgxWCXaaU5vP5zz//DBbJUdaARi9DbPR06GL1mv2EWnPMuMySNgw4MG8uiNZCPqOfBGnWTUkgfx35pUMIUNFCCOiJ5u45F/JrfBiq4UtXE3lFkvbO7g4BPCGrUqc+644qn3m9J7zyN2UIpfQuinioMji+bknHWCzGKypS12H1weSCRzfGeLlc5vP573//++Px+PXr159//nmz2fzud787HA6Y4mB1iLUum6JkIo8mZIV3qeMXpRbg+bF6j/ELEoDgTI4xogMua5GRGn06nT5+/Ljdbn/88Ucg4WSMmFVBoNhiknOgHKmMy2VNMhP/F0homUBDuErtAAAAAElFTkSuQmCC", + "text/plain": [ + "" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "url = 'https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/transformers/tasks/car.jpg?download=true'\n", + "image = Image.open(requests.get(url, stream=True).raw)\n", + "image\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### CPU" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "`config.hidden_act` is ignored, you should use `config.hidden_activation` instead.\n", + "Gemma's activation function will be set to `gelu_pytorch_tanh`. Please, use\n", + "`config.hidden_activation` if you want to override this behaviour.\n", + "See https://github.com/huggingface/transformers/pull/29402 for more details.\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "27cb8013eba248a6bfa08aeb6be0f83e", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Loading checkpoint shards: 0%| | 0/3 [00:00Un auto azul estacionado frente a un edificio.\n", + "
\n" + ], + "text/plain": [ + "Un auto azul estacionado frente a un edificio.\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Instruct the model to create a caption in Spanish\n", + "prompt = 'caption es'\n", + "model_inputs = processor(text=prompt, images=image, return_tensors='pt')\n", + "input_len = model_inputs['input_ids'].shape[-1]\n", + "\n", + "with torch.inference_mode():\n", + " generation = model.generate(**model_inputs, max_new_tokens=100, do_sample=False)\n", + " generation = generation[0][input_len:]\n", + " decoded = processor.decode(generation, skip_special_tokens=True)\n", + " cprint(decoded)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "del model\n", + "import gc\n", + "gc.collect();\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### GPU" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "549d83079f7544c9a517f12efb9b7af2", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Loading checkpoint shards: 0%| | 0/2 [00:00'OCR the text in the image'\n", + "
\n" + ], + "text/plain": [ + "\u001b[32m'OCR the text in the image'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "prompt = 'What does the text say?'\n", + "prompt = 'OCR the text in the image'\n", + "cprint(repr(prompt))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_url = Path('../experiment/cache/Strange_Tales_172005/_crop/Strange_Tales_172005_7_Default, grey pad.png')\n", + "image1 = Image.open(image_url)\n", + "display(image1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==========\n", + "Image: \n", + "\n", + "Prompt: OCR the text in the image\n", + "THE ECHO OF THE OLD MAN'S FOOTSTEPS FADES DOWN THE HALL AS...\n", + "==========\n", + "Prompt: 20.769 tokens-per-sec\n", + "Generation: 62.188 tokens-per-sec\n" + ] + } + ], + "source": [ + "if IN_MAC:\n", + " output = generate(\n", + " model, \n", + " processor, # type: ignore\n", + " image1, # type: ignore\n", + " prompt, # type: ignore\n", + " max_tokens=100,\n", + " temp=0.0,\n", + " top_p=1.0,\n", + " # repetition_penalty=1.2,\n", + " verbose=True\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_url = Path('../experiment/cache/Strange_Tales_172005/_crop/Strange_Tales_172005_0_Default, grey pad.png')\n", + "image2 = Image.open(image_url)\n", + "display(image2)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==========\n", + "Image: \n", + "\n", + "Prompt: OCR the text in the image\n", + "EMBOWERED BY GREAT CHARLED CYPRESS TREES, THE ANCIENT MAYOR STANDS ALONE ON THE OUTSKIRTS OF NEW ORLEANS, KEPT TIDY BY A WHITE-HAIRED OLD MAN KNOWN ONLY AS BAMBU.\n", + "==========\n", + "Prompt: 23.426 tokens-per-sec\n", + "Generation: 62.838 tokens-per-sec\n" + ] + } + ], + "source": [ + "if IN_MAC:\n", + " output = generate(\n", + " model, \n", + " processor, # type: ignore\n", + " image2, # type: ignore\n", + " prompt, # type: ignore\n", + " max_tokens=100,\n", + " temp=0.0,\n", + " top_p=1.0,\n", + " # repetition_penalty=1.2,\n", + " # repetition_context_size=40,\n", + " verbose=True\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAB9CAIAAADC9+jfAAEAAElEQVR4nOz917Nnx4Hg+aU53p/z8/f+ri/vUIVCFQjvCBIEaLuHbD/e7M6MNmJnQqENRShi/gJpR7EbI2mk3THdO929TbJJ0AGELaBQQHl369663vy8O7/jfaYeVo9NKfikfsDnNV/O0zcyMzLzwH/zb/4N+NKXvvSlvwXQ/78/4Etf+tKX/j++7NGXvvSlvy2+7NGXvvSlvy2+7NGXvvSlvy2+7NGXvvSlvy2+7NGXvvSlvy2+7NGXvvSlvy2Y3zTwzbfmJIbLo2SaDgVZ8uKwgABjLPOCN5nmSdo0ZvypHXhOnmZxUghaWTZrYydwOncpgseOnqjU6uPJ1HYdiLCiaDxr9CadHMbzS42rn3366M6DN19789jSUadI4zjO85wiCCDGmIUMCwDIxm4O0jB2rYrOS0Kc5BSy9tRrmCiOQkJItWxgDKPQFwRe5Pnt7W1JNXLEZQQyPJfGYZFEhio5WH2wuj4cTU6fPnP+zNnUdya9A4nBA98XVBPwyn5vur65a1llVRYRoJeX4gxIOS55ubzfGWFeWF6ZjxPv4P7DoytzsgzjeJoloTt1OMwtLaw86Axu3X5g6NVTJ0/79tAQihMrZXfcVnUDQ0Xky6FbJHFKaeK4PYbJV/uEZ8DpE0sCzCLH5gjI49xS9VAuRVGUxlEc+rIsqIqUJpEoik4y5DCviSUWSklcEAYRFgdJIBIm9ANDV2mR8hipijDo9yI/YEGi1eZjzui7iaDyZQ3F9k7q9WW2SkHBsnjqOhBxUUAwq1hmzY5T351oCmvpUuy6k/4YFcjQzNKMxYnGXnucFky9XnWd/nS0r4ho9shCGCWT8ZhNQcMo8bLiMCQSUOJ0sR9FY7tADFOtR1D1poAlUo5cU2BlDgTEC9hMNw0V8NnApVwb8wLBLOLEqRO4diggLvJDURQEKonIcFIYMLQACfCGFYGfOWHaE6/IGQgY1wvyIi6VjXLFaB0cxFlmzjTSArm2DyLK5mihPldIUZKlOwf7bhg1GnOKrBcZkHklxe0syfKE5FGOKWtqJgc5Z+qFxQSzLACAFwVFUZIsdV23ADQPPTbjaCYmklZUVE6EYuCJzpSvVUMBdfo9C3Bxf2J7/vzZExkGPDfjTQ6qRi6x3nTYRZDFSBmN/NBEmACQkbJRYgmmMRUYdtAbcAaVJClPM47jDF0fj8eT4UjX9WppZuLZKUlYAUOc4yLlGSAwuGVLmAKV50WGYwU+SMOJ73KyCJms0xl7bjo/d7TZmI/j2J4Mw8iNIChyhmMtWbKKovCDMQWeKIE5hRSUiTMmJ3KY8mHKKFrdLNW94W0IMSkgz0qiyGeJHyUui4Fm7zqEQZVmN6BY0DRBmjNNp9vdONgta4LGElNkp9Ppbs/m9YbZmAcKB/KCKXIBAQwJK2LEAcd3D/btjBSrN9W/MTvwN52HfPpVgWVQkeW5kkycqe25jdmZWqXKUWj3h5iCkjDT77bGg75VMlTNyCFrVptaueasfZKlhaobkqwWFNiOazueqmsKY7nRVDaYMPXs6TDzMxDTilllDM3zfUkWCATO1NMMk+ek/f39wg0lmYUsrdatlBaO61dqMxwnjVprNC8whpoqSzIvsEwUB/1uT+d4STOBIHtJFueZIHCQpPZkKBSlIM+9JNUqJbNs7h9sTce9pcWmxRZxDtXSbErY1bUtkRMtwyzpWh4/YMWynUgJMsOC8+JQVSVZ4bU8xyiDIGSYlGdR4PmT0TSNcsxrUUJEQcMAJ/60YTJVE036uxlDBc6MQ0bkTBayfmhDGFEQw/pXSR4O2rs8U9RNrUhSkBAMcKGbYeSnaeh6NsMSUeIwhrV6ZZQOIjevKE1LbAReBDHkZeTHbmiHWZbxHMMzLAVFniaEEIHnRZlmUCiw4cRFXkSITpiiX9KxOxXCJPR9d3Nrp15vLq+cZhmFEAYLWhR6pAgwyCSOS4LIc/ySXmnF+5JqsaLFSVpRZEU2ZZkwCcdpYTBRrhK2Vqtxhr4/6g+GQ0UQU5WX86wqwgTE+4FHZVOXGrlNZC7z9g5rDMcyqBf6bk5UpXRy+UTORBNvGhVJjonrTsPAZwDlMQoI5hNORmaCeK6isTxxW5uc5yaSq6klw6gDyvpRCBBBOI+TYDCczMw0GcgHfq4qlqZX4oRmBYF5D2Ps+NMsJ5ZZQ1iZTuIoLJSSG0Z+EsVFlooi36hXZVHyfTeb9Hwv9r1E1Sq1ynxWsGlMZVVTUHfA4FaGkhSXAKdhCrmUSCTsJonKQAjxJLB7vVhhqsvzImbhCFfLQhx283xKIYozkcDSyE7n56jn+7zAQYxzkrEsm9M8DEOJuCzCAAAEYZZlgedzHFev15lEsn07x6lakgkMnUkf0axq6Z30JEshBxBDCAHUjTwniQRFMgUwdSNARMtsmEYliQJnMhQ43Kit9AfudJoixLEszMg4jNpZNhY1hVAgCiohSFNLkmz6fsyxgiCzUZgUGU2CLMsTXZM5HkzsoTVcY8zygHKZYmWQp1FBnaBplSIWKCwIhwciQwRB2h84PuWl0oykiLAo/Mkk9h1CE62sGhXDCdx+yxME4er70m/Xoxe+U4njMBxPrdocLDKQBBKLLdWc2kEYEVkr9cc7Uy/llTJFPIK5yMUgHfJMggSZZ6QkyixD5XA66ncwhBwWOUXKSYY53B70ZmbnEKtRKrK8Mujt91qHpqazkIeASwjXn0TVxpyujhACQRRMnRFkaKVqIQY6jm3B05NpNwgGHJtYllQyVUAL13VF0AQocJOuHXYVU5PksusjiNRZzcwyOc9zN2pb1ZLrEqukuVGrLFTjJO8NvSSFZaskYpwFDslDjAFFTLk+m1Nmr9OL8lxQVIog9ZwoTOeaK4IgRrGfE8d29gvqsvECwrmhMwwTixziGDaLC0nUBt6oyBHLqZ6bEJjPLVUQE/cHe6h0lMsgcqN8EoSBJyiiUFLHobNYvwAAGI1GmEUp8XmB+LEtq0yaCwwWY5+KvDEZ2YDk5YrJ8zjxxuPJlBMF3bKiJPPikOUEluf4YLsAIkUiQkhT+Em/XdZMnLG+rG5vrGky5zlDs1pKMaguzgdZxvm9imnlAXKGkFK9YEHEDoHk5ofIMiszjYUkyYajDmZDxPpJNu203VpjMQ64JGaXjp7MSeH5kyB2dTHlOZ3FahyBLMuCwElzr94ocUGul2f643DqF5ZZy4IoctxmrdyfDCilvCAQQpIsVRQFscxgMLDBtioqhqjzSJAEKYiC3rirmCpmXAYylGCSE4ZhZEEkhISBzwo6y2JR4uMkAZRz/WwyCkrlRiJAjseQxLDIMGR00aQ52znss5LO8ZRh4iy3MUyLPE2j1DJKRJLGgy5LchahJIxFWdfMSpzRCO9yjCEydZIpDJQAyRyvx7CUQbsJBYCVbD9VpJIpWQJlAieYkJzBCct6UdDL46BmzYjI6HYmnmtrmiarCuY5RuAZjk1pEUURZvwozAVOD4MCQcYwlST1ISJZEmDEA8TmGYSI4Tghp3lRFJjlVE7EpAB5RkBuB04IUsUyksFE1yyAJZbXIBYBxkmRdzod3w8Nw4CEIoSyNAIwFTjY7uwbaE4rc5LFU1bKEhy4HqSuqhaseAqCkOGy2ItgzhUBtUdjS1WtOmoP2wnMOUXCDOc5kSIYWUhYWUaEaqzAQNDv9xGHBFPb2tvRZUWSJFmWZVmGENq2HUWRLMtZIQm8+qO/GP52Pbr8ukQp1UWZ4QGHgcSg/uEhy/JpBq3yLEB8EnG2G2lGjWLGcfo0s1k41SSaqnKR5iQvEEoRDZPIhxRXzNkk8p3A1jUTYxUAZTiY8DInSggAMXRdRIkiKoKkun522LcxKy81G2Ho53lWwCxJA5ZF5YqlGerh+k6S+gimigw5FhYkz5Msy7IixwwDChh7oc3wjKIamJEUWc8ztshxkiS8AP3IlyWT59l2Z6ekc0lKbS/PKcdzMiwIB0BJ13ixSOK8O5xwvFRpzMuqBjA3mUxib2gYhqrJw+Ewz3NV0ZMk4zgOZoUzHXJs5vsjReIkQdzdPiAFnDtaR0gSpSoAUkaBF06CZKoafM6Cwg01yNZNCxSkbw99mmQMVfIZURbyPHcDm2EgYHLMAIgJxLwkqnkMxyNvMh6LHCuIjGGqWZIDAFiWJRTklAiimOf5YDAQQACRwnAqJwqqhEka8gB5E6ey/GSv25Y4RlGFIA0moZOzCAlcCXqeO5WxErl8uxPrlVJ5UbLDvXm92T4c8JxWrcwUJLOdVhiPIEq7nRFGQqWyhBnRD0PIFLOLFsKF25+wjIShlCYQQSYv0jQLdEOGPqaY85NCscpLi8uJP+23DgSGjiZjxDIAAAoAy7KCLMmyLEjiTm87DxKcQwZAUzcpht1RjwDamNU8x8/zXORESZIwRL7vp1EsGmaWpZhFmqYhzE2mURwCXSuPIo+QNI2mhq40KtUiLkiGK1Z1a3ciipThwzgZJtE0zxIeC6ZZ6kw9SAmgFAOKIQMgZgVBltRJcMBgkWPUPEFRkCZJIvK4Uim73sPOYAw5QbcaJaOe+AnOscyLHgjDyE7SMSURBphFMsyVKCQFGYiiLIgSQigtMgIzhoUcxyRJwmA+iWmWFLKkZnnkB3bZ0iGOByNbFi3LakLAZ4TkeV7Qwg9GZcOUGM5z/DCIWVlEguCnsUAgL8rN5txgOG53e0VRRElSKpUE2SIEYMzKgogwGQ07YTAulw0xFd3ETmGMBQOzJVqAJB6l2ZBh60k8tUyJQSgLAQckkFFAi2nYUU3DT9OYUlXTprZtKlrJNIOQYAoSz4NFTilFHIYC2xn0NUlSFIXjOIZheJ5P09R13SzLAKMxWPrrvxj/jdn5jftHEFEIgKJKvntIKfGiKM1iURElQwtJ6Dr2vPXs1OnTQshz4I7zPKWqZPCIC/lcVVUEi3Z7Q5JIudFw7NSnvGoJQOYFVvGnAol1TTQoaqfpIS88xfEMIjlmGc8PwySr1EoFxFvbXYyhaeqVcoPjEaUky6NRzxclgFlMAYNYnFEaB0WeshjJrE7TJKEUCGKZ41iFU9I4HdndkGnkuY0RPD13JjrcE1mAQKFxJVDYhABOFCTBhFD23DgvoIgsUQJpOlUMy7Yd0mtV8kYcJSzLyooYxb4fjm17iBBiGZ6BZZCaaXZYUM6qNMxSmUVFEvkczzcaDcASQjnNqCFcGk5j2WiQ2N9t7xvamMQxRZnv+1mWYkWEipiQIre9lOSiyPthrOoKBpwg6lEU8SxyprEq6bIsswziGOB6tufZBeBlWaYME4chzQuJ5RlKGUoFbZkX1K3djh/2mzOlZtWc2MOCQnsUQCrFEXSmsRMGWBIgDxFlh14iCorrE0qZ5aNnABJce8jwNcBJaqUa+kV7PM4zApGE+bksiyS14BiVYYWsQCwn5cRrHXYIiGbNOgCoyBNCKWZ4SWAFovCcEHEsFgSAwpEzBO3cskSpxoTu1GgKBSFhGEKMVEMqaDL0xzSgijRPmERAIPJcL/AAw7CcKEhy4NM44VhWTguQOlmW5pPR2PfCU5eaaQZ9z0sgR0GWJVizqmkBNa0sS3yRB2nkxXGCKECIpMQzLW0w2Jt2DjQNlMqawAqRn7W746DgCAEAMZjlWZYFOUE5TbJIlBeT1Pd8l5C0ADnmWUktFxQkealULkMWQwiDIEijWER8khE/GSZpmOYFL5qSUgZUTiIOsSzCrCDrLBbSKIFMJnEUwihOHVGqwAKOvT4tAMNESeTzLOZ5tjPazgkTp4ntBookQSSkScwwTLma+I6XQg5QLswyFHCGUFZFDgJgT8ejh7skj9IkjJMQEJpH/N4o9r1YlXVVVRu1smU2kiSJEiIUHqIxANT34iCe8pyiGSVVlniOGw+9KPAUSVVEGSMxjXPXdSVzNgWYlSQMeQIL1VDMkuhM+0XIWqaZBlHoBwCQPKECECtWKfC9oiiCIEjTVBRFhmGyLIuiCCuCJJu/KTu/sUcYQgih5zi+7UMKMEHz86e299qQiw8GYz9O1sJPNja3BV7mOMmxXQQoIHmWpF954+zMTDUKvX6vmJkVIsRlAYao3Jv0W+3euO+GE3XGPHfi+CxiDnUzC301zwCLckIQRAgimOYFw/OSxlNQTL3R2OkgWEBUKIpcLltm2fAcMBr7iUckUcOcGYRJHOYcw5GiUGWGR6hIYpIQmvB2x/1wfeuwdYvj8j/+PXV5ro7gENC02Wi22mTqeP2pF+RJlvNBRLMIYDiGZMQx5PLlcwvL9SS0i9xlEGFgsnvo7O4eWJZ15Ogcx1OGYRBF7tTf2/Zu3vh8fl6/dPmEKGZ55lZmypUZwwtgnLLXvnh04/b+0C5ko5zSYjDqv/li+cjK8tGl+cB3DlqHEzcqElYrNwSRj6IozUBe6FMbM6yQJrLjAoyCbnfYqIFmc6Zakj1nGAZ5mkRa3UQAIoxVhS2yLEsIh9n56sK97cAJelc/u9kfDpuzpW+8/pWKKbA8TNI2AlJB2GvX7wwmDifzT1w8e7yxQiHiBTTObUqVlIibjw93O4/rszo8wxqGJeIsDFKO41lGmoz9+/dWZ2Z40zDiRLfHPidK1dosYiIK0iL3EYIMA1iOYgwoyWlOkjQKAGRIwkgcAvl+p9UZ4rJlyFJpbHdFUWRVy3Xd8WFf0zRJNeM4JkTPMycBaRSneRYLiibJpmaUHA9CZAuSSPIsCD1ZkucW57IkdyKqqHVU8G5UBH7CcLJiqYfdHswJwqRW1tOE9todTWZZBna6uyxTLUioajwB4ePHW2mMDG2GFJKmr2ztHU78IC3iIByaurw018gLFgItSrOJcwiRaxmKZVpFgh482N7Y8k+cWqw1VAiDLHEhjCCX+EnMcjwAgmbWFa2epHy3HzouIQQPJ/5k3MliYqmlakmTJMIxMWawpkAWMyynaYrIMIXAQZ5D9mSCGLiyuJJGynCQi5yUZmAyDuaXZnnBiaM0jiggDCvU4pi5f3e4t98yKsZzz18EMKCFPR0nWQqPHDmSJXlMJZGHrhN99P6dNAuf+cq5RsOY2n1TzYs8zCGLsGwYTUGwMJvmhT0cbhmqTFKGpnkCkyAKMJbVcvXTa3f3Dgd6qTm3eLQxa4kSl+UxRZRn+TwrkjyjHMPzPENyQGHghQjCPM3SNI3jOEtSjuMAAJIgAgFPp6Pfukd5kQqCEPiePSpKZkWWrL2d9D/8v96JKMaSXEC0euv9vd0diRdURWIQq6lmllIvCNYerv7JH/9j1wnfeffT2iz+oz/53pmTT3VajpNyrXby4794t7ObNSsP/8W//IO3vnuU8vGta/nhQRcUIQNzTuT648n1u3cKwJhKBSEwndq+Owl815mOT5068Ye//wO8EIWx7/k+pUiWa3GEHqxuPnywUfDiwqL8/AuLzQYe9T3fZ2hSG/eEjz545HgDSka4+Nkf/sE3aX5ISSqy/uZq3B2MVnf31ndaYydlscYhuUihJGS8lH/+2YM//rtvnTnVILkrsOzDh/f/y1/dngzjY0fPGcry4hEFs8l4dPjwwd7P/qp/997Vo0etheWlEycrUZQLEtrdO5h65QcPdq9+tr6xNZ76FHICJ/MAgfH27Te/8TVDXpy6sNVGGbT8mLb2czga9wbtKA5Znul2BgRwEHBpUqgijWIPw/zsE0e+9vqLEAhlc1GU+IiZOrbrx5Eh6yKvOr4zHE9JTn7xq8ebu3uD4YQTuPX1g+XFpYvff9Ue7zJ0HwAtzUwvcK/fuDu0p4etftlsyAgwLCtr1SyVtzdHP/zx+4/W7xw51qjN/CEv4CAIh4NpuzVqHUxHg2h3uydwEaDs8tLx6dRttXefeeb06288s7C00Nt/xAtQUhDPQ0qLjJA0zQM/iXi+Ua7WK3Xf9Q8PunFCxjbf7mR5YIRhGEX+g0eru3t7ly5dOnH61N7ewB5sLs6VLp5fKlUraRblOQojmsN0bdXd3Hq0stJ86tJZxJiDwcizp4GflObrLKcnaREl4WgUABDxXD616cO7D/Z3N2dmysePzNZqiq6xCKeKLmCQAAwRlvJMiEOWAVwQiLvbvZ/89QdD22ElmVdVLwwEDjZnyqrIv/jc5caMwItlCmhK0MQO11d3f/bjD3cOarMzOydOml/7+qmlZb0gGQBhmtkSswwAA4l+uB/dvP3wwdqBG+SEYoyzB3ceedPk1NGTc806KHzdQCvLM0sL6VzT0jWZwQkkgSTyPIfdCVGqpcHAT0JA8/LOrvPrdz8ajIZ/8Ae/31waFwRDRleVmTgWb955+JMfvnv/3tqJ88vVau3iU8thGKmaMVOb1aTSMHJUzTK02sN7G49WDx8+uNdu9X/wg6/XZ2YQcwAKmMYUUAYAaeQmcTxhmEDRsK5Z/mTq2XaahF6c5zhxdrt//defr2/u+RE5evL4f/uv/quTx639vZuynFmMBgAwrRLDMUEQpEnEsjiJYk3XIIQMw6iqyrJslmUQQkVRnMTPAfmteySwjMhjrhAiY6ZSX9peO/yf//2f33+wRZEgmyZBUNdPrCyZPJtmiZvGbpo7BHFGRXPHo3d++l7kM53DtLXXNpR3FV7T1JLKzCbe4143mps/FXnpjXt3Tl663B3v/uKvO598/IGu8CyiY3tEMNOfOmkBONIolcw4DIo8lnl2OMhHrS2OXP/jf1znOE7XDUEyNLXe7R3cvLt65aMvWK5WnyWa4lQqpzRDyT253UquXFntH05Pnj1v29tfXL//6ivPnz13btQf/PrDzz/71TilxTT2uhMnSUmjWi6XKoCgiW3b4+7W+iNFYXTlmzMzxtb2/pVP7t6+0SpSeX/7YRAU3/n++bkl6fHmo7d/8euD3bOVysmx3d7Y6hw/teR4w83N7qA7WNvsPnq4O51mprYkCEUBMkFGfjDdfNz6YfjLkycv1OszN298+ni9kyTiZBKXjcS2x3GWWpZ1cHhYAEwKIIpSTdURztce3bx3786pk8dWlhqSxIsiT3KPQzhKkwRBmdOytHjwcG3t0eb1u7YbBaKkloy674Rbmy3fD/3AMeUx5jg3CCAr2U6RhPzVj+4dWTz1hz+4FERBTnFvFHzy+d079zfyrMhSkAQgDfDmo96Vj6/duvFo2Pd1tRFHBDJKHPqH+7tx6A5Ge8PhcO9w5+WXn3r2qRMsRyh04zgoigIjGVHVd4pffPF5sz6jCOJ4YLtOxHKa4xfbu4ez2mK/3w+CYHtvdzKZFOGRzn77ypVrfrD36isXTh1fXGhaYex4XjYdeIOd0V/+xb1rn1957oULK8fO8qzw8ZV7Nz6/Oxo6C0ePiiI/9SYE5pPx1A/i+bkVCNnpxDnY3y4yf75pfP/vvL7QfDLPRywq0mJSJABhERCJxXIC0OP1/V+/e+3hA5cTeM1iRVHRBHk06t1obfI8u7fZe+31i8+8sFSuWISmo563+qBz+84+5BY6t3banfz0qerK8jLDi1mRhEns24kkqds7nZ///Nr1G+tJDhHPpmm6tHBK5mYYpei1435nF8KMgujDDx79yR89X63MiaLoTscMCnmWZFEuS4ITFa5D8pTvt907t3c++vDeyB4CKP/v/7uLDCtHCbOx07l9++Ddt6+39+yVxYu6TK5e+UxTU16MK2VTVat3bu0IXCkT0vGg89FHN/d2JkUub210Njbbp06dGA9WJc1aaDYJnTvcA4/uPmq3N0Q+fuIrps7riZOSGGPMNmaq0wy//9mv1+5PzNJic1Y9ONi78uGHVeslkRM5iEhGCoYKqgggHLvTJApna3Vd0WmeUgAYhGRR4jjO9/0kSYo0S3xHFgwA8t+uR7IiZllKQTGzsqgrpfZHt9Yeb9XKTYSFME0oQpJa5liIiJ2xIZWkpCBxmmhmRa0Hm91HeVSJAUwB8XHg4j5kQxUf1ZWKxFsFBWHmEhbudqIvbo5u3nQeb7QaFUuXhXbPK1eb504/wfBSa9eRJMmZ7gZOLteNktkEJO+1phjPK4rOi7Io6Z5Pdg87w5Eta4YE1e7B1trDnSefWqpYpYJRJ8H44cZmEkWRq6cRaTabVmWhWn12Y/3GnftBv5cSnDEK16iUiyJTBQLiYegELKOaqlyrLu3vdW7d2jTNrx600N4+lvkFysie5wVBSGgBKBMH3KCND3utao2XZDh1g43N7uZa6/6djd2NTmvC86wY+Gg0HAocJMBP3BiiuFTTlo7OLR6Z29s6/PWv3ssj9cTycwxD9zsfYIZjGC4ldGZuPs2TgqSSLAMHAFCUK4ooA5ZPeSlLcj92KYOzkmKqrJVnfBDgdi9a35jee9hzJ0DWTFJAkjESo2092j7cP8DYLUt8HuEkFOJIkoR5Q5X63T2YazwL+mNPMmdykDzeOkwzuDi3lKUxRmB/p/vRu3cf3OvGnqYIqiKpWTImnI0BcoI+KJjm7FFIok8/eoyJ8cLTJwWRyQmKYkIpBoUy7MXXruxc/bQzHd5LA8dQZEnSopRmgBNVY+OLjwGCsiyziLf0cuDGhzut2Et0qxmEoNMbamoGUcqLhusP33//Ez+oMFw5itjDtu27zqef3d163MozOBhsSrIYJS7CIM5Se+K19xJRUEVRZGElScDetu26RBRNZzoJc79aVifjIEtwEuNuN9rfHd66tbq5uV+pHIuiMHTGJPMALqaBRxBhJWNzq6NqgqwxF55cLpWrod/utPPQ4+rHFU4yrXIuSZJrRwWMREWhpAKRNRoWH79375P37wEoqbpa0NjS9d3VVdOq8KzkJyHD8YZhxJkwGAx++csroii/9MJZVTVoQZJoYo/6GMNUqVfKy+5EvH3zk4erh42ZY5Ja2t5uP7ivnjhzUVYrtx6sf/rZ3cPuWJGqklCC2WFZkxSZxyyJkjSKwzjXZW1+NN17cG/r88/udbtOySxBSAY9JycMlGXC8r2x+/jRzTvXB3vrh7HfwcjR62dOLJ4p16pZlDiB6ydw4sUb+0NTWjQUdWa25IeDyB/rEmdpc/3OnigLbhQOHZsRWcAwkqJSSsMgICAVBAEA4HkeQihJkjzPCSEKZmLXB0D47XqEIZp4XuaFmlw5GMQEF8dPHR21/cB3cgBEVnS90XRySOLeTE38yleeajSXAKvOzh+9u/bvf/7TtTjmBUtu1GZnTzegFQGdgkGRBkkapW3v0KqVzl54guHMau2pMH7n+LFTRRIzHHdkuezFRetwyss0o9Mo9SAOZK1g+YTguFGtPPvCuTBIAQ1wkBPqbe/0Pvnkk3a3U6nPQpd6HmChJLGVPOVdL07yjJOhHMb99p5VUb7//b+TJOj/+m//6u2fXrGn42WrbgdDBHPTkkUR8hBmQVz40xQxVlVBDH64/uCv/uoXqroAaSn0K47TlUX22Injz714ojZjJlnGsbWy8YRdGflR74VXL548derddz99dG9f5RfcSS4IKiiorjKqLDAoMq2iUmWCoO8h79LTJ8N4fPXaeySLyupcNHFBpu3s7RqmzItqPukuLM1HmR3FjhuSJeMkJzDPPv9VswI1E3QHj33fpbSQoNKYWeQFKwyK7e3Dz649uL+6OxhnmlyjhERxXGQAQ47k4fzsjCCJTme9P3STojocFGEoDF2HxfKp4xd6/Q1V1b0oWl3b6g9sP0zCMKxWNVOVrty8d+PqA1iUDclsd3Z57DVqKqgeTkaZzDWjKRr3pzxWYr+8v4kPDreb8yVVRwynkFwIHH71/vZ/+dN3rIU3GMJDpFT1kmFoY9+HnLh47Pht54cZKZLM5kW2MWtJsh8nE02PZWVRkcxSqabofOCN8ox0ur333/+UZZ+vVhdK5cZha7C1+XjvoMuysmWWEw/qkgwBFwQOzwgVQ88KhKk47LsYQ0uv1urz1fJckhRuEGgqOx6M/QCY+kwO+e3N7StXbuwdtEVFJlmSZ065rFolsT/ps9iHgphTv1KZ3dxu5STI8/zSUxeikAt9gBm9O9muWtzJU8tnzpzJk8HhgdtozurqiogX3rt77cpHt0jKX7789OHh7sbO5hPnjz97+ezu3oHjTnWrwgnc1B8naWGUyo/Xbty8ce/M6bnZBhtGaZqmSRKBgsSk2F5/uLHmPri/73koShzXG548vcyx0nBoFxPQ7Y1GtpvliGJm0J9427f/9b/+e/PN8l5rbeL6mmLNzJ98/93bjzY+3NsZun6CkZAmgBLG86JBfzzN7HpdjbJibX3r048eeCNfYpMs7e3u6NFTiSzLPKdWRCUc24PByJ5GWagc7PYG4wNGiI4fmUc067dHiqCGQUwRpZQyLCvJMkmSIidFTlke65oGALBtO0kShBDP86IgWLIc8hSA5LfrkQhKJOuGWTc/zKqVudfeOCVq/scfX7PHlGVri3PnbnxyL86GBR2cPHb6W289aVabB22fonw6BTlJ3LjFKvNHjl86fe6yqJNxuOUf3Gm3OxhKhAwXl5aPHV/iBfPund089XTd6PneYXewOD/jugNJREEUQyLVFprnjh5/5oUnc+JpplBvGEvL8+7hcGrbssFggWN40ag0AD/ujHyYnzpy4YnTl8+3R0QWqD/JAw8jolMx5uXKS2+8ce7Ss1c+uf6f//xHcczNNut7O6vzC7Nnnjj90qvP+Ml4d3/jyImVar1y4+ebP3z7J5X5plQ+EkK9M+IONrfbh94RwRrFvWOn6rVjNBfS3k7w7o/vtO5FrIwXZ5PnnkZZuHbv5u2Rx+QLPncCa0VESZFn0eHB5gvPnfsX//yPNY34/qhlOzxr/fqdq7/+xf0s1WI+bvevTO3BW9/6+7wAHKcLcawp4mSEZ2eebDbnT59++uTycZbpBPEnIj9NwmpWLAmKkcJVIMd+Nmj30LXP1z/48FcTp69pes8++L0/+PbG9t5otF9w6OSl5xN5ZhREWv0rmsi8+/MHb//k16Jgpkk4t2AdtLdmntJYrGlZGdhdjTSallyeFX73H35jd7N75ePHkrHIyHh7/179aO2pJy5+9ztvzZqgP9mXNW44Lv79//OXO7veuScu7be31jdFVSOh111emB+N/CSoHDt9VG+KHjiASipwUJCkB3f2eK6ilrMbn/60csJcXpwvisLSawwVfCdc37g3nu7PPYv+5I9fiPa3rj+OFi4fOXQ679w4dIKXzlT5PH9Y0SfzVePRtb4Y6SwHRq07BVcU2FBky5kOy1q1Xiu1OweWQc6/cYFBoaXRhRl91vCRN1riz4z3AqY5VBSaAfL5rfVPrhx2dxTizcga2wO3zz994fLZ880ZPU6HTuhPPGZnx73x2a/jiDz2jPOnnx4P2B/++N0Prn1w5OiSXUwWl+XFhcTu7mSJA2CChCpmT6/de+f69etBluWCcmtrtVFX/pv/wz88eqx+bP70tL82bm2wgh7Q2i8/XP/i1gbJKZGV9b3HQXwxiDLb3tUkw7Jm7GmqsI1ff35jf8dL/LhiznQHcpKngmFUyseMkvazX7535/ODwuVEJFXqZpyNMg6GcBjTwiqpSqT6I/6vfvTnH3/0WZDHlHBpmJGs8JKMEIZloVby2axsSLO9bX/r7iBLqFppTAMvzJWxc7rbispzOymYqvUTVWvu9jsf410JMllNRSdOVr/xxreeeupCmLuCwrNGAW3kDCatdksQuJWjR1gGjpwxQQVmlaE3pQWBCBoVUxTFLI6m0wnLCBT9zYch/7/1aG+/6yappldF1rBtu8jh0vLszMz3MDK2Hk/W13uk8Hkxr1SsF1++cOpsMwNcQsXtve7Wg5zNFiQEF+qnF2eOM4VCQr93MP3pf/l4e9N3/aw6W/rqVy8LfLK9sX7v+j3f9zHmOFY+e3rl2Mqxz65dmY5H1ep8ljmDwfDchRPnzp3JiinDZY1maTzpFYUvKVgQ+TAhgZ95bupOMwp4XcotS2TYwrYnHd/e2+h0D8I4cwFMVI2ZnTUf3r9x7ZN3NTkXGUKzjlKl3/+735hfmDEtjWVLZ06tmJb+8OFDSTYYLD58sI459sJTR+PI7w8OCA3EEq4gqTarHTu+xPD53c6O5/iSII7JwfGTc6al37u57dk5yKy9B64dxCyyS4ZRrmhzMyuLC8cpYv04kHRrUREnQzIdT+MwK1nVvEiiPJBL3NdefVHVhKnb67R3As+NvcgZTzHh6o0tcsRszPFTR3WnA1EUK+VlTpD3h22Gl1OS7nd27z94HEda2dJz4r34zctPv/xapbn/o7/4VeQWqZN/8NfvY278xMVnRUa/d2cdIVwqWRhpgliYlkIpdqbBqOXs7x3s7m3EeXTkyZOCVBwOeru7u1GiFqzzO7/z4htffTkLCwH51VnZaFRYkYO7Tq0udXqTKO6zTGz3mDRUAROMR3mWyZIkHynX/sU//0d/9ot3h+3hiYVFlHoXn5mLfP6guze3UDHN4p/+g++VSqXNx/397eA//E9/0ev3F5aOvPm1351vni5YJ0uhm0f7m48DJzJ1xUuGzzxz4fmXjyEoOX4RZxCy+PS5i5lEixxdPP8MgxXfCS3DOJdEhBSvvXx6pq6ocurae3kYJiRz3R5BTFm3Ro59+87qx1fubWy57oAyNK+Wa//Hf/2/K+sVS5FMHTFcLcrIZMouLUShm1z/4rbj0Pffu379izUvcOrmyqQbvfg7x779tWdQGDujqFKxLFPWTb437O3uTO7d284zaBg6wuRf/rN/8Nor5+zx7ng6Zrh0ZqksiuYkVE6embV9e2dv39JKFcsAhYEIVgRQpFmSUUmWPFcaduN+3/FyL0U9gFVLF7xxd9jN05jt7KDuQSrxJjYYZ5q6HizprMwJtIBRlAZuurVtP3q84yV5fxCIAqzVy4YpeW5QkDinabffsyx52A92tvoHByOEeVEUkyxN4tweBbVqs1z1Wwe9yeHB+l7n4KC1vbkrKPLykbk/+INvzs0qklTYgykQongShAPA80KjWgMYEEKSMBFFsdlsHuzvpWmKMVZlBSEURRGl1DRL43GL5Yrfer2WEcwKhmnKrd02hLRkUE7jcwlwrNpr+fa4Nx4PWSZs1GeOH2tmhTuexFGE1lZvb67uh37BYLUIyfbqwe3rHznxztTd7+wzMr9Qa6zUZ/znnj/Dc8nwcG93dYfl4HQ6AUQMuLTbmUpCDemaM/EElba7nbfffhuxwR/80bdYPrXtdr/fgpFPKLuga1M7+OzTu1uPeyzSXTf1Ro8Zru/5D+JkmEfJuB9ySJVUI+75SeK59uD+nfs76w9MsRRkgSkJz//gje/8/uuU5CTJHHu4tbnZ64Kdx2sffGgLvF4xsaBKCi/ef3Bze2fNMvUAtS49/6RWhq32TpGRG5/d2Vpr8fmcuULqs2qpZCpyiSNyHnMqNFiEUwBHLRflPAHR//Jnv/ro06unz84//8qlEwvC5uq2PfBkyaJIGE56nMEuLNf++kd/GsehZSqEptOJ7XmBIipFRP/0z35Niu/Nzj6n6exokISpjZlJXISiZvVH4dbW3vXbtx9v7wZTRRTrihJ95/t/UjaNzz97iKkqAvLwi8c7j1zX237pG/DShWddJ5uZaUaRR6k39Z2NzXsv/O73tkaH9+6ud/o9iFJFK2ZmhKmz3+4fcrzE8jqv5G++cfqZSyV3kEza4eFoQ5Zllmqe73J8kSbDTmckKyIHayI3hxkQhQkvyAzHMEz84ktnXvyds4/ur+qCODgcKtzy2z+6eXf9IGvB737ndQEN3Mlgd/Pw2sfD3qFfbx6pVmUFz6ytDvkYVKzK3n7vzrWdnY3D6URlreCF134wM2f+xX/52e17OxnVeMyp1gxbgr6X7R72VLl2bOm07wafXbtPSP72X/+nS5dO/N7vv9aclyFOM5pNYpdksH3L8YL07Z9d2VibLsxfjKzCVPDv/+BbzQVbV5Ui8cNwyBYpL5bmGosN68j2TrZ3GCZB6rvUc5xK2WiYShyHX3/pyaOL83wq8bmGsDPNtnut/f5AjRLBnqY8J8429KX5yqkVK3d3c2eXICrqFBSsqIgV3ZA2O3E0BkUYxVyRsIFbkIqKkZmCGGE4mfo3P9hp7YX9scNYqVjmgkkC4yjzi26P/PLn1x7cHe/sTWuz9OixE8MRoo48Xx8UaXa407m/uvVo1W0dFqubhxQi3RC/851vXn76wqO1e7/42fuAsoayhMlslviDTtZppXkuYhY77ng0GDNYHPeD61/c06CaUagYJkKJIptL80c74zVDn6vVmTA+nO7FGQWx53dHByqc4QR+ZmZG1mTHsdMkl2RhatumbiCEBEFgWTaOY9d1CSGQxwiyLMv+1vMjzEtFQeKIMSSLESBCeRwHUViEodc67IxHPQx4y6ycPn3WssqDbm/s5EEiH+wNNS2VJYQx3du5tbeDKEjDyNZ069ixk4iW4nCcpH4cDXttf/fxJsowgJmiyhwr25Pewd6OrpuVkpUV1HF9QRQ7vfHGxnoQvpy7dre/U6ubgqpCLFXrja1td2ujm8W4WZtrkxGS8tBxVu/vQ1pIQglRHSIBYI6Bii6bk6E77acgZqdhr2Qp333zqydeOJmnk9ZhBxCIIaSQ7O7vvf/J+/fucy+88IJi6usbaxuP1iiIk9TzwvT8s0sXnj3uJeNep5+FKI+ZarXuD0ipJL766su1qloUW7KKAqfP4LCiWFJpwXHdAlDAyIAz2q2eH+3Vm6fmdPLuz97rtJk0LSekSIp86UhNLbPhgbe/t9PrMDzPIwrytJhGmalbJ0+s2Pb+1WvB7KzMc6Ig4QwOk5S4Adnfca5+urX2uK1oEofLScwJgvif/91/9Kf2/sbBXPWkouqHnV0uCvw0d8bs1SsPp5MII8ALgOcF2x3evHXtiZsnaCL0+1673ebY5NmXzn33e68Qzv7hzkFBUByHz7926thxNQzWdakac1mqMqZZGQ7SB/e3uq0+C6EkcsdWlo8uz1qGVCDZDwOYxxRPbbtjlVSS0uUlLfKDuSOl1rb9aP2BIMkL8/Uji7o/2WF4icfg0YMtnilBKN578Lj4zz9zBqPcj5qNpp8E+4N2NI1ZFi2frl967pnbd2785GdX2x2yND+X0uTu6kYBDvttJ0uQLjfuzSznMW21OrqqZYG3fnsz+9armmRu7h0AmMsVQ1MNd2Ctf3p3d9vHbFnS1TTr6hWxPAMQcUSGL0DqpAGAhEVFFgTuFHR7AwAhgRQyhaXqoe+4U/uZZ59emZ3zRpNyoywhyfZ6WR6Mhh7MSo+39gSJD8MpocPf+73vavJ4f+tWSWcRp3Gs4Np42g08n+xs9MadkCMlLxjxLOL4ghWiIk9lw0oT8ZPPP7n1+SQMioQky0eqX/v6i/c/31+7uarx2g9/9KvuXqpJDV2WLz459/LXL/34rx/u7DjtVotDwtj1Nh532x3QHpC9zliz9Gee1M89NXP0VKk/ESVFHfXo40eRKE5fec3Q5TotIj8iTOEfP9E0VTF0YRaRd9/56OzKS3OLNT+Faxu7qw8fE5f7xjeffuGlI0U+yNNBnuYrR89M/GleBCW56Xle4PlZlgRxxPMsoGg4GKMiK5VKIsenUZykKcYMpbnvRRL3N9+k/f/Ro3q1nKQCzxZWqdbubu1ubRmmpumN9n5vY21rMhhCDJrNmbOnV3iOjtIAAcEeepOhnxeU0BzDhOUgx/I8rxmFWi6XPcLu7+1O7L1nX9T6/f72emd9bVtTzE7/IaF5FAU5oYqOecn3Y0fWkWhUJZk9ws88/fQzUZgQmpbN8txM07YPVbXSH3jXP1/ttBwW65N0PJ0MS6rqODZEabU2rwhzCKt+OBx3eyeWzuua/uDm5nTipaEGATl79uzpM+cMfbr1+KrvQ5qru3uDxxu7W5s7t246xxaPe/6E5TDOYezFrAgkSRIV4dz5s/VGtYZKfpBc/fj+aJjqlVK3u60JDQZKjpsvrCx/5YX0s0+vFskUgkF7wOQFlFUjy6DnhZzIAMp/8N61MrPS7flpVmE5MQzCoqCD0aQ/dZvCcY7jEMYQYoZjJQmNJ8Ot7UdIMV98/sTS4mzgDN3U1S0e0mTqR4vHv9I9HHgTzZtQji2UEg2nmT2Mw+Aw8twlqy4iLskoI0mFmj7/8ltldvb9d9/x/Kkk4uMnFz2v7/iEYZjt7cmZoxcNYy7Pb9dnjLfeeuHs6aP/60//0717m2k0s7x8+mtffwWx/mDYkgggxBSE+t5eePOzvfd/9bDbGkOIFE08srS4tEwh00XYyaEXJ4khQIi8giTjTsZzWpZigSuvPrrjhdA0aqdPnLXtoZRzjjv+8IPt/f12uXTa8zyO49bvPqIUp3EyGIeYcpxomBLDqmRm1uz3+7/42ZXRIF6YO2VZRpp7w/GophIiA8UyREFMvTZIwYyRM4y7ePTMZNrutTsz8wLDcFatghjsuJOt7ejnb38+GoBao/JwdbXZZL/65nPHnrC4LEZQjGI2AzmhWbvl3rq2evdmZ8NGnjdAgBQEebFjTye6op69sBx7AaHe/dWPsqTQzMJqCGqqPbrbP2wfmCU1zPqAGVfqNCvaaTZwPSLolwIftXrJ+trh3qbd7yR8UQsiUq+TM2fnjVLsJ4cAFoDiVjf58Mqj4ZiESSFr2cWLc5efPjbcDR5T1Z9yO6P7JW2F5NPXXjv1T//bNzqjnu1tlRrz5fJsXvBTu9jZnt69P1aNlYXlo0HkHD9xxHXtn/zkJ3fvPqCE4Vjpi89v37z9YbX8O3t7hz//1e2xM106zp48W3mU+l7fdbL00WBz4/Ex1TRurm1cuXJTVdVKpXHq1Oz5c4sItCEmLM8VScpjrl5pcERUJbk76DuOU63XOJELAk/geInhMaCh66V5QSGiEEZh5vqeWi0DVPzWPQJZQBI3TZKgyEieibxQseqeCz/76Pbt6+uSaDLMeH7phFnGeT6RJOj72dbGzqA3MYxTjjt0vWG5Kgt84ThtSJidvXZSGEmULi0Yz37lou+Cw/2o3XFpTnXdHA7HSZyXzHKlpM7N14o84gXm29/9R4RmnjdcWa4LbJFnBUJ85ME4Y9y2u7PRvn1r05lEtbqFYMriQFOlghRJntMc9voBQhDyuWIJx1eOjEa97e2dKGAaM9VLzzz1ylefDIrc219ttwNE693W+Fe/urGxNVAUa37uUlRsRjlSlZmTR48wO3gw6SFekiSLQ5Y3Ltrdw4cPdz75ZNUeZUtLBldhdx8f3ry2VpszRVm/9NLlyy+f5FBx49otqXRkdmbx0aO9n/301ziLKuUGwzBJGPynP/vA83hAYRC7BSWKoibeWDWNqR8pVoljWEEQ5puNC+dPKyoHYHHihF7k/enYKRmzs4Ye534CwHJ15b13r7/3s0d3r7eiMJPVmFULSdRwwZU1XrRmR3273wsFoylr4qmXTr763UuP/nr/oLVZKmvnL577oz/+wccfvXfv/u2hPL1za2fcRq3dLoRwfrGytDIz6A0/+fA2JLqqWM88/5Vyo7K5t6XwMqJqY/bEemfjf/r3P7vz+WGRcIqoJumgrOvffONpWd0OU4eRiFFW45hTFBWCLPIcRJQgolZpeXfHuf75PgQKANHicm3+6Axmxd7dnYNDb+XoEQiZ/rgV2B2RIoqlBAAIuYbVbFTm+/52JrePH1+6ef3O55/e1ZWKZaqj0UFeRJBSz/aX5hcR5YIgqlRUQWQwzHVDnmvO8crC4pFqnicYY0RR4Pmu44/GnhcSWZ7FjK5b5IVXTp+7dKSAznA4djxYEM3z0f5Be3frcHd9MGzFPoSqiKrVMsB5t9tuzBuvvfb6iSeOFsWaF402tx8sLa2I1RJWWOqjn/7y7f29oRePqg31xVefD/OYQrp07CxDs1aob2+PPvx4a+1hO/OzzM+LBAmi+dorT3399QtmaTCa2qKk7O51rl11NzddQBOjajz93Pk3XzvLk6k96CKkjZ1M0cz5xfKkt3389CLH2nfufpyDqZdho7bAq9VWb70/SCDQSI7zNMrS6MrHj7Y2nMPWwf7+fqW0IHAlTvHKDdo6HB7sA9cPZAudvVj55veerKnyD/evFTmTFtzGRv/pF7+WF1Hr0DF4K03HHKqLHBJYOU0Iy2jd/SHlGMwjO3RkWVYlmWVZQGiepCxiGZ6bsdThcDh1HYbjWFEqCAIIy5IWBrlmsQD8zUn6zftH0QiRjIHpaOBWa+ZMs4SAfOvze7eubzqjxFzQlk9bzz93WZbYIBhjLLQOu+uP2pHP7g1XT51Z/srJlfl5VZIYTNl2a/TeOx9VRV03pOdeOnnx8rE7d9fWHjq2R6OoS3Goa43Tl88szi94zgSzea+7l6bhfnv/zKnjjYaJYcYyIAoCSRQ4aNTK0uG+40wdQOSSVW/UK/VZzSydEYDHycsAYpZdunvHuf9wZ+LtLs3wJYM6U6cxo0xtfm5l8ckXzkkNodcfgkldYMX1h4NPPlnd255oomZqcpr55iz92utfwYm+dvcAZlhgDILowb7z9p9/Ups12t3DkR2xbK02I0U0RQadFWbu3FgLb8TNlWOXn70wO2sJLHjlG0uMWvanEbc3Mkv1OBykPkiKuNPp8KouCvLUDjCmhmE8cf5kXkS1eunC5Wc+/PBDkZcMU7t549NZp/Lm734/LyJLGe3s7NkDH2RaGCaEI3HOHux57/zwxv17jwOHapLCEhJOW3GU0xQSXj115Nh4khV5mASTlWMn3nj5uVbn8Y3bHxsW8/QzJ//k73734lNnpna/UW8UOXP/wc7ana4uqhCCgkSjfm+wPt5c7QdTTm5IS0fmeVVl9OMsYCcduLq2duXWL69++qCinDz5xKlqBQLQKlXA/CIM7ITkCYSCaTUDnwM5R4s4jwMKcxZJ40H2059cvfLpfYZyl59qnDpjSeWSPU6293eCWIoTP8vGmgmScb5YKwvWrN6YDZx48/P29sNueZG8+MLyE6fOfPj+DUxYicVJaBsapIAHgP/Kc3//3LnzRVGsPrgbJdNTJxfOP3miWtHnSiVCU8cf9vqHLMKQIkQ4DvJbe9fzPPO8hKL4zW+//N3feZ7j+oftHYWgXj9OMnjQyq5c2W7t7bKFILG6024vHWkKDE8wBgiWavXTFy9hVR20o712xwu5Jp1xfW0SeJtrncc7LZFbpFD4zrfffOmVi0E8PuwNS7JURPTGw/Xtff+zzw8nI7tusgjZRlm4dOnYc8+dnG2W09Qv6UcRq609un/vflfSmm7++OKLZ3/vdy+fPsp9/tn9UacN2QbEFs9Hw1H3zKna88+fCAN3d6dtT1zHJ+WZV1a3OvdWDxAyGURgjqulEhw721s7gZdDiEx9NvTpwWh9ZgE/8eSpJCarDzeTLK4vsDNLbEL2mk3p4vmTD1ujYcLfu7dj/vSL9dY0ipEAwoXZar1ugYIQgHiogkziMRtnKeKwZchBECiapmPY6nYIIPV6lef5x2urcZQWAAqyLAAG84KuWaIs2a1eUfz28yMGplNvPB0cmrUFiIo4yNvt4cb6IcgFSeRbre7X3vzW+SeeHg7vjEYux8C7t3bWHvSzrHLmMnnmuYXvf/91w2SnEzsN0JUP7oiyJDMFIE6jrpYsw5mQdicWpLKoiYaqWVZJ5A1nmg667mB0uLmxunJk/urVT1kWvfbKCxhkGORZFDcqlel0wjGYZfXJeKPfm+QZGQ67Rom89NK3ji2xgAk3tvcPD2hW2LZ7SDj75PnzhkFcfz8naQF1vSKyKvn0zvvjibt+Rdbk0tbj3SJjVhaOB1FLU6eVmvLdP/6Tueqx//v/5S++uLI+N3tSkYwUkYkXba32tjf2cxoj3kgKZ+y3S3PC6UuLX5u/+NP33j4Yjve66cON9tycKgoMj+ShHfpuMuhOSSJyuH641WUQmGucbEeexKmVhqHIwsHezuF+K/KDQWuyutPqdDrj4Xh5ZcF1+v/hv/zHrr3xR3/8d9JoDwBX1aTURQDAZn1pMCbvXV1t7YaWrilcXIRoaWbl+KlzmpGZmk5qS0+dPqdj/f/xf/7Tt3925dzRN4/M1n/0f/sf9w62VJlLc0dS8OHh7srK0uXLz1z75GbGYN+LZkpNtlJeXGxcvHjx5u3V2EczjeXFlROyLHS6fcpG+9v7KC9/8cm9O/c/Q1BnOOHq1U9OHJf/+b98fWFJjJN9RBmMJEp5QsQoIJEXy4w8W1NjGPYH4Id/9dMf/fgjq7RQNoyXXj3FSW53Ku5sTt95/54fswxKL1469s1vv84gStyeD6TayvEigu9Jn63fOmwcJ6+++sT+9s7q3YeYoCRJjZr1R3/8d1RNtieexxulxZXxpM+W+2Vr/okXzjSa2qC/72xuiRLPMKhUNSVBIAXgsAAydNB6zApCpV4LfNTtDG7duRcFjxkc4jC8cb3vR7Ouy208DkimGrzkutnFU5dPnDt22N/ujA8dL3m4vvXJZ7ckTZts3nTCjiBrN65/VqlX5pe0u3fWeLHG57WllRNfe/33e/31Xm+wu7E/7Q621rdGE5awtZRKnKQkWW+uUTz/3MqLL56MY3fj8Rqg0dzsbBiw9271Nh73ZX0xhcXC0VlNYw637x9sPhgPWmObp1KVRlStMq9//fl63XK86YljT33yxRXN0Hfbw2l0/We//EDAZQ5XaR6VyvrCbGMoT1QZRz5ynbRI2cX5k09erp07N//p27c6nU7z2Onl08zxMyZi3Vq9Od+svfPFFwzNs0z4y7/8VcfNqzNNnS9ee+25J84e19TCn7qCoHgOWFk8PfbGssnHaYIxNixT0/63F2P6YRjnOcEQzc3NiYrqBfHU89MipgDnBT1y5JgTHgIQ/HY9MrEBBUDNXIhRMU4FReSLjKdUFUxYZKVF8StPnMg9nye6jBc3trsHB2FKWSQysyT9h9++qDWG+/2+Zp0dT/Ib9x67qW87Kis6ZrOKRPGgfeB5XYWvlY0mZ+T9UevevduhE5p6uTkzf+HETL8/PHRW7xD4wlNPNJdqjzbuqCrEUjhjSN2Js3rvzs1P3oO+xwGMCLu4PK9VTBdOuJSZM468+x9/fHBjr4JFvnLq9Zf/KZgOd3d/OpmkumbuPur39xNenJlMRbu134p3c+AlZBI6iVnFZ1+88Ed/9/fKFP3ql5/u7W5TBrdHA07EFIVLswYb6xSg4dhxHR+xfk2HZ5abX33yyQUuzt1OamcV81Q+kTf6WZ5PY/8gjTmWA0k20Q0hK5zZJf7E8dPDod0fT/x0zAJcpEzFVINJKw4mnV17+fglk2KCaGft/tx8mcLs03c+PLNcfev3vs9LHYmOqB9nYcTFCUgmqr4mq4rrK1udR0+9wH/3n5aX5qSycKIsXhzBkSqZb//o5uogmLL54+6NYxuN1i2O787zC8Wl5y6Iml34+zQUX3zuwu31x/adtllt9HsHGeMZC8/tDuiHH7Tz4GjBao+27u7891dKVVXRSkXB+lGY5p7gnfLH7c7k2osvn/rDP3z1zCkT4SlAgescgzREPswAr1KZUsfxO27iKEaREnzYeqQIqiaqi8vqyQtSa3TVEr8y2arn7pmcv3rhefytV08fLavJtOfMLtdR5A8e7N3p3793a1JEr7/+tcrx6vb9jUcPd/NEm5tfylHypz/684KQklXf3utJnFDRzOl40Oo8fv9t6x/9N7938vxSkg4JVHkGZVPSGkmIk73U2dxpD7dkRTSSwi14srXmtnduS1yqKqgzcmjB+/YUQblhGqTgFRWfPH36n/zOn0yz4H/4zxurrUNBttxR8cN/996s2fTTgzTDpRKXUG/9zm1Z0Th2Rsb1/enVxXPP/eVf/mWv0+oeHh7u7wW+a1kGIy+igiq0AJDMzza/+a0nXnp5QZRip+sHKe3bTtpnvrg67hzqK43m+vqtV3/wnacvLKnseLCd9e6zhaPqBp6CHjdq//0//qfHTlbcyaHT7u9eu+N3AqGhh0N/sjda0OcSP6xY4fEjTYz8/f3Hi5fO/uBb382H2Ts/urq3PXEzX2+WHZa9ea+TRtg9tI++cOaYUmFSJ8jx69/81oTFP//Zey6QpYo0I7lR1EeGqB8xeWYc+gVEfJgWFBd7e7cBALHLIo4zDcWbtFt7tqTLM82S40Tj6fTI2Qtpmo4cx3a9PM8FgclJlkeZPcGH7Q4A+m/XI8dxEIfq9UYyTlheBoAghHgBBf640xkCxpibr4oS43qZLIsix0MKNFWceklDW8gdDFxiYiMfJzu3dzsPenjKqjWwdHQBoXh99Xavu0uy0In7SeRAh1BKRYkRWBmQeO/gkciJ8wvzaWgtrazMzjbMslqZGqHfa3fHuiysbU4erm05YVadnQMALJ5sfud3vzW7VOp2x5qudAe9/rA9dfpItnSBY9lC06zF5kIWdtIobu3tU9CCEKd5bsgpx0YyB86dv1SfUSSFXrx0xoCcJpU9u/DslMcmx8s5SdIsCUNXoymFrCYXksAhBnISrllaWVeqKn/2zPI03DrcuxckGACga/JMvewFKM18kSN+2AtC5xtv/eCNN978X/7szz+7vX905QjHspNBPyOpIHCYU8s1oT/cYRgGwELTJMuyGC7LiccyiiTilEAecALL+wgFiTOx+57ncAxiQVHSpbMnT5w/fYHDbtRPJ+5EWRZXHz66dvWz8diulg0I052dR5PJvllanF0wzj9xaWbGSCeDxEX1BPzDv/f3/3T6Z53ByHeCs08fu3DhZJ57j9dvT6aHFQU5dseGk3RcEsUsCFPA5JrBTSeTlcXqG2+9+frXLlZnEKF2RvI0ybygr2g4yqMiSCqVJYBx5hJBZiEwaA4a1ePV8jCOi3Pnzp08dv6za3v5BE6Gvm1358+Zv/+DbzSN+fHOmKFBmvCmobg5O+hPC5LMzdckSdrZbLX2XQxUVjDCMJ30DzPqFUUxMv0gCA5GbluQLU2TeDV2i87OcGlxXuI0EqOiABzH8xIfJXFeRKomHDlae7i2E2WcotQiP0ijIsFZa3eslReLlCbRFNKRJga1Gjx9tvHiC9VaM79/5Wa/t1UxDUlp9BwbIgYhJApY1xU/tL1o2Jg3BVHudUaE401DuX3riyLNSJ4XWYYAtayyLPCkmPi+Xy0bzzzzxLPPHGvO857fa3VbZaUha8qMrFy/vfHeezfiSWWhIdXL8qIeNZVCZ9m2R/xRwiSQiXI3mJRkU+JTCroslwUu67u6roIY+qq2kKVjPwgqJfWrX3/x8lMneT6JkulQMUxeXXuw6YxHaeyUKjIqks8/vgYyoCt4eUmem1UlQcIYTCP3/tb7587ObTxqbDzqKuWygGF/2F5Znl1alABIsixLkyTLsjwtSJazLAshJIREPZ8XsW6oACEGIlWRwjDe2trKsgxjLEoiJUIURUWRy7K8s7cjqdxvXJb9pgFNUyiDMhKJgkAJTtOwUjVffOErcSDce7Cql5EfdXlRl2SmObscxYyq3BD5YjCyJW5FwGrm9KejPswhsEPsAugwoXKwtDBftnDoBgpPEQ0RBM2Z2hePb/E8rytKuWxqiuw6tsjhy88unjr6jcpMJSPJeBJYZck0ysPefla4R08+ubfjffDeg+G4bVnGWVMxSpIXjqsVnSaJH9t6ia80NCQKS0slBnkw5y6cORHawcHBKIuoqpicIMzNzbvuerlUff21F5977iLP0iiYQEQEl3aHk97hIHJjTeU0VcYCm5CQk4pXnjpx5Mgxw6yur2298+v3uoM+DSsqQ3k+//0ffP2rX/9qdxi3utN79x9sb23GjgsYGcIIwuT4sfqZs8++9dYL9bq8uMiXJZx5wwJRU8fLR+aXVqqSSiiIdx5vqYr53HMv1msz7Xa73TmQZObJJ85HwYglKQHECaKCsHpJX+Bmx9Hkgx9/7LgZixJD5pkCh9MsnCCGjf3+SJPkWrl6N9wrCs+yFjETCoLT2ny0cP6SLMvtdr9w+qZckUTmiSeObj536sdv/4Jm4dHlWslkB70DxDjzC6pWFBWzxvE1hGXHzgMvwXzCy8VbX7/w/ItPPvPiKcC5veEGwxNRFP0EagYb5w6FSUrIcHQga3q1ZkbZUMILP/vs/Y/ev2U7QJD4kiVY2vzZ42998UHv86s347C7vNg0VcOzQ13XVYljEBt5ydrqweqjHYYHp04vNWq16bS9tX4Yh5Tn8iT2GJhyPE0TQLOIA27dZAWO850BZMnFsy8+c/6ySNlRPxCwqFUlwzJZLGWjocqz5VpT+J055qe/vn5n0554EHC6ojIQFVHePti0DGNpwTp3avnC+flqOS+XyMKiGMUba1sftg83ClxJfC7yQkvUOCbJUj/0ozgOn7yw8u3ffX175+Av/+JDCLXZ2kKn04lJrCkSLGjo+yABBImvvFArlfXlldnjpxcqNTmIBmEEZ2bmex0b81QzK4QULCrCzO131ks6eO64VBUyWMA04+1pOu51JMVTcHTu7IsqHxAy1fVZTS2rvGdZ7UPSntp+fzjAPPj6t175/vffcL1Dx+0un6whFwz2Ot291sHOTmcwfO3EU0+eXqGrzuO0wzPeygo+fsTAOYz8QhERM5tiiTx36ajbcTM/CPyJzKSXzjdm6wkbYoh4lmGyLIthkgPIshzH8VGWhlFIIavLKmYRJTmLmbKhHwx7iiQLgoAQopQqsogQQgiZ0gxmAADhb9cjjuPiIkuT3NLqfmCHacjLTL1efuON5599/pxmEklHmMuKnAyGvZ3tzY31B+u7k6zgPXrUjkZZcjB1hseWly88dfLzq6v37z2eXy5ZJYZns5XlxjPPXHDGOUnxkxdWnnj5tCAI9apVL1uaKgb+FAF69uxpzyGAIW48cseDnHg8ykkWW7qcQebp5154+LB149ptvWroFXU0bism5nEShG6tUXrre68r5iPbDS5eOjZbFwydX/zBa2eONR9vtB49ejwcjBEOnrtcf+s73/Mdt2waMk8ZQBtSlaQJx7IUeRfOHQ29PE04XhKPnpxZPGpWasKczpVLNQAYnnGS8DgBp5566vK5Eysbq79cXDqysFgOE5Bk4KWvLPZ6A47jPMy47uTgcGdpufn8C8/oBh9Fra994+zWo41erzPTnHnp9a8cP7NgVljIhrY34JJTe7udo0f0pcW5Y64Zhstx7CdpPB11SRqC2E/DgBSMokcJRRwDvvnWC53u0I2c2apGIyIhVSsZEpBirYigIPE8xtGFC8f/6Pe/4wfjd3+JmqZ18nwdsqnrjXA6RhrSTD1BTmNBPnVmbunIylvffpWkk+FgXdGSAg44K9F0JYmLw739KGTOPXni1a+dPXt+lkmCmaaFUN8N+oyQEACdKGJZpUiQqpqjSXc86vM8UEMA2YTlaYFDWZArFY0Tg8qM0Fzk2529cT+aDJJed1uWvbLBpH46bDlHF1Y0Q/GjiT5Tv04fXL95i+HYH/yD7549dez6vfHO7tpk0hJ4pSYoy8tirVnNUkpyTuHUaqXpTGPXic6fP3f52XO6DJJoIrOlOAgH/REgVGAU1VALkLIsLZXRW9+63FgwH28eJHHBM0jhmQsXjlqzS9VKZbY6M1O2dAnn8VjACZfh9dYDjKPmjD4a4yyLlpvK3KylSrjIFhRdL5WMs5eWT56Zn0x2WMbDwGkftpMkicMIEdnQtHJZnK03zp87//wlMjNbyajXHz+w7ViQBF4UeUafXVjsjSa2M1UU6dSJlVvDHRbFf/j733v95cWMZL1BRiVDmynXFiZnT89fuDB35sQr2mLfK9q+7/se5zh+FPrlhiTwmBSxJNJqTRS1IshCEHpBSmvGoo8DBgJZxs0Z9PTTK0uzpc8/9ziQi7JfKbmi6IYen8bULAmNWRAn+VdffqK/67z9wyuD4eFXnp9dnlc8+zGfNQEADGIFQWAxF8EwTXLPDSRdRQgmmRt6vmqoRRJTAk3dwtL8/3aN1vd9AIkgyizL5nnOYSbLo996fuQHHkRYkdQ4DjEDK4ZFaDgaDTGWa1WhAGNBFFkOYMAnQVarWpcvnxHU3erM3KVvHLOWJEasq67gxnYq56//4fNv/d1vVBooTvojeyTz+qkzJzW5aRjlixefGKYRw6BKScegGPRbRXdUZFF/tFkqLY2dceZkQeIVWahLvICkNERUymu18uvfeMWwzKNH5p977iRmnUl/D5aE6XTMAvboqRVFmwmjtHlE59hkoV6OwvTc+cbFp45sbjY7nTaCxekzS5VqMNeUJv1ukTOKrNCMYoTcqZej7Plnj37l6TMAcG5gSwYW1EKUYdzzHLfFccLCnGbpz/C8JAqaO+oZZaMg8Wi8FYaxwCtzDbVZn88KQHQxSapnnBrCNIn6DkWSzFpm8U/+yUvT6bTcqM4t1p1w3OnvZ8AlIKpJJ6sNmuad/UMPQiZNkyxLyhWDY9RBL0aivjC3jBjseCEB/Mzc0itPNnqDwcjpSzolNOcZzlK0zA+L1GER//ILlxaa5XKZKZekSon5N/+nf5UkiVKdUXVGFlXij+P0UC2jJIyOn5s/fmrl3NnzliW0eg9PHZst6W+snzs8/uSCqekIis4ExiGjaoJVTgXF01MZQD9KHV5AplZLMzD1UkpwHHGixMlS2Rc4BmoImgwGPEvSyPn6G8+cu/hEd9KNkuG5C9UsiGs1oVIT5+e4z+9u378VfO+br9fKlufGCECtwlQs9eJT5779vTemrqeoHALZyuLsf/0vv9PtTDlWaMxqi0tytSFCiCGVvMkez+tpxiIsaLoOceq6LZ4hhjnvslMv8lvdDgegwLOCmIAirlZnarPGkRONMM04nmFAUaQhA2hOR6AAiGBVyBUe56xUJMAex42Z5ne/vfD0U6TdSXlOmZ+3DJNA5E+6jGmais55cSsOd0+esn7/+y93Wvmefd/UrYpVqlXLtXKF51hZlKrlMowei5IkMpQikRU0huM9P54Mx0p5hsNcBuiFJ8+uNM+bwrXIG6wclQ4GvQJiQW88+fJFc+7081tr9SpcXlJruDQmLsnrJBGjeOJ5j71x9/yTl07VZrqtOwAFgIzjqKuqlOfNKPaC8UhgQKkiNef1OMvqM2rZ4p48e/xM+TSv9hePQcSEcUgZLKdZ5g27JWOB46WVZaNcRoZZ/cbXn1uYqwDaI6QoigJgyvOiwLGYMk7uRVEECMUYM5ShJCd5CihFgMVFJnH8ZDLxfRdjzLA4cGxCcoZhprTgePSb7ov8xvez33wGM6wkKiIiTJx4DB/FiTMZJZo8b5U0Lzz0ipShbB7TNCw0tTz23N1OZ3FlUarklLqSRBnMtzoRKzQ4qRIX1MBKRsYYhYQgb4JGgzBPM8OUq0uznucwCIos8tyJ59oiz0qSsHjkwkH7IKUZw2GBYQxJAmke+x7Qyyxn8Fzp0ermdDo4dbTKM96wvzUOnWrFEliehSYqNJZldYsSOIkmSeQlGHNls+Y4jiLzssJ124cTf3t2tskiNk8LAfO0gIgiURSDOC8oAQgLkjh2RjkNsyIETMHEVlFkAscSAkIvYrBkahWeUzr+FgsJKEKZw7IsM6wWRbTTHQGDQ5CRJAlAkqaRYYksR1rtPZSpmmEhzAdxRCGBHBUVpBvK/tYhRryqGCzLF0URJ0GWB5omq6I2HvlZgmRFKkjkeC6EoqrV2ULIYUJxWoDAmY55iKuqGTrRsBizYLFirQAQOm5rOp0KLH/8xLKbDilXD3KOxEPgb5JsVG4sbHf98Yg7sfKEwkjd9lZOR2ZFYlk1SZlEDsfjQZGSsrlUseYRyPx4N85bVVQqcspwLEUoChOAMELI80MhX2SFhOLYc9MoEFS1oapyXoSD/m0COUaSGJEdT/umrqEc6nIpmZY+vnLt3oNb1Vn9ja+/KUlVWdKiyEZCJ44KUMiKNON5RW/Yks2sWhcWqjOOnVPCIBTHaSdOhwxEHKuOB/tBDBrNI5yk7x3syhKuVxUE09CeLUAS0XYYRySqyLzAs5MkcklaC5KwPtcwq1Z/0EmCqaFImJLADTCAGCJIaJaGpMhVWTR1rWUHDNLzXIkCUKtVajNilncB8rxedTwdYy4Lsjbk/Hp90Z2q+ztJzNmAFLWKZRoKIbHAIQiK8XiIiMvzPEIYY5ZlWUophJTn+bhgoqgYTieEIgys1CUiF1lWiDGmkCdAzAueFFQUiKpmLBu4W3EAC9Y0Fd7s745+8dMP90bu82++VZGkq599YJaE1776rFUWw8iLIs/zvAdr48W5EyJvOY4zsftHjs4ZpjKxnYpUQdyQlT0AUOBzRSEJUsHwYR5EWcQlgbq3NZYk4Ykn5hBnF2DM0RIAgMMCx0mAwCRI05RQStMizYtIVlhBhAVJGYbhOSHPiZ3BPM8pKHie43iU52kY+nEcY0VEmP70r7TfrkdfvwwA5ARJEnkmjKaYiziO0FzmmRqh2WSyFWCkKSUmZyFhLMsqUNGdtABLdQ4msY8QUxTibtvTavN8SR/7492Hbn1GqVR5ABDIRN/LsjSoN0y9ovT73V67YyiKJPKuY0NCMYac0mR5Ti+ZCBPPnRaBz0OoizKRYRAQiPUwprHvyXzGQ6dIJqM0Ny2VUlrEgsxVLUNDzNQP98OpoUoqx0kkJ0Wa8hxQFObh6r2lozUAgCJrvh+mScFxQp6TUqlEPW8w7AbRVFRYP3YVQxcEKctJGilh6Ao8Y+oqzwoM4CHgSIYn2OdgXERjHqU8yyIgsoJZAN4pvDhKkyTPsozlAC8ACkMAMwRVTS3HEfXclGFlQojj2mma1BqLlIJyuYwxGo5baeZgNic0LoKYRVZa8FESURSJEstyBoN0e9xNqMdrxDBlkhOY5gKGWeCFAMK8WdLn46wThSOSi1kMVU3KuTCBsykxImfQUMaa5KeQORjEfoZnS0s0ICRxTauIieuGCeY0QTaH4wPPGUu8Xi8vaIqY0X6cdAlk4oCYerNszIZh7E7HECYMS7KsIqt0bLfsaaCKC6SQ/SjmBbRQk1r9/RQWsmnwnMpiJvIngTvkYAVDzTLmKABbO5sUwcWlIxNn6k4fCCKCmBf5JsfOFkUWZrtevKlzZh7zLDYlkSmKIaG2KosYiVlBkgIBVmZENYyDInMDr6eIqCRcsP1hinuYF2R8VBfUPD3sd3bn5hYPOm1W4hRds207T1KREdIwEokGABFFXtJEhkGUFjkpiqIghMRRwTM6IpxuyLJKvaDDybS3LY5GPV4mrOJANsSMksU1BjYnKSmyqFzSFAWFwZjnqSKxvmcDiTrTEBaCypscw0KYQRrneTAahapRjorCjQKWMUytynF2GD3mU4nDYp6CwIkwxpzEBJHjR7YCcCaYrFrXRDV3xuNuh1WsuRPnQBzHia+obBA7YeQrspamxWTqzxy5lOTJxB4VOUzi3LKMMJ5Q4usSnxceZWIKmMBHng8QAqLCW0KaJtRU6yzWAIFpEkzsPmaoKbMAIBZzCLJ5AtIopxQymEtJTEgqqwwvgCzxMcYcJ5CcDBKgKArDwCxPKM0YFuV5FgRewkGOY37yF39zj37jek3XdYQFjuPywuN4mNMszzNAWNeeEpoJgtAdT1gkF2FcxPl0OlEt3rKEIHMmj3ssI+QpC4DABurBqLva+mhvsJ3Gc6pBSyWmVqsdWz6HEEcQNKvG1O2LEicrQqls1irVXodP45jn+YRqmGXCIKMow4ilCKVhkDEMyjPTLA1Griyas5Xm/ua9NBmfPbkAnZDlgKxqsQ8mfT+NfU3LKMg67bDV2lx/tKkr6pvfeF1TeJ7njx0577oBACiLWQqlw3bbDQbNuYWc4fQIYMqpsoaYvEgzDkmSULInfrtn8ywUBIZCXFCS5zHN8iyFLkoqJs8IIkhTx7E9f1iqoNm5462dFseKuqIWBU2zIPJtQaJLy3M7nf2+PZXYUrlSz2PGcxMFa1CCRVwTBCH2cRQ7vo/TAiAmEyWWgakoKjJjqSRLgJ0kYRBEMENGxQjSlJUzrSzTnNq9YZSFig4EZDijwnEHUdzm+aJRn0t8Joo9ni+3W3FOAU14vb6gCO5eu6crs7oEW1sH6TQ7MlcFJHemE4JYUcFCrJ5pPhGVRod7B9NWR63XJZFJXRLIoWI28pQZDiNLLc2U5Sju58SlMPXDCWCCUoUXeQZRmfGo508hLSuKkcKExaLIl9ypByljGGowHddqM5OBQwq8uLCgW2KQJAjTudmmYgA/CqYTF8GKZZVN7I29Q5UzfRuThJc4jeM5htERLKa2nxZ8pTEHRW3semmeSaIJaa5JMHGjPEshQ9M0ndjtKavUSkW9Wp9OHEu3nDhutyYMliS2aoimVSsX4V6apgWkeVZ4UUIBwwsKwwsVNXLdQBOkIqNZMnWdNEoCxAhzzVq9rrlh14mGmsGxgjzspKQIy1YdI43jCghCCCPXGScxlRXOziASJBGW84SPnFiRWAzj8WAoMgYuICwIxrhcKYkC7wa+UhasWCFxTvNcFyiCIM0LCCWrUp+6u2aljAWLQ7Bw0pLFlhvqeLJRVq2E2IOOM54Oq5VGWS95bspZRqszpDhISSBLekYxZRjMAVWTPLuVZlkwifICGKXm0VOLDFb8ICb+Y8yiidtlGBsWDCVMuTwvipLIjKIooQXiWF4RxVwkYZAmScqxAscLOQkiP2RYkCZJluSqqimsUBRFlmVpFgeBk2aRJAm6oXICI8si+A1P1v7m+7QMLYJuaHvIPCErahAxmKE8J0NNGQ2yNGvOLI+/uHP9ytXHzkR/+uzZFy4qMrWPKqXtY7P2FEwc7v2Pb3z4/jXPhgJZVNmjcTzWLLAjBJRrzx/1Lr1wbuWMujNeZ0PHdxVLv5wTbaO94+Z9N4zEYkEtkFWXvHwUJtPpeHyw2a7IjXPHVqpIjMJRqUy9oNsbY6uxkKWlrYnHIBQ5I6e/C3NBUxdUvbzTe3zt1pX7H7m9btbvSabOn7uUnqwcHhx2DLxS8BonytfvPf7R25+tbQwW5leevBB89avPTorClGcF4lpKCjOap7qfVX76yecfvh8uzLF/8vvPaoAf9iemXqIQxYUvMtzmwz1L1lShTHKlXhIRSzvt1aKicqI87vZZCPWSkSfAIeln+wPDbWR5ESPhoONxkmZUmlGaOp7bHm5DQu1eL3DtV1952qjMJ3TqxA7nBIqeEjBJIt73FMwq9UYBmD4sjue5Tous3dohRWZyx3DKB4OBI1ZFWRxMN8o1OYnhJNGDIKvONEJH/fzd9/76R/9OlIt/9d/9zguvLkdswmN/2G/ONFVYH4MiDzO9VnuFVfn+pNXqj2+vxoJszS5eIqDTL6Y1vl6ZObq/sf3zq/dOHjv3/HNzGRxOnf0s8hVeHwwyKETmXOHFwyCQnDbe39hfXFZbsJdnXJR4KyfjwFkXwKLnlgV9FmmDzW5PlgxdnVF1pWDb02AMmKNjmN67+/ji2SfyyP3o43ef/MqzCydKByP9RGMFqwOo9hKhnVO+yDkMeKpaBTT2bKZ1v//Z1VvHjs6/9tKxNBvkWVCpriSBNCX1z65e9XbbMtBefWuBbTzmA5aC2ZxpBEDY32kLzPT5CyUkh13PqxkMSvJJIIdwMcWKgiMF2JkvcBQWoJj4Az/0a42maRwJw4QxcDRRRU6QWCH0gzyvmTOSU3STwy/SmNGM8vxyeSoX8STIOOPAwxI5K6tDTmwnzDAH5PEgDnOycGReZucKkIiQAwEdTRwRe5rEAAfDJMBMUfBIUmu6UclJ1unaw0Gmzr08I6d82s+SoM9GGSshGmN734WRoS+4LqNbBqvRUdoyGg2nG8p5kaUMiU1UaCLMQBTN1GtJNrUsazhI8mCeYxdplE4mQ44rQq/kO2Z/97MzR/Rydd4JFFGaUUFuZGGrH/ECixAKfCdOe4Is6SVNKlCm8jTXBVjqdrvu5MAssWHgIKxGfqjLAgawQMSSKkGSe1kR5oKY0oLS35Sd39ij/sSBaSCLTDIeBD6IMl9WJYgUzHB+Ek8n0/f+119+duuz9Q2fwQtMrJ09cuZo0+xOJ6mIEdXv3Fhfv9/msCoJeR4O271+qax4UZInoRenDzc3O4OD73GvVZuCwSt7h71fv/OXngdZMa80MMZqr/WYxuuaKdhxl5VA4Hu3r93JPLBQ++jv/MGFV796WRZFSikqcK/TTtKA4bJGlRUEKnGyzJcxNe/fO/yrn7774dVrclGyKk1VVTzfno4cTalbvJZNNV7memPvF7/46ObNzTyTPtr6wPcOv/WtZxZn50Gcpo4fZhGAmMPSdBJNev7Hn7zLo0JCyT/7R1/TKzCOelGg3bqx/9Hn7y/NN958/QXNMsaTYK/Xh5xslaogNj6/ubq3vlmyzPMXjNLMvG13tncO2pvdjY1NUdLyjD7e3BUEqVKpRWHc2utbms5SKDCAncLnXnpyZqma+UTVSVEUaR6xHCfJDIEZwrSgdGvTe/fdT/2k++zL9YsXTwbj4NqHtzcerbPllb/3D7/35JMnbPde7CESFwDxAlu6s7n6H//0P/ou5fnkL/7yzxaO/D1Dr0LANVA18A+96VBgGJ7HMRhlYXrY3/7krw4ePjp8/uVXZheeNqs8otykO3m4Pfjg1t3Ve7tffLq2eu/2m2+eW1qSvCIgOCvXSpzG9dx1iIySeaJwFcft/A//9i/f+Oalr772DcSovr8fJ6nCE0mSACAcJ9Rr1XZr9PmnnzTnZ595ua4qzEFvP8HxhfOXR73R51/c/dnPP7h1/9Hf+6++H2XJn/3pj5597vjyMX083UMIsVDqdsYcy0Nu9p1fXf/lL24eHtqNqu6OX/3B7563p2u9VsuH0m6/+8ufvNNdHS9Ul06c/ebppVk38EEqrG4M7q4Ou90pifujncO33ngasWkQZCAhvsfYgX338Z1Rd/OJE9UXLp+t1Gueb/sxVLQ52wbv/OrTtUebF59/7flLz5Vr3Ggw/eTqp0OPPv36c1j3wiBUZLWA3q37u5zC1GaWBuPgcK8dO3hhkW00OJIrsmwsK+pw4qUhE6vlqAiCyG93pnmEzxxftma44Sgv8oQTkMAJUyfvbu+rhiZoBh+FuzvrbF0+MivTiOKcA4ziZZlsrSRQDSIBYovlmSj1BrY9nHhpzAYeZBk+TvLbd+4WMD1xas7PfArjJBpDaEJkuD5sD+1ptC6pSqNyThPFmcZ8FE3jjJmZO9Xtpzvra00Lm41mlvqePxb4QpJxlLqOl3OCSAvJsaM0moR+kSUMizVNUYb9SOKSwIlkiWNYJstzQVEBxeOpl6RxnqcA/M2/PPrN67VyHeRBnvnuaKgaKiCAYSVW0A+73vtX7+wfDNc+O+wMgCWeMvTTkceO7CTB6jQNdLPpjZmNe8O9NT/OojQbzFQ1mc+CpKtJaqVUNjM8mhZ7271f/fT67/zgTaOp7+6vvfveR84ECpxYLZdKVnNnw7GdrmYJkMt0i8+zpAgUiVHWV3uffvrJSy+fiyOSRnHZamLKFUWWkYCBPZ5nNLHEwcraw8kHv7hx71oPx7UMKgwWRCFPYpcUKYckhuMSwnW67d19u9cLDXVBlMyCJBhHvf6jSn0p8n2S2CibIiqAHDy4t3X76vrK8vy4M7l+bePyU7PnL3K2Z2894n/4V2uPD/aufrJuT3vf/s5L84tztcrcYIQe7Ua7O4e3bqzd/OJKFNn/4B//0T/+r//BqN3+8//53V5Q7nd7mihXyuUskkYdt/V4KgpCOIyhzNAkJHEw2W4bDHes+XWzstwb3bNtO8kzXQWIlRCiAKAkpp/f6P/i7Qe93n2MTsxW9MNt+st37z5ea0f0kW6g7/7eqSRzSaZJCOq6urW79d//2/+R47jnnn9ic+dGXiQiL7FIDH0aOwNIQw4hlucQzyak2GsffHz9w9VbahgKX1xbWz6jPF/Xoig4OIh+/uP1e3uHNGPs0dCdDBcXuYWFs7zCMIg4w7EsYIRrU4e7/fnOwxuj/cetjbU8Je8/8cSzJ8809lq7AKCMpiyn5gVQRGMwCN9959pf/vmHp0+f1EpfXTkhVapcUlQwEK9//uj656tTO8xo59rV67Z3+Paf3X786Pg/+5ffVXTDdYeNeqnRbCRxNuqBezfWYj+/eOGpQXdrd3sXwad5TvMG3uyRxY4dw1TSJNYZBhuP2icvXwaF+tkXO7/+aGf/gKQZTsN26k2PLM+ePEn7fUdhS4Oe9/H1h7/41Yf93iD+zqWXXn52tzWI4lhR5roj75c/v/L+e1/0e5OYOXXxPLfX777z8/d+8uNf9x3iM/wr337CKjdS6ohWYci6JMwq0tz1ax+984sr06n13POnvvryE0XGtXZ9xAhjDzq+OxjfDRLXi5zx2PecqGreevbS/PnzMyqDp57LMjArJC+j7ji1ymplfra+3Bzv3t/fGwKeEypHvELZbbV0wYwiaI+HnYHt+o4dDEfTcRTTMIIw0zVNgSzZP9iCbNIaHF06MltvlC2ttr42eHS/nYRmXLiPdz+RDeYbX5e/+txxo3Q8nh5OPeZxa/enP//i0Z3rpxbNP/xHf69ekeK8D7BvqJwbuYETUE+gPsKF9etffbqxvnn8ZFORn2o0miIHp/1PMcfAAuUURjkhkIQUTYICkoDn+d96fhRkBSVA1Y15KGiW5ceJZFQJUrf29z+5/sC2k4rUiDTqxWIwjX0x9eMwY9NMymOXfHHl/t7jMUg1icenThivv35yYbHMiKU4BZY19+FH9z65+vCwM75/a/viE+7S3EXP/YBCbBpyFhSDTpcEBUcFXsyDcOQPh4CaLEaR72EpEZWsUllgORQHk1G3RwIAoAIxE0UJw2WYUbrjePPh7SsfrV37fDOJ4WLzFGDw/5uy/+qRLE/TA8//0frYOaaFm5u5VuGhdUZqLaqydFWzu5qqhxyKGa68GGCx2PvZBZbLxQyHasBpNluwu0R3VYrKzMjMiMjQ4eFampu7aW1Ha7UXeztNIL/ED+8LPHie/ng/8MyZUnlxIYVgvqObXDyBh7E739xutzQEzQ76w3xWPLc6ocnVkUp4pstiAEZIlky5ptip70ldPzmZZ1CewCzXMwvFadV0n6wfVGsqQU32+oemD5NCLMSJWl/53ReV3370NOxTDB9RpGB5suUaJye1h3c2q7uK5EACHwNO0KnUKRTnCRpEYWgBNgZ5zjj0ramZTCpJJrKIE/V8NwDQ///TjkJggsiFAeE4WL9rbqz78pi0NQR2sUJywpLgKGrYQYTC1aePH165nk6mMoFDmiDAeHtz91G3q4uJ5FBqz8zlP/zedYalbM33LMQxT/IFESbTro9YHuvYSH/oPHt2DJk3TVs7qR+MpUnTivXq3smhufa4OYIDFmcJLJGIYThG644VQRaAI812tB7Exop3bj//X//N7wKDTHI5lp3f2vvkbz76nE+9DWM0FHpBaFFEiMBUvXb6u0/vf/a7J+Mx8H3eNKLA1SDgcWRBGdmHe51KpR9GRDqVRSGsU++XCzf2Nutbz9TvfP8aQ4/DwCVJnGXx7Sdrju6nYhOIx4OQw1FOkgck5eXTE+OxNO5rKJwA/tixDQSJhU7Gcvr37q3t7415bpmkeQf2GBYhGAwnfCZbSokL69sPN59uwx7gSaRRG+1XWgiCeG64vrl/+8snu1tNgihOlpYVy6oNqyTcb3aGAGRsw/v6y1pp8cLbl+Yt0BzppyHERkhy7XH/o18+e/igxebCjc1aeWIum0wNut5po3na6I9lQxmCAHFMz6Bp3rfDnXuPRycns7mfIQsJR/IlzUJRpjXyHz15LCa5D7/3TgLFkukEsIHhw42+vnbQ+PqrtX6tnWRzsqSONUVWpQACnJgIAkzVXRpBY/GQpD03QurVWr3b/h713enZS08ePdrZbu5uySiSEeIxWaIs1w4hGAIYhjJiYaE/hp/ePfr6cVXp27LSBL/8+B/+/DuphBhYMgQDnIDcCPKikCfT9RP1iy+ePnn4fGpKHA7GH7z3TiE/NZFO0TRpGMZAGjsI7vuojaCJdBEENIKhANjfziMYxxVZ6o9GNxbP+iHsgUhSvd3K7lf3nlVrXYzg9ebB1PwEZ6KNZsd0IDekUKaYorKN5+6TJ3u9voGS8bn56TfeKZ+/mMxnSc3icTw+HoVHh6e9Tosm+TSXWJo7t7PRPNprG7IFQjNwDQQYA6mGozyXoCby6Ua9Lwrm8vL8cDDwfH92duXi5TOeY9BEGOcI15Qs23JC2PBNLEbhUOpov3X362qzoQAMhIFphYMb124eV+Vh5xSBFT/sAYgJYE83xjDK2y6aypSGIzuZZP/JP/3Zyy8XdK1i+XYQel6ARFAEE6yjo5LqY6jYbcphMCidS9AcPBpDOzvWoydVQCUBTl279cp3vvfO9Ez5ydqzv/no0bO1nmEQE7HcWKmMrJPJWXxyhnu+/vDLz78mIbHEkjGGiicYQ5farRbP4uXpWd8HfsaEwyDJM2+/+UI+z4ppNCT6CBMRLkaScds3I+B5vgsgRJXh6oHRaOvxZLKUP7s8t8Dg8Xa70ewZIUaTESWPdNtEaDIjW5qktf1AGA4tHE+fnDSmpuO///Ofnr+YM3VF5CaAH+Ex24t6ytDWLFIzhP4gODnUXYXXRzpEqjivERQ8Vbx8svXkyy/WcFyEI1VWdAqGziyvXr18lRe0niTBGJJJ5gw72N3o7m2MMolSwJr6WGbYRDw++9FnX1+4MX3x0oxrqwBANEO4FnX702/ufP3YDdGpmbNBxNdO+vGk4+oahucNDW7Wx72BnkolLl++fP3q8vbmIxyKo8D5+vMjGObOX54RUxlDN4aD8Tdffw2HUa85OrG0S1fnXr71ghCDZP2IRyehEJYVZzBwfBdAsG+6QX8Ef/X1o0arRVEoSZm2HfqB5kEYlYB9gBg2PK6r+9WhIttwGFE4iVMihgkIjO3u7X3x+b293SaOJjEsqchOiEsIJfFs5HieosA4nOvVyF/8yaFRb59/IaNHPsPQjs89fLC+vz2I0zEHhWPxwnFVvfP5XrvRUnV3JFuWE9I2jlEghBxcZERS0ENGqw33v9lYmH+VFVMhahwfS59+tvnRx19PlJLJ3MTVxckkA/mOz8RSz/eGf/Xr240TzVZciRhYjgZjAUBIBKZIvEBQPMOG7dP+SOoilC6mIJxChZhoWdiTxyd/9Z8+4ug8TQqOY5smRmJJFNFsy4JheDiSYZEzbExWo3iqxDOxcWf3448+euvlM7FZzjFNFEICHyJIhiFFkkk9fvxQU91iqTwa14+OjhGMglFMkTXP8wAAPB+PSEZxI0m1XXMsxqBxfwQA8+08CgJfjAuxGNbXbc1wPA8ZKdrHn3x19976cGSyHLS6knr9rYvN1kj9YhNDAwyLkJDWdejeN4+rta4PCE4AK5enb716nWUNDI8CjR+O4a++el4/Geq6Lnfqq2cvU0RQP9xBnCjB5RA4WFxKnr+cw1AQ+PjE7OxsuTTqdULPKE7kZHUkG3Iml8WQ2GBwTCMST9IQjPkQcOGIJCnTjerV/uefb22uVVEsDDGvWEy88uZrZ8+fwb9Sno3kYW94crSXSoskmcRR/Omjw4NKYzSOSIK+/sLFxeWEa3c4JvAkALmBZpkIGqGEc9LsnTR7hgt4kRPj3jsfXJhbmq5W3eoR7vhihINYVnz5rdf8SPiX//K/7GyvG2YQ+WFSJOrbd6aXsi+cu3X5haVSqfTJ39wZ9kcsnk0yyIu3LiydmeZ4EiMpiorhWMx3kTp85JsWRyILS5MEaZ12Nhv9fSFJFcJFkiR93w0jJwRQ6EbDbnC875pmdzhqYEkdI88YBqapGMvFAO1aDb7fHtSOB1PTE44/QKhgJEfrz2XX5l2PuPHCzRdevGxZx7ohJbg8S1J0MqVaCgVxqYmlTht9+ujhwfNTYGAAtt1AZvBIluzbn289vHesyp5pag5pYCSOhCGAQtd1Fc2yQ4giaG+I1Kvtv/nL+9XjAEH9EG7nc4KjDNP5hfWd39Tb3VuvXEQxgEIAQ6Dacb9y2BmPdIzJaKo13KteuzZDQPEo1Jq1iiJhYYCFEUYydC6fSCX4N1555X/7X/Z1VXr2pDsay52+9NZ7LwMEv3NvY/+xF8AIgPrvf/+FH//s9eIEjUABAy8RNI1a6NLK+bmF/vbjh4tL5euv3OhJ1qMnR2IiyYNgOGhEkRBBhmYFERJy8WxtX9tcPzxu6hCMa+p4Yqb4g5/9BA6E27e/evLk6UjSKIKFINRzjMDzao1KEF1ybI+jWZGzpaFm6dHh82H35PH6UertH19eWLn4+E738eNdz8KSXA4U0Lml5WFNWVs70DU5iELLDnEylkkACA0QkkBR35BbeGQlOcw1RpquxxNCEFm7u9W1Z6e+k7JM7uOPv+ER+NUrcyEijRW11+uBIJwuTcs9Te2MbFchkJDnxbHsHB9VcUoAAKyuzBk2gtMEQLXS9MXLF18dD+G1J0dxohgEEAzruj4cj7EoovI8n02KduDYum6q8trmcGO9OR74cKgTOPzhm5ensxxPIj5IUDQGO5EHMxjOVo9b7dYAgjGW4Ri+kC+mA8jQjIFAC0NpDEBAsQwMuRTFZXGmL6miwCMwAMD7dh4ZphK5OkEEsg+LQsrUvJN64/S069iewDK5fP73/5sPls/knjx4urEBDboDfWxzxCyHxhqdrwg2lmbpudWJ2dUcKRCuFw3aer8G/uavb29vHXkR7jl2Js1cvTzTaK5Xj24TEJRkM7lc4ZVXFi/dyjEMFQaxnb29g51T4Lo8STQqAz+ycJ4BEZZMJn23Mah3BraNwSmMLmKxZBCGJBfbOXx8XO96EAQTYPXMyvs/+O5rb7317NndSqV9uKPMFiYTsUnblsIgSGaKx9VvAEQ4zhjF7XQegeBxu3PAEB6LzWE0b7gmQiIBgE7a7cag78DA11o3X5q5cn0xn506PRq02zCCJr1gPHVm8uDk5KvbX1a2tzDgR5Dp+EZ6PvrD/+H9mYWFqaUVPp7+4va9ve1ejBFMVY5KxcXrZ+NpbjDqpvi44kWV3QNpZEOk0zg5gXxzI79766UVIVvICkEQmq5r+76rWzpBAZJidM2rVa3DHb3ZesZS8LUXVyZK2W/ub9+723B83YcGE/nMQDZPDsdXryIUjSOkubdT3VqvibGrqiYhCFKrVwBo+rZRqx8n+WlbijyYsTxgjeyN9ebvPv5drbKXS7OzSxOyhnbGpw/uHx7uDZ58sxbZYGZqWogxo6bkK5Ztqaenp7Rl43HUtwAYRg+/XO/VRpaMdYbbP/jx9I+/+8Nf/cnO80ZIs0Kv39cMB0fgCPF1S93e3nNMyHb8ELcjFIiJRD4/kxSZkeFM5tOPGo3Tk/p4JL31zq3ZuRKIvOuXL3kW/+tff9HteqajPX265kEmySC7+7uIX1bMoyvXZ3/8d87ni0btZD9GZQqpqZPWvo2lZIupdYfNYWf5Egez0P5+rd2MxBSMU3YIdAjgAAo9H9bMYKh5px3jyXZr/6Bp94fTM5Nvf/ftxERuf72xu17tNUcwiuAoCiInDDWSglqnnepBY7GU/s67H754CfqLX3z6bLMTQJBpil/crkysLMrG1q/+9N7B4QlmQjAjvvf9l7rV/ke/+3rQ7MdFisSj2aW5cnlxNhehBCAY0nPh5ulQHcVnpthrl8oACh3HPjmpbW8d+BZZyi1GkLq+tnFjdVWZ9zKxJI8hU0WQjTebpyNb0VHILhb4TIFO5QpHFXX/YMSymOO5iYT7k7fevnBlQnf6vgcNusj9L9bWHh5QrhEh7sVrUytn2JMT6ehAMxXfNSTDEgkcCQynUjk6rdR1iy7n2e9+8N4//F6B42nHMSCEsizY8SInAqOxrBuCICZYdiTJ/Vu3zr/40mIEaZKucUmGYAUMhVAU9sMAjkISRnkcbZwcoygKwP/+xMjf6hHHUqZiyMOBHKC58mKte/p8a28kyRRBcax46dxZnCMfrz++9+Ar05KSCZGns5ZCn1bU/lAbqApKO9lSjBZBe9CKHGxn/XTjG+fxw4rvQYxAr66u/vT33zhzbuHunQfHR1+jcNFQkhgSX187+ubZR34IY0ih121Fto2FIQGBYiF17srKTDLPUvHTRm26kMO9Tuf0NPQ9hqKEVHpkmX/xi1/99V/e8TQqKSRDxF9YXYin0//uf/0zEPSHPRsOcxw5W8qvlKfl48r49u31tbXdyvFpBEMrFxfn5jM0HUYuCAIvskOKpgIsBARkul692x4oUoQQ2Qx17uwcDEfjkd6sS2vPjnwUP3vu4pf3PuExAbMJRydJBp6fK88tCxcvzy8vxrZ2awf71Jmzs81q2K47MTZhKdWaJv3Z7z4S43QAAlU1mg0dheK5zDQ8drc3dg2pB0OmNXA++OHNcum8HaoMYhqGpVs6juMEQfUNr1GTTo9l31cWFme//6PXl5ZKDx58JUl2IinUxru94RBF8ePDYacRzp1LGVHl+GSbjdE7G6d8jChNzcRijCQ7EfANTUb8AUbzqXwyMPT9g/7as81Rv7M4U3z7zasLZ3/0r//Nv4cwvphflKSTZqfDE+DVN37CLRf+7f/7P6hjY25+anpmKqJlIs2Mbeuk0j7Yrjgako6nX37tjf/+/3wznyg0duVPn+3E4olOf9BudRMihmGeb4atZmc4UKIQiqcEFMkZMqjXW40TTiDoTr+Xy+WiCBIS8YtXLohxDvgqjkDTC/jFq4VnT0/XN3foERGgsunIEAI4lkBo9u/+4R+dWypt798jCAbAxmC8F4snfJ/IFgpTc/P1k3WA+Y1B/c9+8RdYkB+NGlOz9Mx0fNCLQsXOZPIJsdjoNr988OzOk643cknXPXN25er1S/fWnz79661mp97t9ianiu+99y6MoLe/uNdstpLlEgZiCa5IR3ySwX76s5eE1OYvf73thlxA8xtr7T//xe88FT9z7pxcHV6+cAlC/U6/EwRBoTjBs9HcwsRrb76DYmwi2U/m4giGOi4GPMqUJdesUbzruZbqO4d7+yfH9dCfDyFa08YIRlF03PEgxw5cy5wuTbz71qtffPL0SKpcfeHW5Rszcys5lGA++uhZ6G8AhOl2myRuTJV4hnUB4jUawy8/293ZHFFoLEUzxen4T39yy4O7f/Fnn/u2ylGxyXwWwVEWZ1GSIHAUgSICDQs58YcfvJ2gnkrDkRdBEUSptkOw8ZSQUjXr8drRgweP+m0lmxPPX1h6+fUbYaCNx/JoqKbjgu9ozWbbsPQAQhGGZfg4R5F/W/jov+YR2u2kmJBOhQwSO9pa//p3a9XnVTIQU6XcdrX6u2ebJweP8oVzDHUzlR8N2v10Tgy8nX5l1DgZhZ4pxHgSF2sH5F/c+0bkwcJM5kjR7XgdQ9uLZ8988O6Hc4tzrUFv/fDAAmdVZXz2TLzZerT7kVwoTLQbXQI/CXBGHjrZVDn09DtP7+pQNLO4Om44Q22PwTKKAyfmF0GEK2PNao+O9geb96sERCG8r0JNYBKffrz/+K7W7XbD8W4qk09lhwG329AXg5aoedxu7WFouIvT04qpvf7a2zAsbm+fTuaFdCIt90NdNQfyaGp++t6do4PHQwESbL+1tLiwsJoREvSDLxsf/fZ56OmG1lt/sJXCZQSjQoRNlNOzc+QbL5ZuXZotZzN6uyV4PTyi7n725598evuwWctklgLsJcqgvvmkSjFuLpOFfFodAMca9aAOqXAQCi9MzV25Nb96tewS0dh2IgSxFRfG4GQmCyEESWYltf3w+T3FMy+vvPr7//w97kJhsxEZVrl9sImy9cuvse5MaveufLxmVne9iZWFAIrr7SOoUWUI88JFqjxtsFTZs5fopENSyHhoI268ctjRTePBlxsP72+ySRGbcD74766DVjgRT3njSK4KVpCOx3Ovvrs8fZMbjOuIR8Je3nEsFz6CcHs8TB3X4e07R/WjmFA8e/O9KzffSkuIXD/oITkUEcyhBN+5PXjvDTBVjDna6HRDrTyO9FG4tHouv5xZf/gMGGF3f1m++gEoMz2zubN1FMHW8mxuNptxVS2Khkao0OzE5Zug0TvhawjwM70KrjlmZgK0wN7P/95PFq+mhtph6IVirMzFEC9oAzac5cv/9v/71XjrZF64HAzgT//49gQ26lH0pWvz5y5OAAj/5qtqe3gShHSvHz6/V1EO+zN4iEww3/vwn9166cr25trjz+/Vx23N1y+/+Mbv/fwPXnpjeXt3f7PWrukaDHHNpjaRODGlkySfZen8yy8tK2b7ztYT2yI3H0aBC7t2+3DUeO3GS3/nH7z8px/937a+3MPRSSOk2m0JjjHY4y9y6RjUgWbDOUpgghAlgFPK8nn2jN6vGigT+YSlkqOGBTv7YjzgUTsmoFMLTMC7GoOiHoKo7vUy+9p//4LrLAQuLkwENlpp9Olmo+fYVK9fnZjCrs0VJ5O440qaAd+/63/1ucNxVMg9n/9w9u03XuRjdLOS740ZhMRJInB1x4uPjSi1s9auVTBGx+cK8HsvJwDxDAoFEhVsR+8ZR3Q2ipfjqiLKw6XnzzYsByXj3vKV2LkrBdeRlMGIoVjP7svtgeW7KEll00XNcXwQxRKEBWicgABQv51Hrh/6tm8AyEax/YPKk8frhg4QHBsMOxMTyQABlu9u7+6YnuU5MAoQgGKq4e1WTgGACZwaDoe//Mu/8h3a0Jxsgvnmy698KIZgjXfeOXNh9WyRJ812e+3ON7v3n9jGHAYnGqeKaUYJscjTSVtAAIB9XMFTqG01QKidu5C7eDFPkiPb9nk279owScRAFFqm53lIrX50+8vHhop4DoXiOIMhUQSPesNOfQDDILCt3uEhFAVnLl5gOdEwbNsKRD5juodjRS3Pz06WphMpyrU9zWyhmMfyJcv2YglQOTnd3NtpdGQIIr0IWVmeoghiNNRbHclzQwRBOJ7yQ9U3YJ5jJNN67fWX/uAPX40RUqB3a6cNYLu5yaXaUP3m4Wf9US0RF1iC8SLUkVoTCcqyxp3KOkPFEB+QsBZPElRO5eLkxauFt9+fmZiKq2bfdjQAAxhmXMdRNYekMHmk7e1UNU1hOOLSucm5iUxkOrc//fze17sIrl+9sfyTP7heqdhy7V6/Zu/sbWe2+fagsr9XM10NQM6lq+emZ4phGKIoiaEAg4NUQnAdoa8ON7eOtzYqUIhQGPyj77+JRo4LFC4O6Xbz+PEzLuklUnC5LEzPZj7/N/c7nQ7qcWEY+B7kalGzKz9/MtzZOZ5dmoF4Zu35o3oXKuTQJIPqgzGOQRFNoiBot+rDAdKtN//Tn9zf3wpTU8iNG+e//4cf/j/V//Hp5+tra2tCnv3wD7/LM/FGvRMEwcqZBTHOCCIURmyn07VCe3llfrL0T955Q/3TP76/ubHHxXFZap1ZuJTJMo3GgWl08/nJGBWXlA7NEmHkDYadwbDrOLbnwZrq274qyVoyznz3gzevv7T44P76L3oPIAgRYonAhTwd7TUHp6ft0lReTDK6YVSqfcflTat+4cK573/3vTNL6fFgX1GaYRjWaj3H8B/dP1qauJFLFnkuAqg2mcr+3s8/XDyY+MUvvlEkjI1nJMVlKSs3RWHCWOQWaHwwlEOCw5NCJnCQw+3ullnx0SjzqB9gOC+w5ZI4zLNano/hEOJjNMX8/k9/Ukrn7t7ejHP5GzfP5CagAAORY9iRT8AkDNMQAgMMwVDWDNx6T6LisZNTdW+/3mrpCGrMTs8uXZwZyDKbZTe2Nn71N7+rVP3pUn7l7OWXrr/IkSlFApriowjFMEwIB0OpnQmnIi8yNHM4HPZG3dREnkvEKIHvt2QAUwBFzl04r4btRq0GgkSzZowGw0I+63rB3FQ5xtCWpopxTpW1AKEgGAYAU23HBKYbRgCFR7KhOyGGR3+bPP+V/TWARpQPoq3n7TtfbrbbMkVxoS/JphYHyZE6xkPPUDFOiKUSeZ4SSDY2VIzT9rjXH9ExmGEpSdFMzUnyE+lYzpatc2fi5y/OXDibT/BxgcJO632t0R1WJJseT88UvUCnaDaT5oPAEkQIw7BYPIlATCE3efHC7Nw8BcHjIGqI8RgET2tG23Ej03RoMsGQVLu1dlw5wYgzBIJZuiX3VFGMxeKw5PQgGFAiv1yeHw36puvTjDg7k3vycGtr/cj0dUAEV2+cn1uahoBq6Ey361KAiWwcQHAiK+hO4PiQkBINO0ozE/MLaRDB7bZ5eNCRVcPx3WIhBqGgfwiNhyMPRRWtY+hSWiCHPdccj9N5CocESIG8CFimqgyiwIxQGGCR4RphOk7SORFH+EI2t7w6MTklGHhfEKmYiCXTEoTIBK6DwNZ105TTEQSHIY6jfKdhb21Ue/1WOp2mYSWOYZ2OVt876XQrWVGYXSwkxGRYthOZ8GDveG0DMSJoMGw3TiQSsa9cLV25Potjnq7rSTELI6Pu4MCxIyekj07bR5VBr2PAEH7uzMzNSyuI33nwdOv55v0Q5lByzMSQl944e+ulc76nYBBH0wyG4TiJAUA6ZtRruIcbw91qNxsBu7ev2SF1EONwWKTtUe8gEuYZErNMe3dvY2ICBTYxHjkEyyJMTxAibdydnpw4Fg5HPfXjT7/smeqZ2bPN0xaBo7NzRYKJBJGkubSYhJpdLgKuGGcFMUrGE/lsgeA6mcnJf/KPfsbxeBiOEcw1LQV4hGEYuiUV5hKn9Ua1ethojFCYI0zHA6cI4V2+kIVgo9etRoFNUwRDos3T7m9+/YnT8nFALy8Wf/CzDxgB/lf/878+rZoYmgMQydLc2pN7f/Vn/5PmnWJkrjdKZrPTMZLs1DQ4ihcnyBA67asNFIDJ6UUufrZ2JFWOgnZPNg331kvLN15fcrHGlXNvnh77dx+uW1oXRhDJJ0mUtvQwnZ8MlNRpdzDWd2lGK6SiH77/0s++/x1UdaMoEuL0B+/fuHntPIrxJO3rzjEKU0GkW6rsQzQKwThChwiBYLF0kpEMzgX08clOFDLJOILgZj5PMDnCDcjnm+0vb28gOF0ss6YNcKy0tzb+qr/brvd0OapXujjuEzROcNGwITuq3qx1dMOACEjMx4Vc1oVQFyC5bE41JSv0R0PNtVAGi+7e/qTbbsKw8eabZ1+4chW4nmlpBAoPh/3RyKEZhmRiMBowYozDsRAChmWGvudG7rf+10IMMT1E92lNhgZ9N5kuqqoUwXY6TWRz5PxsOSYWtzeajebJsA/xpZjnR5Va57g5ZHjOtPoE5eZTCTgeN2XEUp1UfLI8nbl6bT6bhmg4RqCJSuV5vT6cmZ0eAOjMhQzPF2DIgpHAta1MZqZcnnbVyDLDycLEzHwigluWY7MURZEETnNMLDEc67IUuhZZPVSeP6mZOkpEZiLJJPmCMpYIIkhPYB4U50RuMGJtMzBtC8VFDKOikDipdJ482oYEBkOiwXiwtbUhJkjXUY9OBrtHJyk2ymbjts8N+n6roWo2Uu82X3rtsusNLCPpmNRYckaKjMDhufNX5hbZw2/k2/fu+ZFZrez86Z/Kb758YX4iJYjQ2Dke9u2Hj3qb693QY69cXLh4oZzJe5lMznZ0EKEEmiKxfFxMZXMMwwfj8DSZZky9oygt1wYsSUAAGo4kFEeDCCYJ0dTQTtNRZNcPLCbmXrmwmCBSj+5VpIaDIXBhOnHlyhU8Yop58qXXlpu9rq4E608rOEzQpDhVQn74oxfm5hOOKxs6gUK0aTW9wMhlJ2rDqNcfHRy0cYybmy39vT/8flK0R4oSRYSsqEEAURyYnklfPL8qxuK9TrWYW8qmBmgI0jmBwNlay2wdmd2qE8tnVXcAEY4QS9tjVB5EMBsEdugSWgBwliXefufVM0uzd393YDq4Haq5aXxikhk1j6+fXxme9h882OiOlDtfPzH6AQyQ6anJQjGOEZ4deFK7HwIrk53WjE61Wr19e+uk2jcNLVXAfv7737l4odRsnQA44AVhPDR0W43FYhEcjseDwcAKQg9AfiIpUqynGIPrt87/i//uj1jBanb3ZKkXei6JM4PeaHNrr0iskhz35ru33n73xSfrz/crFRTMMWQuBJXKQbXmI6N+U7VsPjNEmRwCo4ZuWcHIcdUQIKpuyLIFEYpi1483qqeHnaMDx42gy9ev/fDHb0/NMMfHG4nY1OtvXUkW8N5g0Oz2Ws2RZiqjkS7LWqFsRl7AoLijYTvtejFzcPXa5XkG831HUkdeYJNcAsOA5csBYtEBaXo65FshjAA0dMPI0XQv0hDPiMULx/vy06dNy4ZjPJkpiMUC3VJathH//PPt6rEEA5RhUTqRrVSGldqWaeqOHVCYIIq5MJI8YHuQFUOTa5WD7a2jsaaxaSFXKvOJnBeFKAn3FUczLT1wwojJZYrtE/vZo0eDXgCAurp49szcynhcdcywrvYVzYG5CReGGTYuMmQqk262W6f103q9Xs7PC3EaAOXbeWRHDkaJaMAMutVWY4jT4fKZ0jvv3JqcTILIMi0VZko0tSb/tm4oI4EjMASuN7sDSbMc+/0P3l5cTG8+36zsDEMXdQyIpulff7qWnc5MTJ8by7bZN06HVm1k5Qvzg+ah7zrTpVmCCkfDTrttHe4f1U6arozt7hzNzc38wR++O7fEhSDmeqHnRWjQhBADwwMcI/c3e59/vFs71pPi9O7pxvxc+srVudniDYpySUGFKJvmkvfueH/2J79wTOfC2XMsxbab3XarH3nwuEcwTPzB7eP954NCMWl7ykBqj5X+RK7yf/wX/5TnUp999PH648qZKxdX8+XzN+d4xtZl/6Sq9oZjlAaz5dK1a+enprAC6o31zoPNNVUZPX0yVPu9H7338txkmqZmSTLWbfX7PXh+7vJLt25yrBGEx1x2Ms8x9+4+2nr+eGLibOBXdw/uB9Dov/2jf+rbhOtglglo3I84PB5LTU/ENZ9zPBdDhb3t5rOnR5pqinH63MXSpWuXmqfje5/u1Q9VmheWzq7Mzy86muWBo3OX5xoj6eO/PjXb43i6DFPMy29eOHdhEcMN4AWZVByKEMMIERj1fX978+nxUWXUH7JUolQSWNYfjVowhmXSy5nM3uFBLZZEbt26VS7PKEOTQnKjdkuRjWyGiqUpVTefPdxbf2hp3cAI+wHUxQLgGDYDkdNzCynRhxHu0akceKg87k6V8xhK7+0PSCYOk/3rr8zNTCVDA8Ng/tYLFxq9noMgEUSOBuMw8uIJhqYi3ewBFNG1MQSHTtA3THV/t1Y5qFqmm80xb7y+evny0nBQ810NRi2OpclsShqhIQRSmfRO5QRFuXK53KzCBImEkQ6j3vWb501j0B/VcNK6efPyyaH/67986PjmZGFCOjEuL89cf+Hm47XHv/zlbx3Hs1yFJgyaAP12HzZoEk3ESBgHcRSiSMwNQ3+iJCYykB8alkmgUAnAyUql9/lvjjotX1NcPsXOz88GPvLk4fF4aDXA/cWlqfdmz3uhMxrrnZ4Z+OxobDaPxz7Qd4/23DEUuQzwRNuE+uNGzNNwnI1nU4Nh8PjZNkmkl84WE6mJsCdzFBoXkzghYkjG8YiR3NNU24Msip442O3Vj0edtpxLQ6+/uThdTo5guDO0nzyqDgdKNh23jDECKFVxULTPsmwEg/FIYRnEBdasEJ9fWRSRwrC/3ulIMEHninmSSxxVhvau5HVHm5vrqQx7/eaZxeWyZTC3b99vtroIWZwpF/O5kmPBUcDYJtXsqyQbPzgYtFotjmPKM+Xpaeijj3939+6dXq93funa6vkSCma/nUepiYSs4MfVQbVajycT8Qz+wfffvHRppl3fgQIbDw3HVwnIgTwlMBwWjXAEKNLItByUwFbOzH73gyuLU+LjzNGzR7Vms28AuitHf/27hwBzb1y8gXLM2AjMAFY9AIL480e1bkMDkeO4VuD5ve4ocAMxjlSPG5qpnd+fnl6+QXMpWTJQmO/3a4bd5mOEKM7qmtKsj6IQtSzr+otnXrg28fKVYl5IBIEGs7aPIr2+MTg5oSI7DFxbHQeu47tet9uHUAyxciKVGnb77Uq7c2xqtooymB8mTGO9crQXX4mrfYvDherR9oVXShcuT7mttXrLevTouNo4JXB6caW8vDAf4zW8LH/vwxdwAdx5sN1r61Jrj4r8n//eO2fL39/beDYcyKlkOgLwnbuPu52TwBtNrlgshx8fV2r1ocAPQsiVjCNW8P/1v/qP//gf/+Ty1UmKikW+5NmGpnmjgQyRKC8ygsjqxnhj41mt0Vk6L9566ZwcKV/e3zjYP41CbPXiws1XLkbAMUYymrDjCeH6i9c//WSPpIBlHJt+O196r5CdGqpruikTEIlBHMuSMCwYqnta2Xn+dC30GdvpT5QoFww915wplNuNNEkJuXxw/db0q6++lEzF+72xaVonB+vtdldIxAPIbLSbjx+t1yssi84V5xPl8hKGBAwlrMxenistGNpQ0zr272r9nrK1v390tGdo8MMH+57rC1nj/LV5NPShEHINbWGh9O6Hr/+P/6//AIWIBTwU8+bnCoWiqFsdz0cLxUmaprd3h3e+enJ80Ot11WRa+MOfv/XCq8XA67kmgMLIsU3PhSlSoGjS911VNWJ8JrQJkpDDMDg5qWCUNrtET5bSDE1wQhLAqqooMZ4u5NMACSNYGlPh9JnZoar+5je3ayd9gRUt3YKiZqd2kODFXLZUmpjiEoFkWsd1q9sbTJSFxUU+niR1U4sijqYyPTna3tquNwPNRHIT6dfevfL2O9crRxv/27/5U6lnrt4qyq6UTtMMRZBMcmahRDI5N4S3Hm0r+qnmMSBwxgZE8/FchkMRySA0zfOkDvT0UeWT3zzLpqcYgZ/nKAjAQRgAz3dcBQY4BOjQtQgEpBPi4W7l/pcPPcvGYGdqeuLWzUsMJx92ogf3dlwdygoFBvGdSNLkKgAIgnaKxWUESVQrqh/itgkzsQRK8K3GuNOTLR9GSB7G2NOT8eHusTQemf1+9fSkWKI1M8KJPI4ye4cjgknbAFcN/7DS3dnalOQ+RBC1wYiOxTf3q/v7+zxLv/hikIxPDVqm1HdiZHZz/TQI/cvnv6VHAPcBhhgOqNWODWdECJQf6cPxiefJAgULcQFNTnSPW0kBs4cOFlkciXIMzbOcHyqGNXbtQTwOvXxrcbpY+uvf3Pnq64fZ+Vd7zdpXn8tT6cnFucvpeILCiMPdnRifVTTV0NQwcjmG51iRI0iUIULicHa5mC9kGYFwgKPpmuWCYiGbySb3jkxZHphqr16vS0qfZckA0heXXnvzrdUsH8r1U1XtU6Ih5qZQwAxPPkFNDXN8Rxmp40F/ONje3lZUN5bSNHUYeEroShjiMEyIUESIwulMwTVN37VYjBBosm2cxhNzEDCTYsYycRhquqExGgwUrSvJY9/RkwlXzJYwgR1I8PqzU1cf7+4c7+3tXrv8Ybe70R1sWg5tdC3f9yiCmi6/YA2t46NTCEVKyUK/r/qRmU0mEELhaUdgQyhSZbkFIgtHSJIRGQuTDSiKIgh2pmezs/NFWZMnipnCRFLFumOv40A6IyLLlyZnVpLAGjGkHU+mDYyYXy6+/f6Ljz/bON3dC1E3RMDx4SDEbI4nCAREgYfAURhBGMKtzJS/jB5Kup6bLU7Nceki0+9r7ZFdqzcbrVOKxBJpYjCu2u6IIVOKJMOAj0IYQDZCOCHk27Yd2CTKQpcuZb77/k8wmOJYVBQRENmNun76tD1oy9WjdqlYjifE48OKonqer69M87xIUjqCE7QLIJ9Bzl5YLBQzrZoahf7sfPnmrUvZfGws64ZlmbYfRhFGos36aNiFVDmYnyEXV2M4ro6kIRzkIs+GEcx1/Si0eT6NoFGjs81w4l6ntbNz4Hm+4xrFafHHP321WBbkhtod7rnBEILEGMca+rg3bCv68Mar33nx7Zd0rRcFPAoLBIxdf+nMRCE5mTwLoCifnkmlUpJeHaluftfo/6oxGrdHI1+VfShwGSYWQtjBwenBvuzBsBkYVy8vfviTayznPP/zOycHrTRXfvp8VGtu8wxMYiRBJiwP76uG4XmRbqKo7rsGZJE4AhbnM9evTOVzcEe1eCI76oLdA/20Fmjq+PDoNFcq5ETRsIIwtBzH8Z0xHBoAuAKDwZa19/jp0fo2CAWBha5fXZyaKjSao9/++smwifBUfDITmywyrV5dN5Wlc3MXr74YE/LdVvjXv96sHKsAxovFOQTjHj+93x2oEM5qpt9sS9JAV/sSDuG+Bqf4sqFomkQCkO8NHM2mhfT0Qb3T2Tn8q199Kg+a/X5fyBRshIZIxfNkU4OBF3QaCvBInkrnEtOZVGJrp2lo335/bTjuGxYOEBQnUDMIS+UcE8N94JSns0qnFbg6cPRcWnj55uUKX2MJxFCGjqGHvm/7lmPpFANjgLJxKC7mcIpeXJn+8vF4b79KR2j75HChsIA45qBRYwhhJB9xHEMSOAAQiQeOPfYCiGbIzEzqex/+eGll0Q2GEB5ks2l57B83aqHi2UFIMTzH8KIYw4lIt9qOr2bSeZZl+v1tS7EZAgERHLgYEiSWJydah/XFlaUP3nozJcYczzl7frXdtLTgQBoMF1fSlhkIouljKEyh8Vz6xSs/nJlkSDjCkVCTBygOGALpdjrTSdE07Hqjo+smw4Ol5dnixKRjNEbS0wgXUsnc3//5H22fH/SbxxNZbW6ObnW/mF0MCpPRN49aJJNPZJhep9Z4VithcdORIiTk+eyZ8nQqk4ZwVdEb77+zmkrCg96hG4xomvRggKEYG8uLKd7yu7IyWFgq//BHH8REcWIG9wPHDCVC8K1wCKEIxbuW3/EtHY+QQS/seyiWgN/9zlvdo8NhyyqWpxOpOE9lPGQAw04EfIwAYRgGHiRy8bnS5I++/9319eMf/Oz90nTM8RVOiA2H/t17XyhqH0Ip0+6FoBABhONzU9MTHD2gSYZkoHiCoyiQSaVbu0an2aDpeDoeMxQAfEPRmhjjQFT0cOMe8JcxlH77jRcpAr9//6FtiUKSXzyT0wwFtlEioF3TjmjYCYK333vto1/ex2z9zMocSUA7u+uxBAXDmCxpBAmCwOPYZLd1DHysPJ3z/KGkOAQGQSHJc4wPSDc0oijCMCyM3NF4AMHs/t7x0yfPE7FFhqGLk9lLl8/W6vtALoZh6Pt+p3Oq9BOyPKRJFCfQwkxSc5WDo9PdvRpwo1feuf73/+53E3EY81zDHCmaCROtdNxhLUqSQDGTOOqNHQvmmUkUkhgO7qt2pVqVpRCmohTHXbw5V5ikjyvbMNCKOd4eeZadOzqQQGhRCMOyjO55HUWBSTTJkI5loiGV5oTyRPLFWwsXzmcBcoDxCcumOn37tGH3BwFDwQiCcDwWBAgEowTJEDhiqZCu2K4jIzCcjxUKieTSTLnZd8dKmyah4bA/GsoIFHMNg8SIlYXF+TnxzcS14mw6QBVAHEMQCQDgBQyAAEVxmhHbHfnLu/d1E0mmS7jqhT4UeVBg4hyfi2gapfx2/3B+7tLy0o1/+x/+dGPrhCBjqXze55mDSkOkCJafaPfdwtxkRHJmT0kmclHgt+u9k0qr2xy2a11toGgKoNlvnz/CeIrDkYVC/LX56QfbFSLqskwEYKHW8NL0MoS4UktjGOja69euvn6DQpkkF//Re9+5tnS0pRxcuBCvdyscApM4omqtqWns3MWVsxMbO3tnaIa7daaYYuWLK5z53hnbCZjsaxQBIldhaXh+acr03Wq7G89mU8t0IRkft/ayPJ9HYk7XECDSB2HX3JyamgQo2umo6XR0/Upcl8Kp4uIHrwCR7IrpWBRLYACFUY+l+BkRxX/03eLqVCLJJyYiTW/GeeL/+i9+3Gg1t5XpbrMmMFQixsuK5gE8WZiJZwp50Mum4khIvffDs0I5YJOxi7cuFcp5+aSXzcdWFxO9LnbtyoX5Ii717+GojUJBEKgsy+QyWCYxSZGzIGiRlARoKxnw7394FUW2ttfkKXL2yuV5kvRZLDBNPZlLLp9dzE5kYAKK4DAEQYKVJaWD4WQ8sQAjGIITIQTGaouOZD9wfJv1XXNyEv5H/82bUQg7+ogNPDCiI4PMFIMi7fN66DuUERpapDMUE8kn2Vjun/3Tn629fI5JJXLLfJLokdgM5M2PR31pcBICHUGjk3E/ghPXb83cfGkulYqjEOapkZBMZBaZYm5N5PBEjLh8camYyyuSe3T0DKDDN96eS+cvZ6dVN1hj4tRP/8HVpXMWhvK33nVCqkrDCd9yNMPLJ3MI7db6I2Q4nExgN64tIRDGswuW/8mkwF6d+x5np51o0ON6IQl8J4hjqbduzq+WiUFnuHr2DQTPkFFhMDhBsXFKYJVBO2SYc1dKJ42K6RmFC3KYkRws7UV5FHBeFFAET0KhZSid5hEEORPJTADRcYa7dWVV6vv7/db1a+8N1BFEERduzWlKyXPw69eSt7+4y6fuOY51YfXl2fMvwTTRbO0AdxQZSIwMKLbh4A1cTRBRIFKWEw1xGLBMggZtyOya7X47snc2H65cTIUUwaBJgBDV6hgY6y++nkzzB6dHoyjkb778vhk83tjYFgzChkkogPWxK8tDnubmEY8lrOHARCP52rXVm9cvTc0IUzMoCgxlEIOJntRMSVXKHoRoIM1OLswWZuSm2bW2c6mC3LWBi3AcB9NwlMiRLIFF6NmV87/57VEYakvn0anFIcuReOhJ41iztzlbxq6+feHiBWGsDIdy6+ioPj0tJoSMZsiy3ITRTpJDKbTRONhzT0KWJIhgIA1Pkwm62+kwGK0rDZ8PV2Zmr7xwY2FScPqV7v4d0qmUi3MWnmzqSgTZARR4joH7qnraIxkSChTDcTGCuv7m908am/v1PSxO9XQtGV/4P/1fflg56H87j3ydJVEylcRefvMClBzzE1QikSBoRnKHfmTTMMGJBBliKA3BCOY5EQSQGBvj+KWrxZsoCKVODQqcCPYBHEA4GmHexVcuLV5dgiBIiHMIYZ2/Wp5bziAIlp296FpKr3Vi6aNEJu5BUW6aYwVRDnuh0cdCE4+gwAkCV4cRisb8UnnCCWzXg2iGmCznk4KQ4JjpUtb1qtrYxWEBixJuCFxrqOhDHNNDUpw/MxUB23R6JIngCIyEznQ2QyRhLSnEaEJgaQiBrQDSnRBgvmN4J7UKQwmLZydXLs5FBOEhoWxpFOZTKHr+4oKYia0sz8/MlXDECB2vPJWtt/qa1AkikyJ0IkRdq4NEHsHFOIy9tHx+uXT96ZNTnkutrCyxHJGmdUkZO54D4SDCFJRCCQr3I59DaRQPghBAwA5Dj8JgFCchmIEg2PVCLwoIDHhB4NgKgTOZXNIP9NdeXF4oX+fiWmZS83wdISg0gnisxDExNCQIjEFi4MycaMMg1Jjj5hqOcJlEXohzlkvK0oijyTjNmRrE8gmWZSmGVnVDVWSnbyNj9Ma1xUxCjAn0dCkFfIfGUQSQsu6enZu4sjoZoidGsJPiExOXZsuxEMO4WOnQUXxDHYixOLDIfmtA88l/+Pd/8j/9D3/Fs7QL75Tnlv/BP3rplVcmaSLMJjPt0xrLI+lsHGeBqphB2GUFYjaWWJlfNG2o0ax6wAGIAULb9zCOpTgmlZzNxn9M4rQzNU9CqAZFsCiSMmp5vmbYRuhHBEKzPBNGQRBZuuy89c47wHv0xaf3X3nj5jsfvB6Q/Vq3/+j+7XyuhCG8pSkzU/EP3nthf3+3OMFePVsgQFhMZi6sTkW2KgqqLimoxcERFEEUQFkQCH4UwgjCZ6W5SyQhThcLk/nUJBkyWlfBKP9777ywPH1OVyZzJSou8JGLsnQiMV2IczPvvqFvbu8NRx3LUA0pAB5rak6nc+oCpbwoXL564erV88V8gaICw6n1Wj0UIXpa9nDfa7ds1dOIuF9c4oSJyIH7oaXixAQuxEOHgGHYcyQodEJgD0LDocmLr87eYG9OTGGrl+OR46EUhAZjkSfOnk0KSa03XJPlwHNEgSz7poEJdD7JTGRzw64MARcKoFQylZte6fSaAQioOEFn4Kk4N1+aTwnpXKFcnshRCJzLJChaiwk+JzqaVZNUWdc6BAThqMAnkQTgARZFMCgly4YViGIh9LBn61vV4xYXY8fK+Md/9wrN/q19bH9rf/Yf/PyS6yiGOXSHvhVBPoF4qGfZMvA9FtB4RMlhGMImSsEIggYuQkI4T8I47CXjKRyOlHEncLUo8kMEojjOCUIE4SAoAlEUeLbv2CB0cQxGUfikISXiMZ4lgtCBUCiAEduPCJpujHtJLkHDhKOqtj7CUAAjiCQpTDxL8WwEEY4Hg5AgIIRGQ5qEtNGuYfgsPQ3Cgut7Pui4YZthcdNKxHgaw4LAl1EEEBBl65gqR4D1DU0KA9ux1ViM4+KC5QdsTBCSE/1e1zFUiqIwnAwQXHMj1bQTwMVI3gvhIEIYhoKAa2h911Rwt6koHo4LOEXzNEYTsG+aFEoOzIih446DIARZ7zQiJJqcmiMolrWHCAKFCNBNTdJlGEcohvSjIDAVEMEwhgIIgVGEYFgURR3f8x2PYXHfoXTNt2xJVQ0YIjI5DocNyDmDgjRC91T/wPZsihVgDDLGZIwTCIy0LQ8nWJRmZcOx/QAND0mCDwPEcSxN7YehKQoMQ1IozPtRqOmmE/ooRqAEjiK44zgCLg77Bs2QqQxpO5Y8NoLQCSJNDMp+4KKU7YMujBA4Mhl6MQTGhsjz0InkgRbnkjhGhwiUmcwEkbf97HikttmUEU8SlsaigRin05DLEZTnui6EBiFq+pAEkABGUdeDET1l2Vh/aHsgxEmPofx4jEIiKE0VoygKAp9iYMeVW50qAH4mmwIpFoYhx3QN3QcBDoLQdsd+qBDEBeARkUMNe2qjezq1nKESboBq0MjkuYQiW7XTdiZdIElqY2PdNPXVK28JdFZqDxytFXj1bFZIJqY8m4EJiKJhgkaCIHCDEEEg3Rp3uqd4yBeSM74JQ5HDCyiMhW6IGTas2TWAGYo+MC1I4Oc5pgyjJM0Rln+sqAPT1AOPjLElz41OaruOP5ifTgHYQFCYxFgMQygyDDy/39N2G+e+/OSwftwy7Y2LF9l/+A++n81A1dr9opAspOYgR6CxFEVRI7XZkyuS0abTkawg0pjN51bEBMmxti4ZuoRV+9MHh1/NzYUrSzxBRAgQTVOEowSE9QlMsE307t1n3d6ApJBL18/QDPL8CVlvniTyPJ+CKNqx1O7i9HQ+lUPNAIEiadBFYIhmmGcbO72xavvRZqUXuk6S5+dKxclCVkzEYAKxXStbmO13zV/9+puHD/YcH7E8ByX9TCHx0+++U55Dnt7/lvtr9eoxRbgM71i0kxKKAcrrjoZinjYeaaYjMol4mo8wK4At03QCH4FwCqZgFIGax6cUgWBwwLA8hMIAx1BGsHX9tK87th3nuIlcAQ4NedRU9REEeZFnhl4UBrxlO6ppYRRNsqxjuaxYhHCKZAU77I8kBYdCjsKpjIDBOIAwjGAhFLZtO4wcD7iSposEAgLAcqTtIlEIs6ygWeMwckpJXtM0mqRgmpXULsYT8UTGQkzbHuI0I4hp29EA5OIc5jouQlitwYimMC7GQ6HlBSoANEvRKMqxqO4HDghh3/E7vVYQBBRBYBS/17JZMpkVigjmwbSDkJFm+sOhMltaxBB+PNJxIjq/mkR5RLLkbr9LDbyYICTSCZ5lbA81LEv1IM+LRJ6IYAhC4DCC3MC3FSWCIRhGeq3e9GxO4AUMw7jQF0TaNALTkhzfpRDFDTwUHlIs7EZYT5JRCoqRmB1IIUIOlGEQAV5ImpYLIRiGuiCCFN2RVVMURZZKepbhh9h40E6ls2IyJpum7XqB6wIMpgiiP6zAKOWHVK+nIQgSi8UIEvN8PS1S1ZM+ztEJYaHXHbXHXRgoXhBKhpHP8ByLoognsDEfQINWuzOqzJ5bnoViY6XmObpnDsPQiuezwPc1pUMTIkFyIYq5sOsC3TA9VQkFOGA4osgKbhh5vgV82/cAgKKhNvJ8FUFDOuR8F8GwLADGWJI8MIpcyrMpGKIYFoNw37NgRYEZ1vFsmyXCbImbOXMpJGwbUp0wJHnIdbWJiWSplBqPZUUZLi5neH7GVjtkgOTiNJIoGWYQixEMxUJEwjS80Bk5oOOFRuCRCIgxKD2TmYNpLRujhk0tMA009DR5oNue48LiFIGTMKURECTSREJRTNuQwhBAqB6jUQpnDBOOCTTFCETMA3AOjfo4zqiK4bghhsW8AHh+FEVsdb03OBk50jCdDq9fKE8mmVGnwfhM5BGeD6LI8L3ICDHT1WiGx0kMEBLM2AmGoQnf1+XBcBx4vshO5Ap1jkvAkNdpB3AURsEIxYxCAYIhYJtDBCWXlmLziwJJ4bxAep5z5RKdLYgES9IsASORhqMsKlIwT1CqKo9sUyJxNCSg1aW5czSnmvblF2wMhhgUZQmMZQiMgHXHHKmuY/ThCO01m64VlKfn9yrbnU5jdimXyyPZHP6t9yCDcOgHPgzRTJIyXdNSA5wkeSYp9wx57MABzLBU/eS03ttHECItlkQadsiQIdwEJ4xHfc+xsnDWB0it3ZWtlmw6ESw4th3nEF3ReTqiUIHEYdeVV+YWfAA5AQTgkKRgkuWjCOp2BwpHybKcTmK5zJQwk/YdOURMHA9hPTg56UeQEU/nIAD5kA0jAYA9hmZoAad4tj2wXNuJ8QAlOcuE0iQJjDByaZwRSAEx4cgGEJTJNTdbpm1MxUScz+impDieaTiRbk5kZvxIk5SB745wDEEwMQzhKCRHxsj3fQTBQATBCISgjAcwSXYkuDxS8LEDsySaSRNpErfomAsgy4VO2zUUgqnAM5WeWEx6EYsSdBipg7Gk2x5KEpYPAZihGQYnSAxVTdO0bDeIgO26PgAcx3FCEkczpq3Yjh4EkesrDB0TkmnbIT3XjFzI9TXHGiMQsFxatwIYCpJxxHV8CMNInpdVXdUVBEHSSdHXxpI8ilCGEeMIGYtgMoxwKCKmS3GAYpJjhxBOczEEILZuOw4UwjDF4L4LVDWEIcRybBSzIAjeqt/BcZwAAqRZMIJjKc6PQjhESolLHGWP3CPD0OFw6HqQ6ctIBNUbHZqiDImZyM5OrSCOaaC41+wfg8iCMABHGAQwFBYdlwicAPERLh1XDd3yPYqLUTDrmhaDIUKMMkHgaLbjWkYQEFhKjM/BqKLoJ7behIMYAZcIgoiAAiAjkZzNZROGbRMY7tu2ackoFTd8xwewFzJxkuRYGIYBBEURcFAsTKWTUQixyMC16m7IRChrekikBz7Up0h5dnJat23VkNAwJCkeB0wYwFEEFOBW61sxkk+IsG33ODqkA6rW0OzQRlGU4iOWxqHQk2XJ84wA8hk6wfIsgIHvm4ZhOF7oOQ4dg8YdLZHkRbEQ+THHBnYYWJZdbw9H9WOt22Bwd3mSOzeZSQEm8lIlsdB1x76LAcSFqSBCECSMYD/m2QyhoWio0jSOI34IkTbEBaRD0h5iH8QSrK5iJJ4hUCIMzVgMQqmRLvsoCscSEMFgimYEgYtgKElTATwGaVc2ZE9HBS6OEpgjD0aW4gR24FokieYy6SiKbD8IYQcBNga0GEUTSAQ83TahKMKDyMZgK/StzedblcMNCp8w9H4ItFsvX7x4eZ5mPN//3y9j+695NLecH/c7uuZICOa7Ok1hOE62670Hdw+P9/ssXe+riua0fEjBKdrWHtuKdX6l+N4715KrxRSbGnS6u5V+5aR5dNLVHUh3gm5rjMEIBiNo6M5Mp3744a1LV+ZdVx60ZZRkfYRxIlJ3wlrXrNUa+zu7z1p9BINJhiwWi0sL0ysLhXQSHw7ac6lpAoefb1WhI/ns2elcVgCRRJO84+skR9Z6/XsPT5rN1tQUe24plxYFxXJUA9/fHAEGjZfJSrdSqW8I4ixqmtVG/aBtcfEYDIfZrBAXywyNHx33ISCTiJQS0Rgf911cMfzAj6woQmCYxnCGYWGYHmvgoNLb2a81FahTH+ARluDYTIbK5plCKX3m7IojdbgUwCHPtocgoF2Tb/Rs2Qwv5RNu4OMEBWGko+uGZTuGgziBrnqyZLm+ByGYYTmW57E8FI/jkQftH+7F44krV67wQkKRLd2GMFzQoxCDAB+jo5DzIlSIzXPpuI1ovZOK6QaMkQIQOh73dXlMEcDVIRYFFJugkulW3zg+leKMmGRFDCFcU3NBoHnA8FHgRLamB2ZQSKZRIqQ4HooYkmTDANGtrqYpNMW6YYZjOZyIjfoegDE+jjie4VgAx3kvImOJokOMQscNYYhmxTSf70gaFnBkhAaaYAXSWFEhFHGAy4gxy4d104ABAyLaMrEwwGKMqNkazolB6EIYBQGe4JJwFPRG45bTty0DgSDgQTjsW76DYgEAtGsQLM3jGOf5wDJD2/N4nsims3DYUXUJx0AsQfaGzWqji7IxL0Ri2YnQcU9O9ykazeaSWEQqRuT7HuXICM6SIgFjOOSLEQm5hKXatbilBn4U+iwMOBJKAQD8UI4gEycTujoKMTjAAz+CEYwGIEGnsiimGJbi+rrjj2xDl/UAwzAEgwzLx2mU5QiOIS3LD1wtChQUQPF4mqFJiow36sbhUZWLIbEEE+G6mDFiolYspG7eKBUyCQzgcSqPRGC2NOVEcnt0EJgGSZIkkqRxwTeBAGdCpGYbfQ8lCZJn2bSH2bqr8hzleJATQDAWjlXJtXWY5IaKnIznwsgaSK0Q8nTHhQGHR3jkU6PeAKMIGHaDCHiBCyBPMzum6SDCFM0xGA6RMdLSVTh0XdfA4dANQwKCsSjyfQ9BUQQCLEHQNIn4qalStlTkxpqCEvAbb5393k/fIRnYlzq6ogHAfTuP2v2+pZlQQPeMEEE8QcQwjDipjO/erhzstWiqRZCcB6s469AMoUnBoDGIVCdBMw6cvnBmdWxpv/187emTDcOB2VjaDWDMsSOEcAN3POqPu+3JQjw/ERNFPCZmnQA9bUlH9WatPa6ddFuNdrfdZvl4Ops6qdbWvt58kk28fGv1zddXRN73RbbVsO9+tTOUpX5veO16aTJPsTTrBYap+nfunf7Nb3Zqtdq5JS7H0JOxdM3zHm42PvukavtRtowP9ZNmq0sQx0TgdccyycW4RIKgsVScy2eEfCZ+5foVjnQjrx1YnX5X8T0MiuIsx7FiGQ790LVMw5UkY68y3Nzvt7pmrar2Wz0KpjgyBgAg+HDuQtIMwNVyKpWN+0YHRyjUSzSq4OPP97aPGp+J7qVLl6/efAFGiPXNk93DY92wgghEITEaS0EQhAgyliTDdgiSxHGcp/jD46eJRMKL0mfPlzY3qr2OtrI6K86LNJFyTLWy12jVDMe1m+Ogp55ybmB7sA/oCKZGw6E8aqBA8235H/zkxjvf/6DRkD7+8oEfEHFGmEwJN6+cqZ8ObRACnqeT6TBC9qqbe2s7cZpdffVKhGGa4nQbLoriXiS32lVV9gIbMu1DiuYsnbBch6ANRVNcGx0M/uLCaunNN5bny0IY2kAPTAtqdzyBTyBBEJrwSB0xiXGIQEHIEjwfEBRM4fbYG7TN9qnaPO3BYZDJxvMruQvXVjIiLalev+OqA3fUb26tP2qM6rqu27pnyD4GU/m0ODuXWjkzMTudj4mU5w49C0FRdthS7z+473lfff9nb5emS6N+zfGNYqlICfmv7m5+9NldxoQ/+O5bc/MrtisNxgGOs5pm9PvqNJcHHmoawAHaSPJSqYxACyPTPw71XGqaF3IoREGQY5lDM4IRhPNDPpPLAz8yPV22onHfYniRTU+baksxqhgJcIqIUERIMDTNep7T7kWBagZwaLseAggSg6HAiWx9qvxCFAUHh812W59bWOGTbn90lCiEc9eKfCY3UyytXuA8WDsdt8gwjkbA6ZgYHUIIgyCo7UR+FGAEgCDE9mmCi9l+h6EJG2NtGPMIaug7WWJJN1TDdmiUy5bnSIQIHROFdYpGPF/tDE8oGgsAYlikqka9dh+CUYrHAkgMIrgl+zgIURCnSR/Fs4kEh4W2GUSmpSIAAX7AYAQOxygE9y0zsEEEQT4ceo4PUKRXr5xfnf8X/4c/7IyUCEVjuXgmj/UGHUfTEc/61h5BKEvQaOgg+ViJJN0oMO/du/fVFztwFF+cy+um5dkRRcIwZrCUkKBTMTTtm+3nT/eo8sVM3u+OvO7A1iwoigjPw7wQYJ4NR3AqlU2LscGouru7e2Y1fe3GSrvRP24NPv5qbfOwY7q478EgBDBGD/dPCTtwFYWHULXdv//x56sF7NYPXz5qSL/81e92d5qFycJJrZvN4gvT51AEx1lWGkIHh0q7hYX2RGgjsE+FtrvZlX59f217P6QQ7ui0jhMSCEG1titybIiQtu6P+mPLMW1DiVHwdDGnG97VK3OlvOADCzg2hJKexziGCxEBx5AYARvquHbavP/N7taBFMKC3tJ82UQIHPLQIMAUQztETmBMKf3kwxDxGWDiMPb1Vxsff3bQHoMAIz97sj8x8SqBnekORrdvN7/8+qntBjTNxhLkaDQKohAgqOnYFMOls2wIUZYWhVGi1/erJ0p2wv/iy7XPf/fgxZeu/v3/x49JgOxt7/yXP/6T9qkPhRd6CvBQIwaZPsRoFkpQSRAGGOywuN9qNCE/ns+c+eNf/sv/z7/6y7m5Sc8wylnh8rn/+2R+tqepBgK5LjIYqY+fbD/4/F6Cjq13+pYzrp9KkF8ol6YjtNvtnYCQQduJsV6D4CgKhFQqgXN6r9elifwA9PzAmpzkM6lpDNNDBGW4lCjmQqfP0QgL4b1uy7QHEMXAuJBIFU+H426n9vTB050ntUHDVweG78gsFyy8dFGy1enlEoIJ7a57etjpNepbm0cHe9sMwfNMMnIRzRp3K4c7z6zd+dz7P3jt8rVZXsS9CFN6wvZG89MvPlOtmuEPfv4HP4BCx3PNAEQwhA2HZquuDCs9mkvF4mnDso6ruzzPO47XaDTv1fyeMmirPYRjXYAWC7MJITHsDoBdO7t6YXlpMZcjhHgARW7g4CSeMhXNs1157MQExvQIyQ6TKN+QtMZWz/BaxalwaoZBAYGRgh/i/b5Kx4o45oRRGAYhjdNpkTMtyzCt3a2a4zjdnua6hOcCTVM0c0iyePnCUrJIEgDxWQciSAhFfNfzAxsJadO0RoYJcATHCRohPM/TNLmpyJNzFsQRTC7Vl6j99mgM1IZcWwyTOBt3w7SkwJqBS4NBZXsjnRCWz8QSKQZCBATD+43uwU510Gns7/RUREYpIp7OxONFaWChACIQG4UcPai+cuNSOcXlODQ0whhNRAFMUjzP8SiIdAeEcEBiJISiXmAGQbg4v+B4br4QE7P02NRcSNOMCMFcmuIB8rep87d7JEmAIpIUI0BJfm93DYVgD/DtvjaU1IXZEhi2kZRSmMiWSvPzc+c6Te3zz7oty622zfx+79w86HQc1YoYgUBhO593BV6cz65OLYjDob27YRk+GNqthq5PWfkvNrQ/+8/PI3gUwdbwtCWKRDKO4yBtXaUSCYp1F1TVd203csz1fe9cVTxt+LpKhVA4GByfP3Pp5uq5FMzIJw1FR3q4aYVmqLiWrkGFOLUU83C6+vlu9ZtDgcpDpO5HI4FjtP7g4lKSxxOKMYTJoaSPiFjMC1nTJHoDf2/96fI8ZqUwHIfGI5COZWMsMRrVFEnqt7VUppAprHQ6GWsgaQ0pnUYxBsrkhMRk3A/gyMLi8IQ3qkmf7T5IZ37w/e+YPvq7B7d/9cnh+jOiODNFcgOCsA6Pn/a1mzWp0lTuIkwzE5sgYUEfnCaIBJfKN1VFjSxWSI0buwl6CIZBKh6nc0maMLce1bsbWBkpB8cnbnVYkcOjp6nB3jVtcCTwrUKI8EjOpC0Ipju6C5wxiRuh2z8zNfsHb/y9c2/feLh+eLTRW81NpYn5g+NBz7Of7e29+PI5Vz6lENiGspW97tNPG3CwIguC2V0fnTC0Ozdo993GFhtDYZqTzG4WFEiElI0TmtN7kjo+DgGMB6BTyiX37+9uZOmb17Mk50URJFKF0J48HTapmQSa03HK9INU4PP9gXVUOdjr9aoHw4dfd0ZdOZkgAB76PoPgBZxNpxKLzjCqH+2P+trW2snBdltRwGT2agjrI7VFMmwyX3a0jKv1qvvSn//iafn8NZKPDbqHT588+Pi3DwhxritxD/5i7ZWzV1euTbYsrTcIe61w92EdkZHFUoYExLgZ/Nl/+ZuT9j4nCixTsG3SHMG9vp2IZ+IQqY8HB6eVVNyKQtRpEsPNjc389o/+8K0uEziht761E0GIq0aaZtiGRRJsjE24bmjpD0AEwbarOTU8pn74ow/OX71JUML6zsYnn33sO1NTpcWzZ85NlkQtqDNMKDukHpTaI/3R/f1e15Dl/pVr06+/dna18Obezl7LjCwFoUihVRsa1ti1bEv3SJzQPLt22tPlAAmxS+dWGWJ4evzJlctLl7/zihogDHrhv/zqmyfPPjo4ramuDzAyRcYnc4uW6Wl60w3bBIYj4eRvNg9JZv2l75x5/w9udTTji08rz24P9CESAaRiDvOFbHXvFEWbOEFZph+EeBhAMacx2O6kktT777x649KqNW5QsIQ4A0Mz7cg0A4NNc3Wt1T3q59OFhJAYaa3Q90EYQa5FurYY53EONjwIjhEkMQMe9r6dRzGeQmE0cPT2kVzOTo57/a+efTMc1k3bGine+avTq+enbNssFovT5WWGbtfrJQwPh8M+hoCjvZ0Hd78+3N24cHH67XduzU1PQREsEiQfx0+qSuiEEYS2ZLVeHx5XT9cerWEAth3bD404T6RE8uWXLr/9+o/U8BRBY422ubFVP9iptpvG0WH9V7/+zHJwy9ZoEgkhL4JsVRuMSZ0g4KSQPK4dSmOdxplkOTkzlUBxoj1oWS5UmCgOJD8ItGSSmJ/Klm6dn5xIx7g0hAZjfVg5PS6W5kdS+MUXzzc3ql99uZPNg/zEddPTIZjRrTGKMBgJxYgYjuPJROH4uPXrX321d7SfSFEXr07dWJrOTnO4GMimCRy+utG6+zf7YYAaOiMP0UHfe/B1p9/V+BjiBiMW5qaKy92mbinB1QuX1ze+6jebiN8hCOBRvqr0R7pGZeIobCiSmRGQaxfOnSuf6Upmbn6qb8h3790dqipLg4tXL2EQ/emXd462ZYwJy4mMZbY7rY6P2qlsgSITk8tpkgAcp1258Oar1y8INLve6rY7rmn5KMI16kOK5AkMPH/ybP7CJJdMRIHfGyq9RoenmAhiz9y42pZOTzerFM3ML8dcV+32W5hFIyTtQKcIN0rFg8XlbDY73+uYY0lxPRODg8Uzqy/euspSBVsbwRHioLKuKxFW36/s8wKHk5wyDlQlaDXdne36vScnhhK4JiUwaciXEMhlBIIknHNzV/FA3Hq+8Ztf/gYOARwRhjEiMdxWtIlZ7syF2UQmrUrQ84eHjgtnk3P9hn7n9t678ZvVo3GtKjkWFuHkKy98v//0P/32ky8h/kUmzjdOe7/7zdr28y15rHgpIa1E1cP+sGlEFm6HAHEjFOHC0EARCo4IGheJOGmq6qBRHQwGy+XZMPLDkOq3fcPTjk4qmzu7GEn6NmRoJgzDFEHDUI8haRhGJUnKUvxxoz4xh/Taxv5uDUJ7z9YOj/bGe7vVUum03ez84IdvZrNkr1P3HFeRfZoWUYxqN48VpYdCsyiC12uNL7+699UDLfLiOMxgpEFz/ngk93rDXLYA0czR4elUcQmNwL/7D39F4x5F2Dv7J2R5ZmF6/u7d+7/6q9/2umMII60w8qKgJesHqCHwOdvWLFenSIzCx8nEVKv3aGFpEQbR3a8eba71fUeMxVGMNPw+lsAD3dYdzfIVEHkQz4gETjsO7rvExkZr7em//ekP3nvlxlKCg+PpOAZsgmJTbHxgjHGUmJwouXYYejBBMG5gB5Hvu6FrBbBJUKIocjjHwpbpf+v7iCEAjSM2HCzxJZajxjCfYjYTMW66XLxybfm1N661GhWCFHPZXLvdXFt7Vm8cdzodWZGkXqsWhtKgn4xxb7xy7Z3Xr6MwRFEc4mrD8ajT7BwdKMfVpuo5O7ud/ujTccdlEDiwgqlC+rVXX7l2dXmynIhx2fawJRsWEmGhm5P6w3atpSl+u60FcNBsnSCYeeOFxddeu0yz0Ejpzs+UDV0+rjX3dk6NFndz9tKLN1/M56CHa8+29voQxnh+//zZ4u/93sv5lIiGYZxlLIChBOYFk6uXzuUnFg8PekcVedC3nMgsTk4lk0nbBsDFjbEsGyoKB3wmj+HseGjf+XJ9a7sCQJAukJduFGZjkI+0SBKEkNsc1ofSyI482YxosqwpzOO7w+2nTm8giTn73IV504zV93dCgNRP2stnJ3/4wbtXz00gHsARvtENex33sztPukoXh6yXbl69cWF2ZU7Mxac7I43PZf70l3+1vfecgOK5TKq4OLuzvnd0sDOUnDD089P5n7zzd0gS99wwVkrHuAIKc56tTOShUgF35MFwdAID8vnaxt7u8aA/xiCRZ1EmAK3T7kGrtVosJCharxyvP1jrNMeJ7MTibC5tTXuSP1+euXX9KgrjX3y29uXX681mj5xR3/vu9aWVTKlUnMzNW3o0Gg1MXYIJz/M8jovZJuxaIo7DIaUTvGoZJwyf9H3QOTbqdee4ohzst9utkefjiAuxeCiIcKEkLC4vLC8spBMTNPXi5ubm0zs7/aaWTAgsFeCwxNDED978vdIynZmOUpMJP2AfrCx+c3uz1x45ivzNnZ0bL7zdqlCjFkMjxVqzH/KVhJiyPNT1Cbmh1I61w+0KFiF5MZ5ZmHj5tReIkOBwFNiQreuOL6uu6+GQEKdwBJZHY9jVcNiam8Sun58ba67nwrplfv7ZMwjBNcsP3XQQIvmJGdd1MRQOw1AaDkayBoAThqiqt2emZ2+9+PKVC9cx0Xjy/P69O2uGUp4vJw2rtbf3vD8ozCyU1M44LsygYez55tFptUfgTLk4ydIUBiP9gXR4eKp3eN/RENQluRAAPAzjPC8WirPKUM2xIengcBgJCMvTEM0EnqOvr9dQKPl07bjbNSwdYTkGCyAQRg489nwzCDwMZWE0CQFHVjuubZ45fy6fmzg+ONh+2jBkwdJgG2sLnDQlCJkk7AMyDFHX9yw7pCkERaAeE9NMi2OzrhP95S8eHB5W/vl/+74FcSztB0hgmCqOwgQlRD6C0ASFMygKgBcFEB6PcTQHAgyPHMr2EVs9QRHyW3vkWZpsSKbhMgQttbqqHkIuC0fM/Oz51157j+PIa1cmOp3e8WH93t3HW5uHsmSEAbKydDHGUQ8f3PdsZ25+kqfJyLcDAIaK7pu9ja3jJ4+b+/t6d2igDNJrW9XaJjYmbVu9enHq7/7Buy+8cAFG7aHUrEnNqSmKN0FcFFxXxZHI8/zIA+22QXJGvpA4c/bMiy8tLS8WfFc2FFu1zc6wb3tIJllShw4OW5qinpyajfbAdIA0kqamMu+8fXlmimVwnyU4bayqXmipHoYxgpDf2Nh+/PRwf38XQaPl+TM3b7zs+kOaphESh4EHBwGGI6ORFPrY6cnw9FRCYJaLEQwH/GhIJHK2FfWGQbUpHeyPmie6AtN0OT0c6r/96Pbzh/s8M1ko0Wdv0tdv3fji017rueO70M7W2vQ8x/Lh0kwJ9kNX94tTk0cV/fnObnsgz03FfvaDm8VsTBrU+uqASSZOGqen9QYvsDOl8uJc2UOh1slYU3QxHvOjULX9sQ7n+DQrsvuVuzjUsHVUlYfTU/GF6QwcgXyqBPtRraqgGLl4pvjqy29uPKo2Tw6MEUTwyZET9judtYfbp3tVgohfvbF0diVHcjfeeOElnuMoAjY0KLsTI3Eqny6+8NrE+997N5sldEU2NN13AM/g6Ximr2znciLP8lEQcy3SBy6EDinay4QZRUJtkzFUfH/r4N79p6PxGCXhOIPkisVMOj27KN54YbI0FQ8D1HPRe795dOfOvV6vy9BEv3eM5ogf/PjiKy9emmReHzsHzfFTM+zEU/OciKF0qDkSjA5ZZrbX8u9/2R2d2BTNBNHJzu5hBopBVI6gMmKCaRxtu1YY2DaBIR/+7Mpr15cbOyfFQqCxIYKTM0srrDD59PBg2B81KhXEdy4uFy+eWzqzlJqdznQsRFWh3e3ho/tV1yVs0ycQEcWgWr1PUjhNogxDxlNxL7JjHHPx4vkEPJ5fKeWKE2Kcb0vy/l7tuNJKxspDY6SaHYyg+l1NGdq2aSE8EGNCvSnV6v1sPFkuCZmkwLAUJ8Reff3tYHTS7aoIEVE8jMIwz3Ehi3lBcPz8zrVLlxkMMmWpXEI9X4dQL1NKnV09t7W5c1SpYgRFUwQUItpgpOsmmRsvTGdYGnIthGYyxclYKsMgkDe/eDYuMs/X9+yxAHwSIazF1dTFGzOz7HwyKSI4wHE0iCDbCRCYdJxADuCna9WnT2oACBQx0Rwcbx028+WLGc4YyqOxLqEUQVAxhuAYOuYagQtGCBZRFIVhjOEEkmkbpgZhuDkeionkt/YIhkEIfJZHLGUsS8EXn20+fHwwViDboD0701TML3e/fPzoSbc71FRD1w0YRmamF9599/3T2gGCIKyQXFm+sLCwRJJM9ajaqA2/+eZTxyRaHcMNwY0Xzs8unG33m5tbTxSo/tabF//ZH/2dM0sFx+25vmFb2ljukm3BB9RIc3d2jmq1E5KgKVyUxjpkN1gmXFmeXF2ZRFHXd0MxkcVQUvMH61u1w4PO+WTxzddWFhbKW0dP9o56oxECPHh5fqWQJRy7SWM8ABRC4DAcFHPFWn34xe2Hf/3b2whMd/u1IAS3Jl5HcUIamQii8jQTRVAIAs/3TQsBITwam54LG0bE8ezFSxfLU9nD/lEEkju7+v0nqqKh43HouM61KyuxBPvV55/V6u2p4uTK6uSrb0yKCWpmNtacEXf3qo1uhWReg6Bo1JcStEjDMcmW7997cLS7T2L+1XOl2SLrWCqIPIjCNUO9ffur548309ncS69cunLp4ulx82hn3GmoUzMJPpZsnsr//n/+JoLQeDKh6l85Fp6Ol+TxIISUH/zw3Xff/xBmZqXdVrtmoQR65aXyd3+y6prD3bW+SKUwJBFPZVqDo8p+O3TC7ELihdfOTZVwRYYBDel6s9eXRkOk1+siULg4W75+4xJN06apYyjN0UnVN8LAJEmMthCWQU2z3+s2UTglJlMwDIcBMuqRts0ebMkPH54cVZqGJVOCISTQpRL/0q3l1TOXUNxzI6XVlm0b9x36r3/5H7f2dgMEOndl5cbLF86dzZ5fyVhGs288M/2ukOTSE2XTTpxUO8eVoa4DzVZoCn729HGjdhJoWgD8qTk2FCm4lYAhzLURDMGfP9sdDmWKwpJxAqOGkr7Lx8Hf/aO3aRLqDgaMMBXBicNefdCxcSy8dGHpJ99/9exSiiZVlg6Ah4CWzQqQkKJRJGkcGxEEcvl4b6wgKAhDC4YBRaPJgOB4PJkizk1cKy53Jef2cX1yd5s52WVIgvHRncJkyTvR0ChzvEXOFcVcedp0ut16dXf3VNMdYDdXl8TJyVQYmJ7vlOdmv/vdfK3WhAkQS1E+RNTq+u5etVmvTZadH/5oaWW2BHkWAkeKNoZpIpPP1e3ELzeey1JP182JfGmmXHot++Ly4mKUaCZimX5XO9w7pWl6YTFHsoZttwOyf3JCq51EpKc09Wh2RfzJz1+6eGXS01wAQl1XIyiAAYqGFIwwgWIFo+q73z2fymb/3b//NUOxLOnLqhQTE57dDaKQ5/lWv4vrnlhOKSPJUG0yPoAiOPQIz6e8AHJ91wUwhjGxWMJxHADwb+cRwDAM9mIxTkLRjb3aR1/cViRUjGcePnoua24QQd36w2azy3EcSVIMEy0uzV68eJEgwe9uf+66WBSCo6NWTIS/vjt8+mjTMTFFNz3bk9Vescxce2FSYHMbTzY6x4PLt7KzKyxAx9Iw8IL+WFUMD5qemyXQXL07PKl3+yOTYPh8gUJDTkesvq2KBBnjYBAa7ebYMv1sbg7Ase3K4PhUC8MwnfXK5ZCj4X7PqTcikaauXLz84bvXk6kRySEsTfcHJgTxyUwBAnj1+Ojz20821vfzEzmaBdl8anaxLMuymIhLQ41C0MD3oSBwXC2enINR1nzcHI0V14YMGJaHcKvpHZ70vvzim16b95y47phiEr9w+dyZS/O/+/NPHVMuz4mXzk1euDhrjK1nj+/vH4w8BC7MzKA0zsW5VJxtRQoBKIFMdrv1g4NjQ/UmSsLZuTJPBD5C5JJnqsPo+fO16kHV0aLErHhmaZrnqOpxi8ZKUxMhHHnSULUkPAqFCMK7iosQIhQSnoRZYyeeIc6uLi+vzp+cdP76r77cWD+YWEATeUS293NFBI7sfmM4ODGSHLa921lfO8oVStdfu5KdJmuN+xNC0nSdXCYLYRPVytOdnV1Zli+eL79wfY4XkH5/OBppcmhgMIPhYWfYzqVSwA8t3YKhgKQcxxspuhoAJy6sthvmzvbR2tMDCI0SWXZ+JfvS66tnpjAcSxGEY1qe7wFWKJg978HTg1G/hhJ2uhB/9f3zN19c5UgbizRZ1dVwE6MJli+MVfpoz9zf9QY93DZxmuFU1ez0vrH8Y8/pr168cPM7L7Ut+f5/3tHG6tqjdYrhO71xCAJawF94/XKMI01dpiG2OFtOxGmyLbS69tra45P9jjzSp6enX379pYXVBZTQHR9CIjQAZPX0+P7Djf3dQTa34HqK59vtjkrSjGNbnmt5FkTgsB84yqjZPDkcnJv5/mTOieRuW6xXQbupQLA/OZX6Oz/96W9++8vKrvT8yfZEnpldyhuGvL1Z2T+qhX5I8fjqcjkeQ21XFhOcYiDTc/HUBEbQEc1jihzWqq1++4jlsFsfLM9fjscYK7B1CscQi7AipGsPjp7rcmeQFBIsK6yeP5dNZzv19vrWOhFnPGfLtu37d5/aVri0VCqU0dffOOPR8uGTUauCmhKEk8bS+fTEDKbpMkrDrmfrqIEiBITgMKAiQBuKOxyrn3z6x71+hKKWaYx8S08nLumjlqVLKIVCEODZGAyjyqjv6iEcIp7nERiOYTBJoBzFYK4rWXaAujgQ1VH3W99Hlh9qen+kDpK5VdVXcZ5anVnIZtMbW48fPv+t70IiBeE46nlWCNzJcvydDy5NTk7+5jcfyZYB+TEAoUcnve3DtSgyWCJJYymcnZG1/sxS+r3vTZ4/l3z+zak11M+Wl5cvebfenCdgazBS+FjAxXiWSIaw/fXjwcbWzt5xVTMD34d1TYtsHQkRjALvffD6rVuXG6fPq9WKKJQZBq7Vpb3K2Hap2dnk3ByEEx1VyXY6VrcLF4gol2CXprMQbnSGVRgWcTrv+LE7X+/eu/vo+LgzGqrp9KRtKyvnS9/98E2Gi9ueHfo0w+YJko48G0Q2isKOH1iKVGucjsdjik6PR9Z//pMvOCEg6WHj2GJJ1tNaIuv/vR99pzid+Ozzj10PmizPJmOhHXS+/lLq95x6q6Z7PUMnZmbnd44aTze33nh9VszQwHAsZ3R4WFVHdiJWnCuJ55aWKSiKCMbx8X67vbux6xvhdHZuaXqRRNHHDx5+/vHX+dgFlo9qrU3bDQl0EoMATbOuZxApbHXhHORFoc/efHHhyvni0/sf/cf/9FfPPhuhWPDG229dulJkePfGC+e+WV1fu7vx5//Lry+/drV2XIsislguXbx1IZaD7KFEIpMDWdVM14ex/d3eeKTTVJRI+gdbdxNZFoajKIgUI4zxBEkTY0lnJQuCKBwWEnHCDWxZa2MEmctMtur+yWlzOBgrukLS2Ds3X37tnWWCtmR1H4YwmuQDQCEEE6HxRq965+Fz3wOZbPbV91987b0XEyly0DqxDSiXOSOFyEgx6hXzuHLQOkEsExfFRNcZLM5fRhD6tH8iSV0agPe/88qlN169u7UxKMpHtb2nD55gTIyiKJiA+DT17o/e9OAGgcRoQgh9W/ZDn6C6ivTNsy1FCggMmZ7N5Sd51epojskyCAB45Jbbje3jyqjbVwDUxTECQRBTtybzBd9ndU3xfZ/CcBfYI93SdV2aOkagedjJnOyGu1uNRntHyPmvvvQhBmcSorhubA5k6e797uTiRZGLd6osgmEhAq5cXr14cdFyD0kOiecmhio89oYJgWN5YBlSq95qHlVZCLu2em71XJaiWU0b2fIIQwmMTXOxvKt5z2/fgQ0yJHHLNJ89r0DQyenRMUOxrk85Ti+b53TVhiK2cjAcjd0zyzPXb8yufbbXbSi6rE8sscvnkxAuDySJ9jEAQxiOkxTnO6RpIJbh1WrK11/0Hz+qmnrA83g2hcYosFiO4aFi+RCNMWZgZjI513X7rZ5IxykErzSNbIrBGcIKAHBtzXNVSw8QiOdSYroAwPDbeYSgJISgbmTvne7JjmpHVqW+60B9D+560ZDhWChkS+UJMc5NTMaXVjMLK4lut7Kx8xlBZjxA2D6EYGQIkY5l4wgNhVRv4C4tXvln//yFMxfGW2sP6qcqT7I8Q1+6wUzOxKQTRRAEjDB3tw8H6snpoPLNQ6bT60q6TDMcx/AohgSeTyCIOJnL59Nh6Pq+O1mYjAnlCGLDINAMRDOiRFE4s8oUJsgecAwjjEIBDjVXl06rB1yih2KopltHp6edPvTJp19tbe7nMlO65iXSsVicf+fd1xeWJl2fhGF3MOxP5HK+GwSOE0VhGESKqT17urm3t6OqKIFkGTZlO7hr2nJ7jwh4zJOureTf/97lbAH5+NP/vPH1tktc3ZWOz66K7frGsIUXU2/4ZsByfiJ+CYDotL41kGQ3MAnaR2C/Oz7ptkfjkU7gfGmivDgzNxodIQTre1BcSEERLPdVEMDAg3qtZvWw4rvAcjv5EhKfSExOFGdKVyFPBFCoqh2VY1+9fsMcGr6pLi9NqFLz3u1PHt1ZzySLZ6cv/fCH3+czbRD1p1KzN25eGp10Ig3aeHYwGvYoRmRisamlcjIvIbwob+lxPmODcO+kfnTQ1k0nLWJiEkknY/1eEyexbG42iqDBSAmQGMawAJJROOYHrCE7dqTDWIBioaIrx9Xh3v5urXnEsPiNF66/9eY7EyXioPoUMTMcU+60seppH6BATHmNlosSE2JinJiInb14IUSgnYPDyLZRB+qrukFMPl2r7ew1T44NSyUTLBP6TRhrZ5Kr1c5QlpypyTOXliYX5s/UT6vTM6Ut5Lmlqbqj1jr9RLqI4SBbzMBkeLpdARCTzU6jOGRKarM72Do4PTo9DRR8aWXyhZdWl89PDMdV05RwmLMM+2BjvL0p2TZdnsyGIZBlmabJZDIDeShLMC7wMSTKxNOWZXFoslAoXH8RF/mJwMUt1VDGg2S8ML9MXblyKZ9aNJ29tadrkEt1OoOj/cPZ6ZVuR7Ycx7OM8lQxxpNax0RDbH37ueGwE1TJ81UIigaDwdPHT+vH/WxqcmZi+trKFSSwAs9FwkDuGXEoRseK25XDk72e66NQRM/NLKquY9suF3NQBCEiOhaDGNajSExTosGgJyQFlmW/vnt392AojbgotMul1Ox8juVRDMZRGAAA2w5kSkaj3q1VlW7b2d87rR/THHWeQrVWa/3lGxdfuJQrF2JJFrKwPEHDMUbULNnUVIYiUTiMIiefWRL5WOC7pmkhBI5jOE1hIQTGmlWaSn5rj2KcFeOWTZ3WTg/NTldrWxNlPptBKCrxyosf5hKXA+RBJpWYK6cpxmZjaBARlZMAQl4Whf1uux0XJykiORiIxfIkw4fPN7566YXXPvwQn51uKI2QtOcbzV91XIUun8ud+aAxBBweb43Cymm7PSCOq/sbz1o9CzX08Xjcn52dKC1mBFY4Oqi4rlMqXWXF8/tNG+deBlDw6LCqKrvDgTTa85OeM5k35l89C2h+uAaPd6xQpibeS194bxlLxFQLijy5etp78qR1VKl1D2lIIsgEefnMCp8E5y8Ximlgq4dwmLERWsguhGig9fcco8smxZBjOTPWPs7W9sqa04+n6pZr6Yo5WUhmJs+++eGLPibHMlRpefbOp5vrW6wpr7JFOCMW99aqkSukYrFG816EEPO5ZQLtHTW6F1fmV4tFu14PEM0nJpp+ea21LkdymcWu38xXuo8IIQIIoQbETttcO+wrvnHj4tzlywun++1f/OlnJMtN/mD+57/3jxkCpQmEIPBnGxvt/gCHxEX4bd0MAmZ3cgFFCJwPX2Gd/x9l/9lkWZLmB37Hjx8t7z1X3xtxQ4vMyIzUWZWVlaWrumpad4/o6RkDOBxiAbNdrvEFjeTSyO9AviCNZktwCQJYYAaYwUxPte7SKqtSZ0ZkaHW1PFoLd77gWzTN+kv87HH3x/9/MEv7x6Hxz/9sXitOYSg5jrnvfH7hu8q2eSfolh58+SCMda0aNzcChT1LdcYLljr8/Ur+he4R9egBcbLHhn7pzp+8vHl7BghRRWjYTuIFYqW83Ovtsw47v7KJx6KfGIazlyFQKCwouYIf6ZbTn6lXPgvudjtHJAClwvU0mOw/RCRoPLt37HhHQRI82vuyOz18/Z23isXVg7NndRBeXL6qSDV/zBJu3Rpb24/2Oqfd3tbd8WSCSd4PgmlwJJ5Xb7/26vz8DydnD8cPj8PJlJ4rvfytjQCcesYon5UWblX+7rNRUVmq56v2ZDp3Pv/PfvqD9slz0Z8TNIkiMMk5jtG5e/fe57+d0N5yaoxzFF0vpgwcxIFZKy0JYu6DDz74zfuPvSiozNWjJMuS4MJic/P8wmKzLhdnZpolXW8ZkzYDMQP5nFxgoOiqX+8bTz/5rfHkSMrYs8bq0V/8q7cbi0NguYU8VS/mRzs7Gr/S7q71Te7E8IVE2HyhvH6B8tCRWtA6fb2UK9UEbjQiWJkz0/jpfrS7h3Ol2YvX52lpVEwMmqZDQXAw5Mg8rdUnPn64c9o3h5hIyaCvCh6VJeHUOl9p8LyY0SwiWNuNPQQL5ax5XvvOj19Zu3Xn638/sQ6eOJnDN7iNWz9emHtrPDT6LZ0ncaFYtSbWs+3Ds5a5e9A6a/VJkiLpqSyxKLX//E9/8NM/fS8vw8iftqYmAy0cpLNiLfXd8aBf0GqckseIxJ6/tf+oUqsuLi54YXDaOkEILSzM7XWT493HBCH9YR61W32eJyBgXV0yRphj82+8+vpf/os3IBuSOOcYTEp4DEkLLOk5duR7jhsMO71hp2db0xvXrl2/foME1PPnu8+f7x7vGQLMd89GZ8fj+ZpaUvN5jWdoqn3W4YXif/if/hMT0G4vMnpelGI/8abTrjEdSFq50SzVXly/ePFCPp//1S9/OxqNAUE/+PqxIirlqup6ehSFum60W8NOu+uMQLUkzC8sEYDygqQ79Ka61ZidF3hxNIDjljvq9cfjve3dk/4gpVnGCc5Wzzf/9M/funXnSozGXnSWEuMoM6ct8NXjk+7EfefNa69cr/N1NgbUycg7fdDZ22rbtl2aFTeva4pIySy8uDGvclexYHd0l5Opo4PWs0edcR8Xc6uY35pfqbAszUHqtZdvRxG2/XRt7eJvf/l3vJ5oRV6SBAq41fKKnZaePfq6fTJVpdzGhfWZekGRJqPpELAFQSwOTnYYQBcKxbWNC4wkDwyTV/KQphfUc/ZJst9unR2f6PrE8kyShZ1ht8Q7GRjNr7mLf3mDYcivtx/ef/TQdPGFG4sr60VeIP2xIFANgg8sz5JE7h8++EWjMStIuZvX51ZXV54+fkbTbCFfX5hbwWnaH+w933o8mrSrNbYxT9cbZUhMkywVBCavlk4OB599+jXFoh/92bdm8ipARFGGvhcHUUz7Ec0wEECOB3Pz1fXVmSimbMP/7ON745HZbg8dHQGCilGSEFFFa4xOR6OzbDbXcNpPd7b3YpwRkIyiKA7i9mFLH07dacYwHM3SDJku1mff+86VV9+647vg0QfT1km/1mj86M++W6rmIZMuzC3OVhZ643svXL/Rb+E4giur8z/56aulijSxvIWZphFOU5T5RrT1cHiyF2QBG/heuSo2ZjVMhGFs5XMCx/G2Hk+GcRK6WZxYtu8ESV4rFmvLBMw/2RnE4ZkscpBCnj1xHZNj2HOr5y5vXmYgHyFgm4PRSCco+/aLLyw0l1kWe6lP0+DSlfPeMOr1rYcP70NBQmESRZaqlBgWep4XRRFJUiRJojTFOKVp7uRguLfVCX28urHw1ruvXLpamg4OWQrGcRwjUis1ICd9c3//k8++5Bp5UWIZARTq5SSJmEahXp+lIPP0wdMLlzfKKdnp6LmiuHG9cmFjtXt2vLXdtzwyg+z6hc25hdXjk+FXn93/6vMnOKSLxRLGYDK1TMMZTUzPC3hOoEiDZwuXrl146/UX8wqrT85I7HMshICO4mQy1gWRn5tbQBkJAE6yJMvivKZIEp9mIUkiVRGG49HO7vbpmKI4+w/2CGcgi/HUGJ3sWdNxIvE5rZDnGBxkwzju+ymmYCeKYBoQgWNRFB3aXGiEiZ2V5MLm+vyLN2qFknDlsvD+P/pffhpTQJsO7L/9t78QqLf+5V//JPHbLI1hhu3h5D/9v75ZqMwnRqaPbVGWMBllmTfbKL796pWrV6/Wm7OCqDx4vDPs9kAK81qlM5z+/GcfaAUpy2ICoDRB06nJc2JttjTbUPOlSm+gc6zY65vDsVEpF37+q18f7K+AQLFGdpwNvdDnhEKpVoBE5413ll59fUYrebtHe0E8rTY1SEv/7v/+q6+f9M8G1nyj/MqNchxZAVYEturaRwAAUSRmZuVXXz+/ebGGEhegIJfXT1o7BWhrWv3+l5PQm3Ly2fw5dP2N22vLs1S2xMGsVCgCksdYyjDz219knVZLyclaLsdgazQYbx+f/e1//DsAihydFfOcHwy40AWYTAP4dPfwyRdfhYZZrBXOX77Mi8LY87VGIw3R7t3W7metQWtCJNhxrak95HPQjexUG27tfbA5hH/0zoaeHv/yNw8ePz+Whcr3vv+qmkuyzGFgJQhTkWKrVa3e4K7dOM+x0kTvlivFolYa63ukADmW5UhhbI6Pjp60zo5kGW5erc4tSpiILcvieV7mNUsPPvnom2/ubo2mLd0Y/bO/ekuUMcuQgGZpwIVhDEKfAfTQHhWLEkmmpm62zrrbz45HYzvwY0WqVcqFyJmyDHfn2ubcfPPJ/ePO2QHHUYPe2LKiIEkJguQo6JgGTtKIJIPEViV0/ebqygX12gtzDOn/8sPPpu1YEQrnLy6//u6LLG/rw7ZrJCEXXLu+vP24Nzxr0ySElD+/pLhBJ04cKhfmJSyW+LM2cfw8PHyaMVBdXir85Lu3N69rSnmaphNIcXEcjwZJvxV7tmO7URAjQDJ+kO7snG6nR8Z0IsNRkmSSKGdJCklAgHgyHDRmCvVa9ePP79396Nix2fOb1bXFm3ovDuzTudJysSy/9vpLpEd9+MEDD6Iw8kLHp0hfFIgsixKEAz/xfQzjTFAl2x4ngfzNlzuP7p8wWK7PVucXS1KOCAIxTjzIYI3PQUZ58OzoZz//Xasz9Cnu8vL5Uq2AYGbpvkOEvaPt59u7ZbFAnVKm6Q77Ns2g3lSiaJuhub0jzwtZgoZBis/aI3fb+fDDp9sPj3LK2unZGJIIZ2ka+USU5hiaZ6nzF2be/dZbSwuNYo6jSI+jY8cyIabkwpyqyoY5CSMfIURTPEJoMBhoBakxMyuI/HgysWwjQRkFUYTinFqAHPh97Pxej8paNYzo3tnpP/yXn41HriDlQn96enIQopYk8zm14lg2hTgIRImVaEpy4syZJu44yrFpXiBEVvfsPYmH33vvWrOw8vhefzJ5HGdEr6W3Wid+ZL5485I1SZ8+3hM1Bnmx6zgoC0qFYrFUkiSyOVf70Zurc0v1BBEpSIzBKQrD8SiEQC2o6nDUd02DYahisShyYsikHMNN9PbVK3Nra2uy0hqPjd2d/clkxAp5RQtP20/trsCTsloIORHNLcov3Dn/zitvoSzSp49Mi4h9j2IEW6d3Do6fPT4IPXV5frNRnSVw6LiThGBK5abvPfL8nqrhmy9uXLt2WRIj10g5qAYuI/EzlUIhjepnWx/aI5IXybWL/IWNWZbJqgVF4rA+7MtSVVKK9+5tiXSFo/I0wbM0I9GMoQ90o+O4g8Sn56rS1avrWg4GjsVyqsyXvjjdm54dhYElL1Xzmqi7vu3ZGCAn9O89+CawksCMZ2rzgATTqcGkqNrU7PHBucXGqy9cYLLK/SdPu4O2kEeyCmdnCzQYRL6l8K4okoYfxxhfv7L56W+e7O7tKIqUZTHOos0L56MosYxxTpkbtp39rdNe93RubuHS5kalUgmCgCRwvz/kWGLU91onw9DNIMFZphekWKQYLwo4yDbqM/bUmoxG5TI7JqIXblzxzPQ//aff7m5tBWEmCrlqpSyrPMfG+UJu8+LG9773cr1W0SBjtvuPd7b8CAFaiRMSEFASOZ7ChZy4fmUjVyDml6UXby1JakxB0DsLnt3tWkPI04ySoyy/q1CI41mIGZqgxsPD46Nd20pIQPf3Hp60FvPV5spqkw1TrcSkMI2CmEzLyDMTGOVVamaezxVISGcpQCjNUJpEHhp03d7AdwIf0DQlUJ5reM5EYXlVoEUy9bIkclzL8TVNs5zpYDR85c0btYWrO/dDeyw056qvv/LSheWbI+s5jRPdHHl+WtDmrl3daJ0NtztDHIahayzNSBc3ZjVNcpxh4KclrR6lkWeapWKt33J3n3Unw3huVpRkOgPu4dmpSsgYhwyXxYRvTcZf3n1w78FjOVeKfbi309rd3WcZEIQOTnFO1SpajaGFsWH3egOUUCIJe53h9qO9LEHDKUJQ5GX8fGdfdwye4o52uzyt1ueWppOBY4yzyKTIYGmueuvmpY3zq7V5JPC0wGQ8GyWRTRJRqSArsogwZ5pTwzApCpCQSBOCY8XZ2VnPn6RJOJk408kI0mQhp6Y5PgxDYKsp+MP7IAEmsiikYMbJfSmOZ2e1RkMsl0pJRkZpEPkZxeY4QuaBhClEA4ZAdhZjCEjfH48nJxRVLJcF2/JEjrx2fZ6jhanbPj2xJpOJF0wkGb/66tWF6tqvf/67lnnmeh6W0NJC/fXXbly7uqFpEseTGj4cnN2PEFWora0slG5eO3/33rHI0hQfrC6XdV2Po3RuprCysqLr+sHh3tWb51968Vy5IIUhah2dtE4OJIEHhO56Rl7i5jeXa8XZxWW2UOVLtcbCykxgbykyyzMIIMAxBSm30puS977cDvyEoqiX77y4tDzjeycsQ8YRHvX1blvv9zsUT2s5WRHlJPGSmGAoiaEqEKNxb9w967YP9xkSlmdWLm2+zHFcEkz7PVvmMA0hDaFlTLvtTrd9mFO5OLKfPvxmZTbIa8xcs3Hn1sWvvzCrZbFWEWUJcYnKy/UYcwQKJDaw3YTEZre9OzbtODJ8z/Ud1/L1UqlcXyxVNJ7jqfXbN2eWS5XZQrg7vnL9yur6mu0H7eMvD4/2FFX7zg9vlAtq7I8z5Er5oywl7KnDSsra6twrb5zvDw8vXlx4681bjSYFSJtkcHl+BmAWRCoOBY5GMw1lrrmak2b9pJsggkjJwWT65aftk8O+78UbF8+9+srVUlFjqMgzPQSiVA1QlgSeNRmjucZaFGevvfYix4mffnwvTslarVYo5K/c2rRMFydRqQAx6PR6rUIh/s53ruXLYRBDDOXxNDJNG+JU4UGzUfyjv7g+MysDygljY9RrK3KRTIpkwlj2iM2Hs00FISPDFMtwRbHAApLjCJTassxyHDGjNWbnc/XZsmU5MEUcC5w0SuKYzDDAMQSuLHgcb/uez8GEYhjH8wQ6UnOqIgmV+mIuCfzEdf0JAEFVkzWJQKGzuXEjCgmKkmw3UXLy2OhNzW6tMfPg68d7W6cUQZLAKpegyDI5ocgLthvoBKQc1yyW5Pm50gf3PjfddLZS/NH3Xz5/boYEAQUZNa/m1KLvWRyZ+lzmuAbKqHK5qqg8yfgEFaVxZHm0ouAM+YGf+AGZpZgClMRzej+keRITmISZkJE0BaEZe8NJD+L1c3ONStkYeyVNuXS5eWFj+emTHUAHPM0yEg4tYtgbC5An0lTLKaZ7NDVakIjWzteuX7p8+cLCfLMkCkylLtuO5ViG4wIWApIEFMtignRdfzQcAxJjnCZ+QtNZHA1FUQZEGvo+IghVVWkGplkWRyFKU5xmmPzD8/xDz8IIrqw0vvXehj4JG7XVxaWiwHJJqkZRFkVxSjGYpDEAIEGMSOSK1LlLFVaQW60ezWS+7wM9syxbkUSlQBfq9g9/cO3Xvw7n5yqz82oWW4QdvnT9fLMod43TAEUZDWSFL+ZlVWIJFHmhR9BZjHxR1jx/2JzLv/fuzVsvvUixOU51CUy1zvpJghcWFhqNWpJEne6CkkcFhXenHV5AS43GH735cn8IB6PuijJz54U3zjVvE2km5fRCTfV80rB1SVTTwJE4pJUKaSp3p+HTR5OjA19gmVyj8N4fXT9/npr2HhXyEivmz/qeNUGQIEkqsqzhZNIRJJdj09C1adUpVKCqqONWZzo62DvsX1MXFVXMqWrMoMRLKQIBBCzT84KQIAjH32Y5BhF+EA4BIUJMNUr173+7eXljoAhI5HDkhqKgchSfxP6lzZp+tmh61qUbl9fnFE0B3ubig4fPIzuU59lLm7Nvvnx7braGcCQoHKvytms1rtW0Qtk2vdBHtWKdZwmWtV64vlArV05bByB1EzmmSTqvKphkhsP97/3xy+vnmwKbK1dF3+8DYIgCF0dTHAeaknv59osLS5X1jeXV5TmMYBjGPMXOz1cf3z9ttTqO46dJsLBYv35tjQ6DwJ4SUYABaYx6LMUKAjkcnVYqi/pkzIv5K5fnFherilqgaEzRKCbD5bVyFieeNwSkgTNCKnBzYvnCtR/FMZUBpT90JhMDZInI4GpFk/InIqURSKBwDjOII2kggBs35xulcqUJX37lnKwBAMD4bGwl1kyljqJU4LNqNVtcq730+stra00AYJYSnudEg5hgIA0RK1iz81mtop3fyOU1MkNxGsAoAvrEjMUhAYhiGXz21ZGsMo2GOjN3fmmutDZXy7OsZxq5fGGim2quwIoKr0gZQKYzbczWTg4ehFGHYfhcUcoXnKmx67iTJItKs01W0ronY5YjX3vjBYf07NC/vnn5zesrQTrtDLuKmpe4nGU4cWBXinJPP52MxwAnBIh066Q/AXG22JiZzwY8SQ+CcAxJwEFIIwIkkTXtqVBWOU4SZVVhRIFSZJml2MlwOgLJtRvn5+dnphMXE3F9VuI46vQYeGE39r3E9iqVCg24LIhqeYoiJ/kG/8LNC+srzfnZYk4iSexnoBMj2B1KpVIJISEKQ4oTACaijIh9JAtqsVhVVBbhKE1jkqSmU922bY4hUebTNMWJgu8Fk8kEA8RxHCRJSNN/sEcsS7EsSULuvfdet81Y05oiX3BsI4rdNHMYDjNqgcEsjpI0tVPal8rZuev8ymaFA38ZBL5lJQjzJMgnaSop7uZNMTC4i5f+imLT8fRIkQCKoW6fSBxamuWBpFIqSzIARX7iTbIkpsg0yLhieSFGyXA4SPC4WBFv3roAKSGAY0O3azMzGFFxlJrOLgGS2gwD0BjHqT1JhAqYLRf++PuXHY+y/TEpZAonqbSEMhcyPkAxS2hzpYblTxiO4Wjb1fsUHwsCkyILsjHC8eaV5vwKDegxxkHgkRFyCIL8Z3/1g1eHs5hx1y4uUayr68c0wcKsGtqQYFWFqSzUtVdu6YryZG21mcSIYRGRAq1SKiqCoetxhOu1EkmSyfffNDyC5rlXX7leluwodGkoXcrVz21UVZZU2SxxJ+NRN0xsUiSu32xUtLcdx1EUBWGzIuC3bl+4emE1ioBS4xWZKuYgSid+YNFQgKmkUCTNRSnEXkRioN566Vxj7q+yjJiv1SWRn6kXh11z2DEb9boisxNnhIgYMuDchVrgYkhHLARhFEVRECYkSmhZqVy7VtlIi/XZEisFltuLooBlyPFg8s039y3DRinSCuLKSk3JkWF3AqCjshBCSKKY57haXQO07rr9xZVqHKeuPy0U1XKFI0Dih1OchUkSu64Xp46sUDTJY1IR1LIATmOOojhBUKWVNU3iWBz7LERZcpwFXhzBLCZTHzuBmS9wP/3Lt4b9RNRiSQstexQFIPLjKA0xo0lE4d1vvUyz0uz8bGOxODE642lMsVyzWp/aoywjGjPyu99mXrwxo+X4WllGhMdQIg0ljpLrVZZhKd8LV84p/0J6PVcUFtZqM808AxMchiiIEjkH6IiAIeT6nGxlENCcWFZZ3T2+fn3N/hOUIWrlvLy8ksPIC6OEoehBfwq52DTsLA1mGvM/+el3ncAuqSqITZ5DDEs4jhu4LA4JMg6nmSPnyWKBn2kW0jRl+UTVQJRGFF2HJJ8mQ9cyRZbAccwCMN+opSBxoIWIyYVLl37yZz+olfPdTotIcKFQGPt+iu1COe+4PEFjrczFWUJzy6XS8tPtBwdHBwpP87SyeqG+sVZQpWj2yiVFlZLIda0hxi7IAkgBMS9YTvZ4a5ujufXVcyjJjKldLlc5hk2t0PfCOPFmZsuSVDQMS5KkUlEEKel6tucGADI8J9drPMuyBEGc9Ins98b5/36PcqocJeFgOFBUJWZDnuUwzgBOBBHSKCPp2MqiFKMksEOnh2BKUBmnxpLE8UhNE42lFZYVM+QDygKMmWR6hkUK8iQkdbOv5Yq0CFkCiDRHi8IotHrjM5IiiooisMAKHS/weXkNMOyweyhIvG7rFBHZ7mGUpD3rhGOV2Zllx4pNq09RJMuRuTzNECSNaBwSLJkClMkia5tTUYgbc4v2dJrEU57zBckPYxT7OItIXiixkOaZNAImy0fDcfvx1gf3nz2+VK7cuLFGQNMwTytVjUzgpGcgghFy0ws1OaUAZG0MsuZcjcXq2X5K8/kszQBnVpvOW9/j1m7MNRaX5ALS9U7oWT4FOVgCGKVpHKcWw2VvvfEDNwZ+6omSMBw+IckQiFS7P1BlHoUEwTAiSeGUFjhxZA9Oes95mpJzFEX4+thEmC0U54q5CkkLiEBajozDtmmc1suqkpfdkKTk3MTbN6eTJJMzIqUpdPPmKg1y464PVZfls8XFBXPgj/q2mHN5JcRYGU1OKUJ1TZQmrixFLOPREPCMTMAUgE6EXD9gdTOCsY9JqKoNLgungbu3d9Dv+67N/eCPv/ud771t+vuBqcsqACCMshQz2AMZ5KJiSSEJwrTatuVo+Qogyem0zYogQy7LShwrKbIaJC4gY4ZVgFINfVkCZ2GUEnQAGUbgBQbi3mnvbDSaV0mO5xnIJWlSLPD5ipIRrO+nlVnej3XTHDGQcoN4vrkASRzEDkil9XOLvEjzKsOzWBDEMGJMy52CNEIEQZOMQDRmKUkiRDqt1yTDTiAhmXoSxK6cwykMoySu1NmFnFauaqUZNSN8XR8xBFXIaVyhcHJ6sDDX5GSQkvFA110/1gqzqiraLeP733uP5WQ/OxsP24KocjQHMiCquZFulUvVIhSzLMTY1/VO++jJxZmyUhDziuKFpG8j23AZHJAok5r8ufPLBWnTtZNChSjVUZL4W8/2FqnzUo5nSJjEocDQL928sby2afr68sUyQcSyRPK81zdbEbZFWcpgzJMBJ2XNmdz+8ciNXUGuszhVtODK1XU5H736+g1JqDJI3lydo2HXd/bMaJrFSeCaWRqUyhrLEH7gECTJsJya1/rdwc7BUU7Wshg7fuaFoZRiRVGGo/ZwiNM0FwS+IAgMzfphTEGWpnHoxZOJiVAqKXKWJeXyRTeOCSL5r7Lze/tFvv0twUrMhI04ZhYgnc0sTchTVBHx+ZinOkaXddmvP9+29VSR2SvXZvIaGg5O52bnIbe8e/jAzVwA+HJ+CWREv/NsvilXYZkQE0YRkySPowqTkiA5YqlWjpwSbAXISwmdC0DYGxxlHhHZFA1hGPQaNYnMKMcEFCt5mZUCHbBJClw/TFBaE5hmELthphcrSqHAp46vkkKezruTqWn2IIMgRelhoIrFQo5PYrPTyeKsCUQhpPr1ms3yRBZnaSiiuBx73G9+85tPPv3Nt//qO9VakWYIReW1gmLbtq7rBCZzeDMIbV4gWR457iSKPUkSJUmiIQ7SeGyYrChxLM8ANi8rvuVZgUrS3tQ4C4KgUVsulSpxavnh2DihWJYCMPYDgxfoXE7O5ZV+v59X6NQNFECX5Jxt21YaAlnsGhPWt/PcGksxiGxb0SiDjSCrFKozcpYNJttj53CmWROV2ngasDynFsTWhPZsL5eTPacvCAhlmcxVWaoQJowfWlHm0iySBBrEIRHEiiBahIkAR9HaRI/DMJYFCoJAEWkqTn3ftQNHlCWCopMUkzTvOJ6YcASR+/u///R//B//YbaZ/x/+T//y+s3GwfG9fDnHUHmcSTRkg9AkUJTL5aIo5lU6TiyMAxJwic/ahk/CJF9gyJRFFJ1BJkyyfm8sC+LKzJwzNcbGGUDe0lyZIQBKKNsgWK4SxRTNtX0vkYTKVPcZPtYqYDAYRT5PgII8wzmZ6Rs+63LVfEmusoPgjBSIOOQxklzfY8QMETHNKgQSJSCbzgQIyHB0QECWVMiIto0wTU6vXn/TCYje9CCjujSdRBajsnPtfb9Y8uea8ai3KzD5auX8cOgKSh5FqCZQhGtmiHFILqSonAKJWPeMhu/rqkorecb0bD2MtWrzrD8GYppTVYllp8PRoN3naa6ollCCdCpOM6dULuCEzRKRgaLtdknaTTkKoCQcMqHlq4pZqTSyuNTpt8okzBXIxhx7dHwa2LmZ+lU/6kC+a0+DKEpy+SLDykGIZKXgeBHL8hi0Qp1AiURIMqYwCqYZ8lMBZjhmB2kxLtop0+YoUBRFEsthnEpkkiSAyBiKpCAmspQEiILQjQc5rcDQEgV5z4j8kc8iOnFjmGchhZQcBDAGZMqyLE1xiqx5fpamKUIoCALP8wAAGGPXddliPUXGf/nZfz2T7ff/XyMpVatgPgscFqUMJsQMiY6OdN9IRTYA9Ke/ff7Zh49PDgaSRPnOne9+/1atJNJQ7vZPXCfZOxxMdHd9Db1wdWNtZcE220Zsxq5N2KTl5BLbFzBdyZsFzbeSgW/QTNB0CLM16LqePVerrK5UI3eSZlXXdnDGDieBH0/mVwo0RfhUQAEJJqSjiyM3MwwPkU4SUVlKlDU+TcmpHUHAFmdKvEB5AQKhJ/Iywn6CESeJFXVJD+J+r8NjqJVow+q67oSnM1VdevHO7ebKgjpP5dSyIhcCP+2djoOQQVhFOM7V8gVGCSI9iHQ5r2pUOYhS000ruXmOIbS8H6PIdb3AdVqnU8cww5RhuIzjAc9pxpgcdvQ48UiKWG7MmqYJMkFVSoLAGPooSfBc88pw1CUB40WWwDmsAPiIzAhSEwuYZDFBZmTGy/mAZKamMrYTOxqXWF5UmnMFJULp7p4TBHS5qtku4oTl7uRZTqGqlVlAIJRAgc8HTowwThHpWbHn2+WCJjCcNfVCIaVUMUxImmcRpjw/MacmDUJcyVnGWNPyakGlaDKMEkyAJKRGA3+l3rSM9MbNlwlSXVqav33nheF0mxXyKRJBKkBChpRCQs4PrMmE8VyERpySkwmQOGaQBCzDVEQBhVHC0gHCxGisUwxdLMreRO930kappGiXs9i3pgOZYwiEEZGmWUBzAq/UwtTtjvwoxI1C0fEnccpyQsmz2Ht3d/gitbGy4kXm8cleEckx7w77Tl5Z8Fx/MBzPzFdYQUhTwXGRg0dhGuV5laLyvh85bhA5rj6wU5e8+/n7MYHUMrl6QZtrzIc+tqzSbKUyNR84rrd6/iaRkiiharWaIMqQ4FNjECcJAqBUmYGqYkw7tmXxXI4DsaRCPxpZjq7bgR1FJCOYE4NEmCuWGE4ANO0liQoJJa8N+5Mwoh2dxAhlmcMwYRC6OPJ9C3EUSZFRPgdUWSRQGEQdhvFRNPvs6dbf/cNnrEBePPem4ziyprESIqMpEgFNcQRBpaEzDUZeELEsDws5mucBI3gopUFMQByloSznESeJgGQ9HrgeAScxBDxJsaKQ0ALHkxgDlMYZJBmRT5PIcl0S03FG+3EU+m4WZuVCuVmoeqY7skeixKg5Ic28MHKCwLNjx7ZtimYxBhDSGKckSQBAYgQgSRtWjwABQZT+MI+KpWoI0ZPj7UZ+gWHFzMsCnxaEGS8j9vf2nx0+O7qvT8ZA4BuqwkhyrVJuAsJ1HAdn4faTk/d/fj/NAMi4c0ulZkMKXZYDilKEU39y/8GD/pG23lyvvSaSXCqpkI2aETFzerD/N3//wfbTgxevLv63/+t3i4KPM46hKwHStg8ePHr2zYsvr772xlULGL4Z9479va3RoJealsGw4/PntVtvr09Ic3Q6pYN6s1HNS06UmoaXSRTfHZxSMBUEgeKkrZ3Drf3+3vHWCysbr72z2CjnqbkEAUE3IkomNVis1rRh3z3eHR7tD103rDeKK2sriysNRaD9UEcMDTguxUSKuf7IenBv59ndj/JlTatpMY4934h8y9WnWRTGKQvphOPJNGZRoiwunFs/tyRIzIPJASR5mpL6vU6apo43AWQ8M1s5v7FZyhUJ4tQMBhCFUQQYgZZIOWQFjLCXuUEAjk7Q4YkxMkOCSW5dunJ5YWEwPdINrzF7zbXZx0+eH54c2ebRWeebH/3Zrddeu4wygqZEmsx1pu1P7n2tj8aR5weed/Hc+tWrlzGRDxFHB+C0NXT8M90Ku93udNgXWGJjbfGVP3qRIJDrO7Ebhn4MCZ6meBSp//5vPgWAXpxbvXz1er1RMCx3oocAiiAWwhQnkc/Q0DJdw3AYhkti7KUEJhzTmAwHumdnOIvkXFqb4WtltjlXTzMcR7YqsZWCUFIERUAjRxq0nZ3HnYtrc4UCL0pCRqAwtc2xJAi1Zzv39/dOvvVHt3iJCAKmXCh128ZHn+9CJZRpbUaWSJXnOQgYWKushq7w5WcPvvrq4dr6ws2XbhTy6snJMMHDKEn6nzzcPzojAesavm+EDMkW8PLB6aGX6Slrfvf7r7339sbxtvv84d7muej8paXQb3cGrsSxw+4kCeLZeo2gRD7xFIF3XM9ydQogP/BKpRLLkMORE0SuZU9JSEsS58Q+ywgsJesjP/KmuXyh2rwYhqERhr3uROMb+qDfO3ZG436cWtW6XK2WcrkCnZACCSGcQORksWK5vpfYHC8r3MbdB4+f749uvLiSKxUSjIIATq1gvr481c2zbp9iEo6VCJKiac4PU5paBIDHGfT8ocoBnuWNQQeG5DTh8plCMixdShQ69CgLRTBChZjEjp8gAnOcQEBCDxyCIClFYQIhSFjHcymKklU5JdKhM0JJHCU2nXC+n8WpE8chQmkYxkmSyaqUZRmBYZoQUZQxNM8wHEmSisSZ3n+97Oj/n0d+GCCW0vI1BsY0RKYdJBHF8pRpmPfuPvjywRccLgCS4wUhyexWZ/vgVMrnYRB6+tQ4PZzaI5biNZ+N0gAAkfNJREFU4LA/PDndykkLWi4vJXkvsy3X7HR633zVPdkezc9dVEvpQeuQJjYPTo9/++UXTx73jA57qpppaiXpxLEKmFx4/FT/4ONnzw+eYSp89c1XEtrr9CfPHra3n1gTi/b9kCG7MB299M7qcDz86NNnhB2//eYsrTEYdIeOxUmrXhhUqirkcs6E+ujzr5/v9k3LOf7UqVVnGmtpTI0ySLs+jaFsBb67R+7vtvee959vtRw7oihqcan+x3/yw9lFO4wNio+VPEdTQr/vP3xy+vlXBwePJjTXYRRxakwwxkUtr7Bsozo/GOlBpBMgisIwDj1TZybTKQLm7vMdnstpuZnjw77rupBCvIgqVe3aDeL65epyE6s8EUcuIHiJ4QEhp4iGnB+65mnb/e3H7b39JMEohZZlOXyZ5kSWEnjLZz788Mn7P//Itu3Itqfm0fXry8HNxPWHNFRslBzsjz7+4PhgZysNHA5mIpRfuvWqopUSnJj9+PmT6fbBSW+o67oeulZB4TKfu/YtTsvJfoLNqUsTvCzV+23z418/ebAz8F2zoDx77dWXaGrFckAKSMtNs2w6Hhvt9tCxw253OBwboiABAENUjFPHc8wkJoiMsp0xw9mzC8wbt99YXLnQKPHWtMWAWOYgiv3WoB2Q8wd77qBLVvOkIIAMhhmOwxRbcel3n95//2cfnRyd+RitnysUtGIc+//m//3Lk+kZKbmL9d3ld+9U52d0vz/sjym+tvXk5OPfbR3s9/RRcunCK0ac/fIfPnWTyUmrZ/lxlJA5tcgzApWJ+mhcIsdCrsBx9Nlw+vRRyxl+3D9OrDGVhsML17+tFJbSzHF9/PXXT6eD1g++8wafY8ks0YOpFwYMzZOAiOMQMTQjUQTCoRckMeZEHlByhMB0GNz96plhewhRWrmeK5YyAg+m49FoIEf8qB+6Ngpih+achdXy6gpfKua8iXNudU4r+Ah7aSikGUXCiOby0x4H6eb3f/TXL9yas61IH9gUUxP45qMTj6LkURiGZjyZdnu9Ac8LgiD0n3l0ADiaT2hjfY29uCQKqkhQNKvMRDEdECorQiLDUeBmserFPFRK1rQ/HJt+ONIt13FDJZ9vNpvnilVOzIVIhxCLqpj5dph4vAA1WsQ4M62J69okxLIsiiKfJAnP83GUYkwAkCKMKSrjeMBy0Aj5wHX+cI883TMTSSvCdIpxRDPIDbxvHn39uw/vf/XgHqBjguEBjU3LDMNhd+RbfqNQLYLEaR2anWOTAlIxLyw0i3NNLUsDLyDi2I5pF1I0x0tuoB/pPcNZ8WKUQdUzqa3nna++eToaeCV5jaMTQx8xMEBkc3dn+v77Xz3Z3skVuWpjJkvYlMC9o8Hhs+fDnoOlJuC4NMzS2HOdru0YT590WjsERTX5Ml2bp2kB+AGem1+WNWk4Ql/eP3j6fLfXM2VZ3bjSyJe4ILI6HXMwibZ2R7YDpoaNgnRnZw9joOVLspIfDY0nj53mzPNKI1er5W2/73q6qrJnrc6HH3+1/aTfyJeDOA4Cj8C0KhcFthA4yQSzFM2LlBZGriTxnFZwHP/u3acENFUx1z6b0GSlXm8OB+PJtAdI0nfBB7971O/K77xZffXFMsmA0AyiKEp8A6izkpyFgB5MvUdP270eFCTOjyYUFz/bq1+/sZEC/Muf/eyf/vHueOQCADaWNEGc4dkiABABM8rccdd+vj12RgUBLjvomKDsQrnASFSCEknJ3ftkf2939Px5R7cdiqIkroARnIzRaGgykGIYYXXlnMio7RNjZ7u1u93zQyEIKBu7OPWy2Hu0tf9s93BiOkmAbMc0HZvluAzDNMVZipIkanePFZUFJOIYKZ8vSgLvBceBG0IgcJQIUoIl6LzIJr7jOg5F8oNR+PDBSWvvME2Cy9ffrswwI92ELjoaob//2UeDjsUJVZQJ84sXQz/6f/7r//Dk8RDJJA7x8eGw1x2lKjADl8CiFYCj/SmJtc2NmTA2aqUZwzCePrqPSJliS0VR9UJARKSle6rMNyorMsYD4ySLrPPn55eW1s8OR52OxQLxycHW3mmlMHPLddSdZ6dffNafjA5UKf+9n3ybJ3EQjHiRYQToJD5OM9P00kggEp6imLyk+gnwI4gSfu/52W9+/ohl5QxxTjgMkiwlMaYIAFGdJAOP9jw6wxkGYb93+vi+DfBWSYrzf/69uXkVkKFvQxzTMWInHcs6Gj582i7pplaDRa1Um5mlYf70+OibXhCG4cHBwXA47PX6ZyenoijKsuwhyEVsQdOAaJ2eYPqNC4uLdYy442PfO/OXy9Tly7Uidh0fWFNu0Gee/u6p63vDwbTV6U4NG5BMTs2LSvvyknzh8rm5+WqxLIZJyrOkqghp4NIU5fux43iW5UIIAICSJFAUhTMOEClNkzSdYewilMSJg3CKoyaJAEH81yvYfq9HUTCSJRkjL/A9RRV4EZ6eDb74au/rbx44nrF+oXlh4xbAysHO6fGhDSGkKAYQ0Ha9wFTPjqaOjy7fuHDzhZVqlTk7OAORpNAkV6RzSlXNu/liSsZ0vTlPs1OPaHx+d+uLe1PTNgnAEQSlqbIqy0BRAazfe7R9eNwiyaDeUK9d33Sd+Kw/3rt/2ts59FHASlRKVliaKmpqs1zqYTqnVE8x3D/q1J5AIScsLW7Y+zzH88cnw+c77t/+50/a3Q7P0ZuXL/2rf/lmsSo/fHz44GH39AQdH7p+RLi+l89HCKG5+XouL/V6Z7Y/bjYXarNMRZMKOR6QTH8y7rmJZ5kMJCmSwGgUhoETIk4s5FQeZti0nNiKGpeDzUvnT44733y5n5M5gVdTd0pg3jMSGkAi86LEIbBRLYuyLHa7XTknPLr3lKdHa0uv1UvFEA1gkgKSzAI3Ct0sy1w3NSwfkDxDYctMhyMXYf7gqPXRh599/eVR6PPVihZGvm604oiKPCDyBV6pdnqDb+49++DDgUhekrhwOt1qLit33rk206x8+eVT/8j46svt0+Ox5yMCMIIoiQIfO+7p2eDL333w7e+8XdTEOHBxhPvd3tFhazi25Nq8KlDWcAsFRu9k/1c/+/nUBCRTYLAcJgkOM4bNcbxKMxLNsbquN0sUJsLA12kAeUIgcCII9bmmXC/XJsNRMI04MvBiWuAUNV+yLf9nP/vN2UHXt9zRZGg5k6iLLBsL3KLn6xTkg3AKGLy+vnHl0tUPfvPB7tbO8urtoT+xoxQAEadkFGCJrVQqjd9+1d153puMfJZOwnQwHBzGqTU3R7fOMoXlTSckMnZ1ddlzhqE3ksW0rOBzN5au3Nqszy4/edTefnjs+W0rcZYWE7WMJ/r0689P28fuaJh2OubD7b0bo5fkCiPnVJYjHYxdy5Y5VqR5x46zBAuQ4XkBMiRB0SCiPdvLIiLBMI6JOKBZThUZJiMjTKSdzkOW1uKIZTiZ5tUUp0FAZmk06j2e2hcitMiy2CcnGS9SZKl71vv417/pDve5Tqc6h15+KQ+JbDK2n213vznWz06Pz87OcJpIkiRJZQqCKCQid5ATqhzKkiAZd4zuybBRmHci/Mv3v2rtHd+8uFaf/b6slazB5OHX+vaDbmdqI4TSJImjHJupAIDQJ/1u/KvnX3384b3X33nxL/7iPcCRpjVhZBqg0JokBCYpyGt5jiAIkiAIDCEF4xAmaYpoQAAQRyhOfEgRBEGIXG049f5gjyBpizT04yRxGSDIw8Ho3r2Dg/0BRmyjPn/10rU/++lf2gb6x+RXrdZzTFAI0WEM9Elw9DylgTg3R12+Vq3WyG7ncDI0FmpVlqJsK4gjEEYZyWQ4S0maTzPVc4sPnt7b3j0FfKzkNW+qO44Q+Q3L41q7w6/ubTv2eG5eePGFhZXF2t5O+zc/e9K7NyxS6spyIa4W99okNlhVrqlUwQCgWW8MZsz+ZPfD37kEXpDeatTzTdPoP3rc/vzLYXcQyTn19surf/bjN6x0PDkebu+OH31jTsccSeRFJojDfrWh5QqzhUKehFjJz7z21sbq+tyNm0WeykatE8BFRVVxPHzl0vnZ2uXnzwc//5t/PbewkCtUm/OrNCU9+PrxtNuPo+z26++88cZr33z95NHjnYnZrrCIlVLIEJwhXHvx5tq5OqRjRRWrlYbnZv/u3/6H41NTn46fb0V7u3peXWZFQuRZkWeHg9A19SiLkxgBnApCpkoABYogzVa19U5v6/H9vSQgS3lN4CWWU0et0Pf8k8PuycE4hfbO7nDr6RglSorcdn+PEt3bb15b2awRFOx0/H/6z1+2TgZ+HFIMlYEsSaIwBK7noih59uXnFxcrxGJNVZWMiB8+/Obeva/jhDGnOoWGCk+sL1YDx2YycrG+3h2mLElSlJgi2xhME+TyvKbkipYdiayOkU3EE4bOs4AGRJDLM9fWF5ebMyCMOImUaMmzXAYWHRf+w/uf/PyX35AZVAVYrjWD1Eg8gFCj10ZffPaZbdumYaxfW7t+9Wrr+OiX7/8jSFOKIUUghoTEsVKpWNN40g4wERWm4wNTDzCiXM9+461rK2saAeH/8f/8l7/4L0etluEEcDR1d57/rlpmfvTD23NzudA3tLJamqmenU62nhyijFQ1TNPRez9+tzJX+fqTrz/5aA9FqmVZlUZt48YmgJRhOQr0CRISDJAVkQWApSGRsb7nIxzatgM5kRPVkMgaTSlXYvWJPuj5JKnUpHmeJf0oylA4P68sLM8xrASh5rh47+DMsCZh5iyvlxk11S2Xz7KQsAS1xFHnxpZlhj1Aw9n5pYWV9XK93j/xP/jd3Q8/+CrhpMA051QF4DRLYzcNaZLKK8okCWcUOgksRsUNrZzjKpknHez1jJZ7dnCsMkHr7Dw/Yr/8ZPfuF9Ojo0jK4ySKcZyykOQoyBAkIBCJCajMH54+/+azxy9cP3/1cj1yPQenFU0MSRoAioKMKEgY4yB0WQZyPOl7FMaYpikIQZpkANAURZIk8eD+3ccH26K2+Yd5JAkAx46mVh1dsw3i8YPjr7/aH49QFDAL8423Xvv21BiM+2G7fRInQaVSKZVKUegcH59+/kmU18pLa2K1wYkKJkmBm1dLUjnyM4GVwiTpj4amMykrFZbn+/3eL96/NxqZNAdTiEmYIsIThXyjMvu1bT7d7Yymdhg5c/PlN1674jrTf/tv/j9ff2ZVsfD2t1668f2FPs/Hv+60nFMCyeYoYTKpXi3lC9PTs1a/l57s5bcL48q1JdPwoog+OTFmZ88VKv5LL1+szQo7u84nH32ztz31XZWBsj5tazXn9iul5srS7MyiKKhh6DcXCvVZdmLuOvEDOVzodk4wFarFPCZ4jKO8mrt4fmnlv/tvqzONKENhmj17tj0ePWdZZ35xtl6bsy3PcRxRoj3Xdvx0doG/fG39dv0vyjU+TLsk5VSqGsfKcUjfuX39+fbf52RJYBXfJ1EmMiyIUjdyvLxc18OEQBgCiqIRx2SqQnFk8ertH54eWo+f7vG0plU1z0HD7iBDQWgjjKlcrjA3uz422FG/c7xvhR4/nezGxOSf/ct3/9X/5kdDo/380dawjfefmZY75mReVpU0iOMkYmhSFEVeZXJ8v6blcyJLw4ykSYYCnMDl85WxRcR++P0fvHPr2sW/+Z//JnI8kkh6p9OCGqoFNp+j3ACZdpjFIc4SEuGFZrKyOq+oKyInarnZJEohHS6tVmRFTSOLIjKGogErez6xf9T/6ps9SJOqoizMaHdeuRlnfc9KFXH19Mh8/PiRY5ulgnb1yiYNiK2d565t5VTprHNYnp/L7Ozw8KTXHbLVgqFnwAn3906mE5tnCgil33r3tdoM1+nuzy/n/pu//t6/+Xd/93S7y3F+oRC9eGvhu9+/AIGlG0yCM4QSx44cK9WnThhOX3tr9tU330YRODw8ODrctadEuZL/4Z9955W31vNyIdMPIYRBHCAABSGPo4TjOIqkIMVAEh2etMI0o0UtBMLcYv5/93/4VydHo8cPj9unhmNHlt5hWDzXrLzyxsbNFy5xomC7cOvZyI6mSa/P4/Cnf/kvLl6q0iQgaR8Tth8Dcwg++ux40D2pVZWf/PTP77wys/P88S/ff/Cf//3nw5595+VrpjEkBJqhYLVcaF64tr66uL6+Tgoum2pffv7UJqzF84XFesV3qCf3T72xSwNcKLB5jXOtuNea6IYnqSUAdys1mcY4dq2cyC81aorAh77/8UNvpjqfRO7zJ89XFxRR4BzzLLQHzcpNy3RNw/GcNE1TPzAVlZcVLggxQRAULbMsT9N8kmCUAZQR//hP//F40P/Oj/5Aj0RFxVTOyiSPH//u5zv3Ptv37Ixludnm+Te++62eH/kPvnrwcDQ8OwIZmSvRWpk5251pH1ISTerO8MVmY65ZYEKrIKkBW+wbpFyW82Jh+9OH7e3J9GwsL9FOlnZH2c//fjfLMTaffeedH9tH046/xQhoFJa+/Ow3H/x6FCF2br367T95M6XEX/z9NxkqqWuTi4vnfvDf/Zk2Yw++PuAyBrLQzznD4a8obunmixetGOycbru2u7cv2NOAay6HvvgPH371aOfxygL4zvU/funiTX+ctM7Cf/ztbnHmSm6l+ezh3Te+u/FHP7rQM54qLD0zWwCkhjJWEARX16Gj5Uk2KzCl+aUoipM487zA99scOynk8kIlB9kzjJiDx9Sj3x5F02hxjvurv35Lu17e+dK8+8sJihay3F5hA/+rv/5emeIWm76uH5POlCIQgZwsEKd9W+Ont699e+/40UlrTw8MLk+iwCMyj8HIwzZFLSYu02t/TkMtTpiDQ9t3PWl2O/adb77Y41nIcoYf+QnISvVKs1HdPd4ah2ZH9z/66Pm//be/rWtzs2XmuX744x+89tYrbzz+qvvkycOn97ZbO4Nzi819A7fb+7nK3Llzs7s7R8ORWanM2RkJpQBKwPJTq++0O2effPZ4qnuy6FlGdP3S/O3XN5RK+u0/eam+vvDLj3euNYpvXb9eqFQ//OrL93/xa7VQmGmo1rS/OJ//3/9v/1pUIj9yRK7OSVSU9VieIrIc4HRPD2Ves6djmgEE5E86uqJulhY+dka7L935zvpi3ZjwNgID3dsafB3Z83PNmYn7BVV+ejxe/tv/bOzt10uNABTCXD6iPC3ogVMnFS+ZygLr9HrjkUTjtfHwq3feLSrSMAgsSjwN4vNRcmU8eWJMU8s+WLtYeOXNJUqxdX1an/cTf/VkJ//0s87R1kEG+jMrysrmlaCPDg/sUVfCtCpow83L3MuXmutqHYY9G0GSLDMMIAkgUEKQek+39nieV1U5ScNirYExIADtuTHDCVHRV8vixauvP7vX+fXPP+EYPBwcn1tZvL62mqN0iR9wKQN9K5ziNK4Wmxszazcd36AQaUxzonax3TvcevDL6KAfWaByRSnXGLs1zk/z+IymQFmYbQxK0vmr792+dn2mWOifnZXKGkmBj/aeW0Zrvjk3c2OuoaoS17azrX/64vBXX1ohAV+4ePm1y/MSId0/6Ox0rZSdxP7zi3PLM82CVmTn5yrValURijgT9rZPHxr3K5ry5JtP2wenZeF7xUq1Q5FRYg/0wHM8P/J4HJfK+aa8HEWBaRmAYAqFPC8wlm1PLTOJKQhlCITFpdmNzZXft6H9ez2yDT8EKKbS1ql+ctzz3NgyfQAwUSF2t593P30enH1FUfNyTo0IZjy0Hz/YHx3lhy2PYO2lRfXSjcXqbC5zR7btuTFle4JS5FzPIQDiRaFQLJMUe//rJ4enW+XcTCfovvTK5bffvPkPZz/Tbas9sO7e299/2IudAJL+zVsvlAr1e18/uv/wYNiLisulN7/7klIh94+PJpMUpTzHR4LaXVhbSjIR8uDCheqts80nj/aPDqfDdhT+3/5DHKREyN1Y27h8Zf6VF+9AMu4NnhvdCQxtb3QsZoQCstHO6P77x3GGgKK3Do4VxWUYTlHIlXmpPqe5phOlgOEVhid8308JQPMcx3EsS5uGofEwTelWd+oGWUJk5UZVLUqTo+ePP3nuDy2JQovnq+/+YOPcjJSNQ9M+SbLADsahG5a0Rl7NpyQXEHSr1ZpMJlo1L7B85Eciy6AUeIFn2gjQmW5A27a9IKAgSVGUrIjd3ul02MvlRY7CNAMTFJGQyueKIsNQffrZs73/y//1X2892XKmYSpE28f3VtZzN25dmG3OtfoAI204zA5bbpLatqcvr8z82U9+tHHx4vvv/+L993+XZdbS4jnHbhkTXK7mAOKmQwMlSqVQYhglQcMrVxaKJToIB6IUXL/aKFTKCalsLFzwQvzx3Xvl0lxzfl6RaWN8unpuoVZV/HTAICKKbexRmM7SGJRLWnfUxQg6tp9mJE/Jg5FzetIe9MwkJRZnZ2fqVUQEBBOjDOzs7v/it78MzPmJ0Ss2wHxz8ejgaDIeMjSwzPHtH70RD9yWccpzOd9FLFXCKfH4/tNe73AyMStVYa45kyXJeGRzimpb6PnjB6328VTvl8rqi7cunj+/LknAtl3HDemM6XTHuq6nOC6Wc6++euHFW9dd3T98fmiMJ7Y+rjfYO3euVauiYbQlJkZU4nheOA0YlpQjMQgC33ebzfk0DX3fZzia53mK5rOUohjW8dw4hBRmTMMzTKc3aF25uvzq27cga9qhSYbMwcH4/oOz0cgKCQxQ8qt//Cz0ekQapCmTksLh0QnMMGQwDTsz9bnAnvhYffj06Oleuz63Ejnuy1dvaIps9kePP/ni8GBnYXFOzin9cf9oZ3txbvTmHe7iUhWSVOcsM80ojFxGEmabxaW1ZhRF/d7EdwlR0K5fXvnTb7+gFcU4NVgGSxJD4tg2AwhGteriyf4WQ0soIw8PjwV5RpKUZqHm9hBKkzRLSJpK4szx3CiKPD8qalIQ+WHiZgTOayoAIkrpJAb/7J//SRD5//TRf/2J7fd6REGRgYKXUMYEBB6ZJpCnFVHOd89ODk+f1xaV/iAgiT6kBSVfX1+91qwv9p+Zo46fMQeNpRvNJYUVsOciSDMMyYmE0Ou2aCbjOLZQLLmOCsj0+fbBWfssM9jFxdnvvHljocGHyYRX1QgLDx53gaXVC4G4iC9dm3385OAXP98OfDmnyZdfWhU0uj06pXh1dq72wSff6Hpb4ATAkWnoB0GP5+I7dzYWmsuff7Kz9ajlffCc56SNjY3K3MpMpRRFoNVvxyBonz0mUx34LKOU2Sg9uLfffXLkB5abi3lBqTfnKvVSLo/Cm3PCrZkMUroRSDKgKDJGmOJZUeRZlsYEAjSfkeFp1368dTw0TIIhzl1eXTw/9+iLT7a/+TJyinyOub4299aNeX88yLHa/niHorkojlPAMlI1gdrWaeuXH96j6FlV5i9szC/NLwmcyNLY9/QkSyVJISgZ60GCMMbYC/w4TLI4CkgAUEizuN/rNJvN5lyDIFmc0e3JgZwX/YB49rjNAG19qUymLk0EP/7pW5euLKCMPDywHj+aTi1JLi54GM40Zq/fuNJoNFqnJ/1Bh+OIKLF39h5WRWToYGG+5hBWr71lTQkAyMlwVJqNNi7WeS52jQ4LsSzi1QWJIKkQDb64+/zw4CxwyHHfnQ4nlSK+clkN4n4UGzRkTFd3nJSkE4IAHF2tVmZPD9vD8URiJS8Iv7m/t7d/Oh7H6+vzf/W/+N7mhdJEP4lR5qaM4XkLKxdaQYBI/rXXLterC198eNe0xrLCXLy2+e7bd+79+u6BQHE8FyY0Tc5uPX70d3/7gW3HCLh37ty6em2NZek4FSEuGhP0d3//H9udfpqF+UJ5fqHmB95ENyDJOC7v2/6D+1tj3VBUtt5QLl0+Xyrk7j89Pdk/HfUHtYr2R9+68uKt8xnSO2fH+XyupBXypZxjEX7gTqdjhDNFlR3HYVmYZZlpelmGa/UCRrRhuTFMZK7QO3UePdi13ZiThGu3N2dWtMyzwogkqNxwYo2HmKFyVOzGrv+797/J0gkgzZyWQ1g7ObGKOYnn3JmF5MqVSl7hx2Pv2d6QEgoz6+etk70v/ulrgDPftIg0cXync2JCntYqRZbWnj1uE+HHi81oZoaa6lTgy3NN2k2N8+frS8uNg6PpYOgRWM0r0s3LVxfWl0WJmUzbgW96MRl6fut0fHDaMiZzlo4DK00TyFCyZYYHp3uKyspANU2ToihRFFNMQEQquaKaLwEchpEfpTHL8gzLY4JOE0AypOtOaO73Fmb/Xo+yJMVEbmur+49/9+nJXldTiqVCNQjDyaTFSCSFRUjTAOVcP52bb8zPrRm68ezpjj4y5jbh4nlF1KDluYGfiYC2wmDiZhzh1xsNQKZibkiQhmFaUWgahnlj6ZWf/jevvvDObH8yoNmYkqXeJJwEZ3BgVOeZ117byBeo/+lff7C/na2tbbje2Vdffj09mczmxRh5RqDops3RrD9VECEDLJBIpKmg3gAzc7NJCqdTirTijIjaw15xXiov1CwMggBL2tzS5slet31ypCfJWRohpcyqAgrOhhCUilopsIOvD+4RVBSHYb5YKhaKCFtBgCgakRAKLMvyVIbiMPQTJA3ao8ePh6aNGEmoVRtyWdw7Pfjy06dhDDMI3/3Bt9753mIcjqOQ0GNEUVIhX2doautZ9+7X90bD8LQ97nZ8Nd5nOYIGMQ4Da6qbmZ7GRpYFFJEiGI8neuCHgiQyCfSwG6MMwKhcll1jUC7Tr7xySSvOP3x6/LuP7lKyXimvuE5kT/yl+YUkcgUy/ulPvvPCq+thYP7uV8/+6WeP9vaHSl4r1WcsZ2SMJ48e7B0ddvzQ8X2/oNWzlPS9mONSQVQQgdrtTr8zShNEkoEfDIuKJnPAtWxI0CwLAt8hCAIh9Pz09L/87OeTMe85BE5NSZz++PuXXnqxHrgjNadIkszzSeDHcZYmMQ5cz4kihAiK4SlOtcy43TEt0wUkXJ4vz88WPG8w0E8X1y76E+bg8PHjJ70aLy+tLL/68msHuwe99iCJXc+PLl++wtFZmji8QBrW5PBg0DrFdz87c3QCE+bsHHv7znqtqiZJyNIlz6bbJ51O90SSRTVXObcx25jVomhi6G61Mmf5zNaz3lffPIkCoj6vzM4VS+V8FEU4orMQ2IZ9/doL33r3jbwGIsdaWp31Q8pJUxqTnKJIiggIRAICEjhJGVnhGZa2HDOKIst0bCscTYxE4GsluXV22m1PgjCpzWu1uSIjxykhZiTX7YGdnXg8ppOIjQN71B5iv8HxckrYJExFVlmenWP5dOrcO3d1rrkwy3O5j+59dXg6KTQWB6MT3z4GNlAEniOAoCqlYs7y7ZFlBEGQ2CaOgecbA/0McoXdw2Dr6aA7nl55eW55uR5E4bPtw+OzoT71yCzZfnIUkDwBUssY+YHJMkwWk93O6PjI4OG8LBVo7Kyvn8/lcsNBi2PFnFog7IhlWUVRJFE2LNt1HYQoSZIoBlCApQgWk9ALAj+wSZIWeEmQ8EQfEkT+D/QII9div/x40Gt7qpoHKOucnUaxS1NOo14NvdFbr/7QMqX945O8Vo8TfPerTz+/+4yASaGm5oqFDPOOF5OplpBUnNGSlPeHE5biBqOzzmBoukmaIoIgFV5urlRWV4tE1E+8Ac0QU8sO40hJBDAcbFw+d+XyhdPB4OhowHMrge269iAm0s+eGs1CI2Ucl0xclyoJudXKH9cr+UcPu9NJmFJJZR7MzPKmXT/Ys4+2dZp1Siv84o0SU4dPjo96fWdhYaOwcOV7Pz3Xbpnt9njQ7+VlqlkRZnVibEsir44GDsfMYkxsP+rl5NaP//R71fJZFAWYSFkOAoA8xwpCP8uScnXxyejwm3u74y7Pc+Ctd1+6cXO13x+ODJXMN2ea65uvvcbk8MnxkMYlFCvNWmk08vf3xg++MR4+OhmMbQwggBwt9K9fv7K0UGCoDCcxpMhiY4YAycleQpBxbziaGiZBAJphlJxKKBJmkGWOGTp8552X3nv3VYYrnbZHLE2NuiGRjRVxVqDp0Lctv3t+JX/z1nlMk8e77c8+/frgeVfgawIjB14AaYbjSoO2ebzfgQxUcqooiEkC4oBEORMw8f7Jk1//9hc7uwOUsoIE6zP4J99/9/zSSuS3eA6yLLZMi6byoQcmE9c0PJrKcwymiHhhrnzl4qIq4cTPRIZPIyxytMiLYUgAQCOUTv2oXKtGOWI8io9b/dOziRdERS13+coMxfqCTJVAeaQ729uhPiIzX/OIdq2xAiH8/LN7BObrjZJWxqUqf3r4DBIRSSVja7R70JI/2H72qF/UZiNn9Mbra0vLOYGDiBUAWRxOiJOTZ56ve64+v3Tx3IXZWj3HMlKt2gw8snuiH58emraPMS6UG5cuX9By+eGo/+UX945PuryoLq2sFUsVN+iFflYvVaCY73RaRBZqKsOQJE3EAOIoiRAmB4NRkgSCzKcJmkwmUYgVRbGBtrXd/t3vPvejkBeozUtrpYoURhbKFAyFw5PW/nFoOmQax0QWI+SrIuJkyo1BGHmhO4KIVTV2udF853vvVGdWXTPb2R14Ccml/qOHvysUSSNwSCj5npsiQS2oaoEhJTJXwups8/zKxoWNSmUm3d8fnp6lGRJkyb3z8oXl5eX28fFZ2yQprlih8hwcdSeH/SeWZQShg9IEQshQjOdGthnNNLtjY399MX/xco2TfFZmc8WFKPYwFgkCcRzHcDztJUHk237sx25OiwmCJAGdJYQfZI4bMExGcQxDJrIi/MHzEcvyh0fh4Y7je4lcYiUOrC6szS+W5UK8vrkoyFowyH/5ZevZs+00RVGSGl6QQU7N5Q/2tzht7KYtEIZ8ZvMU4nKl5c1mAWYsJZ0ct/cPTgIvx0MQeJ7IkoUFWncPvFY7CBnP8ZMYaTlJ5FDzUvHOKy/kc/MffrFX0GocEu3JiaZmGc1NkUtEHsMyK0uLSSbabVMf4q8/3x+NM5qVEMPYvtkb903DS1N95Jytz+W//5PbyxvFu988/Nu/+bDTyl6+Td6+uXnu/PL8itUaHKZkKIscg3CgWzltQR+aH/7y8357EvuJZVtphEvaLE210yiL4yhMcJJGQeBSNCmLar/lDFqupycCl18/X3n9jes5lfj8owe6oZwOzpZezPdsvXV3TGUSQXCYpL766vODvV6vFyYhT6RyQeFYDjEs8e4ble9/+9syyxFpRMIMcoJWyLuRXSoxKZZQdhgEQZJCQCQsy0qiFKeJnRh37tx4880XRSmNU9sPp6rCiMyi44e5Eh9Q0Vlr//xq6b0fvLq2ufj59v1PP3w86k2rRU3kpTgNptaQlWGvO6Qokud5hFLX8jlG46Coe6Hn+6LMu66nW2OSJACJ0tQ6tzxz5XydIaKR4cYC4BBPS/mitoQG/u7z+57DMAxZLnGDXmuheUli2P5xj5VyrpVO9QkvkpKioURiOTYFcaGg9gctgpQmNvr6wdbzvRNFpGeahaW1pp94nuFGGdMbeLvPe9bEK4qlQnG6tFjrnHVOD/qQKFbKje9991q9xjAmqN28PDwddnUrSNOPP348PhlUxEAqkTduLlKUy9IKxfKGTp0dGY8f7+fygu+5Fy4trp2r2+5YFlmayu+etAlQiiIoSjIJk4XF+sXNcySAW0+PHm899yJ4+84b8ysbAyOEAOv97Oy03+of+56dV+jFZqmsMRJDxpFhTobnLlxHTpqmYZbiJEkAgBQFMAYZrH75za/vPXlGUdzsTO71V26szOfH+oHnc47rPNk5O+50vBTLAllRIM+JHBdX50tKsQoIZndr2jkb2D4+98KqqDaPT83tr7d39jsEzBudMwLH5xaX4PVyXlbzglSvNlRVZUR+Yhp+HDY0rlQUeC4djMz7D43t3TEvwc1r58+tNkIX3/+q/expfxJhBCFB8sO+STCRPhiQJKBIGKVpiDFOUZ5lT7tfXL4w/+33LrvR3vP95/MLNbuTkCTJuIppOW4QFouUpOZUrUaQMIjiIOyiLCMwQQCagIIocwAiRBCm6SZpShDsH+aR72b3vnk87I0KhUKpQv75j//ozosvE8CMiNN8RZxM/P/8i98c7E5RZvIs2emPukOb5KohJgcHmZt1n+3ALPSF1EiDkVIrvhWKf/LyhRAHQZh5QYwxAhSMQ+/KxvmLdxqyZkuQomyBIliBZxmY4nS6eDWnFKQPP9z5zS8fQ4ImkKHwfj1H56rVKDfkJYItzLOlG7uHI9s56Iw/vUZeb9Qhq0mYlyC/0G/p9+4+3n62JQtgeb5RzWM69MKh7rQmfivtitv/j08eXNxYpaXMSqdiWak3Zgtygcdad2zvbu083zljcZaEDssEjRpiuYE17mcZRmn6//u1zEFeZEWRFc1YsiepawRJ1BP5XBQMxz4mUwG5iSrz3eGz4xPG7wf9/XGYorNJ3xmdAMSzVIkG0HFNivbOrdSv3Vi7ejOtzWCWIKxxaFsW9tIY+7Zvsuk8IlLTtlw/BEAhSBJSgGEYSS6cPzfz/R/cLpcIXZ/0h73JpDUatxfzNzE59a2Jm02W1qVv//Dl81cXW5PWz3/+/OvPn4hYFGmAgoEscphDNE2SFaCo4ubmJsMK9x9sjUdDls0BkEGoAoLz/CjwU4HXfCeNg2lRkxRBJzKPpKIYML6XpIjRffPhvcPjg4TIcgil+QqslGZfeflqUcnbhk/LAkgFgaFIwiUxIAAdeBECvuXbZ+1TUa0PptlwahAQFsva5uVly0NEmLGcKMgSgYxe6+HZ4RFNFl+6M1etFX71y99MJ3YcpLOzjZlmKcP9gipyslIqK5wMoizWR1ZeLcjCeHZ+oVzhk8SKKTbOkvEIf/TR/f39I7VALiw2bty8UK6ow2kXYDGvlIqFxtFRNp5YcZrMNgozs1UI4aCvbz09yiAUZCXIwNcPtz6+2xfYjEKEb8aPn3V4HrAwXF7Qvv/erVvXljwXGKNJEAQMzZEkgUGmKGqpXEcZnOj21l7WmQZyoRC401pDrZREmCE2o2Ne2H7wePd028m6s0uV2zfXm1VG5JL5uQ2+INhBdv/uSRwfSqqr1dRbt28yUBpNJu3jLoEptVJnRfadd27V8lheOh95QeoFWZz1e35zoVzOFVr97mi0V6uVDNM6PiRsK2/7bYYbrZ+fm5+v986cg12/241c2iL51AxoNM6KMyJNIkVUeJ5P4th1XQCz+fmZV65eePX2ZZFxH33zm3PLFZ5TzNGYoTmJoUSJRwQVxzHJIIqhEKYJAABgIUWhDCLMMBRNcyTCUZQGthnLqvwHz0dxQu7s7PiBJ+WYa9c3X339ZuZ7ltktNVEQ9E/P2k+f/NbQ1XqtoRXk46Oz/cNBEJ9HHoa4YIypiRmQSSwRyWQ4YHqTmbUjY33OzUyMIMsJJJA0heMw/s63v2XFXTgdNhUACEmR8hztO+agWoy+/ycvsdzsz3/32f7+5PLF5ZVG/uXLbxfEbGX1AsOdIdo5HlZ+9Sn//NE2y3hza16tVLTSsQ/7BMzZOvvJh+2vPtmlANxYkl65vgIDJ52mTaE8LxVZxceTvkhJew+eYMiwhZzic6mf7RuHZ/sH05RHgSOTlKIyKBmvrKoLi+TO3vtFnhZ4SeKENM0AgCzDEwQZunFgZdbEZWlek+RLmyssxFGUnV+5cpd9wBLJw3sPXP24iOe7z+0IZzAHBDHv2Ylt2xVNuHF1bXlFvXSleHFzBjE7o8lhgS9LkkQCGUOMWaCw2vDAzEAynRiO47CigGIU+q5rW9evv7K6WiYx6rTPtILMs+Tq2oLnk+5zpl6c7RjPE6i/950fvfeDV9utk2ePnzx9NopCThUZzxrP1Svnzs2atiXl1Muvvpem6erquuMGg+HZcNTHmIE0Or9+HUK505r2ukZJns0pAqTBytK6ae7wUklWRVZWrZCYWkS73fv464exr+Tys+Ppse8nP/nn333rzZcCo0OEvuv5qsQ3Gw076CACk5gaj/oJHir16quvvTychr/67a8mhikIAkUTa6tzC0uXj08PgzBygvibr59sbz1NopDjyby2gnH29OkWQkBRchc3L/ACFeOIoQQSEI2ZCsOCznQ0HedyVYXlyG+9/U5zhoEYpSHtRgEF2dbZQFXyspJevnKxOVcPo1EQOpEfuCbLkI2nW4+ebe/Ypn37zqV6vTqdGK1Wd9gzAE3RFP9sZ4c8Jk27nUb2XHU+CyAiFI2TW8dP9rZ3VZYo5/lCDhSLZdu2CQKREPEiRxBEFCVhENq2i6mlICIoniUjdO3aOZYBvbM2zyKXcO49/vKodYwZYvF8893vna/mceZPAJkxajI+Nrefb7XPDucWczRH+XEQOZ4z0Sf9/unpqRiz82vrann+3le/9k87W4+esBiuzs4bwylBECSkTceWhZObL/wv4xgcH008Jwc5ipPCjc0ZChDtk7FjQo7RuAqVLxNsQHFFtWNnCcHFgGdJCTAI0CRNw9mljZfvXGrWVXO0e2XzzupClaPlslYJ/FhRMyWXTxEZBJnjeLaXQkogSKhKEkOLGaKjECECY0AQAGEcLi+dt13nD97P9th8rphK+FkwEelsieNtWrNDphMi6HtRvVp46Z2Xjs9GvFzKKe7OszHuQt7fVnnR5tjQ6omsgTFIs0RTKtWqJrlECEYMp8GIExIkCmlmWblquVZekTmYcM1W3Pft4cY5Zfdee2yZhdtr8uwrTz5/mEyPChAmWfzan7+8sSZ5o44gRhMEIkaxCcvtf06Zd9la1g/XJuSJm6UUyqtM9cHjJ3c//hJmAgWE6ur1wtKKlE8Slyo2q7ffSp48/nrQa1dyL+i67nlebPqWN7QPcZalPAQNrCVUYLt9mwKXr62++97rK2uLU31sZkaEYhYgkiVJABMA04SOUqaoAZ4jBsMTOV92IxEKN4P02JGGL7zCn/7HsGayeIc3GFOSCeSYft+uzNSXlhuvv/ryjRcuEIQdJ/18EXCCxeEir0EiDUP3jCZZXqjEmWQ6aTlH7Rx1kzjmOA5QIFcsYIwnw4FtfD5f/YuKPGelhG8YaUwgxEwNRKJKkBiAjzev1F5/eyPxTcoXO09D/zhdWdhotx7NNLn//n/4yeyM2G4drC4v6CSgGZjPye//w/Nex4JI8pxpocTWi0V77Hz18dPUy9kJxfHon/+vfvjCnWqDHXtEagZ+bxpJ5TmG4Q4ffvW8/RWpL+SKfDLqlKuz167NDDu7CgVxlEEZKjXCSFo9v58hKvPGBKKr+XNj9LjVDimwpIkLJGEldOIy2hBX7t2b9gdZb2A8fPpsYoxtWAL14KX33nzjDfZg74CiZghI1ObmvWTqumm17lNBNwH5+rw237zCsZxA6ozqr7/24sWLdGhigRdc28dIOTrZtoInw5HrQ/LytXWG9K3ppMgVIcPrrn82eRBNexUxo7GXz0/LjZSgqJ2D3nEHpS7BsRFFUJmXCTEbRozROysUldhTx90+Th1FJqbmyVA/rlaXGU5y9DhKE4ZhjDjBgJTzPCNRwUB//k+/8k7OLKP11ndfXr++Skl4Rs1hz/ri4VO3HQluqVTkX7t8XuHtMCbjWE2HPY6ZPfzEjk/l+fIaQfTeefN6VQ7wtH+4N7LTem25PJrqB892B60nprMvo4bvhxM/NFqBLClhGAIAy+Wy5/UePcpoVjTds+3tJxnpf+u9a1I9CJ1pt9sd9KdOb3pzWf3jH11RVTGN2faee3LW+uLL+36Mw4REkFIrzQ+/+bA9eSaKYqVWvXDpYtjlbH+U1/hiKcfDOYYdl/Ju1D8k7KxeXUnSaGqbNJ8PAhNlFCbIKEpwmGUoDkKHEXB/0CKI8h/mEQDRrVuXJmddKOe0Iuv5JoitMEijMPO9lOf5t965PRi7DFdOUjEKg0GHD6YOT2e5Cs0w8uzMPMYgjsPllbnNS+fmF2ZEYaIbgShQpZK6vbWdk7j33j6foTZBmBjTJJnSNFQVplZVCQGvLNanRi+nsRQVmvrpDMxzMIwdjyVCyxo52TBiUeBl1rRjTYfabHFxpprL5aLU8DyHhlYaBs7UiBxyeWX18qWSqsYYjbs9nYwLr71+5Y/euz6e9A+OHNd1XdedTsfjycCyjDSLeZ4NPBER6flLq2+89eKVa+fUnMBxTKkiWV7gumYap4oiMQzve14cIUBCUiDeeHdxMHna6XWD+JltEoLolyrExT9/vblR29k9OT7sWo4rCAInrnE83ayW5+bmVpaW1JxgmvFpywt6DkVXOFkOojCJ4tCPkzTmUpagiDDDFMEIosTSWhbqZMpHRAJAoHBEqaBUy5wk2UlmyEyiu9Nh/8AYdfBEEnGUcqEqlDWpbE39p4+2v/nqYaG0Yrvj+cXaD3/0ytVrm57TIwDWdZ0uFxkIJ8Pewe6WY01ySt4PIt81ZSmZjvc9pyOJSGETRWUlAbnWqOUbbhb7JAHzWmhm7f7gZKc16Tswiq3Yiwjm9hvvzqysY3dEBG6Bp81kMhpOCVqUuMXATzmFE/JMEoRZRBKY8ALXHtupg4iMah9M/ud//Q9MaPb64zhFlusgMiVoNDNXvrqxqCpJo4HW123TPGq3n80064Jwq1rN+wMOwzzDeDwPBv1nFElevnDuW6+sSAKdxC5CaeCZjmdbupHFECc8SFyKTFEaojTBkNDtqR0keVVbXxX1yXhqCpVSlWOEOCZ5KBQUzYkilKIki2WRK83MUkw5Sy1IJfmmMpmYVFW7tLl5+6WNteUGy7EUCXiYRVFEMZCAZIoJlqaCKEZpNDV6ljlUVf7S5rn5Zt3RW0ni1DU1MEm9H/gmKCxUq6V5FlJR4OGEUmc00wRnuvv0cCRozLtvvXXh5sthHHz0i199eXc3QUWKy4PUj/wwde0wcETZIeJQ5ViBo2iQKDkpCILj3aczdcgRsiIoZEIwJHnxyqVXXr5SL6a9g85J+8H+8RFCSbFyqVLnBIFy7WRptaBVaAz9wcjpjEzbTSAMUOY8ftzP5bRedzIcGBRNxCiYbZYrde2tGyoE0Xg8dl2fp+UoDB0vTOJoMhywrIgy6LkxACCXUyHFABwFnq8oyh98XqPJ6MqlubL8/dL8IqTTMLJCxxJFTZZVx4pZVhSVKCVjlMWCmHvv21dvXlv0DSew/Vvfmuc4KU3wcDCGFIAUoRvt7qiL/Em9cfHVl2/4NspLzOpq5c4rzaUVHHtRyjA0lbNBtLJSXPvvX2ZVqbzGBcCVQfTGW5cFgWc0VmL9osShFJMk7aYEQcW1knjpwmxiums35q9vrqeJxzIUQogEYV4BM1UhZqj1xcrNq01GNEhI0wt1iMoyr8RJUKuV1XzesnWEUkg1KZpwHOvk9HgyGVXrL8zMlmaapUpVIUCq6z3HxwzNSZwUuWGSBmmQBrbuOB7PydVqw/Yml64spsm3Aj/Z2FjiWR/jKRUnZny6drVcaHIbN2YohldVWZAEjDOeSKIgdrzjxGAkmZ9fqEexzXPi1EIAExzNCSpLEESKqTCLMgJHcSzKak4tMETHd6LY1hUxXlwqvXH7miLGprkbxt1iPl8pcfWyUFRIhgZSgWPVRrNUTryIwYzICGmcUKJrW/3NS+duvnhRK8gAC8vLyyLHOmlijHqdds+ddhns+UYQxU61rtbqaH6x9OMfvWhOSJCUoihamZOvbFS9XVbjmAACF6E4hmxKcQRNp4SSlyg2nc2t3HnjtYwk3CiIXENiKITTk+N+Pr8001wXIFIkHmBve+tByEaawrA8nxcElgQkYiiCGp9MgX+aJBkn8ASLJVUq1xW1wAX6SRLNl0rqq68yeU3udE+WVzQ1J0Zh5niMms8Vi/zmhZnHD74AKGoWm/OlaDRpoSyDiDQNj+ermxc33njVfvr8bPOGpEk0xwCmVPADm2eBptUhK5JriKIum+50caXOU4xj2MZkPGgfoYAtlQvlYnG2Wb52fW11tcZwSZK5pMdQZMoJQBABTWcIZWGQ8jx/sPNUkqRytY7SdDAapQQSRV6WGCVHpdhOPCJLbRKgJIwiz+cprizOy7Tmk0FNq1XzDZEOqZSiWHmYPj8dG5PAiSkWZUAuzgj5Wp5nGOZuijMKBq7l2uOzlfmZl65fOb/+g/d//YEkVer1eqVSkWWZ47jpdHpwcFDRcu+89mKKkt/+02/ygn/n1uqFpdre/m8qlfryWs4yZnN56aVX1spVIc3COInyklCd0WTtQpIxYUSO9eCsPfQ/6oV0URBk34l2nx77UZii6HCnQ0J89Oj+n/z45blZioYUz4tplEKSrJQKSezTFA8IRhFpkoRpFoWhS1NUkkWNmQpBWH+YR2HkCAx344XFlOeTNKIoSkiKoqgwtGBOR2PTzEhbkDDH0IAIosDTyqhS0QDWgrhvuWk+V67N8kEQxLEvKQhSmZrPU3Smysztl66/+MIlVY1I2HbDKUeTw6nLF+r5fD2NM1kReZnHyBJkQg8Hc7NS40evIAHMliWYejiKIcOqskIobK5RmWEWX968xpcZiQMTM5JFQVEgANn6Wu6v/up1FotLjWWWyqzpGBEBBeuKnJ+MzbPW0czMjG3bmMCKKtAMJiEWRJph4fLyckrSq2s5WSU8/wThDDLQmnjjkTlbWIljgWZkmLEApAId0CSdRSyKc1YIlueu5OQckfme1+NYJQ3sjDBIDlOELosRwrbv9gggRFEEZM5wrShIfcjYHqQoRuD4MMYEncsSx49iTCCaJtMswZgQVcnDiaiK5y7UJvrUnLqBg0qacvvGhUsbcySMaY7lhHIUoIJS+vY7b1a1hZN93YsmK+cXb925nBdpO4nObcx96zsv/s3ff1QoypUab1idx090lLgUBKFHQQZCFJc1/taNdQHKB7t9USq+9+3XXry1HIb6tevzIJUm/QQCuLSgJMFUUERW5Kk0DG03w1leBOeWK8YLq4GZkgymWGQODw+spCjTMkdCFFE0KwgSQ1MYxRilcRoLEq4v5TuDFssgjiJmZ/mCkoxGpsoqENJRkkl5ZePi+YXFZqWeE1SSgGG1lg+iWJbwwrxSq2wE4SzLozDwn5y1Smot1EdpRt68sSQy3wls/dxCPZr0mOJYH4Uy01hbvqBI1anjvHR7Zn1TmGvW61V1Oh1mScjwXBTjJPPzqqSVCCHXCCOFYgmajnIqNz+nzi8IEq28+trt8+eWABmzTJrTAo5DCBOlKuUFYZLEFEkBgkyz1PXTKEnL5bLnBpOJzvGiomgMB2kWhml444X1BE7G9kDiMpLwi6UclgQCY5GOGmUJJDHPhYE/Yp0U4RiRiSKyrt1ynZYsZ4LKQ2zvPHyiqOV8voZwOBmNFFH9/rs3fvqnb28sNniSrDWQLMs0DVmWlWUZEygM+W+9Pe+bpmM8RQT+0x/ffPftG7mCmnijipKHJP3Crc1zawykgKIltm0DMuN4Pg56qlSo1qgUMwhx5apSrymyhH79/nMC4/HQsO2Y5+RSpVHQVMd3f/n+l+++vZFXF9OAYAjOiwAEZBKHkARx5MWRS0GBYZg0jUmAC5rqpg7K0j94PhIVsajJNE76el9VCqraMA1vODAY2ocQSrJgOQOJF1gGp0lAQY9lCAABJkgSEgghhBAJKI4VKIoEJMEwpMykkliwbLlSy/mBqShurdawnP1e2+5OZC6qCCzBh0Dhszg2U2fsRVmhwPMynyQip+XdcNjv9MpMnkx4Xikiamo7U4TExaWaWOImcZshYeIHmMFOYHq+NbMilVWJp804kxmWSlMuTTCAZKlWismAlyU1X45il+FwkrqAxAKdJ4BCYCoG5tToTS2fABHLchAIDMM0GrMFOWcYhuM4aZapOaVcUUhIYJw5FkJpWC0XUJb5tkfTAs4IElEypEkvZNIYo2A6HfmhxzWqAk17YSCpXKmsQMBEYRoHaZSEcZIBKACUZXGEs1jkKT+I/BgJUspLVZrB65u5Ym0TZyB2PJFmL6yuR2kvimOaUxm64NsRTYnVElpbcRM4FMTyufVFTaN0vcMLueXzxRBfzNW0F168urbSoKiYRHHsi67t4BSTZEKRCQm8ZlNZaK4ELoiTsDFTjBMPESnLkWnglGs8Q1JxOFIU3kkd1zEyImNoRCAiodHqar5au+W09Gq9Iqj8hZVCFNosSHiScC2b5gvNmRoBaFH0KrIcIs8OTCji5vy86yRB3F9aEV55o9k6HgOCpSCrwmvz8/OXr13VNAURAQEDSMdKju1aESAI152wFKlVRD92Ld0OPOxzfuK7LCfmFP71N66Ghl0SFHOkI4aoVNSCpFE406f73WGHJEfVKliYL5NU4kc+AUgC03GWUZiJEhIzPs0kiAkRSmPEKTnt5kvrWplTeFgq5WhKjxNX4BmaTxAmkjSyQ7tYKkOomqaNCaJYLGcE1vVJfaY51e0gQhQrMhwNGYxhBEA8N1/Vqm94idGYL9JkhChMy3wao8Vl9rs/uDadmuWaUqwCTiDSDNvWJAeExVr+2gWzmvML1fylRd4N7DSSFs8pf/oXL8VRxoHiQq220JADc9AfeHkZ8EKCcQyQj5KAhICjMc/zmTcZDk7TFDFcaWmhSTE8QriuLR9PJqVSaaauOY7jh+MsIXM5RVVVfbyPiTjJwij2SVKiIFvIw82Ls3mhkSZgd+fs+fPjydgK/el04pqW/uILlVJBzuIkC1NMAZamcRZ7jg0BUpS8wPJJREBAUAwVhOF0NMQ+5oXff030+/L83/oTmkksnLgpoDlWUaSy76EoTNWcRNEoivwUpxBgQGQ4QyQJCZILMuCFkcr5JMkkMeE6kaqqHMcY5oSiiMibBKHUaRMYaM25GkWN4nRHFK252rX728TWSTIZnp6rqa9eukqRnofaNhGVRa4sVAbj1MEwQIE3MgkTTKf83GWmvJKG5tQ+DEtCozSbM7N+ipixPgUC66eh6Zg8R7IMSRG4rKwEqU4zTJzkUyRyEusE+niiNwoL40kPEUGGAi1fLBbq04nnu9lsI2e7Q1kFskp5nmdMwzTmOKbAy8M4QhhBjuNZlsVEGkVenIQSWY3iEAAceBbL0BRFupZdKBRAymcoTrMAwDRKQgCAqKhpguw4kBXRcUyUJeVixXPjXmuAMZllAksnDOnlRKBKfBgnbpAyrKxoG17sJzjCJMFAKnQjd+IxJCvSDsnSgBERyAFSTWI8GZ52enu5RQkSUOEVkVNs17P9gBUFWctFDlpabqahOxicsRCiKHWtgGf4MDN4EQEYpTGERJEk1CxLSJhxObXdOlRVupRXyQxIHI+yRB8PeDEvCRwJU8exTdcNMhwiMkqx7EX5YomT5JxWJCFhjweho4/7vaWrr7M0aVqjMPR4RYoQjjCZK5R9z26fnYR+UMgXOZoPvYTENEsJdEKVShWe53V94nqGJJEsj9IsQPlyEsX9dieLM0nMxRlCJClKynjSAZBkRTr0HZGjgY9m8gupi9vxbqWkqjw0jVEQBNL/t73/erYtyQ/8vjQrc3mz/dn7+HOu97fqVlWXN91V3Q0UQHTPACCAGYqaCSoUEqlnvukfYITeFBSpGZCcIYYYiAMQDbQ3VdXlb13v7z3ebL/XXt5nJh9Gj9MT0S8SHurzF+TTNzLXil+mWUeKlZeiApIXxTkHTqsHkMorYip2HGZUBUU1ZyKAELCShkHhum4UeyfXG1SWFIoJIVVR+m7IGa7X2ypHFEuqqmMMo3AeJTNNwY2mXWWW4IQDUjCUV2nJY0gzQgGPe0UVevGxbiFZx0VRASElcS4DJARM85LKwGkqQGKcV+Px1AamQDDLUBiWikFM2zg6KCnesJd3GXBZSaugrUOjphU4YaRspsYMY6jpiiQhITiVpSgKDg72em2zKAqJyADqGJtxUsy8uWGpsE5lqqiqniQJY6WsUCEYQgAUroCoLIREVFWxoiSfzfwkzlS1aRqNySTc3jp6/HQ3CALbcbAEv/nWqbUVEzOXpblGmwhrVJGogQQvWAXzjGdpWVW8qgoAGaGQlNis6f/ib/7DW6TfPL+mOn40azp2Q63NptHuzqAqoGEYqpZwmEEpGx7Aum1oMgVlnjMmJEYMu13r5t5dxoRl1dIk39nZqtdrtqNjDNPUtBvLo1l0/cZWXLAzZ+w4I7LmfPLF9r/+d/uPD4hC8/hM7WRvc3PNskktnk8HB0NYJ1lhhgzmwBi4+aPPd57c99Z24Te/t3p2vaV0BYjgxJ1G0KtrjkxkWV0gUEFKmRbZPPIMQw0iRFS7AjSrlOE0AF5htzTiGCUqVEdRNMX3YcKKKBdYrret+vH+vhfE3SUdApSmyNAWsFZLYxBXz4iiIkG8OIpGU8ZLRSGqRto6ZCyd+cMgdCVKdL2h2Q2hOCVHacqjrMri1HRqttUMcwglOQ+PalKTYOGFw8l0VmRlBSrLqiEuiTKXQAUrVqSlSnW73oREHbhBwYWkGQKiEkhGA+tWCRljfmE1tRzwOI8xMRGGSEXNTj3kZctuU8lhXJEkW1bjWTSLYXCyVx+Ot9zxIE1Cx7AcrdZs1SVALSqVfMZEShUCGMeAC4Gi2B9OTEw7RZkyQGQNzbwpL0pMFKjViaGJKsnLiFWYUpqXVZAEClX3Z/Pp1pHhOBsba6ZVkw29YRrTideo6Y5lB5CPBtO4JLLZFUhPEihrm0jyAK6oBnVdxgAphHTM9mw27w8PFUVptXQBM4kgXdaPiwkGpGYbIkVAEIglLtE8h5C1kywpeQkwLEVhWpqbBhLTLfmqP5m5+UBVgWU5lOgQakiiHvetem0aZlEFDatWxuJ4msR+khcKVYiiGzKRAFchhvVmrdHOonRchUnFCpUSU3eI2tVIreZ0NEX1PXcchBQxQzc6JgZgnhdju3k68LPZNC4qoJgG1ZWkmHrBdKPupDnLSoxQgRGTiBAAibyazWemaQKZY11JWVmWTFV0otfyQkrTjMiGSqhi4CANU1BOpseZdGzUK0W2mVRxlJTYpRZsGq2hrxVFlqVcUZBEJEqURkNGSGoYtTAOiEL80AvjEdXVjqFSRUkQSLIpwB7AkEgKY7k7n0DEVG7ppmUZKmMsjcvQC3hZLLSbGZvLGmgvQMvprG1oaZ4tLnWsmkUZqIoZRghLRFSCcV6h0pKNyA/jOJew2m42GWNhGGBJGIZKGB5PRwCov12PshJUAMdZxbIYAtputTTVBoDNg4PE6+smXF58C1Q5L0IiEadmMCS5WTmaBAaKJawVZYwl1u7UJAlFsW8YSlai2/fv/uhHt27f3V9c7P2Tf/LNN9+65M6e/Pinv/r8i4jWX8hL8NlXj188e+rkZn3qBQ2rrtlOw+z4qcli9PPPrn/8s5vpCA12sgejRwndhd9+cU3tEUgFYJZjhtN5VUp+Eu6P57NYuEE8mY3bnfqFlnru8omiBINhvHfspcJfqpqGZfb3n0TxXFZgHIdAKKIaPbh7PBnFFsONlvzd33vZtm13NhVMyBKNAsGcTFc1waDvgSgUCFEsASHSx/0PV9YXuiutWsMZzTy7ubrQOX3jxpMYzDAFURTs7h8iqOS51D/y67XumiG8eWpbqGJ4PvcRQrZtWqYFi6LMkUE1BZdVloKqrHgaTD2o1TXVFMjYOxyN3L5lYseWTAO1FXkeTidJv4Bqp4XNei/P9CDgUUZi3zcJbVpWyQSUVcvR9IYq4Gg6O0ao7C22DVmvm00klOHRGMpcSIBzlhdxmQnb1A3DSNgcpbX9g/7g+NH5cwubqy0Meb3ZzrMK0+bUC6o0lZDVWehAmRol0+u5Pw2XT6w2GY/z4jiKaB5ZOmp0uj3RGPX3/FnMGAOl3m6sAbm7tTcNguzUyZVGoxv4e0kaKARAAQAQYQYh4aqFdEWSZVoWVcXSMEwj7kqMUGBCQOK4yhlwo/njnR0Ku0Iql9bNxY1mlg3DIpwc9B15cWPtnQLbKaMyyqiARVJkPMuLEDaIF8VeUkXeeHBr13dzFrO9nf2Tm9/VtDRKj46OD8oUdzq9hQWTyFmnrjZbC5aMAQCG2VAVJwvFwWEaZ9MyTwlklibiOOJsJBNf18U8HuWFGI2j8cSreIGVApJE4AwHvXZHbzcbDHlh6mZFTlWLUGjVHEWTy7LUDDOvgOf5WcGKkvihV+RQIXAy9Q2btjrGmWtr7gSFhzkRqSpbQtaJlGN9nuaTeRWbzlXOZQC4qhFCkOe7VZW3Wq2dh/3RdNBasDmKoszt1JuSLOWZi6RWVsyIihHCjGlAEFWDi0u98MiUJRkKCHhFJKoqjDNAsFTBKAyjNAeW0eitKHFcEjXIiyDyVV7OWjUiq7qCLQnrbjidjsaUQIIlCGDgeXleICwoIWmSFDmA8DdV5z8yvzY/WuiteBmyshRIwDAIwnmSZLbV6mrrAIDZ5CBJI84KgnAYK7rqSAUGrh/XVxVaVSxR1DL0gyQjBDX2nyQ3nmlffLAz3U3WaLecRv68eDrlP7u+c+v+UAc9dpxkhee0QLfZJZlFJ73CGQ+mybhkcVr85Ec3f/Hjh3MXWUbX6KzlSbTzNJu8wntrDBVFW16ipfmp9fGdz3d37m37Y5uVthf7O/2HJYy/982V9bOtm3fv/5v/4Q7P1hXZqDfLKLrXnw4UlW4sX71zM7x0qe2Gt58+eRLOlRW5quR069mT9//k3ee+cUmWZVCCXAST0emDIM6DaD7zBsPxPAr9JJ2HURp5S4sLiyvw+//o6ury2vRI/uAH16MgmRVPDvb7o6HLBE7iPAgiWZZVVa1L+dJm75/93/6PptkZHm/ZEjAgrLFyv4BFXKKKq6ai6paX8qhUnbVzEle8yfrf/uDOTz74ayg8U1bXF82339oAZxaRTNvtDYHU2azY2zoMojKItOPCyH3fO7jV0cyqLKMyHwRzrV5fpnBlpfH8i+coSgAUY3cmUwNryqQoqqIF4YJj41KaQlOkgsx883iw8+tf7h7tJ0/uHX7/j2vdLmBxYdBe7E2OhyHV263VzqSYT0bDIsG8kPcz6Yut443OynR/NJ/snT/fAI0ynR8MSD3yadO5DLgK5WqvP/7wV3/tuYU7mi1uNP/Rn31r/dSZND3i2SgYHVYxK4sVy2wQzWCSBlQtYSJIElUzG65fAinlQm22Fcfcun/w2ScHt64/nIMxQfPzp7Q//Mff2NjopkVy9pUTpYC72fRwf/Kzv/qohtFCg3fa+PU3XqqyRATW4fbBg6eHt+/sPH3c10nbkZvT4Xzf/gQr0GqSICuDcPRYDGSsLjTal195cf27L/SWxcPHH5RVZOvFwW70xaePMhcK6BaFa2nKpQtrL750klc5L8yjgP/bv/zJzZtDghpZmhZxH4Hhf/Vf/mltoxbGU1VPJLkCTIhCm7hw0A+FjmRKobACrywKrmn1okj6g6MiF7pB57M7w+MY85pl1nqL0/UTjYXFFQ6GZcVVBRRhRonTrXXjWWU60zwTAsiAaUFcpmlFFZ0jpd4kWHEArBjEjt0qMpCkpaZppqZkmZaWiWpLXCSs5JKkzGYzCRQTN65YsbSyUms3soKUpZHmmYxqaVIUblKCzLFs01JD3+dVxfAeoRRrFueSn3owc6uqhALK9bYsECtFGuZlWYiEiULoqlYpMofst+7RSqeWVrk/9vz5+PTp01QFrjuJkvDfT0tgDCm2ajW72XAA4JGfAIEt06jVapPksGJxmgUIMonahlEvCj2rhvfu3M2zgsr6bDyVDUyJ3T/0dh4NJ8dzzFuKAlQV95bVhVWmdWYJm/fdeeRhlhdPHg+f3c6SAHqzYeQiiRRLG7qusIbTss2F0e5YQPb07r2/vzvYedwfH/pFItWcNjFUUYAkrX7wg1+cv3jJn8jj/iwLAeTmoRZxNKgknObaV+PPk5Bev97XrAmVBVWKRmuDS1ngubAyW/bmg/tPH9zdHvfn/RkcHB7nUUogiuLUjxNBMZapmVq3Ht/xTsm//95LolJv3LvzP/xPP9nfdy+uvxoEJEr0bm9RlJUmodXFtcFodvPm3zzeGp64dPl3vv/68uIKC0buoO+m+5uX30x0CHhcSJARrdNaM3LjwZPDv/nhv5gMjHt33SiJF7vGweDZdL84udK+9saF0WRnuu8mcbr9LHhw7+jg4MDzJ+NyzUAAZ57Ek9CfQYVSp4a18VjHs3mn1WuePut40ZFC1SwuDrfnO2P36HBYseytt67UW+DpYNfU873d0b/6n76cDTOZ0uW1BdOiSCryDHjjaHAw3DmYlmhiNg/DdDRzR0UisYQcxB7IxV/t/FuepLz0Xnhp45/+s9+tKikvFQhqo1Hx6N79+w9u7e/vHuxPBFMMJAjdmPaPWq3W1D2osmnDMFQJ2416HGWQC02SIj8LfZcVcV5CU5fioIDYDkP22edf/uSnnxwfTpMwsRdOuJNhsWSokgO5LEGmy1qUVtc/+/Tjn957+PlhQzEwH73+1uZ7TQfa5Gcf3H74ZO/Z9tgLkOMsa1KdQr3VUanKwtwbT1M3mpZlTgCtMuHPXF+Mw/zB2++csxtKlkaffP7RrS/2nj4eVKmyvt4p0mw7mN279yzn6auvnBt5/Z/8pP/ZZ4/iyNzcXDJNwYvaqM+uf3Xw6hsn222DI+Z6Xl5I3lzcu7f/8MHhPCUIEsFpFOZz1y+rXJYlKqOS6QhUWZbxQimywnMfG3Z18dLif/pHr5+53MzLKYSi2erKUgYlXYDCnR9QonMuojhOshxAyEU+HsU16nAFcsAqUTLIGGBlmZcpmGdRVWHVrOtES4tclBVBKsWq3dBUXQ6TOEx8f2eW5BlVCCGkQoWq2NzSkyCPo1xVVQnLecEAVxmHWcoxKBEAVJFVWaGyNJvONUUvyyoOU0rkWrMNOHddt0yZZlAAfsvvR7k3qARxiFSZVhCGcRoBUBmmnBZVnMQAwSyTCAVxhgDnQeKDCuc0BRyX8RHAgEqEKDYHuhdIW88Gt2492X7yOA1yHTtUsRd6vV7nzDgaTnZTFVqNRqMsQFwkipHFcGtcUNIkVqjU1I1bN5784gdb24+IrOtXn29tLL364N7O3D/kONndOl5ZWiuqxs8+ffLlrx8c7ON+319sq1ItnQe3HKt3elnf2otlEyQBzGOFCqwZEuckygKszyyr26y3Yl8/sbr06Rc/XG9Ib7x6qVlbOrod3n/6VcwnURR9+smNn/74E3dUuuOk5PUyxRIzGON5zCBDLAepV5lwevVk5/V3L5pS48Of3fr0szsVwucuvjJ9uispKA6HT57tQSLb9cWUtbCMT6y/0J/tfv7r+89fu1CrsTiM8jxuOyaMw1a9Ng7Y3swFiKBRtPWw/8XHD64/PJp7KRKOpdlZ4mtacGK5u9DuplWTIzYZsi8+u3/j8y1vlgCU5mWiq5ZCKn/Wt3WgSkaa4VMr1/aP3YfHt4+GYaPdPXtpAyvjKE+GB+nTp/GN2wdBELjeIPKj9//gG0SyxsPo+hePspAamsVYnOdpmHgIA8TM/pH/y5892NoeJpWk17Uc+FURS1yrMuJGQ8cweZhnUUQpaLWWW50TQC5uXT/ee/bs9o2dnZ29JJ5oKlldXtXkVuX29x89/Ov/ZYjxm5unWkx2ZIn4fliAGWCAStV8GrGsqNds1aqPR8fQYO2FTlZ1Pv2q/+Mff/748aGmqgiDef9QksSJ5XVbd6b9AYOFrjZ9N/j45589vT/tNE+1nKbvS421M76Av/rs0x/+/c3D/syury+vnnEnme+GQTr1JjPFmGBFunD5UiGs27fuiVz0ekuOXnu0+1lSbp++YJ48e+XgIHv6ZOfweEgIzTJ4OHCLHEpci+IgLmkK8M7w+O9/9NOpm9cbTlS44+EQ8pCzCFBUsuOstGeBOxzNAbD6R9XDe97WkxQo7fFomiS+quhUdoSoWMnyDFDDrqp06kZZHNrmglWrV2DwdP/R8dPVjTU1zH1Nh1qrx3I5ETqpKzgfW5YNoSrhVJZlqhCEYZ7HWZJUecWEqDgoOWAACIEZwAyCLKritEpiISCSJZ3KJuFKms0LVjCeljkDAADIOBMpy70waTYNjBQJozwFRZ6URVoUuUIszlkcVUCUiiQhAThEsIAI4CRJIAemoVCqccHStAACcUYEQ791j5L5gCi1tr2krz0/HQ/zIpaIiOIEYdqodyEUaQCYqMIw4KIoq4JSBZOqLPKWCeZxnuUCEJqV6tOd6SefPLl187HEq6ooIhGrWt0Li08/uTtPRlt3jjcN8+ql03t7wf1HEWdSmM93Brmudk2xsLc1/+hXt/eeut6k/fLVhf/yv/5u03zxX/63P/+rv/4qq4oqI5FHr1/f/l//3af9o3DZUjUyW19fXOiapRCXnr/Y7C4/frYnN+j5zZXBXnTuzGoccsYrxWytnFp7tD0fD4IsKNZX1l574/x33j//1jvPmaZ5/Dj55HMrZUFvUf/gVz+8eePh+srz9Xbz0faPbV1vOnVdphgBq16rdxqSTM91z1oNyW50+sf+r35879Gz7bLQMZXefGfZrhtB2o2y1GktHR4lX355ndD6pfaSG02LuLI0E1YzwGHN6dQc2x/3n+x4maLCWmcyhj/667+/89H+orOpoHOIP1Vl6cRaD2No1sL33nnxtRee2w/4//aDj65/+jnLFFDpWFQyznqdFlIPq9y7dqVOEZ/OyoN+5HkPi6IaDKMgkj797OnKydr6KZ7G4Z27s1//fLh/eGyadlHih/f63/qWkQP+6a/vP77nB0Fh6kocVWkMFNpQdehNqjsPnkynccVkVbcVRUnjKIlzULAilYpk7sd+w3Fatn3u0snX3np59+jo1v2bX3y41z/wwqBaXelZVrW//wTwEtY4qbKGo6906suteq9hu/OKM9hur7pRloS+BHKKAAVAApJG1XZd9UCa52LvcHrzxrOd7VkccSoJSZIo6l++fPLll09qOvb9Akl053H/o19/ce+z3So3nAXsxl6t2+qdOLU/yb64dfzkYdJob+raapqRnIVBOpJ4snxSX9/sIKq2F/S8IhCeG+zP52NPFJwJUJaSYHr/uPjy050b1/fccU4kQ9VXJ/MphEghqtXsnjz/4mA+++HPb+gmirJyMLk/iw40Xe62dcBQZw3X6yjJZmUlVLMzGsBHj46ePAlHh5XsRElcSkSSFQwRA7ACoIqTKAaublCryTUb6nIqa1WjLW+cqtcMJXI9Rsu8iufRNI3ysZgsNBuWbGUlyvIkjDIAgEQJloQkSWnhMS4qDotSZGXBAYOYc8iKMtU1zag7XEKu64VRLGSg0SqpRhVnAAjbtputOiHY87zBeKQq9SKDEsaK7AjGq6owdKq1OoHHoKgYiyDnCKGCVSwrIISa7jBQUlmilOZZGkUZJXqj06NyNy89APZ/ux41G7WiUtK0mB3ETm2pu2iliT843s3SmBW4YoWmUQw5JkACAGOhKYqiKFUp1JwUHAFhRYXy4Onwww/vPnlwLCGdlMlLL1zd3pt4Qem70x/+8IeSVOkM65Zx9tKa5z5hKWzVTjSczcH0cDrSerR788ajL766zpB67bVzr35Ta/VIMptfuHr51oOzO/uPy1j98rOtf/MXP5x7qLawgp0nb7/7wrfffbXRUAuWYFkqAL+0WKNGrqHkXK3Raf0RBliQWLVl3WrtbKf/+n/8u8GxJ9HwnVcuPP/iRlVNHj66sbJy6Vutq5OZ/9GHn9386lboFWNt0GgtXXn1vYZtXTh1am25F4fz4WRYAa5o8pkXiSzLsavN5/60j+Nxdf5c+9vvvnj2sqg3G0TVZl5+3I+PDz/2ptFir3f/6ZdMeM1mp9PUA2+qUbNl12AFKjZ2/UBVW7MJunFzf2dr7M28jhIhwi6dXkIou3C+cfr8Zn0hWV06Ow3Zrz/65d3rnx/uPTHlhizZdUecOLVw8VLXtmuMR7YjmZbMER67ea25uXsw/Yt/dWvQnz5+uH//bufSlZefPvjyqy8fH+5zgbMwBJqmLS5sSqB94/qNG58fiaJN5ceSVC8LUZW6pi4pauEGu4+e3NveCxnQawqFVZGkLsR5a8HRSP3k5iUMeZZ4585sXrp2oQDV5ze/+rsf/axXu7LQ0/N8f3f/nqrFL7609s6b37GMjlJpTgP1liRIZge7ewICSdI1hShUl2uGqFLMMwqLvIqHo2kSh6C56M7zr25u3bm7A5HcaHSJVKiy+s6b7QsXT69saKWI7EaTSvZnH9/55U9u4LxBiTFzh8SoVi9sHgyGH37Sf/q4kPGqP4NZNk+qw4JNrz2/8t6731zsGabOx7Oo0VwbjLJh/6MwDIVAeV4uLp5fXGjlSe3nP3r0wa/uumNi6l3BJSo3Fa2EqKpZukTY9sFwODh6+rRcqm/ycoJwaDg2oQCiqipyzjmBvMhK21khpf3lVw+ebE1YpamaOvK3ERZUUaJyWLFkZXWxt7iQJMpwOjMMKY5zXqK1ZefE6fbKOl9YFpvshJcPDcNIYTb2hhJW02TE48OcrxIogKCIqgiBQrAoiJI0sGguyTLklECqQ8wA47AsWC4xXHIWximXEEBINeSySIbTsdNRZC4RIum6rqqqJCFCiCpRJmlVJVjFJFACDhHGkoQBAAhRKlNRMQljXSEsL5JSCCYCL2w0aoQC153EcWroDcuuyYpeVTxN89+Und88L6KZeULSBB3P3JyBrGCaQjoLJ5LIS+NY1SSAorJKeVZRIjCSOBBBEMxdvwZDTizF6PiBPBwePXqwt/14t11rnVxUvvWt16pffh5tHdXM+vDooIiDk6vd737v3c6KMQuOdM1a6Z6ScQ3yrEpXb90D9x/Oh27Q6gXf/eNTL7+9djR4Go7ZPIKGvaYq8Y/+7rOSC87I0mpX053W6cu43toL5f05TzKAKCggR6p8Yj2fpWNd5FQ2DAPq9VKr1Yfj8tmTg8O9EYRC0aLnXnx+baWTZn5ZNXf6TxrW0mxcPr3ry2BtbcmMsjxJ85LJ/mg2GH/Bs2g86udVVGvW7GYtqza/++734ry692BrMAoXl1d//w/e/d73XufKFEDZc7P93cO//Ztf3vjqmaVIqX/c7pTnLpw5fbbhzXYwKkHF3FlsG02lpqyqJ/en0kcf3nv2ZCiVbLkrNZve6csL586uqiq0Hc1pG1bj5Dxo/uCHj3/5g7/CND+1bCEkNMrOnzv5yuvnNk81vKOFiqf1jv5w6+7xpN9e7Kg2OXdp8fWX8S9+8eHu9gERugp7924e7z4ZthvniE1Hg3Aymdcd58vPH+7tDHWt6Sc8q4aKsOuNWre7aJj1INx7+mxv/3hUay8hyVxY7DltTaBazSaLjSWKrTiPyyyajFKnY9da9S9v3rlx83Eco2Eeikra2Dx56dLbvS5aXDQvnr1iKs2jSZREg7AIi3AGQGJZVpGVx8fHhnNSV2UISRaXBeOc8yBJphN3sXbtuH98/+HB0WAoqw1D0zjLmjXjvfe+0ei0BYZ7+0dxIooounfvGIhaw2hwhBip1s/11jeW7t15/Mkv71PYLWep7miRPwZy/Py13htvrp06JfUWUJpSLCtcoCwrVNVUZDP1I61mVJXKuXV4kN69vTceFJa15JhOkiSeO5FoWeYRwvbh4fG//Bf/xjJrmrL29NZxzrhqdxzaGM36szTWFB1XK+GcC25yZj/Zmv3yw9t7O/OWtWIKyBy5t9g6cXKFypDzYn1jbbG3FMfp3tPQnU/v3LwznYXycmOtd2Z1uTJqgRSJPCokjgERAmBVaVVVHkZHBBmEqDJVJYjLqiyyCAgVKzIgM4x1XsoC6RBRwMuiCqOs7HXXSyEKAIIsKopQV6VaswZZXYASCk4pFbwaj2YIAITQcm91GEAIUVWicB4lUSwrUhQWfuDWnBVLooxFGDOJSIAjSmUISB5mgnFWcgArRaFUIVlRef4kjkbiNwz3/8d6NM8ZBybW6hut1ng0GG5t12xnfXlJMw1NU23TGkz2hQAIlRCUAlScIcZLJjiiViX06TR9uDM5OJhWBdMkbFDw+ivP2xZlMONSxiVC5MzW6bVLa9/6g28e7Nw9nj5V1GWCUZlHukzdFD877M+CpLt0mmjx3ae7QFEPjoLh4d3d/Wo6ynV9ZWfrEULizMXTYR4MJ+On/UQhh3vrYZWDw6OhrJtmvQWJ9En34NUrLz1/8kS9nkF47Bd+kSp74/jBvYeMMUyydq/eaEI/mAduEcVI0uSpG9/44mD3CaPSGhdgMn46i3z3lmYpSt3UKS+SWOJAPTyYP4wPspH78sU/fPpw51ef/mAQ9tcuvGCuLBxnk2iQ7mw9GxwG9+9sPbh1iJno1lGaTv/on/7O1SsnJezHyVGv3WIpmI3mVSbpXRyH4stPHh0+mFceC2aHl8853/+DC+fPL+eJMC2JEXcWT7f22d1H868e7SfHfs5HZ8633vv2KxcuXNIMVVLyqprrlizJqh9PF5ZXlKZjNHSBi+s3P390b1CmU9uUUEE++PHt258cVilo9ORr77xz99bel58/2NsZjUY/ZCxVZDNwq6WT9dDzsjgaz/D+8aO51x+Nwk7rzGziI4nHaalkRSWSLEmOto7dYVSZndl4fz7Zf7y9ixQnSZSnj904slIGlha6L1179dLlThA83N1+ur/Vx0K3zy6DMtRQVteEJKA782ynWXesIAz6xyNVQ42GnpWoyitqLLT13vEx/PjjxzdvPUoLSNVyPBtUWa7R5f0dNhz5ESvuPNrq9+fBPJscuipteP4xknTdbGBAnz3a2ds5smnNJM1A2+l0jLNXnztzZXFpTe0uINvIRRVEkRKnqN5YEizZ2Tqeu1G91jYN58bO4/l8HkXRdDyTVa0o0+2DI8bKXqeHcBkGIvTyLMIYQlOTKVEVAG3bmoTuYeRJsmTLTZZWiSsruAWJfjTIP/7kwf3H+1WKCRyHM99YUDrtpbNnLtuO6rqzOEq2nk44E8F0Pjwa5EFBuPLw1pPtJ7ff+lbvz/7zt/1JCGV5HviNpVqROre+nEReWAqXyltVwSBACIAwmLMy2djoXrh4mpJmxbTpLB8M3MFk7odzgKuyiof9LwsuoELshrN+cuny5Q0sq2niqQjleQ4EqIoqTWPAha7Klm6bJhUCViUs0ixNOESMEiwrGEk5JKLMgyrNJaniGRJcVYmqWKrgBeOlZZkQkbzASZIUJVJVRVbJbz2/xhCVZFsUmm6zGqeW06YQh/GUYAkw3j/eLSpmWppjmBULozCgEmk2m+12NxtNdK0z7Rc3b1//6c8/jd3w2sWz3/+d755YVu/ubI2mRyWP9w4HKihfe+uN/+LP/tOQgqiaF9xTYDtN55quUE394qOdH/3qbzqtDUXbOO7v/i9/cf0nP9xGhDNeZNWKrZmIJd3eCW92dOvmV3bDkG21PBaIimF6UCZZmVVAYf5+zACJe97ZpcVidQnRQ0nm8TQdHfVv3Ht4796uIjepXJw+u+zU1NADltGr22tZre/36XBw2x2xlaVOXHgcIEOT2hx74+NqXuia1EQMogIrCOv0/XferGvy3bsfBdnx+Rc77ZO9XTfc+vj61vV7t796rEj1MhZFnlApXlwif/qnf/zcWy9jlJQZD30/iWa6ZimLdXea7U/6BG2UKaoCMT+aWib/3e9eff2NlXReASCrEvLKYaNtgtjeOnjcnx/STDp/8dJ333/u9bevUk2fRwEDDEKYgQczF449sHLiORk2koztHx188OGdr64/gQL2ekudRvvOl0+2H/a73e766kKWstHQpcTstOxKTOMkrTfon/7J9zmafHX92fHRSDVyiWZBON/ZHY3HikzMosSzaTSZj6LkgEqZitTUr3jVJLRZgdn27qzfT7BkpaGehFW3ubq7Pf1x+dmTxzTLnwbefhpkVYbBeXWt13IQv3Zu88qZExLgVVU9efQoSKQ49tc2ugzqBQeK1XKsztwNPvjlnXv394IwYxAxnhmmFjN+fDz48//2V1DBQkOD+bgomYRIOk8dQ0HIa7QaK5ubuWC3rt/FTHSslZ0HW812uLa69Pzzy+efW1X03J/vRlW5utSqhL69+/TGjePbt/vDwcy2GkRSjo76Tk33g9nefiEE67QdABK77pw9d9JWlQ9//bHvpXWz27RXVb06PjwqS3a6Dr7z/jd3jvc+/vLLohKMMcbA0kJHp80s4Y8ePb7/YBcg0l5oyEIkQVbmzs3rW/fuPJUVjBBK4gII2TLrRfgkz3PEia40fNcbHO/ubYRRcMGsrTmK9PTwjmnVjmfk3/6rn86GM0qng+xjweFCu7vQbk4nw9Fw7+yZNS/OXjx/Wgi2vR3evPHs1u0HE3fsNDTFIEWMoiwvINfr2tjNVc3GaEGCVNdhmoQJSDFEEpKrsnBnQZlzjwtWCdOoq6rMbU2AStck016QqK7ruGKTIs2LMmUFxpxihRAIBRIcFBWvEGKKqqmqLZiiyATh8rfukUSdajZaUFP3KNEgVg1LM0xEFA6pF8RVXsA4UhXEeAR41KipPJcmh3NWRZgnhRT3fdkHVozoqXMrf/KPX/zOK5078f69D265g8hEi9FEmK3o1CUzVr96+oW2tx0XiA7LW4lzvpBP//zvf3L/wYBiGnhPc0+wqdFwHOANvHhgWj0sP7ZpB1U8Ct1T612kLsVVPHDHF7sr0/mRO7irmsJsKGG6l8QMYbU77Nz+X/+qFp3PXxK1XmrYvb07fLbd7KjWo/EHL33z5MbJa+VcSNm2UvdHPin2lB//6Cdf3PwpczTr9KJIPMTdSsK20Tt98mIcB5hU//gPf391bSGMPFnBtE5/9tF/s//kwQq90kb14dbR55/eyVHmDujm6nqe+n6wWzezb7954Xu/+2rdInzyVZhXWLbS2JrHoqLhPNk3ba1e1O/fGhwfi4wt5YiceeEbV998b8q3aUIa9Z6kNdT8BJG1e4+eHjx+pJSy8dzw2nefe+7VK0UJRZo2atYoyKO8SiwbmLTVNrYO9g92gyrXPvzVnRtfBbXOsqKX33n/m/e3d3750d31c8+/++3L33j11N7R4zQlYUKMtJQq2HHkV99qv/z20tOPwNGTT0KBl8+8HLDaF9cHw6dl1NfMntzs1I+O9gqWOE6zyHKGUFZmq+GgqjJJVL//nW+fa5tffP4JG95vq2AVsZOr1mH/9pZnQUWL2QnF1gZhH943x48FAtGje8fR769du7Ia+EdItk72VqjC8nI2Hm8TakBs3L539OzZaOvzfRagze4JpuC4ZFkqmLBk2fQZTd1p2vc0taYDZ7G38mh6M4wjSVNKIilGdfDolns0WGqeS6JZbXHvnfeu/ZP/7NsMuXl5G1SOobRlqXfrK//As/uD+PNPf3Wws+XoGstn3mSsa04sxoqsESBLsPKGz05u2O++++aVi5e/+uKJCo3eanc490Q56UFFKg43Wubzr7/05u++2Llf/+qrL33f42BuN+rc8EapdjQO97YP3cOpkqO8jCSZUolAJhCooiRMJW45jizLVQk55yKzg2AQZYlpkVZXOn1l6aUrJ2qgsTt/omj2mRPfCCf48199etzfgcI01HPz9GGvteinYP4wtpUWCNL9O3F0itS/v3HzxoP/zwd/e+fmdlFoBNdR2Yk85WSnFTx9ZOmwBsj9Dz5G/s7J/+IfdZad+TxdXFpjPA8Dz9B0CWv+LAqDFGlRb7UjgdJzh5YjWarlz+LD7cOqmC0ur9ab7RQ18rhSsEIETObzWAkFo4ypglsAIapCVQ+oHALY8r3ktz6vZSkrYmZigiiQZamssslkQFRDUS1e5UAUS8sdw5DitIjTgmDNNC1dVsoCAcSZ1Dr055mbwKSq0jyIwrAqg7gMo8IL8mQ+WOx1/uhP/5MXXlwD0mG91nwQzdeXztYaI1NvH++mX/z62dMHEwFIFM+KLE8yUkyx0y56i9ZCr1dJ8Ghv3yDya2+88I1vfGN7f+f+s0dLKz0NVmvwxOLSKysbyxKhk7H/5fUHH//6i6zM7j2+e+WV5Y3156nhzyZgdjx5dGsrnqSIeusnTMvMeeVTOWeC5AxuPdsd9Cd5XmICGzXn8tULL7/ynKJLNl4fjY4n075p08RUnoWzWt1wOq3Dp3vXv9rZ23elonW060KdU16buUNJ0QUm3fW1V169+PZrZ66eaybR/k7/GYwqAWijrSIJszSjstxxOqpOSVzsHD7eOZy4E/3shbO/9/3vYll6tjVuCDqKgKbjnMN07H366ac3b1zXDedb3//DF77xmmRJk9FOMguV0DJrvSym6ZykSXnr5sPbtx650zSJ+GQcnj97jsPp9/7oteXFheuf/g0X+amz7T/+s3fqLfThp3+b5/PVjbqiuFXgn72w3F2sHxw9SViWlSmQGlmGd7aP7z+8159ETf30LLspl4t2W0rzqgTB8vL66bMXOYPB7mG7S89faV+42N3ZfUZs9vq3XvRnrH94tNJotVYX5lEW5xGUKBQcAUgJTWOv3bLGg+Mf/M3fFfGLp04unDt9ngD06NmtKJvJBrVr1K4tjmfBVzc/OvD3GKCYkWRWRUmZR0Xshroa1GqkZD7CXNZqURTtHm8vLDYBlI8GRy98+xqRgB8m9fZCJaS5N11Ybi+faJkNtQI2S4BsduJYf7oX3Lyx8+En+1nuCxDbtWYaR0EUytTQLJl5hHOMJZqELkbR6dMXTm32knD8bOdZmsXE1DGqBCipQhstdWml9u7vPGfW0Nb+Noe03uoWLKMqOHthafXE2t///F9/dfsGlKDTdOIgLkFRb9bGs4ggqOmE8yIIXSwpGCmZl7a73W7PivPCsRvPPXfi4jmj1wI+gJohiFTN/UEa0XbHWWg3nz0bxVFRtzD3XFFyluZpBh1LnDm5ur7R4FEYjUfxeK4w3LDrhBhpOuv3+/OjqlZzvCiZuN7myc5zz19VZHU0nJq24/u+ptN6vZ7GSRS6RFK6vc6BH5dZzmCJEAIAxHHMGKs3G2WOqKIAJFFKiiRO0xQT3XGceRYSQlRVA0IumRAgy/OScVZwmdD/8OXZ/7EeCU6oXDs6mtdOAEVTgjAajsYQkUarK6uabVGA8ulskuW+JkuEyHFUFgknkm52u3sH/oObj/buPIZR1ju/4jQbCWBxzEtOnUZPk7Ur166+9c43VWuwtTv0RurD+0cHOy5QkqazGozNuzdmiZ/LVvXCS+eunN3MfVBk4cnzrTPnzurG+k5/+C//+//3rS9vUlKsb/SyLHInbq3RdC6YZ86cqdea81nw+PHuV9fvbD3Zx5I6DabNVnthqU2JTiHVJbX0g+NnE6wEG+ecq1d6VJrN+tuKUlRZ04sdBa4PDr7iRaPK1R/+zWfrJzZOnF6J02A0fTwaH+dFICvgJx+yi5dP/LN//meybRwN0n6flZWhKGrgBSBipt1sSe2QSHGQehIIajI2bOTUcz5pnD5DqzAKM8XWFCELN+AVRxCRTEozKYjZPHYTUXBaHI+G/F4VRxKpGw/uHU3GhwLgE+dWGnar21GyNBnM4sNRmhZazTkpmbkXenmUHhz3Z4er8/n8F7+8f3x8bNsmANzQ0Npa/cVX31zbQD/60Y+fPd5ZXtk4f6kmG9M7dx7eunFPcKcsEs0I333/+ffevcKwH8f21s2drGK6ZcqkPpuOONdOnF1444VvhrCV5VWrsbTQ28gSoahWd2HJ98OZ3VpdV1qLuccmyOYvvvPKlRdb8yn47MYPy7JkApzUjLICk4nrBYkq1wcjZOtWGvhUkkzdMDRzY3WzKgGsgoV6cxaJAiFMGgdH4edfPtnedX2YAsFLt8oi0bCbS90aqGt1U5mE2zYFfX9eAsNqLnnz2Kobvjd47sKlP/pHv/+jn/5oNHaXly4Nh/k8K771jbc6PWe/P8l5RlWj7+Yff3z37t1xFOPpMMWEQ8Q8v8/yeGN1Y3FhPU0qg8MqB1leAJg/d3XzvfdePL2xMDg4hpBgROMgzuJIJqIsxNrawh//yfunL7ZGx+M7Dx6O3dK025iSnA1zPv/0C+9nv/j48bMhR46mE1kihq23WzUs+1VV6JYKQBXEkWnVDd2ez/1nw5HpyACjFAJk6M21VaKku4P+SpNF4TRLPQk2223j9OnFMAynk5B6YZqmuqY0TLXR0C9ePP3aK89fuXISgHxB1TfrnfS4cgcjLA2dhrLZZUJJ6nXNMJz19asXLp6xbHJ43McSz3JWlAmAJSUIcMEqoFLD0B1ZIVVRMp4iIQQQWZ5joiy22nmsx1k+9wNDtxcWl3AF03kchKFqKAAQIIAAQEKAIwggYzynEgzD4LfukSRRiKFMkR8cyYoiK7Rm6wJhTYUCFlWRMCLnRZjlCWSU5ViUEgY6Jejx/tHHH9z++Jc3o/Hk/Nrqt956Y/PMyjAcFCWaTrzRJOzYm622JWBZFIVdq938YPdw+9h3g1oXuOPw3tZ0cli227WLzy++//6FV79xGheQsdhyQJyw3Z1n4TSHZWkZCufVbDY72Bve/PSu7TSfuc0vb40JVib92eHOQVWUpq5KCOpO/urbz9l19eGDp3XHOd6ZXf/oHk8qRqKLl64tL7cIYholGOGcqUlMPv94Kwlpu75eVdJkNh8du0VSBonvyFqbml6S4LzgWXLzF78+2W689dbrrCQy7QK8i5SooaIkjEU2bGqqJet5nk533P7jh49v3lpZr506s/Tqa9farTkjUgVEzdZtw5mOprOJW4KM2BfPnHr5/oN8PC32Dnf//M/3Tm10NA2GYTibpLFfzL3xq9MLFy9sbHRP7O2OPv3kGUKtVsMRPEO4lBQeZfPbt296u5u6ofjzTJFoEk3aC9aLL116863nTbv3iw//8t/95UeWfPm1V1/6g398UVWj/vE8njs6bXp+/9yZlVdfv7ywmfl+XmbN0E/yQiZVeHy0N55O/Kna3VxaXF1c3Lj84P7DOC37h/Hdew8Gg2NVV4syi2agsyi//vaZP/7jd699Y+3R/eOPf33jycNBpc36gyND0842Ty44TUIYRkyW6oODKYdlUcaaXb704qU33niRl9Gw3+/oUq/bgQHxC6Fona/ubH34wW3fF6EwsyiUUXbiZOedly8sN41gcqwRcOby2ynk/6//+a8e7QYEFQLlU/cACe/M5tknDz6/e/tjQghAmEtQMrWb97dO9p6vuBzmfDgb7R5Nv7yxtbvvgQytdZYZz8rC7yw4L7/0rYsXnpsMoi+/uMvKWJGI606WFpXX3rzk1KA739Mt2l04RaVREKe6VIMiy8K4fXn91dffTtD2g/tPXE+Y1knTaGXFkaLls8ngwy8PBqOiXtscz4vpJHccVddkDgxdg543F0xRVTkvqGBKnokwyCDjZRwzXva3d/q7t7Lgxd/7vddPnj4fHH6chEWr0W63V7JMms9WoBQ/fPDkm6e/KSDv9pqLy816U13o2rpF8mIkgurkYvt77717YW389MkOJOlzL2wsr9ZCZY4RrTndemOhLHicJpIEFZUG4aTdbiepz1mxurwiy8rwaOx50zzKbNuqOappqFQi3jwM3GTqzookwlSmmoYkmhcVKJiAQNENTFiesTxPIeBUIVSCDIGKVVHkMf4bB9h+8/9+ChVDV6ExA+PRaJqkaZZliqJQKsmyzIooFFmjXpOkVuQFVS5qtYYElSBIiIo5iOfuQZF4iwunTp9YWl7pRQXOhL+60g2n1cVzi5cuL0gkwxCZsuOOHx4fP8OadO3a1TSO795+1F1ora3Ufvf339g8gb1gp/BjCRbuPOJCq9sbedgCpSAIr6wura2tzUYRYpgyZfdJSGlJIS3zQpGcRltRZBbF81MXTv/B9942TL69dctWmywDcZS121Z93Xn99dcVSQnnmY4bnKeKXCNQ++yLv/S9UAAMAFKUSlVkzpIimYyPKlUjioplCLIiXFlsXVxZ415w5/at4dGEyOW1lxeev3ox9YOj/e0sSbcf+F4W8yRrmW2c0MPbqbtzdOeD8f/1/35qY229zPPhcNgwahol3DRUWet7arO+urZ8Mo7346iIZkk4TXiRC2xBAVQVUAJrDl1b7u221p7dcUvQ/MXf3bIaMK1mEBU1q1akHEGble6w7xfV/OKV9dNnz5y/tLxxYsGy2bOng3u3duvmGRUtAcC7C8Z8Hg4PytmxCioIkHPhxBsYk+2jjzqtjflIDI8MURGnxjQ54QlU4crwqPzpzz7BGA4GkygoJaKUnBHaABUBJcG4+OqzW402zrN3797e/n/8N3/+6a+eqLQjajklUmmSG18c8Hw3nCfuOCjSqtZcRTAlMFlbaZ853bNNEPqpaUlxELIpEIqiW+bRwL13Z2s29g2pkYsFN7nfWYHvfWfj9769ooj0YJtrlJw+v9qfuRLhnHNvPq/S3E1mVy4tvPfu87sHT6Jw1zIkTSGLi0rC6KB/+N/9Pz9Y6HYzlleYcyzFsWjWGwKiXhOneYEIfuPNF958/a2H9w9+/ONfDA99P+P1mr2wYL3//uVXXj8ZettZkFh6M4rAbBIBpNuGORkfNq3a8uKJ2SxeWu09vP33LFU1pSsYZSV55YXXLp66+Mv/7akoDNVuWwZXKBRVMR54BJAo9IIgVLVM0wzX9/IyI4SUZcGykGii1TAkVE12Z8cPbpevnLXaCzlsGXJiajUgOILR2oa+0Lv05tsnXuu+JHAlQCYplWJgKosknyfpzABmy9Kc82vnNk5PXzrPUbC6aekm341FxZAqkyCc9vsuoVqz2cyKCkKcpqnv+6zKHdus15qWbSiKUqKyYuXRweHcm0qSZOmOTE2MpW53ZTZ3514UkhJUoowyCpClmnVJIAGg4ABywSqGC1aljKcQGZZuAvBbvpftB0MoNWViIKZynikKNgyHEKwQiiGiWAqi1NQtXbewReIwAYAXZZykHpPY5Uu91L02GcYvPPecUZOmk0NZrRxd+4PffevtV6JTJ04t9VppOivSNPDzc+c2XnnV53Lx+mvn/Gl1cHQz8Yf1+hJVr1FVRiKVZaHLGsZMN5rdzqki8FVSyXK1tOJsnmr4buvEWjNPShNUiefNoljVZM2koReRpvzStdO/9/33FzqEc//ixZN1a/3ejTvH4x0qC1NrNWyzKktQEgFolkZQZiplS8uNuTesqqrb7VCqqppsWSZjtZZpX7hwznZ033d1g56/cHp5pfvpp58Mtp8mXnTyQuv1b21cubAmyiqY1fzZ1L0gP3i4/emn96JoHOeUQaJTJ0743/67X/yf/0//3LFrQ/egkBMqEUJhxTIkMgKKb7x4jotqf3cYQX68e9BuNDlD08kxqIuzF5xLlxZOnWwM9xaHB7MnW7PxdMRLbTwfqRppnmyCJOYiMh2yumnWG61X37h86kxXMzlEiWGKvf3xF5/dt9XN/vjRy0VtPgvCqJhNPQkRw2gBIHeanXrTdMsa4HoSZt5sUBUzGWmgGJdB5mhOknqHuzu2w9MwS0LRaqy26u0w8r2hFydzhZKNle7mUqNKJnGczI73yig/e27z5s4Dw6A4oaaqsbzMfKhCVZGBjD0GfFVJXn/99PPPrahKQbAcxxOGxdhzhW5iQxlO59PxlGcFIqVj1WJZvnqu9+1vXb1wvuHNj4RkGbr9ZG/ro8+/evx4T4bLJZMNTTY08dK1i6+9euriFR1I01/+cn8yCZIgyqu0bWo152wYB+NpqBiUKqyKZlQFTt083Lv98qtXnrt28eq18zJlzx7fOtzd7rbP6pkfhSOnYV4436VKmVZJc3ERc7OCuwyGCqGgjMsseOmFl3//P3kfkfL+548f3HiYx7YbHJZludhF1y6cNCWhU4oFC6ZjAdVmrQkhDb14Mt61HafZMqmsswoIwbIs5gKpqqJjiFBcp9LJM4t2be25lzccVRxs3e81WnW7jSXkuVMhWFEEGIv19ZbhIFnR/CBIshkvRFoxIZhuSCzKonQaRi7BpmqJgkXH42GwPWqeaLO8TMqYIH1xscsFzqsSIWBZ1swd2bZtmUqWxoPhcbfVbbfbgMCiyHVNkgisqqpWq1NihGE0nswfPH48cWedXm+pu0RlKiNZMw1ZTiWMiYSyQpRVDliKaCkRaOg6q377/dFospPA+Ymls7Q0MVIYL3lVljmLWKwpqqFqVLPjKCtyl0KcRHHEA1VWNB1zOF5faxq/+3zgi7rTgjgOvbkoIE+0blteXcLNeoLRfhG7gslde1W53Fxc7ggl7Sz29rayd97ddMfwrde+sbxmK1pchQVGmko0iQpeVgfbzyCHb7x+5lWycfLiZqtXnrto/Gf/h7eKiI+C+Ue//mQ2S9ZPdBdXFnqLjfOXz5w4sSYRzHiYCTdJUt9DGY+1Ojo43l3KkvHk2Yrdc2oNpagqAQSaI+i/+I2LZ8+vACjWVnqLi13OGasK27brC5bv+7WaLcRGEASCVlv97VtP7mSejyvUsA0k+fv9hzq1Vlbqm2ud+Cy++uapV7/z4uPH/a2t4cHBOI5nQoAHNw+PdsZiseF7XpWHpm6osioh0tNzQtjyWoeQ09sLxnw87zfB6tIiY4Lz+vpGe/O0efqM02yl337/1OtvXvj53//s+g3uhdIVdV1VVVUu8yTHIDn/ytXzF84YpmxalCpMgEwiZKnbc5yg3gAEzduYXn3+JCspFmR1Tat1QhGEhMRZ+QyAKzp5PnAzIM0K8bHjeKfXV1YW7J37+7mYsTKsygJUmSZDpBOZjgLvaOYNl1daK6sLdaN+9fnNMxfahlyaknzlTG+0PRkfftFpIJnwsvRlqQGwyJOZashcVHG6f+W5zd99/zvPPb9eVePBIOIcOZadKmUcRm4Uychoddqb6yvH9/ve4EBBkDCvpp7IA/7w/hGQSqL1YihVOg5yDqBaJijx0kxkG8/XT2+sHA1vCzR/5+1zjrn2wx/c82aHYeCySBU6RAKpNEuDschE24K6zjSS/el//v4bbz2/vF4Po/nu9hOVpmdP9myjfrjTz6p5u1Fb6BhRPNw9OuCoVjMXSnRAdXcyGpUpUBXQ6Uqqkbve0Qc//Jk37ssyIMRHUnHhwrlumw3277Qb3LGyqRcWJZzPhqom1WtSFE6m/rGmmmklJ3EFMFxe10xLQVic7V5yLNGsqRsraxcundBbbH+4d7R37E32TcPqdLoKpbbdVhUzCEJWSLuzrVbboXblNPSqiGczPwriPCnWljYIwhVhisIIpVmulAJAtSoTBBgtGcirXNVVQuUk9yvGgoALIXq9xe5C4/hobzgc9wdH/X7fsG2EoESgbdtBEBRFkcRefzBs1xY3T5w+QSRMJAKRiuSabjq6CbK+IKSUMEAlzBlHkMqYyDBNE85++x5hUlm6HEbTAmiyohAoC6kSoCyLPAgCQojTWQIMYYwxgJRSKkEioSQNVZJW3G0udOrdWpZUPCs0GYksbToLc/+oEH6STjQiQ85ECdsLPYAGUM6EnEXxECH5T/7s3flsZ2N5I2bheDLQgFiprUoMhOEMSwBxXm9IL796Rq5B1SZ51pd1//kXu6hSZKJ8562LR4NBmpf1dqfZbkAqRZ7f69ayqmQiT3MPw+Zrb7yysNraPry+4YDFJV3RQRJF0XwG+USiRAjx3u+8Y9maopLR4HDQP9RNVQixs323ICcM3VJNM8vyVtcUHO7uTpEEJod9AduWYTiOoek6qqQ0KzgAlVEYTevyyqkT107L1Hr2bP8v/uIvHjx4cPXUhZrRdkxTIUsCZHmWlBwzwEC1o2l0HnorK9qlC6/VDCcLg0m/r+lMkfV2uw2JH+d7QbSNsKKY8p/94XuvvnxpFhWr66csy6nyTEMi8mZ5XWo0Gv3B4XQ2NC1lebmb5fHB/ujcuVP/l//qnwRzz58Xm5udySgq2aTV46++vXjrV8X5893TF6S8SDTjsmaVbOPeP/3npw73a9euvg6FcuPzryhJ1jdbq+snTqwYhl7PS4CQ5IVDIIWXn19tttXjJ4GiSL2GKgSscvH6S1c6jv3o4VbjTO3CuctpUuRJmaaphBe73fZ40g9mi9/5zpudrmLbmFBBCahy6fBgKGQJEtLo1jWrkwS43WwsNJ1qGgFxtFCXNpZWVNiM5kFjsUF1eWtvhwFp4/TFV1+zDx7nM6nw5/2zJ0+9eO25tPqiP3rcbq6e2txQ3u9eOLvx4NF9CZk74x3PjTY6rW5nw9IJL31C87Pn11569VVEMne8KylwbbX+2suX0/mD2zceySA7s7nw2stXLlw48eRg/ODJ47kvv/PWlW/+zqVmh96/sS1K+dLF82+9fdmwGdHU5YX2xnKjH0QaL7HET53S1lZVnbQANLGceTGLMvB0e4vx9JWXLlnm2QThqoTHx9PxaL68tvrG26+srfeKMgaJtLJkZtEkCcJKig8n/WEwaG+0V6k2Gk3CaCo4rUpoWq2avVrkbJLeGidjmCT//r11IUSr04FcKsqCEMykpJIEVQyEkQw0RAlnJI5yzbBr1Cy4SIucUmo6GoEQwKIsy93d3SKPW62GrphVycMwKgA3qawpahzHAgLN0BuNhj8Pl9dXZVWf+x6kpLu4qAg0Ph7UtQpBiRBiS0qpy4xLHAUCZhUrqlIAQP+D2fmN99VevHgdK46k1AyrxvK0iANLUyRJirJCSHIp4MpCsypKWVYxlIhEkUCu66Vp2lnQiioviqKoBKuwEKqEDAnrQJ0qOuQk4jBjOZsPC5RYbXv1MHlcFoljqZoq+/Mgi0pTa6mKXYG+LBEqEQlAxIQEkQQRgjAtdABLQkGWB4EfybKuq/U8r7AhS4BqxMBIDlI/qkK5JjV69WwSz71AllWI6XzuA0hsy4EQe+IgCnzPdXWZthpNURZ5mlmGXmLEK8EYFCVASFIoKcp8Pp85DZ2qCuc8z3OJqLJihEEyGs7++//uq6WlhRdfuHDlyinHgWE0jKMZAlWjp1QVn7sBlXUmUJZVhulAgKPpXFV1266pusJ4HqVuxUKExXQ6ta1mlsAwqChRAQBBOE/TcKNdh5BrKoKg1FWqyDj0A1aURD1lNs0SMjcO8lIgpkrCkLEeRgeMl+PJRCLo9NmzTs0aTydBEECmhkFRJEJTjVbL1rUqyYdBNJp7b/UHu1TOl1cdjIoo9AzD6HS6SVIdDcdukCJM87SI5nOdSr12Y6lBBaZE0zLODwaHgTcxdVqzdct0IJQqJgMu5wV3vTnnVb1en7jby4sr7syPw0Q3VCoJ21EsWxPuWAgIIMaYIEw4F3leZkUxw6VjNznDRQ4lpM/d5OmTveOjochH65u9zZMLjZaKpYoxBgDEiEjccF3P9/04SubzeZrmjUZjeXm5uaFQieZpVcQlqqQi44mXVhVPCgohlBQVSyRI0iBJZVWrNRsIPLJtE0tQwtQyG4HH7t3Z3t3p1+uqYeLV9aZuojgJNaUuk9pkHEzjPUOvQ2DNp+GJ9Wa3DmgJG8rapOiMZ+NZ5G7vPaxK7+r55VMrdUuFI9ccjaZhWKR5NfXctEjqLbPVru+OfadmFGUchK5p6t3uoqqYrAJVPEOYtdoO43ng57w0i1RBwDBrSZolrjvO8sgwVadmSBIEkKtyUWalQhTEpTQqJE4MVQcCJek+phQiygCRiA4ltaxElGaKZEAJZ3lOFLnWqMdp4nqeqmttm2GMsywJA48gWKtbGCI/mMegEEIkcYExKQvOGbIsJ8+L46MQU6LbhqwQUBVECBVgVFWUxJbRosQOgiJJItVCugkrHsKUA0H//Afab9ejb39rkDGZCaW33ItDT5NQkURCCKLqccl004GcU0qJJCVJksYJ5AJjiVKKQQKRgBhTqkAkVwVJM1TkIim3ay2L4TzJE5WqsrCKAJSxSORIgJJKQvAizzKVmLrm8BIWbCZLREIYVEwUFQRAlSghZB7kZZURChECjAlNqamKnWc84pkksEYNVdXSInPTWYlzahEDKK4377QXZU3f3torSmZZThBEtR5GEJZliQRQqIwgFBWDEAKZZVlZ5bAqYZ5VgAvdUHRdNwyDsTIv0rzMq6pgjAkhOBCWeTmKPAAKVUMIpnE8K4uYUEiRwhjDlEqYcoFLxjkTsizbei2O0yhOqqoCkEGppLKQFajQFmdwNPTmbqrIqqarCHEsCVqmeRYDWACWqZSYuoGhpChKECiQgqiMgyJEEkaCoopQrM79o2a7rapqxVlVlUmeMcZkVYmDnDOMhUypqiqYKqUkJQIkQXp1Mj6GUtJqKgiXWRpBCAkhFGtRWhQcQSyzoirTVJNQzdSmhzuCKqrZ1OwGQLgs8ypPWZnv7N1b7K0jrAd+DqCkGToAoixzpy5PJjOV6pJEMQKaghnPsCRMnvteWJalYViabiKEMSaqqg4LP4zjNGG6WpewfnQ0HQ5mkkRlUq2sdhstjYOwKOMkiYSAmmZUKZxMJp4XEEJ03VAURVV0RVG8xGs26xLCoixMVaESCX3Pn3unTz83GI+ms7kASDY0JNGirPKyOO4/3NhcS9Po+PjYMOxGbYlXhDMpzUaEcomWSMoJIarilLk0nyVRFjdaCxKyx6P54oJskKAK06a+JrTVwXBYiDLJA4LyblOmImFFCJUuExhhJc2ZF/hFlQpcZUVcwE6rVQOwnHujipWUqERSCZFVDJPM13RcVmmecVmq80rD0DDsRJJQkkRh5GFJaLpclnkY+ivLHQxRGqWi5DXDoZjygmOMx6Nd1TAVVQOSChFhgGZ5lSRJlsdUUeyaAzByvXlRloZt6bpeZTND1ebzWRSGjuNIEPi+X5ZlbbGJMUni1HU9XbMBwN48aLfbUcQRkTBBAAMCIRFC5pAiKMq5ptpFIRW5UFTKRZoxV1ZBNOEEKn/5q/9wj37jea1TXyJqA2I7Lt1WrSXxHCgq57zkHBMpy0pFNrK08IsIAUEpxViosowQKKISA4gRxLCEAuWsyOI8CvPWAqibqsBGCHWZaBrRMp74uQdkjYsCokpwLumapsmyxLK0IKUsIOQccA44F5iDCgMKMZFLRZdM08SIhEFWlZxzYRiWKpuxFwWhN3eneZnFLOEypyUdB4eGZTKeFQVUNYklJeNpra7KoEJAIkRK02zuRpqmmaYNAIjKAROoAjivQCVkAEHOKWYYxTjN8qJgEAOIIICcUEEpcv07eZ5zUeQlUhVZ1XCtZlNKt++NIISNlpUleZqFnPM4Sx3HCYPK98IoSiRJ0g1ZUSHnoiwrahlBkGQJNrRarVZDmMdJkGfFaDC2TLVeczAsMYIIqUlcjUdhy2qkcRbFOQMVNSFFOecRFCGVIUaVaVABoeu6VZEQQmSKaEvVFUtVLIJoWWZl6QsIJUyn0Z5mZ7LKMS3KMgI4Z4ylUVHXHFWmFJCiTAEoqMJ1ggkuWh0dUS0HMC8SiGQMiYyxgMrSclfXKICSomgSUTgQRZkqgLrzaVlWpkEwxEkUx3Eh4cpxzLyoOIACoiTNwygpy0pV1Xq9adcREfIsD4t4rthkY6VVs/QoSqBMkKKMXD9KpmWZeb5bFIVj15uOzbGguowxJpqsGjqRaCUY5s50mCJQ2pYKDZjmbpRPkFxub32mKEqnpUAkCh5VXAheIsB6vZUwiLGElpZWIISGSRTZTJOyjhcIFX44zPJcUTQAQBAEWV7qiq1SU5bt0uIY51DihAJM2dx9UiYeVTVFA4LzIvYZi1UZTb0jjChVLISIrgsdUQY4SoSpOIpMBBDNRp0QAgD8989GQABZBcqCA4h0XbEtC3AVAhonE4lQy5ENq8l4iTGEUHVqhjvyKKUUIVVVIRJROK/KombZac6JDJGmSEiuAAYcIAAVqjp1OY7jKJyleeZHoaJrjBN3HhKU+/4cY2w7dSxRCKBmkDgIZ9PINGwgqEwtVbGyrIjj3HUDx25AjLIq5xWnqoIRghAQiRpWuyg4KISqyaqqpFkuCpbFpaZ0KVUASH+7/dHXvva1r/3/GPr/9wK+9rWvfe3/6+sefe1rX/uH4usefe1rX/uH4usefe1rX/uH4usefe1rX/uH4usefe1rX/uH4usefe1rX/uH4n8Hv6EGRML2rP4AAAAASUVORK5CYII=", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "image_url = Path('../experiment/cache/Strange_Tales_172005/_crop/Strange_Tales_172005_1_Default, grey pad.png')\n", + "image3 = Image.open(image_url)\n", + "display(image3)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "==========\n", + "Image: \n", + "\n", + "Prompt: OCR the text in the image\n", + "THE HOUSE AND THE OLD MAN ARE ALIKE IN MANY WAYS; TALL, PROUD, PATIENT, CONTENTED ALWAYS TO WAIT UNTIL THEIR MASTER COMES HOME--\n", + "==========\n", + "Prompt: 23.533 tokens-per-sec\n", + "Generation: 62.826 tokens-per-sec\n" + ] + } + ], + "source": [ + "if IN_MAC:\n", + " output = generate(\n", + " model, \n", + " processor, # type: ignore\n", + " image3, # type: ignore\n", + " prompt, # type: ignore\n", + " max_tokens=100,\n", + " temp=0.0,\n", + " top_p=1.0,\n", + " # repetition_penalty=1.2,\n", + " # repetition_context_size=40,\n", + " verbose=True\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if IN_MAC:\n", + " del processor\n", + " del model\n", + " mx.metal.clear_cache()\n", + " import gc\n", + " gc.collect()\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Linux" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### [Model card](https://huggingface.co/google/paligemma-3b-mix-448) examples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4-bit/8-bit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if IN_LINUX:\n", + " model_id = \"google/paligemma-3b-mix-224\"\n", + " device = \"cuda:0\"\n", + " dtype = torch.bfloat16\n", + "\n", + " quantization_config = BitsAndBytesConfig(load_in_8bit=True)\n", + "\n", + " model = PaliGemmaForConditionalGeneration.from_pretrained(\n", + " model_id, quantization_config=quantization_config\n", + " ).eval()\n", + " model.device\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if IN_LINUX:\n", + " # Instruct the model to create a caption in Spanish\n", + " prompt = \"caption es\"\n", + " model_inputs = processor(text=prompt, images=image, return_tensors=\"pt\").to(model.device)\n", + " input_len = model_inputs[\"input_ids\"].shape[-1]\n", + "\n", + " with torch.inference_mode():\n", + " generation = model.generate(**model_inputs, max_new_tokens=100, do_sample=False)\n", + " generation = generation[0][input_len:]\n", + " decoded = processor.decode(generation, skip_special_tokens=True)\n", + " print(decoded)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if IN_LINUX:\n", + " del model\n", + " torch.cuda.empty_cache()\n", + " import gc\n", + " gc.collect();\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### OCR" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "processor = AutoProcessor.from_pretrained(model_id)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "756c1e6c2222451aad5de4391e2e8627", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Loading checkpoint shards: 0%| | 0/2 [00:00 bool:\n", + " return PaliGemmaOCR.PROCESSOR is not None and PaliGemmaOCR.MODEL is not None\n", + " is_model_ready = is_paligemma_available\n", + "\n", + " def setup_paligemma(self):\n", + " if self.PROCESSOR is None:\n", + " type(self).setup_processor(size=self.size, quant=self.quant)\n", + " if self.MODEL is None:\n", + " type(self).setup_model(self.device, self.size, self.quant)\n", + " setup = setup_paligemma\n", + " \n", + " def cleanup(self):\n", + " try: del self.PROCESSOR\n", + " except Exception: pass\n", + " try: del self.MODEL\n", + " except Exception: pass\n", + " if IN_MAC:\n", + " mx.metal.clear_cache()\n", + " else:\n", + " torch.cuda.empty_cache()\n", + " import gc\n", + " gc.collect()\n", + " self.MODEL = self.PROCESSOR = None\n", + "\n", + " def _generation_args_mac(self, image: Image.Image, prompt_text: str):\n", + " prompt = prompt_text\n", + " max_new_tokens = 100\n", + " temperature = 0.0\n", + " top_p = 1.0\n", + " # repetition_penalty = 1.2\n", + " # repetition_context_size = 20\n", + " generation_args: dict = {\n", + " 'model': self.MODEL,\n", + " 'processor': self.PROCESSOR,\n", + " \"image\": image,\n", + " 'prompt': prompt,\n", + " \"max_tokens\": max_new_tokens,\n", + " 'temp': temperature,\n", + " 'top_p': top_p,\n", + " # 'repetition_penalty': repetition_penalty,\n", + " # 'repetition_context_size': repetition_context_size,\n", + " }\n", + " return prompt, generation_args\n", + "\n", + " def _generation_args(self, image: Image.Image, prompt: str):\n", + " model_inputs = self.PROCESSOR(text=prompt, images=image, return_tensors=\"pt\").to(self.MODEL.device)\n", + " max_new_tokens=100\n", + " do_sample = False\n", + " generation_args: dict = {\n", + " 'max_new_tokens': max_new_tokens,\n", + " 'do_sample': do_sample,\n", + " }\n", + " return prompt, model_inputs, generation_args\n", + "\n", + " def _generate_mac(self, image: Image.Image, prompt_text: str):\n", + " prompt, generation_args = self._generation_args_mac(image, prompt_text)\n", + " output = generate(\n", + " **generation_args, \n", + " verbose=False#True\n", + " )\n", + " return prompt, output.strip('').strip(' ')\n", + "\n", + " def _generate(self, image: Image.Image, prompt: str):\n", + " prompt, model_inputs, generation_args = self._generation_args(image, prompt)\n", + " input_len = model_inputs[\"input_ids\"].shape[-1]\n", + " with torch.inference_mode():\n", + " generation = self.MODEL.generate(**model_inputs, **generation_args)\n", + " generation = generation[0][input_len:]\n", + " decoded = self.PROCESSOR.decode(generation, skip_special_tokens=True)\n", + " return prompt, decoded\n", + "\n", + " def postprocess_ocr(self, text):\n", + " return ' '.join(remove_multiple_whitespaces(text).splitlines())\n", + " \n", + " def show_info(self):\n", + " quant = self.quant\n", + " size = self.size\n", + " cfg = PaliGemmaOCR.MODEL.config if PaliGemmaOCR.MODEL is not None else None\n", + " if cfg is not None:\n", + " if hasattr(cfg, 'quantization_config'):\n", + " qcfg = cfg.quantization_config\n", + " quant = '4bit' if qcfg.load_in_4bit else '8bit'\n", + " cprint(\n", + " f\"{'Size':>17}: {size!r}\\n\"\n", + " f\"{'Quantization':>17}: {quant!r}\\n\"\n", + " f\"{'Device':>17}: {self.device!r}\\n\"\n", + " f\"{'VRAM':>17}: {get_gpu_vram(False)}/{get_gpu_vram()} MiB\\n\"\n", + " )\n", + "\n", + "\n", + " def __call__(\n", + " self,\n", + " img_or_path: Image.Image | Path | str,\n", + " lang: str | None = None,\n", + " prompt_text: str | None = None,\n", + " config: str | None = None,\n", + " show_prompt: bool = False,\n", + " **kwargs,\n", + " ) -> str:\n", + " self.setup_paligemma()\n", + " if not self.is_paligemma_available():\n", + " raise RuntimeError(\"PaliGemma is not installed or not found.\")\n", + " prompt_text = prompt_text or self.prompt_text_tmpl.format(lang or self.lang)\n", + " image = load_image(img_or_path)\n", + " gen_func = self._generate_mac if IN_MAC and self.quant != 'bfloat16' else self._generate\n", + " prompt, generated_text = gen_func(image, prompt_text)\n", + " if show_prompt:\n", + " cprint(\"INPUT:\", prompt, \"\\nOUTPUT:\", generated_text)\n", + " return generated_text#.strip('\"')\n", + "\n", + "\n", + " def __init__(self, \n", + " lang: str | None = None, \n", + " size: SizeT | None = None,\n", + " quant: QuantT | None = None,\n", + " device: str | None = None, \n", + " *, \n", + " prompt_text_tmpl: str | None = None, \n", + " lazy: bool | None = False,\n", + " **_\n", + " ):\n", + " self.lang = lang\n", + " self.prompt_text_tmpl = prompt_text_tmpl or self.prompt_text_tmpl\n", + " self.size: SizeT = size or '224'\n", + " self.quant: QuantT = quant or 'bfloat16'#'8bits'\n", + " self.device = device or default_device()\n", + " if not lazy and not self.is_paligemma_available():\n", + " self.setup_paligemma()\n", + "\n", + "\n", + "OCRExperimentContext.register_model('PaliGemma', PaliGemmaOCR, {\n", + " \"size\": '224',\n", + " \"quant\": 'bfloat16',\n", + " })\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Context" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| quant \\ platform | Mem | Mac | Linux | Windows | Colab T4 | Colab L4/H100 |\n", + "| --- | --- | --- | --- | --- | --- | --- |\n", + "| **bfloat16** | 6 GB | ✅ | ✅ | ? | ✅ | ✅ |\n", + "| **8bit** | 3 GB | ✅ | ✅ | ? | ✅ | ✅ |\n", + "| **4bit** | 2 GB | ✅ | ✅ | ? | ✅ | ✅ |\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: cursor\n", + "Cache Directory: System default\n", + "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", + "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
 config cache_dir: None\n",
+       "       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
+       "           device: 'mps'\n",
+       "
\n" + ], + "text/plain": [ + " config cache_dir: \u001b[3;35mNone\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'mps'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
        force_PIL: False\n",
+       "       use_tunnel: False\n",
+       "       server_url: \n",
+       "   experiment dir: ../experiment\n",
+       "       source_dir: ../experiment/source\n",
+       "        cache_dir: ../experiment/cache\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " force_PIL: \u001b[3;91mFalse\u001b[0m\n", + " use_tunnel: \u001b[3;91mFalse\u001b[0m\n", + " server_url: \n", + " experiment dir: ..\u001b[35m/\u001b[0m\u001b[95mexperiment\u001b[0m\n", + " source_dir: ..\u001b[35m/experiment/\u001b[0m\u001b[95msource\u001b[0m\n", + " cache_dir: ..\u001b[35m/experiment/\u001b[0m\u001b[95mcache\u001b[0m\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Experiment runs:\n",
+       "PaliGemma-crop-post: 0\n",
+       "
\n" + ], + "text/plain": [ + "Experiment runs:\n", + "PaliGemma-crop-post: \u001b[1;36m0\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "try: CONTEXT.cleanup_model() # type: ignore\n", + "except: pass\n", + "\n", + "quant = '4bit'\n", + "# quant = '8bit'\n", + "# quant = 'bfloat16'\n", + "CONTEXT = OCRExperimentContext('PaliGemma', EXP_DIR, quant=quant, load=False)\n", + "CONTEXT.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "401f1ae17c0941cea4755e18e8738ebe", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Fetching 9 files: 0%| | 0/9 [00:00 Size: '224'\n", + " Quantization: '4bit'\n", + " Device: 'mps'\n", + " VRAM: 2986/65536 MiB\n", + "\n", + "
\n" + ], + "text/plain": [ + " Size: \u001b[32m'224'\u001b[0m\n", + " Quantization: \u001b[32m'4bit'\u001b[0m\n", + " Device: \u001b[32m'mps'\u001b[0m\n", + " VRAM: \u001b[1;36m2986\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ocr_model = CONTEXT.setup_ocr_model(False)\n", + "ocr_model.show_info()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Embowered by great charled cypress trees, the ancient mayor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
0.96
\n", + "
\n", + "
Embowered by great gnarled cypress trees, the ancient manor stands alone on the outskirts of New Orleans, kept tidy by a white-haired old man known only as Bambu.

Embowered by great charled cypress trees, the ancient mayor stands alone on the outskirts of new orleans, kept tidy by a white-haired old man known only as bambu.
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CONTEXT.reset_results(image_idx=20)\n", + "result = CONTEXT.result('PaliGemma-crop', 20, 0, CropMethod.DEFAULT_GREY_PAD)\n", + "result\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
The echo of the old man's footsteps fades down the hall as...
1.00
\n", + "
\n", + "
The echo of the old man's footsteps fades down the hall as...

The echo of the old man's footsteps fades down the hall as...
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CONTEXT.result('Paligemma', 20, 7, CropMethod.INITIAL_BOX)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
The house and the old man are alike in many ways, tall, proud, patient, contented always to wait until their master comes home--
0.99
\n", + "
\n", + "
The house and the old man are alike in many ways; tall, proud, patient, contented always to wait until their master comes home--

The house and the old man are alike in many ways, tall, proud, patient, contented always to wait until their master comes home--
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CONTEXT.result('Paligemma', 20, 1, CropMethod.DEFAULT)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "IMAGE_PATHS = CONTEXT.image_paths\n", + "\n", + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(IMAGE_PATHS)]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# EXP_RUN" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'PaliGemma-crop-post'" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "EXP_RUN = CONTEXT.experiment_run()\n", + "assert EXP_RUN is not None\n", + "RUN_NAME = EXP_RUN.name\n", + "RUN_NAME\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Base image\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a44c162848d04dc69562869f2d272c93", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HTML(value=\""}},"cd3f6165ed144369a54e4b784cac2a99":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"cdfdd7698432492586d0d19783b20b79":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ce3896c172d4497b805ba27a6464c0da":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"cefeb098a7b04f2782b00e28cd809833":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ac247fdb754c460dac3d2a731a04f74b","placeholder":"​","style":"IPY_MODEL_47000f0cc4ce485b9f249ac32a0dc75b","value":" 74.4k/74.4k [00:00<00:00, 5.22MB/s]"}},"d19ccb7ec79a40a483fe40e712c74c8c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d20d3a3712f64dceaeea4b6aeb435b8d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d338945414dc4b23bb1dc1b81cc17be0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"d468d37a817f44ebb5c8b844fc98182a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Action_Comics_1960-01-00_(262)","Adolf_Cap_01_008","Barnaby_v1-028","Barnaby_v1-029","Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013","Cannon-292","Contrato_con_Dios_028","Erase_una_vez_en_Francia_02_88","FOX_CHILLINTALES_T17_012","Furari_-_Jiro_Taniguchi_selma_056","Galactus_12","INOUE_KYOUMEN_002","MCCALL_ROBINHOOD_T31_010","MCCAY_LITTLENEMO_090","Mary_Perkins_On_Stage_v2006_1_-_P00068","PIKE_BOYLOVEGIRLS_T41_012","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2","Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024","Strange_Tales_172005","Strange_Tales_172021","Tarzan_014-21","Tintin_21_Les_Bijoux_de_la_Castafiore_page_39","Transformers_-_Unicron_000-004","Transformers_-_Unicron_000-016","WARE_ACME_024","Yoko_Tsuno_T01_1972-10","Your_Name_Another_Side_Earthbound_T02_084","manga_0033","ronson-031","哀心迷図のバベル 第01巻 - 22002_00_059"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":20,"layout":"IPY_MODEL_8c8083f3c88c493bb2c86be2ee831cc9","style":"IPY_MODEL_2cf68b7c35634bb684f1a9b5364eebff"}},"d47ae1fd98304f549bb15af1885ba182":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"d6f64705e9da407f9959f1b124e8e47e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_2305ed3b768e4930af09fa8b2809df1a","IPY_MODEL_16fcee1797ec48fdba6c556d996eb0c9","IPY_MODEL_397f4e0b79e84838ba3640db134d7b0d"],"layout":"IPY_MODEL_0e7f53ea18fb47bba3f007b7116b8994"}},"d753fc74422941cfa7031efe2c996f50":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_6d0fe13087244d38b7e2c81442467ad0","placeholder":"​","style":"IPY_MODEL_4cda5365a57e453e9bbdcc0de548f1e3","value":"model.safetensors.index.json: 100%"}},"d7f7174351c44565a4778ae02f7b2d73":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d8416277ca174bdebc879a5eeb559203":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d991113b7e924a9ba14b2ee034bc58bb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d9c15d9a41f24f1a86084b0c863d3af8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_69faa9295aa143629f8ba0ce018454d4","IPY_MODEL_14e4633237104f15850409f4ffcfa30a","IPY_MODEL_413317a231404aa9a2a6580775f06fcb"],"layout":"IPY_MODEL_10442533920f484dbf1974e528c6ec1f"}},"d9fdbddf880c4a0cb12ae568c7c3bc02":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"dac4186c487e46c6b56ba7c292629a41":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"dedf69f896794fdab878d78a44db1fcd":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"df002956627b496a8fe33a02bcec05a8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e2f25159f7b249b9a2d820201413e190":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_9c002b71e1f144998d8f5ce683766c2a","placeholder":"​","style":"IPY_MODEL_304ef8bb5c894f3fb9fbb9309fccb2db","value":"tokenizer_config.json: 100%"}},"e3b557d743624c2680fedc10edc679fe":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50px"}},"e41cf0472cbf40f9b8422faef0f7df6a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e4494cbb70ef4e2fb04a138e12c84e34":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","134608384422912"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_7f5e49d03e4e4dc699479b28c9861e86","IPY_MODEL_e498874bec694db7930da19e87551331"],"layout":"IPY_MODEL_2ab7e8393c274604a8a33d5f84efcd58"}},"e498874bec694db7930da19e87551331":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","134608506364032"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_33d7a2f0e1f74398b7fa7b5f24ca8b2d","IPY_MODEL_1e23724ddd3341c4970f0f084c32c11f","IPY_MODEL_1a36a60101aa405d96f154646e1b04fa"],"layout":"IPY_MODEL_0951a0674c6b416d888f8cc62a0a0bd7"}},"e49c2a376b28457fab3517524e5841d9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b50cb561a7444f488f477b8a1dedbf6a","placeholder":"​","style":"IPY_MODEL_700c364b9ed742e39d7d066f38456853","value":"model-00007-of-00007.safetensors: 100%"}},"e5d23d25fb4646d48d863ba26b592273":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e71b8879e55848479fa6f20a4f5010ea":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e7bc0e0e5fed4f6ebf068100805c2439":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e7f41c7ef7b8464899301192fed93749":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e8a8f2864e2346e9abd9ea7e6371901f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e98b093c952c4e3293abdf5b736b3bd7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ea5a56efc11845e2bf38a65d8e93af7c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"eabc054fcd6b447da92f402662469c8e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_71a15c3988114259961d1943dd4e931c","max":185,"min":0,"orientation":"horizontal","style":"IPY_MODEL_43115512206d4717a02ccd0ef4133555","value":185}},"ed19a655de0e42529a3eca5b105a8e92":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"eed1b76b9a824cca8f7ddb490bcec2ff":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"ef92abc3751b4b03a673a92e817d39de":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f0d73ff6d04040f1962fd50d2352f23d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f10a031bce3948e2bccca61bbb6f101c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e2f25159f7b249b9a2d820201413e190","IPY_MODEL_56a8217adf3944b980a92b2aaea2bd39","IPY_MODEL_5090734da55b47d5a2a6087e51891e0d"],"layout":"IPY_MODEL_6aceed8edb8e4105b1f807e57bb25d5e"}},"f52b8b4144bd414b97fddf1e63f114b4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"initial"}},"f54949799fe747e2b4757d73d40960e6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f56c9aac9b874cb79be45bb93af2519d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":"lightblue","font_weight":"bold"}},"f66a7d2bb62d4ef9aec868904a60d8f7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"fb0037405add4963a01046b1ce4d84da":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fc58444ff3d545fcb1714ac56106734c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}}}},"nbformat":4,"nbformat_minor":0} +{"cells":[{"cell_type":"markdown","metadata":{"id":"FO-koL4wUMUg"},"source":["# Testing `Idefics` OCR for Comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"WDMB4HFe39wf"},"source":["## Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"Mox-OHw539wf"},"source":["To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n","\n","- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n","This allows the notebook to access files stored in your Google Drive.\n","\n","- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n","This acts as the root directory for accessing any files within your Google Drive from the notebook.\n","\n","- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n","This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n"]},{"cell_type":"code","execution_count":1,"metadata":{"executionInfo":{"elapsed":740,"status":"ok","timestamp":1717163941428,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"_ItAMB1U39wg"},"outputs":[],"source":["MOUNT_DRIVE = True\n","GDRIVE_MOUNT_POINT = 'drive'\n","PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'"]},{"cell_type":"markdown","metadata":{"id":"OcFWv_IN39wg"},"source":["# install (Colab)\n"]},{"cell_type":"code","execution_count":2,"metadata":{"executionInfo":{"elapsed":361,"status":"ok","timestamp":1717163944019,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"FsMCNzHZ39wg"},"outputs":[],"source":["import fastcore.all as FC\n","import os\n","import re\n","import sys\n","from pathlib import Path\n","\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," (t := Text(msg)).stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, t, \"_\" * 10)\n"]},{"cell_type":"markdown","metadata":{"id":"RkLIZZbo39wg"},"source":["Mount Google Drive"]},{"cell_type":"code","execution_count":3,"metadata":{"executionInfo":{"elapsed":2,"status":"ok","timestamp":1717163947918,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"qoUI5zQe39wg"},"outputs":[],"source":["mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," if not mnt_point.exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n"," drive.mount(str(mnt_point), force_remount=True)\n"]},{"cell_type":"markdown","metadata":{"id":"AWZnedVS39wg"},"source":["### Install **PanelCleaner**\n","\n","> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n","\n","Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook."]},{"cell_type":"code","execution_count":4,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":224},"executionInfo":{"elapsed":12781,"status":"ok","timestamp":1717163977869,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"5VSxqsyK39wg","outputId":"049bf207-b965-499b-8932-ac3044a01621"},"outputs":[],"source":["if FC.IN_COLAB:\n"," pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n"," tb_path = pc_path/'pcleaner/_testbed'\n"," if tb_path.exists():\n"," info('Installing PanelCleaner from your Google Drive')\n"," else:\n"," info('Installing PanelCleaner from GitHub')\n"," !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n"," tb_path = Path('PanelCleaner/pcleaner/_testbed')\n"," assert tb_path.exists(), \"PanelCleaner not found\"\n"," os.chdir(tb_path)\n"," sys.path.append(f\"{pc_path}\")\n"," sys.path.append(f\"{tb_path}\")\n"," !pip install -q -r requirements-colab.txt\n"]},{"cell_type":"code","execution_count":5,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":244},"executionInfo":{"elapsed":88801,"status":"ok","timestamp":1717162885976,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"lxwhxBydCiDj","outputId":"48d07921-9afe-46df-a468-e3e43b96f303"},"outputs":[{"data":{"text/plain":["'4.42.0.dev0'"]},"execution_count":5,"metadata":{},"output_type":"execute_result"}],"source":["if FC.IN_COLAB:\n"," !pip install -q flash-attn --no-build-isolation\n"," !pip install -q transformers accelerate datasets peft bitsandbytes\n","\n","import transformers\n","transformers.__version__"]},{"cell_type":"markdown","metadata":{"id":"gLER7Z0u39wh"},"source":["# Prologue"]},{"cell_type":"code","execution_count":6,"metadata":{"executionInfo":{"elapsed":28634,"status":"ok","timestamp":1717162918596,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"q_7GYpnWUMUl"},"outputs":[],"source":["from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n","from testbed.ocr_idefics import IdeficsOCR, get_gpu_vram\n","from testbed.helpers import IN_MAC, IN_LINUX\n"]},{"cell_type":"code","execution_count":7,"metadata":{"executionInfo":{"elapsed":13,"status":"ok","timestamp":1717162918597,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"cQ0R9v8r39wh"},"outputs":[],"source":["if IN_MAC:\n"," !pip install -q mlx_vlm\n","\n"," import mlx.core as mx\n"]},{"cell_type":"markdown","metadata":{"id":"CAHWMrX339wh"},"source":["# GPU"]},{"cell_type":"code","execution_count":8,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":396},"executionInfo":{"elapsed":12,"status":"ok","timestamp":1717162918597,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"f8XHRVRG39wh","outputId":"5f2d295c-1a32-40af-b964-20b73d546458"},"outputs":[{"data":{"text/html":["
          metal.is_available(): True\n","           metal.device_info(): {'memory_size': 68719476736, 'max_recommended_working_set_size': 51539607552, \n","'max_buffer_length': 38654705664, 'architecture': 'applegpu_g13s'}\n","     metal.get_active_memory(): 0\n","       metal.get_peak_memory(): 0\n","      metal.get_cache_memory(): 0\n","\n","
\n"],"text/plain":[" \u001b[1;35mmetal.is_available\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[3;92mTrue\u001b[0m\n"," \u001b[1;35mmetal.device_info\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'memory_size'\u001b[0m: \u001b[1;36m68719476736\u001b[0m, \u001b[32m'max_recommended_working_set_size'\u001b[0m: \u001b[1;36m51539607552\u001b[0m, \n","\u001b[32m'max_buffer_length'\u001b[0m: \u001b[1;36m38654705664\u001b[0m, \u001b[32m'architecture'\u001b[0m: \u001b[32m'applegpu_g13s'\u001b[0m\u001b[1m}\u001b[0m\n"," \u001b[1;35mmetal.get_active_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_peak_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_cache_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
     total VRAM: 65536 MiB\n","    active VRAM: 0 MiB\n","
\n"],"text/plain":[" total VRAM: \u001b[1;36m65536\u001b[0m MiB\n"," active VRAM: \u001b[1;36m0\u001b[0m MiB\n"]},"metadata":{},"output_type":"display_data"}],"source":["if IN_MAC:\n"," gpu_name = mx.metal.device_info()['architecture']\n"," cprint(\n"," f\"{'metal.is_available()':>30}: {mx.metal.is_available()}\\n\"\n"," f\"{'metal.device_info()':>30}: {mx.metal.device_info()}\\n\"\n"," f\"{'metal.get_active_memory()':>30}: {mx.metal.get_active_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_peak_memory()':>30}: {mx.metal.get_peak_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_cache_memory()':>30}: {mx.metal.get_cache_memory()//1024//1024}\\n\"\n"," )\n","else:\n"," !nvidia-smi\n"," import subprocess\n"," gpu_name = subprocess.check_output(\n"," \"nvidia-smi --query-gpu=gpu_name --format=csv,noheader\", shell=True\n"," ).decode('utf-8').strip()\n"," \n","\n","cprint( f\"{'GPU':>15}: {gpu_name}\\n\"\n"," f\"{'total VRAM':>15}: {get_gpu_vram()} MiB\\n\"\n"," f\"{'active VRAM':>15}: {get_gpu_vram(False)} MiB\")\n","\n"]},{"cell_type":"markdown","metadata":{"id":"Op4kiDaAUMUl"},"source":["----\n","# Idefics experiments"]},{"cell_type":"markdown","metadata":{"id":"q8q3vnLH39wh"},"source":["## Experiment directory"]},{"cell_type":"markdown","metadata":{"id":"6AB4w9C-39wh"},"source":["Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n","\n","NOTE: the default value assumes we are currently inside `PanelCleaner/pcleaner/_testbed` directory. You can check that is the case with `Path('.').resolve()`."]},{"cell_type":"code","execution_count":9,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":49},"executionInfo":{"elapsed":652,"status":"ok","timestamp":1717162939430,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"poPksk6739wh","outputId":"1452cde6-a74a-447c-eec2-3049bd2f8f19"},"outputs":[{"data":{"text/html":["
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n","Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n","
\n"],"text/plain":[" Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n","Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["EXP_DIR = Path('./experiment')\n","cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n"]},{"cell_type":"markdown","metadata":{},"source":["# Test images\n"]},{"cell_type":"markdown","metadata":{},"source":["Copy your images to the source directory:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[{"data":{"text/html":["
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n","
\n"],"text/plain":["\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{"id":"8Iondm2oUMUl"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"nuHPp1U7UMUl"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":10,"metadata":{"executionInfo":{"elapsed":425,"status":"ok","timestamp":1717162947685,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"nVAga31l39wh"},"outputs":[],"source":["if FC.IN_COLAB:\n"," os.environ['USE_TUNNEL'] = 'True'\n"," os.environ['USE_PIL'] = 'False'\n"]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":184},"executionInfo":{"elapsed":8015,"status":"ok","timestamp":1717162983857,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"tG8xtrBb39wh","outputId":"c2e625b8-0f78-44d0-af3a-ca6895a7a340"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import testbed.web_server as web_server\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"p5YiBbJ739wh"},"source":["# CONTEXT"]},{"cell_type":"markdown","metadata":{"id":"1yjjtdjJ39wi"},"source":["| quant, attn \\ platform | Mem | Mac | Linux | Windows | Colab T4 | Colab L4/H100 |\n","| --- | --- | --- | --- | --- | --- | --- |\n","| **float16** | 17 GB | ✅ | ✅ | ? | ❌ | ✅ |\n","| **float16 + attn** | 17 GB | ❌ | ✅ | ? | ❌ | ✅ |\n","| **8bit** | 10 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **8bit + attn** | 10 GB | ❌ | ✅ | ? | ❌ | ✅ |\n","| **4bit** | 6 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **4bit + attn** | 6 GB | ❌ | ✅ | ? | ❌ | ✅ |\n"]},{"cell_type":"markdown","metadata":{"id":"AUgSvi6CUMUm"},"source":["Creates the `IdeficsExperimentContext` object we'll use to manage the experiments.\n"]},{"cell_type":"code","execution_count":15,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":779},"executionInfo":{"elapsed":43567,"status":"ok","timestamp":1717163091060,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"wroznCt0CQdT","outputId":"0d259b2d-b20a-44cc-a0be-1198ad570b46"},"outputs":[{"name":"stdout","output_type":"stream","text":["Current Configuration:\n","\n","Locale: System default\n","Default Profile: Built-in\n","Saved Profiles:\n","- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n","- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n","\n","Profile Editor: cursor\n","Cache Directory: System default\n","Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n","Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n","GUI Theme: System default\n","\n","--------------------\n","\n","Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n","System default cache directory: /Users/vic/Library/Caches/pcleaner\n"]},{"data":{"text/html":["
 config cache_dir: None\n","       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n","           device: 'mps'\n","
\n"],"text/plain":[" config cache_dir: \u001b[3;35mNone\u001b[0m\n"," model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n"," device: \u001b[32m'mps'\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
        force_PIL: False\n","       use_tunnel: False\n","       server_url: \n","   experiment dir: experiment\n","       source_dir: experiment/source\n","        cache_dir: experiment/cache\n","\n","
\n"],"text/plain":[" force_PIL: \u001b[3;91mFalse\u001b[0m\n"," use_tunnel: \u001b[3;91mFalse\u001b[0m\n"," server_url: \n"," experiment dir: experiment\n"," source_dir: experiment/source\n"," cache_dir: experiment/cache\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Experiment runs:\n","Idefics-crop-post: 16\n","
\n"],"text/plain":["Experiment runs:\n","Idefics-crop-post: \u001b[1;36m16\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
     Quantization: '4bit'\n","Flash attention 2: N/A\n","             VRAM: 0/65536 MiB\n","\n","
\n"],"text/plain":[" Quantization: \u001b[32m'4bit'\u001b[0m\n","Flash attention \u001b[1;36m2\u001b[0m: N/A\n"," VRAM: \u001b[1;36m0\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["quant = '4bit' if IN_MAC or FC.IN_COLAB else 'float16'\n","flashattn = True if not FC.IN_COLAB else False\n","CONTEXT = OCRExperimentContext('Idefics', EXP_DIR, \n"," quant=quant, flashattn=flashattn, \n"," server=SERVER, run_name='Idefics-crop-post', load=True)\n","CONTEXT.show()\n"]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"a93af477ed4c4af8aba4d97397009adc","version_major":2,"version_minor":0},"text/plain":["Fetching 11 files: 0%| | 0/11 [00:00. This is expected, and simply means that the `legacy` (previous) behavior will be used so nothing changes for you. If you want to use the new behaviour, set `legacy=False`. This should only be set if you understand what it means, and thoroughly read the reason why this was added as explained in https://github.com/huggingface/transformers/pull/24565\n","Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n"]},{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"0f89471c58b94c2db7ffab9143b26b6b","version_major":2,"version_minor":0},"text/plain":["Fetching 11 files: 0%| | 0/11 [00:00 Quantization: '4bit'\n","Flash attention 2: N/A\n"," VRAM: 5261/65536 MiB\n","\n","
\n"],"text/plain":[" Quantization: \u001b[32m'4bit'\u001b[0m\n","Flash attention \u001b[1;36m2\u001b[0m: N/A\n"," VRAM: \u001b[1;36m5261\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["ocr_model = CONTEXT.setup_ocr_model(False)\n","ocr_model.show_info()"]},{"cell_type":"markdown","metadata":{"id":"NnKaY8er39wi"},"source":["Check the images are in place"]},{"cell_type":"code","execution_count":17,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":319,"status":"ok","timestamp":1717163095107,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"ZXL84T8dUMUm","outputId":"12d640aa-69d7-46aa-c2c8-9d400cccb701"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":17,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"code","execution_count":20,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":255,"referenced_widgets":["41e7d3d5da8843bf97d53a5acc2fdd9c","def94ca8125e4128901b038c5e2e135f","a5b8058abf214b46a3dbc121c285cca7","7792b1aed8724a98817331a5610f9909","4c558212f11743be83311ff10e506255","db4a37385bc04a27ba786692ff23f32c","5cc2cd6464854d1996f83b6cccb71be6","86692867f33a4e2885722f8a9efaa144","57b0595135a84b04bf1c040150132fca","f9feda61c229465da90f33c69e7a4398","2b2f189c18e0494294ad7dc5e6b5a7ce","0eb627a4cba9497f8ea6833ac8080cf3","93acb5ead7244f2b8cb7ddb3db658dc1","827cc40c923e4081bfe56231f386d855","022996922e9d40919a086ce15625e4f3","74e995f849ec449fb5fd50166397897a","c2494c8753e9409aa5e6d8862be5c773","0e112f697e7d4a34826d2a46a067c14e","ee91033cfb084d4e83529a11edb48134","f5e02d40775a49a5b895d498233464f9","cd03b8f4a3144660a66bfb8361433973","de48c263fb124df9b7bf72805e1c1baa","3e76e6f2463549ad91832afd9da60672","cc0369009fb04a0b83a10510d7ac0388","44f0c3de011d47ccab46270d16c690b7","b2e63ba8c2f149d38e8c7722bc47ef07","0f9ca91ec321450f9ce53a84f2459f86","113566b1f4b74279a27f0ab51cffb683","4b1fe42380a1464180f548aaccb220ba","44e2a19f9dcb450cbca016e7b3e9c79d","7a75478806bf465cabc8d1429030f615","fb224135f5a14ba4872e0e64428d60b6","3fb8a4f0b2444c28a082fcbb278979cc","23f2673b6b2f40f19f0d4b1e1d5c6435","c54baefce7804a0eb8729ba88a22f713","af23aff11ddd45b9abf16daa53884c5f","029cc314dfba464b8c91194ee41bb604","76c165d73f574ab39d3357e87b401ac9","68d09a9f2fc84ead952160fe05c5dc90","74d438026f47463f8aa440eb39a58369","a80659636b7f4aa4aeaea4c1149620ea","86315ef030234020a49cfb2275e4ee53","a863d10b9ee947338b73f542c350efe4","ffeb080904984371bb8b715963c00069","f8bc3fb84517404b94502e7498d5c55a","3e1245f557d54e999d58c858f664a0a7","74d88ac2166a407ca2fb1aaf57006018","27e1a3f6033f4ee0aea9bf5726eb78cc","2348e08910b149048c90269942321d57","e6fac459206848898c206456b9dc8b1a","bfc1517ef24c459aae0a536c315ddad1","b9b462859a1846e2b2fdc625f6904506","167be8a944f0447c9c66fe8a485d309e","11c9edbf48f445d09d85f849915496e2","9bb8a92858144190b6dd506673234315","d0f9bc72d3054c45ba0c12d7839e994b","00120cae44354b1397eabc117243f609","5bdcbdc274d14afa91406ca177fe66b6","a478421e36a344eca8cf732ea07241dd","8470bcc137ba4295996a4ef0a2e8bf9c","5cc12b33d27a4715a995173135478c9c","fd00985eb51141799c4ad95c99461926","4fd269b8015f4be783474e835ff8a52e","decf6497acee49faae554f3db39be3ce","8aef4716537e417ea4203a68711cb4e9","bd64ee547bd049398c6d37f1ca476461","5da238d5b8514352a70b6b16cc9d944f","e74be1cd463d42a783ddea46072f4499","a6072dc7d6294061b840144104e07538","f1513571ca224451a3809b56a5739525","e7caf68af3c84c6195483d0a27225164","f6c25f96ead14b13a1a716a6de4e3f5c","4a51933821d045cd881418ff2a2b30e7","1d1a5dd1cc1d44be948464159187e856","d418846006b8496989e86276d8538b50","2ad60e460fe64f0087cf3052f06451ba","6c0b5365fd624af793b4d37f7449a7a5","9590087714614e948f3a8e4dd537a895","24551ce1bc1c4cdab44c25ffd783216e","6aa5fe05ab024eb0bd2b3da7881949f2","8758c30979a2414aac0d1583ab856acf","5768ef94421043d4b87c3a8f36b2fc88","950f956a453648ddbe66fa8b7f484115","1d40ec2dce6d43ae9ed7b02ca6ee5ade","c160c32bb63b405c81788dd2c49ed74a","d142fa6d7f1f452185080e55b24fef2c","67a75a653d0948ac92b0e30a8057f97f","08e41a3312ec4dc698c9677f13493dec","b8b0508e598c461195fdff01e45cefea","dc4134ab8bc54c9084238bce0d63dedd","d18de743a82d421b95ef67cce0cf8300","65d59de757ae4440b71dafd4fbe1ef0f","d265b8b4b76641599b70674b3b6843c2","f58a0d2e63aa456db54e8b34185a9e19","5bee9b83cf53437da9f86ca3e8c28ec8","feb6497eb22b418b89260242009018b1","fcebd41dea6a49d786827eb30e6202f0","cf9218e035054fe49188325d9173124a","ca76a74d6b204b4cae1f1d15a928782f","4fe39d4b2ce74d529df2c59c9b02b468","14ff55af3b4b4f19be5ecbdd7fdbb4b3","f937e91a44ba4ba29379c6cd98c7b06e","69c93310236e407c9ec47efba5949c2c","a9292503813741b096f1627ac629afcf","31b1c0b2c88244b6a1144b5b9bfd6ff2","4377ad0c4af348689bf257dbc1e45d0f","15beb9c45e974b8b9c7928f7dee85721","00d90919857a4182b41f71e4e029b8c9","a0bfaef233fc485088fd5f1069f0e7b5","91f9cb7da8554114a0fdccf7125323f8","afa6b2be45404268bbeae05757c38ea7","c707c0173ba64f278d29d8f91c5ebe72","f84e4be232c7471e8d7c32463d1e69f4","0ec87ae9355747b381f3a3c4759e30a1","7ff52331ff05443c885358a2bc91e45a","2e7dde21eddb461d94120cc0bc8b635d","acd43b8610784095ba13c79a9a8b66b3","94107ffa62c74aa9a7c1c6e9e0926534","aa8727521af944b990cd47bd7f624875","c49d62b351924bac9b758ed566642bc9","03ca2146c0a249e98891c826dc0c7166","3e67ecba11ed494eb5d04ac09aaf2982","cda2a733038b4a2d8d9126478f7c0ae2","856b386e9e354da6985976453f3146df","ae912f1a78a541d58364872d548fb113","1d92eaf91d064d7799cdbdce29cb4a80","8a4eec25ed2f4d888751714385bffb48","23683387f91d412ebcc1c6bda48f36c4","72ed4329ca9140078197aee662b9fe9c","cdbd26ce916d4aefa6bc2de33451b894","d81b6b93bf85468da26dd410d1fbf9ae","926cfc439c6f42c7bc7874e2abd27b00","925d430a70474c2bb645ab1c9635a3d8","1696aa6d01824c8da87bd6c3c99d9338","28e884495ed9480dbf42901aee98c8da","5cb8ef2c547741c782e0b87b44e88883","dfc87068738d4a51aa4582d66655ed5d","65c5547ef83346a3a7fe89350fd0498c","cc4dafcc559147f39d31c93d7bacead0","5ebed15f4ad74010a9dcc1aee2884acb","1d243bb88a024f5cad553638cb66b58f","00358206e8e44b7f93e33a68c77ed88e","1d01c3b7a45443219a40b6fc175bea93","e9638ccc83e64995b8d08950b5d4177c","a38abadac68d4e909589ede57054c9b3","9f407f26d4494b81acf8a2b3d22a4db0","047b24fa06104e88a4649b55d0704bba","e2ba9bdc71e342eea3fe5f0b2d50cad7","768d6cdbca5b4fd081c3c0b665af29e6","6d67906818de434193c0d07dffc16ca3","2d8e2453d52148de9e6f0af80025d277","beae34e9850d41f2928135a17bb7e24e","9ab61a0b2be94ab4b07712847603099f","18ff5098c2b0481e8122bafbb6773254","0adde2a598044d99b27e88632aa79204","18cd166a13cd40409789425e6ad8b1cf","262c89785cf747f8b2fabb01df958f46","481aca32d2314b71b8e2fe34fd5c2752","52bdbb92c8da4412944a3130a6739ff6","277c284a9a6f469285a8cd4adafeac48","c279c338d2ac48d1a905625818533a46","9e8c07a31ffe42f99b3c9234a53fa6dd","0a19274b68ec450895fd7f92941a2d90","4598f6ae49f94d639503175f378f011e","41fe52cfcadb4fcfb708f7f5e7c027ff","330cc931269846f2b6dc82c67fb2251b","c5d36dc5c318484db7e0c8a078aa175b","c159c8f334a64512a6d28efecaea2a10","479dc71849a4477183258d7ef9c0d4c2","d601d39013c24a5db643a09fe3fbf3af","4356a69037274d4288ab9cb2aaf72aef","747ff338df744bb2b4ea31ec325461bb","62416330d58b40d4b5d7cef51dff2245","bbdba0ab16184329bd1479a315c5946e","66b382b44b994abd9279d5edb90f86a1","a4016511fd92466e999483f4314d0a86","262eb29055f44a6dad1a9ad9d2d06ea0","57677aa2aee34f8b831622091eccdc42","6fe70dc2c58c4f34be8f25e507a203fa","cfcf8add8ce44707b89b97b291819b2e","da875aa1f4af4128b1c42bc30c79a8a8","d8d9489d104747d0aeaceab091a5dbba","b0bf5147c56b4a9e829fe1d7016a8971","06127d2f58d14e9b834f9c42fb6ccdee","1491cc4eedf14d788cc7a1750c84021e","ebae562970a84eac8ba32466a405aa06","acae4f3d583f4bb3bc7dc118ce63ae52","fc6764a48f134c7c863b83ac060a7c4e","b916a63767b44a7f9af4c4fd2d9f9118","44e7eca8403f42eab30a12cb6c4ec177","cad18185ae304fda8d114efce29f8b2b","022a6ebb208c40a38d991a7f48cf8199","5a12c2fbe4f949ec931de9e0ccb035ee","1cac8099d5a84d24bd968b0df0293e72","61e8b3559eb8464b9d3544921f9f716d","04fb26ceffe54dffb6b0f9864a3ada8a","83e6807d435d458ab54317a00543458a","383311a4464e4759972acb80200e05f3","aa8959e5f31a4e2a917849ff38e2d54a","cfad9960dbe7451db558e5d23edd4f87","7c0dbe672a904b7486a3274e87b42588","6f57b2e373e84323a7a0a2052c8a37db","418e999ec09c434ab6ac89e3b4b11365","4359515725fb4bfc93a8ac6ca824c6bd","7a6ff42ed0954523a58a579968191cca","f4f7b2ccfbd94a30a1f7a413c159ef07","7048ae3da65443a1a6996d937af1fec8","b74df493ed504a6aa9e2dd4c4bc48c56","0606d53650544db098d23fdf417584ad","fc986695bc55477099e8df7f9a0022cd","bf2ea05486a644e8ad8166ba0a9ff0a4","8c77254960fc4ed59a0431bb9f43b9dd","adda7298580c4bffb8d3c5e272e8eb7f","b9972d7b5b614566be7408889f1893bf","e364391a3e1d41d899735458a2b01436","7c30a1a41d3747e0b87625488e29c1b3","25cebb1840ea4239983838fdf2e5c84d","26deaa27cdea4addb812a67b4a0aae7a","bd6f1373744c49aa9ad9947714998e5d","83c2db21b673401fb11b45dde165fa14","96f3c7a52a37470a98de481a7ea343ca","eae063c3c5f54c86aee0b68d31f721ff","2472a63aefde4dc1bb199ab9847ca993","c4c988f7315a4734b4b4efcd378d2fe0","a05a89a8727a486792504d208aa43034","2c62ea060f2448ab928eb2b75897a227","b67a72677c674923b15e568e6fcdeb5c","9875ff389f3d46268417e9b53fbceaf5","d6a71cec5ffe4ba5992636efad52b8fe","62ec88a9e4e549729c5531c2c84ae21d","2c3264065ce141ab9f4c02ca29538962","37675716244d46fcb115ba1d8c500d3f","e37b7be566694f66bd5aa6e82572a2e7","b9fa62d6dd5e4e67921be98817cb00e2","9d210efdd32a4aa8a2b084cb9790ed48","3041f272c57c4038b11806de84232840","613b52321ad543d3b1f67c25642edf54","61a3f504ff5645db9d499f8f2ce0cb37","e1dcbdbabc40469793a494f59318b088","b5fe8a048b9a4db3bcfa77c81dfa8b0c","a4a7b41a2d6d4836b1d5b7c46d214a27","ab1faf852db24d418b647d44305f9998","f9b21842783e489d99ad9d25cd7d0914","5674ed00bf624d4fa0180ca9d855a797","66d2a279e9704c4cb03e51791814387e","a24e83fa73e24808a1b39f3f3d29e7ac","2d058a65cfdf4c628a38bd34eed8a8a8","934d301cd7d94a7597047efd861ceb66","113f7abf92c04d61aeb27a53796dddde","357d2c73ff2346a2a04ec63f11796048","7b065f9d0a454070b32e2f539f94769e","6cd377ac03004bf3b12fed2c9ec72aa9","010d7b561b1541e680b2a93007ec8bc5","73b6e040d91845c8ba2d220b53f93c09","ff88a16ea32e4df4b3abce055f6e2bc2","d71eb0b4940b4708a51b90af9e746db7","66f62676485e444db8fb34d870047708","3eb2ad0ee975499691c2655bdb9d90e5","1a7e467e1e7d4adf9c04217b09a54173","4e5a20cc1ed24d5d89305329da2b48e1","6f67bfe2f79c424fafbe0f85e40c1642","f17c2e4e8b2045e9930d9f2d73bf2ac7","cce621f14c99412ea7b92441fd4f3223","2c3a7c4e59e64433be763bcabd340df3","ae6d816055bd43a4a01cb54b8fb84486","598b5756615241c298f8f44d1e3b3f4f","d0567212f6824f5daec8a14d4c7bb0c7","aafbd97ba12d40e4affc97c378ae165e","798fe48e8b184a4ab35f56fca750dcbe","4c7342561d52489581e643f1d3121eb8","777aaee7cfdf4afd974983fdbd37ac8a","95af7b96533b47a7be57deb9cd5b0fb8","49cf9e00eb8b44cd9168574abe3df2c5","b7156a8bbb104cef9ce2ebbcf458f2cb","eb03b5ac6feb452a86ab17129481d3cb","ed6bd84830a642fd832ea549372056ad","6d69bd7081d44f748463fe8252ce675d","8d52617983b442e7b02d3d2ef885376c"],"resources":{"http://localhost:8080/experiment/cache/Action_Comics_1960-01-00_(262)/_crop/Action_Comics_1960-01-00_(262)_13_Default,%20grey%20pad.png":{"data":"CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPWVuPgogIDxtZXRhIGNoYXJzZXQ9dXRmLTg+CiAgPG1ldGEgbmFtZT12aWV3cG9ydCBjb250ZW50PSJpbml0aWFsLXNjYWxlPTEsIG1pbmltdW0tc2NhbGU9MSwgd2lkdGg9ZGV2aWNlLXdpZHRoIj4KICA8dGl0bGU+RXJyb3IgNDA0IChOb3QgRm91bmQpISExPC90aXRsZT4KICA8c3R5bGU+CiAgICAqe21hcmdpbjowO3BhZGRpbmc6MH1odG1sLGNvZGV7Zm9udDoxNXB4LzIycHggYXJpYWwsc2Fucy1zZXJpZn1odG1se2JhY2tncm91bmQ6I2ZmZjtjb2xvcjojMjIyO3BhZGRpbmc6MTVweH1ib2R5e21hcmdpbjo3JSBhdXRvIDA7bWF4LXdpZHRoOjM5MHB4O21pbi1oZWlnaHQ6MTgwcHg7cGFkZGluZzozMHB4IDAgMTVweH0qID4gYm9keXtiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9lcnJvcnMvcm9ib3QucG5nKSAxMDAlIDVweCBuby1yZXBlYXQ7cGFkZGluZy1yaWdodDoyMDVweH1we21hcmdpbjoxMXB4IDAgMjJweDtvdmVyZmxvdzpoaWRkZW59aW5ze2NvbG9yOiM3Nzc7dGV4dC1kZWNvcmF0aW9uOm5vbmV9YSBpbWd7Ym9yZGVyOjB9QG1lZGlhIHNjcmVlbiBhbmQgKG1heC13aWR0aDo3NzJweCl7Ym9keXtiYWNrZ3JvdW5kOm5vbmU7bWFyZ2luLXRvcDowO21heC13aWR0aDpub25lO3BhZGRpbmctcmlnaHQ6MH19I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LnBuZykgbm8tcmVwZWF0O21hcmdpbi1sZWZ0Oi01cHh9QG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWluLXJlc29sdXRpb246MTkyZHBpKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSBuby1yZXBlYXQgMCUgMCUvMTAwJSAxMDAlOy1tb3otYm9yZGVyLWltYWdlOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSAwfX1AbWVkaWEgb25seSBzY3JlZW4gYW5kICgtd2Via2l0LW1pbi1kZXZpY2UtcGl4ZWwtcmF0aW86Mil7I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LTJ4LnBuZykgbm8tcmVwZWF0Oy13ZWJraXQtYmFja2dyb3VuZC1zaXplOjEwMCUgMTAwJX19I2xvZ297ZGlzcGxheTppbmxpbmUtYmxvY2s7aGVpZ2h0OjU0cHg7d2lkdGg6MTUwcHh9CiAgPC9zdHlsZT4KICA8YSBocmVmPS8vd3d3Lmdvb2dsZS5jb20vPjxzcGFuIGlkPWxvZ28gYXJpYS1sYWJlbD1Hb29nbGU+PC9zcGFuPjwvYT4KICA8cD48Yj40MDQuPC9iPiA8aW5zPlRoYXTigJlzIGFuIGVycm9yLjwvaW5zPgogIDxwPiAgPGlucz5UaGF04oCZcyBhbGwgd2Uga25vdy48L2lucz4K","headers":[["content-length","1449"],["content-type","text/html; charset=utf-8"]],"ok":false,"status":404,"status_text":""},"http://localhost:8080/experiment/cache/Strange_Tales_172005/_crop/Strange_Tales_172005_13_Default,%20grey%20pad.png":{"data":"CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPWVuPgogIDxtZXRhIGNoYXJzZXQ9dXRmLTg+CiAgPG1ldGEgbmFtZT12aWV3cG9ydCBjb250ZW50PSJpbml0aWFsLXNjYWxlPTEsIG1pbmltdW0tc2NhbGU9MSwgd2lkdGg9ZGV2aWNlLXdpZHRoIj4KICA8dGl0bGU+RXJyb3IgNDA0IChOb3QgRm91bmQpISExPC90aXRsZT4KICA8c3R5bGU+CiAgICAqe21hcmdpbjowO3BhZGRpbmc6MH1odG1sLGNvZGV7Zm9udDoxNXB4LzIycHggYXJpYWwsc2Fucy1zZXJpZn1odG1se2JhY2tncm91bmQ6I2ZmZjtjb2xvcjojMjIyO3BhZGRpbmc6MTVweH1ib2R5e21hcmdpbjo3JSBhdXRvIDA7bWF4LXdpZHRoOjM5MHB4O21pbi1oZWlnaHQ6MTgwcHg7cGFkZGluZzozMHB4IDAgMTVweH0qID4gYm9keXtiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9lcnJvcnMvcm9ib3QucG5nKSAxMDAlIDVweCBuby1yZXBlYXQ7cGFkZGluZy1yaWdodDoyMDVweH1we21hcmdpbjoxMXB4IDAgMjJweDtvdmVyZmxvdzpoaWRkZW59aW5ze2NvbG9yOiM3Nzc7dGV4dC1kZWNvcmF0aW9uOm5vbmV9YSBpbWd7Ym9yZGVyOjB9QG1lZGlhIHNjcmVlbiBhbmQgKG1heC13aWR0aDo3NzJweCl7Ym9keXtiYWNrZ3JvdW5kOm5vbmU7bWFyZ2luLXRvcDowO21heC13aWR0aDpub25lO3BhZGRpbmctcmlnaHQ6MH19I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LnBuZykgbm8tcmVwZWF0O21hcmdpbi1sZWZ0Oi01cHh9QG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWluLXJlc29sdXRpb246MTkyZHBpKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSBuby1yZXBlYXQgMCUgMCUvMTAwJSAxMDAlOy1tb3otYm9yZGVyLWltYWdlOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSAwfX1AbWVkaWEgb25seSBzY3JlZW4gYW5kICgtd2Via2l0LW1pbi1kZXZpY2UtcGl4ZWwtcmF0aW86Mil7I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LTJ4LnBuZykgbm8tcmVwZWF0Oy13ZWJraXQtYmFja2dyb3VuZC1zaXplOjEwMCUgMTAwJX19I2xvZ297ZGlzcGxheTppbmxpbmUtYmxvY2s7aGVpZ2h0OjU0cHg7d2lkdGg6MTUwcHh9CiAgPC9zdHlsZT4KICA8YSBocmVmPS8vd3d3Lmdvb2dsZS5jb20vPjxzcGFuIGlkPWxvZ28gYXJpYS1sYWJlbD1Hb29nbGU+PC9zcGFuPjwvYT4KICA8cD48Yj40MDQuPC9iPiA8aW5zPlRoYXTigJlzIGFuIGVycm9yLjwvaW5zPgogIDxwPiAgPGlucz5UaGF04oCZcyBhbGwgd2Uga25vdy48L2lucz4K","headers":[["content-length","1449"],["content-type","text/html; charset=utf-8"]],"ok":false,"status":404,"status_text":""}}},"executionInfo":{"elapsed":1557,"status":"ok","timestamp":1717163102674,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"GmAca8fVUMUm","outputId":"407601af-7f59-4bb0-e428-cdde90b5ad8d"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"d4d04b8e8b6048f98d6614d47949e7c0","version_major":2,"version_minor":0},"text/plain":["VBox(children=(HTML(value=\""}},"dfc87068738d4a51aa4582d66655ed5d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_1d243bb88a024f5cad553638cb66b58f","placeholder":"​","style":"IPY_MODEL_00358206e8e44b7f93e33a68c77ed88e","value":"special_tokens_map.json: 100%"}},"e1dcbdbabc40469793a494f59318b088":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e2ba9bdc71e342eea3fe5f0b2d50cad7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_beae34e9850d41f2928135a17bb7e24e","placeholder":"​","style":"IPY_MODEL_9ab61a0b2be94ab4b07712847603099f","value":"config.json: 100%"}},"e364391a3e1d41d899735458a2b01436":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_83c2db21b673401fb11b45dde165fa14","max":4999813704,"min":0,"orientation":"horizontal","style":"IPY_MODEL_96f3c7a52a37470a98de481a7ea343ca","value":4999813704}},"e37b7be566694f66bd5aa6e82572a2e7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e6fac459206848898c206456b9dc8b1a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"e74be1cd463d42a783ddea46072f4499":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e7caf68af3c84c6195483d0a27225164":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_d418846006b8496989e86276d8538b50","placeholder":"​","style":"IPY_MODEL_2ad60e460fe64f0087cf3052f06451ba","value":"processor_config.json: 100%"}},"e9638ccc83e64995b8d08950b5d4177c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"eae063c3c5f54c86aee0b68d31f721ff":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"eb03b5ac6feb452a86ab17129481d3cb":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ebae562970a84eac8ba32466a405aa06":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"ed6bd84830a642fd832ea549372056ad":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"ee91033cfb084d4e83529a11edb48134":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137212937453776"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_76c165d73f574ab39d3357e87b401ac9"],"layout":"IPY_MODEL_68d09a9f2fc84ead952160fe05c5dc90"}},"f1513571ca224451a3809b56a5739525":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e7caf68af3c84c6195483d0a27225164","IPY_MODEL_f6c25f96ead14b13a1a716a6de4e3f5c","IPY_MODEL_4a51933821d045cd881418ff2a2b30e7"],"layout":"IPY_MODEL_1d1a5dd1cc1d44be948464159187e856"}},"f17c2e4e8b2045e9930d9f2d73bf2ac7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f4f7b2ccfbd94a30a1f7a413c159ef07":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f58a0d2e63aa456db54e8b34185a9e19":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_ca76a74d6b204b4cae1f1d15a928782f","max":1636,"min":0,"orientation":"horizontal","style":"IPY_MODEL_4fe39d4b2ce74d529df2c59c9b02b468","value":1636}},"f5e02d40775a49a5b895d498233464f9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"visible","width":null}},"f6c25f96ead14b13a1a716a6de4e3f5c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_6c0b5365fd624af793b4d37f7449a7a5","max":483,"min":0,"orientation":"horizontal","style":"IPY_MODEL_9590087714614e948f3a8e4dd537a895","value":483}},"f84e4be232c7471e8d7c32463d1e69f4":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f8bc3fb84517404b94502e7498d5c55a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f937e91a44ba4ba29379c6cd98c7b06e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f9b21842783e489d99ad9d25cd7d0914":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"f9feda61c229465da90f33c69e7a4398":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137212937454928"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_c2494c8753e9409aa5e6d8862be5c773","IPY_MODEL_0e112f697e7d4a34826d2a46a067c14e","IPY_MODEL_ee91033cfb084d4e83529a11edb48134"],"layout":"IPY_MODEL_f5e02d40775a49a5b895d498233464f9"}},"fb224135f5a14ba4872e0e64428d60b6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"BoundedIntTextModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"BoundedIntTextModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"IntTextView","continuous_update":false,"description":"","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_11c9edbf48f445d09d85f849915496e2","max":14,"min":0,"step":1,"style":"IPY_MODEL_9bb8a92858144190b6dd506673234315","value":0}},"fc6764a48f134c7c863b83ac060a7c4e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"fc986695bc55477099e8df7f9a0022cd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"fcebd41dea6a49d786827eb30e6202f0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fd00985eb51141799c4ad95c99461926":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"block","flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"feb6497eb22b418b89260242009018b1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ff88a16ea32e4df4b3abce055f6e2bc2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ffeb080904984371bb8b715963c00069":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Boxes","Image","Mask","Image & Mask","Page data","Ground truth","Image All","Results","Best results","Accuracy","Dataframe","Config"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":7,"layout":"IPY_MODEL_bd64ee547bd049398c6d37f1ca476461","style":"IPY_MODEL_5da238d5b8514352a70b6b16cc9d944f"}}}}},"nbformat":4,"nbformat_minor":0} diff --git a/pcleaner/_testbed/test_paligemma.ipynb b/pcleaner/_testbed/test_paligemma.ipynb new file mode 100644 index 00000000..0275156a --- /dev/null +++ b/pcleaner/_testbed/test_paligemma.ipynb @@ -0,0 +1 @@ +{"cells":[{"cell_type":"markdown","metadata":{"id":"FO-koL4wUMUg"},"source":["# Testing `PaliGemma` OCR for Comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"HKOXOxox_jG0"},"source":["## Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"GakYQssB_jG0"},"source":["To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n","\n","- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n","This allows the notebook to access files stored in your Google Drive.\n","\n","- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n","This acts as the root directory for accessing any files within your Google Drive from the notebook.\n","\n","- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n","This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n"]},{"cell_type":"code","execution_count":2,"metadata":{"executionInfo":{"elapsed":2,"status":"ok","timestamp":1717165201592,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"uNgZx4vk_jG0"},"outputs":[],"source":["MOUNT_DRIVE = True\n","GDRIVE_MOUNT_POINT = 'drive'\n","PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'"]},{"cell_type":"markdown","metadata":{"id":"1iZhT2Zd_jG1"},"source":["# install (Colab)\n"]},{"cell_type":"code","execution_count":3,"metadata":{"executionInfo":{"elapsed":3,"status":"ok","timestamp":1717165204341,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"RNFlWKSb_jG1"},"outputs":[],"source":["import fastcore.all as FC\n","import os\n","import re\n","import sys\n","from pathlib import Path\n","\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," (t := Text(msg)).stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, t, \"_\" * 10)\n"]},{"cell_type":"markdown","metadata":{"id":"Xrv0xwSP_jG1"},"source":["Mount Google Drive"]},{"cell_type":"code","execution_count":4,"metadata":{"executionInfo":{"elapsed":4,"status":"ok","timestamp":1717165208042,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"7h-QzI37_jG1"},"outputs":[],"source":["mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," if not mnt_point.exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n"," drive.mount(str(mnt_point), force_remount=True)\n"]},{"cell_type":"markdown","metadata":{"id":"41JG2K1G_jG1"},"source":["### Install **PanelCleaner**\n","\n","> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n","\n","Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook."]},{"cell_type":"code","execution_count":5,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":33},"executionInfo":{"elapsed":4564,"status":"ok","timestamp":1717165217825,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"SdiVA--u_jG1","outputId":"4c6a00e8-c8d9-4988-c5f2-7010c1233681"},"outputs":[],"source":["if FC.IN_COLAB:\n"," pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n"," tb_path = pc_path/'pcleaner/_testbed'\n"," if tb_path.exists():\n"," info('Installing PanelCleaner from your Google Drive')\n"," else:\n"," info('Installing PanelCleaner from GitHub')\n"," !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n"," tb_path = Path('PanelCleaner/pcleaner/_testbed')\n"," assert tb_path.exists(), \"PanelCleaner not found\"\n"," os.chdir(tb_path)\n"," sys.path.append(f\"{pc_path}\")\n"," sys.path.append(f\"{tb_path}\")\n"," !pip install -q -r requirements-colab.txt\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[{"data":{"text/plain":["'4.42.0.dev0'"]},"metadata":{},"output_type":"display_data"}],"source":["if FC.IN_COLAB:\n"," !pip install -q accelerate\n","\n","import transformers\n","transformers.__version__"]},{"cell_type":"markdown","metadata":{"id":"8_A18iMfN2-g"},"source":["# Prologue"]},{"cell_type":"code","execution_count":7,"metadata":{"executionInfo":{"elapsed":4223,"status":"ok","timestamp":1717165238956,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"q_7GYpnWUMUl"},"outputs":[],"source":["from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n","from testbed.ocr_paligemma import PaliGemmaOCR, get_gpu_vram\n","from testbed.helpers import IN_MAC, IN_LINUX\n"]},{"cell_type":"code","execution_count":8,"metadata":{"executionInfo":{"elapsed":2,"status":"ok","timestamp":1717165238956,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"CQtkWb9ON2-g"},"outputs":[],"source":["if IN_MAC:\n"," # !pip install -q mlx_vlm\n","\n"," import mlx.core as mx\n"]},{"cell_type":"markdown","metadata":{"id":"DK4iMZ7nN2-g"},"source":["# GPU"]},{"cell_type":"code","execution_count":12,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":396},"executionInfo":{"elapsed":660,"status":"ok","timestamp":1717165239614,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"_qoPb5u3N2-g","outputId":"6dec4a6e-5679-47c5-cc53-17473a6e214b"},"outputs":[{"data":{"text/html":["
          metal.is_available(): True\n","           metal.device_info(): {'memory_size': 68719476736, 'max_recommended_working_set_size': 51539607552, \n","'max_buffer_length': 38654705664, 'architecture': 'applegpu_g13s'}\n","     metal.get_active_memory(): 0\n","       metal.get_peak_memory(): 0\n","      metal.get_cache_memory(): 0\n","\n","
\n"],"text/plain":[" \u001b[1;35mmetal.is_available\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[3;92mTrue\u001b[0m\n"," \u001b[1;35mmetal.device_info\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'memory_size'\u001b[0m: \u001b[1;36m68719476736\u001b[0m, \u001b[32m'max_recommended_working_set_size'\u001b[0m: \u001b[1;36m51539607552\u001b[0m, \n","\u001b[32m'max_buffer_length'\u001b[0m: \u001b[1;36m38654705664\u001b[0m, \u001b[32m'architecture'\u001b[0m: \u001b[32m'applegpu_g13s'\u001b[0m\u001b[1m}\u001b[0m\n"," \u001b[1;35mmetal.get_active_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_peak_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_cache_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
            GPU: applegpu_g13s\n","     total VRAM: 65536 MiB\n","    active VRAM: 0 MiB\n","
\n"],"text/plain":[" GPU: applegpu_g13s\n"," total VRAM: \u001b[1;36m65536\u001b[0m MiB\n"," active VRAM: \u001b[1;36m0\u001b[0m MiB\n"]},"metadata":{},"output_type":"display_data"}],"source":["if IN_MAC:\n"," gpu_name = mx.metal.device_info()['architecture']\n"," cprint(\n"," f\"{'metal.is_available()':>30}: {mx.metal.is_available()}\\n\"\n"," f\"{'metal.device_info()':>30}: {mx.metal.device_info()}\\n\"\n"," f\"{'metal.get_active_memory()':>30}: {mx.metal.get_active_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_peak_memory()':>30}: {mx.metal.get_peak_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_cache_memory()':>30}: {mx.metal.get_cache_memory()//1024//1024}\\n\"\n"," )\n","else:\n"," !nvidia-smi\n"," import subprocess\n"," gpu_name = subprocess.check_output(\n"," \"nvidia-smi --query-gpu=gpu_name --format=csv,noheader\", shell=True\n"," ).decode('utf-8').strip()\n"," \n","\n","cprint( f\"{'GPU':>15}: {gpu_name}\\n\"\n"," f\"{'total VRAM':>15}: {get_gpu_vram()} MiB\\n\"\n"," f\"{'active VRAM':>15}: {get_gpu_vram(False)} MiB\")\n","\n"]},{"cell_type":"markdown","metadata":{"id":"Op4kiDaAUMUl"},"source":["----\n","# PaliGemma experiments"]},{"cell_type":"code","execution_count":10,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":1932,"status":"ok","timestamp":1717165245172,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"D0LeqL6TZ-GY","outputId":"4b587e05-4de3-469b-cbd4-49b58fc0939d"},"outputs":[{"name":"stdout","output_type":"stream","text":["User is already logged in.\n"]}],"source":["from huggingface_hub import notebook_login\n","notebook_login(False, False)"]},{"cell_type":"markdown","metadata":{"id":"Y3IENuzMN2-h"},"source":["## Experiment directory"]},{"cell_type":"markdown","metadata":{"id":"urj8RO7aN2-h"},"source":["Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n","\n","NOTE: the default value assumes we are currently inside `PanelCleaner/pcleaner/_testbed` directory. You can check that is the case with `Path('.').resolve()`."]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":49},"executionInfo":{"elapsed":369,"status":"ok","timestamp":1717165248315,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"cbFj63q4N2-h","outputId":"b10db83f-aa18-496d-e16e-834050b8aea7"},"outputs":[{"data":{"text/html":["
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n","Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n","
\n"],"text/plain":[" Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n","Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["EXP_DIR = Path('./experiment')\n","cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n"]},{"cell_type":"markdown","metadata":{},"source":["# Test images\n"]},{"cell_type":"markdown","metadata":{},"source":["Copy your images to the source directory:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[{"data":{"text/html":["
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n","
\n"],"text/plain":["\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{"id":"8Iondm2oUMUl"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"nuHPp1U7UMUl"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":12,"metadata":{"executionInfo":{"elapsed":559,"status":"ok","timestamp":1717165257647,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"vaf4PGLlUMUm"},"outputs":[],"source":["if FC.IN_COLAB:\n"," os.environ['USE_TUNNEL'] = 'True'\n"," os.environ['USE_PIL'] = 'False'\n"]},{"cell_type":"code","execution_count":13,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":184},"executionInfo":{"elapsed":47202,"status":"ok","timestamp":1717165306667,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"kivkfTrcUMUm","outputId":"6547dd4b-3747-4c99-e393-a422d1a85798"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import testbed.web_server as web_server\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"B0UlRbJ4N2-h"},"source":["# CONTEXT"]},{"cell_type":"markdown","metadata":{"id":"gBET0jZMN2-h"},"source":["| quant \\ platform | Mem | Mac | Linux | Windows | Colab T4 | Colab L4/H100 |\n","| --- | --- | --- | --- | --- | --- | --- |\n","| **bfloat16** | 6 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **8bit** | 3 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **4bit** | 2 GB | ✅ | ✅ | ? | ✅ | ✅ |\n"]},{"cell_type":"markdown","metadata":{"id":"AUgSvi6CUMUm"},"source":["Creates the `ExperimentContext` object we'll use to manage the experiments.\n"]},{"cell_type":"code","execution_count":18,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":504},"executionInfo":{"elapsed":434,"status":"ok","timestamp":1717165321066,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"wroznCt0CQdT","outputId":"ec50236e-dddc-4d60-b3cd-b6fdcb0a584f"},"outputs":[{"name":"stdout","output_type":"stream","text":["Current Configuration:\n","\n","Locale: System default\n","Default Profile: Built-in\n","Saved Profiles:\n","- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n","- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n","\n","Profile Editor: cursor\n","Cache Directory: System default\n","Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n","Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n","GUI Theme: System default\n","\n","--------------------\n","\n","Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n","System default cache directory: /Users/vic/Library/Caches/pcleaner\n"]},{"data":{"text/html":["
 config cache_dir: None\n","       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n","           device: 'mps'\n","
\n"],"text/plain":[" config cache_dir: \u001b[3;35mNone\u001b[0m\n"," model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n"," device: \u001b[32m'mps'\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
        force_PIL: False\n","       use_tunnel: False\n","       server_url: \n","   experiment dir: experiment\n","       source_dir: experiment/source\n","        cache_dir: experiment/cache\n","\n","
\n"],"text/plain":[" force_PIL: \u001b[3;91mFalse\u001b[0m\n"," use_tunnel: \u001b[3;91mFalse\u001b[0m\n"," server_url: \n"," experiment dir: experiment\n"," source_dir: experiment/source\n"," cache_dir: experiment/cache\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Experiment runs:\n","PaliGemma-crop-post: 0\n","
\n"],"text/plain":["Experiment runs:\n","PaliGemma-crop-post: \u001b[1;36m0\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["quant = '8bit' if IN_MAC else 'bfloat16'\n","CONTEXT = OCRExperimentContext('PaliGemma', EXP_DIR, quant=quant, \n"," server=SERVER, run_name='PaliGemma-crop-post', load=True)\n","CONTEXT.show()\n"]},{"cell_type":"code","execution_count":19,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":358,"referenced_widgets":["d086b7598b4848aaa4eb0ffede5da0f7","4856c138483c4bc59c165c6f8c81777a","1bffa03a8dfa4d4ba6e0b2cf76f5f0fd","88ee0bfb700a4f369333729d755fbc91","f2b7ff5971bd43b986d810b9261abd1c","c5431bc93486497faa74330f37d582aa","aec0a793b589469d957a83b767724cc4","8bb2d35ebdbc48dda1f1f365389ac92e","2d8a14b167c943a888fa9a313f6166eb","2930ae9cab9e421f9c6191bdb86d37a4","cde5c9e129e443fb9c1c642156bab294","5d09637e4ba34f14a879dbe44c675285","4b9e45c5e109429da8a7ed75633cdcfb","11d2466d2ced4c69afc62bda1f3baf27","725a2c78a0d94db19517c9f03fdbd76f","635032f84bbc4b0a8b1e4bcfb9d5318d","0e6515360d65481c8b398c02b0b6f437","9ac3df27ca5f442398b86df5d5849fab","6683113218e44183a6a5a1cd1392b452","5c0be55008d045108e2a91a819adfd58","ad5ddbcf9642427ca162e9cfdefe8ded","2682f4f1f76b498091a8bb16c97205e6","513155104caa4340900c728a570728e9","b64f35e753334071ba92cc9c23472f5f","5d772e124d1c4286bc83b0fdfd50b737","3a40dc732037425cb1491bb68f7d7178","4306183c004747b897acb4be6577f46d","78f02d7219cb4e5bbde518ac5e96a341","06d9f190506c40fb9689977c2a2b2757","daabe05918774871ba2f9cba38ca14ff","e72b3672869743e7b8fbbe178a93698a","86e80efa2af4416b9f465e7cb3873c3b","64d05881c560431b86dec6c27c01bfbb","a49fa2c6c92c4191a79f659b114eae0e","2db177bd125f4e0789363306784c51fa","b75c3b4c04a9416ca5e93bdf3b049c12","5d1fd260fdee46d69e8f81f1e146b787","5541585cb2714d82a3fdb9f70a161533","7fa1b8a86fe846c29568b89135748bc2","7694626eeb3b45598fa74862fb5b95a0","4cc8f4e7c0dd442199d94880ca6b718f","7efe7d6323ef4a00a4c4239643ef1d7d","b51706f5a3c14f20a642a64912e068ff","f1cf213ea11e431c8aded42b1af2536b","a26dbf2c5fc647e89984f08d89e11cb4","fd31aabd8e4c4aa8add50c95e55e9d6f","22121cd9a6954bc2908e5a44c6bdd6a9","54abbc4b157c41cba0f0c663bba5eb25","0d416a34a58745ec9558443d076d3d55","64b5967a0be04a05aeddda4a1b977531","aeb9f955725443f5b2c2f0c54ffb1fc8","1c60de0ca3b8455a900affc4690fca1f","06de6316d026491bbd9e7c18efa3a351","f4fd6b82478a444d91242587c0a5045f","8f5f4df805114835b66872e2520edf70","bbf4c62d0b674b2594e455696e6e427a","377aea61c8d441afad1456b08681c7f2","b037f85089e24e5ba970bef2f46e568b","f3863102525f488fb74877a54b447c63","79d600bfe6204618af8ba7a7cb1577a8","0251403980314014b84ae3dc63cc5455","84ab0a402fe54b0f9f8791321c8d9276","4bf8171d649f4a819275590070b734bd","7a2075bd25ac42c984f2e12c2f18b578","0b9d514d2d9249f09095065a9e302c49","4acbacc0ed4a4c1581583f428b69aff7"]},"executionInfo":{"elapsed":31187,"status":"ok","timestamp":1717165357281,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"cSuBWT4YN2-i","outputId":"00cdca4b-4568-4a97-c646-42ab70541d1d"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"6701b0fefb114810a52c202ffb6a4b4d","version_major":2,"version_minor":0},"text/plain":["Fetching 9 files: 0%| | 0/9 [00:00 Size: '224'\n"," Quantization: '8bit'\n"," Device: 'mps'\n"," VRAM: 2986/65536 MiB\n","\n","\n"],"text/plain":[" Size: \u001b[32m'224'\u001b[0m\n"," Quantization: \u001b[32m'8bit'\u001b[0m\n"," Device: \u001b[32m'mps'\u001b[0m\n"," VRAM: \u001b[1;36m2986\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["ocr_model = CONTEXT.setup_ocr_model(False)\n","ocr_model.show_info()"]},{"cell_type":"markdown","metadata":{"id":"rgSiXSTyN2-l"},"source":["Check the images are in place"]},{"cell_type":"code","execution_count":20,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":431,"status":"ok","timestamp":1717165362762,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"ZXL84T8dUMUm","outputId":"92365c79-9c3d-4645-9638-b9f56b3131b7"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":20,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"code","execution_count":22,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":200,"referenced_widgets":["59886ba6cd1c4fe8951884a5c340808b","bd58f503314643659cf9e8a1cef488c9","dda9ef398b524535a68fd6ea11fad818","eca634da59354f1caa467fba3c58c5fc","4b450035de2f401b9e3554a023a3ec65","53d92d965e984ed7afc3496af7d61d70","3d496f12c55645aead4dfe7d0d07dcf0","91b0f76df87a4c56aa5a02943cb28839","c24dd55347c44ee586bab8ee277db7da","3cb6adfc2d764b97b6673765860d47bb","f77c96169250417aad96b5c1d58222f8","f68accd919884dd09190b80513b9646c","e30127ffa4834f609af7939fffe106e8","e6f1a30a76264f7e84e93559d196cb5f","2daa7d0e57fd4e4682ce1adc15b9f84d","4cb1d38e7aec4391b8cd7527ca9febee","d3913b280fba46c4b9053b0e1b7f76fe","c610dd153a364592b786fcdf898c3da3","14fe1f23cc4b4887a5a7d8b987af49eb","7f56d139cd774438be2902f1310d55b6","b24e5e348f604c2fb1359e12f9c1dde1","3b259cdb3ddd4432bd07c36f6145a4de","941510f7665d47f3bda727843f6684ae","85198e7d3abb4492b0cca02083f68a24","143e6c3613d8483d91833a2e13f86fb6","212c95d82afc43a9b849a07cd0193ad6","b3691f5cb09041b5aa88e1caf3a29b20","9ad1e5cabb0d4636a08d306513e63c16","d03fbf56a2934588892fd1bb43739564","491fa386a15f4719bf44fa8e302fd011","fc0380f14a854a6cb040442f98d41000","a3aff0a8b5f4459e872c8a2c05f0226d","d5541144ffea4c418ef5c6c3db1e519e","385f8f44444540af87117059cfec0f5a","816479b548ed4dd99880c862929898fa","ec3cca3523514dc1b21d8d79773cb988","577f895e829e4f9098f600795aa18d08","58e62210fd1c482cb848c00704ee496c","9ca29ee5af0b4f888d2f6c5c011cad7f","a340e132d43a4178b902d6e18cdaa42c","14457502346c40069dda383db7503d76","0f90ecefed3b4b30bff078f97f4a67d7","15a4d0683ce04296ae0426bff451cc06","460853ad40bc474e900544e27d4d8440","041565754c1d4b8188ac80ac296974a3","2567a327e02648e29b2410d406d45217","e892ff1ff8244fb5b4dd1617e7b67bcb","3215c940fe7e485c97a3af8c5dbf8e08","9932bf3222934434baca1a23e649f118","a2ed35e40a0342f1b5209cf2368ec9b8","d35bec09dbe849f9b64a211fd45b80c0","0915b9e3ce76421a8761cc5eaf25e2a7","b6c5b7f105e74dd09000d038b57066e8","d033341173d24e19a5f413ca0a53ce6c","358dfaf8072f4c77aabc4e267e48d833","ea37bd0802504828a90c1d3625e2d39e","b54c98e9b45d4a6391fce48e463488aa","9a1befb039dd4021af786a7cefc7e7fe","d3dc27978259400187c814165ce20091","1a20a2ace0234eca9b4b8f2fc68358b0","215b89c0f4304fb4b2a4642b763f3b8e","d58f6d5a301e4389b4e73b7ae2ef595f","3655dd45e31845cb9cf4bcc1a7572db0","3cd7144832b1489aa0dcdc2eb74da6b4","0f41b180ba3f4e139d00d1d4e41fa808","db7189bed4d04523bafa9267fd5ed194","8ee17913c9124a8f8136f87de059f86f","65f9a631473a4ce989995cfcc84c1388","dd4f665280c1428ea9cb3073d95bc02e"],"resources":{"http://localhost:8080/experiment/cache/Strange_Tales_172005/_crop/Strange_Tales_172005_6_Default,%20grey%20pad.png":{"data":"CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPWVuPgogIDxtZXRhIGNoYXJzZXQ9dXRmLTg+CiAgPG1ldGEgbmFtZT12aWV3cG9ydCBjb250ZW50PSJpbml0aWFsLXNjYWxlPTEsIG1pbmltdW0tc2NhbGU9MSwgd2lkdGg9ZGV2aWNlLXdpZHRoIj4KICA8dGl0bGU+RXJyb3IgNDA0IChOb3QgRm91bmQpISExPC90aXRsZT4KICA8c3R5bGU+CiAgICAqe21hcmdpbjowO3BhZGRpbmc6MH1odG1sLGNvZGV7Zm9udDoxNXB4LzIycHggYXJpYWwsc2Fucy1zZXJpZn1odG1se2JhY2tncm91bmQ6I2ZmZjtjb2xvcjojMjIyO3BhZGRpbmc6MTVweH1ib2R5e21hcmdpbjo3JSBhdXRvIDA7bWF4LXdpZHRoOjM5MHB4O21pbi1oZWlnaHQ6MTgwcHg7cGFkZGluZzozMHB4IDAgMTVweH0qID4gYm9keXtiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9lcnJvcnMvcm9ib3QucG5nKSAxMDAlIDVweCBuby1yZXBlYXQ7cGFkZGluZy1yaWdodDoyMDVweH1we21hcmdpbjoxMXB4IDAgMjJweDtvdmVyZmxvdzpoaWRkZW59aW5ze2NvbG9yOiM3Nzc7dGV4dC1kZWNvcmF0aW9uOm5vbmV9YSBpbWd7Ym9yZGVyOjB9QG1lZGlhIHNjcmVlbiBhbmQgKG1heC13aWR0aDo3NzJweCl7Ym9keXtiYWNrZ3JvdW5kOm5vbmU7bWFyZ2luLXRvcDowO21heC13aWR0aDpub25lO3BhZGRpbmctcmlnaHQ6MH19I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LnBuZykgbm8tcmVwZWF0O21hcmdpbi1sZWZ0Oi01cHh9QG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWluLXJlc29sdXRpb246MTkyZHBpKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSBuby1yZXBlYXQgMCUgMCUvMTAwJSAxMDAlOy1tb3otYm9yZGVyLWltYWdlOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSAwfX1AbWVkaWEgb25seSBzY3JlZW4gYW5kICgtd2Via2l0LW1pbi1kZXZpY2UtcGl4ZWwtcmF0aW86Mil7I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LTJ4LnBuZykgbm8tcmVwZWF0Oy13ZWJraXQtYmFja2dyb3VuZC1zaXplOjEwMCUgMTAwJX19I2xvZ297ZGlzcGxheTppbmxpbmUtYmxvY2s7aGVpZ2h0OjU0cHg7d2lkdGg6MTUwcHh9CiAgPC9zdHlsZT4KICA8YSBocmVmPS8vd3d3Lmdvb2dsZS5jb20vPjxzcGFuIGlkPWxvZ28gYXJpYS1sYWJlbD1Hb29nbGU+PC9zcGFuPjwvYT4KICA8cD48Yj40MDQuPC9iPiA8aW5zPlRoYXTigJlzIGFuIGVycm9yLjwvaW5zPgogIDxwPiAgPGlucz5UaGF04oCZcyBhbGwgd2Uga25vdy48L2lucz4K","headers":[["content-length","1449"],["content-type","text/html; charset=utf-8"]],"ok":false,"status":404,"status_text":""}}},"executionInfo":{"elapsed":639,"status":"ok","timestamp":1717165542401,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"GmAca8fVUMUm","outputId":"4042b144-9cfe-43f0-b391-ac8d44b612f8"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"ed7e79b69996433b87d46e466cb48fb6","version_major":2,"version_minor":0},"text/plain":["VBox(children=(HTML(value=\""}},"c24dd55347c44ee586bab8ee277db7da":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_f68accd919884dd09190b80513b9646c","IPY_MODEL_e30127ffa4834f609af7939fffe106e8","IPY_MODEL_e6f1a30a76264f7e84e93559d196cb5f","IPY_MODEL_2daa7d0e57fd4e4682ce1adc15b9f84d"],"layout":"IPY_MODEL_4cb1d38e7aec4391b8cd7527ca9febee"}},"c5431bc93486497faa74330f37d582aa":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c610dd153a364592b786fcdf898c3da3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["method_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_385f8f44444540af87117059cfec0f5a","IPY_MODEL_816479b548ed4dd99880c862929898fa","IPY_MODEL_ec3cca3523514dc1b21d8d79773cb988"],"layout":"IPY_MODEL_577f895e829e4f9098f600795aa18d08"}},"cde5c9e129e443fb9c1c642156bab294":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d033341173d24e19a5f413ca0a53ce6c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50px"}},"d03fbf56a2934588892fd1bb43739564":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d086b7598b4848aaa4eb0ffede5da0f7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_4856c138483c4bc59c165c6f8c81777a","IPY_MODEL_1bffa03a8dfa4d4ba6e0b2cf76f5f0fd","IPY_MODEL_88ee0bfb700a4f369333729d755fbc91"],"layout":"IPY_MODEL_f2b7ff5971bd43b986d810b9261abd1c"}},"d35bec09dbe849f9b64a211fd45b80c0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d3913b280fba46c4b9053b0e1b7f76fe":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["box_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_491fa386a15f4719bf44fa8e302fd011","IPY_MODEL_fc0380f14a854a6cb040442f98d41000","IPY_MODEL_a3aff0a8b5f4459e872c8a2c05f0226d"],"layout":"IPY_MODEL_d5541144ffea4c418ef5c6c3db1e519e"}},"d3dc27978259400187c814165ce20091":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"d5541144ffea4c418ef5c6c3db1e519e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d58f6d5a301e4389b4e73b7ae2ef595f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"none","flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"daabe05918774871ba2f9cba38ca14ff":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"db7189bed4d04523bafa9267fd5ed194":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"120px"}},"dd4f665280c1428ea9cb3073d95bc02e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"dda9ef398b524535a68fd6ea11fad818":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","140192597210928"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_c24dd55347c44ee586bab8ee277db7da","IPY_MODEL_3cb6adfc2d764b97b6673765860d47bb"],"layout":"IPY_MODEL_f77c96169250417aad96b5c1d58222f8"}},"e30127ffa4834f609af7939fffe106e8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","140192597212656"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_941510f7665d47f3bda727843f6684ae"],"layout":"IPY_MODEL_85198e7d3abb4492b0cca02083f68a24"}},"e6f1a30a76264f7e84e93559d196cb5f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","140192597212608"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_143e6c3613d8483d91833a2e13f86fb6"],"layout":"IPY_MODEL_212c95d82afc43a9b849a07cd0193ad6"}},"e72b3672869743e7b8fbbe178a93698a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"e892ff1ff8244fb5b4dd1617e7b67bcb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":"lightblue","font_weight":"bold"}},"ea37bd0802504828a90c1d3625e2d39e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"ec3cca3523514dc1b21d8d79773cb988":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Initial box","Default","Default, grey pad","Padded 4px","Padded 8px","Extracted, init box","Padded 4, extracted","Padded 8, extracted","Padded 8, dilation 1","Pad 8, fract. 0.5","Pad 8, fract. 0.2"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":2,"layout":"IPY_MODEL_1a20a2ace0234eca9b4b8f2fc68358b0","style":"IPY_MODEL_215b89c0f4304fb4b2a4642b763f3b8e"}},"eca634da59354f1caa467fba3c58c5fc":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":["message_visor-yXy"],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_65f9a631473a4ce989995cfcc84c1388","msg_id":"","outputs":[]}},"f1cf213ea11e431c8aded42b1af2536b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f2b7ff5971bd43b986d810b9261abd1c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f3863102525f488fb74877a54b447c63":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_0b9d514d2d9249f09095065a9e302c49","placeholder":"​","style":"IPY_MODEL_4acbacc0ed4a4c1581583f428b69aff7","value":" 137/137 [00:00<00:00, 13.4kB/s]"}},"f4fd6b82478a444d91242587c0a5045f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f68accd919884dd09190b80513b9646c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","140192597212368"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_b24e5e348f604c2fb1359e12f9c1dde1"],"layout":"IPY_MODEL_3b259cdb3ddd4432bd07c36f6145a4de"}},"f77c96169250417aad96b5c1d58222f8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fc0380f14a854a6cb040442f98d41000":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_0915b9e3ce76421a8761cc5eaf25e2a7","style":"IPY_MODEL_b6c5b7f105e74dd09000d038b57066e8","value":false}},"fd31aabd8e4c4aa8add50c95e55e9d6f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_64b5967a0be04a05aeddda4a1b977531","placeholder":"​","style":"IPY_MODEL_aeb9f955725443f5b2c2f0c54ffb1fc8","value":"Loading checkpoint shards: 100%"}}}}},"nbformat":4,"nbformat_minor":0} diff --git a/pcleaner/_testbed/test_tesseract.ipynb b/pcleaner/_testbed/test_tesseract.ipynb index 24ca973d..4218723c 100644 --- a/pcleaner/_testbed/test_tesseract.ipynb +++ b/pcleaner/_testbed/test_tesseract.ipynb @@ -1 +1 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"XLuXdPExZlIq"},"source":["# Testing `Tesseract` OCR for Comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"O02O4qXwZlIr"},"source":["## Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"dD_MtS4cZlIr"},"source":["We will install the more up-to-date version of PanelCleaner from GitHub. Only affects Colab notebooks."]},{"cell_type":"code","execution_count":1,"metadata":{"id":"V3ABUVumZlIr"},"outputs":[],"source":["DEV_INSTALL = True"]},{"cell_type":"markdown","metadata":{"id":"jgisVUTBZlIs"},"source":["The best way to get the images source of the experiments is to mount your Google Drive.\n"]},{"cell_type":"code","execution_count":2,"metadata":{"id":"fFZBHyWLZlIs"},"outputs":[],"source":["MOUNT_DRIVE = DEV_INSTALL\n","GDRIVE_MOUNT_POINT = 'drive'\n"]},{"cell_type":"markdown","metadata":{"id":"X8I28oA1ZlIs"},"source":["# install (Colab)"]},{"cell_type":"code","execution_count":3,"metadata":{"id":"nT4E7IXbcUbp"},"outputs":[],"source":["import fastcore.all as FC\n"]},{"cell_type":"code","execution_count":4,"metadata":{"id":"jpnPDDFIcFh0"},"outputs":[],"source":["if FC.IN_COLAB:\n"," !pip install -q pyngrok\n"]},{"cell_type":"markdown","metadata":{"id":"gqYSM7iBcZsH"},"source":["Mount Google Drive"]},{"cell_type":"code","execution_count":5,"metadata":{"id":"bPF0CtUaZlIs"},"outputs":[],"source":["import os\n","import re\n","from pathlib import Path\n","\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," text = Text(msg)\n"," text.stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, text, \"_\" * 10)\n","\n","\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," mnt_point = f\"/content/{GDRIVE_MOUNT_POINT}\"\n"," if not Path(mnt_point).exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n","\n"," drive.mount(mnt_point, force_remount=True)\n"]},{"cell_type":"markdown","metadata":{"id":"UjPTi7MfcdxU"},"source":["Install **PanelCleaner**"]},{"cell_type":"code","execution_count":6,"metadata":{"id":"7y3qqqy6ZlIt"},"outputs":[],"source":["if FC.IN_COLAB:\n"," info('Installing PanelCleaner')\n"," if DEV_INSTALL:\n"," assert MOUNT_DRIVE, \"DEV_INSTALL need a mounted google drive\"\n"," info('Installing PanelCleaner from Google Drive')\n"," os.chdir(f\"/content/{GDRIVE_MOUNT_POINT}/MyDrive/Shared/PanelCleaner/\")\n"," !pip install -e .\n"," else:\n"," info('Installing PanelCleaner from Github')\n"," !pip install -q git+https://github.com/civvic/PanelCleaner.git@testbed\n"]},{"cell_type":"markdown","metadata":{"id":"6ylyum-ibQdL"},"source":["**PanelCleaner** is a heavy-weight and sometimes **Colab** refuses (*silently*) to install it. If the cell below gives an error, re-run the cell above. That usually fixes the problem."]},{"cell_type":"code","execution_count":7,"metadata":{"id":"oE3PogewbUQO"},"outputs":[],"source":["import importlib.resources\n","package_path = importlib.resources.files('pcleaner')\n","assert package_path.name == 'pcleaner'\n","\n","os.chdir(package_path/'_testbed')"]},{"cell_type":"code","execution_count":8,"metadata":{"id":"18HJJTQebWoV"},"outputs":[],"source":["from pcleaner._testbed.testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n"]},{"cell_type":"markdown","metadata":{},"source":["## Tesseract setup"]},{"cell_type":"markdown","metadata":{},"source":["Get current version of Tesseract"]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[{"data":{"text/html":["
[\n","    'tesseract 5.3.4',\n","    ' leptonica-1.84.1',\n","    '  libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \n","1.4.0 : libopenjp2 2.5.2',\n","    ' Found NEON',\n","    ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n","    ' Found libcurl/8.6.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.12 nghttp2/1.61.0'\n","]\n","
\n"],"text/plain":["\u001b[1m[\u001b[0m\n"," \u001b[32m'tesseract 5.3.4'\u001b[0m,\n"," \u001b[32m' leptonica-1.84.1'\u001b[0m,\n"," \u001b[32m' libgif 5.2.1 : libjpeg 8d \u001b[0m\u001b[32m(\u001b[0m\u001b[32mlibjpeg-turbo 3.0.0\u001b[0m\u001b[32m)\u001b[0m\u001b[32m : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \u001b[0m\n","\u001b[32m1.4.0 : libopenjp2 2.5.2'\u001b[0m,\n"," \u001b[32m' Found NEON'\u001b[0m,\n"," \u001b[32m' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6'\u001b[0m,\n"," \u001b[32m' Found libcurl/8.6.0 SecureTransport \u001b[0m\u001b[32m(\u001b[0m\u001b[32mLibreSSL/3.3.6\u001b[0m\u001b[32m)\u001b[0m\u001b[32m zlib/1.2.12 nghttp2/1.61.0'\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["out = !tesseract --version # type: ignore\n","cprint(out)\n","if 'tesseract 5.' not in out[0]:\n"," if 'tesseractd 4.' in out[0]:\n"," cprint('Old Tesseract 4.x is installed. You should uninstall it and install Tesseract 5.x')\n"," else:\n"," cprint('You should install Tesseract 5.x')\n"]},{"cell_type":"markdown","metadata":{},"source":["> **NOTE: in below cells, when you encounter lines starting with the exclamation mark `!` (`bang`), uncoment them if you want to excute the shell commands**\n"]},{"cell_type":"markdown","metadata":{},"source":["### Remove Tesseract installation\n","> I you have the old 4.x version, you should consider removing the installation with the following commands.\n"]},{"cell_type":"markdown","metadata":{},"source":["#### Mac (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### WIndows (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### Ubuntu"]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[],"source":["# !sudo apt-get remove tesseract-ocr\n"]},{"cell_type":"markdown","metadata":{},"source":["### Tesseract installation"]},{"cell_type":"markdown","metadata":{},"source":["#### Mac (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### WIndows (TBD)"]},{"cell_type":"markdown","metadata":{},"source":["#### Ubuntu"]},{"cell_type":"markdown","metadata":{},"source":["The **5.x** release series is available in the [another PPA](https://launchpad.net/~alex-p/+archive/ubuntu/tesseract-ocr5) for Ubuntu **18.04**, **20.04**, and **22.04**.\n"]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[],"source":["# !sudo add-apt-repository -y ppa:alex-p/tesseract-ocr5"]},{"cell_type":"markdown","metadata":{},"source":["refresh system package cache in case you’re still running old Ubuntu 18.04"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[],"source":["# !sudo apt update"]},{"cell_type":"markdown","metadata":{},"source":["install the software engine"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[],"source":["# !sudo apt install -y tesseract-ocr"]},{"cell_type":"markdown","metadata":{},"source":["and check version:"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[{"data":{"text/html":["
[\n","    'tesseract 5.3.4',\n","    ' leptonica-1.84.1',\n","    '  libgif 5.2.1 : libjpeg 8d (libjpeg-turbo 3.0.0) : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \n","1.4.0 : libopenjp2 2.5.2',\n","    ' Found NEON',\n","    ' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6',\n","    ' Found libcurl/8.6.0 SecureTransport (LibreSSL/3.3.6) zlib/1.2.12 nghttp2/1.61.0'\n","]\n","
\n"],"text/plain":["\u001b[1m[\u001b[0m\n"," \u001b[32m'tesseract 5.3.4'\u001b[0m,\n"," \u001b[32m' leptonica-1.84.1'\u001b[0m,\n"," \u001b[32m' libgif 5.2.1 : libjpeg 8d \u001b[0m\u001b[32m(\u001b[0m\u001b[32mlibjpeg-turbo 3.0.0\u001b[0m\u001b[32m)\u001b[0m\u001b[32m : libpng 1.6.43 : libtiff 4.6.0 : zlib 1.2.11 : libwebp \u001b[0m\n","\u001b[32m1.4.0 : libopenjp2 2.5.2'\u001b[0m,\n"," \u001b[32m' Found NEON'\u001b[0m,\n"," \u001b[32m' Found libarchive 3.7.2 zlib/1.2.11 liblzma/5.4.6 bz2lib/1.0.8 liblz4/1.9.4 libzstd/1.5.6'\u001b[0m,\n"," \u001b[32m' Found libcurl/8.6.0 SecureTransport \u001b[0m\u001b[32m(\u001b[0m\u001b[32mLibreSSL/3.3.6\u001b[0m\u001b[32m)\u001b[0m\u001b[32m zlib/1.2.12 nghttp2/1.61.0'\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["out = !tesseract --version # type: ignore\n","cprint(out)"]},{"cell_type":"markdown","metadata":{},"source":["### Install Tesseract languages"]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[{"data":{"text/html":["
tessdata path: /opt/homebrew/share/tessdata\n","
\n"],"text/plain":["tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Installed languages:\n","[\n","    'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n","    'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n","    'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n","    'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n","    'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n","    'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n","    'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \n","script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n","    'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \n","script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \n","script/Kannada, script/Khmer',\n","    'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \n","script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n","    'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n","    'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\n","]\n","
\n"],"text/plain":["Installed languages:\n","\u001b[1m[\u001b[0m\n"," \u001b[32m'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces'\u001b[0m,\n"," \u001b[32m'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo'\u001b[0m,\n"," \u001b[32m'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc'\u001b[0m,\n"," \u001b[32m'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert'\u001b[0m,\n"," \u001b[32m'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal'\u001b[0m,\n"," \u001b[32m'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol'\u001b[0m,\n"," \u001b[32m'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \u001b[0m\n","\u001b[32mscript/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur'\u001b[0m,\n"," \u001b[32m'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \u001b[0m\n","\u001b[32mscript/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \u001b[0m\n","\u001b[32mscript/Kannada, script/Khmer'\u001b[0m,\n"," \u001b[32m'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \u001b[0m\n","\u001b[32mscript/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk'\u001b[0m,\n"," \u001b[32m'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel'\u001b[0m,\n"," \u001b[32m'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["out = !tesseract --list-langs # type: ignore\n","tessdata = Path(out[0].split('\"')[1])\n","cprint(f\"tessdata path: {tessdata}\")\n","cprint(\"Installed languages:\", [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]])"]},{"cell_type":"markdown","metadata":{},"source":["#### Install **best** languages and **jpn_ver** Tesseract lang\n","> Much better results than default langs and `jpn` language model.\n"]},{"cell_type":"markdown","metadata":{},"source":["Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best). \n","Donwload from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) a model trained for vertical Japanese text as found in manga.\n","\n","See [here](https://tesseract-ocr.github.io/tessdoc/Data-Files-in-different-versions.html) the languages codes.\n","\n","> Note: I've not play much with `jpn` or `jpn_vert`, `manag-ocr` is surely a much better fit, but it can be educational to compare."]},{"cell_type":"markdown","metadata":{},"source":["Uncomment and excute to download the best language models:\n"]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[],"source":["# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/osd.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/eng.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn.traineddata\n","\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn_vert.traineddata\n","# or\n","# !wget -O jpn_vert.traineddata https://github.com/zodiac3539/jpn_vert/blob/master/jpn_ver5.traineddata\n","\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/spa.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/fra.traineddata"]},{"cell_type":"markdown","metadata":{},"source":["Copy downloaded models to tessdata folder (double check that `tessdata` variable points to the right folder):\n"]},{"cell_type":"code","execution_count":17,"metadata":{},"outputs":[{"data":{"text/html":["
tessdata path: /opt/homebrew/share/tessdata\n","
\n"],"text/plain":["tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint(f\"tessdata path: {tessdata}\")"]},{"cell_type":"code","execution_count":18,"metadata":{},"outputs":[],"source":["# !sudo mv *.traineddata $tessdata"]},{"cell_type":"markdown","metadata":{},"source":["and remove the downloaded models:\n"]},{"cell_type":"code","execution_count":19,"metadata":{},"outputs":[],"source":["# !rm *.traineddata"]},{"cell_type":"markdown","metadata":{},"source":["Check installed languages\n"]},{"cell_type":"code","execution_count":20,"metadata":{},"outputs":[{"data":{"text/html":["
[\n","    Path('/opt/homebrew/share/tessdata/spa.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/eng.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/jpn_vert.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/spa_old.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/fra.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/jpn.traineddata')\n","]\n","
\n"],"text/plain":["\u001b[1m[\u001b[0m\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/eng.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn_vert.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa_old.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/fra.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint(list(filter(lambda x: re.match(r'eng|jpn|jpn_vert|fra|spa', x.name), tessdata.ls()))) # type: ignore\n","# cprint(pytesseract.get_languages())\n"]},{"cell_type":"markdown","metadata":{"id":"fErGl5xSZlI5"},"source":["----\n","# Tesseract experiments"]},{"cell_type":"markdown","metadata":{"id":"op24JaWwfsSv"},"source":["## Experiment directory"]},{"cell_type":"markdown","metadata":{"id":"Av0ceG7efw2L"},"source":["Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n"]},{"cell_type":"code","execution_count":21,"metadata":{"id":"jfMv_sdZfwVY"},"outputs":[{"data":{"text/html":["
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n","Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n","
\n"],"text/plain":[" Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n","Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["EXP_DIR = Path('./experiment')\n","cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n"]},{"cell_type":"markdown","metadata":{"id":"z62cVR57ZlI5"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"qMAn1mOSZlI5"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is `USE_PIL=False`. You can set the environment variable `USE_PIL=True` to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":22,"metadata":{"id":"A0il2cCMZlI5"},"outputs":[],"source":["os.environ['USE_TUNNEL'] = 'True' if FC.IN_COLAB else 'False'\n","os.environ['USE_PIL'] = 'True' if FC.IN_COLAB and os.environ['USE_TUNNEL'] == 'False' else 'False'\n"]},{"cell_type":"code","execution_count":23,"metadata":{"id":"Su0YJikGZlI5"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import pcleaner._testbed.testbed.web_server as web_server\n","\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"2ara95FoZlI5"},"source":["Creates the `OCRExperimentContext` object we'll use to manage the experiments.\n"]},{"cell_type":"code","execution_count":24,"metadata":{"id":"qhQ3nY1OhgdS"},"outputs":[{"name":"stdout","output_type":"stream","text":["Current Configuration:\n","\n","Locale: System default\n","Default Profile: Built-in\n","Saved Profiles:\n","- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n","- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n","\n","Profile Editor: cursor\n","Cache Directory: System default\n","Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n","Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n","GUI Theme: System default\n","\n","--------------------\n","\n","Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n","System default cache directory: /Users/vic/Library/Caches/pcleaner\n"]},{"data":{"text/html":["
 config cache_dir: None\n","       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n","           device: 'mps'\n","
\n"],"text/plain":[" config cache_dir: \u001b[3;35mNone\u001b[0m\n"," model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n"," device: \u001b[32m'mps'\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
        force_PIL: False\n","       use_tunnel: False\n","       server_url: \n","   experiment dir: experiment\n","       source_dir: experiment/source\n","        cache_dir: experiment/cache\n","\n","
\n"],"text/plain":[" force_PIL: \u001b[3;91mFalse\u001b[0m\n"," use_tunnel: \u001b[3;91mFalse\u001b[0m\n"," server_url: \n"," experiment dir: experiment\n"," source_dir: experiment/source\n"," cache_dir: experiment/cache\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["CONTEXT = OCRExperimentContext('Tesseract', EXP_DIR, server=SERVER)\n","CONTEXT.show()"]},{"cell_type":"markdown","metadata":{"id":"5gEd0ZYOZlI5"},"source":["# Test images\n"]},{"cell_type":"markdown","metadata":{"id":"8ecqlXd_h2yc"},"source":["Copy your images to the source directory:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 18TSXLCYAPxAlUsdHmgAe6FZM5d8K6gcT -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{},"source":["Check the images are in place"]},{"cell_type":"code","execution_count":25,"metadata":{"id":"Ha8wqfTHZlI5"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":25,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"markdown","metadata":{"id":"VHtWWQnKj2eU"},"source":["----"]},{"cell_type":"code","execution_count":26,"metadata":{"id":"TZIA3E3jZlI5"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"7153dba0227b423f99fe3417327523ed","version_major":2,"version_minor":0},"text/plain":["VBox(children=(HTML(value=\""}},"03b66d0eb8b5487b8ad21382b93cc68d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"044d11e5bc4e4f87ad9d099734418899":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"068b8601d7364d29b9598b80aeb782e0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0c28619fcebc4c58a9a756888add9140":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["model_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_a2410f8101384beda0114d93ac655edb"],"layout":"IPY_MODEL_24e8764bfd294a629d6c3855b4094f8b"}},"0d4014b56e93430e9782502bf29c7c2e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"initial"}},"0d5a810240d84cc683b42f56b1f4c2d1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0e3ae88bc86f4a31b5aedc1dfd0b1bf2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"120px"}},"0f1bb59001314b13a091c7e1b331c58b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"reset","disabled":false,"icon":"","layout":"IPY_MODEL_3ab779d3f50a456980527636aa763dba","style":"IPY_MODEL_bb3adfcd8e4a4af29079953bc9220ac1","tooltip":""}},"101d1fc2b6df471ebd6a32a44c8120ed":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_df77be57fe7943298432a759e6ce8416","placeholder":"​","style":"IPY_MODEL_8b38a0bdf80149bba72324232beb14ed","value":"Method:"}},"175e7409479d4f56ba4a4faf4c8bebaa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_3f8e2f6b025e4fcd90ad34c2e99025ae","max":11,"min":0,"orientation":"horizontal","style":"IPY_MODEL_044d11e5bc4e4f87ad9d099734418899","value":11}},"1807cf3a1770434599e993a087293d91":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"18ccc64fc8504bdeb2fb07043688c1c4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"25em"}},"1da81d9a8d7446838b76ae017e794e78":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"247e8a63e98441f294c1514a43b35e0d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"24e8764bfd294a629d6c3855b4094f8b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"25cdb8370f70459886e00eeef0f66388":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_247e8a63e98441f294c1514a43b35e0d","placeholder":"​","style":"IPY_MODEL_7a928ad4bd52422b9544d0d312402a5b","value":"Box #1: 100%"}},"27c90e0d46934e80a38889a0ae18a726":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"31dcaeca8806453ea52292112bb0a4f3":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"3588eeb28e024f1ead6cd21f46d65a6c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["method_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_101d1fc2b6df471ebd6a32a44c8120ed","IPY_MODEL_8ca00801b4e54cbd980c998791664f60","IPY_MODEL_ec3c881e1da4414a9c9499497bc5de74"],"layout":"IPY_MODEL_31dcaeca8806453ea52292112bb0a4f3"}},"39648bdbc39c4c7c827510141663804c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"visible","width":null}},"3ab779d3f50a456980527636aa763dba":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":"0px 0px 0px 3em","max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"5em"}},"3cf7099443124d289495da41bfbc8b58":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":"lightblue","font_weight":"bold"}},"3d0ad04ce06b4314b64dcdde269b38e6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"BoundedIntTextModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"BoundedIntTextModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"IntTextView","continuous_update":false,"description":"","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_4aba84bf7b4847fdb1cac927ba6a7ebf","max":14,"min":0,"step":1,"style":"IPY_MODEL_f542dba5c6de48a0a44e698706d87017","value":2}},"3f8e2f6b025e4fcd90ad34c2e99025ae":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4064335db7684f2f81ad237513e90c34":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420256"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_878477e8708a47e8ab49b00be715d1cd"],"layout":"IPY_MODEL_00878ffbdb234a48b8917563f3058107"}},"44f79f7ea58742a0a770aab41e876c9c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"150px"}},"47b4dcc7177b41d1aa69d3918a6e8598":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":["message_visor-yXy"],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_c193eb8285a740208457bbe7985d356f","msg_id":"","outputs":[]}},"48555e1574db42db86f6572e9c888b58":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","137612216365504"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_60e22ee6a0fc428b8e3709e394e44841","IPY_MODEL_7e8086d63d1b4bbf96e4c70c63bc920a"],"layout":"IPY_MODEL_0d5a810240d84cc683b42f56b1f4c2d1"}},"48cfde671ecf42c7a124a94a2962bb66":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420208"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_ad2bbb4b23a648209da1edab0006adae"],"layout":"IPY_MODEL_d6fed923432746c9b3dff00549de596d"}},"496e8548fc0f41b7b0c15c5881596326":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"initial"}},"4aba84bf7b4847fdb1cac927ba6a7ebf":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50px"}},"4f8b904d91eb44028477a6a61c34af54":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_919da88097344a689a9afb6fa5977b29","placeholder":"​","style":"IPY_MODEL_d0ed39572cea4c37bb07dc99577258e3","value":"Box # (of 15):"}},"57f7d34ddc2b4a938d7fcb4bf066deb0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"57f9b685011043418d9552b3cb48784e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"save","disabled":false,"icon":"","layout":"IPY_MODEL_fbb4d3433c6f42e094934b6936659b8f","style":"IPY_MODEL_3cf7099443124d289495da41bfbc8b58","tooltip":""}},"58b2ec779ab64a2b9e85d57160b453c9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"60e22ee6a0fc428b8e3709e394e44841":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e1de76477d764776ac5a209f7ebcc8d6","IPY_MODEL_48cfde671ecf42c7a124a94a2962bb66","IPY_MODEL_4064335db7684f2f81ad237513e90c34","IPY_MODEL_99bbf4dd65424e87aab67bcf162a8171"],"layout":"IPY_MODEL_eee81f49e99f4cbb8db65b56c511adbd"}},"6a87fbd3fc6440c5a81a564ac94400cc":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_01cd556393d643f8bb3fd88c8cd7bb84","IPY_MODEL_48555e1574db42db86f6572e9c888b58","IPY_MODEL_47b4dcc7177b41d1aa69d3918a6e8598","IPY_MODEL_dc75396dcc3c4606a8fe56401d29a4e9"],"layout":"IPY_MODEL_778afca8ec0a431ca8670604c10d8956"}},"6eed00e28fae4570b2348330bb9dcbab":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"72440081608048b1b5fc76e42011ad0c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":null}},"778afca8ec0a431ca8670604c10d8956":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"7a928ad4bd52422b9544d0d312402a5b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"7e8086d63d1b4bbf96e4c70c63bc920a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175421024"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_d89bf137dd5e4d698dc7f6187f2e148c","IPY_MODEL_3588eeb28e024f1ead6cd21f46d65a6c","IPY_MODEL_b0d6d88a4b824cf9be7c01d5611c3426"],"layout":"IPY_MODEL_39648bdbc39c4c7c827510141663804c"}},"878477e8708a47e8ab49b00be715d1cd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["display_option_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_bd6e62f7db8c40d695d6ca3d93cf7e94"],"layout":"IPY_MODEL_068b8601d7364d29b9598b80aeb782e0"}},"8b38a0bdf80149bba72324232beb14ed":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"8ca00801b4e54cbd980c998791664f60":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_0d4014b56e93430e9782502bf29c7c2e","style":"IPY_MODEL_58b2ec779ab64a2b9e85d57160b453c9","value":false}},"90f41682d85f42a6becdca99a59e9a2c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_496e8548fc0f41b7b0c15c5881596326","style":"IPY_MODEL_df9bb4a390fa4e6597b832d09949d24e","value":false}},"919da88097344a689a9afb6fa5977b29":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"929913d45cc9400087eab703338d00f0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"99bbf4dd65424e87aab67bcf162a8171":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175414976"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_57f9b685011043418d9552b3cb48784e","IPY_MODEL_0f1bb59001314b13a091c7e1b331c58b"],"layout":"IPY_MODEL_fb08b9a59d6c4e678b368c915bb97405"}},"9a49e8c567b94a64a19dc3eecdf5a857":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_25cdb8370f70459886e00eeef0f66388","IPY_MODEL_175e7409479d4f56ba4a4faf4c8bebaa","IPY_MODEL_c944b093296248b4a9a75a9139d5003d"],"layout":"IPY_MODEL_72440081608048b1b5fc76e42011ad0c"}},"a2410f8101384beda0114d93ac655edb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Tesseract-crop-post","Tesseract-crop"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":0,"layout":"IPY_MODEL_bfa2f19eedfa4bd99b59d08365ae4676","style":"IPY_MODEL_a7755ebc78f34335a32f75fa342fcd76"}},"a7755ebc78f34335a32f75fa342fcd76":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"ad2bbb4b23a648209da1edab0006adae":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Action_Comics_1960-01-00_(262)","Adolf_Cap_01_008","Barnaby_v1-028","Barnaby_v1-029","Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013","Cannon-292","Contrato_con_Dios_028","Erase_una_vez_en_Francia_02_88","FOX_CHILLINTALES_T17_012","Furari_-_Jiro_Taniguchi_selma_056","Galactus_12","INOUE_KYOUMEN_002","MCCALL_ROBINHOOD_T31_010","MCCAY_LITTLENEMO_090","Mary_Perkins_On_Stage_v2006_1_-_P00068","PIKE_BOYLOVEGIRLS_T41_012","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2","Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024","Strange_Tales_172005","Strange_Tales_172021","Tarzan_014-21","Tintin_21_Les_Bijoux_de_la_Castafiore_page_39","Transformers_-_Unicron_000-004","Transformers_-_Unicron_000-016","WARE_ACME_024","Yoko_Tsuno_T01_1972-10","Your_Name_Another_Side_Earthbound_T02_084","manga_0033","ronson-031","哀心迷図のバベル 第01巻 - 22002_00_059"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":14,"layout":"IPY_MODEL_18ccc64fc8504bdeb2fb07043688c1c4","style":"IPY_MODEL_6eed00e28fae4570b2348330bb9dcbab"}},"b0d6d88a4b824cf9be7c01d5611c3426":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420544"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e13c49f50ebd4f81a1dafe940ac13a31"],"layout":"IPY_MODEL_1da81d9a8d7446838b76ae017e794e78"}},"bb3adfcd8e4a4af29079953bc9220ac1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":null,"font_weight":"bold"}},"bd6e62f7db8c40d695d6ca3d93cf7e94":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Boxes","Image","Mask","Image & Mask","Page data","Ground truth","Image All","Results","Best results","Accuracy","Dataframe","Config"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":7,"layout":"IPY_MODEL_0e3ae88bc86f4a31b5aedc1dfd0b1bf2","style":"IPY_MODEL_929913d45cc9400087eab703338d00f0"}},"bfa2f19eedfa4bd99b59d08365ae4676":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"fit-content"}},"c193eb8285a740208457bbe7985d356f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c944b093296248b4a9a75a9139d5003d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_dcc0c0ee6a284ecb8c40f06891919805","placeholder":"​","style":"IPY_MODEL_1807cf3a1770434599e993a087293d91","value":" 11/11 [00:04<00:00,  2.10it/s]"}},"d0ed39572cea4c37bb07dc99577258e3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d6fed923432746c9b3dff00549de596d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d89bf137dd5e4d698dc7f6187f2e148c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["box_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_4f8b904d91eb44028477a6a61c34af54","IPY_MODEL_90f41682d85f42a6becdca99a59e9a2c","IPY_MODEL_3d0ad04ce06b4314b64dcdde269b38e6"],"layout":"IPY_MODEL_eab60b2fe7a84e4b9a913f1450766452"}},"dc75396dcc3c4606a8fe56401d29a4e9":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_ee44cc3dae5c42299460702dd280dbce","msg_id":"","outputs":[{"data":{"text/html":"
Maybe... but l tn certainly wouldn't feel right holding back tip money!
0.96
\n
\n
Maybe ... but I⎕⎕⎕ certainly wouldn't feel right holding back tip money!

Maybe... but l tn certainly wouldn't feel right holding back tip money!
","text/plain":""},"metadata":{},"output_type":"display_data"}]}},"dcc0c0ee6a284ecb8c40f06891919805":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"df77be57fe7943298432a759e6ce8416":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"df9bb4a390fa4e6597b832d09949d24e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"e13c49f50ebd4f81a1dafe940ac13a31":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":["wrapper-spinner"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_f40fbbd396ac4528a97962ec911d5837","placeholder":"​","style":"IPY_MODEL_03b66d0eb8b5487b8ad21382b93cc68d","value":"\n
\n
\n
\n "}},"e1de76477d764776ac5a209f7ebcc8d6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420016"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_0c28619fcebc4c58a9a756888add9140"],"layout":"IPY_MODEL_fa20ebba2bdb493799524bdf780fa86e"}},"e36c1a1c609c425bb76ea83edf910425":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"eab60b2fe7a84e4b9a913f1450766452":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ec3c881e1da4414a9c9499497bc5de74":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Initial box","Default","Default, grey pad","Padded 4px","Padded 8px","Extracted, init box","Padded 4, extracted","Padded 8, extracted","Padded 8, dilation 1","Pad 8, fract. 0.5","Pad 8, fract. 0.2"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":1,"layout":"IPY_MODEL_44f79f7ea58742a0a770aab41e876c9c","style":"IPY_MODEL_57f7d34ddc2b4a938d7fcb4bf066deb0"}},"ee44cc3dae5c42299460702dd280dbce":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"eee81f49e99f4cbb8db65b56c511adbd":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f40fbbd396ac4528a97962ec911d5837":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"none","flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f542dba5c6de48a0a44e698706d87017":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"fa20ebba2bdb493799524bdf780fa86e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fb08b9a59d6c4e678b368c915bb97405":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fbb4d3433c6f42e094934b6936659b8f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"4em"}}}}},"nbformat":4,"nbformat_minor":0} From 24412a8a1472714282c97f6dc2aab0c2dec17125 Mon Sep 17 00:00:00 2001 From: Spikey Date: Sat, 1 Jun 2024 16:16:35 +0200 Subject: [PATCH 26/27] fix a bug setting incorrect path --- pcleaner/_testbed/test_idefics.ipynb | 9610 +++++++++++++++++++++++- pcleaner/_testbed/test_paligemma.ipynb | 5151 ++++++++++++- pcleaner/_testbed/test_tesseract.ipynb | 3737 ++++++++- 3 files changed, 18495 insertions(+), 3 deletions(-) diff --git a/pcleaner/_testbed/test_idefics.ipynb b/pcleaner/_testbed/test_idefics.ipynb index 9a6b1ea6..fc16b1d1 100644 --- a/pcleaner/_testbed/test_idefics.ipynb +++ b/pcleaner/_testbed/test_idefics.ipynb @@ -1 +1,9609 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"FO-koL4wUMUg"},"source":["# Testing `Idefics` OCR for Comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"WDMB4HFe39wf"},"source":["## Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"Mox-OHw539wf"},"source":["To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n","\n","- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n","This allows the notebook to access files stored in your Google Drive.\n","\n","- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n","This acts as the root directory for accessing any files within your Google Drive from the notebook.\n","\n","- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n","This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n"]},{"cell_type":"code","execution_count":1,"metadata":{"executionInfo":{"elapsed":740,"status":"ok","timestamp":1717163941428,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"_ItAMB1U39wg"},"outputs":[],"source":["MOUNT_DRIVE = True\n","GDRIVE_MOUNT_POINT = 'drive'\n","PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'"]},{"cell_type":"markdown","metadata":{"id":"OcFWv_IN39wg"},"source":["# install (Colab)\n"]},{"cell_type":"code","execution_count":2,"metadata":{"executionInfo":{"elapsed":361,"status":"ok","timestamp":1717163944019,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"FsMCNzHZ39wg"},"outputs":[],"source":["import fastcore.all as FC\n","import os\n","import re\n","import sys\n","from pathlib import Path\n","\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," (t := Text(msg)).stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, t, \"_\" * 10)\n"]},{"cell_type":"markdown","metadata":{"id":"RkLIZZbo39wg"},"source":["Mount Google Drive"]},{"cell_type":"code","execution_count":3,"metadata":{"executionInfo":{"elapsed":2,"status":"ok","timestamp":1717163947918,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"qoUI5zQe39wg"},"outputs":[],"source":["mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," if not mnt_point.exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n"," drive.mount(str(mnt_point), force_remount=True)\n"]},{"cell_type":"markdown","metadata":{"id":"AWZnedVS39wg"},"source":["### Install **PanelCleaner**\n","\n","> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n","\n","Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook."]},{"cell_type":"code","execution_count":4,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":224},"executionInfo":{"elapsed":12781,"status":"ok","timestamp":1717163977869,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"5VSxqsyK39wg","outputId":"049bf207-b965-499b-8932-ac3044a01621"},"outputs":[],"source":["if FC.IN_COLAB:\n"," pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n"," tb_path = pc_path/'pcleaner/_testbed'\n"," if tb_path.exists():\n"," info('Installing PanelCleaner from your Google Drive')\n"," else:\n"," info('Installing PanelCleaner from GitHub')\n"," !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n"," tb_path = Path('PanelCleaner/pcleaner/_testbed')\n"," assert tb_path.exists(), \"PanelCleaner not found\"\n"," os.chdir(tb_path)\n"," sys.path.append(f\"{pc_path}\")\n"," sys.path.append(f\"{tb_path}\")\n"," !pip install -q -r requirements-colab.txt\n"]},{"cell_type":"code","execution_count":5,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":244},"executionInfo":{"elapsed":88801,"status":"ok","timestamp":1717162885976,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"lxwhxBydCiDj","outputId":"48d07921-9afe-46df-a468-e3e43b96f303"},"outputs":[{"data":{"text/plain":["'4.42.0.dev0'"]},"execution_count":5,"metadata":{},"output_type":"execute_result"}],"source":["if FC.IN_COLAB:\n"," !pip install -q flash-attn --no-build-isolation\n"," !pip install -q transformers accelerate datasets peft bitsandbytes\n","\n","import transformers\n","transformers.__version__"]},{"cell_type":"markdown","metadata":{"id":"gLER7Z0u39wh"},"source":["# Prologue"]},{"cell_type":"code","execution_count":6,"metadata":{"executionInfo":{"elapsed":28634,"status":"ok","timestamp":1717162918596,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"q_7GYpnWUMUl"},"outputs":[],"source":["from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n","from testbed.ocr_idefics import IdeficsOCR, get_gpu_vram\n","from testbed.helpers import IN_MAC, IN_LINUX\n"]},{"cell_type":"code","execution_count":7,"metadata":{"executionInfo":{"elapsed":13,"status":"ok","timestamp":1717162918597,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"cQ0R9v8r39wh"},"outputs":[],"source":["if IN_MAC:\n"," !pip install -q mlx_vlm\n","\n"," import mlx.core as mx\n"]},{"cell_type":"markdown","metadata":{"id":"CAHWMrX339wh"},"source":["# GPU"]},{"cell_type":"code","execution_count":8,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":396},"executionInfo":{"elapsed":12,"status":"ok","timestamp":1717162918597,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"f8XHRVRG39wh","outputId":"5f2d295c-1a32-40af-b964-20b73d546458"},"outputs":[{"data":{"text/html":["
          metal.is_available(): True\n","           metal.device_info(): {'memory_size': 68719476736, 'max_recommended_working_set_size': 51539607552, \n","'max_buffer_length': 38654705664, 'architecture': 'applegpu_g13s'}\n","     metal.get_active_memory(): 0\n","       metal.get_peak_memory(): 0\n","      metal.get_cache_memory(): 0\n","\n","
\n"],"text/plain":[" \u001b[1;35mmetal.is_available\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[3;92mTrue\u001b[0m\n"," \u001b[1;35mmetal.device_info\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'memory_size'\u001b[0m: \u001b[1;36m68719476736\u001b[0m, \u001b[32m'max_recommended_working_set_size'\u001b[0m: \u001b[1;36m51539607552\u001b[0m, \n","\u001b[32m'max_buffer_length'\u001b[0m: \u001b[1;36m38654705664\u001b[0m, \u001b[32m'architecture'\u001b[0m: \u001b[32m'applegpu_g13s'\u001b[0m\u001b[1m}\u001b[0m\n"," \u001b[1;35mmetal.get_active_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_peak_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_cache_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
     total VRAM: 65536 MiB\n","    active VRAM: 0 MiB\n","
\n"],"text/plain":[" total VRAM: \u001b[1;36m65536\u001b[0m MiB\n"," active VRAM: \u001b[1;36m0\u001b[0m MiB\n"]},"metadata":{},"output_type":"display_data"}],"source":["if IN_MAC:\n"," gpu_name = mx.metal.device_info()['architecture']\n"," cprint(\n"," f\"{'metal.is_available()':>30}: {mx.metal.is_available()}\\n\"\n"," f\"{'metal.device_info()':>30}: {mx.metal.device_info()}\\n\"\n"," f\"{'metal.get_active_memory()':>30}: {mx.metal.get_active_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_peak_memory()':>30}: {mx.metal.get_peak_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_cache_memory()':>30}: {mx.metal.get_cache_memory()//1024//1024}\\n\"\n"," )\n","else:\n"," !nvidia-smi\n"," import subprocess\n"," gpu_name = subprocess.check_output(\n"," \"nvidia-smi --query-gpu=gpu_name --format=csv,noheader\", shell=True\n"," ).decode('utf-8').strip()\n"," \n","\n","cprint( f\"{'GPU':>15}: {gpu_name}\\n\"\n"," f\"{'total VRAM':>15}: {get_gpu_vram()} MiB\\n\"\n"," f\"{'active VRAM':>15}: {get_gpu_vram(False)} MiB\")\n","\n"]},{"cell_type":"markdown","metadata":{"id":"Op4kiDaAUMUl"},"source":["----\n","# Idefics experiments"]},{"cell_type":"markdown","metadata":{"id":"q8q3vnLH39wh"},"source":["## Experiment directory"]},{"cell_type":"markdown","metadata":{"id":"6AB4w9C-39wh"},"source":["Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n","\n","NOTE: the default value assumes we are currently inside `PanelCleaner/pcleaner/_testbed` directory. You can check that is the case with `Path('.').resolve()`."]},{"cell_type":"code","execution_count":9,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":49},"executionInfo":{"elapsed":652,"status":"ok","timestamp":1717162939430,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"poPksk6739wh","outputId":"1452cde6-a74a-447c-eec2-3049bd2f8f19"},"outputs":[{"data":{"text/html":["
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n","Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n","
\n"],"text/plain":[" Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n","Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["EXP_DIR = Path('./experiment')\n","cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n"]},{"cell_type":"markdown","metadata":{},"source":["# Test images\n"]},{"cell_type":"markdown","metadata":{},"source":["Copy your images to the source directory:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[{"data":{"text/html":["
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n","
\n"],"text/plain":["\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{"id":"8Iondm2oUMUl"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"nuHPp1U7UMUl"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":10,"metadata":{"executionInfo":{"elapsed":425,"status":"ok","timestamp":1717162947685,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"nVAga31l39wh"},"outputs":[],"source":["if FC.IN_COLAB:\n"," os.environ['USE_TUNNEL'] = 'True'\n"," os.environ['USE_PIL'] = 'False'\n"]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":184},"executionInfo":{"elapsed":8015,"status":"ok","timestamp":1717162983857,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"tG8xtrBb39wh","outputId":"c2e625b8-0f78-44d0-af3a-ca6895a7a340"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import testbed.web_server as web_server\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"p5YiBbJ739wh"},"source":["# CONTEXT"]},{"cell_type":"markdown","metadata":{"id":"1yjjtdjJ39wi"},"source":["| quant, attn \\ platform | Mem | Mac | Linux | Windows | Colab T4 | Colab L4/H100 |\n","| --- | --- | --- | --- | --- | --- | --- |\n","| **float16** | 17 GB | ✅ | ✅ | ? | ❌ | ✅ |\n","| **float16 + attn** | 17 GB | ❌ | ✅ | ? | ❌ | ✅ |\n","| **8bit** | 10 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **8bit + attn** | 10 GB | ❌ | ✅ | ? | ❌ | ✅ |\n","| **4bit** | 6 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **4bit + attn** | 6 GB | ❌ | ✅ | ? | ❌ | ✅ |\n"]},{"cell_type":"markdown","metadata":{"id":"AUgSvi6CUMUm"},"source":["Creates the `IdeficsExperimentContext` object we'll use to manage the experiments.\n"]},{"cell_type":"code","execution_count":15,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":779},"executionInfo":{"elapsed":43567,"status":"ok","timestamp":1717163091060,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"wroznCt0CQdT","outputId":"0d259b2d-b20a-44cc-a0be-1198ad570b46"},"outputs":[{"name":"stdout","output_type":"stream","text":["Current Configuration:\n","\n","Locale: System default\n","Default Profile: Built-in\n","Saved Profiles:\n","- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n","- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n","\n","Profile Editor: cursor\n","Cache Directory: System default\n","Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n","Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n","GUI Theme: System default\n","\n","--------------------\n","\n","Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n","System default cache directory: /Users/vic/Library/Caches/pcleaner\n"]},{"data":{"text/html":["
 config cache_dir: None\n","       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n","           device: 'mps'\n","
\n"],"text/plain":[" config cache_dir: \u001b[3;35mNone\u001b[0m\n"," model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n"," device: \u001b[32m'mps'\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
        force_PIL: False\n","       use_tunnel: False\n","       server_url: \n","   experiment dir: experiment\n","       source_dir: experiment/source\n","        cache_dir: experiment/cache\n","\n","
\n"],"text/plain":[" force_PIL: \u001b[3;91mFalse\u001b[0m\n"," use_tunnel: \u001b[3;91mFalse\u001b[0m\n"," server_url: \n"," experiment dir: experiment\n"," source_dir: experiment/source\n"," cache_dir: experiment/cache\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Experiment runs:\n","Idefics-crop-post: 16\n","
\n"],"text/plain":["Experiment runs:\n","Idefics-crop-post: \u001b[1;36m16\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
     Quantization: '4bit'\n","Flash attention 2: N/A\n","             VRAM: 0/65536 MiB\n","\n","
\n"],"text/plain":[" Quantization: \u001b[32m'4bit'\u001b[0m\n","Flash attention \u001b[1;36m2\u001b[0m: N/A\n"," VRAM: \u001b[1;36m0\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["quant = '4bit' if IN_MAC or FC.IN_COLAB else 'float16'\n","flashattn = True if not FC.IN_COLAB else False\n","CONTEXT = OCRExperimentContext('Idefics', EXP_DIR, \n"," quant=quant, flashattn=flashattn, \n"," server=SERVER, run_name='Idefics-crop-post', load=True)\n","CONTEXT.show()\n"]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"a93af477ed4c4af8aba4d97397009adc","version_major":2,"version_minor":0},"text/plain":["Fetching 11 files: 0%| | 0/11 [00:00. This is expected, and simply means that the `legacy` (previous) behavior will be used so nothing changes for you. If you want to use the new behaviour, set `legacy=False`. This should only be set if you understand what it means, and thoroughly read the reason why this was added as explained in https://github.com/huggingface/transformers/pull/24565\n","Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n"]},{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"0f89471c58b94c2db7ffab9143b26b6b","version_major":2,"version_minor":0},"text/plain":["Fetching 11 files: 0%| | 0/11 [00:00 Quantization: '4bit'\n","Flash attention 2: N/A\n"," VRAM: 5261/65536 MiB\n","\n","\n"],"text/plain":[" Quantization: \u001b[32m'4bit'\u001b[0m\n","Flash attention \u001b[1;36m2\u001b[0m: N/A\n"," VRAM: \u001b[1;36m5261\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["ocr_model = CONTEXT.setup_ocr_model(False)\n","ocr_model.show_info()"]},{"cell_type":"markdown","metadata":{"id":"NnKaY8er39wi"},"source":["Check the images are in place"]},{"cell_type":"code","execution_count":17,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":319,"status":"ok","timestamp":1717163095107,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"ZXL84T8dUMUm","outputId":"12d640aa-69d7-46aa-c2c8-9d400cccb701"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":17,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"code","execution_count":20,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":255,"referenced_widgets":["41e7d3d5da8843bf97d53a5acc2fdd9c","def94ca8125e4128901b038c5e2e135f","a5b8058abf214b46a3dbc121c285cca7","7792b1aed8724a98817331a5610f9909","4c558212f11743be83311ff10e506255","db4a37385bc04a27ba786692ff23f32c","5cc2cd6464854d1996f83b6cccb71be6","86692867f33a4e2885722f8a9efaa144","57b0595135a84b04bf1c040150132fca","f9feda61c229465da90f33c69e7a4398","2b2f189c18e0494294ad7dc5e6b5a7ce","0eb627a4cba9497f8ea6833ac8080cf3","93acb5ead7244f2b8cb7ddb3db658dc1","827cc40c923e4081bfe56231f386d855","022996922e9d40919a086ce15625e4f3","74e995f849ec449fb5fd50166397897a","c2494c8753e9409aa5e6d8862be5c773","0e112f697e7d4a34826d2a46a067c14e","ee91033cfb084d4e83529a11edb48134","f5e02d40775a49a5b895d498233464f9","cd03b8f4a3144660a66bfb8361433973","de48c263fb124df9b7bf72805e1c1baa","3e76e6f2463549ad91832afd9da60672","cc0369009fb04a0b83a10510d7ac0388","44f0c3de011d47ccab46270d16c690b7","b2e63ba8c2f149d38e8c7722bc47ef07","0f9ca91ec321450f9ce53a84f2459f86","113566b1f4b74279a27f0ab51cffb683","4b1fe42380a1464180f548aaccb220ba","44e2a19f9dcb450cbca016e7b3e9c79d","7a75478806bf465cabc8d1429030f615","fb224135f5a14ba4872e0e64428d60b6","3fb8a4f0b2444c28a082fcbb278979cc","23f2673b6b2f40f19f0d4b1e1d5c6435","c54baefce7804a0eb8729ba88a22f713","af23aff11ddd45b9abf16daa53884c5f","029cc314dfba464b8c91194ee41bb604","76c165d73f574ab39d3357e87b401ac9","68d09a9f2fc84ead952160fe05c5dc90","74d438026f47463f8aa440eb39a58369","a80659636b7f4aa4aeaea4c1149620ea","86315ef030234020a49cfb2275e4ee53","a863d10b9ee947338b73f542c350efe4","ffeb080904984371bb8b715963c00069","f8bc3fb84517404b94502e7498d5c55a","3e1245f557d54e999d58c858f664a0a7","74d88ac2166a407ca2fb1aaf57006018","27e1a3f6033f4ee0aea9bf5726eb78cc","2348e08910b149048c90269942321d57","e6fac459206848898c206456b9dc8b1a","bfc1517ef24c459aae0a536c315ddad1","b9b462859a1846e2b2fdc625f6904506","167be8a944f0447c9c66fe8a485d309e","11c9edbf48f445d09d85f849915496e2","9bb8a92858144190b6dd506673234315","d0f9bc72d3054c45ba0c12d7839e994b","00120cae44354b1397eabc117243f609","5bdcbdc274d14afa91406ca177fe66b6","a478421e36a344eca8cf732ea07241dd","8470bcc137ba4295996a4ef0a2e8bf9c","5cc12b33d27a4715a995173135478c9c","fd00985eb51141799c4ad95c99461926","4fd269b8015f4be783474e835ff8a52e","decf6497acee49faae554f3db39be3ce","8aef4716537e417ea4203a68711cb4e9","bd64ee547bd049398c6d37f1ca476461","5da238d5b8514352a70b6b16cc9d944f","e74be1cd463d42a783ddea46072f4499","a6072dc7d6294061b840144104e07538","f1513571ca224451a3809b56a5739525","e7caf68af3c84c6195483d0a27225164","f6c25f96ead14b13a1a716a6de4e3f5c","4a51933821d045cd881418ff2a2b30e7","1d1a5dd1cc1d44be948464159187e856","d418846006b8496989e86276d8538b50","2ad60e460fe64f0087cf3052f06451ba","6c0b5365fd624af793b4d37f7449a7a5","9590087714614e948f3a8e4dd537a895","24551ce1bc1c4cdab44c25ffd783216e","6aa5fe05ab024eb0bd2b3da7881949f2","8758c30979a2414aac0d1583ab856acf","5768ef94421043d4b87c3a8f36b2fc88","950f956a453648ddbe66fa8b7f484115","1d40ec2dce6d43ae9ed7b02ca6ee5ade","c160c32bb63b405c81788dd2c49ed74a","d142fa6d7f1f452185080e55b24fef2c","67a75a653d0948ac92b0e30a8057f97f","08e41a3312ec4dc698c9677f13493dec","b8b0508e598c461195fdff01e45cefea","dc4134ab8bc54c9084238bce0d63dedd","d18de743a82d421b95ef67cce0cf8300","65d59de757ae4440b71dafd4fbe1ef0f","d265b8b4b76641599b70674b3b6843c2","f58a0d2e63aa456db54e8b34185a9e19","5bee9b83cf53437da9f86ca3e8c28ec8","feb6497eb22b418b89260242009018b1","fcebd41dea6a49d786827eb30e6202f0","cf9218e035054fe49188325d9173124a","ca76a74d6b204b4cae1f1d15a928782f","4fe39d4b2ce74d529df2c59c9b02b468","14ff55af3b4b4f19be5ecbdd7fdbb4b3","f937e91a44ba4ba29379c6cd98c7b06e","69c93310236e407c9ec47efba5949c2c","a9292503813741b096f1627ac629afcf","31b1c0b2c88244b6a1144b5b9bfd6ff2","4377ad0c4af348689bf257dbc1e45d0f","15beb9c45e974b8b9c7928f7dee85721","00d90919857a4182b41f71e4e029b8c9","a0bfaef233fc485088fd5f1069f0e7b5","91f9cb7da8554114a0fdccf7125323f8","afa6b2be45404268bbeae05757c38ea7","c707c0173ba64f278d29d8f91c5ebe72","f84e4be232c7471e8d7c32463d1e69f4","0ec87ae9355747b381f3a3c4759e30a1","7ff52331ff05443c885358a2bc91e45a","2e7dde21eddb461d94120cc0bc8b635d","acd43b8610784095ba13c79a9a8b66b3","94107ffa62c74aa9a7c1c6e9e0926534","aa8727521af944b990cd47bd7f624875","c49d62b351924bac9b758ed566642bc9","03ca2146c0a249e98891c826dc0c7166","3e67ecba11ed494eb5d04ac09aaf2982","cda2a733038b4a2d8d9126478f7c0ae2","856b386e9e354da6985976453f3146df","ae912f1a78a541d58364872d548fb113","1d92eaf91d064d7799cdbdce29cb4a80","8a4eec25ed2f4d888751714385bffb48","23683387f91d412ebcc1c6bda48f36c4","72ed4329ca9140078197aee662b9fe9c","cdbd26ce916d4aefa6bc2de33451b894","d81b6b93bf85468da26dd410d1fbf9ae","926cfc439c6f42c7bc7874e2abd27b00","925d430a70474c2bb645ab1c9635a3d8","1696aa6d01824c8da87bd6c3c99d9338","28e884495ed9480dbf42901aee98c8da","5cb8ef2c547741c782e0b87b44e88883","dfc87068738d4a51aa4582d66655ed5d","65c5547ef83346a3a7fe89350fd0498c","cc4dafcc559147f39d31c93d7bacead0","5ebed15f4ad74010a9dcc1aee2884acb","1d243bb88a024f5cad553638cb66b58f","00358206e8e44b7f93e33a68c77ed88e","1d01c3b7a45443219a40b6fc175bea93","e9638ccc83e64995b8d08950b5d4177c","a38abadac68d4e909589ede57054c9b3","9f407f26d4494b81acf8a2b3d22a4db0","047b24fa06104e88a4649b55d0704bba","e2ba9bdc71e342eea3fe5f0b2d50cad7","768d6cdbca5b4fd081c3c0b665af29e6","6d67906818de434193c0d07dffc16ca3","2d8e2453d52148de9e6f0af80025d277","beae34e9850d41f2928135a17bb7e24e","9ab61a0b2be94ab4b07712847603099f","18ff5098c2b0481e8122bafbb6773254","0adde2a598044d99b27e88632aa79204","18cd166a13cd40409789425e6ad8b1cf","262c89785cf747f8b2fabb01df958f46","481aca32d2314b71b8e2fe34fd5c2752","52bdbb92c8da4412944a3130a6739ff6","277c284a9a6f469285a8cd4adafeac48","c279c338d2ac48d1a905625818533a46","9e8c07a31ffe42f99b3c9234a53fa6dd","0a19274b68ec450895fd7f92941a2d90","4598f6ae49f94d639503175f378f011e","41fe52cfcadb4fcfb708f7f5e7c027ff","330cc931269846f2b6dc82c67fb2251b","c5d36dc5c318484db7e0c8a078aa175b","c159c8f334a64512a6d28efecaea2a10","479dc71849a4477183258d7ef9c0d4c2","d601d39013c24a5db643a09fe3fbf3af","4356a69037274d4288ab9cb2aaf72aef","747ff338df744bb2b4ea31ec325461bb","62416330d58b40d4b5d7cef51dff2245","bbdba0ab16184329bd1479a315c5946e","66b382b44b994abd9279d5edb90f86a1","a4016511fd92466e999483f4314d0a86","262eb29055f44a6dad1a9ad9d2d06ea0","57677aa2aee34f8b831622091eccdc42","6fe70dc2c58c4f34be8f25e507a203fa","cfcf8add8ce44707b89b97b291819b2e","da875aa1f4af4128b1c42bc30c79a8a8","d8d9489d104747d0aeaceab091a5dbba","b0bf5147c56b4a9e829fe1d7016a8971","06127d2f58d14e9b834f9c42fb6ccdee","1491cc4eedf14d788cc7a1750c84021e","ebae562970a84eac8ba32466a405aa06","acae4f3d583f4bb3bc7dc118ce63ae52","fc6764a48f134c7c863b83ac060a7c4e","b916a63767b44a7f9af4c4fd2d9f9118","44e7eca8403f42eab30a12cb6c4ec177","cad18185ae304fda8d114efce29f8b2b","022a6ebb208c40a38d991a7f48cf8199","5a12c2fbe4f949ec931de9e0ccb035ee","1cac8099d5a84d24bd968b0df0293e72","61e8b3559eb8464b9d3544921f9f716d","04fb26ceffe54dffb6b0f9864a3ada8a","83e6807d435d458ab54317a00543458a","383311a4464e4759972acb80200e05f3","aa8959e5f31a4e2a917849ff38e2d54a","cfad9960dbe7451db558e5d23edd4f87","7c0dbe672a904b7486a3274e87b42588","6f57b2e373e84323a7a0a2052c8a37db","418e999ec09c434ab6ac89e3b4b11365","4359515725fb4bfc93a8ac6ca824c6bd","7a6ff42ed0954523a58a579968191cca","f4f7b2ccfbd94a30a1f7a413c159ef07","7048ae3da65443a1a6996d937af1fec8","b74df493ed504a6aa9e2dd4c4bc48c56","0606d53650544db098d23fdf417584ad","fc986695bc55477099e8df7f9a0022cd","bf2ea05486a644e8ad8166ba0a9ff0a4","8c77254960fc4ed59a0431bb9f43b9dd","adda7298580c4bffb8d3c5e272e8eb7f","b9972d7b5b614566be7408889f1893bf","e364391a3e1d41d899735458a2b01436","7c30a1a41d3747e0b87625488e29c1b3","25cebb1840ea4239983838fdf2e5c84d","26deaa27cdea4addb812a67b4a0aae7a","bd6f1373744c49aa9ad9947714998e5d","83c2db21b673401fb11b45dde165fa14","96f3c7a52a37470a98de481a7ea343ca","eae063c3c5f54c86aee0b68d31f721ff","2472a63aefde4dc1bb199ab9847ca993","c4c988f7315a4734b4b4efcd378d2fe0","a05a89a8727a486792504d208aa43034","2c62ea060f2448ab928eb2b75897a227","b67a72677c674923b15e568e6fcdeb5c","9875ff389f3d46268417e9b53fbceaf5","d6a71cec5ffe4ba5992636efad52b8fe","62ec88a9e4e549729c5531c2c84ae21d","2c3264065ce141ab9f4c02ca29538962","37675716244d46fcb115ba1d8c500d3f","e37b7be566694f66bd5aa6e82572a2e7","b9fa62d6dd5e4e67921be98817cb00e2","9d210efdd32a4aa8a2b084cb9790ed48","3041f272c57c4038b11806de84232840","613b52321ad543d3b1f67c25642edf54","61a3f504ff5645db9d499f8f2ce0cb37","e1dcbdbabc40469793a494f59318b088","b5fe8a048b9a4db3bcfa77c81dfa8b0c","a4a7b41a2d6d4836b1d5b7c46d214a27","ab1faf852db24d418b647d44305f9998","f9b21842783e489d99ad9d25cd7d0914","5674ed00bf624d4fa0180ca9d855a797","66d2a279e9704c4cb03e51791814387e","a24e83fa73e24808a1b39f3f3d29e7ac","2d058a65cfdf4c628a38bd34eed8a8a8","934d301cd7d94a7597047efd861ceb66","113f7abf92c04d61aeb27a53796dddde","357d2c73ff2346a2a04ec63f11796048","7b065f9d0a454070b32e2f539f94769e","6cd377ac03004bf3b12fed2c9ec72aa9","010d7b561b1541e680b2a93007ec8bc5","73b6e040d91845c8ba2d220b53f93c09","ff88a16ea32e4df4b3abce055f6e2bc2","d71eb0b4940b4708a51b90af9e746db7","66f62676485e444db8fb34d870047708","3eb2ad0ee975499691c2655bdb9d90e5","1a7e467e1e7d4adf9c04217b09a54173","4e5a20cc1ed24d5d89305329da2b48e1","6f67bfe2f79c424fafbe0f85e40c1642","f17c2e4e8b2045e9930d9f2d73bf2ac7","cce621f14c99412ea7b92441fd4f3223","2c3a7c4e59e64433be763bcabd340df3","ae6d816055bd43a4a01cb54b8fb84486","598b5756615241c298f8f44d1e3b3f4f","d0567212f6824f5daec8a14d4c7bb0c7","aafbd97ba12d40e4affc97c378ae165e","798fe48e8b184a4ab35f56fca750dcbe","4c7342561d52489581e643f1d3121eb8","777aaee7cfdf4afd974983fdbd37ac8a","95af7b96533b47a7be57deb9cd5b0fb8","49cf9e00eb8b44cd9168574abe3df2c5","b7156a8bbb104cef9ce2ebbcf458f2cb","eb03b5ac6feb452a86ab17129481d3cb","ed6bd84830a642fd832ea549372056ad","6d69bd7081d44f748463fe8252ce675d","8d52617983b442e7b02d3d2ef885376c"],"resources":{"http://localhost:8080/experiment/cache/Action_Comics_1960-01-00_(262)/_crop/Action_Comics_1960-01-00_(262)_13_Default,%20grey%20pad.png":{"data":"CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPWVuPgogIDxtZXRhIGNoYXJzZXQ9dXRmLTg+CiAgPG1ldGEgbmFtZT12aWV3cG9ydCBjb250ZW50PSJpbml0aWFsLXNjYWxlPTEsIG1pbmltdW0tc2NhbGU9MSwgd2lkdGg9ZGV2aWNlLXdpZHRoIj4KICA8dGl0bGU+RXJyb3IgNDA0IChOb3QgRm91bmQpISExPC90aXRsZT4KICA8c3R5bGU+CiAgICAqe21hcmdpbjowO3BhZGRpbmc6MH1odG1sLGNvZGV7Zm9udDoxNXB4LzIycHggYXJpYWwsc2Fucy1zZXJpZn1odG1se2JhY2tncm91bmQ6I2ZmZjtjb2xvcjojMjIyO3BhZGRpbmc6MTVweH1ib2R5e21hcmdpbjo3JSBhdXRvIDA7bWF4LXdpZHRoOjM5MHB4O21pbi1oZWlnaHQ6MTgwcHg7cGFkZGluZzozMHB4IDAgMTVweH0qID4gYm9keXtiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9lcnJvcnMvcm9ib3QucG5nKSAxMDAlIDVweCBuby1yZXBlYXQ7cGFkZGluZy1yaWdodDoyMDVweH1we21hcmdpbjoxMXB4IDAgMjJweDtvdmVyZmxvdzpoaWRkZW59aW5ze2NvbG9yOiM3Nzc7dGV4dC1kZWNvcmF0aW9uOm5vbmV9YSBpbWd7Ym9yZGVyOjB9QG1lZGlhIHNjcmVlbiBhbmQgKG1heC13aWR0aDo3NzJweCl7Ym9keXtiYWNrZ3JvdW5kOm5vbmU7bWFyZ2luLXRvcDowO21heC13aWR0aDpub25lO3BhZGRpbmctcmlnaHQ6MH19I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LnBuZykgbm8tcmVwZWF0O21hcmdpbi1sZWZ0Oi01cHh9QG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWluLXJlc29sdXRpb246MTkyZHBpKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSBuby1yZXBlYXQgMCUgMCUvMTAwJSAxMDAlOy1tb3otYm9yZGVyLWltYWdlOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSAwfX1AbWVkaWEgb25seSBzY3JlZW4gYW5kICgtd2Via2l0LW1pbi1kZXZpY2UtcGl4ZWwtcmF0aW86Mil7I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LTJ4LnBuZykgbm8tcmVwZWF0Oy13ZWJraXQtYmFja2dyb3VuZC1zaXplOjEwMCUgMTAwJX19I2xvZ297ZGlzcGxheTppbmxpbmUtYmxvY2s7aGVpZ2h0OjU0cHg7d2lkdGg6MTUwcHh9CiAgPC9zdHlsZT4KICA8YSBocmVmPS8vd3d3Lmdvb2dsZS5jb20vPjxzcGFuIGlkPWxvZ28gYXJpYS1sYWJlbD1Hb29nbGU+PC9zcGFuPjwvYT4KICA8cD48Yj40MDQuPC9iPiA8aW5zPlRoYXTigJlzIGFuIGVycm9yLjwvaW5zPgogIDxwPiAgPGlucz5UaGF04oCZcyBhbGwgd2Uga25vdy48L2lucz4K","headers":[["content-length","1449"],["content-type","text/html; charset=utf-8"]],"ok":false,"status":404,"status_text":""},"http://localhost:8080/experiment/cache/Strange_Tales_172005/_crop/Strange_Tales_172005_13_Default,%20grey%20pad.png":{"data":"CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPWVuPgogIDxtZXRhIGNoYXJzZXQ9dXRmLTg+CiAgPG1ldGEgbmFtZT12aWV3cG9ydCBjb250ZW50PSJpbml0aWFsLXNjYWxlPTEsIG1pbmltdW0tc2NhbGU9MSwgd2lkdGg9ZGV2aWNlLXdpZHRoIj4KICA8dGl0bGU+RXJyb3IgNDA0IChOb3QgRm91bmQpISExPC90aXRsZT4KICA8c3R5bGU+CiAgICAqe21hcmdpbjowO3BhZGRpbmc6MH1odG1sLGNvZGV7Zm9udDoxNXB4LzIycHggYXJpYWwsc2Fucy1zZXJpZn1odG1se2JhY2tncm91bmQ6I2ZmZjtjb2xvcjojMjIyO3BhZGRpbmc6MTVweH1ib2R5e21hcmdpbjo3JSBhdXRvIDA7bWF4LXdpZHRoOjM5MHB4O21pbi1oZWlnaHQ6MTgwcHg7cGFkZGluZzozMHB4IDAgMTVweH0qID4gYm9keXtiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9lcnJvcnMvcm9ib3QucG5nKSAxMDAlIDVweCBuby1yZXBlYXQ7cGFkZGluZy1yaWdodDoyMDVweH1we21hcmdpbjoxMXB4IDAgMjJweDtvdmVyZmxvdzpoaWRkZW59aW5ze2NvbG9yOiM3Nzc7dGV4dC1kZWNvcmF0aW9uOm5vbmV9YSBpbWd7Ym9yZGVyOjB9QG1lZGlhIHNjcmVlbiBhbmQgKG1heC13aWR0aDo3NzJweCl7Ym9keXtiYWNrZ3JvdW5kOm5vbmU7bWFyZ2luLXRvcDowO21heC13aWR0aDpub25lO3BhZGRpbmctcmlnaHQ6MH19I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LnBuZykgbm8tcmVwZWF0O21hcmdpbi1sZWZ0Oi01cHh9QG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWluLXJlc29sdXRpb246MTkyZHBpKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSBuby1yZXBlYXQgMCUgMCUvMTAwJSAxMDAlOy1tb3otYm9yZGVyLWltYWdlOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSAwfX1AbWVkaWEgb25seSBzY3JlZW4gYW5kICgtd2Via2l0LW1pbi1kZXZpY2UtcGl4ZWwtcmF0aW86Mil7I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LTJ4LnBuZykgbm8tcmVwZWF0Oy13ZWJraXQtYmFja2dyb3VuZC1zaXplOjEwMCUgMTAwJX19I2xvZ297ZGlzcGxheTppbmxpbmUtYmxvY2s7aGVpZ2h0OjU0cHg7d2lkdGg6MTUwcHh9CiAgPC9zdHlsZT4KICA8YSBocmVmPS8vd3d3Lmdvb2dsZS5jb20vPjxzcGFuIGlkPWxvZ28gYXJpYS1sYWJlbD1Hb29nbGU+PC9zcGFuPjwvYT4KICA8cD48Yj40MDQuPC9iPiA8aW5zPlRoYXTigJlzIGFuIGVycm9yLjwvaW5zPgogIDxwPiAgPGlucz5UaGF04oCZcyBhbGwgd2Uga25vdy48L2lucz4K","headers":[["content-length","1449"],["content-type","text/html; charset=utf-8"]],"ok":false,"status":404,"status_text":""}}},"executionInfo":{"elapsed":1557,"status":"ok","timestamp":1717163102674,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"GmAca8fVUMUm","outputId":"407601af-7f59-4bb0-e428-cdde90b5ad8d"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"d4d04b8e8b6048f98d6614d47949e7c0","version_major":2,"version_minor":0},"text/plain":["VBox(children=(HTML(value=\""}},"dfc87068738d4a51aa4582d66655ed5d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_1d243bb88a024f5cad553638cb66b58f","placeholder":"​","style":"IPY_MODEL_00358206e8e44b7f93e33a68c77ed88e","value":"special_tokens_map.json: 100%"}},"e1dcbdbabc40469793a494f59318b088":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e2ba9bdc71e342eea3fe5f0b2d50cad7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_beae34e9850d41f2928135a17bb7e24e","placeholder":"​","style":"IPY_MODEL_9ab61a0b2be94ab4b07712847603099f","value":"config.json: 100%"}},"e364391a3e1d41d899735458a2b01436":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_83c2db21b673401fb11b45dde165fa14","max":4999813704,"min":0,"orientation":"horizontal","style":"IPY_MODEL_96f3c7a52a37470a98de481a7ea343ca","value":4999813704}},"e37b7be566694f66bd5aa6e82572a2e7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e6fac459206848898c206456b9dc8b1a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"e74be1cd463d42a783ddea46072f4499":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e7caf68af3c84c6195483d0a27225164":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_d418846006b8496989e86276d8538b50","placeholder":"​","style":"IPY_MODEL_2ad60e460fe64f0087cf3052f06451ba","value":"processor_config.json: 100%"}},"e9638ccc83e64995b8d08950b5d4177c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"eae063c3c5f54c86aee0b68d31f721ff":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"eb03b5ac6feb452a86ab17129481d3cb":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ebae562970a84eac8ba32466a405aa06":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"ed6bd84830a642fd832ea549372056ad":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"ee91033cfb084d4e83529a11edb48134":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137212937453776"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_76c165d73f574ab39d3357e87b401ac9"],"layout":"IPY_MODEL_68d09a9f2fc84ead952160fe05c5dc90"}},"f1513571ca224451a3809b56a5739525":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e7caf68af3c84c6195483d0a27225164","IPY_MODEL_f6c25f96ead14b13a1a716a6de4e3f5c","IPY_MODEL_4a51933821d045cd881418ff2a2b30e7"],"layout":"IPY_MODEL_1d1a5dd1cc1d44be948464159187e856"}},"f17c2e4e8b2045e9930d9f2d73bf2ac7":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f4f7b2ccfbd94a30a1f7a413c159ef07":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f58a0d2e63aa456db54e8b34185a9e19":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_ca76a74d6b204b4cae1f1d15a928782f","max":1636,"min":0,"orientation":"horizontal","style":"IPY_MODEL_4fe39d4b2ce74d529df2c59c9b02b468","value":1636}},"f5e02d40775a49a5b895d498233464f9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"visible","width":null}},"f6c25f96ead14b13a1a716a6de4e3f5c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_6c0b5365fd624af793b4d37f7449a7a5","max":483,"min":0,"orientation":"horizontal","style":"IPY_MODEL_9590087714614e948f3a8e4dd537a895","value":483}},"f84e4be232c7471e8d7c32463d1e69f4":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f8bc3fb84517404b94502e7498d5c55a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f937e91a44ba4ba29379c6cd98c7b06e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f9b21842783e489d99ad9d25cd7d0914":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"f9feda61c229465da90f33c69e7a4398":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137212937454928"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_c2494c8753e9409aa5e6d8862be5c773","IPY_MODEL_0e112f697e7d4a34826d2a46a067c14e","IPY_MODEL_ee91033cfb084d4e83529a11edb48134"],"layout":"IPY_MODEL_f5e02d40775a49a5b895d498233464f9"}},"fb224135f5a14ba4872e0e64428d60b6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"BoundedIntTextModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"BoundedIntTextModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"IntTextView","continuous_update":false,"description":"","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_11c9edbf48f445d09d85f849915496e2","max":14,"min":0,"step":1,"style":"IPY_MODEL_9bb8a92858144190b6dd506673234315","value":0}},"fc6764a48f134c7c863b83ac060a7c4e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"fc986695bc55477099e8df7f9a0022cd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"fcebd41dea6a49d786827eb30e6202f0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fd00985eb51141799c4ad95c99461926":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"block","flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"feb6497eb22b418b89260242009018b1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ff88a16ea32e4df4b3abce055f6e2bc2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ffeb080904984371bb8b715963c00069":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Boxes","Image","Mask","Image & Mask","Page data","Ground truth","Image All","Results","Best results","Accuracy","Dataframe","Config"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":7,"layout":"IPY_MODEL_bd64ee547bd049398c6d37f1ca476461","style":"IPY_MODEL_5da238d5b8514352a70b6b16cc9d944f"}}}}},"nbformat":4,"nbformat_minor":0} +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `Idefics` OCR for Comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Settings for Google Colab" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n", + "\n", + "- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n", + "This allows the notebook to access files stored in your Google Drive.\n", + "\n", + "- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n", + "This acts as the root directory for accessing any files within your Google Drive from the notebook.\n", + "\n", + "- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n", + "This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "MOUNT_DRIVE = True\n", + "GDRIVE_MOUNT_POINT = 'drive'\n", + "PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "import os\n", + "import re\n", + "import sys\n", + "from pathlib import Path\n", + "\n", + "from rich import print as cprint\n", + "from rich.text import Text\n", + "\n", + "def info(msg: str):\n", + " (t := Text(msg)).stylize(\"bold red\", 0, 6)\n", + " cprint(\"_\" * 10, t, \"_\" * 10)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mount Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n", + "if FC.IN_COLAB:\n", + " if MOUNT_DRIVE:\n", + " if not mnt_point.exists():\n", + " info(\"Mounting Google Drive\")\n", + " from google.colab import drive\n", + " drive.mount(str(mnt_point), force_remount=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install **PanelCleaner**\n", + "\n", + "> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n", + "\n", + "Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_COLAB:\n", + " pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n", + " tb_path = pc_path/'pcleaner/_testbed'\n", + " if tb_path.exists():\n", + " info('Installing PanelCleaner from your Google Drive')\n", + " else:\n", + " info('Installing PanelCleaner from GitHub')\n", + " !rm -rf PanelCleaner\n", + " !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n", + " pc_path = Path('PanelCleaner').absolute()\n", + " tb_path = pc_path/'pcleaner/_testbed'\n", + " assert tb_path.exists(), \"PanelCleaner not found\"\n", + " os.chdir(tb_path)\n", + " sys.path.insert(0, f\"{tb_path}\")\n", + " sys.path.insert(0, f\"{pc_path}\")\n", + " !pip install -q -r requirements-colab.txt\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'4.42.0.dev0'" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "if FC.IN_COLAB:\n", + " !pip install -q flash-attn --no-build-isolation\n", + " !pip install -q transformers accelerate datasets peft bitsandbytes\n", + "\n", + "import transformers\n", + "transformers.__version__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n", + "from testbed.ocr_idefics import IdeficsOCR, get_gpu_vram\n", + "from testbed.helpers import IN_MAC, IN_LINUX\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if IN_MAC:\n", + " !pip install -q mlx_vlm\n", + "\n", + " import mlx.core as mx\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GPU" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
          metal.is_available(): True\n",
+       "           metal.device_info(): {'memory_size': 68719476736, 'max_recommended_working_set_size': 51539607552, \n",
+       "'max_buffer_length': 38654705664, 'architecture': 'applegpu_g13s'}\n",
+       "     metal.get_active_memory(): 0\n",
+       "       metal.get_peak_memory(): 0\n",
+       "      metal.get_cache_memory(): 0\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " \u001b[1;35mmetal.is_available\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[3;92mTrue\u001b[0m\n", + " \u001b[1;35mmetal.device_info\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'memory_size'\u001b[0m: \u001b[1;36m68719476736\u001b[0m, \u001b[32m'max_recommended_working_set_size'\u001b[0m: \u001b[1;36m51539607552\u001b[0m, \n", + "\u001b[32m'max_buffer_length'\u001b[0m: \u001b[1;36m38654705664\u001b[0m, \u001b[32m'architecture'\u001b[0m: \u001b[32m'applegpu_g13s'\u001b[0m\u001b[1m}\u001b[0m\n", + " \u001b[1;35mmetal.get_active_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n", + " \u001b[1;35mmetal.get_peak_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n", + " \u001b[1;35mmetal.get_cache_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
     total VRAM: 65536 MiB\n",
+       "    active VRAM: 0 MiB\n",
+       "
\n" + ], + "text/plain": [ + " total VRAM: \u001b[1;36m65536\u001b[0m MiB\n", + " active VRAM: \u001b[1;36m0\u001b[0m MiB\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "if IN_MAC:\n", + " gpu_name = mx.metal.device_info()['architecture']\n", + " cprint(\n", + " f\"{'metal.is_available()':>30}: {mx.metal.is_available()}\\n\"\n", + " f\"{'metal.device_info()':>30}: {mx.metal.device_info()}\\n\"\n", + " f\"{'metal.get_active_memory()':>30}: {mx.metal.get_active_memory()//1024//1024}\\n\"\n", + " f\"{'metal.get_peak_memory()':>30}: {mx.metal.get_peak_memory()//1024//1024}\\n\"\n", + " f\"{'metal.get_cache_memory()':>30}: {mx.metal.get_cache_memory()//1024//1024}\\n\"\n", + " )\n", + "else:\n", + " !nvidia-smi\n", + " import subprocess\n", + " gpu_name = subprocess.check_output(\n", + " \"nvidia-smi --query-gpu=gpu_name --format=csv,noheader\", shell=True\n", + " ).decode('utf-8').strip()\n", + " \n", + "\n", + "cprint( f\"{'GPU':>15}: {gpu_name}\\n\"\n", + " f\"{'total VRAM':>15}: {get_gpu_vram()} MiB\\n\"\n", + " f\"{'active VRAM':>15}: {get_gpu_vram(False)} MiB\")\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Idefics experiments" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Experiment directory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n", + "\n", + "NOTE: the default value assumes we are currently inside `PanelCleaner/pcleaner/_testbed` directory. You can check that is the case with `Path('.').resolve()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n",
+       "Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n",
+       "
\n" + ], + "text/plain": [ + " Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n", + "Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "EXP_DIR = Path('./experiment')\n", + "cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Copy your images to the source directory:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint((EXP_DIR/'source').resolve())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or download the standard set:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !unzip -qn experiment.zip -d ." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Setup ngrok (Colab)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n", + "\n", + "Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n", + "- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n", + "- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n", + "\n", + "You choose.\n", + "\n", + "If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n", + "\n", + "I you don't change the default settings and\n", + "- the notebook is running locally, it'll serve the images directly without any additional setup.\n", + "- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_COLAB:\n", + " os.environ['USE_TUNNEL'] = 'True'\n", + " os.environ['USE_PIL'] = 'False'\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SERVER = None\n", + "if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n", + " import testbed.web_server as web_server\n", + " SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CONTEXT" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| quant, attn \\ platform | Mem | Mac | Linux | Windows | Colab T4 | Colab L4/H100 |\n", + "| --- | --- | --- | --- | --- | --- | --- |\n", + "| **float16** | 17 GB | ✅ | ✅ | ? | ❌ | ✅ |\n", + "| **float16 + attn** | 17 GB | ❌ | ✅ | ? | ❌ | ✅ |\n", + "| **8bit** | 10 GB | ✅ | ✅ | ? | ✅ | ✅ |\n", + "| **8bit + attn** | 10 GB | ❌ | ✅ | ? | ❌ | ✅ |\n", + "| **4bit** | 6 GB | ✅ | ✅ | ? | ✅ | ✅ |\n", + "| **4bit + attn** | 6 GB | ❌ | ✅ | ? | ❌ | ✅ |\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creates the `IdeficsExperimentContext` object we'll use to manage the experiments.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: cursor\n", + "Cache Directory: System default\n", + "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", + "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
 config cache_dir: None\n",
+       "       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
+       "           device: 'mps'\n",
+       "
\n" + ], + "text/plain": [ + " config cache_dir: \u001b[3;35mNone\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'mps'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
        force_PIL: False\n",
+       "       use_tunnel: False\n",
+       "       server_url: \n",
+       "   experiment dir: experiment\n",
+       "       source_dir: experiment/source\n",
+       "        cache_dir: experiment/cache\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " force_PIL: \u001b[3;91mFalse\u001b[0m\n", + " use_tunnel: \u001b[3;91mFalse\u001b[0m\n", + " server_url: \n", + " experiment dir: experiment\n", + " source_dir: experiment/source\n", + " cache_dir: experiment/cache\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Experiment runs:\n",
+       "Idefics-crop-post: 16\n",
+       "
\n" + ], + "text/plain": [ + "Experiment runs:\n", + "Idefics-crop-post: \u001b[1;36m16\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
     Quantization: '4bit'\n",
+       "Flash attention 2: N/A\n",
+       "             VRAM: 0/65536 MiB\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " Quantization: \u001b[32m'4bit'\u001b[0m\n", + "Flash attention \u001b[1;36m2\u001b[0m: N/A\n", + " VRAM: \u001b[1;36m0\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "quant = '4bit' if IN_MAC or FC.IN_COLAB else 'float16'\n", + "flashattn = True if not FC.IN_COLAB else False\n", + "CONTEXT = OCRExperimentContext('Idefics', EXP_DIR, \n", + " quant=quant, flashattn=flashattn, \n", + " server=SERVER, run_name='Idefics-crop-post', load=True)\n", + "CONTEXT.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "a93af477ed4c4af8aba4d97397009adc", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Fetching 11 files: 0%| | 0/11 [00:00. This is expected, and simply means that the `legacy` (previous) behavior will be used so nothing changes for you. If you want to use the new behaviour, set `legacy=False`. This should only be set if you understand what it means, and thoroughly read the reason why this was added as explained in https://github.com/huggingface/transformers/pull/24565\n", + "Special tokens have been added in the vocabulary, make sure the associated word embeddings are fine-tuned or trained.\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0f89471c58b94c2db7ffab9143b26b6b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Fetching 11 files: 0%| | 0/11 [00:00 Quantization: '4bit'\n", + "Flash attention 2: N/A\n", + " VRAM: 5261/65536 MiB\n", + "\n", + "\n" + ], + "text/plain": [ + " Quantization: \u001b[32m'4bit'\u001b[0m\n", + "Flash attention \u001b[1;36m2\u001b[0m: N/A\n", + " VRAM: \u001b[1;36m5261\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ocr_model = CONTEXT.setup_ocr_model(False)\n", + "ocr_model.show_info()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check the images are in place" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d4d04b8e8b6048f98d6614d47949e7c0", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HTML(value=\"" + } + }, + "dfc87068738d4a51aa4582d66655ed5d": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_1d243bb88a024f5cad553638cb66b58f", + "placeholder": "​", + "style": "IPY_MODEL_00358206e8e44b7f93e33a68c77ed88e", + "value": "special_tokens_map.json: 100%" + } + }, + "e1dcbdbabc40469793a494f59318b088": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e2ba9bdc71e342eea3fe5f0b2d50cad7": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_beae34e9850d41f2928135a17bb7e24e", + "placeholder": "​", + "style": "IPY_MODEL_9ab61a0b2be94ab4b07712847603099f", + "value": "config.json: 100%" + } + }, + "e364391a3e1d41d899735458a2b01436": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatProgressModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_83c2db21b673401fb11b45dde165fa14", + "max": 4999813704, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_96f3c7a52a37470a98de481a7ea343ca", + "value": 4999813704 + } + }, + "e37b7be566694f66bd5aa6e82572a2e7": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e6fac459206848898c206456b9dc8b1a": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": "0px 0px 0px 10px", + "right": null, + "top": null, + "visibility": null, + "width": "initial" + } + }, + "e74be1cd463d42a783ddea46072f4499": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e7caf68af3c84c6195483d0a27225164": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_d418846006b8496989e86276d8538b50", + "placeholder": "​", + "style": "IPY_MODEL_2ad60e460fe64f0087cf3052f06451ba", + "value": "processor_config.json: 100%" + } + }, + "e9638ccc83e64995b8d08950b5d4177c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "eae063c3c5f54c86aee0b68d31f721ff": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "eb03b5ac6feb452a86ab17129481d3cb": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ebae562970a84eac8ba32466a405aa06": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "ed6bd84830a642fd832ea549372056ad": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "ee91033cfb084d4e83529a11edb48134": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137212937453776" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_76c165d73f574ab39d3357e87b401ac9" + ], + "layout": "IPY_MODEL_68d09a9f2fc84ead952160fe05c5dc90" + } + }, + "f1513571ca224451a3809b56a5739525": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_e7caf68af3c84c6195483d0a27225164", + "IPY_MODEL_f6c25f96ead14b13a1a716a6de4e3f5c", + "IPY_MODEL_4a51933821d045cd881418ff2a2b30e7" + ], + "layout": "IPY_MODEL_1d1a5dd1cc1d44be948464159187e856" + } + }, + "f17c2e4e8b2045e9930d9f2d73bf2ac7": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f4f7b2ccfbd94a30a1f7a413c159ef07": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f58a0d2e63aa456db54e8b34185a9e19": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatProgressModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_ca76a74d6b204b4cae1f1d15a928782f", + "max": 1636, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_4fe39d4b2ce74d529df2c59c9b02b468", + "value": 1636 + } + }, + "f5e02d40775a49a5b895d498233464f9": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": "visible", + "width": null + } + }, + "f6c25f96ead14b13a1a716a6de4e3f5c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatProgressModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "success", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_6c0b5365fd624af793b4d37f7449a7a5", + "max": 483, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_9590087714614e948f3a8e4dd537a895", + "value": 483 + } + }, + "f84e4be232c7471e8d7c32463d1e69f4": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "f8bc3fb84517404b94502e7498d5c55a": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f937e91a44ba4ba29379c6cd98c7b06e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "f9b21842783e489d99ad9d25cd7d0914": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "f9feda61c229465da90f33c69e7a4398": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137212937454928" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_c2494c8753e9409aa5e6d8862be5c773", + "IPY_MODEL_0e112f697e7d4a34826d2a46a067c14e", + "IPY_MODEL_ee91033cfb084d4e83529a11edb48134" + ], + "layout": "IPY_MODEL_f5e02d40775a49a5b895d498233464f9" + } + }, + "fb224135f5a14ba4872e0e64428d60b6": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "BoundedIntTextModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "BoundedIntTextModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "IntTextView", + "continuous_update": false, + "description": "", + "description_tooltip": null, + "disabled": false, + "layout": "IPY_MODEL_11c9edbf48f445d09d85f849915496e2", + "max": 14, + "min": 0, + "step": 1, + "style": "IPY_MODEL_9bb8a92858144190b6dd506673234315", + "value": 0 + } + }, + "fc6764a48f134c7c863b83ac060a7c4e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "fc986695bc55477099e8df7f9a0022cd": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "fcebd41dea6a49d786827eb30e6202f0": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fd00985eb51141799c4ad95c99461926": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": "block", + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "feb6497eb22b418b89260242009018b1": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ff88a16ea32e4df4b3abce055f6e2bc2": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ffeb080904984371bb8b715963c00069": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Boxes", + "Image", + "Mask", + "Image & Mask", + "Page data", + "Ground truth", + "Image All", + "Results", + "Best results", + "Accuracy", + "Dataframe", + "Config" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 7, + "layout": "IPY_MODEL_bd64ee547bd049398c6d37f1ca476461", + "style": "IPY_MODEL_5da238d5b8514352a70b6b16cc9d944f" + } + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/pcleaner/_testbed/test_paligemma.ipynb b/pcleaner/_testbed/test_paligemma.ipynb index 0275156a..95268903 100644 --- a/pcleaner/_testbed/test_paligemma.ipynb +++ b/pcleaner/_testbed/test_paligemma.ipynb @@ -1 +1,5150 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"FO-koL4wUMUg"},"source":["# Testing `PaliGemma` OCR for Comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"HKOXOxox_jG0"},"source":["## Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"GakYQssB_jG0"},"source":["To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n","\n","- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n","This allows the notebook to access files stored in your Google Drive.\n","\n","- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n","This acts as the root directory for accessing any files within your Google Drive from the notebook.\n","\n","- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n","This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n"]},{"cell_type":"code","execution_count":2,"metadata":{"executionInfo":{"elapsed":2,"status":"ok","timestamp":1717165201592,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"uNgZx4vk_jG0"},"outputs":[],"source":["MOUNT_DRIVE = True\n","GDRIVE_MOUNT_POINT = 'drive'\n","PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'"]},{"cell_type":"markdown","metadata":{"id":"1iZhT2Zd_jG1"},"source":["# install (Colab)\n"]},{"cell_type":"code","execution_count":3,"metadata":{"executionInfo":{"elapsed":3,"status":"ok","timestamp":1717165204341,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"RNFlWKSb_jG1"},"outputs":[],"source":["import fastcore.all as FC\n","import os\n","import re\n","import sys\n","from pathlib import Path\n","\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," (t := Text(msg)).stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, t, \"_\" * 10)\n"]},{"cell_type":"markdown","metadata":{"id":"Xrv0xwSP_jG1"},"source":["Mount Google Drive"]},{"cell_type":"code","execution_count":4,"metadata":{"executionInfo":{"elapsed":4,"status":"ok","timestamp":1717165208042,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"7h-QzI37_jG1"},"outputs":[],"source":["mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," if not mnt_point.exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n"," drive.mount(str(mnt_point), force_remount=True)\n"]},{"cell_type":"markdown","metadata":{"id":"41JG2K1G_jG1"},"source":["### Install **PanelCleaner**\n","\n","> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n","\n","Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook."]},{"cell_type":"code","execution_count":5,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":33},"executionInfo":{"elapsed":4564,"status":"ok","timestamp":1717165217825,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"SdiVA--u_jG1","outputId":"4c6a00e8-c8d9-4988-c5f2-7010c1233681"},"outputs":[],"source":["if FC.IN_COLAB:\n"," pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n"," tb_path = pc_path/'pcleaner/_testbed'\n"," if tb_path.exists():\n"," info('Installing PanelCleaner from your Google Drive')\n"," else:\n"," info('Installing PanelCleaner from GitHub')\n"," !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n"," tb_path = Path('PanelCleaner/pcleaner/_testbed')\n"," assert tb_path.exists(), \"PanelCleaner not found\"\n"," os.chdir(tb_path)\n"," sys.path.append(f\"{pc_path}\")\n"," sys.path.append(f\"{tb_path}\")\n"," !pip install -q -r requirements-colab.txt\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[{"data":{"text/plain":["'4.42.0.dev0'"]},"metadata":{},"output_type":"display_data"}],"source":["if FC.IN_COLAB:\n"," !pip install -q accelerate\n","\n","import transformers\n","transformers.__version__"]},{"cell_type":"markdown","metadata":{"id":"8_A18iMfN2-g"},"source":["# Prologue"]},{"cell_type":"code","execution_count":7,"metadata":{"executionInfo":{"elapsed":4223,"status":"ok","timestamp":1717165238956,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"q_7GYpnWUMUl"},"outputs":[],"source":["from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n","from testbed.ocr_paligemma import PaliGemmaOCR, get_gpu_vram\n","from testbed.helpers import IN_MAC, IN_LINUX\n"]},{"cell_type":"code","execution_count":8,"metadata":{"executionInfo":{"elapsed":2,"status":"ok","timestamp":1717165238956,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"CQtkWb9ON2-g"},"outputs":[],"source":["if IN_MAC:\n"," # !pip install -q mlx_vlm\n","\n"," import mlx.core as mx\n"]},{"cell_type":"markdown","metadata":{"id":"DK4iMZ7nN2-g"},"source":["# GPU"]},{"cell_type":"code","execution_count":12,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":396},"executionInfo":{"elapsed":660,"status":"ok","timestamp":1717165239614,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"_qoPb5u3N2-g","outputId":"6dec4a6e-5679-47c5-cc53-17473a6e214b"},"outputs":[{"data":{"text/html":["
          metal.is_available(): True\n","           metal.device_info(): {'memory_size': 68719476736, 'max_recommended_working_set_size': 51539607552, \n","'max_buffer_length': 38654705664, 'architecture': 'applegpu_g13s'}\n","     metal.get_active_memory(): 0\n","       metal.get_peak_memory(): 0\n","      metal.get_cache_memory(): 0\n","\n","
\n"],"text/plain":[" \u001b[1;35mmetal.is_available\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[3;92mTrue\u001b[0m\n"," \u001b[1;35mmetal.device_info\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'memory_size'\u001b[0m: \u001b[1;36m68719476736\u001b[0m, \u001b[32m'max_recommended_working_set_size'\u001b[0m: \u001b[1;36m51539607552\u001b[0m, \n","\u001b[32m'max_buffer_length'\u001b[0m: \u001b[1;36m38654705664\u001b[0m, \u001b[32m'architecture'\u001b[0m: \u001b[32m'applegpu_g13s'\u001b[0m\u001b[1m}\u001b[0m\n"," \u001b[1;35mmetal.get_active_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_peak_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n"," \u001b[1;35mmetal.get_cache_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
            GPU: applegpu_g13s\n","     total VRAM: 65536 MiB\n","    active VRAM: 0 MiB\n","
\n"],"text/plain":[" GPU: applegpu_g13s\n"," total VRAM: \u001b[1;36m65536\u001b[0m MiB\n"," active VRAM: \u001b[1;36m0\u001b[0m MiB\n"]},"metadata":{},"output_type":"display_data"}],"source":["if IN_MAC:\n"," gpu_name = mx.metal.device_info()['architecture']\n"," cprint(\n"," f\"{'metal.is_available()':>30}: {mx.metal.is_available()}\\n\"\n"," f\"{'metal.device_info()':>30}: {mx.metal.device_info()}\\n\"\n"," f\"{'metal.get_active_memory()':>30}: {mx.metal.get_active_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_peak_memory()':>30}: {mx.metal.get_peak_memory()//1024//1024}\\n\"\n"," f\"{'metal.get_cache_memory()':>30}: {mx.metal.get_cache_memory()//1024//1024}\\n\"\n"," )\n","else:\n"," !nvidia-smi\n"," import subprocess\n"," gpu_name = subprocess.check_output(\n"," \"nvidia-smi --query-gpu=gpu_name --format=csv,noheader\", shell=True\n"," ).decode('utf-8').strip()\n"," \n","\n","cprint( f\"{'GPU':>15}: {gpu_name}\\n\"\n"," f\"{'total VRAM':>15}: {get_gpu_vram()} MiB\\n\"\n"," f\"{'active VRAM':>15}: {get_gpu_vram(False)} MiB\")\n","\n"]},{"cell_type":"markdown","metadata":{"id":"Op4kiDaAUMUl"},"source":["----\n","# PaliGemma experiments"]},{"cell_type":"code","execution_count":10,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":1932,"status":"ok","timestamp":1717165245172,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"D0LeqL6TZ-GY","outputId":"4b587e05-4de3-469b-cbd4-49b58fc0939d"},"outputs":[{"name":"stdout","output_type":"stream","text":["User is already logged in.\n"]}],"source":["from huggingface_hub import notebook_login\n","notebook_login(False, False)"]},{"cell_type":"markdown","metadata":{"id":"Y3IENuzMN2-h"},"source":["## Experiment directory"]},{"cell_type":"markdown","metadata":{"id":"urj8RO7aN2-h"},"source":["Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n","\n","NOTE: the default value assumes we are currently inside `PanelCleaner/pcleaner/_testbed` directory. You can check that is the case with `Path('.').resolve()`."]},{"cell_type":"code","execution_count":11,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":49},"executionInfo":{"elapsed":369,"status":"ok","timestamp":1717165248315,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"cbFj63q4N2-h","outputId":"b10db83f-aa18-496d-e16e-834050b8aea7"},"outputs":[{"data":{"text/html":["
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n","Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n","
\n"],"text/plain":[" Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n","Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["EXP_DIR = Path('./experiment')\n","cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n"]},{"cell_type":"markdown","metadata":{},"source":["# Test images\n"]},{"cell_type":"markdown","metadata":{},"source":["Copy your images to the source directory:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[{"data":{"text/html":["
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n","
\n"],"text/plain":["\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{"id":"8Iondm2oUMUl"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"nuHPp1U7UMUl"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":12,"metadata":{"executionInfo":{"elapsed":559,"status":"ok","timestamp":1717165257647,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"vaf4PGLlUMUm"},"outputs":[],"source":["if FC.IN_COLAB:\n"," os.environ['USE_TUNNEL'] = 'True'\n"," os.environ['USE_PIL'] = 'False'\n"]},{"cell_type":"code","execution_count":13,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":184},"executionInfo":{"elapsed":47202,"status":"ok","timestamp":1717165306667,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"kivkfTrcUMUm","outputId":"6547dd4b-3747-4c99-e393-a422d1a85798"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import testbed.web_server as web_server\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"B0UlRbJ4N2-h"},"source":["# CONTEXT"]},{"cell_type":"markdown","metadata":{"id":"gBET0jZMN2-h"},"source":["| quant \\ platform | Mem | Mac | Linux | Windows | Colab T4 | Colab L4/H100 |\n","| --- | --- | --- | --- | --- | --- | --- |\n","| **bfloat16** | 6 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **8bit** | 3 GB | ✅ | ✅ | ? | ✅ | ✅ |\n","| **4bit** | 2 GB | ✅ | ✅ | ? | ✅ | ✅ |\n"]},{"cell_type":"markdown","metadata":{"id":"AUgSvi6CUMUm"},"source":["Creates the `ExperimentContext` object we'll use to manage the experiments.\n"]},{"cell_type":"code","execution_count":18,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":504},"executionInfo":{"elapsed":434,"status":"ok","timestamp":1717165321066,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"wroznCt0CQdT","outputId":"ec50236e-dddc-4d60-b3cd-b6fdcb0a584f"},"outputs":[{"name":"stdout","output_type":"stream","text":["Current Configuration:\n","\n","Locale: System default\n","Default Profile: Built-in\n","Saved Profiles:\n","- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n","- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n","\n","Profile Editor: cursor\n","Cache Directory: System default\n","Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n","Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n","GUI Theme: System default\n","\n","--------------------\n","\n","Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n","System default cache directory: /Users/vic/Library/Caches/pcleaner\n"]},{"data":{"text/html":["
 config cache_dir: None\n","       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n","           device: 'mps'\n","
\n"],"text/plain":[" config cache_dir: \u001b[3;35mNone\u001b[0m\n"," model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n"," device: \u001b[32m'mps'\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
        force_PIL: False\n","       use_tunnel: False\n","       server_url: \n","   experiment dir: experiment\n","       source_dir: experiment/source\n","        cache_dir: experiment/cache\n","\n","
\n"],"text/plain":[" force_PIL: \u001b[3;91mFalse\u001b[0m\n"," use_tunnel: \u001b[3;91mFalse\u001b[0m\n"," server_url: \n"," experiment dir: experiment\n"," source_dir: experiment/source\n"," cache_dir: experiment/cache\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Experiment runs:\n","PaliGemma-crop-post: 0\n","
\n"],"text/plain":["Experiment runs:\n","PaliGemma-crop-post: \u001b[1;36m0\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["quant = '8bit' if IN_MAC else 'bfloat16'\n","CONTEXT = OCRExperimentContext('PaliGemma', EXP_DIR, quant=quant, \n"," server=SERVER, run_name='PaliGemma-crop-post', load=True)\n","CONTEXT.show()\n"]},{"cell_type":"code","execution_count":19,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":358,"referenced_widgets":["d086b7598b4848aaa4eb0ffede5da0f7","4856c138483c4bc59c165c6f8c81777a","1bffa03a8dfa4d4ba6e0b2cf76f5f0fd","88ee0bfb700a4f369333729d755fbc91","f2b7ff5971bd43b986d810b9261abd1c","c5431bc93486497faa74330f37d582aa","aec0a793b589469d957a83b767724cc4","8bb2d35ebdbc48dda1f1f365389ac92e","2d8a14b167c943a888fa9a313f6166eb","2930ae9cab9e421f9c6191bdb86d37a4","cde5c9e129e443fb9c1c642156bab294","5d09637e4ba34f14a879dbe44c675285","4b9e45c5e109429da8a7ed75633cdcfb","11d2466d2ced4c69afc62bda1f3baf27","725a2c78a0d94db19517c9f03fdbd76f","635032f84bbc4b0a8b1e4bcfb9d5318d","0e6515360d65481c8b398c02b0b6f437","9ac3df27ca5f442398b86df5d5849fab","6683113218e44183a6a5a1cd1392b452","5c0be55008d045108e2a91a819adfd58","ad5ddbcf9642427ca162e9cfdefe8ded","2682f4f1f76b498091a8bb16c97205e6","513155104caa4340900c728a570728e9","b64f35e753334071ba92cc9c23472f5f","5d772e124d1c4286bc83b0fdfd50b737","3a40dc732037425cb1491bb68f7d7178","4306183c004747b897acb4be6577f46d","78f02d7219cb4e5bbde518ac5e96a341","06d9f190506c40fb9689977c2a2b2757","daabe05918774871ba2f9cba38ca14ff","e72b3672869743e7b8fbbe178a93698a","86e80efa2af4416b9f465e7cb3873c3b","64d05881c560431b86dec6c27c01bfbb","a49fa2c6c92c4191a79f659b114eae0e","2db177bd125f4e0789363306784c51fa","b75c3b4c04a9416ca5e93bdf3b049c12","5d1fd260fdee46d69e8f81f1e146b787","5541585cb2714d82a3fdb9f70a161533","7fa1b8a86fe846c29568b89135748bc2","7694626eeb3b45598fa74862fb5b95a0","4cc8f4e7c0dd442199d94880ca6b718f","7efe7d6323ef4a00a4c4239643ef1d7d","b51706f5a3c14f20a642a64912e068ff","f1cf213ea11e431c8aded42b1af2536b","a26dbf2c5fc647e89984f08d89e11cb4","fd31aabd8e4c4aa8add50c95e55e9d6f","22121cd9a6954bc2908e5a44c6bdd6a9","54abbc4b157c41cba0f0c663bba5eb25","0d416a34a58745ec9558443d076d3d55","64b5967a0be04a05aeddda4a1b977531","aeb9f955725443f5b2c2f0c54ffb1fc8","1c60de0ca3b8455a900affc4690fca1f","06de6316d026491bbd9e7c18efa3a351","f4fd6b82478a444d91242587c0a5045f","8f5f4df805114835b66872e2520edf70","bbf4c62d0b674b2594e455696e6e427a","377aea61c8d441afad1456b08681c7f2","b037f85089e24e5ba970bef2f46e568b","f3863102525f488fb74877a54b447c63","79d600bfe6204618af8ba7a7cb1577a8","0251403980314014b84ae3dc63cc5455","84ab0a402fe54b0f9f8791321c8d9276","4bf8171d649f4a819275590070b734bd","7a2075bd25ac42c984f2e12c2f18b578","0b9d514d2d9249f09095065a9e302c49","4acbacc0ed4a4c1581583f428b69aff7"]},"executionInfo":{"elapsed":31187,"status":"ok","timestamp":1717165357281,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"cSuBWT4YN2-i","outputId":"00cdca4b-4568-4a97-c646-42ab70541d1d"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"6701b0fefb114810a52c202ffb6a4b4d","version_major":2,"version_minor":0},"text/plain":["Fetching 9 files: 0%| | 0/9 [00:00 Size: '224'\n"," Quantization: '8bit'\n"," Device: 'mps'\n"," VRAM: 2986/65536 MiB\n","\n","\n"],"text/plain":[" Size: \u001b[32m'224'\u001b[0m\n"," Quantization: \u001b[32m'8bit'\u001b[0m\n"," Device: \u001b[32m'mps'\u001b[0m\n"," VRAM: \u001b[1;36m2986\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n","\n"]},"metadata":{},"output_type":"display_data"}],"source":["ocr_model = CONTEXT.setup_ocr_model(False)\n","ocr_model.show_info()"]},{"cell_type":"markdown","metadata":{"id":"rgSiXSTyN2-l"},"source":["Check the images are in place"]},{"cell_type":"code","execution_count":20,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":431,"status":"ok","timestamp":1717165362762,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"ZXL84T8dUMUm","outputId":"92365c79-9c3d-4645-9638-b9f56b3131b7"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":20,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"code","execution_count":22,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":200,"referenced_widgets":["59886ba6cd1c4fe8951884a5c340808b","bd58f503314643659cf9e8a1cef488c9","dda9ef398b524535a68fd6ea11fad818","eca634da59354f1caa467fba3c58c5fc","4b450035de2f401b9e3554a023a3ec65","53d92d965e984ed7afc3496af7d61d70","3d496f12c55645aead4dfe7d0d07dcf0","91b0f76df87a4c56aa5a02943cb28839","c24dd55347c44ee586bab8ee277db7da","3cb6adfc2d764b97b6673765860d47bb","f77c96169250417aad96b5c1d58222f8","f68accd919884dd09190b80513b9646c","e30127ffa4834f609af7939fffe106e8","e6f1a30a76264f7e84e93559d196cb5f","2daa7d0e57fd4e4682ce1adc15b9f84d","4cb1d38e7aec4391b8cd7527ca9febee","d3913b280fba46c4b9053b0e1b7f76fe","c610dd153a364592b786fcdf898c3da3","14fe1f23cc4b4887a5a7d8b987af49eb","7f56d139cd774438be2902f1310d55b6","b24e5e348f604c2fb1359e12f9c1dde1","3b259cdb3ddd4432bd07c36f6145a4de","941510f7665d47f3bda727843f6684ae","85198e7d3abb4492b0cca02083f68a24","143e6c3613d8483d91833a2e13f86fb6","212c95d82afc43a9b849a07cd0193ad6","b3691f5cb09041b5aa88e1caf3a29b20","9ad1e5cabb0d4636a08d306513e63c16","d03fbf56a2934588892fd1bb43739564","491fa386a15f4719bf44fa8e302fd011","fc0380f14a854a6cb040442f98d41000","a3aff0a8b5f4459e872c8a2c05f0226d","d5541144ffea4c418ef5c6c3db1e519e","385f8f44444540af87117059cfec0f5a","816479b548ed4dd99880c862929898fa","ec3cca3523514dc1b21d8d79773cb988","577f895e829e4f9098f600795aa18d08","58e62210fd1c482cb848c00704ee496c","9ca29ee5af0b4f888d2f6c5c011cad7f","a340e132d43a4178b902d6e18cdaa42c","14457502346c40069dda383db7503d76","0f90ecefed3b4b30bff078f97f4a67d7","15a4d0683ce04296ae0426bff451cc06","460853ad40bc474e900544e27d4d8440","041565754c1d4b8188ac80ac296974a3","2567a327e02648e29b2410d406d45217","e892ff1ff8244fb5b4dd1617e7b67bcb","3215c940fe7e485c97a3af8c5dbf8e08","9932bf3222934434baca1a23e649f118","a2ed35e40a0342f1b5209cf2368ec9b8","d35bec09dbe849f9b64a211fd45b80c0","0915b9e3ce76421a8761cc5eaf25e2a7","b6c5b7f105e74dd09000d038b57066e8","d033341173d24e19a5f413ca0a53ce6c","358dfaf8072f4c77aabc4e267e48d833","ea37bd0802504828a90c1d3625e2d39e","b54c98e9b45d4a6391fce48e463488aa","9a1befb039dd4021af786a7cefc7e7fe","d3dc27978259400187c814165ce20091","1a20a2ace0234eca9b4b8f2fc68358b0","215b89c0f4304fb4b2a4642b763f3b8e","d58f6d5a301e4389b4e73b7ae2ef595f","3655dd45e31845cb9cf4bcc1a7572db0","3cd7144832b1489aa0dcdc2eb74da6b4","0f41b180ba3f4e139d00d1d4e41fa808","db7189bed4d04523bafa9267fd5ed194","8ee17913c9124a8f8136f87de059f86f","65f9a631473a4ce989995cfcc84c1388","dd4f665280c1428ea9cb3073d95bc02e"],"resources":{"http://localhost:8080/experiment/cache/Strange_Tales_172005/_crop/Strange_Tales_172005_6_Default,%20grey%20pad.png":{"data":"CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPWVuPgogIDxtZXRhIGNoYXJzZXQ9dXRmLTg+CiAgPG1ldGEgbmFtZT12aWV3cG9ydCBjb250ZW50PSJpbml0aWFsLXNjYWxlPTEsIG1pbmltdW0tc2NhbGU9MSwgd2lkdGg9ZGV2aWNlLXdpZHRoIj4KICA8dGl0bGU+RXJyb3IgNDA0IChOb3QgRm91bmQpISExPC90aXRsZT4KICA8c3R5bGU+CiAgICAqe21hcmdpbjowO3BhZGRpbmc6MH1odG1sLGNvZGV7Zm9udDoxNXB4LzIycHggYXJpYWwsc2Fucy1zZXJpZn1odG1se2JhY2tncm91bmQ6I2ZmZjtjb2xvcjojMjIyO3BhZGRpbmc6MTVweH1ib2R5e21hcmdpbjo3JSBhdXRvIDA7bWF4LXdpZHRoOjM5MHB4O21pbi1oZWlnaHQ6MTgwcHg7cGFkZGluZzozMHB4IDAgMTVweH0qID4gYm9keXtiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9lcnJvcnMvcm9ib3QucG5nKSAxMDAlIDVweCBuby1yZXBlYXQ7cGFkZGluZy1yaWdodDoyMDVweH1we21hcmdpbjoxMXB4IDAgMjJweDtvdmVyZmxvdzpoaWRkZW59aW5ze2NvbG9yOiM3Nzc7dGV4dC1kZWNvcmF0aW9uOm5vbmV9YSBpbWd7Ym9yZGVyOjB9QG1lZGlhIHNjcmVlbiBhbmQgKG1heC13aWR0aDo3NzJweCl7Ym9keXtiYWNrZ3JvdW5kOm5vbmU7bWFyZ2luLXRvcDowO21heC13aWR0aDpub25lO3BhZGRpbmctcmlnaHQ6MH19I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LnBuZykgbm8tcmVwZWF0O21hcmdpbi1sZWZ0Oi01cHh9QG1lZGlhIG9ubHkgc2NyZWVuIGFuZCAobWluLXJlc29sdXRpb246MTkyZHBpKXsjbG9nb3tiYWNrZ3JvdW5kOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSBuby1yZXBlYXQgMCUgMCUvMTAwJSAxMDAlOy1tb3otYm9yZGVyLWltYWdlOnVybCgvL3d3dy5nb29nbGUuY29tL2ltYWdlcy9sb2dvcy9lcnJvcnBhZ2UvZXJyb3JfbG9nby0xNTB4NTQtMngucG5nKSAwfX1AbWVkaWEgb25seSBzY3JlZW4gYW5kICgtd2Via2l0LW1pbi1kZXZpY2UtcGl4ZWwtcmF0aW86Mil7I2xvZ297YmFja2dyb3VuZDp1cmwoLy93d3cuZ29vZ2xlLmNvbS9pbWFnZXMvbG9nb3MvZXJyb3JwYWdlL2Vycm9yX2xvZ28tMTUweDU0LTJ4LnBuZykgbm8tcmVwZWF0Oy13ZWJraXQtYmFja2dyb3VuZC1zaXplOjEwMCUgMTAwJX19I2xvZ297ZGlzcGxheTppbmxpbmUtYmxvY2s7aGVpZ2h0OjU0cHg7d2lkdGg6MTUwcHh9CiAgPC9zdHlsZT4KICA8YSBocmVmPS8vd3d3Lmdvb2dsZS5jb20vPjxzcGFuIGlkPWxvZ28gYXJpYS1sYWJlbD1Hb29nbGU+PC9zcGFuPjwvYT4KICA8cD48Yj40MDQuPC9iPiA8aW5zPlRoYXTigJlzIGFuIGVycm9yLjwvaW5zPgogIDxwPiAgPGlucz5UaGF04oCZcyBhbGwgd2Uga25vdy48L2lucz4K","headers":[["content-length","1449"],["content-type","text/html; charset=utf-8"]],"ok":false,"status":404,"status_text":""}}},"executionInfo":{"elapsed":639,"status":"ok","timestamp":1717165542401,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"GmAca8fVUMUm","outputId":"4042b144-9cfe-43f0-b391-ac8d44b612f8"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"ed7e79b69996433b87d46e466cb48fb6","version_major":2,"version_minor":0},"text/plain":["VBox(children=(HTML(value=\""}},"c24dd55347c44ee586bab8ee277db7da":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_f68accd919884dd09190b80513b9646c","IPY_MODEL_e30127ffa4834f609af7939fffe106e8","IPY_MODEL_e6f1a30a76264f7e84e93559d196cb5f","IPY_MODEL_2daa7d0e57fd4e4682ce1adc15b9f84d"],"layout":"IPY_MODEL_4cb1d38e7aec4391b8cd7527ca9febee"}},"c5431bc93486497faa74330f37d582aa":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c610dd153a364592b786fcdf898c3da3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["method_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_385f8f44444540af87117059cfec0f5a","IPY_MODEL_816479b548ed4dd99880c862929898fa","IPY_MODEL_ec3cca3523514dc1b21d8d79773cb988"],"layout":"IPY_MODEL_577f895e829e4f9098f600795aa18d08"}},"cde5c9e129e443fb9c1c642156bab294":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d033341173d24e19a5f413ca0a53ce6c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50px"}},"d03fbf56a2934588892fd1bb43739564":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d086b7598b4848aaa4eb0ffede5da0f7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_4856c138483c4bc59c165c6f8c81777a","IPY_MODEL_1bffa03a8dfa4d4ba6e0b2cf76f5f0fd","IPY_MODEL_88ee0bfb700a4f369333729d755fbc91"],"layout":"IPY_MODEL_f2b7ff5971bd43b986d810b9261abd1c"}},"d35bec09dbe849f9b64a211fd45b80c0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d3913b280fba46c4b9053b0e1b7f76fe":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["box_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_491fa386a15f4719bf44fa8e302fd011","IPY_MODEL_fc0380f14a854a6cb040442f98d41000","IPY_MODEL_a3aff0a8b5f4459e872c8a2c05f0226d"],"layout":"IPY_MODEL_d5541144ffea4c418ef5c6c3db1e519e"}},"d3dc27978259400187c814165ce20091":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"d5541144ffea4c418ef5c6c3db1e519e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d58f6d5a301e4389b4e73b7ae2ef595f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"none","flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"daabe05918774871ba2f9cba38ca14ff":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"db7189bed4d04523bafa9267fd5ed194":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"120px"}},"dd4f665280c1428ea9cb3073d95bc02e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"dda9ef398b524535a68fd6ea11fad818":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","140192597210928"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_c24dd55347c44ee586bab8ee277db7da","IPY_MODEL_3cb6adfc2d764b97b6673765860d47bb"],"layout":"IPY_MODEL_f77c96169250417aad96b5c1d58222f8"}},"e30127ffa4834f609af7939fffe106e8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","140192597212656"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_941510f7665d47f3bda727843f6684ae"],"layout":"IPY_MODEL_85198e7d3abb4492b0cca02083f68a24"}},"e6f1a30a76264f7e84e93559d196cb5f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","140192597212608"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_143e6c3613d8483d91833a2e13f86fb6"],"layout":"IPY_MODEL_212c95d82afc43a9b849a07cd0193ad6"}},"e72b3672869743e7b8fbbe178a93698a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"e892ff1ff8244fb5b4dd1617e7b67bcb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":"lightblue","font_weight":"bold"}},"ea37bd0802504828a90c1d3625e2d39e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"ec3cca3523514dc1b21d8d79773cb988":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Initial box","Default","Default, grey pad","Padded 4px","Padded 8px","Extracted, init box","Padded 4, extracted","Padded 8, extracted","Padded 8, dilation 1","Pad 8, fract. 0.5","Pad 8, fract. 0.2"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":2,"layout":"IPY_MODEL_1a20a2ace0234eca9b4b8f2fc68358b0","style":"IPY_MODEL_215b89c0f4304fb4b2a4642b763f3b8e"}},"eca634da59354f1caa467fba3c58c5fc":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":["message_visor-yXy"],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_65f9a631473a4ce989995cfcc84c1388","msg_id":"","outputs":[]}},"f1cf213ea11e431c8aded42b1af2536b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"f2b7ff5971bd43b986d810b9261abd1c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f3863102525f488fb74877a54b447c63":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_0b9d514d2d9249f09095065a9e302c49","placeholder":"​","style":"IPY_MODEL_4acbacc0ed4a4c1581583f428b69aff7","value":" 137/137 [00:00<00:00, 13.4kB/s]"}},"f4fd6b82478a444d91242587c0a5045f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f68accd919884dd09190b80513b9646c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","140192597212368"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_b24e5e348f604c2fb1359e12f9c1dde1"],"layout":"IPY_MODEL_3b259cdb3ddd4432bd07c36f6145a4de"}},"f77c96169250417aad96b5c1d58222f8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fc0380f14a854a6cb040442f98d41000":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_0915b9e3ce76421a8761cc5eaf25e2a7","style":"IPY_MODEL_b6c5b7f105e74dd09000d038b57066e8","value":false}},"fd31aabd8e4c4aa8add50c95e55e9d6f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_64b5967a0be04a05aeddda4a1b977531","placeholder":"​","style":"IPY_MODEL_aeb9f955725443f5b2c2f0c54ffb1fc8","value":"Loading checkpoint shards: 100%"}}}}},"nbformat":4,"nbformat_minor":0} +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `PaliGemma` OCR for Comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Settings for Google Colab" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n", + "\n", + "- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n", + "This allows the notebook to access files stored in your Google Drive.\n", + "\n", + "- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n", + "This acts as the root directory for accessing any files within your Google Drive from the notebook.\n", + "\n", + "- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n", + "This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "MOUNT_DRIVE = True\n", + "GDRIVE_MOUNT_POINT = 'drive'\n", + "PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# install (Colab)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "import os\n", + "import re\n", + "import sys\n", + "from pathlib import Path\n", + "\n", + "from rich import print as cprint\n", + "from rich.text import Text\n", + "\n", + "def info(msg: str):\n", + " (t := Text(msg)).stylize(\"bold red\", 0, 6)\n", + " cprint(\"_\" * 10, t, \"_\" * 10)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mount Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n", + "if FC.IN_COLAB:\n", + " if MOUNT_DRIVE:\n", + " if not mnt_point.exists():\n", + " info(\"Mounting Google Drive\")\n", + " from google.colab import drive\n", + " drive.mount(str(mnt_point), force_remount=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install **PanelCleaner**\n", + "\n", + "> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n", + "\n", + "Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_COLAB:\n", + " pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n", + " tb_path = pc_path/'pcleaner/_testbed'\n", + " if tb_path.exists():\n", + " info('Installing PanelCleaner from your Google Drive')\n", + " else:\n", + " info('Installing PanelCleaner from GitHub')\n", + " !rm -rf PanelCleaner\n", + " !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n", + " pc_path = Path('PanelCleaner').absolute()\n", + " tb_path = pc_path/'pcleaner/_testbed'\n", + " assert tb_path.exists(), \"PanelCleaner not found\"\n", + " os.chdir(tb_path)\n", + " sys.path.insert(0, f\"{tb_path}\")\n", + " sys.path.insert(0, f\"{pc_path}\")\n", + " !pip install -q -r requirements-colab.txt\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'4.42.0.dev0'" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "if FC.IN_COLAB:\n", + " !pip install -q accelerate\n", + "\n", + "import transformers\n", + "transformers.__version__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n", + "from testbed.ocr_paligemma import PaliGemmaOCR, get_gpu_vram\n", + "from testbed.helpers import IN_MAC, IN_LINUX\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if IN_MAC:\n", + " # !pip install -q mlx_vlm\n", + "\n", + " import mlx.core as mx\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# GPU" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
          metal.is_available(): True\n",
+       "           metal.device_info(): {'memory_size': 68719476736, 'max_recommended_working_set_size': 51539607552, \n",
+       "'max_buffer_length': 38654705664, 'architecture': 'applegpu_g13s'}\n",
+       "     metal.get_active_memory(): 0\n",
+       "       metal.get_peak_memory(): 0\n",
+       "      metal.get_cache_memory(): 0\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " \u001b[1;35mmetal.is_available\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[3;92mTrue\u001b[0m\n", + " \u001b[1;35mmetal.device_info\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'memory_size'\u001b[0m: \u001b[1;36m68719476736\u001b[0m, \u001b[32m'max_recommended_working_set_size'\u001b[0m: \u001b[1;36m51539607552\u001b[0m, \n", + "\u001b[32m'max_buffer_length'\u001b[0m: \u001b[1;36m38654705664\u001b[0m, \u001b[32m'architecture'\u001b[0m: \u001b[32m'applegpu_g13s'\u001b[0m\u001b[1m}\u001b[0m\n", + " \u001b[1;35mmetal.get_active_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n", + " \u001b[1;35mmetal.get_peak_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n", + " \u001b[1;35mmetal.get_cache_memory\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m: \u001b[1;36m0\u001b[0m\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
            GPU: applegpu_g13s\n",
+       "     total VRAM: 65536 MiB\n",
+       "    active VRAM: 0 MiB\n",
+       "
\n" + ], + "text/plain": [ + " GPU: applegpu_g13s\n", + " total VRAM: \u001b[1;36m65536\u001b[0m MiB\n", + " active VRAM: \u001b[1;36m0\u001b[0m MiB\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "if IN_MAC:\n", + " gpu_name = mx.metal.device_info()['architecture']\n", + " cprint(\n", + " f\"{'metal.is_available()':>30}: {mx.metal.is_available()}\\n\"\n", + " f\"{'metal.device_info()':>30}: {mx.metal.device_info()}\\n\"\n", + " f\"{'metal.get_active_memory()':>30}: {mx.metal.get_active_memory()//1024//1024}\\n\"\n", + " f\"{'metal.get_peak_memory()':>30}: {mx.metal.get_peak_memory()//1024//1024}\\n\"\n", + " f\"{'metal.get_cache_memory()':>30}: {mx.metal.get_cache_memory()//1024//1024}\\n\"\n", + " )\n", + "else:\n", + " !nvidia-smi\n", + " import subprocess\n", + " gpu_name = subprocess.check_output(\n", + " \"nvidia-smi --query-gpu=gpu_name --format=csv,noheader\", shell=True\n", + " ).decode('utf-8').strip()\n", + " \n", + "\n", + "cprint( f\"{'GPU':>15}: {gpu_name}\\n\"\n", + " f\"{'total VRAM':>15}: {get_gpu_vram()} MiB\\n\"\n", + " f\"{'active VRAM':>15}: {get_gpu_vram(False)} MiB\")\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# PaliGemma experiments" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User is already logged in.\n" + ] + } + ], + "source": [ + "from huggingface_hub import notebook_login\n", + "notebook_login(False, False)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Experiment directory" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Directory where the images reside (`EXP_DIR/source/`), the auxiliary images will be cached (`EXP_DIR/cache/`), and the experiment results will be saved. You can change the default location here.\n", + "\n", + "NOTE: the default value assumes we are currently inside `PanelCleaner/pcleaner/_testbed` directory. You can check that is the case with `Path('.').resolve()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n",
+       "Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n",
+       "
\n" + ], + "text/plain": [ + " Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n", + "Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "EXP_DIR = Path('./experiment')\n", + "cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Copy your images to the source directory:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint((EXP_DIR/'source').resolve())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or download the standard set:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !unzip -qn experiment.zip -d ." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Setup ngrok (Colab)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n", + "\n", + "Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n", + "- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n", + "- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n", + "\n", + "You choose.\n", + "\n", + "If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is USE_PIL=False. You can set the environment variable USE_PIL=True to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n", + "\n", + "I you don't change the default settings and\n", + "- the notebook is running locally, it'll serve the images directly without any additional setup.\n", + "- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_COLAB:\n", + " os.environ['USE_TUNNEL'] = 'True'\n", + " os.environ['USE_PIL'] = 'False'\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SERVER = None\n", + "if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n", + " import testbed.web_server as web_server\n", + " SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CONTEXT" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "| quant \\ platform | Mem | Mac | Linux | Windows | Colab T4 | Colab L4/H100 |\n", + "| --- | --- | --- | --- | --- | --- | --- |\n", + "| **bfloat16** | 6 GB | ✅ | ✅ | ? | ✅ | ✅ |\n", + "| **8bit** | 3 GB | ✅ | ✅ | ? | ✅ | ✅ |\n", + "| **4bit** | 2 GB | ✅ | ✅ | ? | ✅ | ✅ |\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Creates the `ExperimentContext` object we'll use to manage the experiments.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: cursor\n", + "Cache Directory: System default\n", + "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", + "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
 config cache_dir: None\n",
+       "       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
+       "           device: 'mps'\n",
+       "
\n" + ], + "text/plain": [ + " config cache_dir: \u001b[3;35mNone\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'mps'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
        force_PIL: False\n",
+       "       use_tunnel: False\n",
+       "       server_url: \n",
+       "   experiment dir: experiment\n",
+       "       source_dir: experiment/source\n",
+       "        cache_dir: experiment/cache\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " force_PIL: \u001b[3;91mFalse\u001b[0m\n", + " use_tunnel: \u001b[3;91mFalse\u001b[0m\n", + " server_url: \n", + " experiment dir: experiment\n", + " source_dir: experiment/source\n", + " cache_dir: experiment/cache\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Experiment runs:\n",
+       "PaliGemma-crop-post: 0\n",
+       "
\n" + ], + "text/plain": [ + "Experiment runs:\n", + "PaliGemma-crop-post: \u001b[1;36m0\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "quant = '8bit' if IN_MAC else 'bfloat16'\n", + "CONTEXT = OCRExperimentContext('PaliGemma', EXP_DIR, quant=quant, \n", + " server=SERVER, run_name='PaliGemma-crop-post', load=True)\n", + "CONTEXT.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6701b0fefb114810a52c202ffb6a4b4d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Fetching 9 files: 0%| | 0/9 [00:00 Size: '224'\n", + " Quantization: '8bit'\n", + " Device: 'mps'\n", + " VRAM: 2986/65536 MiB\n", + "\n", + "\n" + ], + "text/plain": [ + " Size: \u001b[32m'224'\u001b[0m\n", + " Quantization: \u001b[32m'8bit'\u001b[0m\n", + " Device: \u001b[32m'mps'\u001b[0m\n", + " VRAM: \u001b[1;36m2986\u001b[0m/\u001b[1;36m65536\u001b[0m MiB\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "ocr_model = CONTEXT.setup_ocr_model(False)\n", + "ocr_model.show_info()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check the images are in place" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ed7e79b69996433b87d46e466cb48fb6", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HTML(value=\"" + } + }, + "c24dd55347c44ee586bab8ee277db7da": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_f68accd919884dd09190b80513b9646c", + "IPY_MODEL_e30127ffa4834f609af7939fffe106e8", + "IPY_MODEL_e6f1a30a76264f7e84e93559d196cb5f", + "IPY_MODEL_2daa7d0e57fd4e4682ce1adc15b9f84d" + ], + "layout": "IPY_MODEL_4cb1d38e7aec4391b8cd7527ca9febee" + } + }, + "c5431bc93486497faa74330f37d582aa": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "c610dd153a364592b786fcdf898c3da3": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "method_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_385f8f44444540af87117059cfec0f5a", + "IPY_MODEL_816479b548ed4dd99880c862929898fa", + "IPY_MODEL_ec3cca3523514dc1b21d8d79773cb988" + ], + "layout": "IPY_MODEL_577f895e829e4f9098f600795aa18d08" + } + }, + "cde5c9e129e443fb9c1c642156bab294": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "d033341173d24e19a5f413ca0a53ce6c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "50px" + } + }, + "d03fbf56a2934588892fd1bb43739564": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d086b7598b4848aaa4eb0ffede5da0f7": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_4856c138483c4bc59c165c6f8c81777a", + "IPY_MODEL_1bffa03a8dfa4d4ba6e0b2cf76f5f0fd", + "IPY_MODEL_88ee0bfb700a4f369333729d755fbc91" + ], + "layout": "IPY_MODEL_f2b7ff5971bd43b986d810b9261abd1c" + } + }, + "d35bec09dbe849f9b64a211fd45b80c0": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "d3913b280fba46c4b9053b0e1b7f76fe": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "box_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_491fa386a15f4719bf44fa8e302fd011", + "IPY_MODEL_fc0380f14a854a6cb040442f98d41000", + "IPY_MODEL_a3aff0a8b5f4459e872c8a2c05f0226d" + ], + "layout": "IPY_MODEL_d5541144ffea4c418ef5c6c3db1e519e" + } + }, + "d3dc27978259400187c814165ce20091": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "0px" + } + }, + "d5541144ffea4c418ef5c6c3db1e519e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d58f6d5a301e4389b4e73b7ae2ef595f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": "none", + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "daabe05918774871ba2f9cba38ca14ff": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "db7189bed4d04523bafa9267fd5ed194": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "120px" + } + }, + "dd4f665280c1428ea9cb3073d95bc02e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "dda9ef398b524535a68fd6ea11fad818": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "140192597210928" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_c24dd55347c44ee586bab8ee277db7da", + "IPY_MODEL_3cb6adfc2d764b97b6673765860d47bb" + ], + "layout": "IPY_MODEL_f77c96169250417aad96b5c1d58222f8" + } + }, + "e30127ffa4834f609af7939fffe106e8": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "140192597212656" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_941510f7665d47f3bda727843f6684ae" + ], + "layout": "IPY_MODEL_85198e7d3abb4492b0cca02083f68a24" + } + }, + "e6f1a30a76264f7e84e93559d196cb5f": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "140192597212608" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_143e6c3613d8483d91833a2e13f86fb6" + ], + "layout": "IPY_MODEL_212c95d82afc43a9b849a07cd0193ad6" + } + }, + "e72b3672869743e7b8fbbe178a93698a": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "e892ff1ff8244fb5b4dd1617e7b67bcb": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ButtonStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "button_color": "lightblue", + "font_weight": "bold" + } + }, + "ea37bd0802504828a90c1d3625e2d39e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": "0px 0px 0px 10px", + "right": null, + "top": null, + "visibility": null, + "width": "initial" + } + }, + "ec3cca3523514dc1b21d8d79773cb988": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Initial box", + "Default", + "Default, grey pad", + "Padded 4px", + "Padded 8px", + "Extracted, init box", + "Padded 4, extracted", + "Padded 8, extracted", + "Padded 8, dilation 1", + "Pad 8, fract. 0.5", + "Pad 8, fract. 0.2" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 2, + "layout": "IPY_MODEL_1a20a2ace0234eca9b4b8f2fc68358b0", + "style": "IPY_MODEL_215b89c0f4304fb4b2a4642b763f3b8e" + } + }, + "eca634da59354f1caa467fba3c58c5fc": { + "model_module": "@jupyter-widgets/output", + "model_module_version": "1.0.0", + "model_name": "OutputModel", + "state": { + "_dom_classes": [ + "message_visor-yXy" + ], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_65f9a631473a4ce989995cfcc84c1388", + "msg_id": "", + "outputs": [] + } + }, + "f1cf213ea11e431c8aded42b1af2536b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "f2b7ff5971bd43b986d810b9261abd1c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f3863102525f488fb74877a54b447c63": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_0b9d514d2d9249f09095065a9e302c49", + "placeholder": "​", + "style": "IPY_MODEL_4acbacc0ed4a4c1581583f428b69aff7", + "value": " 137/137 [00:00<00:00, 13.4kB/s]" + } + }, + "f4fd6b82478a444d91242587c0a5045f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f68accd919884dd09190b80513b9646c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "140192597212368" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_b24e5e348f604c2fb1359e12f9c1dde1" + ], + "layout": "IPY_MODEL_3b259cdb3ddd4432bd07c36f6145a4de" + } + }, + "f77c96169250417aad96b5c1d58222f8": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fc0380f14a854a6cb040442f98d41000": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "CheckboxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "CheckboxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "CheckboxView", + "description": "all", + "description_tooltip": null, + "disabled": false, + "indent": true, + "layout": "IPY_MODEL_0915b9e3ce76421a8761cc5eaf25e2a7", + "style": "IPY_MODEL_b6c5b7f105e74dd09000d038b57066e8", + "value": false + } + }, + "fd31aabd8e4c4aa8add50c95e55e9d6f": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_64b5967a0be04a05aeddda4a1b977531", + "placeholder": "​", + "style": "IPY_MODEL_aeb9f955725443f5b2c2f0c54ffb1fc8", + "value": "Loading checkpoint shards: 100%" + } + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/pcleaner/_testbed/test_tesseract.ipynb b/pcleaner/_testbed/test_tesseract.ipynb index 4218723c..dd558977 100644 --- a/pcleaner/_testbed/test_tesseract.ipynb +++ b/pcleaner/_testbed/test_tesseract.ipynb @@ -1 +1,3736 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"XLuXdPExZlIq"},"source":["# Testing `Tesseract` OCR for comics\n","> Accuracy Enhancements for OCR in `PanelCleaner`\n"]},{"cell_type":"markdown","metadata":{"id":"1fXVD50hsqi-"},"source":["In this notebook, you can test how Tesseract performs with texts from a diverse array of comics, manga, languages, and styles. You can run this notebook locally using Jupyter Lab/Notebook or on any Jupyter-compatible platform like Google Colab or VSCode.\n","\n","We'll begin by setting up [PanelCleaner](https://github.com/VoxelCubes/PanelCleaner) and the [testbed](https://github.com/civvic/PanelCleaner/tree/testbed) in Colab, though the instructions are applicable to other platforms such as [Kaggle](https://www.kaggle.com/code). We will then verify the Tesseract installation, prime an `ExperimentContext`, and create a visor to experiment with different parameters and configurations. \n","\n","**New to Jupyter Notebooks?** If you are not familiar with Jupyter environments, consider exploring the [Introduction to Colab](https://colab.research.google.com/notebooks/intro.ipynb) and the others provided by Google. It offers a quick and comprehensive guide to using Jupyter Notebooks effectively. The Jupyter project is a great way to learn about the notebook interface and the [Jupyter ecosystem](https://jupyter.org/)."]},{"cell_type":"markdown","metadata":{"id":"3Vz9SEk9sqi-"},"source":["# Settings for Google Colab"]},{"cell_type":"markdown","metadata":{"id":"xCL1cU7csqi-"},"source":["To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n","\n","- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n","This allows the notebook to access files stored in your Google Drive.\n","\n","- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n","This acts as the root directory for accessing any files within your Google Drive from the notebook.\n","\n","- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n","This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n"]},{"cell_type":"code","execution_count":1,"metadata":{"executionInfo":{"elapsed":1,"status":"ok","timestamp":1717161960886,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"NGD253mFsqi-"},"outputs":[],"source":["MOUNT_DRIVE = True\n","GDRIVE_MOUNT_POINT = 'drive'\n","PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'"]},{"cell_type":"markdown","metadata":{"id":"O3mFm2CEsqi_"},"source":["## install (Colab)\n"]},{"cell_type":"code","execution_count":2,"metadata":{"executionInfo":{"elapsed":601,"status":"ok","timestamp":1717161965022,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"YHVrkf__sqi_"},"outputs":[],"source":["import fastcore.all as FC\n","import os\n","import re\n","import sys\n","from pathlib import Path\n","\n","from rich import print as cprint\n","from rich.text import Text\n","\n","def info(msg: str):\n"," (t := Text(msg)).stylize(\"bold red\", 0, 6)\n"," cprint(\"_\" * 10, t, \"_\" * 10)\n"]},{"cell_type":"markdown","metadata":{"id":"G3BUsMaHsqi_"},"source":["Mount Google Drive"]},{"cell_type":"code","execution_count":3,"metadata":{"executionInfo":{"elapsed":775,"status":"ok","timestamp":1717161972478,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"B7II6iVwsqi_"},"outputs":[],"source":["mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n","if FC.IN_COLAB:\n"," if MOUNT_DRIVE:\n"," if not mnt_point.exists():\n"," info(\"Mounting Google Drive\")\n"," from google.colab import drive\n"," drive.mount(str(mnt_point), force_remount=True)\n"]},{"cell_type":"markdown","metadata":{"id":"S5FZkSJTsqi_"},"source":["### Install **PanelCleaner**\n","\n","> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n","\n","Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook."]},{"cell_type":"code","execution_count":4,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":33},"executionInfo":{"elapsed":6546,"status":"ok","timestamp":1717161987090,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"B579RzhEsqi_","outputId":"bc78b076-6852-426b-c8dc-00db6d663ce6"},"outputs":[],"source":["if FC.IN_COLAB:\n"," pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n"," tb_path = pc_path/'pcleaner/_testbed'\n"," if tb_path.exists():\n"," info('Installing PanelCleaner from your Google Drive')\n"," else:\n"," info('Installing PanelCleaner from GitHub')\n"," !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n"," tb_path = Path('PanelCleaner/pcleaner/_testbed')\n"," assert tb_path.exists(), \"PanelCleaner not found\"\n"," os.chdir(tb_path)\n"," sys.path.append(f\"{pc_path}\")\n"," sys.path.append(f\"{tb_path}\")\n"," !pip install -q -r requirements-colab.txt\n"]},{"cell_type":"markdown","metadata":{"id":"ii6CcMw_sqjA"},"source":["# Prologue\n","\n","In this section, we import essential components from the `PanelCleaner` testbed. `ExperimentsVisor` is used to manage and visualize the experiments, `CropMethod` defines the cropping strategies for image preprocessing, and `OCRExperimentContext` sets up the context for OCR experiments.\n","\n","If you're curious about the inner workings of these components, you can explore the notebooks that develop them in the `nbs` folder, or check out the source code they generate in the `testbed` directory. For instance, see [experiments.ipynb](nbs/experiments.ipynb) and [`_testbed/testbed/experiments.py`](testbed/experiments.py) for more details."]},{"cell_type":"code","execution_count":5,"metadata":{"executionInfo":{"elapsed":4572,"status":"ok","timestamp":1717162002282,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"18HJJTQebWoV"},"outputs":[],"source":["from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n"]},{"cell_type":"markdown","metadata":{"id":"rehyLeMbsqjA"},"source":["## Tesseract setup\n","> This section ensures that Tesseract OCR is correctly installed and configured for our experiments. We require Tesseract version 5.x due to its improved accuracy and features.\n"]},{"cell_type":"markdown","metadata":{"id":"bYfWu4DlsqjA"},"source":["> **NOTE:** In the following cells, lines starting with an exclamation mark `!` (also known as a \"bang\") are shell commands. Uncomment these lines if you wish to execute the commands directly from this notebook."]},{"cell_type":"markdown","metadata":{"id":"lbgjGH-FsqjA"},"source":["### Check Current Tesseract Version"]},{"cell_type":"code","execution_count":6,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":33},"executionInfo":{"elapsed":552,"status":"ok","timestamp":1717162009373,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"maVw84ptsqjA","outputId":"574df29a-3c03-491a-b829-3b279ab9d828"},"outputs":[{"data":{"text/html":["
Correct version of Tesseract is installed.\n","
\n"],"text/plain":["Correct version of Tesseract is installed.\n"]},"metadata":{},"output_type":"display_data"}],"source":["import subprocess\n","\n","def check_tesseract_version():\n"," version_output = subprocess.run([\"tesseract\", \"--version\"], capture_output=True, text=True)\n"," if 'tesseract 5.' in version_output.stdout:\n"," cprint(\"Correct version of Tesseract is installed.\")\n"," else:\n"," cprint(\"No version or Incorrect version of Tesseract is installed. Please install Tesseract 5.x.\")\n","\n","check_tesseract_version()"]},{"cell_type":"markdown","metadata":{"id":"G1wnq7N7sqjA"},"source":["### Remove Tesseract installation\n","> I you have the old 4.x version, you should consider removing the installation with the following commands.\n"]},{"cell_type":"markdown","metadata":{"id":"QM9oOtf2sqjA"},"source":["#### Mac (TBD)"]},{"cell_type":"markdown","metadata":{"id":"Qodfe6UIsqjA"},"source":["#### WIndows (TBD)"]},{"cell_type":"markdown","metadata":{"id":"1F-oys3dsqjA"},"source":["#### Ubuntu"]},{"cell_type":"code","execution_count":7,"metadata":{"id":"teXKLm6gsqjA"},"outputs":[],"source":["# !sudo apt-get remove tesseract-ocr\n"]},{"cell_type":"markdown","metadata":{"id":"6KuqPXBrsqjB"},"source":["### Install Tesseract 5.x (if necessary)"]},{"cell_type":"markdown","metadata":{"id":"6-GVVIUvsqjB"},"source":["#### Mac (TBD)"]},{"cell_type":"markdown","metadata":{"id":"xZO3cIMDsqjB"},"source":["#### WIndows (TBD)"]},{"cell_type":"markdown","metadata":{"id":"JKNbHfjBsqjB"},"source":["#### Linux (Ubuntu)"]},{"cell_type":"markdown","metadata":{"id":"u8zjEp0vsqjB"},"source":["The **5.x** release series is available in the [another PPA](https://launchpad.net/~alex-p/+archive/ubuntu/tesseract-ocr5) for Ubuntu **18.04**, **20.04**, and **22.04**.\n"]},{"cell_type":"code","execution_count":8,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":7127,"status":"ok","timestamp":1717159937349,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"mB6zqY-csqjB","outputId":"d7f93490-f50c-4a58-b267-49d44315e143"},"outputs":[],"source":["# !sudo add-apt-repository -y ppa:alex-p/tesseract-ocr5"]},{"cell_type":"markdown","metadata":{"id":"E50Mub5ssqjB"},"source":["refresh system package cache in case you’re still running old Ubuntu 18.04"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"m3Mrt-23sqjB"},"outputs":[],"source":["# !sudo apt update"]},{"cell_type":"markdown","metadata":{"id":"h65xnzb0sqjB"},"source":["install the software engine"]},{"cell_type":"code","execution_count":9,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":7877,"status":"ok","timestamp":1717159957612,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"_IAlFgRzsqjB","outputId":"2c813cc8-2192-425c-dd65-fb390a23b629"},"outputs":[],"source":["# !sudo apt install -y tesseract-ocr"]},{"cell_type":"markdown","metadata":{"id":"RZf_GC5BsqjB"},"source":["\n","### Re-check version after installation"]},{"cell_type":"code","execution_count":9,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":33},"executionInfo":{"elapsed":287,"status":"ok","timestamp":1717159961205,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"YsuiKSX3sqjB","outputId":"ada6dc36-1b3d-4a68-e951-f3f513e07552"},"outputs":[{"data":{"text/html":["
Correct version of Tesseract is installed.\n","
\n"],"text/plain":["Correct version of Tesseract is installed.\n"]},"metadata":{},"output_type":"display_data"}],"source":["check_tesseract_version()\n"]},{"cell_type":"markdown","metadata":{"id":"26wuuPsRsqjB"},"source":["### Install Tesseract languages"]},{"cell_type":"code","execution_count":12,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":65},"executionInfo":{"elapsed":864,"status":"ok","timestamp":1717162041268,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"EcR2B--FsqjB","outputId":"e2bdd940-3c12-4876-de2f-532e85fbf332"},"outputs":[{"data":{"text/html":["
tessdata path: /opt/homebrew/share/tessdata\n","
\n"],"text/plain":["tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Installed languages:\n","[\n","    'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n","    'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n","    'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n","    'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n","    'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n","    'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n","    'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \n","script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n","    'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \n","script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \n","script/Kannada, script/Khmer',\n","    'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \n","script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n","    'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n","    'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\n","]\n","
\n"],"text/plain":["Installed languages:\n","\u001b[1m[\u001b[0m\n"," \u001b[32m'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces'\u001b[0m,\n"," \u001b[32m'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo'\u001b[0m,\n"," \u001b[32m'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc'\u001b[0m,\n"," \u001b[32m'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert'\u001b[0m,\n"," \u001b[32m'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal'\u001b[0m,\n"," \u001b[32m'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol'\u001b[0m,\n"," \u001b[32m'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \u001b[0m\n","\u001b[32mscript/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur'\u001b[0m,\n"," \u001b[32m'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \u001b[0m\n","\u001b[32mscript/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \u001b[0m\n","\u001b[32mscript/Kannada, script/Khmer'\u001b[0m,\n"," \u001b[32m'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \u001b[0m\n","\u001b[32mscript/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk'\u001b[0m,\n"," \u001b[32m'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel'\u001b[0m,\n"," \u001b[32m'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["out = !tesseract --list-langs # type: ignore\n","tessdata = Path(out[0].split('\"')[1])\n","cprint(f\"tessdata path: {tessdata}\")\n","cprint(\"Installed languages:\", [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]])"]},{"cell_type":"markdown","metadata":{"id":"s_ylP5uTsqjB"},"source":["#### Install **best** languages and **jpn_ver** Tesseract lang\n","> to get better results than default langs and `jpn` language model.\n"]},{"cell_type":"markdown","metadata":{"id":"h1kl60ArsqjB"},"source":["Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best). \n","Donwload from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) a model trained for vertical Japanese text as found in manga.\n","\n","See [here](https://tesseract-ocr.github.io/tessdoc/Data-Files-in-different-versions.html) the languages codes.\n","\n","**Note:** While the `jpn` and `jpn_vert` language models are available, the `manga-ocr` model use by `PanelCleaner`is generally more suited for manga text recognition. However, comparing these models can provide educational insights into their respective strengths and limitations."]},{"cell_type":"markdown","metadata":{"id":"Q7WvG7QOsqjB"},"source":["Uncomment and excute to download the best language models:\n"]},{"cell_type":"code","execution_count":10,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":5012,"status":"ok","timestamp":1717159997755,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"PGLGCL-_sqjC","outputId":"75f7bdff-c146-4d18-cf00-ae0f962170cc"},"outputs":[],"source":["# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/osd.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/eng.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn.traineddata\n","\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn_vert.traineddata\n","# or\n","# !wget -O jpn_vert.traineddata https://github.com/zodiac3539/jpn_vert/blob/master/jpn_ver5.traineddata\n","\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/spa.traineddata\n","# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/fra.traineddata"]},{"cell_type":"markdown","metadata":{"id":"q6_QS0sisqjC"},"source":["Copy downloaded models to tessdata folder (double check that `tessdata` variable points to the right folder):\n"]},{"cell_type":"code","execution_count":13,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":33},"executionInfo":{"elapsed":306,"status":"ok","timestamp":1717160002438,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"AqMUxfFZsqjC","outputId":"4677359f-7bc5-4b9d-b668-2efa3c26366f"},"outputs":[{"data":{"text/html":["
tessdata path: /opt/homebrew/share/tessdata\n","
\n"],"text/plain":["tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint(f\"tessdata path: {tessdata}\")"]},{"cell_type":"code","execution_count":13,"metadata":{"executionInfo":{"elapsed":297,"status":"ok","timestamp":1717160012026,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"jgMImPcMsqjC"},"outputs":[],"source":["# !sudo mv *.traineddata $tessdata"]},{"cell_type":"markdown","metadata":{"id":"UWpjzsOVsqjC"},"source":["and remove the downloaded models:\n"]},{"cell_type":"code","execution_count":14,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":329,"status":"ok","timestamp":1717160017466,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"NgXafsP-sqjC","outputId":"08109c93-77a1-4c25-f558-77cd48ecd158"},"outputs":[{"name":"stdout","output_type":"stream","text":["rm: cannot remove '*.traineddata': No such file or directory\n"]}],"source":["# !rm *.traineddata"]},{"cell_type":"markdown","metadata":{"id":"M8wh0Uv9sqjC"},"source":["Check installed languages\n"]},{"cell_type":"code","execution_count":14,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":129},"executionInfo":{"elapsed":703,"status":"ok","timestamp":1717162047846,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"6XYS33DLsqjC","outputId":"ffdce0a8-8344-450f-b835-65fcec5eb11d"},"outputs":[{"data":{"text/html":["
[\n","    Path('/opt/homebrew/share/tessdata/spa.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/eng.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/jpn_vert.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/spa_old.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/fra.traineddata'),\n","    Path('/opt/homebrew/share/tessdata/jpn.traineddata')\n","]\n","
\n"],"text/plain":["\u001b[1m[\u001b[0m\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/eng.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn_vert.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa_old.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/fra.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n"," \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n","\u001b[1m]\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint(list(filter(lambda x: re.match(r'eng|jpn|jpn_vert|fra|spa', x.name), tessdata.ls()))) # type: ignore\n","# cprint(pytesseract.get_languages())\n"]},{"cell_type":"markdown","metadata":{"id":"fErGl5xSZlI5"},"source":["----\n","# Tesseract Experiments\n","\n","In this notebook, we focus on applying Tesseract OCR to a variety of comic book images to evaluate its performance across different text styles, languages, and image qualities. \n","\n","The experiments are specifically designed to explore how different cropping methods affect Tesseract's ability to recognize text in complex visual contexts typical of comic panels. By experimenting with various cropping strategies, we want to determine whether feeding Tesseract single cropped boxes, as opposed to whole pages, can enhance OCR accuracy.\n","\n","## Objectives\n","\n","- **Evaluate basic OCR performance:** Assess how well Tesseract recognizes text across a diverse set of comic book images.\n","- **Test different cropping methods:** Systematically vary the way images are cropped to isolate text boxes and see if this improves the accuracy of text recognition.\n","- **Optimize OCR settings (TBD):** Adjust Tesseract's configuration settings based on the results of the cropping experiments to optimize performance for comic texts.\n"]},{"cell_type":"markdown","metadata":{"id":"op24JaWwfsSv"},"source":["## Experiment directory\n","\n","Defines the directory structure for storing images, caching auxiliary data, and saving experiment results.\n","\n","- **Source Directory (`EXP_DIR/source/`):** This is where the original images for the experiments are stored.\n","- **Cache Directory (`EXP_DIR/cache/`):** This directory is used for caching processed images or other auxiliary files that are generated during the experiments.\n","\n","You can modify the default locations of these directories as needed. The default setup assumes that you are working within the `PanelCleaner/pcleaner/_testbed` directory. Use the following code to verify your current working directory and to set up the experiment directory:\n"]},{"cell_type":"code","execution_count":15,"metadata":{"executionInfo":{"elapsed":560,"status":"ok","timestamp":1717162052233,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"jfMv_sdZfwVY"},"outputs":[],"source":["EXP_DIR = Path('./experiment')\n"]},{"cell_type":"code","execution_count":16,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":49},"executionInfo":{"elapsed":2,"status":"ok","timestamp":1717162052658,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"0_2xxaRBsqjC","outputId":"e35faa83-ebe3-4e65-a12c-3acd4c8276c6"},"outputs":[{"data":{"text/html":["
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n","Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n","
\n"],"text/plain":[" Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n","Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n"]},{"cell_type":"markdown","metadata":{},"source":["# Test images\n","\n","Prepare and manage the comic book images for OCR testing.\n","\n","If you have specific comic book images you want to test, upload them to the `EXP_DIR/source/` directory. Ensure that each image file is accompanied by a corresponding text file containing the ground truth data. The text file should have the same name as the image but with a `.txt` extension. Each line in the text file should represent one text box as detected and processed by PanelCleaner.\n","\n","For those who prefer to use a standardized set of images for comparison purposes, we provide a link to download a pre-selected set of comic book images. After downloading, ensure to place these images in the `EXP_DIR/source/` directory.\n","\n","Optionally, you can include a `.json` file for each image, specifying the language of the text on the page. This file should have the same name as the image and a `.json` extension. Here is an example of the content for a language specification file:\n","\n","```json\n","{\n","\"lang\": \"Spanish\"\n","}\n","```"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[{"data":{"text/html":["
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n","
\n"],"text/plain":["\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["cprint((EXP_DIR/'source').resolve())"]},{"cell_type":"markdown","metadata":{},"source":["or download the standard set:\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":["# !unzip -qn experiment.zip -d ."]},{"cell_type":"markdown","metadata":{"id":"z62cVR57ZlI5"},"source":["# Setup ngrok (Colab)"]},{"cell_type":"markdown","metadata":{"id":"qMAn1mOSZlI5"},"source":["The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n","\n","Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n","- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n","- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n","\n","You choose.\n","\n","If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is `USE_PIL=False`. You can set the environment variable `USE_PIL=True` to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n","\n","I you don't change the default settings and\n","- the notebook is running locally, it'll serve the images directly without any additional setup.\n","- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n"]},{"cell_type":"code","execution_count":17,"metadata":{"executionInfo":{"elapsed":1,"status":"ok","timestamp":1717162054215,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"A0il2cCMZlI5"},"outputs":[],"source":["if FC.IN_COLAB:\n"," os.environ['USE_TUNNEL'] = 'True'\n"," os.environ['USE_PIL'] = 'False'\n"]},{"cell_type":"code","execution_count":18,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":184},"executionInfo":{"elapsed":7100,"status":"ok","timestamp":1717162062654,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"Su0YJikGZlI5","outputId":"39d5db0a-d544-4e84-9e85-c338d94fc2af"},"outputs":[],"source":["SERVER = None\n","if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n"," import testbed.web_server as web_server\n"," SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n"]},{"cell_type":"markdown","metadata":{"id":"GPkPmP7rsqjD"},"source":["# CONTEXT\n","> Creates the `OCRExperimentContext` object we'll use to manage the experiments and visualize the configuration.\n"]},{"cell_type":"code","execution_count":22,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":572},"executionInfo":{"elapsed":45996,"status":"ok","timestamp":1717162125752,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"qhQ3nY1OhgdS","outputId":"962a664b-2d3c-443a-c9b4-09a258762b05"},"outputs":[{"name":"stdout","output_type":"stream","text":["Current Configuration:\n","\n","Locale: System default\n","Default Profile: Built-in\n","Saved Profiles:\n","- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n","- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n","\n","Profile Editor: cursor\n","Cache Directory: System default\n","Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n","Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n","GUI Theme: System default\n","\n","--------------------\n","\n","Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n","System default cache directory: /Users/vic/Library/Caches/pcleaner\n"]},{"data":{"text/html":["
 config cache_dir: None\n","       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n","           device: 'mps'\n","
\n"],"text/plain":[" config cache_dir: \u001b[3;35mNone\u001b[0m\n"," model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n"," device: \u001b[32m'mps'\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
        force_PIL: False\n","       use_tunnel: False\n","       server_url: \n","   experiment dir: experiment\n","       source_dir: experiment/source\n","        cache_dir: experiment/cache\n","\n","
\n"],"text/plain":[" force_PIL: \u001b[3;91mFalse\u001b[0m\n"," use_tunnel: \u001b[3;91mFalse\u001b[0m\n"," server_url: \n"," experiment dir: experiment\n"," source_dir: experiment/source\n"," cache_dir: experiment/cache\n","\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["
Experiment runs:\n","Tesseract-crop-post: 17\n","   Tesseract-crop: 0\n","
\n"],"text/plain":["Experiment runs:\n","Tesseract-crop-post: \u001b[1;36m17\u001b[0m\n"," Tesseract-crop: \u001b[1;36m0\u001b[0m\n"]},"metadata":{},"output_type":"display_data"}],"source":["CONTEXT = OCRExperimentContext('Tesseract', EXP_DIR, server=SERVER, load=True)\n","CONTEXT.show()"]},{"cell_type":"markdown","metadata":{"id":"O-M9uxOosqjD"},"source":["## Verify images setup\n","\n","Before visualizing the experiments, verify that all images are correctly recognized and accessible."]},{"cell_type":"code","execution_count":23,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":510,"status":"ok","timestamp":1717162129784,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"Ha8wqfTHZlI5","outputId":"dde8119f-0629-445e-be47-cce08d725ecb"},"outputs":[{"data":{"text/plain":["['00: Action_Comics_1960-01-00_(262).JPG',\n"," '01: Adolf_Cap_01_008.jpg',\n"," '02: Barnaby_v1-028.png',\n"," '03: Barnaby_v1-029.png',\n"," '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n"," '05: Cannon-292.jpg',\n"," '06: Contrato_con_Dios_028.jpg',\n"," '07: Erase_una_vez_en_Francia_02_88.jpg',\n"," '08: FOX_CHILLINTALES_T17_012.jpg',\n"," '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n"," '10: Galactus_12.jpg',\n"," '11: INOUE_KYOUMEN_002.png',\n"," '12: MCCALL_ROBINHOOD_T31_010.jpg',\n"," '13: MCCAY_LITTLENEMO_090.jpg',\n"," '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n"," '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n"," '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n"," '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n"," '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n"," '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n"," '20: Strange_Tales_172005.jpg',\n"," '21: Strange_Tales_172021.jpg',\n"," '22: Tarzan_014-21.JPG',\n"," '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n"," '24: Transformers_-_Unicron_000-004.jpg',\n"," '25: Transformers_-_Unicron_000-016.jpg',\n"," '26: WARE_ACME_024.jpg',\n"," '27: Yoko_Tsuno_T01_1972-10.jpg',\n"," '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n"," '29: manga_0033.jpg',\n"," '30: ronson-031.jpg',\n"," '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']"]},"execution_count":23,"metadata":{},"output_type":"execute_result"}],"source":["[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n"]},{"cell_type":"markdown","metadata":{"id":"sShEU3dZsqjD"},"source":["----\n","# Running an experiment\n","\n","Conduct an OCR experiment using the established context and tools. You will select an image, choose a cropping method, and decide which text box to analyze. The results will be visualized so you can assess the effectiveness of the OCR process.\n","\n","### Selecting and configuring the experiment\n","\n","1. **Choose an image:** Start by selecting an image from the loaded dataset.\n","2. **Specify cropping method:** Choose how the image should be cropped. Different cropping methods can affect OCR accuracy, as they change how the text is presented to the OCR engine.\n","3. **Select text box:** Select the specific text box within the image to focus the OCR process.\n","\n","### Visualizing results\n","\n","The results are visualized immediately. Here, it is crucial to have accurate **ground truth** data to effectively compare and assess the OCR results.\n","\n","You can assess the accuracy of OCR results at various levels: box by box, method by method, and overall. Currently, we use a simplified version of the `edit distance` metric to calculate accuracy. However, we plan to adopt more standardized metrics, such as the `Levenshtein distance`, in future updates.\n","\n","Additionally, we should probably develop a metric specifically tailored to the unique characteristics of comic texts, such as the prevalence of all-caps and handwritten text, to provide more relevant evaluations. OCR models are trained with typeset text, synthetic or real-world, and business, forms, news or literary data, and usually don't perform well on handwritten text. We haven't found any OCR dataset that incorporates comics style data.\n","\n","\n","### Managing experiment data\n","\n","- **Save results:** You have the option to save the results of the experiment, useful for documenting performance and changes over time. However, be cautious with this option as it will overwrite existing results without confirmation.\n"]},{"cell_type":"markdown","metadata":{"id":"HLSafK7UsqjD"},"source":["> **Note:** This visor functionality is currently a work in progress (WIP). The interface and options are being refined to enhance the experience and provide more robust data management. This section gives you a preliminary look at what we are aiming for with the `testbed` project.\n"]},{"cell_type":"code","execution_count":24,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":291,"referenced_widgets":["6a87fbd3fc6440c5a81a564ac94400cc","01cd556393d643f8bb3fd88c8cd7bb84","48555e1574db42db86f6572e9c888b58","47b4dcc7177b41d1aa69d3918a6e8598","dc75396dcc3c4606a8fe56401d29a4e9","778afca8ec0a431ca8670604c10d8956","e36c1a1c609c425bb76ea83edf910425","27c90e0d46934e80a38889a0ae18a726","60e22ee6a0fc428b8e3709e394e44841","7e8086d63d1b4bbf96e4c70c63bc920a","0d5a810240d84cc683b42f56b1f4c2d1","e1de76477d764776ac5a209f7ebcc8d6","48cfde671ecf42c7a124a94a2962bb66","4064335db7684f2f81ad237513e90c34","99bbf4dd65424e87aab67bcf162a8171","eee81f49e99f4cbb8db65b56c511adbd","d89bf137dd5e4d698dc7f6187f2e148c","3588eeb28e024f1ead6cd21f46d65a6c","b0d6d88a4b824cf9be7c01d5611c3426","39648bdbc39c4c7c827510141663804c","0c28619fcebc4c58a9a756888add9140","fa20ebba2bdb493799524bdf780fa86e","ad2bbb4b23a648209da1edab0006adae","d6fed923432746c9b3dff00549de596d","878477e8708a47e8ab49b00be715d1cd","00878ffbdb234a48b8917563f3058107","57f9b685011043418d9552b3cb48784e","0f1bb59001314b13a091c7e1b331c58b","fb08b9a59d6c4e678b368c915bb97405","4f8b904d91eb44028477a6a61c34af54","90f41682d85f42a6becdca99a59e9a2c","3d0ad04ce06b4314b64dcdde269b38e6","eab60b2fe7a84e4b9a913f1450766452","101d1fc2b6df471ebd6a32a44c8120ed","8ca00801b4e54cbd980c998791664f60","ec3c881e1da4414a9c9499497bc5de74","31dcaeca8806453ea52292112bb0a4f3","e13c49f50ebd4f81a1dafe940ac13a31","1da81d9a8d7446838b76ae017e794e78","a2410f8101384beda0114d93ac655edb","24e8764bfd294a629d6c3855b4094f8b","18ccc64fc8504bdeb2fb07043688c1c4","6eed00e28fae4570b2348330bb9dcbab","bd6e62f7db8c40d695d6ca3d93cf7e94","068b8601d7364d29b9598b80aeb782e0","fbb4d3433c6f42e094934b6936659b8f","3cf7099443124d289495da41bfbc8b58","3ab779d3f50a456980527636aa763dba","bb3adfcd8e4a4af29079953bc9220ac1","919da88097344a689a9afb6fa5977b29","d0ed39572cea4c37bb07dc99577258e3","496e8548fc0f41b7b0c15c5881596326","df9bb4a390fa4e6597b832d09949d24e","4aba84bf7b4847fdb1cac927ba6a7ebf","f542dba5c6de48a0a44e698706d87017","df77be57fe7943298432a759e6ce8416","8b38a0bdf80149bba72324232beb14ed","0d4014b56e93430e9782502bf29c7c2e","58b2ec779ab64a2b9e85d57160b453c9","44f79f7ea58742a0a770aab41e876c9c","57f7d34ddc2b4a938d7fcb4bf066deb0","f40fbbd396ac4528a97962ec911d5837","03b66d0eb8b5487b8ad21382b93cc68d","bfa2f19eedfa4bd99b59d08365ae4676","a7755ebc78f34335a32f75fa342fcd76","0e3ae88bc86f4a31b5aedc1dfd0b1bf2","929913d45cc9400087eab703338d00f0","c193eb8285a740208457bbe7985d356f","ee44cc3dae5c42299460702dd280dbce","9a49e8c567b94a64a19dc3eecdf5a857","25cdb8370f70459886e00eeef0f66388","175e7409479d4f56ba4a4faf4c8bebaa","c944b093296248b4a9a75a9139d5003d","72440081608048b1b5fc76e42011ad0c","247e8a63e98441f294c1514a43b35e0d","7a928ad4bd52422b9544d0d312402a5b","3f8e2f6b025e4fcd90ad34c2e99025ae","044d11e5bc4e4f87ad9d099734418899","dcc0c0ee6a284ecb8c40f06891919805","1807cf3a1770434599e993a087293d91"]},"executionInfo":{"elapsed":837,"status":"ok","timestamp":1717162136971,"user":{"displayName":"Vicente Sosa","userId":"11884045517174046483"},"user_tz":-120},"id":"TZIA3E3jZlI5","outputId":"734f248f-a720-4a65-e2ca-a8e70a2f20d5"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"c3ed154f58e6480abe8993b4a2fc22b7","version_major":2,"version_minor":0},"text/plain":["VBox(children=(HTML(value=\""}},"03b66d0eb8b5487b8ad21382b93cc68d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"044d11e5bc4e4f87ad9d099734418899":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"068b8601d7364d29b9598b80aeb782e0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0c28619fcebc4c58a9a756888add9140":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["model_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_a2410f8101384beda0114d93ac655edb"],"layout":"IPY_MODEL_24e8764bfd294a629d6c3855b4094f8b"}},"0d4014b56e93430e9782502bf29c7c2e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"initial"}},"0d5a810240d84cc683b42f56b1f4c2d1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0e3ae88bc86f4a31b5aedc1dfd0b1bf2":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"120px"}},"0f1bb59001314b13a091c7e1b331c58b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"reset","disabled":false,"icon":"","layout":"IPY_MODEL_3ab779d3f50a456980527636aa763dba","style":"IPY_MODEL_bb3adfcd8e4a4af29079953bc9220ac1","tooltip":""}},"101d1fc2b6df471ebd6a32a44c8120ed":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_df77be57fe7943298432a759e6ce8416","placeholder":"​","style":"IPY_MODEL_8b38a0bdf80149bba72324232beb14ed","value":"Method:"}},"175e7409479d4f56ba4a4faf4c8bebaa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_3f8e2f6b025e4fcd90ad34c2e99025ae","max":11,"min":0,"orientation":"horizontal","style":"IPY_MODEL_044d11e5bc4e4f87ad9d099734418899","value":11}},"1807cf3a1770434599e993a087293d91":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"18ccc64fc8504bdeb2fb07043688c1c4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"25em"}},"1da81d9a8d7446838b76ae017e794e78":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"247e8a63e98441f294c1514a43b35e0d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"24e8764bfd294a629d6c3855b4094f8b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"25cdb8370f70459886e00eeef0f66388":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_247e8a63e98441f294c1514a43b35e0d","placeholder":"​","style":"IPY_MODEL_7a928ad4bd52422b9544d0d312402a5b","value":"Box #1: 100%"}},"27c90e0d46934e80a38889a0ae18a726":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"31dcaeca8806453ea52292112bb0a4f3":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"3588eeb28e024f1ead6cd21f46d65a6c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["method_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_101d1fc2b6df471ebd6a32a44c8120ed","IPY_MODEL_8ca00801b4e54cbd980c998791664f60","IPY_MODEL_ec3c881e1da4414a9c9499497bc5de74"],"layout":"IPY_MODEL_31dcaeca8806453ea52292112bb0a4f3"}},"39648bdbc39c4c7c827510141663804c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"visible","width":null}},"3ab779d3f50a456980527636aa763dba":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":"0px 0px 0px 3em","max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"5em"}},"3cf7099443124d289495da41bfbc8b58":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":"lightblue","font_weight":"bold"}},"3d0ad04ce06b4314b64dcdde269b38e6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"BoundedIntTextModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"BoundedIntTextModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"IntTextView","continuous_update":false,"description":"","description_tooltip":null,"disabled":false,"layout":"IPY_MODEL_4aba84bf7b4847fdb1cac927ba6a7ebf","max":14,"min":0,"step":1,"style":"IPY_MODEL_f542dba5c6de48a0a44e698706d87017","value":2}},"3f8e2f6b025e4fcd90ad34c2e99025ae":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4064335db7684f2f81ad237513e90c34":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420256"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_878477e8708a47e8ab49b00be715d1cd"],"layout":"IPY_MODEL_00878ffbdb234a48b8917563f3058107"}},"44f79f7ea58742a0a770aab41e876c9c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"150px"}},"47b4dcc7177b41d1aa69d3918a6e8598":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":["message_visor-yXy"],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_c193eb8285a740208457bbe7985d356f","msg_id":"","outputs":[]}},"48555e1574db42db86f6572e9c888b58":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":["context-visor","137612216365504"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_60e22ee6a0fc428b8e3709e394e44841","IPY_MODEL_7e8086d63d1b4bbf96e4c70c63bc920a"],"layout":"IPY_MODEL_0d5a810240d84cc683b42f56b1f4c2d1"}},"48cfde671ecf42c7a124a94a2962bb66":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420208"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_ad2bbb4b23a648209da1edab0006adae"],"layout":"IPY_MODEL_d6fed923432746c9b3dff00549de596d"}},"496e8548fc0f41b7b0c15c5881596326":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"initial"}},"4aba84bf7b4847fdb1cac927ba6a7ebf":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"50px"}},"4f8b904d91eb44028477a6a61c34af54":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"LabelModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"LabelModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"LabelView","description":"","description_tooltip":null,"layout":"IPY_MODEL_919da88097344a689a9afb6fa5977b29","placeholder":"​","style":"IPY_MODEL_d0ed39572cea4c37bb07dc99577258e3","value":"Box # (of 15):"}},"57f7d34ddc2b4a938d7fcb4bf066deb0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"57f9b685011043418d9552b3cb48784e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"","description":"save","disabled":false,"icon":"","layout":"IPY_MODEL_fbb4d3433c6f42e094934b6936659b8f","style":"IPY_MODEL_3cf7099443124d289495da41bfbc8b58","tooltip":""}},"58b2ec779ab64a2b9e85d57160b453c9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"60e22ee6a0fc428b8e3709e394e44841":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e1de76477d764776ac5a209f7ebcc8d6","IPY_MODEL_48cfde671ecf42c7a124a94a2962bb66","IPY_MODEL_4064335db7684f2f81ad237513e90c34","IPY_MODEL_99bbf4dd65424e87aab67bcf162a8171"],"layout":"IPY_MODEL_eee81f49e99f4cbb8db65b56c511adbd"}},"6a87fbd3fc6440c5a81a564ac94400cc":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_01cd556393d643f8bb3fd88c8cd7bb84","IPY_MODEL_48555e1574db42db86f6572e9c888b58","IPY_MODEL_47b4dcc7177b41d1aa69d3918a6e8598","IPY_MODEL_dc75396dcc3c4606a8fe56401d29a4e9"],"layout":"IPY_MODEL_778afca8ec0a431ca8670604c10d8956"}},"6eed00e28fae4570b2348330bb9dcbab":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"72440081608048b1b5fc76e42011ad0c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":null}},"778afca8ec0a431ca8670604c10d8956":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"7a928ad4bd52422b9544d0d312402a5b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"7e8086d63d1b4bbf96e4c70c63bc920a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175421024"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_d89bf137dd5e4d698dc7f6187f2e148c","IPY_MODEL_3588eeb28e024f1ead6cd21f46d65a6c","IPY_MODEL_b0d6d88a4b824cf9be7c01d5611c3426"],"layout":"IPY_MODEL_39648bdbc39c4c7c827510141663804c"}},"878477e8708a47e8ab49b00be715d1cd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["display_option_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_bd6e62f7db8c40d695d6ca3d93cf7e94"],"layout":"IPY_MODEL_068b8601d7364d29b9598b80aeb782e0"}},"8b38a0bdf80149bba72324232beb14ed":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"8ca00801b4e54cbd980c998791664f60":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_0d4014b56e93430e9782502bf29c7c2e","style":"IPY_MODEL_58b2ec779ab64a2b9e85d57160b453c9","value":false}},"90f41682d85f42a6becdca99a59e9a2c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"CheckboxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"CheckboxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"CheckboxView","description":"all","description_tooltip":null,"disabled":false,"indent":true,"layout":"IPY_MODEL_496e8548fc0f41b7b0c15c5881596326","style":"IPY_MODEL_df9bb4a390fa4e6597b832d09949d24e","value":false}},"919da88097344a689a9afb6fa5977b29":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"929913d45cc9400087eab703338d00f0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"99bbf4dd65424e87aab67bcf162a8171":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175414976"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_57f9b685011043418d9552b3cb48784e","IPY_MODEL_0f1bb59001314b13a091c7e1b331c58b"],"layout":"IPY_MODEL_fb08b9a59d6c4e678b368c915bb97405"}},"9a49e8c567b94a64a19dc3eecdf5a857":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_25cdb8370f70459886e00eeef0f66388","IPY_MODEL_175e7409479d4f56ba4a4faf4c8bebaa","IPY_MODEL_c944b093296248b4a9a75a9139d5003d"],"layout":"IPY_MODEL_72440081608048b1b5fc76e42011ad0c"}},"a2410f8101384beda0114d93ac655edb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Tesseract-crop-post","Tesseract-crop"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":0,"layout":"IPY_MODEL_bfa2f19eedfa4bd99b59d08365ae4676","style":"IPY_MODEL_a7755ebc78f34335a32f75fa342fcd76"}},"a7755ebc78f34335a32f75fa342fcd76":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"ad2bbb4b23a648209da1edab0006adae":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Action_Comics_1960-01-00_(262)","Adolf_Cap_01_008","Barnaby_v1-028","Barnaby_v1-029","Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013","Cannon-292","Contrato_con_Dios_028","Erase_una_vez_en_Francia_02_88","FOX_CHILLINTALES_T17_012","Furari_-_Jiro_Taniguchi_selma_056","Galactus_12","INOUE_KYOUMEN_002","MCCALL_ROBINHOOD_T31_010","MCCAY_LITTLENEMO_090","Mary_Perkins_On_Stage_v2006_1_-_P00068","PIKE_BOYLOVEGIRLS_T41_012","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K","Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2","Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024","Strange_Tales_172005","Strange_Tales_172021","Tarzan_014-21","Tintin_21_Les_Bijoux_de_la_Castafiore_page_39","Transformers_-_Unicron_000-004","Transformers_-_Unicron_000-016","WARE_ACME_024","Yoko_Tsuno_T01_1972-10","Your_Name_Another_Side_Earthbound_T02_084","manga_0033","ronson-031","哀心迷図のバベル 第01巻 - 22002_00_059"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":14,"layout":"IPY_MODEL_18ccc64fc8504bdeb2fb07043688c1c4","style":"IPY_MODEL_6eed00e28fae4570b2348330bb9dcbab"}},"b0d6d88a4b824cf9be7c01d5611c3426":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420544"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e13c49f50ebd4f81a1dafe940ac13a31"],"layout":"IPY_MODEL_1da81d9a8d7446838b76ae017e794e78"}},"bb3adfcd8e4a4af29079953bc9220ac1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":null,"font_weight":"bold"}},"bd6e62f7db8c40d695d6ca3d93cf7e94":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Boxes","Image","Mask","Image & Mask","Page data","Ground truth","Image All","Results","Best results","Accuracy","Dataframe","Config"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":7,"layout":"IPY_MODEL_0e3ae88bc86f4a31b5aedc1dfd0b1bf2","style":"IPY_MODEL_929913d45cc9400087eab703338d00f0"}},"bfa2f19eedfa4bd99b59d08365ae4676":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"fit-content"}},"c193eb8285a740208457bbe7985d356f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c944b093296248b4a9a75a9139d5003d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_dcc0c0ee6a284ecb8c40f06891919805","placeholder":"​","style":"IPY_MODEL_1807cf3a1770434599e993a087293d91","value":" 11/11 [00:04<00:00,  2.10it/s]"}},"d0ed39572cea4c37bb07dc99577258e3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d6fed923432746c9b3dff00549de596d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d89bf137dd5e4d698dc7f6187f2e148c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["box_grp"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_4f8b904d91eb44028477a6a61c34af54","IPY_MODEL_90f41682d85f42a6becdca99a59e9a2c","IPY_MODEL_3d0ad04ce06b4314b64dcdde269b38e6"],"layout":"IPY_MODEL_eab60b2fe7a84e4b9a913f1450766452"}},"dc75396dcc3c4606a8fe56401d29a4e9":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_ee44cc3dae5c42299460702dd280dbce","msg_id":"","outputs":[{"data":{"text/html":"
Maybe... but l tn certainly wouldn't feel right holding back tip money!
0.96
\n
\n
Maybe ... but I⎕⎕⎕ certainly wouldn't feel right holding back tip money!

Maybe... but l tn certainly wouldn't feel right holding back tip money!
","text/plain":""},"metadata":{},"output_type":"display_data"}]}},"dcc0c0ee6a284ecb8c40f06891919805":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"df77be57fe7943298432a759e6ce8416":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":"0px 0px 0px 10px","right":null,"top":null,"visibility":null,"width":"initial"}},"df9bb4a390fa4e6597b832d09949d24e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"0px"}},"e13c49f50ebd4f81a1dafe940ac13a31":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":["wrapper-spinner"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_f40fbbd396ac4528a97962ec911d5837","placeholder":"​","style":"IPY_MODEL_03b66d0eb8b5487b8ad21382b93cc68d","value":"\n
\n
\n
\n "}},"e1de76477d764776ac5a209f7ebcc8d6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":["context-visor","137612175420016"],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_0c28619fcebc4c58a9a756888add9140"],"layout":"IPY_MODEL_fa20ebba2bdb493799524bdf780fa86e"}},"e36c1a1c609c425bb76ea83edf910425":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"eab60b2fe7a84e4b9a913f1450766452":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"ec3c881e1da4414a9c9499497bc5de74":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Initial box","Default","Default, grey pad","Padded 4px","Padded 8px","Extracted, init box","Padded 4, extracted","Padded 8, extracted","Padded 8, dilation 1","Pad 8, fract. 0.5","Pad 8, fract. 0.2"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"","description_tooltip":null,"disabled":false,"index":1,"layout":"IPY_MODEL_44f79f7ea58742a0a770aab41e876c9c","style":"IPY_MODEL_57f7d34ddc2b4a938d7fcb4bf066deb0"}},"ee44cc3dae5c42299460702dd280dbce":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"eee81f49e99f4cbb8db65b56c511adbd":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f40fbbd396ac4528a97962ec911d5837":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"none","flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f542dba5c6de48a0a44e698706d87017":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":"initial"}},"fa20ebba2bdb493799524bdf780fa86e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fb08b9a59d6c4e678b368c915bb97405":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fbb4d3433c6f42e094934b6936659b8f":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"4em"}}}}},"nbformat":4,"nbformat_minor":0} +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Testing `Tesseract` OCR for comics\n", + "> Accuracy Enhancements for OCR in `PanelCleaner`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this notebook, you can test how Tesseract performs with texts from a diverse array of comics, manga, languages, and styles. You can run this notebook locally using Jupyter Lab/Notebook or on any Jupyter-compatible platform like Google Colab or VSCode.\n", + "\n", + "We'll begin by setting up [PanelCleaner](https://github.com/VoxelCubes/PanelCleaner) and the [testbed](https://github.com/civvic/PanelCleaner/tree/testbed) in Colab, though the instructions are applicable to other platforms such as [Kaggle](https://www.kaggle.com/code). We will then verify the Tesseract installation, prime an `ExperimentContext`, and create a visor to experiment with different parameters and configurations. \n", + "\n", + "**New to Jupyter Notebooks?** If you are not familiar with Jupyter environments, consider exploring the [Introduction to Colab](https://colab.research.google.com/notebooks/intro.ipynb) and the others provided by Google. It offers a quick and comprehensive guide to using Jupyter Notebooks effectively. The Jupyter project is a great way to learn about the notebook interface and the [Jupyter ecosystem](https://jupyter.org/)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Settings for Google Colab" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To efficiently manage the image sources for our experiments, we recommend mounting your Google Drive and storing the experiment files there. If you are not familiar with Colab or Jupyter environments, it's best to leave these settings at their default values to ensure smooth operation.\n", + "\n", + "- Set `MOUNT_DRIVE` to `True` to enable mounting Google Drive in the Colab environment.\n", + "This allows the notebook to access files stored in your Google Drive.\n", + "\n", + "- `GDRIVE_MOUNT_POINT` specifies the local directory in Colab where your Google Drive will be mounted.\n", + "This acts as the root directory for accessing any files within your Google Drive from the notebook.\n", + "\n", + "- `PANELCLEANER_IN_GDRIVE` specifies the path within your Google Drive where the PanelCleaner project is located.\n", + "This path is used to access or store any files related to the PanelCleaner project directly from Google Drive.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "MOUNT_DRIVE = True\n", + "GDRIVE_MOUNT_POINT = 'drive'\n", + "PANELCLEANER_IN_GDRIVE = 'MyDrive/Shared/PanelCleaner'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## install (Colab)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import fastcore.all as FC\n", + "import os\n", + "import re\n", + "import sys\n", + "from pathlib import Path\n", + "\n", + "from rich import print as cprint\n", + "from rich.text import Text\n", + "\n", + "def info(msg: str):\n", + " (t := Text(msg)).stylize(\"bold red\", 0, 6)\n", + " cprint(\"_\" * 10, t, \"_\" * 10)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mount Google Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mnt_point = Path(f\"/content/{GDRIVE_MOUNT_POINT}\")\n", + "if FC.IN_COLAB:\n", + " if MOUNT_DRIVE:\n", + " if not mnt_point.exists():\n", + " info(\"Mounting Google Drive\")\n", + " from google.colab import drive\n", + " drive.mount(str(mnt_point), force_remount=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install **PanelCleaner**\n", + "\n", + "> We will attempt to use the version of **PanelCleaner** stored in your Google Drive. If it's not available, we'll install it from GitHub.\n", + "\n", + "Note that we specifically require the `testbed` branch of the **PanelCleaner** repository, not the main trunk. This branch contains necessary configurations and experimental features that are crucial for the tests conducted in this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_COLAB:\n", + " pc_path = mnt_point/PANELCLEANER_IN_GDRIVE\n", + " tb_path = pc_path/'pcleaner/_testbed'\n", + " if tb_path.exists():\n", + " info('Installing PanelCleaner from your Google Drive')\n", + " else:\n", + " info('Installing PanelCleaner from GitHub')\n", + " !rm -rf PanelCleaner\n", + " !git clone -b testbed https://github.com/civvic/PanelCleaner.git\n", + " pc_path = Path('PanelCleaner').absolute()\n", + " tb_path = pc_path/'pcleaner/_testbed'\n", + " assert tb_path.exists(), \"PanelCleaner not found\"\n", + " os.chdir(tb_path)\n", + " sys.path.insert(0, f\"{tb_path}\")\n", + " sys.path.insert(0, f\"{pc_path}\")\n", + " !pip install -q -r requirements-colab.txt\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Prologue\n", + "\n", + "In this section, we import essential components from the `PanelCleaner` testbed. `ExperimentsVisor` is used to manage and visualize the experiments, `CropMethod` defines the cropping strategies for image preprocessing, and `OCRExperimentContext` sets up the context for OCR experiments.\n", + "\n", + "If you're curious about the inner workings of these components, you can explore the notebooks that develop them in the `nbs` folder, or check out the source code they generate in the `testbed` directory. For instance, see [experiments.ipynb](nbs/experiments.ipynb) and [`_testbed/testbed/experiments.py`](testbed/experiments.py) for more details." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from testbed.experiments import ExperimentsVisor, CropMethod, OCRExperimentContext\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Tesseract setup\n", + "> This section ensures that Tesseract OCR is correctly installed and configured for our experiments. We require Tesseract version 5.x due to its improved accuracy and features.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> **NOTE:** In the following cells, lines starting with an exclamation mark `!` (also known as a \"bang\") are shell commands. Uncomment these lines if you wish to execute the commands directly from this notebook." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Check Current Tesseract Version" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Correct version of Tesseract is installed.\n",
+       "
\n" + ], + "text/plain": [ + "Correct version of Tesseract is installed.\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import subprocess\n", + "\n", + "def check_tesseract_version():\n", + " version_output = subprocess.run([\"tesseract\", \"--version\"], capture_output=True, text=True)\n", + " if 'tesseract 5.' in version_output.stdout:\n", + " cprint(\"Correct version of Tesseract is installed.\")\n", + " else:\n", + " cprint(\"No version or Incorrect version of Tesseract is installed. Please install Tesseract 5.x.\")\n", + "\n", + "check_tesseract_version()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Remove Tesseract installation\n", + "> I you have the old 4.x version, you should consider removing the installation with the following commands.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Mac (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### WIndows (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Ubuntu" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo apt-get remove tesseract-ocr\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install Tesseract 5.x (if necessary)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Mac (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### WIndows (TBD)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Linux (Ubuntu)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The **5.x** release series is available in the [another PPA](https://launchpad.net/~alex-p/+archive/ubuntu/tesseract-ocr5) for Ubuntu **18.04**, **20.04**, and **22.04**.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo add-apt-repository -y ppa:alex-p/tesseract-ocr5" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "refresh system package cache in case you’re still running old Ubuntu 18.04" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo apt update" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "install the software engine" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo apt install -y tesseract-ocr" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### Re-check version after installation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Correct version of Tesseract is installed.\n",
+       "
\n" + ], + "text/plain": [ + "Correct version of Tesseract is installed.\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "check_tesseract_version()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Install Tesseract languages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
tessdata path: /opt/homebrew/share/tessdata\n",
+       "
\n" + ], + "text/plain": [ + "tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Installed languages:\n",
+       "[\n",
+       "    'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces',\n",
+       "    'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo',\n",
+       "    'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc',\n",
+       "    'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert',\n",
+       "    'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal',\n",
+       "    'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol',\n",
+       "    'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \n",
+       "script/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur',\n",
+       "    'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \n",
+       "script/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \n",
+       "script/Kannada, script/Khmer',\n",
+       "    'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \n",
+       "script/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk',\n",
+       "    'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel',\n",
+       "    'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "Installed languages:\n", + "\u001b[1m[\u001b[0m\n", + " \u001b[32m'afr, amh, ara, asm, aze, aze_cyrl, bel, ben, bod, bos, bre, bul, cat, ceb, ces'\u001b[0m,\n", + " \u001b[32m'chi_sim, chi_sim_vert, chi_tra, chi_tra_vert, chr, cos, cym, dan, deu, div, dzo, ell, eng, enm, epo'\u001b[0m,\n", + " \u001b[32m'equ, est, eus, fao, fas, fil, fin, fra, frk, frm, fry, gla, gle, glg, grc'\u001b[0m,\n", + " \u001b[32m'guj, hat, heb, hin, hrv, hun, hye, iku, ind, isl, ita, ita_old, jav, jpn, jpn_vert'\u001b[0m,\n", + " \u001b[32m'kan, kat, kat_old, kaz, khm, kir, kmr, kor, kor_vert, lao, lat, lav, lit, ltz, mal'\u001b[0m,\n", + " \u001b[32m'mar, mkd, mlt, mon, mri, msa, mya, nep, nld, nor, oci, ori, osd, pan, pol'\u001b[0m,\n", + " \u001b[32m'por, pus, que, ron, rus, san, script/Arabic, script/Armenian, script/Bengali, script/Canadian_Aboriginal, \u001b[0m\n", + "\u001b[32mscript/Cherokee, script/Cyrillic, script/Devanagari, script/Ethiopic, script/Fraktur'\u001b[0m,\n", + " \u001b[32m'script/Georgian, script/Greek, script/Gujarati, script/Gurmukhi, script/HanS, script/HanS_vert, script/HanT, \u001b[0m\n", + "\u001b[32mscript/HanT_vert, script/Hangul, script/Hangul_vert, script/Hebrew, script/Japanese, script/Japanese_vert, \u001b[0m\n", + "\u001b[32mscript/Kannada, script/Khmer'\u001b[0m,\n", + " \u001b[32m'script/Lao, script/Latin, script/Malayalam, script/Myanmar, script/Oriya, script/Sinhala, script/Syriac, \u001b[0m\n", + "\u001b[32mscript/Tamil, script/Telugu, script/Thaana, script/Thai, script/Tibetan, script/Vietnamese, sin, slk'\u001b[0m,\n", + " \u001b[32m'slv, snd, snum, spa, spa_old, sqi, srp, srp_latn, sun, swa, swe, syr, tam, tat, tel'\u001b[0m,\n", + " \u001b[32m'tgk, tha, tir, ton, tur, uig, ukr, urd, uzb, uzb_cyrl, vie, yid, yor'\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "out = !tesseract --list-langs # type: ignore\n", + "tessdata = Path(out[0].split('\"')[1])\n", + "cprint(f\"tessdata path: {tessdata}\")\n", + "cprint(\"Installed languages:\", [', '.join(sub) for sub in [out[i:i + 15] for i in range(1, len(out), 15)]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Install **best** languages and **jpn_ver** Tesseract lang\n", + "> to get better results than default langs and `jpn` language model.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Download from [tessdata_best](https://github.com/tesseract-ocr/tessdata_best). \n", + "Donwload from [here](https://groups.google.com/g/tesseract-ocr/c/FwjSZzoVgeg/m/u-zyFYQiBgAJ) a model trained for vertical Japanese text as found in manga.\n", + "\n", + "See [here](https://tesseract-ocr.github.io/tessdoc/Data-Files-in-different-versions.html) the languages codes.\n", + "\n", + "**Note:** While the `jpn` and `jpn_vert` language models are available, the `manga-ocr` model use by `PanelCleaner`is generally more suited for manga text recognition. However, comparing these models can provide educational insights into their respective strengths and limitations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Uncomment and excute to download the best language models:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/osd.traineddata\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/eng.traineddata\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn.traineddata\n", + "\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/jpn_vert.traineddata\n", + "# or\n", + "# !wget -O jpn_vert.traineddata https://github.com/zodiac3539/jpn_vert/blob/master/jpn_ver5.traineddata\n", + "\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/spa.traineddata\n", + "# !wget https://raw.githubusercontent.com/tesseract-ocr/tessdata_best/main/fra.traineddata" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Copy downloaded models to tessdata folder (double check that `tessdata` variable points to the right folder):\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
tessdata path: /opt/homebrew/share/tessdata\n",
+       "
\n" + ], + "text/plain": [ + "tessdata path: \u001b[35m/opt/homebrew/share/\u001b[0m\u001b[95mtessdata\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint(f\"tessdata path: {tessdata}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !sudo mv *.traineddata $tessdata" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and remove the downloaded models:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "rm: cannot remove '*.traineddata': No such file or directory\n" + ] + } + ], + "source": [ + "# !rm *.traineddata" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Check installed languages\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n",
+       "    Path('/opt/homebrew/share/tessdata/spa.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/eng.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/jpn_vert.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/spa_old.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/fra.traineddata'),\n",
+       "    Path('/opt/homebrew/share/tessdata/jpn.traineddata')\n",
+       "]\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/eng.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn_vert.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/spa_old.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/fra.traineddata'\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/opt/homebrew/share/tessdata/jpn.traineddata'\u001b[0m\u001b[1m)\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint(list(filter(lambda x: re.match(r'eng|jpn|jpn_vert|fra|spa', x.name), tessdata.ls()))) # type: ignore\n", + "# cprint(pytesseract.get_languages())\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Tesseract Experiments\n", + "\n", + "In this notebook, we focus on applying Tesseract OCR to a variety of comic book images to evaluate its performance across different text styles, languages, and image qualities. \n", + "\n", + "The experiments are specifically designed to explore how different cropping methods affect Tesseract's ability to recognize text in complex visual contexts typical of comic panels. By experimenting with various cropping strategies, we want to determine whether feeding Tesseract single cropped boxes, as opposed to whole pages, can enhance OCR accuracy.\n", + "\n", + "## Objectives\n", + "\n", + "- **Evaluate basic OCR performance:** Assess how well Tesseract recognizes text across a diverse set of comic book images.\n", + "- **Test different cropping methods:** Systematically vary the way images are cropped to isolate text boxes and see if this improves the accuracy of text recognition.\n", + "- **Optimize OCR settings (TBD):** Adjust Tesseract's configuration settings based on the results of the cropping experiments to optimize performance for comic texts.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Experiment directory\n", + "\n", + "Defines the directory structure for storing images, caching auxiliary data, and saving experiment results.\n", + "\n", + "- **Source Directory (`EXP_DIR/source/`):** This is where the original images for the experiments are stored.\n", + "- **Cache Directory (`EXP_DIR/cache/`):** This directory is used for caching processed images or other auxiliary files that are generated during the experiments.\n", + "\n", + "You can modify the default locations of these directories as needed. The default setup assumes that you are working within the `PanelCleaner/pcleaner/_testbed` directory. Use the following code to verify your current working directory and to set up the experiment directory:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "EXP_DIR = Path('./experiment')\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
    Working dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed\n",
+       "Experiments dir: /Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment\n",
+       "
\n" + ], + "text/plain": [ + " Working dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/\u001b[0m\u001b[95m_testbed\u001b[0m\n", + "Experiments dir: \u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/\u001b[0m\u001b[95mexperiment\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint(f\"{'Working dir':>15}: {Path('.').resolve()}\\nExperiments dir: {EXP_DIR.resolve()}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test images\n", + "\n", + "Prepare and manage the comic book images for OCR testing.\n", + "\n", + "If you have specific comic book images you want to test, upload them to the `EXP_DIR/source/` directory. Ensure that each image file is accompanied by a corresponding text file containing the ground truth data. The text file should have the same name as the image but with a `.txt` extension. Each line in the text file should represent one text box as detected and processed by PanelCleaner.\n", + "\n", + "For those who prefer to use a standardized set of images for comparison purposes, we provide a link to download a pre-selected set of comic book images. After downloading, ensure to place these images in the `EXP_DIR/source/` directory.\n", + "\n", + "Optionally, you can include a `.json` file for each image, specifying the language of the text on the page. This file should have the same name as the image and a `.json` extension. Here is an example of the content for a language specification file:\n", + "\n", + "```json\n", + "{\n", + "\"lang\": \"Spanish\"\n", + "}\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/source\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[35m/Users/vic/dev/repo/DL-mac/PanelCleaner/pcleaner/_testbed/experiment/\u001b[0m\u001b[95msource\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "cprint((EXP_DIR/'source').resolve())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or download the standard set:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !gdown --id 1MCqUImwFS5iQ271CD9_t2FSugJXdYj0a -O experiment.zip" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# !unzip -qn experiment.zip -d ." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Setup ngrok (Colab)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The experiments can generate hundreds of images, and maintaining the **PIL** images in memory is not efficient. All the generated images are cached and visualized on demand through a URL pointing to the local cache. This approach prevents the kernel from being overloaded with **PIL** images, with the front-end responsible for fetching the image and the backend web server (not the kernel) for serving the image in another process. This method is quick and efficient. As an added bonus, the saved notebook remains lean and fit; it doesn't store the Base64 versions of all the output cell images.\n", + "\n", + "Unfortunately, this approach does not work as is in **Colab**. Google Colab runs on an older Ubuntu 18.04 VM, so all the usual networking challenges with Docker, or whatever VMs Google is using, apply. Google also goes to great lengths to avoid exposing its internal architecture. We have two options:\n", + "- Let the Jupyter kernel serve the images itself, which is slow and memory-consuming.\n", + "- Use a tunnel to map localhost (server) to whatever IP and port the front-end (the browser you're currently using) is running on. We can use **ngrok** for this, but *ngrok* is a commercial service that has been abused and now requires confirmation the first time the tunnel connects, which can be inconvenient for the user. It also requires the user to open a free account and obtain an auth token.\n", + "\n", + "You choose.\n", + "\n", + "If the notebook is running in Colab and ngrok has been successfully installed and the tunnel has been created, the default setting is `USE_PIL=False`. You can set the environment variable `USE_PIL=True` to force the use of PIL images, but note that in certain circumstances, Colab will complain because the free tiers are usually memory constrained.\n", + "\n", + "I you don't change the default settings and\n", + "- the notebook is running locally, it'll serve the images directly without any additional setup.\n", + "- the notebook is running in Colab, it'll serve the images through a web server and ngrok.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if FC.IN_COLAB:\n", + " os.environ['USE_TUNNEL'] = 'True'\n", + " os.environ['USE_PIL'] = 'False'\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SERVER = None\n", + "if os.environ['USE_PIL'].lower() == 'false' and os.environ['USE_TUNNEL'].lower() == 'true':\n", + " import testbed.web_server as web_server\n", + " SERVER = web_server.setup_ngrok(web_server.WebServerBottle, Path(EXP_DIR))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CONTEXT\n", + "> Creates the `OCRExperimentContext` object we'll use to manage the experiments and visualize the configuration.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current Configuration:\n", + "\n", + "Locale: System default\n", + "Default Profile: Built-in\n", + "Saved Profiles:\n", + "- victess: /Users/vic/dev/repo/DL-mac/cleaned/victess.conf\n", + "- vicmang: /Users/vic/dev/repo/DL-mac/cleaned/vicmang.conf\n", + "\n", + "Profile Editor: cursor\n", + "Cache Directory: System default\n", + "Default Torch Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt\n", + "Default CV2 Model Path: /Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt.onnx\n", + "GUI Theme: System default\n", + "\n", + "--------------------\n", + "\n", + "Config file located at: /Users/vic/Library/Application Support/pcleaner/pcleanerconfig.ini\n", + "System default cache directory: /Users/vic/Library/Caches/pcleaner\n" + ] + }, + { + "data": { + "text/html": [ + "
 config cache_dir: None\n",
+       "       model_path: Path('/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt')\n",
+       "           device: 'mps'\n",
+       "
\n" + ], + "text/plain": [ + " config cache_dir: \u001b[3;35mNone\u001b[0m\n", + " model_path: \u001b[1;35mPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/Users/vic/Library/Caches/pcleaner/model/comictextdetector.pt'\u001b[0m\u001b[1m)\u001b[0m\n", + " device: \u001b[32m'mps'\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
        force_PIL: False\n",
+       "       use_tunnel: False\n",
+       "       server_url: \n",
+       "   experiment dir: experiment\n",
+       "       source_dir: experiment/source\n",
+       "        cache_dir: experiment/cache\n",
+       "\n",
+       "
\n" + ], + "text/plain": [ + " force_PIL: \u001b[3;91mFalse\u001b[0m\n", + " use_tunnel: \u001b[3;91mFalse\u001b[0m\n", + " server_url: \n", + " experiment dir: experiment\n", + " source_dir: experiment/source\n", + " cache_dir: experiment/cache\n", + "\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "
Experiment runs:\n",
+       "Tesseract-crop-post: 17\n",
+       "   Tesseract-crop: 0\n",
+       "
\n" + ], + "text/plain": [ + "Experiment runs:\n", + "Tesseract-crop-post: \u001b[1;36m17\u001b[0m\n", + " Tesseract-crop: \u001b[1;36m0\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "CONTEXT = OCRExperimentContext('Tesseract', EXP_DIR, server=SERVER, load=True)\n", + "CONTEXT.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Verify images setup\n", + "\n", + "Before visualizing the experiments, verify that all images are correctly recognized and accessible." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['00: Action_Comics_1960-01-00_(262).JPG',\n", + " '01: Adolf_Cap_01_008.jpg',\n", + " '02: Barnaby_v1-028.png',\n", + " '03: Barnaby_v1-029.png',\n", + " '04: Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013.jpg',\n", + " '05: Cannon-292.jpg',\n", + " '06: Contrato_con_Dios_028.jpg',\n", + " '07: Erase_una_vez_en_Francia_02_88.jpg',\n", + " '08: FOX_CHILLINTALES_T17_012.jpg',\n", + " '09: Furari_-_Jiro_Taniguchi_selma_056.jpg',\n", + " '10: Galactus_12.jpg',\n", + " '11: INOUE_KYOUMEN_002.png',\n", + " '12: MCCALL_ROBINHOOD_T31_010.jpg',\n", + " '13: MCCAY_LITTLENEMO_090.jpg',\n", + " '14: Mary_Perkins_On_Stage_v2006_1_-_P00068.jpg',\n", + " '15: PIKE_BOYLOVEGIRLS_T41_012.jpg',\n", + " '16: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1.png',\n", + " '17: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K.png',\n", + " '18: Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2.png',\n", + " '19: Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024.jpg',\n", + " '20: Strange_Tales_172005.jpg',\n", + " '21: Strange_Tales_172021.jpg',\n", + " '22: Tarzan_014-21.JPG',\n", + " '23: Tintin_21_Les_Bijoux_de_la_Castafiore_page_39.jpg',\n", + " '24: Transformers_-_Unicron_000-004.jpg',\n", + " '25: Transformers_-_Unicron_000-016.jpg',\n", + " '26: WARE_ACME_024.jpg',\n", + " '27: Yoko_Tsuno_T01_1972-10.jpg',\n", + " '28: Your_Name_Another_Side_Earthbound_T02_084.jpg',\n", + " '29: manga_0033.jpg',\n", + " '30: ronson-031.jpg',\n", + " '31: 哀心迷図のバベル 第01巻 - 22002_00_059.jpg']" + ] + }, + "execution_count": null, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[f\"{i:02}: {_.name}\" for i,_ in enumerate(CONTEXT.image_paths)]\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "----\n", + "# Running an experiment\n", + "\n", + "Conduct an OCR experiment using the established context and tools. You will select an image, choose a cropping method, and decide which text box to analyze. The results will be visualized so you can assess the effectiveness of the OCR process.\n", + "\n", + "### Selecting and configuring the experiment\n", + "\n", + "1. **Choose an image:** Start by selecting an image from the loaded dataset.\n", + "2. **Specify cropping method:** Choose how the image should be cropped. Different cropping methods can affect OCR accuracy, as they change how the text is presented to the OCR engine.\n", + "3. **Select text box:** Select the specific text box within the image to focus the OCR process.\n", + "\n", + "### Visualizing results\n", + "\n", + "The results are visualized immediately. Here, it is crucial to have accurate **ground truth** data to effectively compare and assess the OCR results.\n", + "\n", + "You can assess the accuracy of OCR results at various levels: box by box, method by method, and overall. Currently, we use a simplified version of the `edit distance` metric to calculate accuracy. However, we plan to adopt more standardized metrics, such as the `Levenshtein distance`, in future updates.\n", + "\n", + "Additionally, we should probably develop a metric specifically tailored to the unique characteristics of comic texts, such as the prevalence of all-caps and handwritten text, to provide more relevant evaluations. OCR models are trained with typeset text, synthetic or real-world, and business, forms, news or literary data, and usually don't perform well on handwritten text. We haven't found any OCR dataset that incorporates comics style data.\n", + "\n", + "\n", + "### Managing experiment data\n", + "\n", + "- **Save results:** You have the option to save the results of the experiment, useful for documenting performance and changes over time. However, be cautious with this option as it will overwrite existing results without confirmation.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> **Note:** This visor functionality is currently a work in progress (WIP). The interface and options are being refined to enhance the experience and provide more robust data management. This section gives you a preliminary look at what we are aiming for with the `testbed` project.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c3ed154f58e6480abe8993b4a2fc22b7", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(HTML(value=\"" + } + }, + "03b66d0eb8b5487b8ad21382b93cc68d": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "044d11e5bc4e4f87ad9d099734418899": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ProgressStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ProgressStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "bar_color": null, + "description_width": "" + } + }, + "068b8601d7364d29b9598b80aeb782e0": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "0c28619fcebc4c58a9a756888add9140": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "model_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_a2410f8101384beda0114d93ac655edb" + ], + "layout": "IPY_MODEL_24e8764bfd294a629d6c3855b4094f8b" + } + }, + "0d4014b56e93430e9782502bf29c7c2e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "initial" + } + }, + "0d5a810240d84cc683b42f56b1f4c2d1": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "0e3ae88bc86f4a31b5aedc1dfd0b1bf2": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "120px" + } + }, + "0f1bb59001314b13a091c7e1b331c58b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ButtonModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ButtonView", + "button_style": "", + "description": "reset", + "disabled": false, + "icon": "", + "layout": "IPY_MODEL_3ab779d3f50a456980527636aa763dba", + "style": "IPY_MODEL_bb3adfcd8e4a4af29079953bc9220ac1", + "tooltip": "" + } + }, + "101d1fc2b6df471ebd6a32a44c8120ed": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "LabelModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "LabelModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "LabelView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_df77be57fe7943298432a759e6ce8416", + "placeholder": "​", + "style": "IPY_MODEL_8b38a0bdf80149bba72324232beb14ed", + "value": "Method:" + } + }, + "175e7409479d4f56ba4a4faf4c8bebaa": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "FloatProgressModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "FloatProgressModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ProgressView", + "bar_style": "", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_3f8e2f6b025e4fcd90ad34c2e99025ae", + "max": 11, + "min": 0, + "orientation": "horizontal", + "style": "IPY_MODEL_044d11e5bc4e4f87ad9d099734418899", + "value": 11 + } + }, + "1807cf3a1770434599e993a087293d91": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "18ccc64fc8504bdeb2fb07043688c1c4": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "25em" + } + }, + "1da81d9a8d7446838b76ae017e794e78": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "247e8a63e98441f294c1514a43b35e0d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "24e8764bfd294a629d6c3855b4094f8b": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "25cdb8370f70459886e00eeef0f66388": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_247e8a63e98441f294c1514a43b35e0d", + "placeholder": "​", + "style": "IPY_MODEL_7a928ad4bd52422b9544d0d312402a5b", + "value": "Box #1: 100%" + } + }, + "27c90e0d46934e80a38889a0ae18a726": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "31dcaeca8806453ea52292112bb0a4f3": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "3588eeb28e024f1ead6cd21f46d65a6c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "method_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_101d1fc2b6df471ebd6a32a44c8120ed", + "IPY_MODEL_8ca00801b4e54cbd980c998791664f60", + "IPY_MODEL_ec3c881e1da4414a9c9499497bc5de74" + ], + "layout": "IPY_MODEL_31dcaeca8806453ea52292112bb0a4f3" + } + }, + "39648bdbc39c4c7c827510141663804c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": "visible", + "width": null + } + }, + "3ab779d3f50a456980527636aa763dba": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": "0px 0px 0px 3em", + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "5em" + } + }, + "3cf7099443124d289495da41bfbc8b58": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ButtonStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "button_color": "lightblue", + "font_weight": "bold" + } + }, + "3d0ad04ce06b4314b64dcdde269b38e6": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "BoundedIntTextModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "BoundedIntTextModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "IntTextView", + "continuous_update": false, + "description": "", + "description_tooltip": null, + "disabled": false, + "layout": "IPY_MODEL_4aba84bf7b4847fdb1cac927ba6a7ebf", + "max": 14, + "min": 0, + "step": 1, + "style": "IPY_MODEL_f542dba5c6de48a0a44e698706d87017", + "value": 2 + } + }, + "3f8e2f6b025e4fcd90ad34c2e99025ae": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4064335db7684f2f81ad237513e90c34": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137612175420256" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_878477e8708a47e8ab49b00be715d1cd" + ], + "layout": "IPY_MODEL_00878ffbdb234a48b8917563f3058107" + } + }, + "44f79f7ea58742a0a770aab41e876c9c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "150px" + } + }, + "47b4dcc7177b41d1aa69d3918a6e8598": { + "model_module": "@jupyter-widgets/output", + "model_module_version": "1.0.0", + "model_name": "OutputModel", + "state": { + "_dom_classes": [ + "message_visor-yXy" + ], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_c193eb8285a740208457bbe7985d356f", + "msg_id": "", + "outputs": [] + } + }, + "48555e1574db42db86f6572e9c888b58": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137612216365504" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_60e22ee6a0fc428b8e3709e394e44841", + "IPY_MODEL_7e8086d63d1b4bbf96e4c70c63bc920a" + ], + "layout": "IPY_MODEL_0d5a810240d84cc683b42f56b1f4c2d1" + } + }, + "48cfde671ecf42c7a124a94a2962bb66": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137612175420208" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_ad2bbb4b23a648209da1edab0006adae" + ], + "layout": "IPY_MODEL_d6fed923432746c9b3dff00549de596d" + } + }, + "496e8548fc0f41b7b0c15c5881596326": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "initial" + } + }, + "4aba84bf7b4847fdb1cac927ba6a7ebf": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "50px" + } + }, + "4f8b904d91eb44028477a6a61c34af54": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "LabelModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "LabelModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "LabelView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_919da88097344a689a9afb6fa5977b29", + "placeholder": "​", + "style": "IPY_MODEL_d0ed39572cea4c37bb07dc99577258e3", + "value": "Box # (of 15):" + } + }, + "57f7d34ddc2b4a938d7fcb4bf066deb0": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "57f9b685011043418d9552b3cb48784e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ButtonModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ButtonView", + "button_style": "", + "description": "save", + "disabled": false, + "icon": "", + "layout": "IPY_MODEL_fbb4d3433c6f42e094934b6936659b8f", + "style": "IPY_MODEL_3cf7099443124d289495da41bfbc8b58", + "tooltip": "" + } + }, + "58b2ec779ab64a2b9e85d57160b453c9": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "0px" + } + }, + "60e22ee6a0fc428b8e3709e394e44841": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_e1de76477d764776ac5a209f7ebcc8d6", + "IPY_MODEL_48cfde671ecf42c7a124a94a2962bb66", + "IPY_MODEL_4064335db7684f2f81ad237513e90c34", + "IPY_MODEL_99bbf4dd65424e87aab67bcf162a8171" + ], + "layout": "IPY_MODEL_eee81f49e99f4cbb8db65b56c511adbd" + } + }, + "6a87fbd3fc6440c5a81a564ac94400cc": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_01cd556393d643f8bb3fd88c8cd7bb84", + "IPY_MODEL_48555e1574db42db86f6572e9c888b58", + "IPY_MODEL_47b4dcc7177b41d1aa69d3918a6e8598", + "IPY_MODEL_dc75396dcc3c4606a8fe56401d29a4e9" + ], + "layout": "IPY_MODEL_778afca8ec0a431ca8670604c10d8956" + } + }, + "6eed00e28fae4570b2348330bb9dcbab": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "72440081608048b1b5fc76e42011ad0c": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": "hidden", + "width": null + } + }, + "778afca8ec0a431ca8670604c10d8956": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "7a928ad4bd52422b9544d0d312402a5b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "7e8086d63d1b4bbf96e4c70c63bc920a": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137612175421024" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_d89bf137dd5e4d698dc7f6187f2e148c", + "IPY_MODEL_3588eeb28e024f1ead6cd21f46d65a6c", + "IPY_MODEL_b0d6d88a4b824cf9be7c01d5611c3426" + ], + "layout": "IPY_MODEL_39648bdbc39c4c7c827510141663804c" + } + }, + "878477e8708a47e8ab49b00be715d1cd": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "display_option_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_bd6e62f7db8c40d695d6ca3d93cf7e94" + ], + "layout": "IPY_MODEL_068b8601d7364d29b9598b80aeb782e0" + } + }, + "8b38a0bdf80149bba72324232beb14ed": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "8ca00801b4e54cbd980c998791664f60": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "CheckboxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "CheckboxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "CheckboxView", + "description": "all", + "description_tooltip": null, + "disabled": false, + "indent": true, + "layout": "IPY_MODEL_0d4014b56e93430e9782502bf29c7c2e", + "style": "IPY_MODEL_58b2ec779ab64a2b9e85d57160b453c9", + "value": false + } + }, + "90f41682d85f42a6becdca99a59e9a2c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "CheckboxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "CheckboxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "CheckboxView", + "description": "all", + "description_tooltip": null, + "disabled": false, + "indent": true, + "layout": "IPY_MODEL_496e8548fc0f41b7b0c15c5881596326", + "style": "IPY_MODEL_df9bb4a390fa4e6597b832d09949d24e", + "value": false + } + }, + "919da88097344a689a9afb6fa5977b29": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": "0px 0px 0px 10px", + "right": null, + "top": null, + "visibility": null, + "width": "initial" + } + }, + "929913d45cc9400087eab703338d00f0": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "99bbf4dd65424e87aab67bcf162a8171": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137612175414976" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_57f9b685011043418d9552b3cb48784e", + "IPY_MODEL_0f1bb59001314b13a091c7e1b331c58b" + ], + "layout": "IPY_MODEL_fb08b9a59d6c4e678b368c915bb97405" + } + }, + "9a49e8c567b94a64a19dc3eecdf5a857": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_25cdb8370f70459886e00eeef0f66388", + "IPY_MODEL_175e7409479d4f56ba4a4faf4c8bebaa", + "IPY_MODEL_c944b093296248b4a9a75a9139d5003d" + ], + "layout": "IPY_MODEL_72440081608048b1b5fc76e42011ad0c" + } + }, + "a2410f8101384beda0114d93ac655edb": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Tesseract-crop-post", + "Tesseract-crop" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 0, + "layout": "IPY_MODEL_bfa2f19eedfa4bd99b59d08365ae4676", + "style": "IPY_MODEL_a7755ebc78f34335a32f75fa342fcd76" + } + }, + "a7755ebc78f34335a32f75fa342fcd76": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "ad2bbb4b23a648209da1edab0006adae": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Action_Comics_1960-01-00_(262)", + "Adolf_Cap_01_008", + "Barnaby_v1-028", + "Barnaby_v1-029", + "Buck_Danny_-_12_-_Avions_Sans_Pilotes_-_013", + "Cannon-292", + "Contrato_con_Dios_028", + "Erase_una_vez_en_Francia_02_88", + "FOX_CHILLINTALES_T17_012", + "Furari_-_Jiro_Taniguchi_selma_056", + "Galactus_12", + "INOUE_KYOUMEN_002", + "MCCALL_ROBINHOOD_T31_010", + "MCCAY_LITTLENEMO_090", + "Mary_Perkins_On_Stage_v2006_1_-_P00068", + "PIKE_BOYLOVEGIRLS_T41_012", + "Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1", + "Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_1_K", + "Sal_Buscema_Spaceknights_&_Superheroes_Ocular_Edition_1_2", + "Spirou_Et_Fantasio_Integrale_06_1958_1959_0025_0024", + "Strange_Tales_172005", + "Strange_Tales_172021", + "Tarzan_014-21", + "Tintin_21_Les_Bijoux_de_la_Castafiore_page_39", + "Transformers_-_Unicron_000-004", + "Transformers_-_Unicron_000-016", + "WARE_ACME_024", + "Yoko_Tsuno_T01_1972-10", + "Your_Name_Another_Side_Earthbound_T02_084", + "manga_0033", + "ronson-031", + "哀心迷図のバベル 第01巻 - 22002_00_059" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 14, + "layout": "IPY_MODEL_18ccc64fc8504bdeb2fb07043688c1c4", + "style": "IPY_MODEL_6eed00e28fae4570b2348330bb9dcbab" + } + }, + "b0d6d88a4b824cf9be7c01d5611c3426": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137612175420544" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_e13c49f50ebd4f81a1dafe940ac13a31" + ], + "layout": "IPY_MODEL_1da81d9a8d7446838b76ae017e794e78" + } + }, + "bb3adfcd8e4a4af29079953bc9220ac1": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ButtonStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "button_color": null, + "font_weight": "bold" + } + }, + "bd6e62f7db8c40d695d6ca3d93cf7e94": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Boxes", + "Image", + "Mask", + "Image & Mask", + "Page data", + "Ground truth", + "Image All", + "Results", + "Best results", + "Accuracy", + "Dataframe", + "Config" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 7, + "layout": "IPY_MODEL_0e3ae88bc86f4a31b5aedc1dfd0b1bf2", + "style": "IPY_MODEL_929913d45cc9400087eab703338d00f0" + } + }, + "bfa2f19eedfa4bd99b59d08365ae4676": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "fit-content" + } + }, + "c193eb8285a740208457bbe7985d356f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "c944b093296248b4a9a75a9139d5003d": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_dcc0c0ee6a284ecb8c40f06891919805", + "placeholder": "​", + "style": "IPY_MODEL_1807cf3a1770434599e993a087293d91", + "value": " 11/11 [00:04<00:00,  2.10it/s]" + } + }, + "d0ed39572cea4c37bb07dc99577258e3": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "d6fed923432746c9b3dff00549de596d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "d89bf137dd5e4d698dc7f6187f2e148c": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "box_grp" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_4f8b904d91eb44028477a6a61c34af54", + "IPY_MODEL_90f41682d85f42a6becdca99a59e9a2c", + "IPY_MODEL_3d0ad04ce06b4314b64dcdde269b38e6" + ], + "layout": "IPY_MODEL_eab60b2fe7a84e4b9a913f1450766452" + } + }, + "dc75396dcc3c4606a8fe56401d29a4e9": { + "model_module": "@jupyter-widgets/output", + "model_module_version": "1.0.0", + "model_name": "OutputModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_ee44cc3dae5c42299460702dd280dbce", + "msg_id": "", + "outputs": [ + { + "data": { + "text/html": "
Maybe... but l tn certainly wouldn't feel right holding back tip money!
0.96
\n
\n
Maybe ... but I⎕⎕⎕ certainly wouldn't feel right holding back tip money!

Maybe... but l tn certainly wouldn't feel right holding back tip money!
", + "text/plain": "" + }, + "metadata": {}, + "output_type": "display_data" + } + ] + } + }, + "dcc0c0ee6a284ecb8c40f06891919805": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "df77be57fe7943298432a759e6ce8416": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": "0px 0px 0px 10px", + "right": null, + "top": null, + "visibility": null, + "width": "initial" + } + }, + "df9bb4a390fa4e6597b832d09949d24e": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "0px" + } + }, + "e13c49f50ebd4f81a1dafe940ac13a31": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HTMLModel", + "state": { + "_dom_classes": [ + "wrapper-spinner" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HTMLModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HTMLView", + "description": "", + "description_tooltip": null, + "layout": "IPY_MODEL_f40fbbd396ac4528a97962ec911d5837", + "placeholder": "​", + "style": "IPY_MODEL_03b66d0eb8b5487b8ad21382b93cc68d", + "value": "\n
\n
\n
\n " + } + }, + "e1de76477d764776ac5a209f7ebcc8d6": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "HBoxModel", + "state": { + "_dom_classes": [ + "context-visor", + "137612175420016" + ], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "HBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "HBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_0c28619fcebc4c58a9a756888add9140" + ], + "layout": "IPY_MODEL_fa20ebba2bdb493799524bdf780fa86e" + } + }, + "e36c1a1c609c425bb76ea83edf910425": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "eab60b2fe7a84e4b9a913f1450766452": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "ec3c881e1da4414a9c9499497bc5de74": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Initial box", + "Default", + "Default, grey pad", + "Padded 4px", + "Padded 8px", + "Extracted, init box", + "Padded 4, extracted", + "Padded 8, extracted", + "Padded 8, dilation 1", + "Pad 8, fract. 0.5", + "Pad 8, fract. 0.2" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "", + "description_tooltip": null, + "disabled": false, + "index": 1, + "layout": "IPY_MODEL_44f79f7ea58742a0a770aab41e876c9c", + "style": "IPY_MODEL_57f7d34ddc2b4a938d7fcb4bf066deb0" + } + }, + "ee44cc3dae5c42299460702dd280dbce": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "eee81f49e99f4cbb8db65b56c511adbd": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f40fbbd396ac4528a97962ec911d5837": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": "none", + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "f542dba5c6de48a0a44e698706d87017": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "initial" + } + }, + "fa20ebba2bdb493799524bdf780fa86e": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fb08b9a59d6c4e678b368c915bb97405": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "fbb4d3433c6f42e094934b6936659b8f": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": "4em" + } + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From 473a47425ec4d6e126303fe44f7566175a9a2329 Mon Sep 17 00:00:00 2001 From: Voxel <41875513+VoxelCubes@users.noreply.github.com> Date: Sun, 2 Jun 2024 18:22:37 +0200 Subject: [PATCH 27/27] Revert "Downgrade to Python 10 as Colab not yet support 11" This reverts commit a2d15f4f3996378a33b4943547a6a0063c5bea7a. --- pcleaner/config.py | 19 +++++++------------ pcleaner/gui/profile_parser.py | 2 +- pcleaner/preprocessor.py | 12 ++++++------ pcleaner/structures.py | 4 ++-- 4 files changed, 16 insertions(+), 21 deletions(-) diff --git a/pcleaner/config.py b/pcleaner/config.py index 4d4add4d..1a3066f3 100644 --- a/pcleaner/config.py +++ b/pcleaner/config.py @@ -72,17 +72,13 @@ Percentage = NewType("Percentage", float) -class EnumStr_(Enum): - @classmethod - def display_names(cls) -> dict[str, 'EnumStr_']: - return {e.value: e for e in cls} - -class ReadingOrder(EnumStr_): +class ReadingOrder(StrEnum): AUTO = "auto" MANGA = "manga" COMIC = "comic" -class OCREngine(EnumStr_): + +class OCREngine(StrEnum): AUTO = "auto" MANGAOCR = "manga-ocr" TESSERACT = "tesseract" @@ -1313,14 +1309,13 @@ def try_to_load( return # check before: `StrEnum` is a `str` - elif isinstance(attr_type, type) and issubclass(attr_type, EnumStr_): - names = attr_type.display_names() - if conf_data in names: # type: ignore - attr_value = names[conf_data] + elif isinstance(attr_type, type) and issubclass(attr_type, StrEnum): + if conf_data in attr_type.__members__.values(): + attr_value = conf_data else: print( f"Option {attr_name} in section {section} should be a one " - f"of {', '.join(_.value for _ in attr_type)}.\n" + f"of {', '.join(repr(str(_)) for _ in attr_type.__members__.values())}.\n" f"Failed to parse '{conf_data}'" ) return diff --git a/pcleaner/gui/profile_parser.py b/pcleaner/gui/profile_parser.py index 9aaa48e2..4af9d5bb 100644 --- a/pcleaner/gui/profile_parser.py +++ b/pcleaner/gui/profile_parser.py @@ -206,7 +206,7 @@ def _get_text() -> str | None: enm = {EntryTypes.OCREngine: OCREngine, EntryTypes.ReadingOrder: ReadingOrder}[ entry_type ] - for member in enm: + for member in enm.__members__.values(): self._data_widget.addTextItemLinkedData(member.value, member) self._data_widget.setCurrentIndexByLinkedData(enm.AUTO) self._data_widget.currentIndexChanged.connect(self._value_changed) diff --git a/pcleaner/preprocessor.py b/pcleaner/preprocessor.py index c15cd251..0f43ac3e 100644 --- a/pcleaner/preprocessor.py +++ b/pcleaner/preprocessor.py @@ -130,15 +130,15 @@ def prep_json_file( original_path: str = json_data["original_path"] scale: float = json_data["scale"] boxes: list[st.Box] = [] - page_langs: list[str] = [] + page_langs: list[st.DetectedLang] = [] # Define permitted languages based on strictness. # Since the OCR model is only trained to recognize Japanese, # we need to discard anything that isn't, and if strict, also # those that are unknown (likely a mix). - language_whitelist = [st.DetectedLang.JA.value, st.DetectedLang.ENG.value] + language_whitelist = [st.DetectedLang.JA, st.DetectedLang.ENG] if not preprocessor_conf.ocr_strict_language: - language_whitelist.append(st.DetectedLang.UNKNOWN.value) + language_whitelist.append(st.DetectedLang.UNKNOWN) for data in json_data["blk_list"]: # Check box language. @@ -155,9 +155,9 @@ def prep_json_file( page_langs.append(data["language"]) boxes.append(box) - page_lang: st.DetectedLang = st.DetectedLang.display_names()[( - Counter(page_langs).most_common(1)[0][0] if boxes else st.DetectedLang.UNKNOWN.value - )] + page_lang: st.DetectedLang = ( + Counter(page_langs).most_common(1)[0][0] if boxes else st.DetectedLang.UNKNOWN + ) logger.debug(f"Detected lang: {page_lang}") # reading_order = preprocessor_conf.reading_order diff --git a/pcleaner/structures.py b/pcleaner/structures.py index 8b3a1215..02362bf1 100644 --- a/pcleaner/structures.py +++ b/pcleaner/structures.py @@ -1,7 +1,7 @@ import json import re from enum import Enum -# from enum import StrEnum +from enum import StrEnum from importlib import resources from pathlib import Path from typing import Sequence @@ -15,7 +15,7 @@ import pcleaner.data -class DetectedLang(cfg.EnumStr_): +class DetectedLang(StrEnum): JA = "ja" ENG = "eng" UNKNOWN = "unknown"