Merge pull request #532 from paperless-ngx/feature-barcode-splitter

Feature barcode splitter
This commit is contained in:
Florian authored and GitHub committed 2022-04-11 08:51:48 +02:00
commit 4dedff00b8
27 files changed
+778 -1

No files matched your search

+161
View File
@@ -1,6 +1,12 @@
import logging
import os
import shutil
import tempfile
from typing import List # for type hinting. Can be removed, if only Python >3.8 is used
import tqdm
from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer
from django.conf import settings
from django.db.models.signals import post_save
from documents import index
@@ -14,8 +20,12 @@ from documents.models import Document
from documents.models import DocumentType
from documents.models import Tag
from documents.sanity_checker import SanityCheckFailedException
from pdf2image import convert_from_path
from pikepdf import Pdf
from pyzbar import pyzbar
from whoosh.writing import AsyncWriter
logger = logging.getLogger("paperless.tasks")
@@ -62,6 +72,115 @@ def train_classifier():
logger.warning("Classifier error: " + str(e))
def barcode_reader(image) -> List[str]:
"""
Read any barcodes contained in image
Returns a list containing all found barcodes
"""
barcodes = []
# Decode the barcode image
detected_barcodes = pyzbar.decode(image)
if detected_barcodes:
# Traverse through all the detected barcodes in image
for barcode in detected_barcodes:
if barcode.data:
decoded_barcode = barcode.data.decode("utf-8")
barcodes.append(decoded_barcode)
logger.debug(
f"Barcode of type {str(barcode.type)} found: {decoded_barcode}",
)
return barcodes
def scan_file_for_separating_barcodes(filepath: str) -> List[int]:
"""
Scan the provided file for page separating barcodes
Returns a list of pagenumbers, which separate the file
"""
separator_page_numbers = []
separator_barcode = str(settings.CONSUMER_BARCODE_STRING)
# use a temporary directory in case the file os too big to handle in memory
with tempfile.TemporaryDirectory() as path:
pages_from_path = convert_from_path(filepath, output_folder=path)
for current_page_number, page in enumerate(pages_from_path):
current_barcodes = barcode_reader(page)
if separator_barcode in current_barcodes:
separator_page_numbers.append(current_page_number)
return separator_page_numbers
def separate_pages(filepath: str, pages_to_split_on: List[int]) -> List[str]:
"""
Separate the provided file on the pages_to_split_on.
The pages which are defined by page_numbers will be removed.
Returns a list of (temporary) filepaths to consume.
These will need to be deleted later.
"""
os.makedirs(settings.SCRATCH_DIR, exist_ok=True)
tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR)
fname = os.path.splitext(os.path.basename(filepath))[0]
pdf = Pdf.open(filepath)
document_paths = []
logger.debug(f"Temp dir is {str(tempdir)}")
if not pages_to_split_on:
logger.warning("No pages to split on!")
else:
# go from the first page to the first separator page
dst = Pdf.new()
for n, page in enumerate(pdf.pages):
if n < pages_to_split_on[0]:
dst.pages.append(page)
output_filename = "{}_document_0.pdf".format(fname)
savepath = os.path.join(tempdir, output_filename)
with open(savepath, "wb") as out:
dst.save(out)
document_paths = [savepath]
# iterate through the rest of the document
for count, page_number in enumerate(pages_to_split_on):
logger.debug(f"Count: {str(count)} page_number: {str(page_number)}")
dst = Pdf.new()
try:
next_page = pages_to_split_on[count + 1]
except IndexError:
next_page = len(pdf.pages)
# skip the first page_number. This contains the barcode page
for page in range(page_number + 1, next_page):
logger.debug(
f"page_number: {str(page_number)} next_page: {str(next_page)}",
)
dst.pages.append(pdf.pages[page])
output_filename = "{}_document_{}.pdf".format(fname, str(count + 1))
logger.debug(f"pdf no:{str(count)} has {str(len(dst.pages))} pages")
savepath = os.path.join(tempdir, output_filename)
with open(savepath, "wb") as out:
dst.save(out)
document_paths.append(savepath)
logger.debug(f"Temp files are {str(document_paths)}")
return document_paths
def save_to_dir(
filepath: str,
newname: str = None,
target_dir: str = settings.CONSUMPTION_DIR,
):
"""
Copies filepath to target_dir.
Optionally rename the file.
"""
if os.path.isfile(filepath) and os.path.isdir(target_dir):
dst = shutil.copy(filepath, target_dir)
logging.debug(f"saved {str(filepath)} to {str(dst)}")
if newname:
dst_new = os.path.join(target_dir, newname)
logger.debug(f"moving {str(dst)} to {str(dst_new)}")
os.rename(dst, dst_new)
else:
logger.warning(f"{str(filepath)} or {str(target_dir)} don't exist.")
def consume_file(
path,
override_filename=None,
@@ -72,6 +191,48 @@ def consume_file(
task_id=None,
):
# check for separators in current document
if settings.CONSUMER_ENABLE_BARCODES:
separators = []
document_list = []
separators = scan_file_for_separating_barcodes(path)
if separators:
logger.debug(f"Pages with separators found in: {str(path)}")
document_list = separate_pages(path, separators)
if document_list:
for n, document in enumerate(document_list):
# save to consumption dir
# rename it to the original filename with number prefix
if override_filename:
newname = f"{str(n)}_" + override_filename
else:
newname = None
save_to_dir(document, newname=newname)
# if we got here, the document was successfully split
# and can safely be deleted
logger.debug("Deleting file {}".format(path))
os.unlink(path)
# notify the sender, otherwise the progress bar
# in the UI stays stuck
payload = {
"filename": override_filename,
"task_id": task_id,
"current_progress": 100,
"max_progress": 100,
"status": "SUCCESS",
"message": "finished",
}
try:
async_to_sync(get_channel_layer().group_send)(
"status_updates",
{"type": "status_update", "data": payload},
)
except OSError as e:
logger.warning("OSError. It could be, the broker cannot be reached.")
logger.warning(str(e))
return "File successfully split"
# continue with consumption if no barcode was found
document = Consumer().try_consume_file(
path,
override_filename=override_filename,
Binary file not shown.

After

Width:  |  Height:  |  Size: 836 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

@@ -0,0 +1,243 @@
%PDF-1.6
%äüöß
2 0 obj
<</Length 3 0 R/Filter/FlateDecode>>
stream
xś]QËjÄ0 Ľű+t.Ä+ŮVl�1äµĐŢ=”žú:mË_ŮަˇbŤ<Ł‘Ôßę¨ŃŕČÚx†ŕH‡žŕú¦ďŕł1ä\?Ô¸*"ÔĽëuÖW8 D˝ľ?%¤L ␍ZtČŘŁÇ�;ÉÄl7ŕpĚ6á„s!3.ą
ĺ¸×ćçőA-«:ýk€Ĺ<âźż2żţ¦ú—ËĺΤZj}3ŠĹzŘ(ŽąóL␍ÎŇ•–zB �Č “-ˇ#.Bęë<2sHäk&Ü
NYR±¦ˇ·Ç±~'ń§6:-%.Ő['‚;n+Ůś·%śŕDQ›ÁYÖV¦7ÎÉčNď˙•ä—uŐn"®g#ĽśŐáţě`ţ‚RôŇćmx
endstream
endobj
3 0 obj
284
endobj
4 0 obj
<</Type/XObject/Subtype/Image/Width 828/Height 236/BitsPerComponent 8/Length 5 0 R
/Filter/FlateDecode/ColorSpace/DeviceRGB
>>
stream
xœíÛÁn`IŽdÑüÿŸîYÌ¢„`”ñòÝA8—¢é+½Mý÷ßÿÎÿüeþûËÏü÷—i~æ2j˜þÞ­ü­¾ô®¡ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~º£Ù<õ½ Îäý«î6ÏeþÔ@ß�¸É审ï–�vÒ¶ÆßØ’ÝÆ¶Õ«É$ò·z™mI¦ÁOw4›§¢—Á™¼ÕÝæ¹ÌŸè7¹Ü5ôݲÑNÚÖø[²Ûضz5™DþV/³-É4øéŽfóÔCô28“÷¯ºÛ<—ùS}Câ&—»†¾[6ÚIÛcKvÛV¯&“Èßêe¶%™?ÝÑlžzˆ^gòþUw›ç2j oHÜär×ÐwËF;i[ãolÉncÛêÕdù[½Ì¶$Óà§;šÍSÑËàLÞ¿ênó\æO ô ‰›\îúnÙh'mkü�-Ùml[½šL"«—Ù–dütG³yê!zœÉûWÝmžËü©�¾!q“Ë]Cß-í¤m�¿±%»�m«W“Iäoõ2Û’LƒŸîh6O=D/ƒ3yÿª»Ís™?5Ð7$nr¹kè»e£�´­ñ7¶d·±mõj2‰ü­^f[’iðÓÍæ©‡èep&ï_u·y.ó§ú†ÄM.w }·l´“¶5þÆ–ì6¶­^M&‘¿ÕËlK2 ~Line truncated
g2Éďýy+Ďśţüď~˛OűyëÍ›7oŢĽył;?˙Íý˙•řÉü_§żý篔żĺl©ţöŰ“Ý?˙őň'§Î7oŢĽyóćÍÍĽo¶dŢ7Űß2߼yóćÍ›7»łő-´ű“śóć›íożýßůÉźç}ď˝yóćÍ›7Óyßlď›í}ł˝yóćÍ›7ÎůŰ_ŢßýEţöŻüď~űźßi»ßlľűŐdřfë˙K{óćÍ›7oţµyßlď›íň·˙ĽűľŮŢĽyóćÍ›źçż?ćĎÍsňýŰoüÝo1|łý|ÉĆŮüäÍoOş˙™đ»˙ŢĽyóćÍ›s~ţëI|üů{§Úć·˙í{#Éů9?ůůťłůɛߞt˙3áw˙␍ĽyóćÍ›7˙ňüî#˙Éä_óżőÍooś˝ęo_8^ ů™©™¸Ňď.ÖďľyóćÍ›7˙ćüî[(˙Éä_“ßő;çďľFňÉU?‰ýéüůg¦fâJż»XżűćÍ›7oŢüks˙=@ä_#ůÜ| ý®ű˝3—üíżş7oŢĽyóćÍźóľŮ~ç¤űűf{óćÍ›7oŢüßůŰ_^âo÷ÖWÓżüÍö·÷o˙7š^ěw˙Ą˝yóćÍ›7˙ňĽo¶iÎď¶Ţ7[˛űľŮŢĽyóćÍ›d.ż…ţťo¶˙żľŻ’źś6úyŢwÚ›7oŢĽy3ť÷Í–ükŻr~‰ĺ?ůľŮŢĽyóćÍóü÷—ąůÉ?·gţÝ’Ď´uňۧÎÝË÷i?o˝yóćÍ›7o�Ůý�ţäź[Ť3IřŮĐtÉűÔą{ů>íç­7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢĽyóćÍ›7oŢü;ógŢů
endstream
endobj
5 0 obj
11207
endobj
7 0 obj
<</Length 8 0 R/Filter/FlateDecode/Length1 14992>>
stream
xśÝzy\U¶đ=U˝A7ôBoС»š
„„Ą K˛Q!lI0tD:ŃĐ␍4şCw—q‚ŁqAó—Qă22ľčsflLôEÇQttć9ŽŁ>ő͸ddľqyó&ŽčdÔ§ˇřNÝŞf‰Ńů˝÷űţú
ŞęŢsĎ9÷l÷Üs â�{ÂÄ@†K„ÎţPô†Ý␍B~CX:÷Ćą5M¶UŘž „ů÷îč®ţ;˙ő‚Ó„¨Ž˘=ľ«ďŇîŠýŚC!Ůżé ‡ş*—ŠYRŽ<–ő ,^ŞĹ~ööôÇ/ů"uâěĆţwú"ťˇ{?CÚö…ţĐ%Ń<U+�ýFěsˇţđ·ţ˘ űHŻŹE#±xąnYOHăŃÁp´ńÎŽç YŽ]Vâ ř#]Č4RźaUjŤV—’Ş7¤ĄMfK†Őfw83ł\ ˛Ýä˙˙K}�ŘH�z␍1’(}λŘQ’IŽ2}JęÍ>ĹĆé/˙_Jˇ“_w�Čqr�ĽI.Tę�źô’=™{=C^E¨tůÉvňţ¶ŁäŽËxArHŇäś—źÜNŽ‘_Í›ĹOúÉĺ(ËŁäMXJ^ŔP‰�OAG®$Ď#×OvŢąX1éřč¦Íî9Đ·É]Ě␍d#óvŽH#ŚŹ1‘çČݰ9ÇQĎ�3ŻţÓkÉřl&=d/¶éĄ^sć-’2ý7Ôę
˛‘|ʬ#}s(ž„{ŮTô_ ąmú …ů’�Úö"ć1†™ş;7‘]x‡ug˛ëľÁB˙ă‹m%i°�Í%)çeʉQü’)ť>Í.$©¤uz2 ›Ţ4ý76$¨ÚU ÔkT/~Űš›TýHM¦ß/»Ô›Ő ·ÄDQżc{ ­µĄyëÓćó7mÜĐP_W[łľzťPµvÍęU++W,_V±´ÄW\T�ż(/w!źăő8­f“1=Mźš˘ÓjÔ*–RČ% X›`s9s]�ŻĺC␍E…\­ł§¦¨°–Ż &¸—Ŕ—*Źoh  >”ŕ‚\"_ˇ9ŕ`B@Ěîł0S�Á·š¬–¦ŕąÄK5<w¶oiĂöÁ>Ŕ%>˘íóh[•G;iŘńz‘‚J%IËŐ&ęöö ×QFÓ§®çׇS‹
ÉXŞ›zl%ňůčäŻÚ`ňkWŽ1D—&M‹šÖ†şţ-mµ5.Ż7PT¸!‘Î×Đ!˛ž˛LhÖ'´”%×+‰NnŕĆ
LJo<a"ÁCßş -Á†�v�­ľ6a.H,ćk‹/{ωš‡…|Mm˘@âşiëĚ<›f§„„:×ÄsĂ'¨˙Ń©ů��ŃäšţN¤f‚Yꀭm^érŐˇ­‡‡ëx®n88:1=ÔÁs&~xĚ`ŽÖ˘ą‰ż␍Yś�~âW˘îĆ@Âě�•Eőş­›[v´%�Ü:®'„ü­â˝+\^ó Ž˙›† šŤ�öz%3ÜpB ŘI mi“űép=B_A ÁĄ‘ńä�­UJŽĚ�yôí¦ć¶á„*wC_‹ż!”ęŔčşHr oJ¤ćňňĂ3Wé P\ĄÚĐŐË%Ôyh$¤šK€q#‘ ›h'ý3ůő‘ 'Č3[¸JŮH|jůÚ ň»·Ç‰ 84tC�-m ˇBHńXíX‰)BAtXo␍ufÂÇGVľzĆ»’Xµ˝Ím”D!KX×'H°SˇJřjéşâj‡�5˛/~KŰă¤lzb¬śs+#ĺ$P#!Ű×c”ĺŐ·uu'<AW®»n®ÍĺMôp€o ¤°C -žpŃŕĐXiiŰÔĚoÚ˛˝m…"�< ±Sĺ֞ņosÉl0ş\×ƸŘ"šŔŐa�Ż^ŤĎ„6W‡· ␍NˇRŕVŻćÚŔE’Ř(Fb1W®Qđ¤ţ<¦j)śÖ7$ąi¤.ňYßŕňĽňUTČŕ0§LŚ:ɨ␍É!LS8 Ăř\ß@A’-ťRĐsm|�đ=\Bđ·IşIćˇVVŚAm®řŞe^oޱĐLÄ‹ĂÉŽdĚD]�k®qő´?Óm8kxCr�Öń›š‡%ćĽÂ� äD
aa…ŮEs�´ yĚ˝ś —4]ĐĂc‚ -ćž•~C×0ßܶšbc>ąÂu™4—…l‚M-ŐE…�ÚŞÇx¸nË�×5oo{Ü„uáu-mŹ0Ŕ¬VĆâXŰănĘHP (u8©#qÚŠĹw=.2DGU@űť'€P�. Ňy‚‘a&y˘<:‘@QÉ#B[…0ť ˘0zŤÉdBŞZĐ )‚�Ic\c �AČXǦ9f€4pŤ!ŐV
>Cc)‚KĆB A–đşÖŮ©[··3ŕîě˘Oś¨Zş0\ś=člÜVją.)Pľč¤ĹFěčü…đkŃMüZDcH¤ňáę„žŻ–ŕUĽJ†k$¸Cě€äCč{¤ŘŃćĹ%Ée˝ŕ6}$y*€IeŘô~Z,Ď␍Ď`␍j…ŐÂI Łgt¬Ín :Hauş3›Â)¬…!L{€XŞě`´Ă„ž¶Ă!;ě·C»ČQřĹ“vxŮ#t,j‡&;xč€ OŘá^:ˇd‚J(±Ă»tt�ÂK(dŐ4ťG&;DščŘ$…'’sČĄ™¤ŚĆé4CtEó%ç¸pćÚťĽ•kçYđŻŤHc¤ŞŔLĘśôi.súÚw^Xf¶€ŁŇ\¶´Ä[±ÜĚç�7{Íü˘b(łĂ«Ţ(›şĐµ^uwŤËýëK–ľQáRÝn}V‰ĎżŞŐu±«B*¨€X±r{ĎŮä áRbµf¦Ą§§d¦¸=ŮYţ@6±bÇ‘é †Q«Í[jÓ�&<0î“�*±sŘQ=ŕ÷€ŕ�pđĐaJŽâĐ+”2á�‘9đąĆśgEwÔşŞLj”Q3X u—––€U»ĘJí6T\˛F9źŁUš‹*ĽP§mřת˾3(^|Ĺ;ŻÚ/ví»JŮĎzŠŻţ§k§nË,*ĘdvŽfOeH-5ă,Â…S€ő©EÝHôxZşGč&�ĆlvŘŮ”ćaÁIJ6ÁfńlF�ŮhöŚ6«T¨<í€Ă`˘:ŔďÁăH8`„v9�@0I!�:s~ŚH&h§V�q?Érš~‹Î§0—)ĘkřśĽŠňehvVéË…˘BA(,R(fŽ€Ő»r_řjĄ¤'ËeJk°eúóű<É'ˇÜ«µfĄaH,^’će·?ŕr�X˝? eíCK ş‚KŔż¸%đđh_MK )/A÷ę# AßČBg$\TQć°—•V”ű �ˇâ:lü˘<>GcłÚn–ymě'u?*)Zşé’gŹÂ”ţčđ®»|K*·´ž·ů–íU<čn<śmůđŞš.+ĎöÖtÖ}ç�çĄ~źż¦rsVińúmŇ1�lś>Ĺ~�ńś�=$4YUz’™iR™Üž “?��ţBgíÔÉ”‰ŚcK€±c�ÖĎŤ\B�t�BäF�Âď(Ń9™’ćôž Lęš\␍Ď™Ë-¨iŢ@§H1 V4ÂrsĎ1Żíľ]Ü˙Öë}Í &.~!z†®Ţ˝=0(ž©ŰüŔá=pÚYôĺă™EđŇS?[Ä|h¦:zĹF6�>s/9 lqU‹Ă™ęHÍá+FĄŐ•Ćůiöl—Öµ% ŇšXâ°F�‡!•%<Lđ0NűA„9m´óěRÄŘ$UŠ_IRQIéŮ(y8•sČKĐĘđ9‹ěŮ@#Ęó¤Ą�ßq1č�%7ţw/îîÖ…}L×ű÷l\t†íÎ,Zľ°đË˙úXüŇްXtú|NvóřĎĽSfł”ŁŁŇ&ôi
ąO�ŞńĽ¦ńđ”©fŐ¨•íu=<§‡ăz8އ[őpµâzčŇĂB=Xő Ň㚤‡ő¸,őÔ�_‚Ćő�ĐĂíšô@ô0I»�7mŢšT–äljľpÎâ”l‚>ź]‚iĺŤ@]ÝśĽŇ€ńą›}†¸p÷ëŞĚşÜ\g0dŞX<–ć¤ćl 8mf3†§Ńě13- KµkUŻ6bó�ih´/a`ăB”�ĚD_™ĄŇ''R©8É‘t®B%?.ÂĹh._ UP!y÷ŤŠe M›µ¬tŮrxőΛö�bĆŕŘ'Fî8Xż±«9gĹ}@®ş¦ýPMg)űĚwż7u łhç 8w^ľŽUÝşŔ·ç%^t«Ô;§äŻL±Žý‚% ŕO´Ů�á48Ý™ŚŇT}¶3ĂlHÇEhKÇe¸%Ŕ’q7t»a›7|ę†÷Üđş~é†ÇÜp˝p4迪ÝPꆅn°şA㆞ĎÜđnxÖ␍ʏá¨nvĂŐyµ¸ˇŽbç¸Áâ•N»áŠ˙śŽ»á�$ţ :ܰŐ␍5n(wCžěIü9ŽĎçľ,ÍŠĎ(öŚ4·&ą çĎ•g!•�&Ý0á†W’ÝšäŢEu•ąź¦̸n8ě†!7DÝĐäŁtÉlźW;ě¦á9xÖ:÷Ú}Ö5ř­řrf/ťÉ4ŁKŐGrýăÚĎQ2űZX.%9›Ö%ż ťůŐćFź×łĽĽmĂrńÎ żUüěŘŮ!Ţ´.ë,/«÷ŢÁFq}¸¦"Ě-ř¶ťŮq˙áŤrmâĂÚäŹ�ç�qá
’‘áÔ Z§6Ű˝+’Ć ěŘťţ@ŞÝfALÖ´5ŔšŽRÇ=Gý‚~¬|ŹÚV6lKҰčF»23†Ĺ0¨Ĺe�ŹĚ�ϵ]ű˙ŞB™_źäÍ/PjÎűéJą>ŮŇş ”‹vď,¬ś)Oښەú„îŰ,Y5ýĄęS¬ťuÄBňČIá–”˛@ťžnłyä¨ňĺš‚�\‹GmP‚Łô¬ZíĚpÚŰNU0ŕd3lí� ËH>·ˇ|�ćC0„|�ȇ{)»~
áňáÝ|§�Ú%ů°ňe:lʇIĘ‚PĘWňa„ň’)gŚöµ2W¶ž’ąhľrÎd.ŮxŽąĆ+ĎĂšłSm`¨-SË–ăpżŃhÝ�»TŢ\ö©;ňňŰ÷ ?ůňäđÝ?~čŚst” “éS7]őč/ĹżO±…ýâň¨¨íŻšúŤć¦÷±(ţAVĹíG÷>° ă'×=ó+úşßÜ�qg%[„"łV �Í®1łÉ̤«Í,c5™Ňü“QkHĹL–jk§u>*ät<łS–ѵb¦»ĄĄ˛”ę‚5OŽfŽóĄm“ąŁ`eéőĄ?«÷íKĘę—VłĎ‹.űTuŇă{J/�×ÄfÜ?6ŁlvV›Őz»ÚîpęŚXˇëLv+kĹŚj'NX+8ˇÄ śLN�tÂ+NqÂ�ţ°Úť0§ÚŢ9ł‡•ÍĆ-îdé •/Rˇf–
5ÎLKvóŇŃíâň?żyíČň‚ć¸xúź|s_ĺÂĹđÉ_¦<â—řÄž×őJuŠ$ë#(k*Jű„p%JKÔĄM÷t&ĆęÇ Di'śŕ§ňĘÂNPyÇť� R¦‚Gť¤âË$«îĄ ?ÍhJćÓË*ËdřĽđěś·ókąn&(çŘLŢd}­-WęU Aö±áőß˙ţť˙xëřwŻąjĎľ+Ż‚·EłřÉ_Ď|ţ·ß?űÄÄź~ţýôMüh‡:´�␍3ŮAa{&€1Kg3ڲݙX—3=™¸Ńgf,»?`1Ô[űLš›źpkŔ˝c­źfŞ7pn0Ń˝DNVłĄéśâDÖfv…% s91MJŰľ␍}ť“'9›3ŰUô–ç�jÍţ]Ën-)ąŰŰ/ţöičoď‰ŔÍŔ›–á#~‹~…§ř¨?űTěŢ
w?xôŘ)>;Pמ›–�ë„-ů–Ü\‡Ăâa5ééDC
ó3,–XŔ—<KÜ&7“ÂşÝ<ź đZV DµCZƨ­–Í
�ÂD!ŚB°°›<␍—ů.Ľ0YŠR˝ĚXúČé#é8 Í –Jĺř±�-sPU±čńAĹňµrőŁ‘ŽÍ¸1¶Ą<Â&ľřÓSé«‹Z{ĎmĂ7:´»oĎPEĽ�Żî<\?=răcŁĐ˙čo
ëI;wřÁ«Ż×궦h†ľwíĺŮÎŁŔd™ĹÇn¸ßjűę÷j´Ĺ(ÚÂIrČ%B˝KO8«UC4üB+Çąíîx€ŘMvô˝Ď•)ćXŔ�ćIóĄ±)lZZJ&› °Za!�…0±FBp!`wć‹€”`fł¦Ü’¶ˇąµ9nĎRŕZĚ&ÂÓ}Z˛�%C:ŹAŽĽžMLő˙ůíűo�ý⟯[Çs}ËGFSî¸gěExäËKľ{ĺU—˛Gýń1qD|XĽ+ç?ť� ćÖ×›xôČÍPI×mâólyŤ��ş…˙v�­ćܧô ô|ŽĂăI·Úî X­,«ş'�Î>¸C“ľ�‡Mô¸ńŢćáe<ĺáV®ćˇť‡U<đŕáAĎĂE_ńđŻóđcîâá:ěâAĹĂi^¤p¤ěâAć»�‡Ż’¬~1-<ÔPd·Rć%Ďv9–ÉĘ)ĄŠ’=ÇĂq:Óĺ”oK’ř4ĺ0 ž�˘<řyđQ9ńd•,ËÚĎő©gŢĘüÚŕĽd$•]ľ˛9ľçąµlöt‰![!Ĺó"%;©ĎŔµ÷ŢśpçÖÔT¬Ů
G“mˇiéőŹ/9oEÔĘeđ²Ęó7Íë^@÷™–éSŞ÷1v]d­ŕ5łR8.ČÖ¤·H*¤°©©U&ź­Řϲ!ą�řf"r&{Ş9Ü7‰·Ô‘!}›ÂSŻŮ„âeUPĆjXŤř„x+ě„¶W'5ŐîşÇ�âô©ĎO␍ţzUî:Í;Vč¶Cg™řöO |âż‹żßłĽřßÄç«$ ¦O©ďĆČIn‚§Ć É̲¨Iš1­=ŔŮ[0�’ˇĘ‚Ş®,hÉ‚š,(Ď‚…Y`Í‚ăYp4 nÍ‚«ł ž„›˛±OgÁD0ŻdA" F˛ šţ,řZ±ťôÚśóqYŮÜm�Áf«ŠçV�ĺŽÉ‹ HuíqxaTüüŚřwńóQĆ9
ťă/©ţšUQ‘ućÝO&?9É–ÓöŰâ-Ź“ôĽóČiôE‘ôŤĆˇ[ä&ćEf_±[g]˛DÝ€%VÖuVŐ¤&|đŠĆ}0Iź%>ŕ|rĘ ×7~ŁÉ�IŹĹšŠŮ=_ÚěÜxÓ87¬ăsm»ńž5ťß=đÝÎ5“oÜ÷Ô:ľű¶kn_Óą˙ŔţÎ5ťč{«ző5únĂÎuEĹ+¶íżpä±ńĎG7ö×m[Sč[µăŞŕłoäyi~ÄSÇč76;Y&¸‰Ac6�N+۰f¤§´ŇU¸ˇWÉ{ţîÝ;/<×ŢlˇŮŤásÖä•cŤ#�űűŢëÍ>üÝ«Ě!¨�F1!Ž‹Ď� fDüąřČ�ő°\âűâǪ́x?¦¶‡Äű0Š�¬"DóGSW
–tÜĽ€¤XV§Kł°Y™i'¦ż–Ą¤5¤é5NsŠ^’‘ŃaźŃł «ÓčpAŘ4Ś  ńd U)„*HOĘ
ä&îSs‹^ewöň0['¦€@r—ÝÉ‹¶ăâňŃQ¸␍ŽĂ;04::5q\uĺW/»*äšöŚŠ=S‘őUí/•ë+!ęęb$h>5§Ť*Kš UZ“ŠÍ°¦Ą›Ó�‹Ů &ŤZeĐŞŚ`l¤‚ĺ´ŢłÂëVxÎ
Ç­pÔ
·Záj+Ä­Đe…+ÔXˇÜ
­`µ‚Ę
˙SüĘo!�‹­˘8ăV`V±Âa+ Y!jż+”X�ł‚É
é,„&+śť{ĄĂÜYŕx^&ł‡Ľ2é� ®¨â™/-—•Ňg úů«Lţ ĆzY`˝đ’XĽđĽýĐÔ ÇLM^ 7|ŻUHúâ+ťä)¸JĽBŐ3µGöƢşcŃFÜd@Xk3™\i.Ť=Íj¶�Ó4*g ¸\)Ş”LLvÚö@
kŤJ�KHe1qđ
QNŇ}0)űěˇë¬ĎDTş®fŻ”ž±$ERfbđŕ‹SoÜ;ʬ?3yó•pńMâÓâµ�úýźýxěŘíLٍJFáCO^ó‹Ľ©˙tU0ŤpĹ‘+§~q€ę5}F˝őJ!Ň(řÔV’fMsf:đHęŔĂ©�5áľbŇ& ÉÄőź \&LdÂH&D3ég9í&OŹs˛ńňŇůĐr&Č婪Łâ«â‡Ç/ą˙ł?O}1č˙Eü‘�3ŠçñšÉůęräŕ‘ëQń8&ŠT˛đtD¨®@Y]č�:†k&–ŚŞنŚ` Ý10E`‰Ád`RÔ�Ę岢; =ನôÁ€Ši¨Ř‰lɆh6řłAÚ,•Âü¬Ă/î-ł9`iIHĆ—’0šÜ»Ľ [^ł—“öMďŞŃQöŻŐ\ôő·á"Ź xÄŰ@Śż˛:ă«WeŮŧßLź:="vÝ7uŇô…řOx
Y®nˇ5ZPřo•FĎ›c‹'Ű^©Ď°TÓ¤łéî�
5VµŠÖCÖo(ŇvĚ)©f+4,šâ´bú¦
­|~y&×Yç(Ň^§c3Sm˘gÄy‘’MÖo2Ąžňť©‡ć�"×’F,ŰÚϵĽĎ™ţÁ�äDşž|č2ź‰Ž2ü•>Z੊ţiĂ.oźągÍÝßO¸óÖ×” ~ń‚Ů6űᵏm^µe[ůuËV쨛ßUţn7}Š)R]‰;g˝°(5=]›Á˛§Ę 7ř1␍čŤ�ëÍ[đ|q/=EW9ÁçTR€rŇ/K~Ć·T–Ň/j<äšů
0[™Ť—Ďx,„ÍÁöËŻWýîw«JV6óW[w1·-z㍖©ýëŞMëś*ĆWć‘ţôŰŰŤ«˙N<ň˙÷ý[Í+żťýď-±wVéżŢt‹ň…tZŻXKÎźA‚łţĺËŁ©Äř'’«Âj“©$l6i‘ȱżo/ÂłI¶3ńö©·‘UĚCű›ńíÇwŢŐŘކă-ę_‘UŚ\Źďm6Y…o«D‡ďU8×*Äë@ľV*Áł°že–ŕĎݬ•˝Ś=Ą6© iÔÜ©™ÔƵ˙Ą‹ę>Hům*—z«žč7ęOΤmM;‘ţ�ô¨6RŚç 9Ł›�Ź`}Íü‚ý%¤Q7 ĚčĽmF@ĚmJ›!ZŇ­´YĚCýJ[…8×)m¬yÉJ[�űűýJ[K.#Ç•¶ŽXˇXi§�t¨VÚ©0~Ą­' �§fţc¶�yKi§‘
V§´ÓI»F’^%ý§ß({ľŇ©XĄÍ�tŻ´Y˛ ą­Bś]J[M˛T×*m␍q«~¨´µä´ęiĄ­#ůęcJ;…,Pż­´S™wÔź+m=Yˇ{MiČ)zĄťF.JIΕNĘS^­éÝŐď˝,ÜĹu…â!®3˝t°wWOśËď\Ě•–,-áę#‘]}an}d0 Ĺ{#Ĺ©ëĎF+ĺ¶"‹†PĽ�Ű0ĐYÜŘŰ–qąćđ`o÷Öđ®=}ˇÁu±Îđ@Wx�+âÎĆ8»ż-<“:ĄĹK‹KfĎĆíŤq!.>ę
÷‡/ć"ÝóĺŕĂ»zcńđ {¸ÖâćbÎЇâ\h ‹k™!lęîîí S`gx0BäHĽ%˝hĎ`o¬«·Sš-V<ŁŔk4ÇĂ{ĂÜyˇx<‹ T‡b8JÖŇ;‰rűzz;{¸}ˇ×ŽőîŔÁŽKąů4ކP—��Č^dą7\�rw†c=˝»¸�¤˛BÍĹ{BqIéţp|°·3Ô×w)ş¬?ŠTčŁ}˝ńś¸?ă6‡÷q[#ýˇ�‡ŠeQĐ6ÝhS®·?:ŮKe,Šu†Ă8Y¨+ÔŃŰ×Gn=ˇÁP'Z ÍÖŰŁACpŃĐ@QížÁH4Ś’ž_ß8‹�ĘÖŚEúöâĚö@8Ü%Í�bď␍÷!N܉\,éÓDA»â=Es$ďŽ Ä‘4Â…şşPq´V¤sOżä'4s<)\¨s0‚cŃľPąôÇŠ{âńčJźoßľ}Ĺ!Ĺ5ťč™bäěű¶±řĄŃ°âŹA‰K_#ş@rÝę_I‰ć␍Ť\SíS‡Âq
B!—ŚĚĄĹK•)ĐŚ˝Ńx¬8ÖŰWÜĺkŞk$5¤—ěÂ;Ž÷e$Lş‡wű!lu’‰’KÉ ĹęA(Gňşߥ¤„,Ĺ›#ő�Áń>¤çČzl"•ô Qľ2€i4•Ž|;·RlmU¤h Ô…ŘÚ€ôťČˇé:pt._Ž4SH/¦Y‰rŮ�r„˛ŽÄ�*Ś8]�Ă#8÷yüŁńm´›)Eą–â]rNĘÄ·9qÔŇq:"IÚOĄża¤ű6{p�¦Ţ‹áH�öş(W‰w+b4S,?Ą”,§ł␍P¬–sĚŘ„3v#}'ődł“ň–"BćÁvŹbÓ‹ĐŢ�T‚.J—Ô-†3Ý玍f*Ý^:çy.őct¬ű1E/Ůf-TŠB%[ěCI¤y{h;DíŮE©ĄP(;0ę¸oť‡ShCŠ_č{)%šBĹŢÝôŁóŕ•Oöňüą9j§µşěé~ŤSÜN„÷áĎĄĘ*ëG«Čsu(ëh]•=ŠĆý”/G6ă{ŤŠőŰ€7‡úxÖ*rÜt+qĘQÚ(¶#T‹¤‹¨o$MÂTR©˘+ż)účܲl=4:BÔ·aĹ×qŞAŇ^]Ц’ÔQ
)"µ4.¤őVlz>ć‰Ćsr”-876%źôQycsxPi»ft”­-aő)3É÷Ń|tńŚşiĽÉí˘ÜŠľÁćÝÔ6qeÖ•¨ dŹË±AÚ=Ôňz’Ł9ţ5Ë…¨}#
]”fĄ¸"K?]=4Łd%–>”Nú)¦q8wŐt*k¦X‘Ů÷ż¦“äŠR Î]�3˛ôŁŚŤĘę�Yu{ć¬ß¤'š15Ň|Uâ§N±wiŐśť3—Ňś9_ 9{±§ňĨ-‹©»pĽ gh$J-N¦ Hç¸ĆRüë: Lz`É ’ÍĐNZaYľ«Ć÷zěKďbXC†o␍Â×b5ÂWaîôŕł
ď&Ľá­Â[Ć(A ľ}Jżű…Hń2>�Ţ´
ˇŇ{#öđ]ŻĽë^‹ďZĄżűř&AĐb^EźO�J8SđňpS°˙+đCźţ”ůdr±çáɧ'™¦ŹŰ?~řc¶äc0~ :ň‘é#˙GÁŹ˘Ť|¤I5žů �˙4±Âóîš“­XóN+9‰šť,9é?9t2qR}ŘÖwX»Ç4ÎŤ—ŚGLJĆ_źź×␍=uř)ćçOú<Ć'=O2žcMÇöc�‚ńAĎ�Ś˙®ŕ]Ěá»Áx·çnßÝěťGŠ=GęÝžŰo[䙸mň6ćÄôř±ŰŇĚuOB4’5hĂÍÇŘiĎĂëlpŞeħoŢMxGđ>„7žyÝ�·…lű÷Ałëć‚›/żů†›ŐŃk†®9|␍;tŕđćá˝OďebţĹžČ@�g ~‰'łĚŮŞ-c[58␍Î.lčČÍŻ žvDÚ±˝Äł˝~±'ŁĚŇŞF…U�hd=lŰÄFŘCěÓ¬V·ŐďölÁ{Â?égЎÎŘäiň5±'¦'„đ&/rŰÝ8´‘ÝP·ŘÓPżÂc¬÷Ôűę_®·ţăzM{=Ü‹żu×=]Ç
u‹}uBťŰ[· ÁŐj/łµšÁŘj*3¶2€Ž.#­>ă´‘1ŰŤűŤ¬‘TfČj8‡ÇZš
6ťĐNoÝ”Đůw$ŕşDnłô¶lOh®K�Öí;ÚĆţ)pŕŕARť˝)QÚÜ–f6%ş°!HŤ!l�˛Çě¤:‹Ĺ čŘŢ�OR°§�;c2”ĚŚ“‚Ä0EĹ(HrđY Ť!@˘¤Ţ#ŇC,�‰$ę�ÂŽËÚpîüżTQlV
endstream
endobj
8 0 obj
8993
endobj
9 0 obj
<</Type/FontDescriptor/FontName/CAAAAA+LiberationSerif
/Flags 4
/FontBBox[-543 -303 1277 981]/ItalicAngle 0
/Ascent 891
/Descent -216
/CapHeight 981
/StemV 80
/FontFile2 7 0 R
>>
endobj
10 0 obj
<</Length 360/Filter/FlateDecode>>
stream
xś]’Ën�0E÷|…—é"“‡„�RH$}¨´@ě!E*9dÁß×3“¶R ăń˝Ă5㸬«ÚősüęGÓŔ,şŢY×ńć␍�3\z©DŘŢĚ÷˝ÍĐNQĽÍrťa¨]7ćyż…˝ëě±:Řń Qüâ-řŢ]ÄęŁlÂşąMÓ ŕf!Ł˘şĐ穝žŰbr­k¶űyYËźŕ}™@$´VĹŚ®SkŔ·îQ.e!ňÓ©�ŔŮ{©dËą3ź­R¤RfşśovČ)óYoSäŚ8‘ČÖ�wËŞď¸^"ď™ň�5Ôó‘ëGä’X'Čk�ʬˇďž�ár%™3dÎź˘Fqţű+ĚźH…ýçפáüy9FuÎŻ©?ç×2ç×�_qţ ł)ÎŻńěęžźzVü]<»âü[M�¸˙q Ţ™źQ só>Ś™.Í'Ű;ř˝{Ó8ˇ‹žo@±g
endstream
endobj
11 0 obj
<</Type/Font/Subtype/TrueType/BaseFont/CAAAAA+LiberationSerif
/FirstChar 0
/LastChar 30
/Widths[777 610 500 277 389 250 500 500 277 443 500 500 666 333 443 500
443 500 500 443 666 722 556 722 889 722 666 722 610 443 277 ]
/FontDescriptor 9 0 R
/ToUnicode 10 0 R
>>
endobj
12 0 obj
<</Length 13 0 R/Filter/FlateDecode/Length1 10276>>
stream
xśĺ8kxוçÎŚ~J˛%żÖČ�m9~ČŘ1x0¶01‰_¸H€±„$#�- IĆ!mŠišśPh“>iCÚ¦iK“xLšŕĐ´ˇŰM»» ]H›MÚ”†mŇí—MSč.IŰ$–÷Ü«±14ÍŹýöߎ4sĎűž×˝w¤d|4Ů0<Čţ_ĚY\.Ŕó$Ďż7)>¶ËÓ‚đEîŕPlçČ—Om» „tßŰ9ĽoČüµŻ[˛déCA_ ţ/‹j
— Ťĺ!$ ¦>ˇC|âKB#ÉŰ~¤/[‹ř8âňpÔﻹpI>âg/ńÝ;Íźçq1â >8qä-€"íŹÄ˘‰äK„ĚHIĘŹĹ�1�yd%â÷ŁOG‘FđCŻlµçxAŁŐé32ł˛sr␍đ˙îŇ<ŻyîĐ ěcĎk.a�a `ö»úLmžýó˙Ązö$Ťކ70~?‡Ó Ŕż.”&•¤ŠVŹäÁëp~ň÷¬˘=ŮČŔWá<< Oü9ľCfŕeRŚ}~
!Jk�WČúsiŁp�ĽOö;<HŚŚ»mçál­Ćţ»�ŢÝá~Ň5 ľ/sĎÂWřÜYx}ľ•;Ś´Yx ž'ő¤đ=x�Hŕ|‡ZÄv˙:|îĽJŐ<–zZs`¦LłďŔ“đ4ËŔ~�ďĽŇeňGr×d1Ń“ąšţpŽ©ëŕwqOrÜĚ}�|vâí#żDéĂüÚëÂ9‘ЦBD÷ˇż%=p­<–z*ől‡IîEč‡˙‚‡‹W˙ď`äŢCęä?g˙¦™ď~Čš1Ěľť6¦= Ś�Eř%íˇŮgSű1Żgáż0ű/’byýÖ-w˙¦ľŢžî®[oŮŘyó†Žő®ö¶u­kĺ–5«›oZµňĆË›–Ö;ëjk•ĺK¤2»­Čl2rs˛23ô:­Fŕ95˘BĽí
_.š\>©]ňuÔÖ�íEˇ¶ÚšvÉĺUDź¨ŕ THŚ$ůŃ+*8ř�˝ŠŚ’C×IĘiIy^’Ĺfh¦SH˘r¶M§É–7‡Ű$ʍĽĹŕ[,T0$»5�WÔ[±]qí␍M´{ŃG2••ąNZ̬­�©Ě,łRRlŠ8ÖpŽöUSčsč´i»/ t÷¸Ű۬v»§¶f�’+µ1¬c&í:EÇLŠaę:Ü#NŐś™¸wÚ;ĽŐŮ)ŕŰćVxęNđíw+¦jĄJjSŞn˝#*5R[»RM­vöÎĎÓyuJ˘hĘŤ’8ń6`8Ň[¸–âS)ÚrăŰ@A…[§�^·ť^VćzbÂ%‰® ď„ozv|‡$Ą‰©ěě‰X;¦şÝhbzöô=VĹuŻG1zCd•G␍ÝŐŰ©ä÷lu+\ąK ů�‚ßÉ~ŁŐnš—éţ{lŔ´`r0Ăv;MĂ=Ó2ě@Dďq§qvXO‚ě¬ö(ś—rÎĚq,ý”3>Ç™W÷JXŰÎ>÷„"”oHí�ń{|Ęřě®]´0’QÉ}Çj—&ňLâJ§‡ÉŠčŐ†@XT4�$ÔZ¨€}CU&Ś É}'=ĽeĹ *LyâJ ÍP;íR»Wýî␍ˇÝQťn„MnEnC@ö©kźŞw˘†Ď‹ ·±b*N)¦�ĄÖůęR·ÚĂ}n¦˘Ş)ću
xýŞ–âlgëJlźđ¶Ą] ¶¤÷SĐ8{qj™h}Ľ–�§Ť
¬Ă.«hźp†›×Ŕu7$ş­vEö`…=’;čˇm‡ŞşheÍáa˝˛ÉÝŮ'uölqߨ:’fPsByűuf$·5mPŃ—ëE7gĺ=(hD‚čB@jmƧ˘+×ămÄ„3*mÜÖfŃM¬0'Ťn(Ub{°M•Łř5F5´ťÖuĚYÓRí¬ë°Ú=öôU[Ă![T'F␍=MjÇ ·)dč±?×u0ÍemzŃ-%ŹąŰMcŁéaYV“Ár®ÖjÓ5Ř‚dašŔŽě9„&SqU[&WYĎđy´ă:ö†9¶8ˇ—:ű&¨qI5čůh Ë7š¬l/  Z½W4â’f zbJ–éb­˘F¤␍� ©ĎÝ̤q?ąĂz;ť+:Iç¦ÖÚÜÚZ§$r°gJ&ű¶¸źÂ#W<¸É}’#Ü:o«gj ňÜO‰ř†Č¨ĄR"EDŠPK˝�虼ő)`śqF`¸šŁéçhüÓ\šfLOTÁ&’�CŽ�ćČsŇŇôiÚ8ٱk
hĘäLŤ¬—3äl.‡łNJ:‰”ÓxJfx<›äëjő2ň4źĘ�­i‰q”�Óěż:u˙÷ăŮ€jě‰µŇ ŰĄ(„ĹĆcĄ] ĐFů�'4áőĐĹXü…Hk°LŇtD›­dJÁV%KjĄôJoIÓµ”®Ă%ŐDZöÝ
ˇ°ŐmÇ%)–üłuÂř­”7• ăďjŃąłř6Ň€ďŤ<čŔ&çh9␍Ďńz␍/ ©ĺ¬ó¬)ʬ\ij45.­Ď·›ěů&»é¬|ďŘFţ¬ćŔ»ű5Mď
o¤_sˇ­]h+
ÁwÉ=ŮůůV«`Č(ÂĽ Ľ]Ě6[ÍÖAŹÁl3sfŤą {�Ů,h4ů�śpŃ GČ{ĐNŽÚɸťÄěÄk'Ýv"ŰI=űŠv20°G˝ ĄŠZŞMy°˛ČY=¸}€�čl!s–}ňV.­'fˇŠ�ě˘`1kuĄ„,«�0ІĺůË(ąaąfWęâ,Ě´pwŽdÜu𻏧>µo,…§Ű{zSݧ&Č�OßI>{ćÍ�Ç'oűćbó$yq°;őŤÍ©Śź¤†wbÜ4ĎţAn…
h„ąeIeĄNgÉ5ÔđĽÁÂ7-Ó:z=Z-xrĂą\m.á␍ą¶\.CČÍËËęń䋝ŕěň,±CÁ3M¤«‰ `l␍␍Ő&h¤ńA#Ć680�GĂĽ6<¬�¦¬˘iŮňŇ„a•iuĺkHcC�Ĺd.hlXaÉ奲ŠJI›ŻËĺ,”´†4‘C_U^9÷ĆÍ›nÝ�‘zĹúćsgSU/–;µĄ»‚™Ú˝žŁ;z«×ßÔ:˛ĆüÝcßV8aĹ®ťë{sřĆżśNíÝÚ®ý˘6S+„‚/rś u4ßŇٱ=ýUv7&"%tA¬‘Ëő†˘ÂśĽnŹ>Ǩ1€ĺxŮ_DΑÉ"2XDśEXKZMhiii¬^ĐdŤ¦e•öRbi\Ă56Zh`Ó␍O˛ůLˇJv·.··- ŹňÍž±şĽSĄń�ZĂ›†ßšy‹ľĽC7ÖbÖ˘Zĺ%fKf†�ç3,|I±6§Ë“™©5‚ŮkćrxłŔÔĺAY’‹ś�ć–ĆkRLÓ &#`J 5uD*3–ŻĐär\ď;©+$÷/ĎĽ+¦~—íu˙ňB÷p)1xÁLʉ–d“ę3ßÉíó§>—šr˘Ź␍˛>ˇľÝ‡ľe᯴ząÄ¤Í-dş<FŢÜĺá b…Ä[H´÷|^đw‹ťąc�v±H«,
÷Ą~ťJͤ.‘đ$�¦~őńŰfᎽ„çJSM˝HjĐ␍©N˝šúÓŹK}ć‰óeú˛␍9€+&ňyyů‹3ň3ʤ<Č.éň˛ŤZz¤-KL"´NŤÔ%ö�wËÔ�žŮëH“¤•Ę8“1Źćޱ÷s!a=iˇ9ă7
YÂÖŮüě—?M|«–ăH±>őÚh|OäBôvĂ>Ç?âďÁ ÜRË˝�'É=ď‰��ś4ů�SO§Žţx>oµ�·<(†¨Ľ®0Óh*ČĘâyS&o-)ČęőŘŤ¦CÉŐ`ăiµů¸ŢŚ�ŰăŮo$Fú…‚ăVµ’A+鲧•őŢ.3çŔŔ‚m„î"×®±«-�g˛ŘٲŇpWĆĚÝ|%ő.ÉĽňĆ;37ŹCH¤ôďćÉCú�™Ř‰Ű@L=—ú7ý_;€uá§&>vçť´GťłoUšĎ�>'{uZë"KY6@Yąq‘V[uCąÉh2&<§MäK&rĐD\&Ňl"%&’a"Ů&o3X­ŘÁV«ÍV”đŘt|FÂ#꼺�NŃťŃięu˛n\wTwN§Ńéđ—+vőŔžt”jźăĆčÜ>�ľţvŰd{¦T¶¤˛Ă]Ž;K5iJl‹Yľ„n1¸™ZJ‰P•z˙ňk©+…¤Ôú|0vđS;¶í»Ý7°y·>őűÂť»đ×cźýú$ąű'/ź¶řąŔÎí�×üŰ6ű˝nó“?ű©ňÉ‹„üI¬ďz¬o%ćŁ$č“ëJótÚ"L�6Ź/_b°'=Ů�ÍŔeđÜN-Ö„ÇÂB™‹oϵElś+băüҡ;!‹gE..dÜ41Š<MşCiY— •©?ľúç5D_yxď~®âŃŔéWysćĎ©—�»w␍nă^JJÝ{ü‘ňű~ű›Îţ™—ónękÇî<v÷ŘčᏲ˝g?]SÂ*\S]˛3W§ÓC�ľ ¨7zľŰ“W�mŃ�áÁ"r´�\."JIñ"r wCvŞĹăŘ”-¬R ÖFŔ¶ž&¶®ěMR:ů♡;čbş’­ąńѱG¦…U3_K˝6y�k{z"ttýGc?ž›¤ľu o6Üź—ŰuZ»ŮZ’PbÖ
U7Řs
ůÂŇĎ?X‰×Šç“Őfĺ2«µĐČgöxĚş%:3]Đ}Qn ő7ůâĽ�ťĹqÖ]l_p¦Ď)V…l¨ŠĘĄ$ÝH•u[tŻĐŃ}•– °”l©Ů×^}«ňĎ–ťă{‡7‡ţřđćKŻüčÍĹÍŢ>ܲu˙łcëIóW?üąň[äfyŮj‹łçŔöcŹ~ţÓ%­k›ť+ňJVlĂX‹g˙Č}Fs#î˛7É‹ółł3sô9‚PP�ŁŃjđĐęőZĂüćĎ|75ÎĄś5ÍüŮj’šW4Z-’z¦jÉCűÔˇ/¸•łg›[ě«Cywâ>ţĂTę‡3?ëęĚ}¬ ÔłPűćşî“·VŘô¶RŁN_ŞwT–ńflca o6flz°Ľî żp�O:Č&ąÉA^q�ď;ȱ9Ôé śÍAŔA.:Č9Qä¸�Ś;�—ńÔUĽgĎŕµ�⬇°‰
´Qúu(˝]›ŚěHµ_=h±,…Ťę»Cš­3ńŮőďNý^=w—ţK“vĹ—Çx8őĆC˝a␍7H?61ó4ß±9Z“˙MŰÇbřx䥞題ă÷ÎĐu}7öÜőŚi–ĹĹZ�!§rp1šń„1™Ťą�eáĹ.Ź>vưÓĺšć21rěUw;[şFěž<ruý
G^ú§Ä·ką Mę’ž Âŕ{gΦ^ŢŤżĘŮSWR/¶K·›ľ,Ľ�ÚˇśK]H˝3}ň™ď=r†ýéGĎ™â/]ŘňŔ ˇům,űżëź6„*®ţ•6ű†öچ€cS˙,Đ­IÝ
ë®ţ}xÝ˙oF-ŔYÍOá��€f~1ÜŤc·đ»7Q�[ €ŁďőHŰŹcwŠuTö5ÚKŘG_'KH�<IŢçząÓÜiľ•�ż"ěNhę4źTg5âĎtҧ»ś°␍_Éoá7áďĘ-%‘yß>2ď'bDŐ ¨Â<”@X…0Ăť*¬Áę}A…µ�©°n‡S*¬3YŞÂ�KÚU8“„Iź
gÁ"îéůň븗U8šx­
çB zB„ ÄáűU�@©@T�˝`Sa– •*,€CŘŞÂ(îTa-T_Ua\~¬ÂzphN©p,ŇĽŞÂ™Ü š÷T8 nÔźUálŘ–ˇQáŘ•áSá\X–ń\[xg8ľ=ľ¤OôGcűâᝡ¤čđW‰␍őKëĹőŃčÎá ¸.ŹEăľd8©Ë\w˝X�Ř‹&:|ÉqCÄ_·1Ľ#�–ű|‘Dkt8°6áFÁ¸X+^Ç˝©ôG‚ń%4Ô-­«ż*@ůµ”ż@'ś}b2î G|ńÝbtčZWÄxpg8‘ Ć‘Ž�ýu}ub·/Ś$E_$ nšWě
ű�ŚčĆ“>Ž&Cčđ®Ńx8űél‰şů8$¤/Üoń%“ÁD4ŇęKŕ\čŮÚxx$Z#Ž…Âţ�8ćK��`"Ľ3‚ĚűÄkuDäú0–H$şMî␍Ö ßCń`"Žě4-‰`<<¤š“!_’F>LĆĂ~ßđđ>,ÝH Uw`­ĆÂÉťÝ7|˘.í¦eS*†Gbńč^ć^mÂ#8Ź/ŕŰ'ŃFČ÷ů1Y�±°?Á’�9cľHműh< ˘“›×oĽ*�nĄ™�ď␍&�t$ $h!â0*áÄĂŃčnĘP4Žî’ˇÚţE#ITŤŠľ@cĆDEýŁ#´D�áäśs><ŠĽŘ°/‰VFuˇd2¶Ęé«ó©UńcQęвóĂxÉ}± ZŠ8µ22Ľ+ˇUeĄĄAômŘ(vĹ0?.tNTjÄąĆ\Z·TťÓŽ%u‰đp]4ľÓŮĺÚm¸!íÄ;‰÷í¸Q@Äۇ¸!?D!ű ΤBHńUÇU86@=,Ĺ[„ő(Eţ0ꋸiGQ>Ćž>f7
¨�LĆůpk␍őŞ^t0í„6 ľ-lD˝Č]hW„>Ä"�€VćQs-Â~”Š LeE¨ĹűĂu?ś+ÎŰţ“IĚK4 WKń®˙@ súµóú<O�ÍAóťdę÷ŽqŘŤ´( }hVD” ˛&�dX€YĄ¶űQ˘ŹIu3Mš—$›-¤6}ŔŚ]8ăęűY=ç$ýĚ6í‹´ĺ(Â!5Ă»`”U5�’To.¶Îü·őřŕécŢíesŢÂčO0^+â 5®tÎÖ˛ůFŁąCOčĽ!űX>L›vZDŐÜ�˝'~č<˘ŞëSëÁOeÓ^Rť5ßCě™`óFpáąnI°8ìn ˝YĆ|,˙随 7ÉdýHĆĎ>uŐŤ`~ŇłîP×Ő[ĄˇůŘQŢ^Ć*{5énR»TdÔÂQćű\öjYE¨˙Ać…|lŐď@Ťa6OÚŹë «hP­p’y;—Ą€ő0Ć(µĐÎş�®ő šÉ͸Glü@‹él-ěČ[+{Yޮڎ0oŚťĎ,•VgJG<Ěö˘ÝóUb]–Î^€Y«ý;ůbąIŞłF™Gü¤ëśî¨(ęŽ˛ŞĄWQş‡““9ËoTŐ‹!‡Î•öe„­Šë»¬ÂWJ'zG?u¬ű®żşRęTźť˙k=ęWŚepáŞ�Ďű2‚>nT×|d~­Ť.Xµs•čĂťg#Ű%bj˙¸Ổ×Y kĺús)Ű1ŻŤ"ÝŤaē̟Ëe‹a'ň»p†Ťé÷çô/†Ľp­í'-@ČJč'kÔ±•Čřžm#kq´áx4’UHżGäĂCřĽ‚7G`5ľ_÷Ówlâıq:Ö�*�EÍ*¤ß€¸é•8VŞxâĺ8–«¸DĘ�|™ŠW#Gč&:ú{NAî&çfČ33Ä8C˘ďů=2ţöŃ·|›˙Óĺ&›óňńËÜŕ%âĽ4x)zéřĄW/iţăuŃö»×WŰ~{±ŇöďWŰ^]}ˇ˙7«ńíýBýîáűťkłH)Ú6âSÄ[Ć›ź=CJeGń"ׯůYĽB~%4Ű~ńÂ"ŰĎ_¨°yĎ=ć<O�‹ç5Ółg?_ĽŘ…ă÷Îg㏠Ӥ@6�g~Xa“ż_µÖ%ż¬Ň5MěrĹ“«m0M˘ÓdúT¦␍N8%ž’OyOĹNičpôÔąS—Oi¦‰(çt čŢ'¸ź8÷‡–ĺÜ'˛r]†“�'ą)ľŮFÝ.†Ľ»đćá> :_,;*Ş\¶IçdËäńIÁ0IäÉÜ<{tüQţ⣗ĺľ{˘Év˘»Âö±’’“ÍÔŁ’'‰á;Äđmň4)$ůĐŚu°Čďn¶=p¬ŇöUĽż‚÷ř1ňE—Ăvü “_ŕ>ďj˛î·ÝĎÝw´ÂöŮĎTŘ GlG˘Gö9rDóé{+l]‡‰á^"ß›epŮqźşË`Ľ‹,˙„ëÜ^ś{ď$Ţ Ľ«bÄ#|Ś\‰‘‹ýGŚ Ĺ�'F¦g/ËwÄ0ťŃH‡-âj°•�˘ţâƢ~]#߯źřP×;Ř`Äqű–Ű6WĄmë–Űl[\Kmů␍yý¬®ĐŔ÷Gybŕ[ř.>Ęďç5�}DîsÔ¸äľŇ2|äąv÷~´÷ž^ľ§k‘­ď⮪.ÎÓîâ¦Iž\ë*·mpŰ:\vŰz ú/.LYÔaí/h°ô›�ˇßŘ`čçv,ĚÚ¦‰é¤5Ł\‹ŁÍĐb4ě7�ÓĐe�Ž^5Ět-H»dŕŁ@ş€Ś␍™&G§6őUWwNëf{;]÷V…TĘűčSî٢h*Đże«{Š�O{î:|Zw*␍}nĹ»ŘÓ©�)0Ž€qńT´zÉDr´Z˝H"I C�D‚˛%Í‹0r"‘L&!­’¨N@5}"�ŕLe¨0µĄ~ }ťŽMC�d"I…�ň(}2ŚR©!vá ‰ůé™ĺôPô?OAO3
endstream
endobj
13 0 obj
6443
endobj
14 0 obj
<</Type/FontDescriptor/FontName/BAAAAA+LiberationSans-Bold
/Flags 4
/FontBBox[-481 -376 1303 1033]/ItalicAngle 0
/Ascent 905
/Descent -211
/CapHeight 1033
/StemV 80
/FontFile2 12 0 R
>>
endobj
15 0 obj
<</Length 289/Filter/FlateDecode>>
stream
xś]‘Ín„ …÷<Ëébâ˙L'1&S­‰‹ţ¤¶€pµ$ â·/\¦mŇä»ÜsnŕŐ]Ó)iŁWłđ,ĄÖe3č“T$I©�ÜŢ*ÜůĚ4‰ś·ßW s§ĆĄ,Iôćz«5;=\Ĺ2Ŕ‰^Ś#ŐDuďę~Óú fP–Ć¤Ş¨€ŃÍybú™ÍˇëŘ ×–v?:Ëźŕ}×@S¬“pľX5ă`�š€”q\Ѳm+Jüë%E° #˙dĆI'Ťă<­§Č§Äs†|Ćó<śgž‹Ŕ­çSŕÜó9páů9Ť=_�3ô^_<?„ů¨Ż٦ Ś3ĂĚĆs8ĹGÝnďźçó˙‰ŤňÍ~fĺS’
~˙Q/Ú»p}ÚěŽT
endstream
endobj
16 0 obj
<</Type/Font/Subtype/TrueType/BaseFont/BAAAAA+LiberationSans-Bold
/FirstChar 0
/LastChar 15
/Widths[750 722 556 389 556 610 610 556 277 556 556 610 556 333 889 610
]
/FontDescriptor 14 0 R
/ToUnicode 15 0 R
>>
endobj
17 0 obj
<</F1 16 0 R/F2 11 0 R
>>
endobj
18 0 obj
<</Font 17 0 R
/XObject<</Im4 4 0 R>>
/ProcSet[/PDF/Text/ImageC/ImageI/ImageB]
>>
endobj
1 0 obj
<</Type/Page/Parent 6 0 R/Resources 18 0 R/MediaBox[0 0 595.303937007874 841.889763779528]/Group<</S/Transparency/CS/DeviceRGB/I true>>/Contents 2 0 R>>
endobj
6 0 obj
<</Type/Pages
/Resources 18 0 R
/MediaBox[ 0 0 595 841 ]
/Kids[ 1 0 R ]
/Count 1>>
endobj
19 0 obj
<</Type/Catalog/Pages 6 0 R
/OpenAction[1 0 R /XYZ null null 0]
/Lang(de-DE)
>>
endobj
20 0 obj
<</Creator<FEFF005700720069007400650072>
/Producer<FEFF004C0069006200720065004F0066006600690063006500200037002E0031>
/CreationDate(D:20220401110308+02'00')>>
endobj
xref
0 21
0000000000 65535 f
0000029273 00000 n
0000000019 00000 n
0000000374 00000 n
0000000394 00000 n
0000011762 00000 n
0000029442 00000 n
0000011784 00000 n
0000020862 00000 n
0000020883 00000 n
0000021078 00000 n
0000021508 00000 n
0000021790 00000 n
0000028320 00000 n
0000028342 00000 n
0000028545 00000 n
0000028904 00000 n
0000029131 00000 n
0000029174 00000 n
0000029541 00000 n
0000029638 00000 n
trailer
<</Size 21/Root 19 0 R
/Info 20 0 R
/ID [ <77F1D5E7090F17C94EF7E43CF16B016F>
<77F1D5E7090F17C94EF7E43CF16B016F> ]
/DocChecksum /2F8AB12D558369FCB5C37CF4905E79AE
>>
startxref
29813
%%EOF
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

+316
View File
@@ -1,7 +1,10 @@
import os
import shutil
import tempfile
from unittest import mock
from django.conf import settings
from django.test import override_settings
from django.test import TestCase
from django.utils import timezone
from documents import tasks
@@ -12,6 +15,7 @@ from documents.models import Tag
from documents.sanity_checker import SanityCheckFailedException
from documents.sanity_checker import SanityCheckMessages
from documents.tests.utils import DirectoriesMixin
from PIL import Image
class TestTasks(DirectoriesMixin, TestCase):
@@ -89,6 +93,318 @@ class TestTasks(DirectoriesMixin, TestCase):
mtime3 = os.stat(settings.MODEL_FILE).st_mtime
self.assertNotEqual(mtime2, mtime3)
def test_barcode_reader(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-39-PATCHT.png",
)
img = Image.open(test_file)
separator_barcode = str(settings.CONSUMER_BARCODE_STRING)
self.assertEqual(tasks.barcode_reader(img), [separator_barcode])
def test_barcode_reader2(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t.pbm",
)
img = Image.open(test_file)
separator_barcode = str(settings.CONSUMER_BARCODE_STRING)
self.assertEqual(tasks.barcode_reader(img), [separator_barcode])
def test_barcode_reader_distorsion(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-39-PATCHT-distorsion.png",
)
img = Image.open(test_file)
separator_barcode = str(settings.CONSUMER_BARCODE_STRING)
self.assertEqual(tasks.barcode_reader(img), [separator_barcode])
def test_barcode_reader_distorsion2(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-39-PATCHT-distorsion2.png",
)
img = Image.open(test_file)
separator_barcode = str(settings.CONSUMER_BARCODE_STRING)
self.assertEqual(tasks.barcode_reader(img), [separator_barcode])
def test_barcode_reader_unreadable(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-39-PATCHT-unreadable.png",
)
img = Image.open(test_file)
self.assertEqual(tasks.barcode_reader(img), [])
def test_barcode_reader_qr(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"qr-code-PATCHT.png",
)
img = Image.open(test_file)
separator_barcode = str(settings.CONSUMER_BARCODE_STRING)
self.assertEqual(tasks.barcode_reader(img), [separator_barcode])
def test_barcode_reader_128(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-128-PATCHT.png",
)
img = Image.open(test_file)
separator_barcode = str(settings.CONSUMER_BARCODE_STRING)
self.assertEqual(tasks.barcode_reader(img), [separator_barcode])
def test_barcode_reader_no_barcode(self):
test_file = os.path.join(os.path.dirname(__file__), "samples", "simple.png")
img = Image.open(test_file)
self.assertEqual(tasks.barcode_reader(img), [])
def test_barcode_reader_custom_separator(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-39-custom.png",
)
img = Image.open(test_file)
self.assertEqual(tasks.barcode_reader(img), ["CUSTOM BARCODE"])
def test_barcode_reader_custom_qr_separator(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-qr-custom.png",
)
img = Image.open(test_file)
self.assertEqual(tasks.barcode_reader(img), ["CUSTOM BARCODE"])
def test_barcode_reader_custom_128_separator(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-128-custom.png",
)
img = Image.open(test_file)
self.assertEqual(tasks.barcode_reader(img), ["CUSTOM BARCODE"])
def test_scan_file_for_separating_barcodes(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [0])
def test_scan_file_for_separating_barcodes2(self):
test_file = os.path.join(os.path.dirname(__file__), "samples", "simple.pdf")
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [])
def test_scan_file_for_separating_barcodes3(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t-middle.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [1])
def test_scan_file_for_separating_barcodes4(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"several-patcht-codes.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [2, 5])
def test_scan_file_for_separating_barcodes_upsidedown(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t-middle_reverse.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [1])
def test_scan_file_for_separating_qr_barcodes(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t-qr.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [0])
@override_settings(CONSUMER_BARCODE_STRING="CUSTOM BARCODE")
def test_scan_file_for_separating_custom_barcodes(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-39-custom.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [0])
@override_settings(CONSUMER_BARCODE_STRING="CUSTOM BARCODE")
def test_scan_file_for_separating_custom_qr_barcodes(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-qr-custom.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [0])
@override_settings(CONSUMER_BARCODE_STRING="CUSTOM BARCODE")
def test_scan_file_for_separating_custom_128_barcodes(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-128-custom.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [0])
def test_scan_file_for_separating_wrong_qr_barcodes(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"barcode-39-custom.pdf",
)
pages = tasks.scan_file_for_separating_barcodes(test_file)
self.assertEqual(pages, [])
def test_separate_pages(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t-middle.pdf",
)
pages = tasks.separate_pages(test_file, [1])
self.assertEqual(len(pages), 2)
def test_separate_pages_no_list(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t-middle.pdf",
)
with self.assertLogs("paperless.tasks", level="WARNING") as cm:
pages = tasks.separate_pages(test_file, [])
self.assertEqual(pages, [])
self.assertEqual(
cm.output,
[
f"WARNING:paperless.tasks:No pages to split on!",
],
)
def test_save_to_dir(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t.pdf",
)
tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR)
tasks.save_to_dir(test_file, target_dir=tempdir)
target_file = os.path.join(tempdir, "patch-code-t.pdf")
self.assertTrue(os.path.isfile(target_file))
def test_save_to_dir2(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t.pdf",
)
nonexistingdir = "/nowhere"
if os.path.isdir(nonexistingdir):
self.fail("non-existing dir exists")
else:
with self.assertLogs("paperless.tasks", level="WARNING") as cm:
tasks.save_to_dir(test_file, target_dir=nonexistingdir)
self.assertEqual(
cm.output,
[
f"WARNING:paperless.tasks:{str(test_file)} or {str(nonexistingdir)} don't exist.",
],
)
def test_save_to_dir3(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t.pdf",
)
tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR)
tasks.save_to_dir(test_file, newname="newname.pdf", target_dir=tempdir)
target_file = os.path.join(tempdir, "newname.pdf")
self.assertTrue(os.path.isfile(target_file))
def test_barcode_splitter(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t-middle.pdf",
)
tempdir = tempfile.mkdtemp(prefix="paperless-", dir=settings.SCRATCH_DIR)
separators = tasks.scan_file_for_separating_barcodes(test_file)
self.assertTrue(separators)
document_list = tasks.separate_pages(test_file, separators)
self.assertTrue(document_list)
for document in document_list:
tasks.save_to_dir(document, target_dir=tempdir)
target_file1 = os.path.join(tempdir, "patch-code-t-middle_document_0.pdf")
target_file2 = os.path.join(tempdir, "patch-code-t-middle_document_1.pdf")
self.assertTrue(os.path.isfile(target_file1))
self.assertTrue(os.path.isfile(target_file2))
@override_settings(CONSUMER_ENABLE_BARCODES=True)
def test_consume_barcode_file(self):
test_file = os.path.join(
os.path.dirname(__file__),
"samples",
"barcodes",
"patch-code-t-middle.pdf",
)
dst = os.path.join(settings.SCRATCH_DIR, "patch-code-t-middle.pd")
shutil.copy(test_file, dst)
self.assertEqual(tasks.consume_file(dst), "File successfully split")
@mock.patch("documents.tasks.sanity_checker.check_sanity")
def test_sanity_check_success(self, m):
m.return_value = SanityCheckMessages()